Aurora HomeAurora HomeDocs
DocsConventions Marketing

Conventions — Site Marketing

Standards de code et d'organisation adoptés dans le projet aurora-home-marketing.

Stack technique

Nuxt 4Framework fullstack Vue — routing fichier, SSR, backend Nitro
Vue 3Composition API — réactivité, composables, slots
TypeScript 5Mode strict — noImplicitAny, strictNullChecks, noUncheckedIndexedAccess
Tailwind CSS v4CSS utilitaire v4 — layers personnalisés (glass-panel, glass-button, glass-input)
Three.jsViewer 3D produit — OBJ loader, OrbitControls, export GLTF + AR
PiniaGestion d'état — store panier persisté en localStorage
StripePaiement en ligne — PaymentIntent serveur + Elements client
Chart.js + vue-chartjsGraphiques admin — ventes par jour (Bar chart via vue-chartjs)
better-sqlite3Base de données embarquée — transactions atomiques via better-sqlite3
Phosphor IconsBibliothèque d'icônes (CDN)
ESLint + HuskyLinting + Husky pre-commit hook

Structure des dossiers

aurora-home-marketing/
aurora-home-marketing/
assets/
css/# Tailwind v4 + layers glass-panel, glass-button
main.css# @layer base / components / utilities
components/
TheHeader.vue# Navigation sticky + badge panier
TheFooter.vue# Copyright + liens
LiquidGlass.vue# Wrapper glass-morphism
Product3DViewer.client.vue# Viewer Three.js (client-only)
pages/# Routing fichier automatique Nuxt
index.vue# Accueil — hero + parallax souris
product.vue# Fiche produit + 3D viewer + AR
cart.vue# Tunnel d'achat multi-étapes
about.vue# À propos + mentions légales
confirmation.vue# Succès de commande
admin.vue# Dashboard admin — lazy-loaded
docs.vue# Redirection vers la documentation
server/
api/
products/
index.get.ts# Lister les produits
[id].put.ts# Mettre à jour le stock
orders/
index.get.ts# Lister les commandes
confirm.post.ts# Créer une commande — atomique
payments/
create-intent.post.ts# Créer un PaymentIntent Stripe
db/
index.ts# Singleton SQLite + schéma + seed
shared/
types/
index.ts# Product, CartItem, Order, CheckoutForm...
stores/
cart.ts# Pinia — panier persisté localStorage
app.vue# Racine Nuxt + TheHeader / TheFooter
nuxt.config.ts# Config Nuxt 4 + Pinia + Tailwind + Stripe

Conventions de nommage

Fichiers & Routes APIkebab-case + method suffix
cart.tsmain.cssindex.get.tsconfirm.post.ts[id].put.ts
Composants VuePascalCase
TheHeader.vueTheFooter.vueLiquidGlass.vueProduct3DViewer.client.vue
Stores & Composablesuse* camelCase
useCartStoreuseRouter()useRuntimeConfig()addItem()isProcessing

Composants client-only

Les composants qui accèdent aux APIs navigateur (WebGL, canvas, window) sont suffixés .client.vue. Nuxt les exclut automatiquement du rendu SSR.

components/Product3DViewer.client.vue
// Suffixe .client.vue → Nuxt exclut ce composant du SSR
// Nécessaire car Three.js accède à window, document et WebGL

const renderer = new THREE.WebGLRenderer({ canvas, antialias: true })

const loader = new OBJLoader()
loader.load('/models/model.obj', (obj) => scene.add(obj))

// Export GLTF pour la réalité augmentée (model-viewer)
const exporter = new GLTFExporter()
exporter.parse(scene, (gltf) => {
  const blob = new Blob([gltf as ArrayBuffer], { type: 'model/gltf-binary' })
  arUrl.value = URL.createObjectURL(blob)
}, { binary: true })

Pattern Pinia Store

Le store panier utilise le Setup Store de Pinia avec persistance automatique via localStorage.

stores/cart.ts
export const useCartStore = defineStore('cart', () => {
  const items = ref<CartItem[]>([])

  const total = computed(() =>
    items.value.reduce((sum, i) => sum + i.price * i.quantity, 0).toFixed(2)
  )
  const count = computed(() =>
    items.value.reduce((sum, i) => sum + i.quantity, 0)
  )

  function hydrate() {
    if (!import.meta.client) return   // Guard SSR
    const saved = localStorage.getItem('aurora-cart')
    if (saved) items.value = JSON.parse(saved)
  }

  function persist() {
    localStorage.setItem('aurora-cart', JSON.stringify(items.value))
  }

  function addItem(product: Product) {
    const existing = items.value.find(i => i.id === product.id)
    existing ? existing.quantity++ : items.value.push({ ...product, quantity: 1 })
    persist()
  }

  return { items, total, count, hydrate, addItem, decreaseItem, removeItem, clear }
})

La guard import.meta.client garantit que localStorage n'est jamais accédé côté serveur.

Pattern API Routes (Nitro)

Les routes serveur suivent la convention méthode-suffixe de Nitro. Les transactions SQLite garantissent l'atomicité des opérations critiques (création commande + décrément stock).

server/api/orders/confirm.post.ts
export default defineEventHandler(async (event) => {
  const body = await readBody<ConfirmOrderBody>(event)

  // Transaction atomique : création commande + décrément stock
  return db.transaction(() => {
    const { lastInsertRowid } = db.prepare(
      'INSERT INTO orders (total, delivery_type) VALUES (?, ?)'
    ).run(body.total, body.deliveryType)

    for (const item of body.items) {
      db.prepare('UPDATE products SET stock = stock - ? WHERE id = ?')
        .run(item.quantity, item.id)
      db.prepare(
        'INSERT INTO order_items (order_id, product_id, quantity, price) VALUES (?, ?, ?, ?)'
      ).run(lastInsertRowid, item.id, item.quantity, item.price)
    }

    return { success: true } satisfies SuccessResponse
  })()
})

Le suffixe de la méthode HTTP (.get.ts, .post.ts, .put.ts) est résolu automatiquement par Nitro — aucun routeur manuel requis.

State Machine — Tunnel d'achat

La navigation du panier est modélisée comme une machine à états avec le type discriminé CheckoutStep.

pages/cart.vue
type CheckoutStep = 'cart' | 'delivery' | 'checkout' | 'payment'

const step = ref<CheckoutStep>('cart')

// Navigation linéaire :
// cart → delivery → checkout → payment
//   ↑           ↑           ↑         ↑
// Panier   Livraison    Adresse    Stripe

Lancer le projet

aurora-home-marketing
npm install
npm run dev     # http://localhost:3000
npm run build

Site en production : aurora-home-marketing.vercel.app