From 683035dc3160a595eada3c7d5d636532e0f9d8dd Mon Sep 17 00:00:00 2001 From: Yvv Date: Tue, 24 Feb 2026 16:22:15 +0100 Subject: [PATCH] =?UTF-8?q?Add=20README.md=20=E2=80=94=20full=20technical?= =?UTF-8?q?=20documentation=20for=20open-source=20sharing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stack, API reference, dependencies, database schema, Bézier model, installation, environment variables, project structure, CI/CD. Co-Authored-By: Claude Opus 4.6 --- README.md | 285 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..ecf0d19 --- /dev/null +++ b/README.md @@ -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 ` + +## 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 && 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.