gigafibre-fsm/docs/ARCHITECTURE.md
louispaulb 607ea54b5c refactor: reduce token count, DRY code, consolidate docs
Backend services:
- targo-hub: extract deepGetValue to helpers.js, DRY disconnect reasons
  lookup map, compact CAPABILITIES, consolidate vision.js prompts/schemas,
  extract dispatch scoring weights, trim section dividers across 9 files
- modem-bridge: extract getSession() helper (6 occurrences), resetIdleTimer(),
  consolidate DM query factory, fix duplicate username fill bug, trim headers
  (server.js -36%, tplink-session.js -47%, docker-compose.yml -57%)

Frontend:
- useWifiDiagnostic: extract THRESHOLDS const, split processDiagnostic into
  6 focused helpers (processOnlineStatus, processWanIPs, processRadios,
  processMeshNodes, processClients, checkRadioIssues)
- EquipmentDetail: merge duplicate ROLE_LABELS, remove verbose comments

Documentation (17 → 13 files, -1,400 lines):
- New consolidated README.md (architecture, services, dependencies, auth)
- Merge ECOSYSTEM-OVERVIEW into ARCHITECTURE.md
- Merge MIGRATION-PLAN + ARCHITECTURE-COMPARE + FIELD-GAP + CHANGELOG → MIGRATION.md
- Merge COMPETITIVE-ANALYSIS into PLATFORM-STRATEGY.md
- Update ROADMAP.md with current phase status
- Delete CONTEXT.md (absorbed into README)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 08:39:58 -04:00

298 lines
14 KiB
Markdown

# Gigafibre FSM -- Architecture
## 1. Service Map
```
┌──────────────────┐
│ Authentik SSO │
│ auth.targo.ca │
└────────┬─────────┘
│ forwardAuth
┌──────────────────┐
│ Traefik │
│ :80 / :443 │
│ Let's Encrypt │
└──┬───┬───┬───┬───┘
┌──────────────────┘ │ │ └───────────────────┐
▼ ▼ ▼ ▼
┌────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Ops App │ │ ERPNext v16 │ │ targo-hub │
│ /ops/ (nginx) │ │ erp.gigafibre.ca│ │ msg.gigafibre.ca│
└───────┬────────┘ └───────┬──────────┘ └──┬───┬───┬──────┘
│ /api/* proxy │ │ │ │
│ (token injected) │ │ │ │
└───────────────────┘ │ │ │
│ │ │
┌────────────────────────────────────┘ │ └──────┐
▼ ▼ ▼
┌──────────────────┐ ┌────────────────┐ ┌─────────┐
│ GenieACS NBI │ │ Twilio API │ │ Stripe │
│ 10.5.2.115:7557 │ │ SMS + Voice │ │ Payments│
└───────┬──────────┘ └────────────────┘ └─────────┘
│ CWMP (TR-069)
┌──────────────────┐ ┌──────────────────┐
│ CPE / ONT │◀──────│ modem-bridge │
│ TP-Link XX230v │ HTTPS │ :3301 (internal)│
│ Raisecom HT803G │ │ Playwright │
└──────────────────┘ └──────────────────┘
```
Docker networks: `proxy` (Traefik-facing services), `erpnext` (ERPNext cluster + targo-hub).
---
## 2. Docker Containers
Host: `96.125.196.67` (Proxmox VM, Ubuntu 24.04). All services on one Docker host.
| Container | Image | Port | Network | Purpose |
|-----------|-------|------|---------|---------|
| ops-frontend | nginx:alpine | 80 | proxy | Ops SPA + ERPNext API proxy |
| targo-hub | node:20-alpine | 3300 | proxy, erpnext | API gateway: SSE, SMS, devices, dispatch |
| erpnext-frontend-1 | frappe/erpnext | 8080 | erpnext | ERPNext web + API |
| erpnext-backend | frappe/erpnext | 8000 | erpnext | Frappe worker |
| erpnext-db-1 | postgres:16 | 5432 | erpnext | ERPNext + targo_cache DBs |
| modem-bridge | node:20-slim+Chromium | 3301 | proxy | Headless browser for ONU web GUI |
| oktopus-acs-1 | oktopusp/acs | 9292 | oktopus | USP/TR-369 controller |
| oktopus-mongo-1 | mongo:7 | 27017 | oktopus | Oktopus datastore |
| fn-routr | fonoster/routr-one | -- | fonoster | VoIP SIP routing |
| fn-asterisk | fonoster/asterisk | -- | fonoster | PBX media server |
| fn-postgres | postgres:16 | -- | fonoster | Fonoster DB |
| authentik-* | goauthentik | -- | authentik | SSO provider (staff + client) |
| apps-www-gigafibre-1 | nginx | -- | proxy | Marketing website |
---
## 3. Ops App (Quasar v2 / Vue 3 / Vite)
Served from `/opt/ops-app/` via `ops-frontend` nginx at `erp.gigafibre.ca/ops/`.
### Directory Structure
| Directory | Files | Content |
|-----------|-------|---------|
| `api/` | 10 | ERPNext CRUD, dispatch, offers, presets, SMS, traccar, OCR, auth, reports |
| `components/` | 23 .vue | customer/, dispatch/, shared/, layout/ |
| `composables/` | 41 | Domain-specific reactive logic (see below) |
| `modules/dispatch/components/` | 13 | Timeline, calendar, map, modals, context menus |
| `pages/` | 16 | Routed page views |
| `stores/` | 2 | Pinia: auth, dispatch |
| `config/` | 8 | erpnext, nav, dispatch, ticket-config, hub, table-columns |
### Pages (16)
DashboardPage, ClientsPage, ClientDetailPage, TicketsPage, **DispatchPage**, EquipePage, NetworkPage, TelephonyPage, RapportsPage, SettingsPage, OcrPage, AgentFlowsPage, ReportARPage, ReportRevenuPage, ReportTaxesPage, ReportVentesPage
### Composables (41) -- grouped by domain
| Domain | Composables |
|--------|-------------|
| **Scheduling** | useScheduler, useDragDrop, useBottomPanel, usePeriodNavigation, useAutoDispatch, useBestTech, useJobOffers, useAbsenceResize, useSelection, useUndo, useContextMenus, useTechManagement |
| **Map / GPS** | useMap, useGpsTracking, useAddressSearch |
| **Phone / SMS** | usePhone, useConversations |
| **Data** | useClientData, useDeviceStatus, useSSE, useInlineEdit, useEquipmentActions, usePaymentActions, useSubscriptionActions, useSubscriptionGroups, useLegacySync, useCustomerNotes, usePermissions, usePermissionMatrix, useUserGroups |
| **UI** | useHelpers, useFormatters, useStatusClasses, useDetailModal, useResourceFilter, useTagManagement, useUnifiedCreate, useScanner, useWifiDiagnostic, useWizardCatalog, useWizardPublish |
---
## 4. Targo-Hub (Node.js)
Container `targo-hub` | `msg.gigafibre.ca` | Port 3300 | 40 modules in `lib/`
### Modules (top 15 by size)
| Module | Lines | Purpose |
|--------|------:|---------|
| payments.js | 1374 | Stripe checkout, PPA cron, webhooks |
| network-intel.js | 1221 | Network topology, outage correlation |
| ai.js | 719 | Gemini AI integration (tool-calling) |
| acceptance.js | 672 | Service acceptance workflows |
| outage-monitor.js | 601 | Uptime-Kuma alerts |
| reports.js | 572 | Analytics and report generation |
| tech-mobile.js | 562 | Lightweight mobile page for technicians |
| devices.js | 551 | GenieACS proxy, device summary, poller |
| contracts.js | 548 | Contract generation |
| oktopus.js | 545 | TR-369/USP controller proxy |
| agent.js | 529 | AI SMS agent with tool-calling |
| conversation.js | 499 | Conversation persistence |
| voice-agent.js | 457 | Inbound voice IVR + WebSocket media |
| olt-snmp.js | 419 | OLT SNMP polling, ONU state tracking |
| checkout.js | 399 | Customer checkout / catalog API |
Plus 25 smaller modules: server, twilio, pbx, dispatch, provision, auth, telephony, ical, modem-bridge, config, helpers, sse, email, otp, magic-link, traccar, vision, device-extractors, device-hosts, oktopus-mqtt, tech-absence-sms, address-search, email-templates, project-templates.
### Endpoints -- grouped by domain
**SSE / Real-time**
| Method | Path | Purpose |
|--------|------|---------|
| GET | `/sse?topics=...` | SSE stream (customer, conversations, sms-incoming) |
| POST | `/broadcast` | Push event to SSE clients |
**SMS / Voice / Telephony**
| Method | Path | Purpose |
|--------|------|---------|
| POST | `/send/sms` | Send SMS via Twilio |
| POST | `/webhook/twilio/sms-incoming` | Inbound SMS |
| POST | `/webhook/twilio/sms-status` | Delivery status |
| GET | `/voice/token` | Twilio voice JWT |
| POST | `/voice/twiml`, `/voice/status` | TwiML + call status |
| POST | `/voice/inbound`, `/voice/gather`, `/voice/connect-agent` | IVR voice agent |
| WS | `/voice/ws` | Twilio Media Streams (WebSocket) |
| POST | `/webhook/3cx/call-event` | 3CX call events |
| * | `/telephony/*` | Fonoster/Routr SIP CRUD |
**Devices / Network**
| Method | Path | Purpose |
|--------|------|---------|
| GET | `/devices/lookup?serial=X` | GenieACS device search (3 fallback strategies) |
| GET | `/devices/summary` | Fleet statistics |
| GET | `/devices/:id/hosts` | Connected clients + mesh mapping |
| POST | `/devices/:id/tasks` | Send task (reboot, refresh) |
| * | `/acs/*` | ACS config export |
| * | `/modem/*` | Proxy to modem-bridge |
| * | `/olt/*` | OLT SNMP stats, ONU lookup, registration |
| * | `/oktopus/*` | TR-369 USP proxy |
| * | `/network/*` | Network intelligence / topology |
**Dispatch / Scheduling** -- `/dispatch/*` (CRUD, iCal token + feed)
**Auth / Customer / Payments** -- `/auth/*` (RBAC), `/magic-link/*`, `/api/checkout|catalog|otp|order|address` (customer flow), `/payments/*` + `/webhook/stripe` (Stripe + PPA cron), `/accept/*`, `/contract/*`
**AI / Vision** -- `/ai/*` (Gemini), `/agent/*` (SMS agent), `/vision/barcodes|equipment`, `/conversations/*`
**Other** -- `/traccar/*` (GPS), `/provision/*` (OLT), `/reports/*`, `/t/:token` (tech mobile), `/webhook/kuma` (outage), `/health`
---
## 5. Modem-Bridge (Playwright/Chromium)
Internal-only service on port 3301. Provides REST access to TP-Link ONU web GUIs via headless Chromium. Required because XX230v firmware uses GDPR-encrypted communication (RSA key exchange, AES session, encrypted JSON on `/cgi_gdpr?9`). Playwright lets the modem's own JavaScript handle all crypto natively rather than re-implementing the protocol.
| Method | Path | Purpose |
|--------|------|---------|
| POST | `/session/login` | Authenticate to modem (ip, user, pass) |
| GET | `/session/list` | List active browser sessions |
| DELETE | `/session/:ip` | Close session |
| GET | `/modem/:ip/status` | Device status summary |
| GET | `/modem/:ip/dm/:oid` | Data manager GET |
| GET | `/modem/:ip/screenshot` | PNG screenshot (debug) |
Constraints: ~450MB disk (node + Chromium), ~80MB idle + 150MB per session, 512MB Docker limit, sessions auto-expire after 5 min. Bearer token auth, private IP restriction, read-only operations only.
---
## 6. Secondary Apps
| App | Stack | URL | Purpose |
|-----|-------|-----|---------|
| **Field App** (`apps/field/`) | Vue 3 / Quasar PWA | -- | Tech mobile: daily tasks, barcode scanner, device diagnostics, offline sync |
| **Client Portal** (`apps/client/`) | Vue 3 / Quasar PWA | client.gigafibre.ca | Self-service: invoices, subscriptions, tickets, catalog. Auth via Authentik |
| **Website** (`apps/website/`) | React / Vite / Tailwind | www.gigafibre.ca | Marketing: products, eligibility check, online ordering, FAQ |
---
## 7. Data Model (ERPNext Doctypes)
```
Customer
├── Service Location (LOC-#####)
│ ├── Address + GPS coordinates
│ ├── OLT port, VLAN, network config
│ ├── Service Equipment (EQP-#####)
│ │ ├── Type: ONT / Router / Switch / AP / Decodeur
│ │ ├── Serial + MAC + manage IP + firmware
│ │ └── Status: Active / Inactive / En stock / Defectueux / Retourne
│ └── Service Subscription (SUB-#####)
│ ├── Plan: Internet / IPTV / VoIP / Bundle
│ └── Status: pending → active → suspended → cancelled
└── Sales Invoice → Payment Entry
Dispatch Job
├── Customer + Service Location
├── Dispatch Technician (assigned + assistants)
├── Dispatch Tag Link (tag + level 1-5 + required flag)
├── Schedule: date, time, duration, recurrence (RRULE)
└── Equipment Items / Materials Used
Dispatch Technician
├── weekly_schedule (JSON), extra_shifts (JSON)
└── Dispatch Tag Link (skill level per tag)
```
Custom fields on standard doctypes: Customer (`stripe_id`, `is_commercial`, `ppa_enabled`), Subscription (`actual_price`, `service_location`), Issue (linked dispatch jobs), Sales Invoice (QR code, portal link).
---
## 8. External Integrations
| Service | Purpose | Connection |
|---------|---------|------------|
| GenieACS (10.5.2.115) | TR-069 CPE management | NBI REST, LAN, no auth |
| Twilio | SMS + voice | REST API, Basic auth |
| Stripe | Payments, checkout | API + webhooks |
| Mapbox | Maps, geocoding, routing | JS SDK + Directions API |
| Gemini AI | OCR, SMS agent, AI tools | REST, Bearer token |
| Traccar | GPS tech tracking | REST API, Basic auth |
| 3CX PBX | Call history | REST API poller (30s) |
| Fonoster/Routr | SIP trunking | Direct PostgreSQL |
| Authentik | SSO (staff + client) | Traefik forwardAuth + API |
| n8n | Workflow automation | HTTP webhooks |
| Uptime-Kuma | Outage monitoring | Webhook to targo-hub |
| Cloudflare | DNS for gigafibre.ca | REST API |
---
## 9. Data Flows
### Device Diagnostic
```
Ops App → EquipmentDetail.vue → GET /devices/lookup?serial=X
→ targo-hub → GenieACS NBI (3 fallback strategies) → summarizeDevice()
→ {interfaces, mesh, wifi, opticalStatus, ethernet}
GET /devices/:id/hosts?refresh
→ 2 tasks to CPE (connection_request) → read GenieACS cache
→ clientNodeMap: MAC → {nodeName, band, signal, speed}
→ UI: clients grouped by mesh node (basement, hallway, etc.)
```
### Dispatch Auto-Assign
```
New job with required tags (e.g., Fibre level 3)
→ useAutoDispatch → useBestTech
→ Filter techs: tag level >= required, available in time slot
→ Sort: lowest adequate skill level first (preserve experts)
→ Assign → SSE broadcast → timeline updates
```
### SMS Notification
```
Compose in ChatterPanel → POST /send/sms → targo-hub
→ Twilio API → delivery
→ /webhook/twilio/sms-status → SSE broadcast (conv:{token})
→ UI updates delivery status in thread
Inbound SMS → /webhook/twilio/sms-incoming
→ conversation.js (persist) → SSE broadcast (sms-incoming)
→ agent.js (optional AI auto-reply with tool-calling)
```
### Customer Onboarding
```
Website → /api/address (eligibility check) → /api/catalog
→ /api/checkout (Stripe session) → /webhook/stripe (payment confirmed)
→ ERPNext: create Customer + Service Location + Subscription
→ /api/otp (SMS verification) → magic-link auth
→ provision.js: OLT pre-auth → GenieACS auto-provision on connect
```