SmartPRO Docs ยท Internal ๐Ÿ”’ โ† Back to SmartPRO

Owner: Partnerships / Growth (platform admin) | Review: Quarterly

A partner moves through a tracked, auditable pipeline: admin sends a tokenised proposal, the partner reviews it (engagement is tracked per section), the partner self-signs an NDA to unlock the document vault, and the admin works the relationship on a kanban until the deal is closed and the partner is activated. Every external touch is logged to a timeline, and NDA signatures carry an Oman Electronic Transactions Law evidence chain.

Pipeline stages

The real status enum (partners.status) โ€” note the proposal comes before the NDA, and the NDA is partner-initiated, not emailed for signing:

draft โ†’ proposal_sent โ†’ meeting_scheduled โ†’ nda_signed โ†’ mou_signed โ†’ active
                                                                         โ†˜ on_hold (lost / stalled)

Tracked in Admin โ†’ Partnerships (kanban, one column per status; drag a card to move it).

Step-by-step

Create partner & issue a proposal token

Create the partner record, then `issueProposalToken` mints a signed **30-day JWT**. Prefer tokens over legacy access codes (codes are deprecated, accepted only while `LEGACY_PROPOSAL_CODES_ACCEPTED=true`). Status: `proposal_sent`.

Send the invitation

`sendInvitation` emails a branded message with the token proposal link and the Cal.com booking link. Logged to the timeline.

Partner reviews the proposal (tracked)

Partner opens `/partnership/:id?token=โ€ฆ` โ€” content is **server-only** (never shipped before unlock). An IntersectionObserver fires `trackView` per section (hero, terms, metrics, value, modules, why, next_steps, cta, documents) with time-on-section. First open triggers an admin first-view alert; the kanban card shows the view count. Full vault stays NDA-gated.

Partner signs the NDA

Partner goes to `/sign/:id/nda` โ€” 4 steps: contact info โ†’ review the bilingual (EN/AR) NDA (scroll-to-unlock) โ†’ typed signature โ†’ confirmation (ref `NDA-00001`). `submitNda` records a `partnerNdaRequests` row (validity **+3 years**), captures **IP + User-Agent** (Oman Electronic Transactions Law, RD 69/2008), writes an `nda_signed` timeline entry, auto-creates a "NDA โ€” Signed" vault document, **auto-advances status to `nda_signed`**, and sends dual emails (admin alert + signer's official record).

Grant portal access

`sendPortalAccess` emails the `/portal/{token}` link โ€” a deterministic **HMAC-SHA256 token link** (no password/credentials). The partner sees the timeline, NDA history, vault documents (download-audited), and action items they can mark done.

Work the pipeline & close

On the kanban: `addMeeting` logs a meeting and auto-creates action items + an agenda email; `addAction` / `addDecision` capture follow-ups. Move `nda_signed โ†’ mou_signed` (stamps `mouSignedAt`). `closeDeal('won')` โ†’ `active`; `closeDeal('lost'|'stalled')` โ†’ `on_hold`. On `active`, the NDA vault gate lifts and the timeline becomes the operational log.

NDA evidence chain

Each signature is stored with enough to stand up under Oman's Electronic Transactions Law:

Captured Field
Typed signature signature
Signer identity contactName, contactEmail, contactTitle
IP address logged at submit
User-Agent logged at submit (migration 0150)
Timestamps signedAt (UTC + Oman local), expiresAt (+3 years)
Reference NDA-00001 (padded id)

Rate limits: proposal unlock 5 attempts/hr/IP; NDA submit 3/hr/IP.

Live partners

mol ยท mocipi ยท occi ยท ooredoo ยท bank-sohar ยท usman โ€” content lives in server/data/partnership-content.ts (server-only).

Failure modes

Symptom Cause Fix
Proposal token rejected 30-day JWT expired Re-issue via issueProposalToken, re-send invitation
Partner can't unlock 5 attempts/hr limit hit Wait out the window or send a fresh token link
Legacy access code stopped working LEGACY_PROPOSAL_CODES_ACCEPTED=false in prod Migrate the partner to a token link
NDA submit failing 3/hr limit hit Retry after the window
Partner wants vault before signing requiresNda=true docs are gated Direct them to sign the NDA first
Email not sending Resend key issue Check emailConfig (masked key + last-used); send a testEmail
Need to reset a demo partner โ€” resetPartnerTestData โ€” never run against a real partner

Key files

File Purpose
server/routers/partnerships.ts All partner procedures + email generation
server/data/partnership-content.ts Server-only proposal content
client/src/pages/PartnershipProposalPage.tsx Public tokenised proposal page + view tracking
client/src/pages/PartnerNdaSignPage.tsx 4-step NDA signing flow
client/src/pages/admin/PartnershipsAdminPage.tsx Admin kanban + timeline