Files
lifetrack/README.md
T
MeeJayandClaude Opus 5 fa3db7ff22 Fix 20+ defects found by real Docker/PostgreSQL deployment
Première exécution réelle de la stack (build des images, PostgreSQL 16,
parcours fonctionnels en HTTP) : 28 tables, 105 index, extension pg_trgm,
et 181 assertions rejouées après correction.

Santé : filtres enum invalides renvoyaient 500 au lieu d'une erreur
française ; plan_line s'arrêtait à la fin de la fenêtre du graphique au
lieu de la date d'atteinte de l'objectif ; deficit_target_kcal était
recalculé après le plancher calorique ; « dernière pesée » affichait deux
valeurs différentes selon l'endpoint ; objectif protéines absent.

Vape : durée de vie moyenne des résistances incluait la résistance en
cours ; archiver la recette active la laissait active ; coût théorique
inventé avant la date d'arrêt ; économies projetées dans le futur ;
€/ml arrondi à 2 décimales écrasait le modèle de coût DIY.

Finances : le sankey compensait crédits et débits non catégorisés ;
rows_total excluait les lignes filtrées, faussant l'arithmétique du
rapport d'import.

Socle : les erreurs HTTP du framework fuitaient en anglais dans
l'enveloppe française ; nginx renvoyait sa page 413 HTML au lieu du JSON
français ; fins de ligne normalisées en LF.

348 tests pytest (+7), ruff, tsc et vite build au vert.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 11:40:05 +02:00

601 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# LifeTrack
> Tracker de vie **auto-hébergé** : poids et calories, sevrage tabagique (vape) et finances
> personnelles — le tout dans une interface web sombre et riche en graphiques.
Vos données restent chez vous, dans votre PostgreSQL. Aucun compte tiers, aucune télémétrie,
aucune ressource chargée depuis Internet au moment de l'affichage.
Une seule dépendance réseau existe côté serveur, et elle est facultative : la recherche
d'aliments interroge **Open Food Facts** (base publique, sans clé d'API) et met chaque
produit consulté en cache local. Tout le reste fonctionne hors ligne.
---
## Sommaire
- [À quoi sert LifeTrack](#à-quoi-sert-lifetrack)
- [Fonctionnalités par module](#fonctionnalités-par-module)
- [Captures d'écran](#captures-décran)
- [Démarrage rapide (Docker Compose)](#démarrage-rapide-docker-compose)
- [Premier démarrage](#premier-démarrage)
- [Mode développement](#mode-développement)
- [Architecture](#architecture)
- [Stack technique](#stack-technique)
- [Feuille de route et écarts connus](#feuille-de-route-et-écarts-connus)
- [Documentation](#documentation)
- [Licence](#licence)
---
## À quoi sert LifeTrack
Trois besoins réunis dans une seule application, parce qu'ils s'alimentent mutuellement :
1. **Perdre du poids sans se tromper de chiffres.** LifeTrack calcule votre métabolisme de
base, votre dépense réelle et votre budget calorique quotidien, lisse vos pesées en une
tendance, et projette la date d'atteinte de votre objectif.
2. **Tenir l'arrêt de la cigarette.** Le module vape chiffre au centime près ce que vous
dépensez en e-liquide et en résistances, et le compare à ce que le tabac vous coûterait
aujourd'hui.
3. **Savoir où part l'argent.** Les relevés bancaires s'importent en quelques clics,
se catégorisent tout seuls et alimentent budgets, récurrents et graphiques.
L'application est **mono-utilisateur en pratique** : le premier compte créé est le vôtre,
il n'y a pas d'inscription publique.
---
## Fonctionnalités par module
L'interface est découpée en modules auto-découverts. Voici ce qui existe réellement
aujourd'hui.
### Tableau de bord (`/`)
- Carte « Aujourd'hui » : ce qui est planifié le jour même (pesée, séance, journal
alimentaire), fait ou non, avec les séries en cours.
- Ajout rapide d'une pesée sans quitter la page.
- Widgets KPI et graphiques de synthèse tirés des modules installés.
### Santé (`/sante/...`)
| Page | Contenu |
|---|---|
| **Poids & Objectif** (`/sante/poids`) | Historique des pesées, tendance lissée (EMA), projection de la date d'atteinte, mensurations, calendrier d'assiduité |
| **Nutrition** (`/sante/nutrition`) | Journal alimentaire par repas, recherche d'aliments, favoris, aliments récents, suivi de l'hydratation |
| **Activité & Sport** (`/sante/activite`) | Activité quotidienne (pas, distance, calories, minutes actives, étages), séances de sport |
| **Balance énergétique** (`/sante/balance`) | Calories ingérées contre calories dépensées, déficit cumulé, calibration adaptative du TDEE |
Détails utiles :
- **Profil corporel** (taille, sexe, date de naissance, niveau d'activité) → BMR par la
formule **Mifflin-St Jeor**, puis TDEE.
- **Objectif de poids** en trois modes : rythme hebdomadaire, date cible, ou maintien.
Budget calorique = TDEE lissé sur 7 jours (rythme × 7 700 kcal 7), avec un plancher
de sécurité.
- **Planning de suivi** : vous choisissez les jours de la semaine où vous prévoyez de vous
peser (`weigh_in`), de faire une séance (`workout`) et de tenir votre journal alimentaire
(`food_log`). LifeTrack en déduit assiduité, jours manqués et séries — sans case à cocher :
l'habitude est considérée faite dès qu'une donnée existe pour ce jour.
- **Recherche d'aliments** : cache local d'abord, puis **Open Food Facts** (recherche
plein texte et code-barres) via un proxy côté serveur. Chaque produit consulté est mis en
cache et n'est plus jamais redemandé.
- **Composition corporelle** : IMC, et estimation de masse grasse par la méthode US Navy
quand les mensurations nécessaires sont saisies.
### Vape / sevrage (`/vape`)
| Onglet | Contenu |
|---|---|
| **Consommation** | Recharges quotidiennes en ml, nicotine consommée, tendance, équivalent cigarettes |
| **Coûts & modèle** | Catalogue de produits (base, boosters, arômes, résistances), recettes DIY, coût de revient au ml, achats réels |
| **Résistances** | Changement de résistance en un clic, durée de vie moyenne, volume passé par résistance |
| **Économies** | Économies cumulées face à la référence tabac, cigarettes évitées, temps de vie récupéré, jalons santé |
- **Référence tabac gelée** : date d'arrêt, cigarettes par jour avant l'arrêt, cigarettes par
paquet, prix du paquet. C'est l'ancre de tout le calcul d'économies.
- **Modèle de coût DIY** : chaque recette additionne `quantité × (prix du flacon contenance)`
pour donner un coût au ml, auquel s'ajoute l'amortissement de la résistance.
- **Assistant de recette** : à partir d'un volume total, d'un taux de nicotine visé et d'un
booster, LifeTrack calcule les millilitres de booster, d'arôme et de base.
- **Jalons santé** : 12 étapes chronométrées depuis la date d'arrêt (20 minutes, 8 heures,
24 heures, 48 heures, 72 heures, 2 semaines, 3 mois, 9 mois, 1 an, 5 ans, 10 ans, 15 ans).
### Finances (`/finances`)
| Page | Contenu |
|---|---|
| **Aperçu** (`/finances`) | Flux de trésorerie, dépenses par catégorie, diagramme Sankey, principaux marchands |
| **Transactions** (`/finances/transactions`) | Liste filtrable, catégorisation unitaire ou en masse, saisie manuelle |
| **Budgets** (`/finances/budgets`) | Budget mensuel par catégorie, avancement, projection de fin de mois |
| **Récurrents** (`/finances/recurrents`) | Abonnements et prélèvements détectés automatiquement, prochaine échéance estimée |
| **Comptes** (`/finances/comptes`) | Comptes courants, épargne, PayPal, espèces |
| **Catégories** (`/finances/categories`) | Arborescence de catégories (un jeu français complet est créé automatiquement) |
- **Import de relevés** avec choix du compte, choix du profil bancaire, **aperçu avant
écriture** et **annulation d'un lot** en un clic.
- **Presets de banques intégrés** : CSV générique, BoursoBank / Boursorama, Crédit Agricole,
BNP Paribas, Société Générale, La Banque Postale, Caisse d'Épargne, Fortuneo, Revolut, N26,
OFX (toutes banques) et PayPal.
- **Déduplication** systématique : ré-importer le même fichier n'ajoute rien deux fois.
- **Moteur de règles** de catégorisation (libellé contenant, expression régulière, sens,
fourchette de montant, compte), avec priorité, aperçu et application en masse. Une
catégorisation manuelle n'est jamais écrasée.
- **Virements internes** : détection automatique des paires de transactions qui s'annulent
entre deux de vos comptes, pour ne pas les compter comme dépense.
### Imports et connecteurs (`/imports`)
- Assistant en trois étapes : **Fichier → Vérification → Import**. Le format est détecté à
partir de l'en-tête du fichier ; pour un relevé bancaire, le profil de banque est
présélectionné à partir de ce format et reste modifiable avant l'aperçu.
- Éditeur de mappage de colonnes (séparateur, encodage, format de date, colonnes) enregistré
dans un profil personnel.
- **Formats reconnus** : relevé bancaire CSV, relevé bancaire OFX, PayPal CSV,
Foodvisor CSV, Health Sync / Health Connect CSV, historique de poids CSV (date + poids).
- **Historique des imports** avec statistiques par lot et **annulation (rollback)** :
supprimer un lot supprime les lignes qu'il avait créées.
- Taille maximale d'un fichier : **20 Mio**.
- Carte « Connecteurs & API » : URL d'ingestion à coller dans une passerelle Android, lien
vers les clés d'appareil, et procédure d'export Foodvisor.
### Réglages (`/reglages`)
Cinq onglets : **Profil**, **Objectif**, **Vape**, **Appareils & API** (création et
révocation de clés d'API par appareil), **Application** (préférences locales au navigateur).
---
## Captures d'écran
**Il n'y en a pas, et ce n'est pas un oubli.**
La pile a bien été construite et exécutée (voir « Ce qui est vérifié » ci-dessous), mais la
validation s'est faite **en HTTP, pas dans un navigateur** : aucune session graphique n'a
été ouverte, donc aucune capture authentique n'a pu être prise. Plutôt que de publier des
images de synthèse trompeuses, cette section restera vide jusqu'à votre premier démarrage.
Les pages à capturer en priorité : le tableau de bord, `/sante/poids`, `/vape/economies` et
`/finances`.
---
## Démarrage rapide (Docker Compose)
### Prérequis
- **Docker installé et démarré** ; `docker compose version` doit répondre sans erreur
(Compose v2 ou plus récent). Sous Windows, vérifiez que Docker Desktop est bien actif.
- Environ 2 Go d'espace disque pour les images et la base.
- Aucun autre service n'écoute sur les ports choisis (80 et 8000 par défaut).
### Ce qui est vérifié
La séquence ci-dessous a été **exécutée telle quelle** sur un hôte Ubuntu (Docker Compose
v5.1.1, 8 vCPU, 1,8 Go de RAM), à partir d'un volume de données vide :
- les deux images se construisent (`lifetrack-api` ≈ 330 Mo, `lifetrack-web` ≈ 76 Mo) ;
- les trois conteneurs passent `healthy` en une vingtaine de secondes ;
- le schéma est créé sur un **vrai PostgreSQL 16** (28 tables, 105 index, extension
`pg_trgm` activée) et les données survivent à un `down` / `up` ;
- l'assistant de premier démarrage, puis un parcours par module (pesée + checklist du jour,
réglages vape + recharge + économies cumulées, import d'un relevé bancaire CSV en cp1252
avec ré-import dédupliqué et annulation) ont été rejoués **en HTTP à travers nginx** :
SPA, liens profonds, proxy `/api/` et gros fichiers compris.
Ce qui n'a **pas** été vérifié : le rendu graphique dans un navigateur (voir « Captures
d'écran »). Si un conteneur refuse de démarrer, commencez par
`docker compose logs api`.
> **Hôte avec moins de 2 Go de RAM** : construisez les images **une par une** (étape 3
> ci-dessous) et, si `vite build` se fait tuer par l'OOM killer, décommentez
> `NODE_OPTIONS=--max-old-space-size=1024` dans `.env`.
### 1. Créer le fichier `.env`
Depuis la racine du dépôt :
```bash
cp .env.example .env
```
Sous Windows (PowerShell) :
```powershell
Copy-Item .env.example .env
```
### 2. Modifier les deux variables obligatoires
Ouvrez `.env` et changez **impérativement** ces deux valeurs :
| Variable | Valeur d'exemple à remplacer | Pourquoi |
|---|---|---|
| `LIFETRACK_JWT_SECRET` | `generate-a-long-random-string` | Signe vos jetons de session. Laissée telle quelle, n'importe qui pourrait forger une session valide. |
| `POSTGRES_PASSWORD` | `change-me` | Mot de passe de la base PostgreSQL. |
Pour générer un secret solide :
```bash
openssl rand -hex 32
```
Sans `openssl` (PowerShell) :
```powershell
-join ((1..64) | ForEach-Object { '0123456789abcdef'[(Get-Random -Maximum 16)] })
```
Les autres variables ont des valeurs par défaut utilisables telles quelles :
| Variable | Défaut | Rôle |
|---|---|---|
| `POSTGRES_USER` | `lifetrack` | Utilisateur PostgreSQL |
| `POSTGRES_DB` | `lifetrack` | Nom de la base |
| `LIFETRACK_TIMEZONE` | `Europe/Paris` | Fuseau des agrégations journalières |
| `WEB_PORT` | `80` | Port d'écoute de l'interface web |
Deux variables restent commentées et ne servent qu'au développement :
`LIFETRACK_CORS_ORIGINS` (origines autorisées quand Vite tourne sans proxy) et
`LIFETRACK_MODULES` (liste blanche de modules backend à charger ; vide = tous).
> `LIFETRACK_DATABASE_URL` n'est **pas** à renseigner dans `.env` : `docker-compose.yml` la
> compose automatiquement à partir de `POSTGRES_USER`, `POSTGRES_PASSWORD` et `POSTGRES_DB`.
### 3. Construire les images
C'est la séquence exacte qui a été validée. Les deux builds sont **séparés** : le build web
(`npm ci` + `vite build`) est le seul gros consommateur de mémoire, mieux vaut ne pas le
faire tourner en même temps qu'autre chose.
```bash
docker compose build api # ~30 s
docker compose build web # ~40 s
```
`docker compose build` (sans argument) fonctionne aussi et construit les deux à la suite.
### 4. Lancer la pile
```bash
docker compose up -d
```
Trois conteneurs démarrent : `postgres` (base de données), `api` (FastAPI) et `web`
(nginx servant le frontend compilé et relayant `/api/` vers l'API). Depuis un volume vide,
il faut une vingtaine de secondes pour que les trois soient `healthy`.
Vérifier :
```bash
docker compose ps # attendre (healthy) sur postgres, api et web
docker compose logs -f # au besoin, suivre le démarrage
```
### 5. Ouvrir l'application
<http://localhost>
Si vous avez changé `WEB_PORT`, adaptez l'adresse (par exemple `http://localhost:8080`).
Depuis un autre appareil du réseau local, utilisez l'adresse IP du serveur. L'assistant de
premier démarrage s'ouvre automatiquement et crée le compte administrateur.
Deux adresses utiles :
- <http://localhost/api/healthz> — doit répondre `{"status":"ok"}`
- <http://localhost/api/docs> — documentation interactive de l'API
> `docker-compose.yml` porte `name: lifetrack` : toutes les commandes ci-dessus sont donc
> déjà rattachées au projet `lifetrack`, sans avoir à passer `-p`.
### Arrêter, mettre à jour, repartir de zéro
```bash
docker compose down # arrêt, les données sont conservées
docker compose build api # après mise à jour du code…
docker compose build web
docker compose up -d # …puis redémarrage
docker compose down -v # ⚠️ supprime AUSSI le volume : toutes vos données
```
---
## Premier démarrage
Au premier accès, LifeTrack détecte qu'aucun compte n'existe et vous redirige vers l'écran
de création.
**Étape 1 — Compte administrateur.** Adresse e-mail, prénom ou pseudonyme (facultatif) et
mot de passe de **8 caractères minimum**. C'est le seul compte de l'instance : il n'y a pas
de page d'inscription publique. Vous êtes connecté immédiatement après validation et arrivez
sur le tableau de bord.
**Étape 2 — Profil corporel.** Rendez-vous dans **Réglages → Profil** et renseignez taille,
sexe, date de naissance et niveau d'activité. Sans ces informations, LifeTrack ne peut pas
calculer votre métabolisme de base, donc ni votre dépense estimée ni votre budget calorique.
**Étape 3 — Objectif.** Dans **Réglages → Objectif**, indiquez poids de départ, poids cible
et mode de calcul (rythme hebdomadaire, date cible ou maintien). Le budget calorique
quotidien et la date d'atteinte estimée s'affichent aussitôt. C'est aussi ici que vous
accédez à votre **planning de pesées et de séances**.
**Étape 4 (facultative) — Vape.** Dans **Réglages → Vape**, saisissez votre date d'arrêt du
tabac et votre consommation d'avant : sans cette référence, le module vape reste en mode
« non configuré » et n'affiche aucune économie.
Ensuite seulement : importez vos premières données depuis **Imports**, ou saisissez-les à la
main. Le [guide d'utilisation](docs/GUIDE.md) détaille chaque parcours.
---
## Mode développement
Commandes réellement exécutées et validées sur ce dépôt (Windows, PowerShell ou Git Bash).
### Base de données seule
Le démon Docker doit tourner. Depuis la racine :
```bash
docker compose -f docker-compose.yml -f docker-compose.dev.yml up postgres
```
L'overlay de développement publie le port `5432` sur l'hôte, ce qui permet de faire tourner
l'API directement sur la machine.
### Backend (FastAPI)
L'environnement virtuel Python est déjà présent dans `apps/api/.venv`.
```bash
cd apps/api
# Suite de tests — 348 tests, exécutés sur SQLite en mémoire
.venv/Scripts/python.exe -m pytest
# Lint et formatage
.venv/Scripts/ruff.exe check .
.venv/Scripts/ruff.exe format .
# Serveur de développement avec rechargement à chaud
.venv/Scripts/python.exe -m uvicorn app.main:app --reload --port 8000
```
L'API écoute alors sur <http://localhost:8000>, documentation sur
<http://localhost:8000/api/docs>.
Si l'environnement virtuel doit être recréé :
```bash
cd apps/api
python -m venv .venv
.venv/Scripts/python.exe -m pip install -r requirements.txt -r requirements-dev.txt
```
> Les tests tournent sur **SQLite en mémoire** alors que la production utilise
> **PostgreSQL 16** : tous les types de colonnes doivent rester portables (voir
> [CONVENTIONS.md](CONVENTIONS.md) §C8). `app/tests/test_postgres_ddl.py` vérifie hors
> ligne le DDL réellement émis pour PostgreSQL (types natifs, index partiels, cascades
> d'import) ; ce DDL a par ailleurs été confronté à un vrai serveur PostgreSQL 16.
### Frontend (React + Vite)
```bash
cd apps/web
npm install # une seule fois
npm run dev # serveur de développement sur http://localhost:5173
npm run build # tsc --noEmit puis build de production
npm run preview # prévisualiser le build
```
**Proxy Vite** : `vite.config.ts` redirige tout `/api` vers `http://localhost:8000`. Vous
n'avez donc rien à configurer côté CORS tant que l'API tourne sur le port 8000 — le frontend
appelle simplement `/api/...` en chemin relatif, exactement comme en production derrière
nginx.
Si vous préférez ne pas utiliser le proxy, décommentez `LIFETRACK_CORS_ORIGINS` dans `.env` :
```
LIFETRACK_CORS_ORIGINS=["http://localhost:5173"]
```
### Tout en conteneurs, avec rechargement à chaud
```bash
docker compose -f docker-compose.yml -f docker-compose.dev.yml up
```
L'API tourne alors en `--reload` sur le port 8000 et Vite sur le port 5173, les sources
étant montées depuis l'hôte.
---
## Architecture
### Organisation du dépôt
```
LifeTrack/
├─ apps/
│ ├─ api/ # Backend FastAPI
│ │ ├─ app/
│ │ │ ├─ core/ # config, base, sécurité, pagination, erreurs,
│ │ │ │ # framework d'import et d'ingestion, chargeur de modules
│ │ │ ├─ modules/ # auth, health, vape, finance, imports
│ │ │ ├─ tests/ # 348 tests pytest
│ │ │ └─ main.py # création de l'app — ne jamais modifier pour un module
│ │ ├─ requirements.txt
│ │ └─ openapi.json # schéma OpenAPI exporté
│ └─ web/ # Frontend React + TypeScript
│ └─ src/
│ ├─ app/ # routeur, layout, authentification — ne pas modifier
│ ├─ components/ # composants partagés (ui/, charts/)
│ ├─ lib/ # wrapper API, formatage fr-FR
│ └─ modules/ # home, health, vape, finance, imports, settings
├─ docker/ # Dockerfiles et configuration nginx
├─ docs/ # documents de conception et de recherche
├─ docker-compose.yml
├─ docker-compose.dev.yml
├─ .env.example
├─ CONVENTIONS.md # règles obligatoires pour toute contribution
└─ DESIGN.md # synthèse des décisions de conception
```
### Modules auto-découverts
C'est la décision structurante du projet : **ajouter un module ne demande de modifier aucun
fichier existant.**
- **Côté backend**, `app/core/module_loader.py` parcourt `app/modules/` avec `pkgutil`. Tout
dossier qui expose un `router.py` contenant `router = APIRouter(prefix="/<nom>")` est monté
automatiquement sous `/api`. Les fichiers `models.py`, `importers.py` et `ingest.py` sont
importés au démarrage pour peupler les métadonnées SQLAlchemy et les registres de
connecteurs.
- **Côté frontend**, `src/app/modules.ts` utilise `import.meta.glob` sur
`src/modules/*/index.ts`. Chaque module exporte par défaut un `ModuleManifest` déclarant son
identifiant, son titre français, son ordre, ses routes et ses entrées de navigation.
Pour créer un module, suivez [CONVENTIONS.md](CONVENTIONS.md) §C2 (backend) et §C5
(frontend). Les règles y sont normatives : nommage, unités canoniques, pagination, gestion
des erreurs, portabilité SQLite.
### Où vivent les données
- **PostgreSQL 16**, dans le volume Docker nommé `pgdata`. Il survit à `docker compose down`
mais **pas** à `docker compose down -v`.
- Le schéma est créé au démarrage par `Base.metadata.create_all` — il n'y a **pas encore de
migrations Alembic** en v1.
- Conventions de stockage : horodatages en **UTC**, jours locaux en `Date`, poids en **kg**,
distances en **m**, volumes en **ml**, énergie en **kcal**, durées en **secondes**, argent
en **centimes d'euro**. L'affichage en `fr-FR` (virgule décimale, `€` après le montant) est
fait côté interface.
- Sauvegarde recommandée :
```bash
docker compose exec postgres pg_dump -U lifetrack lifetrack > sauvegarde.sql
```
### API
- Toutes les routes sont préfixées par **`/api`**, suivi du nom du module :
`/api/auth`, `/api/health`, `/api/vape`, `/api/finance`, `/api/imports`, `/api/ingest`.
- En production, nginx relaie `/api/` vers le conteneur `api` sur le port 8000 ; tout le
reste retombe sur `index.html` (application monopage).
- Format d'erreur unique : `{"error": {"code", "message", "details"}}`, `code` stable en
snake_case, `message` en français.
- Les dates-heures sont en UTC ISO 8601, les jours locaux en `YYYY-MM-DD`, et les agrégations
journalières acceptent un paramètre `?tz=` (défaut `Europe/Paris`).
### Authentification
Deux mécanismes, pour deux usages :
1. **JWT** — pour vous, dans le navigateur. Obtenu via `POST /api/auth/login`, envoyé dans
l'en-tête `Authorization: Bearer <jeton>`. Mots de passe hachés en argon2. Durée de
validité : **7 jours** (choix assumé pour un déploiement domestique).
2. **Clés d'appareil** — pour vos machines. Créées dans **Réglages → Appareils & API**,
préfixées `ltk_`, envoyées dans l'en-tête **`X-API-Key`**, et portant des **portées**
explicites (`ingest:health`, `ingest:*`, …). La clé en clair n'est affichée **qu'une seule
fois** à la création ; seul son empreinte est stockée. Chaque clé est révocable
individuellement.
Tout endpoint hors `POST /api/auth/login`, `POST /api/auth/setup`, `GET /api/auth/status` et
`/api/healthz` exige une authentification et filtre systématiquement les données par
utilisateur.
---
## Stack technique
| Couche | Technologies |
|---|---|
| Backend | Python 3.12 · FastAPI · SQLAlchemy 2.0 typé · Pydantic v2 · PyJWT · argon2 (pwdlib) |
| Base de données | PostgreSQL 16 (pilote psycopg 3) — SQLite en mémoire pour les tests |
| Frontend | React 18 · TypeScript strict · Vite 6 · TailwindCSS · Apache ECharts · TanStack Query · React Router |
| Déploiement | Docker Compose : `postgres` + `api` + `web` (nginx 1.27) |
| Qualité | pytest (348 tests) · ruff · `tsc --noEmit` |
Aucune ressource externe n'est chargée à l'exécution : polices, icônes et bibliothèques sont
embarquées dans le build.
---
## Feuille de route et écarts connus
Ce qui suit est **décrit dans les documents de conception mais absent du code
d'aujourd'hui**. Rien de tout cela n'est nécessaire pour utiliser LifeTrack, mais autant le
savoir avant de le chercher dans l'interface.
### Écarts entre la conception et le code actuel
- **Table CIQUAL absente.** La recherche d'aliments prévoyait une base d'aliments génériques
français (ANSES). Le code ne contient ni script d'import ni données : seule la recherche
Open Food Facts fonctionne. Les plats maison se saisissent donc à la main.
- **Adaptateur webhook sans en-tête d'authentification non implémenté.** La recherche
prévoyait une route acceptant un jeton dans l'URL, pour les passerelles Android incapables
de poser un en-tête HTTP. Elle n'existe pas : `POST /api/ingest/{domain}` exige
`X-API-Key` ou un jeton JWT. Conséquence pratique détaillée dans le
[guide](docs/GUIDE.md#connecter-health-connect).
- **Ingestion limitée au domaine `health`.** L'écran de création de clé propose les portées
`ingest:vape` et `ingest:finance`, mais aucun gestionnaire ne les traite :
`POST /api/ingest/vape` et `POST /api/ingest/finance` répondent « Domaine d'ingestion
inconnu ». Ces portées sont réservées pour plus tard.
- **Pas de table de charges utiles brutes.** Chaque ligne conserve sa charge utile d'origine
dans une colonne `raw`, mais il n'existe pas de table dédiée permettant de rejouer une
normalisation après coup.
- **Importeurs de séances absents** : pas de lecteur TCX, GPX ou FIT. Les séances de sport se
saisissent à la main ou arrivent par l'ingestion JSON.
- **Importeurs MyFitnessPal et Cronometer absents** : seul Foodvisor dispose d'un profil
nutrition dédié.
- **Pas de migrations Alembic** : le schéma est créé au démarrage. Une modification de schéma
sur une base existante devra être gérée manuellement.
### v2 — envisagé
- Application compagnon Android maison (Kotlin, SDK Health Connect), avec vraie
authentification par jeton et rattrapage d'historique au-delà de 48 heures.
- Connecteur bancaire **Enable Banking** (PSD2, gratuit pour ses propres comptes) en
remplacement des imports de fichiers.
- Calculateur DIY avancé, migrations Alembic, notifications.
### v3 — exploratoire
- Enregistrement direct des séances de tapis de course via **Web Bluetooth + FTMS**
(Chrome/Edge uniquement, HTTPS requis).
- Analyse photo des repas, multi-utilisateurs complet, thème clair.
---
## Documentation
| Document | Contenu |
|---|---|
| [docs/GUIDE.md](docs/GUIDE.md) | **Guide d'utilisation au quotidien** : connecter Health Connect, suivre poids et calories, nutrition, vape, finances, dépannage |
| [CONVENTIONS.md](CONVENTIONS.md) | Règles obligatoires pour contribuer au code |
| [DESIGN.md](DESIGN.md) | Synthèse des décisions de conception |
| [docs/design/architecture.md](docs/design/architecture.md) | Architecture technique complète |
| [docs/design/datamodel-health-vape.md](docs/design/datamodel-health-vape.md) | Modèle de données et formules santé, nutrition, vape |
| [docs/design/datamodel-finance.md](docs/design/datamodel-finance.md) | Modèle de données et logique finances |
| [docs/design/ux-pages.md](docs/design/ux-pages.md) | Spécification UX page par page |
| [docs/design/addendum-planning.md](docs/design/addendum-planning.md) | Planning d'habitudes, assiduité, séries |
| [docs/research/health-connect.md](docs/research/health-connect.md) | Comment sortir les données de Health Connect |
| [docs/research/nutrition-sources.md](docs/research/nutrition-sources.md) | Foodvisor, Open Food Facts, CIQUAL |
| [docs/research/finance-sources.md](docs/research/finance-sources.md) | Formats d'export réels des banques françaises |
---
## Licence
**Aucune licence n'est déclarée** : ce dépôt est un projet personnel auto-hébergé, il n'est
pas publié sous licence libre. En l'absence de fichier `LICENSE`, tous droits sont réservés
par défaut.
Notez les obligations attachées aux données tierces que vous consommerez :
- **Open Food Facts** — base sous **ODbL**, contenus sous DbCL. Un usage personnel ne pose
aucune difficulté ; une attribution « Données produits : Open Food Facts (ODbL) » reste la
bonne pratique.
- Les applications passerelles Android citées dans la documentation ont leurs propres
licences (AGPL-3.0 pour `health-connect-webhook`, GPL-3.0 pour HCGateway) — elles ne sont
pas distribuées avec LifeTrack.