7fb22bcb29
Nouveau dossier /frontend avec un SPA complet qui couvre les écrans de la
maquette (cf. docs/Capture*.png) : public + admin token. Backend inchangé.
Stack
- Vue 3.5 + Vite 8 + TypeScript 6 + Tailwind v4 (via @tailwindcss/vite)
- Vue Router 4 en mode history, code-split par page (lazy import)
- Aucune lib UI, aucun store (pas de Pinia) — état local + fetch direct
- Bundle initial 50 kB gzip, total dist 240 kB
Pages
- / redirige vers /donut
- /dashboard 4 KPIs + mini donut + flux activité (via /api/stats + /api/activity)
- /donut viz SVG custom : 6 secteurs catégories, projets en points
colorés, anneaux plancher social / plafond écologique,
tooltip + click vers la fiche projet
- /projects grille de cartes paginée + filtres (catégorie, statut, recherche
avec debounce, query string comme source de vérité)
- /projects/new formulaire complet de création (token admin requis)
- /projects/:slug fiche : header méta + tabs Roadmap/Discussions/Ressources
+ panneau droit Progression + Équipe, modal "Rejoindre"
- /archives projets status=archived
- /categories 6 cartes coloured-top-border + count via /api/stats
- /admin/login saisie du token Bearer, validé via POST /api/members (vide)
- 404 fallback
Structure
- src/api/client.ts : wrapper fetch typé + token Bearer auto + ApiError
- src/composables/useAuth : token localStorage + reactivité Vue
- src/types/api.ts : types miroirs des réponses PHP
- src/utils/formatDate.ts : ISO/MySQL/DATE -> JJ mois AAAA, relatif, etc.
- src/components/ : Avatar, ProjectCard, StatusBadge, CategoryBadge,
ProgressBar, LoadingState, ErrorState, JoinProjectModal
- src/layouts/AppLayout : sidebar nav + main scrollable
- src/components/AppSidebar: logo donut SVG, CTA, nav, statut admin en bas
- src/pages/ : 10 pages ci-dessus
Intégration & déploiement
- vite.config.ts proxy /api/* vers http://donut-gestprojet.test (Laragon)
- caddy.conf prod : /api/* -> reverse_proxy PHP, le reste -> static dist/
avec fallback /index.html (history mode), cache long sur /assets/*
- DEPLOY.md mis à jour avec build local + rsync dist/ vers
/srv/donut/web/infolab-front/dist
- README.md mis à jour avec section "Frontend (SPA Vue 3)"
Build & types
- npm run build : vue-tsc strict (TS 6 + erasableSyntaxOnly) -> OK
- paths alias @/* configuré dans tsconfig.app.json
Vérifié localement
- npm run dev sur :5173, proxy /api -> Apache Laragon -> PHP
- Toutes les routes répondent 200 (curl http://localhost:5173/...)
- Routes API consommées correctement (categories, stats, projects, ...)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
268 lines
8.4 KiB
Markdown
268 lines
8.4 KiB
Markdown
# DEPLOY — Le Donut Infolab
|
|
|
|
Procédure exacte de déploiement sur le serveur **Donut Marseille**.
|
|
|
|
- Hôte : `arnaud.donut@82.66.40.209`
|
|
- OS : Ubuntu 26.04
|
|
- Sous-domaine : `infolab.ledonut-marseille.org`
|
|
- Conteneur PHP : `donut-infolab` (UID `33` = www-data côté Apache)
|
|
- BDD : conteneur existant `donut-mariadb`, réseau Docker `donut-net`
|
|
- Reverse proxy : Caddy natif sur l'hôte
|
|
- Front : SPA Vue 3 buildé (statique) servi par Caddy depuis `/srv/donut/web/infolab-front/dist/`
|
|
|
|
> ⚠️ Pré-requis DNS : créer chez OVH un record `A infolab.ledonut-marseille.org → 82.66.40.209`
|
|
> **avant** le reload Caddy (sinon échec ACME challenge).
|
|
|
|
---
|
|
|
|
## 0. Pré-requis vérifiés une fois
|
|
|
|
```bash
|
|
ssh arnaud.donut@82.66.40.209
|
|
|
|
# Le réseau donut-net existe
|
|
docker network ls | grep donut-net
|
|
# Le mariadb tourne et est joignable depuis donut-net
|
|
docker ps | grep donut-mariadb
|
|
# /srv/donut/secrets/mariadb.env est en place et lisible par root
|
|
sudo ls -l /srv/donut/secrets/mariadb.env
|
|
# Le group donut-admins existe
|
|
getent group donut-admins
|
|
```
|
|
|
|
---
|
|
|
|
## 1. Copier le backend vers le serveur
|
|
|
|
Depuis ta machine de dev (à la racine du repo) :
|
|
|
|
```bash
|
|
# Code app PHP -> /srv/donut/web/infolab/ (bind-mount dans le conteneur, UID 33)
|
|
rsync -avz --delete \
|
|
--exclude '.git' --exclude '.idea' --exclude '.env' --exclude 'tests' \
|
|
--exclude 'docker-compose.yml' --exclude 'Dockerfile' --exclude 'caddy.conf' \
|
|
--exclude 'migrations' --exclude 'DEPLOY.md' --exclude 'INSTRUCTIONS.md' \
|
|
--exclude 'frontend' --exclude 'docs' \
|
|
./ arnaud.donut@82.66.40.209:/tmp/infolab-app/
|
|
|
|
# Fichiers d'orchestration -> /srv/donut/compose/infolab/
|
|
rsync -avz \
|
|
docker-compose.yml Dockerfile caddy.conf README.md DEPLOY.md .env.example \
|
|
migrations \
|
|
arnaud.donut@82.66.40.209:/tmp/infolab-compose/
|
|
```
|
|
|
|
Puis sur le serveur :
|
|
|
|
```bash
|
|
ssh arnaud.donut@82.66.40.209
|
|
|
|
# Code app (UID 33 = www-data du conteneur Apache)
|
|
sudo mkdir -p /srv/donut/web/infolab
|
|
sudo rsync -a --delete /tmp/infolab-app/ /srv/donut/web/infolab/
|
|
sudo chown -R 33:33 /srv/donut/web/infolab
|
|
sudo find /srv/donut/web/infolab -type d -exec chmod 755 {} \;
|
|
sudo find /srv/donut/web/infolab -type f -exec chmod 644 {} \;
|
|
|
|
# Orchestration (root:donut-admins, lisible par les admins)
|
|
sudo mkdir -p /srv/donut/compose/infolab
|
|
sudo rsync -a /tmp/infolab-compose/ /srv/donut/compose/infolab/
|
|
sudo chown -R root:donut-admins /srv/donut/compose/infolab
|
|
sudo chmod 750 /srv/donut/compose/infolab
|
|
sudo chmod 640 /srv/donut/compose/infolab/*
|
|
|
|
# Cleanup tmp
|
|
rm -rf /tmp/infolab-app /tmp/infolab-compose
|
|
```
|
|
|
|
---
|
|
|
|
## 1bis. Builder & copier le frontend (SPA Vue)
|
|
|
|
Le SPA est compilé localement (Node 22+ requis) et déployé en statique. Pas de Node sur le serveur prod.
|
|
|
|
```bash
|
|
# Sur la machine de dev, à la racine du repo
|
|
cd frontend
|
|
npm ci # ou `npm install` la 1re fois
|
|
npm run build # produit frontend/dist/
|
|
ls -la dist/ # index.html + assets/ avec hash
|
|
|
|
# Copie de l'artifact vers le serveur (rsync direct, fichiers statiques)
|
|
rsync -avz --delete dist/ arnaud.donut@82.66.40.209:/tmp/infolab-front-dist/
|
|
cd ..
|
|
```
|
|
|
|
Sur le serveur :
|
|
|
|
```bash
|
|
ssh arnaud.donut@82.66.40.209
|
|
sudo mkdir -p /srv/donut/web/infolab-front/dist
|
|
sudo rsync -a --delete /tmp/infolab-front-dist/ /srv/donut/web/infolab-front/dist/
|
|
# Caddy tourne en `caddy` user — donner l'accès en lecture est suffisant
|
|
sudo chown -R caddy:caddy /srv/donut/web/infolab-front
|
|
sudo find /srv/donut/web/infolab-front -type d -exec chmod 755 {} \;
|
|
sudo find /srv/donut/web/infolab-front -type f -exec chmod 644 {} \;
|
|
rm -rf /tmp/infolab-front-dist
|
|
```
|
|
|
|
> ⚠️ Le build embarque l'URL de l'API en relatif (`/api/...`) — donc le SPA et l'API
|
|
> **doivent** être servis depuis le même domaine (ce que fait notre `caddy.conf`).
|
|
|
|
---
|
|
|
|
## 2. Créer les secrets `/srv/donut/secrets/infolab.env`
|
|
|
|
```bash
|
|
ssh arnaud.donut@82.66.40.209
|
|
|
|
DB_PASS="$(openssl rand -hex 24)"
|
|
ADMIN_TOKEN="$(openssl rand -hex 32)"
|
|
|
|
sudo tee /srv/donut/secrets/infolab.env > /dev/null <<EOF
|
|
DB_HOST=donut-mariadb
|
|
DB_PORT=3306
|
|
DB_NAME=infolab
|
|
DB_USER=infolab
|
|
DB_PASS=$DB_PASS
|
|
|
|
ADMIN_TOKEN=$ADMIN_TOKEN
|
|
|
|
CORS_ORIGIN=https://infolab.ledonut-marseille.org
|
|
APP_ENV=production
|
|
APP_DEBUG=false
|
|
EOF
|
|
|
|
sudo chown root:donut-admins /srv/donut/secrets/infolab.env
|
|
sudo chmod 640 /srv/donut/secrets/infolab.env
|
|
|
|
# Note les 2 secrets quelque part de sûr (gestionnaire de mdp) :
|
|
sudo cat /srv/donut/secrets/infolab.env | grep -E '^(ADMIN_TOKEN|DB_PASS)='
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Créer la BDD + le user MariaDB + appliquer les migrations
|
|
|
|
```bash
|
|
# Le script apply.sh fait tout : crée la base, le user, applique les .sql
|
|
# Idempotent : peut être ré-exécuté sans danger (table schema_migrations).
|
|
sudo /srv/donut/compose/infolab/migrations/apply.sh
|
|
```
|
|
|
|
Tu dois voir :
|
|
- `apply 001_init_schema.sql`
|
|
- `apply 002_seed_categories.sql`
|
|
- résumé avec `categories_count = 6`
|
|
|
|
---
|
|
|
|
## 4. Build + start du conteneur
|
|
|
|
```bash
|
|
cd /srv/donut/compose/infolab
|
|
sudo docker compose --env-file /srv/donut/secrets/infolab.env up -d --build
|
|
|
|
# Vérifie qu'il tourne et écoute en local sur 127.0.0.1:8003
|
|
docker ps | grep donut-infolab
|
|
ss -ltn | grep 8003
|
|
|
|
# Sonde de vie via le port mappé en local
|
|
curl -s http://127.0.0.1:8003/api/health
|
|
# {"status":"ok","time":"..."}
|
|
```
|
|
|
|
Si la sonde renvoie `degraded`, vérifier les logs :
|
|
```bash
|
|
docker logs --tail 100 donut-infolab
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Vhost Caddy (sert le SPA + reverse_proxy l'API)
|
|
|
|
Le `caddy.conf` fait deux choses :
|
|
- `/api/*` -> reverse_proxy vers le conteneur PHP `127.0.0.1:8003`
|
|
- tout le reste -> sert `/srv/donut/web/infolab-front/dist/` (SPA), fallback `index.html`
|
|
|
|
```bash
|
|
grep -n 'infolab' /etc/caddy/Caddyfile
|
|
|
|
# Si manquant, ajouter en fin de Caddyfile :
|
|
echo 'import /srv/donut/compose/infolab/caddy.conf' | sudo tee -a /etc/caddy/Caddyfile
|
|
|
|
# Valider la syntaxe puis recharger
|
|
sudo caddy validate --config /etc/caddy/Caddyfile
|
|
sudo systemctl reload caddy
|
|
```
|
|
|
|
Caddy va négocier le certificat Let's Encrypt (à condition que le DNS A
|
|
record soit en place — voir avertissement en tête de fichier).
|
|
|
|
Vérifier qu'il sert bien le SPA et l'API :
|
|
|
|
```bash
|
|
curl -sI https://infolab.ledonut-marseille.org/ # SPA -> 200 text/html
|
|
curl -sI https://infolab.ledonut-marseille.org/api/health # API -> 200 application/json
|
|
curl -sI https://infolab.ledonut-marseille.org/whatever-fake # SPA fallback -> 200 index.html
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Vérification finale
|
|
|
|
```bash
|
|
# Depuis la machine de dev (TLS terminé par Caddy)
|
|
curl -s https://infolab.ledonut-marseille.org/api/health
|
|
curl -s https://infolab.ledonut-marseille.org/api/categories | head -c 400
|
|
|
|
# Smoke tests complets (lit ADMIN_TOKEN depuis le secret côté serveur)
|
|
ssh arnaud.donut@82.66.40.209 'sudo bash -c "
|
|
TOKEN=\$(grep ^ADMIN_TOKEN= /srv/donut/secrets/infolab.env | cut -d= -f2-)
|
|
INFOLAB_URL=https://infolab.ledonut-marseille.org ADMIN_TOKEN=\$TOKEN \
|
|
/srv/donut/compose/infolab/tests/smoke.sh
|
|
"'
|
|
```
|
|
|
|
Si tout est vert : `OK : 11 / FAIL : 0`.
|
|
|
|
---
|
|
|
|
## 7. Cycle de mise à jour (pour plus tard)
|
|
|
|
```bash
|
|
# Backend PHP
|
|
rsync -avz --delete --exclude '.git' --exclude '.env' \
|
|
public/ src/ arnaud.donut@82.66.40.209:/srv/donut/web/infolab/
|
|
|
|
# Frontend Vue (build à chaque release)
|
|
(cd frontend && npm ci && npm run build)
|
|
rsync -avz --delete frontend/dist/ \
|
|
arnaud.donut@82.66.40.209:/srv/donut/web/infolab-front/dist/
|
|
|
|
# Si changement Dockerfile / docker-compose / migrations :
|
|
rsync -avz docker-compose.yml Dockerfile migrations/ \
|
|
arnaud.donut@82.66.40.209:/srv/donut/compose/infolab/
|
|
|
|
ssh arnaud.donut@82.66.40.209 << 'EOF'
|
|
sudo /srv/donut/compose/infolab/migrations/apply.sh # nouvelle migration éventuelle
|
|
cd /srv/donut/compose/infolab
|
|
sudo docker compose --env-file /srv/donut/secrets/infolab.env up -d --build
|
|
sudo chown -R 33:33 /srv/donut/web/infolab
|
|
sudo chown -R caddy:caddy /srv/donut/web/infolab-front
|
|
EOF
|
|
```
|
|
|
|
---
|
|
|
|
## Points à valider une fois en prod
|
|
|
|
- [ ] DNS `A infolab.ledonut-marseille.org → 82.66.40.209` ajouté chez OVH
|
|
- [ ] Certificat Let's Encrypt négocié OK (`caddy.log` côté hôte)
|
|
- [ ] `ADMIN_TOKEN` archivé dans le gestionnaire de mots de passe partagé
|
|
- [ ] `tests/smoke.sh` vert depuis l'extérieur
|
|
- [ ] SPA accessible : `https://infolab.ledonut-marseille.org/` renvoie la page d'accueil
|
|
- [ ] SPA routing OK : `https://infolab.ledonut-marseille.org/projects` aussi (pas de 404 — fallback Caddy)
|
|
- [ ] Conteneur `donut-infolab` visible dans Dozzle (logs Apache + PHP via stderr)
|
|
- [ ] Pas de fuite : `curl -I https://infolab.ledonut-marseille.org/.env` → 403/404
|