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>
153 lines
8.6 KiB
Markdown
153 lines
8.6 KiB
Markdown
# 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_CLIENT` — **SQLite** 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` |
|
|
|
|
<!-- Tableau détaillé (champs sensibles, accès par rôle) à compléter après export des permissions. -->
|
|
|
|
⚠️ `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
|
|
|
|
```bash
|
|
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.
|