Add README.md — full technical documentation for open-source sharing

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>
This commit is contained in:
Yvv
2026-02-24 16:22:15 +01:00
parent 330726dcb3
commit 683035dc31

285
README.md Normal file
View File

@@ -0,0 +1,285 @@
# 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
```bash
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
```bash
# 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
```bash
cd backend && . venv/bin/activate && python seed.py
```
Cree la commune **Saou** avec 363 foyers, 2 comptes admin et 10 votes de demonstration.
| Compte | Email | Mot de passe |
|--------|-------|-------------|
| Super admin | superadmin@sejeteralo.fr | superadmin |
| Admin commune | saou@sejeteralo.fr | saou2024 |
### Lancement
```bash
# 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 :
```bash
make install # Installation complete
make seed # Seed base de donnees
make dev # Lance les 2 serveurs
make test # Tests backend
```
### Docker
```bash
# 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` :
1. **Build frontend**`npm ci && npm run build`
2. **Build backend**`pip install && pytest`
3. **Docker push** — 2 images (backend + frontend) vers registry
4. **Deploy** — SSH + `docker compose pull && up -d`
## Licence
A definir.