new-site/docs/formation-system.md
justin f8cd37ac8c Initial commit — Performance West telecom compliance platform
Includes: API (Express/TypeScript), Astro site, Python workers,
document generators, FCC compliance tools, Canada CRTC formation,
Ansible infrastructure, and deployment scripts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 06:54:22 -05:00

17 KiB

Performance West — 52-Jurisdiction Business Formation System

Last updated: 2026-04-05

50 US states + District of Columbia + British Columbia (Canada) = 52 jurisdictions.

Architecture

Customer                    Website                      API                    Database
  |                           |                           |                       |
  +- Select state ----------->|                           |                       |
  +- Search name ------------>+- GET /states/:code/ ----->+- (proxy to Python) -->|
  |  <-- available/taken ---- |    name-search             |                       |
  +- Fill details ----------->|                           |                       |
  +- Submit order ----------->+- POST /formations ------->+- INSERT ------------->|
  |  <-- order number ------  |                           |   formation_orders     |
  |                           |                           |                       |
  |                    ERPNext (BPM Orchestrator)          |                       |
  |                           |                           |                       |
  |                    +------+------+                    |                       |
  |                    | Webhook     |<-- order.created --|                       |
  |                    | triggers    |   (not polling)      |                       |
  |                    | worker      |                    |                       |
  |                    +------+------+                    |                       |
  |                           |                           |                       |
  |                    +------+------+                    |                       |
  |                    | Load state  |                    |                       |
  |                    | adapter     |                    |                       |
  |                    +------+------+                    |                       |
  |                           |                           |                       |
  |                    +------+------+                    |                       |
  |                    | Playwright  |--> State SOS       |                       |
  |                    | automation  |    Portal          |                       |
  |                    +------+------+                    |                       |
  |                           |                           |                       |
  |                    +------+------+                    |                       |
  |                    | Update DB   |---- UPDATE ------->|                       |
  |                    | with result |   status=filed      |                       |
  |                    +------+------+                    |                       |
  |                           |                           |                       |
  |  <-- email docs --------- |                           |                       |

ERPNext as BPM orchestrator: ERPNext webhooks trigger formation workers on order events (e.g., order.created, payment.confirmed). Workers are event-driven, not polling-based.

Directory Structure

scripts/formation/
+-- __init__.py
+-- base.py                     # StatePortal base class + data models
+-- name_search.py              # Multi-state name search coordinator
+-- formation_worker.py         # Event-driven queue processor (ERPNext webhook triggers)
+-- operating_agreement.py      # Template-based .docx/.pdf generator
+-- ein_worker.py               # IRS EIN online application (Playwright)
+-- document_delivery.py        # SMTP email with attached formation docs
+-- states/
    +-- __init__.py             # Registry: get_adapter(), get_config(), STATES dict
    +-- al/                     # Alabama
    |   +-- __init__.py
    |   +-- config.py           # Portal URLs, NW RA address, fees, CSS selectors
    |   +-- adapter.py          # ALPortal(StatePortal) -- search + filing automation
    +-- ak/                     # Alaska
    +-- az/                     # Arizona
    ... (51 US: 50 states + DC)
    +-- dc/                     # District of Columbia
    +-- bc/                     # British Columbia (Canada) -- CRTC Carrier Package

BC (Canada) — CRTC Carrier Package

British Columbia uses a completely different workflow from US states:

  • Not a state SOS filing — BC adapter handles the CRTC Carrier Package registration
  • Different portal: BC Corporate Online (bcregistryservices.gov.bc.ca) — anonymous, no login required
  • CRTC requirements: Carrier registration with the Canadian Radio-television and Telecommunications Commission
  • Separate API endpoint: /api/v1/canada-crtc for BC-specific orders
  • Separate DB table: canada_crtc_orders tracks BC orders independently
  • 14-step pipeline managed by services/canada_crtc.py

The BC adapter implements BCPortal(StatePortal) but overrides both name search and filing methods for Canadian requirements. BC government fees are passed through at cost.

BC Config (scripts/formation/states/bc/config.py)

The BC config contains configuration blocks for all Canadian-specific services:

Config Block Purpose
bits BITS (international telecom) registration — filing URL, required documents
ccts CCTS (complaint commission) membership — application URL, required info
gckey GCKey signup wizard — 5-step URLs, CSS selectors, hCaptcha sitekeys, password rules
ats Annual Telecommunications Survey — 6 survey forms (REP-T/T1, REP-U, 802a, 802j, Facilities, Pricing) with deadlines and revenue thresholds
corporate_obligations BC corporate tax/filing obligations — T2, GST/HST, T4/T4A, BC PST, WorkSafeBC, CRTC update

GCKey Provisioning

Each carrier needs its own GCKey account (Government of Canada credential) for filing annual telecommunications surveys via My CRTC Account.

  • Username format: pw-{bc_number}
  • Recovery email: regulatory@domain.ca (we control the mailbox)
  • Automation: gckey_provisioner.py — Playwright-based 5-step signup wizard
  • hCaptcha: Invisible challenge on Step 2 (sitekey 99871bd1-7b22-417a-b6cc-7ef645e5147a)
  • Credentials stored in ERPNext Sensitive ID (encrypted)
  • Steps 3-5 selectors inferred from Step 1-2 recon — need verification on first live run

Compliance Calendar (17 Entries Per Carrier)

Created at pipeline Step 13. Entries span regulatory, corporate tax, and survey obligations:

Regulatory (7): BC Annual Report, CRTC Maintenance, Mailbox Renewal, Domain Renewal, DID Renewal, CCTS Renewal, CRTC Registration Update

Corporate Tax (6): T2 Return (Jun 30), Tax Payment (Mar 31), GST/HST (Mar 31), T4/T4A Slips (Feb 28), BC PST (volume-based), WorkSafeBC (Mar 1 — if employees)

Annual Telecom Surveys (4+): REP-T/T1 (mandatory for ALL carriers, Mar 1), REP-U/802a/802j/Facilities/Pricing (only if >$10M CAD revenue)

State Adapter Status

Name Search Methods

Method States How It Works
Socrata REST API CO, IA, IL, MI, NY, OR, PA, VT, WA Free JSON API via state open data portals. No browser needed.
SFTP Bulk Download FL Free SFTP (public credentials) with daily entity dumps. Pre-load into local DB.
Playwright All remaining ~40 US states Browser automation against state SOS web portals.
BC Corporate Online BC (Canada) Browser automation against BC Registry Services.

Filing Method

All 51 US jurisdictions use Playwright — no state offers a filing API. BC (Canada) uses Playwright against BC Corporate Online + CRTC portal.

Implementation Status

State Name Search LLC Filing Corp Filing Selectors Verified
WY Working Stub (needs filing walkthrough) Stub Name search: YES
CO Socrata API (working) Stub Stub N/A (API)
BC Stub (BC Corporate Online) N/A (CRTC Carrier Package) Stub Need portal inspection
All others Stub (structure ready) Stub Stub Need portal inspection

~12 states have real implementations, ~40 still stubbed.

Per-State Work Required

For each state, the following work is needed to go live:

  1. Visit the state's name search URL in a browser
  2. Inspect form elements — record CSS selectors for input fields, buttons, result areas
  3. Update config.py with verified selectors
  4. Test name search with known entities
  5. Visit the filing URL and walk through the LLC formation form
  6. Record all filing form selectors — name, agent, address, member, payment fields
  7. Implement the file_llc() method with the state-specific workflow
  8. Test with a real formation (or test/sandbox environment if available)
  9. Repeat for file_corporation()

Estimated time: 1-3 hours per state depending on portal complexity.

API Endpoints

Method Path Description
GET /api/v1/states All 52 jurisdictions with fees
GET /api/v1/states/:code/name-search?name=... Name availability check
POST /api/v1/formations Create formation order
GET /api/v1/formations/:orderNumber Check order status
GET /api/v1/bundles List available service bundles
GET /api/v1/payment-methods Available payment methods + surcharges
POST /api/v1/agents Sales agent referral tracking
POST /api/v1/canada-crtc BC (Canada) CRTC Carrier Package order

Database Tables

state_filing_fees — 52 rows (populated via migration 002)

All state/jurisdiction filing fees, portal URLs, special requirements (publication, franchise tax, etc.)

formation_orders — Customer orders

Full order lifecycle: received -> processing -> submitted -> filed -> delivered. Includes erpnext_invoice_name and erpnext_payment_request columns for ERPNext integration.

nwra_wholesale_pricing — NW RA costs per state

Our wholesale cost for registered agent service (TBD from portal exploration).

canada_crtc_orders — BC Canada orders

Separate table for CRTC Carrier Package orders with Canadian-specific fields. Includes erpnext_invoice_name and erpnext_payment_request columns.

service_bundles — Pre-configured service bundles

Bundle definitions (e.g., "Complete Formation + RA + EIN") with 20% discount applied.

bundle_orders — Bundle order tracking

Links bundle purchases to individual service orders.

sales_agents — Referral agent accounts

Agent ID (REF-XXXXX), contact info, commission tier, payout details.

commission_ledger — Agent commission tracking

Per-order commission records: agent_id, order_id, service_type, flat_commission_amount, status (pending/paid).

payment_surcharges — Payment method surcharge rates

ACH 0%, Card 3%, Klarna 5%, CashApp 3%, AmazonPay 3%, Crypto 0%.

accounting_advisors — Advisor profiles

Accounting advisor details for post-formation consulting referrals.

accounting_support_accounts — Client accounting support

Links clients to assigned accounting advisors.

conversation_flags — Support conversation metadata

Flags for support conversations (escalation, priority, category).

Formation Worker

scripts/formation/formation_worker.py is triggered by ERPNext webhooks (event-driven):

  1. ERPNext webhook fires on order.created or payment.confirmed
  2. Worker loads the appropriate state adapter
  3. Verifies name availability
  4. Submits the filing via Playwright
  5. Updates DB with filing number and status
  6. Generates operating agreement (if ordered)
  7. Obtains EIN (if ordered)
  8. Emails all documents to customer

Human-paced delays: 30-120 minutes between orders (configurable via env vars) to avoid appearing automated.

Single-instance locking: fcntl.flock on /tmp/formation-worker.lock prevents concurrent runs.

Document Generation — PDF Conversion

  • Primary: Windows DocServer (108.181.102.34, port 22422) — Office 365 Word COM automation via MinIO transport
    • docserver_worker.py polls to-convert/ bucket every 12 seconds
    • Converts via Word COM, drops PDF in converted/ bucket
    • Heartbeat file at minio://performancewest/docserver-heartbeat.json (60s interval)
    • Atomic uploads via .tmp_ prefix + copy_object rename
    • Task Scheduler: PW-DocserverWorker — auto-restart on failure
  • Fallback: LibreOffice headless (soffice --headless --convert-to pdf) auto-activates when DocServer heartbeat stale (>5 min)
  • E2E tested: 36KB DOCX → 82KB PDF in 12 seconds total round-trip

Operating agreements, CRTC letters, and other generated documents go through DocServer first. If the Windows VM is down, the system falls back to LibreOffice automatically.

Northwest Registered Agent Integration

NW RA is used only for registered agent service, not for filings.

  • Wholesale portal at accounts.northwestregisteredagent.com
  • We order RA service for the customer's state after filing completes
  • NW RA address for each state is stored in the state's config.py

Operating Agreement Generator

Template-based using python-docx:

  • Standard 10-article LLC operating agreement
  • Variables filled from order data (entity name, state, members, etc.)
  • Outputs .docx + .pdf (via Windows DocServer, LibreOffice fallback)
  • Disclaimer: "This is not legal advice"

EIN Obtainment

Playwright automation against IRS EIN Assistant:

  • Available Mon-Fri 7am-10pm ET only
  • Fills SS-4 equivalent online form
  • Extracts EIN from confirmation page
  • Saves PDF confirmation

Pricing

Component Customer Pays Our Cost
State filing fee Pass-through (varies $35-$725) Same
Service fee (basic) $179 $0 (our margin)
Service fee (complete) $399 $0 (our margin)
RA service $99/year (WY: $49/year) ~$80/year (NW RA wholesale, TBD)
EIN $49 $0 (IRS is free)
Operating agreement $99 $0 (template-generated)
Expedited Pass-through (varies by state) Same

Service Bundles (20% Off)

Customers can purchase pre-configured bundles at a 20% discount off individual pricing:

Bundle Includes Individual Total Bundle Price
Starter Basic Formation + EIN $198 $158
Professional Complete Formation + EIN + RA (1yr) $573 $458
Full Package Complete Formation + EIN + RA (1yr) + Operating Agreement $672 $538

Bundle orders are tracked in service_bundles and bundle_orders tables.

Payment Methods & Surcharges

Method Surcharge Notes
ACH Direct Debit 0% Recommended — lowest cost
Credit/Debit Card 3% Via Adyen (Visa/MC/Amex + Apple Pay + Google Pay)
Klarna (Pay in 4) 5% Via Adyen — installment payments
Cash App Pay 3% Via Adyen
Amazon Pay 3% Via Adyen
Crypto (BTC/ETH/USDC/USDT/MATIC/TRX/BNB/LTC/DOGE) 0% Via SHKeeper (pay.performancewest.net)

Surcharges are displayed at checkout before payment confirmation. Stored in payment_surcharges table. Surcharge injection is handled by the performancewest_erpnext Frappe app hook.

SHKeeper runs as a self-hosted instance in k3s (Kubernetes) at pay.performancewest.net for crypto payments. Supports any ERC-20/TRC-20/BEP-20 token. Webhook callbacks confirm payment and trigger formation workflow via ERPNext.

Sales Agent Commission System

Sales agents refer clients using a unique referral code (format: REF-XXXXX).

How It Works

  1. Agent shares their referral link: performancewest.net/form?ref=REF-XXXXX
  2. Client receives a 5% discount on service fees
  3. Agent earns a flat commission per service (not percentage-based)

Commission Schedule

Service Agent Commission
Canada CRTC Package $300
Basic Formation $50
Bundle Purchase $100

Commissions are tracked in ERPNext Commission Ledger DocType (with PostgreSQL backup in commission_ledger). Paid 14 days after order delivery via Relay ACH.

Discount Code System

Discount codes can be created in ERPNext and applied at checkout:

  • Percentage-based (e.g., 10% off)
  • Fixed amount (e.g., $25 off)
  • Usage limits (single-use, multi-use, or unlimited)
  • Expiration dates
  • Discount codes stack with agent referral discounts (capped at 15% total)
  • Discounts apply to service fees only — never to state filing fees, government fees, or expedited fees

Employment Pages

Employment/careers pages exist in the codebase but are hidden in production (not linked from navigation, not indexed by search engines). Gated behind import.meta.env.DEV flag. Reserved for future use.