eacffd7755
Build release Docker image / Build Docker Images (push) Successful in 21s
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>
8.6 KiB
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 deattributesimbriqués comme en v4) - Node 18 à 22 (
enginesdu package.json ; v22 utilisée en dev) — gestionnaire : yarn - TypeScript
- Base de données : sélectionnée par
DATABASE_CLIENT— SQLite par défaut en dev (better-sqlite3), PostgreSQL ou MySQL supportés (voirconfig/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 parcontainer.choralsync.com) strapi-v5-plugin-populate-deep(defaultDepth 3)
- Users & Permissions (rôles
- Autres : Stripe (paiements, content-type
order), Puppeteer (génération), cron jobs dansconfig/cron-tasks.ts(ex. récupération d'actualités GNews), templates d'emails danssrc/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: falsesans 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 deentityService.findManysans 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
createcustom qui gèrent des fichiers n'utilisent PAS la conventionfiles.<attribut>de Strapi.ad,post,groupetchat-messagelisent directementctx.request.files.<attribut>(donc un champ multipart nommémedias,media… et nonfiles.medias), uploadent eux-mêmes puis rattachent les ids. Envoyerfiles.<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
findsur 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 viactx.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.
.envjamais commité ;.env.examplemaintenu à jour. Depuis le 26/07/2026,config/plugins.tsne contient plus aucun secret (R2 et SMTP passent parenv()). ⚠️ 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 deproviderOptionsavait produit une config d'upload hybride (endpoint R2 de la base + identifiants MinIO de la surcharge, prioritaires vias3Options.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 pourconfig/env/production/middlewares.ts, qui doit répéter la configstrapi::body(includeUnparsed) sous peine de casser le webhook Stripe.
Points d'audit récurrents
Checklist à dérouler lors d'une revue sécurité :
grep -rn "auth: false" src/— chaque occurrence doit être justifiée.- Rôle Public dans l'export des permissions : uniquement les find/findOne réellement nécessaires au site public.
- Controllers custom : filtrage par user, sanitization, gestion d'erreurs (pas de stack trace renvoyée au client).
- Lifecycles (
lifecycles.ts) : pas de logique qui bypasse les permissions. - Champs privés : vérifier
"private": truedans les schema.json pour les champs sensibles (ils sont sinon exposés dans les réponses API). - Rate limiting / CORS dans
config/middlewares.ts: origines explicites en prod. - API tokens : scope minimal, pas de token full-access utilisé par le front.
- 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/etharmony-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
documentIdet le format de réponse v5 (pas deattributesimbriqués). Toujours vérifier package.json en cas de doute.