revue du code
This commit is contained in:
parent
e3a7edcf21
commit
f66d6af105
13 changed files with 164 additions and 83 deletions
|
|
@ -63,6 +63,6 @@ async def require_executif(
|
|||
Poste.categorie == "executif",
|
||||
)
|
||||
)
|
||||
if not result.scalar_one_or_none():
|
||||
if not result.scalars().first():
|
||||
raise HTTPException(status_code=403, detail="Réservé à l'exécutif")
|
||||
return membre
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ async def require_tresorier(membre=Depends(get_current_membre), db: AsyncSession
|
|||
Poste.nom.ilike("%trésorier%"),
|
||||
)
|
||||
)
|
||||
if not result.scalar_one_or_none():
|
||||
if not result.scalars().first():
|
||||
raise HTTPException(status_code=403, detail="Réservé au trésorier")
|
||||
return membre
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ async def require_resp_jetons(membre=Depends(get_current_membre), db: AsyncSessi
|
|||
Poste.nom.ilike("%jeton%"),
|
||||
)
|
||||
)
|
||||
if not result.scalar_one_or_none():
|
||||
if not result.scalars().first():
|
||||
raise HTTPException(status_code=403, detail="Réservé au responsable des jetons")
|
||||
return membre
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ async def require_tresorier(membre=Depends(get_current_membre), db: AsyncSession
|
|||
Poste.nom.ilike("%trésorier%"),
|
||||
)
|
||||
)
|
||||
if not result.scalar_one_or_none():
|
||||
if not result.scalars().first():
|
||||
raise HTTPException(status_code=403, detail="Réservé au trésorier")
|
||||
return membre
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ async def require_tresorier(membre=Depends(get_current_membre), db: AsyncSession
|
|||
Poste.nom.ilike("%trésorier%"),
|
||||
)
|
||||
)
|
||||
if not result.scalar_one_or_none():
|
||||
if not result.scalars().first():
|
||||
raise HTTPException(status_code=403, detail="Réservé au trésorier")
|
||||
return membre
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ async def require_resp_jetons(membre=Depends(get_current_membre), db: AsyncSessi
|
|||
Poste.nom.ilike("%jeton%"),
|
||||
)
|
||||
)
|
||||
if not result.scalar_one_or_none():
|
||||
if not result.scalars().first():
|
||||
raise HTTPException(status_code=403, detail="Réservé au responsable des jetons")
|
||||
return membre
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ async def require_resp_litterature(membre=Depends(get_current_membre), db: Async
|
|||
Poste.nom.ilike("%littérature%"),
|
||||
)
|
||||
)
|
||||
if not result.scalar_one_or_none():
|
||||
if not result.scalars().first():
|
||||
raise HTTPException(status_code=403, detail="Réservé au responsable de la littérature")
|
||||
return membre
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ async def require_secretaire(membre=Depends(get_current_membre), db=Depends(get_
|
|||
(Poste.nom.ilike("%secrétaire%") | (Poste.categorie == "executif")),
|
||||
)
|
||||
)
|
||||
if not result.scalar_one_or_none():
|
||||
if not result.scalars().first():
|
||||
raise HTTPException(status_code=403, detail="Réservé au secrétaire ou à l'exécutif")
|
||||
return membre
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ async def require_secretaire(membre=Depends(get_current_membre), db=Depends(get_
|
|||
(Poste.nom.ilike("%secrétaire%") | (Poste.categorie == "executif")),
|
||||
)
|
||||
)
|
||||
if not result.scalar_one_or_none():
|
||||
if not result.scalars().first():
|
||||
raise HTTPException(status_code=403, detail="Réservé au secrétaire ou à l'exécutif")
|
||||
return membre
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ async def require_rsg(membre=Depends(get_current_membre), db=Depends(get_db)):
|
|||
(Poste.nom.ilike("%RSG%") | (Poste.categorie == "executif")),
|
||||
)
|
||||
)
|
||||
if not result.scalar_one_or_none():
|
||||
if not result.scalars().first():
|
||||
raise HTTPException(status_code=403, detail="Réservé au RSG ou à l'exécutif")
|
||||
return membre
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ async def require_animateur(membre=Depends(get_current_membre), db: AsyncSession
|
|||
(Poste.nom.ilike("%animateur%") | (Poste.categorie == "executif")),
|
||||
)
|
||||
)
|
||||
if not result.scalar_one_or_none():
|
||||
if not result.scalars().first():
|
||||
raise HTTPException(status_code=403, detail="Réservé à l'animateur ou à l'exécutif")
|
||||
return membre
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ async def require_resp_litterature(membre=Depends(get_current_membre), db: Async
|
|||
Poste.nom.ilike("%littérature%"),
|
||||
)
|
||||
)
|
||||
if not result.scalar_one_or_none():
|
||||
if not result.scalars().first():
|
||||
raise HTTPException(status_code=403, detail="Réservé au responsable de la littérature")
|
||||
return membre
|
||||
|
||||
|
|
|
|||
|
|
@ -1,29 +1,41 @@
|
|||
# Guide de déploiement — Groupe Méditation
|
||||
|
||||
## 27 modules · Phases 0 à 9 · Infrastructure Debian + NGINX + PostgreSQL
|
||||
## 27 modules · Debian Bookworm + NGINX + PostgreSQL 16
|
||||
|
||||
Testé sur Debian 12 (Bookworm) avec un utilisateur `ansible` ayant accès sudo.
|
||||
|
||||
---
|
||||
|
||||
## Prérequis
|
||||
|
||||
- Debian 12+ ou Ubuntu 24.04+
|
||||
- PostgreSQL 16+
|
||||
- Python 3.11+
|
||||
- Node.js 20+ (pour le build frontend)
|
||||
- NGINX 1.24+
|
||||
- Certbot (Let's Encrypt)
|
||||
|
||||
---
|
||||
|
||||
## 1. Installer PostgreSQL
|
||||
## 0. Prérequis système
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install -y curl ca-certificates gnupg
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. Installer PostgreSQL 16
|
||||
|
||||
Debian Bookworm inclut PostgreSQL 15 par défaut. Pour le 16, ajouter le dépôt officiel PGDG :
|
||||
|
||||
```bash
|
||||
sudo install -d /usr/share/postgresql-common/pgdg
|
||||
sudo curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc \
|
||||
--fail https://www.postgresql.org/media/keys/ACCC4CF8.asc
|
||||
echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" \
|
||||
| sudo tee /etc/apt/sources.list.d/pgdg.list
|
||||
|
||||
sudo apt update
|
||||
sudo apt install -y postgresql-16 postgresql-client-16
|
||||
|
||||
sudo systemctl enable postgresql
|
||||
sudo systemctl start postgresql
|
||||
```
|
||||
|
||||
Créer l'utilisateur et la base :
|
||||
|
||||
```bash
|
||||
sudo -u postgres psql << 'SQL'
|
||||
CREATE USER grpmed WITH PASSWORD 'CHANGEZ_CE_MOT_DE_PASSE';
|
||||
CREATE DATABASE groupe_meditation OWNER grpmed;
|
||||
|
|
@ -33,53 +45,104 @@ GRANT ALL ON SCHEMA public TO grpmed;
|
|||
SQL
|
||||
```
|
||||
|
||||
## 2. Installer Python et les dépendances
|
||||
Vérifier :
|
||||
|
||||
```bash
|
||||
sudo -u postgres psql -c "SELECT version();"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Installer Node.js 20
|
||||
|
||||
Debian Bookworm inclut Node.js 18. Pour le 20 :
|
||||
|
||||
```bash
|
||||
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
||||
sudo apt install -y nodejs
|
||||
```
|
||||
|
||||
Vérifier :
|
||||
|
||||
```bash
|
||||
node --version
|
||||
npm --version
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Installer Python et les dépendances système
|
||||
|
||||
```bash
|
||||
sudo apt install -y python3 python3-pip python3-venv
|
||||
|
||||
# Dépendances système pour WeasyPrint (rapports PDF)
|
||||
sudo apt install -y libpango-1.0-0 libpangocairo-1.0-0 libgdk-pixbuf2.0-0 libffi-dev libcairo2
|
||||
|
||||
sudo mkdir -p /opt/groupe-meditation
|
||||
sudo chown $USER:$USER /opt/groupe-meditation
|
||||
|
||||
cp -r backend/ /opt/groupe-meditation/backend/
|
||||
cp -r deploy/ /opt/groupe-meditation/deploy/
|
||||
|
||||
cd /opt/groupe-meditation/backend
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
sudo apt install -y libpango-1.0-0 libpangocairo-1.0-0 \
|
||||
libgdk-pixbuf2.0-0 libffi-dev libcairo2
|
||||
```
|
||||
|
||||
## 3. Configurer le backend
|
||||
---
|
||||
|
||||
## 4. Installer NGINX
|
||||
|
||||
```bash
|
||||
sudo apt install -y nginx
|
||||
sudo systemctl enable nginx
|
||||
sudo systemctl start nginx
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Déployer le code source
|
||||
|
||||
```bash
|
||||
# Copier l'archive sur le serveur, puis :
|
||||
cd ~
|
||||
tar xzf groupe-meditation-complet.tar.gz
|
||||
|
||||
# Backend
|
||||
sudo mkdir -p /opt/groupe-meditation
|
||||
sudo cp -r ~/groupe-meditation/backend/ /opt/groupe-meditation/backend/
|
||||
sudo cp -r ~/groupe-meditation/deploy/ /opt/groupe-meditation/deploy/
|
||||
|
||||
# Environnement virtuel Python
|
||||
cd /opt/groupe-meditation/backend
|
||||
sudo python3 -m venv venv
|
||||
sudo /opt/groupe-meditation/backend/venv/bin/pip install -r requirements.txt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Configurer le backend
|
||||
|
||||
```bash
|
||||
cd /opt/groupe-meditation/backend
|
||||
cp .env.example .env
|
||||
nano .env
|
||||
sudo cp .env.example .env
|
||||
sudo nano .env
|
||||
```
|
||||
|
||||
Modifier `.env` :
|
||||
|
||||
```
|
||||
DATABASE_URL=postgresql+asyncpg://grpmed:VOTRE_MOT_DE_PASSE@localhost:5432/groupe_meditation
|
||||
JWT_SECRET=GENEREZ_AVEC_openssl_rand_base64_48
|
||||
JWT_SECRET=COLLEZ_ICI_LA_SORTIE_DE_LA_COMMANDE_SUIVANTE
|
||||
CORS_ORIGINS=["https://groupe-meditation.chezlepro.ca"]
|
||||
INVITATION_EXPIRE_HOURS=48
|
||||
```
|
||||
|
||||
Générer le secret JWT :
|
||||
|
||||
```bash
|
||||
openssl rand -base64 48
|
||||
```
|
||||
|
||||
## 4. Initialiser la base de données (23 tables)
|
||||
---
|
||||
|
||||
## 7. Initialiser la base de données (23 tables)
|
||||
|
||||
```bash
|
||||
cd /opt/groupe-meditation
|
||||
source backend/venv/bin/activate
|
||||
python deploy/seed.py
|
||||
sudo /opt/groupe-meditation/backend/venv/bin/python deploy/seed.py
|
||||
```
|
||||
|
||||
Le script crée **interactivement** :
|
||||
|
|
@ -87,26 +150,36 @@ Le script crée **interactivement** :
|
|||
- Les 10 postes prédéfinis
|
||||
- La répartition par défaut des contributions (30/30/30/10)
|
||||
- La littérature de base (5 titres)
|
||||
- Le premier groupe et le premier membre avec son poste
|
||||
- Le premier groupe et le premier membre
|
||||
- Un code d'invitation valide 7 jours
|
||||
|
||||
## 5. Créer le service systemd
|
||||
---
|
||||
|
||||
## 8. Créer le service systemd
|
||||
|
||||
```bash
|
||||
sudo cp deploy/groupe-meditation.service /etc/systemd/system/
|
||||
sudo cp /opt/groupe-meditation/deploy/groupe-meditation.service /etc/systemd/system/
|
||||
sudo chown -R www-data:www-data /opt/groupe-meditation
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable groupe-meditation
|
||||
sudo systemctl start groupe-meditation
|
||||
|
||||
# Vérifier
|
||||
curl http://127.0.0.1:8000/api/health
|
||||
```
|
||||
|
||||
## 6. Construire le frontend
|
||||
Vérifier :
|
||||
|
||||
```bash
|
||||
cd frontend/
|
||||
sudo systemctl status groupe-meditation
|
||||
curl -s http://127.0.0.1:8000/api/health
|
||||
```
|
||||
|
||||
Doit retourner `{"status":"ok","app":"Groupe Méditation","version":"0.1.0"}`
|
||||
|
||||
---
|
||||
|
||||
## 9. Construire et déployer le frontend
|
||||
|
||||
```bash
|
||||
cd ~/groupe-meditation/frontend
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
|
|
@ -115,45 +188,56 @@ sudo cp -r dist/* /var/www/groupe-meditation/
|
|||
sudo chown -R www-data:www-data /var/www/groupe-meditation
|
||||
```
|
||||
|
||||
## 7. Configurer NGINX
|
||||
---
|
||||
|
||||
NGINX fait tout : servir les fichiers statiques du frontend ET proxy vers FastAPI. Pas besoin d'Apache.
|
||||
## 10. Configurer NGINX
|
||||
|
||||
NGINX fait tout : fichiers statiques du frontend + reverse proxy vers FastAPI.
|
||||
|
||||
```bash
|
||||
sudo cp deploy/nginx-groupe-meditation.conf /etc/nginx/sites-available/groupe-meditation
|
||||
sudo ln -s /etc/nginx/sites-available/groupe-meditation /etc/nginx/sites-enabled/
|
||||
sudo cp ~/groupe-meditation/deploy/nginx-groupe-meditation.conf \
|
||||
/etc/nginx/sites-available/groupe-meditation
|
||||
sudo ln -sf /etc/nginx/sites-available/groupe-meditation /etc/nginx/sites-enabled/
|
||||
|
||||
# Retirer le site par défaut si présent
|
||||
sudo rm -f /etc/nginx/sites-enabled/default
|
||||
|
||||
sudo nginx -t
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
# Certificat TLS
|
||||
Tester en HTTP :
|
||||
|
||||
```bash
|
||||
curl -s http://groupe-meditation.chezlepro.ca/api/health
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Certificat TLS (Let's Encrypt)
|
||||
|
||||
```bash
|
||||
sudo apt install -y certbot python3-certbot-nginx
|
||||
sudo certbot --nginx -d groupe-meditation.chezlepro.ca
|
||||
```
|
||||
|
||||
NGINX sert :
|
||||
- `/api/*` → reverse proxy vers FastAPI (Uvicorn port 8000)
|
||||
- `/*` → fichiers statiques du build React (SPA routing via `try_files`)
|
||||
- Cache 1 an sur les assets (JS, CSS, images), pas de cache sur index.html
|
||||
Certbot modifie automatiquement la config NGINX pour ajouter HTTPS et la redirection 80→443.
|
||||
|
||||
## 8. Sauvegarde automatique
|
||||
---
|
||||
|
||||
## 12. Sauvegarde automatique
|
||||
|
||||
```bash
|
||||
sudo cp deploy/backup.sh /etc/cron.daily/groupe-meditation-backup
|
||||
sudo cp ~/groupe-meditation/deploy/backup.sh /etc/cron.daily/groupe-meditation-backup
|
||||
sudo chmod +x /etc/cron.daily/groupe-meditation-backup
|
||||
```
|
||||
|
||||
- pg_dump quotidien en format custom (-Fc)
|
||||
- Rétention 30 jours
|
||||
- **Test de restauration mensuel recommandé** :
|
||||
---
|
||||
|
||||
## 13. Vérification finale
|
||||
|
||||
```bash
|
||||
pg_restore -U grpmed -d groupe_meditation_test /var/backups/groupe-meditation/grpmed_DERNIER.dump
|
||||
```
|
||||
|
||||
## 9. Vérification finale
|
||||
|
||||
```bash
|
||||
# API
|
||||
# API en HTTPS
|
||||
curl -s https://groupe-meditation.chezlepro.ca/api/health | python3 -m json.tool
|
||||
|
||||
# Documentation OpenAPI
|
||||
|
|
@ -172,27 +256,24 @@ curl -s https://groupe-meditation.chezlepro.ca/api/health | python3 -m json.tool
|
|||
|----------|----------|
|
||||
| API ne démarre pas | `sudo journalctl -u groupe-meditation -f` |
|
||||
| Erreur base de données | `sudo -u postgres psql -d groupe_meditation -c "SELECT count(*) FROM groupes;"` |
|
||||
| NGINX 502 | `sudo systemctl status groupe-meditation` (vérifier que FastAPI tourne) |
|
||||
| NGINX 502 | `sudo systemctl status groupe-meditation` |
|
||||
| WeasyPrint échoue | `sudo apt install libpango-1.0-0 libpangocairo-1.0-0` |
|
||||
| Mise à jour frontend | `cd frontend && npm run build && sudo cp -r dist/* /var/www/groupe-meditation/` |
|
||||
| Mise à jour backend | `sudo systemctl restart groupe-meditation` |
|
||||
| seed.py ImportError | Vérifier les noms de classes dans `backend/app/models/` |
|
||||
|
||||
## Mise à jour de l'application
|
||||
|
||||
```bash
|
||||
# Backend
|
||||
cd /opt/groupe-meditation/backend
|
||||
source venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
sudo venv/bin/pip install -r requirements.txt
|
||||
sudo systemctl restart groupe-meditation
|
||||
|
||||
# Frontend
|
||||
cd frontend
|
||||
npm install
|
||||
npm run build
|
||||
cd ~/groupe-meditation/frontend
|
||||
npm install && npm run build
|
||||
sudo cp -r dist/* /var/www/groupe-meditation/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Hébergé au Québec · 100% logiciel libre · Zéro traçage · 23 tables · 25 routers · 27 modules**
|
||||
**Hébergé au Québec · 100% logiciel libre · Zéro traçage**
|
||||
|
|
|
|||
Loading…
Reference in a new issue