feat: §5.2 batch — trend lineare, soglia allarme, guide misure, daily check-in
Quattro feature del PRD §5.2 Tracking peso e progressi.
§5.2.1 Trend regressione lineare + proiezione
- @ketopath/shared/tracking/weight-trend: linearWeightTrend() (least squares),
projectGoalDate() con cap a 52 settimane e check di direzione coerente
- 9 unit test (slope/intercept, segno, cap)
- /tracking: terza statistica "Trend settimanale" + frase
"Al ritmo attuale raggiungerai 75.0 kg il 24 luglio 2026"
§5.2.2 Soglia di allarme peso personalizzabile
- Profile.alertWeightKg @encrypted
- profileInputSchema accetta il campo, profile.routes lo persiste
- ProfileForm: nuovo input "Soglia di allarme peso (kg)"
- /tracking: banner pomodoro "Sei sopra la soglia" con suggerimento
"settimana di riparazione" senza colpa
§5.2.3 Linee guida "come misurare bene"
- Disclosure inline in WeightEntryForm con istruzioni tecniche per
girovita, fianchi, coscia, braccio + tip generale (ora del giorno,
metro morbido, stessa procedura)
§5.2.4 Daily check-in indicatori soggettivi
- Nuovo modello DailyCheckIn (date, energy, sleep, hunger, mood, notes)
con unique(userId, date) e migration
- shared dailyCheckInInputSchema (zod)
- API: GET /me/check-ins (last 30), GET /me/check-ins/today,
POST /me/check-ins (upsert sul giorno)
- /tracking: card lampo in cima con 4 slider 1-10 + Salva/Aggiorna,
10 secondi di compilazione
i18n: namespace Tracking esteso (weeklyTrend, projection, alertEyebrow/Message/Hint,
measurementsHelpToggle + measurementGuides{}, checkIn*, mood). Profile esteso
(alertWeightKg + hint).
Schema migrations: add_alert_weight_kg, add_daily_check_in.
81/81 unit test verdi (9 nuovi). Lint, typecheck verdi.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
ea88ed8775
commit
9327e75395
18 files changed
+627
-8
No files matched your search
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "profiles" ADD COLUMN "alert_weight_kg" TEXT;
|
||||
@@ -0,0 +1,24 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "daily_check_ins" (
|
||||
"id" TEXT NOT NULL,
|
||||
"user_id" TEXT NOT NULL,
|
||||
"date" DATE NOT NULL,
|
||||
"energy" INTEGER,
|
||||
"sleep" INTEGER,
|
||||
"hunger" INTEGER,
|
||||
"mood" INTEGER,
|
||||
"notes" TEXT,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "daily_check_ins_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "daily_check_ins_user_id_date_idx" ON "daily_check_ins"("user_id", "date");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "daily_check_ins_user_id_date_key" ON "daily_check_ins"("user_id", "date");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "daily_check_ins" ADD CONSTRAINT "daily_check_ins_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -100,6 +100,7 @@ model User {
|
||||
sessions Session[]
|
||||
accounts Account[]
|
||||
weightEntries WeightEntry[]
|
||||
dailyCheckIns DailyCheckIn[]
|
||||
fastEvents FastEvent[]
|
||||
mealPlans MealPlan[]
|
||||
deviceTokens DeviceToken[]
|
||||
@@ -187,6 +188,10 @@ model Profile {
|
||||
// PRD §5.1 — % grasso corporeo stimata (US Navy) per BMR Katch-McArdle.
|
||||
/// @encrypted
|
||||
bodyFatPct String? @map("body_fat_pct")
|
||||
// PRD §5.2 — soglia di allarme peso. Quando il peso corrente la supera,
|
||||
// mostriamo un banner di "settimana di riparazione" in /tracking.
|
||||
/// @encrypted
|
||||
alertWeightKg String? @map("alert_weight_kg")
|
||||
// PRD §5.1 — storia delle diete restrittive precedenti, per stimare
|
||||
// l'adattamento metabolico (Fothergill 2016, Rosenbaum 2008). Categoriale:
|
||||
// NONE / SOME / EXTENSIVE / SEVERE. Cifrato perché può alludere a
|
||||
@@ -228,6 +233,29 @@ model Preferences {
|
||||
|
||||
// PRD §5.2 — pesata settimanale, misure, indicatori soggettivi.
|
||||
// I campi sanitari sono cifrati at-rest (ADR 0002).
|
||||
// PRD §5.2 — check-in lampo quotidiano (10s): solo indicatori soggettivi.
|
||||
// Distinto da WeightEntry (settimanale, con peso e misure).
|
||||
model DailyCheckIn {
|
||||
id String @id @default(cuid())
|
||||
userId String @map("user_id")
|
||||
date DateTime @db.Date
|
||||
energy Int? // 1..10
|
||||
sleep Int? // 1..10
|
||||
hunger Int? // 1..10
|
||||
mood Int? // 1..10
|
||||
/// @encrypted
|
||||
notes String?
|
||||
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([userId, date])
|
||||
@@index([userId, date])
|
||||
@@map("daily_check_ins")
|
||||
}
|
||||
|
||||
model WeightEntry {
|
||||
id String @id @default(cuid())
|
||||
userId String @map("user_id")
|
||||
|
||||
Reference in new issue
Block a user