@startuml title Node Initialization — Pair A (InitNode) participant "main (Pair A)" as MainA participant "Node A" as NodeA participant "libp2p (Pair A)" as libp2pA participant "DB Pair A (oc-lib)" as DBA participant "NATS A" as NATSA participant "Indexer (partagé)" as IndexerA participant "StreamService A" as StreamA participant "PubSubService A" as PubSubA MainA -> NodeA: InitNode(isNode, isIndexer, isNativeIndexer) NodeA -> NodeA: LoadKeyFromFilePrivate() → priv NodeA -> NodeA: LoadPSKFromFile() → psk NodeA -> libp2pA: New(PrivateNetwork(psk), Identity(priv), ListenAddr:4001) libp2pA --> NodeA: host A (PeerID_A) note over NodeA: isNode == true NodeA -> libp2pA: NewGossipSub(ctx, host) libp2pA --> NodeA: ps (GossipSub) NodeA -> IndexerA: ConnectToIndexers → SendHeartbeat /opencloud/heartbeat/1.0 note over IndexerA: Heartbeat long-lived établi\nScore qualité calculé (bw + uptime + diversité) IndexerA --> NodeA: OK NodeA -> NodeA: claimInfo(name, hostname) NodeA -> IndexerA: TempStream /opencloud/record/publish/1.0 NodeA -> IndexerA: json.Encode(PeerRecord A signé) IndexerA -> IndexerA: DHT.PutValue("/node/"+DID_A, record) NodeA -> DBA: NewRequestAdmin(PEER).Search(SELF) DBA --> NodeA: peer A local (ou UUID généré) NodeA -> NodeA: StartGC(30s) — GC sur StreamRecords NodeA -> StreamA: InitStream(ctx, host, PeerID_A, 1000, nodeA) StreamA -> StreamA: SetStreamHandler(heartbeat/partner, search, planner, ...) StreamA -> DBA: Search(PEER, PARTNER) → liste partenaires DBA --> StreamA: [] (aucun partenaire au démarrage) StreamA --> NodeA: StreamService A NodeA -> PubSubA: InitPubSub(ctx, host, ps, nodeA, streamA) PubSubA -> PubSubA: subscribeEvents(PB_SEARCH, timeout=-1) PubSubA --> NodeA: PubSubService A NodeA -> NodeA: SubscribeToSearch(ps, callback) note over NodeA: callback: GetPeerRecord(evt.From)\n→ StreamService.SendResponse NodeA -> NATSA: ListenNATS(nodeA) note over NATSA: Enregistre handlers:\nCREATE_RESOURCE, PROPALGATION_EVENT NodeA --> MainA: *Node A prêt @enduml