Initial import: LifeTrack v1 (santé, vape, finances)
Tracker de vie auto-hébergé : suivi poids/calories/sport avec planning de pesées, sevrage tabac (vape) avec modèle de coût DIY et économies, et finances personnelles avec import de relevés bancaires. Architecture : FastAPI + SQLAlchemy 2.0 + PostgreSQL 16, React 18 + TS + Vite + Tailwind + ECharts, déploiement Docker Compose. Modules auto-découverts des deux côtés (pkgutil / import.meta.glob) et framework de connecteurs à deux voies (importeurs de fichiers + ingestion JSON) pour brancher de nouvelles sources sans toucher au noyau. Validé : 292 tests pytest, tsc + vite build, contrat API/web vérifié contre le schéma OpenAPI, et déploiement Docker réel sur PostgreSQL 16 (28 tables, SPA servie par nginx, wizard de premier démarrage). Documentation : README.md, docs/GUIDE.md, CONVENTIONS.md, et les documents de conception et de recherche dans docs/. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,565 @@
|
||||
# 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**, avec détection
|
||||
automatique du format à partir de l'en-tête du fichier.
|
||||
- É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.**
|
||||
|
||||
L'application a été développée et testée intégralement hors ligne : la suite de tests
|
||||
backend et la compilation du frontend passent, mais **la pile Docker Compose n'a jamais été
|
||||
démarrée** (le démon Docker était indisponible pendant tout le développement). Aucune
|
||||
capture n'a donc pu être prise sur une instance réelle.
|
||||
|
||||
Plutôt que de publier des images de synthèse trompeuses, cette section restera vide jusqu'à
|
||||
votre premier démarrage. Une fois l'application lancée, les pages à capturer en priorité
|
||||
sont : le tableau de bord, `/sante/poids`, `/vape/economies` et `/finances`.
|
||||
|
||||
---
|
||||
|
||||
## Démarrage rapide (Docker Compose)
|
||||
|
||||
### Prérequis
|
||||
|
||||
- **Docker Desktop installé ET démarré.** Vérifiez que la baleine est bien active dans la
|
||||
barre des tâches ; `docker compose version` doit répondre sans erreur.
|
||||
- Environ 2 Go d'espace disque pour les images et la base.
|
||||
- Aucun autre service n'écoute sur le port choisi (80 par défaut).
|
||||
|
||||
> ⚠️ **À lire avant le premier lancement.** Le démon Docker était **hors service pendant
|
||||
> toute la phase de développement** : la pile Compose n'a donc jamais été construite ni
|
||||
> démarrée. Le code applicatif, lui, est validé (292 tests backend, compilation frontend).
|
||||
> Attendez-vous éventuellement à un petit ajustement lors du tout premier `up` — le plus
|
||||
> probable étant un temps de build long, ou une image de base à retélécharger. Si un
|
||||
> conteneur refuse de démarrer, consultez ses journaux avec
|
||||
> `docker compose logs api` avant toute autre chose.
|
||||
|
||||
### 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. Lancer la pile
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
Trois conteneurs démarrent : `postgres` (base de données), `api` (FastAPI) et `web`
|
||||
(nginx servant le frontend compilé et relayant `/api/` vers l'API). Le premier build prend
|
||||
plusieurs minutes.
|
||||
|
||||
Suivre le démarrage :
|
||||
|
||||
```bash
|
||||
docker compose logs -f
|
||||
```
|
||||
|
||||
### 4. 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.
|
||||
|
||||
Deux adresses utiles :
|
||||
|
||||
- <http://localhost/api/healthz> — doit répondre `{"status":"ok"}`
|
||||
- <http://localhost/api/docs> — documentation interactive de l'API
|
||||
|
||||
### Arrêter, mettre à jour, repartir de zéro
|
||||
|
||||
```bash
|
||||
docker compose down # arrêt, les données sont conservées
|
||||
docker compose up -d --build # reconstruction après mise à jour du code
|
||||
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 — 292 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).
|
||||
|
||||
### 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/ # 292 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 (292 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.
|
||||
Reference in New Issue
Block a user