Commit Graph

31 Commits

Author SHA1 Message Date
louispaulb
7a15bfd600 feat: Phase 6 — 242K tickets migrated as Issues with parent/child
- 38 Issue Types from ticket_dept
- 242,605 Issues created (open + closed)
- 25,805 parent/child links (incident pattern)
- Custom fields: parent_incident, is_incident, affected_clients, impact_zone, service_location, legacy_ticket_id
- Communications deferred (778K closed ticket messages — import separately)
- 0 staff→user mapped (ERPNext users need to be created/linked)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 15:06:58 -04:00
louispaulb
571f89976d feat: Phase 5 opening balance + AR analysis
- Journal Entry draft created with 1,918 customer balance lines
- AR analysis: $423K monthly billing, $77.96 avg/client, $62K aging 90j+
- Temporary Opening equity account created
- Scheduler remains PAUSED

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 14:47:18 -04:00
louispaulb
93dd7a525f feat: migration legacy → ERPNext phases 1-4 complete
Phase 1: 833 Items + 34 Item Groups + custom fields (ISP speeds, RADIUS, legacy IDs)
Phase 2: 6,667 Customers + Contacts + Addresses via direct PG (~30s)
Phase 3: Tax template QC TPS+TVQ + 92 Subscription Plans
Phase 4: 21,876 Subscriptions with RADIUS data

CRITICAL: ERPNext scheduler is PAUSED — do not reactivate without explicit go.

Includes:
- ARCHITECTURE-COMPARE.md: full schema mapping legacy vs ERPNext
- CHANGELOG.md: detailed migration log
- MIGRATION-PLAN.md: strategy and next steps
- scripts/migration/: idempotent Python scripts (direct PG method)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 14:35:02 -04:00
louispaulb
2e55a7d031 security: remove exposed credentials, add .gitignore, harden infra
- Replace hardcoded ERPNext token and Twilio SID with $VAR placeholders
- Add .gitignore to exclude .env files, node_modules, build output
- Untrack apps/website/.env (contained Supabase key)
- Remove git.gigafibre.ca references (use git.targo.ca only)

Server-side (applied live):
- Traefik: disable dashboard, close port 8080
- Oktopus: add Authentik forwardAuth middleware
- Log level: DEBUG → WARN

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 09:17:33 -04:00
louispaulb
04dc0ceb14 refactor: monorepo structure — apps/dispatch, apps/website, erpnext/
- Merged dispatch-app (17 commits) into apps/dispatch/
- Merged site-web-targo (4 commits) into apps/website/
- Renamed scripts/ → erpnext/
- Removed empty doctypes/
- Updated README with monorepo layout and Gigafibre branding

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 08:10:15 -04:00
louispaulb
6620652900 merge: import site-web-targo into apps/website/ (4 commits preserved)
Integrates www.gigafibre.ca (React/Vite) into the monorepo.
Full git history accessible via `git log -- apps/website/`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 08:09:15 -04:00
louispaulb
7da22ff132 merge: import dispatch-app into apps/dispatch/ (17 commits preserved)
Integrates the Dispatch PWA (Vue/Quasar) into the gigafibre-fsm monorepo.
Full git history accessible via `git log -- apps/dispatch/`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 08:08:51 -04:00
louispaulb
4c64e218a0 docs: infrastructure complète — schéma serveur, DNS, auth, APIs, gotchas
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>
2026-03-28 08:03:42 -04:00
louispaulb
c22240e6bf feat: Mailjet email for contact form + lead capture
- Contact form POSTs to /rpc/contact → Mailjet email to support@targo.ca
- Lead capture (availability dialog) POSTs to /rpc/lead → Mailjet email
- API server handles both endpoints with proper HTML formatting
- No Supabase edge functions needed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 15:56:23 -04:00
louispaulb
d8200b73e4 feat: add Accessibilité + Politique de confidentialité pages
- Import content from targo.ca/accessibilite/ and /politique-de-confidentialite/
- Styled with site design (Header, Footer, prose layout)
- Routes: /accessibilite, /politique-de-confidentialite
- Footer links now point to real pages instead of placeholders

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 15:33:25 -04:00
louispaulb
0af24643ff fix: contact form sends to API, remove dead links, secure .env
- Contact form now POSTs to /rpc/contact (www-api → n8n webhook)
- Footer links: Mon compte → store.targo.ca, placeholder # → /support
- .env added to .gitignore (Supabase keys should not be committed)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 15:28:06 -04:00
louispaulb
88dc3714a1 Initial deploy: gigafibre.ca website with self-hosted address search
React/Vite/shadcn-ui site for Gigafibre ISP.
Address qualification via PostgreSQL (5.2M AQ addresses, pg_trgm fuzzy search).
No Supabase dependency for address search.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 14:37:50 -04:00
louispaulb
fe8e3116bc docs: competitive analysis — Gaiia, Odoo, Zuper, Salesforce, ServiceTitan
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>
2026-03-27 14:04:05 -04:00
louispaulb
49494cf1a7 Initial commit: FSM data model, architecture docs, setup scripts
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>
2026-03-27 14:02:25 -04:00
louispaulb
6fc8a2d37f refactor: externalize ERP service token via VITE_ERP_TOKEN env var
Token is no longer hardcoded in source — injected at build time.
Build with: VITE_ERP_TOKEN="key:secret" npx quasar build
Prevents accidental token invalidation and keeps secrets out of git.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 13:39:41 -04:00
louispaulb
1263786b90 fix: update service token + fix API proxy routing
- Regenerated Admin API token (old one was invalidated by generate_keys)
- Traefik: separate routers for app (with Authentik) and /api/ (no auth)
- Nginx proxy: use container IP (cross-compose DNS doesn't resolve names)
- /outpost.goauthentik.io/ route for Authentik callbacks

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 13:39:11 -04:00
louispaulb
7ef22873f0 fix: handle Authentik session expiry in SPA
- authFetch uses redirect:'manual' to detect 302 from Authentik
- If session expired (302/401/opaqueredirect), reload page to trigger
  Traefik forwardAuth → Authentik re-login flow
- Logout redirects to Authentik invalidation flow
- App.vue calls checkSession on mount to populate user identity

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 13:34:39 -04:00
louispaulb
f1faffeab9 feat: switch Dispatch auth to Authentik forwardAuth
- Remove login form from App.vue (Authentik handles auth at Traefik level)
- Simplify auth store: no more checkSession/generate_keys complexity
- All ERPNext API calls use a service token (reliable, no CORS issues)
- User identity provided by Authentik X-authentik-email header
- Logout redirects to Authentik end-session URL
- Removed: login(), generate_keys, cookie fallback, token localStorage

Infrastructure:
- Created Authentik Proxy Provider for dispatch.gigafibre.ca
- Added to embedded outpost
- Applied authentik@file middleware to dispatch Traefik router
- Also removed unused Gitea (git.gigafibre.ca) containers + volumes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 13:33:09 -04:00
louispaulb
6d8339fa16 fix: map markers zoom drift — fixed-size container + center anchor
- All elements (SVG ring + avatar + badge) inside a fixed-size
  container (45x45px) with absolute positioning
- Avatar centered with calculated offset, ring fills container
- Mapbox marker anchor changed from 'bottom' to 'center'
- No more variable margins causing offset drift on zoom

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 13:08:36 -04:00
louispaulb
6f901f911c feat: SVG circular progress ring on map tech markers
Replace faint linear bars with SVG ring around avatar:
- Outer arc (faded): planned load / 8h capacity, color-coded
  green→yellow→orange→red based on load percentage
- Inner arc (solid green): jobs completed / total jobs
- Ring uses stroke-dasharray for clean arcs with round caps
- Tooltip: "Name — 2/5 jobs (3.0h / 7.0h)"
- Crew badge (purple "2") positioned on avatar corner

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 13:05:32 -04:00
louispaulb
f7fea2b8e5 feat: dual progress bar on map markers (load + completion)
- Background bar (faded): planned hours / 8h capacity
  Color codes: green <4h, yellow 4-6h, orange 6-7h, red 7h+
- Foreground bar (solid green): completed hours / 8h
  Shows real-time job completion progress
- Tooltip: "Name — X.Xh complété / X.Xh planifié"
- Both bars stacked with absolute positioning for clean overlay

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 12:22:11 -04:00
louispaulb
15813e6caf feat: map markers — workload progress bar + crew group badge
- Progress bar under each tech avatar showing daily load (0-8h)
  Green (<4h) → Yellow (4-6h) → Orange (6-8h) → Red (8h+)
  Includes both primary queue and assistant jobs
- Crew badge: purple circle with count (e.g. "2") when tech has
  assistants on today's jobs — indicates grouped team
- Tooltip shows "Name — X.Xh / 8h"
- Marker now uses gpsCoords || coords for visibility check
  (fixes techs with GPS but no static coords)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 12:16:56 -04:00
louispaulb
af42c6082e feat: auth gate, GPS hybrid tracking, tech CRUD modal, ERPNext API proxy
Authentication:
- Add App.vue login gate (v-if auth.loading / v-else-if !auth.user / router-view)
- Fix auth.checkSession with try/finally to always reset loading
- Fix generate_keys method name for Frappe v16 (generate_keys, not generate_keys_for_api_user)
- Auto-generate API token on cookie-based auth (Authentik SSO support)
- Remove duplicate checkSession from DispatchV2Page (was causing infinite mount/unmount loop)

GPS Tracking — Hybrid REST + WebSocket:
- Initial REST fetch per-device in parallel (Traccar API only supports one deviceId per request)
- WebSocket real-time updates via wss://dispatch.gigafibre.ca/traccar/api/socket
- Auto-fallback to 30s polling if WebSocket fails, with exponential backoff reconnect
- Module-level guards (__gpsStarted, __gpsPolling) to prevent loops on component remount
- Only update tech.gpsCoords when value actually changes (prevents unnecessary reactive triggers)

Tech Management (GPS Modal):
- Add/delete technicians directly from GPS modal → persists to ERPNext
- Inline edit: double-click name to rename, phone field, status select
- Auto-generate technician_id (TECH-N+1)
- Unlink jobs before delete to avoid ERPNext LinkExistsError
- Added phone/email custom fields to Dispatch Technician doctype

Infrastructure:
- Nginx proxy: /api/ → ERPNext (same-origin, eliminates all CORS issues)
- Nginx proxy: /traccar/ WebSocket support (Upgrade headers, 86400s timeout)
- No-cache headers on index.html and sw.js for instant PWA updates
- BASE_URL switched to empty string in production (same-origin via proxy)

Bug fixes:
- ERPNext Number Card PostgreSQL fix (ORDER BY on aggregate queries)
- Traccar fetchPositions: parallel per-device calls (API ignores multiple deviceId params)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 12:02:04 -04:00
louispaulb
f1badea201 fix: add watcher for GPS position updates on map markers
Technician GPS positions from Traccar were being fetched and stored
correctly every 30s but drawMapMarkers() was never triggered on
gpsCoords change, so markers stayed at their initial position.

Added a deep watcher on store.technicians[].gpsCoords in useMap.js
that calls drawMapMarkers() whenever any technician's GPS position
is updated by pollGps().

Also includes traccar.js API module and dispatch store GPS polling
(pollGps / startGpsPolling / stopGpsPolling).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 20:17:13 -04:00
louispaulb
859f043bb2 Refactor: extract autoDispatch, serializeAssistants, store assign logic
- Extract useAutoDispatch.js (autoDistribute + optimizeRoute)
- Add serializeAssistants() to useHelpers — removes 6 duplications
- Move smartAssign/fullUnassign into Pinia store
- Add drag-and-drop on dispatch criteria modal
- DispatchV2Page.vue: 1463 → 1385 lines

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 17:25:33 -04:00
louispaulb
a5822f7a5b Add deploy-fast.sh — local build + docker cp (~5s vs ~30s)
No Docker image rebuild needed. Builds PWA locally with npx quasar
then copies dist/pwa directly into the ERPNext frontend container.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 16:12:07 -04:00
louispaulb
632e4ae0d1 Refactor: modular architecture — extract composables & components
- Extract useDragDrop.js (drag/drop, block move, resize)
- Extract useSelection.js (lasso, multi-select, hover linking)
- Extract WeekCalendar.vue, MonthCalendar.vue, RightPanel.vue
- DispatchV2Page.vue: 3018 → 1438 lines (orchestration only)
- Remove <style scoped> — styles cascade to child components
- Add .dockerignore (build context 214MB → 112KB)
- Add infra/ with docker-compose reference and .env.example

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 16:08:56 -04:00
louispaulb
b90db4673a Fix: restore techCtx and openTechCtx lost during map extraction
These were accidentally deleted when removing ~576 lines of inline map code.
Caused ReferenceError preventing the app from loading data.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 14:22:19 -04:00
louispaulb
ec385c99d0 Add ARCHITECTURE.md — full project documentation
Covers: stack, directory structure, routes, ERPNext doctypes,
PostgreSQL extensions, features, component communication,
planned modules, and deploy instructions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 14:11:40 -04:00
louispaulb
e2b775c077 Clean up: remove duplicate TagInput, delete quasar-migration branch
- Removed src/components/shared/TagInput.vue (exact duplicate of src/components/TagInput.vue)
- Deleted feature/quasar-migration branch from local and remote
- Verified build + deploy: design intact

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 14:11:40 -04:00
louispaulb
1b0fc89304 Initial commit — OSS/BSS Field Dispatch app
Current state: custom CSS + vanilla Vue components
Architecture: modular with composables, provide/inject pattern
Ready for progressive migration to Quasar native components

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 14:11:40 -04:00