CuisineWeek – Documentation Technique

Application Android · Kotlin · Room · MVVM · BTS SIO SLAM 2025–2026

📱 Android 8.0+ (API 28)
🔤 Kotlin 2.1.0
🗄️ Room 2.6.1
🏗️ Architecture MVVM
📅 Mars 2026

📋 Table des matières

  1. Présentation du projet
  2. Architecture MVVM
  3. Diagramme de classes
  4. Modèle Conceptuel de Données (MCD)
  5. Modèle Logique de Données (MLD)
  6. Schéma de base de données
  7. Diagramme de cas d'utilisation
  8. Flux de données
  9. Intégration API OpenFoodFacts
  10. Stack technique
1. Présentation du projet

Contexte et objectifs de l'application CuisineWeek

CuisineWeek est une application mobile Android développée en Kotlin dans le cadre du BTS SIO option SLAM. Elle permet à l'utilisateur de consulter des recettes de cuisine, de planifier ses repas à la semaine et de générer automatiquement une liste de courses à partir du menu planifié.

Fonctionnalités principales

ModuleFonctionnalitéStatut
CatalogueAffichage de la liste des recettes avec RecyclerView✅ Implémenté
CatalogueRecherche et filtrage des recettes🔄 Prévu Sprint 5
Menu semaineNavigation jour par jour avec DatePicker✅ Implémenté
Menu semaineAjout / suppression de repas (Midi, Soir, Matin)✅ Implémenté
Liste coursesScan code-barre via OpenFoodFacts✅ Implémenté
Liste coursesCases à cocher et partage✅ Implémenté
Recettes persoCréation de recettes personnalisées🔄 Prévu Sprint 5
2. Architecture MVVM

Model – View – ViewModel : séparation des responsabilités

L'application suit le pattern architectural MVVM (Model-View-ViewModel) recommandé par Google pour les applications Android. Ce pattern garantit une séparation claire entre la logique métier et l'interface utilisateur.

🖥️ VIEW — Couche présentation
MainActivity
RecettesFragment
SemaineFragment
CoursesFragment
SelectionRecetteDialog
RecetteAdapter
ArticleCoursesAdapter
⬆️ observe LiveData    ⬇️ appelle fonctions
🧠 VIEWMODEL — Couche logique
RecetteViewModel
MenuViewModel
CoursesViewModel
⬆️ LiveData    ⬇️ appelle fonctions suspend
📦 REPOSITORY — Couche d'accès aux données
RecetteRepository
RetrofitClient (OpenFoodFacts)
⬆️ entités    ⬇️ requêtes SQL / HTTP
🗄️ DATA — Couche données
AppDatabase (Room)
RecetteDao
MenuDao
ArticleCoursesDao
OpenFoodFactsApi (Retrofit)
DatabaseSeeder

Principes appliqués

PrincipeApplication dans CuisineWeek
Séparation des responsabilitésChaque couche a un rôle unique et ne connaît pas les détails des autres
Réactivité (LiveData)L'UI se met à jour automatiquement quand les données changent en BDD
Asynchronisme (Coroutines)Toutes les opérations BDD et réseau s'exécutent en arrière-plan (Dispatchers.IO)
Singleton (AppDatabase)Une seule instance de la BDD dans toute l'application (pattern @Volatile + synchronized)
Injection de dépendancesLes DAOs sont injectés dans les ViewModels via AppDatabase.getDatabase()
3. Diagramme de classes

Représentation UML des classes principales et leurs relations

Entités (data/entity)

«Entity» Recette
PK id : Int
+ nom : String
+ description : String
+ tempsPrep : Int
+ tempsCuisson : Int
+ nbPersonnes : Int
+ difficulte : String
FK categorieId : Int?
+ imageUri : String?
+ estPersonnalisee : Boolean
«Entity» Categorie
PK id : Int
+ nom : String
+ icone : String
«Entity» Ingredient
PK id : Int
+ nom : String
+ uniteDefaut : String
+ categorieCourses : String
«Entity» RecetteIngredient
PK/FK recetteId : Int
PK/FK ingredientId : Int
+ quantite : Double
+ unite : String
«Entity» MenuSemaine
PK id : Int
+ semaineDu : String
+ nbPersonnes : Int
«Entity» MenuRecette
PK/FK menuId : Int
PK/FK recetteId : Int
PK jour : String
PK typeRepas : String
«Entity» ArticleCourses
PK id : Int
+ nom : String
+ quantite : String
+ codeBarres : String
+ coche : Boolean

DAOs (data/dao)

«interface» RecetteDao
getAllRecettes() : LiveData<List<Recette>>
searchRecettes(q) : LiveData<List<Recette>>
getRecetteById(id) : Recette?
getCount() : Int
insert(recette) : Long
update(recette)
delete(recette)
«interface» MenuDao
getMenuBySemaine(s) : MenuSemaine?
insertMenu(menu) : Long
insertMenuRecette(mr)
deleteMenuRecette(id,j,t)
getRecetteIdPourRepas() : Int?
getRecettesDuJour() : LiveData
«interface» ArticleCoursesDao
getAllArticles() : LiveData<List>
insert(article)
update(article)
delete(article)
deleteAll()

ViewModels (viewmodel)

RecetteViewModel
- repository : RecetteRepository
+ toutesLesRecettes : LiveData
rechercherRecettes(q)
inserer(recette)
supprimer(recette)
MenuViewModel
- menuDao : MenuDao
- recetteDao : RecetteDao
+ jourActuel : LiveData<LocalDate>
+ recetteMidi : LiveData<Recette?>
+ recetteSoir : LiveData<Recette?>
+ recetteMatin : LiveData<Recette?>
jourSuivant()
jourPrecedent()
allerALaDate(date)
ajouterRecette(id, type)
supprimerRepas(type)
chargerMenuDuJour()
CoursesViewModel
- dao : ArticleCoursesDao
+ articles : LiveData<List>
ajouterDepuisScan(barcode)
toggleCoche(article)
supprimer(article)
toutEffacer()
4. Modèle Conceptuel de Données (MCD)

Représentation Merise des entités et associations

📊 Schéma MCD disponible dans Excalidraw

Le MCD complet (entités, associations avec cardinalités, clés primaires/étrangères) a été réalisé avec Excalidraw pour un rendu propre et précis. Il représente les entités suivantes et leurs relations :

  • RECETTEINGREDIENT via l'association contient (0,N — 0,N) avec quantite et unite
  • RECETTECATEGORIE via l'association appartient (0,N — 1,N)
  • RECETTEMENU_SEMAINE via l'association planifie (0,N — 1,N) avec jour et typeRepas
  • ARTICLE_COURSES alimenté par l'API OpenFoodFacts (source externe)
RECETTE PK id nom description tempsPrep tempsCuisson nbPersonnes difficulte FK categorieId CATEGORIE PK id nom icone INGREDIENT PK id nom uniteDefaut categorieCourses contient quantite, unite 0,N 0,N 0,1 1,N appartient MENU_SEMAINE PK id semaineDu nbPersonnes planifie jour, typeRepas 1,N 1,N 0,N ARTICLE_COURSES PK id nom quantite codeBarres coche OpenFoodFacts API Source externe (Retrofit) alimente Légende Entité principale Association / Relation PK Clé primaire FK Clé étrangère
5. Modèle Logique de Données (MLD)

Traduction du MCD en tables relationnelles

-- Tables issues du MCD CuisineWeek CATEGORIE (id, nom, icone) RECETTE (id, nom, description, tempsPrep, tempsCuisson, nbPersonnes, difficulte, imageUri, estPersonnalisee, #categorieId → CATEGORIE.id) INGREDIENT (id, nom, uniteDefaut, categorieCourses) RECETTE_INGREDIENT (#recetteId → RECETTE.id, #ingredientId → INGREDIENT.id, quantite, unite) MENU_SEMAINE (id, semaineDu, nbPersonnes) MENU_RECETTE (#menuId → MENU_SEMAINE.id, #recetteId → RECETTE.id, jour, typeRepas) ARTICLE_COURSES (id, nom, quantite, codeBarres, coche) -- Conventions : souligné = clé primaire, # = clé étrangère

Contraintes d'intégrité

TableContrainteComportement
RECETTEcategorieId → CATEGORIE.idSET NULL si catégorie supprimée
RECETTE_INGREDIENTrecetteId → RECETTE.idCASCADE DELETE
RECETTE_INGREDIENTingredientId → INGREDIENT.idRESTRICT
MENU_RECETTEmenuId → MENU_SEMAINE.idCASCADE DELETE
MENU_RECETTErecetteId → RECETTE.idRESTRICT
6. Schéma de base de données (Room SQLite)

Définition SQL des tables telle qu'implémentée avec Room

-- Générée automatiquement par Room à partir des @Entity CREATE TABLE categories ( id INTEGER PRIMARY KEY AUTOINCREMENT, nom TEXT NOT NULL, icone TEXT NOT NULL ); CREATE TABLE recettes ( id INTEGER PRIMARY KEY AUTOINCREMENT, nom TEXT NOT NULL, description TEXT NOT NULL, tempsPrep INTEGER NOT NULL, tempsCuisson INTEGER NOT NULL, nbPersonnes INTEGER NOT NULL, difficulte TEXT NOT NULL, categorieId INTEGER, imageUri TEXT, estPersonnalisee INTEGER NOT NULL DEFAULT 0, FOREIGN KEY (categorieId) REFERENCES categories(id) ON DELETE SET NULL ); CREATE TABLE ingredients ( id INTEGER PRIMARY KEY AUTOINCREMENT, nom TEXT NOT NULL, uniteDefaut TEXT NOT NULL, categorieCourses TEXT NOT NULL ); CREATE TABLE recette_ingredients ( recetteId INTEGER NOT NULL, ingredientId INTEGER NOT NULL, quantite REAL NOT NULL, unite TEXT NOT NULL, PRIMARY KEY (recetteId, ingredientId), FOREIGN KEY (recetteId) REFERENCES recettes(id) ON DELETE CASCADE, FOREIGN KEY (ingredientId) REFERENCES ingredients(id) ); CREATE TABLE menus_semaine ( id INTEGER PRIMARY KEY AUTOINCREMENT, semaineDu TEXT NOT NULL, nbPersonnes INTEGER NOT NULL DEFAULT 4 ); CREATE TABLE menu_recettes ( menuId INTEGER NOT NULL, recetteId INTEGER NOT NULL, jour TEXT NOT NULL, typeRepas TEXT NOT NULL, PRIMARY KEY (menuId, recetteId, jour, typeRepas), FOREIGN KEY (menuId) REFERENCES menus_semaine(id) ON DELETE CASCADE, FOREIGN KEY (recetteId) REFERENCES recettes(id) ); CREATE TABLE articles_courses ( id INTEGER PRIMARY KEY AUTOINCREMENT, nom TEXT NOT NULL, quantite TEXT NOT NULL DEFAULT '', codeBarres TEXT NOT NULL, coche INTEGER NOT NULL DEFAULT 0 );

Requête clé — Génération liste de courses depuis le menu

-- Récupère et additionne tous les ingrédients du menu de la semaine SELECT i.nom AS ingredient, SUM(ri.quantite * (m.nbPersonnes / r.nbPersonnes)) AS quantite_totale, ri.unite AS unite, i.categorieCourses AS categorie FROM menu_recettes mr JOIN recettes r ON mr.recetteId = r.id JOIN recette_ingredients ri ON r.id = ri.recetteId JOIN ingredients i ON ri.ingredientId = i.id JOIN menus_semaine m ON mr.menuId = m.id WHERE m.id = :menuId GROUP BY i.nom, ri.unite ORDER BY i.categorieCourses, i.nom;
7. Diagramme de cas d'utilisation

Actions disponibles pour l'utilisateur (acteur unique — pas de gestion de comptes)

🍳 Module Recettes

  • Consulter la liste des recettes
  • Rechercher une recette par nom
  • Filtrer par catégorie
  • Consulter le détail d'une recette
  • Créer une recette personnalisée
  • Modifier une recette personnalisée
  • Supprimer une recette personnalisée

📅 Module Menu Semaine

  • Naviguer entre les jours
  • Sélectionner une date via DatePicker
  • Ajouter une recette au midi
  • Ajouter une recette au soir
  • Ajouter une recette au matin
  • Changer une recette planifiée
  • Supprimer un repas planifié

🛒 Module Courses

  • Scanner un code-barre produit
  • Ajouter un produit à la liste
  • Cocher un article acheté
  • Supprimer un article
  • Vider toute la liste
  • Partager la liste (Android Intent)
8. Flux de données — Scan code-barre

Séquence complète d'un scan jusqu'à l'affichage dans la liste

1. UIClic bouton Scanner (FAB)
2. ZXingCaméra ouverte, scan code-barre
3. ViewModelajouterDepuisScan(barcode)
4. RetrofitGET /product/{barcode}.json
5. APIOpenFoodFacts répond en JSON
6. GsonDésérialisation → OpenFoodFactsResponse
7. DAOinsert(ArticleCourses)
8. LiveDataMise à jour automatique → RecyclerView

Flux de données — Ajout d'une recette au menu

1. UIClic "+ Ajouter un repas"
2. DialogSelectionRecetteDialog s'ouvre
3. UIClic sur une recette
4. ViewModelajouterRecette(id, typeRepas)
5. DAOgetOuCreerMenuId()
6. DAOinsertMenuRecette()
7. LiveDatarecetteMidi/Soir/Matin mis à jour
8. UINom de la recette affiché
9. Intégration API OpenFoodFacts

Documentation de l'intégration de l'API externe

Endpoint utilisé

GET https://world.openfoodfacts.org/api/v0/product/{barcode}.json -- Exemple : GET https://world.openfoodfacts.org/api/v0/product/3017620422003.json

Réponse JSON (extraite)

{ "status": 1, // 1 = trouvé, 0 = non trouvé "product": { "product_name": "Nutella", "quantity": "400g", "nutrition_grades": "e" } }

Modèles de données Kotlin

Classe KotlinChamp JSONTypeDescription
OpenFoodFactsResponse.statusstatusInt1=trouvé, 0=introuvable
OpenFoodFactsResponse.productproductProduct?Objet produit (nullable)
Product.nomproduct_nameString?Nom du produit
Product.quantitequantityString?Quantité (ex: "400g")
Product.nutriscorenutrition_gradesString?Lettre A→E

Gestion des erreurs réseau

try { val response = RetrofitClient.api.getProduct(barcode) if (response.status == 1 && response.product != null) { // Produit trouvé → insertion en BDD } } catch (e: Exception) { // Pas de connexion, timeout, serveur indisponible // L'app ne crashe pas — l'erreur est loggée silencieusement e.printStackTrace() }
10. Stack technique

Toutes les technologies et bibliothèques utilisées

CatégorieTechnologieVersionRôle
LangageKotlin2.1.0Langage principal Android
IDEAndroid StudioMeerkat 2024.3Environnement de développement
BuildGradle8.11.1Gestion des dépendances et compilation
BuildAndroid Gradle Plugin8.9.1Plugin Android pour Gradle
BuildKSP2.1.0-1.0.29Génération de code Room à la compilation
BDD localeRoom2.6.1ORM SQLite Android (Jetpack)
ArchitectureViewModel2.7.0Survie aux rotations d'écran
ArchitectureLiveData2.7.0Données observables réactives
ArchitectureCoroutines1.7.3Asynchronisme (Dispatchers.IO)
UIRecyclerView1.3.2Listes scrollables performantes
UICardView1.0.0Cartes avec ombres et coins arrondis
UIMaterial Design1.11.0BottomNavigationView, FAB
UIConstraintLayout2.1.4Layouts flexibles et contraints
RéseauRetrofit2.9.0Client HTTP pour l'API REST
RéseauGson Converter2.9.0Désérialisation JSON → Kotlin
ScannerZXing Android Embedded4.3.0Scan code-barre via caméra
API externeOpenFoodFactsv0Base de données produits alimentaires
NavigationFragment + FragmentManager1.6.2Navigation entre les écrans
CuisineWeek · Documentation Technique v1.0 · BTS SIO SLAM 2025–2026