Portfolio personnel de Maxime Jolivet, développeur web full-stack. Site multilingue (FR/EN/BR), déployé en SSR sur Vercel.
.claude/skills/ :
.agents/skills/ :
Look at the Nuxt 4 documentation to learn more.
- Framework : Nuxt 4 (SSR en dev comme en prod, hébergé sur Vercel)
- UI : Vue 3, composants organisés par domaine (
components/sections,components/cards,components/layout,components/ui,components/navigation) - State : Pinia
- i18n :
@nuxtjs/i18n, trois locales (frpar défaut,en-US,br-FR), préfixe d'URL (/fr/...,/en/...,/br/...) - Data : Supabase (articles de blog, études de cas projets)
- Sécurité :
nuxt-security(CSP stricte avec nonce) - SEO :
@nuxtjs/sitemap,@nuxt/image - Icônes : collections
@iconify-json/*(devicon, devicon-plain, logos, lucide, material-icon-theme, selfhst, skill-icons), résolues viautils/resolveIcon.tsà partir d'un sous-ensemble généré (voir Icônes)
flowchart TD
visitor((Visitor))
subgraph presentation["Portfolio presentation"]
app["Nuxt application<br/>app.vue"]
home["Home page<br/>index.vue"]
sections["Portfolio sections"]
locale["Locale rendering<br/>i18n.config.ts"]
end
subgraph engagement["Visitor engagement"]
chat["AI chat widget"]
contact["Contact section<br/>ContactSection.vue"]
cal["Cal.eu booking"]
end
subgraph content["Content and projects"]
projects["Projects listing<br/>index.vue"]
study["Project case study<br/>[slug].vue"]
blog["Blog listing<br/>index.vue"]
article["Blog article<br/>[slug].vue"]
clients["Client sectors<br/>ClientsSection.vue"]
cards["Project cards<br/>ProjectCard.vue"]
projectQ["Project queries<br/>useProjects.ts"]
articleQ["Article queries<br/>useArticle.ts"]
listQ["Article list queries<br/>useArticles.ts"]
end
subgraph ssr["SSR and APIs"]
api["Machine-readable APIs"]
llm["LLM content endpoint"]
db[("Supabase content")]
end
visitor -->|requests route| app
app -->|renders route| home
app -->|loads locale| locale
app -.->|loads widget| chat
home -->|renders sections| sections
home -->|translates content| locale
contact -.->|books call| cal
app -->|renders route| projects
app -->|renders route| study
app -->|renders route| blog
app -->|renders route| article
projects -->|renders sectors| clients
projects -->|renders results| cards
projects -->|loads projects| projectQ
projectQ -->|returns projects| projects
study -->|loads case study| projectQ
blog -->|loads articles| listQ
listQ -->|returns articles| blog
article -->|loads article| articleQ
articleQ -->|returns article| article
content -->|translates filters, studies, articles| locale
projectQ -->|reads projects| db
articleQ -->|reads article| db
listQ -->|reads articles| db
api -->|serves content| db
llm -->|reads projects| db
classDef presentationNode fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
classDef engagementNode fill:#ffe4e6,stroke:#be123c,color:#881337
classDef contentNode fill:#fef3c7,stroke:#d97706,color:#78350f
classDef ssrNode fill:#dcfce7,stroke:#16a34a,color:#14532d
class app,home,sections,locale presentationNode
class chat,contact,cal engagementNode
class projects,study,blog,article,clients,cards,projectQ,articleQ,listQ contentNode
class api,llm,db ssrNode
| Route (FR) | Route (EN) | Route (BR) | Contenu |
|---|---|---|---|
/ |
/ |
/ |
Accueil (hero, à propos, expérience, stack) |
/cv |
/cv |
/cv |
Curriculum vitæ |
/projets |
/projects |
/raktresou |
Liste des projets (noindex - travail client) |
/projets/:slug |
/projects/:slug |
/raktresou/:slug |
Étude de cas projet (noindex si pro) |
/blog |
/blog |
/blog |
Liste des articles |
/blog/:slug |
/blog/:slug |
/blog/:slug |
Article de blog |
/mentions-legales |
/legal-notice |
/menegou-lezennel |
Mentions légales |
/accessibilite |
/accessibility |
/haezadusted |
Déclaration d'accessibilité |
/nouveautes |
/changelog |
/kemmou-nevez |
Journal des mises à jour (généré depuis Git) |
/status |
/status |
/status |
État du build/déploiement |
Make sure to install the dependencies:
# npm
npm install
# pnpm
pnpm install
# yarn
yarn install
# bun
bun installCopier .env.example en .env et renseigner les variables Supabase (supabaseUrl, supabaseKey).
To update the dependencies in your Nuxt 4 project, you can use the npm-check-updates tool. This tool helps you to easily check for and update outdated dependencies in your package.json file.
# Install the tool globally
npm install -g npm-check-updates
# Check which packages can be updated
ncu
# Update the versions in package.json
ncu -u
# Reinstall dependencies with the updated versions
npm installStart the development server on http://localhost:8000 (non-standard port, see nuxt.config.ts):
# npm
npm run dev
# pnpm
pnpm run dev
# yarn
yarn dev
# bun
bun run devBuild the application for production:
# npm
npm run build
# pnpm
pnpm run build
# yarn
yarn build
# bun
bun run buildGenerate a static export (manual/local use only — production on Vercel builds SSR, not this):
npm run generateLocally preview production build:
# npm
npm run preview
# pnpm
pnpm run preview
# yarn
yarn preview
# bun
bun run previewCheck out the deployment documentation for more information.
utils/resolveIcon.ts ne lit pas directement les paquets @iconify-json/* (chaque icons.json complet pèse plusieurs Mo, jusqu'à ~31 Mo cumulés) : ça faisait planter nuxt build/nuxt generate par manque de mémoire. À la place, scripts/generate-icon-subset.mjs scanne le code (icon="prefix:nom") et génère utils/generated/icon-subset.json, qui ne contient que les icônes réellement utilisées.
npm run icons:generate # ou : make iconsCe script tourne automatiquement avant dev, build, generate, deploy et après install (hooks pre*/postinstall dans package.json) — pas besoin de le lancer à la main sauf pour vérifier une icône. utils/generated/ est gitignoré et régénéré à chaque fois. Si une icône n'apparaît pas, vérifier le préfixe/nom dans le warning affiché par le script.
Le site est hébergé sur Vercel, connecté via son intégration Git (build SSR standard, pas d'export statique). Déploiement automatique au push sur master. La branche de travail est develop : pour déployer, ouvrir une PR develop → master.
npm run lint # ESLint only
npm run lintfix # ESLint --fix (+ auto-format via Prettier)
npm run prettier # Check format (fail on mismatch)
npm run prettier:fix # Format files in-place
npx prettier --check . # Same as npm run prettierOu via Makefile :
make infos # Infos projet (version, Node, branche...) et liste des commandes
make install # npm install
make dev # Serveur de dev
make build # Build SSR
make generate # Build statique (manuel/local, pas le chemin de prod)
make preview # Prévisualiser un build généré
make deploy # Build + generate
make lint # ESLint only
make lintfix # ESLint --fix
make prettier # Check format
make prettier-fix # Format in-place
make test # Vitest
make icons # Régénère utils/generated/icon-subset.json
make clean # Supprime .nuxt, .output, node_modulesPas de point-virgule, guillemets simples, indentation 2 espaces, largeur de ligne 100 (voir CLAUDE.md pour le détail des conventions).
.github/workflows/ci.yml tourne sur push/PR vers master (pas sur simple push develop) :
- lint-test :
npm run lint,npm run test, et unnpm cipassé par Socket Firewall (sfw npm ci) qui bloque les paquets malveillants/typosquattés à l'installation - SonarQube Cloud : scan + quality gate bloquant
La Socket Security GitHub App (installée hors dépôt) complète en commentant/vérifiant chaque PR sur le risque des dépendances ajoutées.
Chaque commit bump automatiquement la version patch du package.json et ajoute un tag ci-dessous (hook pre-commit, scripts/update-release-log.mjs). Historique généré automatiquement, ne pas éditer à la main.