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>
66 KiB
LifeTrack — Spécification UX complète (page par page)
Document de référence pour l'implémentation. Prose en français, identifiants de code en anglais. Stack imposée : React 18 + TypeScript + Vite + TailwindCSS + Apache ECharts. UI 100 % en français, thème sombre par défaut. Ce document est exhaustif : les agents d'implémentation ne feront aucune recherche complémentaire.
Table des matières
- Principes globaux et layout
- Formatage français (nombres, dates, unités)
- Sémantique des couleurs
- Design system (tokens Tailwind, composants, palette charts)
- Composants transverses
- Configuration ECharts commune
- Page — Tableau de bord
- Page — Poids & Objectif
- Page — Nutrition
- Page — Activité & Sport
- Page — Balance énergétique
- Page — Vape
- Page — Finances
- Page — Imports
- Page — Réglages
- États vides (empty states) — récapitulatif
- Accessibilité
1. Principes globaux et layout
1.1 Structure générale
┌────────────┬──────────────────────────────────────────────┐
│ │ Topbar : titre de page + PeriodSelector + │
│ Sidebar │ actions rapides + menu utilisateur │
│ (nav) ├──────────────────────────────────────────────┤
│ │ Contenu : grille de KpiCard, ChartCard, │
│ │ tables, sections │
└────────────┴──────────────────────────────────────────────┘
- Sidebar (desktop ≥ 1024 px) : largeur
260px, repliable en mode icônes72px(bouton chevron en bas de la sidebar, état persisté danslocalStorage). Fondbg-base(#0D0D0D), séparée du contenu par une bordure hairline. - Entrées de navigation (ordre fixe, icônes Lucide entre parenthèses) :
- Tableau de bord (
layout-dashboard) — route/ - Poids & Objectif (
scale) — route/poids - Nutrition (
utensils) — route/nutrition - Activité & Sport (
footprints) — route/activite - Balance énergétique (
flame) — route/balance - Vape (
cloud) — route/vape - Finances (
wallet) — route/finances - Imports (
upload) — route/imports - Réglages (
settings) — route/reglages
- Tableau de bord (
- Item actif : fond
bg-surface-2, barre verticale3pxcouleuraccent(#3987E5) à gauche, textetext-primary. Items inactifs :text-secondary, hoverbg-surface-2/50. - En bas de sidebar : logo + version + bouton repli.
- Topbar : hauteur
56px, contient (gauche → droite) : titre de la page (h1, 18 px semibold),PeriodSelector(voir §5.1), bouton « + Ajouter » (menu déroulant d'actions rapides, voir §5.6), avatar/menu utilisateur (Profil, Réglages, Déconnexion).
1.2 Responsive
Breakpoints Tailwind standard : sm 640, md 768, lg 1024, xl 1280, 2xl 1536.
| Élément | Mobile (< 768) | Tablette (768–1023) | Desktop (≥ 1024) |
|---|---|---|---|
| Navigation | Barre inférieure fixe 5 items : Tableau de bord, Poids, Nutrition, Vape, « Plus » (bottom-sheet listant les autres pages) | Sidebar repliée (icônes) | Sidebar complète |
| PeriodSelector | Menu déroulant compact (icône calendrier + libellé court) | Segmented control | Segmented control |
| Grille KPI | 2 colonnes | 3 colonnes | 4 à 6 colonnes |
| ChartCard | Pleine largeur, hauteur min 240px |
1–2 colonnes | Grille 2 colonnes (graphique principal en pleine largeur) |
| Tables | Défilement horizontal dans la carte (overflow-x-auto), colonnes clés épinglées à gauche (Date, Libellé) ; jamais de scroll horizontal de page |
idem | Table complète |
| Ajout rapide | FAB + en bas à droite (au-dessus de la nav), ouvre le menu d'actions rapides |
Bouton topbar | Bouton topbar |
- Toutes les zones tactiles ≥
44px. Les graphiques restent lisibles à 360 px de large (labels d'axe X inclinés ou échantillonnés viaaxisLabel.interval: 'auto'). - Les modales deviennent des bottom-sheets plein écran sur mobile.
1.3 Thème
- Sombre par défaut. Un thème clair existe (Réglages → Application) mais le sombre est la référence de conception. Tout hex de ce document est donné pour le fond sombre.
color-scheme: darksur:root[data-theme="dark"]; bascule via attributdata-theme(dark|light|auto).
2. Formatage français
Toutes les valeurs affichées passent par des helpers centralisés (src/lib/format.ts) basés sur Intl avec locale fr-FR. Le séparateur de milliers est l'espace fine insécable (U+202F, produite nativement par Intl.NumberFormat('fr-FR')), le séparateur décimal est la virgule.
| Type | Helper | Exemple |
|---|---|---|
| Monnaie | formatCurrency(v) → Intl.NumberFormat('fr-FR', {style:'currency', currency:'EUR'}) |
1 234,56 € · −45,90 € |
| Poids | formatWeight(v) — 1 décimale |
82,4 kg |
| Calories | formatKcal(v) — entier groupé |
1 850 kcal |
| Millilitres | formatMl(v) — 1 décimale |
4,2 ml |
| Nicotine | formatMg(v) — 1 décimale |
12,6 mg |
| Distance | formatKm(v) — 2 décimales |
5,25 km |
| Pas | formatSteps(v) — entier groupé |
9 542 |
| Pourcentage | formatPercent(v) — espace avant % |
82 % |
| Grammes (macros) | formatG(v) — entier |
132 g |
| Durée | formatDuration(min) |
1 h 05 · 45 min |
| Date | formatDate(d) — dd/MM/yyyy |
13/08/2026 |
| Date + heure | formatDateTime(d) — dd/MM/yyyy HH:mm |
13/08/2026 19:30 |
| Date courte (axes) | formatDateShort(d) — dd/MM |
13/08 |
| Mois (axes) | formatMonth(d) |
août 2026 (axe : août 26) |
| Semaine (axes) | formatWeek(d) |
Sem. 33 (tooltip : du 10/08 au 16/08) |
| Nombre signé | formatSigned(v) — signe explicite, « − » U+2212 |
+0,3 kg · −450 kcal |
Règles :
- Saisie : les champs numériques acceptent la virgule et le point comme séparateur décimal (normalisation à la volée).
- Stockage : UTC en base ; affichage converti en
Europe/Pariscôté client (le backend renvoie de l'ISO 8601 UTC). - « Aujourd'hui » et « Hier » remplacent la date dans les listes quand pertinent (journal nutrition, dernières transactions).
- Alignement : montants et nombres alignés à droite dans les tables, avec
font-variant-numeric: tabular-nums.
3. Sémantique des couleurs
Deux familles distinctes : la palette de séries (identité, §4.4) et les couleurs sémantiques (polarité/état). Ne jamais utiliser une couleur sémantique comme couleur de série ordinaire.
| Signification | Couleur (fond sombre) | Usage |
|---|---|---|
| Positif / favorable — déficit calorique, économies vape, cashflow positif, budget respecté, perte de poids (si l'objectif est de perdre) | #0CA30C (semantic-positive) |
Barres de balance nette en déficit, aire « Économies cumulées », deltas KPI favorables, cashflow > 0 |
| Négatif / défavorable — surplus calorique, dépassement de budget, cashflow négatif, reprise de poids | #D03B3B (semantic-negative) |
Barres de surplus, budget > 100 %, deltas KPI défavorables |
| Avertissement — budget entre 80 et 100 %, résistance en fin de vie, import partiel | #FAB219 (semantic-warning) |
Badges, jauges, statuts |
| Sérieux (entre warning et negative) | #EC835A (semantic-serious) |
Réservé aux statuts d'import et alertes |
| Neutre / information | #3987E5 (slot 1 de la palette) |
Liens, éléments actifs, info |
Règles impératives :
- Direction consciente de l'objectif : pour le poids, le vert signifie « va dans le sens de l'objectif ». Si
goal.direction = lose, une variation négative est verte ; sigain, c'est l'inverse. Centraliser dans un helperdeltaTone(value, goalDirection). - Une couleur sémantique n'est jamais seule porteuse de sens : elle est toujours accompagnée d'un signe (
+/−), d'une icône (trending-down,alert-triangle…) ou d'un libellé. - Montants dans les tables Finances : dépenses en
text-primaryavec signe−, revenus ensemantic-positiveavec signe+(le signe porte l'info, la couleur renforce).
4. Design system
4.1 Tokens Tailwind (extrait de tailwind.config.ts)
// tailwind.config.ts — theme.extend
colors: {
base: '#0D0D0D', // fond de page
surface: '#1A1A19', // fond des cartes / graphiques
'surface-2': '#242423', // hover, éléments imbriqués, inputs
border: 'rgba(255,255,255,0.10)', // bordure hairline
ink: {
DEFAULT: '#FFFFFF', // text-primary
secondary:'#C3C2B7',
muted: '#898781', // labels d'axes, placeholders
},
grid: '#2C2C2A', // lignes de grille des graphiques
axis: '#383835', // ligne de base / axe
accent: '#3987E5',
semantic: {
positive: '#0CA30C',
negative: '#D03B3B',
warning: '#FAB219',
serious: '#EC835A',
},
chart: {
1: '#3987E5', 2: '#D95926', 3: '#199E70', 4: '#C98500',
5: '#D55181', 6: '#008300', 7: '#9085E9', 8: '#E66767',
},
},
borderRadius: { card: '12px' },
fontFamily: { sans: ['system-ui', '-apple-system', '"Segoe UI"', 'sans-serif'] },
Thème clair (non prioritaire, mêmes rôles) : base #F9F9F7, surface #FCFCFB, ink #0B0B0B, ink-secondary #52514E, border rgba(11,11,11,0.10), grid #E1E0D9, palette charts clair : #2A78D6, #EB6834, #1BAF7A, #EDA100, #E87BA4, #008300, #4A3AA7, #E34948, semantic-positive texte : #006300.
4.2 Composant Card
Base de toutes les cartes (KPI, graphiques, tables, sections de réglages) :
- Fond
bg-surface,rounded-card(12 px), bordure1px solid border, padding16px(mobile) /20px(desktop). Pas d'ombre portée (thème sombre) — la séparation vient du contraste fond/carte et de la bordure. - En-tête optionnel : titre 14 px semibold
text-ink, sous-titre 12 pxtext-ink-muted, zone d'actions à droite.
4.3 KpiCard
┌──────────────────────────────┐
│ LIBELLÉ (12px, muted, caps) │
│ 82,4 kg (28px, semibold) │
│ ▼ −0,4 kg sur 7 j (12px) │ ← delta coloré + icône
│ [sparkline optionnelle 40px] │
└──────────────────────────────┘
- Valeur principale : 28 px desktop / 24 px mobile,
text-ink. - Delta : icône
trending-up/trending-down+ valeur signée, colorée viadeltaTone. - Variante avec jauge de progression (barre 6 px arrondie) pour les KPI « X / budget ».
- Toute la carte est cliquable quand elle renvoie vers une page de détail (curseur pointer + hover
bg-surface-2/40).
4.4 Palette de graphiques (fond sombre — validée CVD, ne pas réordonner)
L'ordre des slots est un mécanisme de sécurité daltonisme (validé par script : pire paire adjacente CVD ΔE 8,4 ; vision normale 19,3 ; tous les slots ≥ 3:1 de contraste sur #1A1A19). Attribution fixe par entité — jamais recyclée, jamais réassignée quand une série est filtrée.
| Slot | Hex | Attribution LifeTrack (identité fixe) |
|---|---|---|
chart-1 bleu |
#3987E5 |
Poids (tendance), dépense énergétique (kcal out), distance, solde total |
chart-2 orange |
#D95926 |
Apports caloriques (kcal in), kcal actives |
chart-3 vert d'eau |
#199E70 |
Protéines, pas quotidiens |
chart-4 jaune |
#C98500 |
Glucides, coût vape |
chart-5 magenta |
#D55181 |
Lipides, nicotine |
chart-6 vert |
#008300 |
(réservé — éviter près de semantic-positive) |
chart-7 violet |
#9085E9 |
Vape (ml), poids théorique |
chart-8 rouge |
#E66767 |
Dernier recours (jamais pour un sens « négatif ») |
- Variantes d'une même entité (ex. projection du poids) : teintes séquentielles du même bleu —
#86B6EF(clair),#3987E5(base),#1C5CAB(foncé) — jamais un nouveau slot. - Catégories de dépenses (Finances) : slots 1→7 dans l'ordre, au-delà regroupement « Autres » en
ink-muted(#898781). Pour les donuts et le sankey (formes où toutes les paires se comparent), limiter à 7 catégories + « Autres ». - Chaque catégorie financière reçoit un slot à sa création (stocké en base) → couleur stable dans le temps.
- ≥ 2 séries ⇒ légende toujours affichée ; 1 série ⇒ pas de légende (le titre nomme la série).
- Jamais de valeur numérique sur chaque point : labels directs sélectifs (dernier point, max, min) uniquement.
- Jamais de double axe Y. Deux mesures d'échelles différentes = deux graphiques empilés partageant le même axe X et le même zoom (
echarts.connect).
4.5 Boutons et champs
- Bouton primaire : fond
accent, texte blanc,rounded-lg, hauteur 40 px. Secondaire : fondsurface-2, bordure hairline. Destructif : fondsemantic-negative. Ghost : texteaccent. - Inputs : fond
surface-2, bordure hairline, focus ringaccent, hauteur 40 px, labels au-dessus (12 pxtext-secondary), erreurs en 12 pxsemantic-negativesous le champ. - Selects natifs stylés + combobox avec recherche pour listes longues (catégories, aliments).
5. Composants transverses
5.1 PeriodSelector (sélecteur de période)
- Segmented control :
7 j·30 j·90 j·1 an·Tout·Personnalisé. Option active : fondsurface-2, textetext-ink; inactivestext-secondary. Personnaliséouvre un popover avec deux champs date (dd/MM/yyyy, datepicker fr, lundi premier jour de semaine) + raccourcis « Ce mois-ci », « Le mois dernier », « Cette année ». Libellé affiché ensuite :01/06/2026 – 13/08/2026.- Par défaut : 30 j partout, sauf Finances (Ce mois-ci) et Imports (pas de période).
- La période est globale à la page, persistée par page (
localStorage, cléperiod:<route>) et reflétée dans l'URL (?periode=30jou?du=2026-06-01&au=2026-08-13). - Chaque
ChartCardpeut surcharger localement sa période (menu ⋯), la surcharge est signalée par un badge sur la carte.
5.2 ChartCard
Card + en-tête standard : titre du graphique, sous-titre optionnel (période effective), actions à droite : menu ⋯ avec « Voir les données » (bascule le graphique en table triable des mêmes valeurs — obligatoire, c'est la vue accessible), « Exporter PNG », « Exporter CSV », « Plein écran ». Hauteur par défaut du canvas : 280 px (mini-graphes du tableau de bord : 120 px ; graphiques principaux : 360 px).
5.3 DataTable
- En-têtes triables (flèche), lignes hauteur 44 px, zébrage désactivé (bordures hairline entre lignes), hover
surface-2/40. - Pagination 20 lignes (50/100 au choix), pied « 1–20 sur 254 ».
- Barre de filtres au-dessus, sur une seule ligne (wrap sur mobile) ; champ recherche à gauche, filtres à droite.
- Ligne vide → composant
EmptyState(voir §16).
5.4 EmptyState
Illustration légère (icône 48 px ink-muted), titre 16 px, texte d'aide 14 px text-secondary, 1 à 2 boutons d'action (primaire = action de saisie ou d'import). Textes exacts par page en §16.
5.5 Modales
Overlay rgba(0,0,0,0.6), carte centrée max-w-md (formulaires rapides) ou max-w-2xl (règles, mapping d'import). Titre + croix de fermeture. Boutons en pied : « Annuler » (ghost) + action primaire. Esc ferme, Entrée valide les formulaires à un champ principal. Sur mobile : bottom-sheet plein écran.
5.6 Menu « + Ajouter » (actions rapides globales)
Disponible partout (topbar / FAB mobile). Items :
- « Pesée » → modale Quick-add poids (§8.5)
- « Aliment » → modale Quick-add aliment (§9.5)
- « Recharge vape » → modale Quick-add recharge (§12.5)
- « Résistance changée » → action un clic + toast (§12.6)
- « Séance de sport » → modale séance (§10.5)
- « Transaction » → modale transaction manuelle (§13.6)
- « Importer un fichier » → route
/imports
Raccourcis clavier : a ouvre le menu ; p pesée ; n aliment ; v recharge.
5.7 Toasts
En bas à droite (desktop) / haut (mobile). Succès : « Pesée enregistrée ✓ » avec lien « Annuler » (undo 5 s). Erreur : semantic-negative + détail.
6. Configuration ECharts commune
Fichier src/lib/echarts.ts : enregistrement des composants nécessaires (tree-shaking), locale FR d'ECharts, et un thème lifetrack-dark :
// Theme ECharts "lifetrack-dark" (extrait)
{
backgroundColor: 'transparent',
color: ['#3987E5','#D95926','#199E70','#C98500','#D55181','#008300','#9085E9','#E66767'],
textStyle: { color: '#C3C2B7', fontFamily: 'system-ui, "Segoe UI", sans-serif' },
axisLine: { lineStyle: { color: '#383835' } },
splitLine: { lineStyle: { color: '#2C2C2A' } },
axisLabel: { color: '#898781', fontSize: 11 },
legend: { textStyle: { color: '#C3C2B7' }, icon: 'circle', itemWidth: 8, itemHeight: 8, top: 0 },
tooltip: {
backgroundColor: '#1A1A19', borderColor: 'rgba(255,255,255,0.10)',
textStyle: { color: '#FFFFFF' }, padding: [8, 12],
},
}
Règles communes à tous les graphiques :
grid: { left: 8, right: 16, top: 36, bottom: 8, containLabel: true }(bottom 44 sidataZoomslider).- Tooltip :
trigger: 'axis'avecaxisPointer: { type: 'line' }pour les séries temporelles ;trigger: 'item'pour donut/sankey/barres horizontales. Formatter systématiquement en français via les helpers de §2 (date complète en tête, puis● Série valeurpar ligne, valeurs alignées à droite). - Zoom : tous les graphiques temporels reçoivent
dataZoom: [{ type: 'inside' }](molette + pincement) ; les graphiques « principaux » de page (poids, transactions par mois, ml vape) ajoutent{ type: 'slider', height: 20 }. - Lignes :
width: 2,symbol: 'circle',symbolSize: 6,showSymbol: false(symboles visibles au hover seulement) ;smooth: 0.2maximum, jamais de lissage exagéré. - Barres :
barMaxWidth: 28, coins arrondis côté extrémité de donnée uniquement (borderRadius: [4,4,0,0]vers le haut, inversé vers le bas), espace de 2 px entre segments empilés (itemStyle.borderColor: '#1A1A19', borderWidth: 1). - Aires : dégradé vertical de la couleur de série à 25 % → 0 % d'opacité.
- Axe Y : commence à 0 pour les barres ; pour le poids (ligne),
min/maxauto avec marge (scale: true). markLine(budgets, objectifs) : pointillés[4,4], couleur#C3C2B7, label au bout à droite (ex. « Budget 1 800 »),symbol: 'none'.- Pas d'animation à la mise à jour de période > 300 ms (
animationDuration: 300). - Chaque graphique expose
aria-labeldescriptif et l'alternative « Voir les données » (§5.2).
7. Page — Tableau de bord
Route / · Titre « Tableau de bord » · Période par défaut : 30 j (s'applique aux mini-graphes ; les KPI « aujourd'hui » et « ce mois-ci » l'ignorent).
Objectif UX : une vue croisée de tous les modules en un écran, chaque bloc cliquable vers sa page de détail. Composé d'une rangée de 6 KPI, d'une rangée d'actions rapides, puis d'une grille de 6 cartes-modules avec mini-graphe.
7.1 KPI (rangée 1 — 6 cartes, 2×3 sur mobile)
| # | Libellé | Valeur | Sous-texte | Couleur delta |
|---|---|---|---|---|
| 1 | Poids actuel | 82,4 kg (dernière pesée) |
▼ −0,4 kg sur 7 j (delta de la tendance EMA) |
deltaTone selon objectif |
| 2 | Calories aujourd'hui | 1 450 / 1 800 kcal |
jauge + Reste 350 kcal (ou Dépassement de 120 kcal en rouge) |
vert ≤ budget, rouge > |
| 3 | Déficit cumulé (30 j) | −12 450 kcal |
≈ −1,6 kg théoriques |
vert si déficit |
| 4 | Vape aujourd'hui | 3,8 ml |
≈ 11,4 mg de nicotine |
neutre |
| 5 | Économies vape | 1 245,80 € |
depuis le 15/03/2025 |
toujours vert |
| 6 | Dépenses du mois | 1 234,56 € / 1 500,00 € |
jauge + 82 % du budget global |
vert < 80 %, jaune 80–100 %, rouge > 100 % |
Si un module n'a pas de données, sa KpiCard affiche — + lien « Configurer ».
7.2 Actions rapides (rangée 2)
Boutons pleine largeur sur une ligne : « + Pesée » · « + Aliment » · « + Recharge vape » · « Résistance changée » · « + Séance » · « Importer » — mêmes actions que §5.6, en accès direct.
7.3 Cartes-modules (grille 2 colonnes desktop, 1 colonne mobile)
Chaque carte : titre + valeur clé + mini-graphe ECharts (120 px, sans axe Y visible, axe X en dates courtes, tooltip actif, pas de zoom) + lien « Voir le détail → ».
- « Poids » — mini-line : tendance EMA (bleu
chart-1, 2 px) +markLinehorizontale objectif (pointillés muted, label « Objectif 78,0 kg »). Période sélectionnée. - « Nutrition » — mini-bar 7 derniers jours : kcal/jour, chaque barre colorée
semantic-positivesi ≤ budget du jour,semantic-negativesinon +markLinebudget. - « Balance énergétique » — mini-bar : balance nette/jour (in − out), barres vertes si < 0 (déficit), rouges si > 0, ligne zéro visible (
axisLinesur y=0). - « Vape » — mini-line ml/jour (violet
chart-7) + moyenne mobile 7 j en trait plein, valeurs brutes en points 40 % d'opacité. - « Économies » — mini-area cumulée verte (
#0CA30C, dégradé) ; label direct sur le dernier point :1 245,80 €. - « Finances » — mini-bar 6 derniers mois : dépenses/mois (barres
chart-1) +markLinebudget mensuel global ; le mois courant est hachuré (mois incomplet,decalECharts).
7.4 États particuliers
- Première visite (aucune donnée nulle part) : le tableau de bord est remplacé par un écran d'accueil : « Bienvenue sur LifeTrack 👋 » + 3 cartes d'onboarding : « Configurez votre profil » (→
/reglages), « Définissez votre objectif de poids » (→/reglages?tab=objectif), « Importez vos premières données » (→/imports).
8. Page — Poids & Objectif
Route /poids · Titre « Poids & Objectif » · Période par défaut : 90 j.
Définitions de calcul (implémentation) :
trendWeight: EMA des pesées,alpha = 0.1(≈ tendance sur ~20 jours), calculée sur jours calendaires (interpolation : l'EMA n'avance que sur les jours avec pesée).weeklyRate: pente de la tendance sur 7 jours glissants, en kg/semaine.projection: régression linéaire de la tendance sur les 21 derniers jours, extrapolée jusqu'àgoal.targetWeight(bornée à +365 j).bmi = poids / taille².
8.1 KPI (6 cartes)
| Libellé | Valeur | Sous-texte |
|---|---|---|
| Poids actuel | 82,4 kg |
Pesée du 13/08/2026 |
| Tendance (EMA) | 82,7 kg |
▼ −0,4 kg sur 7 j |
| Rythme hebdo | −0,45 kg/sem |
Objectif : −0,50 kg/sem (vert si |
| IMC | 26,3 |
Surpoids (catégories : < 18,5 Maigreur · 18,5–25 Corpulence normale · 25–30 Surpoids · ≥ 30 Obésité) |
| Objectif | 78,0 kg |
Reste 4,4 kg · 61 % + jauge (départ → objectif) |
| Atteinte estimée | 24/10/2026 |
dans 10 semaines (ou — · rythme insuffisant si la pente ne converge pas) |
8.2 Graphiques
G1 — « Évolution du poids » (principal, pleine largeur, 360 px)
- Type :
line+scattercombinés, axe Xtime(dates), axe Y kg (scale: true, marge ±1 kg). - Séries :
Pesées— scatter, symboles 6 px,#3987E5à 45 % d'opacité ;Tendance— line 2 px#3987E5, sans symboles ;Projection— line pointillée[6,4]#86B6EF, ne démarre qu'au dernier point de tendance, s'étend dans le futur ;Objectif—markLinehorizontale àtargetWeight, pointillés, label « Objectif 78,0 kg » ;markPointdiscret à l'intersection projection/objectif avec label date estimée.
- Interactions : tooltip axe (Date · Pesée · Tendance),
dataZoominside + slider, légende (3 séries), clic-légende pour masquer les pesées brutes.
G2 — « Rythme hebdomadaire » (demi-largeur)
- Type :
bar, une barre par semaine ISO, axe X semaines (Sem. 31…), axe Y kg/sem. - Couleur par pièce (
visualMap.pieces) : variation dans le sens de l'objectif →semantic-positive, sens inverse →semantic-negative(direction-aware §3). markLineau rythme cible (ex.−0,50). Tooltip item :Sem. 32 · du 03/08 au 09/08 — −0,45 kg.
G3 — « IMC » (demi-largeur)
- Type :
line(IMC de la tendance), axe Y IMCmin 16, max 35. markAreade fond aux 4 bandes (opacité 6 % : bleu maigreur, vert normal, jaune surpoids, rouge obésité) + labels de bande à droite en 10 px muted. Tooltip :13/08/2026 — IMC 26,3 (Surpoids).
G4 — « Mensurations » (pleine largeur, affiché seulement si ≥ 1 mesure existe)
- Type :
linemulti-séries, axe Y cm. Séries (ordre de palette) :Tour de taille(1),Hanches(2),Poitrine(3),Bras(4),Cuisse(5). Légende obligatoire + labels directs en bout de ligne. Tooltip axe.connectdu zoom avec G1.
8.3 Table « Historique des pesées »
Colonnes : Date · Poids · Tendance · Variation (vs pesée précédente, signée et colorée) · Note · actions (✎ modifier, 🗑 supprimer avec confirmation). Tri par date desc. Bouton d'en-tête « + Ajouter une pesée ».
8.4 Carte « Objectif » (résumé)
Rappel de l'objectif configuré : Départ 89,2 kg (12/01/2026) → Objectif 78,0 kg + jauge de progression + « Modifier l'objectif » (→ Réglages, onglet Objectif).
8.5 Modale « Ajouter une pesée » (quick-add global)
Champs :
- Poids (kg) — numérique, pas 0,1, focus auto, pré-rempli avec la dernière valeur. Validation : 20–300 kg.
- Date — datepicker, défaut aujourd'hui. Heure — optionnelle, défaut maintenant.
- Note — texte libre optionnel (placeholder : « ex. après le sport »).
- Section repliable « Mensurations (optionnel) » : Tour de taille, Hanches, Poitrine, Bras, Cuisse (cm, 1 décimale).
- Si une pesée existe déjà ce jour : avertissement « Une pesée existe déjà le 13/08/2026 (82,6 kg). Enregistrer remplacera cette valeur. » avec choix « Remplacer » / « Ajouter quand même ».
- Boutons : « Annuler » / « Enregistrer » → toast « Pesée enregistrée ✓ ».
9. Page — Nutrition
Route /nutrition · Titre « Nutrition » · Période par défaut : 30 j (graphes) ; le journal est journalier avec son propre navigateur de date.
Le budget kcal du jour vient de la Balance énergétique (§15.3) : dailyBudget = TDEE − targetDeficit, ou valeur manuelle.
9.1 KPI (6 cartes)
| Libellé | Valeur | Sous-texte |
|---|---|---|
| Aujourd'hui | 1 450 / 1 800 kcal |
jauge + Reste 350 kcal |
| Moyenne 7 j | 1 720 kcal/j |
Budget moyen : 1 800 kcal/j |
| Protéines aujourd'hui | 96 / 130 g |
jauge (objectif §15.3) |
| Répartition du jour | P 27 % · G 45 % · L 28 % |
en % des kcal |
| Jours dans le budget | 18 / 30 j |
sur la période sélectionnée |
| Écart moyen au budget | −80 kcal/j |
vert si négatif |
9.2 Graphiques
G1 — « Calories par jour » (principal, pleine largeur)
- Type :
bar+line. Axe X jours, axe Y kcal (un seul axe — même unité). - Série 1
Apports: barres, couleur par jour via callbackitemStyle.color:semantic-positivesikcal ≤ budgetOfDay,semantic-negativesinon (comparaison au budget du jour, le budget peut évoluer). - Série 2
Budget: ligne en escalier (step: 'end'), pointillés,#C3C2B7. - Tooltip axe :
mar. 12/08 — Apports 1 940 kcal · Budget 1 800 kcal · Écart +140 kcal. Zoom inside + slider. Légende (2 séries).
G2 — « Macronutriments par jour » (pleine largeur)
- Type :
barempilées, unité kcal (P ×4, G ×4, L ×9 — permet la comparaison visuelle avec G1). Séries :Protéines#199E70,Glucides#C98500,Lipides#D55181(espace 2 px entre segments). Légende. Tooltip axe avec grammes ET kcal :Protéines 96 g (384 kcal). Toggle dans le menu ⋯ : « Afficher en grammes ».
G3 — « Répartition du jour » (tiers de largeur)
- Type :
pie(donut, radius['55%','80%']). 3 parts P/G/L, mêmes couleurs que G2. Centre :1 450 kcal(graphic text). Labels directs :Protéines 27 %. Tooltip item :Glucides — 652 kcal (45 %) · 163 g. Suit la date du journal (§9.4).
G4 — « Répartition par repas » (deux tiers de largeur)
- Type :
barempilées 100 % (stack+ normalisation), une barre par jour. Séries :Petit-déjeuner(slot 1),Déjeuner(2),Dîner(3),Collations(4). Tooltip : kcal réels + %. Légende. Objectif : voir si un repas dérape (grignotage).
G5 — « Top aliments » (pleine largeur, 320 px)
- Type :
barhorizontales, top 10 des aliments par kcal totales sur la période. Axe Y : noms d'aliments (tronqués à 24 caractères + tooltip complet), axe X kcal. Une seule série → couleur uniquechart-2, pas de légende. Label direct à droite de chaque barre :12 340 kcal. Tooltip item :Pain complet — 12 340 kcal · 28 fois · 441 kcal/fois en moyenne. Clic sur une barre → filtre le journal sur cet aliment (badge de filtre actif au-dessus du journal).
9.3 Bibliothèque d'aliments (panneau secondaire)
Accessible par un bouton « Mes aliments » dans l'en-tête de page : panneau latéral (drawer) listant les aliments mémorisés — Nom · kcal/100 g (ou /portion) · P/G/L · Utilisé n fois · actions ✎ 🗑. Recherche en tête. C'est cette bibliothèque qu'interroge l'autocomplete du quick-add (§9.5) ; les aliments importés de Foodvisor y sont ajoutés automatiquement (dédupliqués par nom normalisé).
9.4 Journal alimentaire (section « Journal du jour »)
- Navigateur de date :
‹ mer. 13/08/2026 ›+ bouton « Aujourd'hui ». Swipe gauche/droite sur mobile. - Bandeau du jour :
Total : 1 450 / 1 800 kcal · P 96 g · G 163 g · L 45 g+ jauge. - 4 groupes repliables : Petit-déjeuner / Déjeuner / Dîner / Collations, chacun avec sous-total (
620 kcal) et bouton « + Ajouter un aliment ». - Ligne d'entrée : nom · quantité (
150 g) · kcal · P/G/L (masqués sur mobile, visibles au tap) · actions ✎ / 🗑 / ⧉ (dupliquer vers un autre jour/repas). - Les entrées importées de Foodvisor portent un badge source
Foodvisor(tooltip : « Importé le 10/08/2026 »).
9.5 Modale « Ajouter un aliment » (quick-add global)
- Recherche (focus auto) : autocomplete sur la bibliothèque personnelle (aliments déjà saisis/importés), résultats avec kcal/100 g. Sélection → pré-remplit tout.
- Nom (texte, requis) · Repas (select : Petit-déjeuner / Déjeuner / Dîner / Collations — défaut selon l'heure : < 11 h petit-déj., 11–15 h déjeuner, 15–18 h collations, > 18 h dîner) · Date (défaut : jour affiché dans le journal).
- Quantité + Unité (
g/ml/portion) — si l'aliment vient de la bibliothèque, kcal et macros se recalculent proportionnellement. - Calories (kcal) (requis) · Protéines (g) · Glucides (g) · Lipides (g) (optionnels).
- Case « Mémoriser cet aliment dans ma bibliothèque » (cochée par défaut pour une saisie manuelle).
- Boutons : « Annuler » / « Ajouter » / « Ajouter et continuer » (garde la modale ouverte, vide la recherche — saisie en rafale d'un repas).
10. Page — Activité & Sport
Route /activite · Titre « Activité & Sport » · Période par défaut : 30 j.
Sources : Health Connect (pas, distance, kcal actives via bridge), FitShow (séances tapis), saisie manuelle. stepsGoal configurable (défaut 10 000).
10.1 KPI (6 cartes)
| Libellé | Valeur | Sous-texte |
|---|---|---|
| Pas aujourd'hui | 7 842 / 10 000 |
jauge |
| Moyenne pas (7 j) | 9 120 /j |
▲ +6 % vs 7 j précédents |
| Kcal actives aujourd'hui | 320 kcal |
Moyenne 7 j : 410 kcal/j |
| Distance (période) | 86,4 km |
≈ 2,9 km/j |
| Séances cette semaine | 3 séances · 2 h 15 |
Semaine dernière : 4 · 3 h 05 |
| Objectif atteint | 21 / 30 j |
jours ≥ objectif de pas sur la période |
10.2 Graphiques
G1 — « Pas par jour » (principal, pleine largeur)
- Type :
bar+line. SériePas: barres#199E70(chart-3) ; jours ≥ objectif : opacité 100 %, sinon 55 % (renfort non-couleur : l'axe le montre aussi). SérieMoyenne 7 j: ligne 2 px blanche à 60 %.markLineobjectif (« Objectif 10 000 »). Tooltip axe, zoom inside + slider. Légende (2 séries).
G2 — « Calories actives par jour » (demi-largeur)
- Type :
bar, série unique#D95926(chart-2), pas de légende.markLinemoyenne de période (label « Moy. 410 »). Tooltip axe.
G3 — « Entraînement par semaine » (demi-largeur)
- Type :
barempilées par semaine ISO, axe Y heures (1 h 30au tooltip). Séries = types de séance :Tapis de course(1),Marche(2),Vélo(3),Renforcement(4),Autre(5, muted). Légende. Tooltip axe : détail par type + total semaine.
G4 — « Distance cumulée » (pleine largeur, 240 px)
- Type :
lineen aire, cumul de la distance (pas + séances) depuis le début de la période,#3987E5avec dégradé. Label direct sur le dernier point (86,4 km). Tooltip axe :12/08 — cumul 84,1 km (+2,3 km ce jour).
10.3 Carte « Records » (stat tiles, pas un graphique)
4 tuiles : Max pas en un jour 18 452 · 21/06/2026 · Plus longue séance 1 h 32 · tapis · 05/07/2026 · Meilleure distance en séance 12,4 km · Meilleure semaine 78 500 pas · Sem. 25. Chaque record est cliquable → surligne le jour dans G1.
10.4 Table « Séances »
Colonnes : Date · Type (badge icône) · Durée · Distance · Kcal · FC moy. (si dispo) · Source (badge : FitShow / Health Connect / Manuel) · actions ✎ 🗑. Filtres : type, source. Tri par date desc.
10.5 Modale « Ajouter une séance »
Champs : Type (select : Tapis de course / Marche / Course à pied / Vélo / Renforcement / Natation / Autre) · Date (défaut aujourd'hui) · Heure de début · Durée (champ hh:mm, requis) · Distance (km) (optionnel) · Calories (kcal) (optionnel — placeholder « estimées automatiquement si vide », estimation MET simple par type) · FC moyenne (bpm) (optionnel) · Note. Boutons « Annuler » / « Enregistrer ».
11. Page — Balance énergétique
Route /balance · Titre « Balance énergétique » · Période par défaut : 30 j.
Définitions (constantes en src/lib/energy.ts) :
BMR: Mifflin-St Jeor (10×kg + 6.25×cm − 5×âge + s,s = +5homme /−161femme), recalculé chaque jour avec le poids de tendance.TDEE = BMR × activityFactor(§15.1) ouBMR + kcal actives mesuréessi la source d'activité est complète (choix dans Réglages :tdeeMode: 'factor' | 'measured').netBalance(day) = kcalIn − TDEE(day). Négatif = déficit = vert.KCAL_PER_KG = 7700pour toutes les conversions kcal ↔ kg.- Un jour sans journal alimentaire est exclu des cumuls (et hachuré dans les graphes) plutôt que compté à 0 — règle anti-fausses-données.
11.1 KPI (6 cartes)
| Libellé | Valeur | Sous-texte |
|---|---|---|
| Balance aujourd'hui | −520 kcal |
Apports 1 450 · Dépense 1 970 |
| Déficit moyen (7 j) | −430 kcal/j |
Cible : −550 kcal/j |
| Cumul (période) | −12 450 kcal |
≈ −1,6 kg théoriques |
| TDEE estimé | 2 350 kcal/j |
BMR 1 780 × 1,32 (ou BMR + actives mesurées) |
| Budget quotidien | 1 800 kcal |
TDEE − 550 |
| Réel vs théorique | +0,4 kg |
le réel décroche au-dessus du modèle (voir G4) |
11.2 Graphiques
G1 — « Entrées vs sorties » (principal, pleine largeur)
- Type :
baren miroir sur un seul axe kcal : sérieApportsen valeurs positives (#D95926,chart-2), sérieDépense énergétiqueen valeurs négatives (#3987E5,chart-1, arrondis vers le bas). Ligne zéro marquée (axisLiney=0 en#383835). - Tooltip axe :
mar. 12/08 — Apports 1 940 · Dépense 2 310 · Balance −370 kcal(balance colorée). Légende (2 séries). Zoom inside + slider. Jours sans journal : barres hachurées (decal) + mention tooltip « journal incomplet ».
G2 — « Balance nette quotidienne » (demi-largeur)
- Type :
bar, une sérienet = in − out.visualMap.pieces:< 0→semantic-positive(déficit),> 0→semantic-negative(surplus).markLineà la cible de déficit (−550, pointillés). Tooltip :12/08 — Balance −370 kcal (déficit).
G3 — « Déficit cumulé » (demi-largeur)
- Type :
lineen aire, cumul denetdepuis le début de période. Couleursemantic-positivesi le cumul est négatif (cas normal), l'aire se remplit sous zéro. Axe Y kcal ; le tooltip donne la double lecture :Cumul −12 450 kcal ≈ −1,6 kg(pas de second axe — l'équivalence kg vit dans le tooltip et le KPI).
G4 — « Poids théorique vs poids réel » (pleine largeur)
- Type :
line, 2 séries, axe Y kg (même unité, un seul axe) :Poids réel (tendance)—#3987E5, 2 px ;Poids théorique—#9085E9(chart-7), pointillés[6,4]:startWeight + cumul(net)/7700, ancré sur la tendance au 1er jour de la période.
- Légende + labels directs en bout de lignes. Tooltip axe : les deux valeurs +
Écart +0,4 kg. C'est le graphique de vérité du module : si le réel et le théorique divergent durablement, le TDEE est recalibré (voir carte méthode).
11.3 Carte « Méthode & calibration »
Carte informative repliable : explication en 3 phrases du modèle (BMR Mifflin-St Jeor, TDEE, 7 700 kcal/kg), et ligne de calibration : « Sur les 30 derniers jours, votre dépense réelle estimée d'après la pesée est de 2 410 kcal/j (modèle : 2 350). » + bouton « Utiliser cette valeur comme TDEE » (écrit un override dans Réglages).
11.4 État dégradé
Cette page exige pesées + journal alimentaire. S'il manque l'un des deux sur la période : bandeau jaune « Données incomplètes : X jours sans journal alimentaire sur la période. Les cumuls excluent ces jours. »
12. Page — Vape
Route /vape · Titre « Vape » · Période par défaut : 30 j.
Modèle de coût (constantes dans Réglages §15.4) :
costPerMl= (prix base/ml + prix nicotine/ml au taux cible + prix arôme/ml au dosage) — détail affiché en §12.4.coilCostPerDay= prix résistance ÷ durée de vie moyenne (jours).vapeCostPerDay(d) = ml(d) × costPerMl + coilCostPerDay.tobaccoCostPerDay= (cigarettes/jour avant arrêt ÷ cigarettes/paquet) × prix du paquet — figé à la config baseline, avec historique de prix optionnel.savings(d) = Σ depuis quitDate (tobaccoCostPerDay − vapeCostPerDay).avoidedCigarettes = jours depuis quitDate × cigarettes/jour avant(compteur temps réel au prorata de la journée).- Consommation ml/jour : dérivée des recharges (une recharge de 10 ml le 12/08 puis une le 15/08 ⇒ ~3,3 ml/j lissés sur l'intervalle) ; une saisie quotidienne directe est aussi possible — les deux modes coexistent, la donnée quotidienne prime.
12.1 KPI (8 cartes, 2 rangées)
| Libellé | Valeur | Sous-texte |
|---|---|---|
| Aujourd'hui | 3,8 ml |
Moyenne 7 j : 4,1 ml/j |
| Nicotine aujourd'hui | 11,4 mg |
3,8 ml × 3,0 mg/ml |
| Coût moyen / jour | 0,62 €/j |
dont résistances 0,17 €/j |
| Économies cumulées | 1 245,80 € |
vs 8,50 €/j de tabac — toujours vert |
| Cigarettes évitées | 7 654 |
compteur animé (odometer), ≈ 15/j |
| Sans tabac depuis | 511 jours |
depuis le 15/03/2025 |
| Résistance actuelle | J+9 |
Moyenne : 12 j — à surveiller (badge jaune si ≥ moyenne − 2 j, rouge si > moyenne) |
| Stock estimé | 34 ml |
≈ 8 jours restants (si suivi de stock activé, sinon carte masquée) |
12.2 Graphiques
G1 — « Consommation d'e-liquide » (principal, pleine largeur)
- Type :
line+scatter. Sérieml/jour: points#9085E9(chart-7) à 45 % ; sérieMoyenne mobile 7 j: ligne 2 px#9085E9.markLineoptionnelle « Objectif » si un objectif de réduction est défini (§15.4). Tooltip axe :12/08 — 4,2 ml · moyenne 7 j : 4,0 ml. Zoom inside + slider. Légende (2 séries). - Les jours de changement de résistance apparaissent en
markPointdiscrets (petit pictogramme ⚙ sous l'axe, tooltip « Résistance changée »).
G2 — « Nicotine absorbée » (demi-largeur)
- Type :
bar, série uniquemg/jour#D55181(chart-5).markLinemoyenne de période. Tooltip :12/08 — 12,6 mg (4,2 ml × 3,0 mg/ml). Si le taux a changé dans la période, chaque jour utilise le taux effectif de la recharge courante.
G3 — « Coût quotidien » (demi-largeur)
- Type :
line, série€/jour#C98500(chart-4), moyenne mobile 7 j (le brut en points 45 %).markLinede référence :Tabac : 8,50 €/j(pointillés#C3C2B7) — l'écart visuel entre la ligne et la markLine est l'économie quotidienne. Tooltip :12/08 — vape 0,66 € · tabac évité 8,50 € · gain 7,84 €.
G4 — « Économies cumulées » (pleine largeur, 320 px — le graphique plaisir)
- Type :
lineen aire, cumulsavingsdepuisquitDate, couleur#0CA30Cavec dégradé d'aire. Période forcée « Tout » par défaut (surcharge locale possible). Label direct sur le dernier point :1 245,80 €.markPointaux paliers franchis :100 €,250 €,500 €,1 000 €,2 000 €,5 000 €(pin avec étiquette). Tooltip axe :12/08 — 1 238,40 € économisés. Zoom inside + slider.
G5 — « Durée de vie des résistances » (pleine largeur, 260 px)
- Type :
bar, une barre par résistance terminée, axe X = date de changement (catégorie), axe Y = durée en jours. Couleur uniquechart-7; la résistance courante (en cours) apparaît en dernière barre hachurée (decal) avec sa durée provisoire.markLinemoyenne (label « Moy. 12 j »). Tooltip item :Changée le 04/08/2026 — a duré 13 j · ~52 ml vapotés · GT Mesh 0,15 Ω.
12.3 Timeline « Jalons santé » (composant liste, pas ECharts)
Timeline verticale (rail à gauche, points verts = atteint, gris = à venir, le prochain jalon porte une jauge de progression). Jalons depuis quitDate (libellés exacts) :
| Échéance | Libellé |
|---|---|
| 20 minutes | « Pouls et tension redescendent » |
| 8 heures | « Le monoxyde de carbone diminue de moitié » |
| 24 heures | « Le CO est éliminé, les poumons évacuent les résidus » |
| 48 heures | « Goût et odorat s'améliorent » |
| 72 heures | « Respirer devient plus facile » |
| 2 semaines | « La circulation sanguine s'améliore » |
| 1 mois | « La peau retrouve son éclat » |
| 3 mois | « Toux et fatigue diminuent, souffle nettement meilleur » |
| 6 mois | « Capacité pulmonaire en nette hausse » |
| 1 an | « Risque d'infarctus réduit de moitié » |
| 5 ans | « Risque d'AVC redevenu comparable à un non-fumeur » |
| 10 ans | « Risque de cancer du poumon réduit de moitié » |
12.4 Carte « Modèle de coût » (repliable)
Décomposition affichée : Base PG/VG 0,08 €/ml + Nicotine 0,11 €/ml + Arôme 0,09 €/ml = 0,28 €/ml · Résistance : 3,90 € ÷ 12 j = 0,33 €/j · Référence tabac : 15 cig./j × (12,50 € / 20) = 9,38 €/j (valeurs = exemples). Bouton « Modifier le modèle » → Réglages §15.4.
12.5 Modale « Recharge » (quick-add global)
Champs : Quantité (ml) — numérique, défaut = contenance de flacon par défaut (§15.4), boutons rapides 10 30 50 · Taux de nicotine (mg/ml) — défaut = taux courant des Réglages · Date et heure — défaut maintenant · Arôme / recette (texte optionnel, autocomplete sur les précédents) · Note. Boutons « Annuler » / « Enregistrer » → toast « Recharge de 10,0 ml enregistrée ✓ ».
Variante dans la même modale (onglets) : « Conso du jour » — saisie directe ml pour une date (corrige/remplace l'estimation par recharges).
12.6 Bouton « Résistance changée » (action un clic)
Depuis le menu « + Ajouter », la page Vape (bouton dédié dans l'en-tête de G5) ou le tableau de bord : enregistre coilChange(now) immédiatement, toast « Résistance changée ✓ — la précédente a duré 13 jours » + lien « Ajouter un détail » (ouvre une mini-modale : Modèle (texte, autocomplete), Valeur (Ω), Prix unitaire (défaut Réglages), Note).
12.7 Tables
- « Historique des recharges » :
Date·Quantité·Nicotine·Arôme·Coût estimé· actions ✎ 🗑. - « Historique des résistances » :
Posée le·Retirée le·Durée·Conso (ml)·Modèle·Prix· actions ✎ 🗑.
13. Page — Finances
Route /finances · Titre « Finances » · Période par défaut : Ce mois-ci (le PeriodSelector affiche ici en tête : Ce mois-ci · 3 mois · 6 mois · 1 an · Tout · Personnalisé).
La page est organisée en 4 onglets internes (tabs sous la topbar) : Vue d'ensemble · Transactions · Budgets · Récurrents. L'URL les reflète (/finances, /finances/transactions, /finances/budgets, /finances/recurrents).
13.1 KPI (communs, affichés sur « Vue d'ensemble »)
| Libellé | Valeur | Sous-texte |
|---|---|---|
| Solde total | 4 812,34 € |
3 comptes (au dernier import) |
| Dépenses du mois | 1 234,56 € |
Moyenne 6 mois : 1 480,00 € |
| Revenus du mois | 2 300,00 € |
|
| Cashflow du mois | +1 065,44 € |
vert si > 0, rouge sinon |
| Budget global | 82 % |
jauge 1 234,56 € / 1 500,00 € |
| À catégoriser | 14 transactions |
carte cliquable → onglet Transactions filtré catégorie = aucune (badge jaune si > 0) |
13.2 Onglet « Vue d'ensemble » — graphiques
G1 — « Évolution du solde total » (pleine largeur)
- Type :
lineen aire, solde total reconstitué jour par jour (somme des comptes),#3987E5. Tooltip axe :12/08 — 4 812,34 €. Zoom inside + slider. Sous le graphique, rangée de tuiles par compte : nom du compte, solde1 852,10 €, date de dernière donnée (badge jaune « Dernier import il y a 32 j » si > 30 j).
G2 — « Dépenses par catégorie » (demi-largeur, période courante)
- Type :
piedonut (radius['50%','78%']), top 7 catégories + partAutres(#898781). Couleur = slot fixe de chaque catégorie (§4.4). Centre : total1 234,56 €. Labels directs :Alimentation 24 %. Tooltip item :Alimentation — 296,40 € (24 %) · 18 transactions. Clic sur une part → onglet Transactions filtré sur la catégorie + la période.
G3 — « Dépenses mensuelles par catégorie » (demi-largeur)
- Type :
barempilées, 12 derniers mois, mêmes couleurs de catégories (top 7 + Autres, espaces 2 px). Légende. Tooltip axe : détail par catégorie + total du mois. Mois courant hachuré (decal, incomplet). Clic sur un segment → Transactions filtrées (mois + catégorie).
G4 — « Cashflow mensuel » (pleine largeur)
- Type :
bargroupées +line, un seul axe € :Revenus(barressemantic-positive),Dépenses(barressemantic-negative, affichées en positif, côte à côte),Net(ligne blanche 2 px, peut passer sous zéro). Légende (3). Tooltip axe :juin 2026 — Revenus 2 300,00 € · Dépenses 1 890,50 € · Net +409,50 €.
G5 — « Flux du mois » (pleine largeur, 380 px)
- Type :
sankey, orientation gauche → droite : nœudsRevenus(par catégorie de revenu : Salaire, Autres revenus) → nœud centralBudget du mois→ catégories de dépenses (top 7 + Autres) → l'écart restant sort vers un nœudÉpargne(vert) si positif. Liens colorés par catégorie cible à 40 % d'opacité. Tooltip lien :Budget → Alimentation : 296,40 €. Nœuds : label + montant. Pas de zoom ; drag des nœuds désactivé (draggable: false).
13.3 Onglet « Transactions »
Barre de filtres (une ligne, wrap mobile) : Recherche texte (libellé) · Compte (multi-select) · Catégorie (multi-select avec « Sans catégorie ») · Type (Tout / Dépenses / Revenus) · Montant min/max · période (héritée de la page). Badges de filtres actifs effaçables ; bouton « Réinitialiser ».
Table (le cœur du module) — colonnes :
| Colonne | Contenu |
|---|---|
Date |
dd/MM/yyyy (groupes visuels par mois au scroll : sous-en-tête « août 2026 — 1 234,56 € de dépenses ») |
Libellé |
libellé bancaire nettoyé, sous-ligne : libellé brut original en 11 px muted |
Compte |
badge court (« Courant », « PayPal ») |
Catégorie |
éditable en ligne : badge coloré (pastille couleur du slot) cliquable → combobox avec recherche ; Sans catégorie = badge jaune pointillé |
Montant |
aligné droite, tabular ; dépenses −45,90 € en text-ink, revenus +2 300,00 € en semantic-positive |
| Actions (hover / menu ⋯) | ✎ Modifier · ⚡ « Créer une règle » · 🗑 Supprimer (les transactions importées se suppriment avec confirmation renforcée) |
- Sélection multiple (checkbox) → barre d'actions groupées : « Catégoriser (n) », « Supprimer (n) ».
- Une transaction re-catégorisée à la main affiche une pastille « manuel » (les règles ne l'écrasent plus).
Modale « Créer une règle » (ouverte depuis une transaction, pré-remplie) :
- Si le libellé contient (texte, pré-rempli avec le mot significatif du libellé, ex.
CARREFOUR) — select d'opérateur :contient/commence par/expression régulière. - Conditions optionnelles (ajout par bouton « + Condition ») : Compte est (select) · Montant entre (min/max) · Type (dépense/revenu).
- Alors catégoriser en : combobox catégorie (+ « Créer une catégorie… » inline).
- Aperçu en direct : « 12 transactions existantes correspondent à cette règle » + mini-liste des 5 premières.
- Case « Appliquer aux transactions existantes non catégorisées manuellement » (cochée par défaut).
- Boutons « Annuler » / « Créer la règle ». Toast : « Règle créée ✓ — 12 transactions catégorisées ».
13.4 Onglet « Budgets »
- Sélecteur de mois (
‹ août 2026 ›). - Liste de barres de progression par catégorie (composant, pas ECharts) : pastille + nom ·
296,40 € / 350,00 €· barre 8 px (vert < 80 %, jaune 80–100 %, rouge > 100 % — le dépassement déborde en rouge au-delà de 100 % avec largeur plafonnée et libellé118 %) · reste53,60 €ouDépassé de 22,40 €. - En tête : budget global (somme) avec la même barre + « Rythme » :
Au 13/08, vous avez dépensé 82 % du budget pour 42 % du mois écoulé(jauge à double repère : position du jour vs consommation). - Graphique G6 — « Budget vs réalisé (6 mois) » :
bargroupées par mois :Budget(barres#89878140 %) vsDépensé(barreschart-1), un axe €. Légende. Tooltip axe. - Bouton « Modifier les budgets » → Réglages §15.5 (ou édition inline du montant au clic).
13.5 Onglet « Récurrents »
- Détection automatique : transactions au libellé similaire, périodicité ~mensuelle/hebdo/annuelle (tolérance ±4 j), ≥ 3 occurrences.
- Table « Dépenses récurrentes détectées » :
Libellé·Catégorie·Fréquence(Mensuel,Annuel…) ·Montant moyen·Dernière occurrence·Prochaine échéance estimée(badge jaune si dépassée = possible résiliation ou changement) ·Coût annuel(tri par défaut, desc) · actions : « Confirmer » / « Ignorer » (les ignorés vont dans un panneau repliable). - KPI d'onglet : « Total récurrent mensuel »
184,90 €/mois· « Part des dépenses »15 %· « Coût annuel »2 218,80 €. - Graphique G7 — « Échéancier du mois » : frise horizontale du mois (composant custom léger) avec les échéances positionnées au jour, passées en plein / à venir en contour.
13.6 Modale « Ajouter une transaction » (manuelle)
Champs : Type (toggle Dépense / Revenu) · Montant (€) · Date · Libellé · Compte (select) · Catégorie (combobox) · Note. Utilisée pour les espèces ; badge source « Manuel ».
14. Page — Imports
Route /imports · Titre « Imports » · pas de PeriodSelector.
14.1 Zone d'upload (carte principale)
- Drag & drop pleine largeur : pointillés
border, icôneupload-cloud, texte : « Glissez un fichier ici ou cliquez pour parcourir » · sous-texte : « CSV, OFX, XLSX ou ZIP — 20 Mo max ». Multi-fichiers accepté (file d'attente). - Choix du profil de source (select, avec auto-détection : le parseur tente de reconnaître en-têtes/format et pré-sélectionne, badge « détecté automatiquement ») :
Health Connect — export (zip/csv)— pas, poids, distance, kcal actives, séancesFoodvisor — export— journal alimentaireFitShow — export— séances tapisRelevé bancaire — CSV générique(avec étape de mappage)Relevé bancaire — OFXPayPal — activité (CSV)Pesées — CSV générique(date; poids[; note])Vape — CSV générique(date; ml[; mg/ml])
- Flux en 3 étapes (stepper « 1. Fichier → 2. Vérification → 3. Import ») :
- Fichier : upload + profil (+ pour les profils bancaires : select Compte de destination, avec « Créer un compte… » inline).
- Vérification : pour le CSV générique, écran de mappage de colonnes (aperçu des 5 premières lignes ; pour chaque colonne cible — Date, Libellé, Montant (ou Débit/Crédit séparés), etc. — un select de colonne source ; format de date détecté ; option « ignorer la première ligne ») ; le mappage est mémorisé par profil+banque. Puis aperçu : table des 20 premières lignes normalisées + bandeau : « 254 lignes lues · 12 doublons ignorés (déjà importés) · 2 lignes en erreur ».
- Import : barre de progression, puis récapitulatif.
- Déduplication : hash par ligne normalisée (source + date + montant + libellé, ou date+valeur pour les mesures) — les ré-imports du même fichier sont sans effet (idempotent).
14.2 Table « Historique des imports »
Colonnes : Date (13/08/2026 19:32) · Fichier (nom + taille) · Profil (badge) · Lignes (254) · Importées (240 en vert) · Doublons (12 en muted) · Erreurs (2 — badge rouge cliquable) · Statut (Terminé vert / Partiel jaune / Échec rouge / Annulé muted) · actions : « Détails », « Annuler cet import » (rollback : supprime les lignes créées par cet import, avec confirmation « Cette action supprimera les 240 entrées créées par cet import. »).
14.3 Panneau « Erreurs » (détail d'un import)
Ouvert depuis la table : liste des lignes en erreur — N° de ligne · Contenu brut (mono, tronqué) · Motif en français (« Date invalide : "31/02/2026" », « Montant illisible : "12,3O" », « Colonne "Poids" absente »). Bouton « Télécharger le rapport d'erreurs (CSV) ».
14.4 Carte « Connecteurs & API »
Rappel : « Votre téléphone peut envoyer les données Health Connect automatiquement via l'application compagnon. » + statut de la dernière synchronisation (Dernière réception : 13/08/2026 07:12 · 4 types de données) + bouton « Gérer les clés d'appareil » → Réglages §15.6.
15. Page — Réglages
Route /reglages · Titre « Réglages » · navigation par onglets verticaux (desktop) / accordéon (mobile) : Profil · Objectif · Nutrition · Vape · Finances · Appareils & API · Application. Chaque onglet = cartes de formulaires avec bouton « Enregistrer » par carte (toast de confirmation).
15.1 Onglet « Profil » (profil corporel)
- Prénom / pseudonyme (affichage) · Sexe (radio : Homme / Femme — utilisé pour le BMR) · Date de naissance (datepicker) · Taille (cm).
- Niveau d'activité (select avec descriptions) :
Sédentaire (×1,2)·Légèrement actif (×1,375)·Modérément actif (×1,55)·Très actif (×1,725)·Extrêmement actif (×1,9). - Mode de calcul du TDEE (radio) : « Facteur d'activité (recommandé au départ) » / « BMR + calories actives mesurées » / « Valeur manuelle : ___ kcal/j » (renseignée aussi par la calibration §11.3).
- Encart calculé en direct :
BMR : 1 780 kcal · TDEE estimé : 2 350 kcal/j.
15.2 Onglet « Objectif »
- Poids de départ (pré-rempli : première pesée) et date de départ.
- Poids cible (kg) · Rythme visé (slider
0,25 — 1,0 kg/semaine, graduations 0,25 · repère « recommandé : 0,5 ») ; - Lignes calculées en direct :
Déficit quotidien nécessaire : ≈ 550 kcal/j·Date d'atteinte estimée : 24/10/2026; - Alternative : saisir une date cible → le rythme et le déficit se recalculent (les trois champs sont liés, le dernier modifié gagne).
- Garde-fou : si le budget résultant < 1 200 kcal/j (femme) / 1 500 (homme) : avertissement jaune « Ce rythme impose un budget très bas. Envisagez un objectif plus progressif. »
15.3 Onglet « Nutrition »
- Budget calorique (radio) : « Automatique : TDEE − déficit (1 800 kcal/j actuellement) » / « Manuel : ___ kcal/j ».
- Objectifs de macros : Protéines (
g/kg de poids— défaut 1,6 — ou g fixes), Glucides / Lipides en % des kcal restantes (deux sliders liés). - Repas : liste réordonnable des repas du journal (défaut : Petit-déjeuner, Déjeuner, Dîner, Collations) — renommage possible.
- Objectif de pas (utilisé page Activité) : défaut
10 000.
15.4 Onglet « Vape »
Carte « Référence tabac (avant l'arrêt) » :
- Date d'arrêt du tabac (datepicker — ancre des économies et jalons) · Cigarettes par jour (défaut 15) · Cigarettes par paquet (défaut 20) · Prix du paquet (€) (défaut 12,50) — ligne calculée :
Coût tabac de référence : 9,38 €/j.
Carte « Modèle de coût DIY » :
- Base PG/VG : prix (€) + contenance (ml) →
€/mlcalculé. - Booster de nicotine : prix du flacon (€), contenance (ml, défaut 10), concentration (mg/ml, défaut 20).
- Taux de nicotine cible (mg/ml) de la préparation (défaut 3,0) → part booster calculée.
- Arôme : prix (€), contenance (ml), dosage ( %) (défaut 10 %).
- Résistances : prix unitaire (€) (+ prix du pack et nombre, au choix).
- Contenance de flacon par défaut (ml) pour le quick-add recharge (défaut 10).
- Encart calculé :
Coût de revient : 0,28 €/ml · avec résistances : ≈ 0,62 €/j au rythme actuel. - Objectif de réduction (optionnel) :
ml/jour viséset/outaux nicotine visé→ matérialisés en markLine sur G1/G2 de la page Vape.
15.5 Onglet « Finances »
Quatre cartes :
- Comptes — table CRUD :
Nom(« Compte courant ») ·Type(Courant / Épargne / PayPal / Espèces / Autre) ·Banque·Solde initial+Date du solde initial·Devise(EUR fixe v1) · actions ✎ 🗑 (suppression bloquée si transactions liées — proposer l'archivage). - Catégories — liste hiérarchique (2 niveaux max) : pastille couleur (slot proposé automatiquement, modifiable parmi les 8), icône (picker), nom ; catégories par défaut livrées : Alimentation, Logement, Transports, Santé, Loisirs, Abonnements, Restaurants, Shopping, Vape/Tabac, Épargne, Revenus (type revenu), Autres. Drag pour réordonner.
- Règles de catégorisation — table :
Priorité(drag & drop, la première règle qui matche gagne) ·Condition(résumé lisible : « Libellé contient "CARREFOUR" ») ·Catégorie·Nb de transactions touchées· actif (switch) · actions ✎ 🗑. Bouton « Tester les règles » : ré-exécute sur les non-catégorisées (aperçu avant application). - Budgets mensuels — table : catégorie · montant €/mois (input inline) · switch « reporter le non-dépensé » (v2, désactivé) ; ligne de total.
15.6 Onglet « Appareils & API »
- Texte d'intro : « Créez une clé pour permettre à l'application compagnon Android (Health Connect) d'envoyer ses données à LifeTrack. »
- Table des clés :
Nom(« Pixel de Julien ») ·Préfixe(ltk_a3f4…) ·Portées(badges :health:write,weight:write…) ·Créée le·Dernière utilisation(« il y a 2 h » — vert si < 24 h) · actions : 🗑 « Révoquer » (confirmation). - Bouton « Créer une clé » → modale : Nom, portées (checkboxes), puis écran d'affichage unique de la clé complète avec bouton copier + avertissement « Cette clé ne sera plus jamais affichée. »
- Encart développeur repliable : méthode + URL du endpoint d'ingestion (
POST /api/v1/ingest), en-têteAuthorization: Bearer <clé>, exemple de payload JSON minimal. - Journal de synchronisation : 20 dernières réceptions (date, appareil, types de données, nb d'enregistrements, statut).
15.7 Onglet « Application »
- Thème : Sombre (défaut) / Clair / Automatique. · Langue : Français (v1). · Fuseau horaire : Europe/Paris (info, non modifiable v1). · Premier jour de la semaine : Lundi.
- Accessibilité : switch « Motifs et textures sur les graphiques » (active les textures ECharts
decalpour daltonisme/impression). - Sauvegarde : « Exporter toutes mes données (JSON) » · « Exporter (CSV par module, ZIP) ».
- Zone dangereuse (bordure rouge) : « Vider un module… » (select module + confirmation par saisie du mot SUPPRIMER) · « Supprimer le compte ».
- Utilisateurs (préparation multi-utilisateur) : table des utilisateurs (v1 : le seul admin) + bouton « Inviter » désactivé avec badge « bientôt ».
15.8 Assistant de premier lancement (first-run wizard)
Plein écran, 4 étapes, jamais bloquant (« Passer » partout sauf étape 1) :
- « Créez votre compte administrateur » — e-mail, mot de passe (×2, jauge de robustesse).
- « Votre profil » — sexe, naissance, taille, poids actuel, niveau d'activité (§15.1).
- « Votre objectif » — poids cible + rythme (§15.2), affichage immédiat du budget kcal.
- « Vos modules » — 3 cartes activables : Vape (si activée → mini-formulaire baseline tabac §15.4), Finances (créer le premier compte), Import (lien vers
/imports). Bouton final : « C'est parti → » (vers le tableau de bord).
16. États vides
Chaque page/section a un EmptyState (§5.4) avec ce texte exact :
| Contexte | Titre | Texte | Actions |
|---|---|---|---|
| Tableau de bord (tout vide) | « Bienvenue sur LifeTrack 👋 » | « Configurez votre profil et importez vos premières données pour voir vos tableaux de bord prendre vie. » | « Configurer mon profil » · « Importer des données » |
| Poids | « Aucune pesée pour l'instant » | « Ajoutez votre première pesée ou importez un historique — la tendance et les projections apparaîtront dès 3 pesées. » | « + Ajouter une pesée » · « Importer un CSV » |
| Nutrition (journal du jour) | « Rien dans le journal aujourd'hui » | « Ajoutez votre premier aliment ou importez votre historique Foodvisor depuis la page Imports. » | « + Ajouter un aliment » · « Importer Foodvisor » |
| Activité | « Aucune activité enregistrée » | « Connectez l'application compagnon Health Connect, importez un export FitShow, ou saisissez une séance manuellement. » | « + Ajouter une séance » · « Voir les imports » |
| Balance énergétique | « Il manque des données » | « La balance énergétique a besoin de vos pesées et de votre journal alimentaire. Complétez ces deux modules pour débloquer cette page. » | « Aller à Poids » · « Aller à Nutrition » |
| Vape | « Module vape non configuré » | « Renseignez votre consommation de cigarettes avant l'arrêt et votre modèle de coût : LifeTrack calculera vos économies au centime près. » | « Configurer la vape » |
| Vape (configurée, sans données) | « Aucune recharge enregistrée » | « Enregistrez votre première recharge d'e-liquide — deux clics suffisent. » | « + Recharge » |
| Finances | « Aucune transaction » | « Importez un relevé bancaire (CSV ou OFX) ou un export PayPal pour démarrer. La catégorisation automatique fera le tri. » | « Importer un relevé » |
| Finances → Récurrents | « Pas encore de récurrents détectés » | « La détection a besoin d'au moins 3 mois de transactions pour repérer vos abonnements et charges fixes. » | — |
| Imports (historique) | « Aucun import pour l'instant » | « Déposez un fichier ci-dessus : LifeTrack détecte le format et vous montre un aperçu avant d'importer quoi que ce soit. » | — |
| Table filtrée sans résultat | « Aucun résultat » | « Aucune ligne ne correspond à ces filtres. » | « Réinitialiser les filtres » |
| Graphique sans données sur la période | (dans le canvas) « Pas de données sur cette période » | — | « Élargir la période » (passe à Tout) |
17. Accessibilité
- Palette validée (script de validation CVD — voir §4.4) ; l'ordre des slots ne doit pas être modifié sans re-validation.
- La couleur n'est jamais seule : légendes systématiques dès 2 séries, signes
+/−, icônes de tendance, labels directs sélectifs, badges texte sur les statuts. - « Voir les données » sur chaque ChartCard = équivalent tabulaire complet (triable, exportable CSV).
- Option « Motifs et textures » (§15.7) : applique des hachures
decalà 45°/135° sur les séries des graphiques empilés et miroirs. - Navigation clavier complète : sidebar et tabs focusables, modales avec focus trap,
Escferme, tables navigables aux flèches. - Contrastes : textes ≥ 4,5:1 sur
surface; les 8 slots de série ≥ 3:1 sur#1A1A19. prefers-reduced-motion: désactive l'animation des graphiques et le compteur odometer (affichage direct).- Tooltips ECharts doublés d'un
aria-labeldescriptif par graphique (« Graphique en ligne : évolution du poids du 15/05 au 13/08, de 85,1 à 82,4 kg »).
Fin de la spécification UX. Toute divergence d'implémentation doit être signalée et arbitrée contre ce document.