ce7cd19fef
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
3.6 KiB
3.6 KiB
Architecture
Analysis Date: 2026-04-10
SSR Strategy
Nuxt 4 with ssr: true and compatibilityVersion: 4. Every page renders server-side HTML with SEO metadata before hydrating client-side. Cookie-only persistence for locale and theme (no localStorage, SSR-safe).
Layer Breakdown
Pages (app/pages/)
└─> Layout (app/layouts/default.vue)
├─> AppHeader (nav, locale toggle, theme toggle)
├─> Page content (slot)
└─> AppFooter (social links, copyright)
└─> Components (app/components/)
└─> Composables (app/composables/)
└─> Static Data (app/data/)
└─> Shared Types (shared/types/)
Server (server/api/)
└─> Contact POST handler (nodemailer SMTP)
Data Flow
Static Data + i18n
app/data/projects.tsexports projects WITHOUT translatable fields (title, description, longDescription omitted)app/composables/useProjects.tsmerges static data with i18n translations at runtime viacomputed()- Components consume
useProjects()which returns reactive translated data - Language changes trigger recomputation automatically
SSR Render Flow
- Request hits Nitro server
- Nuxt resolves locale from cookie (
i18n_redirected) or URL prefix (/en/) useLocaleHead()inapp.vuesets<html lang="...">and alternate links- Page's
useSeoMeta()resolves i18n keys server-side useHead()injects JSON-LD structured data- Full HTML sent to client with correct locale, theme class, SEO metadata
Theme Resolution
@nuxtjs/color-modereadsnuxt-color-modecookie- Default:
darkfor new visitors - Cookie persistence — no flash on cold load (class applied server-side)
Contact Form Flow
- Client: Zod validation in
ContactForm.vue - POST to
/api/contact(Nitro route) - Server: manual validation, nodemailer SMTP via
useRuntimeConfig()env vars - Response: success/error JSON
Module System
| Module | Purpose |
|---|---|
@nuxt/ui |
Component library (Nuxt UI v3) |
@nuxtjs/i18n |
Internationalization (prefix_except_default, FR default) |
@nuxtjs/sitemap |
Auto-generated sitemap with i18n alternates |
nuxt-gtag |
Google Analytics (runtime config) |
@nuxt/image |
Image optimization |
@nuxt/eslint |
ESLint integration |
Entry Points
| File | Role |
|---|---|
app/app.vue |
Root — wraps in <UApp>, applies useLocaleHead() |
app/layouts/default.vue |
Default layout — AppHeader + slot + AppFooter |
app/error.vue |
Global error handler (404 page) |
nuxt.config.ts |
App configuration |
app.config.ts |
Nuxt UI theme tokens (primary color) |
State Management
No Pinia store. All state is:
- Composable-scoped:
useProjects()returns reactive computed data - Module-managed: locale via
@nuxtjs/i18n, theme via@nuxtjs/color-mode - Component-local:
ref()/reactive()in<script setup>
Error Handling
- Pages:
throw createError({ status: 404 })for invalid routes/IDs app/error.vuecatches all errors with i18n messages and navigation back- Contact form:
try/catch/finallywithuseToast()user feedback - Server routes:
createError({ statusCode: 400 })for validation failures
Cross-Cutting Concerns
- SEO:
useSeoMeta()per page +useHead()for JSON-LD +useLocaleHead()global - Accessibility: Semantic HTML, aria attributes, keyboard navigation
- i18n: All user-facing text via
t()keys,te()guards for optional keys - Images: WebP in
public/images/, served via@nuxt/image
Architecture analysis: 2026-04-10