@startuml
title NATS — CREATE_RESOURCE : Peer A crée/met à jour Peer B (connexion on-demand)

participant "App Peer A (oc-api)" as AppA
participant "NATS A" as NATSA
participant "Node A" as NodeA
participant "StreamService A" as StreamA
participant "Node B" as NodeB
participant "DB Peer A (oc-lib)" as DBA

note over AppA: Peer B est découvert\n(via indexeur ou manuellement)

AppA -> NATSA: Publish(CREATE_RESOURCE, {\n  FromApp:"oc-api",\n  Datatype:PEER,\n  Payload: Peer B {StreamAddress_B, Relation:PARTNER}\n})

NATSA -> NodeA: ListenNATS callback → CREATE_RESOURCE

NodeA -> NodeA: json.Unmarshal(payload) → peer.Peer B
NodeA -> NodeA: if peer == self ? → skip

alt peer B.Relation == PARTNER
    NodeA -> StreamA: ToPartnerPublishEvent(ctx, PB_CREATE, PEER, payload)
    note over StreamA: Pas de heartbeat permanent.\nConnexion on-demand : ouvre un stream,\nenvoie l'événement, ferme ou laisse expirer.
    StreamA -> StreamA: PublishCommon(PEER, user, B.PeerID,\n  ProtocolUpdateResource, selfPeerJSON)
    StreamA -> NodeB: TempStream /opencloud/resource/update/1.0\n(TTL court, fermé après envoi)
    StreamA -> NodeB: stream.Encode(Event{from, datatype, payload})
    NodeB --> StreamA: (traitement applicatif)

else peer B.Relation != PARTNER (révocation / blacklist)
    note over NodeA: Ferme tous les streams existants vers Peer B
    loop Pour chaque stream actif vers PeerID_B
        NodeA -> StreamA: streams[proto][PeerID_B].Stream.Close()
        NodeA -> StreamA: delete(streams[proto], PeerID_B)
    end
end

NodeA -> DBA: (pas d'écriture directe — seule l'app source gère la DB)

@enduml
