Repository navigation
feat(api): signaler un parcours en ligne (POST /routes/:id/reports) - #592
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Rebasée sur main par l'équipe pour repasser l'audit vite 8.3.4, aucun changement de code. |
00bb89d to
304324f
Compare
|
📋 MANAGER, 2026-10-21 — relecture contre #437 : verdict B (fusionnable après rebase sur Rebase : la branche part de Critères : tous tenus, après deux corrections du ticket par MANAGER (les écarts annoncés dans la PR sont justes) :
Recouvrement avec la pile admin : aucun. #479 (#54, A-03 onglet Parcours) lit et tranche les Risque : niveau 2 juste (endpoint authentifié, entrée non fiable). Revue OWASP présente et concrète (accès, injection, abus par verrou et règle des 7 jours, journalisation, données personnelles). À suivre ailleurs : le jeton d'un compte anonyme (D-099) devra recevoir 403 Modèle de PR : complet (lien, écrans, vérification, risque, taille, retour arrière). Il manque les labels À faire avant la fusion : rebase sur |
…te (D-056) The body of POST /routes/:id/reports follows the rules of reports.ts: a step for « place_changed » and no other reason, a comment of 80 characters for « place_changed » (optional) and « other » (required), never « low_rating ». The answer holds the report and nothing of the reporter. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ver 7 days (D-056) POST /routes/:id/reports answers 201 with the open report, 409 with reportedAt inside the window, 403 on the route of the caller, 404 for a route that is not online or unknown. It rests on createRouteReport: the rule of the 7 days, the check of the step and the lock against two reports at once are its own. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
304324f to
581552e
Compare
|
Rebasée et complétée par l'équipe : rebase sur |
|
Accord de niveau 2 consigné par MANAGER : Paul (opérateur) a donné son accord en session le 2026-10-21 (« on fusionne »), PR fusionnée le même jour. Cet accord vaut accord de l'opérateur avant production au sens de la règle du niveau 2 ; le déploiement en production reste manuel, par Ilan ou Paul, après un staging vert. |
Résultat et problème
L'app n'avait aucune route pour signaler un parcours : la table
route_reportset la règle des 7 jours existaient (#184, PR #432), mais rien ne permettait d'écrire un signalement depuis un client. Cette PR exposePOST /v1/routes/:id/reports, que « Signaler ce parcours » (E-05, ticket #50) appellera et que l'onglet Parcours de l'admin (A-03, ticket #54) lit.apps/api/src/routes/route-reports.ts) : authentifiée, jamais en cache. Corps{ reason, stepId?, comment? }, strict. Elle repose surcreateRouteReport(feat(api): ajouter les tables route_reports et notifications #432) : la règle des 7 jours glissants, la vérification de l'étape et le verrou contre deux envois simultanés (la file hors connexion de l'app qui renvoie) sont les siens ; rien n'est dupliqué.open, date : rien du signaleur) ; 409conflictavecdetails.reportedAtdu premier signalement sous 7 jours ; 403 sur son propre parcours ; 404 pour un parcours qui n'est pas en ligne, retiré ou inconnu ; 401 sans jeton ; 422validation_errorpour un corps invalide ; 400 pour un identifiant de parcours qui n'est pas un UUID.packages/shared/src/schemas/route-report.ts, d'aprèsreports.ts) : un motif parmi ceux que l'utilisateur choisit (jamaislow_rating) ;stepIdpourplace_changedet aucun autre motif ; commentaire de 80 caractères en texte brut, facultatif pourplace_changed, obligatoire pourother, refusé pour les autres motifs.Écarts avec le ticket (annoncés dans mon commentaire de démarrage sur le ticket)
route_reportedn'est pas émis par cette PR. L'API n'émet aucun événement PostHog (aucun client PostHog côté serveur), Analytics ne range pasroute_reportedparmi les événements « (serveur) », et le ticket dit lui-même que l'envoi hors connexion est côté app (Afficher et saisir la vérification des lieux dans la fiche et le parcours en cours #50). Le critère «route_reportedest émis avecroute_id,reason,step_index» n'est donc pas tenu ici : l'événement est celui de l'app, à émettre avec le ticket Afficher et saisir la vérification des lieux dans la fiche et le parcours en cours #50.needs_fix) reste signalable : il est toujours en ligne (onlineRouteStatuses, comme la fiche et les avis). Le ticket dit « parcours non publié » pour le 404 ; un brouillon, un parcours refusé ou retiré, et un identifiant inconnu répondent 404, indiscernables les uns des autres.Fixes #437
Écrans : aucun (l'écran « Signaler ce parcours » est E-05, ticket #50)
Dépendance : aucune (base
main)Comment vérifier
Il n'y a pas d'écran. Les mêmes requêtes se rejouent contre l'API locale avec un compte de l'émulateur d'authentification Firebase (
firebase emulators:start --only auth --project demo-widoo, l'API lancée avecFIREBASE_PROJECT_ID=demo-widooetFIREBASE_AUTH_EMULATOR_HOST=127.0.0.1:9099) :{"reason":"inappropriate"}sur un parcours publié répond 201 avec"status":"open"; une ligneopenapparaît dansroute_reports.{"reason":"false_info"}: 409 avec la date du premier.{"reason":"place_changed"}sans étape,{"reason":"other"}sans commentaire, etplace_changedavec une étape d'un autre parcours : 422.Tests : 13 tests d'intégration (
route-reports.test.ts: 201 et la ligne écrite, l'étape et le commentaire gardés, le 409 avecreportedAtetmyReportde la fiche, un nouveau signalement permis une fois le premier décidé (D-057) et par un autre lecteur, 403, 404 (brouillon, retiré, inconnu), 401,needs_fixsignalable, neuf corps refusés en 422 sans rien écrire, 400 pour un identifiant invalide, quatre envois simultanés qui n'écrivent qu'un signalement, chaque motif sans étape ni commentaire) et 4 sur le schéma côtéshared.Vérification humaine : aucune. Marco n'a pas rejoué les requêtes à la main (décision du 2026-10-21) et s'appuie sur les tests d'intégration et sur un passage des mêmes requêtes contre l'API locale, relevé par l'agent le 2026-10-21 (201, 409, 403, 404, trois 422).
pnpm lint && pnpm typecheck && pnpm testverts en local (chaque commit passe lint et types)Formatage mécanique : non
Risque
Niveau : 2 — nouvel endpoint authentifié qui écrit à partir d'une entrée non fiable, sans migration.
Taille : tous les commits sous 400 lignes utiles (123 et 321, tests compris). Aucun fichier généré.
Revue OWASP (Top 10, édition en cours)
requireAuth(401 sans jeton) ; l'auteur d'un parcours ne peut pas le signaler (403) ; un parcours qui n'est pas en ligne répond 404, sans distinguer un brouillon, un refus, un retrait ou un identifiant inconnu. Le signaleur est celui du jeton, jamais une valeur du corps.stepIdrevérifié contre les étapes du parcours dans la transaction. Le commentaire n'est lu que par l'équipe et n'est jamais publié.admin_actions(ce n'est pas une écriture de l'admin) ; la décision de l'équipe sur le signalement est journalisée par A-03. Ni le commentaire ni le compte ne vont dans les journaux applicatifs.users/export) couvre déjàroute_reports.Nouvelle dépendance : aucune.
Retour arrière
Le revert de la PR suffit : la route disparaît (404), le code d'écriture
createRouteReportet la table restent. Les signalements déjà écrits restent en base et dans l'admin ; il n'y a aucune migration à annuler.🤖 Generated with Claude Code