Application de fitness intelligente : spécifications de l'architecture client
ArtefactIl s'agit de l'artefact utilisé dans l'épisode 3 : "Donnez un cerveau à votre application" et l'épisode 4 : "Plan d'implémentation d'une application sans code". Vous pouvez utiliser cette spécification comme référence pour les vues d'interface, les composants d'interface utilisateur réutilisables, la gestion de l'état du client et les scénarios de test en langage naturel.
Connectez-vous pour accéder à cet artefact
Connectez-vous avec votre profil de développeur Google pour afficher et copier l'artefact complet utilisé dans la série Build It!.
Profil de développeur requis
Vous n'êtes pas éligible à un profil de développeur. Demandez à votre administrateur Workspace d'activer cette fonctionnalité.
Créer un profil de développeur
Créez un profil de développeur Google sans frais pour débloquer tous les prompts et artefacts Build It!.
Rejoignez Builder Central pour débloquer
Récupérez votre badge de membre Builder sans frais en un clic pour débloquer tous les prompts et artefacts Build It!.
État : prêt pour la session de planification (rédaction avec le compagnon de planification client)
Document d'accompagnement : Spécifications de l'architecture de données
Objectif de l'architecture : refonte propre, gérable, modulaire et testable de l'interface du prototype de fitness intelligent d'AI Studio.
0. Pile technique de base et normes d'ingénierie
- Framework d'exécution : Next.js (App Router, React 19) + mise en cache des éléments hors connexion de la progressive web app (PWA).
- Architecture de style : Tailwind CSS v4 + Tailwind Variants (pour le style de composant déterministe) + Lucide React (icônes).
- Division de l'État du client :
- Zustand (session locale) : gère l'état volatile de la salle de sport (
useActiveSessionStore), les chronomètres, les tampons de séries actives et le séquençage des étapes précalculées. Synchronisé aveclocalStoragepour la récupération du verrouillage du téléphone. - TanStack Query (état du serveur) : gère la mise en cache des documents Firestore, la revalidation en arrière-plan et les mises à jour optimistes pour
weekly_plans,user_profiles,prsetworkout_logs.
- Zustand (session locale) : gère l'état volatile de la salle de sport (
- Visualisation des graphiques : Recharts (avec des jetons personnalisés pour le mode sombre de la salle de sport).
- Authentification : Firebase Authentication avec en-tête d'authentification par jeton de support transmis à tous les points de terminaison du serveur.
1. Principes de conception et d'interface
- Ergonomie pensée pour le sport : conçu pour une utilisation tactile d'une seule main pendant l'entraînement, même avec les mains moites. Cibles tactiles généreuses (minimum 48 x 48 dp), lisibilité à contraste élevé et saisie minimale requise.
- Interface utilisateur optimiste et résilience hors connexion : l'enregistrement des séries, le démarrage des minuteurs de repos et le changement d'exercice doivent répondre instantanément (< 16 ms) dans l'interface utilisateur. La synchronisation en arrière-plan gère la persistance du serveur vers
POST /api/workouts/logsans bloquer l'utilisateur. - Séparation stricte des responsabilités : les composants de présentation/"dumb" reçoivent des données et émettent des événements à l'aide de propriétés. Les vues de conteneur "smart" gèrent la logique métier, les magasins d'état et la coordination des API.
- UX de mutation par étapes : les propositions générées par le coach IA (
POST /api/coach/chat) s'affichent sous forme de fiches d'aperçu interactives par étapes avec des commandes explicites [Accepter le plan] et [Modifier] avant de valider les modifications de l'état de l'application. - Qualité basée sur le comportement : chaque page, composant et interaction est associé à des scénarios de test en anglais simple qui définissent sans ambiguïté le comportement attendu.
2. Navigation dans l'application et hiérarchie des vues
| Chemin de l'itinéraire | Nom de la vue | Objet principal | Composants clés inclus |
|---|---|---|---|
/ |
Redirection racine | Redirection instantanée vers /today. |
(Router redirect) |
/today |
Aperçu de l'entraînement du jour | Vue par défaut. Résolution automatique vers le jour de la semaine actuel et affichage de l'aperçu de l'entraînement du jour. | <BackButton />, <WorkoutHeader />, <CoachNoteCard />, <WorkoutExerciseSummary />, <WorkoutBlock />, <ExerciseCard />, <EmptyDayPlaceholder />, <ModifyWithCoachCard /> |
/workouts/:day |
Aperçu de l'entraînement quotidien | Affiche un aperçu de l'entraînement pour un jour spécifique de la semaine (par exemple, /workouts/monday, /workouts/thursday). |
<BackButton />, <WorkoutHeader />, <CoachNoteCard />, <WorkoutExerciseSummary />, <WorkoutBlock />, <ExerciseCard />, <EmptyDayPlaceholder />, <ModifyWithCoachCard /> |
/workout/active |
Suivi des sessions actives | Écran d'exécution d'un entraînement à enjeux élevés (séries, répétitions, minuteur). La barre de navigation inférieure reste visible. | <ActiveSessionStickyHeader />, <ActiveExerciseCardHeader />, <CoachTipCard />, <CurrentSetTargetCard />, <SetNavigationRow />, <ExerciseSetsTable />, <ActiveRestTimerDock />, <SessionExerciseOverview />, <ActiveSessionControlsDock />, <SwapExerciseModal />, <FinishConfirmationModal /> |
/week |
Planning d'entraînement/Vue "Semaine" | Aperçu complet du planning sur 7 jours avec agrégats hebdomadaires de volume/temps. | <WeekHeader />, <WeeklyStatsSummary />, <DayScheduleCardList />, <DayScheduleCard />, <ModifyWeekWithCoachCard /> |
/coach |
Chat avec le coach IA | Coaching conversationnel avec des chips contextuels et des propositions d'entraînement par étapes. | <CoachHeader />, <ChatMessageList />, <ChatBubble />, <StagedProposalCard />, <ContextualPromptsBar />, <ChatInputDock />, <ContextBanner />, <ChatInputBar />, <SpeechToTextButton /> |
/progress |
Progression et analyses | Journaux d'entraînement historiques, records personnels et graphiques de volume. | <ProgressHeader />, <PRShowcaseBanner />, <VolumeProgressChartCard />, <AllTimeStatsGrid />, <WorkoutHistorySection />, <HistorySessionCard />, <EmptyHistoryPlaceholder /> |
/settings |
Profil utilisateur et préférences | Profil d'équipement, notifications et gestion de la mémoire à trois niveaux. | <SettingsHeader />, <UserProfileCard />, <EquipmentSelectorCard />, <EquipmentToggleChip />, <PreferencesGroup />, <MemoryTierViewerCard />, <MemoryItemCard />, <AccountActionsGroup /> |
/exercises/:exerciseId |
Détails de l'encyclopédie des exercices | Guide d'exercices avec liens profonds (par exemple, /exercises/incline-db-bench-press) avec des conseils vidéo et de posture. |
<BackButton />, <ExerciseVideoPlayer />, <TargetMusclesCard />, <HowToPerformCard />, <FormTipsCard /> |
3. Spécifications des pages et des vues
Afficher : DailyWorkoutView (/today et /workouts/:day)
- Objectif : affiche le programme d'entraînement prévu pour un jour spécifique (y compris l'objectif de l'entraînement, la durée, la répartition de la charge musculaire cible, les notes du coach, les blocs de séries simples et les blocs de superséries), avec un état vide propre lorsque aucun entraînement n'est prévu.
- Anatomie visuelle :
- Haut :
<BackButton label="Back to Week" targetRoute="/week" />. - En-tête : titre sur une seule ligne (
"Today"ou jour de la semaine) avec badge"✓ Completed"conditionnel, pastille de durée ("⏱ 50 min") et barres de pourcentage d'intensité musculaire cible. - Note du coach : fiche de conseils contextuels avec icône et bordure verte.
- Corps : liste déroulante de blocs d'exercices utilisant
<WorkoutExerciseSummary />(séries simples ou supersets avec badgeborder-left: 3px solid #a3e635et🔁 SUPERSET BLOCK). - État vide :
<EmptyDayPlaceholder message="Nothing scheduled for this day" />. - Action du pied de page inférieur :
<ModifyWithCoachCard />(redirige vers/coach?day=:day).
- Haut :
Afficher : WeekScheduleView (/week)
- Objectif : affiche un aperçu complet du programme d'entraînement sur 7 jours, y compris des métriques générales sur le volume/la durée hebdomadaires, une liste de jours d'entraînement actifs (en excluant strictement les jours de repos/non programmés) et un raccourci direct pour modifier le programme hebdomadaire avec le coach IA.
- Anatomie visuelle :
<WeekHeader />,<WeeklyStatsSummary />à trois colonnes (Temps total, Volume total, Fréquence), liste des jours programmés à l'aide de<DayScheduleCard variant="normal" />(avec un badgeTODAYvert fluo sur le jour actuel) et<ModifyWeekWithCoachCard />(redirige vers/coach?context=week).
Afficher : CoachChatView (/coach)
- Objectif : Hub de coaching conversationnel avec l'agent d'entraînement Gemini. Fournit des conseils d'entraînement motivants et stratégiques, prend en charge la reconnaissance vocale et propose des ajustements d'entraînement par étapes avec intervention humaine et des commandes d'acceptation explicites.
- Anatomie visuelle :
<CoachHeader />,<ChatMessageList />à faire défiler (<ChatBubble />et<StagedProposalCard />),<ContextualPromptsBar />conditionnel et<ChatInputDock />ancré (<ContextBanner />avec[✕]pour ignorer +<ChatInputBar />+<SpeechToTextButton />).
Afficher : ExerciseDetailView (/exercises/:exerciseId)
- Objectif : entrée d'encyclopédie accessible par lien profond, proposant une démonstration vidéo en boucle automatique sans son (
<ExerciseVideoPlayer />), des badges pour les muscles cibles principaux et secondaires (<TargetMusclesCard />), des instructions d'exécution étape par étape (<HowToPerformCard />) et des conseils de posture (<FormTipsCard />).
Afficher : ActiveWorkoutView (/workout/active)
- Objectif : écran d'exécution d'entraînement et d'enregistrement des séries à enjeux élevés. Gère l'état du chronomètre de la session en direct, les objectifs définis actuels, les entrées de répétitions/poids, la validation instantanée (< 16 ms), l'alternance automatique des supersets, les comptes à rebours du minuteur de repos avec retour haptique/audio, l'échange d'exercices et la persistance finale dans
POST /api/workouts/log. - Anatomie visuelle :
<ActiveSessionStickyHeader />,<ActiveExerciseCardHeader />,<CoachTipCard />,<CurrentSetTargetCard />,<ActiveRestTimerDock />flottant (+30s,Skip),<SetNavigationRow />,<ExerciseSetsTable />(+ Add Set),<SessionExerciseOverview />,<ActiveSessionControlsDock />ancré ([⇄ SWAP EXERCISE]+[▶ START WORKOUT]/[⏸ PAUSE]/[▶ RESUME]),<SwapExerciseModal />et<FinishConfirmationModal />.
Afficher : ProgressView (/progress)
- Objectif : suivre la progression athlétique au fil du temps, célébrer les records personnels récents (
<PRShowcaseBanner />), visualiser les tendances de volume hebdomadaires/mensuelles avec des Recharts interactifs (<VolumeProgressChartCard />avec des boutons4W | 3M | 1Y), afficher<AllTimeStatsGrid />et archiver les séances d'entraînement terminées (<WorkoutHistorySection />/<HistorySessionCard />).
Afficher : SettingsView (/settings)
- Objectif : gère les informations du profil de l'athlète (
<UserProfileCard />), l'inventaire de l'équipement (<EquipmentSelectorCard />/<EquipmentToggleChip />), les préférences d'entraînement (<PreferencesGroup />pourLBS / KG, les retours haptiques, le son) et fournit une gestion transparente des utilisateurs et la suppression de la mémoire vive à trois niveaux de l'entraîneur IA (<MemoryTierViewerCard />/<MemoryItemCard />).
4. Catalogue et interfaces de composants réutilisables
Contrats de propriétés des composants TypeScript clés dans l'application :
// src/components/workout/WorkoutExerciseSummary.tsx
interface WorkoutExerciseSummaryProps {
blocks: Array<{
label?: string;
category?: string;
exercises: Array<{
exercise_id: string; // Canonical slug (e.g. 'incline-db-bench-press')
name: string; // Denormalized display name (e.g. 'Incline DB Bench Press')
target_sets: number;
target_reps: string | number;
rest_seconds?: number;
}>;
}>;
activeExerciseId?: string;
onSelectExercise?: (exerciseId: string) => void;
}
// src/components/week/DayScheduleCard.tsx
interface DayScheduleCardProps {
dayName: string;
dayShort: string;
subtitleLabel?: string;
isToday?: boolean;
title: string;
focusBadge: string;
durationMin: number;
volumeLbs?: number;
targetMuscles: string[];
variant?: 'normal' | 'condensed';
onPress: (dayName: string) => void;
}
// src/components/coach/StagedProposalCard.tsx
interface StagedProposalCardProps {
proposalId: string;
type: 'UPDATE_DAY' | 'UPDATE_WEEK';
targetDay?: string;
summaryDiff: string;
proposalData: any;
isApplied?: boolean;
onAccept: (proposalId: string, data: any) => void;
onModify: (summaryDiff: string) => void;
}
// src/components/workout/CurrentSetTargetCard.tsx
interface CurrentSetTargetCardProps {
setNumber: number;
targetWeightLbs: number;
targetReps: number;
isCompleted: boolean;
onWeightChange: (weight: number) => void;
onRepsChange: (reps: number) => void;
onToggleComplete: () => void;
}5. Matrice de gestion de l'état du client et de flux de données
5.1 Règle sur la latence et le chargement : le moteur à deux vitesses
- UI optimiste pour la salle de sport (< 16 ms) : les actions tactiles effectuées à la salle de sport (cocher des séries, augmenter les poids/répétitions, changer d'onglet et changer d'équipement) mettent à jour l'état local et s'affichent à nouveau en moins de 16 millisecondes. Les utilisateurs ne sont jamais bloqués par des indicateurs de chargement lorsqu'ils tiennent des poids.
- Indicateurs de chargement explicites pour les opérations asynchrones :
- Conversations avec le coach IA (
POST /api/coach/chat) : l'envoi d'un message de chat affiche immédiatement une bulle animée avec un indicateur de chargement indiquant que le coach réfléchit dans le flux de chat jusqu'à ce que Gemini renvoie sa réponse ou sa proposition d'entraînement. - Démarrage à froid initial et synchronisation réseau : les conteneurs de vue affichent des squelettes de chargement et des icônes de chargement à contraste élevé lors de la récupération de
weekly_plansouhistorical_workouts. - Envoi de l'entraînement (
[Finish]) : la fenêtre modale de confirmation de fin affiche un indicateur de chargement actif pendant que la charge utile de la session est enregistrée dansPOST /api/workouts/logdans Cloud Firestore.
- Conversations avec le coach IA (
5.2 Architecture du magasin client et limites du domaine
| Calque des magasins | Domaine d'état et propriétés clés | Persistance et stratégie de cache | Contrat de backend coordonné |
|---|---|---|---|
useActiveSessionStore (Zustand) |
sessionState (unstarted, running, paused), elapsedSeconds, currentStepIndex, steps: WorkoutStep[], loggedExercises. |
Synchronisé avec localStorage toutes les secondes pour une récupération infaillible en cas de verrouillage/actualisation du téléphone. |
Envoie la charge utile terminée à POST /api/workouts/log. |
useWeeklyPlanQuery (TanStack Query) |
Programme actuel sur sept jours, objets d'entraînement quotidien, blocs de supersets, états d'achèvement (scheduled, completed). |
Mise en cache dans TanStack Query (staleTime: 5 min) ; préchargement au lancement. |
Enregistré lorsque l'utilisateur appuie sur [Accept Plan] pour les propositions de POST /api/coach/chat. |
useCoachChatStore (Zustand + TanStack) |
Bulles de message chronologiques, activeContext, chips de prompt, isCoachTyping: boolean, propositions par étapes. |
Synchronisé avec le bucket de chat hebdomadaire Firestore à l'aide de l'abonnement en temps réel (onSnapshot). |
Envoie des requêtes à POST /api/coach/chat. |
useProgressQuery (TanStack Query) |
Archive des entraînements historiques, tableau des records personnels (/users/{userId}/prs), agrégats de volume de tous les temps, filtre de période (4W, 3M, 1Y). |
Mise en cache dans TanStack Query (staleTime: 10 min). |
Mis à jour immédiatement après la fin d'une séance d'entraînement. |
useUserProfileStore (TanStack Query) |
Inventaire de l'équipement, unités (LBS/KG), boutons d'activation/désactivation du son et du retour haptique, mémoire vive à trois niveaux (essentiels, physiologiques, situationnels). |
Mise en cache dans TanStack Query avec synchronisation bidirectionnelle vers Firestore user_profiles. |
Mise à jour autonome à l'aide de memory_mutations de POST /api/coach/chat. |
useExerciseLibraryQuery (TanStack Query) |
Entrées d'encyclopédie statiques, URL de vidéos, muscles principaux/secondaires, étapes, conseils de forme. | Mise en cache agressive avec une valeur TTL infinie (staleTime: Infinity). |
Lecture seule à partir de la collection Firestore immuable exercises. |
5.3 Graphique des étapes de session active précalculées
export interface WorkoutStep {
stepIndex: number; // 1-based index (e.g. 1 to 13)
totalSteps: number; // Total sets in the session
blockIndex: number; // Index of block in day plan
blockType: 'straight' | 'superset';
exerciseId: string; // Canonical slug
exerciseName: string; // Display name
setNumber: number; // Set index for this exercise (1, 2, 3...)
targetWeightLbs: number; // Target weight in lbs
targetReps: string | number; // Target reps (e.g. "8-10")
restSecondsAfter: number; // Prescribed rest duration
isCompleted: boolean; // Completion checkmark status
actualWeightLbs?: number; // User entered weight
actualRepsCompleted?: number; // User entered reps
}5.4 Flux de données de bout en bout et matrice de mutation
| Déclencheur utilisateur | Vue d'origine | Magasin client modifié | Latence de l'UI/État de chargement | Coordination du backend | Rollback/Gestion des échecs |
|---|---|---|---|---|---|
Appuyez sur [✓] Série terminée. |
/workout/active |
useActiveSessionStore |
<16ms (optimiste) |
Le tampon de session local a été mis à jour. Aucune attente réseau. | Écriture en mémoire locale avec persistance locale fiable. |
Appuyez sur [Finish Workout] |
/workout/active |
useActiveSessionStore, useWeeklyPlanStore, useProgressStore |
Le bouton affiche une icône de chargement pendant la synchronisation | Envoie à POST /api/workouts/log. Marque le jour Firestore comme completed. |
Si l'appareil est hors connexion, la charge utile est mise en file d'attente dans le tampon de synchronisation local et une nouvelle tentative est effectuée lors de la reconnexion. |
Appuyez sur [Accept Plan] |
/coach |
useWeeklyPlanStore, useCoachChatStore |
Sticker d'UI instantanée ("✓ Plan Applied") |
Valide proposal.data dans Firestore weekly_plans. |
En cas de défaillance du réseau, une notification toast alerte l'utilisateur, et les boutons restent actifs pour réessayer. |
| Envoyer un message dans Chat | /coach |
useCoachChatStore, useUserProfileStore |
Ajout d'une bulle optimiste + icône de chargement de réflexion du coach | Il appelle POST /api/coach/chat. Les commits ont renvoyé memory_mutations. |
Remplace l'icône de chargement par "Échec de l'envoi. Appuyez pour réessayer". |
| Activer/Désactiver le chip d'équipement | /settings |
useUserProfileStore |
Bouton d'activation/désactivation instantané (<16ms) |
Envoie l'écriture en arrière-plan vers Firestore user_profiles. |
Annule la sélection du chip et affiche un message d'erreur en cas d'échec de l'écriture. |
Supprimer l'élément de mémoire IA [🗑] |
/settings |
useUserProfileStore |
Suppression instantanée (<16ms) |
Envoie une mutation de suppression à Firestore user_profiles. |
Restaure l'élément de mémoire et alerte l'utilisateur en cas d'échec de la suppression. |
6. Parcours utilisateur de bout en bout et matrice de test en langage naturel
- Suite 1 : App Shell, navigation et gestion des routes (tests 1.1 à 1.6 : redirection du lancement racine, dock persistant, retour rapide à la session active, remplacement en cas de jour de la semaine non valide, remplacement en cas de route 404 inconnue, remplacement en cas de lien profond d'exercice non valide).
- Suite 2 : Vue de l'entraînement quotidien et rendu des blocs (tests 2.1 à 2.7 : résolution dynamique du titre du jour, itinéraire et bouton Retour pour un jour spécifique, traitement des blocs simples par rapport aux super-ensembles, espace réservé pour les jours vides, tampon d'entraînement terminé, navigation pure sur le bouton de lecture central, modification avec l'ajout du contexte du coach).
- Suite 3 : Vue "Planning de la semaine" et fiche "Planning du jour" (tests 3.1 à 3.6 : affichage des statistiques hebdomadaires, filtre "Jours programmés uniquement", accroche visuelle "Aujourd'hui", navigation dans la fiche "Jour", modification de la navigation dans la semaine, affichage de la variante condensée).
- Suite 4 : Coach Chat & Staged Mutation (tests 4.1 à 4.7 : rendu du flux de messages de chat, ajout et suppression de la bannière de contexte, préremplissage des chips de prompt, activation/désactivation de la dictée vocale, isolation des mutations par étapes, acceptation et commit de la proposition, aperçu et commit de la proposition de refonte hebdomadaire).
- Suite 5 : Détails de l'exercice et encyclopédie (tests 5.1 à 5.5 : rendu des détails de l'exercice, lecture en boucle automatique sans son, bouton de pause de la vidéo, tags des muscles principaux et secondaires, retour en arrière et remplacement).
- Suite 6 : Suivi et enregistrement des entraînements actifs (tests 6.1 à 6.7 : état initial non démarré et démarrage manuel, mise en pause et reprise du chronomètre, enregistrement tactile des séries et activation/désactivation de la coche, alternance des étapes de superset, modal de changement d'exercice et remplacement, confirmation de fin et synchronisation avec le serveur, récupération de l'état de la session lors de l'actualisation).
- Suite 7 : Analyses de la progression et de l'historique (tests 7.1 à 7.5 : rendu de la vue d'ensemble du tableau de bord de progression, affichage de la bannière de présentation des records personnels, bouton d'activation/de désactivation de la période du graphique, état de l'historique vide, appui sur l'historique des sessions passées).
- Suite 8 : Paramètres utilisateur, Équipement et Mémoire de l'IA (tests 8.1 à 8.4 : rendu de la vue des paramètres, mise à jour du bouton d'activation/désactivation de l'équipement, changement d'unités, suppression d'éléments de la mémoire de l'IA).