03 — Reconciliation and Surface Inventory
Build plan section 3 of n · tellatribe · 2026-10-03
Inputs: PRODUCT.md (confirmed truth), PRD.md v0.1 (authoritative requirements), PRD-Activation-Platform.md v1.1 (commercial vision, pending reconciliation — this document is that reconciliation).
Precedence: PRODUCT.md and PRD.md win every conflict with PRD-Activation-Platform.md.
Direction: internal first, commercial-shaped. The structure must survive the pivot to a sellable multi-tenant SaaS; the feature set does not have to.
Three confirmed truths used as hard filters below:
| Truth | Source | Effect on reconciliation |
|---|---|---|
| Two levels, permanently | PRD §2.1, §5.2, §11.3; PRODUCT.md | Anything implying depth, ranks, volume qualification or breakaways is Out |
| No fee to an affiliate, ever | PRD §2.1, §11.1 | Any affiliate-facing billing is Out; merchant-facing billing is a hook that stays empty |
| Admin success is absence | PRD §1, §10, §14; PRODUCT.md principle 5 | Any feature whose value requires a recurring admin login (approval of drafts, recommendation review, browsing dashboards) is Out or demoted to a report |
Part A — Reconciliation
A.1 Requirement-by-requirement table
Verdict key:
- As-is — in v1 as written (possibly under a different name).
- Reshaped — in v1 in a smaller or different form; the "how" is stated.
- Deferred/arch — not in v1, but a v1 architectural decision must leave room; the decision is stated.
- Deferred — not in v1, purely additive later, nothing to decide now.
- Out — conflicts with confirmed product truth; the reason is stated.
Priorities (P0/P1) are the Activation PRD's and are listed only so the team can see where the two documents disagree on what is core (notably: Mode 2 publishing is P1 there and v1-core here; Stripe payouts are P1 there and v1-core here).
§7.1 Workspace, onboarding, program setup
| ID | Activation requirement (short) | Pri | Verdict | Disposition |
|---|---|---|---|---|
| ONB-01 | Workspace creation for merchant / agency / network admins; tenant-isolated | P0 | Deferred/arch | Create a workspaces table with exactly one row. Every tenant-owned table carries workspace_id NOT NULL; RLS reads it. No workspace creation UI, no agency/network types, no data region. See checklist A.2 #1. |
| ONB-02 | Guided first-program builder from business-type templates | P0 | Deferred/arch | Programs are rows (PRD §5.1), never constants. Defaults live in one program_defaults seed object — that object is the template in embryo. No wizard, no template picker; the admin Program form is the v1 builder. |
| ONB-03 | Recommended defaults for tracking, attribution, fraud, disclosure, maturity, each explained | P0 | Reshaped | Program form ships PRD defaults (30-day hold, $50 minimum, 90-day window, last-click + customer lock) with a one-line "why this default" beside each field. "Persist the selected policy version" is already satisfied by PRD §5.1 (plan level in force at conversion pays) and §11.4 (versioned terms). |
| ONB-04 | Integration health check and sandbox test conversion before activation | P0 | Reshaped | An integration panel on the Program screen: API key, redirect-route snippet, Stripe webhook endpoint, last click received, last webhook received, and a test-mode conversion button. Directly serves PRD §14 "new product integrates in under a day." This is the one admin element in Part B not literally in PRD §10; it is pulled forward deliberately. |
| ONB-05 | Migration import of partners, links, historical conversions, assets, payout balances | P1 | Deferred for partners/links/assets (additive CSV). Out for payout balances | An imported balance would be a commission row with no conversion_id, which PRD §5.3/§11.2 forbids by schema constraint. If a legacy balance is ever needed it enters at the payout layer as an adjustment on a payout, never in commissions. |
§7.2 Partner recruitment, identity, network access
| ID | Activation requirement (short) | Pri | Verdict | Disposition |
|---|---|---|---|---|
| PRT-01 | Branded application/invitation flows with configurable fields, eligibility questions, approval steps, invite expiry; magic-link accept | P0 | Reshaped | One signup flow: recruiting link carries the sponsor code; affiliate claims a referral code; accepts a specific terms version. Magic link via Supabase Auth. Build the pending_approval enrollment state and its queue item regardless of the gated/open decision (D.1), so gating is a program toggle, not a build. Configurable form fields, eligibility questions: deferred, no arch impact (a JSONB column later). |
| PRT-02 | Portable partner profile across programs; each merchant sees only authorized fields | P0 | As-is within one workspace (PRD §5.2: one affiliate globally, per-program enrollment rows). Deferred/arch across workspaces |
Decide now: auth.users is platform-level; affiliates is workspace-scoped (one row per person per workspace); affiliate_programs is the enrollment inside the workspace. Cross-merchant portability later = one auth user, several affiliate rows. Do not make affiliates a global table without workspace_id. See A.2 #1. |
| PRT-03 | Partner segmentation and tags (status, channel, location, performance, risk, custom tags) | P0 | Reshaped (minimal) / Deferred | v1 targeting exists only where PRD §9.3 needs it: assets restricted by program or by performance threshold. Tags, channel, location: deferred, additive table. |
| PRT-04 | Opt-in vetted marketplace and direct recruitment | P1 | Deferred | PRD §4 names marketplace out of v1. Additive flag later; no v1 decision required. |
| PRT-05 | Partner education in the campaign workflow; acknowledgements gate packs when configured | P1 | Reshaped | v1 = the plain-English "what you may and may not claim" page (PRD §9.3) acknowledged once at signup with the terms. Per-asset gating: deferred, no arch impact. |
§7.3 Enablement Hub (collateral → activation)
| ID | Activation requirement (short) | Pri | Verdict | Disposition |
|---|---|---|---|---|
| ENB-01 | Campaign-centred asset library with type, owner, locale, channels, offer, dates, rights, approval, version | P0 | Reshaped + Deferred/arch | v1 assets are per-product, categorised, versioned, targetable (PRD §9.3). No campaign object. Arch: assets.product_id plus nullable program_id; the vault's grouping is data-driven, not a hardcoded product tab list, so a later "campaign" grouping is one more column. Do not name the link's free-text label campaign_id. |
| ENB-02 | Ingest files, URLs, product feeds, copy blocks, templates; validate; malware-scan | P0 | Reshaped | Upload image/video/document, copy blocks, scripts; type/size validation. Product feeds: Out of v1 (no ecommerce product). Malware scan: deferred, storage-hook, no arch impact. |
| ENB-03 | Channel-ready creative variants with source/version linkage | P0 | Reshaped + Deferred/arch | PRD Mode 1 requires correct aspect ratios per platform; Mode 2 requires per-network rendition. Arch: asset_versions → asset_renditions(platform, placement, file) from day one rather than one file per asset. |
| ENB-04 | Activation Packs per channel as an immutable snapshot of what was presented | P0 | Reshaped | The v1 "pack" is a token-rendered asset + caption + disclosure + the affiliate's link, taken by one of three modes. Record every take as an asset_uses row: asset_version_id, link_id, affiliate_id, mode (copy/download/publish/record), platform, created_at. This is the pack's ancestor, the source of PRD's usage count, and the data behind the affiliate's own used/posted marks on the vault. |
| ENB-05 | Partner-specific tracking outputs inside packs (link, deep link, coupon, sub-ID, QR) | P0 | As-is for link/deep link/QR/short link via tokens (PRD §9.3). Out for coupon | PRD §4 excludes coupon attribution in v1. Sub-ID = the link's campaign label. |
| ENB-06 | Enforce visibility, rights, expiry, approval; mark affected packs "update required" | P0 | Reshaped + Deferred/arch | v1: versioning plus program/threshold restriction. Arch: asset_versions.status (draft/active/retired) and nullable expires_at from day one; because asset_uses references the version, "which affiliates took the stale one" is a query later, not a migration. |
| ENB-07 | Compliant claims/disclosure modules; pack cannot be ready until acknowledgement recorded | P0 | As-is for disclosure on every asset + claims page (PRD §9.3, §11.5–6). Out for per-pack acknowledgement | A gate before every copy contradicts principle 4 (collateral is finished work; each rung removes a reason to stall). One acknowledgement at signup. |
| ENB-08 | Co-branding / limited personalisation via approved merge fields | P1 | As-is | PRD tokens {{ref_link}} {{short_link}} {{affiliate_name}} {{product_name}}. Logo merge field: deferred, one more token. |
| ENB-09 | Content approval workflow (submit draft/proof/URL; reviewer approves) | P1 | Out | Requires a human in the loop on every post — the daily login the product exists to eliminate. The Mode 2 "exactly what we will post" preview is the affiliate's own check, not an admin gate. |
| ENB-10 | Attribute pack/asset use through to clicks, conversions, commission, reversal rate | P0 | Reshaped + Deferred/arch | PRD §10 Reports: collateral usage vs revenue. Arch: clicks must carry link_id, not only ref_code, and asset_uses must carry link_id; otherwise asset-level revenue is unrecoverable later. When an affiliate takes an asset, the embedded link is the affiliate's default link for that product with the asset slug recorded on the asset_uses row and passed as the campaign label, so the chain asset → link → click → conversion → commission exists without the affiliate building anything. |
| ENB-11 | Partner content calendar; expiry/deadline/new-kit notifications in partner's timezone | P1 | Reshaped | v1 = "new since your last visit" badge + new-collateral email (PRD §9.3, §9.6) + the affiliate's own Mode 2 publish queue (scheduled posts). A campaign calendar: deferred. |
| ENB-12 | Graceful retirement: replacement / revoke / grace period; detect affected packs | P0 | Reshaped | v1: new version supersedes, old version retired. Detection of affected published items: deferred, enabled by ENB-06 arch. |
§7.4 Tracking and attribution
| ID | Activation requirement (short) | Pri | Verdict | Disposition |
|---|---|---|---|---|
| TRK-01 | First-party conversion tracking via SDK/pixel and server-side, idempotent, consent-aware | P0 | As-is (server-side) / Deferred (pixel) | PRD §6: /r/[code] on the product domain, S2S conversion API, Stripe webhook path, idempotency key required. Pixel: deferred, no arch impact; PRD §2.2 makes server-side primary on purpose. |
| TRK-02 | Links, direct links, deep links, coupons, QR, sub-IDs; enable/disable per program | P0 | Reshaped | Links, deep links, QR, short link, campaign label in v1. Coupons: Out of v1 (PRD §4). Per-program method toggles: deferred, no arch impact. |
| TRK-03 | Plain-language attribution presets plus advanced rule builder with multi-touch simulator | P0 | Reshaped (one preset) / Out (rule builder, multi-touch) | PRD §6.5 fixes last-click-wins within a per-program window plus customer lock on first conversion. A rule builder is the enterprise administration burden the Activation PRD's own §14 warns against, and multi-touch is incoherent with customer-locked recurring commissions. The window is already per-program; nothing more to shape. |
| TRK-04 | Attribution explanation for every conversion (candidates, rule version, winner, calculation) | P0 | Reshaped | Pulled forward. Admin: conversion detail shows click → code → affiliate, customer_attribution lock, program/plan level in force, flags tripped. Affiliate: commission detail shows amount basis, level, state, and the payable-on date. There is only ever one candidate, so no "excluded candidates" list. |
| TRK-05 | Reconcile cancellations, refunds, subscriptions, upgrades, chargebacks, offline/imported conversions | P1 | As-is (refund/chargeback/recurring via webhooks; voided/reversed states). Deferred (imported) | PRD §6.4, §7.3. Upgrades are just invoice.paid amounts. Offline conversions already have a path (S2S API) — nothing to add. |
| TRK-06 | Webhooks and REST APIs with scoped credentials, versioning, idempotency, rate limits, docs | P1 | Reshaped (inbound) / Out (outbound) | Inbound /v1 API with per-product scoped keys and idempotency is v1 (PRD §6.3, §12). Outbound webhooks to products conflict with "products call it; it never calls them" (PRODUCT.md). If a future merchant demands them it is an additive webhook_subscriptions table. Rate limits: deferred, edge-level. |
§7.5 Commissioning, payments, finance
| ID | Activation requirement (short) | Pri | Verdict | Disposition |
|---|---|---|---|---|
| PAY-01 | Commission templates: percent, flat, recurring share, new-customer rate, one-time bonus | P0 | As-is (percent/flat/recurring via plan_level.kind/basis/recurring_months). Deferred (bonus) |
"New-customer rate" is the first_payment basis. A volume bonus (PRD §4 allows one) must still attach to a conversion_id — the conversion that crossed the threshold — or it violates the structural guard. Not in v1; see D.7. |
| PAY-02 | Rules by product, category, customer status, channel, partner group, geography, coupon, date; conflict detection; test calc | P1 | As-is (by product, by date) / Out (the rest) | Program-per-product and program-in-force-at-conversion cover product and date. Category/channel/geo/group/coupon rules are the administration burden PRD §1 rejects. The pure commission engine (PRD §12) can take richer rules later without a rewrite — that is the only accommodation, and it is already required. |
| PAY-03 | Immutable ledger: earn, pending, approved, held, reversed, paid, adjustment; linked to events and policy versions; exportable | P0 | As-is | PRD §7. Name mapping: Activation "held" = PRD pending inside hold_days (plus flagged for manual holds); "adjustment" = a negative row pointing at its parent. One gap: PRD lists no manual transition into flagged for an already-pending commission. See D.5. |
| PAY-04 | Configurable maturity/approval/payout schedules; partner sees exact status, next eligible date, reason | P0 | As-is | PRD §5.3 hold_days, §8 monthly run, §9.1 balances by state with next payout date. Make the per-row "payable on" date and the reason ("30-day refund window") visible on the commission row — PRODUCT.md calls the hold period affiliate-visible. |
| PAY-05 | Payment-provider integration plus controlled exports | P1 | As-is | Stripe Connect Express primary, PayPal secondary, CSV escape hatch (PRD §8). Failed payouts return rows to approved. |
| PAY-06 | Tax/payment onboarding via processor; completeness state; gates payout | P1 | As-is | Stripe hosted onboarding owns KYC/1099 (PRD §2.5, §8). Payout run skips and notifies the un-onboarded. |
§7.6 Fraud, policy, trust
| ID | Activation requirement (short) | Pri | Verdict | Disposition |
|---|---|---|---|---|
| RSK-01 | Default risk policies: self-referral, duplicate attribution, coupon leakage, velocity, suspicious signups, restricted traffic; adjustable with false-positive note | P0 | As-is for the PRD §7.4 six (self-referral, duplicate customer, 2+ chargebacks/30d, refund rate, click-to-convert speed, IP volume). Out coupon leakage. Deferred restricted traffic sources | Thresholds are program/workspace config with a one-line consequence note, consistent with ONB-03. |
| RSK-02 | Explainable case queue: evidence, score, related events, recommended action, prior decisions, approve/hold/reject with reason | P0 | As-is (reshaped detail) | This is the PRD §10 exceptions queue. v1 rules are boolean, so there is no score; show which rules tripped and the evidence. "Prior decisions" = this affiliate's audit-log entries. |
| RSK-03 | Terms acknowledgement; violation register with evidence, corrective action, appeal | P0 | As-is (terms, PRD §11.4) / Deferred (violation register) | Suspend-with-reason, audited (PRD §10) covers v1. A structured register and appeal flow is additive. |
| RSK-04 | Append-only audit log for sensitive actions | P0 | As-is | PRD §12 audit_log. Must cover: reparent, suspend, manual commission state change, program rate change, API key create/revoke, payout release, admin view-as. |
§7.7 Reporting and operating cockpit
| ID | Activation requirement (short) | Pri | Verdict | Disposition |
|---|---|---|---|---|
| RPT-01 | Role-specific "Today" dashboards: operator action queue, partner work/earnings, finance payables | P0 | Reshaped | Admin home is the exceptions queue (PRD §10) — that is Today. Affiliate home is a what-happened / what's-next board, not stat cards (fits the chosen "Board" direction). A finance role does not exist in v1. |
| RPT-02 | Program/partner/campaign/channel/asset dashboards with consistent definitions and drill to ledger | P0 | Reshaped | PRD §10 Reports: revenue by affiliate/product/level, cohort retention, collateral usage vs revenue, liability outstanding. Every figure drills to its ledger rows. No channel/campaign cuts in v1. |
| RPT-03 | Custom reports, saved views, CSV/API exports with definitions | P1 | Deferred | v1 exports: affiliate statements, payout-run CSV, ledger CSV. Saved views additive. |
| RPT-04 | Activation funnel: invited → approved → onboarded → opened → pack created → published → clicked → converted → paid | P0 | Deferred/arch | Emit the events now, build the report later. PRD §14's own success criteria ("median affiliate visits the vault within 48h and posts something") cannot be measured without signed_up, code_claimed, link_created, link_copied, asset_used(mode), first_click, first_conversion, payout_onboarded, first_paid. One events table, append-only, from day one. |
| RPT-05 | Recommended next actions with evidence; dismissible; never auto-alter money | P1 | Deferred | Recommendations are things an admin logs in to read. Automated affiliate nudges (email on new collateral, PRD §9.6) do the useful part without the admin. |
§7.8 Integrations (no IDs in source; labelled by class)
| Class | Activation P0 / P1 | Verdict | Disposition |
|---|---|---|---|
| INT-Ecommerce | Shopify + generic (P0); Woo/BigCommerce/Adobe/feeds (P1) | Deferred | No ecommerce product in the portfolio. The generic S2S conversion API is the adapter; a Shopify app is additive. |
| INT-Billing | Stripe + generic subscription events (P0); Paddle/Chargebee/Recurly (P1) | As-is (Stripe) | PRD §6.4. Scope the webhook to platform revenue only for HealthyApp — never Connect tenant charges. |
| INT-Marketing | CSV + link-compatible email (P0); Klaviyo/Mailchimp/HubSpot/Salesforce/social publishing (P1) | Reshaped | Social publishing is v1-core here (Mode 2), not P1. Email/CRM connectors: deferred. |
| INT-Payments | CSV export (P0); processor orchestration (P1) | As-is, inverted | Stripe Connect is v1; CSV is the escape hatch. |
| INT-Identity | Magic link + MFA for staff (P0); SSO/SAML/SCIM, custom domains, retention controls (P1) | As-is (magic link; admin MFA) / Deferred/arch (custom domains) | Admin MFA is cheap and sits on the money boundary — ship it. Custom portal domains: resolve the workspace from the session, never from the URL, so a subdomain-per-workspace later is a routing change only (A.2 #6). |
Activation PRD §8–§10 (IA, permissions, data model) — handled in A.2
Summary of the name mapping so the team reads both documents without translating twice:
| Activation PRD object | v1 table(s) | Note |
|---|---|---|
| Workspace | workspaces |
One row in v1 |
| Program | programs, plan_levels |
As PRD §5.1 |
| Partner identity | auth.users + affiliates |
User is platform-level; affiliate is workspace-scoped |
| Enrollment | affiliate_programs |
Carries approval state and accepted terms version |
| Campaign | — | No v1 object. Free-text label on links |
| Asset | assets, asset_versions, asset_renditions |
PRD lists only assets; versions and renditions are additions this document requires |
| Activation Pack | asset_uses |
Replaces PRD's asset_views; records mode, version, link |
| Tracking output | referral_codes, links |
PRD lists referral_codes but per-link performance (§9.2) needs a links row |
| Touchpoint / conversion | clicks, conversions, customer_attribution |
As PRD §6 |
| Commission ledger entry | commissions |
As PRD §7 |
| Payout batch | payout_runs, payouts, payout_items |
PRD lists payouts/payout_items; the run itself needs a row |
| Risk case | queue view over commissions.state = flagged, payouts.state = failed, negative balances, affiliate_programs.state = pending_approval |
No separate table in v1; the queue is a query |
| Audit event | audit_log |
As PRD §12 |
| (not in Activation PRD) | social_accounts, publish_jobs, recordings |
Required by PRD §9.3 Modes 2 and 3; absent from PRD §12's table list, which predates the Oct 3 §9.3 update |
A.2 The "commercial-shaped" checklist
Decisions that must be made in Phase 1 (Ledger) and Phase 2 (Tracking) so the SaaS pivot is a feature project, not a rewrite.
| # | Decision | Do in v1 | Do NOT build yet | Cost of getting it wrong |
|---|---|---|---|---|
| 1 | Tenancy boundary | workspaces table, one seeded row. workspace_id NOT NULL FK on products, programs, affiliates, affiliate_programs, links, clicks, conversions, customer_attribution, commissions, payouts, payout_runs, assets (+versions/renditions/uses), social_accounts, publish_jobs, recordings, events, audit_log, api_keys. One current_workspace_id() SQL helper that every RLS policy uses. Composite uniques include workspace_id — except referral_codes.code, which is globally unique because go.tellatribe.com/CODE is one shared short domain. Partition clicks/conversions by month with workspace_id as a leading index column. |
Workspace switcher, workspace creation, agency/network workspace types, data region, plan tiers. | clicks and conversions are the hottest, partitioned, never-updated tables (PRD §12). Adding a column and rewriting every RLS policy on them after launch is the single most expensive retrofit in the system, and the RLS boundary is "the highest-consequence security boundary" (PRD §12). |
| 2 | Roles and permissions | Two roles: owner and affiliate. Model as workspace_members(user_id, workspace_id, role) even with one row. Authorise through one can(actor, action, resource) helper, never if (role === 'admin') scattered in components. Admin "view as affiliate" is a server-side read-only context flag, written to audit_log. Admin MFA on. |
Program manager, creative manager, finance approver, compliance reviewer, agency manager, partner team member; dual approval; step-up auth; partner organisations with members. | Authorization sprinkled as role checks across every screen means every screen is touched at pivot. Building six roles now for one human means six untested permission matrices guarding real money. |
| 3 | Program templates vs hardcoded program | Programs and plan levels are rows (PRD §5.1 already). MAX_DEPTH = 2 is a named constant in the engine with the legal reason in a comment, plus CHECK (level IN (1,2)) on plan_levels. All defaults (hold 30, min $50, window 90, attribution last-click) live in one program_defaults object that seeds the Program form. The engine stays a pure function (conversion, program, tree) → commission[]. |
Template picker, business-type templates, setup wizard, rule builder, per-channel/geo rules. | HealthyApp's 25%/5% hardcoded anywhere outside a plan_levels row means the second product is a code change and the first paying merchant is an engine rewrite. |
| 4 | API-key scoping | api_keys(workspace_id, product_id, scopes[], key_hash, prefix, mode: test/live, created_by, revoked_at). Scopes: clicks:write, conversions:write. Shown once on creation; two keys may be live at once for rotation. Every inbound request resolves workspace_id from the key, never from the payload. Test-mode keys write to the same tables with mode='test' and are excluded from the ledger's payable set. |
Key-management UI beyond create/reveal-once/revoke on the Program screen; rate limiting; OAuth client credentials; per-key IP allowlists. | A single AFFILIATE_API_SECRET env var means re-keying every integration at pivot and no way to attribute an inbound event to a tenant. Test mode retrofitted later means the first merchant's integration test pollutes a live ledger. |
| 5 | Asset ownership by workspace | assets.workspace_id; storage paths /{workspace_id}/{asset_id}/{version}/{rendition}; signed URLs only. Token substitution is a pure function (asset_version, affiliate, link) → rendered with no knowledge of any product. Product marks are data (products.name, logo_url, mark_color), rendered by one component; no HealthyApp-specific component anywhere in the vault. Scripts are an asset type with read_seconds_at_default_speed. |
Brand-kit import, rights metadata, locale variants, DAM features, malware scanning, product feeds. | The vault is the second differentiator (PRODUCT.md). A flat bucket plus product-aware components means re-uploading and re-rendering every asset for the first external merchant — and a cross-tenant signed-URL leak on collateral is a sales-killing incident. |
| 6 | Branding / white-label hooks | All colour, type and spacing as CSS custom properties on :root, once. workspaces.branding JSONB exists and holds tellatribe's own defaults (name, logo path, support email, sender name); transactional emails and the portal header read from it. Workspace resolved from session membership, never from the URL path. Portal stays at tellatribe. |
Theme editor, per-workspace palettes, custom portal domains, custom email sending domains, white-label toggle. The tellatribe palette is locked once chosen; this item is about tokenisation, not colour. | Hex values and the string "tellatribe" hardcoded in components and email templates means a grep-and-pray pass over every file when the first merchant wants their logo in the header. A workspace slug baked into every route means rewriting routing and every internal link. |
| 7 | Billing hooks that stay empty | workspaces.plan = 'internal' column; no Stripe customer for the workspace; no billing code path anywhere. Keep the payout Stripe account reference on the workspace (workspaces.payout_account_ref) so the payout engine asks the workspace which account pays, rather than reading one env var. |
Plans, metering, invoices, trials, usage limits, merchant checkout. | Low cost if the column exists; high cost if the payout rail is read from a global env var — the SaaS payout model (does tellatribe pay out as platform, or does each merchant connect their own Stripe?) is a genuine fork, and a workspace-level account reference is what keeps both branches open. |
| 8 | Event instrumentation and promotional-action counting | Append-only events(workspace_id, actor, affiliate_id?, name, props JSONB, occurred_at) from day one; the names in RPT-04 above. Separately, every promotional action is already a row — asset_uses(mode), publish_jobs, recordings — so "actions per affiliate per period" is a query. PRODUCT.md requires this count from day one for the future activity bonus (D.7). |
Funnel report, dashboards over it, warehouse export, the bonus itself. | Without it, PRD §14's success criteria are unmeasurable, the commercial pitch ("time to first promotion") has no evidence, and the activity bonus cannot be switched on without a backfill that does not exist. Cannot be back-filled. |
| 9 | Config, not constants | Hold days, minimum payout, cookie window, 1099 threshold, chargeback-flag threshold, refund-rate threshold: rows on programs or workspaces, never env or code constants. PRD §2.5 and §5.3 already say this. |
Settings search, advanced-mode toggle. | Every one of these is a per-merchant number in the SaaS. |
A.3 What the Activation PRD got right that PRD.md lacks
Pulled forward because each makes the internal product better, not bigger.
- "Why this default?" lines (ONB-03). One sentence beside each program setting — "30 days matches the refund window; pay earlier and you chase money back." Costs nothing; stops the one admin from guessing in a year.
- The "Today" framing for the affiliate (RPT-01, §8.2 My Work). PRD §9.1 describes a stats dashboard. The affiliate's home should instead be the next payout and a feed of what happened, with one next action. Stats move to Earnings. This matches the chosen Board direction and principle 3 (depth on demand).
- A per-conversion explanation (TRK-04) and per-row "payable on + reason" (PAY-04). PRD guarantees traceability in the schema; these make it visible. The affiliate-facing version is the cheapest dispute prevention available.
- The Activation Pack as a snapshot (ENB-04, §10). Reshaped to
asset_uses, it makes "collateral usage vs revenue" actually computable, powers the affiliate's own used/posted marks on the vault, and later enables "update required" on stale takes. - Asset expiry and retirement (ENB-06, ENB-12). Launch collateral goes stale.
expires_atand aretiredstatus on versions cost two columns now. - Guardrail metrics (§5). Replace vanity with: confirmed-invalid conversion rate, tracking error rate (webhook events failed/dead-lettered), time-to-resolution for queue items, ledger-vs-Stripe reconciliation variance. These are the admin's monthly glance.
- Activation funnel events (RPT-04, §12). Instrument now; see A.2 #8.
- Integration health check (ONB-04). Last click / last webhook received and a test conversion are what make "integrates in under a day" verifiable rather than hoped.
- Empty-state rule (§8.3). Every empty state says what to do next, why it matters, and how long it takes. Adopt as a design rule for every screen in Part B.
Not pulled forward, with reason: content approval (admin login), recommendations (admin login), rule builder and multi-touch (administration burden; incoherent with customer lock), marketplace (PRD §4), coupons (PRD §4), six staff roles (one human).
A.4 Recommendation on the documents
Keep PRD-Activation-Platform.md as a frozen appendix retitled "v2 vision — commercial platform," with its status line changed to point at this reconciliation as the authoritative mapping; do not fold it into PRD.md and do not retire it. Folding would triple the length of the authoritative document and reintroduce every Out item as a standing temptation in the file engineers actually read; retiring would discard the only articulation of the sellable product and the only place the commercial personas, guardrail metrics and funnel taxonomy are written down. PRD.md should gain a short §16 "Commercial shape" that lists the nine checklist decisions in A.2 by reference, and PRD.md §12's key-table list should be updated with the additions named in the mapping table above (workspaces, links, asset_versions, asset_renditions, asset_uses, payout_runs, social_accounts, publish_jobs, recordings, events, api_keys).
Part B — Surface inventory
Derived from PRD §9 (portal), §9.3 (three collateral modes), §10 (admin), §11 (terms versioning), §8 (payouts), plus the four pull-forwards marked PF in A.3 (integration panel, commission detail, per-row payable-on, affiliate home as a board). Nothing else is added.
Conventions:
- Affiliate portal is mobile-first; design and review at 390 wide. Admin is desktop-first. Public is mobile-first.
- Common states not repeated per row: loading (skeleton of the same layout; a commission row never changes size or position across states — only the state mark changes) and error (inline, retryable, never a blank page). Rows list only domain states.
- Routes are the portal's;
/r/[code]lives on each product's domain andgo.tellatribe.com/[code]is a bare redirect. Neither is a screen.
B.1 Public (unauthenticated)
| # | Screen | Route | Purpose | Primary action | Data shown | Domain states | Form |
|---|---|---|---|---|---|---|---|
| P1 | Join | /join · /join/[sponsor_code] |
Become an affiliate; sponsor set from the recruiting link | Continue (sends magic link) | Sponsor name if code present ("Invited by Ashley"); email; display name; referral-code claim with live availability check and a suggestion from the name; the current terms version and the claims guidelines, accepted together | Code taken; sponsor code invalid/suspended (join proceeds without sponsor, says so); already an affiliate (→ sign in); signup closed (if gated and closed — D.1) | Mobile |
| P2 | Check your email | /join/sent · /sign-in/sent |
Confirm the magic link went out | Open mail app / Resend | Masked email | Resend cooldown; link expired (from P4) | Mobile |
| P3 | Sign in | /sign-in |
Returning affiliate or admin | Send magic link | Unknown email (same message as success — no enumeration) | Mobile | |
| P4 | Auth confirm | /auth/confirm |
Token exchange; no UI beyond a spinner | — | — | Expired/used token → P3 with message | — |
| P5 | Pending approval | /join/pending |
Shown only if the program is gated (D.1) | — | What happens next and expected time | Approved (redirect on next visit); declined | Mobile |
| P6 | Terms | /terms/[version] |
The exact versioned text an affiliate accepted (PRD §11.4) | — | Terms text, version, effective date | Superseded version (banner linking to current) | Mobile |
B.2 Affiliate portal (mobile-first)
| # | Screen | Route | Purpose | Primary action | Data shown | Domain states | Form |
|---|---|---|---|---|---|---|---|
| A1 | Board (home) PF | / |
The three things PRODUCT.md "Portal Priorities" names, in order: what you can promote · where you stand · jump into collateral. Acceptance test: "it should feel simple to take some action" — a first-timer takes one promotional action without reading | PROMOTE on a product row (→ A10 filtered to that product; the asset already carries the link) · secondary: GET A LINK (→ A8) | Products strip (priority 1): one row per enrolled product — mark, name, your L1/L2 rate in plain words ("25% of first 12 months"), count of collateral, PROMOTE. Standing hero (priority 2): next payout amount, date, days away, state word; pending / approved split one tap away; guidelines link (→ A17) sits with it. Feed: commission earned (product mark, L1/L2, amount, state, time), commission approved, payout sent, downline joined, new collateral, click milestones (first click, then every 100 — not every click). Payout-onboarding banner when a pending commission exists and onboarding is incomplete (D.4) |
First run: hero reads "$0.00 — first payout after your first sale"; products strip is the dominant element; three-step list: Promote something · Get your own link · Set up payouts (later). Link live, nothing yet: "Your link is live · 0 clicks". Negative balance: hero shows the net and why. Suspended: read-only board with the reason and contact. Terms updated: blocking interstitial A20 | Mobile |
| A2 | Earnings | /earnings |
PRD §9.1 metrics with density on demand | Change period | Clicks, unique visitors, conversions, conversion rate, EPC, earnings for period, across all products and per product; pending / approved / paid balances separately; next payout date and projected amount; downline counts by level; 30-day sparkline. Segments: Ledger · Payouts · Team · Payout method | No data yet (explains what each number will mean); period with zero activity; negative balance | Mobile |
| A3 | Commission detail PF | /earnings/commissions/[id] (sheet) |
Why this amount, why this state | — | Amount; level (direct / override on name); product; conversion date; plan rule in force (e.g. "25% of $99 first payment"); state; payable on date and reason ("30-day refund window"); if reversed/voided, the reason and the parent row; payout it was paid in | Pending · Approved · Paid · Voided · Reversed · Flagged ("under review — you don't need to do anything") | Mobile |
| A4 | Payouts | /earnings/payouts · /earnings/payouts/[id] |
PRD §9.5 payout history with per-payout commission detail | Download statement | List: date, amount, method, status. Detail: every commission row inside it, netted reversals, provider reference | No payouts yet; failed (what happened, what to fix); skipped under minimum (balance rolled forward); skipped — onboarding incomplete (→ A6) | Mobile |
| A5 | Team (downline) | /earnings/team |
PRD §9.4 single list of recruits | Share recruiting link | Name, join date, product(s), activity level. Never earnings or contact details. L2 count in header | Empty: "No one yet — bring in someone good, earn on what they sell" + recruiting link | Mobile |
| A6 | Payout method | /earnings/payout-method |
PRD §9.5 onboarding and tax status | Set up with Stripe (hosted) / Use PayPal instead | Method; onboarding state; tax-form state (from Stripe); minimum payout and next run date | Not started; in progress (Stripe requirements outstanding — list them); complete; restricted by provider; PayPal (email only); country unsupported by Stripe (→ PayPal) | Mobile |
| A7 | Links | /links |
Every link with its own numbers (PRD §9.2) | New link | Per link: product mark, label, destination, clicks, conversions, earnings; copy on the row. A default link per enrolled product is minted at join (label "Default") so collateral can carry a link before the affiliate has built one; labelled links are the pro's per-channel breakdown. Pinned section: recruiting link (visually distinct, "sets sponsorship, earns nothing by itself") | Never truly empty (the default link exists); "only your default link so far" explains labels in one line; one product only (list collapses the product column) | Mobile |
| A8 | Link builder | /links/new |
Product → destination → label → link, short link, QR | Create | Product picker (skipped when enrolled in one); destination page (default: product home; curated list + custom path); campaign label (optional) | Not enrolled in the chosen product; short domain not configured (short-link row hidden — D.8) | Mobile |
| A9 | Link detail | /links/[id] (sheet) |
Copy, QR, per-link performance | Copy / Download QR / Share | Full link, short link, QR, clicks, conversions, earnings, created date | Zero traffic yet | Mobile |
| A10 | Studio (vault) | /studio |
PRD §9.3 collateral, three modes | Open an asset | Per product, by category (email swipes, social captions, images, video, one-pagers, webinar decks, FAQ/objections, scripts). Each card: thumbnail, title, running time (script read time, video length), "new since your last visit" badge, recommended-use note, the affiliate's own marks (used / posted), mode affordances (Copy · Post · Record). Filters: product, category, mode | Empty (no collateral for your products yet — honest, dated); only-populated categories shown; restricted asset (threshold not met — says what unlocks it); new version available on something already used | Mobile |
| A11 | Asset detail | /studio/[asset] |
The rendered, personalised asset | Copy / Download (Mode 1) · Post (→A12) · Record (→A15, scripts only) | Rendered preview with {{ref_link}} etc. substituted; caption with disclosure already inside; renditions per platform (aspect ratio chips); version; which link it carries (per-asset link, A.1 ENB-10) |
Copied (confirmation that survives a glance); downloaded; posted before (date, where); restricted; superseded version | Mobile |
| A12 | Post composer (Mode 2) | /studio/[asset]/post |
Publish from inside the portal | Post now / Schedule | Connected accounts to pick; per-network "exactly what we will post" preview (rendition, caption, link placement, disclosure); time picker | No connected accounts (→A13 inline); account token expired; network rejected (reason); queued; posted (link to the post) | Mobile |
| A13 | Connected accounts | /studio/accounts |
OAuth connection manager | Connect | Per network: account name, status, connected date | None connected; expired (reconnect); revoked by network | Mobile |
| A14 | Publish queue | /studio/queue |
Scheduled, posted, failed — with retry | Retry / Cancel | Items: asset, network, scheduled time, status, failure reason | Empty; failed with retry; posting in progress | Mobile |
| A15 | Prompter (Mode 3) | /studio/[asset]/record |
Phone as teleprompter over live camera | Record | Script over the lens (not beside), substituted CTA already in it, disclosure inside the script; speed thumb adjustable during recording; countdown; visible recording state readable at a glance; front/rear toggle; portrait default; caption safe-area marked; elapsed vs estimated read time | Camera/mic permission denied (how to fix, fall back to Download script); Standby → Countdown → Recording → Recorded; interrupted (call/background) keeps the partial take | Mobile, full-screen, bottom bar hidden |
| A16 | Review take | /studio/[asset]/record/review |
Keep, retake, or ship it | Post (→A12) / Save to phone / Retake | Playback; take length; retake is one tap and never threatens the previous take until the new one lands | Multiple takes (pick one); saving; saved; uploaded for posting | Mobile |
| A17 | Guidelines | /studio/guidelines |
PRD §9.3 what you may and may not claim; disclosure | — | Plain-English claims rules per product (HealthyApp health claims called out), the exact disclosure text, income-claim prohibition | Updated since acceptance (badge) | Mobile |
| A18 | Settings | /settings |
Profile, preferences | Save | Name, email, referral code (immutable once used — shown, not editable), sponsor name, terms version accepted (→P6), delete-account request (PRD §11.7 — anonymises, ledger survives) | Deletion requested (pending admin) | Mobile |
| A19 | Notifications | /settings/notifications |
PRD §9.6 each switch individual | Toggle | First click · first conversion · daily conversion digest · commission approved · payout sent · new collateral · downline signup | All off (warns that payout problems will still be sent — operational mail is not optional) | Mobile |
| A20 | Terms update | interstitial on any route | PRD §11.4: accept the new version to continue | Accept | What changed, version, link to full text | Declined (read-only board, no new links) | Mobile |
B.3 Admin (desktop-first)
| # | Screen | Route | Purpose | Primary action | Data shown | Domain states | Form |
|---|---|---|---|---|---|---|---|
| D0 | Admin sign-in | /sign-in (+ MFA step) |
Owner login | Send magic link → enter MFA code | — | MFA not enrolled (enrol on first login) | Desktop |
| D1 | Queue (home) | / |
PRD §10 exceptions queue — the only screen that must be good at being empty | Per item, 2–3 buttons | Items: flagged commissions/conversions (which rules, evidence), failed payouts (provider reason), negative balances (amount, since, producing or not), pending approvals (if gated), deletion requests. Count by type; age of oldest | Empty — the normal state ("All services running normally"; last run, next run, pending total); items; item actioned (slides out, undo for 10s where reversible) | Desktop |
| D2 | Exception detail PF | drawer on D1 (and from D4) | TRK-04 explanation | Approve / Void / Suspend affiliate · Retry payout / Mark paid manually · Write off / Keep · Approve / Decline applicant | Click (time, IP hash, referer, campaign) → code → link → affiliate; customer_ref and attribution lock; amount; program and plan levels in force; L1 and L2 rows generated; rules tripped with evidence; this affiliate's prior queue decisions (audit) | Each action requires a reason for anything manual; result written to audit | Desktop |
| D3 | Programs | /programs · /programs/[id] |
PRD §10 create product, rates, hold, minimum, window, terms | Save (forward-only) | Product (name, domain, logo, mark colour); L1 and L2: kind, value, basis, recurring months; hold days; minimum payout; cookie window; attribution (fixed: last click + customer lock, shown not editable); terms (versioned, new version = new acceptance); gated toggle (D.1). Each default with its one-line "why". Integration panel (PF ONB-04): API keys (create, reveal once, revoke; test/live), redirect-route snippet, Stripe webhook URL + signing secret, last click received, last webhook received, test conversion button | New (unsaved, nothing integrated); live; rate changed (banner: applies to conversions from now); no events received yet; test conversion result pass/fail with remediation | Desktop |
| D4 | Affiliates | /affiliates · /affiliates/[id] |
PRD §10 search, view, adjust, suspend, reparent, view-as | Search; on detail: Suspend · Reparent · Flag a commission · Write off · View as | List: name, code, status, products, sponsor, downline count, balances by state, open flags. Detail: profile, enrollments and accepted terms version, sponsor and downline, links with stats, ledger (every row, drill to D2), payouts, payout-onboarding state, audit trail | Pending approval; active; suspended (reason); negative balance; onboarding incomplete; deletion requested. "Adjust" means: flag/void a commission with reason or write off a negative balance — never edit a row (PRD §7.1) | Desktop |
| D5 | Payout runs | /payouts · /payouts/[run] |
PRD §10 one screen: review the batch, release | Release | Upcoming: run date, affiliates included, batch total, netted reversals, skipped under minimum (count, rolled total), skipped onboarding-incomplete (count, notified), method split. History: runs with totals and failure counts. Run detail: per-affiliate payout → rows | Nothing payable; ready; releasing (progress); completed with failures (→ D1); released by whom, when (audit) | Desktop |
| D6 | Collateral | /collateral · /collateral/new · /collateral/[id] |
PRD §10 upload, categorise, version, target — the most-used admin screen | Publish version | Product; category; title; files and renditions per platform; copy with token insertion and live preview as a sample affiliate; required disclosure block; recommended-use note; restriction (program / performance threshold); expires_at; versions; usage: takes by mode, posts, revenue attributed. Scripts: text, estimated read time at default scroll speed, spoken CTA token |
Draft; active; retired; expired; superseded; missing disclosure (cannot publish); rendition missing for an enabled network (warns) | Desktop |
| D7 | Reports | /reports |
PRD §10 revenue by affiliate / product / level; referred-customer cohort retention; collateral usage vs revenue; commission liability outstanding. PF guardrails: invalid-conversion rate, webhook failure/dead-letter count, queue time-to-resolution, ledger-vs-Stripe variance | Change period / Export CSV | As listed; every figure drills to ledger rows | No data; period with none | Desktop |
| D8 | Audit log | /audit |
PRD §12 audit_log as a screen |
Filter | Actor, action, object, reason, before/after, time, IP | Empty | Desktop |
| D9 | Workspace settings | /settings |
The one row | Save | Workspace name; support/sender email; payout account reference (read-only); 1099 threshold; fraud thresholds (chargebacks/30d, refund rate, click-to-convert seconds, IP volume) each with a consequence line; admin members (owner only in v1); MFA status | — | Desktop |
B.4 Non-screen surfaces the design must still cover
- Redirects:
/r/[code]on each product domain (302, setsac_click);go.tellatribe.com/[code]. Failure must still land on the destination (PRD §12 non-negotiable; Activation §11 reliability). - Transactional email (PRD §9.6 + operational): first click; first conversion; daily conversion digest; commission approved; payout sent; new collateral; downline signup; operational, not switchable: magic link, payout onboarding needed, payout skipped/failed, terms updated, account suspended, admin queue alert and monthly run reminder.
- Hosted third-party steps: Stripe Connect Express onboarding (return and refresh URLs → A6); social OAuth consent screens (return → A13).
- QR code and statement PDF as downloadable artefacts.
B.5 The affiliate's first five minutes
Assumes open signup (D.1 recommended default), one product live (HealthyApp), and arrival via a recruiting link.
| Min | Screen | What they do | What they see that proves it worked |
|---|---|---|---|
| 0:00 | P1 /join/ASHLEY |
Sees "Invited by Ashley". Enters email, name. Code field pre-suggests from the name; they accept or edit; availability confirmed inline. Accepts terms vN and the claims guidelines in one checkbox with both linked. Continue. | Code shown as theirs before leaving the screen |
| 0:40 | P2 → mail → P4 | Taps the magic link | Lands signed in; no password ever existed |
| 1:00 | A1 Board, first run | Sees the three things in order: HealthyApp row with "25% of first 12 months · 14 pieces of collateral · PROMOTE"; hero "$0.00 — first payout after your first sale" with the guidelines link beside it; three steps. Taps PROMOTE | Nothing to read first; the one action is the biggest control on the screen |
| 1:10 | A10 Studio | Filtered to HealthyApp; sees only the categories that exist; a social caption marked NEW. Taps it | A11 renders with their link already in the caption and the disclosure already present — the default per-asset link was minted when they joined, so no link-builder step stands between them and the asset |
| 1:40 | A11 | Taps Copy caption, then Download image | Both confirmations; the card now carries their own "used" mark. asset_uses and events rows written; promotional-action count for the period = 2 |
| 2:10 | A1 Board | Returns. Step 1 ticked; feed row Your link is live · 0 clicks; step 2 "Get your own link" offered for the pro who wants a labelled one | They leave with a caption on the clipboard and an image on the phone |
| 2:30 | A8 Link builder (optional) | One product, so the picker is pre-selected; destination defaults to the product home; label optional. Create → A9 → Copy | "Copied"; the link appears in A7 with its own numbers |
| ~5:00 | (optional) A11 → A15 | If the asset was a script: Record → prompter → review → Save to phone or Post | A video, from script to file, without leaving the portal (PRD §14) |
Where payout onboarding is asked for — recommendation: after first earnings, not at signup.
Trigger it when the first commission reaches pending: an email, a Board banner, and step 3 on the first-run list turns active with a date ("set up payouts by approval date"). The 30-day hold guarantees at least a month of runway before anything is payable, and the payout run already skips-and-notifies the un-onboarded (PRD §8 step 4), so nothing is lost. Stripe Express asks for date of birth, SSN/ITIN and a bank account; asking that of a coach who has not yet seen a single click is the largest avoidable drop-off in affiliate signup and buys nothing for 30+ days. Hard requirement remains: no payout leaves without completed onboarding. Escalate the banner's prominence as the approval date nears; after approval with onboarding still incomplete, the Board hero itself reads "Approved · waiting on your payout details."
B.6 The admin's week
Normal week (queue empty) — zero logins.
| When | Screen | Why | Login? |
|---|---|---|---|
| Daily | — (email) | Queue digest: "Queue empty · 14 conversions · $1,240 pending · next run Nov 1" | No |
| Ad hoc, when there is new material | D6 Collateral | Upload, set disclosure, renditions, publish; affiliates get the new-collateral email | Yes — the one voluntary login |
| 1st of the month | D5 Payout runs | Review batch total, skipped counts; Release. Stay for the completion state. | Yes — the one required login |
| After the run | D7 Reports | Monthly glance: revenue by product/level, liability, the four guardrails | Same session |
Exception week.
| Trigger (email) | Screen path | Decision |
|---|---|---|
| "2 flagged conversions" | D1 → D2 drawer | Read rules tripped and evidence → Approve (→ pending) or Void with reason. If the affiliate has a pattern (prior decisions in the drawer) → D4 detail → Suspend with reason |
| "Payout failed — 1 affiliate" | D1 → D2 → D5 run detail | Retry after affiliate fixes bank detail (rows are back in approved automatically), or Mark paid manually with reference if paid out-of-band |
| "Negative balance, not producing — 90 days" | D1 → D4 | Write off (audited) or Keep rolling |
| Applicant pending (only if gated) | D1 → D2 | Approve / Decline |
| Affiliate dispute by email | D4 detail → ledger → D2 | Answer from the ledger in under five minutes (PRD §14); if a reparent is warranted → Reparent with reason (forward-only) |
| Deletion request | D1 → D4 | Anonymise (ledger rows survive as financial records, PRD §11.7) |
Everything above returns to D1, and D1 returns to empty.
B.7 Navigation model
Affiliate bottom bar — BOARD · LINKS · STUDIO · EARNINGS, evaluated against B.2.
| Tab | Holds | Verdict |
|---|---|---|
| BOARD | A1, A20 (interstitial) | Holds |
| LINKS | A7, A8, A9, recruiting link (pinned section of A7) | Holds |
| STUDIO | A10, A11, A12, A13, A14, A15, A16, A17 | Holds. Record (A15/A16) takes the full screen and hides the bar; it is still Studio's. Connected accounts and the publish queue belong here because they only exist for Mode 2 |
| EARNINGS | A2, A3, A4, A5 (Team), A6 (Payout method) | Holds, with two placements that must be explicit: Team (downline) lives under Earnings, because its economic meaning is the L2 override and PRD §9.1 puts downline counts on the earnings dashboard; Payout method lives under Earnings, because it is a money setting and the "set up payouts" nudge points there |
| (homeless) | A18 Settings, A19 Notifications | Not a destination. Place behind the avatar/code in the header (the enamel header already shows the affiliate's code at right). |
Verdict: the four destinations hold every screen. Two risks to design against: Earnings becomes the dense tab (five segments) — acceptable, it is where the pro's density lives (principle 3), but the segmented control must be visible without scrolling; and "Studio" must read as the whole vault, not only the recorder — the Record affordance is a button on a script, not the meaning of the tab. Deep links from email land directly on A3, A4, A11 and A6 so a notification never drops someone on a tab root.
Admin primary nav — Queue · Collateral · Payouts · Affiliates · Programs · Reports, with Audit and Settings in an overflow. Ordered by frequency of real use (PRD §10: collateral gets the most actual use; payouts monthly; the rest exceptional). Compared with the Activation PRD §8.1 (Today, Programs, Partners, Campaigns & Collateral, Conversions, Payouts, Insights, Settings): Campaigns is dropped (no object), Conversions is dropped as a top-level destination because a browsable conversions list invites the daily look the product is designed to remove — conversions are reached through an affiliate, a queue item, or a report.
B.8 Open decisions
Stated as questions with recommended defaults. D.1–D.3 are PRD §15 items; the rest surfaced from this inventory. Rates (PRD §15.1) and domain registration (§15.5) are not screen decisions and are listed only where they touch a screen.
| # | Question | Recommended default | Screen impact |
|---|---|---|---|
| D.1 | Gated or open signup? | Open, auto-approved, as a per-program toggle defaulting off. The downside (junk signups, self-referral) is already handled by PRD §7.4 flags and the hold; gating adds a queue item type and a waiting screen that an internal program with HealthyApp customers as the growth lever does not need. Build the pending_approval state anyway so flipping is a setting. |
P5 exists but is off; D1 has an "applicants" type that is normally hidden; D3 has the toggle |
| D.2 | Can customers become affiliates? | Yes. It is the largest growth lever (PRD §15.3). The entry point is HealthyApp's surface, not ours: an "Earn" link inside HealthyApp deep-links to /join?product=healthyapp&customer_ref=… so the affiliate row carries customer_ref and self-referral matching is exact rather than email-fuzzy. |
P1 accepts customer_ref; A1 first-run copy acknowledges "you already use it"; no new screen |
| D.3 | Cross-product downline? | Yes (PRD §5.2 already assumes a global sponsor). A sponsor earns L2 on everything their recruit sells, under each product's own L2 rate. | A5 shows product(s) per recruit; A2 Team segment shows L2 by product; nothing to toggle |
| D.4 | Payout onboarding before or after first earnings? | After — triggered by the first pending commission, hard-required before the first payout (B.5). |
A1 banner and step 3 behaviour; A6 reachable but never a gate on A8/A10 |
| D.5 | Can the admin manually flag (hold) a pending or approved commission? | Yes. PRD §7.2 has no manual transition into flagged; add pending → flagged and approved → flagged as admin actions with a required reason, audited. Without it the only tool for a suspected-but-unflagged row is Suspend, which is too blunt. |
D4 ledger gets a "Flag" action; A3 shows "under review" |
| D.6 | Which networks does Mode 2 publish to at launch? | Instagram (business/creator accounts via Graph API), Facebook Pages, LinkedIn. TikTok and X via Mode 1 download at launch; their APIs' approval timelines and posting constraints should not gate the vault. | A13 list; A12 preview variants; D6 rendition set |
| D.7 | Bonuses in v1? | No — but shape for the one PRODUCT.md names. The future bonus rewards promotional actions per period (posting, recording, sharing) — never recruiting, never volume. Count from day one: asset_uses(mode) plus publish_jobs and recordings give actions per affiliate per period with no backfill. When switched on, it is paid through a separate bonus_awards ledger that joins payout_items, not as a commissions row, so PRD §11.2 (commission requires a conversion) stays a schema constraint. A sales-volume bonus, if ever wanted, attaches to the conversion that crossed the threshold. |
None in v1; later a "this period: N actions" line on A1/A2 and a bonus row type in A3/A4 |
| D.8 | Short-link domain go.tellatribe.com? |
Register and use it. If not available at launch, A8/A9 hide the short-link row rather than show a placeholder. | A8, A9, A11 token {{short_link}} falls back to {{ref_link}} |
| D.9 | Is the vault allowed to launch empty? | No. Seed at least one asset in each of: social caption (with image renditions), email swipe, one script, and the guidelines page for HealthyApp before Phase 6 ships; show only populated categories. PRD §15.6 asks what exists today — that inventory is a prerequisite for the Studio design review. | A10 empty state should be a build-time failure, not a design |
| D.10 | Does the platform store Mode 3 recordings? | Yes, briefly: keep the upload for 7 days to serve the publish queue, then delete unless it was posted (then keep the posted reference, not the file). Say so on A16. | A16 copy; A14 item lifetime |
| D.11 | What does the affiliate see about clicks on the Board? | Milestones only (first click, every 100th) plus the running total on A2/A7. Every click as a feed row is noise that buries money rows. | A1 feed rules |
| D.12 | Admin MFA mandatory? | Yes, enrol on first login. One human, real money, magic-link-only is one phished inbox away from a payout run. | D0 |
| D.13 | Terms re-acceptance blocks what? | New links and new takes, not viewing. A20 appears on entry; declining leaves a read-only board. Existing links keep working — a dead link is worse than an unaccepted clause (PRD §6.1 reasoning). | A20, A7, A10 disabled affordances |
Rendered from build-plan/03-reconciliation-and-surfaces.md. Edit the source, not this page.