release: dev -> main (P1 conception v0.2 + front P5 + admin shell) #1

Merged
Corentin merged 34 commits from dev into main 2026-06-04 17:44:30 +02:00
76 changed files with 628 additions and 0 deletions
Showing only changes of commit 84d2559ba9 - Show all commits

41
docs/design/README.md Normal file
View file

@ -0,0 +1,41 @@
# Design - maquette borne Wakdo
## Fichiers
- `maquette-borne.pdf` : maquette ecrans complete fournie avec le brief ecole
## Source en ligne
Prototype Figma public :
```
https://www.figma.com/design/0qnd0pH4qryZqjzXcB4qjN/borne?node-id=97-775
```
Le PDF est un export fige de cette maquette. Pour les modifications eventuelles ou pour
cliquer dans le prototype interactif, referencer le Figma comme source de verite.
## Utilisation prevue
Cette maquette guide :
1. **L'integration front en phase P5** : composants UI a reproduire en HTML/CSS/JS vanilla
dans `src/public/borne/`.
2. **Les decisions UX au CDCF** : flows utilisateur (parcours commande, choix sur place / a
emporter, options de paiement), nombre d'ecrans, transitions.
3. **Le mapping criteres RNCP Bloc 1** : tracabilite entre maquette et code livre, point
d'appui pour les questions oral type *"comment vous etes passe de la maquette au code ?"*.
## Assets visuels associes
Tous les assets utilises par la maquette (logo, illustrations, vignettes, icones) ont ete
copies et normalises (kebab-case minuscule) dans `src/public/borne/assets/images/` :
```
src/public/borne/assets/images/
produits/{burgers,wraps,encas,boissons,sauces,desserts,frites,salades}/
categories/
ui/
```
Voir `docs/merise/_sources/source-school.md` pour la note sur la normalisation.

Binary file not shown.

View file

@ -0,0 +1,47 @@
[
{
"id":1,
"title": "menus",
"image": "/categories/menus.png"
},
{
"id":2,
"title": "boissons",
"image": "/categories/boissons.png"
},
{
"id":3,
"title": "burgers",
"image": "/categories/burgers.png"
},
{
"id":4,
"title": "frites",
"image": "/categories/frites.png"
},
{
"id":5,
"title": "encas",
"image": "/categories/encas.png"
},
{
"id":6,
"title": "wraps",
"image": "/categories/wraps.png"
},
{
"id":7,
"title": "salades",
"image": "/categories/salades.png"
},
{
"id":8,
"title": "desserts",
"image": "/categories/desserts.png"
},
{
"id":9,
"title": "sauces",
"image": "/categories/sauces.png"
}
]

View file

@ -0,0 +1,418 @@
{
"menus":[
{
"id": 1,
"nom":"Menu Le 280",
"prix": 8.80,
"image": "/burgers/280.png"
},
{
"id": 2,
"nom":"Menu Big Tasty",
"prix": 10.60,
"image": "/burgers/BIG_TASTY_1_VIANDE.png"
},
{
"id": 3,
"nom":"Menu Big Tasty Bacon",
"prix": 10.90,
"image": "/burgers/BIG_TASTY_BACON_1_VIANDE.png"
},
{
"id": 4,
"nom":"Menu Big Mac",
"prix": 8.00,
"image": "/burgers/BIGMAC.png"
},
{
"id": 5,
"nom":"Menu CBO",
"prix": 10.90,
"image": "/burgers/CBO.png"
},
{
"id": 6,
"nom":"Menu MC Chicken",
"prix": 9.30,
"image": "/burgers/MCCHICKEN.png"
},
{
"id": 7,
"nom":"Menu MC Crispy",
"prix": 7.20,
"image": "/burgers/MCCRISPY.png"
},
{
"id": 8,
"nom":"Menu MC Fish",
"prix": 7.20,
"image": "/burgers/MCFISH.png"
},
{
"id": 9,
"nom":"Menu Royal Bacon",
"prix": 7.05,
"image": "/burgers/ROYALBACON.png"
},
{
"id": 10,
"nom":"Menu Royal Cheese",
"prix": 6.40,
"image": "/burgers/ROYALCHEESE.png"
},
{
"id": 11,
"nom":"Menu Royal Deluxe",
"prix": 7.40,
"image": "/burgers/ROYALDELUXE.png"
},
{
"id": 12,
"nom":"Menu Signature BBQ Beef 2 viandes",
"prix": 13.50,
"image": "/burgers/SIGNATURE_BBQ_BEEF_(2_VIANDES).png"
},
{
"id": 13,
"nom":"Menu Signature Beef BBQ",
"prix": 11.90,
"image": "/burgers/SIGNATURE_BEEF_BBQ_BURGER_(1_VIANDE).png"
}
],
"burgers":[
{
"id": 14,
"nom":"Le 280",
"prix": 6.80,
"image": "/burgers/280.png.png"
},
{
"id": 15,
"nom":"Big Tasty",
"prix": 8.60,
"image": "/burgers/BIG_TASTY_1_VIANDE.png"
},
{
"id": 16,
"nom":"Big Tasty Bacon",
"prix": 8.90,
"image": "/burgers/BIG_TASTY_BACON_1_VIANDE.png"
},
{
"id": 17,
"nom":"Big Mac",
"prix": 6.00,
"image": "/burgers/BIGMAC.png"
},
{
"id": 18,
"nom":"CBO",
"prix": 8.90,
"image": "/burgers/CBO.png"
},
{
"id": 19,
"nom":"MC Chicken",
"prix": 7.30,
"image": "/burgers/MCCHICKEN.png"
},
{
"id": 20,
"nom":"MC Crispy",
"prix": 5.30,
"image": "/burgers/MCCRISPY.png"
},
{
"id": 21,
"nom":"MC Fish",
"prix": 4.85,
"image": "/burgers/MCFISH.png"
},
{
"id": 22,
"nom":"Royal Bacon",
"prix": 5.10,
"image": "/burgers/ROYALBACON.png"
},
{
"id": 23,
"nom":"Royal Cheese",
"prix": 4.40,
"image": "/burgers/ROYALCHEESE.png"
},
{
"id": 24,
"nom":"Royal Deluxe",
"prix": 5.40,
"image": "/burgers/ROYALDELUXE.png"
},
{
"id": 25,
"nom":"Signature BBQ Beef 2 viandes",
"prix": 11.40,
"image": "/burgers/SIGNATURE_BBQ_BEEF_(2_VIANDES).png"
},
{
"id": 26,
"nom":"Signature Beef BBQ",
"prix": 10.30,
"image": "/burgers/SIGNATURE_BEEF_BBQ_BURGER_(1_VIANDE).png"
}
],
"boissons":[
{
"id": 27,
"nom":"Coca Cola",
"prix": 1.90,
"image": "/boissons/coca-cola.png"
},
{
"id": 28,
"nom":"Coca Sans Sucres",
"prix": 1.90,
"image": "/boissons/coca-sans-sucres.png"
},
{
"id": 29,
"nom":"Eau",
"prix": 1.00,
"image": "/boissons/eau.png"
},
{
"id": 30,
"nom":"Fanta Orange",
"prix": 1.90,
"image": "/boissons/fanta.png"
},
{
"id": 31,
"nom":"Ice Tea Pêche",
"prix": 1.90,
"image": "/boissons/ice-tea-peche.png"
},
{
"id": 32,
"nom":"Ice Tea Citron",
"prix": 1.90,
"image": "/boissons/the-vert-citron-sans-sucres.png"
},
{
"id": 33,
"nom":"Jus d'Orange",
"prix": 2.10,
"image": "/boissons/jus-orange.png"
},
{
"id": 34,
"nom":"Jus de Pommes Bio",
"prix": 2.30,
"image": "/boissons/jus-pomme-bio.png"
}
],
"frites":[
{
"id": 35,
"nom":"Petite Frite",
"prix": 1.45,
"image": "/frites/PETITE_FRITE.png.png"
},
{
"id": 36,
"nom":"Moyenne Frite",
"prix": 2.75,
"image": "/frites/MOYENNE_FRITE.png.png"
},
{
"id": 37,
"nom":"Grande Frite",
"prix": 3.50,
"image": "/frites/GRANDE_FRITE.png.png"
},
{
"id": 38,
"nom":"Potatoes",
"prix": 2.15,
"image": "/frites/POTATOES.png.png"
},
{
"id": 39,
"nom":"Grande Potatoes",
"prix": 3.40,
"image": "/frites/GRANDE_POTATOES.jpg.png"
}
],
"encas":[
{
"id": 40,
"nom":"Cheeseburger",
"prix": 2.60,
"image": "/encas/cheeseburger.png.png"
},
{
"id": 41,
"nom":"Croc MCdo",
"prix": 3.20,
"image": "/encas/croc-mc-do.png"
},
{
"id": 42,
"nom":"Nuggets x4",
"prix": 4.20,
"image": "/encas/nuggets_4.png"
},
{
"id": 43,
"nom":"Nuggets x20",
"prix": 13.00,
"image": "/encas/nuggets_20.png"
}
],
"desserts":[
{
"id": 44,
"nom":"Brownie",
"prix": 2.60,
"image": "/desserts/brownies.png"
},
{
"id": 45,
"nom":"Cheesecake chocolat M&M'S",
"prix": 3.10,
"image": "/desserts/cheesecake_choconuts_M&M_s.png"
},
{
"id": 46,
"nom":"Cheesecake Fraise",
"prix": 3.10,
"image": "/desserts/cheesecake_fraise.png"
},
{
"id": 47,
"nom":"Cookie",
"prix": 3.20,
"image": "/desserts/cookie.png"
},
{
"id": 48,
"nom":"Donut",
"prix": 2.60,
"image": "/desserts/doghnut.png"
},
{
"id": 49,
"nom":"Macarons",
"prix": 2.70,
"image": "/desserts/macarons.png"
},
{
"id": 50,
"nom":"MC Fleury",
"prix": 4.40,
"image": "/desserts/MCFleury.png"
},
{
"id": 51,
"nom":"Muffin",
"prix": 3.60,
"image": "/desserts/muffin.png"
},
{
"id": 52,
"nom":"Sunday",
"prix": 1.00,
"image": "/desserts/sunday.png"
}
],
"sauces":[
{
"id": 53,
"nom":"Classic Barbecue",
"prix": 0.70,
"image": "/sauces/classic-barbecue.png"
},
{
"id": 54,
"nom":"Classic Moutarde",
"prix": 0.70,
"image": "/sauces/classic-moutarde.png"
},
{
"id": 55,
"nom":"Creamy Deluxe",
"prix": 0.70,
"image": "/sauces/cremy-deluxe.png"
},
{
"id": 56,
"nom":"Ketchup",
"prix": 0.70,
"image": "/sauces/ketchup.png"
},
{
"id": 57,
"nom":"Chinoise",
"prix": 0.70,
"image": "/sauces/sauce-chinoise.png"
},
{
"id": 58,
"nom":"Curry",
"prix": 0.70,
"image": "/sauces/sauce-curry.png"
},
{
"id": 59,
"nom":"Pommes Frites",
"prix": 0.70,
"image": "/sauces/sauce-pommes-frite.png"
}
],
"salades":[
{
"id": 60,
"nom":"Petite Salade",
"prix": 3.30,
"image": "/salades/PETITE-SALADE.png"
},
{
"id": 61,
"nom":"Cesar Classic",
"prix": 8.80,
"image": "/salades/SALADE_CLASSIC_CAESAR.png"
},
{
"id": 62,
"nom":"Italienne Mozza",
"prix": 8.80,
"image": "/salades/SALADE_ITALIAN_MOZZA.png"
}
],
"wraps":[
{
"id": 63,
"nom":"MC Wrap chevre",
"prix": 3.10,
"image": "/wraps/mcwrap-chevre.png"
},
{
"id": 64,
"nom":"MC Wrap Poulet Bacon",
"prix": 3.30,
"image": "/wraps/MCWRAP-POULET-BACON.png"
},
{
"id": 65,
"nom":"Ptit Wrap Chevre",
"prix": 2.60,
"image": "/wraps/PTIT_WRAP_CHEVRE.png"
},
{
"id": 66,
"nom":"Ptit Wrap Ranch",
"prix": 2.60,
"image": "/wraps/PTIT_WRAP_RANCH.png"
}
]
}

View file

@ -0,0 +1,122 @@
# Source de donnees - brief ecole "wacdo"
Cette matiere brute provient du brief ecole sur lequel ce projet **Wakdo** est construit.
Conservee non modifiee dans ce dossier pour la tracabilite jury : le MCD/MLD de la phase
P1 derivera de cette source, et garder l'original permet de retracer les choix de modelisation
(qu'est-ce que j'ai garde tel quel, qu'est-ce que j'ai normalise, qu'est-ce que j'ai enrichi).
## Provenance
- Auteur : brief ecole (projet pedagogique baptise "wacdo" cote ecole)
- Date d'arrivee : 2026-04-30 (Session 4)
- Format : 2 fichiers JSON + assets visuels + maquette PDF
- **Notre projet s'appelle Wakdo** (avec un k), pas wacdo. Le naming "wacdo" reste uniquement
dans ce dossier `_sources/` pour la tracabilite. Tout le reste du repo utilise Wakdo.
## Contenu du dossier
- `categories.json` : 9 categories de produits
- `produits.json` : 66 produits repartis sur les 9 categories
## Schemas observes
`categories.json` :
```json
[
{ "id": int, "title": string, "image": string }
]
```
9 entrees. Le champ `image` pointe sur un chemin relatif type `/categories/menus.png`.
`produits.json` :
```json
{
"<categorie>": [
{ "id": int, "nom": string, "prix": float, "image": string }
]
}
```
Cles de premier niveau (correspond a une categorie) : `menus`, `boissons`, `burgers`, `frites`,
`encas`, `wraps`, `salades`, `desserts`, `sauces`. Comptes par categorie :
| Categorie | Nb produits |
|---|---|
| menus | 13 |
| burgers | 13 |
| desserts | 9 |
| boissons | 8 |
| sauces | 7 |
| frites | 5 |
| encas | 4 |
| wraps | 4 |
| salades | 3 |
| **Total** | **66** |
## Typos detectes dans la source (laisses tels quels, corriges en aval)
Les JSON sources contiennent des typos sur les chemins d'images (le fichier physique est correct,
seule la reference JSON est buguee) :
| JSON ref | Fichier reel apres normalisation | Note |
|---|---|---|
| `/burgers/280.png.png` | `/burgers/280.png` | double extension |
| `/frites/PETITE_FRITE.png.png` | `/frites/petite-frite.png` | double extension |
| `/frites/MOYENNE_FRITE.png.png` | `/frites/moyenne-frite.png` | double extension |
| `/frites/GRANDE_FRITE.png.png` | `/frites/grande-frite.png` | double extension |
| `/frites/POTATOES.png.png` | `/frites/potatoes.png` | double extension |
| `/encas/cheeseburger.png.png` | `/encas/cheeseburger.png` | double extension (le fichier source avait aussi le typo, corrige a la copie) |
| `/frites/GRANDE_POTATOES.jpg.png` | `/frites/grande-potatoes.png` | extensions `.jpg.png` accolees, fichier reel en `.png` simple |
La fonction de normalisation (kebab-case + lowercase + collapse extensions doubles `.png.png`)
recupere automatiquement les 6 premieres. Le 7eme cas (`.jpg.png` chez Grande Potatoes) n'est
pas couvert par la normalisation et serait detecte comme MISS si on utilisait ce JSON tel quel
en runtime - resolu en P1 par regeneration du seed depuis le filesystem canonique.
Conclusion : les JSON sources ne sont **pas utilisables en l'etat** pour servir de fallback
runtime ou pour piloter le seed. Ils servent uniquement de matiere de reference humaine. Le
seed sera construit en croisant la source (pour les libelles, prix, ids) avec le filesystem
images normalise (pour les chemins).
## Ecarts identifies a corriger lors du passage au MCD
- **Pas de FK explicite produit -> categorie** : la relation passe par la cle d'objet
(`"burgers": [...]`). Au MCD, ajouter `category_id` dans l'entite Produit avec FK vers
Categorie.
- **Prix en flottants** (8.80, 1.9, 10.60) : risque d'arrondi. Decision a graver au MCD :
conversion en centimes `INT UNSIGNED` au DDL pour stockage exact.
- **Pas de composition de menu** : "Menu Big Mac" (id=4) coute 8.00 EUR mais la source ne
precise pas son contenu (burger + accompagnement + boisson + sauce). PROJECT_CONTEXT
evoque cette composition, donc enrichissement majeur a faire au MCD (entite Composition,
ou tables de jointure Menu_Produit avec roles).
- **Champs metier absents** : description, allergenes, valeurs nutritionnelles, stock, TVA,
ordre d'affichage. A enrichir selon les besoins exprimes au CDCF.
## Reference design
- PDF de la maquette : `docs/design/maquette-borne.pdf`
- Figma public : `https://www.figma.com/design/0qnd0pH4qryZqjzXcB4qjN/borne?node-id=97-775`
## Lien avec les images
Les chemins d'images dans ces 2 JSON pointent sur les noms originaux (ex : `/burgers/BIGMAC.png`,
`/wraps/mcwrap-chevre.png`). La source ecole melange 3 conventions de casse (MAJUSCULES,
minuscules, mixed). Lors de la copie vers `src/public/borne/assets/images/`, les fichiers ont
ete normalises en kebab-case minuscule (`bigmac.png`, `mcwrap-chevre.png`) pour eviter le
piege case-sensitive Linux (le serveur tourne dans Docker sur Linux, ou `BIGMAC.png` !=
`bigmac.png`).
Consequence : ces JSON ne peuvent pas servir directement de fallback runtime - leurs paths
pointent sur la convention source. La generation des fichiers JSON fallback en P1 partira
du seed normalise, pas de ces fichiers.
## Utilisation prevue en P1
1. Extraction des entites + attributs vers le **dictionnaire de donnees**
2. Derivation du **MCD** (entites + relations) en enrichissant les ecarts ci-dessus
3. Generation du **DDL** (`db/migrations/0001_init_schema.sql`)
4. Transformation en **seed** (`db/seeds/0001_demo_data.sql`) avec normalisation des prix
5. Export des **JSON fallback** (`src/public/borne/data/*.json`) depuis le seed

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 991 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 777 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B