You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

969 lines
27 KiB
Markdown

# 📅 Semaine 5 - Setup & Structure
**Durée** : 20 heures
**Objectif** : Poser les fondations techniques et créer la documentation architecturale
---
## 🎯 Objectifs de la Semaine
1. ✅ Initialiser le projet Next.js avec configuration optimale
2. ✅ Mettre en place la structure microservices
3. ✅ Configurer Supabase (base de données, auth, storage)
4. ✅ Créer les 8 documents livrables (cahier des charges)
5. ✅ Setup CI/CD basique
6. ✅ Installer et configurer tous les outils (ESLint, Prettier, Testing)
---
## 📋 Tâches Détaillées
### Jour 1 : Initialisation Next.js & Configuration (4h)
#### Tâche 1.1 : Créer le projet Next.js (30 min)
```bash
# Créer le projet
cd apps/
npx create-next-app@latest modern-app \
--typescript \
--tailwind \
--app \
--src-dir \
--import-alias "@/*" \
--no-eslint
cd modern-app
# Installer dépendances supplémentaires
pnpm add \
@supabase/supabase-js \
@supabase/auth-helpers-nextjs \
zod \
react-hook-form \
@hookform/resolvers \
zustand \
@tanstack/react-query \
date-fns \
clsx \
tailwind-merge
# Dépendances dev
pnpm add -D \
@types/node \
@types/react \
@types/react-dom \
jest \
@testing-library/react \
@testing-library/jest-dom \
@playwright/test \
eslint-config-prettier \
prettier \
husky \
lint-staged
```
**Critères d'acceptation** :
- ✅ Projet Next.js 14 créé avec App Router
- ✅ TypeScript configuré en mode strict
- ✅ Tailwind CSS fonctionnel
- ✅ Toutes les dépendances installées
---
#### Tâche 1.2 : Configuration TypeScript strict (30 min)
**Fichier** : `tsconfig.json`
```json
{
"compilerOptions": {
"target": "ES2020",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": false,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"],
"@/services/*": ["./src/services/*"],
"@/components/*": ["./src/components/*"],
"@/shared/*": ["./src/shared/*"]
},
// Options strictes supplémentaires
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"forceConsistentCasingInFileNames": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
```
**Critères d'acceptation** :
- ✅ TypeScript strict mode activé
- ✅ Path aliases configurés
-`pnpm tsc --noEmit` passe sans erreur
---
#### Tâche 1.3 : Configuration ESLint & Prettier (30 min)
**Fichier** : `.eslintrc.json`
```json
{
"extends": [
"next/core-web-vitals",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"rules": {
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/explicit-function-return-type": "off",
"prefer-const": "error",
"no-console": ["warn", { "allow": ["warn", "error"] }]
}
}
```
**Fichier** : `.prettierrc`
```json
{
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 80,
"arrowParens": "always"
}
```
**Fichier** : `package.json` (scripts)
```json
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"lint:fix": "next lint --fix",
"format": "prettier --write \"src/**/*.{ts,tsx,json,md}\"",
"type-check": "tsc --noEmit",
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage",
"e2e": "playwright test",
"e2e:ui": "playwright test --ui"
}
}
```
**Critères d'acceptation** :
- ✅ ESLint configuré avec règles strictes
- ✅ Prettier configuré
-`pnpm lint` passe sans erreur
-`pnpm format` fonctionne
---
#### Tâche 1.4 : Configuration shadcn/ui (1h)
```bash
# Initialiser shadcn/ui
pnpm dlx shadcn-ui@latest init
# Installer les composants de base
pnpm dlx shadcn-ui@latest add button
pnpm dlx shadcn-ui@latest add input
pnpm dlx shadcn-ui@latest add card
pnpm dlx shadcn-ui@latest add dialog
pnpm dlx shadcn-ui@latest add form
pnpm dlx shadcn-ui@latest add toast
pnpm dlx shadcn-ui@latest add table
pnpm dlx shadcn-ui@latest add badge
pnpm dlx shadcn-ui@latest add avatar
pnpm dlx shadcn-ui@latest add select
pnpm dlx shadcn-ui@latest add calendar
```
**Fichier** : `src/lib/utils.ts` (créé par shadcn)
```typescript
import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
```
**Critères d'acceptation** :
- ✅ shadcn/ui initialisé
- ✅ Composants de base installés dans `src/components/ui/`
- ✅ Tailwind config mise à jour avec les tokens shadcn
---
#### Tâche 1.5 : Configuration des tests (Jest) (1h 30min)
**Fichier** : `jest.config.js`
```javascript
const nextJest = require('next/jest')
const createJestConfig = nextJest({
dir: './',
})
const customJestConfig = {
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
testEnvironment: 'jest-environment-jsdom',
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
collectCoverageFrom: [
'src/**/*.{ts,tsx}',
'!src/**/*.d.ts',
'!src/**/*.stories.tsx',
'!src/app/**', // Exclure les pages Next.js
],
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80,
},
},
}
module.exports = createJestConfig(customJestConfig)
```
**Fichier** : `jest.setup.js`
```javascript
import '@testing-library/jest-dom'
```
**Fichier** : `playwright.config.ts`
```typescript
import { defineConfig, devices } from '@playwright/test'
export default defineConfig({
testDir: './tests/e2e',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
baseURL: 'http://localhost:3000',
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
webServer: {
command: 'pnpm dev',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
},
})
```
**Critères d'acceptation** :
- ✅ Jest configuré avec React Testing Library
- ✅ Playwright configuré pour E2E
-`pnpm test` exécute les tests unitaires
-`pnpm e2e` exécute les tests E2E
---
### Jour 2 : Structure Microservices & Architecture (4h)
#### Tâche 2.1 : Créer la structure des microservices (2h)
```bash
# Créer la structure complète
mkdir -p src/services/{auth,catalogue,reservation,inventory,payment,notification}/{domain/{entities,repositories,value-objects},application/{use-cases,services},infrastructure/{repositories,external}}
mkdir -p src/shared/{domain/{entities,value-objects},infrastructure/{di,events,supabase},utils}
mkdir -p src/components/{ui,features,layouts}
mkdir -p src/hooks
mkdir -p src/lib
mkdir -p src/types
mkdir -p tests/{unit,integration,e2e}
mkdir -p docs
```
**Critères d'acceptation** :
- ✅ Structure des 6 microservices créée
- ✅ Chaque service suit Clean Architecture (3 couches)
- ✅ Dossiers shared/ créés
- ✅ Dossiers tests/ créés
---
#### Tâche 2.2 : Créer les interfaces de base (Repository Pattern) (2h)
**Fichier** : `src/shared/domain/repositories/base.repository.interface.ts`
```typescript
export interface IBaseRepository<T, ID = string> {
findById(id: ID): Promise<T | null>
findAll(filters?: Record<string, unknown>): Promise<T[]>
create(data: Omit<T, 'id'>): Promise<T>
update(id: ID, data: Partial<T>): Promise<T>
delete(id: ID): Promise<void>
}
```
**Fichier** : `src/shared/domain/entities/base.entity.ts`
```typescript
export abstract class BaseEntity {
id: string
createdAt: Date
updatedAt: Date
constructor(id: string, createdAt?: Date, updatedAt?: Date) {
this.id = id
this.createdAt = createdAt || new Date()
this.updatedAt = updatedAt || new Date()
}
}
```
**Fichier** : `src/shared/domain/value-objects/result.ts`
```typescript
// Result Pattern (pour gérer succès/erreur)
export class Result<T> {
public isSuccess: boolean
public isFailure: boolean
public error?: string
private _value?: T
private constructor(isSuccess: boolean, error?: string, value?: T) {
this.isSuccess = isSuccess
this.isFailure = !isSuccess
this.error = error
this._value = value
}
public get value(): T {
if (this.isFailure) {
throw new Error('Cannot get value from failed result')
}
return this._value as T
}
public static ok<U>(value?: U): Result<U> {
return new Result<U>(true, undefined, value)
}
public static fail<U>(error: string): Result<U> {
return new Result<U>(false, error)
}
}
```
**Critères d'acceptation** :
- ✅ Interfaces de base créées
- ✅ Result Pattern implémenté
- ✅ BaseEntity créé
---
### Jour 3 : Configuration Supabase (4h)
#### Tâche 3.1 : Créer le projet Supabase (30 min)
1. Aller sur https://supabase.com
2. Créer un nouveau projet : `bricoloc-moderne`
3. Choisir la région : Europe (eu-central-1)
4. Noter les credentials :
- Project URL
- Anon Key
- Service Role Key
**Fichier** : `.env.local`
```bash
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
**Critères d'acceptation** :
- ✅ Projet Supabase créé
- ✅ Variables d'environnement configurées
---
#### Tâche 3.2 : Créer le schéma de base de données (2h)
**Fichier** : `supabase/migrations/001_initial_schema.sql`
```sql
-- Enable UUID extension
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- Table users (étendue de auth.users)
CREATE TABLE public.profiles (
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
email TEXT NOT NULL,
nom TEXT,
prenom TEXT,
telephone TEXT,
adresse TEXT,
ville TEXT,
code_postal TEXT,
is_admin BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Table categories
CREATE TABLE public.categories (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
nom TEXT NOT NULL,
description TEXT,
slug TEXT UNIQUE NOT NULL,
icone TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Table entrepots
CREATE TABLE public.entrepots (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
nom TEXT NOT NULL,
ville TEXT NOT NULL,
adresse TEXT NOT NULL,
code_postal TEXT NOT NULL,
telephone TEXT,
email TEXT,
horaires_ouverture TEXT,
latitude DECIMAL(10, 8),
longitude DECIMAL(11, 8),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Table outils
CREATE TABLE public.outils (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
nom TEXT NOT NULL,
description TEXT,
marque TEXT,
modele TEXT,
categorie_id UUID REFERENCES categories(id) ON DELETE SET NULL,
prix_jour DECIMAL(10, 2) NOT NULL,
caution DECIMAL(10, 2),
puissance TEXT,
poids TEXT,
dimensions TEXT,
specifications JSONB,
image_principale TEXT,
images TEXT[],
reservable_professionnels_seulement BOOLEAN DEFAULT FALSE,
actif BOOLEAN DEFAULT TRUE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Index pour recherche
CREATE INDEX idx_outils_nom ON outils USING gin(to_tsvector('french', nom));
CREATE INDEX idx_outils_description ON outils USING gin(to_tsvector('french', description));
CREATE INDEX idx_outils_categorie ON outils(categorie_id);
-- Table stocks
CREATE TABLE public.stocks (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
outil_id UUID NOT NULL REFERENCES outils(id) ON DELETE CASCADE,
entrepot_id UUID NOT NULL REFERENCES entrepots(id) ON DELETE CASCADE,
quantite_totale INTEGER NOT NULL DEFAULT 0,
quantite_disponible INTEGER NOT NULL DEFAULT 0,
quantite_reservee INTEGER NOT NULL DEFAULT 0,
seuil_alerte INTEGER DEFAULT 2,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(outil_id, entrepot_id)
);
-- Table reservations
CREATE TABLE public.reservations (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
utilisateur_id UUID NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
outil_id UUID NOT NULL REFERENCES outils(id) ON DELETE RESTRICT,
entrepot_id UUID NOT NULL REFERENCES entrepots(id) ON DELETE RESTRICT,
date_debut DATE NOT NULL,
date_fin DATE NOT NULL,
nombre_jours INTEGER NOT NULL,
prix_jour DECIMAL(10, 2) NOT NULL,
prix_total DECIMAL(10, 2) NOT NULL,
caution DECIMAL(10, 2),
statut TEXT NOT NULL CHECK (statut IN ('en_attente_paiement', 'confirmee', 'en_cours', 'terminee', 'annulee')),
date_retrait TIMESTAMPTZ,
date_retour TIMESTAMPTZ,
notes TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_reservations_utilisateur ON reservations(utilisateur_id);
CREATE INDEX idx_reservations_outil ON reservations(outil_id);
CREATE INDEX idx_reservations_dates ON reservations(date_debut, date_fin);
CREATE INDEX idx_reservations_statut ON reservations(statut);
-- Table transactions (paiements)
CREATE TABLE public.transactions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
reservation_id UUID NOT NULL REFERENCES reservations(id) ON DELETE CASCADE,
montant DECIMAL(10, 2) NOT NULL,
statut TEXT NOT NULL CHECK (statut IN ('en_attente', 'reussie', 'echouee', 'remboursee')),
methode_paiement TEXT,
stripe_payment_intent_id TEXT,
stripe_charge_id TEXT,
metadata JSONB,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Fonction pour mettre à jour updated_at
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Triggers pour updated_at
CREATE TRIGGER update_profiles_updated_at BEFORE UPDATE ON profiles FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_categories_updated_at BEFORE UPDATE ON categories FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_entrepots_updated_at BEFORE UPDATE ON entrepots FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_outils_updated_at BEFORE UPDATE ON outils FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_stocks_updated_at BEFORE UPDATE ON stocks FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_reservations_updated_at BEFORE UPDATE ON reservations FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_transactions_updated_at BEFORE UPDATE ON transactions FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
```
**Exécuter la migration** :
```bash
# Via Supabase CLI (optionnel)
supabase migration new initial_schema
# Copier le SQL ci-dessus dans le fichier généré
supabase db push
# OU via l'interface Supabase
# SQL Editor > Nouvelle requête > Coller le SQL > Exécuter
```
**Critères d'acceptation** :
- ✅ Schéma de base de données créé
- ✅ 7 tables créées (profiles, categories, entrepots, outils, stocks, reservations, transactions)
- ✅ Index de recherche créés
- ✅ Triggers updated_at fonctionnels
---
#### Tâche 3.3 : Configuration Row Level Security (RLS) (1h)
**Fichier** : `supabase/migrations/002_rls_policies.sql`
```sql
-- Enable RLS on all tables
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
ALTER TABLE categories ENABLE ROW LEVEL SECURITY;
ALTER TABLE entrepots ENABLE ROW LEVEL SECURITY;
ALTER TABLE outils ENABLE ROW LEVEL SECURITY;
ALTER TABLE stocks ENABLE ROW LEVEL SECURITY;
ALTER TABLE reservations ENABLE ROW LEVEL SECURITY;
ALTER TABLE transactions ENABLE ROW LEVEL SECURITY;
-- Profiles policies
CREATE POLICY "Users can view their own profile" ON profiles FOR SELECT USING (auth.uid() = id);
CREATE POLICY "Users can update their own profile" ON profiles FOR UPDATE USING (auth.uid() = id);
CREATE POLICY "Admins can view all profiles" ON profiles FOR SELECT USING ((SELECT is_admin FROM profiles WHERE id = auth.uid()));
-- Categories policies (lecture publique)
CREATE POLICY "Categories are viewable by everyone" ON categories FOR SELECT USING (true);
CREATE POLICY "Only admins can insert categories" ON categories FOR INSERT WITH CHECK ((SELECT is_admin FROM profiles WHERE id = auth.uid()));
CREATE POLICY "Only admins can update categories" ON categories FOR UPDATE USING ((SELECT is_admin FROM profiles WHERE id = auth.uid()));
-- Entrepots policies (lecture publique)
CREATE POLICY "Entrepots are viewable by everyone" ON entrepots FOR SELECT USING (true);
CREATE POLICY "Only admins can manage entrepots" ON entrepots FOR ALL USING ((SELECT is_admin FROM profiles WHERE id = auth.uid()));
-- Outils policies (lecture publique)
CREATE POLICY "Outils are viewable by everyone" ON outils FOR SELECT USING (actif = true OR (SELECT is_admin FROM profiles WHERE id = auth.uid()));
CREATE POLICY "Only admins can manage outils" ON outils FOR ALL USING ((SELECT is_admin FROM profiles WHERE id = auth.uid()));
-- Stocks policies (lecture publique)
CREATE POLICY "Stocks are viewable by everyone" ON stocks FOR SELECT USING (true);
CREATE POLICY "Only admins can manage stocks" ON stocks FOR ALL USING ((SELECT is_admin FROM profiles WHERE id = auth.uid()));
-- Reservations policies
CREATE POLICY "Users can view their own reservations" ON reservations FOR SELECT USING (utilisateur_id = auth.uid() OR (SELECT is_admin FROM profiles WHERE id = auth.uid()));
CREATE POLICY "Users can create reservations" ON reservations FOR INSERT WITH CHECK (utilisateur_id = auth.uid());
CREATE POLICY "Users can update their own reservations" ON reservations FOR UPDATE USING (utilisateur_id = auth.uid() AND statut = 'en_attente_paiement');
CREATE POLICY "Admins can manage all reservations" ON reservations FOR ALL USING ((SELECT is_admin FROM profiles WHERE id = auth.uid()));
-- Transactions policies
CREATE POLICY "Users can view their own transactions" ON transactions FOR SELECT USING (
(SELECT utilisateur_id FROM reservations WHERE id = reservation_id) = auth.uid()
OR (SELECT is_admin FROM profiles WHERE id = auth.uid())
);
CREATE POLICY "Only system can insert transactions" ON transactions FOR INSERT WITH CHECK (false); -- Via API seulement
```
**Critères d'acceptation** :
- ✅ RLS activé sur toutes les tables
- ✅ Policies créées pour sécuriser l'accès
- ✅ Utilisateurs ne peuvent voir que leurs données
- ✅ Admins ont accès complet
---
#### Tâche 3.4 : Seed data de test (30 min)
**Fichier** : `supabase/seed.sql`
```sql
-- Insérer des catégories
INSERT INTO categories (nom, description, slug) VALUES
('Perceuses', 'Perceuses électriques et sans fil', 'perceuses'),
('Scies', 'Scies circulaires et sauteuses', 'scies'),
('Ponceuses', 'Ponceuses orbitales et excentriques', 'ponceuses'),
('Meuleuses', 'Meuleuses d''angle', 'meuleuses'),
('Échelles', 'Échelles et échafaudages', 'echelles');
-- Insérer des entrepôts
INSERT INTO entrepots (nom, ville, adresse, code_postal, telephone, email) VALUES
('BricoLoc Toulouse', 'Toulouse', '15 Avenue de la Gare', '31000', '05 61 00 00 00', 'toulouse@bricoloc.fr'),
('BricoLoc Paris', 'Paris', '42 Rue de Rivoli', '75004', '01 40 00 00 00', 'paris@bricoloc.fr');
-- Insérer quelques outils (seront complétés en Semaine 7)
INSERT INTO outils (nom, description, marque, categorie_id, prix_jour, caution, image_principale) VALUES
('Perceuse Bosch Professional', 'Perceuse à percussion 18V', 'Bosch', (SELECT id FROM categories WHERE slug = 'perceuses'), 12.00, 150.00, '/images/outils/perceuse-bosch.jpg'),
('Scie Circulaire Makita', 'Scie circulaire 1200W', 'Makita', (SELECT id FROM categories WHERE slug = 'scies'), 15.00, 200.00, '/images/outils/scie-makita.jpg');
-- Insérer des stocks
INSERT INTO stocks (outil_id, entrepot_id, quantite_totale, quantite_disponible) VALUES
((SELECT id FROM outils WHERE nom LIKE 'Perceuse%'), (SELECT id FROM entrepots WHERE ville = 'Toulouse'), 5, 5),
((SELECT id FROM outils WHERE nom LIKE 'Scie%'), (SELECT id FROM entrepots WHERE ville = 'Toulouse'), 3, 3);
```
**Critères d'acceptation** :
- ✅ Catégories de test insérées
- ✅ Entrepôts de test insérés
- ✅ Quelques outils de test insérés
---
### Jour 4 : Documentation Livrables (4h)
Créer les 6 documents requis par le cahier des charges.
#### Tâche 4.1 : Exigences Non Fonctionnelles (1h)
Créer `docs/NON_FUNCTIONAL_REQUIREMENTS.md` - Voir fichier séparé
#### Tâche 4.2 : Architecture Logique (1h)
Créer `docs/LOGICAL_ARCHITECTURE.md` - Voir fichier séparé
#### Tâche 4.3 : Comparaison Styles Architecturaux (1h)
Créer `docs/ARCHITECTURE_STYLES_COMPARISON.md` - Voir fichier séparé
#### Tâche 4.4 : Matrice de Choix Technologique (1h)
Créer `docs/TECHNOLOGY_DECISION_MATRIX.md` - Voir fichier séparé
**Critères d'acceptation** :
- ✅ 4 documents créés et complets
- ✅ Format Markdown professionnel
- ✅ Diagrammes Mermaid inclus
---
### Jour 5 : CI/CD & Finalisation (4h)
#### Tâche 5.1 : Configuration GitHub Actions (2h)
**Fichier** : `.github/workflows/ci.yml`
```yaml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
lint-and-type-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Lint
run: pnpm lint
- name: Type check
run: pnpm type-check
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Run tests
run: pnpm test:coverage
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
files: ./coverage/lcov.info
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Build
run: pnpm build
- name: Check bundle size
run: |
BUNDLE_SIZE=$(du -sh .next/static | cut -f1)
echo "Bundle size: $BUNDLE_SIZE"
```
**Critères d'acceptation** :
- ✅ CI configuré sur GitHub Actions
- ✅ Lint, type-check, tests et build automatisés
- ✅ Pipeline s'exécute sur chaque push/PR
---
#### Tâche 5.2 : Configuration Vercel (30 min)
1. Connecter le repo GitHub à Vercel
2. Configurer les variables d'environnement :
- `NEXT_PUBLIC_SUPABASE_URL`
- `NEXT_PUBLIC_SUPABASE_ANON_KEY`
3. Déploiement automatique sur push `main`
**Critères d'acceptation** :
- ✅ Projet déployé sur Vercel
- ✅ URL de production accessible
- ✅ Variables d'environnement configurées
---
#### Tâche 5.3 : Documentation README (1h)
**Fichier** : `README.md`
```markdown
# BricoLoc - Application Moderne
Application de location d'outils démontrant une architecture microservices moderne avec Clean Architecture.
## Stack Technique
- **Frontend** : Next.js 14, React 18, TypeScript
- **UI** : Tailwind CSS, shadcn/ui
- **Backend** : Supabase (PostgreSQL, Auth, Realtime, Storage)
- **Tests** : Jest, React Testing Library, Playwright
- **CI/CD** : GitHub Actions, Vercel
## Architecture
Cette application suit une architecture microservices hybride avec 6 services :
- Auth Service
- Catalogue Service
- Reservation Service
- Inventory Service
- Payment Service
- Notification Service
Chaque service implémente Clean Architecture avec 3 couches :
- Domain Layer (Entities, Business Rules)
- Application Layer (Use Cases, Services)
- Infrastructure Layer (Repositories, External APIs)
## Installation
```bash
# Installer les dépendances
pnpm install
# Configurer les variables d'environnement
cp .env.example .env.local
# Éditer .env.local avec vos credentials Supabase
# Lancer en développement
pnpm dev
```
## Scripts Disponibles
- `pnpm dev` - Lancer le serveur de développement
- `pnpm build` - Build de production
- `pnpm start` - Lancer le build de production
- `pnpm lint` - Linter le code
- `pnpm type-check` - Vérifier les types TypeScript
- `pnpm test` - Tests unitaires
- `pnpm test:coverage` - Tests avec coverage
- `pnpm e2e` - Tests E2E avec Playwright
## Documentation
- [Roadmap](./docs/ROADMAP_MODERN.md)
- [Exigences Non Fonctionnelles](./docs/NON_FUNCTIONAL_REQUIREMENTS.md)
- [Architecture Logique](./docs/LOGICAL_ARCHITECTURE.md)
- [Comparaison Styles Architecturaux](./docs/ARCHITECTURE_STYLES_COMPARISON.md)
- [Matrice de Choix Technologique](./docs/TECHNOLOGY_DECISION_MATRIX.md)
## License
MIT
```
**Critères d'acceptation** :
- ✅ README complet et professionnel
- ✅ Instructions d'installation claires
- ✅ Liens vers documentation
---
#### Tâche 5.4 : Revue et Tests (30 min)
- Vérifier que toutes les commandes fonctionnent
- Vérifier que le CI passe
- Vérifier que le déploiement Vercel fonctionne
- Commit et push final
**Critères d'acceptation** :
- ✅ Toutes les commandes s'exécutent sans erreur
- ✅ CI GitHub Actions au vert
- ✅ Application déployée sur Vercel
---
## ✅ Checklist de Fin de Semaine 5
### Configuration Projet
- [x] Next.js 14 initialisé avec App Router ✅
- [x] TypeScript strict mode configuré ✅
- [x] ESLint + Prettier configurés ✅
- [x] shadcn/ui installé et configuré ✅
- [x] Jest + Playwright configurés ✅
### Structure
- [x] Structure microservices créée (6 services) ✅
- [x] Clean Architecture par service (3 couches) ✅
- [x] Shared/ avec DI, Event Bus, utils ✅
- [x] Interfaces de base (Repository, Entity, Result) ✅
### Supabase
- [x] Projet Supabase créé ✅
- [x] Schéma de base de données créé (7 tables) ✅
- [x] RLS policies configurées ✅
- [x] Types TypeScript générés ✅
### Documentation
- [x] NON_FUNCTIONAL_REQUIREMENTS.md ✅
- [x] LOGICAL_ARCHITECTURE.md ✅
- [x] ARCHITECTURE_STYLES_COMPARISON.md ✅
- [x] TECHNOLOGY_DECISION_MATRIX.md ✅
- [x] SUPABASE_SETUP.md ✅
### CI/CD
- [x] GitHub Actions configuré ✅
- [ ] Vercel connecté et déployé (à configurer manuellement)
- [x] README.md complet ✅
### Tests
- [x] `pnpm lint` passe ✅
- [x] `pnpm type-check` passe (src/) ✅
- [x] `pnpm build` réussit ✅
- [x] Tests unitaires (14 tests) ✅
- [ ] CI GitHub Actions au vert (nécessite push sur GitHub)
- [ ] Déploiement Vercel fonctionnel (nécessite connexion manuelle)
---
## 🚀 Prochaine Étape
**Semaine 6** : Implémenter Auth Service avec Supabase Auth
Voir : [Semaine 6 - Auth Service](./WEEK_6_AUTH.md)
---
**Maintenu par** : Équipe Architecture BricoLoc
**Dernière mise à jour** : 31 Octobre 2025