Smart Fitness App: Client Architecture Spec
АртефактЭтот артефакт используется в эпизоде 3 "Добавьте в приложение искусственный интеллект" и эпизоде 4 "План реализации приложения без кода". Вы можете использовать эту спецификацию в качестве справочника по представлениям интерфейса, повторно используемым компонентам пользовательского интерфейса, управлению состоянием клиента и тестовым сценариям на простом английском языке.
Чтобы получить доступ к этому объекту, войдите в аккаунт.
Войдите в профиль разработчика Google, чтобы посмотреть и скопировать полный артефакт, используемый в серии Build It!.
Требуется профиль разработчика
Вы не можете создать профиль разработчика. Попросите администратора Workspace включить эту функцию.
Создать профиль разработчика
Создайте бесплатный профиль разработчика Google, чтобы получить доступ ко всем подсказкам и артефактам Build It!.
Присоединяйтесь к Builder Central, чтобы получить доступ
Получите бесплатный значок участника Builder, чтобы разблокировать все запросы и артефакты Build It!
Статус: готово к сеансу планирования (составление черновика с помощью Client Planning Companion).
Сопутствующий документ: спецификация архитектуры данных.
Цель архитектуры: чистая, поддерживаемая, модульная и тестируемая переработка интерфейса прототипа умного фитнеса AI Studio.
0. Основные технические средства и стандарты разработки
- Фреймворк среды выполнения: Next.js (App Router, React 19) + кеширование офлайн-объектов прогрессивного веб-приложения (PWA).
- Архитектура стилей: Tailwind CSS v4 + Tailwind Variants (для детерминированного оформления компонентов) + Lucide React (значки).
- Client State Division:
- Zustand (локальный сеанс). Управляет временными данными о тренировке (
useActiveSessionStore), таймерами секундомера, буферами активных подходов и предварительно рассчитанной последовательностью шагов. Синхронизировано сlocalStorageдля восстановления блокировки экрана. - TanStack Query (состояние сервера). Управляет кешированием документов Firestore, фоновой повторной проверкой и оптимистичными обновлениями для
weekly_plans,user_profiles,prsиworkout_logs.
- Zustand (локальный сеанс). Управляет временными данными о тренировке (
- Визуализация диаграмм: Recharts (с использованием токенов темной темы).
- Аутентификация. Firebase Authentication с заголовком аутентификации токена на предъявителя, передаваемым всем конечным точкам сервера.
1. Принципы разработки и дизайна интерфейса
- Эргономика для тренировок. Удобное управление одной рукой даже во время интенсивных занятий. Крупные области прикосновения (не менее 48 x 48 dp), высокая контрастность и минимум ввода текста.
- Оптимистичный интерфейс и устойчивость к офлайн-режиму. Запись подходов, запуск таймеров отдыха и замена упражнений должны мгновенно (< 16 мс) отражаться в интерфейсе. Фоновая синхронизация обеспечивает сохранение данных на сервере
POST /api/workouts/log, не блокируя пользователя. - Строгое разделение ответственности. Компоненты представления получают данные и генерируют события с помощью свойств. Умные контейнеры управляют бизнес-логикой, хранилищами состояний и координацией API.
- Поэтапное изменение UX. Предложения, созданные ИИ-тренером (
POST /api/coach/chat), отображаются в виде интерактивных карточек предварительного просмотра с кнопками Принять план и Изменить. - Качество, основанное на поведении. Каждая страница, компонент и взаимодействие сопряжены с тестовыми сценариями на простом английском языке, которые однозначно определяют ожидаемое поведение.
2. Навигация по приложению и иерархия View
| Путь маршрута | Название представления | Основная цель | Основные компоненты |
|---|---|---|---|
/ |
Переадресация корневого каталога | Мгновенное перенаправление на /today. |
(Перенаправление маршрутизатора) |
/today |
Предварительный просмотр сегодняшней тренировки | Режим по умолчанию. Автоматически определяет текущий день недели и показывает тренировку на сегодня. | <BackButton />, <WorkoutHeader />, <CoachNoteCard />, <WorkoutExerciseSummary />, <WorkoutBlock />, <ExerciseCard />, <EmptyDayPlaceholder />, <ModifyWithCoachCard /> |
/workouts/:day |
Предварительный просмотр ежедневной тренировки | Показывает предварительный просмотр тренировки на любой конкретный день недели (например, /workouts/monday, /workouts/thursday). |
<BackButton />, <WorkoutHeader />, <CoachNoteCard />, <WorkoutExerciseSummary />, <WorkoutBlock />, <ExerciseCard />, <EmptyDayPlaceholder />, <ModifyWithCoachCard /> |
/workout/active |
Отслеживание активных сеансов | Экран выполнения тренировки с высокой нагрузкой (подходы, повторения, таймер). Нижняя панель навигации остается видимой. | <ActiveSessionStickyHeader />, <ActiveExerciseCardHeader />, <CoachTipCard />, <CurrentSetTargetCard />, <SetNavigationRow />, <ExerciseSetsTable />, <ActiveRestTimerDock />, <SessionExerciseOverview />, <ActiveSessionControlsDock />, <SwapExerciseModal />, <FinishConfirmationModal /> |
/week |
Расписание тренировок/Просмотр недели | Полный обзор расписания на 7 дней с агрегированными данными по объему/времени за неделю. | <WeekHeader />, <WeeklyStatsSummary />, <DayScheduleCardList />, <DayScheduleCard />, <ModifyWeekWithCoachCard /> |
/coach |
Чат с ИИ-тренером | Тренировки в формате диалога с контекстными чипами и поэтапными предложениями. | <CoachHeader />, <ChatMessageList />, <ChatBubble />, <StagedProposalCard />, <ContextualPromptsBar />, <ChatInputDock />, <ContextBanner />, <ChatInputBar />, <SpeechToTextButton /> |
/progress |
Прогресс и аналитика | Журналы тренировок, личные рекорды и диаграммы объема. | <ProgressHeader />, <PRShowcaseBanner />, <VolumeProgressChartCard />, <AllTimeStatsGrid />, <WorkoutHistorySection />, <HistorySessionCard />, <EmptyHistoryPlaceholder /> |
/settings |
Профиль пользователя и настройки | Профиль оборудования, уведомления и трехуровневое управление памятью. | <SettingsHeader />, <UserProfileCard />, <EquipmentSelectorCard />, <EquipmentToggleChip />, <PreferencesGroup />, <MemoryTierViewerCard />, <MemoryItemCard />, <AccountActionsGroup /> |
/exercises/:exerciseId |
Энциклопедия упражнений | Руководство по упражнениям с видео и советами по технике выполнения, на которое можно сослаться (например, /exercises/incline-db-bench-press). |
<BackButton />, <ExerciseVideoPlayer />, <TargetMusclesCard />, <HowToPerformCard />, <FormTipsCard /> |
3. Спецификации страниц и представлений
Посмотреть: DailyWorkoutView (/today и /workouts/:day)
- Назначение. Показывает запланированный режим тренировок на определенный день, включая фокус тренировки, продолжительность, целевое распределение мышечной нагрузки, заметки тренера, блоки прямых сетов и блоки суперсетов, с чистым резервным пустым состоянием, когда тренировка не запланирована.
- Visual Anatomy:
- Верх:
<BackButton label="Back to Week" targetRoute="/week" />. - Заголовок: однострочный заголовок (
"Today"или день недели) с условным значком"✓ Completed", индикатором продолжительности ("⏱ 50 min") и полосами интенсивности целевых мышц. - Примечание тренера: карточка с контекстными советами, значком и зеленой рамкой.
- Основная часть: прокручиваемый список блоков упражнений с использованием
<WorkoutExerciseSummary />(простые подходы или суперсеты со значкомborder-left: 3px solid #a3e635и🔁 SUPERSET BLOCK). - Пустой раздел:
<EmptyDayPlaceholder message="Nothing scheduled for this day" />. - Действие в нижнем колонтитуле:
<ModifyWithCoachCard />(перенаправляет на/coach?day=:day).
- Верх:
Просмотр: WeekScheduleView (/week)
- Назначение. Показывает полное расписание тренировок на 7 дней, включая общие показатели объема и времени тренировок за неделю, список дней с активными тренировками (без дней отдыха и дней, когда тренировки не запланированы), а также кнопку для изменения плана на неделю с помощью ИИ-тренера.
- Визуальные элементы.
<WeekHeader />,<WeeklyStatsSummary />с тремя столбцами ("Общее время", "Общий объем", "Частота"), список запланированных дней с использованием<DayScheduleCard variant="normal" />(с неоново-зеленым значкомTODAYна текущем дне) и<ModifyWeekWithCoachCard />(ведет на/coach?context=week).
Просмотр: CoachChatView (/coach)
- Назначение. Разговорный коучинг с агентом-тренером Gemini. Дает мотивирующие и стратегические советы по тренировкам, поддерживает преобразование речи в текст и позволяет человеку в контуре корректировать этапы тренировки с явным контролем принятия.
- Визуальная анатомия.
<CoachHeader />, прокручиваемый<ChatMessageList />(<ChatBubble />и<StagedProposalCard />), условный<ContextualPromptsBar />и закрепленный<ChatInputDock />(<ContextBanner />с[✕]отклонением +<ChatInputBar />+<SpeechToTextButton />).
Просмотр: ExerciseDetailView (/exercises/:exerciseId)
- Назначение. Статья энциклопедии с возможностью создания ссылки на контент, содержащая автоматически зацикленное видео без звука (
<ExerciseVideoPlayer />), значки основных и дополнительных целевых мышц (<TargetMusclesCard />), пошаговые инструкции по выполнению (<HowToPerformCard />) и советы по технике (<FormTipsCard />).
Просмотр: ActiveWorkoutView (/workout/active)
- Назначение. Экран для выполнения тренировок с высокими ставками и регистрации подходов. Управляет состоянием секундомера в текущем сеансе, текущими целями, вводом повторений/веса, мгновенным завершением с галочкой (<16 мс), автоматическим чередованием суперсетов, таймерами отдыха с вибрацией/звуком, заменой упражнений и окончательным сохранением в
POST /api/workouts/log. - Визуальная анатомия:
<ActiveSessionStickyHeader />,<ActiveExerciseCardHeader />,<CoachTipCard />,<CurrentSetTargetCard />, плавающая<ActiveRestTimerDock />(+30s,Skip),<SetNavigationRow />,<ExerciseSetsTable />(+ Add Set),<SessionExerciseOverview />, закрепленная<ActiveSessionControlsDock />([⇄ SWAP EXERCISE]+[▶ START WORKOUT]/[⏸ PAUSE]/[▶ RESUME]),<SwapExerciseModal />и<FinishConfirmationModal />.
Просмотр: ProgressView (/progress)
- Назначение. Отслеживание спортивного прогресса, фиксация личных рекордов (
<PRShowcaseBanner />), визуализация еженедельных и ежемесячных тенденций с помощью интерактивных графиков (<VolumeProgressChartCard />с переключателями4W | 3M | 1Y), отображение<AllTimeStatsGrid />и архивирование прошлых тренировок (<WorkoutHistorySection />/<HistorySessionCard />).
Просмотр: SettingsView (/settings)
- Назначение. Управление информацией в профиле спортсмена (
<UserProfileCard />), инвентарем (<EquipmentSelectorCard />/<EquipmentToggleChip />), настройками тренировок (<PreferencesGroup />дляLBS / KG, вибрация, звук), а также прозрачное управление пользователями и удаление трехуровневой памяти ИИ-тренера (<MemoryTierViewerCard />/<MemoryItemCard />).
4. Каталог и интерфейсы многоразовых компонентов
Ключевые контракты свойств компонентов TypeScript в приложении:
// 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. Управление состоянием клиента и матрица потока данных
5.1. Правила в отношении задержки и загрузки: двухскоростной движок
- Оптимистичный интерфейс для тренировок (< 16 мс). Тактильные действия, такие как отметка выполненных подходов, увеличение веса или количества повторений, переключение вкладок и выбор оборудования, обновляют локальное состояние и повторно отрисовываются в течение 16 миллисекунд. Пользователи никогда не блокируются индикаторами загрузки при удержании весов.
- Явные индикаторы загрузки для асинхронных операций.
- Разговоры с ИИ-тренером (
POST /api/coach/chat). После отправки сообщения в чате появляется анимированный пузырь с индикатором ожидания, который показывает, что тренер думает. Он исчезает, когда Gemini возвращает ответ или предложение тренировки. - Первоначальный холодный запуск и синхронизация с сетью. При получении
weekly_plansилиhistorical_workoutsв контейнерах просмотра отображаются скелетные загрузчики и высококонтрастные индикаторы загрузки. - Отправка данных о тренировке (
[Finish]). В модальном окне подтверждения завершения тренировки отображается активный индикатор загрузки, пока полезная нагрузка сеанса фиксируется вPOST /api/workouts/logв Cloud Firestore.
- Разговоры с ИИ-тренером (
5.2. Архитектура хранилища клиента и границы домена
| Слой магазинов | Домен состояния и ключевые свойства | Правила хранения и кеширования | Координированный контракт на серверную часть |
|---|---|---|---|
useActiveSessionStore (Zustand) |
sessionState (unstarted, running, paused), elapsedSeconds, currentStepIndex, steps: WorkoutStep[], loggedExercises. |
Синхронизируется с localStorage каждую секунду, чтобы вы не потеряли данные, если телефон заблокируется или вы обновите страницу. |
Отправляет заполненную полезную нагрузку в POST /api/workouts/log. |
useWeeklyPlanQuery (TanStack Query) |
Текущее расписание на 7 дней, объекты тренировок по дням, блоки суперсетов, статусы выполнения (scheduled, completed). |
Кешируется в TanStack Query (staleTime: 5 min); предварительно загружается при запуске. |
Применяется, когда пользователь нажимает [Accept Plan] для предложений от POST /api/coach/chat. |
useCoachChatStore (Zustand + TanStack) |
Хронологические речевые пузыри, activeContext, чипы запросов, isCoachTyping: boolean, поэтапные предложения. |
Синхронизировано с еженедельным сегментом чата Firestore с использованием подписки в реальном времени (onSnapshot). |
Отправляет запросы в POST /api/coach/chat. |
useProgressQuery (TanStack Query) |
Архив тренировок, доска рекордов (/users/{userId}/prs), агрегированные данные по объему за все время, фильтр по временным рамкам (4W, 3M, 1Y). |
Кешировано в TanStack Query (staleTime: 10 min). |
Обновляется сразу после завершения тренировки. |
useUserProfileStore (TanStack Query) |
Инвентарь, единицы измерения (LBS/KG), переключатели звука и вибрации, трехуровневая память (основные, физиологические и ситуационные потребности). |
Кешируется в TanStack Query с двунаправленной синхронизацией с Firestore user_profiles. |
Автоматически обновлено с помощью memory_mutations из POST /api/coach/chat. |
useExerciseLibraryQuery (TanStack Query) |
Статические энциклопедические статьи, URL видео, основные/второстепенные мышцы, шаги, советы по форме. | Агрессивное предварительное кеширование с бесконечным TTL (staleTime: Infinity). |
Только для чтения из неизменяемой коллекции Firestore exercises. |
5.3. График шагов за активный сеанс, рассчитанный заранее
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. Сквозной поток данных и матрица изменений
| Триггер пользователя | Исходное представление | Изменено хранилище клиента | Задержка интерфейса/состояние загрузки | Координация серверной части | Откат и обработка ошибок |
|---|---|---|---|---|---|
Нажмите [✓] "Завершить". |
/workout/active |
useActiveSessionStore |
<16ms (оптимистичный) |
Буфер локального сеанса обновлен. Ожидание сети не требуется. | Запись в локальную память с надежным локальным хранением. |
Нажмите [Finish Workout]. |
/workout/active |
useActiveSessionStore, useWeeklyPlanStore, useProgressStore |
Во время синхронизации на кнопке показывается индикатор загрузки. | Отправляет данные в POST /api/workouts/log. Отмечает день Firestore как completed. |
Если устройство находится в офлайн-режиме, полезная нагрузка помещается в локальный буфер синхронизации и отправляется повторно после подключения к интернету. |
Нажмите [Accept Plan]. |
/coach |
useWeeklyPlanStore, useCoachChatStore |
Мгновенный штамп интерфейса ("✓ Plan Applied") |
Фиксирует proposal.data в Firestore weekly_plans. |
Если произойдет сбой сети, пользователь получит всплывающее уведомление, а кнопки останутся активными, чтобы можно было повторить попытку. |
| Отправить сообщение в Chat | /coach |
useCoachChatStore, useUserProfileStore |
Оптимистичное добавление облачка + индикатор размышления тренера | Звонки POST /api/coach/chat. Возвращено фиксаций: memory_mutations. |
Вместо индикатора загрузки появляется сообщение "Не удалось отправить. Нажмите, чтобы повторить попытку". |
| Переключатель "Оборудование" | /settings |
useUserProfileStore |
Мгновенное переключение (<16ms) |
Отправляет фоновую запись в Firestore user_profiles. |
Отменяет выбор чипа и показывает сообщение об ошибке, если запись не удалась. |
Удалить элемент из памяти ИИ [🗑] |
/settings |
useUserProfileStore |
Мгновенное удаление (<16ms) |
Отправляет мутацию удаления в Firestore user_profiles. |
Восстанавливает объект памяти и предупреждает пользователя, если удаление не удалось. |
6. Полные пути пользователей и матрица тестов на простом английском языке
- Набор 1. Оболочка приложения, навигация и обработка маршрутов. Тесты 1.1–1.6: перенаправление при запуске из корневого каталога, закрепленная панель, быстрый возврат к активному сеансу, резервный вариант для недействительного дня недели, резервный вариант для неизвестного маршрута 404, резервный вариант для недействительной ссылки на контент в тренировке.
- Набор 2. Просмотр ежедневных тренировок и рендеринг блоков (тесты 2.1–2.7: динамическое разрешение названия дня, маршрут для определенного дня и кнопка "Назад ", обработка блоков с одним упражнением и суперсетом, плейсхолдер для пустого дня, штамп завершенной тренировки, чистая навигация по центральной кнопке воспроизведения, изменение с прикреплением контекста тренера).
- Набор 3. Режим просмотра расписания на неделю и карточка расписания на день. Тесты 3.1–3.6: отрисовка статистики за неделю, фильтр "Только дни с расписанием", визуальное выделение сегодняшнего дня, навигация по карточке дня, изменение навигации по неделе, отрисовка сокращенного варианта.
- Набор 4. Чат с тренером и поэтапное изменение (тесты 4.1–4.7: рендеринг потока сообщений чата, прикрепление и закрытие контекстного баннера, автоматическое заполнение чипа запроса, переключение голосового ввода, изоляция поэтапного изменения, принятие и фиксация предложения, предварительный просмотр и фиксация предложения еженедельного пересмотра).
- Набор 5. Сведения об упражнении и энциклопедия (тесты 5.1–5.5: отрисовка сведений об упражнении, автоматическое зацикливание воспроизведения без звука, переключатель паузы видео, теги основных и второстепенных мышц, обратная навигация по истории и резервный вариант).
- Набор 6. Отслеживание и регистрация активных тренировок (тесты 6.1–6.7: начальное состояние до запуска и запуск вручную, приостановка и возобновление секундомера, регистрация подходов и переключение флажков, чередование шагов суперсета, модальное окно замены упражнения и замена, подтверждение завершения и синхронизация с сервером, восстановление состояния сеанса при перезагрузке).
- Набор 7. Прогресс и статистика за прошлые периоды. Тесты 7.1–7.5: обзорная панель прогресса, баннер с личным рекордом, переключатель временных рамок на диаграмме, пустая история, нажатие на историю прошлых занятий.
- Набор 8. Пользовательские настройки, снаряжение и память ИИ. Тесты 8.1–8.4: отрисовка настроек, переключение снаряжения, переключение единиц измерения, удаление элементов из памяти ИИ.