Skip to content

feat(admin): réglages et journal des actions (A-11, A-12) - #500

Open
Nascimento95 wants to merge 10 commits into
issue/341-users-and-rolesfrom
issue/348-settings-and-log
Open

Nascimento95 wants to merge 10 commits into
issue/341-users-and-rolesfrom
issue/348-settings-and-log

Conversation

@Nascimento95

Copy link
Copy Markdown
Collaborator

Résultat et problème

Changer un seuil de l'app (Premium, limite de relecture, badge, regroupement de la carte, recommandation) demandait une mise en ligne ou un accès à la base, et rien ne gardait la trace de ce que l'équipe modifie dans l'admin. A-11 « Réglages » et A-12 « Journal » règlent les deux, pour l'admin seulement.

  • Réglages (A-11) : 7 réglages groupés par thème, avec libellé, explication, valeur en vigueur (défaut tant que l'équipe n'a rien changé), bornes, dernière modification et historique. « Modifier » ouvre une confirmation avec un motif obligatoire ; l'API tient la valeur aux bornes de sa clé ; l'effet s'applique à l'app en une minute au plus, sans mise en ligne. Chaque changement écrit admin_actions (avant, après, motif).
  • Journal (A-12) : toutes les écritures de l'équipe, de la plus récente à la plus ancienne, filtrables par auteur, type d'action, type de cible et période ; le détail montre le JSON avant et après, le motif, et un lien vers la cible tant qu'elle existe (le nom d'un compte, d'un parcours ou d'un lieu remplace son identifiant). Lecture seule, rien ne s'y efface.
  • API : GET /admin/settings, PATCH /admin/settings/:key, GET /admin/actions, plus GET /admin/actions/filters pour remplir les filtres.

Réglages gérés : premium.min_steps, max_pending_routes, certification.min_verified_routes, certification.min_rating, certification.min_completed_routes, search.cluster_area_km2, recommendation.weights. Ce sont ceux que l'API lit réellement dans settings.

Limites

  • Critère d'acceptation « passer premium.min_steps de 4 à 5 change l'accès des parcours au prochain recalcul » : tenu pour le réglage et le journal, non démontrable pour l'accès. premium.min_steps ne sert aujourd'hui qu'à la fiche de modération (proposition Premium) ; aucun code ne s'en sert pour donner ou retirer l'accès, et le recalcul nocturne est le ticket Planifier le recalcul nocturne et le passage en needs_fix #56, absent.
  • Absents de la liste, faute de lecteur dans le code (les modifier ne changerait rien) : coherence.* (l'API utilise les valeurs par défaut), premium.min_ratings, premium.min_rating, les seuils de vérification des lieux. Le wiki Admin-Web › A-11 les cite : à ajouter quand le code les lira. Signalé sur l'Inbox.
  • Bornes hautes ajoutées par prudence contre une faute de frappe (code sans borne) : premium.min_steps 1 à 20, max_pending_routes 1 à 20, certification.* comptes 0 à 100, search.cluster_area_km2 0,1 à 10 000. Les autres suivent le code (note 0 à 5, poids 0 à 10, pas tous à zéro).
  • Les libellés et explications français des réglages sont une proposition à valider (DESIGN / Ilan).

Fixes #348
Écrans : A-11, A-12
Dépendance : PR empilée sur #499 (#341, base issue/341-users-and-roles), elle-même sur #479, #398, #365 et #363.

Comment vérifier

  1. pnpm install, docker-compose up -d, pnpm --filter @widoo/api db:migrate && pnpm --filter @widoo/api db:seed, pnpm dev.
  2. Connecté en admin, Réglages : ouvrir « Étapes d'un parcours Premium », « Modifier », mettre 5 avec un motif : toast, valeur « Modifié par l'équipe », historique « 4 étapes → 5 étapes ». Essayer 0, 25 et 4,5 : refus. Essayer les poids de la recommandation, tous à 0 : refus.
  3. Journal : la ligne « Réglage modifié » avec son motif ; ses filtres ; le détail avant/après ; « Ouvrir la cible » d'un compte existant, et son absence pour un compte supprimé.
  4. Connecté en moderator : ni « Réglages » ni « Journal » dans le menu, et un écran de refus à l'adresse /reglages ou /journal.

Tests : validation par clé (bornes, entiers, poids connus et non tous nuls), écriture avec journal avant/après et motif, 403 pour moderator et editor, filtres et périodes du journal, nom de la cible ; affichage des libellés et lecture de la saisie côté admin.

  • pnpm lint && pnpm typecheck && pnpm test verts en local (chaque commit passe lint et types) ; l'échec connu de reports/repository.test.ts (délai de 5 s) disparaît seul

Formatage mécanique : non

Risque

Niveau : 2 — un réglage change le comportement de l'app et de la modération, de façon réversible et bornée ; aucune migration.

Taille : tous les commits sous 400 lignes utiles (le plus gros : 361).

Revue OWASP (ciblée)

  • A01 Contrôle d'accès : les deux sections sont fermées à l'éditeur et au moderator par le garde de section (rôle lu en base à chaque appel), et l'API refuse (403) toute écriture hors admin ; l'écran ne fait que cacher. Testé pour editor et moderator.
  • A04 Conception non sécurisée : une valeur est tenue aux bornes de sa clé avant écriture (400) ; une valeur stockée hors bornes se lit comme le défaut, comme le code qui l'utilise : une faute de frappe ne désactive aucune règle. Une clé inconnue répond 404.
  • A09 Journalisation : chaque changement écrit admin_actions dans la transaction du changement, avec le motif obligatoire ; le journal n'a aucune route d'écriture ni de suppression.
  • A03 Injection : requêtes paramétrées ; filtres du journal validés (identifiant, période énumérée, longueurs) ; texte du motif en texte brut sans balises.
  • Données personnelles : le journal montre le prénom ou l'e-mail de l'auteur et le nom de la cible, à l'admin seulement, cache-control: no-store ; les états avant/après ne portent que ce que chaque action change.
  • Aucune nouvelle dépendance.

Retour arrière

Revert de la PR, sans migration. Les valeurs déjà enregistrées dans settings restent valides pour le code d'avant (mêmes clés, mêmes bornes que celles qu'il lit) ; pour revenir aux défauts, remettre les valeurs par défaut dans l'admin avant le revert, ou supprimer les lignes de settings concernées. Le journal garde les lignes écrites.

🤖 Generated with Claude Code

Nascimento95 and others added 10 commits October 16, 2026 14:58
…1, A-12)

Schemas of the settings (value in force, default, bounds, update with a reason) and of the
journal (lines with author, target and its name, filters, periods).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…orce (A-11)

GET /admin/settings, admin only. The catalog holds the settings the API reads and applies
(premium.min_steps, max_pending_routes, certification, search clustering, recommendation
weights) with their bounds and default; a stored value outside them reads as the default, like
the code that uses it. Settings no code reads are left out, as changing them would do nothing.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
PATCH /admin/settings/:key, admin only: the value is held to the bounds of its key (a count is
whole, weights name known components and are not all zero), then written with its journal line
(before, after, reason) in one transaction. The API reads settings again within a minute at
most. An unknown key answers 404, a value out of bounds 400.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
GET /admin/actions, admin only: the writes of the team, most recent first, filtered by author,
kind of action, kind of target, one object and period, with the name of each target (account,
route, place) as it is today. GET /admin/actions/filters gives the values the filters offer.
Read only.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…1, A-12)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… the journal reads (A-11, A-12)

French labels of the actions, targets and periods, of each setting and its explanation; the
address filters of the journal; the name, label and link of the target of a line, none for an
object that is gone.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… of a setting (A-11, A-12)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…fore and after (A-12)

Journal, admins only: the lines the address asks for, filtered by author, action, target and
period, and next to it the detail of one line with its reason, its target (a link while it
exists) and the JSON before and after. Read only.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…its history (A-11)

Réglages, admins only: the settings grouped by theme with their value and whether the team
changed it, and the detail of one: explanation, value, default, bounds, last change and its
history from the journal.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
« Modifier » opens a window with the value (one field, or one per weight, typed with a decimal
comma), the bounds, and the required reason kept in the journal. A refused value is told in a
toast; once saved, the list and the history are read again.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

This branch has not been deployed

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

Labels

level:2 Risque niveau 2 (SECURITY.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant