Skip to content

Implementation status

Honest, per-item state. Done means built, used end to end in the browser or covered by tests. Partial means it works but a named part is missing. Not started items are not visible in the product.

Last updated: 2026-10-19 (Phases A to J complete, including the nonce-based CSP and the React Compiler lint clean-up; all twelve acceptance scenarios pass (docs/acceptance/REPORT.md); the Docker image and the backup scripts are written but were not run on this development machine, which has no Docker; Stripe and the real email providers are written against their APIs but not yet run against real accounts (the Anthropic API ran on 2026-10-19); platform invoices are collected by hand).

Verified this session

  • Test server on Railway (2026-10-19, docs/acceptance/TEST_SERVER.md): the Dockerfile built and ran, 17 migrations on an empty PostgreSQL 18, rampline.patricdaccache.com and a customer domain with valid certificates, installation check 0 to fix, smoke test over public HTTPS, customer domain verified by TXT, backup and restore of database and files with the app running on the restored database.
  • Security follow-up (2026-10-19): the CSP now allows scripts only with a nonce per request; in the dev server and the production build every script tag carried it, the 404 page included (it now renders per request). npm run perf against the production build: no console errors and no CSP violations. The 28 React Compiler readiness findings are fixed and the four rules are errors again: lint 0 errors, 0 warnings. In the editor on the production build an evergreen countdown counted down each second and kept its stored deadline when switched to a fixed date and back. npx tsc --noEmit, npm test (21 files, 170 tests) and the production build pass; npm run acceptance against the dev server: 12 of 12 passed.
  • Phase J acceptance: npm run acceptance drove headless Chrome through the twelve scenarios of the brief against the dev server: sign-up, template, headline edited on the canvas and published, domain added with its TXT record; a visitor's form submission created one contact in the right workspace and the worker ran its workflow; a sales member moved the deal to Won on the board and the revenue report counted it; a test-card purchase granted course access and queued a receipt; an agency created two clients through the console and their data stayed apart; an operator set product name, app domain, email sender, plans and a customer, and its domain's sign-in page showed its brand; a fresh database installed as the independent edition with a signed license passed the smoke test; the revenue report showed measured, attributed and estimated figures and contribution margin; an A/B test kept every visitor on one version and named no winner on little data; a failing webhook was retried and then shown as failed with Retry; the workspace export contained only its own rows and no secrets; the release package installed from scratch with npm ci and passed the clean-installation test. 12 of 12 passed; scenarios 1 to 11 also passed against the production build.
  • Found and fixed by these runs: the storage driver (src/lib/storage) had never been committed because .gitignore ignored every folder named storage; the home page was frozen at build time so / redirected to sign-in in production; favicon requests answered 404.
  • Production build in Chrome: 16 pages without console errors or CSP violations; load figures in docs/acceptance/PERFORMANCE.md.
  • Account security walked through in the browser: two-factor setup with QR code, sign-in with password then a recovery code, wrong code refused, two-factor turned off with the password; password reset link from the log, new password, signed in; other sessions signed out.
  • npm test: 21 files, 170 tests; npm audit --omit=dev: 0 vulnerabilities; lint: 0 errors (28 React Compiler warnings at the time; fixed 2026-10-19).
  • Phase I: the demo seed builds "Northwind Yoga (demo)" through the real services (form submissions, test checkout with the published test card, access grants, commissions, an A/B test with a published version B, deals, a workflow, spend) and spreads it over 30 days; --local adds sign-in accounts, a demo agency with three clients and an example license. In the browser: /demo opened the workspace without a password; all 25 navigation pages loaded for the demo account without errors; creating a funnel as the demo account was refused (first with a crash page, fixed: write buttons are hidden for the demo account, refused actions show a demo message, the editor works as an unsaved sandbox); signing out worked.
  • npm run screenshots took 21 views (workspace, editor, CRM, automations, revenue, lab, rescue, course, affiliates, public page and checkout, agency console, branding, licensing, installation, setup wizard preview, phone view) into public/screenshots; reviewed by eye, template placeholders on the demo pages were found and replaced with example copy.
  • Sales website: all 30 routes answered 200 (an unknown feature page and an unknown document answered 404), no horizontal scroll at 390 px on the checked pages, the contact form stored an enquiry, notified the platform administrator and showed under Platform → Enquiries. Claims checked against the code while writing (for example: there is no API with keys, so the integrations page says so; the AI architect asks nine questions).
  • npm run build (production, separate output folder): compiles; every website route renders at request time so SALES_SITE is read at runtime.
  • npm test: 18 files, 150 tests, all passing, including 5 for Phase I (demo account cannot write through row-level security even as admin, enquiries, documentation escaping and allow-list).
  • Phase H walk-through in the browser: a course built in the editor (module, two lessons, YouTube video, markdown text, free preview, published), a product set to unlock it, a test purchase through the public checkout; the worker made the buyer a member, gave access and recorded the sign-in email; the receipt's "Open my member area" signed the buyer in; the portal showed "Start here", the lesson with video embed (the in-app browser loads no external frames, the embed address was checked), "Mark as done and continue" and "You finished the course"; the phone layout has no horizontal scroll. A community created by the team, published for all members; the member posted with markdown, commented and liked. The affiliate program opened with terms; the member joined from the portal, got the link ?ref=ines; a visit through that link and a second test purchase were counted: 1 visit, 1 sale, a commission of 20% of the order before tax waiting for the 30-day hold, the same in the team view. A template saved from a funnel and a course, published, approved by a platform administrator, listed in the marketplace and installed again from there.
  • Found while testing and fixed: a Rampline dev server started in the morning (Phase A code, port 3351) was still running with its worker and took jobs from the same database. It explains the dead "No handler" order jobs since Phase C; the process tree was ended and the four lost jobs were put back in the queue and done.
  • npm test: 17 files, 145 tests, all passing, including 34 for Phase H.
  • Phase G: a clean installation into an empty database (migrations, first-run setup, setup refused a second time, schema, service role and storage checks, smoke test with published funnel, form, test checkout, cleanup) passes as npm run install:check -- --fresh and as a test. The smoke test also passed against the running dev server over HTTP, including the worker. The setup wizard was walked through in the browser on a second instance with an empty database: link from the log, step validation, a wrong license shown at the field with all entries kept, sign-in and the installation page afterwards. The demo workspace was exported from the dev installation and imported into that second installation: 366 rows, its live pages answered 200 and its uploaded image was served from the new storage; the operator downloaded the same export from the customer page, a foreign id got 403.
  • npm run build with no database reachable: compiles (the Docker build stage has no database).
  • npm test: 13 files, 111 tests, all passing, including 4 for Phase G.
  • Phase F walk-through: workspace branding saved and the tab title followed the new product name; plan and usage page for a workspace; example plans created as operator; a customer put on Growth with a 14-day trial; customer list with plan; platform owner view with margins (estimates); a self-hosted license signed and issued in the browser; signed revocation list served at /api/license/revocations.
  • npm test: 12 files, 107 tests, all passing, including 15 for Phase F (CSS filter, branding inheritance, plan limits at creation, invoice with usage lines, overdue and paid, agency client creation within the plan, owner invitation accepted with a new account, staff assignment, time-boxed support access with audit entry, funnel rollout, workspace duplication without contacts, owner-only approvals, suspension, operator customer without operator membership, invitation bound to the invited address, license signing, tampering, grace, domain, version, revocation, independent edition refusing new workspaces).
  • Bugs found by these tests and fixed: storage usage read a table that does not exist (media instead of media_assets), and an approval request was silently discarded because a failed notification insert aborted its transaction.
  • Phase E walk-through: revenue report with test orders, Lead Rescue flagged a form lead without owner and reply and drafted a follow-up, Conversion Lab created an A/B test (version B opens in the editor), personalization rule editor with block picker, health checks found a downsell without price and three historic dead jobs, AI architect shows that no API key is set.
  • Phase D walk-through (log email provider, nothing delivered): CSV import with semicolons, automatic column mapping, invalid row reported, existing contact only tagged; workflow from the hot-lead template switched on, tagging a contact ran it (stage, owner rotation, task, notification, run on the timeline); deal created, moved between stages, marked lost with a reason; campaign to a tag segment counted 2 of 4 contacts (consent rule), preview, send, personalised subjects in Sent messages marked as recorded, not delivered.
  • npm run build, npm run lint, npx tsc --noEmit: clean.
  • npm test: 11 files, 92 tests, all passing (16 commerce, 19 CRM/email/automations, 20 intelligence) (schema safety, document operations, tenant isolation through RLS, publish and form lifecycle, media, global sections, popups, funnel transfer, websites, blog scheduling, redirects, sitemaps).
  • Phase B second walk-through: starter website created, image uploaded and placed through the media picker, alt-text check cleared, popup created and seen opening after its delay on the live site, blog post written and published, blog index and post page live with the shared header and footer.
  • Browser walk-through on localhost: sign-up creates a workspace, template picker, funnel map, editor (inline edit, autosave, mobile preview), publish, live page, form submission redirects along the funnel edge, contact appears in the right workspace with consent, funnel table shows measured visitors and submissions, worker processed the job.

Phase A: Foundations

ItemStateNotes
Organization hierarchy operator / agency / workspaceDoneParent rules enforced by trigger
System roles per organization kind, permission catalogDoneprivate.seed_roles
Row-level security on every tenant tableDoneprivate.tenant_table; tests prove cross-tenant reads and writes fail
Email + password auth, hashed sessions, rate-limited sign-in and sign-upDone
MFA (TOTP) with recovery codesDonePhase J; optional for everyone
OIDC / SSO providersNot started
Email verification, password reset, invitations by emailDonePhase J for reset and verification; delivery needs a system mail provider (without one, development prints the email to the log)
Audit log (automatic + explicit publish/export entries)DoneSettings → Audit log
Job queue with retries, backoff, dead state, stale-lock recovery, heartbeatDonePostgres queue; dead-letter UI for admins is Phase J
Branding resolution workspace → agency → operator → defaultsDone (engine)Branding settings UI is Phase F
App shell, navigation from module registry, Ctrl+K, light/dark tokensDone
Health endpoint /api/healthDoneDatabase, migrations, worker heartbeat

Phase B: Funnels and pages

ItemStateNotes
Funnel templates (lead magnet, webinar, application, blank)DonePlaceholders in [brackets], no invented proof; checks flag leftovers
Funnel map with draggable steps, conditional edges, entry stepDoneConditions: default, form submitted. Purchase/declined arrive with Phase C
Step add / rename / change address / deleteDone
Page document schema (zod), safe inline markup, URL allow-listDoneNo stored HTML anywhere
Visual editor: palette (16 element types), sections with 6 layoutsDone
Drag and drop (new elements, move elements), click to addDone
Inline text editing on canvas, properties panel per elementDone
Undo / redo, keyboard shortcuts, autosave with conflict detectionDone
Desktop / tablet / mobile preview (container queries, same CSS as live)Done
Per-device visibility, sticky sections, entrance animationsDoneReduced-motion respected
Revision history, named versions, restoreDone
Publish, rollback to earlier publication, take offlineDoneAudited
Accessibility, content, speed and SEO checksDoneRule-based
Page SEO (title, description, share image, noindex)Done
Custom code block (sandboxed iframe, permission-gated)Done
Published pages /s/{workspace}/{funnel}/{step}Done
Forms → contacts (dedupe by email, consent wording stored, UTM, honeypot, rate limit)Done
Page-view and submission events, per-step funnel tableDoneMeasured only
Custom domains: add, TXT verification, routing by host to a funnel or a websitePartialTLS issuance belongs to the reverse proxy (Phase G docs); not tested against a real domain
Media library: upload (drag and drop), type detection from file bytes, size limits, dedupe, alt text, usage check before delete, picker in the editorDoneLocal disk driver tested; S3-compatible driver (own SigV4 client) written but not tested against a real bucket
Global sections (shared headers, footers, banners): save from the editor, own editor, draft/publish, detachDoneOne publish updates every page that uses it
Design presets: five built-in, save and delete workspace presetsDone
Popups: delay, exit intent, scroll depth, button click; frequency; forms inside popupsDoneExit intent needs a mouse (documented in the panel)
Funnel duplication, JSON export and importDoneExport inlines global sections, never contains contacts or ids; import validates every page
Websites: starter and blank templates, pages, home page, menu, menu bar element, settingsDoneServed at /w/{workspace}/{website} and on custom domains
Redirects (301/302), sitemap.xml, robots.txt on custom domainsDoneNext.js answers 301 as 308 and 302 as 307 (same meaning for browsers and search engines)
Blog: posts with the same editor, categories, tags, excerpt, cover, author, scheduling, blog index, category pages, latest-posts elementDoneScheduled posts appear at their time without a background job
A/B testingDonePhase E, Conversion Lab
Content scheduling for website pagesNot startedPosts only

Phase C: Commerce

ItemStateNotes
Products (digital, physical, service), immutable prices (one-time, recurring with trial), archiveDone/app/products
Coupons (percent or fixed, per product, max uses, expiry)DoneFixed discounts on subscriptions apply every period
Tax: none, inclusive or exclusive at one rate, seller details on receiptsDoneCountry-based rates (EU VAT on digital goods) not supported; Stripe Tax not integrated
Checkout step with Checkout element: product choice, order bumps, coupon field, optional phone and address, live totals from server pricesDonePrices are always recomputed from the database
One-click upsell and downsell (Offer buttons), purchased and declined paths on the funnel mapDoneOne-time prices only. If a bank asks for confirmation, the buyer pays that offer on Stripe's page
Product sales template (sales, checkout, upsell, downsell, thank you)Done
Built-in test provider: hosted test payment page, published test card numbers only, test badge on every orderDoneVerified end to end in the browser and in tests
Stripe: Checkout Sessions, saved card for upsells, off-session charges, refunds, billing portal, subscriptionsWritten, not run against StripeNeeds a Stripe test account (sk_test key) to verify; request encoding and signatures are unit-tested
Stripe webhooks: signature check, idempotent inbox, worker processing with retries, visible failures; checkout completed/expired, refunds made in Stripe, subscription updates, renewals, failed renewalsDone (processing tested with signed sample events)Live delivery from Stripe not yet observed
Orders: numbering per workspace, items with roles, contact tags and downloads granted on payment, events order.paid / order.refundedDone
Refunds: partial and full, never above what was paid, recorded per provider refund idDone
Subscriptions list, cancel now or at period end (admin), self-service cancel and Stripe portal from the receiptDoneRenewals of test-provider subscriptions are not simulated
Receipts: signed public link, printable, downloads, refunds, subscription statusDoneReceipt email queued on every paid order (transactional stream, sent without marketing consent)
Failed payment recoveryPartialStripe Smart Retries plus status and event here; no dunning email sequence yet (a workflow trigger for failed renewals is the missing piece)
Physical shipping (rates, fulfilment status)Not startedAddress is collected and stored

Phase D: CRM, pipelines, automations, email

ItemStateNotes
Contacts: filters (search, tag, lifecycle stage, owner, score), sorting, bulk tag / stage / owner / delete / add to workflow, select all matchingDone
Contact page: edit, custom fields, consent recorded with a note, tags, notes / calls / meetings, tasks, deals, timeline (forms, orders, emails, automations, visits)DoneEarlier anonymous page views are linked to the contact on form submission
Companies with domain linkingDone
Tasks with due dates, assignees, reminders as notificationsDoneReminder sweep every 5 minutes in the worker
CSV import: delimiter detection, mapping with guesses, custom fields, tag per import, consent only from a yes column, update or skip existing, error report, rollbackDone5 MB / 20,000 rows per file
Duplicates (same phone incl. 00/+ prefix, or same name at one company) and merge with full history moveDoneSame email is merged automatically at capture
Lead scoring rules (events, tags, opens, clicks)DoneRecomputed on events; manual recalculation for all
Custom contact fields (text, number, date, choice, yes/no, link)DoneCompany and deal custom fields: schema only
Pipelines: multiple, stage editor (open/won/lost, probability), Kanban with drag and drop and keyboard move, deal page, lost reason, weighted total labelled as estimateDoneTotals per currency, never summed across currencies
Workflow builder: triggers (form, order paid, tag added, contact created, deal stage, manual), steps (wait, if/else, approval, end, tags, lifecycle, custom field, email, webhook, task, round-robin owner, notify, create/move deal)DoneVertical flow with branches
Workflow engine: immutable versions on activation, runs keep their version, idempotent per trigger occurrence, re-entry setting, loop protection (depth 3), retries with backoff then failed with Retry, step log, run history, approvals inboxDoneTested in tests/crm.test.ts
Test run (dry run) against a real contact without side effectsDone
Signed outgoing webhooks (HMAC SHA-256), private networks blocked in productionDone
Email block editor with live preview, personalisation tokens with fallbacks, templatesDoneSame renderer for preview and send
Campaigns: segment (tags any/all/exclude, stage, score), live audience count, A/B subject, test send, send now or schedule with confirmation, results per variantDoneOpens labelled as estimates
Delivery rules: consent required (setting), unsubscribed, bounced, suppression list, checked again at send timeDone
Unsubscribe page and one-click unsubscribe (List-Unsubscribe, RFC 8058), open pixel, signed click redirectsDone
Providers: log (default), SMTP, Resend, Postmark, credentials encrypted, verified on save; SPF/DMARC lookup; bounce and complaint webhooksWritten, not run against real accountsLog provider verified end to end; SMTP/Resend/Postmark need your credentials
Two-way inbox (email/SMS replies), SMS, calendar bookingsNot started

Phase E: Intelligence

ItemStateNotes
Revenue report: visitors, leads, qualified, meetings logged, deals, won, new customers, net revenue, refunds, contribution margin where unit costs exist, revenue per lead and customer, churn, lifetime value estimate with formulaDoneEvery figure badged measured, attributed or estimate; test orders excluded by default
Source attribution: first touch (contact's first UTM) and last touch (UTM at checkout), by source, campaign or funnel; marketing spend entered by the team, cost per customer, return on spendDoneMissing attribution shown as a share with an explanation
Ad platform connections (Google Ads, Meta Ads)Not startedUTM-based attribution only
Booked and completed meetingsNot trackedNeeds the booking module; logged meetings are counted
Lead Rescue: unassigned leads, no first response, overdue tasks, stale deals, unfinished checkouts; notify, escalate, optional round-robin reassignment, auto-resolveDoneSweep every 5 minutes
Response performance (median first reply, share within target, per owner), lead aging, value at stake (entered deal values; estimate only from your assumptions), lost reasonsDone
Follow-up drafts and one-to-one email (unsubscribe, bounce and suppression checks; checkout reminders need consent)DoneTemplates, not AI; nothing is sent automatically
Unanswered messages, abandoned bookings, incomplete formsNot startedNeed the inbox, booking and partial-form capture
A/B tests: version B as editable copy, stable assignment, forced previews not counted, per-visitor results by goal (next step, form, order), always-valid sequential p-value, 95% intervals, winner only with 100 visitors per arm, 20 conversions and 7 days, adopt B publishes itDone
Diagnostics: unusual drop-offs, silent forms, device gaps (two-proportion test), slow pages (LCP beacon), failing page checks, each with evidence and a recommendationDoneRule-based
AI-generated variants, heatmaps and session recordingsNot started
Personalization rules: UTM fields, URL parameters, browser language, country header, device, returning visitor, contact tag; text replacement or hiding per block; previews; visitors and submissions per ruleDoneCountry needs a host header (Cloudflare, Vercel)
Health monitor: unpublished or invalid live steps, checkout without provider or price, domain verification and https reachability, internal and external links, stopped submissions, traffic and conversion drops, dead jobs, worker heartbeat, failed payment and workflow webhooks, email errors and bounce rate; incidents with history, auto-resolve, one alert per incidentDoneEvery 15 minutes; email alerts not built (in-app notifications)
Agency overview of client incidentsDoneAlso in the agency console (Phase F)
AI architect: plan with funnel template and outline, sales stages, messaging, qualification, follow-up drafts, assumptions with confidence, KPIs, integrations, week plan, risks; applying creates an unpublished funnel, a pipeline and a switched-off workflowDoneRun against the Anthropic API on 2026-10-19 (claude-sonnet-5-5): one plan in 79 s, 2,507 input and 9,388 output tokens including thinking
AI sales assistant: contact call brief with cited sources and a follow-up draft; pipeline bottleneck analysis from computed figuresDoneRun against the Anthropic API on 2026-10-19 on the demo workspace: brief in 18 s with sources cited and gaps named, pipeline analysis in 16 s saying 8 deals are too few to judge
AI gateway: per-workspace switch (off by default), monthly budget, usage ledger with estimated cost, structured answers validated before useDoneStructured outputs (output_config.format, streamed); Claude 5.5 models refuse forced tool use. Prices from env (AI_PRICE_INPUT_PER_MTOK, AI_PRICE_OUTPUT_PER_MTOK), defaults are the claude-sonnet-5-5 list prices
Voice and transcription providersNot started

Phase F: Agency and white label

ItemStateNotes
Tenant hierarchy: platform owner, operators, agencies, client workspaces, businesses; sign-up on an operator's app domain lands under that operatorDone
Branding per operator, agency and workspace with inheritance (closest level wins): product and company name, logo, favicon, colours, heading and body font, login headline and text, support email, help, terms and privacy links, footer, billing note, email sender name and address, app domain, extra navigation links, custom CSSDoneCustom CSS filtered (no @import, no http URLs, no script or HTML); fonts are local stacks, no requests to font services
White-label fields only with the white-label flag of the plan (operators always)DoneStored values are kept when a plan loses the flag
Branded login and sign-up pages, page titles, favicon and transactional mail on custom app domainsDoneApp routes are never rewritten to published sites on custom hosts; reserved step slugs
Team invitations: by email with role, link shown when no email provider delivers, accept as existing user or with a new account, bound to the invited address, revokeDoneDelivery needs a real email provider
Plans: per seller (operator or agency), audience, monthly and yearly price or custom pricing, trial, limits (workspaces, members, funnels, domains, contacts, emails, automation runs, AI spend, storage), flags (agency, white label, custom code, AI), usage prices above the limitsDoneExample plans Starter, Growth, Agency, Agency Pro, Enterprise; their prices are a starting point to change
Limits enforced on the server where things are created: funnels (new, import, duplicate), domains, media, contacts (manual, import), campaigns and workflow emails, automation runs, AI requests, custom code, invitations, client workspacesDoneLeads from published forms are never refused; existing data is never locked; one notification a day when automations hit the limit
Subscriptions: subscribe, trial, change plan (no proration), cancel at period end, discount, price snapshotDone
Platform invoices at the end of each period: base price plus usage lines above the limits, numbered per seller, printable invoice page, overdue marks the subscription past due, paid reactivates itDoneCollected by hand (mark paid). Usage lines for monthly billing only. No tax calculation on platform invoices
Platform billing through Stripe Billing or another providerNot startedKept separate from the customers' own checkout payments
Agency console: client list with plan, members, live funnels, leads, visitors, incidents, approvals; new client (owner invited, agency member gets admin access); staff assignment per client and role; time-boxed support access with reason, audit entry and owner notification; funnel rollout to several clients; workspace duplication (funnels, pipelines, templates, fields, scoring, workflows as drafts, no contacts); client report; suspend and reactivateDoneCovered by tests; not yet walked through in the browser with a seeded agency
Client approvals: the agency asks, only the client's owner decides (not agency or support members)Done
Operator console: customers (agencies and businesses) created without operator membership, optional plan and owner invitation; CSV exports of customers, subscriptions and invoicesDoneOperators see inside a customer only when its owner invites them
Platform owner view: operators, edition, operating cost rates, contribution margin per customer (AI measured, email, storage and jobs from your rates)DoneMargins are estimates and labelled so
Licensing: Ed25519-signed licenses checked offline, license types and rights, workspace and user limits, domains, version range, validity with grace period, signed revocation list, activation on the installationDoneNo phone-home and no remote switch. See docs/LICENSING.md
Independent edition: without a valid license new workspaces and users are refused; existing data keeps workingDone
License agreements (texts)Not startedNeed a lawyer; the software only records the rights granted
Client-specific API credentialsNot startedThe template marketplace followed in Phase H
Email alerts for limits, overdue invoices and incidentsNot startedIn-app notifications only

Phase G: Independent distribution

ItemStateNotes
Migration runner on plain pg (no development packages), advisory lock, deploy (database, migrations, role passwords from the environment, BYPASSRLS warning), status with pending and unknown migrationsDonenode scripts/db.mjs deploy runs on every app start in Docker
First-run setup wizard: protected by a token from the environment or printed to the log, administrator, platform name and product name, currency and time zone, edition, optional license checked offline; all in one transaction, refused once set up; sign-in and sign-up redirect to it on a fresh installationDonenpm run setup:token prints a new link
Installation page and npm run install:check: address, secrets, database passwords, service role, migrations, worker, storage probe, system email, payments, AI, proxy, license, Node version, with the fix for each problemDone
Smoke test (--smoke): temporary workspace, funnel published and loaded over HTTP, form submitted over HTTP, checkout paid with the built-in test provider, worker processed the jobs, everything deletedDone
Clean-installation test (--fresh): installs into a throwaway database on the same server, runs setup, checks and smoke test, drops itDoneAlso part of npm test
Workspace export and import between installations: all tenant tables, users by name and email, uploaded files; no passwords, sessions, tokens or provider credentials; access of the old parent left behind; ids kept; domains, payment and email settings reset with instructionsDoneDownload for the owner (Settings, Data export) and for the operator or agency above (client page), audited; import on the command line with the database admin connection. Export is built in memory: very large workspaces use --no-media
Dockerfile (multi-stage, production dependencies only, non-root, health check), docker-compose.yml (PostgreSQL 17, app, worker, Caddy profile), Caddy with on-demand certificates for customer domains (/api/tls/ask)PartialThe image was built and run on Railway with a real domain and certificates (docs/acceptance/TEST_SERVER.md); docker compose with Caddy not yet run on a Linux server
.env.production.example with every variable explainedDoneOptional variables commented out, since an empty value counts as set
Backup, restore (including disaster recovery on a new server) and upgrade scriptsPartialBackup and restore drilled on Railway with pg_dump/pg_restore and a file archive, the app ran on the restored database (TEST_SERVER.md); the shell scripts for docker compose are not run yet
Release package (npm run release:pack): committed source as tar.gz with SHA-256, refuses uncommitted changes and committed secretsDone
Third-party dependency register (npm run deps:register, docs/DEPENDENCIES.md)Done99 shipped packages; sharp (image processing, pulled in by Next.js) ships libvips under LGPL 3.0, listed for review
CI workflow (lint, types, tests with embedded PostgreSQL, clean installation, build, Docker build)Written, not runNo remote repository yet
Documentation: docs/INSTALL.md, docs/OPERATIONS.md (backup, restore, upgrade, rollback, moving workspaces, monitoring, troubleshooting), docs/TRANSFER.md (handover, asset ownership, domain and infrastructure checklists, signing key)Done
Agreement outlines for legal review (docs/legal/)Done as outlinesNot agreements; every open point marked [NEED]
Deleting a whole workspace from the appDonePhase J: owner or the agency/operator above, grace period, purge with files
Update channel (in-app notice of new releases)Not startedUpgrades are applied from a release package

Phase H: Courses, communities, affiliates, marketplace

ItemStateNotes
Member accounts per workspace (end customers): portal at /p/<workspace> in the workspace's branding, sign-in by one-time emailed link, own password, or from a receipt within 30 days; sessions per portalDoneLinks are emailed through the workspace's provider; with the log provider the team can pass a link on
Courses: modules and lessons, markdown text rendered safely, video (YouTube privacy mode, Vimeo, MP4/WebM from the library or https), downloads, drip by days per module or lesson, free preview lessons, draft and published, progress and completionDoneLesson files and videos uploaded to the media library are reachable by their unguessable address, not protected per member
Access: products unlock courses, communities and membership levels; the order job grants access and emails a sign-in link; a full refund revokes it; subscriptions keep it while active, trialing or past due and end it with the subscription (at period end when cancelled that way); manual grants with end dates; revoke; block membersDone
Customer dashboard: continue where you left off, courses with progress, communities, purchases with receiptsDone
Automation triggers: access granted, course completedDone
Team pages: course editor with reordering, drop-off per lesson, members with access; member list and detailDone
Communities: open to every member or only with access, posts with markdown, comments, likes, reports, approval of new posts, announcement spaces (team posts only), pin, close comments, hide, remove members; moderators notified in the appDoneNo email notifications for replies yet
Affiliate and referral program: one per workspace, percent or fixed commission, cookie window, first or last click, hold period, partner or customer-only, product list, minimum payout, terms accepted at sign-up, automatic or manual approval of affiliatesDone
Tracking and attribution: ?ref= on any public page sets first and last referral cookies; visits counted from the page-view beacon (repeat visits within 30 minutes once); the checkout stores the referral; the order job records the commission on the order before taxDoneRenewals of subscriptions earn no commission yet
Fraud signals: buying through one's own link, purchase within seconds of the click, several orders from one visitor; flagged commissions wait for a person, the rest are approved by the worker after the holdDone
Refunds: commissions scale with partial refunds, reverse on full refunds, and become a negative adjustment when already paidDone
Payouts: recorded by the team per affiliate and currency, with method and reference; affiliates see their payoutsDoneMoney moves outside the software; no payout provider integration
Affiliate area in the portal: sign-up (also for people who are not customers yet), link builder, visits, sales, commissions by status, payoutsDone
Template library: save funnels, workflows, email templates, pipelines and courses as one package with their images; checks block credentials and list personal data for confirmation; references between items survive, other ids (people, products) are removed; duplicate, export, import, install; agency templates offered to client workspacesDoneCheckout steps arrive without their products; booking pages need the booking module (not built)
Marketplace: publishers list templates with price, license scope (workspace or agency) and terms; every version is reviewed by a platform administrator; versions declare compatible software versions; buyers install free templates directly and paid ones after the publisher grants a license; installs recorded, updates offeredDonePayment for paid templates is collected outside the software; no revenue share for the platform owner yet

Phase I: Sales website, demo, screenshots, acquisition package

ItemStateNotes
Sales website: home, platform overview, seven feature pages, integrations, agencies, white-label licensing, independent edition, pricing, demo, FAQ, contact, legal pagesDoneOnly on installations with SALES_SITE=on (on in development, off by default in production); real screenshots only; status chips for built, needs-account and not-built items; no testimonials or invented figures
Pricing read live from the house operator's active plans; licenses on request; source/asset sale separated from a business saleDone
Contact sales: form with rate limit and honeypot, enquiries stored for platform administrators, in-app notification, Platform → EnquiriesDoneNo email to the sales team
Documentation pages rendering a fixed list of docs/*.md (manuals, API, install, operations, licensing, transfer, architecture, status, dependencies)DoneSafe Markdown subset with tables and code
Legal pagesPartialOperator facts read from PRODUCT_COMPANY_NAME and SUPPORT_EMAIL; everything else marked [NEED] for the operator and a lawyer
Read-only public demo: /demo signs in a shared demo account; read permissions only, actions refused, read-only database transactions, banner, editor as sandbox, rate limited, DEMO_ACCESS switchDoneRebuild nightly with npm run demo:seed -- --reset
Demo data seed through the real services; --local accounts, demo agency and example license for screenshotsDone
Screenshot automation (npm run screenshots, playwright-core with installed Chrome or Edge) with manifestDone21 views
Setup wizard preview for platform administrators (/setup?preview=1)DoneSaves nothing
User, administrator and operator manuals; API and webhooks documentationDonedocs/manuals, docs/API.md
Acquisition package (docs/acquisition): overview, inventory, technology and repository, deployment, generated database schema (npm run docs:schema), security, license register, commercial model, white label and resellers, limitations and technical debt, maintenance and costs, demo and walkthrough, financial reporting templateDoneNo figures: the service has not run commercially; open owner decisions marked [NEED]

Phase J: Security, reliability and production verification

ItemStateNotes
Acceptance suite for the twelve scenarios of the brief (npm run acceptance, docs/acceptance/REPORT.md)DoneBrowser, HTTP, database and command steps; needs a running installation; not in CI yet
Production-mode check and load test (npm run perf, docs/acceptance/PERFORMANCE.md)DoneSingle machine; no production-sized data
Internal security review (docs/acceptance/SECURITY_REVIEW.md) with a static authorization test for every server actionDoneExternal penetration test not done
Outbound request guard against private networks for webhooks, link checks, domain checks, SMTP hostsDoneALLOW_PRIVATE_NETWORK=true lifts it
Content Security Policy on the platform's own pagesDoneScripts only with a per-request nonce ('strict-dynamic', no 'unsafe-inline'); inline styles still allowed; published pages excluded on purpose; inline scripts in custom code blocks run on the published page but not in the editor or preview
Two-factor sign-in, password reset, email verification, password change, session listDoneNo setting yet to require two-factor sign-in
Workspace deletion with grace period, restore, purge with files; event retention; daily clean-up; one person's data as JSONDonedocs/PRIVACY.md
Background job overview for platform administrators (run again, discard)Done
Error pages for app, website, portal, editor and a global fallbackDone
Dependency upgrades: Next.js 16.4, nodemailer 10, ESLint CLIDonenpm audit --omit=dev: 0

Other modules

ModuleState
Conversations inbox, SMS, bookingsNot started

Known gaps to close next

  1. An external penetration test, then encrypted backups.
  2. Run the Stripe path against a Stripe test account (needs your sk_test key and a webhook secret).
  3. Connect a real email provider (SMTP, Resend or Postmark) and send a first test of invitations, password reset and receipts.
  4. Run docker compose with the Caddy profile on a plain Linux server (on-demand certificates, backup.sh, restore.sh, upgrade.sh), and push the repository to a remote so the CI workflow runs; then add the acceptance suite to CI against a throwaway database. (Image, domain, certificates and a backup and restore drill are done on Railway.)
  5. Decide how platform invoices are collected (Stripe Billing or by hand) and whether they need tax lines; have the license agreements, terms and privacy notice drafted by a lawyer.
  6. Image resizing (responsive sizes) for uploaded images; S3 driver verification against a real bucket.
  7. A setting to require two-factor sign-in for administrators; single sign-on if enterprise buyers ask.
  8. Email notifications for community replies, affiliate events, incidents and limits; commissions on subscription renewals; payment collection for paid marketplace templates.