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>
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-crtcfor BC-specific orders - Separate DB table:
canada_crtc_orderstracks 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:
- Visit the state's name search URL in a browser
- Inspect form elements — record CSS selectors for input fields, buttons, result areas
- Update
config.pywith verified selectors - Test name search with known entities
- Visit the filing URL and walk through the LLC formation form
- Record all filing form selectors — name, agent, address, member, payment fields
- Implement the
file_llc()method with the state-specific workflow - Test with a real formation (or test/sandbox environment if available)
- 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):
- ERPNext webhook fires on
order.createdorpayment.confirmed - Worker loads the appropriate state adapter
- Verifies name availability
- Submits the filing via Playwright
- Updates DB with filing number and status
- Generates operating agreement (if ordered)
- Obtains EIN (if ordered)
- 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.pypollsto-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_objectrename - 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
- Agent shares their referral link:
performancewest.net/form?ref=REF-XXXXX - Client receives a 5% discount on service fees
- 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.