Au démarrage, la configuration météo était illisible (« Rust type Option<NaiveDateTime> (as SQL type TIMESTAMP) is not compatible with SQL type TIMESTAMPTZ ») et /api/weather/current renvoyait 500 : weather_settings.created_at est timestamptz en production alors que shared/schema.ts et init.sql le déclarent timestamp. Les types réels de la production ne figurent dans aucune migration du dépôt : plutôt que de deviner colonne par colonne, chaque colonne timestamp des structures générées est lue par crate::db::AnyTimestamp(Opt), qui accepte timestamp et timestamptz (rendu en UTC). Le champ reste NaiveDateTime et la sérialisation (crate::json::ts, « …Z ») ne change pas. scripts/gen-rust-schema.ts émet le même attribut #[sqlx(try_from)] ; schema.rs est modifié à l'identique (62 colonnes). Non compilé : pas de chaîne Rust sur ce poste. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Serveur LogiFlow (Rust)
Serveur unique de l'application : il sert l'API (src/router.rs) et l'interface construite par Vite (dist/public), applique les migrations au démarrage (src/startup.rs) et lance les tâches de fond (src/jobs.rs : sauvegarde automatique quotidienne, purge des caches, compte admin par défaut sur une base vide). Il a remplacé le serveur Node/Express, dont il reprend le comportement à l'identique (docs/PLAN-MIGRATION-RUST.md) : mêmes réponses, même cookie de session (connect.sid, table sessions), mêmes secrets chiffrés.
Lancer en local
npx vite build # interface dans dist/public
DATABASE_URL=postgres://… SESSION_SECRET=… cargo run --manifest-path server-rs/Cargo.toml
Puis ouvrir http://localhost:3000. Pour travailler sur l'interface : npm run dev:server et, à côté, npm run dev (Vite sur http://localhost:5173, qui relaie /api vers le port 3000).
| Variable | Rôle | Défaut |
|---|---|---|
PORT |
port d'écoute | 3000 |
DATABASE_URL |
base PostgreSQL | obligatoire |
STATIC_DIR |
interface construite par Vite | dist/public |
SESSION_SECRET |
signature du cookie de session | fallback-secret-key |
ENCRYPTION_KEY |
clé des secrets chiffrés en base (à défaut SESSION_SECRET) |
— |
BACKUP_DIR |
dossier des sauvegardes (pg_dump doit être installé) |
backups |
NODE_ENV |
renvoyé par /api/health |
production |
ALLOWED_ORIGINS |
origines acceptées en plus de l'hôte du serveur pour les requêtes d'écriture (https://a.fr,https://b.fr), voir src/origin.rs |
— |
RUST_LOG |
niveau des journaux (info, debug…) |
info |
Ne pas changer SESSION_SECRET ni ENCRYPTION_KEY d'une installation existante : les sessions ouvertes et les secrets déjà chiffrés (mot de passe SMTP, jeton NocoDB) deviendraient illisibles.
Vérifier
cargo fmt --check && cargo clippy --all-targets -- -D warnings && cargo test
Puis le banc de comparaison avec le serveur Node de référence (scripts/bench/README.md) : aucun écart attendu, hors écarts déclarés.
Organisation
src/router.rs: table des adresses de l'API.src/express_routes.rsretrouve l'adresse qu'Express aurait servie (casse, « / » final) ;src/static_files.rssert l'interface et la page 404 d'Express.src/modules/: un fichier par module de l'application ;src/services/: services partagés (NocoDB, vérification des factures, courriels, dates).- Socle : session et utilisateur (
auth.rs), droits (access.rs, matrice deshared/permissions.json), validation au format zod (zod.rs), accès aux tables (db.rs), formats JSON de Node (json.rs,js.rs), secrets chiffrés (crypto.rs), erreurs (error.rs). src/schema.rsest généré depuisshared/schema.ts: après un changement de schéma,DATABASE_URL=… npm run gen:rust-schema, et la migration correspondante danssrc/startup.rs.- Ajouter ou modifier une adresse :
PORTAGE.md(règles et outils du socle).
Maintenance (décision R6)
- Mainteneur et relecteur : @R0m1k3 (
.github/CODEOWNERS). Toute modification passe par une PR dont la CI est verte :cargo fmt,clippy -D warnings, tests, contrôle de type de l'interface et banc. - Dans les réglages GitHub du dépôt, protéger
main: relecture des CODEOWNERS et vérifications « Serveur Rust » obligatoires. - Dépendances :
cargo updatepuis banc complet, une fois par mois ; Rust stable, imagerust:1.97-alpinemontée en même temps. - Heure : « aujourd'hui » se calcule à Paris (
src/clock.rs, décision R5) ; ne jamais utiliserUtc::now().date_naive()pour une date du jour. - Écritures d'un autre site refusées (
src/origin.rs, décision R4) : un nouveau service qui appelle l'API depuis un navigateur sur une autre adresse se déclare dansALLOWED_ORIGINS.