# Gigafibre FSM — Documentation > **Start here.** Pick a row by intent, jump to the module index when you > need scope, or go straight to the cross-module map when you're chasing a > call that hops surfaces. **Last refreshed:** 2026-04-22 (expanded module index, added dispatch / customer portal / tech mobile docs, cross-interaction matrix) --- ## 1. Quick nav by intent | I want to… | Open | |---|---| | **See the plan** — what's shipped, what's queued, with clickable links to every live module | [roadmap.md](roadmap.md) | | **Understand the system end-to-end** — services, containers, networks, SSO, Traefik routes | [architecture/overview.md](architecture/overview.md) | | **See who calls who** — one-page matrix of every module → module interaction | [architecture/module-interactions.md](architecture/module-interactions.md) | | **Build a new feature** — UI patterns, folder layout, router conventions, Pinia, feature-sliced design | [architecture/app-design.md](architecture/app-design.md) | | **Touch ERPNext data** — doctypes, customer → subscription → equipment → invoice, "Lead to Live" flow | [architecture/data-model.md](architecture/data-model.md) | | **Work on dispatch** — drag-and-drop scheduling, tech assignment, travel-time optimization, magic-link SMS | [features/dispatch.md](features/dispatch.md) | | **Work on the tech mobile app** — scan-to-identify, equipment install, job status, JWT auth | [features/tech-mobile.md](features/tech-mobile.md) | | **Work on the customer portal** — passwordless magic-link, invoice + ticket self-service | [features/customer-portal.md](features/customer-portal.md) | | **Work on billing, Stripe, payments** — subscription lifecycle, invoice OCR, payment reconciliation, PPA | [features/billing-payments.md](features/billing-payments.md) | | **Touch CPE / modems / ONTs** — GenieACS, Oktopus, TR-069 → TR-369 migration, TP-Link XX230v diagnostics | [features/cpe-management.md](features/cpe-management.md) | | **Build or debug the scanner / OCR** — Gemini vision pipeline, barcode/equipment/invoice endpoints, offline queue, AI_API_KEY rotation | [features/vision-ocr.md](features/vision-ocr.md) | | **Work on agent flows / automation** — Flow Template model, trigger wiring, step editor, runtime contract | [features/flow-editor.md](features/flow-editor.md) | | **Audit the wizard's SKU mapping vs legacy** | [reference/erpnext-item-diff.md](reference/erpnext-item-diff.md) | | **Inspect the legacy PHP wizard** | [reference/legacy-wizard/](reference/legacy-wizard/) | | **Read a historical status snapshot** | [archive/status-snapshots/](archive/status-snapshots/) | --- ## 2. Module index Every deployed surface, by app. Each row links to its primary doc and names the exact code paths so you can `grep` from here. ### 2a. Ops SPA (`apps/ops/`) — `https://erp.gigafibre.ca/ops/` **Single pane of glass for internal teams.** Quasar PWA (SPA mode in dev, PWA mode in prod), Vue 3 + Pinia, hash router. Wrapped by Authentik via Traefik `forwardAuth` on `/ops/*`. Bottom of the same app hosts the tech mobile module on `/j/*` with magic-link auth. | Module | URL | Purpose | Primary doc | Primary code | |---|---|---|---|---| | **Dashboard** | `/ops/#/` | KPIs (MRR, AR, active tickets), dispatch summary, live SSE feed | — | `src/pages/DashboardPage.vue` | | **Clients** | `/ops/#/clients` · `/clients/:id` | Customer 360: profile, subscriptions, invoices, equipment, tickets, communication timeline | — | `src/pages/ClientsPage.vue` · `ClientDetailPage.vue` · `src/modules/clients/` | | **Dispatch** | `/ops/#/dispatch` | Drag-and-drop tech schedule, job board, travel-time optimization, SMS magic-link issuance | [features/dispatch.md](features/dispatch.md) | `src/pages/DispatchPage.vue` · `src/modules/dispatch/` | | **Tickets** | `/ops/#/tickets` | Support ticket board, SLA clock, linked equipment + jobs | — | `src/pages/TicketsPage.vue` · `src/modules/tickets/` | | **Équipe** | `/ops/#/equipe` | Technician roster, skills/tags, availability, today's jobs | [features/dispatch.md §6](features/dispatch.md) | `src/pages/EquipePage.vue` · `src/modules/equipe/` | | **Rapports** | `/ops/#/rapports` + `/revenus` · `/ventes` · `/taxes` · `/ar` | Revenue, sales, tax, AR reports (renders in-browser; PDF export via hub) | [features/billing-payments.md §9](features/billing-payments.md) | `src/pages/Rapports*.vue` · `src/modules/rapports/` | | **OCR** | `/ops/#/ocr` | Upload scanned supplier bills → Gemini parse → pre-fill Purchase Invoice | [features/vision-ocr.md §4](features/vision-ocr.md) | `src/pages/OcrPage.vue` | | **Settings** | `/ops/#/settings` | Feature flags, integration keys, user management (mirror of ERPNext) | — | `src/pages/SettingsPage.vue` | | **Telephony** | `/ops/#/telephony` | SIP click-to-dial (Twilio Voice SDK + sip.js fallback), call history | [architecture/overview.md §3](architecture/overview.md) | `src/pages/TelephonyPage.vue` | | **Agent Flows** | `/ops/#/agent-flows` | Visual editor for Flow Template (automation runtime) | [features/flow-editor.md](features/flow-editor.md) | `src/pages/AgentFlowsPage.vue` | | **Network** | `/ops/#/network` | Cytoscape-rendered OLT/ONT topology, live link status from GenieACS | [features/cpe-management.md](features/cpe-management.md) | `src/pages/NetworkPage.vue` | ### 2b. Ops tech module (`apps/ops/src/modules/tech/`) — `https://erp.gigafibre.ca/ops/#/j/*` **Same SPA, different mount.** Techs hit a magic-link SMS, land on `/j/:token`, the token redirects to `/j` with JWT in localStorage. Mobile-first layout with bottom tab bar. | Route | Purpose | Primary doc | Primary code | |---|---|---|---| | `/j` | Today's jobs, grouped by status | [features/tech-mobile.md §4a](features/tech-mobile.md) | `TechTasksPage.vue` | | `/j/job/:name` | Job detail + equipment management (Ajouter/Scanner/Rechercher/Créer) | [features/tech-mobile.md §5](features/tech-mobile.md) | `TechJobDetailPage.vue` | | `/j/scan` | Standalone scanner (native camera → Gemini) | [features/tech-mobile.md §3](features/tech-mobile.md) | `TechScanPage.vue` | | `/j/device/:serial` | Per-device detail, diagnostic shortcut | — | `TechDevicePage.vue` | | `/j/diagnostic` | In-browser speed test + GenieACS probe | [features/cpe-management.md](features/cpe-management.md) | `TechDiagnosticPage.vue` | | `/j/more` | Settings, token expiry, logout | — | `TechMorePage.vue` | | `/j/:token` | Magic-link handler (last route, accepts any JWT) | [features/tech-mobile.md §2](features/tech-mobile.md) | `TechTasksPage.vue` (same component, different entry) | ### 2c. Field PWA (`apps/field/`) — `https://erp.gigafibre.ca/field/` **Transitional standalone PWA, retiring.** Authentik-protected; byte-for-byte closer to the legacy workflow techs had before the Ops tech module existed. No magic-link — tech logs in via Authentik. Kept alive while the SMS link still points at the hub SSR page (see tech-mobile doc §1). Same page set as §2b (TasksPage, ScanPage, JobDetailPage, DevicePage, DiagnosticPage, MorePage), same Gemini-native scanner composable. `apps/field/src/pages/JobDetailPage.vue` is the reference implementation we port *from* when the Ops tech module drifts. ### 2d. Customer portal (`apps/client/`) — `https://portal.gigafibre.ca/` **Passwordless self-service.** Standalone Quasar PWA served by a dedicated nginx container (`client-portal`) bind-mounted from `/opt/client-app/` on the Proxmox VM. No Authentik — customers get a magic-link email (HS256 JWT, 24h TTL). | Module | URL | Purpose | Primary doc | Primary code | |---|---|---|---|---| | **Login** | `/#/login` | Email entry → magic-link email send | [features/customer-portal.md §3](features/customer-portal.md) | `src/pages/LoginPage.vue` | | **Dashboard** | `/#/` | Balance, next invoice, active tickets, recent activity | [features/customer-portal.md §4a](features/customer-portal.md) | `DashboardPage.vue` | | **Account** | `/#/account` | Profile, saved payment methods (Stripe PM), address book | [features/billing-payments.md §6](features/billing-payments.md) | `AccountPage.vue` | | **Catalog / Cart** | `/#/catalog` · `/#/cart` | Shop add-ons (extra mesh, static IP), add to Stripe Checkout | [features/billing-payments.md](features/billing-payments.md) | `CatalogPage.vue` · `CartPage.vue` | | **Invoices** | `/#/invoices` · `/#/invoices/:name` | List + PDF of all Sales Invoices, Stripe-linked pay button | [features/billing-payments.md §8](features/billing-payments.md) | `InvoicesPage.vue` · `InvoiceDetailPage.vue` | | **Tickets** | `/#/tickets` · `/#/tickets/:name` | Create support ticket, reply thread, attach photos | — | `TicketsPage.vue` · `TicketDetailPage.vue` | | **Messages** | `/#/messages` | Unified comm thread (SMS + email) with support | — | `MessagesPage.vue` | | **Payment flows** | `/#/payment-success` · `/payment-cancel` · `/payment-card-added` · `/order-success` | Stripe return URL landings | [features/billing-payments.md §7](features/billing-payments.md) | `Payment*.vue` · `OrderSuccessPage.vue` | ### 2e. Legacy portal (`apps/portal/`) — **retired 2026-04-22** Old ERPNext-embedded customer portal. Host `client.gigafibre.ca` now 307s to `portal.gigafibre.ca/*` via Traefik; see `apps/portal/traefik-client-portal.yml`. Codebase retained as historical reference only. Do not build. ### 2f. Marketing site (`apps/website/`) — `https://www.gigafibre.ca/` React + Vite marketing site. Self-contained, no ERPNext dependency, no docs beyond its own README. --- ## 3. Services (backends) Everything in `services/*` is backend infrastructure. Usually you don't edit these unless you're adding a new endpoint. | Service | Port | Role | Primary docs | |---|---|---|---| | `services/targo-hub/` | `msg.gigafibre.ca:3300` | **API gateway.** Vision (Gemini), magic-link JWT, Twilio SMS, SSE fanout, Stripe webhooks, ACS proxy, Legacy-DB read proxy, tech-mobile SSR | [overview.md §3](architecture/overview.md) · [vision-ocr.md](features/vision-ocr.md) · [customer-portal.md](features/customer-portal.md) · [tech-mobile.md](features/tech-mobile.md) · [billing-payments.md](features/billing-payments.md) | | `services/modem-bridge/` | `:3301` (internal) | Playwright + Chromium wrapper that logs into TP-Link XX230v modems and reads encrypted TR-181 data | [cpe-management.md](features/cpe-management.md) | | `services/docuseal/` | `docs.gigafibre.ca:3000` | Contract signing for commercial quotes + residential service agreements | [flow-editor.md §5](features/flow-editor.md) (briefly) | | `services/legacy-db/` | `:3305` (internal) | Read-only proxy over the retired MariaDB for lookups that haven't migrated | [architecture/overview.md](architecture/overview.md) | **ERPNext** (`erp.gigafibre.ca`) is not under `services/` — it's a standard Frappe-Bench install on the VM. See [architecture/data-model.md](architecture/data-model.md) for the doctype catalog. --- ## 4. Cross-module interactions (one-page map) > Full matrix + sequence diagrams in > [architecture/module-interactions.md](architecture/module-interactions.md). > The summary below is just the high-traffic edges. ```text ┌───────────────────────────────────────┐ │ ERPNext (source of truth) │ │ Customer · Subscription · │ │ Equipment · Dispatch Job · │ │ Sales Invoice · Ticket │ └──┬──────────────┬──────────┬──────────┘ │ │ │ REST+token │ REST+token │ REST+token │ │ │ ┌────────────▼──┐ ┌───────▼────────┐ │ │ targo-hub │ │ Ops SPA │ │ │ (gateway) │◄──┤ apps/ops/ │ │ │ │ └────┬───────────┘ │ │ /vision/* │ │ │ │ /magic-link/* │ │ bundles │ │ /sse │ │ tech module │ │ /sms │ │ at /j/* │ │ /stripe/* │ │ │ │ /acs/* │ └─────────────┘ │ /t/{token} │ │ └──┬──────┬─────┘ │ │ │ │ SMS │ │ email (magic link) │ /SSE │ │ │ ▼ ▼ ▼ ┌─────────────────┐ ┌────────────────────────┐ │ Tech mobile │ │ Customer portal │ │ (SSR OR Vue) │ │ apps/client/ │ │ /t or /ops/#/j/ │ │ portal.gigafibre.ca │ └─────────────────┘ └────────────────────────┘ ``` **Highest-traffic edges (read these docs first if you're chasing one):** | From | To | Via | Where it's documented | |---|---|---|---| | Dispatch (Ops) | Tech mobile | Magic-link SMS → hub/magic-link.js → Twilio | [dispatch.md §5](features/dispatch.md) + [tech-mobile.md §2](features/tech-mobile.md) | | Tech mobile scanner | Gemini | POST hub `/vision/barcodes` + `/vision/equipment` | [vision-ocr.md §2](features/vision-ocr.md) + [tech-mobile.md §3](features/tech-mobile.md) | | Ops OCR page | Gemini | POST hub `/vision/invoice` | [vision-ocr.md §3](features/vision-ocr.md) | | Customer portal | ERPNext | Authenticated via customer JWT → hub proxies `/api/resource/*` | [customer-portal.md §6](features/customer-portal.md) | | Stripe | ERPNext | Webhook → hub `/stripe/webhook` → creates Payment Entry | [billing-payments.md §7](features/billing-payments.md) | | Ops dispatch | SSE live updates | hub `/sse` (tech status, job flip, ETA) | [dispatch.md §4](features/dispatch.md) | | Agent-flows | Any module | Runtime in hub → triggers any ERPNext op via service token | [flow-editor.md §6](features/flow-editor.md) | | GenieACS | Modem-bridge | hub `/acs/probe` → modem-bridge for TP-Link deep params | [cpe-management.md §4](features/cpe-management.md) | --- ## 5. Folder map ```text docs/ ├── README.md ← you are here ├── roadmap.md ← phase tracker + live module URLs │ ├── architecture/ ← the system itself │ ├── overview.md (services, Docker, Traefik, SSO, retirement plan) │ ├── data-model.md (ERPNext doctypes + "Lead to Live") │ ├── app-design.md (Vue/Quasar patterns, feature-sliced layout) │ └── module-interactions.md (full call graph + sequence diagrams) │ ├── features/ ← one doc per business capability │ ├── README.md (per-doc index) │ ├── dispatch.md (Ops dispatch board, scheduling, tags, SMS) │ ├── tech-mobile.md (Gemini-native scanner, equipment UX, JWT) │ ├── customer-portal.md (Plan A magic-link, Stripe self-service) │ ├── billing-payments.md (Stripe, invoices, subscriptions, PPA) │ ├── cpe-management.md (GenieACS, Oktopus, XX230v, modem-bridge) │ ├── vision-ocr.md (Gemini, scan pipeline, offline queue, keys) │ └── flow-editor.md (Flow Template, triggers, runtime) │ ├── reference/ ← lookup material │ ├── erpnext-item-diff.md (new SKUs vs legacy gestionclient) │ └── legacy-wizard/ (read-only snapshot of the PHP wizard) │ ├── assets/ ← PPTX decks, screenshots, generated diagrams │ └── archive/ ← frozen docs, do not edit ├── HANDOFF-2026-04-18.md ├── MIGRATION.md ├── LEGACY-ACCOUNTING-ANALYSIS.md └── status-snapshots/ (dated session reports) ``` --- ## 6. Conventions - **Edit in place.** Don't copy-paste a section into a new file — link to it instead. - **Module index = source of truth for URLs.** If you change a route or a deployed host, update §2 of this file *and* the relevant feature doc. `grep -r "erp.gigafibre.ca" docs/` should not return stale hostnames. - **Cross-doc links use repo-relative paths,** e.g. `[features/dispatch.md](features/dispatch.md)` — so `git mv`ing a doc surfaces every incoming link. - **Code comments that reference a doc** use the full repo-relative path, e.g. `// See docs/features/vision-ocr.md §10` — so `grep docs/` still surfaces them if we reorganize again. - **Dated snapshots go to `archive/status-snapshots/`.** Don't create `STATUS_YYYY-MM-DD.md` at the root anymore. - **The root `README.md`** (one level up) is the repo introduction for non-technical readers; `docs/README.md` (this file) is the engineering index. --- ## 7. What changed on 2026-04-22 Big reorganization: 1. **New feature docs** added: `dispatch.md`, `customer-portal.md`, `tech-mobile.md`. The first was missing entirely despite being the most-used surface in Ops; the second codifies the Plan A magic-link cutover; the third replaces a stale `tech-mobile.md` that incorrectly referenced `html5-qrcode` (never shipped — scanner has always been native camera + Gemini). 2. **New architecture doc** added: `module-interactions.md` — the one-page call graph with sequence diagrams for the hot paths (dispatch → SMS → tech scan → equipment install). 3. **Module index** (§2 above) now lists *every* deployed surface, not just the three that had feature docs. Dispatch, Tickets, Équipe, Rapports, Telephony, Network, Agent Flows, OCR, and every customer-portal page now have a named row. 4. **Customer portal topology clarified.** `portal.gigafibre.ca` is the live SPA; `client.gigafibre.ca` 307s to portal. The legacy `apps/portal/` tree is retained as historical reference only. 5. **Earlier flattening (still in effect):** docs were flattened out of a single folder into `architecture/`, `features/`, `reference/`, `archive/`. Every file move used `git mv` so `git log --follow` still works. The old paths (`docs/ARCHITECTURE.md`, `docs/VISION_AND_OCR.md`, etc.) no longer exist — if you land on one of those links from an external bookmark, use §1 above to find the new location. Legacy references remain only inside `archive/HANDOFF-2026-04-18.md` and `archive/status-snapshots/*.md`, where they're preserved as a frozen historical record.