Files
PleinR/package.json
T
Claude 8d4443a1a1 Boîte mail de l'association : trois transports, une file d'attente
Le site savait composer de beaux messages et ne savait pas les envoyer :
`email-client.ts` ne proposait que la copie ou le téléchargement d'un
brouillon Outlook, complété à la main. `/backend/boite-mail` branche
désormais la boîte de l'association, sur le modèle exact de l'écran
Réseaux sociaux — secrets chiffrés, jamais renvoyés au navigateur, champ
laissé vide qui conserve la valeur enregistrée, contrôle de santé qui ne
lève jamais.

Trois transports, un seul actif à la fois, désigné par l'administrateur —
pas de cascade automatique : si Google se bloque, la bascule se voit.

- **Google** passe par l'API Gmail plutôt que par SMTP avec XOAUTH2 :
  celui-ci exigerait `https://mail.google.com/`, portée *restreinte* et
  donc audit de sécurité, là où `gmail.send` est simplement *sensible*.
- **Microsoft** passe par Graph : l'authentification basique SMTP est
  désactivée depuis 2024, y compris sur outlook.com et hotmail.com.
- **SMTP** couvre le reste via `nodemailer`, seule dépendance ajoutée.

`from_address` est **lu chez le fournisseur** et non saisi : Gmail expédie
comme l'utilisateur authentifié, Graph comme la boîte. Une adresse d'un
autre domaine ferait tomber SPF et DKIM.

La file `mail_messages` porte un destinataire unique par ligne — la
confidentialité d'une diffusion est structurelle, aucune copie partagée
n'est possible. Elle est vidée par la boucle de fond, avec réclamation en
`FOR UPDATE SKIP LOCKED`, réessais espacés et reprise des verrous laissés
par un conteneur arrêté en plein envoi.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014QsLjRAnuLwivqxCbM4WeP
2026-09-14 16:00:11 +00:00

47 lines
1.5 KiB
JSON

{
"name": "plein-r",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"db:generate": "drizzle-kit generate",
"db:migrate": "tsx src/db/migrate.ts",
"db:seed": "tsx src/db/seed.ts",
"db:purge-demo": "tsx src/db/purge-demo.ts",
"build:scripts": "esbuild src/db/migrate.ts --bundle --platform=node --target=node20 --format=cjs --outfile=dist/migrate.cjs --external:pg-native && esbuild src/db/seed.ts --bundle --platform=node --target=node20 --format=cjs --outfile=dist/seed.cjs --external:pg-native && esbuild src/db/purge-demo.ts --bundle --platform=node --target=node20 --format=cjs --outfile=dist/purge-demo.cjs --external:pg-native",
"test": "tsx --test tests/**/*.test.ts"
},
"dependencies": {
"bcryptjs": "^2.4.3",
"dotenv": "^16.4.7",
"drizzle-orm": "^0.45.2",
"next": "^15.5.25",
"next-auth": "^5.0.0-beta.32",
"nodemailer": "^8.0.11",
"pg": "^8.23.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"zod": "^3.24.1"
},
"devDependencies": {
"@types/bcryptjs": "^2.4.6",
"@types/node": "^22.10.5",
"@types/nodemailer": "^8.0.1",
"@types/pg": "^8.11.10",
"@types/react": "^19.0.7",
"@types/react-dom": "^19.0.3",
"drizzle-kit": "^0.31.10",
"esbuild": "^0.28.1",
"tsx": "^4.19.2",
"typescript": "^5.7.3"
},
"overrides": {
"postcss": "^8.5.23",
"sharp": "^0.35.3",
"esbuild": "^0.28.1"
}
}