Files
harmony-back/CLAUDE.md
T
admin eacffd7755
Build release Docker image / Build Docker Images (push) Successful in 21s
docs: record the decision to keep choral-permission and permissions-template
Inutilisés (aucune référence, 0 ligne) mais conservés sciemment le
27/07/2026 comme fondation d'un modèle de permissions plus riche.
Tableau des content-types mis à jour après la suppression de
conversation et direct-message.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 17:59:49 +02:00

8.6 KiB

Backend ChoralSync — Strapi

Racine du repo backend. Vue d'ensemble front + back : ../CLAUDE.md.

Stack

  • Strapi 5.8.1 (⚠️ API v5 : documentId, réponses aplaties — pas de attributes imbriqués comme en v4)
  • Node 18 à 22 (engines du package.json ; v22 utilisée en dev) — gestionnaire : yarn
  • TypeScript
  • Base de données : sélectionnée par DATABASE_CLIENTSQLite par défaut en dev (better-sqlite3), PostgreSQL ou MySQL supportés (voir config/database.ts)
  • Plugins actifs :
    • Users & Permissions (rôles Public, Authenticated)
    • Documentation (@strapi/plugin-documentation)
    • Email : nodemailer via ZeptoMail (SMTP)
    • Upload : aws-s3 vers Cloudflare R2 (bucket choralsync, servi par container.choralsync.com)
    • strapi-v5-plugin-populate-deep (defaultDepth 3)
  • Autres : Stripe (paiements, content-type order), Puppeteer (génération), cron jobs dans config/cron-tasks.ts (ex. récupération d'actualités GNews), templates d'emails dans src/email-templates/

Structure

src/
├── api/                    # 34 content-types (un dossier chacun)
│   └── <name>/
│       ├── content-types/<name>/schema.json
│       ├── controllers/
│       ├── routes/
│       └── services/
├── components/             # composants Strapi partagés
├── email-templates/        # templates des emails transactionnels
├── extensions/             # overrides : documentation, upload, users-permissions
└── admin/                  # customisation admin
config/                     # server, database, plugins, middlewares, cron-tasks, api

Content-types

Vue par domaine (32 au total, liste exhaustive dans src/api/) :

Domaine Content-types
Chorale choral, choral-membership, choral-permission ⚠️, permissions-template ⚠️
Social (offre gratuite) post, post-ownership, comment, activity, report
Groupes group, group-membership
Événements event, event-relationship
Boards (kanban) board, board-list, board-card
Messagerie — deux systèmes distincts, inventaire détaillé dans ../CLAUDE.md générale : chat-conversation, chat-conversation-member, chat-message · chorale : channel, message
Notifications notification, announcement, invite
Paiement order (Stripe — ⚠️ route custom auth: false dans src/api/order/routes/order.ts, webhook)
Contenu / divers page, legal-page, ad, contact, contact-meta, form-template, mails

⚠️ choral-permission et permissions-template sont inutilisés : aucune référence dans le back ni le front, 0 ligne en base. La gestion des permissions passe en réalité par le composant permissions de choral-membership, permission_exceptions, et choral.available_roles — c'est là que updatePermissionsTemplatesAction écrit. Décision du 27/07/2026 : on les conserve, comme fondation d'un modèle de permissions plus riche. Ne pas les proposer à la suppression sans une nouvelle décision. Leurs permissions permissions-template.create/delete restent accordées pour rien.

Sécurité — règles NON NÉGOCIABLES

  • Aucune route custom en auth: false sans justification écrite en commentaire ET mention dans le CLAUDE.md parent. État actuel : 1 occurrence (src/api/order/routes/order.ts — webhook Stripe).
  • Tout controller custom qui lit/écrit des données utilisateur DOIT filtrer par ctx.state.user.id. Jamais de entityService.findMany sans filtre dans un contexte authentifié multi-utilisateurs.
  • Toujours utiliser sanitizeOutput / les sanitizers Strapi avant de retourner une entité depuis un controller custom (ne jamais renvoyer l'objet brut).
  • populate=* interdit côté serveur comme côté client : populate explicite. ⚠️ Le plugin populate-deep (defaultDepth 3) est installé — ne pas en abuser, il peut exposer des relations non prévues.
  • Les permissions du plugin Users & Permissions sont versionnées dans src/permissions-sync.ts (source de vérité) et synchronisées au démarrage par le bootstrap (src/index.ts) — synchro ADDITIVE et idempotente : les manquantes sont créées, les permissions en trop sont seulement loguées ([permissions-sync]), jamais supprimées automatiquement. Toute nouvelle route/action consommée par le front DOIT être ajoutée à ce fichier (et jamais cochée uniquement dans l'admin, sinon elle sera signalée comme non déclarée).
  • ⚠️ Les controllers create custom qui gèrent des fichiers n'utilisent PAS la convention files.<attribut> de Strapi. ad, post, group et chat-message lisent directement ctx.request.files.<attribut> (donc un champ multipart nommé medias, media… et non files.medias), uploadent eux-mêmes puis rattachent les ids. Envoyer files.<attribut> à l'un d'eux ne produit aucune erreur : l'entité est créée, les fichiers sont ignorés en silence. Avant de brancher un formulaire avec upload, lire le controller du content-type visé. Symptôme : « le contenu s'enregistre mais pas l'image ».
  • ⚠️ Une relation peuplée via l'API REST exige find sur le content-type cible. Le sanitizer de l'API REST retire silencieusement les relations peuplées vers un content-type que le rôle n'a pas le droit de lire — pas d'erreur, juste un champ vide. C'est ce qui rendait les commentaires invisibles sur la page de détail d'une publication (corrigé en 0.13.16), alors qu'ils s'affichaient dans le fil : les controllers custom qui renvoient via ctx.send() ne passent pas par ce sanitizer, et masquent donc le problème. Symptôme à reconnaître : « ça marche dans le fil, pas dans le détail ».
  • Secrets uniquement en variables d'environnement. .env jamais commité ; .env.example maintenu à jour. Depuis le 26/07/2026, config/plugins.ts ne contient plus aucun secret (R2 et SMTP passent par env()). ⚠️ Les clés historiques ont vécu en clair dans l'historique git : rotation R2 + ZeptoMail à faire, l'historique n'étant pas réécrit.
  • ⚠️ Pas de config/env/<env>/plugins.ts. Strapi fusionne les surcharges d'environnement en profondeur : une surcharge partielle de providerOptions avait produit une config d'upload hybride (endpoint R2 de la base + identifiants MinIO de la surcharge, prioritaires via s3Options.credentials) et cassé tous les uploads de mai à juillet 2026. Les différences entre environnements passent par les variables d'environnement, pas par un second fichier. Même vigilance pour config/env/production/middlewares.ts, qui doit répéter la config strapi::body (includeUnparsed) sous peine de casser le webhook Stripe.

Points d'audit récurrents

Checklist à dérouler lors d'une revue sécurité :

  1. grep -rn "auth: false" src/ — chaque occurrence doit être justifiée.
  2. Rôle Public dans l'export des permissions : uniquement les find/findOne réellement nécessaires au site public.
  3. Controllers custom : filtrage par user, sanitization, gestion d'erreurs (pas de stack trace renvoyée au client).
  4. Lifecycles (lifecycles.ts) : pas de logique qui bypasse les permissions.
  5. Champs privés : vérifier "private": true dans les schema.json pour les champs sensibles (ils sont sinon exposés dans les réponses API).
  6. Rate limiting / CORS dans config/middlewares.ts : origines explicites en prod.
  7. API tokens : scope minimal, pas de token full-access utilisé par le front.
  8. Webhook Stripe (order) : vérification de la signature (stripe.webhooks.constructEvent).

Commandes

yarn develop                                      # dev + admin (strapi develop --debug)
yarn build
yarn strapi config:dump -f config/sync/permissions.json     # export permissions
yarn strapi config:restore -f config/sync/permissions.json  # import permissions

Règles pour Claude

  • Toute modification de schema.json = migration implicite : signaler l'impact (données existantes, types front à mettre à jour dans harmony-web/types/ et harmony-web/interfaces/).
  • Après modification d'une route/permission : mettre à jour le tableau des content-types ici ET dans le CLAUDE.md parent.
  • Ne jamais modifier directement la base de données.
  • Strapi 5 : utiliser les documentId et le format de réponse v5 (pas de attributes imbriqués). Toujours vérifier package.json en cas de doute.