gigafibre-fsm/CONTEXT.md
louispaulb 101faa21f1 feat: inline editing, search, notifications + full repo cleanup
- 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>
2026-03-31 07:34:41 -04:00

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, latitude
  • priority (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_date
  • tags (Table→Dispatch Tag Link), assistants (Table→Dispatch Job Assistant)
  • equipment_items, materials_used, checklist, photos, customer_signature
  • actual_start, actual_end, travel_time_min, completion_notes

Dispatch Technician

  • technician_id, full_name, user (Link→User), phone, email
  • status (Disponible/En route/En pause/Hors ligne), color_hex
  • longitude, 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)
  • 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_staff
  • issue_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_important
  • service_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:

  1. Each job has tags with required flag and level (minimum skill needed)
  2. Each tech has tags with level (skill proficiency 1-5)
  3. Auto-dispatch: find techs where tech.level >= job.requiredLevel for all required tags
  4. Among matches, pick the lowest adequate tech (closest skill to required level)
  5. 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

  1. Tag technicians with skills — assign Fibre/Télé/etc. tags + levels to 46 techs
  2. Wire auto-dispatch logic — implement the matching algorithm in useAutoDispatch.js
  3. Ticket-to-dispatch UI — button in ticket detail modal to create Dispatch Job from Issue
  4. Customer portal — store.targo.ca/clients replacement with Stripe payments
  5. Field tech mobile app — barcode scanner, equipment install, job completion
  6. 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