# How this data was made (2026-10-14)

This file states how we altered the source data (ODbL 4.6(b), FSANZ Data User Licence 4B).

## What is included

Every catalog row whose `share_alike` column carries this licence family. The database pins that column to the source with a CHECK constraint and keeps it on every copy with triggers, so the selection is one predicate. Imported rows come from our verified local copy, which the production sync keeps identical to what the app serves. Rows people derived in the app come from production.

## Values

- All nutrient values are per 100 g of edible portion, in canonical units: grams for macronutrients, milligrams or micrograms for minerals and vitamins, kcal and kJ for energy. Unit conversions use fixed factors; vitamin D in IU becomes micrograms.
- `basis` records what the source published. Values published per 100 ml were divided by the density in `density_g_per_ml` (its origin in `density_source`); values published per serving were scaled by 100 / `serving_g`. `edible_fraction` is stored as published and never applied to the values.
- Energy: published kcal and kJ are kept as published. When only one was published, the other was derived (factor 4.184). When neither was, kcal was computed from protein, fat and carbohydrate.
- Carbohydrate: `carbohydrate_available_g` and `carbohydrate_total_g` are kept apart. When only one was published and fibre is known, the other was derived (total = available + fibre).
- Sodium: when only salt was published, sodium = salt x 400 mg.
- Every derived value is marked in `nutrient_meta` with `q: "derived"`, and the row's `quality_flags` record why. Other `q` values mark trace amounts (stored as 0), values below a detection limit (the published bound), estimated, borrowed, calculated, approximate and converted values. A missing value is null, never 0.
- Rows were rejected, not loaded, for negative values, protein, fat, carbohydrate, fibre and alcohol summing to more than 120 g per 100 g, energy above 950 kcal per 100 g, or no name in any language. Rows whose stated energy disagrees with their macronutrients by more than 20 kcal and 20% load with the `energyMismatch` flag.

## Barcodes

Every code was normalized to GTIN-14: shorter GTINs are left-padded with zeros, UPC-E codes expanded (the other reading kept in `gtin_alternates`), and a missing check digit appended (`gtin_repair` says which repair was made). ISBN, ISSN, coupon and refund codes were dropped. Any other unusable code, such as one failing its check digit, leaves `gtin14` empty and stays in `barcode_raw`. Restricted in-store codes keep their scope in `gtin_scope`; Swedish variable-measure codes are stored under their value-zeroed key, with the scanned code in `barcode_raw`. No barcode is unique: several rows may share one.

## Names and search text

Names are Unicode NFC, trimmed, whitespace collapsed and at most 300 characters, keyed by BCP 47 language tag. `search_text` is derived text: the brand first, then the names, generic names and synonyms, each lower-cased, accents on Latin letters removed, everything that is not a letter or digit turned into a space, repeated words dropped, cut at 400 characters.

## Rows people derived in the app

These rows are anonymized: no owner, creator, timestamps, review state or text a person typed. A copy of an imported food carries the names and brand of the first imported food it descends from (`based_on_id`), or none when that chain was cut by a deleted private food, plus its factual values, barcode and portions in grams. Its own texts and portion labels are left out.

A recipe has no original, so it carries only its id, kind and nutrient values, and its portions only in grams. A recipe's nutrients are computed, never typed in: each ingredient's value per 100 g times the grams used, summed and divided by the recipe's yield in grams. A nutrient is stored only when every ingredient has it. Recipes are in this dump only when every ingredient is from this licence family, or, for Open Food Facts, from public-domain or the user's own from-scratch foods.

## FSANZ specifics

- AFCD and AUSNUT 2023 values are per 100 g edible portion as published. Where a Public Food Key is in both, the AFCD food carries the AUSNUT measures as its portions.
- AFCD specific gravity is used as density when positive. Energy and carbohydrate variants without dietary fibre or polyols stay under their own codes in `extra_nutrients`.
- Values FSANZ borrowed from another table are marked `q: "borrowed"` with the table in `src`, and carry a credit line in `food_text`.

## Columns

Column names follow the database. `source` and `origin_source` are ids in the source registry: 250 = Australian Food Composition Database (AFCD), 251 = AUSNUT 2023; 900 = a food a person created in the app, 901 = a recipe.
