# Performance West — Build Plan **Last updated:** 2026-04-05 **Status:** Pre-launch. CRTC pipeline ~95% built (14 steps, BITS/CCTS/compliance calendar implemented). DocServer provisioned. US formation plumbing exists but no state has been filed end-to-end. Payment flow is wired but gateways not yet configured in ERPNext UI. > **See also:** [`docs/multi-province-plan.md`](multi-province-plan.md) — Plan to extend CRTC to multi-province + standalone Canadian formation + universal compliance calendar. 28-36 hours, 16 sub-phases. > **See also:** [`docs/competitive-pricing.md`](competitive-pricing.md) — Competitor pricing analysis: US formation, Canadian formation, registered agents. Updated 2026-04-05. --- ## How to Read This Plan Tracks are independent workstreams. Within each track, items are ordered by dependency — complete them top-to-bottom. Across tracks, work in parallel where possible. **Labels:** - `[BLOCKER]` — nothing ships until this is done - `[CRTC]` — affects the $3,899 flagship product - `[FORMATION]` — affects US LLC/Corp product - `[INFRA]` — server/ops - `[PLUMBING]` — backend wiring, no user-facing change --- ## Track 1 — CRTC Pipeline (Flagship Revenue) The Canada CRTC Carrier Package is the highest-value product. Get one real order through end-to-end before doing anything else. ### 1.1 ERPNext Payment Config `[BLOCKER][CRTC]` ERPNext gateways exist as code but are not configured in the UI — no payment can complete. - [ ] Configure Crypto Payment Settings: URL = `https://pay.performancewest.net`, SHKeeper API key - [ ] Create Payment Gateway Account `Crypto-Crypto` in ERPNext - [ ] Configure Adyen Settings (5 instances: Card, ACH, Klarna, CashApp, AmazonPay) — pending Adyen account approval - [ ] Create 5 Adyen Payment Gateway Accounts - [ ] Configure ERPNext SMTP for outbound email (invoices, notifications) - [ ] Test: place a $1 test order, confirm Payment Request is created, confirm redirect to checkout, confirm webhook fires back to Express API ### 1.2 COLIN Selector Verification `[BLOCKER][CRTC]` The BC incorporation adapter (`frappe_ca_registry/provinces/bc/adapter.py`) has 13 steps mapped but selectors are unverified against the live portal. No real BC incorporation can complete until this is tested. - [ ] Place a real test incorporation order against COLIN (corporateonline.gov.bc.ca) - [ ] Verify/fix selectors for: Step 6 Director, Step 7 Office Addresses, Step 8 Share Structure, Step 9 Notification, Step 12 Payment - [ ] Verify payment step: COLIN accepts Visa/MC — use `relay-filing-card` via `get_filing_card` API - [ ] Implement multiple-directors loop (currently only first director is inserted) - [ ] Confirm that BC sends certificate email to `filings@performancewest.net` - [ ] End-to-end smoke test: `frappe_ca_registry` creates Filing Request → COLIN automation completes → certificate arrives ### 1.3 CRTC Pipeline Remaining Stubs `[CRTC]` - [ ] **Anytime Mailbox automation hardening** — provider has no API, but Playwright flow now exists. Validate selectors against live UI and stabilize OTP retrieval via Carbonio IMAP, then keep admin handoff as fallback. - [ ] **CCTS registration** — Step 11 is a stub. Research CCTS online registration form, implement Playwright or keep as admin ToDo with instructions. - [ ] **eSign workflow for CRTC letter** — Step 6 generates the DOCX letter but customer signature is not collected. Use ERPNext built-in eSign (drawing pad). Wire: generate letter → send for eSign → on signed → continue pipeline. - [ ] **CRTC letter email submission** — After eSign, email the signed letter to CRTC from the customer's provisioned `.ca` address (`regulatory@{domain}.ca`). Requires IMAP send via HestiaCP provisioned mailbox. - [ ] **BITS affidavit** — BITS requires a notarized affidavit confirming the company is a US carrier (or Canadian equivalent). Provider: NotaryLive ($59/mo platform + $23/session). Implement: generate affidavit DOCX → send NotaryLive session invite → on completion → attach to binder. - [ ] **Order confirmation email** — After payment, send customer a confirmation email with order summary, expected timeline, and next steps checklist. Currently nothing is sent at payment time. - [ ] **Branded HTML email templates** — 15 ERPNext Email Notifications are plain text. Design and import HTML templates (header logo, PW brand colors, footer with unsubscribe). ### 1.4 Customer Portal Auth `[CRTC]` Portal pages (`/portal/domain-search`, `/portal/manage-services`) exist but have no authentication. Any URL visitor can access any order. - [ ] Implement portal authentication via ERPNext portal login (ERPNext has a built-in portal user system) - [ ] Generate a signed JWT or ERPNext portal token and embed in the email links sent to customers - [ ] Add auth middleware to all `/portal/*` API routes — validate token, scope to customer's own orders only - [ ] Add session expiry (24h) and re-send link flow ### 1.5 End-to-End CRTC Test `[CRTC]` - [ ] Place a real CRTC order (numbered company, test customer) - [ ] Walk through all 12 pipeline steps - [ ] Confirm: DID provisioned, COLIN automation runs, domain registered, CRTC letter generated + eSigned, binder compiled, MinIO upload, customer emails received - [ ] Document any failures and fix before first real customer order --- ## Track 2 — US Formation (Second Revenue Stream) ### 2.1 Wyoming End-to-End `[FORMATION]` WY is the highest-priority state — selectors verified on name search, no CAPTCHA, cheapest filing fee. - [ ] Implement WY filing automation: walk the WYO SOS filing wizard step-by-step with Playwright, map all form field selectors - [ ] Wire payment step: WY SOS accepts credit card — use `relay-filing-card` - [ ] Test: place a real WY LLC order, confirm name search works, confirm filing completes, confirm confirmation number saved to DB - [ ] Wire formation worker to create ERPNext Formation Order + Sales Invoice on order receipt - [ ] Wire formation worker to send order confirmation email after payment ### 2.2 Colorado End-to-End `[FORMATION]` CO name search is already working (Socrata API). Need filing automation. - [ ] Research CO SOS filing wizard (sos.state.co.us), map selectors - [ ] Implement CO LLC filing automation - [ ] Test end-to-end ### 2.3 Server-Side Fee Validation `[FORMATION][PLUMBING]` Currently the API trusts client-submitted `state_fee_cents`. This is a billing vulnerability. - [ ] Add server-side lookup: on order receipt, look up `state_fee_cents` from `state_filing_fees` DB table using `state` code - [ ] Reject any order where client-submitted fee does not match DB value - [ ] Audit and fix the 12+ known fee discrepancies between the frontend hardcoded array and DB (identified last session) ### 2.4 Operating Agreement + EIN `[FORMATION]` - [ ] Test operating agreement DOCX generation end-to-end (template → DocxBuilder → PDF → MinIO) - [ ] Test EIN obtainment worker (IRS Playwright) on a real WY entity after filing - [ ] Confirm both documents are attached to the ERPNext Formation Order and emailed to customer ### 2.5 DocServer (Windows VM) `[FORMATION][INFRA]` LibreOffice fallback produces lower-quality PDFs. Office 2021 on Windows is required for production-quality DOCX→PDF conversion. - [ ] Provision Windows Server 2022 VM in Proxmox (2 vCPU, 4 GB RAM, 40 GB SSD) - [ ] Install Microsoft Office 2021 - [ ] Deploy DocServer Flask app on port 5050 - [ ] Configure `DOCSERVER_URL` env var to point workers at Windows VM - [ ] Verify: workers use DocServer when available, fall back to LibreOffice when not ### 2.6 Remaining State Adapters `[FORMATION]` Priority order based on formation volume. Each requires: portal inspection, selector extraction, Playwright implementation, payment wiring. - [ ] Delaware (DE) — CAPTCHA. Integrate 2captcha or AntiCaptcha solving service first. - [ ] Florida (FL) — High demand. Playwright needed, no CAPTCHA expected. - [ ] Texas (TX) — SOSDirect account needed for search. Get account first. - [ ] Nevada (NV) — WAF. Use stealth Playwright (playwright-extra + puppeteer-stealth). - [ ] Utah (UT) — Name search works without login. Filing needs UtahID OAuth. - [ ] New Mexico, Ohio, Montana — Untested, research portals. - [ ] Remaining 37 states — Batch: inspect portals, extract selectors, implement in priority order. --- ## Track 3 — Infrastructure & Ops ### 3.1 Production Deployment `[INFRA][BLOCKER]` The rsync to production timed out. Get the current codebase deployed. - [ ] Fix rsync: run with `--timeout=30` and `--compress`, or use a staged approach (`tar | ssh`) - [ ] On server: `docker compose build && docker compose up -d` - [ ] Update ERPNext Docker image: rebuild `performancewest-erpnext:latest` with latest `frappe_ca_registry` + `performancewest_erpnext` changes - [ ] Run any pending DB migrations on production ### 3.2 Environment Variables `[INFRA]` Several env vars are not yet set in production `.env`. - [ ] `PORKBUN_API_KEY` / `PORKBUN_SECRET_KEY` - [ ] `FLOWROUTE_ACCESS_KEY` / `FLOWROUTE_SECRET_KEY` - [ ] `HESTIA_HOST` / `HESTIA_USER` / `HESTIA_PASSWORD` - [ ] `SHKEEPER_API_KEY` - [ ] `ADYEN_API_KEY` / `ADYEN_MERCHANT_ACCOUNT` / `ADYEN_CLIENT_KEY` (when account approved) - [ ] `DOCSERVER_URL` (when Windows VM is provisioned) - [ ] `CUSTOMER_JWT_SECRET` (for portal auth) ### 3.3 Monitoring & Alerts `[INFRA]` - [ ] Set up UptimeRobot (free) to monitor: performancewest.net, api.performancewest.net, crm.performancewest.net, pay.performancewest.net - [ ] Configure alert email to `ops@performancewest.net` - [ ] Set up weekly automated DB backup to MinIO (pg_dump → minio/backups/) - [ ] Verify ERPNext daily backup is configured and uploading to MinIO --- ## Track 4 — Payment & Billing Completion ### 4.1 Bundle / Compliance Checkout `[PLUMBING]` The Express API returns `null` for bundle and compliance service checkout. These are broken. - [ ] Implement bundle checkout in `api/src/routes/checkout.ts`: look up bundle from `service_bundles` table, create Sales Order + Invoice with correct line items and 20% bundle discount - [ ] Implement compliance service checkout (CCPA audit, FLSA audit, etc.): create Sales Invoice with correct item and turnaround date - [ ] Test both flows end-to-end through payment ### 4.2 Subscription / Renewal Billing `[PLUMBING]` Annual renewals (RA $99/yr ($49 WY), Annual Report $99/yr, CRTC Maintenance $349/yr) exist as ERPNext Subscription Plans but the renewal worker is not wired to trigger them. - [ ] Wire `renewal_handler.py`: on subscription due date (from Compliance Calendar), create ERPNext Sales Invoice + Payment Request, send renewal email with payment link - [ ] Test: manually trigger a renewal for a test customer, confirm invoice created, confirm email sent, confirm payment marks subscription renewed ### 4.3 Refund Flow `[PLUMBING]` - [ ] Verify ERPNext Credit Note flow works end-to-end - [ ] Test: issue a partial refund on a test invoice, confirm Adyen processes the refund, confirm customer email is sent - [ ] Document refund policy in customer-facing portal --- ## Track 5 — Docs Update All 15 docs have stale content. These need to be rewritten to match current state before bringing on any contractors or making architectural decisions. **Critical (do first):** - [x] `docs/architecture.md` — Replaced Mautic with Listmonk. Added DocServer, workers, portal. Updated container count to 15. - [x] `docs/go-live-todo.md` — Marked completed items. Added multi-province priority 11. Updated pricing. - [x] `docs/formation-system.md` — Updated BC section with BITS/CCTS/GCKey/compliance. Updated DocServer. - [x] `docs/crm.md` — Replaced Mautic Integration → Listmonk. Added CRTC campaign. **High priority:** - [x] `docs/product-facts.md` — Added Canada annual maintenance ($349), consulting ($75/hr), Canadian formation (C$449), maintenance bundles ($179/yr). Updated CRTC pipeline to 14 steps. - [x] `docs/billing.md` — Added renewal billing, compliance calendar billing, maintenance bundles, Canadian formation pricing. - [x] `docs/infrastructure.md` — Replaced Mautic/MySQL with Listmonk. Updated container count to 15. Added portal nginx config. **Medium priority:** - [ ] `docs/marketing.md` — Add FCC RMD as primary lead gen channel. Add Listmonk drip campaign details. Add 3 campaign descriptions. - [x] `docs/state-automation-status.md` — Updated BC section with all new capabilities + GCKey automation table. - [ ] `docs/document-generation.md` — Update DocServer section (MinIO transport, not HTTP). Add template list. --- ## Track 6 — frappe_registry Migration (Future) This is a significant refactor — ~24 hours of work. Do not start until CRTC pipeline is working end-to-end and at least WY formation is live. - [ ] Rename `frappe_ca_registry` → `frappe_registry` - [ ] Generalize `CA Filing Request` DocType to `Registry Filing Request` (55 jurisdictions) - [ ] Add `Registry Settings` DocType: NWRA defaults, per-state RA override, CA mailbox config - [ ] Move 51 US state adapters from `scripts/formation/states/` into Frappe app - [ ] Add extra-provincial registration support (10 Canadian provinces) - [ ] Add foreign state qualification support (US foreign entity) - [ ] Define `BaseAdapter` interface with auto-discovery by jurisdiction code - [ ] Build fee scraper framework: - [ ] `base_scraper.py` — abstract scraper class with rate limiting, retry, user-agent rotation - [ ] `pdf_scraper.py` — Tesseract OCR for scanned fee schedule PDFs, pdfplumber for text PDFs - [ ] `fee_change_detector.py` — compares scraped values against DB, generates diff report - [ ] Admin email alert when any fee changes (does NOT auto-update — human review required) - [ ] Monthly cron job in workers container (`0 6 1 * *` — 1st of each month, 6am) - [ ] Store scraped results in `state_fee_scrape_history` table with timestamp + source URL + old/new values - [ ] Implement US state fee scrapers (51 jurisdictions): - [ ] Tier 1 (top 10 by formation volume): WY, DE, FL, TX, NV, CA, CO, NY, GA, IL - [ ] Tier 2 (remaining 41 states + DC) - [ ] Handle: annual report fees, franchise taxes, business license fees, privilege taxes, personal property returns - [ ] Reference: `docs/state-annual-fees-complete.md` for current verified values + source URLs - [ ] Implement Canadian province fee scrapers (10 provinces): - [ ] BC, AB, ON, QC, MB, SK, NS, NB, PE, NL - [ ] Scrape in CAD, convert to USD via `fx.ts` Bank of Canada rate + 10% buffer - [ ] Fix fee data integrity: DB as single source of truth, frontend fetches from API, server-side validation (see 2.3) --- ## Launch Readiness Checklist Before accepting the first paying customer: - [ ] ERPNext payment gateways configured (Track 1.1) - [ ] CRTC end-to-end test passes (Track 1.5) - [ ] Portal authentication implemented (Track 1.4) - [ ] Order confirmation email sends after payment (Track 1.3) - [ ] Production deployed with current codebase (Track 3.1) - [ ] All env vars set in production (Track 3.2) - [ ] UptimeRobot monitoring configured (Track 3.3) Formation orders can follow ~2 weeks after CRTC is live (WY first). --- ## Open Questions / Decisions Needed | Question | Context | Deadline | |----------|---------|----------| | Adyen account approval status? | Without Adyen, card/ACH payments are blocked. Only crypto works. | Before first customer | | NotaryLive account — go or no-go? | $59/mo + $23/session for BITS affidavit notarization. Alternative: partner with a Canadian notary. | Before first CRTC delivery | | Anytime Mailbox credential handoff policy? | Provider confirmed no API; Playwright signup uses shared inbox OTP. Decide whether to bootstrap with `filings@performancewest.net` then transfer to client, or require client email from the start. | Before first customer | | Portal auth strategy? | ERPNext portal login vs. signed JWT in email link. Signed JWT is simpler, no password needed. | Before first customer uses portal | | Canadian accountant? | 3 hours free accounting support is promised in the CRTC package. Need to onboard a freelance Canadian accountant. | Before first delivery |