Optimisation sûre (vérifiée, 0 régression) :
- helpers.js : `cors()` partagé (en-têtes CORS génériques) au lieu de 2 copies locales.
- address-conformity.js : réutilise `pool` (address-db) + `cors` (helpers) au lieu de redéfinir un Pool +
cors → 1 seul client pg local partagé pour rqa_addresses/fiber.
- address-validate.js : utilise helpers.cors.
docs/architecture/VISION.md (NOUVEAU) — vision + plan de modularisation + roadmap d'optimisation, fondé sur
un audit chiffré (hub 58 modules/23k lignes, Ops 45k lignes, god-files identifiés). Découpe en 9 domaines
(bounded contexts), principe « source de vérité + validation à la saisie + lien stable » (modèle Adresses
généralisé à Client/Device/Service), optimisations P0/P1/P2, métriques de succès. Complète les docs
architecture existants + ENGINEERING_PRACTICES.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- address-search.js : expose searchAddressesRpc() → RPC Postgres `search_addresses` (pg_trgm), la MÊME
recherche que l'autocomplete de disponibilité fibre. Trouve les rues que l'ilike manquait (générique géré
par la colonne odonyme_recompose_long + phase 2 trigram), priorise les CP J0L/J0S (territoire).
- geocodeRQA() (bridge) bascule de l'ilike vers la RPC. Garde-fou : la phase 2 trigram dérive quand le
civique est absent du RQA (« 2245 René-Vinet » → « Rue Grenet, Montréal »). On n'accepte un résultat que si
le civique concorde + un token de nom de rue correspond + (territoire J0L/J0S OU CP/ville legacy concordants).
Vérifié sur les données réelles : accepte 494 Av Curry / 3055 Routhier / 228 Principale / 61 Jean-François ;
rejette René-Vinet→Grenet/Panet, chemin Ridge→Ferme, rue West→Perras (bons faux positifs écartés).
- Le faible compte RQA (8) = haute précision (l'ilike comptait 17 dont des faux positifs). Mapbox couvre le
reste (rues neuves/civiques absents) ; ~109/125 (87 %) coordonnés ; les « aucune » = campings/villes mal écrites.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pont (legacy-dispatch-sync.js) :
- Import des coordonnées par job via cascade : table legacy `delivery` (point de service exact,
JOIN ticket.delivery_id) > Service Location ERPNext > géocodage RQA > géocodage Mapbox.
Validation bornes Québec (coord()). Couverture 153/172 (89%).
- Géocodage RQA corrigé : retrait du générique de voie (Rue/Rang/Chemin absent de
odonyme_recompose_normal) + code postal non accolé au terme (sinon ilike ne matche jamais).
- Repli Mapbox geocoding pour rues trop récentes pour le RQA (MAPBOX_TOKEN).
- Backfill + UPGRADE : coords delivery écrasent des coords SL moins précises (jamais l'inverse).
- Comptabilité honnête : vérifie r.ok sur create/update (erp ne throw pas) → errors + error_samples.
- Verrou de sérialisation sync() : tick + runs manuels ne se chevauchent plus (frappe_pg).
- Subject tronqué à 140 (champ Data) → corrige CharacterLengthExceededError sur jobs sans SL.
- Observabilité : coord_src tally + error_samples dans le résumé.
Ops Planification (éditeur de journée) :
- travelBetween() consulte une matrice Mapbox Matrix chargée à l'ouverture (loadDayRoute) →
temps de trajet ROUTIERS RÉELS ; réordonnancement instantané sans nouvelle requête.
Repli haversine si Mapbox indispo. Indicateur 🚗 réel vs 📏 vol d'oiseau.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- pont : stocke legacy_dept (dept osTicket) sur le Dispatch Job + backfill des 70 existants
- useHelpers.jobColor/legacyDeptColor : palette comme legacy (Installation vert, Réparation or,
Télé rose, Téléphonie vert pâle, Désinstallation rouge foncé) ; tech en pause = rouge vif prioritaire
- store _mapJob : expose legacyDept + legacyTicketId
- RightPanel : champ « Ticket legacy » (#id · dept) — le client est déjà un lien cliquable vers la fiche
- doc mise à jour
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tire régulièrement les tickets ouverts assignés au compte « Tech Targo » (staff 3301)
de la DB legacy MariaDB et crée/maj un Dispatch Job ERPNext (pool à répartir).
- lib/legacy-dispatch-sync.js : fetch (status=open AND assign_to=3301) + mapping
customer (legacy_account_id) / Service Location (coords) / job_type (dept) /
scheduled_date (epoch→America/Toronto) / start_time (am|pm|HH:MM) / priority
- Idempotent via Custom Field Dispatch Job.legacy_ticket_id (lookup avant create) ;
ne clobbe pas le travail du répartiteur (maj date seulement si encore open+non assigné)
- SÉQUENTIEL (frappe_pg) ; endpoints GET preview (dry-run) + POST run
- Récurrence opt-in : startSync() au boot, LEGACY_DISPATCH_SYNC=on + _MIN=15
- server.js : route /dispatch/legacy-sync + startSync()
- doc docs/features/legacy-dispatch-bridge.md + index
Mise en service : 70 tickets importés (0 erreur), récurrence 15 min active.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- On Hold : onCellDrop REFUSE d'assigner un job en attente d'un prérequis (notify), reste au panneau (≠ 🔒 visuel)
- Hors quart publié : marqueur ⚠ dans la cellule libre (offShiftJobs/rawCellJobs lit occByTechDay brut) +
badge « hors quart » dans la timeline ressource — surface les jobs assignés un jour sans quart
- Deep-link : Planif gotoDispatch(tech) → /dispatch?tech=&date= ; DispatchPage lit route.query
(goToDay(date+T12:00:00) anti-décalage tz + selectTechOnBoard)
- #58 : bouton « Désaffecter + aviser le client » dans le dialogue d'unassign Dispatch →
roster.notifyReschedule (désassigne serveur + SMS lien /book au mobile du Customer)
- Doc docs/features/roster.md mise à jour (Fait récemment / TODO)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Panneau « jobs à assigner » v2 : multi-sélection (cases), groupes parent-enfant
surlignés, heuristique terrain/à distance (activation/netadmin pré-décochés),
pré-total d'heures, aperçu d'occupation PROJETÉE au survol (barre fantôme + badge).
Fix barre d'occupation figée après drop : /roster/assign-job pose désormais un
start_time (premier-trou-libre dans le shift) + garantit duration_h, sinon le job
compte dans les heures mais n'affiche aucun bloc. Nouvel endpoint
/roster/backfill-start-times (idempotent) pour rattraper l'historique.
Infobulle de cellule : nb de jobs + liste triée par priorité (occupancyByTechDay
renvoie jobs[]). Timeline contextuelle par ressource (dialogue, 0 appel réseau).
Lisibilité du drag : fantôme compact semi-transparent décalé sous le curseur
(ne masque plus l'aperçu) + source estompée.
Scoring de priorité : hook proximité (neutre — secteur géré manuellement),
réservé à 20% du score quand la géoloc arrivera.
Refactor hub : helper partagé firstFitStart (assign-job + backfill).
Nettoyage : retrait code mort (onDeleteRosterTag, projUsedH), carte des sections
en tête de PlanificationPage. Doc : docs/features/roster.md + index.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Spec v1 du module de gestion de shifts + approbations dans le dispatch
(décision build-our-own vs Frappe HR déjà actée: PG + multitenant + géofence-job).
Modèle de données, workflows d'approbation (ShiftRequest/Swap/AttendanceRequest),
géofence vs adresse du job dispatch, auto-attendance, auto-roster Timefold,
mapping validé vs Frappe HR, intégrations (Authentik/dispatch/ERPNext API), phasage.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reviewer-facing document covering company/use-case, why we need
delivery_type=SHORTLINK (brand+language+deliverability), what data
we send (no PII beyond name/email/internal opaque ID), security
posture (token in env, sandbox-by-default with email override
to a single test inbox), CASL compliance, customer experience,
and the planned /gifts/{uuid} redemption polling.
Provided as a single markdown file under docs/ so it can be exported
to PDF for the Giftbit review team.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Done what the docs suggested in c31a9e0 — actually installed
excel-azmin/frappe_pg on prod erp.gigafibre.ca (1.0.0, master pinned
at commit a237f5995b). Hit one compat bug along the way and fixed it.
The bug
frappe_pg monkey-patches PostgresDatabase.commit() and .rollback()
with wrappers that have the OLD `(self)` signature. Frappe 16.12+
now calls `db.rollback(chain=True)` from app.py:sync_database(),
which makes every HTTP request crash with:
TypeError: patched_rollback() got an unexpected keyword argument 'chain'
Symptom: HTTP 500 on /api/method/ping, Sales Invoice list, etc.
Customer Server Scripts that don't return through sync_database
(like our customer_balance) still worked, which is why the bug
only surfaced after the post-install restart.
The fix
Two-part: signatures take `*args, **kwargs`, and the wrapped call
forwards them to the original. Idempotent sed.
-def patched_rollback(self):
+def patched_rollback(self, *args, **kwargs):
- return _original_rollback(self)
+ return _original_rollback(self, *args, **kwargs)
Both files in frappe_pg need it: postgres/database_patches.py and
patches/postgres_fix.py. Same fix for patched_commit.
Saved as patches/fix_frappe_pg_signatures.sh so we can re-apply after
every `bench update` or fresh install. The comment block in the
script documents why it exists and links the upstream issue (TODO:
file PR at excel-azmin/frappe_pg). docs/SETUP.md §7 was updated to
mention the post-install patch step, the nginx-IP-cache gotcha that
will produce a confusing 502 if you only restart the backend, and
the correct repo (excel-azmin, not the-commit-company that I had
hallucinated in the previous commit).
Smoke test results post-install:
ping, Customer list, Sales Invoice list, Service Location list,
customer_balance Server Script, ops SPA, hub /health — all 200.
ERPNext was built for MariaDB; we run it on PostgreSQL because that's
what fit the legacy migration. Frappe's SQL generator is loose on
MariaDB (missing GROUP BY columns OK, double-quoted strings OK,
HAVING without GROUP BY OK) but strict on Postgres, so we end up
hand-patching files in `patches/fix_pg_groupby.py` after every
ERPNext upgrade. The community has packaged a comprehensive fix as
a Frappe app — `frappe_pg` — that covers the same bugs in one
place. The cleaner path long-term is to install that app instead
of growing our own patch set.
Two doc updates:
- docs/architecture/overview.md §6 item 8 — full background:
the 3 SQL patterns that break (GROUP BY, HAVING, double-quoted
string literals), the 12 hotspots we've already patched, the
4 known remaining (bank_clearance, bank_reconciliation_tool,
accounts/utils L1660, gross_profit), and the install
recommendation with trade-offs (pin a commit, validate on
staging, keep our patches as backup for 4-6 weeks).
- docs/SETUP.md §7 — quick-start install commands for whoever
decides to flip the switch, plus the warning about pinning
rather than tracking main. Also notes that custom Server
Scripts with raw SQL (like `customer_balance`) need the same
single-quote vs double-quote vigilance even after installing
frappe_pg, and the export-fixtures hint to version-control
them.
Three places in last week's docs refresh got the DocuSeal URL wrong —
must have been a copy-paste glitch since other parts of the same docs
(roadmap.md, module-interactions.md, archive snapshots) had it right.
Verified against the deployed Traefik labels:
traefik.http.routers.docuseal.rule = Host(`sign.gigafibre.ca`)
`docs.gigafibre.ca` doesn't even resolve in DNS. Fixed in:
• README.md (services table)
• docs/README.md (services tree)
• docs/architecture/overview.md (infra ASCII diagram)
Mass refresh — the docs were last touched 2026-04-22, two weeks behind
shipped reality. This commit updates 9 files to reflect current truth.
WHAT CHANGED IN THE PRODUCT (since 22 Apr) THAT THE DOCS NOW REFLECT:
• Oktopus CE / TR-369 stack decommissioned (containers + volumes +
images all removed; broker had filled /dev/sdb with 75 GB of debug
logs and took ERPNext down for 4 days). Hub gates the integration
behind OKTOPUS_DISABLED=1 — modules retained, no-op'd at runtime.
• dispatch.gigafibre.ca (legacy PHP SPA) replaced by an nginx 301
redirect to /ops/#/dispatch.
• Top toolbar of the dispatch module: collapsed to single-color
Lucide icons + ⋯ overflow menu + "Vue principale ▾" + "[👥 N ▾]"
resource type chip (defaults to techs, materials in the dropdown
only when relevant).
• Tech home base / departure point: editable per-tech via 📍 button,
address geocode (Nominatim) or click-on-map picker, right-click
on tech pin opens the same actions. Map defaults centered on
Gigafibre HQ (1867 chemin de la Rivière, Sainte-Clotilde) instead
of downtown Montreal.
• POST /auth/users invite flow on the hub: creates the Authentik
user, sets a temp password, mails it via Mailjet (Authentik's
own recovery flow isn't configured), creates the matching ERPNext
System User. Surfaced in ops Settings → Utilisateurs → Inviter.
• Two Authentik instances clarified as parallel-and-permanent (not
a migration): auth.targo.ca for staff, id.gigafibre.ca for clients.
FILES TOUCHED:
README.md — service table refreshed, arch diagram redrawn (no
Oktopus row), auth section explains the invite flow + two
parallel instances.
docs/architecture/overview.md — new "Decommissioned" section,
correct retirement status for dispatch-app + apps/field, two
Authentik instances explicitly distinguished, dev-gotchas list
rewritten (drops MongoDB AVX, adds log-rotation hard-learned
lesson, adds note about Authentik recovery flow).
docs/architecture/data-model.md — Step 5 hardware provisioning
now describes the GenieACS path (TR-069 Inform → preset push)
instead of the dead TR-369 path.
docs/architecture/module-interactions.md — oktopus.js and
oktopus-mqtt.js entries marked as gated, provision.js note
updated, GenieACS row in external-integrations updated, MQTT
row removed from real-time channels, interaction matrix loses
the Oktopus column and gains an Authentik admin REST cell.
docs/features/dispatch.md — Top bar section completely rewritten
to match the current chrome (left/center/right regions,
single-color Lucide, dropdowns); new Tech home base section
documenting the 📍 + map-pick + right-click flows; retirement
note now reads as a status, not a plan.
docs/features/cpe-management.md — full rewrite. Oktopus migration
plan replaced by a "decommissioned" note + the existing GenieACS
+ modem-bridge architecture as the steady state. TP-Link XX230v
deep-dive sections preserved (still accurate).
docs/README.md, docs/features/README.md, docs/roadmap.md —
intent-table descriptions and live-URLs table corrected.
The docs/archive/ snapshots (2026-04-18, 2026-04-19) are untouched —
they're historical and should remain that way.
A few connected fixes around the invite UI shipped in 81d61aa:
1. **Bug in 81d61aa**: `auth.js` referenced `erpFetch` without importing
it, so every invite returned `erpnext.ok=false` with the silent
"erpFetch is not defined" error in the catch. Imported it from
./helpers alongside the other helpers we already used.
2. **Authentik recovery flow not configured** (caught while smoke-testing):
the brand `auth.targo.ca` has `flow_recovery=None` and no SMTP, so
`POST /core/users/{pk}/recovery_email/` returned 400 "No recovery
flow set." Rather than build out a full Authentik recovery flow
via API (multiple stages, brand patch, SMTP env var changes), the
hub now generates a strong-but-readable temp password
(`X7K2-9NQB-4GHM-3RTW` style — no look-alike chars), POSTs it via
`/core/users/{pk}/set_password/`, and emails it via the existing
Mailjet SMTP (already wired into lib/email.js for invoice sends).
Returns `{temp_password, password_set, email_sent}` so the admin
has a fallback if Mailjet drops the message.
3. **Settings dialog** now shows a credentials panel after submit:
• Green banner "✓ Courriel envoyé" when email_sent=true
• Yellow "⚠ transmettez manuellement" when email_sent=false
• The temp password as a copyable field either way
• ERPNext User creation status
4. **Dev onboarding**: added `apps/ops/.env.example`,
`services/targo-hub/.env.example`, and a top-level `docs/SETUP.md`
that explains the local-dev flow (clone → cp .env.example .env →
npm install → npx quasar dev). The example envs are commented
per-section so a new dev knows which keys correspond to which
external integration. None of the real secrets are checked in —
the .gitignore already covers .env files.
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>
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>
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>
Records what shipped in e50ea88 (scan + device pages, offline store,
Gemini vision pipeline) and lays out the remaining phases: PWA
hardening, auth unification, magic-link tech access, flow-runtime
integration, and final apps/field removal.
Fixes stale `/t/{token}` route reference in Phase 2 → `/j/`.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Invoice OCR migrated from Ollama (GPU-bound, local) to Gemini 2.5
Flash via new targo-hub /vision/invoice endpoint with responseSchema
enforcement. Ops VM no longer needs a GPU.
- Ops /j/* now has full camera scanner (TechScanPage) ported from
apps/field with 8s timeout + offline queue + auto-link to Dispatch
Job context on serial/barcode/MAC 3-tier lookup.
- New TechDevicePage reached via /j/device/:serial showing every
ERPNext entity related to a scanned device: Service Equipment,
Customer, Service Location, active Subscription, open Issues,
upcoming Dispatch Jobs, OLT info.
- New docs/VISION_AND_OCR.md (full pipeline + §10 relationship graph
+ §8.1 secrets/rotation policy). Cross-linked from ARCHITECTURE,
ROADMAP, HANDOFF, README.
- Nginx /ollama/ proxy blocks removed from both ops + field.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Full system documentation: Docker containers, request flows,
targo-hub endpoints, GenieACS integration, ops app structure,
external service dependencies, and device diagnostics data flow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- EquipmentDetail: collapsible node groups (clients grouped by mesh node)
- Signal strength as RSSI % (0-255 per 802.11-2020) with 10-tone color scale
- Management IP clickable link to device web GUI (/superadmin/)
- Fibre status compact top bar (status + Rx/Tx power when available)
- targo-hub: WAN IP detection across all VLAN interfaces
- targo-hub: full WiFi client count (direct + EasyMesh mesh repeaters)
- targo-hub: /devices/:id/hosts endpoint with client-to-node mapping
- ClientsPage: start empty, load only on search (no auto-load all)
- nginx: dynamic ollama resolver (won't crash if ollama is down)
- Cleanup: remove unused BillingKPIs.vue and TagInput.vue
- New docs and migration scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add /acs/export endpoint: dumps all provisions, presets, virtual
params, files metadata in one call (insurance policy for migration)
- Add /acs/provisions, /acs/presets, /acs/virtual-parameters, /acs/files
- Shell script export_genieacs.sh for offline full backup
- TR069-TO-TR369-MIGRATION.md: phased migration plan from GenieACS
to Oktopus with parallel run, provision mapping, CPE batching
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- InlineField component + useInlineEdit composable for Odoo-style dblclick editing
- Client search by name, account ID, and legacy_customer_id (or_filters)
- SMS/Email notification panel on ContactCard via n8n webhooks
- Ticket reply thread via Communication docs
- All migration scripts (51 files) now tracked
- Client portal and field tech app added to monorepo
- README rewritten with full feature list, migration summary, architecture
- CHANGELOG updated with all recent work
- ROADMAP updated with current completion status
- Removed hardcoded tokens from docs (use $ERP_SERVICE_TOKEN)
- .gitignore updated (docker/, .claude/, exports/, .quasar/)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Guide de référence et de transfert couvrant toute l'infra Gigafibre:
Traefik, Authentik SSO, ERPNext, Dispatch PWA, n8n, Mailjet, Twilio,
DNS Cloudflare, Docker compose, build/deploy, pièges connus.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Full feature matrix comparing 6 FSM platforms with Gigafibre.
Gaiia (YC, $13.2M) is the primary comparable — ISP-specific OSS/BSS.
Key insights:
- Gaiia charges per-subscriber; Gigafibre is self-hosted (free)
- Our dispatch UX already exceeds Gaiia's public features
- Biggest gaps: customer portal, online checkout, mobile tech app
- Quick wins: auto travel time, tech status updates, SMS notifications
Priority roadmap ordered by ROI for a 2-10 tech ISP operation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Data model inspired by Odoo OCA Field Service + Salesforce FS patterns.
Adapted for small ISP/telecom (Gigafibre) running ERPNext.
Doctypes: Service Location, Service Equipment, Service Subscription
+ child tables for equipment history, checklists, photos, materials
+ extended Dispatch Job with customer/location/equipment links
Docs: architecture overview, tech stack, auth flow, industry comparison, roadmap
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>