88ac8870f4c88f62e922e5c73a0ba2d36ae6eb44
Some checks failed
Tests / test (push) Has been cancelled
Tourne sur push main/dev et pull_request. Runner node:22-bullseye. Pas de deploy automatique : l'upload FTP reste manuel. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Portfolio — Johan Leroy
Site vitrine personnel en Astro 6 hybrid (SSG public + SSR admin), déployé sur Plesk Node.js.
🎧 Dev le jour, DJ la nuit — stack cyberpunk dark, contenu éditable sans recompilation.
Stack
- Astro 6 (
output: 'static'+ adapter Node standalone — hybrid viaprerender: falsesur/admin/*et/api/*) - React 19 (îlots interactifs)
- Tailwind CSS 4 + custom design system cyberpunk
- Framer Motion + GSAP + Lenis (animations)
- @react-three/fiber (hero 3D disco ball)
- Zod (validation schémas de contenu)
- jose + bcryptjs (auth admin JWT cookie)
Développement
npm install
npm run dev
Édition du contenu
Tout le contenu éditable est dans public/content/*.json :
| Fichier | Rôle |
|---|---|
profile.json |
Profil, photo, CTA hero, réseaux sociaux |
skills.json |
Compétences techniques (primary + secondary) |
experiences.json |
Parcours pro + compétences techniques & transverses |
formations.json |
Diplômes et formations |
projects.json |
Portfolio de projets |
interests.json |
Centres d'intérêt |
site.json |
Meta SEO + flags features |
Tu peux éditer :
- Via
/admin(interface web protégée par mot de passe) — recommandé en prod - Manuellement en éditant les JSON et en rechargeant la page
Aucune recompilation n'est nécessaire : les fichiers sont servis statiquement côté site public, et relus au runtime côté admin.
Admin
Configuration initiale
- Générer un hash de mot de passe :
npm run hash:password -- monMotDePasse - Copier les deux lignes générées (
ADMIN_PASSWORD_HASHetADMIN_JWT_SECRET) dans un fichier.env(local) ou dans les variables d'environnement Plesk (prod).
Accès
→ http://localhost:3100/admin (ou https://johanleroy.fr/admin en prod)
Login via mot de passe, cookie httpOnly 7 jours.
Déploiement Plesk Node.js
Variables d'environnement à définir sur Plesk
| Variable | Valeur |
|---|---|
ADMIN_PASSWORD_HASH |
hash bcrypt généré |
ADMIN_JWT_SECRET |
secret JWT aléatoire |
PORT |
3100 (ou ce que Plesk impose) |
HOST |
0.0.0.0 |
NODE_ENV |
production |
Paramètres Plesk Node.js
- Node.js version : 22+ (24.x OK)
- Application root :
/httpdocs/johanleroy - Document root Apache :
/httpdocs/johanleroy/dist/client(Apache sert les statiques buildés, le reste passe en proxy vers Node) - Application startup file :
dist/server/entry.mjs - Application URL : https://johanleroy.fr (SSL Let's Encrypt obligatoire pour les cookies admin)
Déploiement manuel
- Build local :
npm run build(vérifier quedist/server/entry.mjsest généré) - Upload FTP/SFTP vers le répertoire de l'application Plesk (ex :
/httpdocs/johanleroy/) :dist/(écrase l'existant)public/(écrase l'existant)package.jsonpackage-lock.json
- Plesk → Node.js → NPM install (à faire si
package.jsona changé) - Plesk → Node.js → Restart App pour recharger le nouveau bundle
Ne JAMAIS écraser : data/, .env, node_modules/ côté serveur.
Structure
src/
├── components/
│ ├── Header.astro, Footer.astro, SEO.astro
│ ├── ProjectCard.astro
│ └── islands/ # composants React hydratés
│ ├── Hero3D.tsx
│ ├── RolesMorph.tsx
│ ├── Reveal.tsx
│ ├── SkillCard.tsx
│ ├── SmoothScroll.tsx
│ └── CustomCursor.tsx
├── content/schemas/ # schémas Zod (typages + validation)
├── lib/
│ ├── auth.ts # JWT cookie admin
│ └── content.ts # lecture/écriture JSON
├── layouts/BaseLayout.astro
├── middleware.ts # protection routes /admin et /api
├── pages/
│ ├── index.astro
│ ├── formations.astro
│ ├── experience.astro
│ ├── projets.astro
│ ├── 404.astro
│ ├── admin/
│ │ ├── login.astro
│ │ ├── index.astro
│ │ └── edit/[section].astro
│ └── api/
│ ├── auth/login.ts, logout.ts
│ ├── content/[section].ts
│ └── upload.ts
└── styles/global.css
public/
├── content/*.json # données éditables
├── img/ # images (icônes, entreprises, projets, photos)
└── assets/cv.pdf
Direction artistique
Cyberpunk Dark — noir profond + cyan/magenta néon.
- Palette :
#0A0A0F / #00F0FF / #FF2A6D / #D1F7FF - Typographies : Space Grotesk (display), Inter (body), JetBrains Mono (mono)
- Effets : disco ball 3D, smooth scroll Lenis, curseur custom, glow néon, scanlines, glitch
Licence
© 2026 Johan Leroy.
Description
Languages
TypeScript
38.2%
Astro
32.6%
CSS
28.9%
JavaScript
0.3%