feat: replace age integer with date_of_birth across backend and client

Store date_of_birth (DATE) instead of a static age integer so that age
is always computed dynamically from the stored date of birth.

- Migration 011: adds date_of_birth, backfills from age, drops age
- AgeFromDOB helper computes current age from YYYY-MM-DD string
- User model, repository SQL, and service validation updated
- Flutter: User.age becomes a computed getter; profile edit screen
  uses a date picker bounded to [today-120y, today-10y]

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
dbastrikin
2026-03-09 23:37:58 +02:00
parent 765346d4e4
commit c9ddb708b1
13 changed files with 202 additions and 73 deletions

View File

@@ -3,6 +3,7 @@ package user
import (
"context"
"fmt"
"time"
)
type Service struct {
@@ -46,10 +47,11 @@ func (s *Service) UpdateProfile(ctx context.Context, userID string, req UpdatePr
if req.WeightKG != nil {
weight = req.WeightKG
}
age := current.Age
if req.Age != nil {
age = req.Age
dob := current.DateOfBirth
if req.DateOfBirth != nil {
dob = req.DateOfBirth
}
age := AgeFromDOB(dob)
gender := current.Gender
if req.Gender != nil {
gender = req.Gender
@@ -89,9 +91,17 @@ func validateProfileRequest(req UpdateProfileRequest) error {
return fmt.Errorf("weight_kg must be between 30 and 300")
}
}
if req.Age != nil {
if *req.Age < 10 || *req.Age > 120 {
return fmt.Errorf("age must be between 10 and 120")
if req.DateOfBirth != nil {
t, err := time.Parse("2006-01-02", *req.DateOfBirth)
if err != nil {
return fmt.Errorf("date_of_birth must be in YYYY-MM-DD format")
}
if t.After(time.Now()) {
return fmt.Errorf("date_of_birth cannot be in the future")
}
age := AgeFromDOB(req.DateOfBirth)
if *age < 10 || *age > 120 {
return fmt.Errorf("date_of_birth must yield an age between 10 and 120")
}
}
if req.Gender != nil {