Smart Fitness App: Client Architecture Spec
ArtifactThis is the artifact used in Episode 3: Give Your App a Brain and Episode 4: The No-Code App Implementation Plan. You can use this specification as a reference for frontend views, reusable UI components, client state management, and plain-English test cases.
Sign in to access this artifact
Sign in with your Google Developer Profile to view and copy the full artifact used in the Build It! series.
Developer Profile Required
You are not eligible for a developer profile. Notify your workspace administrator to enable this feature.
Create a Developer Profile
Create a free Google Developer Profile to unlock all Build It! prompts and artifacts.
Join Builder Central to Unlock
Claim your free Builder member badge in one click to unlock all Build It! prompts and artifacts.
Status: Ready for Planning Session (Drafting with Client Planning Companion)
Companion Document: Data Architecture Spec
Architecture Goal: Clean, maintainable, modular, and testable frontend rebuild of the AI Studio smart fitness prototype.
0. Core Technical Stack & Engineering Standards
- Runtime Framework: Next.js (App Router, React 19) + Progressive Web App (PWA) offline asset caching.
- Styling Architecture: Tailwind CSS v4 + Tailwind Variants (for deterministic component styling) + Lucide React (icons).
- Client State Division:
- Zustand (Local Session): Manages volatile gym-floor state (
useActiveSessionStore), stopwatch timers, active set buffers, and pre-computed step sequencing. Synced tolocalStoragefor phone-lock recovery. - TanStack Query (Server State): Manages Firestore document caching, background revalidation, and optimistic updates for
weekly_plans,user_profiles,prs, andworkout_logs.
- Zustand (Local Session): Manages volatile gym-floor state (
- Chart Visualization: Recharts (styled with custom dark gym-mode tokens).
- Authentication: Firebase Authentication with Bearer token authentication header passed to all server endpoints.
1. Frontend Tenets & Design Principles
- Gym-First Ergonomics: Designed for tactile, one-handed operation mid-workout with sweaty hands. Generous tap targets (minimum 48x48dp), high-contrast legibility, and minimal required typing.
- Optimistic UI & Offline Resilience: Logging sets, starting rest timers, and swapping exercises must respond instantly (<16ms) in the UI. Background sync handles server persistence to
POST /api/workouts/logwithout blocking the user. - Strict Separation of Concerns: Dumb/Presentational components receive data and emit events using props; smart container views manage business logic, state stores, and API coordination.
- Staged Mutation UX: Proposals generated by the AI Coach (
POST /api/coach/chat) render as interactive staged preview cards with explicit [Accept Plan] and [Modify] controls before committing changes to application state. - Behavior-Driven Quality: Every page, component, and interaction is paired with plain-English test cases that unambiguously define expected behavior.
2. Application Navigation & View Hierarchy
| Route Path | View Name | Primary Purpose | Key Components Contained |
|---|---|---|---|
/ |
Root Redirect | Instant redirect to /today. |
(Router redirect) |
/today |
Today's Workout Preview | Default view. Automatically resolves to current day of week and displays today's workout preview. | <BackButton />, <WorkoutHeader />, <CoachNoteCard />, <WorkoutExerciseSummary />, <WorkoutBlock />, <ExerciseCard />, <EmptyDayPlaceholder />, <ModifyWithCoachCard /> |
/workouts/:day |
Daily Workout Preview | Shows workout preview for any specific day in the week (e.g., /workouts/monday, /workouts/thursday). |
<BackButton />, <WorkoutHeader />, <CoachNoteCard />, <WorkoutExerciseSummary />, <WorkoutBlock />, <ExerciseCard />, <EmptyDayPlaceholder />, <ModifyWithCoachCard /> |
/workout/active |
Active Session Tracker | High-stakes workout execution screen (sets, reps, timer). Bottom nav remains visible. | <ActiveSessionStickyHeader />, <ActiveExerciseCardHeader />, <CoachTipCard />, <CurrentSetTargetCard />, <SetNavigationRow />, <ExerciseSetsTable />, <ActiveRestTimerDock />, <SessionExerciseOverview />, <ActiveSessionControlsDock />, <SwapExerciseModal />, <FinishConfirmationModal /> |
/week |
Training Schedule / Week View | Full 7-day schedule overview with weekly volume/time aggregates. | <WeekHeader />, <WeeklyStatsSummary />, <DayScheduleCardList />, <DayScheduleCard />, <ModifyWeekWithCoachCard /> |
/coach |
AI Coach Chat | Conversational coaching with contextual chips & staged workout proposals. | <CoachHeader />, <ChatMessageList />, <ChatBubble />, <StagedProposalCard />, <ContextualPromptsBar />, <ChatInputDock />, <ContextBanner />, <ChatInputBar />, <SpeechToTextButton /> |
/progress |
Progress & Analytics | Historical training logs, PR achievements, and volume charts. | <ProgressHeader />, <PRShowcaseBanner />, <VolumeProgressChartCard />, <AllTimeStatsGrid />, <WorkoutHistorySection />, <HistorySessionCard />, <EmptyHistoryPlaceholder /> |
/settings |
User Profile & Preferences | Equipment profile, notifications, and 3-tier memory management. | <SettingsHeader />, <UserProfileCard />, <EquipmentSelectorCard />, <EquipmentToggleChip />, <PreferencesGroup />, <MemoryTierViewerCard />, <MemoryItemCard />, <AccountActionsGroup /> |
/exercises/:exerciseId |
Exercise Encyclopedia Detail | Deep-linkable exercise guide (e.g. /exercises/incline-db-bench-press) with video & form tips. |
<BackButton />, <ExerciseVideoPlayer />, <TargetMusclesCard />, <HowToPerformCard />, <FormTipsCard /> |
3. Page & View Specifications
View: DailyWorkoutView (/today & /workouts/:day)
- Purpose: Displays the scheduled training regimen for a specific day—including workout focus, duration, target muscle load distribution, coach notes, straight-set blocks, and superset blocks—with a clean empty state fallback when no workout is scheduled.
- Visual Anatomy:
- Top:
<BackButton label="Back to Week" targetRoute="/week" />. - Header: Single-line Title (
"Today"or day of week) with conditional"✓ Completed"badge, duration pill ("⏱ 50 min"), and target muscle intensity percentage bars. - Coach Note: Contextual advice card with icon and green border tint.
- Body: Scrollable list of exercise blocks using
<WorkoutExerciseSummary />(straight sets or supersets withborder-left: 3px solid #a3e635and🔁 SUPERSET BLOCKbadge). - Empty State:
<EmptyDayPlaceholder message="Nothing scheduled for this day" />. - Bottom Footer Action:
<ModifyWithCoachCard />(routes to/coach?day=:day).
- Top:
View: WeekScheduleView (/week)
- Purpose: Displays the complete 7-day training schedule overview, including high-level weekly volume/time metrics, a curated list of active workout days (strictly filtering out unscheduled/rest days), and a direct shortcut to overhaul the weekly plan with the AI Coach.
- Visual Anatomy:
<WeekHeader />, 3-column<WeeklyStatsSummary />(Total Time, Total Volume, Frequency), list of scheduled days using<DayScheduleCard variant="normal" />(with neon-greenTODAYbadge on current day), and<ModifyWeekWithCoachCard />(routes to/coach?context=week).
View: CoachChatView (/coach)
- Purpose: Conversational coaching hub with the Gemini trainer agent. Delivers motivational and strategic training advice, supports speech-to-text dictation, and renders human-in-the-loop staged workout adjustments with explicit acceptance controls.
- Visual Anatomy:
<CoachHeader />, scrollable<ChatMessageList />(<ChatBubble />and<StagedProposalCard />), conditional<ContextualPromptsBar />, and docked<ChatInputDock />(<ContextBanner />with[✕]dismiss +<ChatInputBar />+<SpeechToTextButton />).
View: ExerciseDetailView (/exercises/:exerciseId)
- Purpose: Deep-linkable encyclopedia entry delivering an auto-looping muted video demonstration (
<ExerciseVideoPlayer />), primary versus secondary target muscle badges (<TargetMusclesCard />), ordered step-by-step performance instructions (<HowToPerformCard />), and form tips (<FormTipsCard />).
View: ActiveWorkoutView (/workout/active)
- Purpose: High-stakes workout execution and set logging screen. Manages live session stopwatch state, current set targets, reps/weight inputs, instantaneous checkmark completion (<16ms), automatic superset alternation, rest timer countdowns with haptics/audio, exercise swapping, and final persistence to
POST /api/workouts/log. - Visual Anatomy:
<ActiveSessionStickyHeader />,<ActiveExerciseCardHeader />,<CoachTipCard />,<CurrentSetTargetCard />, floating<ActiveRestTimerDock />(+30s,Skip),<SetNavigationRow />,<ExerciseSetsTable />(+ Add Set),<SessionExerciseOverview />, docked<ActiveSessionControlsDock />([⇄ SWAP EXERCISE]+[▶ START WORKOUT]/[⏸ PAUSE]/[▶ RESUME]),<SwapExerciseModal />, and<FinishConfirmationModal />.
View: ProgressView (/progress)
- Purpose: Tracks athletic progression over time, celebrates recent Personal Records (
<PRShowcaseBanner />), visualizes weekly/monthly volume trends with interactive Recharts (<VolumeProgressChartCard />with4W | 3M | 1Ytoggles), displays<AllTimeStatsGrid />, and archives past completed workout sessions (<WorkoutHistorySection />/<HistorySessionCard />).
View: SettingsView (/settings)
- Purpose: Manages athlete profile information (
<UserProfileCard />), equipment inventory (<EquipmentSelectorCard />/<EquipmentToggleChip />), workout preferences (<PreferencesGroup />forLBS / KG, haptics, sound), and provides transparent user management and deletion of the AI trainer's 3-Tier Living Memory (<MemoryTierViewerCard />/<MemoryItemCard />).
4. Reusable Component Catalog & Interfaces
Key TypeScript component prop contracts across the 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. Client State Management & Data Flow Matrix
5.1 Latency & Loading Policy: The Two-Speed Engine
- Gym-Floor Optimistic UI (<16ms): Tactile gym-floor actions—checking off sets, incrementing weights/reps, switching tabs, and toggling equipment—update local state and re-render within 16 milliseconds. Users are never blocked by loading indicators while holding weights.
- Explicit Loading Spinners & Indicators for Asynchronous Operations:
- AI Coach Conversations (
POST /api/coach/chat): Submitting a chat message immediately renders an animated Coach Thinking Spinner Bubble in the chat stream until Gemini returns its response or workout proposal. - Initial Cold-Start & Network Sync: View containers display skeleton loaders and high-contrast loading spinners while fetching
weekly_plansorhistorical_workouts. - Workout Submission (
[Finish]): The finish confirmation modal renders an active loading spinner while the session payload is committed toPOST /api/workouts/login Cloud Firestore.
- AI Coach Conversations (
5.2 Client Store Architecture & Domain Boundaries
| Store Layer | State Domain & Key Properties | Persistence & Cache Policy | Coordinated Backend Contract |
|---|---|---|---|
useActiveSessionStore (Zustand) |
sessionState (unstarted, running, paused), elapsedSeconds, currentStepIndex, steps: WorkoutStep[], loggedExercises. |
Synced to localStorage every second for bulletproof phone-lock/refresh recovery. |
Submits completed payload to POST /api/workouts/log. |
useWeeklyPlanQuery (TanStack Query) |
Current 7-day schedule, day workout objects, superset blocks, completion statuses (scheduled, completed). |
Cached in TanStack Query (staleTime: 5 min); pre-fetched on launch. |
Committed upon user tapping [Accept Plan] for proposals from POST /api/coach/chat. |
useCoachChatStore (Zustand + TanStack) |
Chronological message bubbles, activeContext, prompt chips, isCoachTyping: boolean, staged proposals. |
Synced with Firestore weekly chat bucket using real-time subscription (onSnapshot). |
Dispatches queries to POST /api/coach/chat. |
useProgressQuery (TanStack Query) |
Historical workouts archive, PR record board (/users/{userId}/prs), all-time volume aggregates, timeframe filter (4W, 3M, 1Y). |
Cached in TanStack Query (staleTime: 10 min). |
Updated immediately upon completing a workout session. |
useUserProfileStore (TanStack Query) |
Equipment inventory, units (LBS/KG), sound/haptic toggles, 3-tier living memory (Staples, Physiological, Situational). |
Cached in TanStack Query with bi-directional sync to Firestore user_profiles. |
Autonomously updated using memory_mutations from POST /api/coach/chat. |
useExerciseLibraryQuery (TanStack Query) |
Static encyclopedia entries, video URLs, primary/secondary muscles, steps, form tips. | Aggressive cache-first with infinite TTL (staleTime: Infinity). |
Read-only from immutable Firestore exercises collection. |
5.3 Pre-Computed Active Session Step Graph
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 End-to-End Data Flow & Mutation Matrix
| User Trigger | Originating View | Client Store Mutated | UI Latency / Loading State | Backend Coordination | Rollback / Failure Handling |
|---|---|---|---|---|---|
Tap [✓] Complete Set |
/workout/active |
useActiveSessionStore |
<16ms (Optimistic) |
Local session buffer updated; no network wait. | Local memory write with reliable local persistence. |
Tap [Finish Workout] |
/workout/active |
useActiveSessionStore, useWeeklyPlanStore, useProgressStore |
Button displays loading spinner while syncing | Submits to POST /api/workouts/log. Marks Firestore day as completed. |
If offline, queues payload to local sync buffer and retries upon reconnection. |
Tap [Accept Plan] |
/coach |
useWeeklyPlanStore, useCoachChatStore |
Instant UI stamp ("✓ Plan Applied") |
Commits proposal.data to Firestore weekly_plans. |
If network fails, toast notification alerts user and buttons remain active to retry. |
| Send Message in Chat | /coach |
useCoachChatStore, useUserProfileStore |
Optimistic bubble append + Coach Thinking Spinner | Calls POST /api/coach/chat. Commits returned memory_mutations. |
Replaces spinner with "Failed to send. Tap to retry." bubble. |
| Toggle Equipment Chip | /settings |
useUserProfileStore |
Instant toggle (<16ms) |
Dispatches background write to Firestore user_profiles. |
Reverts chip selection and displays error toast if write fails. |
Delete AI Memory Item [🗑] |
/settings |
useUserProfileStore |
Instant deletion (<16ms) |
Dispatches delete mutation to Firestore user_profiles. |
Restores memory item and alerts user if deletion fails. |
6. End-to-End User Journeys & Plain-English Test Matrix
- Suite 1: App Shell, Navigation & Route Handling (Tests 1.1–1.6: Root launch redirect, persistent dock, active session quick-return, invalid day-of-week fallback, unknown route 404 fallback, invalid exercise deep-link fallback).
- Suite 2: Daily Workout View & Block Rendering (Tests 2.1–2.7: Dynamic day title resolution, specific day route & back button, single versus superset block treatment, empty day placeholder, completed workout stamp, pure navigation on center play button, modify with coach context attachment).
- Suite 3: Week Schedule View & Day Schedule Card (Tests 3.1–3.6: Weekly stats render, scheduled days only filter, today visual callout, day card navigation, modify week navigation, condensed variant rendering).
- Suite 4: Coach Chat & Staged Mutation (Tests 4.1–4.7: Chat message stream render, context banner attachment & dismissal, prompt chip pre-population, speech dictation toggle, staged mutation isolation, proposal acceptance & commit, weekly overhaul proposal preview & commit).
- Suite 5: Exercise Detail & Encyclopedia (Tests 5.1–5.5: Exercise detail rendering, auto-looping muted playback, video pause toggle, primary versus secondary muscle tags, history back navigation & fallback).
- Suite 6: Active Workout Tracker & Logging (Tests 6.1–6.7: Unstarted initial state & manual start, pause and resume stopwatch, tactile set logging & checkmark toggle, superset step alternation, swap exercise modal & replacement, finish confirmation & server sync, session state recovery on reload).
- Suite 7: Progress & Historical Analytics (Tests 7.1–7.5: Progress dashboard overview render, PR showcase banner display, chart timeframe toggle, empty history state, past session history tap).
- Suite 8: User Settings, Equipment & AI Memory (Tests 8.1–8.4: Settings view rendering, equipment toggle update, units switch, AI memory item deletion).