Build status
All modules built and live · Oct 19: Creator Campaigns Part B shipped (briefs, applications, deals, verification → bounties, brand balance + Stripe funding, disputes, reports) on top of the tax-identity gate and annual statements · awaiting owner inputs: tellatribe Stripe account (payments + Connect + funding webhook), HealthyApp webhook secret, Ayrshare key. The log below is the build plan's own status table, newest last; the decisions are the fifteen settled with the owner on October 3, 2026, and the ones that surfaced during integration.
Status log
- Oct 3
Wave 0: repo, pnpm monorepo, engine contract,
0001_tenancy, PGlite harness. 7 tests. Vercel projectaffiliate-coach(sales-boss) created and linked. - Oct 4
Wave 1 merged on
phase-1(M1, M2, M3, E). Stubs removed; the real chain0001→0007runs on one tree. Gate 1a green (123 schema tests). Gate 1b green (78 engine tests, 100% branch coverage, golden replay checked in). - Oct 4
Supabase project
affiliate-coachcreated under the sales boss org (us-west-1) with Jonathan's approval; all seven migrations applied withsupabase db push— the chain holds on real Postgres, not only PGlite. - Oct 4
Wave 2 started: L (ledger service) and I (gate-1c suite) in parallel worktrees against
packages/ledger'sSqlport andcreateLedgerServicefactory. - Oct 4
Wave 2 merged. Gate 1c green: 14 scenario groups (first sale L1+L2 with the terms lock; recurring to 12 then 13; refund before and after payout, proportional; dispute; suspended sponsor and suspended L1; self-referral at both tiers; duplicate customer; rate change under the lock; idempotency incl. cross-month; serialized concurrency; hold sweep; fees; the 200-conversion golden replay through the real tables). Phase 1 complete: 299 tests — 78 engine (100% branch coverage), 125 schema across
0001–0008, 96 ledger. Live Supabase project matches the tree through0008. - Oct 4
phase-1fast-forwarded intomainwith Jonathan's OK.phase-2cut. Wave 3 started, four agents in parallel: A1apps/api(key auth,/v1/clicks,/v1/conversions, cron routes, PostgresSqladapter) · A2@affiliate-coach/sdk(/r/[code]handler, cookies,getClickId,stripeCheckoutFields,convert) · A3@affiliate-coach/stripe-webhooks(platform-event handler with the four topology guards, event ledger, dead letters) · A4 Phase 6 Mode 1:0009_collateral+ the token resolver in core. - Oct 4
Wave 3 merged. Gate 2 green: SDK redirect →
/v1/clicks→ first-party cookies → Stripe Checkout metadata → signedinvoice.paidthrough the mounted platform webhook → L1 + L2 rows → partialcharge.refunded→ proportional reversals, on one tree (apps/api/test/gate2.e2e.test.ts). Phase 2 complete: 519 tests (124 core incl. collateral resolver, 149 schema0001–0009, 96 ledger, 66 SDK, 43 webhooks, 41 API).0009_collaterallive on Supabase.phase-2→main;phase-3cut. Integration decisions:RecordConversionInput.modeadded (test keys record test rows); API bodies follow the SDK contract (camelCase,outcome); SDK honours the program'scookieWindowDays; HealthyApp mounts the redirect at/go/[code]becauseapp/r/[token]is taken. - Oct 4
Wave 4a started on
phase-3: S portal shell (apps/portal: Supabase magic-link auth, Tailwind theme from.impeccable/design.json, tab shell) · D admin app (apps/admin: Queue, Programs with integration panel, Affiliates) · Y payouts (packages/payouts: Express onboarding, two-phase run, statements; API mounts) · B publishing (0010_publishing, Ayrshare adapter, publish worker, composer contract). - Oct 4
apps/apideployed to production: https://api.tellatribe.com (prebuilt from the workspace root; recipe inAGENTS.md).DATABASE_URLverified against the live pooler (the ledger's Postgres adapter test ran green against Supabase);CRON_SECRET,CLICK_SALTset; crons registered. Smoke: unauthenticated click 401, cron 401, unconfigured product slug 404. - Oct 4
HealthyApp seeded in the live database by
scripts/seed-product.mts: product (redirect_origin https://healthyapp.coach), evergreen program with terms v1, rates 25% recurring 12 months (L1) / 5% lifetime (L2) — the PRD's suggested plan, applied as a decision so Phase 7 can start; change throughset_plan_level(). A livetrack+convertAPI key was minted once and lives only in the keychain. Live smoke with that key returnsunknown_code404 — the production stack answers end to end. Agent H started: the documentation hub (apps/docs, code 3003). - Oct 4
Wave 4a Y merged:
packages/payouts— Express onboarding ("ask Stripe, don't trust the return"), two-phase payout run (assemble marks paid → check funding → release withpayout:{id}idempotency; 4xx returns rows viafail_payout(); insufficient funds halts and fails the rest withrun_halted), reconciler, statements, tax-year summary, Connect webhook with its own event-ledger rows. Gate 5 green (35 tests). Mounted and redeployed:/api/stripe/connect, cronpayout-runon the 1st at 14:00 UTC. Awaiting from Jonathan: the dedicated tellatribe Stripe account (decision 9) →STRIPE_SECRET_KEY,STRIPE_CONNECT_WEBHOOK_SECRET, andworkspaces.payout_stripe_account_id; until then/api/stripe/connectanswers 500 (no key) andstartOnboardingrefuses. 588 tests. - Oct 4
Wave 4a landed on
phase-3: S portal shell (Supabase magic-link auth, join with live code check, terms interstitial, Settings sheet, theme fromdesign.json;0010_affiliate_preferences) · B publishing (0011_publishing:social_connections,publish_jobs,enqueue_publish_jobwith the X open-balance gate, Ayrshare client + six adapters, preview, worker with backoff; cronpublish-workerevery 5 min) · D admin (MFA-gated; Queue with exception drawer and reasoned actions; Programs withset_plan_level(), terms, integration panel with reveal-once keys and a test conversion; Affiliates with reparent/suspend/write-off/view-as;0012_admin_flags) · H documentation hub, live at https://docs.tellatribe.com (code 3003). Migrations renumbered at merge (publishing 0010→0011, admin flags 0011→0012) because Supabase keys migrations by version;0010–0012applied live. Wave 4b running: P1 Wall + Studio, P2 Links + Earnings (+0013_links). Full suite 693 tests when run unloaded; two ledger scenarios timed out once under a load average of 29 and pass in isolation. - Oct 4
Admin and portal deployed:
https://admin.tellatribe.com(MFA-gated sign-in) andhttps://tellatribe.com(shell; Wall/Links/Studio/Earnings screens landing from wave 4b). Env set on both (Supabase URL + anon key as public config, service role,DATABASE_URL, API URL).scripts/deploy-app.shdoes the per-app prebuilt deploy. Supabase Auth still needs the magic-link template pointed at/auth/confirmwith{{ .TokenHash }}and the two app origins in the redirect allow-list before anyone can sign in. - Oct 4
Wave 4b landed and the portal is live with all four tabs: P1 Wall (billboard with first-run / under-minimum / needs-payout / negative states, 4:5 tiles, caption rendering per platform with
/go/links, Join-to-promote) + Studio (asset sheet, composer with server-side disclosure check, "Record it" script sheet as Mode 3 v1, posters, signed-rendition redirect) · P2 Links (list, builder, detail;0013_links) + Earnings (ledger, next payout, commission sheet, payouts list/detail, CSV statement, payout method with Stripe onboarding action).0013_linksapplied live. Full suite + typecheck green onphase-3. Portal redeployed:/wall /links /studio /earningsanswer 200 behind sign-in. Wave 5 running: D2 admin second half (Collateral authoring, Payout runs, Reports, Audit, Settings) · R@affiliate-coach/media(renditions matrix, sharp/ffmpeg, Storage bucket, cron) · K HealthyApp integration branch in vera-wellness. Interpretations logged inDECISIONS-FOR-REVIEW.md. - Oct 4
Phase 7 prepared — K: HealthyApp integration on branch
affiliate-coach-integrationin vera-wellness (commit69b1ec8, not merged, not pushed): SDK vendored tolib/affiliate-coach/,app/go/[code]redirect with.healthyapp.coachcookie domain,/go/exempted from the auth middleware,stripeCheckoutFormFieldsspread intostartPlatformSubscriptiononly; 13 tests, repo suite 482/482. Go-live checklist in that branch'sINTEGRATION.md. Portal: signed-in Join-to-promote flow (/wall/join/[program]) added and deployed; live portal verified signed in as the test affiliateTESTAFF(four tabs render; screenshots in the docs hub). Docs hub status line and Decisions-for-review page live. Agents T (teleprompter, 6c) and C (Connect → publish wiring, 6b) started. - Oct 4
Phase 6 Mode 1 media landed — R:
packages/media(17-cell rendition matrix, sharp images / ffmpeg video / PDF cover card, Storage port, claim-with-skip-locked worker; 39 tests), cron/api/cron/renditionsevery 2 min live and answering (401 unauth, 200 →{attempted:0,…}). Getting it live took four deploys: sharp must be a direct dep ofapps/api(else bundled), Vercel runs the API on linux-arm64 sopnpm-workspace.yamlnow installs that platform's sharp/ffmpeg beside the Mac's,ffmpeg-static→@ffmpeg-installer/ffmpeg, and the media package resolves ffmpeg lazily with a pnpm-store scan because the installer's symlink cannot be traced. Bucketcollateral(private, 500 MiB, 16 mimes) created via the Storage API —supabase config pushdid not create it. API env gainedSUPABASE_URL,SUPABASE_SERVICE_ROLE_KEY. Shell: Links tab count now frommy_links. - Oct 4
Checkpoint:
mainfast-forwarded tophase-3(809 tests, typecheck clean). Phase 6c teleprompter landed — T and deployed:/studio/record/[asset](camera gate with in-app-browser detection, 3-2-1 countdown, pace fromscriptTimingwith 0.8–1.4× speed, 60 s soft / 3 min hard marks,MediaRecordermp4→webm preference, review with save-to-phone via share sheet, record again, Done →record_completedevent +used_at); burn-in opt-in viaaffiliates.preferences.burn_in_disclosurewith canvas compositing when supported; 32 tests. Studio "Takes" copy updated. Remaining agents: D2 (admin half 2) and C (Connect → publish wiring). - Oct 4
Admin complete — D2 (Collateral authoring with token palette, sample-affiliate preview, 150 wpm read time, publish gate incl. claims attestation; Payout runs as Assemble → Check funding → Release with history, run detail, statement CSV; Reports with the four guardrails and row drills + CSV export; Audit with before/after diff; Settings with why/consequence lines; 73 tests). The renditions seam now imports the media package's SQL-only half (
@affiliate-coach/media/enqueue, new subpath) so the admin never carries sharp/ffmpeg. Phase 6b wired — C: Connect accounts → Ayrshare link session →/studio/connect/return(HMAC state) →syncConnections; Disconnect/Reconnect (0014_social_reconnect, applied live); Composer preflight + preview parity with the worker; X offered only when the gate passes; honest no-key state. Every module in the build plan is now built. AwaitingAYRSHARE_API_KEYfor live posting. - Oct 5
Found while demoing: a conversion in the same second as its click went unattributed (Stripe reports whole seconds) →
CLOCK_SKEW_TOLERANCE_MS(60 s) in the window check; focused caption tiles overlapped their title → two-line clamp. Decisions 53–54. - Oct 9–13
Paid social:
ads/engine (statics 4:5 / 1:1 / 9:16, two motion MP4s, two carousels) and 14 UGC-style videos (Higgsfield → whisper word timestamps → PNG caption overlays, since the homebrew ffmpeg has no libass); $1,410 demo earnings on the TESTAFF portal screens; docs hub gains the screens gallery and the paid-social page. Executive deck (20 slides, PPTX) with the market-data and Campaigns slides. - Oct 14
Creator Campaigns strategy + PRD (
PRD-Creator-Campaigns.md, Part A/B, competitive landscape appendix incl. 2025–26 upstarts); Jonathan's six Campaign decisions (55–60). - Oct 19
Stripe setup guide for the account administrator (two accounts, hand-off via 1Password). Tax identity shipped (
0015_tax_identity):affiliates.tax_statusmirrored fromaccount.updated, payout run and admin preview skiptax_identity_missing, Reports → Paid by recipient · tax year (CSV, drill), portal annual statements per calendar year, payout-method tax line. Decisions 61–66. PayPal Payouts evaluated and parked (guide Part 7). - Oct 19
Rebrand: affiliate.coach → tellatribe (
0016_rebrand_tellatribe, display values only; package scope unchanged). Domains live: tellatribe.com · admin.tellatribe.com · api.tellatribe.com · docs.tellatribe.com. Ads/screens carry the tellatribe wordmark. - Oct 19
Creator Campaigns Part B shipped (
0017_campaigns,0018_funding_endpoint,0019_campaigns_vocabulary; build contractbuild-plan/04). Four parallel streams merged:packages/campaignsengine (eligibility, quality score, SOW, escrow, review, verification →bounty, disputes, funding ledger; 37 tests), admin Campaigns section + balance strip + Add funds (Stripe Checkout) + four queue kinds + gift value on the 1099 report, portal Open calls / sheets / Studio → Deals / bounty rows, API/api/stripe/funding+/api/cron/campaigns. Decisions 67–106. Totals: schema 221 · engine 37 · admin 87 · portal 166 · API 53 · payouts 40 · ledger 99. Migrations 0015–0019 live; all three apps + docs deployed. Open: campaign screens not yet exercised with live rows; Stripe account (payments + Connect + funding webhook) and Ayrshare key still awaited.
Decisions that surfaced during integration
0008_flag_vocabularyadmitsaffiliate_suspendedincommissions.flag_reasonandfraud_flags.kind; the engine's reason is stored verbatim, never mapped tomanual.- A reused idempotency key returns
duplicateregardless of body; a body mismatch is written onto theapi_requestsmemo (body_mismatch_seen) for the admin and never acted on. The API layer should surface it as a warning, not a 409. - A refund larger than the conversion raises
refund_exceeds_conversion; the webhook route should dead-letter that event rather than retry it. - A suspended converting affiliate is paid into
flagged(held visibly);closed/pendingaffiliates are unattributed and never lock a customer. approveMatured(workspaceId, now)is scoped per call so one cron sweeps every workspace.- Rows born
approved(reversal, fee, adjustment) carryapproved_atat insert; the trigger only stamps it on a transition. - Phase 1 ran on PGlite; the migrations were also applied to the live project, so the chain is proven on real Postgres. True concurrent-request tests (two connections racing on one customer lock) belong to Phase 2's API tests against Supabase.
Decisions (§5)
- 1
Commission basis
Net of tax and discounts —
amount_paid − tax, after discountsDefault
- 2
Plan terms over a subscription's life
Locked at first conversion. A referred customer keeps paying under the rates in force when they converted, for the life of that customer
Departure from the default. Snapshot
plan_level_idper level oncustomer_attribution(track 01 §8 Q2 names the two nullable columns); the ledger's commission-detail copy must show the locked rate and its date - 3
Partial refunds
Proportional reversal, floored to the cent, per level; disputes always reverse in full
Default
- 4
Payout minimum scope
One per affiliate across all products ($50, on the workspace)
Default
- 5
Cross-product downline
Yes — a sponsor earns each product's own L2 rate on everything their recruit sells
Default
- 6
Caption editing in the Post-for-me composer
Affiliates may edit anything, including the disclosure. No locked span. The composer warns once when the disclosure is missing and logs the removal, then posts
Departure. Liability for an undisclosed endorsement published through the platform sits with the merchant; the claims-guidelines page and the one-time warning are the mitigations
- 7
Customers as affiliates
Yes — an "Earn" link inside HealthyApp deep-links to join with
customer_ref, so self-referral matching is exactDefault
- 8
Signup
Open, auto-approved, as a per-program toggle
Default
- 9
Payout Stripe account
A new tellatribe Stripe account, not HealthyApp's revenue account
Departure. Phase 5 gains a monthly funding transfer from each product's revenue account and a reconciliation step;
workspaces.payout_account_refalready keeps this shape open (track 01 §0.5) - 10
Mode 2 aggregator
Ayrshare Business from day one; register own Meta/TikTok apps in parallel as the migration path
Default
- 11
X posting
Enabled, gated and self-funded. Post-for-me to X is available only to affiliates with an open balance owed to them (pending + approved > $0), and the per-post link fee (~$0.20) is deducted from that affiliate's payout
Departure. Adds a
feeledger row kind (negative, references thepublish_job), netted in the payout run alongside reversals; the composer states the cost before posting ("This post costs $0.20, taken from your next payout"); an affiliate with no open balance sees X greyed with the reason. Fee amount is config, not a constant - 12
Disclosure burn-in on recordings
Off by default; the affiliate can turn it on per take
Departure. The spoken disclosure line stays mandatory in every script and the caption disclosure stays attached; the review screen carries a "Burn in disclosure" toggle, remembered per affiliate. Weaker FTC posture for video than the default; the claims-guidelines page says so plainly
- 13
Review queue before publish
None in v1. Posts go out when the affiliate taps Post; controls are the fraud flags, the guidelines page, and the caption-edit log. Built as a v1.5 per-program option
Default
- 14
Chargeback velocity (2+ in 30 days)
Flag and queue, never auto-suspend. Open rows move to Held, an exceptions item opens with the evidence, the admin decides
Default
- 15
Raw click retention
13 months, then the monthly partition is dropped
Default
Decisions already made (§2)
| Area | Decision | Where |
|---|---|---|
| Shape | Internal first, commercial-shaped. One merchant in v1; the schema, auth boundary, and tokens are built so the SaaS pivot is a feature project, not a rewrite. | PRODUCT.md; 03 §A.2 |
| Tiers | Two levels, permanently. MAX_DEPTH = 2 in the engine with the legal reason in a comment; CHECK (level IN (1,2)) on plan_levels. No third level, no ranks, no volume qualifications. | PRD §2.1, §5.2, §11 |
| Tenancy | workspaces table with one seeded row; workspace_id NOT NULL on every top-level table from migration one, with composite FKs so the column is a boundary, not a label. | 01 §0.1; 03 §A.2 #1 |
| Ledger | Append-only: money columns frozen by trigger; state advances along the PRD §7.2 edges only; every transition logged. A commission row cannot exist without a positive conversion. | 01 §0.2–0.3, §1.5 |
| Stripe topology | Two webhook endpoints: platform revenue events and connected-account events never share a route. The click id travels in metadata.ac_click_id, with client_reference_id only as a guarded fallback, because HealthyApp's Connect checkout already uses client_reference_id for something else. | 01 §0.4, §4.2–4.3 |
| Payout rail | Stripe Connect Express as primary; PayPal Payouts for countries Stripe can't serve; CSV as the escape hatch. One payout account per workspace — a new tellatribe Stripe account, funded monthly from each product's revenue account (decision 9). | PRD §8; 01 §0.5, §5 |
| Collateral | Three delivery modes: download → publish-for-me → record-with-teleprompter. Mode 1 ships first and must be excellent alone. | PRD §9.3; 02 §0 |
| Mode 2 | Through an aggregator (Ayrshare Business) in v1 so platform approvals are off the critical path; register our own Meta and TikTok apps in parallel as the migration path. Networks at launch: LinkedIn, Instagram, Facebook Page, TikTok. X built but off by default. | 02 §3.2, §6 |
| Mode 3 | Pure web (no Capacitor) with server-side remux of every recording and an in-app-browser fallback card. Ships as v1.5, two to four weeks after v1. | 02 §4.2, §6 |
| Portal direction | The Title Wall: each product a row, each piece of collateral a tile; the focused tile grows and says what it pays and how long it takes; standing lives in the billboard on top. Deep neutral ground, one accent spent only on the focused tile, the primary action, and money. | .impeccable/surfaces/design-portal.md |
| Portal navigation | Four tabs hold every screen: Wall · Links · Studio · Earnings. Team and Payout method live under Earnings; Settings and Notifications behind the code chip in the header. Studio means the affiliate's work in progress (taken, scheduled, takes, connected accounts, rules), not only the recorder. | 03 §B.7; prototype |
| Signup | Open and auto-approved by default, as a per-program toggle; the pending_approval state exists so gating is a setting. | 03 §B.8 D.1 |
| Payout onboarding | Asked after the first commission reaches pending, never at signup; hard-required before the first payout. | 03 §B.5, D.4 |
| Bonuses | None in v1. Promotional actions are counted from day one (asset_uses, publish_jobs, recordings); any future bonus pays through a separate bonus_awards ledger, never as a commissions row. | PRODUCT.md; 03 D.7 |
Generated at build time from BUILD-PLAN.md. To change anything here, change the build plan.