gigafibre-fsm/docs/INFRASTRUCTURE.md
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

12 KiB

Gigafibre — Infrastructure & Services

Document de référence pour l'infrastructure complète. Sert de guide de transfert pour toute personne reprenant l'environnement.

Vue d'ensemble

Internet
  │
  ▼
96.125.196.67 (Proxmox VM, Ubuntu 24.04)
  │
  ├─ Traefik v2.11 (ports 80/443)
  │   ├─ Let's Encrypt TLS auto-renew
  │   ├─ ForwardAuth middleware → Authentik
  │   └─ Routes → Docker containers
  │
  ├─ Authentik SSO (auth.targo.ca)
  │   └─ ForwardAuth pour toutes les apps protégées
  │
  ├─ ERPNext v16.10.1 (erp.gigafibre.ca)
  │   ├─ 9 containers (frontend, backend, worker, scheduler, redis, postgres)
  │   └─ Custom doctypes: Dispatch + FSM
  │
  ├─ Dispatch PWA (dispatch.gigafibre.ca)
  │   ├─ nginx servant les fichiers statiques Vue/Quasar
  │   └─ Proxy /api/ → ERPNext, /traccar/ → Traccar
  │
  ├─ n8n (n8n.gigafibre.ca)
  │   ├─ Auto-login proxy (lit X-authentik-email de forwardAuth)
  │   └─ Workflows: SMS routing, sharing, automation
  │
  ├─ Gitea (git.targo.ca)
  │
  ├─ www.gigafibre.ca
  │   ├─ React/Vite site vitrine
  │   └─ API Node.js (recherche adresses, contact, SMS)
  │
  ├─ Oktopus CE (oss.gigafibre.ca) — TR-069 CPE management
  │
  └─ Hub (hub.gigafibre.ca) — Dashboard interne

DNS (Cloudflare)

Domaine gigafibre.ca géré sur Cloudflare en mode DNS-only (pas de proxy CF, Traefik gère le TLS).

Record Type Valeur Notes
@ A 96.125.196.67
*.gigafibre.ca A 96.125.196.67 Wildcard
@ MX aspmx.l.google.com (10) Google Workspace
@ MX alt1-4.aspmx.l.google.com
@ TXT v=spf1 include:spf.mailjet.com include:_spf.google.com ~all
mailjet._748826c7 TXT 748826c702abf9015ac2e8a202336527 DKIM Mailjet

Domaine targo.ca encore sur OpenSRS (migration Cloudflare planifiée).

Reverse Proxy (Traefik)

Emplacement serveur: /opt/traefik/

  • Version: v2.11 (ne pas upgrader à v3 — incompatible Docker 29, API v1.24 vs v1.40)
  • TLS: Let's Encrypt HTTP-01 challenge
  • Réseau Docker: proxy (tous les containers exposés doivent y être)

Middleware Authentik

# /opt/traefik/dynamic/routes.yml
http:
  middlewares:
    authentik:
      forwardAuth:
        address: http://authentik-server:9000/outpost.goauthentik.io/auth/traefik
        trustForwardHeader: true
        authResponseHeaders:
          - X-authentik-username
          - X-authentik-email
          - X-authentik-name

Gotcha: Le redirect HTTP→HTTPS ne doit pas intercepter /.well-known/acme-challenge/ sinon Let's Encrypt échoue.

Authentik SSO

URL: https://auth.targo.ca

Flux d'authentification

Utilisateur → app.gigafibre.ca
  → Traefik vérifie session via forwardAuth
  → Pas de session? → Redirect auth.targo.ca/flows/authorize/
  → Login (username/password ou SSO)
  → Callback → Cookie session set → App charge

Applications configurées

App Type Status
dispatch.gigafibre.ca ForwardAuth (Traefik) Actif
n8n.gigafibre.ca ForwardAuth + auto-login proxy Actif
hub.gigafibre.ca ForwardAuth (Traefik) Actif
erp.gigafibre.ca OAuth2/OIDC (Provider) En place

n8n auto-login (workaround)

n8n Community Edition ne supporte pas OIDC. Solution :

  • Proxy Node.js (/opt/n8n-proxy/server.js) devant n8n
  • Lit le header X-authentik-email injecté par forwardAuth
  • Crée une session n8n via POST /api/v1/login avec owner credentials
  • Forward le cookie de session au navigateur

ERPNext

URL: https://erp.gigafibre.ca Compose: /opt/erpnext/ DB: PostgreSQL, base _eb65bdc0c4b1b2d6

Token API (service token)

$ERP_SERVICE_TOKEN   # stocké dans /opt/dispatch-app/.env sur le serveur

Utilisé par le Dispatch PWA pour les appels API côté serveur (pas de session utilisateur — Authentik gère l'auth frontend, le token fixe gère l'auth API).

Gotcha: Ne jamais appeler generate_keys sur l'utilisateur Administrator — ça invalide le token existant.

Doctypes personnalisés (module: Dispatch)

Core:

  • Dispatch Job — Ordres de travail (SUP-#####)
  • Dispatch Technician — Profils techniciens + GPS
  • Dispatch Tag — Catégorisation

FSM (extension):

  • Service Location (LOC-#####) — Locaux client
  • Service Equipment (EQP-#####) — ONT, routeur, etc.
  • Service Subscription (SUB-#####) — Forfaits actifs
  • Checklist Template — Templates réutilisables

Tables enfants: Equipment Move Log, Job Equipment Item, Job Material Used, Job Checklist Item, Job Photo, Checklist Template Item, Dispatch Job Assistant, Dispatch Tag Link

Patch appliqué

number_card.py — ERPNext v16 PostgreSQL: ORDER BY creation sur queries agrégées cause erreur. Corrigé avec order_by="".

Dispatch PWA

URL: https://dispatch.gigafibre.ca Repo: git.targo.ca/louis/OSS-BSS-Field-Dispatch Stack: Vue 3 / Quasar / Pinia / Mapbox GL JS

Architecture du code

src/
  App.vue                     — Router view + auth check au mount
  api/
    auth.js                   — Service token, détection expiry Authentik
    dispatch.js               — CRUD ERPNext (authFetch)
    traccar.js                — GPS REST + WebSocket
  stores/
    dispatch.js               — Store principal: jobs, techs, GPS
    auth.js                   — Session check (simplifié, Authentik gère)
  pages/
    DispatchV2Page.vue        — Page principale (~1500 lignes)
  composables/
    useMap.js                 — Carte Mapbox, marqueurs SVG progress ring
    useScheduler.js           — Algorithme timeline
    useDragDrop.js            — Drag & drop avec batch
    useSelection.js           — Lasso, multi-select
    useAutoDispatch.js        — Auto-distribute + route optimize
    useBottomPanel.js         — Panel jobs non-assignés
    useUndo.js                — Undo stack groupé
  config/
    erpnext.js                — BASE_URL (vide en prod = same-origin)

GPS Tracking

  • Traccar sur tracker.targointernet.com:8082
  • Proxy nginx: dispatch.gigafibre.ca/traccar/api/* → Traccar
  • Hybride REST + WebSocket: REST initial → WebSocket real-time → fallback polling 30s
  • Guards module-level (__gpsStarted, __gpsPolling) pour survivre au remount Vue

Build & Deploy

cd dispatch-app
DEPLOY_BASE=/ npx quasar build -m pwa
tar czf /tmp/dispatch-pwa.tar.gz -C dist/pwa .
cat /tmp/dispatch-pwa.tar.gz | ssh -i ~/.ssh/proxmox_vm root@96.125.196.67 \
  'rm -rf /opt/dispatch-app/*.js /opt/dispatch-app/*.html /opt/dispatch-app/*.json /opt/dispatch-app/assets /opt/dispatch-app/icons; cat > /tmp/d.tar.gz && cd /opt/dispatch-app && tar xzf /tmp/d.tar.gz && rm /tmp/d.tar.gz'

nginx config

/opt/dispatch-app/nginx.conf:

  • SPA fallback: try_files $uri /index.html
  • Proxy /api/erpnext-frontend-1:8080 (Docker DNS)
  • Proxy /traccar/tracker.targointernet.com:8082
  • No-cache sur index.html et sw.js (éviter caching stale)
  • Réseau partagé: container dans erpnext_erpnext network + resolver 127.0.0.11

Site web (www.gigafibre.ca)

Repo: git.targo.ca/louis/site-web-targo Stack: React / Vite / Tailwind / shadcn-ui Origine: lovable.dev (modifié)

API backend

/opt/www-api/server.js — Node.js Express:

Endpoint Fonction
POST /rpc/search_addresses Recherche fuzzy 5.2M adresses québécoises
POST /rpc/contact Formulaire contact → email Mailjet
POST /rpc/lead Qualification adresse → email Mailjet
POST /rpc/sms Envoi SMS Twilio
POST /rpc/sms-incoming Webhook Twilio entrant → email Mailjet

Base de données adresses (RQA)

  • Table rqa_addresses: 5.2M lignes (Répertoire Québécois des Adresses)
  • Table fiber_availability: 21,623 entrées (matching numero + code_postal)
  • Recherche 3 phases: exact → fuzzy pg_trgm → J0S/J0L priority
  • PostgreSQL dans le compose ERPNext (même instance DB)

Email (Mailjet)

Expéditeur: noreply@targo.ca (Name: Gigafibre)

Flux

Contact form (www) → /rpc/contact → Mailjet API → support@targo.ca
Lead capture (www) → /rpc/lead → Mailjet API → louis@targo.ca
SMS entrant (Twilio) → webhook → Mailjet API → louis@targo.ca

DNS requis (targo.ca)

  • SPF: v=spf1 include:spf.mailjet.com include:_spf.google.com ~all
  • DKIM: mailjet._748826c7.targo.ca → valeur Mailjet
  • Status: SPF/DKIM pour targo.ca en erreur côté Mailjet (à corriger)

SMS (Twilio)

Numéro: +1 (438) 231-3838 SID: $TWILIO_ACCOUNT_SID # voir 1Password / secrets manager Status: Compte trial (SMS limité aux numéros vérifiés)

Flux

Envoi: App → /rpc/sms → Twilio API → Destinataire
Réception: Twilio → webhook POST → n8n.gigafibre.ca/webhook/sms-incoming
  → Forward vers www.gigafibre.ca/rpc/sms-incoming → Email Mailjet

À faire:

  • Upgrader vers compte Twilio production
  • Configurer 10DLC ou acheter numéro Toll-Free
  • Changer webhook vers n8n directement une fois workflow activé

n8n Workflows

URL: https://n8n.gigafibre.ca Compose: Dans /opt/erpnext/ (override n8n)

Workflows créés

Nom ID Fonction Status
[System] Share all workflows MC5CxJ6QD2s8OCrr Partage workflows/credentials entre projets (SQLite) À activer via UI
SMS Incoming → Email + Router j8lC0f6aHrV9L5Ud Webhook Twilio → forward API À activer via UI

Gotcha: L'activation via API (POST /activate) ne registre pas les webhooks dans n8n 2.x — toujours activer via le toggle UI.

Gotcha: Le node executeCommand n'existe pas dans n8n 2.x — utiliser n8n-nodes-base.code avec require('child_process').

Repos Git (git.targo.ca)

Repo Contenu
louis/OSS-BSS-Field-Dispatch Dispatch PWA (Vue/Quasar)
louis/site-web-targo www.gigafibre.ca (React/Vite)
louis/gigafibre-fsm Docs architecture, scripts setup FSM
louis/gigafibre-infra Configs serveur (traefik, docker-compose)

Note: git.gigafibre.ca a été supprimé — utiliser uniquement git.targo.ca.

Docker — Réseaux et Compose

Fichiers compose sur le serveur

Emplacement Services
/opt/traefik/docker-compose.yml Traefik
/opt/erpnext/compose.yaml ERPNext (9 containers)
/opt/erpnext/overrides/compose.n8n.yaml n8n + auto-login proxy
/opt/apps/docker-compose.yml Gitea + dispatch-frontend + targo-db
/opt/oktopus/docker-compose.yml Oktopus CE (8 containers)
/opt/www-api/docker-compose.yml API www.gigafibre.ca

Réseaux Docker

Réseau Usage
proxy Traefik ↔ tous les containers exposés
erpnext_erpnext ERPNext interne + dispatch nginx (pour proxy /api/)

Gotcha: Containers multi-réseaux → label traefik.docker.network=proxy obligatoire.

Gotchas & Pièges

  1. Traefik v3 incompatible avec Docker 29 (API v1.24 vs v1.40) — rester sur v2.11
  2. HTTP→HTTPS redirect ne doit pas intercepter ACME challenge
  3. MongoDB 5+ nécessite AVX — CPU Proxmox doit être type "host"
  4. netplan override systemd-networkd — supprimer netplan.io
  5. DEPLOY_BASE=/ requis pour quasar build en déploiement root domain
  6. nginx SPA fallback: try_files $uri /index.html
  7. ERPNext generate_keys invalide le token existant — ne jamais appeler
  8. Mixed content HTTPS→HTTP — toujours utiliser proxy pour Traccar
  9. Service Worker cache — headers no-cache sur index.html et sw.js
  10. Traccar API ne supporte qu'un seul deviceId par requête — parallel calls

Accès serveur

# SSH (voir 1Password pour la clé)
ssh -i ~/.ssh/proxmox_vm root@96.125.196.67

# Logs Traefik
docker logs -f traefik

# Logs ERPNext
cd /opt/erpnext && docker compose logs -f backend

# Logs n8n
cd /opt/erpnext && docker compose -f compose.yaml -f overrides/compose.n8n.yaml logs -f n8n

# Restart dispatch nginx
docker restart dispatch-frontend

# Rebuild dispatch
# (voir section Build & Deploy ci-haut)

Tâches en cours

  • Activer les 2 workflows n8n via UI toggle
  • Twilio: upgrade production + 10DLC
  • Corriger SPF/DKIM targo.ca dans Mailjet
  • Google Workspace: ajouter gigafibre.ca comme domaine alias
  • FSM Phase 2: customer/location picker, equipment scan, checklist UI
  • Portail client self-service sur www.gigafibre.ca
  • Pousser frappe_docker mods sur gitea