diff --git a/docs/INFRASTRUCTURE.md b/docs/INFRASTRUCTURE.md new file mode 100644 index 0000000..3ba2900 --- /dev/null +++ b/docs/INFRASTRUCTURE.md @@ -0,0 +1,361 @@ +# 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.gigafibre.ca / 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 + +```yaml +# /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) + +``` +b273a666c86d2d0:613842e506d13b8 +``` + +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 + +```bash +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:** ACddff61c2e272ddc4a94586fa7b68e90e +**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) | + +## 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 + +```bash +# SSH +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