5.5 KiB
CLAUDE.md — Portfolio johanleroy.fr
Site vitrine personnel en Astro 6 hybrid (SSG public + SSR admin), identité Cyberpunk Dark / Free Party tekno.
Contexte rapide
- Utilisateur : Johan Leroy — dev fullstack + DJ tekno
- Objectif : remplacer l'ancien portfolio Angular 19 (
~/WebstormProjects/Portfolio_angular/) par une version moderne, animée, maintenable sans recompilation - Déploiement : Plesk Node.js sur
johanleroy.fr(upload FTP manuel, pas de CI) - Commande
/context johanleroycharge tout le contexte projet
Stack
- Astro 6 hybrid (
output: 'static'+@astrojs/nodestandalone) - React 19 (îlots interactifs uniquement)
- Tailwind CSS 4 + design system custom
- Framer Motion + Lenis (animations)
- Zod (schémas de contenu)
- jose + bcryptjs (auth admin)
- @iconify-icon/react (icônes simple-icons + lucide)
Points critiques à connaître
Content
Tout le contenu du site est dans data/content/*.json (7 fichiers, gitignored). Chaque fichier est validé par un schéma Zod dans src/content/schemas/. Édition possible via /admin ou directement en éditant le JSON. Au premier run, les JSON sont copiés depuis public/content/*.json (seeds versionnés en repo) si data/content/ est vide — voir src/lib/content.ts.
Persistance prod (Plesk)
Le déploiement (FTP manuel) réécrit dist/ et public/ à chaque upload. C'est pour ça que tout le contenu dynamique est dans data/ (gitignored, jamais touché par l'upload, conservé entre déploiements) :
data/content/*.json— JSON édités via/admindata/uploads/img/{folder}/*— images uploadéesdata/uploads/assets/{folder}/*— PDF (CV)
Les fichiers de data/uploads/ sont servis via la route /api/files/[...path] (Astro SSR) — donc les chemins en JSON sont du type /api/files/img/pp/foo.png ou /api/files/assets/cv.pdf.
Init prod (premier déploiement post-refonte) :
- Sur le serveur Plesk, créer
data/{content,uploads/img,uploads/assets}avec les bons droits (utilisateur Node). - Copier les seeds :
cp public/content/*.json data/content/etcp -r public/img/* data/uploads/img/etcp public/assets/cv.pdf data/uploads/assets/. - Lors des uploads FTP suivants, ne jamais sélectionner
data/— uploader uniquementdist/,public/,package.json,package-lock.json. - Tester un upload via
/admin→ vérifier que le fichier arrive bien dansdata/uploads/...et que/api/files/...le sert.
Sécurité : /api/files/[...path].ts protège contre le path traversal (résolu via resolve() + check préfixe). Les uploads passent par /api/upload qui est JWT-gated dans src/middleware.ts.
Admin
Protégé par mot de passe bcrypt + JWT cookie httpOnly 7j. Middleware dans src/middleware.ts. Routes /admin/* et /api/* ont export const prerender = false.
Env vars (.env)
ADMIN_PASSWORD_HASH=$2b$12$...
ADMIN_JWT_SECRET=...
PORT=3100
Générer : npm run hash:password -- 'monMotDePasse' (⚠️ guillemets simples toujours — les ! et $ sont interprétés par bash sinon).
Important : src/lib/auth.ts lit à la fois import.meta.env (dev Vite) ET process.env (prod Node standalone). Ne pas casser ce merge.
Design
- Palette :
--color-bg #0A0A0F,--color-cyan #00F0FF,--color-acid #C6FF00,--color-magenta #FF2A6D,--color-red #FF0040 - Typos : Inter (body), Space Grotesk (display), JetBrains Mono (code), Bebas Neue (stencil signature)
- Dark only — pas de light mode
- Ligne éditoriale : pro avant tout (nav FR, URLs grand public), free party = déco (stickers, BPM, LED, stencil)
Animations
Tous les composants animés doivent respecter prefers-reduced-motion. Les 14 blocs livrés sont listés dans la memory animations-blocks.md.
Feedback important
- ❌ Pas de 3D Hero pour l'instant (supprimé — on y reviendra)
- ❌ Pas de curseur custom (supprimé)
- ✅ Nav FR standards (
/projets,/experience,/formations) - ✅ Sons off par défaut, togglables via header
- ✅ Boot sequence au 1er load uniquement (sessionStorage)
- ✅ Responsive : fallback grid pour le Crate horizontal pinned sur mobile
Commandes utiles
npm run dev— port 3100npm run build— check + build prodnpm run check—astro checknpm run hash:password -- 'mdp'— génère bcrypt + JWT secret
Conventions de code
- Tous les îlots React dans
src/components/islands/ - Composants Astro pure (sans JS) directement dans
src/components/ - Les schémas Zod sont la source de vérité pour les types — ne pas écrire de type custom à la main pour le contenu
astro checkdoit passer à 0 erreur avant commit- Utiliser
classNameen TSX etclassen Astro (erreur Astro commune)
Workflow d'édition
- Lire
docs/README.mdpuisdocs/01-analyse-et-plan.md+docs/02-moodboard-freeparty.mdpour la direction artistique - Pour un changement de contenu → éditer
data/content/*.json(ou via/admin). Les seeds danspublic/content/*.jsonne sont utilisés qu'au premier run (bootstrap) - Pour un changement de design → modifier
src/styles/global.css+ composants - Pour un changement structurel → modifier schéma Zod d'abord, puis composant, puis JSON
Ne PAS faire sans demander
- Ne pas changer la stack (Astro + React + Tailwind 4 est verrouillé)
- Ne pas réintroduire de 3D hero sans validation
- Ne pas retirer le respect
prefers-reduced-motion - Ne pas commiter
.env(vérifier.gitignore) - Ne pas toucher à
dist/(généré par build)