tellatribe

Enter the access code to read the project documents.

tellatribe Docs 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

Overview · read from BUILD-PLAN.md

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

  1. Oct 3

    Wave 0: repo, pnpm monorepo, engine contract, 0001_tenancy, PGlite harness. 7 tests. Vercel project affiliate-coach (sales-boss) created and linked.

  2. Oct 4

    Wave 1 merged on phase-1 (M1, M2, M3, E). Stubs removed; the real chain 0001→0007 runs on one tree. Gate 1a green (123 schema tests). Gate 1b green (78 engine tests, 100% branch coverage, golden replay checked in).

  3. Oct 4

    Supabase project affiliate-coach created under the sales boss org (us-west-1) with Jonathan's approval; all seven migrations applied with supabase db push — the chain holds on real Postgres, not only PGlite.

  4. Oct 4

    Wave 2 started: L (ledger service) and I (gate-1c suite) in parallel worktrees against packages/ledger's Sql port and createLedgerService factory.

  5. 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 through 0008.

  6. Oct 4

    phase-1 fast-forwarded into main with Jonathan's OK. phase-2 cut. Wave 3 started, four agents in parallel: A1 apps/api (key auth, /v1/clicks, /v1/conversions, cron routes, Postgres Sql adapter) · 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.

  7. Oct 4

    Wave 3 merged. Gate 2 green: SDK redirect → /v1/clicks → first-party cookies → Stripe Checkout metadata → signed invoice.paid through the mounted platform webhook → L1 + L2 rows → partial charge.refunded → proportional reversals, on one tree (apps/api/test/gate2.e2e.test.ts). Phase 2 complete: 519 tests (124 core incl. collateral resolver, 149 schema 0001–0009, 96 ledger, 66 SDK, 43 webhooks, 41 API). 0009_collateral live on Supabase. phase-2 → main; phase-3 cut. Integration decisions: RecordConversionInput.mode added (test keys record test rows); API bodies follow the SDK contract (camelCase, outcome); SDK honours the program's cookieWindowDays; HealthyApp mounts the redirect at /go/[code] because app/r/[token] is taken.

  8. 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).

  9. Oct 4

    apps/api deployed to production: https://api.tellatribe.com (prebuilt from the workspace root; recipe in AGENTS.md). DATABASE_URL verified against the live pooler (the ledger's Postgres adapter test ran green against Supabase); CRON_SECRET, CLICK_SALT set; crons registered. Smoke: unauthenticated click 401, cron 401, unconfigured product slug 404.

  10. 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 through set_plan_level(). A live track+convert API key was minted once and lives only in the keychain. Live smoke with that key returns unknown_code 404 — the production stack answers end to end. Agent H started: the documentation hub (apps/docs, code 3003).

  11. 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 with payout:{id} idempotency; 4xx returns rows via fail_payout(); insufficient funds halts and fails the rest with run_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, cron payout-run on the 1st at 14:00 UTC. Awaiting from Jonathan: the dedicated tellatribe Stripe account (decision 9) → STRIPE_SECRET_KEY, STRIPE_CONNECT_WEBHOOK_SECRET, and workspaces.payout_stripe_account_id; until then /api/stripe/connect answers 500 (no key) and startOnboarding refuses. 588 tests.

  12. 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 from design.json; 0010_affiliate_preferences) · B publishing (0011_publishing: social_connections, publish_jobs, enqueue_publish_job with the X open-balance gate, Ayrshare client + six adapters, preview, worker with backoff; cron publish-worker every 5 min) · D admin (MFA-gated; Queue with exception drawer and reasoned actions; Programs with set_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–0012 applied 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.

  13. Oct 4

    Admin and portal deployed: https://admin.tellatribe.com (MFA-gated sign-in) and https://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.sh does the per-app prebuilt deploy. Supabase Auth still needs the magic-link template pointed at /auth/confirm with {{ .TokenHash }} and the two app origins in the redirect allow-list before anyone can sign in.

  14. 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_links applied live. Full suite + typecheck green on phase-3. Portal redeployed: /wall /links /studio /earnings answer 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 in DECISIONS-FOR-REVIEW.md.

  15. Oct 4

    Phase 7 prepared — K: HealthyApp integration on branch affiliate-coach-integration in vera-wellness (commit 69b1ec8, not merged, not pushed): SDK vendored to lib/affiliate-coach/, app/go/[code] redirect with .healthyapp.coach cookie domain, /go/ exempted from the auth middleware, stripeCheckoutFormFields spread into startPlatformSubscription only; 13 tests, repo suite 482/482. Go-live checklist in that branch's INTEGRATION.md. Portal: signed-in Join-to-promote flow (/wall/join/[program]) added and deployed; live portal verified signed in as the test affiliate TESTAFF (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.

  16. 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/renditions every 2 min live and answering (401 unauth, 200 → {attempted:0,…}). Getting it live took four deploys: sharp must be a direct dep of apps/api (else bundled), Vercel runs the API on linux-arm64 so pnpm-workspace.yaml now 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. Bucket collateral (private, 500 MiB, 16 mimes) created via the Storage API — supabase config push did not create it. API env gained SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY. Shell: Links tab count now from my_links.

  17. Oct 4

    Checkpoint: main fast-forwarded to phase-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 from scriptTiming with 0.8–1.4× speed, 60 s soft / 3 min hard marks, MediaRecorder mp4→webm preference, review with save-to-phone via share sheet, record again, Done → record_completed event + used_at); burn-in opt-in via affiliates.preferences.burn_in_disclosure with canvas compositing when supported; 32 tests. Studio "Takes" copy updated. Remaining agents: D2 (admin half 2) and C (Connect → publish wiring).

  18. 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. Awaiting AYRSHARE_API_KEY for live posting.

  19. 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.

  20. 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.

  21. 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).

  22. Oct 19

    Stripe setup guide for the account administrator (two accounts, hand-off via 1Password). Tax identity shipped (0015_tax_identity): affiliates.tax_status mirrored from account.updated, payout run and admin preview skip tax_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).

  23. 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.

  24. Oct 19

    Creator Campaigns Part B shipped (0017_campaigns, 0018_funding_endpoint, 0019_campaigns_vocabulary; build contract build-plan/04). Four parallel streams merged: packages/campaigns engine (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_vocabulary admits affiliate_suspended in commissions.flag_reason and fraud_flags.kind; the engine's reason is stored verbatim, never mapped to manual.
  • A reused idempotency key returns duplicate regardless of body; a body mismatch is written onto the api_requests memo (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/pending affiliates 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) carry approved_at at 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. 1

    Commission basis

    Net of tax and discounts — amount_paid − tax, after discounts

    Default

  2. 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_id per level on customer_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. 3

    Partial refunds

    Proportional reversal, floored to the cent, per level; disputes always reverse in full

    Default

  4. 4

    Payout minimum scope

    One per affiliate across all products ($50, on the workspace)

    Default

  5. 5

    Cross-product downline

    Yes — a sponsor earns each product's own L2 rate on everything their recruit sells

    Default

  6. 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. 7

    Customers as affiliates

    Yes — an "Earn" link inside HealthyApp deep-links to join with customer_ref, so self-referral matching is exact

    Default

  8. 8

    Signup

    Open, auto-approved, as a per-program toggle

    Default

  9. 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_ref already keeps this shape open (track 01 §0.5)

  10. 10

    Mode 2 aggregator

    Ayrshare Business from day one; register own Meta/TikTok apps in parallel as the migration path

    Default

  11. 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 fee ledger row kind (negative, references the publish_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. 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. 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. 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. 15

    Raw click retention

    13 months, then the monthly partition is dropped

    Default

Decisions already made (§2)

AreaDecisionWhere
ShapeInternal 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
TiersTwo 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
Tenancyworkspaces 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
LedgerAppend-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 topologyTwo 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 railStripe 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
CollateralThree delivery modes: download → publish-for-me → record-with-teleprompter. Mode 1 ships first and must be excellent alone.PRD §9.3; 02 §0
Mode 2Through 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 3Pure 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 directionThe 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 navigationFour 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
SignupOpen 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 onboardingAsked after the first commission reaches pending, never at signup; hard-required before the first payout.03 §B.5, D.4
BonusesNone 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.