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:
285
README.md
Normal file
285
README.md
Normal 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.
|
||||
Reference in New Issue
Block a user