Setup complet de l'infrastructure projet : - Frontend Nuxt 4 (SSR, TypeScript, i18n, Pinia, TailwindCSS) - Backend Laravel 12 API-only avec middleware X-API-Key et CORS - Design tokens (sky-dark, sky-accent, sky-text) et polices (Merriweather, Inter) - Documentation planning et implementation artifacts Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
14 KiB
14 KiB
Story 1.1: Initialisation du monorepo et infrastructure
Status: review
Story
As a développeur, I want un projet monorepo Nuxt 4 + Laravel 12 initialisé avec les configurations de base, so that le développement peut commencer sur des fondations solides.
Acceptance Criteria
- Given un nouveau repository Git When le projet est initialisé Then la structure monorepo
frontend/(Nuxt 4) +api/(Laravel 12) est en place - And Nuxt 4 est configuré avec SSR activé, TypeScript, et les modules
@nuxtjs/i18n,@nuxtjs/tailwindcss,@pinia/nuxt,nuxt/image,@nuxtjs/sitemap - And Laravel 12 est configuré en mode API-only avec CORS autorisant le domaine frontend
- And le middleware API Key (
X-API-Key) est en place sur les routes API - And les fichiers
.env.exampleexistent pour frontend et backend - And TailwindCSS est configuré avec les design tokens (
sky-dark,sky-accent#fa784f,sky-text) - And les polices sont définies (serif narrateur + sans-serif UI)
- And le
.gitignoreest approprié pour les deux applications
Tasks / Subtasks
-
Task 1: Initialisation structure monorepo (AC: #1)
- Créer le dossier racine
skycel/avec README.md - Configurer
.gitignoreglobal (node_modules, vendor, .env, etc.) - Initialiser Git repository
- Créer le dossier racine
-
Task 2: Setup Frontend Nuxt 4 (AC: #1, #2)
- Exécuter
npx nuxi@latest init frontend - Confirmer structure Nuxt 4 avec dossier
app/ - Activer TypeScript (déjà par défaut dans Nuxt 4)
- Installer modules:
@nuxtjs/i18n,@nuxtjs/tailwindcss,@pinia/nuxt,@nuxt/image,@nuxtjs/sitemap - Configurer
nuxt.config.tsavec SSR activé - Créer
frontend/.env.example
- Exécuter
-
Task 3: Setup Backend Laravel 12 (AC: #1, #3, #4)
- Exécuter
composer create-project laravel/laravel api - Configurer en mode API-only (supprimer views Blade inutiles)
- Configurer CORS dans
config/cors.phppour autoriser le domaine frontend - Créer middleware
VerifyApiKeypour vérifier headerX-API-Key - Enregistrer le middleware sur les routes API
- Créer
api/.env.example
- Exécuter
-
Task 4: Configuration TailwindCSS avec design tokens (AC: #6)
- Configurer
tailwind.config.jsavec thème custom - Définir tokens couleurs:
sky-dark(noir→bleu),sky-accent(#fa784f),sky-text(blanc cassé) - Définir variantes hover/focus pour l'accent
- Configurer purge pour production
- Configurer
-
Task 5: Configuration des polices (AC: #7)
- Choisir police serif élégante pour narrateur/PNJ (ex: Merriweather, Lora, Playfair Display)
- Choisir police sans-serif moderne pour UI (ex: Inter, Open Sans, Nunito)
- Configurer les polices dans
tailwind.config.js(fontFamily) - Importer les polices via Google Fonts ou fichiers locaux
-
Task 6: Fichiers .env.example (AC: #5)
frontend/.env.exampleavec:NUXT_PUBLIC_API_URL,NUXT_PUBLIC_API_KEYapi/.env.exampleavec:APP_KEY,DB_*,API_KEY,CORS_ALLOWED_ORIGINS
-
Task 7: Validation finale (AC: tous)
cd frontend && npm run devfonctionnecd api && php artisan servefonctionne- Requête API avec header
X-API-Keyvalide retourne 200 - Requête API sans header retourne 401
- Structure des dossiers conforme
Dev Notes
Architecture Monorepo
skycel/
├── frontend/ # Application Nuxt 4
│ ├── app/ # Code applicatif (structure Nuxt 4)
│ │ ├── pages/
│ │ ├── components/
│ │ ├── composables/
│ │ ├── stores/
│ │ ├── layouts/
│ │ ├── plugins/
│ │ ├── assets/
│ │ └── app.vue
│ ├── server/ # Server routes/API Nuxt (si besoin)
│ ├── public/
│ ├── i18n/
│ ├── nuxt.config.ts
│ ├── tailwind.config.js
│ ├── .env.example
│ └── package.json
├── api/ # Backend Laravel 12
│ ├── app/
│ │ ├── Http/
│ │ │ ├── Controllers/
│ │ │ ├── Middleware/
│ │ │ │ └── VerifyApiKey.php # CRÉER
│ │ │ ├── Requests/
│ │ │ └── Resources/
│ │ └── Models/
│ ├── database/
│ ├── routes/
│ │ └── api.php
│ ├── config/
│ │ └── cors.php # CONFIGURER
│ ├── bootstrap/
│ │ └── app.php # Enregistrer middleware
│ ├── .env.example
│ └── composer.json
├── docs/ # Documentation projet (existe déjà)
├── .gitignore
└── README.md
Commandes d'initialisation
# Frontend Nuxt 4
npx nuxi@latest init frontend
cd frontend
npm install @nuxtjs/i18n @nuxtjs/tailwindcss @pinia/nuxt @nuxt/image @nuxtjs/sitemap pinia-plugin-persistedstate
# Backend Laravel 12
composer create-project laravel/laravel api
cd api
# Pas de packages supplémentaires pour cette story
Configuration nuxt.config.ts
// frontend/nuxt.config.ts
export default defineNuxtConfig({
devtools: { enabled: true },
// SSR activé (défaut)
ssr: true,
// Structure Nuxt 4
future: {
compatibilityVersion: 4,
},
modules: [
'@nuxtjs/i18n',
'@nuxtjs/tailwindcss',
'@pinia/nuxt',
'@nuxt/image',
'@nuxtjs/sitemap',
],
// i18n sera configuré en Story 1.3
i18n: {
locales: ['fr', 'en'],
defaultLocale: 'fr',
strategy: 'prefix_except_default',
},
// Transitions de page (configuré en Story 1.4)
app: {
pageTransition: { name: 'page', mode: 'out-in' },
},
runtimeConfig: {
public: {
apiUrl: process.env.NUXT_PUBLIC_API_URL || 'http://localhost:8000/api',
apiKey: process.env.NUXT_PUBLIC_API_KEY || '',
},
},
})
Design Tokens TailwindCSS
// frontend/tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./app/**/*.{vue,js,ts}',
'./components/**/*.{vue,js,ts}',
'./layouts/**/*.{vue,js,ts}',
'./pages/**/*.{vue,js,ts}',
],
theme: {
extend: {
colors: {
'sky-dark': {
DEFAULT: '#0a0e1a', // Noir tirant vers le bleu
50: '#1a1f2e',
100: '#151a28',
200: '#10141f',
300: '#0c1019',
400: '#080c14',
500: '#0a0e1a', // Base
600: '#060810',
700: '#04060c',
800: '#020408',
900: '#010204',
},
'sky-accent': {
DEFAULT: '#fa784f', // Orange chaud
hover: '#fb8c68',
active: '#f96436',
50: '#fff4f0',
100: '#ffe8e0',
200: '#ffd1c1',
300: '#ffb9a2',
400: '#fca283',
500: '#fa784f', // Base
600: '#e86940',
700: '#d65a31',
800: '#c44b22',
900: '#b23c13',
},
'sky-text': {
DEFAULT: '#f5f0e6', // Blanc cassé tirant vers jaune
muted: '#b8b3a8',
50: '#fdfcfa',
100: '#fbf9f5',
200: '#f7f3eb',
300: '#f5f0e6', // Base
400: '#e8e3d9',
500: '#dbd6cc',
600: '#cec9bf',
700: '#c1bcb2',
800: '#b4afa5',
900: '#a7a298',
},
},
fontFamily: {
// Police narrative (serif) - pour narrateur, PNJ, dialogues
'narrative': ['Merriweather', 'Georgia', 'serif'],
// Police UI (sans-serif) - pour interface, boutons, labels
'ui': ['Inter', 'system-ui', 'sans-serif'],
},
},
},
plugins: [],
}
Middleware Laravel VerifyApiKey
<?php
// api/app/Http/Middleware/VerifyApiKey.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class VerifyApiKey
{
public function handle(Request $request, Closure $next): Response
{
$apiKey = $request->header('X-API-Key');
if (!$apiKey || $apiKey !== config('app.api_key')) {
return response()->json([
'error' => [
'code' => 'INVALID_API_KEY',
'message' => 'Invalid or missing API key',
]
], 401);
}
return $next($request);
}
}
Configuration CORS Laravel
<?php
// api/config/cors.php
return [
'paths' => ['api/*'],
'allowed_methods' => ['*'],
'allowed_origins' => explode(',', env('CORS_ALLOWED_ORIGINS', 'http://localhost:3000')),
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => false,
];
Variables d'environnement
frontend/.env.example:
# API Configuration
NUXT_PUBLIC_API_URL=http://localhost:8000/api
NUXT_PUBLIC_API_KEY=your-api-key-here
# Site URL (for sitemap, SEO)
NUXT_PUBLIC_SITE_URL=http://localhost:3000
api/.env.example:
APP_NAME=Skycel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost:8000
# Database
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=skycel
DB_USERNAME=root
DB_PASSWORD=
# API Security
API_KEY=your-api-key-here
# CORS
CORS_ALLOWED_ORIGINS=http://localhost:3000
Project Structure Notes
- Nuxt 4 utilise la nouvelle structure
app/(passrc/) - Les composants dans
app/components/sont auto-importés - Les composables dans
app/composables/sont auto-importés - Les stores Pinia dans
app/stores/sont accessibles via auto-import - Composants client-only: utiliser le suffixe
.client.vue(pas de SSR)
References
- [Source: docs/planning-artifacts/architecture.md#Starter-Template-Evaluation]
- [Source: docs/planning-artifacts/architecture.md#Structure-Monorepo]
- [Source: docs/planning-artifacts/architecture.md#Authentication-&-Security]
- [Source: docs/planning-artifacts/ux-design-specification.md#Color-System]
- [Source: docs/planning-artifacts/ux-design-specification.md#Typography-System]
- [Source: docs/planning-artifacts/epics.md#Story-1.1]
Technical Requirements
| Requirement | Value | Source |
|---|---|---|
| Nuxt version | 4.x (latest) | Architecture |
| Laravel version | 12.x | Architecture |
| Node.js | 18+ | Nuxt 4 requirement |
| PHP | 8.2+ | Laravel 12 requirement |
| TypeScript | Enabled | Architecture |
| SSR | Enabled | Architecture, NFR5 |
Libraries to Install
Frontend (npm):
| Package | Version | Purpose |
|---|---|---|
| @nuxtjs/i18n | 8.x | Internationalisation |
| @nuxtjs/tailwindcss | 6.x | Styling |
| @pinia/nuxt | 0.5.x | State management |
| @nuxt/image | 1.x | Image optimization |
| @nuxtjs/sitemap | 5.x | SEO sitemap |
| pinia-plugin-persistedstate | 3.x | LocalStorage persistence |
Backend (composer):
- Aucun package supplémentaire pour cette story (Laravel de base suffit)
Dev Agent Record
Agent Model Used
Claude Opus 4.5 (claude-opus-4-5-20251101)
Debug Log References
- TailwindCSS: Le module
@nuxtjs/tailwindcssv6.14 provoquait une erreur PostCSSCannot use 'import.meta' outside a modulesur Node.js 18. Résolu en remplaçant le module par une configuration PostCSS directe dansnuxt.config.ts. - PHP: Le PHP en PATH (8.0.3) est incompatible avec Laravel 12. Utilisation de PHP 8.2.29 disponible dans Laragon pour la création du projet et l'exécution.
- pinia-plugin-persistedstate: La v4 requiert pinia 3+, incompatible avec @pinia/nuxt 0.9.0 (pinia 2). Downgrade vers v3.2.
Completion Notes List
- Structure monorepo
frontend/+api/créée et fonctionnelle - Nuxt 4 (3.17.5) configuré avec SSR, TypeScript, i18n, Pinia, @nuxt/image, sitemap
- TailwindCSS v3 configuré via PostCSS avec design tokens (sky-dark, sky-accent, sky-text)
- Polices Merriweather (narrative) et Inter (UI) importées via Google Fonts
- Laravel 12.50 installé en mode API-only avec CORS et middleware VerifyApiKey
- Middleware API Key vérifié : 401 sans clé, 200 avec clé valide
- Fichiers .env.example créés pour frontend et backend
Change Log
| Date | Change | Author |
|---|---|---|
| 2026-02-03 | Story créée avec contexte complet | SM Agent |
| 2026-02-05 | Implémentation complète de toutes les tâches (Tasks 1-7) | Dev Agent (Claude Opus 4.5) |
File List
Nouveaux fichiers :
README.md- Documentation racine du monorepo.gitignore- Gitignore globalfrontend/package.json- Dependencies Nuxt 4frontend/nuxt.config.ts- Configuration Nuxt 4 avec SSR, modules, PostCSSfrontend/tsconfig.json- Config TypeScriptfrontend/tailwind.config.js- Design tokens TailwindCSSfrontend/app/app.vue- Composant racine Vuefrontend/app/pages/index.vue- Page d'accueil placeholderfrontend/app/assets/css/main.css- CSS global avec import policesfrontend/.env.example- Variables d'environnement frontendapi/- Projet Laravel 12 complet (via composer create-project)api/app/Http/Middleware/VerifyApiKey.php- Middleware authentification API Keyapi/config/cors.php- Configuration CORSapi/routes/api.php- Routes API avec endpoint /health
Fichiers modifiés :
api/bootstrap/app.php- Routing API-only, enregistrement middleware VerifyApiKeyapi/config/app.php- Ajout config api_keyapi/.env.example- Ajout APP_NAME=Skycel, DB config MySQL, API_KEY, CORS_ALLOWED_ORIGINSapi/.env- Mêmes ajouts que .env.example avec valeurs devapi/routes/web.php- Vidé (mode API-only)