gigafibre-fsm/docs
louispaulb 2b04e6bd86 feat(portal): passwordless magic-link login — retire ERPNext /login
Customers no longer authenticate with passwords. A POST to the hub's
/portal/request-link mints a 24h customer-scoped JWT and sends it via
email + SMS; the /#/login Vue page sits on top of this and a navigation
guard hydrates the Pinia store from the token on arrival.

Why now: legacy customer passwords are unsalted MD5 from the old PHP
system. Migrating hashes to PBKDF2 would still require a forced reset
for every customer, so it's simpler to drop passwords entirely. The
earlier Authentik forwardAuth attempt was already disabled on
client.gigafibre.ca; this removes the last vestige of ERPNext's
password form from the customer-facing path.

Hub changes:
  - services/targo-hub/lib/portal-auth.js (new) — POST /portal/request-link
    • 3-requests / 15-min per identifier rate limit (in-memory Map + timer)
    • Lookup by email (email_id + email_billing), customer id (legacy +
      direct name), or phone (cell + tel_home)
    • Anti-enumeration: always 200 OK with redacted contact hint
    • Email template with CTA button + raw URL fallback; SMS short form
  - services/targo-hub/server.js — mount the new /portal/* router

Client changes:
  - apps/client/src/pages/LoginPage.vue (new) — standalone full-page,
    single identifier input, success chips, rate-limit banner
  - apps/client/src/api/auth-portal.js (new) — thin fetch wrapper
  - apps/client/src/stores/customer.js — hydrateFromToken() sync decoder,
    stripTokenFromUrl (history.replaceState), init() silent Authentik
    fallback preserved for staff impersonation
  - apps/client/src/router/index.js — PUBLIC_ROUTES allowlist + guard
    that hydrates from URL token before redirecting
  - apps/client/src/api/auth.js — logout() clears store + bounces to
    /#/login (no more Authentik redirect); 401 in authFetch is warn-only
  - apps/client/src/composables/useMagicToken.js — thin read-through to
    the store (no more independent decoding)
  - PaymentSuccess/Cancel/CardAdded pages — goToLogin() uses router,
    not window.location to id.gigafibre.ca

Infra:
  - apps/portal/traefik-client-portal.yml — block /login and
    /update-password on client.gigafibre.ca, redirect to /#/login.
    Any stale bookmark or external link lands on the Vue page, not
    ERPNext's password form.

Docs:
  - docs/roadmap.md — Phase 4 checkbox flipped; MD5 migration item retired
  - docs/features/billing-payments.md — replace MD5 reset note with
    magic-link explainer

Online appointment booking (Plan B from the same discussion) is queued
for a follow-up session; this commit is Plan A only.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 13:25:28 -04:00
..
architecture docs: reorganize into architecture/features/reference/archive folders 2026-04-22 11:51:33 -04:00
archive docs: reorganize into architecture/features/reference/archive folders 2026-04-22 11:51:33 -04:00
assets docs: reorganize into architecture/features/reference/archive folders 2026-04-22 11:51:33 -04:00
features feat(portal): passwordless magic-link login — retire ERPNext /login 2026-04-22 13:25:28 -04:00
reference docs: reorganize into architecture/features/reference/archive folders 2026-04-22 11:51:33 -04:00
README.md docs: reorganize into architecture/features/reference/archive folders 2026-04-22 11:51:33 -04:00
roadmap.md feat(portal): passwordless magic-link login — retire ERPNext /login 2026-04-22 13:25:28 -04:00

Gigafibre FSM — Documentation

Start here. Everything you need to understand the system is one or two clicks away. Pick the row that matches why you're here.


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
Understand the system end-to-end — services, containers, networks, SSO, Traefik routes architecture/overview.md
Build a new feature — UI patterns, folder layout, router conventions, Pinia, feature-sliced design architecture/app-design.md
Touch ERPNext data — doctypes, customer → subscription → equipment → invoice, "Lead to Live" flow architecture/data-model.md
Work on billing, Stripe, payments — subscription lifecycle, invoice OCR, payment reconciliation, PPA features/billing-payments.md
Touch CPE / modems / ONTs — GenieACS, Oktopus, TR-069 → TR-369 migration, TP-Link XX230v diagnostics 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
Work on agent flows / automation — Flow Template model, trigger wiring, step editor, runtime contract features/flow-editor.md
Audit the wizard's SKU mapping vs legacy reference/erpnext-item-diff.md
Inspect the legacy PHP wizard reference/legacy-wizard/
Read a historical status snapshot archive/status-snapshots/

Folder map

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)
├── features/                    ← one doc per business capability
│   ├── billing-payments.md      (Stripe, invoices, subscriptions, PPA)
│   ├── cpe-management.md        (GenieACS, Oktopus, XX230v)
│   ├── 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)

Conventions

  • Edit in place. Don't copy-paste a section into a new file — link to it instead.
  • Dated snapshots go to archive/status-snapshots/. Don't create STATUS_YYYY-MM-DD.md at the root anymore.
  • 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.
  • The root README.md (one level up) is the repo introduction for non-technical readers; docs/README.md (this file) is the engineering index.

What changed on 2026-04-22

The 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 the table above to find the new location.

The only place old names still appear is inside archive/HANDOFF-2026-04-18.md and archive/status-snapshots/*.md, where the links are intentionally preserved as a frozen historical record.