Mixology Engine

Modèle de Données — Conceptuel (MERISE 2) & Physique

23 entités · 607 templates · 5 diagrammes · Version 1.34.2.14

1. Légende notation MERISE 2

Entité
Association
Réflexive / hiérarchie
0,N · 1,1 · 1,N · 0,1 Cardinalités (min,max)

Identifiants : soulignés (id_template). FKs : en italique vert (creator_id). Cardinalités : 0,1 optionnel max 1 — 1,1 obligatoire exactement 1 — 0,N optionnel illimité — 1,N obligatoire illimité.

2. Vue d'ensemble (carte des 23 entités)

Le modèle compte 23 entités organisées autour de TEMPLATE (cocktail).

Carte topologique des 23 entités regroupées par domaine
COMPOSITION (cœur) TEMPLATE 607 cocktails STEP ~12k composer INGREDIENT ~700 items ROLE 9 R1-R9 QUANTITY 3401 parsed TAXONOMIE GROUP 56 (auto-réf) ARCHETYPE 22 valeurs GÉOGRAPHIE PLACE 403 (5 niveaux hiérarchiques) CULTURE PERSON 98 (multi-rôles) WORK 8 (movie/book/song) ALIAS noms alternatifs VOCABULAIRES AROMA_PROFILE 134 profils ACCORD 12 accords FAMILY 23 familles ALLERGEN_VOCAB 6 codes SERVICE GLASS 25 verres TECHNIQUE 24 techniques ICE 9 types

Chaque diagramme thématique ci-dessous détaille les associations et cardinalités précises pour un cluster du modèle.

3. Diagramme 1 — Composition

Cœur du modèle : un TEMPLATE est composé de plusieurs STEP, chacun référençant un INGREDIENT positionné dans un ROLE (R1-R9) avec une QUANTITY structurée.

Composition d'un cocktail
TEMPLATE id_template name, year iba, iconic, iba_period volume, diff, time abv, abv_servi (calc) vegan (calc) history, process sweetness, acidity, bitterness body, intensity ingredients_count, spirits_count has_X[], is_X[] (filtres) group_id, subgroup_id, etc. (voir D2-D5 pour autres FKs) composer position, optional 1,1 1,N STEP id_step (relatif) template_id ingredient_id role_id cat (sous-cat R) qty (texte brut) quantity_parsed refs[] (alternatives) optional txt (note éditoriale) référencer 1,1 0,N INGREDIENT name (lc) abv, vegan cats[] familles[] substituts[] positionner 1,1 0,N ROLE id_role (R1-R9) label obligatoire cats[] quantifier 1,1 0,N QUANTITY value (Number ou null) unit (cl/ml/oz/dash/piece...) modifier (texte libre) raw (qty originale préservée) Embedded sur STEP (1:1) appartenir 1,N 1,N
Lecture : un TEMPLATE compose 1 à N STEP. Chaque STEP référence exactement 1 INGREDIENT, est positionné dans exactement 1 ROLE, et quantifié par exactement 1 QUANTITY. Un INGREDIENT peut appartenir à plusieurs ROLEs (multi-rôle via CROSS_ROLE_INDEX ; 14 ingrédients concernés, ex : champagne = R1+R5, velvet falernum = R2+R3).

4. Diagramme 2 — Taxonomie

Hiérarchie unifiée GROUP auto-référente remplaçant les anciens champs grp et subgrp dénormalisés.

GROUP (hiérarchie) + ARCHETYPE
TEMPLATE id_template group_id, subgroup_id, archetype_id classer 0,N 2,2 GROUP id_group label parent_id (self) depth (1=grp, 2=sub) children[] 56 instances 11 niveau 1 (grps) 45 niveau 2 (subgrps) hiérarchiser parent/enfant 0,1 0,N ARCHETYPE id_archetype label (22 valeurs) famille_structurelle description incarner 1,1 1,N

5. Diagramme 3 — Géographie

Hiérarchie unifiée PLACE auto-référente sur 5 niveaux : continent → country → region → city → bar.

PLACE (hiérarchie géographique 5 niveaux)
TEMPLATE id_template continent_id, country_id region_id, city_id bar_id localiser création 0,5 PLACE id_place name type (continent|country|region|city|bar) level (1-5) parent_id (self) 238 instances 12 continents, 58 countries 102 regions, 21 cities, 45 bars 0,N hiérarchiser parent/enfants 0,1 0,N Hiérarchie type Niveau 1 — Continent └ Niveau 2 — Country └ Niveau 3 — Region └ Niveau 4 — City └ Niveau 5 — Bar Ex Tommy's Margarita : Amérique du Nord └ États-Unis └ Californie └ San Francisco └ Tommy's Mexican Restaurant

6. Diagramme 4 — Références culturelles

PERSON unifiée (bartenders + célébrités + auteurs) avec rôles multiples, et WORK unifié (movies + books + songs).

PERSON multi-rôle & WORK polymorphique
TEMPLATE id_template creator_id (0,1) celebrity_ids[] (0,N) work_ids[] (0,N) alias_ids[] (0,N) être créé par bartender 0,1 0,N associer à celebrity 0,N 0,N PERSON id_person name roles[] (bartender|celebrity|writer) biography (optionnel) years (born/died) 98 instances apparaître dans référence 0,N 0,N WORK id_work title type (movie|book|song) year author_id (PERSON) écrire 0,N 0,1 ALIAS id_alias nom_alternatif être connu 0,N 1,1 Ex : Hemingway roles: [writer, bartender] → creator d'un cocktail → author d'une WORK → référence littéraire

7. Diagramme 5 — Sensoriel & Service

Vocabulaires contrôlés (AROMA_PROFILE, ACCORD, FAMILY, ALLERGEN_VOCAB) + service (GLASS, TECHNIQUE, ICE).

Profil sensoriel, accords, allergens et fiche de service
TEMPLATE id_template sweetness, acidity, bitterness, intensity body (léger/moyen/corsé) aroma_profile_ids[], accord_ids[] allergen_ids[], glass_id, technique_id, ice_id AROMA_PROFILE id_profile label (134 valeurs) présenter 0,N 1,N ACCORD id_accord label (12 valeurs) accorder avec 0,N 0,N ALLERGEN_VOCAB id_allergen code, label, icon contenir 0,N 0,N FAMILY id_family label (23 valeurs) appartenir olfactif 0,N 0,N → INGREDIENT (cf D1) GLASS id_glass capacité_cl, forme usage, temp_target 25 instances servir dans 0,N 1,1 TECHNIQUE id_technique durée, difficulté dilution_taux 24 instances préparer par 0,N 1,1 ICE id_ice dilution, tenue refroidir 0,N 0,1

8. Dictionnaire des entités (23 entités)

TEMPLATE — Recette de cocktail (entité centrale)

607 occurrences. Voir aussi le découpage conceptuel en 5 sous-entités logiques.

id_template PK entier
name, year
volume, diff, time
abv, abv_servi (calc)
sweetness, acidity, bitterness, intensity
body
iba, iconic, vegan
history, process
Clés étrangères
group_id, subgroup_id, archetype_id
creator_id, celebrity_ids[], work_ids[]
continent_id, country_id, region_id, city_id, bar_id
accord_ids[], aroma_profile_ids[], allergen_ids[]
glass_id, technique_id, ice_id

STEP — Étape de composition (entité faible)

~12 000 occurrences. Identifiée par position relative dans TEMPLATE.steps[].

id_step PK relative
template_id FK obligatoire
ingredient_id FK
role_id FK R1-R9
cat sous-catégorie
qty texte brut préservé
quantity_parsed objet {value, unit, modifier, raw}
refs[] alternatives
optional, txt

INGREDIENT — Ingrédient référençable

~700 occurrences. Couvre ingrédients-matière (R1-R7) et étiquettes-métier (R8-R9). Voir sous-types XT.

name PK (lowercase normalisée)
cats[] rôles + sous-cats
abv, vegan
profile_aroma[]
familles[]
substituts[]
origin

ROLE, GLASS, TECHNIQUE, ICE, ARCHETYPE, ALIAS

9, 25, 24, 9, 22 et ~3 occurrences. Entités de référence avec PKs textuelles ou numériques.

GROUP — Hiérarchie taxonomique auto-référente

56 occurrences (11 niveau 1 + 45 niveau 2). Unifie grp et subgrp.

id_group PK textuelle (grp-N / sub-N)
label
parent_id FK self (null = top-level)
depth 1 ou 2
children[] IDs enfants directs

PERSON — Bartenders, célébrités, auteurs unifiés

98 occurrences. Multi-rôle : un même PERSON peut être writer + bartender + celebrity.

id_person PK textuelle (per-N)
name
roles[] bartender | celebrity | writer

WORK — Œuvres culturelles unifiées

8 occurrences. Type polymorphique : movie | book | song.

id_work PK textuelle (wrk-N)
title
type movie | book | song
year
author_id FK PERSON (optionnel)

PLACE — Géographie hiérarchique 5 niveaux

238 occurrences (12 continents, 58 countries, 102 regions, 21 cities, 45 bars). Le 12e membre continent, « International », est un catch-all non géographique pour les cocktails d'origine mondiale/sans pays unique — couverture continent_id totale (607/607).

id_place PK textuelle (plc-N)
name
type continent|country|region|city|bar
level 1 à 5
parent_id FK self

ACCORD, AROMA_PROFILE, FAMILY, ALLERGEN_VOCAB — Vocabulaires contrôlés

12 + 134 + 23 + 6 occurrences. Promotion en entités à part entière des anciens strings volatiles.

id PK textuelle préfixée par type
label Libellé normalisé
code, icon Pour ALLERGEN_VOCAB

QUANTITY — Quantité structurée (embedded sur STEP)

3 401 quantités parsées. Embedded value object (pas une vraie entité avec PK propre).

value Number ou null (top/qsp)
unit cl/ml/oz/dash/piece/zeste/rondelle/...
modifier Texte libre (option)
raw Quantité originale préservée

9. Dictionnaire des associations (26)

AssociationEntitésCardinalitésSémantique
composerTEMPLATE — STEP1,N — 1,1Composition ordonnée d'un cocktail
référencerSTEP — INGREDIENT1,1 — 0,NChoix d'ingrédient
positionnerSTEP — ROLE1,1 — 0,NRôle fonctionnel R1-R9
quantifierSTEP — QUANTITY1,1 — embeddedVolume / pièces (value object)
appartenirINGREDIENT — ROLE1,N — 1,NMulti-rôle (champagne = R1+R5)
classerTEMPLATE — GROUP2,2 — 0,NToujours 2 groups (niveau 1 + 2)
hiérarchiser (réflexive)GROUP — GROUP0,1 — 0,Nparent/enfant taxonomique
incarnerTEMPLATE — ARCHETYPE1,1 — 1,NFamille structurelle
localiserTEMPLATE — PLACE0,5 — 0,NChaîne géographique (jusqu'à 5 niveaux)
hiérarchiser (réflexive)PLACE — PLACE0,1 — 0,Nparent/enfant géographique
être créé parTEMPLATE — PERSON0,1 — 0,Ncreator role=bartender
associer àTEMPLATE — PERSON0,N — 0,Ncelebrities role=celebrity
apparaître dansTEMPLATE — WORK0,N — 0,NRéférences culturelles
écrirePERSON — WORK0,N — 0,1Auteur d'une œuvre
être connuTEMPLATE — ALIAS0,N — 1,1Noms alternatifs
présenterTEMPLATE — AROMA_PROFILE1,N — 0,NProfils aromatiques
présenterINGREDIENT — AROMA_PROFILE0,N — 0,NProfil natif de l'ingrédient
accorder avecTEMPLATE — ACCORD0,N — 0,NAccords gastronomiques
contenirTEMPLATE — ALLERGEN_VOCAB0,N — 0,NAllergens propagés via steps
contenirINGREDIENT — ALLERGEN_VOCAB0,N — 0,NAllergens natifs
appartenirINGREDIENT — FAMILY0,N — 0,NFamilles olfactives
servir dansTEMPLATE — GLASS1,1 — 0,NVerre de service
préparer parTEMPLATE — TECHNIQUE1,1 — 0,NTechnique principale
refroidirTEMPLATE — ICE0,1 — 0,NType de glace
dériver (réflexive)TEMPLATE — TEMPLATE0,N — 0,NVariantes & cousins
substituer (réflexive)INGREDIENT — INGREDIENT0,N — 0,NSubstituts possibles

10. CIF — Contraintes d'Intégrité Fonctionnelle

CIF-01 — ABV calculé

TEMPLATE.abv et TEMPLATE.abv_servi sont fonctionnellement déterminés par STEP × INGREDIENT.abv × TECHNIQUE.dilution_taux. Recalculé au boot via _deriveTemplateAbv().

CIF-02 — Allergens propagés

TEMPLATE.allergen_ids est l'union des INGREDIENT.allergen_ids de tous ses STEP, plus les allergens R9 déclarés.

CIF-03 — Cohérence des clés étrangères

Pour tout TEMPLATE : group_id doit correspondre au string grp, idem subgroup_id ↔ subgrp, creator_id ↔ creator, etc. Chaque FK doit correspondre à la valeur de référence de l'entité cible.

CIF-04 — Cohérence has_X / allergens

has_dairy ⇔ allergen_ids contient l'id "dairy", idem pour eggs, gluten, etc.

CIF-05 — Hiérarchie PLACE consistante

Pour tout PLACE, parent_id doit pointer vers un PLACE de niveau strictement inférieur. Ex : un city (level=4) ne peut avoir comme parent qu'un country (level=2) ou region (level=3).

CIF-06 — PERSON multi-rôle

Un même PERSON apparaissant dans plusieurs contextes (creator + celebrity + writer) DOIT être référencé via le MÊME id_person. Garanti par la déduplication par nom à la construction.

11. Découpage conceptuel de TEMPLATE

L'entité TEMPLATE (~40 attributs) est conceptuellement découpée en 6 sous-entités logiques (toutes en 1:1 avec TEMPLATE, donc physiquement dans la même structure mais facilitant la lecture du modèle).

Découpage logique de TEMPLATE (vue éclatée)
TEMPLATE id_template (PK) TEMPLATE_CORE name, year group_id, subgroup_id, archetype_id iba, iconic, iba_inclusion/removed_year 1,1 TEMPLATE_COMPOSITION volume, abv, abv_servi ingredients_count, spirits_count vegan, allergen_ids[] 1,1 TEMPLATE_SENSORY sweetness, acidity, bitterness body, intensity aroma_profile_ids[] 1,1 TEMPLATE_SERVICE glass_id, technique_id, ice_id diff, time is_shaken, is_stirred, is_built 1,1 TEMPLATE_NARRATIVE history, process creator_id, city_id, bar_id work_ids[], celebrity_ids[] 1,1 TEMPLATE_FILTERS has_citrus, has_dairy, has_eggs has_herbs, has_bubbles accord_ids[] 1,1
Sous-entitéAttributsRôle
TEMPLATE_COREname, year, group_id, subgroup_id, archetype_id, iba, iconic, iba_inclusion_year, iba_removed_yearIdentification + taxonomie
TEMPLATE_COMPOSITIONvolume, abv, abv_servi, ingredients_count, spirits_count, vegan, allergen_ids[], volume_variableChimie & composition
TEMPLATE_SENSORYsweetness, acidity, bitterness, body, intensity, aroma_profile_ids[]Profil gustatif
TEMPLATE_SERVICEglass_id, technique_id, ice_id, diff, time, is_shaken/stirred/built/layeredPréparation & service
TEMPLATE_NARRATIVEhistory, process, creator_id, country_id, region_id, city_id, bar_id, continent_id, work_ids[], celebrity_ids[], alias_ids[]Storytelling & culture
TEMPLATE_FILTERShas_X[] booléens, accord_ids[]Filtres et pré-calculs
Note d'implémentation : ces sous-entités sont en relation 1:1 avec TEMPLATE. Les séparer physiquement n'apporterait rien (pas de cardinalité multiple). Le découpage est donc uniquement conceptuel, pour clarifier le modèle et permettre des audits ciblés par dimension. Une migration future vers BDD relationnelle pourrait néanmoins exploiter ce découpage.

12. DATA_TMP — Table principale des templates

Tableau JavaScript de 607 objets, un par cocktail. Implémentation physique de l'entité TEMPLATE et de ses clés étrangères vers les entités normalisées.

Attributs descriptifs

ChampType physiqueDescription
idNumberClé primaire (entier unique)
nameStringNom du cocktail
yearNumber | nullAnnée de création
grp / subgrpStringLibellés taxonomiques (miroir lisible des FK)
archetypeStringFamille structurelle (22 valeurs)
iba, iconicBooleanMembre IBA actuel ou passé (modèle inclusif : le tag suit l'historique début→fin ; un retiré reste iba=true avec iba_removed_year), statut iconique
iba_inclusion_year, iba_removed_yearNumber | nullPériode IBA (entrée / retrait). Dérivé everIBA = a figuré sur la liste à un moment ; le tag IBA suit cet historique (cocktails retirés affichés ex-IBA)
abv, abv_serviNumberTitrage alcoolique (calculé au boot)
veganBooleanCalculé depuis les ingrédients
sweetness, acidity, bitterness, intensityNumber (0-5)Profil gustatif
bodyStringLéger / moyen / corsé
stepsArray<Object>Étapes de composition (entité STEP)
history, processStringRécit + préparation
has_citrus, has_dairy, has_eggs, …BooleanPré-calculs de filtrage
is_shaken, is_stirred, is_built, is_layeredBooleanTechnique principale

Clés étrangères (16) vers les entités normalisées

FKTypeCibleCouverture
group_idStringGROUPS (depth 1)607 / 607
subgroup_idStringGROUPS (depth 2)607 / 607
creator_idString | nullPERSONS (bartender)93 / 607
celebrity_ids[]Array<String>PERSONS (celebrity)4 / 607
work_ids[]Array<String>WORKS48 / 607
continent_idString | nullPLACES (continent)607 / 607
country_idString | nullPLACES (country)607 / 607
region_idString | nullPLACES (region)241 / 607
city_idString | nullPLACES (city)126 / 607
bar_idString | nullPLACES (bar)110 / 607
accord_ids[]Array<String>ACCORDS607 / 607
aroma_profile_ids[]Array<String>AROMA_PROFILES607 / 607
allergen_ids[]Array<String>ALLERGENS_VOCAB282 / 607

STEP (objet imbriqué dans steps[])

ChampTypeDescription
refStringNom de l'ingrédient (→ INGREDIENT)
roleStringR1 à R9
catStringSous-catégorie du rôle
qtyStringQuantité brute (texte original préservé)
quantity_parsedObject{value, unit, modifier, raw} — 3 394 steps parsés
optionalBooleanIngrédient facultatif

13. DATA_ING — Catalogue ingrédients par rôle

Objet structuré par rôle fonctionnel (R1 à R9). Chaque rôle contient des catégories, chaque catégorie une liste d'items. Implémentation physique de l'entité INGREDIENT.

RôleIntituléCatégoriesItems
R1Base Alcoolisée23100
R2Modificateur1995
R3Sucrant / Sirop737
R4Acide & Jus1541
R5Allongeur1147
R6Liant1534
R7Bitters & Épices637
R8Dressing / Présentation10122
R9Fiche de service (verre, glace, technique, profil…)13161
Les rôles R1-R7 portent les ingrédients-matière (entrant dans la composition liquide), R8 les garnitures, R9 les métadonnées de service (verre, glace, technique, profil aromatique, accords, allergènes). Un même ingrédient peut appartenir à plusieurs rôles (multi-rôle).

14. Tables des entités normalisées

Huit structures Map construites au démarrage, chacune indexée par sa clé primaire textuelle. Ce sont les tables de référence vers lesquelles pointent les clés étrangères de DATA_TMP.

Table (Map)PK (pattern)EntréesChamps principaux
GROUPSgrp-N / sub-N57label, parent_id, depth, children[]
PERSONSper-N71name, roles[]
WORKSwrk-N8title, type, year, author_id
PLACESplc-N238name, type, level, parent_id
ACCORDSacc-N12label
AROMA_PROFILESapr-N20label
ALLERGENS_VOCABall-N6code, label, icon
FAMILIESfam-N23label

Tables structurées — seeds BDD-orientation

Tables lues au démarrage pour peupler les champs dérivés sans aucun parsing ni regex : elles sont la source unique des champs autrefois extraits de la prose ou du nom.

SeedEntréesChamp cible
TEMPLATE_ORIGINS607origin {country,region} → géo (country_id / region_id / city_id)
TEMPLATE_CREATORS93creatorcreator_id (PERSON)
TEMPLATE_ATTRIBUTION198 (≠ anonyme)attribution_type (défaut anonyme)
TEMPLATE_ARCHETYPE607archetype
TEMPLATE_BAR110signature_barbar_id (PLACE)
TEMPLATE_CULTURAL48apparitions → work_ids / celebrity_ids
CITRUS_ITEMS / HERB_ITEMS / BUBBLE_ITEMS44 / 17 / 9has_citrus / has_herbs / has_bubbles
TECH_FLAGS52is_shaken / is_stirred / is_built / is_layered

GROUPS — hiérarchie taxonomique

57 entrées : 11 grands groupes (depth 1) et 46 sous-groupes (depth 2). Auto-référence via parent_id.

PLACES — hiérarchie géographique sur 5 niveaux

TypeNiveauEntrées
continent112
country258
region3102
city421
bar545

Déduplication stricte par (type, name) : un lieu de même nom et type est unique, quel que soit son rattachement parent.

15. Index dérivés au runtime

Structures construites une fois au démarrage pour accélérer filtres et recherches. Ce sont des vues : leur source de vérité est toujours DATA_TMP ou les tables d'entités.

IndexStructureSourceUsage
ITEM_INDEXMap nom → donnéesDATA_INGRecherche par ingrédient
SUB_CATSObject grp → [subgrps]GROUPSBoutons de filtre taxonomique
ORIGIN_TO_TPLSObject pays → Set(ids)PLACES + country_idWorldmap (comptage par pays)
WORLDMAP_CONTINENTSObject continent → [pays]PLACES (hiérarchie)Worldmap (groupement)
GROUP_BY_LABELMap label → idGROUPSRésolution label → FK (filtrage)
PLACE_BY_NAMEMap nom → idPLACESRésolution nom → FK
PERSON_BY_NAMEMap nom → idPERSONSRésolution nom → FK
CROSS_ROLE_INDEXMap ingrédient → rôlesDATA_INGPills multi-rôle
r9IndexMap item → templatesDATA_TMPFiltres de service (R9)
Les vues géographiques (ORIGIN_TO_TPLS, WORLDMAP_CONTINENTS) et taxonomiques (SUB_CATS) sont dérivées des entités normalisées (PLACES, GROUPS), qui constituent la source unique de vérité. L'interface compare via les clés étrangères (group_id, country_id) résolues par les index inversés.

16. Pipeline de construction au démarrage

Ordre de dérivation des structures, du chargement des données brutes jusqu'aux vues prêtes pour l'interface.

Séquence de boot
DATA_TMP / DATA_ING données brutes (607 + catalogue) _buildNormalizedEntities 8 entités + 16 FK + quantity_parsed _buildReverseIndexes GROUP_BY_LABEL, PLACE_BY_NAME… _rebuildGeoFromPlaces ORIGIN_TO_TPLS, WORLDMAP_CONTINENTS _rebuildSubCatsFromGroups SUB_CATS Interface prête grille, filtres, worldmap

Cette séquence s'exécute après le chargement du DOM. Chaque étape ne dépend que des structures construites aux étapes précédentes, garantissant un ordre déterministe.

17. Conventions & règles métier

BDD-orientation — zéro regex de dérivation

Tous les champs autrefois dérivés par parsing de prose ou de nom (créateur, attribution, ville, bar, apparitions culturelles, has_*/is_*, archétype, en-tête d'history) proviennent désormais des tables structurées (seeds, §14) ou de compute sur le modèle. Les parseurs _parseHistMeta/_histAttribution et les regex creatorPatterns / BAR_REGEX / ARCH_BY_NAME / *_PATTERNS ont été retirés ; un audit (noregex_guard) interdit leur réapparition.

Couverture d'audit

Suite audit2 : 14 modules, 101 tests (cohérence données / éditoriale / fonctionnelle, invariants property-based des filtres, FK des entités, non-régression BDD-orientation), sur un seul boot jsdom. Hygiène : seuls les contrôles porteurs de signal sont conservés ; les vérifications garanties par construction (existence des FK produites par getOrCreate*) sont élaguées.

Source unique de vérité

DATA_TMP et DATA_ING sont les données brutes. Toutes les autres structures (entités, index, vues) en dérivent au démarrage. Aucune donnée structurelle n'est dupliquée manuellement.

Compatibilité des accès

Chaque clé étrangère possède un miroir lisible (grpgroup_id, country_origincountry_id). L'interface filtre via les FK ; les libellés restent disponibles pour l'affichage.

Apostrophes & casse

Apostrophes normalisées en U+0027 (ASCII). Les clés d'ingrédients sont en minuscules normalisées ; ITEM_INDEX préserve la casse d'affichage, ITEM_INDEX_LC sert aux comparaisons.

Rôles R9 obligatoires

Chaque template déclare ses métadonnées de service via les catégories R9 (verre, glace, technique, profil aromatique, accords, allergènes), entre 9 et 13 catégories selon le cocktail.

Valeurs calculées au runtime

abv, abv_servi et vegan sont recalculés à partir de la composition réelle (ingrédients × titrages × dilution technique) plutôt que stockés en dur.