Stack, API reference, dependencies, database schema, Bézier model, installation, environment variables, project structure, CI/CD. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
9.0 KiB
SejeteralO
Outil de democratie participative pour la tarification de l'eau.
Les citoyens ajustent une courbe de Bezier parametrique pour exprimer leur preference tarifaire. Le systeme calcule automatiquement le prix au palier (p0) pour equilibrer les recettes de la commune, puis agrege les votes par mediane element-par-element.
Stack technique
| Couche | Technologie | Version |
|---|---|---|
| Backend | Python | 3.11 |
| FastAPI | 0.115.6 | |
| SQLAlchemy (async) | 2.0.36 | |
| Pydantic | 2.10.3 | |
| Uvicorn | 0.34.0 | |
| Frontend | Node.js | 20 |
| Nuxt | 4.3.1 | |
| Vue | 3.5.28 | |
| Pinia | 3.0.2 | |
| TypeScript | 5.8.2 | |
| Base de donnees | SQLite (aiosqlite) | 0.20.0 |
| Migrations | Alembic | 1.14.0 |
| CI/CD | Woodpecker CI | — |
| Conteneurs | Docker (multi-stage) | — |
| Reverse proxy | Traefik (labels) | — |
API
REST (pas de GraphQL) — prefixe /api/v1/.
| Route | Description | Auth |
|---|---|---|
POST /auth/admin/login |
Connexion admin (email + password) | — |
POST /auth/citizen/verify |
Connexion citoyen (slug + auth_code) | — |
GET /communes/ |
Liste des communes | public |
GET /communes/{slug} |
Detail commune | public |
GET /communes/{slug}/params |
Parametres tarifaires | public |
PUT /communes/{slug}/params |
Modifier parametres | admin |
POST /communes/{slug}/params/publish |
Publier courbe de reference | admin |
POST /tariff/compute |
Calcul tarif (p0, impacts) | public |
GET /communes/{slug}/votes/current |
Courbe mediane + baseline | public |
GET /communes/{slug}/votes/current/overlay |
Faisceau des votes | public |
POST /communes/{slug}/votes |
Soumettre un vote | citoyen |
GET /communes/{slug}/households/distribution |
Histogramme consommations | public |
GET /communes/{slug}/households/volumes |
Volumes anonymises | public |
GET /communes/{slug}/households/stats |
Statistiques foyers | public |
POST /communes/{slug}/households/import |
Import CSV/XLSX | admin |
GET /communes/{slug}/content |
Pages CMS | public |
PUT /communes/{slug}/content/{page} |
Editer page CMS | admin |
GET /api/health |
Health check | — |
Documentation interactive : http://localhost:8000/docs (Swagger UI).
Dependances backend
fastapi==0.115.6 # Framework web async
uvicorn[standard]==0.34.0 # Serveur ASGI
sqlalchemy==2.0.36 # ORM async
alembic==1.14.0 # Migrations schema
pydantic==2.10.3 # Validation schemas
pydantic-settings==2.7.0 # Configuration .env
python-jose[cryptography]==3.3.0 # JWT tokens
passlib[bcrypt]==1.7.4 # Hachage mots de passe
bcrypt==4.1.3
python-multipart==0.0.18 # Upload fichiers
numpy==1.26.4 # Calcul integrales Bezier
pandas==2.2.3 # Import donnees
openpyxl==3.1.5 # Lecture .xlsx
xlrd==2.0.1 # Lecture .xls
aiosqlite==0.20.0 # Driver SQLite async
pytest==8.3.4 # Tests
pytest-asyncio==0.24.0 # Tests async
httpx==0.28.1 # Client HTTP (tests)
Dependances frontend
nuxt@^4.3.1 # Framework SSR/SPA
vue@^3.5.28 # UI reactif
vue-router@^5.0.3 # Routage
pinia@^3.0.2 # State management
@pinia/nuxt@^0.9.0 # Integration Pinia/Nuxt
typescript@^5.8.2 # Typage statique
Base de donnees
SQLite en dev/production legere, configurable via DATABASE_URL.
Schema (8 tables)
communes 1──N tariff_params
│ 1──N households
│ 1──N votes
│ 1──N commune_contents
└── M──N ──── admin_users (via admin_commune)
households 1──N votes
| Table | Champs cles |
|---|---|
communes |
slug (unique), name, vote_deadline |
tariff_params |
abop, abos, recettes, pmax, vmax, published_vinf/a/b/c/d/e/p0 |
households |
identifier, status (RP/RS/PRO), volume_m3, auth_code (8 chars) |
votes |
vinf, a, b, c, d, e, computed_p0, is_active |
admin_users |
email, role (super_admin/commune_admin) |
commune_contents |
slug, title, body_markdown |
Migrations
cd backend && . venv/bin/activate
alembic upgrade head # Appliquer
alembic revision --autogenerate -m "description" # Creer
Authentification
JWT (HS256) via python-jose.
| Type | Duree | Claims |
|---|---|---|
| Admin | 24h | sub=admin_id, role, type="admin" |
| Citoyen | 4h | sub=household_id, commune_slug, type="citizen" |
Header : Authorization: Bearer <token>
Le modele Bezier
Courbe de tarification a deux paliers (cubique de Bezier) :
Palier 1 (0 → vinf m3) : tarification population
Palier 2 (vinf → vmax m3) : tarification consommations exceptionnelles
6 parametres citoyens : vinf, a, b, c, d, e (a..e ∈ [0,1])
1 parametre calcule : p0 = (Recettes - Σabo - Σβ₂) / Σ(α₁ + α₂)
Le prix au palier d'inflexion (p0) est automatiquement ajuste pour que la somme des factures de tous les foyers atteigne les recettes cibles de la commune.
Double implementation :
- Backend :
backend/app/engine/pricing.py(numpy) - Frontend :
frontend/app/utils/bezier-math.ts(Cardano + Newton-Raphson)
Le frontend calcule localement pour un retour instantane ; le backend fait autorite.
Installation
Prerequis
- Python 3.11+
- Node.js 20+
- (Optionnel) Docker + Docker Compose
Installation locale
# Cloner
git clone <url> && cd sejeteralo
# Backend
cd backend
python3 -m venv venv
. venv/bin/activate
pip install -r requirements.txt
# Frontend
cd ../frontend
npm install
# Configuration
cp .env.example .env
# Editer .env si necessaire
Initialisation base + donnees demo
cd backend && . venv/bin/activate && python seed.py
Cree la commune Saou avec 363 foyers, 2 comptes admin et 10 votes de demonstration.
| Compte | Mot de passe | |
|---|---|---|
| Super admin | superadmin@sejeteralo.fr | superadmin |
| Admin commune | saou@sejeteralo.fr | saou2024 |
Lancement
# Terminal 1 : backend (port 8000)
cd backend && . venv/bin/activate
uvicorn app.main:app --reload --port 8000
# Terminal 2 : frontend (port 3009)
cd frontend && npm run dev
Ou via Makefile :
make install # Installation complete
make seed # Seed base de donnees
make dev # Lance les 2 serveurs
make test # Tests backend
Docker
# Production (Traefik)
make docker-up
# Developpement (hot-reload)
make docker-dev
Variables d'environnement
| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
sqlite+aiosqlite:///./sejeteralo.db |
URL de connexion base |
SECRET_KEY |
change-me-... |
Cle de signature JWT |
DEBUG |
true |
Mode debug (echo SQL) |
CORS_ORIGINS |
["http://localhost:3000"] |
Origines CORS autorisees |
NUXT_PUBLIC_API_BASE |
http://localhost:8000/api/v1 |
URL API pour le frontend |
Structure du projet
sejeteralo/
├── backend/
│ ├── app/
│ │ ├── main.py # Point d'entree FastAPI
│ │ ├── config.py # Settings (pydantic-settings)
│ │ ├── database.py # SQLAlchemy async engine
│ │ ├── models/models.py # 8 modeles ORM
│ │ ├── schemas/schemas.py # Schemas Pydantic (request/response)
│ │ ├── routers/ # 6 routers (auth, communes, tariff, votes, households, content)
│ │ ├── services/ # auth_service, import_service
│ │ └── engine/ # pricing, integrals, median, current_model
│ ├── alembic/ # Migrations
│ ├── seed.py # Donnees de demo
│ └── requirements.txt
├── frontend/
│ ├── nuxt.config.ts
│ ├── app/
│ │ ├── pages/ # Routes (file-based)
│ │ ├── components/ # DisplaySettings, BezierEditor, VoteOverlayChart
│ │ ├── stores/ # Pinia (auth, commune)
│ │ ├── composables/ # useApi (fetch + auth)
│ │ ├── utils/bezier-math.ts # Port TypeScript du moteur tarifaire
│ │ └── assets/css/main.css # Styles globaux + dark mode
│ └── package.json
├── docker/
│ ├── backend.Dockerfile # Multi-stage Python
│ ├── frontend.Dockerfile # Multi-stage Node
│ ├── docker-compose.yml # Production (Traefik)
│ └── docker-compose.dev.yml # Dev (hot-reload)
├── .woodpecker.yml # CI/CD pipeline
├── .env.example
├── Makefile
└── CLAUDE.md
CI/CD
Woodpecker CI (.woodpecker.yml) — declenchement sur push main :
- Build frontend —
npm ci && npm run build - Build backend —
pip install && pytest - Docker push — 2 images (backend + frontend) vers registry
- Deploy — SSH +
docker compose pull && up -d
Licence
A definir.