feat: initialiser le projet CVP (Next.js 14 + FastAPI + PostgreSQL)
- Frontend : Next.js 14 App Router, TypeScript strict, Tailwind 3, shadcn/ui, next-intl (fr/en) - Backend : FastAPI, SQLAlchemy 2 async, Alembic, Pydantic 2, Python 3.11 - Infrastructure : Docker Compose (PostgreSQL 16 + Ollama) - Tooling : ESLint + Prettier (frontend), Ruff (backend), pytest - Structure complète des dossiers avec pages et routers placeholder
This commit is contained in:
@@ -0,0 +1,746 @@
|
||||
# Phase 1 — Fondations : Scaffolding du projet CVP
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Initialiser le monorepo CVP avec un frontend Next.js 14 et un backend FastAPI, configurer le tooling (lint, format, tests), créer la structure de dossiers, et produire un commit initial propre.
|
||||
|
||||
**Architecture:** Monorepo avec deux sous-projets : `frontend/` (Next.js 14 App Router, TypeScript strict, Tailwind 3, shadcn/ui) et `backend/` (FastAPI, SQLAlchemy 2, Alembic, Python 3.11). Docker Compose pour PostgreSQL 16 et Ollama. Les deux sous-projets sont indépendants et communiquent via REST API.
|
||||
|
||||
**Tech Stack:** Next.js 14, React 18, TypeScript, Tailwind CSS 3, shadcn/ui, next-intl, FastAPI, SQLAlchemy 2, Alembic, Pydantic 2, PostgreSQL 16, Python 3.11
|
||||
|
||||
---
|
||||
|
||||
## Prérequis
|
||||
|
||||
- Python 3.11 doit etre installé (`sudo dnf install -y python3.11 python3.11-pip python3.11-devel`)
|
||||
- Node.js 22+ et npm 10+ sont déjà disponibles
|
||||
- PostgreSQL 16 sera lancé via Docker Compose
|
||||
|
||||
---
|
||||
|
||||
## Task 1 : Fichiers racine du monorepo
|
||||
|
||||
**Files:**
|
||||
- Create: `.gitignore`
|
||||
- Create: `.env.example`
|
||||
- Create: `docker-compose.yml`
|
||||
|
||||
- [ ] **Step 1: Créer le `.gitignore`**
|
||||
|
||||
```gitignore
|
||||
# Dependencies
|
||||
node_modules/
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.venv/
|
||||
venv/
|
||||
|
||||
# Environment
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Build
|
||||
.next/
|
||||
out/
|
||||
dist/
|
||||
build/
|
||||
*.egg-info/
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Testing
|
||||
coverage/
|
||||
htmlcov/
|
||||
.pytest_cache/
|
||||
.coverage
|
||||
|
||||
# Database
|
||||
*.db
|
||||
*.sqlite3
|
||||
|
||||
# Generated
|
||||
*.pdf
|
||||
*.docx
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Créer le `.env.example`**
|
||||
|
||||
```env
|
||||
# PostgreSQL
|
||||
POSTGRES_HOST=localhost
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_DB=cvp
|
||||
POSTGRES_USER=cvp
|
||||
POSTGRES_PASSWORD=cvp_dev_password
|
||||
|
||||
# France Travail API
|
||||
FRANCE_TRAVAIL_CLIENT_ID=
|
||||
FRANCE_TRAVAIL_CLIENT_SECRET=
|
||||
|
||||
# Adzuna API
|
||||
ADZUNA_APP_ID=
|
||||
ADZUNA_APP_KEY=
|
||||
|
||||
# Ollama
|
||||
OLLAMA_BASE_URL=http://localhost:11434
|
||||
OLLAMA_MODEL=phi3:mini
|
||||
|
||||
# Backend
|
||||
BACKEND_HOST=0.0.0.0
|
||||
BACKEND_PORT=8000
|
||||
|
||||
# Frontend
|
||||
NEXT_PUBLIC_API_URL=http://localhost:8000
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Créer le `docker-compose.yml`**
|
||||
|
||||
```yaml
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
environment:
|
||||
POSTGRES_DB: cvp
|
||||
POSTGRES_USER: cvp
|
||||
POSTGRES_PASSWORD: cvp_dev_password
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
|
||||
ollama:
|
||||
image: ollama/ollama:latest
|
||||
ports:
|
||||
- "11434:11434"
|
||||
volumes:
|
||||
- ollama_data:/root/.ollama
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: 1
|
||||
capabilities: [gpu]
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
ollama_data:
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 2 : Initialiser le frontend Next.js
|
||||
|
||||
**Files:**
|
||||
- Create: `frontend/` (via `create-next-app`)
|
||||
- Modify: `frontend/tsconfig.json`
|
||||
- Modify: `frontend/package.json`
|
||||
|
||||
- [ ] **Step 1: Créer le projet Next.js 14**
|
||||
|
||||
```bash
|
||||
cd /home/localadm/cvp
|
||||
npx create-next-app@14 frontend \
|
||||
--typescript \
|
||||
--tailwind \
|
||||
--eslint \
|
||||
--app \
|
||||
--src-dir \
|
||||
--import-alias "@/*" \
|
||||
--no-turbopack
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Vérifier que TypeScript strict est activé**
|
||||
|
||||
Dans `frontend/tsconfig.json`, s'assurer que `"strict": true` est présent dans `compilerOptions`.
|
||||
|
||||
- [ ] **Step 3: Vérifier que l'app démarre**
|
||||
|
||||
```bash
|
||||
cd /home/localadm/cvp/frontend
|
||||
npm run dev &
|
||||
sleep 5
|
||||
curl -s http://localhost:3000 | head -20
|
||||
kill %1
|
||||
```
|
||||
|
||||
Expected: réponse HTML valide.
|
||||
|
||||
---
|
||||
|
||||
## Task 3 : Configurer Tailwind, shadcn/ui et next-intl dans le frontend
|
||||
|
||||
**Files:**
|
||||
- Modify: `frontend/tailwind.config.ts` (thème CVP)
|
||||
- Modify: `frontend/src/app/globals.css`
|
||||
- Create: `frontend/components.json` (via shadcn init)
|
||||
- Create: `frontend/src/messages/fr.json`
|
||||
- Create: `frontend/src/messages/en.json`
|
||||
- Create: `frontend/src/i18n/request.ts`
|
||||
- Create: `frontend/src/i18n/routing.ts`
|
||||
- Modify: `frontend/next.config.js` (plugin next-intl)
|
||||
- Modify: `frontend/package.json` (ajout next-intl)
|
||||
|
||||
- [ ] **Step 1: Installer et configurer shadcn/ui**
|
||||
|
||||
```bash
|
||||
cd /home/localadm/cvp/frontend
|
||||
npx shadcn@latest init -d
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Configurer le thème Tailwind CVP**
|
||||
|
||||
Modifier `frontend/tailwind.config.ts` pour ajouter les couleurs du design system :
|
||||
- Primaire : indigo (#6366F1)
|
||||
- Secondaire : cyan (#06B6D4)
|
||||
- Accent : orange (#F59E0B)
|
||||
- Succès : vert (#10B981)
|
||||
- Danger : rouge (#EF4444)
|
||||
- Fond dark : #0F172A / #1E293B
|
||||
- Polices : Inter (UI) + JetBrains Mono (code)
|
||||
- `borderRadius` : `xl` par défaut
|
||||
|
||||
- [ ] **Step 3: Installer et configurer next-intl**
|
||||
|
||||
```bash
|
||||
cd /home/localadm/cvp/frontend
|
||||
npm install next-intl
|
||||
```
|
||||
|
||||
Créer `src/messages/fr.json` :
|
||||
```json
|
||||
{
|
||||
"common": {
|
||||
"appName": "CVP",
|
||||
"loading": "Chargement...",
|
||||
"error": "Une erreur est survenue",
|
||||
"save": "Enregistrer",
|
||||
"cancel": "Annuler",
|
||||
"delete": "Supprimer",
|
||||
"edit": "Modifier",
|
||||
"back": "Retour"
|
||||
},
|
||||
"nav": {
|
||||
"dashboard": "Tableau de bord",
|
||||
"offres": "Offres",
|
||||
"profil": "Profil",
|
||||
"cv": "CV",
|
||||
"candidatures": "Candidatures",
|
||||
"parametres": "Parametres"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Créer `src/messages/en.json` avec les traductions anglaises correspondantes.
|
||||
|
||||
Créer `src/i18n/routing.ts` :
|
||||
```typescript
|
||||
import { defineRouting } from "next-intl/routing";
|
||||
|
||||
export const routing = defineRouting({
|
||||
locales: ["fr", "en"],
|
||||
defaultLocale: "fr",
|
||||
});
|
||||
```
|
||||
|
||||
Créer `src/i18n/request.ts` :
|
||||
```typescript
|
||||
import { getRequestConfig } from "next-intl/server";
|
||||
import { routing } from "./routing";
|
||||
|
||||
export default getRequestConfig(async ({ requestLocale }) => {
|
||||
let locale = await requestLocale;
|
||||
if (!locale || !routing.locales.includes(locale as "fr" | "en")) {
|
||||
locale = routing.defaultLocale;
|
||||
}
|
||||
return {
|
||||
locale,
|
||||
messages: (await import(`../messages/${locale}.json`)).default,
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
Mettre a jour `next.config.js` avec le plugin `createNextIntlPlugin`.
|
||||
|
||||
- [ ] **Step 4: Restructurer le App Router pour i18n**
|
||||
|
||||
Déplacer les pages sous `src/app/[locale]/` et créer le layout racine avec `NextIntlClientProvider`. Créer le middleware `src/middleware.ts` pour la redirection de locale.
|
||||
|
||||
---
|
||||
|
||||
## Task 4 : Créer la structure de dossiers frontend
|
||||
|
||||
**Files:**
|
||||
- Create: `frontend/src/components/ui/.gitkeep`
|
||||
- Create: `frontend/src/components/layout/.gitkeep`
|
||||
- Create: `frontend/src/components/offres/.gitkeep`
|
||||
- Create: `frontend/src/components/cv/.gitkeep`
|
||||
- Create: `frontend/src/components/profil/.gitkeep`
|
||||
- Create: `frontend/src/lib/.gitkeep`
|
||||
- Create: `frontend/src/hooks/.gitkeep`
|
||||
- Create: `frontend/src/types/.gitkeep`
|
||||
- Create: `frontend/src/app/[locale]/dashboard/page.tsx`
|
||||
- Create: `frontend/src/app/[locale]/offres/page.tsx`
|
||||
- Create: `frontend/src/app/[locale]/profil/page.tsx`
|
||||
- Create: `frontend/src/app/[locale]/cv/page.tsx`
|
||||
- Create: `frontend/src/app/[locale]/candidatures/page.tsx`
|
||||
- Create: `frontend/src/app/[locale]/parametres/page.tsx`
|
||||
|
||||
- [ ] **Step 1: Créer les dossiers de composants**
|
||||
|
||||
Créer les sous-dossiers dans `components/` avec des `.gitkeep` pour les dossiers vides.
|
||||
|
||||
- [ ] **Step 2: Créer les pages placeholder**
|
||||
|
||||
Chaque page sous `src/app/[locale]/` est un simple composant avec le titre de la section :
|
||||
|
||||
```tsx
|
||||
// src/app/[locale]/dashboard/page.tsx
|
||||
export default function DashboardPage() {
|
||||
return (
|
||||
<main className="p-8">
|
||||
<h1 className="text-3xl font-bold">Tableau de bord</h1>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
Meme pattern pour : `offres/page.tsx`, `profil/page.tsx`, `cv/page.tsx`, `candidatures/page.tsx`, `parametres/page.tsx`.
|
||||
|
||||
---
|
||||
|
||||
## Task 5 : Configurer ESLint et Prettier pour le frontend
|
||||
|
||||
**Files:**
|
||||
- Modify: `frontend/.eslintrc.json`
|
||||
- Create: `frontend/.prettierrc`
|
||||
- Modify: `frontend/package.json` (scripts)
|
||||
|
||||
- [ ] **Step 1: Installer Prettier**
|
||||
|
||||
```bash
|
||||
cd /home/localadm/cvp/frontend
|
||||
npm install -D prettier eslint-config-prettier
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Créer `.prettierrc`**
|
||||
|
||||
```json
|
||||
{
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "all",
|
||||
"printWidth": 100
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Configurer ESLint**
|
||||
|
||||
Mettre a jour `.eslintrc.json` pour inclure `prettier` dans `extends` et ajouter les regles : `no-console: warn`, `@typescript-eslint/no-explicit-any: error`.
|
||||
|
||||
- [ ] **Step 4: Ajouter les scripts npm**
|
||||
|
||||
Dans `package.json`, ajouter :
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"lint": "next lint",
|
||||
"lint:fix": "next lint --fix",
|
||||
"format": "prettier --write \"src/**/*.{ts,tsx,json,css}\"",
|
||||
"format:check": "prettier --check \"src/**/*.{ts,tsx,json,css}\"",
|
||||
"type-check": "tsc --noEmit"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Vérifier que lint passe**
|
||||
|
||||
```bash
|
||||
cd /home/localadm/cvp/frontend
|
||||
npm run lint
|
||||
npm run format:check
|
||||
npm run type-check
|
||||
```
|
||||
|
||||
Expected: pas d'erreurs.
|
||||
|
||||
---
|
||||
|
||||
## Task 6 : Initialiser le backend Python
|
||||
|
||||
**Files:**
|
||||
- Create: `backend/pyproject.toml`
|
||||
- Create: `backend/requirements.txt`
|
||||
- Create: `backend/app/__init__.py`
|
||||
- Create: `backend/app/main.py`
|
||||
- Create: `backend/app/config.py`
|
||||
|
||||
- [ ] **Step 1: Installer Python 3.11 et créer le virtualenv**
|
||||
|
||||
```bash
|
||||
sudo dnf install -y python3.11 python3.11-pip python3.11-devel
|
||||
cd /home/localadm/cvp/backend
|
||||
python3.11 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Créer `pyproject.toml`**
|
||||
|
||||
```toml
|
||||
[project]
|
||||
name = "cvp-backend"
|
||||
version = "0.1.0"
|
||||
description = "CVP - Backend API pour la recherche d'emploi intelligente"
|
||||
requires-python = ">=3.11"
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
asyncio_mode = "auto"
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py311"
|
||||
line-length = 100
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = ["E", "F", "W", "I", "N", "UP", "ANN", "B", "A", "SIM"]
|
||||
ignore = ["ANN101", "ANN102"]
|
||||
|
||||
[tool.ruff.lint.isort]
|
||||
known-first-party = ["app"]
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Créer `requirements.txt`**
|
||||
|
||||
```txt
|
||||
fastapi==0.115.12
|
||||
uvicorn[standard]==0.34.2
|
||||
sqlalchemy[asyncio]==2.0.41
|
||||
asyncpg==0.30.0
|
||||
alembic==1.15.2
|
||||
pydantic==2.11.3
|
||||
pydantic-settings==2.9.1
|
||||
python-dotenv==1.1.0
|
||||
httpx==0.28.1
|
||||
apscheduler==3.11.0
|
||||
weasyprint==65.1
|
||||
python-docx==1.1.2
|
||||
ollama==0.4.8
|
||||
|
||||
# Dev
|
||||
pytest==8.3.5
|
||||
pytest-asyncio==0.25.3
|
||||
pytest-cov==6.1.1
|
||||
ruff==0.11.8
|
||||
httpx==0.28.1
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Installer les dépendances**
|
||||
|
||||
```bash
|
||||
cd /home/localadm/cvp/backend
|
||||
source .venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Créer le point d'entrée FastAPI**
|
||||
|
||||
`backend/app/__init__.py` : fichier vide.
|
||||
|
||||
`backend/app/config.py` :
|
||||
```python
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
postgres_host: str = "localhost"
|
||||
postgres_port: int = 5432
|
||||
postgres_db: str = "cvp"
|
||||
postgres_user: str = "cvp"
|
||||
postgres_password: str = "cvp_dev_password"
|
||||
|
||||
france_travail_client_id: str = ""
|
||||
france_travail_client_secret: str = ""
|
||||
|
||||
adzuna_app_id: str = ""
|
||||
adzuna_app_key: str = ""
|
||||
|
||||
ollama_base_url: str = "http://localhost:11434"
|
||||
ollama_model: str = "phi3:mini"
|
||||
|
||||
model_config = {"env_file": ".env", "env_file_encoding": "utf-8"}
|
||||
|
||||
@property
|
||||
def database_url(self) -> str:
|
||||
return (
|
||||
f"postgresql+asyncpg://{self.postgres_user}:{self.postgres_password}"
|
||||
f"@{self.postgres_host}:{self.postgres_port}/{self.postgres_db}"
|
||||
)
|
||||
|
||||
|
||||
settings = Settings()
|
||||
```
|
||||
|
||||
`backend/app/main.py` :
|
||||
```python
|
||||
import logging
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
app = FastAPI(
|
||||
title="CVP API",
|
||||
description="API pour la recherche d'emploi intelligente",
|
||||
version="0.1.0",
|
||||
)
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["http://localhost:3000"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
async def health_check() -> dict[str, str]:
|
||||
return {"status": "ok"}
|
||||
```
|
||||
|
||||
- [ ] **Step 6: Vérifier que le backend démarre**
|
||||
|
||||
```bash
|
||||
cd /home/localadm/cvp/backend
|
||||
source .venv/bin/activate
|
||||
uvicorn app.main:app --host 0.0.0.0 --port 8000 &
|
||||
sleep 3
|
||||
curl -s http://localhost:8000/health
|
||||
kill %1
|
||||
```
|
||||
|
||||
Expected: `{"status":"ok"}`
|
||||
|
||||
---
|
||||
|
||||
## Task 7 : Créer la structure de dossiers backend
|
||||
|
||||
**Files:**
|
||||
- Create: `backend/app/api/__init__.py`
|
||||
- Create: `backend/app/api/routes/__init__.py`
|
||||
- Create: `backend/app/api/routes/offres.py`
|
||||
- Create: `backend/app/api/routes/profil.py`
|
||||
- Create: `backend/app/api/routes/cv.py`
|
||||
- Create: `backend/app/api/routes/candidatures.py`
|
||||
- Create: `backend/app/api/routes/parametres.py`
|
||||
- Create: `backend/app/api/deps.py`
|
||||
- Create: `backend/app/models/__init__.py`
|
||||
- Create: `backend/app/schemas/__init__.py`
|
||||
- Create: `backend/app/services/__init__.py`
|
||||
- Create: `backend/app/templates/.gitkeep`
|
||||
- Create: `backend/app/db/__init__.py`
|
||||
- Create: `backend/app/db/database.py`
|
||||
- Create: `backend/tests/__init__.py`
|
||||
- Create: `backend/tests/test_health.py`
|
||||
|
||||
- [ ] **Step 1: Créer les packages Python**
|
||||
|
||||
Créer tous les dossiers avec `__init__.py` vides pour : `api/`, `api/routes/`, `models/`, `schemas/`, `services/`, `db/`, `tests/`.
|
||||
|
||||
- [ ] **Step 2: Créer les routers placeholder**
|
||||
|
||||
Chaque fichier de route est un router minimal :
|
||||
|
||||
```python
|
||||
# backend/app/api/routes/offres.py
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter(prefix="/offres", tags=["offres"])
|
||||
```
|
||||
|
||||
Meme pattern pour `profil.py`, `cv.py`, `candidatures.py`, `parametres.py`.
|
||||
|
||||
- [ ] **Step 3: Créer le module database**
|
||||
|
||||
```python
|
||||
# backend/app/db/database.py
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||
|
||||
from app.config import settings
|
||||
|
||||
engine = create_async_engine(settings.database_url, echo=False)
|
||||
async_session = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
||||
|
||||
|
||||
async def get_db() -> AsyncSession:
|
||||
async with async_session() as session:
|
||||
yield session
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Créer le module deps**
|
||||
|
||||
```python
|
||||
# backend/app/api/deps.py
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.db.database import get_db
|
||||
|
||||
DbSession = Annotated[AsyncSession, Depends(get_db)]
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Enregistrer les routers dans main.py**
|
||||
|
||||
Ajouter dans `app/main.py` :
|
||||
```python
|
||||
from app.api.routes import offres, profil, cv, candidatures, parametres
|
||||
|
||||
app.include_router(offres.router, prefix="/api")
|
||||
app.include_router(profil.router, prefix="/api")
|
||||
app.include_router(cv.router, prefix="/api")
|
||||
app.include_router(candidatures.router, prefix="/api")
|
||||
app.include_router(parametres.router, prefix="/api")
|
||||
```
|
||||
|
||||
- [ ] **Step 6: Écrire le premier test**
|
||||
|
||||
```python
|
||||
# backend/tests/test_health.py
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from app.main import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
def test_health_check():
|
||||
response = client.get("/health")
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"status": "ok"}
|
||||
```
|
||||
|
||||
- [ ] **Step 7: Lancer le test**
|
||||
|
||||
```bash
|
||||
cd /home/localadm/cvp/backend
|
||||
source .venv/bin/activate
|
||||
pytest tests/test_health.py -v
|
||||
```
|
||||
|
||||
Expected: 1 test PASSED.
|
||||
|
||||
---
|
||||
|
||||
## Task 8 : Configurer Ruff (lint + format) pour le backend
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/pyproject.toml` (déjà fait en Task 6)
|
||||
|
||||
- [ ] **Step 1: Vérifier que ruff lint passe**
|
||||
|
||||
```bash
|
||||
cd /home/localadm/cvp/backend
|
||||
source .venv/bin/activate
|
||||
ruff check app/ tests/
|
||||
```
|
||||
|
||||
Expected: pas d'erreurs (corriger si nécessaire).
|
||||
|
||||
- [ ] **Step 2: Vérifier que ruff format passe**
|
||||
|
||||
```bash
|
||||
ruff format --check app/ tests/
|
||||
```
|
||||
|
||||
Expected: pas de diff (corriger si nécessaire avec `ruff format app/ tests/`).
|
||||
|
||||
---
|
||||
|
||||
## Task 9 : Configurer Alembic pour les migrations
|
||||
|
||||
**Files:**
|
||||
- Create: `backend/alembic.ini`
|
||||
- Create: `backend/app/db/migrations/env.py`
|
||||
- Create: `backend/app/db/migrations/versions/.gitkeep`
|
||||
- Create: `backend/app/db/migrations/script.py.mako`
|
||||
|
||||
- [ ] **Step 1: Initialiser Alembic**
|
||||
|
||||
```bash
|
||||
cd /home/localadm/cvp/backend
|
||||
source .venv/bin/activate
|
||||
alembic init app/db/migrations
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Configurer `alembic.ini`**
|
||||
|
||||
Mettre `sqlalchemy.url` a vide (sera fourni par `env.py` dynamiquement).
|
||||
|
||||
- [ ] **Step 3: Configurer `env.py`**
|
||||
|
||||
Modifier `app/db/migrations/env.py` pour :
|
||||
- Importer `settings` depuis `app.config`
|
||||
- Utiliser `settings.database_url` comme URL de connexion
|
||||
- Importer le `Base` de SQLAlchemy pour l'autogénération des migrations
|
||||
|
||||
---
|
||||
|
||||
## Task 10 : Générer le CLAUDE.md
|
||||
|
||||
**Files:**
|
||||
- Create: `CLAUDE.md`
|
||||
|
||||
- [ ] **Step 1: Créer le CLAUDE.md a la racine**
|
||||
|
||||
Le fichier doit contenir :
|
||||
- Description du projet
|
||||
- Commandes utiles (dev, test, lint, format, build)
|
||||
- Conventions de codage (résumé du PROMPT.md)
|
||||
- Structure du projet
|
||||
- Regles impératives
|
||||
|
||||
---
|
||||
|
||||
## Task 11 : Commit initial
|
||||
|
||||
- [ ] **Step 1: Vérifier que tout fonctionne**
|
||||
|
||||
```bash
|
||||
# Frontend
|
||||
cd /home/localadm/cvp/frontend
|
||||
npm run lint
|
||||
npm run type-check
|
||||
npm run build
|
||||
|
||||
# Backend
|
||||
cd /home/localadm/cvp/backend
|
||||
source .venv/bin/activate
|
||||
ruff check app/ tests/
|
||||
pytest tests/ -v
|
||||
```
|
||||
|
||||
Expected: tout passe sans erreur.
|
||||
|
||||
- [ ] **Step 2: Commit initial**
|
||||
|
||||
```bash
|
||||
cd /home/localadm/cvp
|
||||
git add .
|
||||
git commit -m "feat: initialiser le projet CVP (Next.js 14 + FastAPI + PostgreSQL)"
|
||||
```
|
||||
|
||||
Note : ne PAS ajouter `Co-Authored-By`.
|
||||
Reference in New Issue
Block a user