Files
sejeteralo/README.md
Yvv 683035dc31 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>
2026-02-24 16:22:15 +01:00

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 Email 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 :

  1. Build frontendnpm ci && npm run build
  2. Build backendpip install && pytest
  3. Docker push — 2 images (backend + frontend) vers registry
  4. Deploy — SSH + docker compose pull && up -d

Licence

A definir.