Initial project scaffold: FastAPI backend + Svelte 5 frontend
Backend (uv): FastAPI app with routers (foods, log, targets, OFF proxy), SQLAlchemy models, Pydantic schemas, migration runner + 0001 initial schema, example pytest suite (7 tests). Frontend (npm): Vite 7 + Svelte 5 runes, lib/ (api, stores, scanner, format) per spec §7, placeholder components, example vitest suite (4 tests). SPEC.md §1: registered uvicorn and Vitest (rule §8.3.3).
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
-- 0001: initial schema (SPEC.md §2)
|
||||
|
||||
CREATE TABLE foods (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
brand TEXT,
|
||||
barcode TEXT UNIQUE,
|
||||
source TEXT NOT NULL CHECK (source IN ('openfoodfacts', 'manual', 'meal')),
|
||||
is_meal INTEGER NOT NULL DEFAULT 0,
|
||||
unit_type TEXT NOT NULL DEFAULT 'weight' CHECK (unit_type IN ('weight', 'count')),
|
||||
calories_per_unit REAL,
|
||||
protein_per_unit REAL,
|
||||
carbs_per_unit REAL,
|
||||
fat_per_unit REAL,
|
||||
fiber_per_unit REAL,
|
||||
saturated_fat_per_unit REAL,
|
||||
sugars_per_unit REAL,
|
||||
sodium_per_unit REAL,
|
||||
serving_size_g REAL,
|
||||
serving_name TEXT,
|
||||
off_data TEXT,
|
||||
deleted_at TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
||||
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
||||
-- Meal nutrition is derived from components, never stored (spec §2.1)
|
||||
CHECK (is_meal = 1 OR calories_per_unit IS NOT NULL)
|
||||
);
|
||||
|
||||
CREATE TABLE meal_components (
|
||||
id INTEGER PRIMARY KEY,
|
||||
meal_id INTEGER NOT NULL REFERENCES foods(id),
|
||||
food_id INTEGER NOT NULL REFERENCES foods(id),
|
||||
quantity REAL NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE daily_log (
|
||||
id INTEGER PRIMARY KEY,
|
||||
date TEXT NOT NULL, -- client-supplied YYYY-MM-DD (spec §8.1 rule 8)
|
||||
food_id INTEGER NOT NULL REFERENCES foods(id),
|
||||
quantity REAL NOT NULL,
|
||||
meal_slot TEXT CHECK (meal_slot IN ('breakfast', 'lunch', 'dinner', 'snack')),
|
||||
sort_order INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
|
||||
);
|
||||
|
||||
CREATE INDEX idx_daily_log_date ON daily_log(date);
|
||||
|
||||
CREATE TABLE targets (
|
||||
id INTEGER PRIMARY KEY,
|
||||
start_date TEXT NOT NULL,
|
||||
end_date TEXT, -- null = currently active
|
||||
calories INTEGER NOT NULL,
|
||||
protein_g REAL,
|
||||
carbs_g REAL,
|
||||
fat_g REAL
|
||||
);
|
||||
Reference in New Issue
Block a user