În FMCG moldovenesc, distribuitorul își angajează agenți care vizitează magazinele pe teren. Munca lor zilnică e să aducă noi parteneri în catalog. Cele două scenarii tehnice — magazinul există deja în SDIApp vs. magazinul e nou — apar diferit ca implementare backend, dar pentru agent e același tap, același flux.
Soluția (deja în Phase 3, documentată în api-spec.md): două callable-uri separate cu intent identic din punctul de vedere al UI-ului. UI-ul agentului face lookup-ul după telefon/IDNO, decide ramura și apelează callable-ul potrivit. Permisiunea retailers.onboard e deja acordată ambelor roluri.
retailers.onboard — acordat la distributor_owner + distributor_agentinviteExistingRetailerToLink({distributorIdno, retailerIdno, message?}) → scrie distributorLinkRequests/{id} · acceptat de retailer prin acceptDistributorLinkRequestinviteRetailerToOnboard({distributorIdno, invitedPhone, suggestedRetailerName?, suggestedRetailerIdno?, suggestedAddress?, message?}) → scrie retailerOnboardingInvitations/{id} keyed by phoneclaimRetailerOnboardingInvitation({invitationId, retailerIdno, retailerName, retailerAddress}) apelat de retailer după ce instalează app + sign in cu acel telefon · tranzacție atomică: creează org + adaugă owner + activează link cu sourceKind: 'onboarding'claimRetailerOnboardingInvitationHero "Adaugă magazin nou" — signature card cu accent. Acțiunea zilei: aduce noi parteneri. Vizitele programate dedesubt.
distributorLinkRequests filtrat după initiatedBy == me. Magazinele pe care le-am adus rămân vizibile aici 30 zile.
Caută după telefon sau IDNO. Sistemul răspunde instant: magazinul există deja. Ramură A: doar trimite o cerere de legătură.
inviteExistingRetailerToLink. Proprietarul primește notificare în app + SMS de backup; acceptă cu acceptDistributorLinkRequest.
Telefonul nu corespunde niciunui magazin. Ramură B: agentul completează rapid datele magazinului. Sistemul creează org + invitație + link request, totul atomic.
inviteRetailerToOnboard({distributorIdno, invitedPhone: '+37369887234', suggestedRetailerName, suggestedRetailerIdno, suggestedAddress, message?}) · scrie retailerOnboardingInvitations/{id} keyed by phone · trimite SMS cu deep linkclaimRetailerOnboardingInvitation care atomic: creează organizations/{retailerIdno}, adaugă caller ca retailer_owner, scrie distributorLinks cu sourceKind: 'onboarding'
După trimitere, agentul vede QR + cod 6-cifre pe loc. Proprietarul scanează cu camera telefonului → App Store/Play → instalează → app deschide direct ecranul "Acceptă invitația".