Smart Fitness App: Data Structure, Database Schema & Server Design Spec
مصنوعاین آرتیفکت در قسمت ۲ استفاده شده است: مشخصات سیستم برنامهتان را برنامهریزی کنید (بدون کد). میتوانید از این مشخصات بهعنوان مرجعی برای ساختاردهی مجموعههای Cloud Firestore، نقاط پایانی سرور، و حافظه عامل ۳-سطحی استفاده کنید.
برای دسترسی به این آرتیفکت، به سیستم وارد شوید
با «نمایه توسعهدهنده Google» خود به سیستم وارد شوید تا بتوانید کل مصنوع استفادهشده در مجموعه Build It! را مشاهده و کپی کنید.
نمایه توسعهدهندگان نرمافزار لازم است
واجدشرایط نمایه توسعهدهندگان نیستید. به سرپرست فضای کاریتان اطلاع دهید تا این ویژگی را فعال کند.
ایجاد نمایه تولیدکننده
برای باز کردن قفل همه پیاموارهها و مصنوعات Build It!، «نمایه توسعهدهنده Google» رایگان ایجاد کنید.
برای باز کردن قفل، به Builder Central بپیوندید
با یک کلیک، نشان عضویت رایگان «سازنده» را مطالبه کنید تا قفل همه پیاموارهها و خروجیهای ساختاریافته Build It! باز شود.
وضعیت: درحال انجام (پیشنویس با «همیار برنامهریزی»)
پایگاه داده هدف: Google Cloud Firestore
هدف معماری: بازسازی تمیز، قابلنگهداری، و آماده تولید نمونه اولیه تناسب اندام هوشمند AI Studio.
۰. تصمیمات مربوط به معماری سیستم و پشته فنی اصلی
برای اطمینان از پایداری تولید، عملکرد، و مرزهای مشخص، خط مبنای معماری زیر برای همه پیادهسازیها قفل شده است:
- چارچوب Frontend: Next.js (App Router، React 19) با ذخیره موقت دارایی آفلاین «برنامه وب پیشرو» (PWA) (بااستفاده از Serwist /
@ducanh2912/next-pwa). - Styling & UI Components: Tailwind CSS v4 + Tailwind Variants (for variant management) + Lucide React (icons).
- معماری وضعیت مشتری:
- Zustand (با میانافزار
persist): وضعیت محلی، لمسی، و زودگذر کارخواه را مدیریت میکند (زمانسنجهای وقتنگهدار، میانگیرهای مجموعه فعال، نمودار گام، و ورودیهای ذخیرهنشده سالن ورزشی). - TanStack Query (React Query): همه حالتهای ناهمگام سرور، ذخیرهسازی سند Firestore، اعتبارسنجی مجدد پسزمینه، حذف تکرار درخواست، و جهشهای خوشبینانه را مدیریت میکند.
- Zustand (با میانافزار
- زمان اجرای زیرینه و میزبانی API: Next.js Route Handlers (
app/api/...) میزبانیشده در Google Cloud Run در همان منطقه Firestore و Gemini Context Caching برای تأخیر داخلی زیر ۱۵ میلیثانیه. - اصالتسنجی: اصالتسنجی Firebase (ورود به سیستم با Google، ایمیل/گذرواژه، و پیوند آمادهسازی ناشناس). کارخواه
Authorization: Bearer <Firebase_ID_Token>را به همه درخواستهای API پیوست میکند؛ سرور هویت را بااستفاده ازfirebase-admin.auth().verifyIdToken(token)درستیسنجی میکند. - پایگاه داده اصلی: Google Cloud Firestore.
۱. نمای کلی سیستم و مسیر کاربر اصلی
۱.۱ اصول معماری و دامنه
این مشخصات مدلهای داده، طرحهای Cloud Firestore، قراردادهای نقطه پایانی سرور، و ساختارهای حافظه عامل هوش مصنوعی را برای برنامه Smart Fitness تعریف میکند. این سند یک منبع واحد حقیقت برای همه برنامهریزیهای تمرین، ثبت سابقه جلسات، و حافظه مربیگری چندسطحی مستقل ایجاد میکند که کاملاً از چارچوبهای ارائه سمت کاربر (که در مشخصات طراحی UI/UX اختصاصی به آنها پرداخته شده است) جدا شده است.
۱.۲ اصول اصلی دادهها
- جداسازی نگرانیها: مرز دقیق بین قراردادهای داده (باطن/پایگاه داده) و طراحی میانای کاربر کارخواه.
- معماری کتابخانه ترکیبی: دانشنامه تمرین ثابت و تغییرناپذیر (
exercises) همراه با ترکیببندی پویای هوش مصنوعی از برنامههای هفتگی (weekly_plans). - تغییرات مرحلهای با مشارکت انسانی در حلقه: تغییرات تمرین تولیدشده با هوش مصنوعی بهعنوان پیشنهادهای مرحلهای برگردانده میشوند؛ نوشتن در پایگاه داده منحصراً پساز پذیرش صریح کاربر انجام میشود.
- حافظه زنده ۳سطحی پیوسته: هوش مصنوعی بهطور خودکار حقایق کاربر را در سراسر موارد دائمی، حالتهای فیزیولوژیکی منقضیشده (با TTL صریح)، و بافت موقعیتی گذرا ضبط، بهروزرسانی، و پاک میکند.
- خوانشهای دانهای تکسندی: دادهها در اسناد بهینهسازیشده (مانند دفترهای سیمی برنامه هفتگی و دستههای گپ هفتگی) ساختاردهی میشوند تا تأخیر خوانش به حداقل برسد و پُرسمانهای زائد حذف شوند.
۲. نقطههای پایانی سرور و قراردادهای میانای برنامهسازی کاربردی
هر نقطه پایانی باید منبع پاسخ (
AGENT،DATABASE، یاHYBRID) را مشخص کند تا نقاط پایانی با پشتیبانی نماینده بتوانند بهدرستی درطول پیادهسازی پیکربندی شوند.
POST /api/coach/chat
- هدف: تعامل مکالمهای با «مربی شخصی هوش مصنوعی»، رسیدگی به سؤالات مربیگری، پشتیبانی انگیزشی، و تولید اصلاحات پیشنهادی برای تمرین (هم اصلاحات روزانه و هم بازنگریهای هفتگی).
- راهانداز: کاربر پیامی را در برگه «مربی» ارسال میکند یا روی تراشه ویرایش پیشنهادی بافتاری درونخطی (مثلاً «پرس آرنولد را با پرس شانه با دمبل جایگزین کن») تکضرب میزند.
- منبع پاسخ:
AGENT— از Gemini با قابلیتهای فراخوانی تابع/ابزار ساختاریافته و جاریسازی استفاده میکند. مستقیماً پایگاه داده را تغییر نمیدهد؛ پیشنهاد مرحلهای را برای بازبینی مشارکت انسانی در حلقه برمیگرداند. - سرصفحهها:
Authorization: Bearer <Firebase_ID_Token>،Content-Type: application/json
پایهبار درخواست:
{
"message": "string (user input or selected prompt chip text)",
"context": {
"active_tab": "string (enum: today | week | coach)",
"week_start_date": "string (ISO date YYYY-MM-DD)",
"selected_day": "string (e.g. monday, optional)"
}
}پایهبار پاسخ:
{
"message": "string (conversational coaching response displayed in chat bubble)",
"proposal": {
"id": "string (unique proposal ID, nullable)",
"type": "string (enum: NONE | UPDATE_DAY | UPDATE_WEEK)",
"target_day": "string (e.g. monday, nullable)",
"summary_diff": "string (concise summary of changes, e.g. 'Swapped Arnold Press ➔ DB Shoulder Press', nullable)",
"data": "map (full proposed workout day object or weekly plan object, nullable)"
},
"memory_mutations": [
{
"operation": "string (enum: CREATE | UPDATE | DELETE)",
"target_tier": "string (enum: tier_1_staples | tier_2_physiological | tier_3_situational)",
"memory_id": "string (required for UPDATE and DELETE)",
"entry": "map (memory payload with fact, category, expires_at, etc., required for CREATE and UPDATE)",
"reason": "string (concise rationale for why memory was mutated)"
}
]
}- نوشتن دوگانه در
weekly_chats: در هر نوبت، سرور پیام ورودی کاربر (text) و پاسخ مربی (text) را بااستفاده ازFieldValue.arrayUnion()در/users/{userId}/weekly_chats/{week_start_date}ذخیره میکند. - الگوی جهش مرحلهای: بار داده پیشنهادی را بدون تغییر دادن
/weekly_plansبرمیگرداند تا زمانی که کاربر روی [پذیرفتن طرح] تکضرب بزند. - مدیریت حافظه خودکار پیوسته:
memory_mutationsرا برای ایجاد، بهروزرسانی، یا پاکسازی موارد از نمایه ۳سطحی کاربر صادر میکند.
POST /api/workouts/log
- هدف: جلسه تمرین تکمیلشده را در بایگانی تمرین دائمی کاربر حفظ میکند، مجموع حجم/تکرار نهایی را محاسبه میکند، رکوردهای شخصی (PR) را بررسی میکند، و روز زمانبندیشده را بهعنوان تکمیلشده علامتگذاری میکند.
- راهانداز: کاربر روی «پایان تمرین» در صفحه پیگیری تمرین تکضرب میزند.
- منبع پاسخ:
DATABASE— تراکنش مستقیم پایگاه داده/نوشتن در Cloud Firestore.
پایهبار درخواست:
{
"plan_reference": {
"week_start_date": "string (ISO date YYYY-MM-DD)",
"day_of_week": "string (e.g. monday)"
},
"title": "string (e.g. Upper Body Hypertrophy)",
"started_at": "string (ISO timestamp)",
"completed_at": "string (ISO timestamp)",
"duration_seconds": "number (e.g. 3120)",
"exercises_logged": [
{
"exercise_id": "string (canonical slug, e.g. incline-db-bench-press)",
"exercise_name": "string (e.g. Incline DB Bench Press)",
"sets": [
{
"set_number": "number (e.g. 1)",
"weight_lbs": "number (e.g. 60)",
"reps_completed": "number (e.g. 12)",
"completed": "boolean"
}
]
}
],
"user_notes": "string (optional subjective feedback)",
"perceived_exertion": "number (optional 1-10 RPE rating)"
}پایهبار پاسخ:
{
"success": "boolean",
"log_id": "string (newly created workout log document ID)",
"summary": {
"total_volume_lbs": "number",
"total_sets_completed": "number",
"total_reps_completed": "number"
},
"new_prs": [
{
"exercise_id": "string (canonical slug, e.g. incline-db-bench-press)",
"metric": "string (e.g. '10 Rep Max' or 'Estimated 1RM')",
"value": "string (e.g. '65 lbs' or '105 lbs')"
}
]
}۳. معماری پایگاه داده Cloud Firestore
کلکسیون: exercises
سلسلهمراتب: مجموعه ریشه (/exercises/{exercise_id}) • هدف: دانشنامه تمرین ایستا حاوی چندرسانهای، نشانههای فرم، الزامات تجهیزات، و دستورالعملها.
{
"id": "string (canonical slug matching document ID, e.g. incline-db-bench-press)",
"name": "string (e.g. Incline DB Bench Press)",
"category": "string (e.g. Strength, Hypertrophy, Cardio, Mobility)",
"target_muscles": {
"primary": ["string (e.g. Upper Chest)"],
"secondary": ["string (e.g. Front Deltoids, Triceps)"]
},
"media": {
"video_url": "string (URL to demonstration video)",
"poster_url": "string (URL to video poster / thumbnail image)"
},
"instructions": ["string (step-by-step execution guidance)"],
"form_tips": ["string (critical cues and common pitfalls)"],
"equipment_required": ["string (e.g. Dumbbells, Incline Bench)"]
}کلکسیون: weekly_plans
سلسلهمراتب: /users/{userId}/weekly_plans/{week_start_date} • هدف: «دفترچه یادداشت سیمی» حاوی برنامه کامل تمرین هفتگی، سنجههای خلاصه، و تمرینات روزانه فردی.
{
"week_start_date": "string (ISO date YYYY-MM-DD, e.g. 2026-09-07)",
"theme": "string (e.g. Hypertrophy Focus & Upper Body Overload)",
"summary": {
"total_time_minutes": "number (raw minutes, e.g. 180)",
"total_volume_lbs": "number (raw tonnage in lbs, e.g. 38400)",
"frequency": "number (active workout days, e.g. 4)"
},
"suggested_edits": ["string (pre-generated AI prompt suggestion)"],
"days": {
"monday": {
"date": "string (ISO date YYYY-MM-DD)",
"day_of_week": "string (e.g. Monday)",
"is_rest_day": "boolean",
"status": "string (enum: scheduled | completed | skipped)",
"completed_log_id": "string (nullable)",
"completed_at": "string (ISO timestamp, nullable)",
"title": "string (e.g. Upper Body Hypertrophy)",
"focus_tag": "string (e.g. Push & Chest Dominant)",
"duration_minutes": "number",
"estimated_volume_lbs": "number",
"coach_note": "string",
"muscle_focus": [{ "muscle": "string", "intensity": "number (0-100)" }],
"suggested_edits": ["string"],
"blocks": [
{
"label": "string (e.g. Main Compound Block)",
"exercises": [
{
"exercise_id": "string",
"name": "string",
"target_sets": "number",
"target_reps": "string or number",
"rest_seconds": "number"
}
]
}
]
}
}
}کلکسیون: weekly_chats
سلسلهمراتب: /users/{userId}/weekly_chats/{week_start_date} • هدف: «Weekly Chat Bucket» حاوی سابقه کامل مکالمه برای یک هفته آموزشی مشخص در یک سند خواندهشده.
{
"week_start_date": "string (ISO date YYYY-MM-DD, e.g. 2026-09-07)",
"messages": [
{
"id": "string (unique message ID)",
"sender": "string (enum: user | coach)",
"text": "string (conversational message body)",
"created_at": "timestamp (server timestamp)",
"proposal": {
"id": "string (proposal UID, nullable)",
"type": "string (enum: UPDATE_DAY | UPDATE_WEEK, nullable)",
"target_day": "string (e.g. monday, nullable)",
"summary_diff": "string (nullable)",
"status": "string (enum: pending | accepted | dismissed)",
"data": "map (workout or week snapshot payload, nullable)"
}
}
]
}کلکسیون: workout_logs
سلسلهمراتب: /users/{userId}/workout_logs/{log_id} • هدف: بایگانی دائمی و تغییرناپذیر سابقه جلسههای تمرین تکمیلشده.
{
"id": "string (document ID)",
"plan_reference": {
"week_start_date": "string (ISO date YYYY-MM-DD)",
"day_of_week": "string (e.g. monday)"
},
"title": "string (e.g. Upper Body Hypertrophy)",
"started_at": "timestamp",
"completed_at": "timestamp",
"duration_seconds": "number",
"summary": {
"total_volume_lbs": "number",
"total_sets_completed": "number",
"total_reps_completed": "number"
},
"exercises_logged": [
{
"exercise_id": "string",
"exercise_name": "string",
"sets": [
{
"set_number": "number",
"weight_lbs": "number",
"reps_completed": "number",
"completed": "boolean"
}
]
}
],
"user_notes": "string (nullable)",
"perceived_exertion": "number (1-10 RPE, nullable)"
}کلکسیون: user_profiles
سلسلهمراتب: /users/{userId}/profile/main • هدف: «نمودار مشتری زنده» که نمایه حافظه ۳ سطحی کاربر را ذخیره میکند.
{
"user_id": "string (document owner UID)",
"display_name": "string (e.g. Alex)",
"email": "string (e.g. alex@example.com)",
"preferences": {
"units": "string (enum: lbs | kg)",
"haptics": "boolean",
"sound": "boolean"
},
"equipment_ids": ["string (e.g. 'dumbbells', 'bench_adjustable', 'pull_up_bar')"],
"onboarding_status": "string (enum: not_started | in_progress | completed)",
"created_at": "timestamp",
"tier_1_staples": [
{
"id": "string (e.g. mem_01)",
"category": "string (enum: equipment | preference | goal | chronic_condition)",
"fact": "string (e.g. Home gym with dumbbells up to 50 lbs and adjustable bench)",
"source": "string (e.g. conversational_onboarding | manual_entry)"
}
],
"tier_2_physiological": [
{
"id": "string (e.g. mem_02)",
"body_part": "string (e.g. hamstrings, shoulder)",
"condition": "string (e.g. soreness, acute_fatigue, minor_strain)",
"fact": "string (e.g. Hamstrings are moderately sore from hill sprints)",
"effective_date": "string (ISO date YYYY-MM-DD)",
"expires_at": "timestamp"
}
],
"tier_3_situational": [
{
"id": "string (e.g. mem_03)",
"event": "string (e.g. golf_competition, travel)",
"fact": "string (e.g. Major golf tournament on Saturday; avoid excessive arm/lat fatigue on Friday)",
"week_start_date": "string (ISO date YYYY-MM-DD)",
"expires_at": "timestamp"
}
]
}کلکسیون: prs
سلسلهمراتب: /users/{userId}/prs/{exercise_slug} • هدف: «سوابق شخصی» همیشگی، معیارهای تخمینی «بیشینه یک تکرار»، و سوابق مختص تکرار را ذخیره میکند.
{
"exercise_id": "string (canonical slug, e.g. incline-db-bench-press)",
"exercise_name": "string (e.g. Incline DB Bench Press)",
"estimated_1rm": "number (calculated using Brzycki formula, e.g. 105)",
"max_weight_set": {
"weight_lbs": "number (e.g. 80)",
"reps": "number (e.g. 10)",
"achieved_at": "timestamp"
},
"rep_records": {
"10": 80,
"8": 85,
"5": 95
},
"last_updated": "timestamp"
}۴. چرخه حیات داده و خط لوله عامل
۴.۱ خط لوله ۱: مربیگری، تولید تمرین، و اصلاح مرحلهای
- کنش کاربر: ورودی با قالب آزاد ارسال میکند یا روی تراشه ویرایش بافتاری ازپیش تولیدشده ضربه میزند.
- مونتاژ بافت: سرور نمایه حافظه ۳-سطحی فعال و طرح هفته جاری را بازیابی میکند و موارد حافظه منقضیشده را هرس میکند.
- استنتاج عامل: Gemini پیامواره و بافت را بااستفاده از فراخوانی تابع/ابزار ساختاریافته پردازش میکند.
- جهش حافظه خودکار: حقایق استخراجشده کاربر در
/user_profiles/{userId}اعمال میشود و باequipment_idsهمگامسازی میشود. - Staged Proposal Staging: اصلاحات پیشنهادی تمرین با
proposal.status = "pending"در/weekly_chats/{week_start_date}برگردانده میشود. - وضوح و پایداری کاربر: تکضرب زدن روی [پذیرفتن طرح] دادههای پیشنهادی را به
/weekly_plansمتعهد میکند و پیشنهاد را بهعنوان"accepted"علامتگذاری میکند.
۴.۲ خط لوله ۲: اجرای تمرین و بایگانی کردن (واقعیت عینی)
- ضبط جلسه زنده: کارخواه بار واقعی بلندشده، تکرارهای تکمیلشده، و پرچمهای تکمیل را در وضعیت واسط کاربر محلی ردیابی میکند.
- ارسال جلسه: کارخواه
POST /api/workouts/logرا در «پایان تمرین» فراخوانی میکند. - محاسبه و اعتبارسنجی انبوه: سرور حجم تجمعی جلسه را محاسبه میکند و بااستفاده از فرمول برزیکی، رکوردهای شخصی را بررسی میکند.
- پایداری تغییرناپذیر: یک رکورد تغییرناپذیر در
/workout_logsمینویسد، روز"completed"را در/weekly_plansعلامتگذاری میکند، و درخواستهای ادغام جدید را در/prsبهروزرسانی میکند.
۴.۳ خط لوله ۳: دریافت و باطلسازی خودکار حافظه
- جذب: حقایق بهطور مداوم ازطریق همه تعاملهای مکالمهای استخراج میشوند.
- طبقهبندی: سطح ۱ (اصلی، بدون انقضا)، سطح ۲ (وضعیت فیزیولوژیکی، TTL ۳ تا ۴ روزه)، سطح ۳ (بافتار موقعیتی، TTL مبتنی بر رویداد).
- هرس کردن و باطل کردن: موارد منقضیشده (
current_timestamp > expires_at) از بافت پیامواره فیلتر میشوند و بهصورت تنبل پاکسازی میشوند.
۵. مشخصات نمایه ترکیبی و قوانین امنیتی Firestore
۵.۱ قوانین امنیتی (firestore.rules)
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
match /profile/{document=**} { allow read, write: if request.auth != null && request.auth.uid == userId; }
match /weekly_plans/{planId} { allow read, write: if request.auth != null && request.auth.uid == userId; }
match /weekly_chats/{chatId} { allow read, write: if request.auth != null && request.auth.uid == userId; }
match /prs/{exerciseSlug} { allow read, write: if request.auth != null && request.auth.uid == userId; }
match /workout_logs/{logId} {
allow read, create: if request.auth != null && request.auth.uid == userId;
allow update, delete: if false;
}
}
match /exercises/{exerciseId} {
allow read: if request.auth != null;
allow write: if false;
}
}
}۵.۲ نمایههای پُرسمان ترکیبی (firestore.indexes.json)
{
"indexes": [
{
"collectionGroup": "workout_logs",
"queryScope": "COLLECTION",
"fields": [{ "fieldPath": "completed_at", "order": "DESCENDING" }]
},
{
"collectionGroup": "weekly_plans",
"queryScope": "COLLECTION",
"fields": [{ "fieldPath": "week_start_date", "order": "DESCENDING" }]
},
{
"collectionGroup": "prs",
"queryScope": "COLLECTION",
"fields": [{ "fieldPath": "last_updated", "order": "DESCENDING" }]
}
]
}۶. گزارش تغییرات و تصمیمات قفلشده
| تاریخ | عنصر / تصمیم | نوع | قفلشده توسط |
|---|---|---|---|
| راهاندازی اولیه | داربست مشخصات خالی مقداردهی اولیه شد | راهاندازی سیستم | تیم |
| 2026-09-04 | مجموعههای Firestore اضافهشده: exercises و weekly_plans | طرح | تیم |
| 2026-09-04 | نقطه پایانی POST /api/coach/chat و مجموعه chat_messages اضافه شد | نقطه پایانی و طرحواره | تیم |
| 2026-09-04 | Refactored chat storage to weekly_chats bucket schema | طرح | تیم |
| 2026-09-04 | نقطه پایانی POST /api/workouts/log و مجموعه workout_logs اضافه شد | نقطه پایانی و طرحواره | تیم |
| 2026-09-04 | Added user_profiles 3-tier memory schema & updated POST /api/coach/chat with memory_mutations | نقطه پایانی و طرحواره | تیم |
| 2026-09-04 | بخش ۱ (دامنه و اصول سیستم) و بخش ۴ (چرخه حیات و خطوط لوله داده) تکمیل شده است | تکمیل مشخصات کامل | تیم |
| 2026-09-22 | مشخصات هماهنگشده: پشته Next.js + Tailwind + Zustand، احراز هویت Bearer، زیرمجموعه PR، قوانین Firestore، و نامکهای تمرین متعارف | هماهنگسازی کامل مشخصات | بازبینی معماری |