Files
formulation/docs/culinary-data-model.md
T
2026-08-14 18:24:33 -05:00

7.3 KiB
Raw Blame History

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.