- Volume data/ (bind mount ./data) remplace le volume uploads nommé
data/notes/ → .md auto-générés, data/uploads/ → médias, data/backup/ → dumps
- Service Redis (redis:7-alpine) + worker ARQ (backend-worker)
- notes_markdown.py : frontmatter YAML + contenu + pièces jointes (liens relatifs)
Nom : YYYY-MM-DD_slug-titre_shortid.md, rotation si titre modifié
- api/notes.py : publie export_note_markdown / remove_note_markdown sur Redis
après chaque create / update / delete / add_attachment / delete_attachment
- api/admin.py : POST /backup, GET /backups, POST /restore/{filename} (pg_dump/pg_restore)
- Backend Dockerfile : postgresql-client ; requirements : arq==0.26.1
- ConfigPage : section "Base de données" avec sauvegarde + liste + restauration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
13 KiB
HomeHub — Plan de développement
Approche itérative : chaque phase livre quelque chose d'utilisable.
Stack : FastAPI · React/Vite/TS · PostgreSQL 16 · Docker Compose
Phase 1 — Socle technique ✅
Objectif : environnement opérationnel, rien de métier, mais tout tourne.
Backend
- Structure projet FastAPI (
app/api/,app/core/,app/models/,app/schemas/,app/services/) - Configuration SQLAlchemy 2.0 async + pool de connexions
- Création des schémas PostgreSQL (
todos,shopping,notes) via Alembic - Migration initiale : toutes les tables (voir spec section 3)
- Endpoint santé :
GET /api/health - Module media (
app/services/media.py) :- Validation des formats acceptés (JPG, PNG, SVG, WebP, WebM, M4A)
- Génération miniature Pillow : 150×150 (shopping), 300×300 (notes), 400×300 (inline)
- Sauvegarde
originals/+thumbnails/sur le volume - Endpoint
POST /api/media/upload→ retourne{ file_path, thumbnail_path } - Endpoint
DELETE /api/media/{uuid}→ supprime original + miniature
- Middleware CORS pour réseau local
10.0.0.0/22 - Configuration via variables d'environnement (
.env) - Dockerfile backend (Python 3.12 slim)
Frontend
- Scaffold Vite + React 18 + TypeScript
- Tailwind CSS configuré avec les tokens Gruvbox (via
tokens.json) - Intégration
design_system/components/ui-kit.jsx @vite-pwa/pluginconfiguré (Service Worker + manifest)manifest.jsonavec icônes iOS + Android- Routage React Router v6
- Layout de base : navigation mobile (bottom bar) + navigation laptop (sidebar)
- Dockerfile frontend (Nginx + proxy
/api/→ backend) - Favicon maison (SVG Gruvbox orange)
Infra
docker-compose.ymlavec 3 services (frontend, backend, db)- Volume PostgreSQL persistant
- Volume uploads persistant (
/uploads/) - Fichier
.env.example - Script de seed (
backend/app/data/seed.py) : 113 produits + 9 magasins
Phase 2 — Module Todos ✅
Objectif : créer, lister, modifier, terminer et reporter des tâches depuis mobile et laptop.
Backend
GET /api/todos— liste avec filtres (domaine, statut, priorité, tags, période)POST /api/todos— créationPATCH /api/todos/{id}— mise à jour partielleDELETE /api/todos/{id}— suppressionPOST /api/todos/{id}/postpone— incrémente postponed_count + décale due_date- Schémas Pydantic : TodoCreate, TodoUpdate, TodoResponse
- Tests d'intégration (9 tests)
Frontend Mobile
- Page Todos : liste des tâches en cours, groupées par domaine
- Bouton "+ Tâche" flottant → Modal création (titre + domaine + date + priorité + tags)
- Double-tap → Modal édition pré-rempli
- Swipe droite → marquer done
- Swipe gauche → actions (reporter 1j / reporter 1 semaine / supprimer)
- Badge compteur par domaine
Frontend Laptop
- Vue tableau avec filtres : domaine, statut, priorité, période
- Formulaire complet (tous les champs) via Modal
- Double-clic sur titre → Modal édition
- Actions inline : ✓ done / +1j / +1S / ✕ supprimer
Phase 3 — Module Shopping (liste de courses) ✅
Objectif : liste de courses fonctionnelle en magasin depuis smartphone, avec génération automatique.
Backend
GET /api/shopping/stores— liste magasinsGET /api/shopping/products— catalogue avec recherche (paramq)GET /api/shopping/lists— listes de courses avec compteursPOST /api/shopping/lists— création listeGET /api/shopping/lists/{id}— détail liste avec articlesPATCH /api/shopping/lists/{id}— mise à jour listeDELETE /api/shopping/lists/{id}— suppressionPOST /api/shopping/lists/{id}/items— ajout article (produit catalogue ou custom)PATCH /api/shopping/lists/{id}/items/{item_id}— cocher / modifierDELETE /api/shopping/lists/{id}/items/{item_id}— suppression articlePOST /api/shopping/lists/{id}/finish— terminer les courses (report articles non cochés → nouvelle liste draft aveccarried_over=True)POST /api/shopping/lists/generate— liste magique V1 (score = retard / intervalle moyen, articles cochés comme historique)- Schémas Pydantic complets (listes, articles, produits, magasins)
- Tests d'intégration (10 tests)
- Champ
tags TEXT[]sur les produits du catalogue (migration 006)
Frontend
- Page Shopping avec 3 vues : liste des listes / détail / mode magasin
- Vue "listes" : cartes par liste (statut, compteur articles), FAB + bouton "Liste magique"
- Bouton "Liste magique" : désactivé si une liste
draft/activeexiste - Vue "détail" : articles avec swipe-to-delete, FAB ajout article, bouton ✏️ modal gestion
- Modal ✏️ : ajout rapide d'article + bouton rouge "Supprimer la liste en cours"
- Vue "Mode magasin" : plein écran, grands boutons (48px+), section cochés/non cochés
- Wake Lock API activée automatiquement en mode magasin
- Composant
Modalgénérique réutilisable (overlay + Escape + stopPropagation) - Composant
ItemRow: checkbox circulaire + swipe-to-delete + mode magasin - Hook
useWakeLockavec fallback gracieux (mode économie d'énergie) - Client API TypeScript typé (
frontend/src/api/shopping.ts) - Migration TodoForm vers Modal (plus de panneau inline)
- Bottom sheet multi-select pour l'ajout d'articles depuis le catalogue
- Stats d'achat dans le catalogue : dernier achat + intervalle moyen par produit
- Swipe gauche → modal édition (TodoPage + ShoppingPage)
- Tags sur les produits : chip-input dans CatalogueModal, recherche étendue aux tags
- Recherche article :
type="search"supprime la suggestion URL iOS,autoFocusautomatique - Upload photo produit : support HEIC/HEIF, redimensionnement 500×500 max (ratio conservé), miniature auto
- Collage Ctrl+V photo dans CatalogueModal et TodoForm
Phase 4 — Module Notes ✅
Objectif : saisie rapide de notes avec photo, audio et GPS depuis smartphone.
Backend
GET /api/notes— liste avec search full-text + filtres tags/catégoriePOST /api/notes— créationPATCH /api/notes/{id}— mise à jourDELETE /api/notes/{id}— suppressionPOST /api/notes/{id}/attachments— upload fichier (image/audio)DELETE /api/notes/{id}/attachments/{att_id}— suppression pièce jointe- Compression image Pillow → WebP (service media partagé)
- Recherche FTS PostgreSQL français
Frontend Mobile
- Page Notes : liste chronologique avec aperçu
- Bouton "+ Note" → formulaire rapide (contenu + tags) via Modal
- Bouton 📷 → Camera API (capture directe ou import galerie)
- Bouton 🎤 → MediaRecorder (enregistrement audio inline)
- Bouton 📍 → Geolocation API → affichage coordonnées
- Visionneuse photo inline + lecteur audio inline
- Compression WebP côté client (Canvas API) — différé Phase 5+
- Waveform visuel enregistrement — différé Phase 5+
Frontend Laptop
- Grille notes avec vignettes photo
- Recherche full-text
- Filtres rapides : avec photo, avec audio, avec GPS
- Vue carte pour les notes avec GPS (Leaflet.js) — différé Phase 5+
Phase 4b — UX transversale ✅
Objectif : améliorations d'expérience applicables à tous les modules.
Thème et apparence
ThemeContext: gestion dark / light / system avec persistancelocalStorage- Script anti-flash dans
index.html: thème et zoom appliqués avant le premier rendu - Page
/config: boutons thème + slider police (0.8–1.4, pas de 0.05) - Aperçu temps réel du texte sur le slider
- Zoom CSS sur
<html>: scale global compatible avec les tailles en pixels fixes TopBar: en-tête fixe 44px avec bouton de thème cyclique (lune / soleil / demi-cercle)- Tuile "Paramètres" sur la page d'accueil (
/config, icônefa-sliders)
Mobile — clavier iOS
BottomSheet:visualViewportAPI pour remonter le panneau au-dessus du clavier virtuel- Transition fluide (0.15s) sur
bottom,max-height,border-radiusà l'ouverture du clavier
Todos
- Case "Pas de date" pré-cochée par défaut dans
TodoForm(champ date masqué) - Collage Ctrl+V pour coller une image directement dans le formulaire Todo
Infra / Media
- nginx :
location ^~ /media/pour éviter que la règle regex WebP prenne la priorité - nginx :
client_max_body_size 15mpour les photos de smartphone (3–8 Mo)
Phase 5 — Export Markdown notes + Backup BDD ✅
Objectif : persistance double des notes (BDD source de vérité + fichiers Markdown partagés), infrastructure Redis, backup/restore depuis l'interface.
Architecture
- Volume Docker
./data/(bind mount) remplace le volume nomméuploadsdata/notes/— fichiers.mdauto-générésdata/uploads/— médias (photos, audio)data/backup/— dumps PostgreSQL
Backend
- Service Redis :
redis:7-alpinedans docker-compose - Worker ARQ (
backend-worker) : consomme la queuenotes:markdown, même image que backend app/core/redis.py— pool ARQ,enqueue()best-effort (silence si Redis down)app/workers/notes_worker.py— tâchesexport_note_markdown+remove_note_markdownapp/services/notes_markdown.py— génère le frontmatter YAML + contenu + pièces jointes (liens relatifs../uploads/…)- Nom de fichier :
YYYY-MM-DD_slug-du-titre_shortid.md - Rotation automatique si titre modifié (recherche par
*_{shortid}.md)
- Nom de fichier :
app/api/notes.py— publie sur Redis après create / update / delete / add_attachment / delete_attachmentapp/api/admin.py—POST /api/admin/backup,GET /api/admin/backups,POST /api/admin/restore/{filename}backend/Dockerfile— ajoutpostgresql-clientpour pg_dump / pg_restorerequirements.txt— ajoutarq==0.26.1
Frontend
frontend/src/api/admin.ts— client TypeScript backup/restore- Page Config — section "Base de données" : bouton sauvegarde + liste des dumps + bouton Restaurer par fichier
Phase 6 — Scan produits + enrichissement catalogue
Objectif : scan code-barres depuis mobile, auto-remplissage depuis OpenFoodFacts.
Services Docker
- Dockerfile
product-search/: Python slim +requests+ client OpenFoodFacts - Ajout service
product-searchdansdocker-compose.yml(port 8002) - Ajout service
searxngdansdocker-compose.yml(images uniquement)
Backend (endpoints proxy)
GET /api/products/lookup?barcode=→ proxifie vers product-searchGET /api/products/search?q=→ proxifie vers product-searchPOST /api/products/import→ crée produit depuis données OpenFoodFacts
Frontend Mobile — scan
- Intégration
zxing-js(BarcodeReader via flux caméra) - Bouton "Scanner" dans le formulaire d'ajout de produit
- Sur scan réussi → auto-remplissage formulaire
Frontend Laptop — enrichissement catalogue
- CRUD complet produits dans catalogue
- Recherche texte → OpenFoodFacts → import 1 clic
- Gestion magasins
Phase 7 — Service OCR (conteneur dédié)
Objectif : OCR partagé, prérequis pour shopping avancé et notes avancées.
- Dockerfile
ocr/: Python slim + Tesseract 5 + langues (fra, eng) + Pillow POST /extract: reçoit image (multipart), retourne{ text, confidence }- Endpoint backend
POST /api/ocr/extract: proxifie versocr:8001 - Ajout du service
ocrdansdocker-compose.yml
Phase 8 — Shopping avancé (OCR + suivi prix)
Backend
POST /api/shopping/ocr/price-tag— photo étiquette → extraction prixPOST /api/shopping/ocr/receipt— photo ticket → reconciliation listeGET /api/shopping/products/{id}/price-history— historique prix par produit + magasin
Frontend
- Bouton 📷 sur chaque article → OCR étiquette → pré-remplissage prix
- Graphique d'évolution du prix par produit (Recharts)
- Comparaison prix par magasin
Phase 9 — MCP Server
Objectif : exposer les outils HomeHub aux agents IA (Hermes, Claude, etc.).
- Intégration SDK MCP Python (
mcppackage) - Endpoint SSE
/mcp - Implémentation des outils :
get_todos(),add_todo(),add_shopping_item(),search_notes() - Documentation OpenAPI des outils MCP
Phases futures (hors scope initial)
Phase 9 — Authentification multi-utilisateurs
- Auth JWT (login / refresh token)
- Activation de
owner_iddans toutes les tables - Page connexion React
Phase 10 — Calendrier + intégrations
- Sync Google Calendar (OAuth2 + worker)
- Endpoint CalDAV pour iOS
- Redis pour la queue de synchronisation
- Webhooks Gitea → Kanban
- Home Assistant : capteur "tâches en retard"
Phase 11 — Vision IA
- Endpoint analyse frigo (photo → suggestions liste de courses)
- Amélioration OCR via modèle Vision local (Ollama)
Ordre de développement
Phase 1 ✅ → Phase 2 ✅ → Phase 3 ✅ → Phase 4 ✅ → Phase 4b ✅ → Phase 5 ✅ → Phase 6 (Scan) → Phase 7 (OCR) → Phase 8 (Shopping avancé) → Phase 9 (MCP)