7.3 KiB
Culinary data model
Direction
Schema version 2 is a vendor-neutral culinary domain model designed to map cleanly to relational tables while remaining portable, reviewable YAML. Astro is a presentation consumer only. It must not become the authority for quantities, conversions, nutrition, allergens, purchasing, or calculated values.
schema_version describes a document's data contract. Recipes represent their
current canonical state. Names used for search or display belong in ingredient
aliases; canonical references always use stable entity IDs.
Canonical and derived boundaries
Canonical writable records live in SQLite. They include authored or observed
facts: recipes, ingredients, measurements, provenance, suppliers, packages,
and price observations. YAML under culinary/ is portable seed/interchange
data, while generated site projections and exports are downstream products.
Neither is an independently writable source of truth.
Derived recipe records contain reproducible nutrition, allergen rollups, and costs. They identify the recipe, calculation version, calculation time, and an input fingerprint. Derived values are disposable and must never be copied back into canonical source fields as though they were observations.
Entity model
The schema set in container/schemas/v2/ defines these prospective relational
entities:
| Entity | Main relationships |
|---|---|
| Recipe | components; ordered lines and steps; ingredients or sub-recipes |
| Ingredient | aliases; sourced density/measure observations; nutrition/allergen mappings |
| Unit | dimension and conversion to a base unit within that dimension |
| Prep action | optional default edible-yield factor |
| Source mapping | ingredient, purchasing-item, or recipe nutrition/allergen evidence |
| Supplier | purchasing items |
| Purchasing item | ingredient, supplier, package, dated prices, product mappings |
| Equipment | referenced by recipe steps |
| Collection | ordered recipe references for menus or collections |
| Derived recipe | calculated cost, nutrition, allergens, completeness, and warnings |
Recipe components, component lines, and preparation steps are embedded because they form a recipe aggregate and are edited together. Reusable facts remain independent records referenced by stable IDs.
Equipment is a reusable, vendor-neutral entity. A recipe may declare equipment
needed anywhere in the process with equipment_ids; individual steps may add
their own equipment_ids to show when each item is used. The displayed setup
list is the union of both sets, without duplicating equipment definitions in
recipe files.
Allergen mappings and suppliers are optional capabilities. A purchasing item may record an exact product, package, and price without identifying a formal supplier. Recipes and ingredients never require allergen or supplier records.
Quantities, scaling, and yield
An amount is always a numeric quantity plus a normalized unit_id. A recipe
declares amount, percentage, or hybrid scaling. Hybrid records include both
canonical amounts and percentages; calculation tooling must verify agreement
against the declared basis.
Recipe yield is explicit and identifies whether it is measured, estimated, or theoretical. A finished measured yield is preferred for per-100-gram nutrition and costing. Serving count and serving size are separate optional facts.
Prep actions may override their default yield_factor on a recipe line. The
recipe amount is the usable quantity entering the formula; the factor determines
the larger as-purchased quantity required for costing. For example, 100 grams of
usable onion at an 80% prep yield requires purchasing 125 grams. Cooking loss
that affects the entire recipe belongs in recipe yield, not an ingredient
purchase factor.
In operational recipe management, the finished recipe yield is authoritative for costing, portioning, and per-weight nutrition. Record the actual finished weight after cooking and handling; this single measurement captures evaporation, absorption, rendering, and material left on equipment. Ingredient-specific trimming, peeling, and draining remain explicit prep-action yield factors. Cooking water deliberately added to rice is a normal recipe input.
Units, density, and household measures
Universal unit conversion applies only within a dimension: mass-to-mass, volume-to-volume, time-to-time, and so on. Volume-to-mass conversion requires ingredient-specific evidence.
For normalized units, base_conversion means:
base value = source value × factor + offset. Mass resolves to grams, volume
to milliliters, time to minutes, count to each, length to millimeters, and
temperature to Celsius. US volume units are identified explicitly; an
unqualified international "cup" is not assumed.
An ingredient density measurement stores a mass, a volume, physical state,
temperature when relevant, and provenance. This is intentionally represented
as an observed ratio rather than a context-free density scalar. A rounded
culinary approximation can coexist with a laboratory measurement without
pretending they have equal precision.
Ingredient measure_conversions cover non-density measures such as one clove,
one packed cup, or one drained can. Preparation state belongs on the conversion
because sifted, packed, chopped, and whole materials may have different bulk
measures.
USDA FoodData Central
USDA FoodData Central mappings are provenance records, not attributes that define an ingredient. A reviewed mapping records the FDC ID, FoodData Central data type, exact description, retrieval date, and the normalized nutrient values imported from that record. Candidate mappings remain distinguishable from reviewed mappings.
Prefer Foundation Foods for suitable basic foods, followed by SR Legacy or FNDDS when they are a better semantic match. Use a Branded record only for the specific purchasing item or when the canonical ingredient intentionally means that exact product. Prepared components should normally derive nutrition from their recipes instead of being forced onto an approximate FDC record.
The USDA API key must never be stored in the repository. Future import tooling should propose candidates, cache source payloads or normalized facts with their retrieval dates, and require review before a mapping becomes authoritative.
Canonical storage
SQLite is the canonical application store. The files in culinary/ are a
portable import/export dataset and initial seed, not a second writable source of
truth. Recipes without authored instructions contain one explicit TODO step.
Formula-only conversions use a nominal 100 g basis and a
theoretical yield until those values are replaced by observed production data.
Application and agent changes must use validated domain save functions and SQLite transactions. Direct SQL is reserved for schema-aware maintenance where no domain operation exists. Reset/import commands flow from YAML into SQLite and therefore overwrite the current store; export commands flow from SQLite into a portable representation.
Astro reads SQLite through the application data layer. Generated projections support read-only presentation, and interactive calculators are Preact islands supplied with resolved, typed recipe data. Astro, Preact, and projections remain presentation consumers; culinary calculations and editing originate in SQLite and shared domain tools.