mitai-jinkendo/backend/models.py
Lars 410b2ce308
All checks were successful
Deploy Development / deploy (push) Successful in 49s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s
feat(v9d): add training types system + logout button
Phase 1: Training Types Basis
=============================

Backend:
- Migration 004: training_types table + seed data (24 types)
- New router: /api/training-types (grouped, flat, categories)
- Extend activity_log: training_type_id, training_category, training_subcategory
- Extend ActivityEntry model: support training type fields

Frontend:
- TrainingTypeSelect component (two-level dropdown)
- TrainingTypeDistribution component (pie chart)
- API functions: listTrainingTypes, listTrainingTypesFlat, getTrainingCategories

Quick Win: Logout Button
========================
- Add LogOut icon button in app header
- Confirm dialog before logout
- Redirect to / after logout
- Hover effect: red color on hover

Not yet integrated:
- TrainingTypeSelect not yet in ActivityPage form
- TrainingTypeDistribution not yet in Dashboard
  (will be added in next commit)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 13:05:33 +01:00

129 lines
3.9 KiB
Python

"""
Pydantic Models for Mitai Jinkendo API
Data validation schemas for request/response bodies.
"""
from typing import Optional
from pydantic import BaseModel
# ── Profile Models ────────────────────────────────────────────────────────────
class ProfileCreate(BaseModel):
name: str
avatar_color: Optional[str] = '#1D9E75'
sex: Optional[str] = 'm'
dob: Optional[str] = None
height: Optional[float] = 178
goal_weight: Optional[float] = None
goal_bf_pct: Optional[float] = None
class ProfileUpdate(BaseModel):
name: Optional[str] = None
avatar_color: Optional[str] = None
sex: Optional[str] = None
dob: Optional[str] = None
height: Optional[float] = None
goal_weight: Optional[float] = None
goal_bf_pct: Optional[float] = None
# ── Tracking Models ───────────────────────────────────────────────────────────
class WeightEntry(BaseModel):
date: str
weight: float
note: Optional[str] = None
class CircumferenceEntry(BaseModel):
date: str
c_neck: Optional[float] = None
c_chest: Optional[float] = None
c_waist: Optional[float] = None
c_belly: Optional[float] = None
c_hip: Optional[float] = None
c_thigh: Optional[float] = None
c_calf: Optional[float] = None
c_arm: Optional[float] = None
notes: Optional[str] = None
photo_id: Optional[str] = None
class CaliperEntry(BaseModel):
date: str
sf_method: Optional[str] = 'jackson3'
sf_chest: Optional[float] = None
sf_axilla: Optional[float] = None
sf_triceps: Optional[float] = None
sf_subscap: Optional[float] = None
sf_suprailiac: Optional[float] = None
sf_abdomen: Optional[float] = None
sf_thigh: Optional[float] = None
sf_calf_med: Optional[float] = None
sf_lowerback: Optional[float] = None
sf_biceps: Optional[float] = None
body_fat_pct: Optional[float] = None
lean_mass: Optional[float] = None
fat_mass: Optional[float] = None
notes: Optional[str] = None
class ActivityEntry(BaseModel):
date: str
start_time: Optional[str] = None
end_time: Optional[str] = None
activity_type: str
duration_min: Optional[float] = None
kcal_active: Optional[float] = None
kcal_resting: Optional[float] = None
hr_avg: Optional[float] = None
hr_max: Optional[float] = None
distance_km: Optional[float] = None
rpe: Optional[int] = None
source: Optional[str] = 'manual'
notes: Optional[str] = None
training_type_id: Optional[int] = None # v9d: Training type categorization
training_category: Optional[str] = None # v9d: Denormalized category
training_subcategory: Optional[str] = None # v9d: Denormalized subcategory
class NutritionDay(BaseModel):
date: str
kcal: Optional[float] = None
protein_g: Optional[float] = None
fat_g: Optional[float] = None
carbs_g: Optional[float] = None
# ── Auth Models ───────────────────────────────────────────────────────────────
class LoginRequest(BaseModel):
email: str
password: str
class PasswordResetRequest(BaseModel):
email: str
class PasswordResetConfirm(BaseModel):
token: str
new_password: str
class RegisterRequest(BaseModel):
name: str
email: str
password: str
# ── Admin Models ──────────────────────────────────────────────────────────────
class AdminProfileUpdate(BaseModel):
role: Optional[str] = None
ai_enabled: Optional[int] = None
ai_limit_day: Optional[int] = None
export_enabled: Optional[int] = None