102 lines
5.5 KiB
Markdown
102 lines
5.5 KiB
Markdown
# 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 johanleroy` charge tout le contexte projet
|
|
|
|
## Stack
|
|
|
|
- **Astro 6** hybrid (`output: 'static'` + `@astrojs/node` standalone)
|
|
- **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 `/admin`
|
|
- `data/uploads/img/{folder}/*` — images uploadées
|
|
- `data/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)** :
|
|
1. Sur le serveur Plesk, créer `data/{content,uploads/img,uploads/assets}` avec les bons droits (utilisateur Node).
|
|
2. Copier les seeds : `cp public/content/*.json data/content/` et `cp -r public/img/* data/uploads/img/` et `cp public/assets/cv.pdf data/uploads/assets/`.
|
|
3. Lors des uploads FTP suivants, **ne jamais sélectionner `data/`** — uploader uniquement `dist/`, `public/`, `package.json`, `package-lock.json`.
|
|
4. Tester un upload via `/admin` → vérifier que le fichier arrive bien dans `data/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 3100
|
|
- `npm run build` — check + build prod
|
|
- `npm run check` — `astro check`
|
|
- `npm 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 check` doit passer à 0 erreur avant commit
|
|
- Utiliser `className` en TSX et `class` en Astro (erreur Astro commune)
|
|
|
|
## Workflow d'édition
|
|
|
|
1. Lire `docs/README.md` puis `docs/01-analyse-et-plan.md` + `docs/02-moodboard-freeparty.md` pour la direction artistique
|
|
2. Pour un changement de contenu → éditer `data/content/*.json` (ou via `/admin`). Les seeds dans `public/content/*.json` ne sont utilisés qu'au premier run (bootstrap)
|
|
3. Pour un changement de design → modifier `src/styles/global.css` + composants
|
|
4. 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)
|