- 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>
7.5 KiB
7.5 KiB
Targo/Gigafibre FSM — Context for Claude Cowork
Last updated: 2026-03-30
Project Overview
Targo Internet is a fiber ISP in Quebec. Gigafibre is the consumer brand. We're migrating from a legacy PHP/MariaDB system to ERPNext v16 + custom Vue.js (Quasar) apps.
Architecture
Server: 96.125.196.67 (Proxmox VM)
Traefik v2.11 (80/443) → Docker containers:
erp.gigafibre.ca → ERPNext v16.10.1 (PostgreSQL, 9 containers)
erp.gigafibre.ca/ops/ → Ops PWA (Quasar/Vue3, Authentik SSO via forwardAuth)
dispatch.gigafibre.ca → Legacy dispatch app (being replaced by ops /dispatch)
auth.targo.ca → Authentik SSO
oss.gigafibre.ca → Oktopus CE (TR-069)
git.targo.ca → Gitea
n8n.gigafibre.ca → n8n workflows
Codebase Layout
gigafibre-fsm/
├── apps/
│ ├── ops/ ← Main ops PWA (Quasar v2 + Vite)
│ │ ├── src/
│ │ │ ├── api/
│ │ │ │ ├── auth.js # authFetch with token: b273a666c86d2d0:06120709db5e414
│ │ │ │ ├── dispatch.js # CRUD for Dispatch Job, Tech, Tag + rename/delete
│ │ │ │ ├── service-request.js # ServiceRequest, ServiceBid, EquipmentInstall
│ │ │ │ └── traccar.js # GPS tracking (Traccar API)
│ │ │ ├── components/
│ │ │ │ ├── shared/
│ │ │ │ │ ├── TagEditor.vue # Universal inline tag editor (autocomplete, color, level, required)
│ │ │ │ │ └── TagInput.vue # Old tag input (deprecated, replaced by TagEditor)
│ │ │ │ └── customer/ # CustomerHeader, CustomerInfoCard, etc.
│ │ │ ├── composables/ # useHelpers, useScheduler, useMap, useDragDrop, etc.
│ │ │ ├── config/
│ │ │ │ └── erpnext.js # BASE_URL='', MAPBOX_TOKEN, TECH_COLORS
│ │ │ ├── modules/
│ │ │ │ └── dispatch/
│ │ │ │ └── components/ # TimelineRow, BottomPanel, JobEditModal, RightPanel, etc.
│ │ │ ├── pages/
│ │ │ │ ├── DispatchPage.vue # Full-screen dispatch V2 (1600+ lines)
│ │ │ │ ├── ClientDetailPage.vue
│ │ │ │ ├── ClientsPage.vue
│ │ │ │ ├── TicketsPage.vue
│ │ │ │ └── ...
│ │ │ ├── stores/
│ │ │ │ ├── dispatch.js # Pinia store: technicians, jobs, allTags
│ │ │ │ └── auth.js
│ │ │ └── router/index.js # / = MainLayout, /dispatch = standalone
│ │ └── deploy.sh # Build + deploy to erp.gigafibre.ca
│ └── dispatch/ # Legacy standalone dispatch app (deprecated)
├── scripts/migration/ # Python migration scripts (tickets, customers, etc.)
└── CONTEXT.md # This file
Key ERPNext Custom Doctypes
Dispatch Job
ticket_id,subject,customer(Link→Customer),service_location(Link→Service Location)job_type(Select: Installation/Réparation/Maintenance/Retrait/Dépannage/Autre)source_issue(Link→Issue),address,longitude,latitudepriority(low/medium/high),duration_h,status(open/assigned/in_progress/done)assigned_tech(Link→Dispatch Technician),assigned_user(Link→User)scheduled_date,start_time,end_datetags(Table→Dispatch Tag Link),assistants(Table→Dispatch Job Assistant)equipment_items,materials_used,checklist,photos,customer_signatureactual_start,actual_end,travel_time_min,completion_notes
Dispatch Technician
technician_id,full_name,user(Link→User),phone,emailstatus(Disponible/En route/En pause/Hors ligne),color_hexlongitude,latitude,traccar_device_id,employee(Link→Employee)tags(Table→Dispatch Tag Link)
Dispatch Tag
label,color(hex),category(Skill/Service/Region/Equipment/Custom)- Current tags: Fibre (#3b82f6), Téléphonie (#f59e0b), TV (#06b6d4), Installation (#06b6d4), Fusionneur (#f59e0b), Monteur (#8b5cf6), Câblage (#10b981), Caméra IP (#a855f7), Garage (#78716c), Urgence (#ef4444), Rive-Sud (#14b8a6), Montréal (#06b6d4)
Dispatch Tag Link (child table)
tag(Link→Dispatch Tag),level(Int, default 0),required(Check, default 0)- On techs: level = skill proficiency (1=base, 5=expert)
- On jobs: level = minimum required proficiency, required = mandatory for dispatch matching
Issue (ERPNext standard + custom fields)
legacy_ticket_id,assigned_staff(group name e.g. "Tech Targo"),opened_by_staffissue_type: "Reparation Fibre", "Installation Fibre", "Install/Reparation Télé", "Téléphonie", "Télévision", "Monteur", "Fusionneur", "Installation", "Support", "ToDo", "Projet", "Conception"is_incident,impact_zone,affected_clients,parent_incident,is_importantservice_location(Link→Service Location)
Auth Pattern
All API calls use token auth via authFetch():
Authorization: token $ERP_SERVICE_TOKEN // see server .env
Authentik SSO protects the ops app at Traefik level (forwardAuth). The token is injected server-side by the nginx proxy (or via VITE_ERP_TOKEN in dev).
Tag/Skill System — Auto-Dispatch Logic (designed, not yet wired)
The dispatch system uses a cost-optimization model inspired by AI agent routing:
- Each job has tags with
requiredflag andlevel(minimum skill needed) - Each tech has tags with
level(skill proficiency 1-5) - Auto-dispatch: find techs where
tech.level >= job.requiredLevelfor all required tags - Among matches, pick the lowest adequate tech (closest skill to required level)
- This preserves experts for complex jobs — don't send the level-5 splicer to a basic install
Example:
- Job: Fibre (required, level 3) → needs someone competent
- Tech A: Fibre level 5 (expert) — can do it but overkill
- Tech B: Fibre level 3 (adequate) — send this one, keep A free
20 Test Dispatch Jobs (2026-03-31)
Created from Tech Targo Issues. Tagged by issue_type:
- 6 jobs: Fibre only (Reparation Fibre)
- 4 jobs: Fibre + Installation (Installation/Installation Fibre)
- 10 jobs: TV + Téléphonie (Install/Reparation Télé)
46 Dispatch Technicians
All imported from legacy system. Not yet tagged with skills — need team breakdown.
Deploy
cd apps/ops && bash deploy.sh # builds Quasar PWA + deploys to erp.gigafibre.ca
Pending Work
- Tag technicians with skills — assign Fibre/Télé/etc. tags + levels to 46 techs
- Wire auto-dispatch logic — implement the matching algorithm in useAutoDispatch.js
- Ticket-to-dispatch UI — button in ticket detail modal to create Dispatch Job from Issue
- Customer portal — store.targo.ca/clients replacement with Stripe payments
- Field tech mobile app — barcode scanner, equipment install, job completion
- Code optimization — extract components from ClientDetailPage.vue (1500+ lines)
ERPNext PostgreSQL Gotchas
- GROUP BY requires all selected columns (not just aggregates)
- HAVING clause needs explicit column references
- Double-quoted identifiers are case-sensitive
- Transaction abort cascades (one error blocks subsequent queries until rollback)
- Patches applied in
scripts/migration/for bulk operations