Aplikasi Kebugaran Smart: Spesifikasi Arsitektur Klien
ArtefakIni adalah artefak yang digunakan dalam Episode 3: Berikan Otak pada Aplikasi Anda dan Episode 4: Rencana Penerapan Aplikasi Tanpa Kode. Anda dapat menggunakan spesifikasi ini sebagai referensi untuk tampilan frontend, komponen UI yang dapat digunakan kembali, pengelolaan status klien, dan kasus pengujian dalam bahasa Inggris biasa.
Login untuk mengakses artefak ini
Login dengan Profil Developer Google Anda untuk melihat dan menyalin artefak lengkap yang digunakan dalam seri Build It!.
Profil Developer Diperlukan
Anda tidak memenuhi syarat untuk mendapatkan profil developer. Minta administrator Workspace Anda untuk mengaktifkan fitur ini.
Buat Profil Developer
Buat Profil Developer Google gratis untuk mengakses semua perintah dan artefak Build It!
Bergabunglah dengan Builder Central untuk Membuka Akses
Klaim badge anggota Builder gratis Anda dengan sekali klik untuk membuka semua perintah dan artefak Build It!.
Status: Siap untuk Sesi Perencanaan (Penyusunan dengan Pendamping Perencanaan Klien)
Dokumen Pendamping: Spesifikasi Arsitektur Data
Sasaran Arsitektur: Membangun ulang frontend prototipe smart fitness AI Studio yang bersih, mudah dikelola, modular, dan dapat diuji.
0. Stack Teknis Inti & Standar Rekayasa
- Framework Runtime: Next.js (App Router, React 19) + caching aset offline Progressive Web App (PWA).
- Arsitektur Gaya: Tailwind CSS v4 + Tailwind Variants (untuk gaya komponen deterministik) + Lucide React (ikon).
- Divisi Negara Bagian Klien:
- Zustand (Sesi Lokal): Mengelola status gym-floor yang tidak stabil (
useActiveSessionStore), timer stopwatch, buffer set aktif, dan pengurutan langkah yang telah dihitung sebelumnya. Disinkronkan kelocalStorageuntuk pemulihan kunci ponsel. - TanStack Query (Server State): Mengelola caching dokumen Firestore, validasi ulang latar belakang, dan update optimis untuk
weekly_plans,user_profiles,prs, danworkout_logs.
- Zustand (Sesi Lokal): Mengelola status gym-floor yang tidak stabil (
- Visualisasi Diagram: Recharts (ditata gayanya dengan token mode gelap kustom).
- Autentikasi: Firebase Authentication dengan header autentikasi token Bearer yang diteruskan ke semua endpoint server.
1. Prinsip Frontend & Desain
- Ergonomi yang Mengutamakan Aktivitas Gym: Dirancang untuk pengoperasian satu tangan yang taktil di tengah latihan dengan tangan berkeringat. Target ketuk yang besar (minimum 48x48 dp), keterbacaan kontras tinggi, dan pengetikan yang diperlukan minimal.
- UI Optimis & Ketahanan Offline: Mencatat set, memulai timer istirahat, dan menukar latihan harus merespons secara instan (<16 md) di UI. Sinkronisasi latar belakang menangani persistensi server ke
POST /api/workouts/logtanpa memblokir pengguna. - Pemisahan Masalah yang Ketat: Komponen Dumb/Presentational menerima data dan memunculkan peristiwa menggunakan properti; tampilan penampung smart mengelola logika bisnis, penyimpanan status, dan koordinasi API.
- UX Mutasi Bertahap: Proposal yang dihasilkan oleh Pelatih AI (
POST /api/coach/chat) dirender sebagai kartu pratinjau bertahap interaktif dengan kontrol [Setujui Rencana] dan [Ubah] yang eksplisit sebelum menerapkan perubahan pada status aplikasi. - Kualitas Berbasis Perilaku: Setiap halaman, komponen, dan interaksi dipasangkan dengan kasus pengujian dalam bahasa Inggris sederhana yang menentukan perilaku yang diharapkan secara jelas.
2. Navigasi Aplikasi & Hierarki Tampilan
| Jalur Rute | Nama Tampilan | Tujuan Utama | Komponen Utama yang Terkandung |
|---|---|---|---|
/ |
Pengalihan Root | Pengalihan instan ke /today. |
(Pengalihan router) |
/today |
Pratinjau Latihan Fisik Hari Ini | Tampilan default. Secara otomatis me-resolve ke hari saat ini dan menampilkan pratinjau latihan fisik hari ini. | <BackButton />, <WorkoutHeader />, <CoachNoteCard />, <WorkoutExerciseSummary />, <WorkoutBlock />, <ExerciseCard />, <EmptyDayPlaceholder />, <ModifyWithCoachCard /> |
/workouts/:day |
Pratinjau Latihan Fisik Harian | Menampilkan pratinjau olahraga untuk hari tertentu dalam seminggu (misalnya, /workouts/monday, /workouts/thursday). |
<BackButton />, <WorkoutHeader />, <CoachNoteCard />, <WorkoutExerciseSummary />, <WorkoutBlock />, <ExerciseCard />, <EmptyDayPlaceholder />, <ModifyWithCoachCard /> |
/workout/active |
Pelacak Sesi Aktif | Layar eksekusi latihan berisiko tinggi (set, repetisi, timer). Navigasi bawah tetap terlihat. | <ActiveSessionStickyHeader />, <ActiveExerciseCardHeader />, <CoachTipCard />, <CurrentSetTargetCard />, <SetNavigationRow />, <ExerciseSetsTable />, <ActiveRestTimerDock />, <SessionExerciseOverview />, <ActiveSessionControlsDock />, <SwapExerciseModal />, <FinishConfirmationModal /> |
/week |
Jadwal Pelatihan/Tampilan Minggu | Ringkasan jadwal 7 hari penuh dengan agregat volume/waktu mingguan. | <WeekHeader />, <WeeklyStatsSummary />, <DayScheduleCardList />, <DayScheduleCard />, <ModifyWeekWithCoachCard /> |
/coach |
Percakapan Pelatih AI | Pelatihan percakapan dengan chip kontekstual & proposal latihan bertahap. | <CoachHeader />, <ChatMessageList />, <ChatBubble />, <StagedProposalCard />, <ContextualPromptsBar />, <ChatInputDock />, <ContextBanner />, <ChatInputBar />, <SpeechToTextButton /> |
/progress |
Progres & Analytics | Log latihan historis, pencapaian PR, dan diagram volume. | <ProgressHeader />, <PRShowcaseBanner />, <VolumeProgressChartCard />, <AllTimeStatsGrid />, <WorkoutHistorySection />, <HistorySessionCard />, <EmptyHistoryPlaceholder /> |
/settings |
Profil & Preferensi Pengguna | Profil peralatan, notifikasi, dan manajemen memori 3 tingkat. | <SettingsHeader />, <UserProfileCard />, <EquipmentSelectorCard />, <EquipmentToggleChip />, <PreferencesGroup />, <MemoryTierViewerCard />, <MemoryItemCard />, <AccountActionsGroup /> |
/exercises/:exerciseId |
Detail Ensiklopedia Latihan | Panduan latihan yang dapat di-deep link (misalnya, /exercises/incline-db-bench-press) dengan video & tips gerakan. |
<BackButton />, <ExerciseVideoPlayer />, <TargetMusclesCard />, <HowToPerformCard />, <FormTipsCard /> |
3. Spesifikasi Halaman & Tampilan
Tampilan: DailyWorkoutView (/today & /workouts/:day)
- Tujuan: Menampilkan program latihan terjadwal untuk hari tertentu—termasuk fokus latihan, durasi, target distribusi beban otot, catatan pelatih, blok set lurus, dan blok superset—dengan penggantian status kosong yang rapi saat tidak ada latihan yang dijadwalkan.
- Anatomi Visual:
- Atas:
<BackButton label="Back to Week" targetRoute="/week" />. - Header: Judul Satu Baris (
"Today"atau hari dalam seminggu) dengan badge"✓ Completed"bersyarat, pil durasi ("⏱ 50 min"), dan batang persentase intensitas otot target. - Catatan Pelatih: Kartu saran kontekstual dengan ikon dan warna batas hijau.
- Isi: Daftar blok latihan yang dapat di-scroll menggunakan
<WorkoutExerciseSummary />(set lurus atau superset dengan badgeborder-left: 3px solid #a3e635dan🔁 SUPERSET BLOCK). - Status Kosong:
<EmptyDayPlaceholder message="Nothing scheduled for this day" />. - Tindakan Footer Bawah:
<ModifyWithCoachCard />(mengarahkan ke/coach?day=:day).
- Atas:
Tampilan: WeekScheduleView (/week)
- Tujuan: Menampilkan ringkasan jadwal latihan 7 hari yang lengkap, termasuk metrik volume/waktu mingguan tingkat tinggi, daftar hari latihan aktif yang diseleksi (secara ketat memfilter hari tidak terjadwal/istirahat), dan pintasan langsung untuk merombak rencana mingguan dengan Pelatih AI.
- Anatomi Visual:
<WeekHeader />,<WeeklyStatsSummary />3 kolom (Total Waktu, Total Volume, Frekuensi), daftar hari yang dijadwalkan menggunakan<DayScheduleCard variant="normal" />(dengan badgeTODAYhijau neon pada hari saat ini), dan<ModifyWeekWithCoachCard />(mengarahkan ke/coach?context=week).
Tampilan: CoachChatView (/coach)
- Tujuan: Hub pelatihan percakapan dengan agen pelatih Gemini. Memberikan saran pelatihan motivasi dan strategis, mendukung dikte speech-to-text, dan merender penyesuaian latihan bertahap yang memerlukan interaksi manusia dengan kontrol penerimaan eksplisit.
- Anatomi Visual:
<CoachHeader />,<ChatMessageList />yang dapat di-scroll (<ChatBubble />dan<StagedProposalCard />),<ContextualPromptsBar />bersyarat, dan<ChatInputDock />yang diposisikan di dok (<ContextBanner />dengan[✕]tutup +<ChatInputBar />+<SpeechToTextButton />).
Tampilan: ExerciseDetailView (/exercises/:exerciseId)
- Tujuan: Entri ensiklopedia yang dapat di-deep link yang menampilkan demonstrasi video bisu yang diulang otomatis (
<ExerciseVideoPlayer />), badge target otot primer versus sekunder (<TargetMusclesCard />), petunjuk performa langkah demi langkah yang diurutkan (<HowToPerformCard />), dan tips postur (<FormTipsCard />).
Tampilan: ActiveWorkoutView (/workout/active)
- Tujuan: Layar pencatatan set dan pelaksanaan latihan yang penting. Mengelola status stopwatch sesi live, target set saat ini, input repetisi/beban, penyelesaian tanda centang instan (<16 md), pergantian superset otomatis, hitung mundur timer istirahat dengan haptik/audio, pertukaran latihan, dan persistensi akhir ke
POST /api/workouts/log. - Anatomi Visual:
<ActiveSessionStickyHeader />,<ActiveExerciseCardHeader />,<CoachTipCard />,<CurrentSetTargetCard />,<ActiveRestTimerDock />mengambang (+30s,Skip),<SetNavigationRow />,<ExerciseSetsTable />(+ Add Set),<SessionExerciseOverview />,<ActiveSessionControlsDock />terpasang ([⇄ SWAP EXERCISE]+[▶ START WORKOUT]/[⏸ PAUSE]/[▶ RESUME]),<SwapExerciseModal />, dan<FinishConfirmationModal />.
Tampilan: ProgressView (/progress)
- Tujuan: Melacak progres atletik dari waktu ke waktu, merayakan Rekor Pribadi (
<PRShowcaseBanner />) terbaru, memvisualisasikan tren volume mingguan/bulanan dengan Recharts interaktif (<VolumeProgressChartCard />dengan tombol4W | 3M | 1Y), menampilkan<AllTimeStatsGrid />, dan mengarsipkan sesi latihan yang telah selesai (<WorkoutHistorySection />/<HistorySessionCard />).
Tampilan: SettingsView (/settings)
- Tujuan: Mengelola informasi profil atlet (
<UserProfileCard />), inventaris peralatan (<EquipmentSelectorCard />/<EquipmentToggleChip />), preferensi olahraga (<PreferencesGroup />untukLBS / KG, haptik, suara), dan menyediakan pengelolaan pengguna yang transparan serta penghapusan Memori Aktif 3 Tingkat pelatih AI (<MemoryTierViewerCard />/<MemoryItemCard />).
4. Katalog & Antarmuka Komponen yang Dapat Digunakan Kembali
Kontrak properti komponen TypeScript utama di seluruh aplikasi:
// 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. Pengelolaan Status Klien & Matriks Aliran Data
5.1 Kebijakan Latensi & Pemuatan: Mesin Dua Kecepatan
- UI Optimis di Gym (<16 md): Tindakan taktil di gym—mencentang set, menambah beban/repetisi, beralih tab, dan mengaktifkan/menonaktifkan peralatan—memperbarui status lokal dan merender ulang dalam waktu 16 milidetik. Pengguna tidak pernah terhalang oleh indikator pemuatan saat memegang beban.
- Indikator & Spinner Pemuatan yang Jelas untuk Operasi Asinkron:
- Percakapan Pelatih AI (
POST /api/coach/chat): Mengirim pesan chat akan langsung merender Balon Spinner Pelatih Sedang Berpikir animasi di aliran chat hingga Gemini menampilkan respons atau proposal latihan fisiknya. - Cold-Start Awal & Sinkronisasi Jaringan: Penampung tampilan menampilkan pemuat skeleton dan indikator lingkaran berputar pemuatan dengan kontras tinggi saat mengambil
weekly_plansatauhistorical_workouts. - Pengiriman Latihan (
[Finish]): Modal konfirmasi selesai merender indikator lingkaran berputar yang aktif saat payload sesi di-commit kePOST /api/workouts/logdi Cloud Firestore.
- Percakapan Pelatih AI (
5.2 Arsitektur Penyimpanan Klien & Batas Domain
| Lapisan Toko | Domain Status & Properti Utama | Kebijakan Persistensi & Cache | Kontrak Backend Terkoordinasi |
|---|---|---|---|
useActiveSessionStore (Zustand) |
sessionState (unstarted, running, paused), elapsedSeconds, currentStepIndex, steps: WorkoutStep[], loggedExercises. |
Disinkronkan ke localStorage setiap detik untuk pemulihan penguncian/refresh ponsel yang aman. |
Mengirimkan payload yang telah selesai ke POST /api/workouts/log. |
useWeeklyPlanQuery (TanStack Query) |
Jadwal 7 hari saat ini, objek latihan harian, blok superset, status penyelesaian (scheduled, completed). |
Di-cache di TanStack Query (staleTime: 5 min); diambil di awal saat peluncuran. |
Diterapkan setelah pengguna mengetuk [Accept Plan] untuk proposal dari POST /api/coach/chat. |
useCoachChatStore (Zustand + TanStack) |
Balon pesan kronologis, activeContext, chip perintah, isCoachTyping: boolean, proposal bertahap. |
Disinkronkan dengan bucket chat mingguan Firestore menggunakan langganan real-time (onSnapshot). |
Mengirim kueri ke POST /api/coach/chat. |
useProgressQuery (TanStack Query) |
Arsip histori olahraga, papan rekor PR (/users/{userId}/prs), agregat volume sepanjang waktu, filter jangka waktu (4W, 3M, 1Y). |
Di-cache di TanStack Query (staleTime: 10 min). |
Diperbarui segera setelah menyelesaikan sesi latihan fisik. |
useUserProfileStore (TanStack Query) |
Inventaris peralatan, unit (LBS/KG), tombol suara/haptik, memori hidup 3 tingkat (Kebutuhan Pokok, Fisiologis, Situasional). |
Di-cache di TanStack Query dengan sinkronisasi dua arah ke Firestore user_profiles. |
Diperbarui secara otomatis menggunakan memory_mutations dari POST /api/coach/chat. |
useExerciseLibraryQuery (TanStack Query) |
Entri ensiklopedia statis, URL video, otot primer/sekunder, langkah-langkah, tips postur. | Cache-first agresif dengan TTL tak terbatas (staleTime: Infinity). |
Hanya baca dari koleksi exercises Firestore yang tidak dapat diubah. |
5.3 Grafik Langkah Sesi Aktivitas yang Telah Dihitung Sebelumnya
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 Alur Data Menyeluruh & Matriks Mutasi
| Pemicu Pengguna | Tampilan Asal | Client Store Mutated | Latensi UI/Status Pemuatan | Koordinasi Backend | Rollback/Penanganan Kegagalan |
|---|---|---|---|---|---|
Ketuk [✓] Set Lengkap |
/workout/active |
useActiveSessionStore |
<16ms (Optimis) |
Buffer sesi lokal diperbarui; tidak ada penundaan jaringan. | Penulisan memori lokal dengan persistensi lokal yang andal. |
Ketuk [Finish Workout] |
/workout/active |
useActiveSessionStore, useWeeklyPlanStore, useProgressStore |
Tombol menampilkan indikator lingkaran berputar saat menyinkronkan | Mengirim ke POST /api/workouts/log. Menandai hari Firestore sebagai completed. |
Jika offline, mengantrekan payload ke buffer sinkronisasi lokal dan mencoba lagi setelah terhubung kembali. |
Ketuk [Accept Plan] |
/coach |
useWeeklyPlanStore, useCoachChatStore |
Stempel UI instan ("✓ Plan Applied") |
Melakukan commit proposal.data ke Firestore weekly_plans. |
Jika jaringan gagal, notifikasi toast akan memberi tahu pengguna dan tombol akan tetap aktif untuk mencoba lagi. |
| Mengirim Pesan di Chat | /coach |
useCoachChatStore, useUserProfileStore |
Penambahan balon optimis + Indikator Berputar Pelatih Berpikir | Panggilan POST /api/coach/chat. Commit menampilkan memory_mutations. |
Mengganti indikator lingkaran berputar dengan "Gagal mengirim. Ketuk untuk mencoba lagi." |
| Chip Alih Peralatan | /settings |
useUserProfileStore |
Tombol instan (<16ms) |
Mengirim penulisan latar belakang ke Firestore user_profiles. |
Mengembalikan pilihan chip dan menampilkan toast error jika penulisan gagal. |
Hapus Item Memori AI [🗑] |
/settings |
useUserProfileStore |
Penghapusan instan (<16ms) |
Mengirim mutasi penghapusan ke Firestore user_profiles. |
Memulihkan item memori dan memberi tahu pengguna jika penghapusan gagal. |
6. Perjalanan Pengguna Menyeluruh & Matriks Uji Bahasa Sederhana
- Suite 1: App Shell, Navigation & Route Handling (Pengujian 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: Tampilan Latihan Harian & Rendering Blok (Pengujian 2.1–2.7: Resolusi judul hari dinamis, rute hari tertentu & tombol kembali, perlakuan blok tunggal versus superset, placeholder hari kosong, stempel latihan selesai, navigasi murni pada tombol putar tengah, modifikasi dengan lampiran konteks pelatih).
- Suite 3: Tampilan Jadwal Mingguan & Kartu Jadwal Harian (Pengujian 3.1–3.6: Rendering statistik mingguan, filter khusus hari yang dijadwalkan, info visual hari ini, navigasi kartu harian, modifikasi navigasi mingguan, rendering varian yang diringkas).
- Suite 4: Coach Chat & Staged Mutation (Pengujian 4.1–4.7: Render stream pesan chat, lampiran & penutupan banner konteks, isi otomatis chip perintah, tombol dikte ucapan, isolasi mutasi bertahap, penerimaan & commit proposal, pratinjau & commit proposal perbaikan mingguan).
- Suite 5: Detail Latihan & Ensiklopedia (Pengujian 5.1–5.5: Rendering detail latihan, pemutaran otomatis yang dibisukan, tombol jeda video, tag otot primer versus sekunder, navigasi kembali & penggantian histori).
- Suite 6: Pelacak & Pencatatan Latihan Fisik Aktif (Pengujian 6.1–6.7: Status awal yang belum dimulai & mulai manual, jeda dan lanjutkan stopwatch, pencatatan set taktil & tombol tanda centang, pergantian langkah superset, modal & penggantian latihan, konfirmasi selesai & sinkronisasi server, pemulihan status sesi saat pemuatan ulang).
- Suite 7: Progress & Historical Analytics (Pengujian 7.1–7.5: Render ringkasan dasbor progres, tampilan banner showcase PR, tombol rentang waktu diagram, status histori kosong, ketukan histori sesi sebelumnya).
- Suite 8: Setelan Pengguna, Peralatan & Memori AI (Pengujian 8.1–8.4: Rendering tampilan setelan, pembaruan tombol peralatan, pengalihan unit, penghapusan item memori AI).