gigafibre-fsm/docs/README.md
louispaulb 30a867a326 fix(tech): restore Gemini-native scanner + port equipment UX into ops
The ops tech module at /ops/#/j/* had drifted from the field app in two ways:

1. Scanner — a prior "restoration" re-added html5-qrcode, but the
   design has always been native <input capture="environment"> → Gemini
   2.5 Flash via targo-hub /vision/barcodes (up to 3 codes) and
   /vision/equipment (structured labels, up to 5). Revert useScanner.js
   + ScanPage.vue + TechScanPage.vue to commit e50ea88 and drop
   html5-qrcode from both package.json + lockfiles. No JS barcode
   library, no camera stream, no polyfills.

2. Equipment UX — TechJobDetailPage.vue was a 186-line stub missing the
   Ajouter bottom-sheet (Scanner / Rechercher / Créer), the debounced
   SN-then-MAC search, the 5-field create dialog, Type + Priority
   selects on the info card, and the location-detail contact expansion.
   Port the full UX from apps/field/src/pages/JobDetailPage.vue (526
   lines) into the ops module (458 lines after consolidation).

Rebuilt and deployed both apps. Remote smoke test confirms 0 bundles
reference html5-qrcode and the new TechJobDetailPage.1075b3b8.js chunk
(16.7 KB vs ~5 KB stub) ships the equipment bottom-sheet strings.

Docs:

- docs/features/tech-mobile.md — new. Documents all three delivery
  surfaces (legacy SSR /t/{jwt}, transitional apps/field/, unified
  /ops/#/j/*), Gemini-native scanner pipeline, equipment UX, magic-link
  JWT, cutover plan. Replaces an earlier stub that incorrectly
  referenced html5-qrcode.
- docs/features/dispatch.md — new. Dispatch board, scheduling, tags,
  travel-time optimization, magic-link SMS, SSE updates.
- docs/features/customer-portal.md — new. Plan A passwordless magic-link
  at portal.gigafibre.ca, Stripe self-service, file inventory.
- docs/architecture/module-interactions.md — new. One-page call graph
  with sequence diagrams for the hot paths.
- docs/README.md — expanded module index (§2) now lists every deployed
  surface with URL + primary doc + primary code locations (was missing
  dispatch, tickets, équipe, rapports, telephony, network, agent-flows,
  OCR, every customer-portal page). New cross-module edge map in §4.
- docs/features/README.md + docs/architecture/README.md — cross-link
  all new docs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 15:56:38 -04:00

280 lines
19 KiB
Markdown

# 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.