- 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>
364 lines
12 KiB
Markdown
364 lines
12 KiB
Markdown
# 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
|
|
|
|
```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)
|
|
|
|
```
|
|
$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
|
|
|
|
```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:** `$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
|
|
|
|
```bash
|
|
# 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
|