Use one canonical representation
Nutrition values are stored per 100 grams, with grams and milliliters as base units. Conversions happen at explicit boundaries instead of creating parallel representations.
An offline-first Flutter nutrition tracker designed around a strict domain model: canonical units, centralized calculations, and clear boundaries between business logic and UI.
01 / Context
Nutrition apps look simple at the screen level, but their data model becomes fragile quickly. Serving sizes, unit conversion, recipe totals, and daily logs can all produce conflicting answers when calculation logic leaks into widgets or each feature stores nutrition differently.
This project starts with the domain rules instead of the interface. Nutrition is normalized to a single internal representation, recipes are derived from ingredients, and the presentation layer only asks for results. That foundation is intended to keep later feature work consistent and testable.
02 / System
03 / Decisions
Nutrition values are stored per 100 grams, with grams and milliliters as base units. Conversions happen at explicit boundaries instead of creating parallel representations.
A centralized nutrition engine owns portion calculations, unit conversion, and recipe aggregation. Widgets consume domain results rather than reimplementing formulas.
Recipes are compositions, not separately maintained nutrition records. Totals are derived from ingredient values and quantities so edits have one source of truth.
Drift and SQLite provide the intended local persistence boundary. Riverpod coordinates application state while repositories separate storage concerns from domain behavior.
04 / Delivery
Current state
Phase 1 establishes the architecture, navigation, feature surfaces, documentation, and testing setup. The case study describes the intended system design without presenting placeholder screens as finished product functionality.