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>
378 lines
23 KiB
Markdown
378 lines
23 KiB
Markdown
# System Architecture
|
|
|
|
**Last updated:** 2026-04-17 (15 Docker containers + k3s SHKeeper pods + Windows DocServer VM + dev stack + crypto treasury + foreign qualification + compliance check tool)
|
|
|
|
## Overview
|
|
|
|
Performance West runs as a multi-service stack on a Debian 13 VM (207.174.124.71):
|
|
|
|
- **Astro static site** — marketing pages, service descriptions, CRTC order form, crypto payment page
|
|
- **Express API** — order creation, Stripe/PayPal/SHKeeper checkout, identity verification, webhook receiver, portal setup API
|
|
- **ERPNext** — CRM, orders, invoicing, ticketing, customer portal (v15 + MariaDB, custom image with 4 Frappe apps). Portal at `portal.performancewest.net`
|
|
- **Listmonk** — email marketing at `lists.performancewest.net` (Go binary, PostgreSQL-backed). 22 campaigns across 4 lists. Bounce processing via POP3 from Carbonio.
|
|
- **MinIO** — S3-compatible document storage (formation docs, compliance reports, binder PDFs)
|
|
- **Ollama** — local LLM for document generation and email drafting (qwen2.5:7b)
|
|
- **Workers** — Python automation: Anytime Mailbox signup (Playwright + IMAP OTP), BC incorporation, Flowroute DID provisioning, document generation, AMB location scraping, payment reminders, GCKey provisioning (Playwright), compliance calendar renewal lifecycle, client email processing
|
|
- **SHKeeper** — self-hosted crypto payment processor via k3s (BTC, LTC, DOGE, ETH, BNB, MATIC, TRX). TRX uses nginx proxy at :5555 → TronGrid with API key injection. ETH uses proxy at :5556 → publicnode.
|
|
- **Crypto Treasury** — post-payment pipeline: SHKeeper → Bridge (Stripe) offramp → RelayFi bank → Relay debit card → vendor payments. Manual mode until Bridge approval.
|
|
- **Umami** — self-hosted web analytics at `analytics.performancewest.net`
|
|
- **PostgreSQL** — API state, orders, identity verifications, AMB locations, sessions, jurisdictions, foreign qualifications, crypto ledger (api-postgres; also hosts Listmonk DB). 67 migrations applied.
|
|
- **Dev stack** — separate environment at `dev.performancewest.net` / `api.dev.performancewest.net` (port 4323/3002, own PG on 5433). Systemd unit: `performancewest-dev.service`.
|
|
|
|
## Payment Gateway Architecture
|
|
|
|
**Active gateways:** Stripe (card/ACH/Klarna), PayPal Direct (Orders API v2), SHKeeper (crypto).
|
|
|
|
| Gateway | Status | Methods | Surcharge |
|
|
|---------|--------|---------|-----------|
|
|
| Stripe | **Active** | Card (+3%), ACH (0%), Klarna (+6%) | Via Stripe Checkout Sessions |
|
|
| PayPal | **Active** | PayPal Direct (+3%) | Orders API v2 with capture/tracking/refund |
|
|
| SHKeeper | **Active** | Crypto (0%) — BTC/LTC/DOGE + EVM chains | Branded `/order/crypto-pay` page with coin selector |
|
|
| Adyen | Future | Card/ACH/Klarna/CashApp/AmazonPay (frappe_adyen installed, not configured) |
|
|
|
|
**Payment card routing for vendor expenses:**
|
|
|
|
| Customer paid with | Filing card | ERPNext SID | Funds timing |
|
|
|---|---|---|---|
|
|
| Card/ACH/Klarna | Stripe Issuing virtual card | SID-0002 | T+2 card, T+4 ACH |
|
|
| PayPal | PayPal Mastercard | SID-0001 | Instant |
|
|
| Crypto | crypto-filing-card | crypto-filing-card | Manual |
|
|
|
|
**Fund availability detection:** Stripe `balance.available` webhook checks settlement timing (T+2 card/Klarna, T+4 ACH). PayPal is instant. Crypto is manual. When funds clear: Stripe Issuing topup → advance to "Client Selection" → email client portal setup link.
|
|
|
|
ERPNext custom Frappe apps (baked into `performancewest-erpnext:latest`):
|
|
|
|
| App | Purpose |
|
|
|-----|---------|
|
|
| `frappe_crypto` | SHKeeper crypto gateway |
|
|
| `frappe_adyen` | Adyen gateway (future) |
|
|
| `frappe_ca_registry` | BC Corporate Online incorporation automation |
|
|
| `performancewest_erpnext` | Surcharge hooks, identity gate, custom DocTypes |
|
|
|
|
## Service Architecture
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ Proxmox Host │
|
|
│ │
|
|
│ ┌── Linux VM (Debian 13) — 207.174.124.71 ───────────────┐ │
|
|
│ │ │ │
|
|
│ │ Docker Compose (15 containers) │ │
|
|
│ │ ├── site (Astro → nginx:alpine) :4322 │ │
|
|
│ │ ├── api (Express/TypeScript) :3001 │ │
|
|
│ │ ├── api-postgres (app data) :5432 │ │
|
|
│ │ ├── erpnext (custom image + 4 apps) :8080 │ │
|
|
│ │ ├── erpnext-worker-default │ │
|
|
│ │ ├── erpnext-worker-short │ │
|
|
│ │ ├── erpnext-scheduler │ │
|
|
│ │ ├── erpnext-mariadb :3306 │ │
|
|
│ │ ├── erpnext-redis :6379 │ │
|
|
│ │ ├── listmonk (email marketing) :9100 │ │
|
|
│ │ ├── minio (document storage) :9000/:9001 │ │
|
|
│ │ ├── workers (Python automation) :8090 │ │
|
|
│ │ ├── ollama (local LLM) :11434 │ │
|
|
│ │ ├── umami (analytics) :3100 │ │
|
|
│ │ └── umami-postgres │ │
|
|
│ │ │ │
|
|
│ │ Dev Stack (docker compose at /opt/performancewest-dev) │ │
|
|
│ │ ├── dev-site (Astro → nginx:alpine) :4323 │ │
|
|
│ │ ├── dev-api (Express/TypeScript) :3002 │ │
|
|
│ │ ├── dev-api-postgres :5433 │ │
|
|
│ │ └── dev-workers (Python automation) │ │
|
|
│ │ │ │
|
|
│ │ k3s / Kubernetes (SHKeeper crypto payments) │ │
|
|
│ │ ├── shkeeper-deployment (Flask API) NodePort :30723 │ │
|
|
│ │ ├── bitcoin-shkeeper (3 containers) │ │
|
|
│ │ ├── ethereum-shkeeper (3 containers) via :5556 proxy │ │
|
|
│ │ ├── polygon-shkeeper (3 containers) │ │
|
|
│ │ ├── bnb-shkeeper (3 containers) │ │
|
|
│ │ ├── tron-shkeeper (3 containers) via :5555 proxy │ │
|
|
│ │ ├── litecoin-shkeeper (3 containers) │ │
|
|
│ │ ├── dogecoin-shkeeper (3 containers) │ │
|
|
│ │ └── mariadb (SHKeeper database) │ │
|
|
│ │ │ │
|
|
│ │ nginx RPC Proxies (inject API keys, strip basic auth) │ │
|
|
│ │ ├── :5555 → api.trongrid.io + TRON-PRO-API-KEY │ │
|
|
│ │ └── :5556 → ethereum-rpc.publicnode.com │ │
|
|
│ └──────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌── Windows VM (DocServer) — 108.181.102.34 ─────────────┐ │
|
|
│ │ SSH: port 22422 (key auth) │ │
|
|
│ │ Office 365 Word (COM automation) │ │
|
|
│ │ Python 3.13 + pywin32 + minio SDK │ │
|
|
│ │ docserver_worker.py (MinIO poller, 12s interval) │ │
|
|
│ │ Task Scheduler: PW-DocserverWorker (AtLogOn) │ │
|
|
│ │ Auto-logon configured (requires RDP after cold reboot) │ │
|
|
│ │ Private network: 10.4.20.247 → MinIO via nginx │ │
|
|
│ └──────────────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## DNS
|
|
|
|
| Domain | Target |
|
|
|--------|--------|
|
|
| `performancewest.net` | site (:4322) |
|
|
| `api.performancewest.net` | api (:3001) |
|
|
| `crm.performancewest.net` | ERPNext (:8080) |
|
|
| `lists.performancewest.net` | Listmonk (:9100) — email marketing |
|
|
| `portal.performancewest.net` | ERPNext (:8080) — client portal |
|
|
| `analytics.performancewest.net` | Umami (:3100) |
|
|
| `pay.performancewest.net` | SHKeeper API (:5000 via k3s NodePort :30723) |
|
|
| `crypto.performancewest.net` | SHKeeper admin UI (:30723 via nginx) |
|
|
| `dev.performancewest.net` | Dev site (:4323) |
|
|
| `api.dev.performancewest.net` | Dev API (:3002) |
|
|
| `minio.performancewest.net` | MinIO S3 API (:9000) |
|
|
| `minio-console.performancewest.net` | MinIO Console (:9001) |
|
|
|
|
All A records point to `207.174.124.71`. TLS via Let's Encrypt (certbot, 8 certs). Mail records unchanged (HestiaCP at `207.174.124.15`).
|
|
|
|
**External panels:**
|
|
|
|
| Domain | Service |
|
|
|--------|---------|
|
|
| `cp.carrierone.com` | HestiaCP — DNS, .ca domain/email provisioning |
|
|
|
|
## Data Flow
|
|
|
|
```
|
|
Browser
|
|
│
|
|
├── performancewest.net ──────> nginx ──> site (static pages)
|
|
│
|
|
├── api.performancewest.net ──> nginx ──> Express API
|
|
│ ├── api-postgres (state fees, API keys)
|
|
│ ├── ERPNext REST API (CRM, orders, tickets)
|
|
│ ├── Listmonk API (email marketing)
|
|
│ └── Workers HTTP API (job dispatch)
|
|
│
|
|
├── crm.performancewest.net ──> nginx ──> ERPNext
|
|
│ ├── erpnext-mariadb
|
|
│ └── erpnext-redis
|
|
│
|
|
├── pay.performancewest.net ──> nginx ──> SHKeeper (k3s :5000)
|
|
│
|
|
├── lists.performancewest.net ──> nginx ──> Listmonk (:9100)
|
|
│
|
|
├── portal.performancewest.net ──> nginx ──> ERPNext (:8080)
|
|
│
|
|
├── minio.performancewest.net ──> nginx ──> MinIO S3 (:9000)
|
|
└── minio-console.performancewest.net ──> nginx ──> MinIO Console (:9001)
|
|
```
|
|
|
|
## Order Flow (ERPNext BPM)
|
|
|
|
```
|
|
Customer places order → Express API → ERPNext Sales Invoice + Payment Request
|
|
→ ERPNext payment gateway (Adyen or SHKeeper) → Customer pays
|
|
→ ERPNext webhook → Express API → Workers job server
|
|
→ Workers execute: name search → filing → EIN → doc gen
|
|
→ Documents uploaded to MinIO
|
|
→ ERPNext status → Review → Admin approves → Delivered
|
|
```
|
|
|
|
## Key Integration Points
|
|
|
|
| From | To | Method | Purpose |
|
|
|------|----|--------|---------|
|
|
| Website | Express API | HTTPS | Forms, orders, name search |
|
|
| Express API | ERPNext | REST API | CRM, orders, invoicing, tickets |
|
|
| Express API | Workers | HTTP :8090 | Job dispatch (via webhooks) |
|
|
| Express API | Listmonk | REST API | Subscriber onboarding, email campaigns |
|
|
| ERPNext | Express API | Webhooks | Workflow state change notifications |
|
|
| ERPNext | Adyen | Sessions API v71 | Card/ACH/Klarna/CashApp/AmazonPay (via frappe_adyen) |
|
|
| ERPNext | SHKeeper | REST API :5000 | Crypto payment requests (via frappe_crypto) |
|
|
| Workers | ERPNext | REST API | Status updates, workflow advances |
|
|
| Workers | MinIO | S3 API | Document upload/download |
|
|
| Workers | Ollama | HTTP :11434 | LLM doc generation, email drafting |
|
|
| Workers | DocServer | MinIO transport | DOCX-to-PDF conversion (MinIO poller: to-convert/ → converted/) |
|
|
| Workers | State portals | Playwright | Name search, entity filing |
|
|
| Workers | IRS | Playwright | EIN obtainment |
|
|
| ERPNext | Email | SMTP | Invoices, notifications, ticket replies |
|
|
| Relay debit card | State portals | Playwright | Filing fee payment |
|
|
| Workers | HestiaCP | SSH | .ca domain/email provisioning (cp.carrierone.com) |
|
|
| Workers | Flowroute | REST API | Canadian DID provisioning |
|
|
| Workers | Porkbun | REST API | .ca domain registration |
|
|
| Workers | Client mailboxes | IMAP | Monitor/process client .ca email |
|
|
| Website | Anytime Mailbox | External | Vancouver mailbox for Canadian carrier clients |
|
|
| ERPNext | Venn.ca | Referral | Canadian business banking referral |
|
|
| AI Agents | MCP Server | stdio | Service lookup, pricing, tools (npm package) |
|
|
|
|
## Worker Processes (Python)
|
|
|
|
The `workers` container runs a job server (`job_server.py` on port 8090) that dispatches jobs
|
|
to specialized worker modules. Jobs are triggered by ERPNext webhooks via the Express API.
|
|
|
|
| Worker | File | Trigger | Purpose |
|
|
|--------|------|---------|---------|
|
|
| Job Server | `job_server.py` | HTTP POST :8090 | Central dispatcher — 22 job handlers |
|
|
| CRTC Pipeline | `services/canada_crtc.py` | Webhook | 14-step CRTC carrier registration pipeline |
|
|
| GCKey Provisioner | `gckey_provisioner.py` | Called by CRTC Step 11 | Playwright-based GCKey account creation (5-step wizard, hCaptcha) |
|
|
| Renewal Worker | `renewal_worker.py` | Daily cron (7 AM) | Compliance calendar lifecycle: upcoming → due soon → invoice → paid → completed → re-calendar |
|
|
| Formation Worker | `formation_worker.py` | Webhook | US state LLC/Corp filing via Playwright |
|
|
| Binder Compiler | `binder_compiler.py` | Called by pipeline | PDF merge: certificate + articles + CRTC letter + OA |
|
|
| Document Gen | `document_gen/` | Called by pipeline | DOCX template fill → MinIO → DocServer PDF conversion |
|
|
| HestiaCP Provisioner | `hestia_provisioner.py` | Called by pipeline | .ca domain + 14 mailboxes via SSH to cp.carrierone.com |
|
|
| Client Email Processor | `client_email_processor.py` | Cron (15 min) | IMAP monitor for client .ca mailboxes |
|
|
| AMB Scraper | `amb_location_scraper.py` | Daily cron | Anytime Mailbox location pricing + sold-out detection |
|
|
| Payment Reminder | `payment_reminder.py` | Cron (5 min) | Abandoned cart recovery (15min/1d/2d intervals) |
|
|
| Commission Worker | `commission_worker.py` | Cron (daily 02:00) | Agent commission eligibility check (14-day holdback) |
|
|
| Crypto Payment Worker | `crypto_payment_worker.py` | Cron (60s) | Treasury state machine: received → sizing → offramping → funds_at_relay → settled |
|
|
| Cold Wallet Sweeper | `cold_wallet_sweeper.py` | Cron (30 min) | Sweep SHKeeper hot wallet excess to cold storage |
|
|
| Relay Deposit Monitor | `relay_deposit_monitor.py` | Cron (5 min) | IMAP parser for Relay bank deposit alerts |
|
|
| USF Factor Monitor | `usf_factor_monitor.py` | Cron (daily 09:00 CT) | Scrape USAC quarterly USF factor, email all FCC carriers |
|
|
| De Minimis Check | `deminimis_factor_check.py` | Cron (daily 03:00) | Alert if fcc_deminimis_factors missing for current/next year |
|
|
| CDR Retention Sweeper | `cdr_retention_sweeper.py` | Cron (daily 05:00) | Purge CDR data past retention window |
|
|
| CDR Unlock Nudge | `cdr_unlock_nudge.py` | Cron (daily 10:00 CT) | Email customers with locked CDR studies behind paywall |
|
|
| FCC RMD Scraper | `fcc_rmd_removed_scraper.py` | Cron (weekly Wed) | Track FCC RMD carrier removals |
|
|
| Foreign Qual Handler | `services/foreign_qualification.py` | Webhook | Multi-state Certificate of Authority filings |
|
|
| New Carrier Bundle | `services/new_carrier_bundle.py` | Webhook | 6-handler chain: CORES → DC Agent → 499 Init → RMD → CPNI → CALEA |
|
|
|
|
### CRTC Pipeline Steps (14 total)
|
|
|
|
| Step | Name | Key Actions |
|
|
|------|------|-------------|
|
|
| 1 | Order Received | Validate, create ERPNext Sales Order |
|
|
| 2 | Payment Confirmed | Create Sales Invoice + Payment Entry |
|
|
| 3 | Client Selection | Client picks mailbox unit, DID, domain |
|
|
| 4 | BC Incorporation | Playwright → BC Corporate Online |
|
|
| 5 | Domain Registration | Porkbun .ca + HestiaCP provisioning |
|
|
| 6a | CRTC Letter Generation | DOCX template → MinIO → DocServer PDF |
|
|
| 6b | eSign | Email JWT link → client signs → resume pipeline |
|
|
| 7 | CRTC Submission | Mail signed letter to Secretary General |
|
|
| 8 | Anytime Mailbox | Playwright signup + IMAP OTP |
|
|
| 9 | Binder Compilation | PDF merge of all documents |
|
|
| 10 | Delivery | Email binder + admin print/ship email |
|
|
| 11 | BITS Registration | GCKey provisioning + admin ToDo for BITS filing |
|
|
| 12 | CCTS Membership | Admin ToDo + client obligations email |
|
|
| 13 | Compliance Calendar | Create 17 compliance entries (regulatory + tax + ATS) |
|
|
| 14 | Ready for Review | Final admin review before marking Delivered |
|
|
|
|
### Compliance Calendar Renewal Lifecycle
|
|
|
|
The `renewal_worker.py` runs daily at 7 AM and manages the full lifecycle of recurring
|
|
compliance obligations for all carriers:
|
|
|
|
```
|
|
Upcoming → Due Soon (30 days out) → Invoice Sent → Paid → Completed → auto-re-calendar next year
|
|
```
|
|
|
|
- **17 entries per carrier:** BC annual report, CRTC annual maintenance, mailbox renewal,
|
|
domain renewal, DID renewal, CCTS renewal, T2 tax return, corporate tax payment,
|
|
GST/HST return, T4/T4A slips, BC PST, WorkSafeBC, CRTC registration update,
|
|
plus ATS survey forms (REP-T/T1 mandatory for all carriers)
|
|
- **Billable items** generate ERPNext Sales Invoice; entry cannot be completed until paid
|
|
- **On payment:** entry marked Completed, admin ToDo created, next-year entry auto-created
|
|
- **Webhook-triggered:** `handle_renewal_payment` in job_server for immediate processing
|
|
|
|
### DocServer (Windows VM)
|
|
|
|
MinIO-based transport — no direct HTTP connection between Linux and Windows VMs.
|
|
|
|
```
|
|
Workers: upload DOCX to minio://performancewest/to-convert/{uuid}.docx
|
|
→ DocServer polls to-convert/ bucket every 12 seconds
|
|
→ Word COM converts DOCX → PDF
|
|
→ DocServer uploads PDF to minio://performancewest/converted/{uuid}.pdf
|
|
→ Workers poll converted/ bucket for result
|
|
```
|
|
|
|
- **Heartbeat:** DocServer writes `docserver-heartbeat.json` to MinIO every 60 seconds
|
|
- **Fallback:** If heartbeat is stale (>5 min), workers auto-switch to LibreOffice headless
|
|
|
|
## Boot Sequence
|
|
|
|
All services auto-start on reboot via systemd:
|
|
|
|
| Unit | What it starts | Depends on |
|
|
|------|----------------|------------|
|
|
| `docker.service` | Docker daemon | network |
|
|
| `k3s.service` | k3s + all SHKeeper pods | docker |
|
|
| `nginx.service` | Reverse proxy + TLS + RPC proxies (:5555/:5556) | network |
|
|
| `performancewest.service` | Prod docker compose (15 containers) | docker |
|
|
| `performancewest-dev.service` | Dev docker compose (4 containers) | docker, performancewest |
|
|
|
|
All containers use `restart: unless-stopped`. k3s manages pod restarts via deployment specs. The nginx RPC proxy configs for TronGrid (:5555) and ETH (:5556) are in `/etc/nginx/conf.d/` and load automatically. UFW rules for ports 5555/5556 are persistent (allow from 10.42.0.0/16 only).
|
|
|
|
## Scheduled Workers (systemd timers)
|
|
|
|
Deployed via `infra/ansible/roles/worker-crons/`. Each timer runs `docker compose exec -T workers python -m <module>`.
|
|
|
|
| Timer | Cadence | Module |
|
|
|---|---|---|
|
|
| `pw-usf-factor-monitor` | daily 09:00 CT | `scripts.workers.usf_factor_monitor` |
|
|
| `pw-deminimis-factor-check` | daily 03:00 UTC | `scripts.workers.deminimis_factor_check` |
|
|
| `pw-cold-wallet-sweep` | every 30 min | `scripts.workers.cold_wallet_sweeper` |
|
|
| `pw-crypto-payment-worker` | every 60s | `scripts.workers.crypto_payment_worker` |
|
|
| `pw-relay-deposit-monitor` | every 5 min | `scripts.workers.relay_deposit_monitor` |
|
|
| `pw-commission-worker` | daily 02:00 UTC | `scripts.workers.commission_worker` |
|
|
| `pw-renewal-worker` | daily 04:00 UTC | `scripts.workers.renewal_worker` |
|
|
| `pw-cdr-retention` | daily 05:00 UTC | `scripts.workers.cdr_retention_sweeper` |
|
|
| `pw-cdr-unlock-nudge` | daily 10:00 CT | `scripts.workers.cdr_unlock_nudge` |
|
|
| `pw-payment-reminder` | daily 11:00 CT | `scripts.workers.payment_reminder` |
|
|
| `pw-fcc-rmd-removed` | weekly Wed 08:00 CT | `scripts.workers.fcc_rmd_removed_scraper` |
|
|
| `pw-client-email-processor` | every 15 min | `scripts.workers.client_email_processor` |
|
|
| `pw-amb-location-scraper` | daily 06:00 UTC | `scripts.workers.amb_location_scraper` |
|
|
|
|
## Database Schema (67 migrations)
|
|
|
|
Key tables added in this cycle:
|
|
|
|
| Table | Migration | Purpose |
|
|
|---|---|---|
|
|
| `jurisdictions` | 066 | Unified US states + CA provinces (55 rows) |
|
|
| `foreign_qualification_registrations` | 066 | Per-state COA filings |
|
|
| `state_compliance_obligations` | 067 | Annual report fees/dates for all 51 US jurisdictions |
|
|
| `crypto_payment_ledger` | 062 | Immutable append-only money movement ledger |
|
|
| `crypto_payment_jobs` | 065 | Treasury state machine (received → settled) |
|
|
| `vendor_obligations` | 063 | Sizer: filing fees + commission reserves |
|
|
| `cold_wallet_config` / `cold_wallet_sweeps` | 064 | Cold wallet management |
|
|
|
|
## FCC Compliance Check Tool
|
|
|
|
Public at `/tools/fcc-compliance-check`. Queries FRN against CORES, RMD, 499 Filer DB, and CPNI records. Displays:
|
|
- CORES registration status (red-light check)
|
|
- RMD filing + certification date
|
|
- STIR/SHAKEN implementation (self-reported from RMD, hidden until STI-PA API access)
|
|
- CPNI annual certification (past-due detection with correct deadline logic)
|
|
- Form 499-A annual filing (CY-year-aware)
|
|
- Form 499-Q quarterly (de minimis trade-off explanation)
|
|
- BDC broadband/voice interactive toggle (two-step questionnaire)
|
|
|
|
Remediation CTA links to `/order/fcc-compliance?services=cpni,499a,...` for bundled ordering with 15% discount.
|
|
|
|
## Compliance Service Catalog (34 handlers)
|
|
|
|
| Slug | Handler | Price |
|
|
|---|---|---|
|
|
| `new-carrier-bundle` | NewCarrierBundleHandler (6 sub-handlers) | $1,799 |
|
|
| `fcc-full-compliance` | FullComplianceHandler | $1,499 |
|
|
| `fcc-499a` | Form499AHandler | $499 |
|
|
| `fcc-499a-499q` | Form499ABundleHandler | $599 |
|
|
| `cpni-certification` | CPNIFilingHandler (9 category variants) | $149 |
|
|
| `rmd-filing` | RMDFilingHandler | $219 |
|
|
| `calea-ssi` | CALEASSIHandler (6 category variants) | $299 |
|
|
| `bdc-filing` / `bdc-broadband` / `bdc-voice` | BDCFilingHandler | $299/$199/$149 |
|
|
| `foreign-qualification-single` | ForeignQualificationHandler | $149 + state fees |
|
|
| `foreign-qualification-multi` | ForeignQualificationHandler | $99/state + fees |
|
|
| `dc-agent` | DCAgentHandler (NWRA wholesale) | $99/yr |
|
|
| `cores-frn-registration` | CORESFRNRegistrationHandler | $99 |
|
|
| `fcc-499-initial` | Form499InitialHandler | $299 |
|
|
| `ocn-registration` | OCNRegistrationHandler | $799 |
|
|
|
|
## State Formation Adapters
|
|
|
|
10 states with real adapters (name search via Playwright + portal config):
|
|
WY (237 lines), CO (177), DE (119), FL (118), TX (SOSDirect), NV (SilverFlume), UT (DCC), NM, OH, MT.
|
|
~40 remaining states have stub adapters that create admin todos for manual filing.
|
|
|
|
JurisdictionConfig abstraction at `scripts/formation/jurisdictions/` reads from the `jurisdictions` DB table (migration 066) and provides per-state fees, portal URLs, NWRA addresses, and entity type catalogs.
|
|
|
|
## Deployment
|
|
|
|
**Production:** `ansible-playbook infra/ansible/playbooks/deploy.yml -i infra/ansible/inventory/hosts.yml`
|
|
|
|
**Dev:** `bash scripts/deploy-dev.sh` — rsyncs source files + rebuilds Docker containers. Static pages (tools, services, homepage) are in `site/public/` and survive Astro rebuilds.
|
|
|
|
**nginx cache policy:** `_astro/` = immutable (1 year). HTML = no-cache. Images = 30 days.
|
|
- **Atomic uploads:** `.tmp_` prefix + `copy_object` rename prevents partial reads
|