gigafibre-fsm/docs/archive/status-snapshots/2026-04-18.md
louispaulb beb6ddc5e5 docs: reorganize into architecture/features/reference/archive folders
All docs moved with git mv so --follow preserves history. Flattens the
single-folder layout into goal-oriented folders and adds a README.md index
at every level.

- docs/README.md — new landing page with "I want to…" intent table
- docs/architecture/ — overview, data-model, app-design
- docs/features/ — billing-payments, cpe-management, vision-ocr, flow-editor
- docs/reference/ — erpnext-item-diff, legacy-wizard/
- docs/archive/ — HANDOFF-2026-04-18, MIGRATION, status-snapshots/
- docs/assets/ — pptx sources, build scripts (fixed hardcoded path)
- roadmap.md gains a "Modules in production" section with clickable
  URLs for every ops/tech/portal route and admin surface
- Phase 4 (Customer Portal) flipped to "Largely Shipped" based on
  audit of services/targo-hub/lib/payments.js (16 endpoints, webhook,
  PPA cron, Klarna BNPL all live)
- Archive files get an "ARCHIVED" banner so stale links inside them
  don't mislead readers

Code comments + nginx configs rewritten to use new doc paths. Root
README.md documentation table replaced with intent-oriented index.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 11:51:33 -04:00

16 KiB

Gigafibre FSM — Status Snapshot (2026-04-18) — ARCHIVED

⚠️ ARCHIVED snapshot. Links below point to the pre-reorganization layout and are stale. For the current state, see ../../roadmap.md. For the live index, see ../../README.md.

Audience (original): new contributor, stakeholder, or future-me opening this cold. Goal (original): be able to hold a coherent conversation about the system in 10 minutes.


TL;DR

Gigafibre (consumer brand of TARGO Internet) is a Quebec fiber ISP. We are migrating a legacy PHP/MariaDB billing system (used daily since ~2012) to ERPNext v16 on PostgreSQL, wrapping it in Vue 3/Quasar PWAs for ops, dispatch, field, and customer self-service. The accounting, subscriptions, invoices, and payments are already migrated and balanced. We are now in the "live ops" transition phase: new quotes flow through ERPNext + DocuSeal e-signature, dispatch runs on the new PWA, and the legacy system is kept in read-only mode pending customer-portal cutover.


Where we are (at a glance)

Area State Notes
Accounting migration Shipped 629,935 invoices + 343,684 payments, GL balanced ($130M debit/credit)
Master data migration Shipped 15,303 customers · 833 items · 21,876 subscriptions · 7,241 equipment
Staff SSO (auth.targo.ca) Live Authentik forwardAuth, 6 groups
Ops PWA (erp.gigafibre.ca/ops/) Live ClientDetail, Tickets, Dispatch, Dashboard
Dispatch PWA v1 Live Timeline + Mapbox + drag-drop
Field tech PWA Live Mobile via /t/{token}
GenieACS TR-069 Live ~7,560 CPEs polled every 5 min
targo-hub gateway Live 11 modules (ERP, Twilio, SIP, AI, SSE, etc.)
Quotation + DocuSeal flow 🆕 Just shipped (2026-04-18) See "New this cycle" below
Customer SSO (id.gigafibre.ca) Live Authentik federated from staff
Customer portal v2 🚧 In progress Vue SPA spec ready; checkout + Stripe pending
ERPNext scheduler ⏸ Paused pause_scheduler=1 — requires explicit approval to reactivate
Invoice PDF "Facture TARGO" Live Inline-SVG logo, QR to Stripe/portal
Quote PDF "Soumission TARGO" Live Same branding, QR to DocuSeal signing URL
Legacy PHP/MariaDB 🗃 Read-only Accessed from 10.100.80.100 for residual lookups

Architecture at a glance

                 Internet (Cloudflare DNS for gigafibre.ca)
                               │
          ┌────────────────────┴───────────────────┐
          │    Proxmox VM — 96.125.196.67          │
          │    Ubuntu 24.04 · Docker · Traefik v2.11│
          └────────────────────┬───────────────────┘
                               │
   ┌──────────┬───────────┬────┴─────┬──────────┬─────────────┐
   │          │           │          │          │             │
 ERPNext   Ops PWA    targo-hub    n8n     DocuSeal      Authentik
 erp.      /ops/      msg.         n8n.    sign.         auth.targo.ca
 giga.ca   (nginx)    giga.ca      giga.ca giga.ca       id.giga.ca
   │                     │
   │                     ├─── Twilio (SMS, +14382313838)
   │                     ├─── 3CX PBX (targopbx.3cx.ca)
   │                     ├─── Mailjet SMTP
   │                     ├─── Fonoster/Routr (SIP @ voice.giga.ca)
   │                     ├─── GenieACS NBI (10.5.2.115:7557)
   │                     ├─── Oktopus TR-369 (oss.giga.ca)
   │                     ├─── Gemini AI (agent/voice/OCR)
   │                     ├─── Stripe (payments)
   │                     └─── Traccar (tech GPS, tracker.targointernet.com)
   │
   └─── Legacy MariaDB (read-only, 10.100.80.100)

For the authoritative breakdown see ARCHITECTURE.md.


Features inventory (by surface)

👥 Staff — Ops PWA (erp.gigafibre.ca/ops/)

  • ClientDetailPage — master client view, 8 parallel API calls (contacts, devices, subscriptions, invoices, payments, tickets, equipment, SMS history). Inline-editable fields Odoo-style.
  • TicketsPage — issue triage, assignment, status, SLA indicators.
  • DispatchPage (v1) — today's jobs, technician rows, drag-drop re-assign, Mapbox job map.
  • DashboardPage — KPIs, outstanding AR, job throughput.
  • Wizard (ProjectWizard.vue) — creates Quotation with wizard_steps JSON describing dispatch + subscription creation deferred until acceptance.
  • Theme — light mode everywhere except Dispatch (dark by design).

🔧 Staff — Dispatch PWA v2 (dispatch.gigafibre.ca) [in migration]

  • Larger Mapbox-driven timeline, undo support, technician lanes, planned features include Gantt view and auto-dispatch by skill tags.

📱 Field — Field tech PWA (mobile)

  • Route at /t/{token} (no login — token-based).
  • Offline-first IndexedDB; photo upload, checklist, materials used, customer signature.
  • Barcode/serial scanner: native camera capture (<input capture="environment">) → Gemini 2.5 Flash Vision via msg.gigafibre.ca/vision/barcodes (extracts barcode / S/N / MAC / model from a single photo).

🧑‍💼 Customer — Client portal (client.gigafibre.ca) [v2 in progress]

Live today:

  • Authentik client SSO at id.gigafibre.ca.
  • Legacy password bridge: MD5 → PBKDF2 on first login (11,800 portal users provisioned).
  • ERPNext Portal Server Script resolves X-Authentik-Email → Customer.

In flight (Phase 4):

  • Vue SPA: see invoices, pay via Stripe Payment Element, view subscriptions, update contact info.
  • Online appointment booking.
  • Real-time tech arrival tracking via SMS.
  • QR code on modem → subscriber dashboard.

🌐 Public — Marketing site (www.gigafibre.ca)

  • React + Vite + Tailwind + shadcn/ui.
  • RQA address eligibility check, AQ address normalization.
  • Uses Supabase for pre-signup intake; Twilio for SMS OTP on checkout intent.

✍️ Quotation → Signature flow (just shipped)

  1. Wizard creates Quotation w/ wizard_steps JSON (dispatch + subscriptions to execute on acceptance).
  2. Wizard calls POST /accept/generate with use_docuseal: true.
  3. Hub creates DocuSeal submission (template 1), writes sign_url to Quotation.custom_docuseal_signing_url.
  4. PDF print format Soumission TARGO renders with QR + "SIGNER CETTE SOUMISSION" button.
  5. Customer signs → DocuSeal webhook fires form.completed → hub runs acceptQuotation() → dispatch jobs + subscriptions materialized from wizard_steps.

See project_docuseal_quote.md for deep detail.


ERPNext customisations

Custom doctypes (FSM module)

Doctype ID Purpose
Service Location LOC-##### Customer premises (address, GPS, OLT port, network config)
Service Equipment EQP-##### ONT / router / TV box — serial, MAC, IP, parent
Service Subscription SUB-##### Active plans — speed, price, billing, RADIUS creds
Service Contract CTR-##### Long-term agreement with benefits
Dispatch Job DJ-##### Work order — materials, checklist, photos, signature
Dispatch Technician DT-##### Tech profile — skills, Traccar GPS, color
Dispatch Tag Skill tag with level (1 base → 5 expert)
Checklist Template Re-usable job checklists

Custom fields (highlights)

Doctype Field Purpose
Item custom_billing_frequency One-time / Monthly / Annual (source of truth)
Quotation Item · Sales Invoice Item · Sales Order Item custom_billing_frequency Inherited from Item via fetch_from, overridable per-line
Quotation custom_docuseal_signing_url, custom_docuseal_envelope_id Populated by hub after DocuSeal submit
Quotation custom_quote_type Résidentiel / Commercial
Quotation wizard_steps, wizard_context JSON blobs driving post-acceptance workflow
Customer legacy_account_id, legacy_customer_id, ppa_enabled, stripe_id Legacy mapping + Stripe link
Item legacy_product_id, download_speed, upload_speed, olt_profile Network profile
Subscription radius_user, radius_pwd, legacy_service_id Network auth
Issue legacy_ticket_id, assigned_staff, issue_type, is_important, service_location Ticket context
User legacy_password_md5 Bridge for legacy portal passwords

Print formats

Format Doctype State
Facture TARGO Sales Invoice Live — used for monthly billing, QR to Stripe/portal
Soumission TARGO Quotation Live (2026-04-18) — QR to DocuSeal signing URL, split totals (Services récurrents + Frais uniques)

Known ERPNext v16 quirks

  • PostgreSQL GROUP BY / HAVING / double-quote bugs — patches applied, bulk submit workflow documented.
  • Scheduler paused (pause_scheduler=1) — do NOT reactivate without approval; Subscription → Invoice automation depends on it.
  • Frappe REST filter on Quotation.customer rejected — use party_name when quotation_to == "Customer".

Integrations (live + credentialed)

Integration URL / endpoint Auth Used by
Authentik (staff) auth.targo.ca OAuth client + forwardAuth ERPNext, ops, dispatch, n8n, hub
Authentik (client) id.gigafibre.ca forward_single proxy client.gigafibre.ca
Twilio api.twilio.com Basic (SID/token) targo-hub twilio.js, SMS, OTP
Cloudflare api.cloudflare.com X-Auth-Key + X-Auth-Email (Global) DNS, ops app checks
GenieACS http://10.5.2.115:7557 LAN no-auth targo-hub devices.js (5-min poll)
Oktopus (TR-369) oss.gigafibre.ca user/pass CPE next-gen mgmt
Stripe api.stripe.com secret key Customer checkout, webhook
Fonoster / Routr voice.gigafibre.ca:5160/5163 SIP creds Voice calls via WSS
3CX PBX targopbx.3cx.ca Basic Voice polling, call logs
Mailjet SMTP in-v3.mailjet.com:587 user/pass DocuSeal + transactional email
Traccar tracker.targointernet.com:8082 user/pass Tech GPS
DocuSeal sign.gigafibre.ca API key Quotation e-signature (just live)
n8n n8n.gigafibre.ca webhook (no auth) SMS, OLT SSH commands, subscription automations
Gemini AI generativelanguage.googleapis.com Bearer agent replies, OCR, voice

All tokens/keys live in /opt/targo-hub/.env on the production host and are tracked in memory records (never in repo).


🆕 New this cycle (2026-04-08 → 2026-04-18)

  • DocuSeal e-signature for Quotations — hub routes, Custom Fields, "Soumission TARGO" print format, signing URL writeback, webhook → acceptQuotation.
  • Billing frequency systemcustom_billing_frequency on Item + Quotation Item + Sales Invoice Item + Sales Order Item; print format splits Récurrent vs One-time with their own subtotals.
  • Print format fixes — inline-SVG logo (was oversized PNG), frappe.db.commit() fix (was silently rolling back), correct party_name usage.
  • HubDOCUSEAL_DEFAULT_TEMPLATE_ID env knob, writeback of sign_url to Quotation.
  • Custom appgigafibre_utils.api.url_qr_base64(url) helper for QR generation in print formats.

🚧 In flight (right now)

  1. Customer portal v2 (Vue SPA) — invoice list, Stripe Payment Element, subscription view, contact update. Spec ready. No front-end code yet.
  2. Dispatch v2 — larger rewrite of dispatch PWA at dispatch.gigafibre.ca. Timeline + Mapbox + Gantt + auto-dispatch by tag/skill.
  3. ClientDetailPage refactor — 1,512-line monolith → composables (useCustomer, useSubscriptionGroups, useFormatters, useStatusClasses).
  4. Service deactivation workflow — n8n webhook ties Subscription cancellation to OLT port shutdown.
  5. Multi-email account cleanup — ~30 customers have multiple emails; manual triage pending.

🎯 Next priorities (ordered)

Update this list at the end of each working session.

# Item Why now Owner Blocked by
1 Register DocuSeal webhook in UI → msg.gigafibre.ca/accept/docuseal-webhook on form.completed Without this, signed quotes don't materialise dispatch jobs manual (UI)
2 Validate Subscription → Sales Invoice scheduler flow on a pilot subscription Before reactivating scheduler for full run eng
3 Reactivate pause_scheduler=0 for April billing Recurring invoices must generate eng + ops approval #2
4 Customer portal v2 MVP (invoice list + Stripe Payment Element) Drive self-serve payment, reduce AR calls eng
5 Tag 46 techs with skills Enable auto-dispatch ops
6 Issue → Dispatch Job auto-creation wiring Close ticket/dispatch loop eng
7 Fix 15 invoices flagged "Credit Note Issued" with $3,695.77 overpaid Accounting hygiene accounting
8 10DLC Twilio production upgrade Avoid SMS rate throttling at scale ops Twilio approval

🐛 Known issues & technical debt

  • Scheduler paused — subscriptions won't produce invoices until reactivated.
  • Tech debt in ClientDetailPage.vue (1,512 LOC) — slated for composable extraction.
  • Multiple formatDate / formatMoney implementations across files — should consolidate.
  • 6+ ad-hoc statusClass functions (subStatusClass, eqStatusClass, ticketStatusClass...) — extract to useStatusClasses.
  • Dispatch v1 vs v2 live simultaneously — cutover plan not yet written.
  • 15 "Credit Note Issued" invoices with overpayment of $3,695.77.
  • ~30 customers share emails across accounts — migration chose one per; manual reconciliation TBD.
  • GenieACS CPE count ≠ ERPNext Service Equipment count — TPLG serial vs real serial mismatch; MAC-based lookup required.

🚨 Gotchas (don't get burned)

  • Traefik HTTP → HTTPS global redirect breaks Let's Encrypt HTTP-01. Add redirect per-route or use TLS-ALPN. See feedback_traefik_ssl.md.
  • Docker 29 + Traefik v3 don't play well — stay on v2.11.
  • MongoDB 5+ needs AVX — Proxmox CPU must be set to host type.
  • netplan overrides systemd-networkd — remove for static networking.
  • Docker exec + nested SSH quoting is fragile — always write .py to disk, docker cp, then exec. See feedback_docker_exec.md.
  • iptables + Docker — avoid iptables-multiport, don't persist bridge rules, use the raw table. See feedback_ddos_iptables.md.
  • ERPNext Customer doctype has multi-address — but legacy assumed 1:1. Device hierarchy is tied to address, not customer, intentionally — preserves manage IP / credentials / parent relationships across customer changes.
  • Ops app deploy path — upload dist/spa/* (contents), not dist/spa/ (dir), to /opt/ops-app/. See feedback_deploy_path.md.

How to share this context

  • "I need someone on-board in 30 min": have them read the README + this file.
  • "They need to work on dispatch": add DATA_AND_FLOWS.md + APP_DESIGN_GUIDELINES.md.
  • "They need to work on billing/invoicing": add BILLING_AND_PAYMENTS.md.
  • "They need to work on CPE / network gear": add CPE_MANAGEMENT.md.
  • "They need server / infra access": credentials live on the host in /opt/targo-hub/.env — share out-of-band. Memory records in ~/.claude/.../memory/ note the shape of each credential.

Last updated: 2026-04-18 · Maintained alongside ROADMAP.md. When this file drifts more than a week out of date, create a new dated snapshot (STATUS_YYYY-MM-DD.md) and link it from the top of README.