Akıllı Fitness Uygulaması: Veri Yapısı, Veritabanı Şeması ve Sunucu Tasarım Spesifikasyonu
ÖğeBu, 2. Bölüm: Uygulamanızın Sistem Spesifikasyonunu Planlama (Kod Yok) bölümünde kullanılan yapıdır. Bu spesifikasyonu Cloud Firestore koleksiyonlarını, sunucu uç noktalarını ve 3 katmanlı temsilci belleğini yapılandırmak için referans olarak kullanabilirsiniz.
Bu öğeye erişmek için oturum açın
Build It! serisinde kullanılan yapının tamamını görüntülemek ve kopyalamak için Google Geliştirici Profilinizle oturum açın.
Geliştirici Profili Gerekli
Geliştirici profili için uygun değilsiniz. Bu özelliği etkinleştirmek için Workspace yöneticinizle iletişime geçin.
Geliştirici Profili oluşturun
Tüm Build It! istemlerinin ve yapılarının kilidini açmak için ücretsiz bir Google Geliştirici Profili oluşturun.
Builder Central'a katılarak erişim elde edin
Tüm Build It! istemlerine ve yapılarına erişmek için ücretsiz Builder üye rozetinizi tek tıklamayla alın.
Status: In Progress (Drafting with Planning Companion)
Target Database: Google Cloud Firestore
Architecture Goal: Clean, maintainable, production-ready rebuild of the AI Studio smart fitness prototype.
0. Temel Teknik Altyapı ve Sistem Mimarisi Kararları
Üretim kararlılığını, performansını ve net sınırları sağlamak için aşağıdaki mimari temel tüm uygulamalarda kilitlenir:
- Ön uç çerçevesi: Progresif Web Uygulaması (PWA) çevrimdışı öğe önbelleğe alma (Serwist /
@ducanh2912/next-pwakullanarak) ile Next.js (App Router, React 19). - Stil ve kullanıcı arayüzü bileşenleri: Tailwind CSS v4 + Tailwind Variants (varyant yönetimi için) + Lucide React (simgeler).
- İstemci Durumu Mimarisi:
- Zustand (
persistara katman yazılımı ile): Yerel, dokunsal ve geçici istemci durumunu (kronometre zamanlayıcıları, etkin set arabellekleri, adım grafiği ve kaydedilmemiş spor salonu girişleri) yönetir. - TanStack Query (React Query): Tüm eşzamansız sunucu durumunu, Firestore belge önbelleğe almayı, arka planda yeniden doğrulamayı, istek tekilleştirmeyi ve iyimser mutasyonları yönetir.
- Zustand (
- Arka uç çalışma zamanı ve API barındırma: 15 milisaniyenin altında dahili gecikme için Firestore ve Gemini bağlam önbelleğe alma ile aynı bölgede Google Cloud Run'da barındırılan Next.js rota işleyicileri (
app/api/...). - Kimlik doğrulama: Firebase Authentication (Google ile Oturum Açma, E-posta/Şifre ve Anonim oryantasyon bağlantısı). İstemci, tüm API isteklerine
Authorization: Bearer <Firebase_ID_Token>ekler; sunucu,firebase-admin.auth().verifyIdToken(token)kullanarak kimliği doğrular. - Birincil Veritabanı: Google Cloud Firestore.
1. Sisteme Genel Bakış ve Temel Kullanıcı Yolculuğu
1.1 Kapsam ve Mimari İlkeleri
Bu spesifikasyon; Smart Fitness uygulamasının veri modellerini, Cloud Firestore şemalarını, sunucu uç nokta sözleşmelerini ve yapay zeka ajanı bellek yapılarını tanımlar. Tüm antrenman planlaması, geçmiş seans kaydı ve otonom katmanlı koçluk hafızası için tek bir doğruluk kaynağı oluşturur. Bu kaynak, ön uç sunum çerçevelerinden (özel bir kullanıcı arayüzü/kullanıcı deneyimi tasarım spesifikasyonunda ele alınır) tamamen ayrılmıştır.
1.2 Temel Veri İlkeleri
- İlgilerin ayrılması: Veri sözleşmeleri (arka uç/veritabanı) ile istemci kullanıcı arayüzü tasarımı arasında kesin bir sınır vardır.
- Karma Kitaplık Mimarisi: Statik, değişmez egzersiz ansiklopedisi (
exercises) ve haftalık programların dinamik yapay zeka kompozisyonu (weekly_plans). - İnsan müdahalesi gerektiren aşamalı mutasyonlar: Yapay zeka tarafından oluşturulan antrenman değişiklikleri, aşamalı teklifler olarak döndürülür. Veritabanı yazma işlemleri yalnızca kullanıcının açık onayıyla gerçekleşir.
- Sürekli 3 Katmanlı Canlı Bellek: Yapay zeka; kalıcı temel bilgiler, süresi dolan fizyolojik durumlar (açık TTL ile) ve geçici durumsal bağlam genelinde kullanıcı bilgilerini otonom olarak yakalar, günceller ve temizler.
- Ayrıntılı tek doküman okuma: Veriler, okuma gecikmesini en aza indirmek ve gereksiz sorguları ortadan kaldırmak için optimize edilmiş dokümanlar (ör. haftalık plan spiral defterleri ve haftalık sohbet grupları) halinde yapılandırılır.
2. Sunucu Uç Noktaları ve API Sözleşmeleri
Temsilci destekli uç noktaların uygulama sırasında uygun şekilde yapılandırılabilmesi için her uç nokta Yanıt Kaynağı'nı (
AGENT,DATABASEveyaHYBRID) belirtmelidir.
POST /api/coach/chat
- Amaç: Yapay zeka destekli kişisel antrenörle etkileşim kurma, koçluk sorularını yanıtlama, motivasyon desteği sağlama ve önerilen antrenman değişikliklerini (hem günlük ayarlamalar hem de haftalık düzenlemeler) oluşturma.
- Tetikleyici: Kullanıcı, Koç sekmesinde bir mesaj gönderir veya satır içi bağlama dayalı önerilen düzenleme çipine (ör. "Arnold Press'i DB Shoulder Press ile değiştir") dokunur.
- Response Source:
AGENT— Yapılandırılmış araç/işlev çağrısı ve akış özellikleriyle Gemini'dan yararlanır. Veritabanını doğrudan değiştirmez. İnsan müdahalesi gerektiren inceleme için aşamalı bir teklif döndürür. - Üstbilgiler:
Authorization: Bearer <Firebase_ID_Token>,Content-Type: application/json
İstek Yükü:
{
"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)"
}
}Yanıt Yükü:
{
"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'e çift yazma: Her turda sunucu, gelen kullanıcı mesajını (text) ve koçun yanıtını (text)FieldValue.arrayUnion()kullanarak/users/{userId}/weekly_chats/{week_start_date}'e kaydeder.- Aşamalı Değişiklik Deseni: Kullanıcı [Planı Kabul Et]'e dokunana kadar
/weekly_plansdeğerini değiştirmeden teklif yükünü döndürür. - Sürekli Otonom Bellek Yönetimi: Kullanıcının 3 katmanlı profilinde öğe oluşturmak, güncellemek veya temizlemek için
memory_mutationsyayınlar.
POST /api/workouts/log
- Amaç: Tamamlanan bir antrenman oturumunu kullanıcının kalıcı antrenman arşivine kaydeder, nihai hacim/tekrar toplamlarını hesaplar, kişisel rekorları (PR) kontrol eder ve planlanan günü tamamlandı olarak işaretler.
- Tetikleyici: Kullanıcı, antrenman takibi ekranında "Antrenmanı Bitir"e dokunur.
- Yanıt Kaynağı:
DATABASE- Doğrudan veritabanı işlemi/Cloud Firestore'a yazma.
İstek Yükü:
{
"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)"
}Yanıt Yükü:
{
"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')"
}
]
}3. Cloud Firestore Veritabanı Mimarisi
Koleksiyon: exercises
Hiyerarşi: Kök Koleksiyon (/exercises/{exercise_id}) • Amaç: Multimedya, form ipuçları, ekipman gereksinimleri ve talimatlar içeren statik egzersiz ansiklopedisi.
{
"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)"]
}Koleksiyon: weekly_plans
Hiyerarşi: /users/{userId}/weekly_plans/{week_start_date} • Amaç: Haftalık antrenman programının tamamını, özet metrikleri ve her günün antrenmanlarını içeren "Spiral Notebook".
{
"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"
}
]
}
]
}
}
}Koleksiyon: weekly_chats
Hiyerarşi: /users/{userId}/weekly_chats/{week_start_date} • Amaç: Belirli bir eğitim haftasının tüm sohbet geçmişini tek bir belge okumasında içeren "Haftalık Sohbet Grubu".
{
"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)"
}
}
]
}Koleksiyon: workout_logs
Hiyerarşi: /users/{userId}/workout_logs/{log_id} • Amaç: Tamamlanan antrenman seanslarının kalıcı, değiştirilemez geçmiş arşivi.
{
"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)"
}Koleksiyon: user_profiles
Hiyerarşi: /users/{userId}/profile/main • Amaç: Kullanıcının 3 katmanlı hafıza profilini depolayan "Canlı Müşteri Tablosu".
{
"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"
}
]
}Koleksiyon: prs
Hiyerarşi: /users/{userId}/prs/{exercise_slug} • Amaç: Tüm zamanların kişisel rekorlarını, tahmini 1 tekrarlı maksimum karşılaştırmaları ve tekrara özel rekorları depolar.
{
"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"
}4. Veri Yaşam Döngüsü ve Temsilci Ardışık Düzeni
4.1 Ardışık Düzen 1: Koçluk, Antrenman Oluşturma ve Aşamalı Değişiklik
- Kullanıcı İşlemi: Serbest biçimli giriş gönderir veya önceden oluşturulmuş bağlamsal düzenleme çipine dokunur.
- Bağlam Birleştirme: Sunucu, etkin 3 katmanlı hafıza profilini ve mevcut haftanın planını alır, süresi dolmuş hafıza öğelerini ayıklar.
- Temsilci Çıkarımı: Gemini, yapılandırılmış araç/işlev çağrısını kullanarak istemi ve bağlamı işler.
- Otonom Bellek Mutasyonu: Ayıklanan kullanıcı bilgileri
/user_profiles/{userId}hizmetine uygulanır veequipment_idsile senkronize edilir. - Aşamalı Teklif Hazırlama: Önerilen antrenman değişiklikleri,
/weekly_chats/{week_start_date}içindeproposal.status = "pending"ile döndürülür. - Kullanıcı Çözümlemesi ve Kalıcılık: [Planı Kabul Et]'e dokunulduğunda önerilen veriler
/weekly_plans'e kaydedilir ve teklif"accepted"olarak işaretlenir.
4.2 2. Ardışık Düzen: Antrenman Uygulama ve Arşivleme (Gerçek Doğru)
- Canlı Oturum Kaydı: İstemci, kaldırılan gerçek yükü, tamamlanan tekrarları ve tamamlanma işaretlerini yerel kullanıcı arayüzü durumunda izler.
- Oturum Gönderme: İstemci, "Antrenmanı Bitir" seçeneğinde
POST /api/workouts/logyöntemini çağırır. - Toplu Hesaplama ve Doğrulama: Sunucu, kümülatif seans hacmini hesaplar ve Brzycki formülünü kullanarak PR'leri kontrol eder.
- Değişmez Kalıcılık:
/workout_logstablosuna değişmez bir kayıt yazar,/weekly_planstablosunda"completed"gününü işaretler ve/prstablosuna yeni PR'leri ekler veya günceller.
4.3 Ardışık Düzen 3: Otonom Bellek Alımı ve Geçersiz Kılma
- Besleme: Gerçekler, tüm etkileşimli sohbetlerden sürekli olarak çıkarılır.
- Sınıflandırma: 1. Kademe (Temel ihtiyaçlar, geçerlilik süresi yok), 2. Kademe (Fizyolojik durum, 3-4 günlük TTL), 3. Kademe (Durumsal bağlam, etkinliğe dayalı TTL).
- Budama ve geçersiz kılma: Süresi dolan öğeler (
current_timestamp > expires_at) istem bağlamından filtrelenir ve geç temizlenir.
5. Firestore Güvenlik Kuralları ve Bileşik Dizin Özellikleri
5.1 Güvenlik Kuralları (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;
}
}
}5.2 Bileşik Sorgu Dizinleri (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" }]
}
]
}6. Değişiklik günlüğü ve kilitli kararlar
| Tarih | Bileşen/Karar | Tür | Kilitleyen |
|---|---|---|---|
| İlk Kurulum | Boş spesifikasyon iskeleti başlatıldı | Sistem Kurulumu | Ekip |
| 2026-09-04 | Added Firestore collections: exercises and weekly_plans | Şema | Ekip |
| 2026-09-04 | POST /api/coach/chat uç noktası ve chat_messages koleksiyonu eklendi | Uç nokta ve şema | Ekip |
| 2026-09-04 | Sohbet depolama alanı, weekly_chats paketi şemasına göre yeniden düzenlendi. | Şema | Ekip |
| 2026-09-04 | POST /api/workouts/log uç noktası ve workout_logs koleksiyonu eklendi | Uç nokta ve şema | Ekip |
| 2026-09-04 | user_profiles 3 katmanlı bellek şeması eklendi ve POST /api/coach/chat, memory_mutations ile güncellendi | Uç nokta ve şema | Ekip |
| 2026-09-04 | 1. Bölüm (Sistem Kapsamı ve İlkeleri) ve 4. Bölüm (Veri Yaşam Döngüsü ve Ardışık Düzenleri) tamamlandı. | Tam Spesifikasyon Tamamlama | Ekip |
| 2026-09-22 | Uyumlaştırılmış spesifikasyonlar: Next.js + Tailwind + Zustand yığını, Bearer kimlik doğrulaması, PR alt koleksiyonu, Firestore kuralları ve standart egzersiz kısa adları | Tam Spesifikasyon Harmonizasyonu | Mimari İnceleme |