Ajout de BLUEPRINT.md : socle réutilisable pour une nouvelle appli
Philosophie, stack, architecture, style et conventions de l'appli, débarrassés du domaine métier. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
85e841ae4a
commit
5b493c9737
+362
@@ -0,0 +1,362 @@
|
|||||||
|
# BLUEPRINT — Socle réutilisable
|
||||||
|
|
||||||
|
Ce fichier capture la **philosophie, la stack, l'architecture, le style et
|
||||||
|
les conventions** de l'application « Gestion des bénévoles », débarrassés de
|
||||||
|
son domaine métier (festival, créneaux, cotisations…). Il sert de point de
|
||||||
|
départ pour une nouvelle application construite sur les mêmes bases.
|
||||||
|
|
||||||
|
**Mode d'emploi pour une nouvelle appli :**
|
||||||
|
|
||||||
|
1. Copier ce fichier dans le nouveau dépôt.
|
||||||
|
2. Le donner à Claude avec le brief métier : « Crée l'appli X sur les bases
|
||||||
|
de `BLUEPRINT.md` ».
|
||||||
|
3. La première étape produit un `CLAUDE.md` propre au nouveau projet (même
|
||||||
|
plan que celui de `benevoles` : glossaire, modèle, règles, périmètre,
|
||||||
|
arborescence, commandes, conventions, déploiement, journal des étapes),
|
||||||
|
qui devient ensuite le contrat de travail.
|
||||||
|
|
||||||
|
Les passages marqués **⟨à adapter⟩** dépendent du métier ; tout le reste est
|
||||||
|
le socle à reprendre tel quel.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Philosophie
|
||||||
|
|
||||||
|
- **Un outil pour une petite organisation réelle** (association, 50–200
|
||||||
|
personnes), pas une plateforme générique. On résout le besoin concret,
|
||||||
|
sans sur-ingénierie, mais avec un vrai niveau de qualité (tests, sécurité,
|
||||||
|
RGPD, déploiement automatisé).
|
||||||
|
- **Le métier parle français, le code parle anglais.** Un glossaire
|
||||||
|
FR ↔ EN fige les noms une fois pour toutes ; aucun nom métier français
|
||||||
|
dans le code, aucun texte d'interface en dur nulle part.
|
||||||
|
- **`CLAUDE.md` est le contrat de travail.** Il décrit le modèle, les règles,
|
||||||
|
les choix et leurs *raisons*. Il est mis à jour **à chaque étape**, en même
|
||||||
|
temps que le code. Quand un bug est corrigé, la cause et la règle qui
|
||||||
|
l'empêche de revenir y sont notées (« bug corrigé une fois — faire Y
|
||||||
|
recréerait la même classe de bug »).
|
||||||
|
- **Étapes courtes et validées.** Une étape = une fonctionnalité cohérente,
|
||||||
|
montrée à l'utilisateur, puis validée avant de continuer. Un commit atomique
|
||||||
|
par étape, message en français. Le journal des étapes (§ 10 du `CLAUDE.md`)
|
||||||
|
garde l'historique des décisions.
|
||||||
|
- **Le cœur métier est pur et testé d'abord.** Les règles critiques vivent
|
||||||
|
dans un module isolé, sans base de données ni HTTP (fonction pure :
|
||||||
|
entrée typée → résultat typé), écrit en TDD : un cas passant + un cas
|
||||||
|
déclenchant par règle. Un `loader.py` est le seul point de contact avec la
|
||||||
|
base.
|
||||||
|
- **L'outil assiste, l'humain décide.** Les calculs « intelligents »
|
||||||
|
(solveur, suggestions) proposent ; ils ne persistent jamais rien
|
||||||
|
d'eux-mêmes. La validation reste seule juge au moment de l'écriture.
|
||||||
|
- **Erreurs = codes, pas phrases.** Le backend renvoie
|
||||||
|
`{"detail": {"code": "domaine.raison", ...params}}` ; la traduction se
|
||||||
|
fait côté locales. Les violations de règles sont typées (`BLOCKING` /
|
||||||
|
`WARNING`) avec des paramètres structurés.
|
||||||
|
- **Simplicité assumée et documentée.** Quand on simplifie (ex. « vérifié
|
||||||
|
seulement contre l'existant, pas entre deux suggestions »), on l'écrit
|
||||||
|
explicitement comme simplification assumée.
|
||||||
|
- **Retirer est une fonctionnalité.** On n'hésite pas à supprimer un concept
|
||||||
|
devenu inutile (table, règle, écran) — migration, API, front et doc
|
||||||
|
nettoyés ensemble, plutôt que de laisser du code mort.
|
||||||
|
- **Aucune dépendance locale hors Docker.** Tout se lance, se teste et se
|
||||||
|
migre via `docker compose`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Stack technique
|
||||||
|
|
||||||
|
### Backend
|
||||||
|
|
||||||
|
| Rôle | Choix |
|
||||||
|
|------|-------|
|
||||||
|
| Langage | Python 3.12 |
|
||||||
|
| Gestion des dépendances | `uv` (`pyproject.toml`, groupe `dev`) |
|
||||||
|
| API | FastAPI + Uvicorn |
|
||||||
|
| ORM / schémas | SQLModel (SQLAlchemy + Pydantic) |
|
||||||
|
| Base | PostgreSQL 16 (driver `psycopg[binary]` v3) |
|
||||||
|
| Migrations | Alembic (autogenerate + `alembic check` pour vérifier modèle ↔ migrations) |
|
||||||
|
| Configuration | `pydantic-settings` (`app/config.py`, valeurs réelles dans `.env` non versionné) |
|
||||||
|
| Auth | `pyjwt` (HS256) + `bcrypt` |
|
||||||
|
| Tests | `pytest` + `pytest-cov`, **vraie base PostgreSQL de test** |
|
||||||
|
| Lint / format | `ruff` (line-length 100, règles `E F I UP B`) |
|
||||||
|
| Outils ponctuels | `openpyxl` (import/export Excel), `reportlab` + `pypdf` (PDF), `pillow` (validation d'images), `httpx` (API tierces), `ortools` (optimisation) — **⟨à adapter⟩** selon le besoin |
|
||||||
|
|
||||||
|
### Frontend
|
||||||
|
|
||||||
|
| Rôle | Choix |
|
||||||
|
|------|-------|
|
||||||
|
| Framework | React 18 + TypeScript (strict) |
|
||||||
|
| Build | Vite 5 |
|
||||||
|
| Style | Tailwind CSS 3 (thème étendu, aucune lib de composants) |
|
||||||
|
| Données serveur | TanStack React Query 5 (hooks centralisés dans `src/api/hooks.ts`) |
|
||||||
|
| Routing | React Router 6 |
|
||||||
|
| Graphiques | SVG maison (`components/charts.tsx`), aucune bibliothèque |
|
||||||
|
| Qualité | ESLint 9 + `tsc --noEmit` + script `smoke` (rendu headless via `tsx`) |
|
||||||
|
|
||||||
|
Dépendances runtime volontairement minimales : `react`, `react-dom`,
|
||||||
|
`react-router-dom`, `@tanstack/react-query`. Rien d'autre sans bonne raison.
|
||||||
|
|
||||||
|
### Infra
|
||||||
|
|
||||||
|
- Docker Compose en dev (db + backend en hot reload + frontend Vite).
|
||||||
|
- Production : images `backend` (uvicorn) et `frontend` (build statique
|
||||||
|
servi par nginx), ports exposés uniquement sur `127.0.0.1`, Caddy du VPS en
|
||||||
|
reverse proxy HTTPS (`/api/*` → backend avec préfixe retiré, le reste →
|
||||||
|
frontend).
|
||||||
|
- Dépôt Gitea auto-hébergé + Gitea Actions (`act_runner`) : tests → build des
|
||||||
|
images (registre Gitea) → SSH sur le VPS → `pull` → `alembic upgrade head`
|
||||||
|
→ `up -d`.
|
||||||
|
- Fuseau horaire : `TZ=Europe/Paris` + `tzdata` dans le conteneur.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Architecture
|
||||||
|
|
||||||
|
### Arborescence type
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── CLAUDE.md # contrat de travail (tenu à jour à chaque étape)
|
||||||
|
├── README.md
|
||||||
|
├── Makefile # make demo / make blank / make down / make logs
|
||||||
|
├── docker-compose.yml # dev
|
||||||
|
├── .env.example # toutes les variables, sans vraies valeurs
|
||||||
|
├── .gitea/workflows/ci-cd.yml
|
||||||
|
├── deploy/ # docker-compose.prod.yml, bloc Caddyfile, README de mise en service
|
||||||
|
├── docker/postgres-init/ # crée la base de test au premier démarrage
|
||||||
|
├── backend/
|
||||||
|
│ ├── pyproject.toml · Dockerfile · alembic.ini
|
||||||
|
│ ├── app/
|
||||||
|
│ │ ├── main.py # instance FastAPI, montage des routers
|
||||||
|
│ │ ├── config.py # Settings (pydantic-settings), get_settings() en cache
|
||||||
|
│ │ ├── db.py # engine + get_session
|
||||||
|
│ │ ├── logging_config.py # logs sans PII + identifiant de requête
|
||||||
|
│ │ ├── request_logging.py # middleware : une ligne par requête, X-Request-ID, 500 tracées
|
||||||
|
│ │ ├── api/ # un router par ressource + schemas.py + deps.py
|
||||||
|
│ │ ├── auth/ # passwords, magic_link, tokens (JWT), deps (rôles), rate_limit
|
||||||
|
│ │ ├── email/ # sender (SMTP), templates (texte), html (rendu thémé), check (diagnostic)
|
||||||
|
│ │ ├── models/ # enums.py, base.py (TimestampMixin, local_now), domain.py
|
||||||
|
│ │ ├── validation/ # cœur métier pur : models.py, engine.py, loader.py
|
||||||
|
│ │ ├── <module_métier>/ # même découpage pour chaque calcul isolé ⟨à adapter⟩
|
||||||
|
│ │ ├── i18n/ # t(key, **params) + locales/fr.json
|
||||||
|
│ │ ├── bootstrap.py # instance vierge : 1re entité racine + 1er compte admin
|
||||||
|
│ │ ├── seed.py # jeu de démonstration réaliste et déterministe
|
||||||
|
│ │ └── migrations/
|
||||||
|
│ └── tests/ # conftest.py (vraie base), factories.py, test_<module>.py
|
||||||
|
└── frontend/
|
||||||
|
├── Dockerfile · Dockerfile.prod · nginx.conf
|
||||||
|
├── tailwind.config.js # palette et primitives du design
|
||||||
|
├── scripts/smoke.tsx # rendu headless + vérifications structurelles
|
||||||
|
└── src/
|
||||||
|
├── api/ # types.ts (interface Api), schema.ts (miroir des schémas backend),
|
||||||
|
│ # http-client.ts, mock/ (même surface, en mémoire), hooks.ts, session.ts
|
||||||
|
├── app/ # AppShell.tsx, router.tsx
|
||||||
|
├── auth/ # auth-context, RequireAuth, roles (homePath par rôle)
|
||||||
|
├── components/ # ui.tsx (primitives), state.tsx (chargement/erreur), charts.tsx
|
||||||
|
├── i18n/ # t(key, params) + locales/fr.json
|
||||||
|
├── lib/ # logique pure testable (calculs, dates, env, cx)
|
||||||
|
└── pages/ # un écran par fichier, sous-dossiers si gros écran
|
||||||
|
```
|
||||||
|
|
||||||
|
### Principes d'architecture backend
|
||||||
|
|
||||||
|
- **Multi-tenant par une entité racine** (ici `Edition`) : toute entité
|
||||||
|
métier porte son `<racine>_id`, toutes les routes sont préfixées
|
||||||
|
`/<racines>/{id}/...` et la dépendance `get_<racine>` renvoie 404
|
||||||
|
`error.not_found` si elle n'existe pas. **⟨à adapter⟩** (organisation,
|
||||||
|
projet, saison…).
|
||||||
|
- **Clés primaires UUID**, champs d'audit `created_at`/`updated_at` sur
|
||||||
|
toutes les tables sauf associations (`TimestampMixin`).
|
||||||
|
- **Énumérations en `VARCHAR` + `CHECK`** (`native_enum=False`), jamais
|
||||||
|
d'ENUM natif PostgreSQL (migrations plus simples).
|
||||||
|
- **`ON DELETE CASCADE` au niveau base** sur les liens vers la racine et
|
||||||
|
entre entités : la suppression RGPD d'une personne est un vrai *hard
|
||||||
|
delete* qui emporte tout ce qui la concerne.
|
||||||
|
- **Dates naïves en heure locale** (`local_now()`), interprétées
|
||||||
|
Europe/Paris. Pas de mélange UTC/local.
|
||||||
|
- **Modules isolés pour la logique non triviale** : `models.py` (types
|
||||||
|
purs, dataclasses), `engine.py` (fonction pure), `loader.py` (seul accès
|
||||||
|
base). Testés sans HTTP.
|
||||||
|
- **Un router par ressource**, schémas Pydantic `XCreate` / `XRead` /
|
||||||
|
`XUpdate` dans `api/schemas.py`. En `PATCH` : `None`/absent = inchangé,
|
||||||
|
`[]` = vider une liste.
|
||||||
|
- **Secrets jamais renvoyés** par l'API (`xxx_set: bool` à la place ;
|
||||||
|
chaîne vide en écriture = effacer).
|
||||||
|
- **Tâches de fond** (`BackgroundTasks`) pour les emails, en *best effort* :
|
||||||
|
un échec SMTP est journalisé mais ne fait jamais échouer l'appel HTTP.
|
||||||
|
- **Nettoyage paresseux** plutôt que tâches planifiées (purge des données
|
||||||
|
périmées au passage d'une requête), tant que le volume le permet.
|
||||||
|
- **Instance vierge et démo** : `bootstrap.py` (CLI, crée la racine + le
|
||||||
|
1er compte) et `seed.py` (jeu réaliste avec des cas intéressants :
|
||||||
|
trous, conflits, données de chaque fonctionnalité).
|
||||||
|
|
||||||
|
### Principes d'architecture frontend
|
||||||
|
|
||||||
|
- **Une interface `Api` unique, deux implémentations** : client HTTP réel
|
||||||
|
et **mock en mémoire de même surface** (`VITE_API_MODE=mock|http`). Le
|
||||||
|
front se développe et se démontre sans backend ; passer de l'un à l'autre
|
||||||
|
ne change aucun écran. Le mock calcule les mêmes résultats que le backend.
|
||||||
|
- **`schema.ts` = miroir de `backend/app/api/schemas.py`**, gardé
|
||||||
|
synchrone à la main.
|
||||||
|
- **Toutes les données serveur passent par React Query** (`hooks.ts`), jamais
|
||||||
|
de `fetch` dans les pages.
|
||||||
|
- **Logique pure dans `src/lib/`**, souvent miroir d'une fonction backend
|
||||||
|
(ex. `festivalDay` ↔ `day_boundary`) : la règle est écrite à l'identique
|
||||||
|
des deux côtés et le `CLAUDE.md` le signale.
|
||||||
|
- **Auth** : JWT en `localStorage`, `Authorization: Bearer`, une 401
|
||||||
|
déconnecte ; `<RequireAuth>` sur toutes les pages métier ; page d'accueil
|
||||||
|
et onglets visibles selon le rôle.
|
||||||
|
- **Variables Vite figées au build** (`VITE_*`) : l'image de prod est
|
||||||
|
construite pour un environnement donné.
|
||||||
|
- **Téléchargements** (PDF, Excel) : blob → `<a download>` généré côté
|
||||||
|
client.
|
||||||
|
- **Chaque erreur affiche sa référence** (`X-Request-ID`) sous le message,
|
||||||
|
pour retrouver la ligne de log correspondante.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Sécurité et RGPD (non négociables)
|
||||||
|
|
||||||
|
- **Deux systèmes d'authentification, une même session JWT** :
|
||||||
|
- mot de passe (bcrypt, ≥ 10 caractères) pour les administrateurs ;
|
||||||
|
- **lien magique** (jeton aléatoire haché SHA-256 en base, usage unique,
|
||||||
|
TTL court) pour les autres comptes ; réponse `202` constante, sans jamais
|
||||||
|
révéler si un compte existe.
|
||||||
|
- **Rôles** appliqués côté backend par endpoint, documentés dans une
|
||||||
|
**matrice ressource × rôle** dans le `CLAUDE.md`. **⟨à adapter⟩**
|
||||||
|
(ici `COORDINATOR` / `LEAD` / `VOLUNTEER`).
|
||||||
|
- **Limiteurs de tentatives** en mémoire (connexion, lien magique,
|
||||||
|
formulaires publics, sondages vers API tierces) — `429
|
||||||
|
error.too_many_requests`.
|
||||||
|
- **Démarrage refusé en production** avec un `JWT_SECRET` par défaut, vide
|
||||||
|
ou trop court.
|
||||||
|
- **Pages publiques protégées par jeton** dans l'URL (`secrets.token_urlsafe`,
|
||||||
|
comparaison `secrets.compare_digest`, 404 générique), régénérable pour
|
||||||
|
révoquer un lien qui a fuité ; hCaptcha optionnel (désactivé si la clé est
|
||||||
|
absente).
|
||||||
|
- **Fichiers importés revalidés** (décodage réel d'image avec PIL, pas
|
||||||
|
seulement le `Content-Type`) ; exports Excel protégés contre l'injection de
|
||||||
|
formule (CWE-1236).
|
||||||
|
- **Aucune donnée nominative dans les logs** (ni nom, ni email, ni
|
||||||
|
téléphone, ni sujet d'email personnalisable) : on logue des identifiants.
|
||||||
|
Journal d'accès d'uvicorn **désactivé** (il écrivait les query strings,
|
||||||
|
donc les jetons).
|
||||||
|
- **Logs de diagnostic** : une ligne par requête (méthode, route *modèle*
|
||||||
|
+ identifiants, statut, durée, code d'erreur métier, compte) ; WARNING en
|
||||||
|
4xx, ERROR + trace complète en 5xx ; `X-Request-ID` propagé jusque dans les
|
||||||
|
tâches de fond. Erreur 422 : emplacement + type, jamais la valeur saisie.
|
||||||
|
- **Rétention paramétrable** des données nominatives sur l'entité racine ;
|
||||||
|
endpoint de suppression complète d'une personne.
|
||||||
|
- **En-têtes de sécurité** dans nginx et Caddy ; backend et frontend
|
||||||
|
n'écoutent que sur `127.0.0.1`.
|
||||||
|
- **Emails** : SMTP auto-hébergé, `EMAIL_ENABLED=false` en dev/tests (simple
|
||||||
|
journalisation), `multipart/alternative` (texte brut = source de vérité
|
||||||
|
des tests + HTML au thème de l'appli, tableaux et styles en ligne, logo en
|
||||||
|
pièce jointe inline par Content-ID plutôt qu'une URL qui fuiterait un
|
||||||
|
jeton). Commande de diagnostic SMTP dédiée.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Style visuel (design « néo-brutaliste »)
|
||||||
|
|
||||||
|
Identité forte, lisible, sans bibliothèque de composants : **bordures
|
||||||
|
franches noires, ombres portées dures sans flou, libellés en capitales, fond
|
||||||
|
crème, accents saturés**.
|
||||||
|
|
||||||
|
### Palette (`tailwind.config.js`)
|
||||||
|
|
||||||
|
| Jeton | Valeur | Usage |
|
||||||
|
|-------|--------|-------|
|
||||||
|
| `cream` | `#F5EFE1` | fond général |
|
||||||
|
| `ink` | `#14110E` | encre, bordures, ombres |
|
||||||
|
| `paper` | `#FFFDF7` | panneaux, cartes |
|
||||||
|
| `sand` / `sand-line` / `sand-dark` | `#EFE8D6` / `#E0D8C4` / `#E7E0CE` | barres secondaires, séparateurs |
|
||||||
|
| `yellow` / `yellow-soft` / `yellow-hover` | `#FFD23F` / `#FFE68A` / `#FFDF77` | action principale, état incomplet |
|
||||||
|
| `orange` / `orange-dark` | `#FF5C39` / `#E0421F` | urgence, danger |
|
||||||
|
| `green` | `#0E9F6E` | succès, survol de l'action principale |
|
||||||
|
| `blue` / `blue-strong` | `#A8C4FF` / `#2A6BFF` | information |
|
||||||
|
| `mauve` / `mauve-hover` | `#CBA6E3` / `#BE93D9` | dépassement / surplus |
|
||||||
|
|
||||||
|
### Typographie
|
||||||
|
|
||||||
|
- `font-display` : **Archivo** (400 → 900), titres et boutons en
|
||||||
|
`font-black`/`font-extrabold`, `uppercase`, `tracking-wide`, petites
|
||||||
|
tailles (11–12 px).
|
||||||
|
- `font-mono` : **DM Mono**, pour les heures, chiffres, codes.
|
||||||
|
- Chargées depuis Google Fonts dans `index.html`.
|
||||||
|
|
||||||
|
### Primitives (`components/ui.tsx`)
|
||||||
|
|
||||||
|
- **Ombres** : `shadow-brutal-sm` (2 px), `brutal` (3 px), `brutal-md`
|
||||||
|
(4 px), `brutal-lg` (6 px) — toutes `Npx Npx 0 #14110E`.
|
||||||
|
- **`Panel`** : `border-[3px] border-ink bg-paper` + ombre portée.
|
||||||
|
- **`PanelHeader`** : bandeau `bg-ink text-cream` en capitales (variante
|
||||||
|
hachurée `bg-hatch-ink text-yellow`).
|
||||||
|
- **`Btn`** : `border-2 border-ink`, capitales, variantes `solid` (jaune →
|
||||||
|
vert au survol), `ghost` (crème → jaune), `danger` (crème → orange), `dark`
|
||||||
|
(encre → jaune).
|
||||||
|
- **Trames d'état** en `backgroundImage` : hachures orange (critique), mauve
|
||||||
|
(surplus), encre (brouillon), sable (fermé), pointillés.
|
||||||
|
- Infobulles (`HelpTip`) en `position: fixed` positionnées par JS
|
||||||
|
(`useTooltipPosition`), bornées à l'écran — jamais en `absolute` dans un
|
||||||
|
conteneur qui défile.
|
||||||
|
- Graphiques SVG maison, palette vérifiée daltonisme/contraste sur `paper`,
|
||||||
|
**chaque graphique doublé d'une vue tableau**.
|
||||||
|
- Écrans mobiles dédiés aux rôles « terrain » (consultation simple), écrans
|
||||||
|
denses pour l'administration.
|
||||||
|
|
||||||
|
Aucun texte dans les primitives : les libellés viennent toujours de l'i18n.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Conventions de code
|
||||||
|
|
||||||
|
- **Code, base, fichiers en anglais** ; français uniquement dans les
|
||||||
|
locales, les commentaires de contexte métier et les commits.
|
||||||
|
- **i18n partout, même en monolingue** : backend `app.i18n.t(key,
|
||||||
|
**params)` (`str.format`), frontend `t(key, params)` (`{nom}`).
|
||||||
|
- **Commentaires qui expliquent le *pourquoi*** (contraintes, bug évité,
|
||||||
|
choix non évident), pas le *quoi*.
|
||||||
|
- **Tests backend** : vraie base PostgreSQL (créée par
|
||||||
|
`docker/postgres-init`), chaque test dans une transaction annulée
|
||||||
|
(savepoints, `join_transaction_mode="create_savepoint"`), fixtures
|
||||||
|
`autouse` qui coupent le SMTP et réinitialisent les limiteurs,
|
||||||
|
`factories.py` pour les données. Un fichier `test_<module>.py` par module
|
||||||
|
ou router ; tests d'autorisation dédiés (`test_authz.py`).
|
||||||
|
- **Tests frontend** : `typecheck` + `lint` + `smoke` (rendu SSR des écrans
|
||||||
|
avec le mock, et vérifications structurelles quand un bug visuel a déjà eu
|
||||||
|
lieu — ex. positions de grille rendues).
|
||||||
|
- **Migrations** numérotées (`0001`, `0002`…), une par étape qui touche le
|
||||||
|
modèle, vérifiées par `alembic check`.
|
||||||
|
- **Pas de nouvelle dépendance sans raison écrite** (commentaire dans
|
||||||
|
`pyproject.toml` si contrainte de version).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Commandes types
|
||||||
|
|
||||||
|
| Action | Commande |
|
||||||
|
|--------|----------|
|
||||||
|
| Tout lancer avec la démo | `make demo` |
|
||||||
|
| Instance vierge | `make blank EMAIL=… PASSWORD=… NAME=…` |
|
||||||
|
| Dev | `docker compose up --build` (API : http://localhost:8000/docs, front : http://localhost:5173) |
|
||||||
|
| Tests backend | `docker compose run --rm backend uv run pytest` |
|
||||||
|
| Lint / format | `docker compose run --rm backend uv run ruff check .` / `ruff format .` |
|
||||||
|
| Migration | `docker compose run --rm backend uv run alembic revision --autogenerate -m "…"` |
|
||||||
|
| Appliquer / vérifier | `… alembic upgrade head` puis `… alembic check` |
|
||||||
|
| Front | `npm run typecheck && npm run lint && npm run smoke` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Méthode de travail avec Claude
|
||||||
|
|
||||||
|
1. **Étape 1 — squelette** : monorepo, Docker Compose, backend qui démarre
|
||||||
|
(`/health`), frontend vide, CI/CD, `CLAUDE.md` initial avec glossaire.
|
||||||
|
2. **Étape 2 — modèle de données complet** + migration initiale.
|
||||||
|
3. **Ensuite** : import des données existantes (analyse puis exécution,
|
||||||
|
mode simulation, rapport ligne par ligne, détection de doublons), CRUD,
|
||||||
|
cœur métier en TDD, seed de démo, authentification, puis fonctionnalités
|
||||||
|
une par une.
|
||||||
|
4. **À chaque étape** : code + tests + migration + mise à jour du
|
||||||
|
`CLAUDE.md` (modèle, règles, journal) + front (mock compris) → montrer le
|
||||||
|
résultat → attendre la validation → commit atomique en français.
|
||||||
|
5. **Revues de sécurité régulières** avant toute ouverture au public, notées
|
||||||
|
comme étapes à part entière.
|
||||||
Reference in New Issue
Block a user