Développer en local
Faire tourner un projet Fraza sur son poste avec une base, un stockage et un courriel locaux, sans compte chez un fournisseur, et éviter les pièges courants.
Un projet Fraza tourne en local avec trois services : une base PostgreSQL, un stockage compatible S3 et un moyen de lire les courriels. Aucun ne demande de compte chez un fournisseur. Avec Docker, une commande les démarre tous. Sans Docker, cette page dit quoi mettre dans .env.local pour chacun. Elle finit par les pièges qu'on rencontre en développant.
Il y a deux façons de développer :
| Développement local (par défaut) | Avec les données de production | |
|---|---|---|
| Base, fichiers, courriels | Sur le poste, vides au départ | Ceux du vrai site |
| Ce qu'on casse | Rien : npm run services:reset remet tout à zéro | Le vrai site |
| Valeurs | .env.example, copié en .env.local par npm run dev | Celles de production, écrites dans .env.local |
| Pour qui | Tout développeur du projet | La personne qui a accès à la production |
Le développement local est le cas normal. Travailler sur la production se fait en connaissance de cause : voir Développer avec les données de production.
Avec Docker
Un projet créé par @fraza/start a un compose.yaml, et son .env.example porte déjà les valeurs qui vont avec.
npm run services # PostgreSQL, S3 local et Mailpit
npx fraza-db init # les tables
npm run dev # le siteC'est tout, pour le premier développeur comme pour un collègue qui clone le projet : npm run dev crée .env.local depuis .env.example s'il manque.
- Les ports sont ceux de la machine. Au premier lancement, chaque service reçoit un port libre (5432, sinon 5433…), gardé ensuite dans
.env.localavec les adresses qui le portent. Deux projets tournent ainsi côte à côte. Le site fait de même à partir de 3000, etNEXT_PUBLIC_URLsuit. - Les courriels arrivent dans la boîte de réception de Mailpit, dont
npm run servicesaffiche l'adresse,http://localhost:8025d'habitude. - Les fichiers vont dans le S3 local, dont le bucket est créé au démarrage.
- Repartir de zéro :
npm run services:resetsupprime la base, les fichiers et les courriels locaux, redémarre les services et recrée les tables. Pour la base seule,npx fraza-db reset --adminla recrée avec un compte admin local, etnpx fraza-db seedla remplit des données de démonstration des modules. - Arrêter :
npm run services:stop. Les données restent.
Le détail est dans fraza-dev. Les sections qui suivent servent à qui monte ses services autrement.
La base
Un PostgreSQL 14 ou plus sur le poste, sans TLS :
FRAZA_DATABASE_URL=postgres://fraza@localhost:5432/fraza?sslmode=disable?sslmode=disable est nécessaire : TLS est strict par défaut, en développement comme en production. Voir Configuration.
npx fraza-db init # crée les tables, sans risque à relancer
npx fraza-db drop # supprime toutes les tables, pour repartir de zéroUne seule base suffit pour développer. Les tests prennent leurs propres schémas jetables sur la base de FRAZA_TEST_DATABASE_URL, qui peut être la même : voir Tests.
Le courriel
Deux façons de lire les courriels du site sans rien envoyer.
Dans le terminal, avec le fournisseur log :
FRAZA_EMAIL_PROVIDER=log
FRAZA_EMAIL_FROM_ADDRESS=[email protected]Chaque courriel s'écrit dans le terminal de npm run dev : le code de vérification dans le sujet, les liens dans le texte. Voir Le fournisseur log.
Dans une boîte de réception locale, avec Mailpit, qui reçoit en SMTP et affiche les courriels sur http://localhost:8025 :
FRAZA_EMAIL_PROVIDER=smtp
FRAZA_EMAIL_SMTP_HOST=localhost
FRAZA_EMAIL_SMTP_PORT=1025
FRAZA_EMAIL_FROM_ADDRESS=[email protected]Mailpit n'offre pas de chiffrement et ne demande pas d'identifiant : laisser FRAZA_EMAIL_SMTP_USER, FRAZA_EMAIL_SMTP_PASSWORD et FRAZA_EMAIL_SMTP_REQUIRE_TLS vides. Le journal avertit que l'envoi part en clair, ce qui est attendu sur localhost. Mailpit montre le rendu HTML réel du courriel, ce que log ne fait pas.
Un fournisseur log laissé en production fait échouer l'envoi : il est refusé avec NODE_ENV=production.
Le stockage
Le core parle à n'importe quel serveur compatible S3. En local, un serveur comme Versity S3 Gateway suffit, et le core l'appelle en http:// :
FRAZA_STORAGE_PROVIDER=backblaze
FRAZA_STORAGE_ENDPOINT=http://localhost:9000
FRAZA_STORAGE_REGION=us-east-1
FRAZA_STORAGE_BUCKET=fraza-local
FRAZA_STORAGE_ACCESS_KEY=fraza-local
FRAZA_STORAGE_SECRET_KEY=fraza-local-secrethttp:// n'est accepté que pour un hôte local : localhost, 127.0.0.1 ou [::1]. Il n'y a donc ni certificat à générer ni NODE_EXTRA_CA_CERTS à poser. Un endpoint distant en http:// est refusé, pour ne jamais envoyer un fichier en clair sur le réseau. Voir Stockage.
FRAZA_STORAGE_REGION doit valoir la région que le serveur local attend, us-east-1 le plus souvent, sinon les signatures sont refusées.
Sans stockage, le site tourne, mais tout ce qui touche aux fichiers échoue : photo de profil, médiathèque, pièces jointes.
Les paiements
Stripe a un mode test et un CLI qui relaie les webhooks vers le poste :
stripe listen --forward-to localhost:3000/za/api/payments/stripe/webhookLe whsec_… affiché par la commande va dans STRIPE_WEBHOOK_SECRET, et la clé sk_test_… du tableau de bord dans STRIPE_SECRET_KEY. Ces clés de test se partagent par le coffre de l'équipe, pas par git : voir Partager les variables d'un projet.
Les outils de l'admin
Sous npm run dev, l'admin a un devkit, sans rien poser : la galerie des composants, le catalogue d'icônes, le nuancier du thème, et les tâches planifiées, avec un bouton pour en lancer une sans attendre son heure. Un envoi groupé de courriels part alors tout de suite dans Mailpit. Voir DevKit.
Sans Docker, en bref
Un PostgreSQL installé sur le poste, et le fournisseur de courriel log :
FRAZA_DATABASE_URL=postgres://moi@localhost:5432/mon_site?sslmode=disable
FRAZA_TEST_DATABASE_URL=postgres://moi@localhost:5432/mon_site?sslmode=disable
FRAZA_EMAIL_PROVIDER=logLe site tourne, les courriels s'affichent dans le terminal. Seuls les envois de fichiers échouent, tant qu'aucun S3 n'est configuré.
Développer avec les données de production
Il suffit d'écrire les valeurs de production dans .env.local : elles passent avant celles de .env.example, et npm run dev ne réécrit que les adresses locales (localhost). Une base, un bucket ou un serveur de courriel distants gardent leur valeur.
# .env.local
NEXT_PUBLIC_URL=http://localhost:3000 # jamais l'adresse du vrai site, voir plus bas
FRAZA_DATABASE_URL=postgres://site:…@db.exemple.ca:5432/site
FRAZA_ENCRYPTION_KEY=… # celle de production
FRAZA_STORAGE_ENDPOINT=s3.ca-east-006.backblazeb2.com
FRAZA_STORAGE_BUCKET=mon-site
FRAZA_STORAGE_ACCESS_KEY=…
FRAZA_STORAGE_SECRET_KEY=…
FRAZA_EMAIL_PROVIDER=resend
FRAZA_EMAIL_RESEND_APIKEY=…Trois valeurs demandent de l'attention :
NEXT_PUBLIC_URLrestehttp://localhost:3000. Le site tourne sur le poste, et la vérification CSRF compare l'origine du navigateur à cette adresse. Avechttps://exemple.ca, toute écriture est refusée : connexion, envoi de fichier, enregistrement.npm run devavertit dans ce cas.FRAZA_ENCRYPTION_KEYest celle de production. Une autre clé laisse illisible ce que le site a chiffré, comme les secrets enregistrés par les modules.- Une partie seulement peut viser la production. La base de production avec le stockage local, par exemple : les pages s'affichent, mais les images de la vraie médiathèque manquent.
Au démarrage, npm run dev nomme ce qui est hors du poste :
⚠ Données hors de ce poste : la base db.exemple.ca, le stockage s3.ca-east-006.backblazeb2.com, les courriels par Resend. Ce que fait ce serveur les touche pour de vrai.
⚠ Tâches planifiées arrêtées : la base n'est pas sur ce poste. FRAZA_CRON=true dans .env.local pour les lancer quand même.Les tâches planifiées s'arrêtent d'elles-mêmes quand la base n'est pas sur le poste. Sans cela, le portable du développeur ferait tourner les tâches du vrai site : rappels de facture, purges, synchronisations. Le serveur de production les fait déjà. FRAZA_CRON=true dans .env.local les relance, pour déboguer une tâche par exemple. La page « Tâches planifiées » du devkit dit alors pourquoi elle est vide.
Ce qui reste réel : une photo supprimée disparaît du vrai bucket, un courriel part vraiment, un compte modifié l'est pour tous. npx fraza-db reset et seed refusent une base qui n'est pas sur le poste, sauf avec --remote.
Les valeurs de production viennent du coffre de l'équipe, fiche « production », jamais d'un fichier suivi par git. Voir Partager les variables d'un projet.
Modifier un module
Le core charge les modules une seule fois, au démarrage de next dev : leurs pages, routes, menus et permissions sont enregistrés à ce moment. Une route ou un menu modifié dans un module garde son ancienne version jusqu'au prochain démarrage.
npm run dev redémarre le serveur tout seul quand un module lié est recompilé, en quelques secondes. Un module lié, c'est un module installé par file: ou npm link, dont le dossier réel est hors de node_modules. Seul son dossier dist/ est lu : le recompiler, par npm run build ou un tsup --watch dans le module, suffit.
Un module développé dans le projet, sous modules/<nom>/ et installé par file:./modules/<nom>, est compilé par npm run dev lui-même : au démarrage, puis à chaque modification. npx fraza-modules build le compile sans lancer le site. Voir fraza-dev et Cycle de vie d'un module.
Un serveur lancé par next dev directement, sans npm run dev, ne redémarre pas : l'arrêter et le relancer après une modification.
Un module lié hors du dossier du projet, un dépôt voisin installé par npm link ou file:../module-x par exemple, n'est pas trouvé par Turbopack, qui ne lit rien hors de la racine du projet : « Module not found: Can't resolve 'module-x' ». Poser la racine sur le dossier qui contient les deux, dans next.config.mjs :
import path from 'node:path';
const nextConfig = {
turbopack: {
root: path.resolve('..'),
// les règles existantes restent
},
};Un module placé dans le projet, sous modules/ ou vendor/, n'en a pas besoin.
Changer un FRAZA_MODULE_* demande aussi un redémarrage : fraza-modules sync, lancé par npm run dev, relit les variables et régénère app/.fraza/.
Pièges courants
| Symptôme | Cause | Solution |
|---|---|---|
docker compose is not available | Docker absent ou arrêté | Démarrer Docker, ou suivre « Sans Docker, en bref ». |
| Pages qui se rechargent en boucle (« Fast Refresh » ou « Compiled in … ms » sans fin), surtout après l'ajout, le retrait ou le renommage d'un module | Cache Turbopack incohérent | fraza-modules sync vide .next/dev quand la liste des modules change. Si la boucle persiste : arrêter npm run dev, supprimer .next/dev, relancer. |
Se connecter à un projet déconnecte un autre projet ouvert sur localhost | Les cookies ne dépendent pas du port : les deux projets partagent le cookie fraza_session | Lancer chaque projet par npm run dev, qui donne au cookie le nom du projet. Sinon, poser un FRAZA_AUTH_SESSION_COOKIE_NAME propre à chaque projet. |
| Les écritures sont refusées (formulaires, API) | NEXT_PUBLIC_URL ne correspond pas à l'adresse du navigateur : next dev passé sur 3001, ou l'adresse du vrai site recopiée avec les valeurs de production | Lancer le site par npm run dev, qui fait suivre le port. Sinon, mettre NEXT_PUBLIC_URL=http://localhost:3000 dans .env.local, et retirer un .env.development.local qui la fixerait. |
Aucune tâche planifiée ne tourne sous npm run dev | La base n'est pas sur le poste : npm run dev pose FRAZA_CRON=false | Voulu. FRAZA_CRON=true dans .env.local les relance. |
| Une page publique de module voit un registre vide, alors que le démarrage l'a rempli | État gardé dans une variable de module : la page et le démarrage sont compilés séparément | Ranger l'état sur globalThis. Voir Registres et singletons. |
| Un module installé n'apparaît pas | FRAZA_MODULE_<NOM>=true absent de .env.local au moment de npm install ou de npm run dev | Poser la variable, puis relancer npm run dev. |
| « Requête invalide » sur un formulaire de connexion | Anti-robot : champ caché rempli par un gestionnaire de mots de passe, ou formulaire envoyé trop vite | Recharger la page, ou utiliser une fenêtre privée. |
| Courriel ou fichier en échec sans message clair | Variable mal saisie | npx fraza-doctor confronte .env.local au catalogue des variables. |