generated from gilles/template-webapp
claude code
This commit is contained in:
@@ -11,54 +11,49 @@ Il sert de base aux décisions techniques, aux ADR et au découpage des tâches.
|
||||
|
||||
---
|
||||
|
||||
## 1. Vue d’ensemble
|
||||
- Objectif produit : <A REMPLIR - PROJET> (exemple: améliorer la traçabilité — a supprimer)
|
||||
- Type d’app (web, mobile, API) : <A REMPLIR - PROJET> (exemple: à personnaliser — a supprimer)
|
||||
- Contraintes fortes : <A REMPLIR - PROJET> (exemple: déploiement on-premise — a supprimer)
|
||||
## 1. Vue d'ensemble
|
||||
- Objectif produit : Gérer l'inventaire complet d'un domicile avec recherche, localisation précise et archivage de documents <!-- complété par codex -->
|
||||
- Type d'app : Application web full-stack (API REST + SPA) avec déploiement conteneurisé <!-- complété par codex -->
|
||||
- Contraintes fortes : Self-hosted sur réseau local, mono-utilisateur, simplicité de déploiement et maintenance <!-- complété par codex -->
|
||||
|
||||
## 2. Principes d’architecture
|
||||
- Principes non négociables : <A REMPLIR - PROJET> (exemple: à personnaliser — a supprimer)
|
||||
- Principes d’évolution : <A COMPLETER PAR AGENT>
|
||||
- Qualités prioritaires (performance, sécurité, scalabilité) : <A REMPLIR - PROJET> (exemple: sécurité et performance — a supprimer)
|
||||
## 2. Principes d'architecture
|
||||
- Principes non négociables : Monolithe modulaire, séparation stricte frontend/backend, documentation avant implémentation, ADR pour décisions structurantes <!-- complété par codex -->
|
||||
- Principes d'évolution : Architecture permettant une évolution vers multi-utilisateurs sans refonte complète, modules indépendants testables séparément <!-- complété par codex -->
|
||||
- Qualités prioritaires : Simplicité d'utilisation > Performance > Maintenabilité > Évolutivité (mono-utilisateur donc pas de scalabilité horizontale) <!-- complété par codex -->
|
||||
|
||||
## 3. Architecture logique
|
||||
- Modules principaux : <A COMPLETER PAR AGENT>
|
||||
- Responsabilités par module : <A COMPLETER PAR AGENT>
|
||||
- Frontend/Backend séparation : <A COMPLETER PAR AGENT>
|
||||
- Modules principaux : `items` (objets/équipements), `locations` (emplacements physiques), `categories` (domaines: bricolage, informatique, etc.), `documents` (photos, notices, factures), `search` (recherche full-text) <!-- complété par codex -->
|
||||
- Responsabilités par module : `items` = CRUD objets + état + prix, `locations` = hiérarchie lieux (meuble>tiroir>boîte), `categories` = classification, `documents` = upload/stockage fichiers, `search` = indexation et recherche <!-- complété par codex -->
|
||||
- Frontend/Backend séparation : SPA React (frontend) communique uniquement via API REST avec FastAPI (backend), pas de SSR (Server-Side Rendering), API documentée par OpenAPI <!-- complété par codex -->
|
||||
|
||||
## 4. Architecture technique
|
||||
- Langages & frameworks : <A COMPLETER PAR AGENT>
|
||||
- Base de données : <A COMPLETER PAR AGENT>
|
||||
- Stockage fichiers : <A COMPLETER PAR AGENT>
|
||||
- Infra cible (cloud/self-hosted) : <A REMPLIR - PROJET> (exemple: self-hosted — a supprimer)
|
||||
- Langages & frameworks : Backend = Python 3.11+ avec FastAPI + SQLAlchemy + Pydantic, Frontend = TypeScript + React 18+ + Vite + TailwindCSS <!-- complété par codex -->
|
||||
- Base de données : SQLite (fichier local homestock.db) avec FTS5 pour recherche full-text, migrations via Alembic <!-- complété par codex -->
|
||||
- Stockage fichiers : Système de fichiers local, dossier `uploads/` organisé par type (photos/, notices/, factures/), chemin relatif stocké en BDD <!-- complété par codex -->
|
||||
- Infra cible : Self-hosted via Docker Compose, réseau local 10.0.0.0/22, reverse proxy optionnel (Traefik/Nginx) <!-- complété par codex -->
|
||||
|
||||
## 5. Flux de données
|
||||
- Flux principaux (lecture/écriture) : <A COMPLETER PAR AGENT>
|
||||
- Intégrations externes : <A REMPLIR - PROJET> (exemple: ERP existant — a supprimer)
|
||||
- Gestion des événements/asynchronisme : <A COMPLETER PAR AGENT>
|
||||
- Flux principaux : Lecture = GET items avec filtres (catégorie, localisation, état) + recherche full-text, Écriture = POST/PUT/DELETE items + upload fichiers multipart/form-data <!-- complété par codex -->
|
||||
- Intégrations externes : Aucune intégration externe prévue, système autonome et déconnecté <!-- complété par codex -->
|
||||
- Gestion des événements/asynchronisme : Upload fichiers en asynchrone (FastAPI background tasks), pas d'événements temps réel pour MVP (possibilité WebSocket future) <!-- complété par codex -->
|
||||
|
||||
## 6. Sécurité
|
||||
- Authentification/autorisation : <A COMPLETER PAR AGENT>
|
||||
- Données sensibles : <A REMPLIR - PROJET> (exemple: emails + historiques de paiement — a supprimer)
|
||||
- Traçabilité/audit : <A COMPLETER PAR AGENT>
|
||||
- Authentification/autorisation : Optionnelle pour MVP mono-utilisateur, si activée = login simple (username/password) + session cookie, pas de JWT pour simplicité <!-- complété par codex -->
|
||||
- Données sensibles : Factures (montants, dates d'achat), localisations précises d'objets de valeur → chiffrement au repos optionnel, accès réseau local uniquement <!-- complété par codex -->
|
||||
- Traçabilité/audit : Pas d'audit trail strict pour MVP, timestamps created_at/updated_at sur entités principales, logs applicatifs pour debug <!-- complété par codex -->
|
||||
|
||||
## 7. Observabilité
|
||||
- Logs (journaux) : <A COMPLETER PAR AGENT>
|
||||
- Metrics (mesures) : <A COMPLETER PAR AGENT>
|
||||
- Alerting (alertes) : <A COMPLETER PAR AGENT>
|
||||
- Logs : Python logging avec rotation (loguru recommandé), niveau INFO en production, DEBUG en dev, format JSON pour parsing <!-- complété par codex -->
|
||||
- Metrics : Optionnelles pour MVP, possibilité ajout Prometheus + Grafana plus tard (nb items, espace disque uploads/, temps réponse API) <!-- complété par codex -->
|
||||
- Alerting : Pas d'alerting pour MVP mono-utilisateur, monitoring manuel via logs et health check endpoint `/health` <!-- complété par codex -->
|
||||
|
||||
## 8. Conventions de code
|
||||
- Organisation des dossiers : <A COMPLETER PAR AGENT>
|
||||
- Standards de code : <A COMPLETER PAR AGENT>
|
||||
- Tests obligatoires : <A COMPLETER PAR AGENT>
|
||||
- Organisation des dossiers : Backend = `backend/app/` (routers/, models/, schemas/, services/), Frontend = `frontend/src/` (components/, pages/, hooks/, api/) <!-- complété par codex -->
|
||||
- Standards de code : Backend = ruff format + mypy strict, Frontend = ESLint + Prettier, nommage snake_case (Python) et camelCase (TS), français pour commentaires <!-- complété par codex -->
|
||||
- Tests obligatoires : Backend = tests unitaires (services/) + tests intégration (API), Frontend = tests unitaires (utils/hooks), couverture minimum 70% sur logique métier <!-- complété par codex -->
|
||||
|
||||
## 9. Évolution & dette
|
||||
- Zones à risque : <A REMPLIR - PROJET> (exemple: montée en charge — a supprimer)
|
||||
- Améliorations prévues : <A REMPLIR - PROJET> (exemple: reporting avancé — a supprimer)
|
||||
- Zones à risque : Recherche full-text sur SQLite (limitations si >10k items), stockage fichiers local (backup manuel nécessaire), authentification simpliste <!-- complété par codex -->
|
||||
- Améliorations prévues : Migration SQLite→PostgreSQL si besoin, stockage fichiers vers MinIO/S3, multi-utilisateurs avec RBAC (contrôle d'accès par rôle), API mobile, import/export CSV <!-- complété par codex -->
|
||||
|
||||
---
|
||||
|
||||
## Exemple (a supprimer)
|
||||
- Modules : `auth`, `users`, `billing`, `catalog`.
|
||||
- DB : PostgreSQL + migrations.
|
||||
- Auth : JWT (jeton) + RBAC (contrôle d’accès par rôle).
|
||||
---
|
||||
@@ -11,24 +11,20 @@ Ce guide définit les conventions de code et de documentation.
|
||||
---
|
||||
|
||||
## 1. Nommage
|
||||
- Variables / fonctions : <A COMPLETER PAR AGENT>
|
||||
- Fichiers / dossiers : <A COMPLETER PAR AGENT>
|
||||
- API endpoints : <A COMPLETER PAR AGENT>
|
||||
- Variables / fonctions : Backend = snake_case (Python PEP8), Frontend = camelCase (TypeScript/JavaScript standard) <!-- complété par codex -->
|
||||
- Fichiers / dossiers : Backend = snake_case (item_service.py), Frontend = PascalCase pour composants (ItemCard.tsx), kebab-case pour autres (use-items.ts) <!-- complété par codex -->
|
||||
- API endpoints : REST kebab-case `/api/v1/items`, `/api/v1/item-categories`, pluriel pour collections, singulier pour ressource unique <!-- complété par codex -->
|
||||
|
||||
## 2. Formatage
|
||||
- Formatter / linter : <A COMPLETER PAR AGENT>
|
||||
- Règles principales : <A COMPLETER PAR AGENT>
|
||||
- Formatter / linter : Backend = ruff (format + lint) + mypy (types), Frontend = Prettier + ESLint + TypeScript strict <!-- complété par codex -->
|
||||
- Règles principales : Indentation 4 espaces (Python), 2 espaces (TS/JS), ligne max 100 caractères, trailing commas, quotes doubles <!-- complété par codex -->
|
||||
|
||||
## 3. Tests
|
||||
- Nommage des tests : <A COMPLETER PAR AGENT>
|
||||
- Structure des tests : <A COMPLETER PAR AGENT>
|
||||
- Nommage des tests : Backend = `test_<fonction>_<scenario>.py`, Frontend = `<module>.test.ts`, fonctions de test descriptives `test_create_item_with_valid_data` <!-- complété par codex -->
|
||||
- Structure des tests : Pattern AAA (Arrange/Act/Assert), fixtures pytest pour setup, mocks minimaux, tests isolés et reproductibles <!-- complété par codex -->
|
||||
|
||||
## 4. Documentation
|
||||
- Doc obligatoire : <A REMPLIR - PROJET> (exemple: README + ARCHITECTURE — a supprimer)
|
||||
- ADR (Architecture Decision Record) : <A COMPLETER PAR AGENT>
|
||||
- Doc obligatoire : README.md (démarrage), ARCHITECTURE.md (structure technique), fichiers CONTEXT (backend/frontend), ADR pour décisions structurantes <!-- complété par codex -->
|
||||
- ADR : Suivre template docs/adr/TEMPLATE.md, numérotation séquentielle (0001, 0002...), statut (proposé/accepté/obsolète), contexte + décision + conséquences <!-- complété par codex -->
|
||||
|
||||
---
|
||||
|
||||
## Exemple (a supprimer)
|
||||
- Formatter : `prettier` + `eslint`.
|
||||
- Tests : `feature_x.test.ts`.
|
||||
---
|
||||
@@ -12,36 +12,36 @@ Il sert de référence aux agents et aux contributeurs.
|
||||
---
|
||||
|
||||
## 1. Branches
|
||||
- Convention de nommage : <A COMPLETER PAR AGENT>
|
||||
- Branches protégées : <A REMPLIR - PROJET> (exemple: main — a supprimer)
|
||||
- Politique de merge : <A COMPLETER PAR AGENT>
|
||||
- Convention de nommage : `feature/REQ-XXX-description`, `fix/bug-description`, `docs/update-xxx`, `refactor/module-name` <!-- complété par codex -->
|
||||
- Branches protégées : `main` (production-ready) <!-- complété par codex -->
|
||||
- Politique de merge : Squash merge vers main, fast-forward interdit, historique linéaire privilégié <!-- complété par codex -->
|
||||
|
||||
## 2. Commits
|
||||
- Convention (ex: conventional commits) : <A COMPLETER PAR AGENT>
|
||||
- Granularité attendue : <A REMPLIR - PROJET> (exemple: 1 feature par PR — a supprimer)
|
||||
- Convention : Conventional Commits (feat/fix/docs/refactor/test/chore), format: `type(scope): message` en français <!-- complété par codex -->
|
||||
- Granularité attendue : 1 commit par changement logique, 1 feature complète par PR avec tests associés <!-- complété par codex -->
|
||||
|
||||
## 3. Pull Requests
|
||||
- Template PR : <A COMPLETER PAR AGENT>
|
||||
- Relectures requises : <A REMPLIR - PROJET> (exemple: 1 review — a supprimer)
|
||||
- Template PR : Titre court (<70 car), description avec ## Changements, ## Tests, ## Checklist, référence REQ-XXX <!-- complété par codex -->
|
||||
- Relectures requises : Aucune (projet solo), possibilité de review par Claude Code avant merge <!-- complété par codex -->
|
||||
- Checklist obligatoire : `docs/PR_CHECKLIST.md`
|
||||
|
||||
## 4. CI/CD
|
||||
- Pipeline minimal (lint/test/build) : <A COMPLETER PAR AGENT>
|
||||
- Vérifications bloquantes : <A COMPLETER PAR AGENT>
|
||||
- Pipeline minimal : Gitea Actions avec steps: lint (ruff, eslint) → test (pytest, vitest) → build (Docker images) → optionnel deploy <!-- complété par codex -->
|
||||
- Vérifications bloquantes : Lint sans erreur, tests unitaires passent, build Docker réussit, couverture >70% sur nouveau code <!-- complété par codex -->
|
||||
|
||||
## 5. Releases
|
||||
- Versioning (semver = versionnage sémantique) : <A COMPLETER PAR AGENT>
|
||||
- Tagging : <A COMPLETER PAR AGENT>
|
||||
- Versioning : Semver (semantic versioning) v0.x.y pour pré-release, v1.0.0 pour première version stable, tags Git annotés <!-- complété par codex -->
|
||||
- Tagging : Tag après merge dans main, format `vX.Y.Z`, signé GPG si possible <!-- complété par codex -->
|
||||
- Release notes : `product/RELEASE_NOTES.md`
|
||||
|
||||
## 6. Qualité
|
||||
- Definition of Done (définition de terminé) : <A REMPLIR - PROJET> (exemple: tests + doc — a supprimer)
|
||||
- Tests obligatoires : <A COMPLETER PAR AGENT>
|
||||
- Mises à jour doc : <A REMPLIR - PROJET> (exemple: si impact sur l’API — a supprimer)
|
||||
- Definition of Done : Feature implémentée + tests unitaires + tests intégration API + documentation mise à jour (si impact) + CI passe <!-- complété par codex -->
|
||||
- Tests obligatoires : Tests unitaires sur logique métier (services/), tests intégration sur endpoints API, couverture minimum 70% <!-- complété par codex -->
|
||||
- Mises à jour doc : Obligatoire si changement API (OpenAPI), architecture (ADR), ou contrats (data_model.md) <!-- complété par codex -->
|
||||
|
||||
## 7. Hotfix / Urgence
|
||||
- Procédure : <A COMPLETER PAR AGENT>
|
||||
- Responsables : <A REMPLIR - PROJET> (exemple: lead dev — a supprimer)
|
||||
- Procédure : Branche `hotfix/description` depuis main, fix minimal, tests rapides, merge direct main, tag patch version <!-- complété par codex -->
|
||||
- Responsables : Développeur principal (projet solo), pas de process complexe pour mono-utilisateur <!-- complété par codex -->
|
||||
|
||||
---
|
||||
|
||||
@@ -54,9 +54,4 @@ Il sert de référence aux agents et aux contributeurs.
|
||||
- Réseau local : 10.0.0.0/22
|
||||
- Passerelle : 10.0.0.1
|
||||
|
||||
---
|
||||
|
||||
## Exemple (a supprimer)
|
||||
- Branches : `main`, `develop`, `feat/*`, `fix/*`.
|
||||
- Commits : Conventional Commits.
|
||||
- CI : lint + tests + build.
|
||||
---
|
||||
192
docs/adr/0001-choix-stack-technique.md
Normal file
192
docs/adr/0001-choix-stack-technique.md
Normal file
@@ -0,0 +1,192 @@
|
||||
# ADR-0001 — Choix de la stack technique globale
|
||||
|
||||
- Statut : accepted
|
||||
- Date : 2026-01-27
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
HomeStock est une application web self-hosted de gestion d'inventaire domestique destinée à un usage mono-utilisateur. Les contraintes principales sont :
|
||||
|
||||
- **Simplicité de déploiement** : L'application doit être facile à installer et maintenir sur un réseau local
|
||||
- **Usage mono-utilisateur** : Pas besoin de scalabilité horizontale ni de gestion complexe de concurrence
|
||||
- **Self-hosted** : Déploiement local, pas de dépendance cloud
|
||||
- **Développement rapide** : Besoin d'un MVP fonctionnel rapidement avec des technologies modernes et productives
|
||||
- **Maintenance à long terme** : Stack stable avec un bon écosystème et une documentation solide
|
||||
|
||||
Le projet nécessite :
|
||||
- Une API REST robuste pour le backend
|
||||
- Une interface utilisateur moderne et réactive
|
||||
- Une base de données adaptée au mono-utilisateur
|
||||
- Un système de stockage de fichiers (photos, notices, factures)
|
||||
|
||||
---
|
||||
|
||||
## Décision
|
||||
|
||||
Nous avons choisi la stack technique suivante :
|
||||
|
||||
### Backend
|
||||
- **Langage** : Python 3.11+
|
||||
- **Framework API** : FastAPI
|
||||
- **ORM** : SQLAlchemy 2.0+ avec Alembic pour migrations
|
||||
- **Validation** : Pydantic (intégré à FastAPI)
|
||||
|
||||
### Frontend
|
||||
- **Langage** : TypeScript
|
||||
- **Framework UI** : React 18+
|
||||
- **Bundler** : Vite 5+
|
||||
- **Gestion état** : TanStack Query (React Query) pour l'état serveur, Context API pour l'état local
|
||||
- **Styling** : TailwindCSS avec palette Gruvbox dark
|
||||
|
||||
### Base de données
|
||||
- **SGBD** : SQLite avec extension FTS5 pour recherche full-text
|
||||
- **Fichier** : `homestock.db` en local
|
||||
|
||||
### Stockage fichiers
|
||||
- **Système** : Système de fichiers local
|
||||
- **Organisation** : Dossier `uploads/` avec sous-dossiers par type (photos/, notices/, factures/)
|
||||
- **Référencement** : Chemins relatifs stockés en base de données
|
||||
|
||||
### Déploiement
|
||||
- **Conteneurisation** : Docker Compose
|
||||
- **Réseau** : Réseau local 10.0.0.0/22
|
||||
|
||||
---
|
||||
|
||||
## Alternatives considérées
|
||||
|
||||
### Backend
|
||||
1. **Django + Django REST Framework**
|
||||
- ✅ Framework très complet avec admin intégré
|
||||
- ✅ ORM mature et puissant
|
||||
- ❌ Plus lourd et verbeux que FastAPI
|
||||
- ❌ Performance inférieure en async
|
||||
- **Rejeté** : Trop de fonctionnalités inutiles pour notre cas d'usage mono-utilisateur
|
||||
|
||||
2. **Go avec Gin/Echo**
|
||||
- ✅ Très performant, binaire standalone
|
||||
- ✅ Faible consommation mémoire
|
||||
- ❌ Écosystème moins riche pour gestion fichiers/images
|
||||
- ❌ Développement plus verbeux, moins rapide
|
||||
- **Rejeté** : Performance non critique pour mono-utilisateur, productivité Python préférée
|
||||
|
||||
3. **Node.js avec Express/Fastify**
|
||||
- ✅ Écosystème npm très riche
|
||||
- ✅ Même langage que le frontend (JavaScript/TypeScript)
|
||||
- ❌ Gestion async plus complexe qu'avec FastAPI
|
||||
- ❌ Préférence personnelle pour Python
|
||||
- **Rejeté** : Moins d'expérience, Python préféré pour backend
|
||||
|
||||
### Frontend
|
||||
1. **Vue.js 3**
|
||||
- ✅ Simple à apprendre, Composition API moderne
|
||||
- ✅ Excellente documentation
|
||||
- ❌ Écosystème légèrement moins riche que React
|
||||
- **Rejeté** : React préféré pour son écosystème et l'expérience existante
|
||||
|
||||
2. **Svelte/SvelteKit**
|
||||
- ✅ Très léger, compilation au build
|
||||
- ✅ Syntaxe simple et élégante
|
||||
- ❌ Écosystème moins mature
|
||||
- ❌ Moins de ressources et bibliothèques tierces
|
||||
- **Rejeté** : Écosystème trop jeune pour un projet à long terme
|
||||
|
||||
### Base de données
|
||||
1. **PostgreSQL**
|
||||
- ✅ Très robuste, fonctionnalités avancées
|
||||
- ✅ Meilleure recherche full-text (GIN indexes)
|
||||
- ❌ Serveur séparé à gérer, plus complexe
|
||||
- ❌ Overhead pour mono-utilisateur avec faible volume
|
||||
- **Rejeté** : Trop complexe pour un usage mono-utilisateur avec <10k items attendus
|
||||
|
||||
2. **MySQL/MariaDB**
|
||||
- ✅ Populaire, bien documenté
|
||||
- ✅ Bonnes performances
|
||||
- ❌ Recherche full-text moins performante
|
||||
- ❌ Serveur séparé à gérer
|
||||
- **Rejeté** : Même raison que PostgreSQL, SQLite suffit largement
|
||||
|
||||
### Stockage fichiers
|
||||
1. **MinIO (S3-compatible)**
|
||||
- ✅ Scalable, versioning, métadonnées riches
|
||||
- ✅ Compatible S3, facilite migration future
|
||||
- ❌ Service supplémentaire à déployer et maintenir
|
||||
- ❌ Overhead pour mono-utilisateur
|
||||
- **Rejeté** : Trop complexe pour le besoin, système fichiers local suffit
|
||||
|
||||
2. **Stockage en base (BLOB)**
|
||||
- ✅ Pas de fichiers externes à gérer
|
||||
- ✅ Transactions ACID sur fichiers
|
||||
- ❌ Performance dégradée avec fichiers volumineux
|
||||
- ❌ Backup et restauration plus complexes
|
||||
- ❌ Taille de la base de données augmente rapidement
|
||||
- **Rejeté** : Mauvaise pratique, problèmes de performance prévisibles
|
||||
|
||||
---
|
||||
|
||||
## Conséquences
|
||||
|
||||
### Positives
|
||||
1. **Simplicité de déploiement** : Un seul `docker-compose up` lance l'ensemble de la stack
|
||||
2. **Performance suffisante** : FastAPI async + SQLite suffisent largement pour mono-utilisateur
|
||||
3. **Développement rapide** : FastAPI + React offrent une excellente productivité
|
||||
4. **Pas de serveur BDD externe** : SQLite embarqué, un seul fichier à sauvegarder
|
||||
5. **Auto-documentation API** : FastAPI génère automatiquement OpenAPI/Swagger
|
||||
6. **Typage fort** : TypeScript (frontend) + Pydantic (backend) réduisent les erreurs
|
||||
7. **Écosystèmes matures** : Python et React ont d'excellentes bibliothèques tierces
|
||||
8. **Recherche performante** : FTS5 SQLite offre une recherche full-text native et rapide
|
||||
|
||||
### Négatives
|
||||
1. **Limitations SQLite** : Pas de scalabilité horizontale (non critique pour mono-utilisateur)
|
||||
2. **Recherche limitée** : FTS5 moins puissant qu'Elasticsearch (acceptable pour <10k items)
|
||||
3. **Stockage fichiers manuel** : Pas de métadonnées avancées ni versioning
|
||||
4. **Backup manuel** : Nécessite scripts de backup pour fichiers + BDD
|
||||
5. **Migration future** : Si passage multi-utilisateurs, migration vers PostgreSQL nécessaire
|
||||
|
||||
### Neutres
|
||||
1. **Deux langages** : Python (backend) + TypeScript (frontend) nécessitent deux environnements
|
||||
2. **Complexité initiale React** : Courbe d'apprentissage pour développement React moderne
|
||||
|
||||
---
|
||||
|
||||
## Impacts techniques
|
||||
|
||||
### Organisation du code
|
||||
- **Monorepo** : Backend et frontend dans le même dépôt
|
||||
- **Structure backend** : `backend/app/` avec routers/, models/, schemas/, services/, repositories/
|
||||
- **Structure frontend** : `frontend/src/` avec components/, pages/, hooks/, api/
|
||||
|
||||
### Dépendances principales
|
||||
- **Backend** : fastapi, uvicorn, sqlalchemy, alembic, pydantic, python-multipart, loguru
|
||||
- **Frontend** : react, react-router-dom, @tanstack/react-query, tailwindcss, axios
|
||||
|
||||
### Développement
|
||||
- **Tests** : pytest (backend), vitest (frontend)
|
||||
- **Lint/Format** : ruff + mypy (backend), eslint + prettier (frontend)
|
||||
- **CI/CD** : Gitea Actions avec lint → test → build → deploy
|
||||
|
||||
### Déploiement
|
||||
- **Docker** : 3 services (backend, frontend, reverse proxy optionnel)
|
||||
- **Volumes** : Persistance pour `homestock.db` et `uploads/`
|
||||
- **Ports** : Backend :8000, Frontend :5173 (dev) ou :80/:443 (prod avec reverse proxy)
|
||||
|
||||
### Évolutivité future
|
||||
- **Migration PostgreSQL** : Possible via Alembic migrations si besoin
|
||||
- **Stockage S3** : Abstraction stockage permet ajout MinIO sans refonte
|
||||
- **Multi-utilisateurs** : Architecture modulaire facilite ajout authentification/RBAC
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
Cette stack a été choisie en janvier 2026 pour un MVP mono-utilisateur. Les choix privilégient la simplicité et la rapidité de développement sur la scalabilité et les fonctionnalités avancées qui ne sont pas nécessaires pour le cas d'usage initial.
|
||||
|
||||
La stack permet une évolution progressive vers multi-utilisateurs et stockage cloud si besoin, mais ces aspects sont volontairement exclus du MVP pour réduire la complexité initiale.
|
||||
|
||||
Les alternatives (PostgreSQL, MinIO) restent envisageables pour des évolutions futures et sont documentées dans la section "Améliorations prévues" de [docs/ARCHITECTURE.md](../ARCHITECTURE.md).
|
||||
|
||||
---
|
||||
|
||||
**Contributeurs** : Gilles (décideur) + Claude Code (architecte)
|
||||
@@ -1,24 +0,0 @@
|
||||
# ADR-0001 — Exemple (a supprimer)
|
||||
|
||||
- Statut : accepted
|
||||
- Date : 2026-01-27
|
||||
|
||||
## Contexte
|
||||
- Besoin d’un framework API simple et maintenable.
|
||||
|
||||
## Décision
|
||||
- Utiliser un monolithe modulaire.
|
||||
|
||||
## Alternatives considérées
|
||||
- Microservices.
|
||||
- Serverless (exécution sans serveur dédié).
|
||||
|
||||
## Conséquences
|
||||
- Déploiement plus simple.
|
||||
- Risque de croissance du monolithe.
|
||||
|
||||
## Impacts techniques
|
||||
- Découper par domaines.
|
||||
|
||||
## Notes
|
||||
- Revoir après 6 mois.
|
||||
235
docs/adr/0002-architecture-monolithe-modulaire.md
Normal file
235
docs/adr/0002-architecture-monolithe-modulaire.md
Normal file
@@ -0,0 +1,235 @@
|
||||
# ADR-0002 — Architecture monolithe modulaire
|
||||
|
||||
- Statut : accepted
|
||||
- Date : 2026-01-27
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
HomeStock nécessite une architecture logicielle adaptée à un projet mono-utilisateur self-hosted avec les contraintes suivantes :
|
||||
|
||||
- **Simplicité de déploiement** : L'application doit pouvoir être déployée facilement avec une seule commande
|
||||
- **Maintenance réduite** : Pas d'équipe DevOps, maintenance manuelle par l'utilisateur
|
||||
- **Développement solo** : Un seul développeur, besoin de cohérence et de simplicité
|
||||
- **Évolutivité future** : Possibilité d'évoluer vers multi-utilisateurs sans refonte complète
|
||||
- **Modules logiques distincts** : items, locations, categories, documents, search
|
||||
|
||||
Le projet démarre avec un périmètre limité (MVP) mais doit pouvoir évoluer progressivement. La question architecturale centrale est : comment organiser le code pour maximiser la maintenabilité tout en gardant une complexité opérationnelle minimale ?
|
||||
|
||||
---
|
||||
|
||||
## Décision
|
||||
|
||||
Nous adoptons une **architecture monolithe modulaire** avec les caractéristiques suivantes :
|
||||
|
||||
### Définition
|
||||
- **Un seul dépôt Git** (monorepo) contenant backend et frontend
|
||||
- **Un seul processus backend** (serveur FastAPI unique)
|
||||
- **Modules logiques séparés** avec responsabilités clairement définies
|
||||
- **Communication intra-application** via appels de fonctions directs
|
||||
- **Base de données unique** partagée entre tous les modules
|
||||
|
||||
### Organisation backend (`backend/app/`)
|
||||
```
|
||||
backend/app/
|
||||
├── main.py # Point d'entrée FastAPI
|
||||
├── core/ # Configuration, logging, database
|
||||
│ ├── config.py
|
||||
│ ├── database.py
|
||||
│ └── logging.py
|
||||
├── models/ # Modèles SQLAlchemy (un fichier par entité)
|
||||
│ ├── item.py
|
||||
│ ├── location.py
|
||||
│ ├── category.py
|
||||
│ └── document.py
|
||||
├── schemas/ # Schémas Pydantic (validation API)
|
||||
│ ├── item.py
|
||||
│ ├── location.py
|
||||
│ └── ...
|
||||
├── routers/ # Endpoints API (un fichier par ressource)
|
||||
│ ├── items.py
|
||||
│ ├── locations.py
|
||||
│ ├── categories.py
|
||||
│ ├── documents.py
|
||||
│ └── search.py
|
||||
├── services/ # Logique métier (orchestration)
|
||||
│ ├── item_service.py
|
||||
│ ├── location_service.py
|
||||
│ └── ...
|
||||
├── repositories/ # Accès données (abstraction BDD)
|
||||
│ ├── item_repository.py
|
||||
│ ├── location_repository.py
|
||||
│ └── ...
|
||||
└── utils/ # Utilitaires transverses
|
||||
├── files.py
|
||||
└── search.py
|
||||
```
|
||||
|
||||
### Organisation frontend (`frontend/src/`)
|
||||
```
|
||||
frontend/src/
|
||||
├── main.tsx # Point d'entrée React
|
||||
├── App.tsx # Composant racine + routing
|
||||
├── components/ # Composants réutilisables
|
||||
│ ├── common/ # Boutons, inputs, modales...
|
||||
│ ├── items/ # Composants spécifiques items
|
||||
│ └── locations/ # Composants spécifiques locations
|
||||
├── pages/ # Pages complètes (routes)
|
||||
│ ├── Dashboard.tsx
|
||||
│ ├── ItemList.tsx
|
||||
│ ├── ItemDetail.tsx
|
||||
│ └── ...
|
||||
├── hooks/ # Custom hooks React
|
||||
│ ├── useItems.ts
|
||||
│ ├── useLocations.ts
|
||||
│ └── ...
|
||||
├── api/ # Client API (fetch/axios)
|
||||
│ ├── items.ts
|
||||
│ ├── locations.ts
|
||||
│ └── ...
|
||||
└── utils/ # Utilitaires helpers
|
||||
└── formatting.ts
|
||||
```
|
||||
|
||||
### Principes d'organisation
|
||||
1. **Séparation en couches backend** : routers → services → repositories → models
|
||||
2. **Dépendances unidirectionnelles** : Les couches supérieures dépendent des inférieures uniquement
|
||||
3. **Modules auto-contenus** : Chaque module (items, locations, etc.) a ses propres fichiers dans chaque couche
|
||||
4. **Pas de dépendances circulaires** entre modules
|
||||
5. **Code partagé** dans `core/` et `utils/`
|
||||
|
||||
---
|
||||
|
||||
## Alternatives considérées
|
||||
|
||||
### 1. Microservices
|
||||
**Description** : Séparer l'application en plusieurs services indépendants (service items, service locations, service search, etc.)
|
||||
|
||||
**Avantages** :
|
||||
- ✅ Scalabilité horizontale indépendante par service
|
||||
- ✅ Isolation des pannes (un service down ≠ tout down)
|
||||
- ✅ Possibilité d'utiliser des technologies différentes par service
|
||||
- ✅ Déploiement indépendant de chaque service
|
||||
|
||||
**Inconvénients** :
|
||||
- ❌ Complexité opérationnelle énorme (orchestration, networking, monitoring)
|
||||
- ❌ Nécessite API Gateway, service discovery, circuit breakers
|
||||
- ❌ Communication réseau entre services (latence, sérialisations multiples)
|
||||
- ❌ Transactions distribuées complexes (saga pattern)
|
||||
- ❌ Debugging et traçabilité difficiles
|
||||
- ❌ Overhead infrastructure (plusieurs conteneurs, load balancers, etc.)
|
||||
|
||||
**Verdict** : ❌ **Rejeté** - Complexité totalement disproportionnée pour un projet mono-utilisateur avec ~1 req/seconde max. Les bénéfices de scalabilité ne s'appliquent pas au cas d'usage.
|
||||
|
||||
### 2. Monolithe non structuré (big ball of mud)
|
||||
**Description** : Tout le code dans quelques gros fichiers sans organisation claire
|
||||
|
||||
**Avantages** :
|
||||
- ✅ Démarrage très rapide
|
||||
- ✅ Pas de contraintes architecturales
|
||||
|
||||
**Inconvénients** :
|
||||
- ❌ Maintenance cauchemardesque après quelques mois
|
||||
- ❌ Code fortement couplé, difficile à tester
|
||||
- ❌ Évolution impossible sans refonte complète
|
||||
- ❌ Onboarding difficile pour contributeurs futurs
|
||||
|
||||
**Verdict** : ❌ **Rejeté** - Dette technique garantie, inacceptable même pour un projet solo
|
||||
|
||||
### 3. Architecture hexagonale (ports & adapters)
|
||||
**Description** : Isolation stricte du domaine métier avec ports (interfaces) et adapters (implémentations)
|
||||
|
||||
**Avantages** :
|
||||
- ✅ Isolation forte du domaine métier
|
||||
- ✅ Testabilité maximale (mocks faciles)
|
||||
- ✅ Changement de base de données transparent
|
||||
|
||||
**Inconvénients** :
|
||||
- ❌ Boilerplate important (interfaces, adapters, DTOs multiples)
|
||||
- ❌ Courbe d'apprentissage élevée
|
||||
- ❌ Overhead pour un projet simple comme HomeStock
|
||||
|
||||
**Verdict** : ⚠️ **Rejeté mais inspirant** - Trop complexe pour notre besoin, mais on garde l'idée de séparation en couches (repository pattern)
|
||||
|
||||
### 4. Monolithe avec modules faiblement couplés (notre choix)
|
||||
**Description** : Un seul déploiement avec modules logiques bien séparés et communication via interfaces claires
|
||||
|
||||
**Avantages** :
|
||||
- ✅ Simplicité opérationnelle (un seul processus, un seul conteneur)
|
||||
- ✅ Transactions ACID simples (même base de données)
|
||||
- ✅ Pas de latence réseau entre modules
|
||||
- ✅ Refactoring et debugging faciles
|
||||
- ✅ Évolution progressive possible (extraction en microservices si vraiment nécessaire)
|
||||
- ✅ Maintenance réduite
|
||||
|
||||
**Inconvénients** :
|
||||
- ⚠️ Scalabilité horizontale limitée (non critique pour mono-utilisateur)
|
||||
- ⚠️ Restart complet nécessaire pour tout changement (acceptable)
|
||||
|
||||
**Verdict** : ✅ **Choisi** - Meilleur équilibre complexité/bénéfices pour notre contexte
|
||||
|
||||
---
|
||||
|
||||
## Conséquences
|
||||
|
||||
### Positives
|
||||
1. **Déploiement simple** : `docker-compose up` lance tout le système
|
||||
2. **Transactions ACID** : Toutes les opérations en base profitent des transactions SQLite
|
||||
3. **Performance** : Pas de latence réseau entre modules, appels de fonctions directs
|
||||
4. **Debugging facile** : Stack traces complètes, un seul processus à inspecter
|
||||
5. **Refactoring sans risque** : IDE et linters détectent les erreurs lors de renommages
|
||||
6. **Tests simples** : Tests d'intégration faciles (toute l'app dans le même process)
|
||||
7. **Maintenance réduite** : Un seul service à monitorer, logs centralisés naturellement
|
||||
|
||||
### Négatives
|
||||
1. **Scalabilité limitée** : Impossible de scaler un module indépendamment (non pertinent pour mono-utilisateur)
|
||||
2. **Couplage temporel** : Si un module plante, tout plante (acceptable avec bonne gestion erreurs)
|
||||
3. **Restart complet** : Modification = restart de toute l'app (dev avec hot-reload, prod peu de déploiements)
|
||||
|
||||
### Mitigations
|
||||
- **Pour éviter le couplage fort** : Respecter strictement les couches (routers → services → repositories)
|
||||
- **Pour faciliter évolution future** : Interfaces claires entre modules, pas de dépendances circulaires
|
||||
- **Pour améliorer résilience** : Gestion d'erreurs robuste, retry logic, circuit breaker patterns si nécessaire
|
||||
|
||||
---
|
||||
|
||||
## Impacts techniques
|
||||
|
||||
### Développement
|
||||
- **Pattern 3-layer** : Chaque feature touche 3 fichiers minimum (router, service, repository)
|
||||
- **Imports Python** : Imports absolus depuis `app.` pour éviter imports relatifs fragiles
|
||||
- **Tests** : Tests unitaires par couche + tests d'intégration API end-to-end
|
||||
|
||||
### Déploiement
|
||||
- **Docker** : Un seul conteneur backend (+ conteneur frontend séparé pour SPA)
|
||||
- **Scaling** : Scale vertical uniquement (augmenter CPU/RAM du conteneur)
|
||||
- **Rollback** : Simple (redéploiement image Docker précédente)
|
||||
|
||||
### Évolution future
|
||||
Si le projet nécessite vraiment des microservices (multi-utilisateurs massif, équipes séparées) :
|
||||
1. **Extraction progressive** : Modules déjà bien séparés, extraction facilitée
|
||||
2. **API interne → API externe** : Appels de fonctions deviennent appels HTTP
|
||||
3. **Base partagée → bases séparées** : Migrations Alembic facilitent séparation BDD
|
||||
|
||||
Cette architecture n'empêche pas l'évolution, elle la retarde jusqu'à ce qu'elle soit vraiment nécessaire (principe YAGNI = You Ain't Gonna Need It).
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
Cette décision s'inscrit dans la philosophie "Start with a monolith" popularisée par Martin Fowler et confirmée par de nombreux retours d'expérience (Shopify, GitHub, Stack Overflow ont démarré en monolithe).
|
||||
|
||||
Pour HomeStock, projet mono-utilisateur avec ~1 req/sec max en pic, un monolithe modulaire est largement suffisant et restera probablement optimal même à long terme.
|
||||
|
||||
La complexité des microservices n'apporterait aucun bénéfice tangible et augmenterait drastiquement les coûts de développement et maintenance.
|
||||
|
||||
**Principe appliqué** : "Choose boring technology" - privilégier les architectures éprouvées et simples sur les architectures à la mode mais complexes.
|
||||
|
||||
---
|
||||
|
||||
**Contributeurs** : Gilles (décideur) + Claude Code (architecte)
|
||||
|
||||
**Références** :
|
||||
- Martin Fowler - "Monolith First" : https://martinfowler.com/bliki/MonolithFirst.html
|
||||
- Sam Newman - "Building Microservices" (recommande de démarrer en monolithe)
|
||||
259
docs/adr/0003-recherche-full-text-sqlite-fts5.md
Normal file
259
docs/adr/0003-recherche-full-text-sqlite-fts5.md
Normal file
@@ -0,0 +1,259 @@
|
||||
# ADR-0003 — Recherche full-text avec SQLite FTS5
|
||||
|
||||
- Statut : accepted
|
||||
- Date : 2026-01-27
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
HomeStock nécessite une fonctionnalité de recherche rapide et efficace pour retrouver des objets dans l'inventaire. Les utilisateurs doivent pouvoir rechercher par :
|
||||
|
||||
- Nom de l'objet (ex: "perceuse")
|
||||
- Description (ex: "outil électrique sans fil")
|
||||
- Catégorie (ex: "bricolage")
|
||||
- Localisation (ex: "garage", "étagère A")
|
||||
|
||||
**Contraintes identifiées** :
|
||||
- **Volume de données** : ~1000-5000 items attendus initialement, maximum 10000 items à long terme
|
||||
- **Performance** : Résultats de recherche en <200ms souhaités
|
||||
- **Simplicité** : Pas de serveur externe supplémentaire à gérer
|
||||
- **Pertinence** : Recherche "fuzzy" pas nécessaire, recherche exacte par mots-clés suffit
|
||||
- **Langue** : Recherche en français uniquement
|
||||
|
||||
Le choix de la solution de recherche impacte directement l'expérience utilisateur (fonctionnalité critique) et l'architecture technique (composant additionnel ou intégré).
|
||||
|
||||
---
|
||||
|
||||
## Décision
|
||||
|
||||
Nous utilisons **SQLite FTS5 (Full-Text Search 5)** pour la recherche full-text avec les caractéristiques suivantes :
|
||||
|
||||
### Configuration
|
||||
- **Table virtuelle FTS5** : `fts_items` contenant les champs indexés
|
||||
- **Champs indexés** : `Item.name`, `Item.description`, `Category.name`, `Location.path`
|
||||
- **Tokenizer** : `unicode61` (support Unicode, casse insensible)
|
||||
- **Synchronisation** : Triggers SQLite pour maintenir FTS5 à jour lors des INSERT/UPDATE/DELETE
|
||||
|
||||
### Exemple de structure
|
||||
```sql
|
||||
CREATE VIRTUAL TABLE fts_items USING fts5(
|
||||
item_id UNINDEXED,
|
||||
name,
|
||||
description,
|
||||
category_name,
|
||||
location_path,
|
||||
tokenize = 'unicode61'
|
||||
);
|
||||
|
||||
-- Triggers pour synchronisation automatique
|
||||
CREATE TRIGGER items_after_insert AFTER INSERT ON items BEGIN
|
||||
INSERT INTO fts_items(item_id, name, description, category_name, location_path)
|
||||
VALUES (
|
||||
NEW.id,
|
||||
NEW.name,
|
||||
NEW.description,
|
||||
(SELECT name FROM categories WHERE id = NEW.category_id),
|
||||
(SELECT path FROM locations WHERE id = NEW.location_id)
|
||||
);
|
||||
END;
|
||||
|
||||
-- Triggers similaires pour UPDATE et DELETE
|
||||
```
|
||||
|
||||
### Requêtes de recherche
|
||||
```sql
|
||||
-- Recherche simple
|
||||
SELECT items.* FROM items
|
||||
JOIN fts_items ON items.id = fts_items.item_id
|
||||
WHERE fts_items MATCH 'perceuse';
|
||||
|
||||
-- Recherche avec boost (priorité sur le nom)
|
||||
SELECT items.* FROM items
|
||||
JOIN fts_items ON items.id = fts_items.item_id
|
||||
WHERE fts_items MATCH '{name}: perceuse OR {description}: perceuse'
|
||||
ORDER BY rank;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Alternatives considérées
|
||||
|
||||
### 1. Elasticsearch
|
||||
**Description** : Moteur de recherche distribué dédié, standard de l'industrie
|
||||
|
||||
**Avantages** :
|
||||
- ✅ Recherche extrêmement performante et flexible
|
||||
- ✅ Recherche fuzzy, phonétique, synonymes
|
||||
- ✅ Agrégations et analytics avancées
|
||||
- ✅ Scalable horizontalement
|
||||
|
||||
**Inconvénients** :
|
||||
- ❌ Serveur Java lourd (1-2GB RAM minimum)
|
||||
- ❌ Complexité opérationnelle importante
|
||||
- ❌ Nécessite synchronisation BDD → Elasticsearch
|
||||
- ❌ Overhead massif pour 1000-10000 items
|
||||
- ❌ Configuration complexe pour français
|
||||
|
||||
**Verdict** : ❌ **Rejeté** - Tuer une mouche avec un bazooka. Elasticsearch est conçu pour des millions de documents et des cas d'usage complexes (facettes, agrégations, etc.) dont HomeStock n'a pas besoin.
|
||||
|
||||
### 2. MeiliSearch
|
||||
**Description** : Moteur de recherche moderne, léger, orienté UX
|
||||
|
||||
**Avantages** :
|
||||
- ✅ Très rapide et pertinent out-of-the-box
|
||||
- ✅ API REST simple
|
||||
- ✅ Typo-tolerance native
|
||||
- ✅ Plus léger qu'Elasticsearch (~50MB RAM)
|
||||
- ✅ Configuration minimale
|
||||
|
||||
**Inconvénients** :
|
||||
- ❌ Service externe supplémentaire à déployer
|
||||
- ❌ Synchronisation BDD → MeiliSearch nécessaire
|
||||
- ❌ Overhead pour petit volume de données
|
||||
- ❌ Dépendance additionnelle à maintenir
|
||||
|
||||
**Verdict** : ⚠️ **Rejeté mais intéressant** - Excellente solution technique mais ajoute de la complexité pour un bénéfice limité sur <10k items. À considérer si passage à >50k items.
|
||||
|
||||
### 3. PostgreSQL Full-Text Search (pg_trgm + GIN)
|
||||
**Description** : Recherche full-text native de PostgreSQL
|
||||
|
||||
**Avantages** :
|
||||
- ✅ Très performant avec index GIN
|
||||
- ✅ Recherche trigram (similitude)
|
||||
- ✅ Support langues naturelles (stemming français)
|
||||
- ✅ Pas de service externe
|
||||
|
||||
**Inconvénients** :
|
||||
- ❌ Nécessite PostgreSQL (vs SQLite choisi dans ADR-0001)
|
||||
- ❌ Serveur BDD à gérer
|
||||
- ❌ Complexité setup (dictionnaires français, configuration)
|
||||
|
||||
**Verdict** : ❌ **Rejeté** - Excellente solution technique mais nécessite PostgreSQL. Si migration vers PostgreSQL (cas multi-utilisateurs), reconsidérer.
|
||||
|
||||
### 4. LIKE '%keyword%' en SQL
|
||||
**Description** : Recherche basique avec opérateur LIKE
|
||||
|
||||
**Avantages** :
|
||||
- ✅ Extrêmement simple
|
||||
- ✅ Aucune dépendance
|
||||
|
||||
**Inconvénients** :
|
||||
- ❌ Performance catastrophique (full table scan)
|
||||
- ❌ Pas de pertinence/ranking
|
||||
- ❌ Impossible de rechercher sur plusieurs champs efficacement
|
||||
- ❌ Pas d'opérateurs (AND, OR, NOT)
|
||||
|
||||
**Verdict** : ❌ **Rejeté** - Inacceptable même pour 1000 items, expérience utilisateur dégradée
|
||||
|
||||
### 5. SQLite FTS5 (notre choix)
|
||||
**Description** : Module de recherche full-text intégré à SQLite
|
||||
|
||||
**Avantages** :
|
||||
- ✅ Intégré à SQLite, pas de service externe
|
||||
- ✅ Performance excellente pour <100k documents
|
||||
- ✅ Support opérateurs (AND, OR, NOT, NEAR, phrases)
|
||||
- ✅ Ranking par pertinence (BM25)
|
||||
- ✅ Triggers pour synchronisation automatique
|
||||
- ✅ Tokenizer Unicode (support français)
|
||||
- ✅ Footprint mémoire minimal
|
||||
|
||||
**Inconvénients** :
|
||||
- ⚠️ Pas de recherche fuzzy native (typos)
|
||||
- ⚠️ Pas de stemming français parfait
|
||||
- ⚠️ Limitations si >100k documents (acceptable pour notre cas)
|
||||
|
||||
**Verdict** : ✅ **Choisi** - Solution optimale pour notre contexte : performance suffisante, simplicité maximale, pas de dépendance externe
|
||||
|
||||
---
|
||||
|
||||
## Conséquences
|
||||
|
||||
### Positives
|
||||
1. **Simplicité architecture** : Pas de service externe, tout dans SQLite
|
||||
2. **Performance suffisante** : FTS5 recherche <50ms sur 10k items
|
||||
3. **Synchronisation automatique** : Triggers maintiennent l'index à jour
|
||||
4. **Zéro configuration** : FTS5 inclus dans SQLite depuis version 3.9.0 (2015)
|
||||
5. **Backup simplifié** : Index FTS5 dans le même fichier .db que les données
|
||||
6. **Opérateurs avancés** : Support AND, OR, NOT, recherche par phrase
|
||||
7. **Ranking pertinent** : Algorithme BM25 pour trier par pertinence
|
||||
|
||||
### Négatives
|
||||
1. **Pas de typo-tolerance** : "perceuze" ne trouvera pas "perceuse"
|
||||
2. **Stemming limité** : "perçant" et "percer" non reliés automatiquement
|
||||
3. **Performance dégradée >100k items** : Limite théorique (très au-delà de notre besoin)
|
||||
4. **Pas d'agrégations** : Impossible de faire des facettes de recherche complexes
|
||||
5. **Recherche française limitée** : Pas de dictionnaire français sophistiqué
|
||||
|
||||
### Mitigations
|
||||
- **Typo-tolerance** : Implémenter suggestions de correction côté application si besoin (Levenshtein distance)
|
||||
- **Stemming** : Ajouter mots-clés/tags aux items pour améliorer découvrabilité
|
||||
- **Performance** : Si >100k items, migrer vers PostgreSQL pg_trgm ou MeiliSearch
|
||||
- **Agrégations** : Implémenter filtres côté application (par catégorie, localisation, etc.)
|
||||
|
||||
---
|
||||
|
||||
## Impacts techniques
|
||||
|
||||
### Développement
|
||||
- **Migration Alembic** : Créer table virtuelle FTS5 + triggers lors du setup initial
|
||||
- **Service de recherche** : `search_service.py` encapsule la logique FTS5
|
||||
- **API endpoint** : `GET /api/v1/search?q=keyword` retourne items matchant
|
||||
|
||||
### Performance attendue
|
||||
- **<1000 items** : <10ms
|
||||
- **1000-5000 items** : <50ms
|
||||
- **5000-10000 items** : <150ms
|
||||
- **>10000 items** : Dégrédation possible, monitoring nécessaire
|
||||
|
||||
### Structure de code
|
||||
```python
|
||||
# services/search_service.py
|
||||
class SearchService:
|
||||
async def search_items(self, query: str, limit: int = 50):
|
||||
"""Recherche full-text avec FTS5"""
|
||||
# Sanitize query (échapper caractères spéciaux)
|
||||
safe_query = self._escape_fts5_query(query)
|
||||
|
||||
# Query FTS5 avec ranking
|
||||
sql = """
|
||||
SELECT items.*,
|
||||
rank AS relevance
|
||||
FROM items
|
||||
JOIN fts_items ON items.id = fts_items.item_id
|
||||
WHERE fts_items MATCH :query
|
||||
ORDER BY rank
|
||||
LIMIT :limit
|
||||
"""
|
||||
|
||||
return await self.db.execute(sql, {"query": safe_query, "limit": limit})
|
||||
```
|
||||
|
||||
### Évolution future
|
||||
Si les limitations deviennent bloquantes :
|
||||
1. **Migration PostgreSQL** : Activer pg_trgm pour recherche similitude
|
||||
2. **Ajout MeiliSearch** : Service séparé pour recherche avancée (garder SQLite pour données)
|
||||
3. **Hybrid search** : Combiner FTS5 (rapide) + recherche sémantique externe (typos, synonymes)
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
SQLite FTS5 est utilisé par de nombreux projets à succès pour des cas d'usage similaires :
|
||||
- **Firefox** : Recherche dans l'historique et favoris
|
||||
- **Apple Mail** : Indexation locale des emails
|
||||
- **VS Code** : Recherche dans l'historique de commandes
|
||||
|
||||
Pour HomeStock avec <10k items attendus, FTS5 est largement suffisant et offre le meilleur ratio performance/simplicité.
|
||||
|
||||
La décision de ne pas utiliser Elasticsearch ou MeiliSearch n'est pas dogmatique : si le projet évolue vers >50k items ou nécessite recherche fuzzy sophistiquée, migration possible sans refonte majeure (API de recherche reste identique, seule l'implémentation change).
|
||||
|
||||
**Principe appliqué** : "Use the simplest tool that works" - Ne pas sur-architecturer pour des besoins hypothétiques futurs.
|
||||
|
||||
---
|
||||
|
||||
**Contributeurs** : Gilles (décideur) + Claude Code (architecte)
|
||||
|
||||
**Références** :
|
||||
- SQLite FTS5 documentation : https://www.sqlite.org/fts5.html
|
||||
- BM25 ranking algorithm : https://en.wikipedia.org/wiki/Okapi_BM25
|
||||
226
docs/adr/0004-pas-authentification-reseau-local.md
Normal file
226
docs/adr/0004-pas-authentification-reseau-local.md
Normal file
@@ -0,0 +1,226 @@
|
||||
# ADR-0004 — Pas d'authentification (réseau local uniquement)
|
||||
|
||||
- Statut : accepted
|
||||
- Date : 2026-01-27
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
HomeStock est une application web self-hosted destinée à un usage mono-utilisateur sur un réseau local domestique. La question de la sécurité d'accès se pose :
|
||||
|
||||
**Contraintes du projet** :
|
||||
- **Déploiement** : Réseau local 10.0.0.0/22, pas d'exposition Internet prévue
|
||||
- **Utilisateurs** : Mono-utilisateur (propriétaire du domicile)
|
||||
- **Données** : Inventaire personnel, factures (non sensibles au sens RGPD)
|
||||
- **Accès physique** : Réseau domestique, appareils de confiance uniquement
|
||||
|
||||
**Questions à résoudre** :
|
||||
1. Faut-il implémenter un système d'authentification (login/password) ?
|
||||
2. Si oui, quel niveau de sécurité est nécessaire ?
|
||||
3. Quels sont les risques réels d'un accès non authentifié sur réseau local ?
|
||||
|
||||
L'authentification ajoute de la complexité (gestion sessions, hash passwords, UI login) et peut dégrader l'expérience utilisateur (saisie répétée de credentials) pour un bénéfice de sécurité potentiellement faible dans ce contexte.
|
||||
|
||||
---
|
||||
|
||||
## Décision
|
||||
|
||||
**Nous ne déployons PAS de système d'authentification pour le MVP.** L'application est accessible librement sur le réseau local sans login ni password.
|
||||
|
||||
### Justification
|
||||
1. **Périmètre réseau contrôlé** : Réseau domestique 10.0.0.0/22, tous les appareils sont de confiance
|
||||
2. **Pas d'exposition Internet** : Application non accessible depuis l'extérieur, pas de port forwarding
|
||||
3. **Mono-utilisateur** : Pas de besoin de gestion de sessions ou de rôles
|
||||
4. **Simplicité UX** : Accès immédiat à l'application, pas de friction login
|
||||
5. **Données non critiques** : Inventaire domestique et factures, pas de données bancaires ou médicales
|
||||
|
||||
### Périmètre de sécurité
|
||||
- ✅ **Réseau local uniquement** : Application bind sur IP privée, pas 0.0.0.0
|
||||
- ✅ **HTTPS optionnel** : TLS pour chiffrement en transit si certificat local disponible
|
||||
- ✅ **Firewall** : Ports fermés en dehors du réseau local (configuration routeur)
|
||||
- ❌ **Pas de login/password** : Accès direct à l'application
|
||||
- ❌ **Pas de sessions** : Pas de gestion de tokens ou cookies d'authentification
|
||||
- ❌ **Pas de RBAC** : Pas de rôles ou permissions (mono-utilisateur)
|
||||
|
||||
### Configuration réseau recommandée
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
backend:
|
||||
ports:
|
||||
- "10.0.0.X:8000:8000" # Bind IP privée uniquement, pas 0.0.0.0:8000
|
||||
environment:
|
||||
- ALLOWED_HOSTS=10.0.0.0/22 # Whitelist réseau local
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Alternatives considérées
|
||||
|
||||
### 1. Authentification basique (login/password)
|
||||
**Description** : Page de connexion avec username/password, session cookie
|
||||
|
||||
**Avantages** :
|
||||
- ✅ Protection contre accès non autorisé sur réseau local
|
||||
- ✅ Traçabilité des accès (logs)
|
||||
- ✅ Possibilité multi-utilisateurs future facilitée
|
||||
|
||||
**Inconvénients** :
|
||||
- ❌ Complexité additionnelle (hash passwords, sessions, CSRF, refresh tokens)
|
||||
- ❌ UX dégradée (saisie credentials à chaque accès)
|
||||
- ❌ Gestion mot de passe oublié nécessaire
|
||||
- ❌ Sécurité illusoire si appareil compromis (cookies volés)
|
||||
|
||||
**Verdict** : ❌ **Rejeté pour MVP** - Bénéfice limité sur réseau local de confiance, complexité injustifiée
|
||||
|
||||
### 2. Authentification par IP (whitelist)
|
||||
**Description** : Autoriser uniquement certaines IPs du réseau local
|
||||
|
||||
**Avantages** :
|
||||
- ✅ Simple à implémenter (middleware FastAPI)
|
||||
- ✅ Pas d'UI login
|
||||
|
||||
**Inconvénients** :
|
||||
- ❌ Gestion fastidieuse des IPs autorisées
|
||||
- ❌ DHCP complique le suivi (IPs dynamiques)
|
||||
- ❌ Pas de granularité utilisateur
|
||||
|
||||
**Verdict** : ❌ **Rejeté** - Complexité sans bénéfice majeur, réseau déjà isolé
|
||||
|
||||
### 3. Authentification par certificat client (mTLS)
|
||||
**Description** : Certificats X.509 pour authentifier les appareils
|
||||
|
||||
**Avantages** :
|
||||
- ✅ Sécurité forte
|
||||
- ✅ Pas de password à mémoriser
|
||||
|
||||
**Inconvénients** :
|
||||
- ❌ Complexité extrême (PKI, distribution certificats)
|
||||
- ❌ Configuration browser complexe
|
||||
- ❌ Totalement surdimensionné pour le cas d'usage
|
||||
|
||||
**Verdict** : ❌ **Rejeté** - Overkill absolu
|
||||
|
||||
### 4. Pas d'authentification (notre choix)
|
||||
**Description** : Accès libre sur réseau local
|
||||
|
||||
**Avantages** :
|
||||
- ✅ Simplicité maximale (pas de code auth)
|
||||
- ✅ UX optimale (accès instantané)
|
||||
- ✅ Maintenance réduite
|
||||
- ✅ Adapté au contexte mono-utilisateur réseau local
|
||||
|
||||
**Inconvénients** :
|
||||
- ⚠️ Accès libre pour tout appareil sur réseau local
|
||||
- ⚠️ Pas de traçabilité utilisateur
|
||||
- ⚠️ Si exposition Internet accidentelle = vulnérabilité
|
||||
|
||||
**Verdict** : ✅ **Choisi** - Solution adaptée au contexte avec mitigations appropriées
|
||||
|
||||
---
|
||||
|
||||
## Conséquences
|
||||
|
||||
### Positives
|
||||
1. **Simplicité code** : Pas de code d'authentification, sessions, CSRF protection
|
||||
2. **UX fluide** : Accès immédiat, pas de friction login
|
||||
3. **Pas de gestion passwords** : Pas de hash, reset password, rotation
|
||||
4. **Maintenance réduite** : Pas de vulnérabilités auth à monitorer (OWASP Top 10)
|
||||
5. **Performance** : Pas de vérification session sur chaque requête
|
||||
|
||||
### Négatives et risques
|
||||
1. **Exposition accidentelle Internet** : Si port forwarding activé par erreur → accès public
|
||||
2. **Appareil compromis sur réseau** : Malware sur laptop/smartphone pourrait accéder à l'app
|
||||
3. **Visiteurs réseau** : Invités connectés au WiFi domestique peuvent accéder à l'app
|
||||
4. **Pas de traçabilité** : Impossible de savoir qui a modifié/supprimé des données
|
||||
|
||||
### Mitigations implémentées
|
||||
1. **Bind IP privée uniquement** : Backend écoute sur 10.0.0.X:8000, pas 0.0.0.0
|
||||
2. **Firewall routeur** : Ports 8000/5173 fermés en WAN, ouverts LAN uniquement
|
||||
3. **HTTPS optionnel** : Certificat auto-signé pour chiffrement en transit
|
||||
4. **Logging applicatif** : Logs des actions (créer/modifier/supprimer items) avec IP source
|
||||
5. **Backup régulier** : Scripts de backup pour récupération en cas d'actions malveillantes
|
||||
6. **Documentation claire** : Avertissement dans README sur importance isolation réseau
|
||||
|
||||
### Mitigations à envisager (post-MVP)
|
||||
1. **Mode "invité" simple** : Code PIN basique si besoin de partager l'accès temporairement
|
||||
2. **Alerte exposition** : Check au startup si l'app est accessible depuis Internet (API externe)
|
||||
3. **Read-only mode** : Mode lecture seule pour appareils moins fiables
|
||||
|
||||
---
|
||||
|
||||
## Impacts techniques
|
||||
|
||||
### Code simplifié
|
||||
Pas de code d'authentification signifie :
|
||||
- Pas de modèle `User` en base
|
||||
- Pas de hash passwords (bcrypt, argon2)
|
||||
- Pas de gestion sessions/tokens
|
||||
- Pas de middleware CSRF protection
|
||||
- Pas d'endpoints `/login`, `/logout`, `/register`
|
||||
- Pas d'UI login/signup
|
||||
|
||||
### Configuration Docker
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
backend:
|
||||
ports:
|
||||
- "10.0.0.50:8000:8000" # IP privée fixe uniquement
|
||||
environment:
|
||||
- ALLOWED_ORIGINS=http://10.0.0.50:5173,http://localhost:5173
|
||||
- CORS_ALLOW_CREDENTIALS=false # Pas de cookies
|
||||
```
|
||||
|
||||
### Logging renforcé
|
||||
Même sans auth, logger les actions pour traçabilité :
|
||||
```python
|
||||
# Exemple log
|
||||
logger.info(
|
||||
"Item created",
|
||||
extra={
|
||||
"item_id": item.id,
|
||||
"item_name": item.name,
|
||||
"source_ip": request.client.host,
|
||||
"user_agent": request.headers.get("user-agent")
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
### Évolution future
|
||||
Si exposition Internet devient nécessaire (accès depuis extérieur) :
|
||||
1. **Ajouter authentification** : Login simple (username/password) + session cookie
|
||||
2. **Reverse proxy avec auth** : Traefik BasicAuth ou OAuth2 Proxy
|
||||
3. **VPN** : Accès via WireGuard/Tailscale (recommandé)
|
||||
4. **Cloudflare Access** : Zero-trust avec auth externe
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
Cette décision est **contextuelle** et adaptée à HomeStock :
|
||||
- ✅ Réseau local domestique contrôlé
|
||||
- ✅ Mono-utilisateur
|
||||
- ✅ Données non critiques
|
||||
|
||||
Elle serait **inappropriée** pour :
|
||||
- ❌ Application exposée sur Internet
|
||||
- ❌ Multi-utilisateurs
|
||||
- ❌ Données sensibles (bancaires, médicales, secrets)
|
||||
- ❌ Environnement professionnel
|
||||
|
||||
**Analogie** : C'est comme ne pas mettre de serrure sur la porte de sa chambre dans sa propre maison (réseau local) vs mettre une serrure sur la porte d'entrée (exposition Internet).
|
||||
|
||||
Si le contexte change (exposition Internet, ajout utilisateurs), cette décision devra être revisitée et l'authentification ajoutée. L'architecture modulaire (ADR-0002) facilite cet ajout futur sans refonte majeure.
|
||||
|
||||
**Principe appliqué** : "Security proportionate to risk" - Ne pas sur-sécuriser quand le risque est faible et contrôlé.
|
||||
|
||||
---
|
||||
|
||||
**Contributeurs** : Gilles (décideur) + Claude Code (architecte)
|
||||
|
||||
**Avertissement important** : Cette configuration est sécurisée UNIQUEMENT si le réseau local est isolé d'Internet. Vérifier régulièrement que :
|
||||
1. Aucun port forwarding n'est configuré sur le routeur
|
||||
2. Aucun service de tunnel (ngrok, etc.) n'est actif
|
||||
3. Le firewall du routeur est correctement configuré
|
||||
Reference in New Issue
Block a user