Développement

Dans le conteneur dev (recommandé)

docker build -f Dockerfile.local --build-arg UID=$(id -u) --build-arg GID=$(id -g) -t wap-crm:dev .
docker run -d --name wap-crm-dev --network proxy -v "$PWD":/app wap-crm:dev
docker exec -it wap-crm-dev bash
bun install
bun run dev            # convex dev + vite (nécessite `bunx convex login` une fois)
bun run dev:frontend   # vite seul (les fonctions déjà déployées suffisent)

Aucun port n'est publié : le conteneur rejoint le réseau proxy et le reverse proxy de l'hôte route vers wap-crm-dev:4202 (vite écoute sur 0.0.0.0:4202). Sans reverse proxy, remplacer --network proxy par -p 4202:4202 et ouvrir http://localhost:4202. L'entrypoint du conteneur est inerte (tail -f) : relancer docker exec -d wap-crm-dev bun run dev:frontend après un redémarrage.

Directement sur la machine

bun install
bun run dev

Scripts

ScriptEffet
bun run devconvex dev + vite en parallèle
bun run dev:frontend / dev:backendl'un des deux seulement
bun run buildtsc --noEmit + vite build → dist/
bun run typechecktsconfig app + tsconfig convex + tsconfig tests
bun run codegenrégénère convex/_generated (commité)
bun run openapirégénère convex/lib/api/openapi.generated.ts depuis docs/openapi.yaml (commité)
bun run lintBiome : format et règles ; un avertissement fait échouer la commande
bun run unusedknip : exports, types, fichiers et dépendances que rien n'utilise (knip.ts) ; la CI échoue s'il en trouve. Ce qu'une surcouche importe est listé dans tests/*/extensionSurface.test.ts et compte comme utilisé
bun run testlance les suites bun:test
bun run test:watchidem, en mode watch

Tests

Tous les tests sont sous tests/ (backend/ avec convex-test, frontend/), aucun dans convex/ ni src/. tests/setup.ts, chargé avant chaque fichier (bunfig.toml), pose quatre règles :

Les tests sont typés comme le reste (tests/tsconfig.json, dans bun run typecheck). La suite ne dépend pas de l'ordre : la CI la lance dans un ordre aléatoire (bun test --randomize, la graine est affichée pour rejouer un échec avec --seed). Elle la lance une seconde fois avec un overlay de substitution (bun run test:stand-in) : src/extensions.tsx est remplacé par tests/support/overlayStandIn.ts, où chaque point d'extension est défini et répond à tout, et convex/extensions.ts par tests/support/backendStandIn.ts, qui répond là où une réponse se voit et ne refuse rien, comme l'overlay privé sans tenant configuré ; un test du cœur seul qui ne le dit pas échoue là, avant d'échouer chez un overlay.

Bootstrap & connexion locale

Un déploiement neuf n'a aucun utilisateur : créer un premier employé (seuls les utilisateurs employee accèdent au CRM) :

bunx convex run seed/devEmployee:createDevEmployee '{"email":"you@example.com","firstName":"You","lastName":"Example"}'

La connexion passe ensuite par un code envoyé par e-mail : il faut un fournisseur d'e-mail configuré (Brevo ou SMTP, Paramètres → E-mail), et l'adresse dans DEV_WHITELIST_EMAILS si la liste est définie. Il n'existe pas de porte dérobée de session.