Cause racine : les Signed URLs Supabase étaient générées au moment du
rendu ISR et embarquées dans le HTML mis en cache. Si Vercel servait
le HTML avant régénération ou si la signed URL expirait, l'image
était cassée et necessitait plusieurs rechargements.
Solution — proxy /api/img/[key] :
- app/api/img/[key]/route.ts : nouvelle route publique force-dynamic
qui génère une Signed URL fraîche à chaque requête image (TTL 1h),
avec Cache-Control 55 min côté navigateur/CDN ; fallback sur l'image
Unsplash par défaut si createSignedUrl échoue ; 302 direct pour les
URLs externes
- lib/site-images.ts : getSiteImages() ne génère plus jamais de Signed
URL — les chemins storage: retournent /api/img/<key> (URL permanente),
les URLs externes sont retournées telles quelles
Résultat : le HTML statique/ISR ne contient plus jamais de signed URL
éphémère → zéro image cassée, zéro rechargement nécessaire.
https://claude.ai/code/session_01PzA98VhLMmsHpzs7gnLHGs
- lib/site-images.ts : nouvelle clé macon_photo_cyprien (url vide par
défaut, l'admin upload la vraie photo)
- app/macon/page.tsx : remplace le placeholder SVG par un <img> conditionnel
— affiche l'image quand la clé est renseignée, conserve le placeholder
texte "Photo de Cyprien (sur le chantier)" tant qu'aucune photo n'est
uploadée
https://claude.ai/code/session_01PzA98VhLMmsHpzs7gnLHGs
- Nouvelle route POST /api/admin/upload : upload multipart vers le bucket
private-gallery, validation MIME + taille (max 5 Mo), retourne storage:path
- lib/site-images.ts : détecte le préfixe "storage:" et génère une Signed
URL temporaire (60 min) côté serveur avant chaque rendu de page
- GET /api/admin/site-images : résout aussi les signed URLs pour les previews
admin (champ previewUrl distinct de url brute)
- PUT /api/admin/site-images : accepte désormais les chemins "storage:..."
en plus des URLs externes
- Page admin images : drag & drop + input file avec upload automatique +
sauvegarde en BDD, badge "bucket privé", instructions SQL pour créer
la table et la policy du bucket private-gallery
https://claude.ai/code/session_01PzA98VhLMmsHpzs7gnLHGs
- Redesign Hero section with new copy focused on the triptych offering
- Add Process component (replaces System) with zigzag layout for 3 pillars:
Google Maps reviews, managed Facebook, converting website
- Redesign AboutMe with orange background and stats row
- Add admin panel for managing site image URLs (replaces Sanity dependency)
- Create site_images API routes and Supabase-backed storage with defaults
- Update FAQ to reference built-in admin panel
- Add site_images table type to database types
- Pass images prop through homepage components
https://claude.ai/code/session_01V8YAjpqRQ3bfBYsABYsEgo
- Disable Sanity CDN cache so published changes appear immediately
- Add revalidate=60 to page so Next.js refreshes data every 60s
- Wire AboutMe component to use siteSettings from Sanity (name, bio,
photo, address, map coordinates)
https://claude.ai/code/session_01H2aRGDaKgarPvhay2HxN6Y
Transformation complète du site HookLab de formation TikTok Shop
vers une landing page haute conversion pour agence web locale ciblant
les artisans du bâtiment dans le Nord (Douai, Orchies, Valenciennes).
- Nouveau design system : bleu nuit/orange sur fond clair (mobile-first)
- Hero avec promesse artisan + CTA orange "Réserver mon Audit"
- Section "Le Système" (3 étapes : Trouvé, Choisi, Contacté)
- Portfolio connecté à Sanity.io (fallback data intégré)
- Section "Qui suis-je" avec carte OpenStreetMap interactive
- FAQ orientée artisans avec JSON-LD pour Google
- Formulaire contact audit gratuit
- SEO local : 12 keywords artisans, JSON-LD LocalBusiness
- Sanity.io schemas (portfolio, siteSettings) + client conditionnel
- Accessibilité : skip-to-content, focus-visible, aria-labels
https://claude.ai/code/session_01H2aRGDaKgarPvhay2HxN6Y
Store auth session in cookies instead of localStorage so server-side
code (admin layout, API routes, protected layout) can read the session.
Implements chunked cookie support for large session tokens.
https://claude.ai/code/session_01H2aRGDaKgarPvhay2HxN6Y
- Add auth options (autoRefreshToken: false, persistSession: false) to
createAdminClient so service role key works correctly with supabase-js
- Return actual Supabase error message in candidature API for debugging
https://claude.ai/code/session_01H2aRGDaKgarPvhay2HxN6Y
@supabase/ssr uses __dirname internally which crashes in Vercel's Edge
runtime, causing MIDDLEWARE_INVOCATION_FAILED even without a middleware
file. Replaced with @supabase/supabase-js directly:
- Server client: manual cookie-based session restoration
- Browser client: direct createClient from supabase-js
- Admin client: already using supabase-js
https://claude.ai/code/session_01H2aRGDaKgarPvhay2HxN6Y
- Add serverExternalPackages for @supabase/ssr in next.config.ts
- Add export const runtime = 'nodejs' to all pages/routes using Supabase
- Replace createAdminClient to use @supabase/supabase-js directly (no SSR)
- Prevents @supabase/ssr from running in Edge runtime on Vercel
https://claude.ai/code/session_01H2aRGDaKgarPvhay2HxN6Y
Next.js 16.1.6 is not yet fully supported by Vercel's build system,
causing 404 on all routes. Downgraded to Next.js 15.5.12 + React 18,
fixed ESLint config, TypeScript config, and lint errors.
https://claude.ai/code/session_01H2aRGDaKgarPvhay2HxN6Y
- Remove middleware.ts entirely (caused __dirname ReferenceError in Edge)
- Auth protection handled by dashboard layout.tsx (server-side redirect)
- Move pages out of (marketing) and (auth) route groups to fix 404 on /
- Keep (protected) route group for dashboard/formations/profil shared layout
https://claude.ai/code/session_01H2aRGDaKgarPvhay2HxN6Y