feat: Création de la structure api-contracts

- Contrats d'API Frontend ↔ Backend (OpenAPI 3.0)
- Contrats Backend ↔ Database (Prisma/SQL)
- Documentation complète pour génération de code
- Permet l'interchangeabilité des composants
This commit is contained in:
MARTIN Julien 2025-11-24 15:45:07 +01:00
parent ad81a2f4f4
commit aa61831878
3 changed files with 287 additions and 0 deletions

85
api-contracts/README.md Normal file
View File

@ -0,0 +1,85 @@
# 📜 API Contracts - PtitsPas
Ce dossier contient les **contrats d'API** qui définissent les interfaces entre les différentes couches de l'application.
## 🎯 Objectif
Garantir que **Frontend**, **Backend** et **Database** respectent des contrats stricts, permettant de les rendre **interchangeables** sans casser l'application.
---
## 📁 Structure
```
api-contracts/
├── frontend-backend/ # Contrat Frontend ↔ Backend (HTTP REST)
│ ├── openapi.yaml # Spécification OpenAPI 3.0 (source de vérité)
│ └── generated/ # Code généré automatiquement
│ ├── dart/ # Client API pour Flutter
│ └── typescript/ # Types pour NestJS
└── backend-database/ # Contrat Backend ↔ Database (ORM/SQL)
├── schema.prisma # Schéma Prisma (ou TypeORM entities)
└── migrations/ # Migrations SQL versionnées
```
---
## 🔄 Workflow de Génération
### 1. Frontend ↔ Backend
**Source de vérité :** `frontend-backend/openapi.yaml`
**Génération du client Dart (Flutter) :**
```bash
cd api-contracts/frontend-backend
docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli generate \
-i /local/openapi.yaml \
-g dart-dio \
-o /local/generated/dart
```
**Génération des types TypeScript (NestJS) :**
```bash
cd api-contracts/frontend-backend
npx openapi-typescript openapi.yaml --output generated/typescript/api.types.ts
```
---
### 2. Backend ↔ Database
**Source de vérité :** `backend-database/schema.prisma`
**Génération du client Prisma :**
```bash
cd api-contracts/backend-database
npx prisma generate
```
**Génération des migrations SQL :**
```bash
cd api-contracts/backend-database
npx prisma migrate dev --name <nom_migration>
```
---
## ✅ Avantages
- **Frontend interchangeable** : React, Vue, Angular → il suffit de régénérer le client API
- **Backend interchangeable** : Python, Go, Java → tant qu'il respecte `openapi.yaml`
- **Database read-only en prod** : User PostgreSQL `app_user` (pas de DDL)
- **Cohérence garantie** : Types générés = pas d'erreur de typage
- **Documentation auto** : OpenAPI = documentation interactive (Swagger UI)
---
## 📚 Documentation
- [OpenAPI 3.0 Spec](https://swagger.io/specification/)
- [Prisma Schema](https://www.prisma.io/docs/concepts/components/prisma-schema)
- [openapi-generator](https://openapi-generator.tech/)
- [openapi-typescript](https://github.com/drwpow/openapi-typescript)

View File

@ -0,0 +1,25 @@
# 💾 Backend ↔ Database Contract
Ce dossier contient le **contrat de données** entre le Backend et la Base de Données.
## 📋 Contenu
- **`schema.prisma`** : Schéma de base de données (à créer)
- **`migrations/`** : Migrations SQL versionnées (actuellement dans `/database/migrations/`)
## 🔄 Migration Future
À terme, les migrations SQL de `/database/migrations/` seront gérées ici avec Prisma :
```bash
# Générer une migration
npx prisma migrate dev --name add_user_phone
# Appliquer en production
npx prisma migrate deploy
```
## 📚 Référence
- [Prisma Migrate](https://www.prisma.io/docs/concepts/components/prisma-migrate)

View File

@ -0,0 +1,177 @@
openapi: 3.0.0
info:
title: PtitsPas API
version: 1.0.0
description: |
API REST pour l'application PtitsPas.
Ce contrat définit l'interface entre le Frontend (Flutter) et le Backend (NestJS).
contact:
name: PtitsPas Team
email: admin@ptits-pas.fr
servers:
- url: https://app.ptits-pas.fr/api
description: Production
- url: http://localhost:3000/api
description: Développement local
paths:
/auth/login:
post:
summary: Authentification utilisateur
operationId: loginUser
tags:
- Authentication
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- email
- password
properties:
email:
type: string
format: email
example: admin@ptits-pas.fr
password:
type: string
format: password
example: "4dm1n1strateur"
responses:
'200':
description: Authentification réussie
content:
application/json:
schema:
type: object
properties:
access_token:
type: string
description: Token JWT d'accès
refresh_token:
type: string
description: Token JWT de rafraîchissement
user:
$ref: '#/components/schemas/User'
'401':
description: Identifiants invalides
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/users:
get:
summary: Liste des utilisateurs
operationId: listUsers
tags:
- Users
security:
- bearerAuth: []
parameters:
- name: role
in: query
schema:
$ref: '#/components/schemas/RoleType'
- name: statut
in: query
schema:
$ref: '#/components/schemas/StatutUtilisateurType'
responses:
'200':
description: Liste des utilisateurs
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/User'
'401':
description: Non authentifié
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
User:
type: object
required:
- id
- email
- role
- statut
properties:
id:
type: string
format: uuid
example: "550e8400-e29b-41d4-a716-446655440000"
email:
type: string
format: email
example: "parent@ptits-pas.fr"
prenom:
type: string
example: "Jean"
nom:
type: string
example: "Dupont"
role:
$ref: '#/components/schemas/RoleType'
statut:
$ref: '#/components/schemas/StatutUtilisateurType'
telephone:
type: string
example: "0612345678"
adresse:
type: string
photo_url:
type: string
format: uri
cree_le:
type: string
format: date-time
RoleType:
type: string
enum:
- parent
- assistante_maternelle
- gestionnaire
- administrateur
- super_admin
StatutUtilisateurType:
type: string
enum:
- en_attente
- actif
- suspendu
Error:
type: object
required:
- message
- statusCode
properties:
message:
type: string
example: "Identifiants invalides"
statusCode:
type: integer
example: 401
error:
type: string
example: "Unauthorized"
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: Token JWT obtenu via /auth/login