# Socialex

Site vitrine + futur espace client pour un cabinet d'expertise juridique en droit des sociétés et droit des marques.

## Positionnement (règle d'anonymat)

**Le site doit rester strictement anonyme** : pas de localisation géographique, pas de mention de la profession exacte (avocat / avocate), pas de "agence". On parle d'**expert** ou d'**expert juridique** uniquement.

À bannir partout :
- "avocat", "avocate", "cabinet d'avocats" → remplacer par "expert", "expert juridique", "cabinet d'expertise juridique"
- "Rennes", "Bretagne", toute ville/région
- "agence" en référence au cabinet (l'utilisation générique pour décrire un type d'établissement secondaire est tolérée mais préférer "bureau")
- "Barreau de X", "n° de toque", numéro téléphone, adresse postale

À utiliser :
- "expert juridique", "expert en droit des sociétés", "expert en droit des marques"
- Si besoin de désigner l'entité : "Socialex" ou "le cabinet" sans qualificatif

## Client & positionnement

- **Domaines** : droit des sociétés (création, modifications, dépôts, dissolution) + droit des marques (dépôt, surveillance)
- **Public** : dirigeants, ETI, entrepreneurs — clientèle premium
- **Email contact** : `contact@socialex.pro` (seul canal exposé publiquement)
- **Ton** : ultra-professionnel, épuré, rassurant, unique. Le juridique impose la rigueur ET la confiance.

## Périmètre du site

- **Vitrine multi-page** : Accueil, Sociétés, Marques, Contact
- **Espace client e-commerce** (à venir, phase 2) : réception de demandes, partage de documents, suivi de dossier en temps réel, paiement
- Langue principale : français
- **Pas d'em-dashes** (`—`) dans le contenu — règle stricte (cf. Règles de production)
- **Anonymat strict** : pas d'adresse, pas de téléphone, pas de localisation, pas de mention "avocat". Seul l'email est exposé.

## Stack technique

- **Next.js 16.2.4** App Router + Turbopack + TypeScript
- **Tailwind CSS v4** (config CSS-based dans `app/globals.css` via `@theme`)
- **next/font** : Noto Serif + Inter (variables `--font-noto-serif` / `--font-inter`)
- **Material Symbols Outlined** pour les icônes (CDN, weight 300)
- **Port dev : 3001** (utilisateur a un autre projet sur 3000) — `npm run dev` lance directement sur 3001
- **Better Auth 1.6** (email + mot de passe, signup public désactivé, sessions DB-backed)
- **Drizzle ORM 0.45** + **PGlite** en dev (file-based `./pgdata`) / **Postgres 16** en prod
- **Nodemailer** + SMTP perso `mail.nexus-games.com:587` (STARTTLS)
- **Recharts** (dashboard admin) + **Zod 4** (validation runtime)
- En prod : **Docker** (Next.js standalone + Postgres) derrière **Apache 2.4** reverse proxy + **Cloudflare** (Full strict)

Reste à brancher (phase Stripe) :
- **Stripe Checkout** : variables `STRIPE_SECRET_KEY` / `STRIPE_PUBLISHABLE_KEY` / `STRIPE_WEBHOOK_SECRET` à ajouter quand le client aura ses clés. UI déjà préparée à l'étape 3 du formulaire (bouton "Payer par carte" en placeholder désactivé).

## Design system (Sovereign Precision)

Issu des maquettes Stitch fournies dans `stitch_socialex_professional_legal_platform/sovereign_precision/DESIGN.md`.

### Couleurs (CSS vars dans `app/globals.css`)
- `primary` : `#000000` (noir pur — autorité)
- `secondary` : `#775a19` (or sombre — accent rare, prestige)
- `secondary-container` : `#fed488`
- `background` / `surface` : `#f7f9ff` (off-white légèrement bleuté)
- `surface-container` : `#e6effa`, `surface-container-low` : `#ecf4ff`
- `on-surface` : `#141c25`, `on-surface-variant` : `#45474b`
- `outline` : `#76777b`, `outline-variant` : `#c6c6cb`
- Pas de couleurs vives. Monochrome + or rare = signature.

### Typographie
- **Display / titres** : Noto Serif — `display-lg` (4.5rem/600), `headline-xl` (3rem/500), `headline-md` (2rem/500)
- **Corps** : Inter — `body-lg` (1.125rem/400), `body-md` (1rem/400)
- **Eyebrow** : Inter 0.75rem/600, letter-spacing 0.1em, uppercase, couleur `secondary` (or)
- Boutons et liens nav : serif uppercase `tracking-widest`

### Spacing & layout
- `gutter` : 32px, `section-gap` : 160px, `margin-page` : 80px
- Containers `max-w-1280px` ou `1920px`
- `border-radius` minimal (0.125rem default, 0.25rem lg, 0.5rem xl) — angles francs

### Composants signature
- Nav fixe `bg-white/90 backdrop-blur-md`
- CTA primary : noir → or au hover, serif uppercase tracking-widest
- CTA secondary : transparent + border outline, hover → primary plein
- Cards : fond blanc, `border-outline-variant`, hover `border-primary`
- Headlines avec deuxième ligne en italique (pattern repris partout : "Création de société : / *statuts, formalité, K-bis.*")
- Trust band noir avec KPIs en `display-lg` blanc
- Sections tarif : prix géant en or (`text-6xl→8xl`, `tracking-[-0.02em]`, `text-secondary`)
- Photos grayscale (`grayscale` / `grayscale-[0.2]`)
- Animations `reveal-hero` (stagger initial du hero) + `reveal` (sections au scroll via `RevealInit`)

## Architecture des pages

### Routes en place

```
PUBLIC (route group `(public)` — Nav + Footer)
/                              Accueil (DomainList featured, why-us, CTA)
/contact                       Form contact + FAQ + ContactPage schema (server action → email contact@socialex.pro)
/societes                      Liste services Sociétés publiés (10 services)
/societes/[bespoke]            5 pages bespoke (création, dépôt comptes, dissolution, transfert siège, dépôt marque)
/societes/[slug]               ServiceDetail générique pour les 5 services restants (changement dénomination, objet social, nomination dirigeant, CAC, bénéficiaires effectifs, acte isolé)
/societes/[slug]/formulaire    Formulaire DYNAMIQUE 3 étapes (questions → docs → récap+paiement)
/marques + /marques/[slug]/formulaire
/societes/merci                Confirmation après soumission

ADMIN (auth requise, role=admin, sidebar dédiée)
/socialexadmin                          Dashboard métriques (CA semaine/mois/année + dernières factures/dossiers)
/socialexadmin/clients                  Liste clients (lignes cliquables vers fiche)
/socialexadmin/clients/[id]             Fiche client : édite infos, reset password, supprime
/socialexadmin/factures                 Toutes les factures
/socialexadmin/dossiers/formulaires            Form builder : édite les templates par service
/socialexadmin/dossiers/formulaires/[slug]     Éditeur du template (champs + docs + fichier modèle attachable)
/socialexadmin/dossiers/en-cours               Dossiers formulaire/en_attente_paiement/en_cours
/socialexadmin/dossiers/termines               Dossiers terminés
/socialexadmin/dossiers/[id]                   Fiche dossier : réponses, docs (download), factures, statut, supprime

CLIENT (auth requise, role=client, sidebar dédiée)
/espace-client               Dashboard perso (dossiers actifs, docs à fournir, factures à payer)
/espace-client/dossiers      Liste de mes dossiers
/espace-client/factures      Mes factures

AUTH FLOW
/login                       Connexion partagée admin + client (lien "Mot de passe oublié ?")
/forgot-password             Demande de magic link reset (anti-énumération : toujours "email envoyé")
/set-password?token=&uid=    Définit / réinitialise le mot de passe via token (24h, single-use)

API
/api/auth/[...all]                        Better Auth handler
/api/samples/[slug]/[docId]               Public : télécharge le fichier modèle attaché à un doc demandé
/api/admin/documents/[id]/download        Admin : télécharge un fichier uploadé par client (Content-Disposition: attachment forcé)
/api/admin/invoices/[id]/print            Admin : facture HTML imprimable en PDF via window.print()

UTILITAIRES
/sitemap.xml, /robots.txt, /llms.txt, /not-found
```

### Routes héritées (hors nav, noindex)
- `/philosophie` — page complète mais retirée de la nav, en `noindex` (à conserver pour réactivation future)
- `/logos` — preview interne des logos candidats (`noindex`, à supprimer quand un logo final sera choisi)

### Données services (`lib/services.ts`)

Type `Service` avec :
- `slug, category, title, shortTitle, icon, excerpt, description, highlights`
- `faqs?: ServiceFAQ[]` — affichées par le template générique ou bespoke
- `steps?: ServiceStep[]` — étapes méthodologie spécifiques (override `defaultSteps` du template générique)
- `thresholds?: ServiceThresholds` — section seuils avec tableau (PACTE, dépôt confidentiel) affichée avant méthodologie
- `published?: boolean` — défaut true ; false = hors listings et hors sitemap (mais URL accessible)
- `featured?: boolean` — true = visible dans "Domaines d'intervention" de l'accueil
- `priceEur?: number` + `priceNote?: string` — affichés dans la section "Tarif transparent"

Helpers : `getService(slug)`, `getServicesByCategory(cat)`, `getFeaturedServicesByCategory(cat)`.

**11 services au total, tous publiés** :

Sociétés (10) :
- **Création de société** — 650 € (bespoke, featured)
- **Dépôt des comptes** — 295 € (bespoke, featured)
- **Dissolution de société** — 800 € / 600 € TUP (bespoke, featured, 2 cards prix)
- **Transfert de siège ou d'établissement** — 600 € intra / 800 € hors ressort (bespoke, featured, 2 cards prix)
- **Changement de dénomination sociale** — 650 € (générique avec steps personnalisés)
- **Modification de l'objet social** — 650 € (générique avec steps personnalisés)
- **Nomination/révocation de dirigeant** — 400 € (générique avec steps personnalisés)
- **Nomination/révocation commissaire aux comptes** — 400 € (générique avec steps + thresholds PACTE)
- **Modification des bénéficiaires effectifs** — 90 € (générique avec steps personnalisés)
- **Rédaction d'acte isolé** — 95 € (générique, sans formalité greffe)

Marques (1) :
- **Dépôt de marque** — 340 € INPI / 1 050 € EUIPO / sur devis international (bespoke, featured, 3 cards prix)

**Featured sur l'accueil** : création, dépôt comptes, dissolution, transfert siège + dépôt marque.

**Tous les prix sont validés par le client** sauf dépôt marque international (sur devis).

### Pages bespoke vs template générique

- **Bespoke (5 pages)** : création, dépôt comptes, dissolution, transfert siège, dépôt marque. Chacune avec hero custom, comparatif/tableau spécifique, FAQ longue (3-9 questions), schémas JSON-LD complets (BreadcrumbList + Service avec offers/priceCurrency + FAQPage). HowTo retiré (Google déprécié sept 2023).
- **Template générique** ([components/ServiceDetail.tsx](components/ServiceDetail.tsx)) — sert les 6 services restants. Lit `service.steps` si défini sinon `defaultSteps`, lit `service.thresholds` si défini pour afficher la section seuils avant méthodologie.

### Composants partagés

- `Nav`, `Footer`, `Icon`, `Section`, `ContactForm`, `JsonLd`, `RevealInit` (motion), `ServiceDetail`
- `dashboard/Shell` (layout admin + client avec sidebar)
- `public/DynamicForm` (renderer générique des formulaires de soumission, basé sur `lib/forms/types.ts`)

## Backend & infra

### Stack server
- **Better Auth** (email + mot de passe, signup public désactivé). Config dans [lib/auth.ts](lib/auth.ts).
- **Drizzle ORM** + **PGlite** en dev (file-based dans `./pgdata`) / **Postgres-js** en prod.
  Bascule auto via la présence de `DATABASE_URL`. Schema unique : [lib/db/schema.ts](lib/db/schema.ts).
- **Nodemailer** + SMTP perso (mail.nexus-games.com:587 STARTTLS). Config dans [lib/email.ts](lib/email.ts).
- **Form builder** dynamique : un template par service stocké en DB (table `form_template`), édité par
  l'admin, rendu côté public par `<DynamicForm />`. Cf. [lib/forms/types.ts](lib/forms/types.ts).

### Tables DB principales
- `user`, `session`, `account`, `verification` (Better Auth + champ `role` admin/client custom)
- `client_profile` (1:1 avec user où role=client)
- `dossier` (référence "D-YYYY-XXXX", statut, formData jsonb, lié à un client + un service)
- `document` (demandés par admin, uploadés par client, statut demande/uploade/valide/rejete)
- `invoice` ("F-YYYY-XXXX", amountCents, statut envoyee/payee, lié à un dossier)
- `notification` (in-app, par user)
- `activity_log` (audit + timeline UX par dossier)
- `form_template` (un par service, édité par admin)

### Form builder (admin) + DynamicForm (public)
- Types de champs : text, email, phone, number, date, textarea, select, radio, checkbox, **file**
- Documents demandés : chaque entrée est aussi un upload côté client (statut `uploade` à la soumission, ou `demande` si optionnel non fourni)
- Admin peut **attacher un fichier modèle** à chaque document demandé (téléchargeable côté client comme template à compléter). Stockage dans `_samples/{slug}/{docId}/`
- Validation côté client (required + format email/phone) + côté server (Zod). Si erreur server pointe sur étape 1, jump-back automatique.

### Workflow de soumission publique (3 étapes UI)
1. Visiteur remplit `/societes/[slug]/formulaire`
   - **Étape 1** "Vos informations" : questions du formulaire avec stepper visuel
   - **Étape 2** "Pièces à joindre" : uploads des documents (avec lien "Télécharger le modèle" si présent)
   - **Étape 3** "Validation et paiement" : récap dossier+facture en noir/or + boutons paiement
2. Server action [submit-form.ts](app/(public)/_actions/submit-form.ts), enrobée d'un try/catch global :
   - Valide via Zod dynamique depuis le template + valide tailles fichiers
   - Crée user (role=client) si nouveau, ou retrouve par email
   - Crée le dossier (status=`en_attente_paiement`) avec formData jsonb
   - Écrit les fichiers sur disk : `/var/www/html/socialex/uploads/{dossierId}/{fieldId}/{uuid}-{name}` ou `.../doc-{docId}/...`
   - Insert les `document` (status=`uploade` si fichier reçu, sinon `demande`)
   - Crée la facture (status=`envoyee`) avec le `priceEur`
   - Génère un **magic-link set-password** unique (24h) via [lib/auth-tokens.ts](lib/auth-tokens.ts)
   - Envoie email facture + lien activation via Nodemailer
3. Client reçoit email → clique magic-link → définit son mot de passe → `/login` → `/espace-client`
4. *(Stripe à brancher)* Paiement direct CB depuis l'étape 3 du formulaire ou depuis `/espace-client/factures`. Pour l'instant : virement (coordonnées par email) ou paiement manuel + admin marque payée.

### Auth flow détaillé
- **Login** : email + mot de passe (Better Auth `signIn.email`)
- **Reset password** : `/forgot-password` → action `requestPasswordReset(email)` → token sha256 dans table `verification` → email avec lien `/set-password?token=&uid=`. **Anti-énumération** : on retourne toujours "email envoyé".
- **Confirm password** : `/set-password` → action `confirmPasswordReset(userId, token, newPassword)` → hash via `auth.$context.password.hash()` → upsert dans table `account` → invalide les sessions actives → consomme le token.
- Tokens stockés en sha256 (jamais en clair), TTL 24h, cleanup opportuniste des expirés.

### Garde-fous auth
- [middleware.ts](middleware.ts) : check edge permissif (présence de cookie contenant "session_token", n'importe quel préfixe). La validation crypto se fait dans les layouts.
- [lib/guards.ts](lib/guards.ts) : `getSession()` hit en **loopback** `http://localhost:3000/api/auth/get-session` (var `INTERNAL_AUTH_URL` dans docker-compose). Raison : `auth.api.getSession({ headers })` ne voit pas systématiquement le cookie en Server Components Next.js 16 → redirect loops. Le loopback fetch est plus fiable.
- `requireAdmin()` / `requireClient()` redirigent vers `/login?from=...` si pas de session, ou vers `/espace-client` si rôle insuffisant.

### Action admin (côté `/socialexadmin`)
- **Clients** : édite infos (nom/email/société/SIRET/adresse/notes), reset password (invalide les sessions), supprime (bloqué si dossiers existants — FK restrict)
- **Dossiers** : voit réponses formulaire (labels résolus depuis template), télécharge fichiers uploadés, change statut (5 valeurs), supprime (cascade documents/log, factures gardées avec dossierId=null)
- **Factures** : marque payée (bascule auto le dossier en `en_cours`), génère PDF via route `print` (HTML stylé Sovereign Precision + window.print()), supprime
- **Form templates** : édite questions/docs/fichiers modèle pour chaque service

### Déploiement (cf. [DEPLOYMENT.md](DEPLOYMENT.md))
- **VPS Hetzner Debian 12** (188.40.186.181), Apache2 reverse proxy, Cloudflare devant en **Full strict** (origin certs dans `/etc/cloudflare/socialex.pro.{pem,key}`)
- **CI/CD** : push sur `main` → GitHub Actions rsync code au VPS → `docker compose build` (avec `--build-arg BUILD_SHA` pour bust cache) → `up -d --force-recreate app`
- **Stack prod** :
  - `socialex-app` (Next.js standalone) écoute sur `127.0.0.1:3001` (Apache proxie depuis 443)
  - `socialex-postgres` (Postgres 16) sur réseau Docker interne `socialex_internal`, port non exposé
  - Volume `socialex_pgdata` (persistance DB) + bind `/var/www/html/socialex/uploads` (documents + samples + factures)
- **Coexistence** avec les 3 autres sites du VPS : ports/volumes/networks préfixés `socialex_`, port app loopback uniquement (3000 pris par un autre Next, on est sur 3001).
- **Apache vhost** ([deploy/apache-vhost.conf](deploy/apache-vhost.conf)) : redirige `www.socialex.pro` → `socialex.pro` (canonique pour Better Auth origin check), forward avec `X-Forwarded-Host: socialex.pro` hardcodé (la syntaxe `%{Host}i` ne marche pas avec `RequestHeader set`).
- **Cleanup auto** à chaque deploy : `docker image prune` (Socialex + dangling) + `docker builder prune --keep-storage 1GB`. Sans ça le disque se remplit vite.

### Secrets GitHub Actions
- `VPS_HOST`, `VPS_USER`, `VPS_SSH_KEY` (clé dédiée `socialex_deploy`)
- `POSTGRES_PASSWORD`, `BETTER_AUTH_SECRET`, `SMTP_PASS`
- `SEED_ADMIN_EMAIL`, `SEED_ADMIN_PASSWORD`
- `NEXT_SERVER_ACTIONS_ENCRYPTION_KEY` : rend les IDs des Server Actions stables entre builds (sinon "Server Action not found" sur les onglets ouverts pendant un déploiement)
- *(à venir Stripe)* `STRIPE_SECRET_KEY`, `STRIPE_PUBLISHABLE_KEY`, `STRIPE_WEBHOOK_SECRET`

### Pièges connus en prod (pour pas re-tomber dedans)
- Les Server Actions de Next.js 16 comparent `X-Forwarded-Host` à `Origin`. Apache doit envoyer la bonne valeur (hardcodée dans notre vhost).
- `serverActions.allowedOrigins` doit être whitelist dans `next.config.ts` (sinon "Invalid Server Actions request").
- Cloudflare en SSL **Flexible** = boucle infinie de redirects entre CF et Apache (port 80 redirige vers HTTPS qui retourne à CF en HTTP...). **Toujours en Full strict.**
- `auth.api.getSession({ headers: await headers() })` ne lit pas le cookie en Server Components Next.js 16. On hit `/api/auth/get-session` en loopback (`INTERNAL_AUTH_URL=http://localhost:3000`).
- Docker Compose `up -d` ne recrée pas toujours le container après un rebuild d'image → `--force-recreate` obligatoire dans le workflow.
- Build Docker peut servir l'ancien code via cache même si `rsync` a copié le nouveau → on bust le cache à `COPY . .` via `ARG BUILD_SHA` dans le Dockerfile.
- Cloudflare ne cache PAS `/_next/static/*` par défaut malgré `Cache-Control: max-age=31536000, immutable` envoyé par l'origin. Il faut une **Cache Rule explicite** côté CF (URI Path contains `/_next/static/` → eligible for cache + Edge TTL 1 month).
- Cloudflare "Email Address Obfuscation" injecte `email-decode.min.js` (~280 ms dans le critical path). À désactiver dans CF si emails sont publics par design (notre cas).
- Cloudflare "AI Audit" injecte `Content-Signal: search=yes,ai-train=no` dans `/robots.txt` qui est rejeté par certains validateurs Lighthouse (directive non-standard). Désactivable dans CF.

### Cleanup Docker manuel (à lancer périodiquement, le disque sature vite)
```powershell
ssh -i "$env:USERPROFILE\.ssh\socialex_deploy" root@188.40.186.181 'docker system prune -af && docker builder prune -af && cd /var/www/html/socialex && docker compose --env-file .env.production -f docker-compose.prod.yml build --build-arg BUILD_SHA="manual-$(date +%s)" app && docker compose --env-file .env.production -f docker-compose.prod.yml up -d --force-recreate app && df -h /'
```
Préserve les volumes nommés (`socialex_pgdata`) → DB safe. Libère typiquement 5-15 GB selon le nombre de builds successifs.

### Optimisations perf appliquées
- Images PNG hero converties en WebP/AVIF avec next/image priority sur le LCP (gain -5,5 MB sur l'accueil)
- Material Symbols variable font lockée à `opsz=24, wght=300, FILL=0..1` (1,1 MB → ~150 KB)
- Polices Noto Serif / Inter via `next/font` avec preload + weights réduits
- preconnect à fonts.googleapis.com et fonts.gstatic.com
- `Cache-Control: public, max-age=31536000, immutable` sur tous les assets statiques (via Next.js `headers()`)
- `overflow-x: clip` global sur html/body (anti-débordement horizontal)
- browserslist exclut IE11 / Opera Mini pour réduire les polyfills
- `next.config.ts` : `images.formats: ["avif", "webp"]`, `images.minimumCacheTTL: 31536000`

## Skills installés (`.claude/skills/`)

- `frontend-design` — règles Anthropic pour des UI distinctives, anti-AI-slop
- `web-design-guidelines` — audit Vercel des UI (à lancer avant chaque milestone)
- `marketing-skills` — index Corey Haines (CRO, copy, SEO, growth)
- `claude-seo` — pointer vers AgriciDaniel/claude-seo
- `awesome-claude-skills` — index curé
- Référence externe : `https://github.com/nextlevelbuilder/ui-ux-pro-max-skill`

## Règles de production

- **Ne jamais sacrifier l'épure** : si un composant paraît surchargé, retirer avant d'ajouter.
- **Rigueur juridique = rigueur visuelle** : alignements parfaits, hiérarchie typo stricte, espaces blancs généreux.
- **Le secondary (or) est rare** : eyebrows, accents micro, prix géants, jamais en aplat large.
- **Tout texte en français** côté UI. Les maquettes Stitch ont des bouts en anglais (Book Consultation, Learn More) — à franciser systématiquement.
- **Pas d'em-dashes (`—`)** : remplacer par `:` (énumération), `,` (apposé), `(...)` (parenthétique), `|` (titre meta SEO).
- **Accessibilité** : contrastes AA, focus visibles (`outline-secondary` global), alt textes, `<nav aria-label>`, `<dl>` pour comparatifs.
- **SEO** : H1 unique, hiérarchie H2/H3, meta par page, JSON-LD systématique (BreadcrumbList + Service + FAQPage). Mots-clés ciblés par page (cf. champ `keywords` des metadata).
- **Motion** : `reveal-hero` une seule fois sur le hero (stagger orchestré), `reveal` sur chaque section au scroll via IntersectionObserver. `prefers-reduced-motion` respecté globalement.
- **Préférence copy** : tight, sans superlatifs vides. Le client itère beaucoup sur les textes (souvent en mode "retire X", "remplace Y par Z").

## TODO ouvert

**Bloquant pour l'ouverture publique :**
- **Pages légales** (mentions, RGPD, CGV, cookies) — masquées dans le footer (`legalLinks: []`), à compléter par contenu juridique du client puis réactiver.
- **Stripe Checkout** (CB) : le bouton est en placeholder à l'étape 3 du formulaire. Quand le client a ses clés Stripe → ajouter `STRIPE_*` aux GH Secrets + brancher l'action côté server + webhook de paiement.
- **Rate limiting** sur `/api/auth/*`, `/contact`, `/societes/*/formulaire` — soit Cloudflare WAF, soit middleware Next.
- **Logo haute def** : actuel `Logo.png` est 47×44 (favicon flou sur HDPI/iOS). Demander un export 256×256 ou 512×512 carré sans fond.

**Contenu (à valider avec le client) :**
- Nom / bio / photo / qualifications de l'expert juridique (le site reste anonyme, mais on aura besoin pour la version interne / mentions légales)
- KPIs (4j, 100% conformité…) — placeholders crédibles
- Photos marque (en remplacement des Unsplash via `lib/images.ts` — bureau.png/stylo.png/Efficacité.png déjà fournis pour l'accueil, désormais en WebP/AVIF)
- Choisir logo final + supprimer la route preview `/logos`

**Améliorations (nice-to-have) :**
- Migrer `middleware.ts` → `proxy.ts` (Next.js 16 a déprécié l'ancien nom)
- Génération PDF côté serveur (puppeteer ou pdfkit) pour les factures, au lieu du HTML print
- Antivirus (ClamAV) sur les uploads
- Cron backup `pg_dump` + tar uploads
- Monitoring (UptimeRobot ou similaire)
- Notifications in-app (table déjà là, UI à brancher)
- Cache CF rule sur `/_next/static/*` (à activer côté CF pour passer le score Lighthouse desktop de ~86 à ~95+)
- Étoffer page `/societes/transfert-de-siege-social` (~600 mots → ~1500 mots pour parité avec autres bespokes)

## Commandes

```
npm run dev      # Dev server sur http://localhost:3001
npm run build    # Build prod (~16 routes statiques)
npm run start    # Serve prod sur 3001
```
