Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

622 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DevisRapide

Plateforme web belge de mise en relation particuliers ↔ artisans. Modèle pay-per-lead avec wallet rechargeable côté pro.

Next.js TypeScript React Tailwind Prisma Neon Stripe


Vue d'ensemble

DevisRapide met en relation des particuliers cherchant un artisan en Belgique avec des professionnels validés par la plateforme. Le particulier soumet sa demande via un wizard en 3 étapes (projet → infos → coordonnées), et le système propose le lead à tous les artisans validés de la zone via un algorithme de matching géographique (Haversine SQL custom), le rayon s'élargissant progressivement par paliers. Un nombre limité et configurable d'entre eux peut l'acheter depuis son wallet rechargeable (Stripe Checkout) : plusieurs pour un lead partagé, un seul pour un lead exclusif.

Acteurs :

  • Client (particulier) — pas de compte authentifié en V1, anonyme
  • Pro (artisan) — compte auth, wallet, dashboard, leads acceptés / refusés
  • Admin — panel /admin pour validation pros, lifecycle, wallet override, stats

Tech stack

Couche Technos
Framework Next.js 16 (App Router, Turbopack, Server Components) + React 19
Langage TypeScript strict, Zod pour la validation runtime
Styling Tailwind v4 (@theme inline), shadcn/ui primitives, Phosphor icons, Bricolage Grotesque
Base de données PostgreSQL (Neon) + Prisma 6
Auth Auth.js v5 + Prisma adapter (Credentials provider, JWT strategy)
Paiement Stripe Checkout one-time + webhook idempotent (StripeWebhookEvent.stripeEventId @unique)
Animation CSS-only Reveal (IntersectionObserver) sur landing + framer-motion AnimatePresence sur wizards
Rate limit Upstash Ratelimit (sliding window)
Hébergement Vercel Pro + Vercel Cron
Monitoring Sentry (server + client + edge), captureException sur les call-sites critiques (admin actions, cron, Stripe webhook)
Anti-bot Cloudflare Turnstile (CAPTCHA invisible) sur /demande, /inscription-pro, /connexion
PWA manifest.ts natif Next + service worker manuel + offline fallback + install prompt (Android natif + iOS instructions)
Push web-push + VAPID, branchement 8 events (nouveau lead, wallet faible au franchissement, 4 lifecycle, lead offert, lead bientôt expiré, auto-accept declenche, lead pris par un autre) + master-switch notifyByPush
Email Resend + React Email templates, master-switch notifyByEmail via helper deliver() requiresOptIn, emails essentials (recharge, lifecycle, lead-offert, no-match client) toujours envoyes
Tests Vitest (logique métier pure : pricing, geo, stats) — 29 tests verts

Setup local

Prérequis

  • Node 20+
  • pnpm 10+
  • PostgreSQL : compte Neon recommandé (free tier OK), ou Postgres local

Installation

# 1. Clone + install
git clone https://github.com/Namirop/devisrapide.git
cd devisrapide
pnpm install

# 2. Copier l'exemple d'env et compléter
cp .env.local.example .env.local
# Au minimum : DATABASE_URL, NEXTAUTH_SECRET, NEXTAUTH_URL,
# ADMIN_EMAIL, ADMIN_INITIAL_PASSWORD.
# Variables Stripe/Resend/Upstash/Sentry/Turnstile optionnelles en dev
# (les modules tombent gracefully en no-op si vars absentes — cf. section
# variables d'environnement).

# 3. Appliquer migrations + seed
pnpm db:deploy
pnpm db:seed

# 4. Lancer le dev server
pnpm dev
# → http://localhost:3000

Stripe Checkout en local

Le webhook /api/stripe/webhook doit recevoir les events Stripe pour créditer le wallet. En local, utilise le CLI Stripe :

# Dans un terminal séparé (laisse tourner)
stripe listen --forward-to localhost:3000/api/stripe/webhook
# → affiche un webhook signing secret "whsec_..."

Recopie ce whsec_... dans ton .env.local comme STRIPE_WEBHOOK_SECRET, relance pnpm dev.

Carte de test : 4242 4242 4242 4242 / expiration future / CVC quelconque.

PWA et Push notifications en dev

VAPID keys : Générez votre paire via :

pnpm dlx web-push generate-vapid-keys

Et placez publicKey / privateKey dans .env.local (NEXT_PUBLIC_VAPID_PUBLIC_KEY + VAPID_PRIVATE_KEY). Sans ces variables, sendPushToProfile est gracefully no-op (les events déclenchent toujours le code mais aucun push n'est émis), et le composant client PushSubscriptionManager affiche une erreur si on tente d'activer.

Service worker en dev : par défaut désactivé pour ne pas interférer avec le HMR Turbopack. Pour tester l'enregistrement + flow push en local, set NEXT_PUBLIC_SW_DEV=1 dans .env.local. En vrai test de prod : pnpm build && pnpm start.

Icônes PWA : régénérables depuis le logo source via node scripts/generate-pwa-icons.mjs (sharp). Output : public/icons/icon-{192,256,384,512}.png + icon-maskable-512.png (safe-zone 80% pour Android).

Sentry et Turnstile en dev

Sentry : Sans NEXT_PUBLIC_SENTRY_DSN / SENTRY_DSN configurés, Sentry.init est gracefully no-op (pas de network, pas d'erreur). Les capture calls inline (Sentry.captureException dans withAuditLog, cron, webhook) ne font rien. Pour activer en dev, créer un projet Sentry et coller le DSN dans .env.local.

Cloudflare Turnstile : Sans NEXT_PUBLIC_TURNSTILE_SITE_KEY / TURNSTILE_SECRET_KEY, le widget client utilise la sitekey de test Cloudflare 1x00000000000000000000AA (toujours-pass) et verifyTurnstileToken server-side accepte tout token en dev (NODE_ENV !== "production"). En prod, les keys deviennent obligatoires (cf. src/lib/turnstile/verify.ts). Pour activer en dev : créer un site sur Cloudflare > Turnstile, copier les keys dans .env.local.

Seed dev fakes

pnpm db:seed crée le catalogue + un admin. Pour ajouter des données de test (pros, leads, wallet) utiles au test des espaces pro/admin : pnpm db:seed:fakes (idempotent, cf. prisma/seed-fakes.ts).


Variables d'environnement

Variable Requis Description
DATABASE_URL URL Postgres complète (Neon recommandé)
NEXTAUTH_SECRET Secret signing JWT (openssl rand -base64 32)
NEXTAUTH_URL URL publique (ex: http://localhost:3000 en dev)
ADMIN_EMAIL Email admin seedé au premier db:seed
ADMIN_INITIAL_PASSWORD Mot de passe admin initial (changeable depuis /admin/parametres)
STRIPE_SECRET_KEY ⚠️ Paiement Clef secrète Stripe (sk_test_...)
STRIPE_WEBHOOK_SECRET ⚠️ Paiement Secret webhook (whsec_..., généré par stripe listen)
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY ⚠️ Paiement Clef publique Stripe (pk_test_...)
RESEND_API_KEY ⚠️ Email Si absent : emails tombent en console.log
RESEND_FROM_EMAIL ⚠️ Email Default onboarding@resend.dev
UPSTASH_REDIS_REST_URL ⚠️ Si absent : rate limit no-op (utile dev)
UPSTASH_REDIS_REST_TOKEN ⚠️ idem
CRON_SECRET ⚠️ Cron Bearer token cron Vercel (openssl rand -hex 32)
SENTRY_DSN ⚪ Monitoring DSN Sentry (côté server)
NEXT_PUBLIC_SENTRY_DSN ⚪ Monitoring DSN Sentry (côté client)
NEXT_PUBLIC_VAPID_PUBLIC_KEY ⚪ Push VAPID public (push subscribe côté navigateur)
VAPID_PRIVATE_KEY ⚪ Push VAPID privé (signature serveur, jamais exposé client)
VAPID_SUBJECT ⚪ Push mailto:contact@… requis par la spec Web Push
NEXT_PUBLIC_SW_DEV dev only 1 pour activer le service worker en dev (default = prod-only pour ne pas casser le HMR)

Voir .env.local.example pour la liste complète et commentée.


Scripts

Script Action
pnpm dev Dev server (Turbopack, hot reload)
pnpm build Build prod (prisma migrate deploy + next build)
pnpm start Sert le build prod
pnpm lint ESLint
pnpm db:migrate prisma migrate dev (nouvelle migration en dev)
pnpm db:deploy prisma migrate deploy (applique migrations en prod / CI)
pnpm db:seed Seed catalogue + admin
pnpm db:seed:fakes Ajoute des données de test (pros, leads, wallet)
pnpm db:studio Prisma Studio UI
pnpm db:generate Régénère le client Prisma
pnpm test Vitest run (tests unitaires logique métier)
pnpm test:watch Vitest mode watch
pnpm test:ui Vitest UI (debug visuel)

Architecture

App Router avec route groups : (public) / (legal) / (pro-public) / (dashboard) / (admin). Server Components par défaut, 'use client' placé le plus bas possible dans l'arbre. Server Actions pour les mutations user-driven, Route Handlers pour les webhooks/cron.

Modèle métier : 3 niveaux de catalogue (Universe → Category → SubCategory), Lead avec workflow PENDING_MATCH → ASSIGNED → ACCEPTED → COMPLETED, LeadAssignment pivot avec snapshot prix et expiresAt, Wallet en Int (centimes) + WalletTransaction log immuable, AuditLog systématique sur toutes les actions admin.

Voir docs/architecture.md pour la doc complète (modèle de données, flow matching, sécurité, RGPD, etc.).


Conventions code

  • TypeScript strict, zéro any / as any douteux
  • Result type pattern sur toutes les Server Actions : { success: true; data } | { success: false; code; message }
  • requireProSession() / requireAdminSession() au début de chaque action sensible
  • Tous les montants en Int représentant des centimes (jamais Float)
  • Wallet : transaction Prisma Serializable + SELECT ... FOR UPDATE sur tout débit
  • Webhook Stripe : signature vérifiée + body raw + idempotence par stripeEventId @unique
  • Conventional commits (feat:, fix:, refactor:, etc.)

Détail complet : docs/conventions.md.


Documentation


Limitations V1 connues

  • Clients particuliers anonymes — pas de login client en V1. Auth.js Email magic link prévue en V2 pour permettre au client de revenir voir ses devis.
  • B2B / Copropriétés — section LP en mode "Bientôt", fonctionnalité V2.
  • RGPD utilisateur — droits d'accès / effacement traités manuellement en V1, endpoints /dashboard/profil/donnees prévus V2.
  • Cookie banner CMP — V1 ne dépose que des cookies essentiels (auth, CSRF, Stripe Checkout), pas de CMP requis. À revoir si analytics V2.
  • Cron Vercelvercel.json configure 2 crons (process-leads toutes les 15min, check-no-match-leads daily 9h), actifs en prod sur plan Vercel Pro. En dev local : trigger manuel via curl -H "Authorization: Bearer $CRON_SECRET".
  • Tests automatisés — Vitest sur la logique métier pure (pricing, geo, stats — 29 tests). Pas de Playwright en V1, couverture e2e envisagée post-launch.

Licence

Repo public à des fins de portfolio dev — utilisation, reproduction ou réutilisation du code soumise à autorisation préalable.


Contact

  • Support produit : contact@devisrapide.be
  • Dev (questions techniques code) : voir profil GitHub @Namirop

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages