- Fichiers statiques servis avant la session (plus de requêtes SQL par
asset), /assets en cache immuable 1 an, index.html en no-cache, et
compression gzip/brotli des réponses (dépendance compression, externe
dans le bundle esbuild du Dockerfile).
- req.user (déjà chargé par deserializeUser) réutilisé dans les handlers
au lieu de relire l'utilisateur et ses magasins à chaque appel ;
GET /api/user ne refait plus de requête.
- Listes : le magasin joint est réduit aux champs lus par l'interface
(plus de logo base64 ni de configuration SMTP/NocoDB dans chaque ligne),
plus aucune empreinte de mot de passe dans les créateurs/auteurs ni dans
/api/users.
- N+1 supprimés (/api/users, annonces, historique SAV, caches de
vérification des factures), requêtes indépendantes en parallèle (stats,
analytics, météo, getDelivery, getUserWithGroups), jointure
multiplicative des statistiques par magasin corrigée.
- Échéancier limité au magasin demandé ; filtre status sur
GET /api/deliveries.
- Index de performance créés en arrière-plan au démarrage
(CREATE INDEX CONCURRENTLY, reliquats invalides purgés sans verrou
exclusif).
- La connexion n'attend plus la sauvegarde quotidienne ; purge du cache
des factures active en production ; logs volumineux retirés des
chemins chauds ; NODE_ENV fixé dans l'image.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MsDJjQrAggcJwbbBtKhgyb
Encryption (server/crypto.ts):
- AES-256-GCM with a key derived from ENCRYPTION_KEY, falling back to
SESSION_SECRET so existing deployments need no new configuration
- stored format enc:v1:<iv>:<tag>:<data>; encryption is idempotent and
decryption passes legacy plaintext through unchanged, so nothing breaks
mid-migration
- tampered data or a changed key raises an explicit error instead of
returning garbage
- encrypt/decrypt is confined to the storage layer: group writes encrypt
smtpPassword (decrypted only in emailService at connection time, never sent
to the client), NocoDB config writes encrypt apiToken and reads decrypt it
so the invoice verification and the admin page behave as before
- startup migration sweep encrypts secrets already stored in plaintext,
idempotently; the active-config log line no longer prints the token
Mail history (supplier_mail_logs):
- every send attempt is recorded: delivery, store, supplier, recipient,
subject, status sent/failed with error, message id, user id and name;
a logging failure never fails the send itself
- GET /api/supplier-mail-logs restricted to the user's stores (admin may
filter by store)
- on the reconciliation page the mail icon turns green once a request has
been sent, with the date and sender in the tooltip; clicking again resends
- table created in init.sql, versioned migrations and the production
startup migration, with delivery/group indexes
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHdE9nEh8zHhQNGpCgrtYe
Replaces the mailto: link with a server-side send, so the message carries the
store's signature and logo instead of depending on each workstation's Outlook.
Store record (groups):
- address, phone and logo (data URI, 200 KB cap) feed the mail signature
- per-store SMTP settings: host, port, SSL/STARTTLS, credentials, sender
address and display name, with an enable switch
- "test connection" button verifies the server without sending anything
- the empty-form literal, previously repeated five times, becomes one constant
Sending:
- nodemailer transport built per store from its own settings
- multipart mail: plain-text alternative plus HTML whose signature embeds the
logo as an inline CID attachment, which Outlook renders without the remote
image blocking that a data: URI would hit
- delivery details are HTML-escaped
- Reply-To set to the store address; the row shows a spinner and refuses a
second click while a send is in flight
Credentials:
- the SMTP password is never returned to the client; a response-layer
sanitizer strips it from every /api payload and replaces it with a
smtpPasswordSet flag, covering the ten-plus queries that join full group
rows into deliveries, orders and user relations
- an empty password field on save keeps the stored one rather than clearing it
Verified end-to-end against a local SMTP server: transport, auth, From/Reply-To,
multipart structure and the inline logo attachment.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FHdE9nEh8zHhQNGpCgrtYe