Projet d'examen : Perdu de vue
Bloc Laravel · projet d'examen · remise le 1er novembre 2026 à 23 h 59
La gare de Wavre a un bureau des objets trouvés, à côté des guichets. Chaque jour, le personnel y apporte ce que les voyageurs oublient dans le hall, sur les quais et dans les trains. Au comptoir, l'agent enregistre l'objet, note où et quand il a été trouvé, choisit sa couleur et lui colle des étiquettes comme « fragile » ou « vivant ». Quand le propriétaire se présente, l'agent marque l'objet restitué, et l'objet quitte la liste. Une fiche créée en double se supprime. Le site n'a pas de compte : l'authentification arrive au cours suivant. Vous construisez ce site seul, depuis un projet Laravel vide, avec tout ce que le bloc Laravel vous a appris.
À la fin de ce projet, vous aurez montré que vous savez :
- créer un projet Laravel et le versionner sur GitHub, une étape après l'autre,
- construire une base de trois tables et une table de liaison, avec ses migrations, ses modèles, ses enums et ses données,
- écrire les routes, les contrôleurs et les vues d'un site, à partir d'un tableau de routes imposées,
- valider des formulaires d'ajout et de modification, et afficher leurs erreurs en français,
- mettre en forme un site avec Tailwind CSS et des composants Blade.
1. Le projet
Le domaine
Le site manipule trois choses. Un lieu est un endroit de la gare où l'on ramasse des objets : le hall des guichets, un quai, un train. Un objet a été trouvé dans un seul lieu, à une date donnée, et porte une couleur. Une étiquette décrit un objet en un mot ou deux, et un objet peut en porter plusieurs. Une même étiquette sert à beaucoup d'objets.
| Table | Colonnes | Relation |
|---|---|---|
places |
name, kind (texte, enum PlaceKind) |
un lieu a plusieurs objets |
items |
place_id, name (60 caractères), description (facultative), color (texte, enum Color), found_on (date), returned_at (date, facultative) |
un objet appartient à un lieu et porte des étiquettes |
tags |
name |
une étiquette est portée par plusieurs objets |
item_tag |
item_id, tag_id, clé primaire composée des deux |
la table de liaison |
Les trois premières tables ont aussi id et les deux colonnes de dates de timestamps(). Les trois clés étrangères s'écrivent constrained()->cascadeOnDelete(), comme au chapitre 12.
Les modèles
Le modèle des étiquettes s'appelle Tag, comme celui des traits de caractère du refuge. Item a une méthode isReturned(), qui renvoie true quand returned_at contient une date. La clé étrangère place_id est une composition : supprimer un lieu supprime ses objets. La table item_tag relie les objets et leurs étiquettes, comme animal_tag au refuge du chapitre 17. Le diagramme de classes n'est pas fourni : vous le dessinez vous-même pour le rapport, avec les classes, les enums, les attributs et les multiplicités.
Les deux enums
La base enregistre la valeur de l'enum en texte, platform ou red. Dans le modèle, casts() change ce texte en cas de l'enum, comme pour l'espèce du refuge. Chaque enum a une méthode label() qui donne le texte affiché :
<?php
namespace App\Enums;
enum PlaceKind: string
{
case Hall = 'hall';
case Platform = 'platform';
case Train = 'train';
public function label(): string
{
return match ($this) {
self::Hall => 'Hall',
self::Platform => 'Quai',
self::Train => 'Train',
};
}
}
Color suit la même forme, avec ces douze cas :
| Cas | Valeur en base | label() |
|---|---|---|
Black |
black |
Noir |
White |
white |
Blanc |
Grey |
grey |
Gris |
Red |
red |
Rouge |
Blue |
blue |
Bleu |
Green |
green |
Vert |
Yellow |
yellow |
Jaune |
Orange |
orange |
Orange |
Brown |
brown |
Brun |
Pink |
pink |
Rose |
Purple |
purple |
Mauve |
Multicolor |
multicolor |
Multicolore |
Les données
Le seeder crée au moins 4 lieux, 8 étiquettes et 15 objets, dont 3 restitués. Un lieu est une ligne de la table places, avec un nom et une sorte : la solution en a quatre, le hall des guichets, deux quais et un train, et les trois sortes de l'enum PlaceKind y sont représentées. Écrivez des données fixes, sans fake() dans le seeder : après php artisan migrate:fresh --seed, la liste montre toujours les mêmes objets, dans le même ordre. Les dates de découverte se situent en octobre 2026, aucune dans le futur, et un objet est restitué après avoir été trouvé.
Les objets sont les vôtres. Inventez-les drôles et crédibles, avec une description qui aiderait leur propriétaire à les reconnaître. Pour donner le ton : un nain de jardin prénommé Gérard, trouvé sur un quai, un poisson rouge dans son sachet, oublié dans un train, ou une seule chaussure de sport, pointure 44. Les objets visibles sur les captures de cet énoncé viennent de la solution : ne les recopiez pas.
Chaque modèle a aussi sa fabrique, PlaceFactory, ItemFactory et TagFactory, comme au chapitre 11, section 4. Les fabriques peuvent utiliser fake(). Elles servent aux tests, et à remplir la base si vous voulez voir une longue liste.
2. Ce que vous créez vous-même
Le projet et le dépôt
Il n'y a pas de dépôt de départ, et aucun test n'est fourni : les écrire est la supplémentaire S11. Dans le dossier de Herd ou de Laragon, créez le projet comme au chapitre 4, avec PHP 8.4 :
laravel new perdu-de-vue --git --no-boost
Répondez « No » au starter kit, puis choisissez Blade. Gardez Pest, SQLite et npm, proposés par défaut. Sur GitHub, créez ensuite un dépôt public nommé perdu-de-vue, et poussez-y le projet depuis VS Code, comme pour les katas. Commitez régulièrement, à chaque étape franchie, et poussez : les migrations, les modèles et les enums, les seeders, la liste et la fiche, l'ajout, la validation, la modification, la restitution, la suppression, la mise en forme. Un message de commit dit ce que l'étape ajoute, par exemple « Ajoute la restitution d'un objet ». Le .gitignore de Laravel écarte déjà .env, vendor/, node_modules/ et database/database.sqlite : ne le modifiez pas.
Quelques réglages se font au début du projet. Installez les traductions françaises, comme au chapitre 15, section 4, et enregistrez le dossier lang/ dans un commit :
composer require laravel-lang/common --dev
php artisan lang:add fr
Mettez APP_LOCALE=fr et APP_FAKER_LOCALE=fr_BE dans .env et dans .env.example : la première pour les messages de validation, la seconde pour que fake() produise des noms et des adresses belges dans les fabriques. Dans config/app.php, réglez 'timezone' => 'Europe/Brussels' : en UTC, today() donne encore la date de la veille pendant la première heure après minuit en hiver, et les deux premières en été.
Pint est l'outil de mise en forme du code PHP livré avec Laravel. Il n'a pas été vu au cours. vendor/bin/pint réécrit vos fichiers selon les conventions de Laravel, indentation, espaces, ordre des use, sans toucher à ce qu'ils font. vendor/bin/pint --test les contrôle sans rien modifier et liste ceux qui s'écartent des conventions. Sous PowerShell, les deux commandes s'écrivent .\vendor\bin\pint. Lancez la mise en forme avant chaque commit. Créez à la racine un fichier pint.json qui écarte lang/ du contrôle :
{
"preset": "laravel",
"exclude": [
"lang"
]
}
Sans ce fichier, Pint signale les six fichiers de lang/fr/ produits par Laravel-Lang, que vous n'avez pas écrits.
Ce que vous pouvez recopier
Les quatre composants de champ de la friterie et du refuge, <x-label>, <x-input>, <x-select> et <x-textarea>, peuvent être recopiés tels quels. Prenez les quatre fichiers dans resources/views/components/ de friterie-26 ou de refuge-26. Le reste des deux dépôts, le layout, la navigation, les boutons, les cartes et les badges, peut vous servir de point de départ : reprenez ce qui vous est utile et modifiez-le pour qu'il colle à « Perdu de vue », ses pages, ses couleurs et son vocabulaire.
| Ce que vous écrivez | Où |
|---|---|
| les quatre migrations | database/migrations/ |
les enums PlaceKind et Color |
app/Enums/ |
les modèles Place, Item et Tag, avec leurs relations, #[Fillable] et casts() |
app/Models/ |
| les fabriques et les seeders | database/factories/, database/seeders/ |
| les routes | routes/web.php |
ItemController et PlaceController |
app/Http/Controllers/ |
la Form Request ItemRequest |
app/Http/Requests/ |
| le layout, vos composants et les vues des pages | resources/views/ |
3. Les routes imposées
Le verbe, l'adresse, le nom de la route et la méthode du contrôleur sont imposés. Les adresses sont en français, les noms et les méthodes en anglais. Le paramètre s'écrit {item} ou {place}, avec la liaison de modèle du chapitre 15, section 6 : un objet inconnu répond 404 sans une ligne de plus. Posez whereNumber sur le paramètre, ou déclarez /objets/nouveau avant /objets/{item}, pour éviter le piège de l'ordre du chapitre 7.
| Verbe | Adresse | Nom | Méthode |
|---|---|---|---|
ANY |
/ |
redirection vers /objets |
|
GET |
/objets |
items.index |
ItemController@index |
GET |
/objets/nouveau |
items.create |
ItemController@create |
POST |
/objets |
items.store |
ItemController@store |
GET |
/objets/{item} |
items.show |
ItemController@show |
GET |
/objets/{item}/modifier |
items.edit |
ItemController@edit |
PUT |
/objets/{item} |
items.update |
ItemController@update |
PATCH |
/objets/{item}/restitution |
items.return |
ItemController@return |
DELETE |
/objets/{item} |
items.destroy |
ItemController@destroy |
GET |
/lieux/{place} |
places.show |
PlaceController@show |
GET |
/composants |
styleguide |
la vue styleguide |
La première et la dernière route n'ont pas de contrôleur à écrire. Vous les avez vues au chapitre 7. Route::redirect() répond à tous les verbes, et route:list affiche ANY :
Route::redirect('/', '/objets');
Route::view('/composants', 'styleguide')->name('styleguide');
La page /composants montre chacun de vos composants dans ses variantes, comme celle du refuge. Elle vous sert de référence pendant le projet, et au correcteur pour voir vos composants d'un coup d'œil. return est un mot-clé de PHP, mais une méthode peut porter ce nom : public function return(Item $item) s'écrit sans erreur. Une fois les routes écrites, php artisan route:list --except-vendor affiche « Showing [11] routes ».
4. Les fonctionnalités obligatoires
Tout le monde rend ce socle. Le tableau dit ce que le correcteur vérifie pour chaque fonctionnalité. Les numéros reviennent dans le canevas du rapport.
| # | Fonctionnalité | Ce qui est vérifié |
|---|---|---|
| O1 | Le projet | créé avec laravel new perdu-de-vue --git --no-boost, PHP 8.4, Blade, Pest, SQLite, dépôt GitHub public, des commits réguliers |
| O2 | La base | les quatre tables, les clés étrangères en cascade, l'enum PlaceKind sur kind, l'enum Color sur color, casts() sur les enums et les dates |
| O3 | Les données | les trois fabriques, un seeder fixe d'au moins 4 lieux, 8 étiquettes et 15 objets dont 3 restitués |
| O4 | La liste | GET /objets montre les objets non restitués, du plus récent au plus ancien, avec le lieu, la date, la couleur et les étiquettes en badges, et les filtres ?lieu= et ?couleur= |
| O5 | La fiche | GET /objets/{item} montre tout l'objet, son lieu en lien vers sa page, ses étiquettes et sa date de restitution s'il en a une |
| O6 | Le lieu | GET /lieux/{place} montre le lieu et tous ses objets, restitués compris, chacun avec un badge « En attente » ou « Restitué » |
| O7 | Ajouter | le formulaire avec @csrf, les quatre composants de champ et les cases des étiquettes, la validation, les erreurs en français sous chaque champ, old() sur tous les champs, un message flash |
| O8 | Modifier | le formulaire pré-rempli, @csrf et @method('PUT'), la même Form Request ItemRequest que l'ajout, sync() des étiquettes, des cases qui gardent leur état après un refus |
| O9 | Restituer | un formulaire avec @csrf et @method('PATCH') pose returned_at à today(), affiche un message flash, et l'objet quitte la liste. Un objet déjà restitué garde sa date |
| O10 | Supprimer | un bouton type="submit" dans un formulaire avec @csrf et @method('DELETE'), une confirmation, un message flash, et les lignes de item_tag disparaissent avec l'objet |
| O11 | La mise en forme | le layout <x-layouts.app> avec sa navigation, au moins trois composants réutilisés, les états hover et focus, des badges colorés selon l'enum |
| O12 | Le code | identifiants en anglais, adresses et textes en français, contrôleurs courts, aucune requête dans les vues |
| O13 | Le rapport et le carnet | le rapport selon le canevas, et le carnet métacognitif, en PDF (section 7) |
La liste et ses filtres
Au-dessus de la liste, un formulaire en GET propose deux listes déroulantes, le lieu et la couleur. Envoyé, il ajoute ?lieu=2&couleur=red à l'adresse : lieu porte l'id du lieu, couleur la valeur de l'enum. Les deux filtres se combinent. Une couleur inconnue, comme ?couleur=violet, est ignorée : Color::tryFrom(), vue au chapitre 7 de la POO, renvoie alors null. Chargez les lieux et les étiquettes avec with(), pour éviter le piège N+1 du chapitre 12, section 6.

Sur chaque carte, la couleur apparaît deux fois : en pastille dans l'en-tête, et en badge avec son libellé. Seul le badge est demandé.
Les règles de validation
Les règles vivent dans ItemRequest, partagée par store() et update(), comme au chapitre 16, section 3. Les champs portent les mêmes noms à l'ajout et à la modification :
| Champ | Élément | Règles | Nom dans les messages |
|---|---|---|---|
name |
<input type="text"> |
required, string, min:2, max:60 |
nom |
color |
<select> sur Color::cases() |
required, Rule::enum(Color::class) |
couleur |
found_on |
<input type="date"> |
required, date, before_or_equal:today |
date de découverte |
place_id |
<select> sur les lieux |
required, integer, exists:places,id |
lieu |
description |
<textarea> |
nullable, string, max:1000 |
description |
tags |
cases name="tags[]" value="{{ $tag->id }}" |
nullable, array |
étiquettes |
tags.* |
integer, exists:tags,id |
étiquette |
Les noms français des champs vont dans le tableau attributes de lang/fr/validation.php, comme au chapitre 15, section 4, ou dans la méthode attributes() de la Form Request. Pour la date future, remplacez le message « … au today » par le vôtre dans messages(), comme au kata 17.4. Aucun champ ne porte l'attribut HTML required : envoyé vide, le formulaire part au serveur, et quatre messages s'affichent.

Après un refus, les cases des étiquettes gardent l'état choisi avant l'envoi, toutes décochées comprises. Reprenez session()->hasOldInput() du kata 17.5 : sans lui, une liste vide après un refus ferait revenir les étiquettes enregistrées.
Restituer et supprimer
Sur la fiche d'un objet en attente, un formulaire d'un bouton envoie la restitution avec @method('PATCH'). Sur la fiche d'un objet restitué, ce bouton disparaît. Un bouton absent ne suffit pourtant pas : une fiche ouverte dans un deuxième onglet garde le sien. return() vérifie donc isReturned() avant d'écrire, et un objet déjà restitué garde sa première date, avec un message qui le dit.
La suppression demande une confirmation, avec onsubmit="return confirm('…')" comme au chapitre 16, section 7. Elle redirige vers la liste, et le message flash s'affiche dans le layout. Les textes des messages sont libres. Ceux de la solution donnent le ton :
| Action | Message flash de la solution |
|---|---|
| ajout | L'objet a été ajouté. |
| modification | L'objet a été modifié. |
| restitution | « Parapluie à motifs de canards » a retrouvé son propriétaire. |
| restitution d'un objet déjà restitué | Cet objet a déjà été restitué le 06/10/2026. |
| suppression | L'objet a été supprimé. |
5. Les fonctionnalités supplémentaires
Les fonctionnalités supplémentaires sont facultatives, et aucune n'est vue en séance. Chacune vous fait apprendre une notion seul, avec la documentation ou le chapitre indiqué. Une fonctionnalité bien faite vaut mieux que trois bâclées. Bien faite veut dire : dans le style du reste du site, validée quand elle reçoit une saisie, et présentée dans le rapport. Une supplémentaire ne compense jamais une obligatoire manquante. Gardez les numéros du tableau : le canevas du rapport les reprend. Les étoiles donnent l'effort estimé.
| # | Fonctionnalité | Ce que vous apprenez | À lire | Effort |
|---|---|---|---|---|
| S1 | Photo de l'objet | enctype, $request->file(), store(), le disque public, storage:link, la règle image, la suppression du fichier |
le chapitre 18 « Téléverser une image », qui le fait sur le refuge | ★ |
| S2 | Pagination | paginate(9), {{ $items->links() }}, les filtres gardés avec withQueryString() |
pagination | ★ |
| S3 | Recherche par texte | un champ ?q=, where('name', 'like', …), combiné aux filtres |
where | ★ |
| S4 | Tri de la liste | ?tri=date ou ?tri=nom, une valeur comparée à une liste fixe avant orderBy |
ordering | ★ |
| S5 | Dates en français | « il y a 3 jours » avec diffForHumans(), « 2 octobre 2026 » avec isoFormat('D MMMM YYYY') |
Carbon, localisation | ★ |
| S7 | Déclaration de perte | une quatrième table claims : un voyageur décrit ce qu'il a perdu sur /perdu, l'agent relie la déclaration à un objet, item_id facultatif |
one to many | ★★ |
| S9 | Page de statistiques | les objets par lieu et par mois, selectRaw, groupBy, des barres en largeur Tailwind sans bibliothèque |
aggregates, grouping | ★★ |
| S11 | Tests Pest des routes | un test par route imposée, assertSee, assertDatabaseHas, la CI GitHub Actions de refuge-26 (.github/workflows/tests.yml) |
HTTP tests, database testing | ★★ |
| S13 | Mode sombre | la variante dark: sur le layout et les composants, comme au bonus 14.8 |
dark mode | ★ |
| S14 | Galerie de photos | plusieurs photos par objet, une table photos, une photo de couverture, la suppression d'une photo, à la suite de S1 |
file uploads | ★★★ |
| S15 | Mise en ligne | le site sur un hébergement, l'adresse dans le rapport | les chapitres « Hébergement OVH » et « Hébergement O2Switch » du cours | ★★★ |
| S16 | Interface en deux langues | lang/en, __() sur les textes affichés, une langue choisie et gardée en session |
localization | ★★ |
Faites chaque supplémentaire dans sa propre suite de commits, ou dans une branche fusionnée avant la remise. Si une supplémentaire casse une obligatoire, retirez-la : le socle passe avant.
6. La mise en forme
La mise en forme est libre, dans un cadre précis. Chaque page s'affiche dans le layout <x-layouts.app>, avec un en-tête, une navigation et le message flash. Le lien de la page ouverte se distingue des autres dans la navigation. Au moins trois composants sont écrits par vous et réutilisés sur plusieurs pages : un bouton <x-button> avec ses variantes, un badge <x-badge> et une carte <x-card>. Un composant <x-item-card>, partagé par la liste et la page d'un lieu, évite de recopier la carte d'un objet.
Les badges prennent leur couleur de l'enum. Une méthode de l'enum renvoie les classes Tailwind de chaque cas, écrites en entier, car Tailwind ne voit pas un nom de classe assemblé (chapitre 13) :
public function badgeClasses(): string
{
return match ($this) {
self::Hall => 'bg-sky-50 text-sky-800',
self::Platform => 'bg-amber-50 text-amber-900',
self::Train => 'bg-orange-50 text-orange-800',
};
}
Dans le composant, @class ajoute ces classes à celles du badge :
<span @class(['rounded-full px-2 py-0.5 text-xs font-semibold', $place->kind->badgeClasses()])>
{{ $place->kind->label() }}
</span>
Les liens et les boutons ont un état hover et un contour au clavier avec focus-visible, comme au chapitre 14. Un champ refusé a une bordure rouge et son message juste en dessous. Un site lisible sur un téléphone compte dans le degré de maîtrise : à 375 pixels de large, la liste montre une carte par ligne, les filtres s'empilent et la navigation reste utilisable. Vérifiez chaque page avec F12 puis Ctrl+Maj+M, comme au chapitre 14, section 1.

La palette est libre. La solution reprend les couleurs d'une signalétique de gare, et votre site peut prendre une tout autre direction, tant que les couleurs restent les mêmes sur toutes les pages et que le texte reste lisible.
7. Le rapport et le carnet
Téléchargez les deux documents Word, remplissez-les, puis enregistrez-les en PDF.
Le canevas du rapport compte neuf sections : introduction, cahier des charges réalisé, base de données, fonctionnalités, validation et sécurité, mise en forme, difficultés rencontrées, autocritique et conclusion. Il contient le tableau O1 à O13 à cocher, le tableau des supplémentaires retenues, la place du diagramme de classes, qui est obligatoire, et la liste des captures attendues. Remplacez chaque consigne en italique par votre contenu. Tenez un journal de vos difficultés au fil du projet, avec la date, le problème et la solution : la section 7 se remplira presque toute seule. Pour cocher une case des deux documents, remplacez le carré par un « x », ou par ☑ si vous préférez.
Carnet métacognitif (Word)DOCX
Le carnet rappelle d'abord ce qui distingue un assistant d'un agent, et ce que chacun a le droit de faire. Il décrit ensuite votre usage de l'IA en trois parties : la déclaration d'usage, avec vos outils et votre niveau d'usage de 0 à 4, la démarche et les vérifications, puis un regard critique. Il demande un prompt qui a marché, un qui a raté, une vérification qui a révélé un problème, et cinq à dix lignes de votre projet expliquées avec vos mots. Il se termine par une attestation signée. Le carnet est individuel. Un usage intensif et bien vérifié, décrit honnêtement, vaut mieux qu'un usage caché.
Votre nom et votre prénom figurent sur la première page de chaque document et dans le nom de chaque fichier : rapport-5xcos-NOM-Prenom.pdf et carnet-5xcos-NOM-Prenom.pdf.
8. L'IA
Un assistant est une IA à qui vous parlez, dans un chat ou dans l'éditeur : vous lui posez une question, il répond, et c'est vous qui écrivez dans vos fichiers. Un agent est une IA qui agit à votre place : il lit vos fichiers, en crée, les modifie et lance des commandes. La règle du cours tient en deux phrases. L'assistant est autorisé pour le code : expliquer une notion ou une erreur, aider à déboguer, proposer une solution que vous recopiez et comprenez. L'agent est interdit pour écrire ou modifier du code, et autorisé pour lire votre projet et répondre à vos questions sur lui.
Pour le rapport et le carnet, l'assistant est autorisé en coproduction encadrée : les idées et le contenu sont les vôtres, l'IA corrige, reformule ou structure, et vous vérifiez que tout ce qui est écrit est vrai. Vous devez comprendre et pouvoir expliquer chaque ligne que vous remettez, du code comme du rapport. Le carnet le montre, avec ses lignes expliquées et ses vérifications.
Vérifiez ce qu'un assistant propose avec la documentation de Laravel 13 et avec le navigateur. Un assistant écrit souvent pour une ancienne version : un app/Http/Kernel.php qui n'existe plus depuis Laravel 11, protected $fillable à la place de #[Fillable], une route en fonction anonyme quand le tableau impose un contrôleur. Déclarez votre usage dans le carnet.
9. La remise et la note
Le projet est individuel. Remettez trois pièces dans le devoir dédié du groupe Teams du cours, au plus tard le 1er novembre 2026 à 23 h 59 :
- le lien de votre dépôt GitHub public,
- le rapport en PDF,
- le carnet métacognitif en PDF.
Il n'y a pas de défense orale. Le dépôt est lu tel qu'il est à l'heure de la remise : ne poussez plus rien ensuite. Avant de remettre, ouvrez le lien du dépôt dans une fenêtre de navigation privée, pour vérifier qu'il est bien public.
Attention
Les trois pièces sont indispensables à la recevabilité du projet. Sans rapport en PDF portant votre nom, l'acquis d'apprentissage 1.4 est non acquis. Sans carnet en PDF portant votre nom, l'acquis 1.5 est non acquis. Sans dépôt accessible, l'acquis 1.3 est non acquis. Un seul acquis non acquis suffit pour l'ajournement.
La grille d'évaluation compte deux parties de 50 points. La première vérifie que les cinq acquis d'apprentissage sont atteints : les fonctionnalités, la qualité du code, Git, le rapport et le carnet. Chaque acquis est décrit en quatre niveaux. Quand les cinq sont atteints, la seconde partie mesure le degré de maîtrise sur quatre critères : l'interface, la robustesse, l'architecture et l'analyse du rapport. Lisez la grille avant de commencer, et relisez-la avant de remettre.
Grille d'évaluation 2026-2027 (PDF)PDF
À vérifier avant de remettre
Cette liste reprend ce que les acquis d'apprentissage exigent. Le reste, un site lisible sur un téléphone, Pint sans remarque, un historique Git qui raconte le projet, compte dans le degré de maîtrise, pas dans la réussite.
| Vérification | Comment |
|---|---|
| La base se reconstruit | php artisan migrate:fresh --seed passe sans erreur, et la liste montre au moins 12 objets en attente |
| Les onze routes existent | php artisan route:list --except-vendor affiche « Showing [11] routes », avec les noms du tableau |
| Le formulaire vide est refusé | quatre messages en français, chacun sous son champ |
| La modification est pré-remplie | la date s'affiche dans son champ, les étiquettes de l'objet sont cochées |
| La restitution retire l'objet de la liste | restituez un objet depuis sa fiche : la liste ne le montre plus, la page de son lieu le montre avec le badge « Restitué » |
| La suppression vide la liaison | après la suppression de l'objet 5, DB::table('item_tag')->where('item_id', 5)->count() renvoie 0 dans php artisan tinker |
| Le dépôt est public | ouvert dans une fenêtre de navigation privée, il s'affiche sans connexion |
| Les PDF sont nommés | votre nom sur la première page et dans le nom des deux fichiers, rapport-5xcos-NOM-Prenom.pdf et carnet-5xcos-NOM-Prenom.pdf |