← Retour aux projets

Bizleen

Live · bizleen.com

Carte de visite digitale SaaS multi-tier (Free / Pro 9€/an / Business 19€/an) sur Cloudflare edge. URL personnelle /@toi, QR code scannable, vCard 4.0, design 3D flip + parallax + holo, tier Business avec mini-site (photos, menus, horaires, réservation, analytics). Auth maison Lucia-style, D1 + R2 + Workers Standard, 26+ routes SSR, 9 migrations, Stripe billing. RGPD-compliant France.

FR EN
~11.8K Lignes
26+ Routes SSR
12 Composants
9 Migrations D1
8 Thèmes
3 Tiers (Free/Pro/Business)

Pourquoi j'ai construit ça

J'ai vu Azzapp et je me suis dit : la fonctionnalité "ta carte de visite" est top, mais l'app est lourde (multi-features CRM, scanner, teams) et le rendu manque de chair. Je voulais juste une carte premium qui me ressemble, une URL /@dan, un QR, une vCard, point. Le MVP V1 c'était un site statique perso avec ma carte hardcodée, sous le nom MindVision Card. Une fois en main, je l'ai pivoté en vrai SaaS multi-users en Phase 2-4 — auth maison, D1, R2, Resend — pour que n'importe qui puisse créer la sienne en 3 minutes. Puis Phase 5 : rebrand vers <strong>Bizleen</strong> + ajout d'un tier Business avec mini-site (photos, menus, horaires, réservation, analytics) pour les freelances, commerces de proximité et restaurateurs. Billing Stripe 3 tiers. Tout reste sur Cloudflare edge, $5/mo Workers Standard suffit. Aucun tracking, aucune pub, RGPD France complet by design.

Décisions techniques structurantes

01
Composant CardPreview canonique avec container queries

Un seul composant Astro pour 3 contextes visuels (gallery thumbnail 240px, hero phones 240px, /@handle fullscreen 440px). La clé : tailles en cqi (container query units) pas vw, donc la carte scale relativement à son propre conteneur, pas au viewport. Résultat : pixel-perfect identique à toutes les échelles, sans dupliquer le markup ou maintenir 3 variantes CSS.

02
Auth maison Lucia v3-style + Workers Standard pour argon2id

Lucia v3 est unmaintained depuis mars 2025 — l'auteur recommande de copier ~80 LOC dans le repo. Fait. Sessions = SHA-256(raw_token) en hex côté DB, raw token côté cookie HttpOnly/Secure/SameSite=Lax, sliding 30j. Password hash argon2id via @noble/hashes + AUTH_PEPPER server-side (defense in depth). Workers Standard ($5/mo) requis pour le CPU >10ms du argon2id — Workers Free coupe à 10ms, donc inutilisable pour la crypto sérieuse.

03
Tier Business + Stripe billing en boucle fermée

Pivot SaaS post-V1 : 3 tiers (Free / Pro 9€/an / Business 19€/an) avec 4 price IDs Stripe dont 2 founder pricing pour early adopters. Routes /api/subscribe + webhook signé + customer portal. Le tier Business débloque le mini-site (photos, menus, horaires, lien de réservation, page analytics user-side) — extension naturelle de la carte vers vrai outil pour pros de proximité (resto, beauté, retail). Pas un CRM gonflé : juste ce qu'un freelance/commerçant veut partager via QR sur sa devanture.

04
Anti-flicker GPU compositor (14 cartes + vidéos parallèles)

La landing affiche 6 hero phones + 8 gallery cards = 14 cartes simultanées avec backdrop-filter blur(18px) + bg video sur chacune. Compositor GPU saturé → flicker dramatique au resize, particulièrement sur les composants posés au-dessus de la vidéo. Diagnostic non-évident : c'est le backdrop-filter, pas le décodage vidéo, qui sature le GPU. Fix : remplacer par background semi-opaque (rgba 65%) sans blur. Scheduler vidéo associé : ne JAMAIS éjecter un video qui joue pour faire de la place — seul un scroll-out naturel pause. Cap à 6 décodages concurrents.

05
RGPD France-grade by design

Cookie banner LCEN (un seul cookie strictement nécessaire : session HttpOnly). Pages /privacy + /terms + /mentions-legales (SIRET 83515065700012, CNIL, droit français). Checkbox consent obligatoire signup avec liens vers Terms + Privacy en target=_blank. API /api/export-data (droit à la portabilité, dump JSON) + /api/delete-account (droit à l'oubli, cascade DB + R2). Anti-énumération sur /app/forgot (toujours le même message). Rate-limits login 5/15min, signup 3/h/IP. Aucun tracker, aucun analytics tiers.

Le challenge non-trivial

Faire tenir la cohérence visuelle entre rendu thumbnail 240px et fullscreen 440px sans dupliquer le code

La carte doit avoir le MÊME rendu visuel sur trois échelles : (1) hero landing dans un PhoneMockup 240px, (2) gallery dans un PhoneMockup 240px avec QR scan en back, (3) /@handle en fullscreen 440px max-width. Première itération avec font-size en vw donnait des cartes oversized en thumbnail (clamp atteint au max) et des cartes correctes en fullscreen. Switch à cqi (container query units, fixé depuis 2023 sur Chrome 105 / Safari 16) résout : font-size: clamp(14px, 7cqi, 22px) scale proportionnellement à la largeur du .cp lui-même, pas du viewport. À 240px → 17px, à 440px → 31px. Cohérence parfaite, zéro fork de markup. Plus complexe : la back face d'un flip 3D doit garder rotateY(180deg) — toute tentative de layer promotion avec transform: translateZ(0) sur .cp-face écrase ce rotation et rend les deux faces coplanaires (back visible à travers la front). Trouvé après 2h de debug. La solution est d'utiliser will-change seul, ou de promouvoir un parent.

Leçon retenue

Les composants UI qui doivent vivre à plusieurs échelles doivent être pensés en container queries dès le commit zéro. Le réflexe vw est intuitif mais casse la cohérence dès que le contexte change. Et pour le flicker GPU sur N>=4 surfaces avec backdrop-filter + media derrière : retirer le blur, garder l'opacité. Un effet GPU coûteux × N éléments = budget compositor explosé. Compter avant de blur. Côté produit : un MVP perso bien conçu (composant canonique, schema D1 propre, auth durcie) se pivote en SaaS multi-tier en quelques sprints, sans réécrire la base — la rebrand MindVision Card → Bizleen + ajout Business mini-site n'a touché ni la couche auth, ni le schema, ni le composant carte. La règle : ne pas spécialiser tant qu'on n'a pas vu l'usage.

Fonctionnalités

🪪
Carte canonique CardPreview

Un composant unique, 4 modes (bare/appMode/signupMode/bind), rendu identique sur thumbnail 240px et fullscreen 440px via container queries (cqi)

🔄
Flip 3D + parallax + holo

Front avec photo + contacts + CTAs, back avec QR + handle. Tilt qui suit le pointeur, holo sheen, transitions cubic-bezier 0.85s

🏪
Tier Business — mini-site resto/retail

Pages photos, menus, horaires, lien de réservation, analytics intégrés. Pour freelances, commerces de proximité, restaurateurs qui veulent un "link-in-bio" + vCard + mini-vitrine sans installer une app

💳
Stripe billing 3 tiers + Founder pricing

Free / Pro 9€/an / Business 19€/an. 4 price IDs Stripe (incl. founder pricing early adopters). Subscribe + webhook + change-plan + cancel via portal Stripe

🔐
Auth maison Lucia v3 style

argon2id + sel + poivre serveur, session sliding 30j, rate-limits login/signup, email verification + password reset via Resend

🎨
8 thèmes + 12 fonds vidéo

ruby/gold/emerald/ocean/amber/noir/beige/glass + 12 backgrounds Vecteezy Pro boomerang-encoded, picker live preview dans l'éditeur

📱
PWA installable + vCard 4.0

Manifest dynamique par user, SW network-first sur HTML cache-first sur assets. vCard avec fallback PHOTO;VALUE=uri pour iOS Contacts (qui parse pas le WebP base64)

🇫🇷
RGPD France complet

Privacy + Terms + Mentions légales (SIRET, CNIL, droit français), cookie banner LCEN, checkbox consent signup, export JSON + delete account RGPD-compliant

Stack technique

Frontend
Astro 6 SSRTypeScript strictVanilla CSSContainer queries (cqi)
Backend
Cloudflare Workers StandardAstro middleware
Données
Cloudflare D1 (SQLite)R2 (custom domain avatars)9 migrations
Auth
Lucia v3-style maison@noble/hashes argon2id@oslojs/cryptoAUTH_PEPPER
Billing
Stripe (3 tiers + founder)Webhooks signésCustomer portal
Email
Resend (SPF/DKIM/DMARC)Verification + resetTemplates HTML inline
Médias
12 vidéos Vecteezy Proffmpeg boomerangqrcode SVG SSR