Skip to content

feat(api): chercher, créer et modifier un lieu (E-13) - #594

Merged
PaulThiberville merged 5 commits into
mainfrom
issue/46-places-search-create
Oct 21, 2026
Merged

PaulThiberville merged 5 commits into
mainfrom
issue/46-places-search-create

Conversation

@Nascimento95

@Nascimento95 Nascimento95 commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Résultat et problème

Un créateur ne pouvait ni retrouver un lieu existant ni en ajouter un : aucune route n'écrivait ni ne cherchait les lieux (seuls le seed et les tests le faisaient). Cette PR livre la partie API de #46 (E-13), selon le wiki API › Lieux :

  • GET /v1/places/search?q=&near=lat,lng&category=&limit= : lieux dont le nom contient le texte ou lui ressemble (trigrammes), triés par proximité de nom puis par distance (mètres) ; les lieux fermés ne sortent pas ; au moins q ou near.
  • POST /v1/places : crée un lieu unverified dans la ville qui le contient. Si un lieu de nom proche (similarité ≥ 0,4) existe à moins de 50 m : 409 conflict avec ce lieu dans details.candidate, sauf force: true. Plus de 20 créations en 24 h par compte : 429 rate_limited (details.reason: place_creation).
  • endsOn (date de fin d'un lieu éphémère, D-050) : accepté par POST /v1/places (nul par défaut) et par PATCH, date ISO AAAA-MM-JJ, enregistré dans places.ends_on (commit ajouté par l'équipe).
  • PATCH /v1/places/:id : le créateur tant que seuls ses propres parcours utilisent le lieu ; un modérateur ou un admin toujours ; les horaires sont remplacés en bloc.

Aucune migration : la table places, l'index trigramme et les horaires existent déjà.

Limites restantes

Fixes #46
Écrans : E-13 (partie API)
Dépendance : aucune (depuis main)

Comment vérifier

Tests : pnpm --filter api exec vitest run src/routes/places.test.ts (19 tests : recherche par texte, position, catégorie, % et _ du texte pris comme lettres, lieu fermé exclu, 400 sans critère ou avec clé inconnue, 401 ; création avec horaires, doublon à 20 m, force, lieu lointain ou de nom différent non pris pour un doublon, hors ville, quota de 20 par jour propre à chaque compte, corps invalide ; modification par le créateur, refus d'un tiers, refus du créateur une fois le lieu utilisé par le parcours d'un autre, modérateur, 404, corps vide).

En local (Postgres, émulateur Auth, API sur le port 8081), dans Postman :

  • GET /v1/places/search?q=carnavalet&near=48.85732,2.36247 : 200, Musée Carnavalet, distanceM 0.
  • POST /v1/places « Café de Flore » en 48.8541, 2.3327 : 201, verificationStatus: "unverified".
  • Même corps à 48.85428 (≈ 20 m) : 409 avec le premier lieu ; avec "force": true : 201.
  • Position 0, 0 : 422 outside_service_area.
  • PATCH /v1/places/:id { "phone": "...", "priceRange": "medium" } : 200 ; sans jeton : 401.

Vérification humaine : Marco a testé la recherche, la création et le refus hors ville dans Postman en local le 2026-10-21 (captures dans la session), et déclaré avoir tout essayé.

  • pnpm lint && pnpm typecheck && pnpm test verts en local (API : 787 tests, shared : 677)
  • Testé sur iOS / Android — sans objet, aucun code mobile

Formatage mécanique : non

Risque

Niveau : 2 — nouveaux endpoints authentifiés qui écrivent des données (lieux visibles de tous les créateurs), sans migration ni donnée existante modifiée.

Taille : 785 lignes au total dont 310 de tests ; commits de 122, 203, 290, 149 et 24 lignes, tous sous 400 (le troisième compte 151 lignes de tests).

Revue OWASP (Top 10:2025, ciblée)

  • A01 Contrôle d'accès : PATCH réservé au créateur tant que seuls ses parcours utilisent le lieu, sinon rôle moderator (lu en base) ; le lieu est verrouillé (for update) pendant la vérification. Tests : tiers 403, créateur 403 après usage par un autre, modérateur 200, inconnu 404.
  • A05/A03 Injection : requêtes Drizzle paramétrées ; le texte de ILIKE échappe %, _ et \ (test) ; textes en texte brut sans <, > ni caractères de contrôle, liens en https seulement, clés inconnues refusées.
  • A06 Conception non sûre : quota de 20 lieux par jour et par compte, compté sous verrou de la ligne du compte pour que deux créations simultanées ne prennent pas la dernière place ; détection de doublon avant insertion.
  • Données personnelles : created_by est la seule donnée liée au compte ; la réponse ne l'expose pas.

Retour arrière

Revert de la PR suffit : aucune migration. Les lieux créés pendant que la PR est en ligne restent en base (lieux unverified, ville existante) et sont sans conséquence si les routes disparaissent.

@Nascimento95 Nascimento95 added type:feature Nouvelle fonctionnalité area:api apps/api level:2 Risque niveau 2 (SECURITY.md) labels Oct 21, 2026
@vercel

vercel Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
widoo-web Ready Ready Preview Oct 21, 2026 5:34pm UTC

@PaulThiberville

Copy link
Copy Markdown
Collaborator

Rebasée sur main par l'équipe pour repasser l'audit vite 8.3.4, aucun changement de code.

@PaulThiberville

Copy link
Copy Markdown
Collaborator

📋 MANAGER, 2026-10-21 — relecture contre #46 : verdict B (fusionnable après rebase, un petit commit et Fixes #46 ; niveau 2 confirmé)

Rebase : la branche part de 134c2b4a, 151 commits derrière main (d95f8793). Essayé dans un worktree, sans rien pousser : rebase sans conflit, seule et par-dessus #592 (app.ts et packages/shared/src/index.ts se fusionnent sans heurt). Sur le résultat : pnpm lint et pnpm typecheck verts, places.test.ts vert, pnpm --filter @widoo/api test 985/985 seule et 998/998 avec #592, avec la même instabilité que main sur les tests de recherche (#623).

Découpage de #46 (la PR demandait : « l'ajouter ici ou la sortir en ticket ») : la partie mobile sort dans #622, bloqué par #46. #46 ne porte plus que l'API ; cette PR doit donc passer de Refs #46 à Fixes #46.

Critères de #46 (version API) :

  • doublon à 20 m en 409 avec le candidat, force : tenu, testé ;
  • quotas, doublon, droits d'édition testés : tenu ;
  • manque : endsOn, la date de fin d'un lieu éphémère (D-050), que E-13 saisit à la création ; la colonne places.ends_on existe, mais CreatePlace ne l'accepte pas. Critère ajouté à API : rechercher, créer et modifier un lieu avec détection de doublons (E-13) #46 : un petit commit avec son test.

Recouvrement avec la pile admin (#398, #55, sur main) : deux règles pour une même chose. findCityId (admin, 400 hors ville, doublon = même nom à 50 m) et cityHolding (ici, 422 outside_service_area, similarité ≥ 0,4 à 50 m). Pas bloquant : l'unification est #616, bloqué par #46. Il y ajoute aussi la ligne admin_actions qui manque quand un modérateur modifie un lieu par PATCH /places/:id hors de l'admin.

Contrôles et modération des lieux créés : le lieu naît unverified, avec « lieux non vérifiés » vu dans A-02 et la vérification communautaire ; quota de 20 par jour sous verrou ; texte brut, liens https, clés inconnues refusées ; ILIKE échappé. Le refus des comptes suspendus arrive de main par requireAuth. À suivre : le jeton anonyme (D-099) devra recevoir 403 account_required (#532). Observation sans ticket : le créateur peut déplacer ou renommer un lieu déjà vérifié tant que seuls ses parcours l'utilisent, sans retour à unverified. À reprendre si la vérification communautaire (#49) le demande.

Risque : niveau 2 juste. Modèle de PR : complet, labels présents.

À faire avant la fusion : rebase, commit endsOn et son test, Fixes #46 dans le corps, CI verte. Fusionnable ensuite sous l'autorisation permanente de Paul (niveau ≤ 2), après #592.

Nascimento95 and others added 5 commits October 21, 2026 19:32
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@PaulThiberville
PaulThiberville force-pushed the issue/46-places-search-create branch from 12d1f55 to f0c3e17 Compare October 21, 2026 17:33
@PaulThiberville

Copy link
Copy Markdown
Collaborator

Rebasée et complétée par l'équipe : rebase sur main après #592, commit endsOn d'un lieu éphémère (D-050) avec son test, Fixes #46 dans le corps ; lint, typecheck et tests (API 999, shared 742) verts en local.

@PaulThiberville
PaulThiberville merged commit b8ec2bd into main Oct 21, 2026
8 checks passed
@PaulThiberville
PaulThiberville deleted the issue/46-places-search-create branch October 21, 2026 17:39
@PaulThiberville

Copy link
Copy Markdown
Collaborator

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:api apps/api level:2 Risque niveau 2 (SECURITY.md) type:feature Nouvelle fonctionnalité

Projects

None yet

Development

Successfully merging this pull request may close these issues.

API : rechercher, créer et modifier un lieu avec détection de doublons (E-13)

2 participants