Merge master into develop - Synchronisation des branches
Fusion des travaux : - Backend complet (ConfigService, DocumentsLegaux, Auth, etc.) - Frontend étapes inscription 1-2 - Infrastructure Docker - Documentation technique Résolution des conflits : - Images déplacées vers frontend/assets/images/ - Dossier Archives supprimé - Backend : version master conservée - Frontend : améliorations UI de develop conservées
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
# 📚 Index de la Documentation - PtitsPas App
|
||||
|
||||
Bienvenue dans la documentation complète de l'application PtitsPas.
|
||||
|
||||
Ce fichier sert d'index pour naviguer dans toute la documentation du projet.
|
||||
|
||||
## 📖 Table des matières
|
||||
|
||||
### 📋 Cahier des Charges
|
||||
- [**01 - Cahier des Charges**](./01_CAHIER-DES-CHARGES.md) - Cahier des charges complet du projet P'titsPas (V1.3 - 24/11/2025)
|
||||
|
||||
### Architecture & Infrastructure
|
||||
- [**02 - Architecture**](./02_ARCHITECTURE.md) - Vue d'ensemble de l'architecture mono-repo et multi-conteneurs
|
||||
- [**03 - Déploiement**](./03_DEPLOYMENT.md) - Guide complet de déploiement et configuration CI/CD
|
||||
|
||||
### Planification
|
||||
- [**04 - Roadmap Générale**](./04_ROADMAP-GENERALE.md) - Roadmap complète du projet (Phases 1 à 5+)
|
||||
|
||||
### Développement
|
||||
- [**10 - Database Schema**](./10_DATABASE.md) - Schéma de la base de données et modèles
|
||||
- [**11 - API Documentation**](./11_API.md) - Documentation complète des endpoints REST
|
||||
|
||||
### Workflows Fonctionnels
|
||||
- [**20 - Workflow Création de Compte**](./20_WORKFLOW-CREATION-COMPTE.md) - Workflow complet de création et validation des comptes utilisateurs
|
||||
- [**21 - Configuration Système**](./21_CONFIGURATION-SYSTEME.md) - Configuration on-premise dynamique
|
||||
- [**22 - Documents Légaux**](./22_DOCUMENTS-LEGAUX.md) - Gestion CGU/Privacy avec versioning
|
||||
- [**23 - Liste des Tickets**](./23_LISTE-TICKETS.md) - 61 tickets Phase 1 détaillés
|
||||
- [**24 - Décisions Projet**](./24_DECISIONS-PROJET.md) - Décisions architecturales et fonctionnelles
|
||||
- [**25 - Backlog Phase 2**](./25_PHASE-2-BACKLOG.md) - Fonctionnalités techniques reportées
|
||||
|
||||
### Administration (À créer)
|
||||
- [**30 - Guide d'administration**](./30_ADMIN.md) - Gestion des utilisateurs, accès PgAdmin, logs
|
||||
- [**31 - Troubleshooting**](./31_TROUBLESHOOTING.md) - Résolution des problèmes courants
|
||||
|
||||
### Frontend (À créer)
|
||||
- [**40 - Frontend Flutter**](./40_FRONTEND.md) - Structure de l'application mobile/web
|
||||
|
||||
### Audit & Analyse
|
||||
- [**90 - Audit du projet YNOV**](./90_AUDIT.md) - Analyse complète du code étudiant et fonctionnalités
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
```bash
|
||||
# Cloner le projet
|
||||
git clone ssh://gitea-jmartin/jmartin/app.git ptitspas-app
|
||||
|
||||
# Lancer l'environnement de développement
|
||||
cd ptitspas-app
|
||||
docker compose up -d
|
||||
|
||||
# Accéder aux services
|
||||
Frontend: https://app.ptits-pas.fr
|
||||
API: https://app.ptits-pas.fr/api
|
||||
PgAdmin: https://app.ptits-pas.fr/pgadmin
|
||||
```
|
||||
|
||||
## 🔗 Liens utiles
|
||||
|
||||
- **Gitea** : https://git.ptits-pas.fr
|
||||
- **Production** : https://app.ptits-pas.fr
|
||||
- **Mail** : https://mail.ptits-pas.fr
|
||||
|
||||
## 📝 Maintenance
|
||||
|
||||
Cette documentation est maintenue par Julien Martin (julien.martin@ptits-pas.fr).
|
||||
|
||||
Dernière mise à jour : Novembre 2025
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,72 @@
|
||||
# 🏗️ Architecture du projet P'tits Pas
|
||||
|
||||
## 📁 Structure du projet
|
||||
|
||||
Ce projet est organisé en **3 dépôts Git distincts** :
|
||||
|
||||
- **`ptitspas-frontend`** : Application Flutter (interface utilisateur)
|
||||
- **`ptitspas-backend`** : API NestJS (serveur backend)
|
||||
- **`ptitspas-database`** : Configuration PostgreSQL et migrations
|
||||
|
||||
## 🌍 Deux environnements supportés
|
||||
|
||||
### 🚀 **Environnement de production (serveur)**
|
||||
- **Localisation** : `/home/ynov/project/` sur le serveur
|
||||
- **Configuration** : `docker-compose.yml` + `.env`
|
||||
- **Domaine** : `https://ynov.ptits-pas.fr`
|
||||
- **Reverse proxy** : Traefik avec SSL automatique
|
||||
- **Gestion** : Déploiement automatique via webhooks Gitea
|
||||
|
||||
### 💻 **Environnement de développement (local)**
|
||||
- **Configuration** : `docker-compose.dev.yml` + `.env.example` dans chaque dépôt
|
||||
- **Accès** : Ports locaux (3000, 8000, 8080, 5432)
|
||||
- **Hot reload** : Modifications de code prises en compte instantanément
|
||||
- **Base locale** : PostgreSQL indépendante avec PgAdmin
|
||||
|
||||
## 🏃♂️ Guide de démarrage développeur
|
||||
|
||||
### 1. **Backend** (à démarrer en premier)
|
||||
```bash
|
||||
git clone <url-backend>
|
||||
cd ptitspas-backend
|
||||
cp .env.example .env
|
||||
docker compose -f docker-compose.dev.yml up -d
|
||||
```
|
||||
**Accès** : http://localhost:3000/api
|
||||
|
||||
### 2. **Frontend**
|
||||
```bash
|
||||
git clone <url-frontend>
|
||||
cd ptitspas-frontend
|
||||
cp .env.example .env
|
||||
docker compose -f docker-compose.dev.yml up -d
|
||||
```
|
||||
**Accès** : http://localhost:8000
|
||||
|
||||
### 3. **PgAdmin** (inclus avec le backend)
|
||||
**Accès** : http://localhost:8080
|
||||
- Email : admin@localhost
|
||||
- Mot de passe : admin123
|
||||
|
||||
## 🔄 Workflow de développement
|
||||
|
||||
1. **Développer localement** avec les `docker-compose.dev.yml`
|
||||
2. **Tester les modifications** sur http://localhost:8000
|
||||
3. **Commiter et pousser** dans les dépôts respectifs
|
||||
4. **Déploiement automatique** sur le serveur via webhooks
|
||||
|
||||
## 🗂️ Fichiers de configuration
|
||||
|
||||
| Fichier | Usage | Localisation |
|
||||
|---------|-------|--------------|
|
||||
| `docker-compose.yml` | Production (serveur) | `/home/ynov/project/` |
|
||||
| `docker-compose.dev.yml` | Développement (local) | Chaque dépôt |
|
||||
| `.env` | Variables production | Serveur uniquement |
|
||||
| `.env.example` | Template développement | Chaque dépôt |
|
||||
|
||||
## 🔒 Sécurité
|
||||
|
||||
- ✅ Fichiers `.env` **non versionnés** (ajoutés au `.gitignore`)
|
||||
- ✅ Variables sensibles **externalisées**
|
||||
- ✅ Configurations **séparées** dev/prod
|
||||
- ✅ SSL automatique en production via Let's Encrypt
|
||||
@@ -0,0 +1,144 @@
|
||||
# 🚀 Déploiement YNOV - Architecture Complète
|
||||
|
||||
## 🌐 URLs d'accès
|
||||
|
||||
- **Application principale** : https://ynov.ptits-pas.fr/
|
||||
- **API Backend** : https://ynov.ptits-pas.fr/api/
|
||||
- **Administration DB** : https://ynov.ptits-pas.fr/pgadmin/
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ Frontend │ │ Backend │ │ Database │
|
||||
│ (Flutter) │───▶│ (NestJS) │───▶│ (PostgreSQL) │
|
||||
│ ynov-frontend │ │ ynov-backend │ │ ynov-postgres │
|
||||
│ Port: 80 │ │ Port: 3000 │ │ Port: 5432 │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│ │ │
|
||||
└───────────────────────┼───────────────────────┘
|
||||
│
|
||||
ynov_network (réseau interne)
|
||||
│
|
||||
proxy_network (Traefik)
|
||||
│
|
||||
Internet
|
||||
```
|
||||
|
||||
## 📁 Structure des fichiers
|
||||
|
||||
```
|
||||
/home/ynov/project/
|
||||
├── docker-compose.yml # Orchestration globale
|
||||
├── backend/
|
||||
│ ├── Dockerfile # Build NestJS
|
||||
│ ├── src/ # Code source
|
||||
│ └── package.json # Dépendances
|
||||
├── frontend/
|
||||
│ └── frontend/
|
||||
│ ├── Dockerfile # Build Flutter
|
||||
│ ├── pubspec.yaml # Config Flutter
|
||||
│ └── lib/ # Code source
|
||||
└── database/
|
||||
├── docker-compose.yml # Config spécifique DB
|
||||
└── migrations/ # Scripts SQL
|
||||
```
|
||||
|
||||
## 🔑 Credentials
|
||||
|
||||
### Base de données
|
||||
- **Host** : `ynov-postgres` (interne) ou `localhost:5433` (externe)
|
||||
- **User** : `admin`
|
||||
- **Password** : `admin123`
|
||||
- **Database** : `ptitpas_db`
|
||||
|
||||
### PgAdmin
|
||||
- **Email** : `admin@ynov.local`
|
||||
- **Password** : `admin123`
|
||||
|
||||
## 🚀 Commandes de déploiement
|
||||
|
||||
### Déploiement complet
|
||||
```bash
|
||||
cd /home/ynov/project
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
### Déploiement par service
|
||||
```bash
|
||||
# Base de données seulement
|
||||
docker compose up -d database pgadmin
|
||||
|
||||
# Backend seulement
|
||||
docker compose up -d --build backend
|
||||
|
||||
# Frontend seulement
|
||||
docker compose up -d --build frontend
|
||||
```
|
||||
|
||||
### Monitoring
|
||||
```bash
|
||||
# Voir les logs
|
||||
docker compose logs -f
|
||||
|
||||
# Statut des services
|
||||
docker compose ps
|
||||
|
||||
# Redémarrer un service
|
||||
docker compose restart backend
|
||||
```
|
||||
|
||||
## 🔧 Configuration réseau
|
||||
|
||||
### Réseaux Docker
|
||||
- **ynov_network** : Communication interne entre services
|
||||
- **proxy_network** : Exposition via Traefik
|
||||
|
||||
### Priorités Traefik
|
||||
- **Frontend** : Priority 10 (plus basse = défaut)
|
||||
- **Backend** : Priority 20
|
||||
- **PgAdmin** : Priority 30 (plus haute = prioritaire)
|
||||
|
||||
## 📝 Variables d'environnement
|
||||
|
||||
### Backend
|
||||
- `DATABASE_URL` : Connexion PostgreSQL
|
||||
- `NODE_ENV` : Mode production
|
||||
|
||||
### Frontend
|
||||
- `API_URL` : URL de l'API backend
|
||||
|
||||
## 🔄 Webhooks de déploiement
|
||||
|
||||
### Repository Frontend
|
||||
- **Trigger** : Push sur `main`
|
||||
- **Action** : `docker compose up -d --build frontend`
|
||||
|
||||
### Repository Backend
|
||||
- **Trigger** : Push sur `main`
|
||||
- **Action** : `docker compose up -d --build backend`
|
||||
|
||||
### Repository Database
|
||||
- **Trigger** : Push sur `main`
|
||||
- **Action** : `docker compose up -d --build database`
|
||||
|
||||
## 🛠️ Dépannage
|
||||
|
||||
### Logs par service
|
||||
```bash
|
||||
docker compose logs frontend
|
||||
docker compose logs backend
|
||||
docker compose logs database
|
||||
```
|
||||
|
||||
### Rebuild complet
|
||||
```bash
|
||||
docker compose down
|
||||
docker compose up -d --build --force-recreate
|
||||
```
|
||||
|
||||
### Vérifier la connectivité réseau
|
||||
```bash
|
||||
docker network ls
|
||||
docker network inspect project_ynov_network
|
||||
```
|
||||
@@ -0,0 +1,330 @@
|
||||
# 🗺️ Roadmap Générale - Projet P'titsPas
|
||||
|
||||
**Version** : 1.0
|
||||
**Date** : 28 Novembre 2025
|
||||
**Auteur** : Équipe PtitsPas
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Avertissement
|
||||
|
||||
Les **Phases 2, 3, 4+** sont des **ébauches indicatives** qui seront affinées au fur et à mesure du développement et des retours utilisateurs. Certaines fonctionnalités mentionnées (comme la facturation) ne seront peut-être pas développées ou seront remplacées par d'autres priorités.
|
||||
|
||||
**Seule la Phase 1 est détaillée et validée.**
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Vue d'ensemble
|
||||
|
||||
| Phase | Focus | Estimation | Statut |
|
||||
|-------|-------|------------|--------|
|
||||
| **Phase 1** | Comptes & Auth | ~173h | ✅ Détaillée (61 tickets) |
|
||||
| **Phase 2** | Recherche & Contact | ~100h | 📋 Ébauche |
|
||||
| **Phase 3** | Contrats & Planning | ~120h | 📋 Ébauche |
|
||||
| **Phase 4** | Suivi & Avancé | ~140h+ | 📋 Ébauche |
|
||||
| **Phase 5+** | Optimisations | ~200h+ | 📋 Ébauche |
|
||||
| **TOTAL** | | **~733h+** | |
|
||||
|
||||
---
|
||||
|
||||
## 📦 Phase 1 (v1.0.0) - 🔐 Création de comptes & Authentification
|
||||
|
||||
**Objectif** : MVP fonctionnel avec gestion des utilisateurs
|
||||
|
||||
### Fonctionnalités
|
||||
|
||||
- ✅ Configuration système (on-premise)
|
||||
- ✅ Authentification & Sécurité
|
||||
- ✅ Inscription Parents (workflow 6 étapes)
|
||||
- ✅ Inscription Assistantes Maternelles (workflow 5 panneaux)
|
||||
- ✅ Validation par Gestionnaires (dashboard 2 onglets)
|
||||
- ✅ Documents légaux (CGU/Privacy avec versioning)
|
||||
- ✅ Upload photos (enfants, AM)
|
||||
- ✅ Notifications email (validation, refus, création MDP)
|
||||
- ✅ Logging & Monitoring
|
||||
- ✅ Tests & Documentation
|
||||
|
||||
### Versions incrémentales
|
||||
|
||||
| Version | Objectif | Tickets | Estimation |
|
||||
|---------|----------|---------|------------|
|
||||
| **0.1.0** | MVP Fonctionnel | ~21 | ~45h |
|
||||
| **0.2.0** | Sécurité & RGPD | ~10 | ~35h |
|
||||
| **0.3.0** | Interfaces Complètes | ~17 | ~52h |
|
||||
| **0.4.0** | Tests & Documentation | ~6 | ~24h |
|
||||
| **0.5.0** | Monitoring & Optimisations | ~7 | ~17h |
|
||||
| **1.0.0** | 🎉 **Release Phase 1** | **61** | **~173h** |
|
||||
|
||||
### Livrable
|
||||
|
||||
Application installable avec création et validation de comptes utilisateurs.
|
||||
|
||||
**Référence** : [23_LISTE-TICKETS.md](./23_LISTE-TICKETS.md)
|
||||
|
||||
---
|
||||
|
||||
## 📦 Phase 2 (v2.0.0) - 🤝 Mise en relation & Communication
|
||||
|
||||
**Objectif** : Permettre aux parents de trouver et contacter des assistantes maternelles
|
||||
|
||||
### Fonctionnalités (ébauche)
|
||||
|
||||
- 🔍 **Recherche d'AM**
|
||||
- Recherche par critères (ville, capacité, disponibilité, tarifs)
|
||||
- Filtres avancés
|
||||
- Géolocalisation (optionnel)
|
||||
|
||||
- 👤 **Profils détaillés AM**
|
||||
- Présentation complète
|
||||
- Photos du lieu de garde
|
||||
- Expérience et qualifications
|
||||
- Avis/Témoignages (optionnel)
|
||||
|
||||
- 💬 **Messagerie interne**
|
||||
- Conversations sécurisées Parent ↔ AM
|
||||
- Pièces jointes
|
||||
- Historique des échanges
|
||||
|
||||
- 📨 **Demandes de contact**
|
||||
- Workflow de demande Parent → AM
|
||||
- Validation/Refus par AM
|
||||
- Notifications
|
||||
|
||||
- ⭐ **Favoris/Shortlist**
|
||||
- AM sauvegardées par parents
|
||||
- Comparaison de profils
|
||||
|
||||
### Estimation
|
||||
|
||||
~100h (à affiner)
|
||||
|
||||
### Livrable
|
||||
|
||||
Parents peuvent trouver, consulter et contacter des assistantes maternelles.
|
||||
|
||||
---
|
||||
|
||||
## 📦 Phase 3 (v3.0.0) - 📄 Contrats & Planning
|
||||
|
||||
**Objectif** : Formaliser les gardes et gérer les plannings
|
||||
|
||||
### Fonctionnalités (ébauche)
|
||||
|
||||
- 📄 **Gestion des contrats**
|
||||
- Création contrats (modèle type personnalisable)
|
||||
- Signature électronique ou validation
|
||||
- Stockage documents contractuels (PDF)
|
||||
- Historique des contrats
|
||||
- Renouvellement/Modification
|
||||
|
||||
- 📅 **Planning & Disponibilités**
|
||||
- Calendrier AM (disponibilités, absences, congés)
|
||||
- Réservations/Demandes de garde
|
||||
- Validation/Refus par AM
|
||||
- Vue planning Parent (enfants gardés)
|
||||
- Alertes conflits de planning
|
||||
- Export calendrier (iCal)
|
||||
|
||||
### Estimation
|
||||
|
||||
~120h (à affiner)
|
||||
|
||||
### Livrable
|
||||
|
||||
Contrats formalisés + Planning opérationnel pour gérer les gardes.
|
||||
|
||||
---
|
||||
|
||||
## 📦 Phase 4 (v4.0.0) - 📊 Suivi & Fonctionnalités avancées
|
||||
|
||||
**Objectif** : Suivi quotidien des enfants et fonctionnalités complémentaires
|
||||
|
||||
### Fonctionnalités (ébauche)
|
||||
|
||||
- 📔 **Suivi des Enfants (Carnet de liaison numérique)**
|
||||
- Activités quotidiennes (repas, sieste, jeux)
|
||||
- Photos/Vidéos sécurisées (partage Parent ↔ AM)
|
||||
- Notes/Observations
|
||||
- Suivi médical (médicaments, allergies, vaccins)
|
||||
- Historique complet par enfant
|
||||
- Export PDF (bilan mensuel)
|
||||
|
||||
- 🎯 **Autres fonctionnalités à définir**
|
||||
- ⚠️ **Pas de facturation** (décision validée)
|
||||
- Fonctionnalités à déterminer selon retours utilisateurs Phase 2 et 3
|
||||
|
||||
### Estimation
|
||||
|
||||
~140h+ (à affiner)
|
||||
|
||||
### Livrable
|
||||
|
||||
Suivi quotidien des enfants + Fonctionnalités complémentaires.
|
||||
|
||||
---
|
||||
|
||||
## 📦 Phase 5+ (v5.0.0+) - 🚀 Optimisations & Améliorations
|
||||
|
||||
**Objectif** : Optimisations, monitoring, et fonctionnalités premium
|
||||
|
||||
### Fonctionnalités (ébauche)
|
||||
|
||||
#### 📊 Statistiques & Reporting
|
||||
- Dashboard gestionnaire (stats inscriptions, validations)
|
||||
- Rapports collectivité (CSV/PDF)
|
||||
- Graphiques évolution
|
||||
- Tableaux de bord personnalisés
|
||||
|
||||
#### 🔒 RGPD avancé
|
||||
- Droit à l'oubli (suppression compte)
|
||||
- Export données personnelles (portabilité)
|
||||
- Anonymisation automatique comptes inactifs
|
||||
- Audit trail complet
|
||||
|
||||
#### 📈 Monitoring & Infrastructure
|
||||
- Métriques système (CPU, RAM, BDD)
|
||||
- Dashboard monitoring admin
|
||||
- Sauvegarde automatique BDD (cron)
|
||||
- Procédures de restauration
|
||||
- Alertes automatiques
|
||||
|
||||
#### 📚 Documentation & Formation
|
||||
- Guides utilisateur (Gestionnaire, Parent, AM)
|
||||
- Vidéos tutoriels
|
||||
- FAQ interactive
|
||||
- Base de connaissances
|
||||
|
||||
#### 🎨 Améliorations UX
|
||||
- Mode sombre
|
||||
- Notifications push (PWA)
|
||||
- Accessibilité (WCAG 2.1)
|
||||
- Multi-langue (i18n)
|
||||
- Responsive avancé
|
||||
|
||||
#### 🌟 Fonctionnalités Premium (optionnel)
|
||||
- Géolocalisation AM (carte interactive)
|
||||
- Système d'avis/notation
|
||||
- Badges/Certifications AM
|
||||
- Intégrations tierces (CAF, etc.)
|
||||
- Application mobile native
|
||||
|
||||
### Estimation
|
||||
|
||||
~200h+ (à affiner)
|
||||
|
||||
### Livrable
|
||||
|
||||
Application mature, optimisée et riche en fonctionnalités.
|
||||
|
||||
**Référence** : [25_PHASE-2-BACKLOG.md](./25_PHASE-2-BACKLOG.md) (anciennes fonctionnalités techniques)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Logique de progression
|
||||
|
||||
```
|
||||
Phase 1 : "Je peux créer un compte"
|
||||
↓
|
||||
Phase 2 : "Je peux trouver et contacter une AM"
|
||||
↓
|
||||
Phase 3 : "Je peux signer un contrat et gérer le planning"
|
||||
↓
|
||||
Phase 4 : "Je peux suivre mon enfant au quotidien"
|
||||
↓
|
||||
Phase 5+ : "L'application est optimisée et riche en fonctionnalités"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔢 Schéma de versioning
|
||||
|
||||
```
|
||||
X.Y.Z
|
||||
|
||||
X = Phase majeure (0 = dev Phase 1, 1 = Phase 1 livrée, 2 = Phase 2 livrée, etc.)
|
||||
Y = Version incrémentale dans la phase (0.1, 0.2, 0.3... → 1.0)
|
||||
Z = Patch/Hotfix (0 par défaut, incrémenté pour corrections)
|
||||
|
||||
Exemples :
|
||||
- 0.1.0 → Phase 1 en dev, Version 1 (MVP)
|
||||
- 0.1.1 → Phase 1 en dev, Version 1, Patch 1 (correction bug)
|
||||
- 0.2.0 → Phase 1 en dev, Version 2 (Sécurité)
|
||||
- 1.0.0 → Livraison finale Phase 1
|
||||
- 1.0.1 → Patch Phase 1
|
||||
- 2.0.0 → Livraison finale Phase 2
|
||||
- 3.0.0 → Livraison finale Phase 3
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📅 Critères de passage entre phases
|
||||
|
||||
### Phase 1 → Phase 2
|
||||
- ✅ Phase 1 terminée (61 tickets)
|
||||
- ✅ Application déployée en production (au moins 1 collectivité)
|
||||
- ✅ Utilisateurs réels (au moins 10 comptes validés)
|
||||
- ✅ Feedback terrain collecté
|
||||
- ✅ Bugs critiques corrigés
|
||||
|
||||
### Phase 2 → Phase 3
|
||||
- ✅ Phase 2 terminée
|
||||
- ✅ Recherche et messagerie utilisées activement
|
||||
- ✅ Au moins 5 mises en relation réussies
|
||||
- ✅ Feedback utilisateurs positif
|
||||
- ✅ Besoin de formalisation des contrats exprimé
|
||||
|
||||
### Phase 3 → Phase 4
|
||||
- ✅ Phase 3 terminée
|
||||
- ✅ Contrats et planning utilisés activement
|
||||
- ✅ Au moins 10 contrats signés
|
||||
- ✅ Feedback utilisateurs positif
|
||||
- ✅ Besoin de suivi quotidien exprimé
|
||||
|
||||
### Phase 4 → Phase 5+
|
||||
- ✅ Phase 4 terminée
|
||||
- ✅ Application stable en production
|
||||
- ✅ Base utilisateurs significative (50+ comptes actifs)
|
||||
- ✅ Demandes d'optimisations et fonctionnalités avancées
|
||||
|
||||
---
|
||||
|
||||
## 📝 Notes importantes
|
||||
|
||||
1. **Flexibilité** : Cette roadmap est indicative et sera ajustée en fonction :
|
||||
- Des retours utilisateurs
|
||||
- Des priorités des collectivités
|
||||
- Des contraintes techniques découvertes
|
||||
- Des évolutions réglementaires
|
||||
|
||||
2. **Priorisation** : Les fonctionnalités de chaque phase peuvent être réorganisées selon :
|
||||
- L'urgence métier
|
||||
- La valeur ajoutée
|
||||
- La complexité technique
|
||||
- Les dépendances
|
||||
|
||||
3. **Décisions actées** :
|
||||
- ❌ Pas de facturation automatique (gestion externe)
|
||||
- ❌ Pas de SMS (email uniquement)
|
||||
- ✅ Application on-premise (auto-hébergée)
|
||||
- ✅ Configuration dynamique (pas de hardcoding)
|
||||
|
||||
4. **Documentation** : Chaque phase aura sa propre documentation détaillée avant démarrage.
|
||||
|
||||
---
|
||||
|
||||
## 📚 Documents de référence
|
||||
|
||||
- [00_INDEX.md](./00_INDEX.md) - Index général de la documentation
|
||||
- [01_CAHIER-DES-CHARGES.md](./01_CAHIER-DES-CHARGES.md) - Cahier des charges v1.3
|
||||
- [20_WORKFLOW-CREATION-COMPTE.md](./20_WORKFLOW-CREATION-COMPTE.md) - Workflow création de comptes
|
||||
- [23_LISTE-TICKETS.md](./23_LISTE-TICKETS.md) - Liste des 61 tickets Phase 1
|
||||
- [24_DECISIONS-PROJET.md](./24_DECISIONS-PROJET.md) - Décisions architecturales
|
||||
- [25_PHASE-2-BACKLOG.md](./25_PHASE-2-BACKLOG.md) - Anciennes fonctionnalités techniques
|
||||
|
||||
---
|
||||
|
||||
**Dernière mise à jour** : 28 Novembre 2025
|
||||
**Version** : 1.0
|
||||
**Statut** : 📋 Roadmap indicative - Phase 1 détaillée et validée
|
||||
|
||||
|
||||
@@ -0,0 +1,421 @@
|
||||
# 🗄️ Documentation Base de Données
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
L'application PtitsPas utilise **PostgreSQL 14** avec l'extension **pgcrypto** pour la gestion des UUID.
|
||||
|
||||
**Nom de la base** : `ptitpas_db`
|
||||
**Port** : `5432`
|
||||
**Conteneur Docker** : `ptitspas-postgres`
|
||||
|
||||
## Schéma de la base de données
|
||||
|
||||
### Types ENUM
|
||||
|
||||
La base de données utilise plusieurs types énumérés PostgreSQL :
|
||||
|
||||
| Type ENUM | Valeurs possibles | Usage |
|
||||
|-----------|------------------|-------|
|
||||
| `role_type` | `parent`, `gestionnaire`, `super_admin`, `assistante_maternelle`, `administrateur` | Rôles des utilisateurs |
|
||||
| `genre_type` | `H`, `F`, `Autre` | Genre des utilisateurs et enfants |
|
||||
| `statut_utilisateur_type` | `en_attente`, `actif`, `suspendu` | Statut du compte utilisateur |
|
||||
| `statut_enfant_type` | `a_naitre`, `actif`, `scolarise` | Statut de l'enfant |
|
||||
| `statut_dossier_type` | `envoye`, `accepte`, `refuse` | Statut de la candidature |
|
||||
| `statut_contrat_type` | `brouillon`, `en_attente_signature`, `valide`, `resilie` | Statut du contrat |
|
||||
| `statut_avenant_type` | `propose`, `accepte`, `refuse` | Statut des avenants au contrat |
|
||||
| `type_evenement_type` | `absence_enfant`, `conge_am`, `conge_parent`, `arret_maladie_am`, `evenement_rpe` | Type d'événement |
|
||||
| `statut_evenement_type` | `propose`, `valide`, `refuse` | Statut de l'événement |
|
||||
| `statut_validation_type` | `en_attente`, `valide`, `refuse` | Statut de validation générique |
|
||||
|
||||
---
|
||||
|
||||
## Tables
|
||||
|
||||
### 1. `utilisateurs`
|
||||
|
||||
Table centrale pour tous les types d'utilisateurs.
|
||||
|
||||
| Colonne | Type | Contraintes | Description |
|
||||
|---------|------|-------------|-------------|
|
||||
| `id` | UUID | PRIMARY KEY | Identifiant unique |
|
||||
| `email` | VARCHAR(255) | NOT NULL, UNIQUE | Email (avec validation regex) |
|
||||
| `password` | TEXT | NOT NULL | Mot de passe hashé (bcrypt) |
|
||||
| `prenom` | VARCHAR(100) | | Prénom |
|
||||
| `nom` | VARCHAR(100) | | Nom de famille |
|
||||
| `genre` | genre_type | | Genre de l'utilisateur |
|
||||
| `role` | role_type | NOT NULL | Rôle de l'utilisateur |
|
||||
| `statut` | statut_utilisateur_type | DEFAULT 'en_attente' | Statut du compte |
|
||||
| `telephone` | VARCHAR(20) | | Téléphone principal |
|
||||
| `adresse` | TEXT | | Adresse complète |
|
||||
| `photo_url` | TEXT | | URL de la photo de profil |
|
||||
| `consentement_photo` | BOOLEAN | DEFAULT false | Consentement photo |
|
||||
| `date_consentement_photo` | TIMESTAMPTZ | | Date du consentement |
|
||||
| `changement_mdp_obligatoire` | BOOLEAN | DEFAULT false | Force changement de MDP |
|
||||
| `cree_le` | TIMESTAMPTZ | DEFAULT now() | Date de création |
|
||||
| `modifie_le` | TIMESTAMPTZ | DEFAULT now() | Dernière modification |
|
||||
| `ville` | VARCHAR(150) | | Ville |
|
||||
| `code_postal` | VARCHAR(10) | | Code postal |
|
||||
| `mobile` | VARCHAR(20) | | Téléphone mobile |
|
||||
| `telephone_fixe` | VARCHAR(20) | | Téléphone fixe |
|
||||
| `profession` | VARCHAR(150) | | Profession |
|
||||
| `situation_familiale` | VARCHAR(50) | | Situation familiale |
|
||||
| `date_naissance` | DATE | | Date de naissance |
|
||||
|
||||
**Contraintes** :
|
||||
- Email validé par regex : `^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$`
|
||||
|
||||
---
|
||||
|
||||
### 2. `assistantes_maternelles`
|
||||
|
||||
Extension de la table `utilisateurs` pour les assistantes maternelles.
|
||||
|
||||
| Colonne | Type | Contraintes | Description |
|
||||
|---------|------|-------------|-------------|
|
||||
| `id_utilisateur` | UUID | PRIMARY KEY, FK → utilisateurs(id) | Référence à l'utilisateur |
|
||||
| `numero_agrement` | VARCHAR(50) | | Numéro d'agrément |
|
||||
| `nir_chiffre` | CHAR(15) | | NIR (Sécurité sociale) |
|
||||
| `nb_max_enfants` | INT | | Capacité maximale d'accueil |
|
||||
| `biographie` | TEXT | | Présentation |
|
||||
| `disponible` | BOOLEAN | DEFAULT true | Disponibilité |
|
||||
| `ville_residence` | VARCHAR(100) | | Ville de résidence |
|
||||
| `date_agrement` | DATE | | Date d'obtention de l'agrément |
|
||||
| `annee_experience` | SMALLINT | | Années d'expérience |
|
||||
| `specialite` | VARCHAR(100) | | Spécialités |
|
||||
| `place_disponible` | INT | | Nombre de places disponibles |
|
||||
|
||||
**Cascade** : `ON DELETE CASCADE` (suppression si utilisateur supprimé)
|
||||
|
||||
---
|
||||
|
||||
### 3. `parents`
|
||||
|
||||
Extension de la table `utilisateurs` pour les parents.
|
||||
|
||||
| Colonne | Type | Contraintes | Description |
|
||||
|---------|------|-------------|-------------|
|
||||
| `id_utilisateur` | UUID | PRIMARY KEY, FK → utilisateurs(id) | Référence à l'utilisateur |
|
||||
| `id_co_parent` | UUID | FK → utilisateurs(id) | Référence au co-parent (optionnel) |
|
||||
|
||||
**Cascade** : `ON DELETE CASCADE`
|
||||
|
||||
---
|
||||
|
||||
### 4. `enfants`
|
||||
|
||||
Table des enfants pris en charge.
|
||||
|
||||
| Colonne | Type | Contraintes | Description |
|
||||
|---------|------|-------------|-------------|
|
||||
| `id` | UUID | PRIMARY KEY | Identifiant unique |
|
||||
| `statut` | statut_enfant_type | | Statut de l'enfant |
|
||||
| `prenom` | VARCHAR(100) | | Prénom |
|
||||
| `nom` | VARCHAR(100) | | Nom |
|
||||
| `genre` | genre_type | | Genre |
|
||||
| `date_naissance` | DATE | | Date de naissance |
|
||||
| `date_prevue_naissance` | DATE | | Date prévue (si à naître) |
|
||||
| `photo_url` | TEXT | | URL de la photo |
|
||||
| `consentement_photo` | BOOLEAN | DEFAULT false | Consentement photo |
|
||||
| `date_consentement_photo` | TIMESTAMPTZ | | Date du consentement |
|
||||
| `est_multiple` | BOOLEAN | DEFAULT false | Indique si grossesse multiple |
|
||||
|
||||
---
|
||||
|
||||
### 5. `enfants_parents`
|
||||
|
||||
Table de liaison entre enfants et parents (relation N:N).
|
||||
|
||||
| Colonne | Type | Contraintes | Description |
|
||||
|---------|------|-------------|-------------|
|
||||
| `id_parent` | UUID | FK → parents(id_utilisateur) | Référence au parent |
|
||||
| `id_enfant` | UUID | FK → enfants(id) | Référence à l'enfant |
|
||||
|
||||
**Clé primaire composite** : `(id_parent, id_enfant)`
|
||||
**Cascade** : `ON DELETE CASCADE`
|
||||
|
||||
---
|
||||
|
||||
### 6. `dossiers`
|
||||
|
||||
Dossiers de candidature des parents pour une assistante maternelle.
|
||||
|
||||
| Colonne | Type | Contraintes | Description |
|
||||
|---------|------|-------------|-------------|
|
||||
| `id` | UUID | PRIMARY KEY | Identifiant unique |
|
||||
| `id_parent` | UUID | FK → parents(id_utilisateur) | Parent demandeur |
|
||||
| `id_enfant` | UUID | FK → enfants(id) | Enfant concerné |
|
||||
| `presentation` | TEXT | | Présentation de la demande |
|
||||
| `type_contrat` | VARCHAR(50) | | Type de contrat souhaité |
|
||||
| `repas` | BOOLEAN | DEFAULT false | Demande de repas |
|
||||
| `budget` | NUMERIC(10,2) | | Budget disponible |
|
||||
| `planning_souhaite` | JSONB | | Planning souhaité (format JSON) |
|
||||
| `statut` | statut_dossier_type | DEFAULT 'envoye' | Statut du dossier |
|
||||
| `cree_le` | TIMESTAMPTZ | DEFAULT now() | Date de création |
|
||||
| `modifie_le` | TIMESTAMPTZ | DEFAULT now() | Dernière modification |
|
||||
|
||||
**Cascade** : `ON DELETE CASCADE`
|
||||
|
||||
---
|
||||
|
||||
### 7. `messages`
|
||||
|
||||
Messages échangés dans le cadre d'un dossier.
|
||||
|
||||
| Colonne | Type | Contraintes | Description |
|
||||
|---------|------|-------------|-------------|
|
||||
| `id` | UUID | PRIMARY KEY | Identifiant unique |
|
||||
| `id_dossier` | UUID | FK → dossiers(id) | Dossier lié |
|
||||
| `id_expediteur` | UUID | FK → utilisateurs(id) | Expéditeur |
|
||||
| `contenu` | TEXT | | Contenu du message |
|
||||
| `re_redige_par_ia` | BOOLEAN | DEFAULT false | Message réécrit par IA |
|
||||
| `cree_le` | TIMESTAMPTZ | DEFAULT now() | Date d'envoi |
|
||||
|
||||
**Cascade** : `ON DELETE CASCADE`
|
||||
|
||||
---
|
||||
|
||||
### 8. `contrats`
|
||||
|
||||
Contrats conclus entre parents et assistantes maternelles.
|
||||
|
||||
| Colonne | Type | Contraintes | Description |
|
||||
|---------|------|-------------|-------------|
|
||||
| `id` | UUID | PRIMARY KEY | Identifiant unique |
|
||||
| `id_dossier` | UUID | UNIQUE, FK → dossiers(id) | Dossier source (1:1) |
|
||||
| `planning` | JSONB | | Planning défini (format JSON) |
|
||||
| `tarif_horaire` | NUMERIC(6,2) | | Tarif horaire |
|
||||
| `indemnites_repas` | NUMERIC(6,2) | | Indemnités repas |
|
||||
| `date_debut` | DATE | | Date de début du contrat |
|
||||
| `statut` | statut_contrat_type | DEFAULT 'brouillon' | Statut du contrat |
|
||||
| `signe_parent` | BOOLEAN | DEFAULT false | Signature parent |
|
||||
| `signe_am` | BOOLEAN | DEFAULT false | Signature assistante maternelle |
|
||||
| `finalise_le` | TIMESTAMPTZ | | Date de finalisation |
|
||||
| `cree_le` | TIMESTAMPTZ | DEFAULT now() | Date de création |
|
||||
| `modifie_le` | TIMESTAMPTZ | DEFAULT now() | Dernière modification |
|
||||
|
||||
**Cascade** : `ON DELETE CASCADE`
|
||||
|
||||
---
|
||||
|
||||
### 9. `avenants_contrats`
|
||||
|
||||
Modifications apportées aux contrats existants.
|
||||
|
||||
| Colonne | Type | Contraintes | Description |
|
||||
|---------|------|-------------|-------------|
|
||||
| `id` | UUID | PRIMARY KEY | Identifiant unique |
|
||||
| `id_contrat` | UUID | FK → contrats(id) | Contrat modifié |
|
||||
| `modifications` | JSONB | | Détails des modifications (JSON) |
|
||||
| `initie_par` | UUID | FK → utilisateurs(id) | Utilisateur initiateur |
|
||||
| `statut` | statut_avenant_type | DEFAULT 'propose' | Statut de l'avenant |
|
||||
| `cree_le` | TIMESTAMPTZ | DEFAULT now() | Date de création |
|
||||
| `modifie_le` | TIMESTAMPTZ | DEFAULT now() | Dernière modification |
|
||||
|
||||
**Cascade** : `ON DELETE CASCADE`
|
||||
|
||||
---
|
||||
|
||||
### 10. `evenements`
|
||||
|
||||
Événements liés au planning (absences, congés, etc.).
|
||||
|
||||
| Colonne | Type | Contraintes | Description |
|
||||
|---------|------|-------------|-------------|
|
||||
| `id` | UUID | PRIMARY KEY | Identifiant unique |
|
||||
| `type` | type_evenement_type | | Type d'événement |
|
||||
| `id_enfant` | UUID | FK → enfants(id) | Enfant concerné |
|
||||
| `id_am` | UUID | FK → utilisateurs(id) | Assistante maternelle |
|
||||
| `id_parent` | UUID | FK → parents(id_utilisateur) | Parent |
|
||||
| `cree_par` | UUID | FK → utilisateurs(id) | Créateur de l'événement |
|
||||
| `date_debut` | TIMESTAMPTZ | | Date de début |
|
||||
| `date_fin` | TIMESTAMPTZ | | Date de fin |
|
||||
| `commentaires` | TEXT | | Commentaires |
|
||||
| `statut` | statut_evenement_type | DEFAULT 'propose' | Statut de l'événement |
|
||||
| `delai_grace` | TIMESTAMPTZ | | Délai de grâce |
|
||||
| `urgent` | BOOLEAN | DEFAULT false | Événement urgent |
|
||||
| `cree_le` | TIMESTAMPTZ | DEFAULT now() | Date de création |
|
||||
| `modifie_le` | TIMESTAMPTZ | DEFAULT now() | Dernière modification |
|
||||
|
||||
**Cascade** : `ON DELETE CASCADE`
|
||||
|
||||
---
|
||||
|
||||
### 11. `signalements_bugs`
|
||||
|
||||
Signalements de bugs par les utilisateurs.
|
||||
|
||||
| Colonne | Type | Contraintes | Description |
|
||||
|---------|------|-------------|-------------|
|
||||
| `id` | UUID | PRIMARY KEY | Identifiant unique |
|
||||
| `id_utilisateur` | UUID | FK → utilisateurs(id) | Utilisateur signalant |
|
||||
| `description` | TEXT | | Description du bug |
|
||||
| `cree_le` | TIMESTAMPTZ | DEFAULT now() | Date du signalement |
|
||||
|
||||
---
|
||||
|
||||
### 12. `uploads`
|
||||
|
||||
Fichiers téléversés par les utilisateurs.
|
||||
|
||||
| Colonne | Type | Contraintes | Description |
|
||||
|---------|------|-------------|-------------|
|
||||
| `id` | UUID | PRIMARY KEY | Identifiant unique |
|
||||
| `id_utilisateur` | UUID | FK → utilisateurs(id), ON DELETE SET NULL | Utilisateur |
|
||||
| `fichier_url` | TEXT | NOT NULL | URL du fichier |
|
||||
| `type` | VARCHAR(50) | | Type de fichier |
|
||||
| `cree_le` | TIMESTAMPTZ | DEFAULT now() | Date d'upload |
|
||||
|
||||
---
|
||||
|
||||
### 13. `notifications`
|
||||
|
||||
Notifications envoyées aux utilisateurs.
|
||||
|
||||
| Colonne | Type | Contraintes | Description |
|
||||
|---------|------|-------------|-------------|
|
||||
| `id` | UUID | PRIMARY KEY | Identifiant unique |
|
||||
| `id_utilisateur` | UUID | FK → utilisateurs(id) | Destinataire |
|
||||
| `contenu` | TEXT | | Contenu de la notification |
|
||||
| `lu` | BOOLEAN | DEFAULT false | Statut de lecture |
|
||||
| `cree_le` | TIMESTAMPTZ | DEFAULT now() | Date de création |
|
||||
|
||||
**Cascade** : `ON DELETE CASCADE`
|
||||
|
||||
---
|
||||
|
||||
### 14. `validations`
|
||||
|
||||
Validations génériques de données utilisateur.
|
||||
|
||||
| Colonne | Type | Contraintes | Description |
|
||||
|---------|------|-------------|-------------|
|
||||
| `id` | UUID | PRIMARY KEY | Identifiant unique |
|
||||
| `id_utilisateur` | UUID | FK → utilisateurs(id) | Utilisateur à valider |
|
||||
| `type` | VARCHAR(50) | | Type de validation |
|
||||
| `statut` | statut_validation_type | DEFAULT 'en_attente' | Statut |
|
||||
| `cree_le` | TIMESTAMPTZ | DEFAULT now() | Date de demande |
|
||||
| `modifie_le` | TIMESTAMPTZ | DEFAULT now() | Dernière modification |
|
||||
| `valide_par` | UUID | FK → utilisateurs(id) | Validateur |
|
||||
| `commentaire` | TEXT | | Commentaire du validateur |
|
||||
|
||||
---
|
||||
|
||||
## Relations principales
|
||||
|
||||
```
|
||||
utilisateurs (1) ──┬──> (1) assistantes_maternelles
|
||||
├──> (1) parents
|
||||
└──> (N) messages
|
||||
|
||||
parents (1) ───> (N) enfants_parents <─── (N) enfants
|
||||
|
||||
parents (1) ───> (N) dossiers <─── (1) enfants
|
||||
dossiers (1) ───> (N) messages
|
||||
dossiers (1) ───> (1) contrats
|
||||
contrats (1) ───> (N) avenants_contrats
|
||||
|
||||
enfants (1) ───> (N) evenements
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Données initiales (SEED)
|
||||
|
||||
### Super Administrateur par défaut
|
||||
|
||||
**Email** : `admin@ptits-pas.fr`
|
||||
**Mot de passe** : `4dm1n1strateur`
|
||||
**Rôle** : `super_admin`
|
||||
**Statut** : `actif`
|
||||
|
||||
> ⚠️ **Sécurité** : Le mot de passe est hashé avec bcrypt (`$2b$12$...`).
|
||||
> Il est **impératif** de changer ce mot de passe en production.
|
||||
|
||||
---
|
||||
|
||||
## Migrations
|
||||
|
||||
Les migrations sont gérées manuellement via le fichier SQL :
|
||||
|
||||
**Fichier** : `/database/migrations/01_init.sql`
|
||||
|
||||
### Appliquer les migrations
|
||||
|
||||
```bash
|
||||
# Depuis le conteneur backend
|
||||
npx prisma migrate deploy
|
||||
|
||||
# Ou manuellement depuis psql
|
||||
psql -U admin -d ptitpas_db -f /database/migrations/01_init.sql
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Accès à la base de données
|
||||
|
||||
### Via PgAdmin
|
||||
|
||||
**URL** : `https://app.ptits-pas.fr/pgadmin`
|
||||
**Email** : `admin@ptits-pas.fr`
|
||||
**Mot de passe** : `admin123`
|
||||
|
||||
**Configuration serveur** :
|
||||
- Host : `ptitspas-postgres`
|
||||
- Port : `5432`
|
||||
- Database : `ptitpas_db`
|
||||
- Username : `admin`
|
||||
- Password : `admin123`
|
||||
|
||||
### Via terminal (Docker)
|
||||
|
||||
```bash
|
||||
# Connexion au conteneur PostgreSQL
|
||||
docker exec -it ptitspas-postgres psql -U admin -d ptitpas_db
|
||||
|
||||
# Lister les tables
|
||||
\dt
|
||||
|
||||
# Voir le schéma d'une table
|
||||
\d utilisateurs
|
||||
|
||||
# Quitter
|
||||
\q
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Recommandations de sécurité
|
||||
|
||||
1. ✅ **Mots de passe hashés** avec bcrypt
|
||||
2. ✅ **Validation email** via regex
|
||||
3. ⚠️ **Changer les credentials par défaut en production**
|
||||
4. ⚠️ **Créer un utilisateur read-only pour les analytics**
|
||||
5. ⚠️ **Activer SSL/TLS pour les connexions PostgreSQL**
|
||||
6. ✅ **Utiliser des UUID** plutôt que des identifiants séquentiels
|
||||
|
||||
---
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Backup de la base
|
||||
|
||||
```bash
|
||||
docker exec ptitspas-postgres pg_dump -U admin ptitpas_db > backup.sql
|
||||
```
|
||||
|
||||
### Restauration
|
||||
|
||||
```bash
|
||||
docker exec -i ptitspas-postgres psql -U admin ptitpas_db < backup.sql
|
||||
```
|
||||
|
||||
### Vérifier la taille de la base
|
||||
|
||||
```sql
|
||||
SELECT pg_size_pretty(pg_database_size('ptitpas_db'));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Dernière mise à jour** : Novembre 2025
|
||||
|
||||
+873
@@ -0,0 +1,873 @@
|
||||
# 🌐 Documentation API
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
L'API PtitsPas est une API REST construite avec **NestJS**.
|
||||
|
||||
**URL de base** : `https://app.ptits-pas.fr/api/v1`
|
||||
**Format** : JSON
|
||||
**Authentication** : JWT Bearer Token
|
||||
|
||||
---
|
||||
|
||||
## Authentication
|
||||
|
||||
Toutes les routes (sauf `/auth/login`, `/auth/register`, `/auth/refresh`) nécessitent un token JWT dans le header :
|
||||
|
||||
```http
|
||||
Authorization: Bearer <access_token>
|
||||
```
|
||||
|
||||
### Tokens
|
||||
|
||||
L'API utilise deux types de tokens :
|
||||
- **Access Token** : Durée de vie courte, utilisé pour les requêtes API
|
||||
- **Refresh Token** : Durée de vie longue, utilisé pour renouveler l'access token
|
||||
|
||||
---
|
||||
|
||||
## Endpoints
|
||||
|
||||
### 🔐 Authentification (`/auth`)
|
||||
|
||||
#### POST `/auth/login`
|
||||
|
||||
Connexion d'un utilisateur.
|
||||
|
||||
**Public** : ✅ Oui
|
||||
|
||||
**Request Body** :
|
||||
```json
|
||||
{
|
||||
"email": "admin@ptits-pas.fr",
|
||||
"password": "4dm1n1strateur"
|
||||
}
|
||||
```
|
||||
|
||||
**Response** (200) :
|
||||
```json
|
||||
{
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||
"user": {
|
||||
"id": "uuid",
|
||||
"email": "admin@ptits-pas.fr",
|
||||
"role": "super_admin",
|
||||
"prenom": "Admin",
|
||||
"nom": "Système"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Errors** :
|
||||
- `401` : Email ou mot de passe incorrect
|
||||
- `403` : Compte suspendu ou en attente de validation
|
||||
|
||||
---
|
||||
|
||||
#### POST `/auth/register`
|
||||
|
||||
Inscription d'un nouvel utilisateur (parent ou assistante maternelle).
|
||||
|
||||
**Public** : ✅ Oui
|
||||
|
||||
**Request Body** :
|
||||
```json
|
||||
{
|
||||
"email": "parent@example.com",
|
||||
"password": "motdepasse123",
|
||||
"prenom": "Jean",
|
||||
"nom": "Dupont",
|
||||
"role": "parent",
|
||||
"telephone": "0601020304"
|
||||
}
|
||||
```
|
||||
|
||||
**Response** (201) :
|
||||
```json
|
||||
{
|
||||
"message": "Inscription réussie. Votre compte est en attente de validation.",
|
||||
"userId": "uuid"
|
||||
}
|
||||
```
|
||||
|
||||
**Errors** :
|
||||
- `409` : Email déjà utilisé
|
||||
- `400` : Données invalides
|
||||
|
||||
---
|
||||
|
||||
#### POST `/auth/refresh`
|
||||
|
||||
Rafraîchir l'access token à l'aide du refresh token.
|
||||
|
||||
**Public** : ✅ Oui
|
||||
|
||||
**Request Body** :
|
||||
```json
|
||||
{
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
}
|
||||
```
|
||||
|
||||
**Response** (200) :
|
||||
```json
|
||||
{
|
||||
"access_token": "nouveau_token...",
|
||||
"refresh_token": "nouveau_refresh_token..."
|
||||
}
|
||||
```
|
||||
|
||||
**Errors** :
|
||||
- `401` : Token de rafraîchissement invalide ou expiré
|
||||
|
||||
---
|
||||
|
||||
#### GET `/auth/me`
|
||||
|
||||
Récupérer le profil de l'utilisateur connecté.
|
||||
|
||||
**Auth** : 🔒 Requis
|
||||
|
||||
**Response** (200) :
|
||||
```json
|
||||
{
|
||||
"id": "uuid",
|
||||
"email": "admin@ptits-pas.fr",
|
||||
"role": "super_admin",
|
||||
"prenom": "Admin",
|
||||
"nom": "Système",
|
||||
"statut": "actif"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### POST `/auth/logout`
|
||||
|
||||
Déconnexion (invalide le refresh token).
|
||||
|
||||
**Auth** : 🔒 Requis
|
||||
|
||||
**Response** (200) :
|
||||
```json
|
||||
{
|
||||
"message": "Déconnexion réussie"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 👥 Utilisateurs (`/users`)
|
||||
|
||||
**Auth** : 🔒 Requis pour toutes les routes
|
||||
|
||||
#### GET `/users`
|
||||
|
||||
Liste tous les utilisateurs.
|
||||
|
||||
**Rôles autorisés** : `super_admin`
|
||||
|
||||
**Response** (200) :
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "uuid",
|
||||
"email": "user@example.com",
|
||||
"role": "parent",
|
||||
"prenom": "Jean",
|
||||
"nom": "Dupont",
|
||||
"statut": "actif",
|
||||
"cree_le": "2025-01-15T10:30:00Z"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### GET `/users/:id`
|
||||
|
||||
Récupérer un utilisateur par son ID.
|
||||
|
||||
**Rôles autorisés** : `super_admin`, `gestionnaire`
|
||||
|
||||
**Response** (200) :
|
||||
```json
|
||||
{
|
||||
"id": "uuid",
|
||||
"email": "user@example.com",
|
||||
"role": "parent",
|
||||
"prenom": "Jean",
|
||||
"nom": "Dupont",
|
||||
"telephone": "0601020304",
|
||||
"statut": "actif"
|
||||
}
|
||||
```
|
||||
|
||||
**Errors** :
|
||||
- `404` : Utilisateur non trouvé
|
||||
- `403` : Accès refusé
|
||||
|
||||
---
|
||||
|
||||
#### POST `/users`
|
||||
|
||||
Créer un nouvel utilisateur.
|
||||
|
||||
**Rôles autorisés** : `super_admin`
|
||||
|
||||
**Request Body** :
|
||||
```json
|
||||
{
|
||||
"email": "newuser@example.com",
|
||||
"password": "password123",
|
||||
"role": "gestionnaire",
|
||||
"prenom": "Marie",
|
||||
"nom": "Martin"
|
||||
}
|
||||
```
|
||||
|
||||
**Response** (201) :
|
||||
```json
|
||||
{
|
||||
"id": "uuid",
|
||||
"email": "newuser@example.com",
|
||||
"role": "gestionnaire"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### PATCH `/users/:id`
|
||||
|
||||
Mettre à jour un utilisateur.
|
||||
|
||||
**Rôles autorisés** : `super_admin`
|
||||
|
||||
**Request Body** (tous les champs sont optionnels) :
|
||||
```json
|
||||
{
|
||||
"prenom": "Jean-Claude",
|
||||
"telephone": "0612345678",
|
||||
"adresse": "1 rue de la Paix, 75001 Paris"
|
||||
}
|
||||
```
|
||||
|
||||
**Response** (200) :
|
||||
```json
|
||||
{
|
||||
"id": "uuid",
|
||||
"email": "user@example.com",
|
||||
"prenom": "Jean-Claude",
|
||||
"telephone": "0612345678"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### PATCH `/users/:id/valider`
|
||||
|
||||
Valider un compte utilisateur en attente.
|
||||
|
||||
**Rôles autorisés** : `super_admin`, `gestionnaire`, `administrateur`
|
||||
|
||||
**Request Body** :
|
||||
```json
|
||||
{
|
||||
"comment": "Compte validé après vérification des documents"
|
||||
}
|
||||
```
|
||||
|
||||
**Response** (200) :
|
||||
```json
|
||||
{
|
||||
"message": "Compte validé avec succès",
|
||||
"userId": "uuid"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### PATCH `/users/:id/suspendre`
|
||||
|
||||
Suspendre un compte utilisateur.
|
||||
|
||||
**Rôles autorisés** : `super_admin`, `gestionnaire`, `administrateur`
|
||||
|
||||
**Request Body** :
|
||||
```json
|
||||
{
|
||||
"comment": "Compte suspendu pour non-respect des conditions"
|
||||
}
|
||||
```
|
||||
|
||||
**Response** (200) :
|
||||
```json
|
||||
{
|
||||
"message": "Compte suspendu",
|
||||
"userId": "uuid"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### DELETE `/users/:id`
|
||||
|
||||
Supprimer un utilisateur.
|
||||
|
||||
**Rôles autorisés** : `super_admin`
|
||||
|
||||
**Response** (200) :
|
||||
```json
|
||||
{
|
||||
"message": "Utilisateur supprimé"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🏢 Gestionnaires (`/gestionnaires`)
|
||||
|
||||
**Auth** : 🔒 Requis pour toutes les routes
|
||||
|
||||
#### GET `/gestionnaires`
|
||||
|
||||
Liste tous les gestionnaires.
|
||||
|
||||
**Rôles autorisés** : `super_admin`, `gestionnaire`
|
||||
|
||||
**Response** (200) :
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "uuid",
|
||||
"email": "gestionnaire@ptits-pas.fr",
|
||||
"role": "gestionnaire",
|
||||
"prenom": "Sophie",
|
||||
"nom": "Leroy"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### GET `/gestionnaires/:id`
|
||||
|
||||
Récupérer un gestionnaire par son ID.
|
||||
|
||||
**Rôles autorisés** : `super_admin`, `gestionnaire`
|
||||
|
||||
**Response** (200) : Identique à `/users/:id`
|
||||
|
||||
---
|
||||
|
||||
#### POST `/gestionnaires`
|
||||
|
||||
Créer un nouveau gestionnaire.
|
||||
|
||||
**Rôles autorisés** : `super_admin`
|
||||
|
||||
**Request Body** :
|
||||
```json
|
||||
{
|
||||
"email": "nouveau.gestionnaire@ptits-pas.fr",
|
||||
"password": "password123",
|
||||
"prenom": "Laurent",
|
||||
"nom": "Bernard"
|
||||
}
|
||||
```
|
||||
|
||||
**Response** (201) :
|
||||
```json
|
||||
{
|
||||
"id": "uuid",
|
||||
"email": "nouveau.gestionnaire@ptits-pas.fr",
|
||||
"role": "gestionnaire"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### PATCH `/gestionnaires/:id`
|
||||
|
||||
Mettre à jour un gestionnaire.
|
||||
|
||||
**Rôles autorisés** : `super_admin`
|
||||
|
||||
**Request Body** : Identique à `/users/:id` (PATCH)
|
||||
|
||||
---
|
||||
|
||||
### 👶 Parents (`/parents`)
|
||||
|
||||
**Auth** : 🔒 Requis pour toutes les routes
|
||||
|
||||
#### GET `/parents`
|
||||
|
||||
Liste tous les parents.
|
||||
|
||||
**Rôles autorisés** : `super_admin`, `gestionnaire`
|
||||
|
||||
**Response** (200) :
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id_utilisateur": "uuid",
|
||||
"id_co_parent": "uuid",
|
||||
"utilisateur": {
|
||||
"email": "parent@example.com",
|
||||
"prenom": "Jean",
|
||||
"nom": "Dupont"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### GET `/parents/:id`
|
||||
|
||||
Récupérer un parent par son ID utilisateur.
|
||||
|
||||
**Rôles autorisés** : `super_admin`, `gestionnaire`
|
||||
|
||||
**Response** (200) :
|
||||
```json
|
||||
{
|
||||
"id_utilisateur": "uuid",
|
||||
"id_co_parent": "uuid",
|
||||
"utilisateur": {
|
||||
"email": "parent@example.com",
|
||||
"prenom": "Jean",
|
||||
"nom": "Dupont",
|
||||
"telephone": "0601020304"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### POST `/parents`
|
||||
|
||||
Créer un nouveau parent.
|
||||
|
||||
**Rôles autorisés** : `super_admin`, `gestionnaire`
|
||||
|
||||
**Request Body** :
|
||||
```json
|
||||
{
|
||||
"email": "parent@example.com",
|
||||
"password": "password123",
|
||||
"prenom": "Jean",
|
||||
"nom": "Dupont",
|
||||
"telephone": "0601020304",
|
||||
"id_co_parent": "uuid" // optionnel
|
||||
}
|
||||
```
|
||||
|
||||
**Response** (201) : Identique à GET
|
||||
|
||||
---
|
||||
|
||||
#### PATCH `/parents/:id`
|
||||
|
||||
Mettre à jour un parent.
|
||||
|
||||
**Rôles autorisés** : `super_admin`, `gestionnaire`
|
||||
|
||||
**Request Body** :
|
||||
```json
|
||||
{
|
||||
"id_co_parent": "uuid",
|
||||
"telephone": "0612345678"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 👧 Enfants (`/enfants`)
|
||||
|
||||
**Auth** : 🔒 Requis pour toutes les routes
|
||||
|
||||
#### GET `/enfants`
|
||||
|
||||
Liste tous les enfants.
|
||||
|
||||
**Rôles autorisés** : `super_admin`, `gestionnaire`, `administrateur`
|
||||
|
||||
**Response** (200) :
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "uuid",
|
||||
"prenom": "Alice",
|
||||
"nom": "Dupont",
|
||||
"genre": "F",
|
||||
"date_naissance": "2020-05-15",
|
||||
"statut": "actif"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### GET `/enfants/:id`
|
||||
|
||||
Récupérer un enfant par son ID.
|
||||
|
||||
**Rôles autorisés** : `super_admin`, `gestionnaire`, `administrateur`, `parent` (si c'est son enfant)
|
||||
|
||||
**Response** (200) :
|
||||
```json
|
||||
{
|
||||
"id": "uuid",
|
||||
"prenom": "Alice",
|
||||
"nom": "Dupont",
|
||||
"genre": "F",
|
||||
"date_naissance": "2020-05-15",
|
||||
"statut": "actif",
|
||||
"consentement_photo": false
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### POST `/enfants`
|
||||
|
||||
Créer un nouvel enfant.
|
||||
|
||||
**Rôles autorisés** : `parent`
|
||||
|
||||
**Request Body** :
|
||||
```json
|
||||
{
|
||||
"prenom": "Alice",
|
||||
"nom": "Dupont",
|
||||
"genre": "F",
|
||||
"date_naissance": "2020-05-15",
|
||||
"statut": "actif"
|
||||
}
|
||||
```
|
||||
|
||||
**Response** (201) : Identique à GET
|
||||
|
||||
---
|
||||
|
||||
#### PATCH `/enfants/:id`
|
||||
|
||||
Mettre à jour un enfant.
|
||||
|
||||
**Rôles autorisés** : `super_admin`, `administrateur`, `parent` (si c'est son enfant)
|
||||
|
||||
**Request Body** :
|
||||
```json
|
||||
{
|
||||
"statut": "scolarise",
|
||||
"consentement_photo": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### DELETE `/enfants/:id`
|
||||
|
||||
Supprimer un enfant.
|
||||
|
||||
**Rôles autorisés** : `super_admin`
|
||||
|
||||
**Response** (200) :
|
||||
```json
|
||||
{
|
||||
"message": "Enfant supprimé"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 👩🍼 Assistantes Maternelles (`/assistantes-maternelles`)
|
||||
|
||||
**Auth** : 🔒 Requis pour toutes les routes
|
||||
|
||||
#### GET `/assistantes-maternelles`
|
||||
|
||||
Liste toutes les assistantes maternelles.
|
||||
|
||||
**Rôles autorisés** : `super_admin`, `gestionnaire`
|
||||
|
||||
**Response** (200) :
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id_utilisateur": "uuid",
|
||||
"numero_agrement": "AM123456",
|
||||
"nb_max_enfants": 4,
|
||||
"place_disponible": 2,
|
||||
"disponible": true,
|
||||
"utilisateur": {
|
||||
"email": "am@example.com",
|
||||
"prenom": "Marie",
|
||||
"nom": "Martin"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### GET `/assistantes-maternelles/:id`
|
||||
|
||||
Récupérer une assistante maternelle par son ID utilisateur.
|
||||
|
||||
**Rôles autorisés** : `super_admin`, `gestionnaire`
|
||||
|
||||
**Response** (200) :
|
||||
```json
|
||||
{
|
||||
"id_utilisateur": "uuid",
|
||||
"numero_agrement": "AM123456",
|
||||
"nir_chiffre": "123456789012345",
|
||||
"nb_max_enfants": 4,
|
||||
"place_disponible": 2,
|
||||
"biographie": "Assistante maternelle depuis 10 ans...",
|
||||
"disponible": true,
|
||||
"ville_residence": "Paris",
|
||||
"date_agrement": "2015-06-01",
|
||||
"annee_experience": 10,
|
||||
"specialite": "Pédagogie Montessori"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### POST `/assistantes-maternelles`
|
||||
|
||||
Créer une nouvelle assistante maternelle.
|
||||
|
||||
**Rôles autorisés** : `super_admin`, `gestionnaire`
|
||||
|
||||
**Request Body** :
|
||||
```json
|
||||
{
|
||||
"email": "am@example.com",
|
||||
"password": "password123",
|
||||
"prenom": "Marie",
|
||||
"nom": "Martin",
|
||||
"numero_agrement": "AM123456",
|
||||
"nb_max_enfants": 4,
|
||||
"ville_residence": "Paris"
|
||||
}
|
||||
```
|
||||
|
||||
**Response** (201) : Identique à GET
|
||||
|
||||
---
|
||||
|
||||
#### PATCH `/assistantes-maternelles/:id`
|
||||
|
||||
Mettre à jour une assistante maternelle.
|
||||
|
||||
**Rôles autorisés** : `super_admin`, `gestionnaire`
|
||||
|
||||
**Request Body** :
|
||||
```json
|
||||
{
|
||||
"place_disponible": 1,
|
||||
"disponible": true,
|
||||
"biographie": "Nouvelle bio..."
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### DELETE `/assistantes-maternelles/:id`
|
||||
|
||||
Supprimer une assistante maternelle.
|
||||
|
||||
**Rôles autorisés** : `super_admin`, `gestionnaire`, `administrateur`
|
||||
|
||||
**Response** (200) :
|
||||
```json
|
||||
{
|
||||
"message": "Assistante maternelle supprimée"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🏠 Root (`/`)
|
||||
|
||||
#### GET `/`
|
||||
|
||||
Aperçu de l'API.
|
||||
|
||||
**Public** : ✅ Oui
|
||||
|
||||
**Response** (200) :
|
||||
```json
|
||||
{
|
||||
"message": "Bienvenue sur l'API PtitsPas",
|
||||
"version": "1.0.0",
|
||||
"endpoints": {
|
||||
"auth": "/api/v1/auth",
|
||||
"users": "/api/v1/users",
|
||||
"parents": "/api/v1/parents",
|
||||
"enfants": "/api/v1/enfants",
|
||||
"assistantes-maternelles": "/api/v1/assistantes-maternelles",
|
||||
"gestionnaires": "/api/v1/gestionnaires"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### GET `/hello`
|
||||
|
||||
Endpoint de test.
|
||||
|
||||
**Public** : ✅ Oui
|
||||
|
||||
**Response** (200) :
|
||||
```text
|
||||
Hello World!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Codes d'erreur HTTP
|
||||
|
||||
| Code | Signification | Explication |
|
||||
|------|---------------|-------------|
|
||||
| `200` | OK | Requête réussie |
|
||||
| `201` | Created | Ressource créée |
|
||||
| `400` | Bad Request | Données invalides |
|
||||
| `401` | Unauthorized | Non authentifié ou token invalide |
|
||||
| `403` | Forbidden | Accès refusé (rôle insuffisant) |
|
||||
| `404` | Not Found | Ressource non trouvée |
|
||||
| `409` | Conflict | Conflit (ex: email déjà existant) |
|
||||
| `500` | Internal Server Error | Erreur serveur |
|
||||
|
||||
---
|
||||
|
||||
## Format des réponses d'erreur
|
||||
|
||||
```json
|
||||
{
|
||||
"statusCode": 400,
|
||||
"message": "Validation failed",
|
||||
"error": "Bad Request"
|
||||
}
|
||||
```
|
||||
|
||||
Ou avec détails :
|
||||
|
||||
```json
|
||||
{
|
||||
"statusCode": 403,
|
||||
"message": "Accès refusé : rôle insuffisant",
|
||||
"error": "Forbidden"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Authentification et Rôles
|
||||
|
||||
### Hiérarchie des rôles
|
||||
|
||||
1. **super_admin** : Accès total
|
||||
2. **administrateur** : Gestion des utilisateurs
|
||||
3. **gestionnaire** : Gestion des dossiers et validation
|
||||
4. **assistante_maternelle** : Accès à ses propres données
|
||||
5. **parent** : Accès à ses propres données et enfants
|
||||
|
||||
### Guards
|
||||
|
||||
L'API utilise deux guards :
|
||||
- **AuthGuard** : Vérifie la validité du token JWT
|
||||
- **RolesGuard** : Vérifie que l'utilisateur a le bon rôle
|
||||
|
||||
### Décorateurs
|
||||
|
||||
- `@Public()` : Route accessible sans authentification
|
||||
- `@Roles(...roles)` : Restreint l'accès aux rôles spécifiés
|
||||
- `@User()` : Injecte l'utilisateur connecté dans le contrôleur
|
||||
|
||||
---
|
||||
|
||||
## Swagger / OpenAPI
|
||||
|
||||
L'API expose automatiquement sa documentation Swagger :
|
||||
|
||||
**URL** : `https://app.ptits-pas.fr/api/docs`
|
||||
|
||||
Cette documentation interactive permet de :
|
||||
- Visualiser tous les endpoints
|
||||
- Tester les requêtes directement
|
||||
- Voir les schémas de données
|
||||
|
||||
---
|
||||
|
||||
## Exemples d'utilisation
|
||||
|
||||
### Connexion et récupération du profil
|
||||
|
||||
```bash
|
||||
# 1. Login
|
||||
curl -X POST https://app.ptits-pas.fr/api/v1/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email":"admin@ptits-pas.fr","password":"4dm1n1strateur"}'
|
||||
|
||||
# Response
|
||||
{
|
||||
"access_token": "eyJhbGc...",
|
||||
"refresh_token": "eyJhbGc..."
|
||||
}
|
||||
|
||||
# 2. Récupérer son profil
|
||||
curl https://app.ptits-pas.fr/api/v1/auth/me \
|
||||
-H "Authorization: Bearer eyJhbGc..."
|
||||
```
|
||||
|
||||
### Créer un parent
|
||||
|
||||
```bash
|
||||
curl -X POST https://app.ptits-pas.fr/api/v1/parents \
|
||||
-H "Authorization: Bearer <access_token>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"email": "parent@example.com",
|
||||
"password": "password123",
|
||||
"prenom": "Jean",
|
||||
"nom": "Dupont",
|
||||
"telephone": "0601020304"
|
||||
}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Limitations et Rate Limiting
|
||||
|
||||
**Actuellement** : Aucune limitation n'est active.
|
||||
|
||||
**À implémenter** :
|
||||
- Rate limiting (ex: 100 requêtes/minute)
|
||||
- Pagination pour les listes longues
|
||||
- Filtrage et tri sur les endpoints de liste
|
||||
|
||||
---
|
||||
|
||||
## Évolutions prévues
|
||||
|
||||
- [ ] Endpoints pour les dossiers (`/dossiers`)
|
||||
- [ ] Endpoints pour les contrats (`/contrats`)
|
||||
- [ ] Endpoints pour les événements (`/evenements`)
|
||||
- [ ] Endpoints pour les messages (`/messages`)
|
||||
- [ ] Endpoints pour les notifications (`/notifications`)
|
||||
- [ ] WebSocket pour les notifications en temps réel
|
||||
- [ ] Upload de fichiers (`/uploads`)
|
||||
- [ ] Génération de PDF (contrats)
|
||||
|
||||
---
|
||||
|
||||
**Dernière mise à jour** : Novembre 2025
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,712 @@
|
||||
# 🔧 Documentation Technique - Configuration Système On-Premise
|
||||
|
||||
**Version** : 1.0
|
||||
**Date** : 25 Novembre 2025
|
||||
**Auteur** : Équipe PtitsPas
|
||||
**Référence** : Architecture On-Premise
|
||||
|
||||
---
|
||||
|
||||
## 📖 Table des matières
|
||||
|
||||
1. [Vue d'ensemble](#vue-densemble)
|
||||
2. [Architecture de configuration](#architecture-de-configuration)
|
||||
3. [Table configuration](#table-configuration)
|
||||
4. [Service Configuration](#service-configuration)
|
||||
5. [Workflow Setup Initial](#workflow-setup-initial)
|
||||
6. [APIs Configuration](#apis-configuration)
|
||||
7. [Interface Admin](#interface-admin)
|
||||
8. [Exemples de configuration](#exemples-de-configuration)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Vue d'ensemble
|
||||
|
||||
### Problématique
|
||||
|
||||
L'application P'titsPas est déployée **on-premise** chez différentes collectivités. Chaque collectivité a :
|
||||
- Son propre serveur SMTP
|
||||
- Ses propres ports et configurations réseau
|
||||
- Son propre nom de domaine
|
||||
- Sa propre charte graphique
|
||||
|
||||
**Solution** : Configuration dynamique stockée en base de données, modifiable via interface web.
|
||||
|
||||
### Principes
|
||||
|
||||
1. ✅ **Pas de hardcoding** : Aucune valeur en dur dans le code
|
||||
2. ✅ **Pas de redéploiement** : Modification sans rebuild Docker
|
||||
3. ✅ **Sécurité** : Mots de passe chiffrés en AES-256
|
||||
4. ✅ **Traçabilité** : Qui a modifié quoi et quand
|
||||
5. ✅ **Setup wizard** : Configuration guidée à la première connexion
|
||||
6. ✅ **Validation** : Test SMTP avant sauvegarde
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Architecture de configuration
|
||||
|
||||
### Flux de données
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Application │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ Frontend │─────▶│ Backend │ │
|
||||
│ │ (Admin) │ │ ConfigAPI │ │
|
||||
│ └──────────────┘ └──────┬───────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────┐ │
|
||||
│ │ ConfigService│ │
|
||||
│ │ (Cache) │ │
|
||||
│ └──────┬───────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────┐ │
|
||||
│ │ PostgreSQL │ │
|
||||
│ │ configuration│ │
|
||||
│ └──────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Composants
|
||||
|
||||
1. **Table `configuration`** : Stockage clé/valeur en BDD
|
||||
2. **ConfigService** : Cache en mémoire + chiffrement
|
||||
3. **ConfigAPI** : Endpoints REST pour CRUD
|
||||
4. **Guard Setup** : Redirection forcée si config incomplète
|
||||
5. **Interface Admin** : Formulaire de configuration
|
||||
|
||||
---
|
||||
|
||||
## 📊 Table configuration
|
||||
|
||||
### Schéma SQL
|
||||
|
||||
```sql
|
||||
-- Table de configuration système (clé/valeur)
|
||||
CREATE TABLE configuration (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
cle VARCHAR(100) UNIQUE NOT NULL, -- Clé unique (ex: 'smtp_host')
|
||||
valeur TEXT, -- Valeur (peut être NULL)
|
||||
type VARCHAR(50) NOT NULL, -- Type: 'string', 'number', 'boolean', 'json', 'encrypted'
|
||||
categorie VARCHAR(50), -- Catégorie: 'email', 'app', 'security'
|
||||
description TEXT, -- Description pour l'interface admin
|
||||
modifie_le TIMESTAMPTZ DEFAULT now(), -- Date dernière modification
|
||||
modifie_par UUID REFERENCES utilisateurs(id) -- Qui a modifié (traçabilité)
|
||||
);
|
||||
|
||||
-- Index pour performance
|
||||
CREATE INDEX idx_configuration_cle ON configuration(cle);
|
||||
CREATE INDEX idx_configuration_categorie ON configuration(categorie);
|
||||
```
|
||||
|
||||
### Seed initial
|
||||
|
||||
```sql
|
||||
INSERT INTO configuration (cle, valeur, type, categorie, description) VALUES
|
||||
-- === Configuration Email (SMTP) ===
|
||||
('smtp_host', 'localhost', 'string', 'email', 'Serveur SMTP (ex: mail.mairie-bezons.fr, smtp.gmail.com)'),
|
||||
('smtp_port', '25', 'number', 'email', 'Port SMTP (25, 465, 587)'),
|
||||
('smtp_secure', 'false', 'boolean', 'email', 'Utiliser SSL/TLS (true pour port 465)'),
|
||||
('smtp_auth_required', 'false', 'boolean', 'email', 'Authentification SMTP requise'),
|
||||
('smtp_user', '', 'string', 'email', 'Utilisateur SMTP (si authentification requise)'),
|
||||
('smtp_password', '', 'encrypted', 'email', 'Mot de passe SMTP (chiffré en AES-256)'),
|
||||
('email_from_name', 'P''titsPas', 'string', 'email', 'Nom de l''expéditeur affiché dans les emails'),
|
||||
('email_from_address', 'no-reply@ptits-pas.fr', 'string', 'email', 'Adresse email de l''expéditeur'),
|
||||
|
||||
-- === Configuration Application ===
|
||||
('app_name', 'P''titsPas', 'string', 'app', 'Nom de l''application (affiché dans l''interface)'),
|
||||
('app_url', 'https://app.ptits-pas.fr', 'string', 'app', 'URL publique de l''application (pour les liens dans emails)'),
|
||||
('app_logo_url', '/assets/logo.png', 'string', 'app', 'URL du logo de l''application'),
|
||||
('setup_completed', 'false', 'boolean', 'app', 'Configuration initiale terminée'),
|
||||
|
||||
-- === Configuration Sécurité ===
|
||||
('password_reset_token_expiry_days', '7', 'number', 'security', 'Durée de validité des tokens de création/réinitialisation de mot de passe (en jours)'),
|
||||
('jwt_expiry_hours', '24', 'number', 'security', 'Durée de validité des sessions JWT (en heures)'),
|
||||
('max_upload_size_mb', '5', 'number', 'security', 'Taille maximale des fichiers uploadés (en MB)'),
|
||||
('bcrypt_rounds', '12', 'number', 'security', 'Nombre de rounds bcrypt pour le hachage des mots de passe');
|
||||
```
|
||||
|
||||
### Types de données
|
||||
|
||||
| Type | Description | Exemple |
|
||||
|------|-------------|---------|
|
||||
| `string` | Chaîne de caractères | `"mail.example.com"` |
|
||||
| `number` | Nombre entier ou décimal | `587` |
|
||||
| `boolean` | Booléen | `true` / `false` |
|
||||
| `json` | Objet JSON | `{"key": "value"}` |
|
||||
| `encrypted` | Chaîne chiffrée AES-256 | `"a3f8b2..."` (hash) |
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Service Configuration
|
||||
|
||||
### Responsabilités
|
||||
|
||||
1. **Cache en mémoire** : Chargement au démarrage
|
||||
2. **Lecture** : `get(key, defaultValue)`
|
||||
3. **Écriture** : `set(key, value, userId)`
|
||||
4. **Chiffrement** : AES-256 pour type `encrypted`
|
||||
5. **Conversion de types** : string → number/boolean/json
|
||||
6. **Test SMTP** : Validation connexion
|
||||
|
||||
### Implémentation (TypeScript)
|
||||
|
||||
```typescript
|
||||
// backend/src/config/config.service.ts
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Configuration } from './entities/configuration.entity';
|
||||
import * as crypto from 'crypto';
|
||||
|
||||
@Injectable()
|
||||
export class ConfigService {
|
||||
private cache: Map<string, any> = new Map();
|
||||
private readonly ENCRYPTION_KEY = process.env.CONFIG_ENCRYPTION_KEY;
|
||||
|
||||
constructor(
|
||||
@InjectRepository(Configuration)
|
||||
private configRepo: Repository<Configuration>,
|
||||
) {
|
||||
this.loadCache();
|
||||
}
|
||||
|
||||
// Chargement du cache au démarrage
|
||||
async loadCache() {
|
||||
const configs = await this.configRepo.find();
|
||||
configs.forEach(config => {
|
||||
let value = config.valeur;
|
||||
|
||||
// Déchiffrement si nécessaire
|
||||
if (config.type === 'encrypted' && value) {
|
||||
value = this.decrypt(value);
|
||||
}
|
||||
|
||||
// Conversion de type
|
||||
value = this.convertType(value, config.type);
|
||||
|
||||
this.cache.set(config.cle, value);
|
||||
});
|
||||
}
|
||||
|
||||
// Récupération d'une valeur
|
||||
get(key: string, defaultValue?: any): any {
|
||||
return this.cache.has(key) ? this.cache.get(key) : defaultValue;
|
||||
}
|
||||
|
||||
// Mise à jour d'une valeur
|
||||
async set(key: string, value: any, userId: string): Promise<void> {
|
||||
const config = await this.configRepo.findOne({ where: { cle: key } });
|
||||
|
||||
if (!config) {
|
||||
throw new Error(`Configuration key '${key}' not found`);
|
||||
}
|
||||
|
||||
let valueToStore = String(value);
|
||||
|
||||
// Chiffrement si nécessaire
|
||||
if (config.type === 'encrypted') {
|
||||
valueToStore = this.encrypt(valueToStore);
|
||||
}
|
||||
|
||||
config.valeur = valueToStore;
|
||||
config.modifie_par = userId;
|
||||
config.modifie_le = new Date();
|
||||
|
||||
await this.configRepo.save(config);
|
||||
|
||||
// Mise à jour du cache
|
||||
this.cache.set(key, value);
|
||||
}
|
||||
|
||||
// Récupération de toutes les configs par catégorie
|
||||
async getByCategory(category: string): Promise<any> {
|
||||
const configs = await this.configRepo.find({ where: { categorie: category } });
|
||||
|
||||
return configs.reduce((acc, config) => {
|
||||
let value = config.valeur;
|
||||
|
||||
if (config.type === 'encrypted') {
|
||||
value = '***********'; // Masquer les mots de passe
|
||||
} else {
|
||||
value = this.convertType(value, config.type);
|
||||
}
|
||||
|
||||
acc[config.cle] = {
|
||||
value,
|
||||
description: config.description,
|
||||
type: config.type,
|
||||
};
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
// Test de connexion SMTP
|
||||
async testSmtpConnection(): Promise<boolean> {
|
||||
const nodemailer = require('nodemailer');
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: this.get('smtp_host'),
|
||||
port: this.get('smtp_port'),
|
||||
secure: this.get('smtp_secure'),
|
||||
auth: this.get('smtp_auth_required') ? {
|
||||
user: this.get('smtp_user'),
|
||||
pass: this.get('smtp_password'),
|
||||
} : undefined,
|
||||
});
|
||||
|
||||
try {
|
||||
await transporter.verify();
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('SMTP test failed:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Utilitaires
|
||||
private convertType(value: string, type: string): any {
|
||||
switch (type) {
|
||||
case 'number': return Number(value);
|
||||
case 'boolean': return value === 'true';
|
||||
case 'json': return JSON.parse(value);
|
||||
default: return value;
|
||||
}
|
||||
}
|
||||
|
||||
private encrypt(text: string): string {
|
||||
const cipher = crypto.createCipher('aes-256-cbc', this.ENCRYPTION_KEY);
|
||||
let encrypted = cipher.update(text, 'utf8', 'hex');
|
||||
encrypted += cipher.final('hex');
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
private decrypt(text: string): string {
|
||||
const decipher = crypto.createDecipher('aes-256-cbc', this.ENCRYPTION_KEY);
|
||||
let decrypted = decipher.update(text, 'hex', 'utf8');
|
||||
decrypted += decipher.final('utf8');
|
||||
return decrypted;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Workflow Setup Initial
|
||||
|
||||
### Diagramme de séquence
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant SA as Super Admin
|
||||
participant App as Application
|
||||
participant Guard as SetupGuard
|
||||
participant API as ConfigAPI
|
||||
participant DB as PostgreSQL
|
||||
participant SMTP as Serveur SMTP
|
||||
|
||||
SA->>App: Première connexion
|
||||
App->>Guard: Vérifier setup_completed
|
||||
Guard->>DB: SELECT valeur FROM configuration<br/>WHERE cle='setup_completed'
|
||||
DB-->>Guard: 'false'
|
||||
|
||||
Guard-->>App: Redirection forcée vers<br/>/admin/setup
|
||||
|
||||
SA->>SA: Remplit formulaire config<br/>(SMTP, app, sécurité)
|
||||
|
||||
SA->>App: Clic "Tester la connexion SMTP"
|
||||
App->>API: POST /api/v1/configuration/test-smtp
|
||||
API->>SMTP: Test connexion
|
||||
|
||||
alt Test SMTP OK
|
||||
SMTP-->>API: ✅ Connexion réussie
|
||||
API->>SA: Envoi email de test
|
||||
API-->>App: ✅ Test réussi
|
||||
App-->>SA: Message: "Email de test envoyé"
|
||||
else Test SMTP KO
|
||||
SMTP-->>API: ❌ Erreur connexion
|
||||
API-->>App: ❌ Erreur détaillée
|
||||
App-->>SA: Message: "Erreur: vérifiez les paramètres"
|
||||
end
|
||||
|
||||
SA->>App: Clic "Sauvegarder"
|
||||
App->>API: PATCH /api/v1/configuration/bulk<br/>{smtp_host, smtp_port, ...}
|
||||
|
||||
API->>DB: BEGIN TRANSACTION
|
||||
API->>DB: UPDATE configuration SET valeur=...<br/>FOR EACH key
|
||||
API->>DB: UPDATE configuration<br/>SET valeur='true'<br/>WHERE cle='setup_completed'
|
||||
API->>DB: COMMIT
|
||||
|
||||
API->>API: Recharger cache ConfigService
|
||||
|
||||
API-->>App: ✅ Configuration sauvegardée
|
||||
App-->>SA: Redirection vers /admin/dashboard
|
||||
|
||||
SA->>App: Accès complet à l'application
|
||||
```
|
||||
|
||||
### Étapes détaillées
|
||||
|
||||
#### 1. Détection configuration incomplète
|
||||
|
||||
**Guard** : `SetupGuard` (NestJS)
|
||||
|
||||
```typescript
|
||||
@Injectable()
|
||||
export class SetupGuard implements CanActivate {
|
||||
constructor(private configService: ConfigService) {}
|
||||
|
||||
canActivate(context: ExecutionContext): boolean {
|
||||
const request = context.switchToHttp().getRequest();
|
||||
const setupCompleted = this.configService.get('setup_completed', false);
|
||||
|
||||
// Exemptions
|
||||
const exemptedRoutes = ['/auth/login', '/admin/setup', '/api/v1/configuration'];
|
||||
if (exemptedRoutes.some(route => request.url.includes(route))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Si setup non complété, bloquer
|
||||
if (!setupCompleted) {
|
||||
throw new HttpException(
|
||||
'Configuration initiale requise',
|
||||
HttpStatus.TEMPORARY_REDIRECT,
|
||||
{ location: '/admin/setup' }
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. Formulaire Setup (Frontend)
|
||||
|
||||
**3 onglets** :
|
||||
|
||||
##### Onglet 1 : Configuration Email 📧
|
||||
|
||||
| Champ | Type | Valeur par défaut | Obligatoire |
|
||||
|-------|------|-------------------|-------------|
|
||||
| Serveur SMTP | Text | `localhost` | ✅ |
|
||||
| Port SMTP | Number | `25` | ✅ |
|
||||
| Sécurité | Select | `Aucune` / `STARTTLS` / `SSL/TLS` | ✅ |
|
||||
| Authentification requise | Checkbox | `false` | - |
|
||||
| Utilisateur SMTP | Text | - | Si auth |
|
||||
| Mot de passe SMTP | Password | - | Si auth |
|
||||
| Nom expéditeur | Text | `P'titsPas` | ✅ |
|
||||
| Email expéditeur | Email | `no-reply@ptits-pas.fr` | ✅ |
|
||||
|
||||
**Bouton** : "🧪 Tester la connexion SMTP"
|
||||
|
||||
##### Onglet 2 : Personnalisation 🎨
|
||||
|
||||
| Champ | Type | Valeur par défaut | Obligatoire |
|
||||
|-------|------|-------------------|-------------|
|
||||
| Nom de l'application | Text | `P'titsPas` | ✅ |
|
||||
| URL de l'application | URL | `https://app.ptits-pas.fr` | ✅ |
|
||||
| Logo | File (PNG/JPG) | Logo par défaut | ❌ |
|
||||
|
||||
##### Onglet 3 : Paramètres avancés ⚙️
|
||||
|
||||
| Champ | Type | Valeur par défaut | Obligatoire |
|
||||
|-------|------|-------------------|-------------|
|
||||
| Durée validité token MDP (jours) | Number | `7` | ✅ |
|
||||
| Durée session JWT (heures) | Number | `24` | ✅ |
|
||||
| Taille max upload (MB) | Number | `5` | ✅ |
|
||||
|
||||
**Bouton** : "💾 Sauvegarder et terminer la configuration"
|
||||
|
||||
---
|
||||
|
||||
## 🔌 APIs Configuration
|
||||
|
||||
### Endpoint 1 : Récupérer config par catégorie
|
||||
|
||||
```http
|
||||
GET /api/v1/configuration/:category
|
||||
Authorization: Bearer <super_admin_token>
|
||||
```
|
||||
|
||||
**Paramètres** :
|
||||
- `category` : `email` | `app` | `security`
|
||||
|
||||
**Réponse 200** :
|
||||
```json
|
||||
{
|
||||
"smtp_host": {
|
||||
"value": "localhost",
|
||||
"description": "Serveur SMTP",
|
||||
"type": "string"
|
||||
},
|
||||
"smtp_port": {
|
||||
"value": 25,
|
||||
"description": "Port SMTP",
|
||||
"type": "number"
|
||||
},
|
||||
"smtp_password": {
|
||||
"value": "***********",
|
||||
"description": "Mot de passe SMTP",
|
||||
"type": "encrypted"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Endpoint 2 : Mise à jour multiple
|
||||
|
||||
```http
|
||||
PATCH /api/v1/configuration/bulk
|
||||
Authorization: Bearer <super_admin_token>
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
**Body** :
|
||||
```json
|
||||
{
|
||||
"smtp_host": "mail.mairie-bezons.fr",
|
||||
"smtp_port": 587,
|
||||
"smtp_secure": false,
|
||||
"smtp_auth_required": true,
|
||||
"smtp_user": "noreply@mairie-bezons.fr",
|
||||
"smtp_password": "SecretPassword123",
|
||||
"email_from_name": "P'titsPas - Mairie de Bezons",
|
||||
"email_from_address": "noreply@mairie-bezons.fr",
|
||||
"app_name": "P'titsPas Bezons",
|
||||
"app_url": "https://ptitspas.mairie-bezons.fr"
|
||||
}
|
||||
```
|
||||
|
||||
**Réponse 200** :
|
||||
```json
|
||||
{
|
||||
"message": "Configuration mise à jour avec succès",
|
||||
"updated": 10
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Endpoint 3 : Test connexion SMTP
|
||||
|
||||
```http
|
||||
POST /api/v1/configuration/test-smtp
|
||||
Authorization: Bearer <super_admin_token>
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
**Body** :
|
||||
```json
|
||||
{
|
||||
"smtp_host": "mail.mairie-bezons.fr",
|
||||
"smtp_port": 587,
|
||||
"smtp_secure": false,
|
||||
"smtp_auth_required": true,
|
||||
"smtp_user": "noreply@mairie-bezons.fr",
|
||||
"smtp_password": "SecretPassword123",
|
||||
"test_email": "admin@mairie-bezons.fr"
|
||||
}
|
||||
```
|
||||
|
||||
**Réponse 200** :
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Connexion SMTP réussie. Email de test envoyé à admin@mairie-bezons.fr"
|
||||
}
|
||||
```
|
||||
|
||||
**Réponse 400** :
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "Erreur de connexion SMTP",
|
||||
"error": "ECONNREFUSED: Connection refused"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💻 Interface Admin
|
||||
|
||||
### Écran Setup Initial
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 🚀 Configuration Initiale - P'titsPas │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Bienvenue ! Configurez votre installation P'titsPas │
|
||||
│ │
|
||||
│ [ 📧 Email ] [ 🎨 Personnalisation ] [ ⚙️ Avancé ] │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📧 Configuration Email (SMTP) │
|
||||
│ │
|
||||
│ Serveur SMTP * │
|
||||
│ [_____________________________________________] │
|
||||
│ Ex: mail.mairie-bezons.fr, smtp.gmail.com │
|
||||
│ │
|
||||
│ Port SMTP * │
|
||||
│ [_____] 25 (standard), 465 (SSL), 587 (STARTTLS) │
|
||||
│ │
|
||||
│ Sécurité * │
|
||||
│ [ ▼ Aucune ] STARTTLS SSL/TLS │
|
||||
│ │
|
||||
│ ☐ Authentification requise │
|
||||
│ │
|
||||
│ Utilisateur SMTP │
|
||||
│ [_____________________________________________] │
|
||||
│ │
|
||||
│ Mot de passe SMTP │
|
||||
│ [_____________________________________________] │
|
||||
│ │
|
||||
│ Nom de l'expéditeur * │
|
||||
│ [_____________________________________________] │
|
||||
│ Ex: P'titsPas - Mairie de Bezons │
|
||||
│ │
|
||||
│ Email expéditeur * │
|
||||
│ [_____________________________________________] │
|
||||
│ Ex: noreply@mairie-bezons.fr │
|
||||
│ │
|
||||
│ [ 🧪 Tester la connexion SMTP ] │
|
||||
│ │
|
||||
│ ───────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ [ ← Précédent ] [ Suivant → ] │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Écran Paramètres (accès permanent)
|
||||
|
||||
Identique au Setup Initial, mais accessible depuis le menu admin :
|
||||
- Menu Admin → Paramètres → Configuration Système
|
||||
|
||||
---
|
||||
|
||||
## 📋 Exemples de configuration
|
||||
|
||||
### Configuration 1 : Mairie (serveur local)
|
||||
|
||||
```json
|
||||
{
|
||||
"smtp_host": "mail.mairie-bezons.fr",
|
||||
"smtp_port": 25,
|
||||
"smtp_secure": false,
|
||||
"smtp_auth_required": false,
|
||||
"email_from_name": "P'titsPas - Mairie de Bezons",
|
||||
"email_from_address": "noreply@mairie-bezons.fr",
|
||||
"app_name": "P'titsPas Bezons",
|
||||
"app_url": "https://ptitspas.mairie-bezons.fr"
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration 2 : Gmail (pour tests)
|
||||
|
||||
```json
|
||||
{
|
||||
"smtp_host": "smtp.gmail.com",
|
||||
"smtp_port": 587,
|
||||
"smtp_secure": false,
|
||||
"smtp_auth_required": true,
|
||||
"smtp_user": "contact@ptits-pas.fr",
|
||||
"smtp_password": "abcd efgh ijkl mnop",
|
||||
"email_from_name": "P'titsPas",
|
||||
"email_from_address": "contact@ptits-pas.fr",
|
||||
"app_name": "P'titsPas",
|
||||
"app_url": "https://app.ptits-pas.fr"
|
||||
}
|
||||
```
|
||||
|
||||
**Note** : Pour Gmail, utiliser un "Mot de passe d'application" (App Password)
|
||||
|
||||
### Configuration 3 : Office 365
|
||||
|
||||
```json
|
||||
{
|
||||
"smtp_host": "smtp.office365.com",
|
||||
"smtp_port": 587,
|
||||
"smtp_secure": false,
|
||||
"smtp_auth_required": true,
|
||||
"smtp_user": "noreply@collectivite.fr",
|
||||
"smtp_password": "MotDePasseSecurise123",
|
||||
"email_from_name": "P'titsPas - Collectivité",
|
||||
"email_from_address": "noreply@collectivite.fr",
|
||||
"app_name": "P'titsPas",
|
||||
"app_url": "https://ptitspas.collectivite.fr"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Sécurité
|
||||
|
||||
### Chiffrement des mots de passe
|
||||
|
||||
**Algorithme** : AES-256-CBC
|
||||
**Clé** : Variable d'environnement `CONFIG_ENCRYPTION_KEY` (32 caractères)
|
||||
|
||||
**Génération de la clé** :
|
||||
```bash
|
||||
# Linux/Mac
|
||||
openssl rand -hex 32
|
||||
|
||||
# Node.js
|
||||
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
||||
```
|
||||
|
||||
**Fichier `.env`** :
|
||||
```env
|
||||
CONFIG_ENCRYPTION_KEY=a3f8b2c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2
|
||||
```
|
||||
|
||||
### Variables d'environnement critiques
|
||||
|
||||
**Fichier `.env`** (à créer lors de l'installation) :
|
||||
|
||||
```env
|
||||
# Base de données
|
||||
DATABASE_URL=postgresql://app_user:password@ptitspas-postgres:5432/ptitpas_db
|
||||
|
||||
# JWT
|
||||
JWT_SECRET=VotreSecretJWTTresLongEtAleatoire123456789
|
||||
JWT_EXPIRY=24h
|
||||
|
||||
# Configuration
|
||||
CONFIG_ENCRYPTION_KEY=VotreCleDeChiffrementAES256TresLongue32Caracteres
|
||||
|
||||
# Application
|
||||
NODE_ENV=production
|
||||
PORT=3000
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Références
|
||||
|
||||
### Documentation interne
|
||||
- [01_CAHIER-DES-CHARGES.md](./01_CAHIER-DES-CHARGES.md)
|
||||
- [02_ARCHITECTURE.md](./02_ARCHITECTURE.md)
|
||||
- [03_DEPLOYMENT.md](./03_DEPLOYMENT.md)
|
||||
- [10_DATABASE.md](./10_DATABASE.md)
|
||||
- [11_API.md](./11_API.md)
|
||||
|
||||
### Documentation externe
|
||||
- [NestJS Configuration](https://docs.nestjs.com/techniques/configuration)
|
||||
- [Nodemailer SMTP](https://nodemailer.com/smtp/)
|
||||
- [Node.js Crypto](https://nodejs.org/api/crypto.html)
|
||||
|
||||
---
|
||||
|
||||
**Dernière mise à jour** : 25 Novembre 2025
|
||||
**Version** : 1.0
|
||||
**Statut** : ✅ Document validé
|
||||
|
||||
@@ -0,0 +1,698 @@
|
||||
# 📄 Documentation Technique - Gestion Documents Légaux (CGU/Privacy)
|
||||
|
||||
**Version** : 1.0
|
||||
**Date** : 25 Novembre 2025
|
||||
**Auteur** : Équipe PtitsPas
|
||||
**Référence** : RGPD & Conformité juridique
|
||||
|
||||
---
|
||||
|
||||
## 📖 Table des matières
|
||||
|
||||
1. [Vue d'ensemble](#vue-densemble)
|
||||
2. [Architecture](#architecture)
|
||||
3. [Tables BDD](#tables-bdd)
|
||||
4. [Service Documents Légaux](#service-documents-légaux)
|
||||
5. [Workflow Upload & Activation](#workflow-upload--activation)
|
||||
6. [Workflow Acceptation Utilisateur](#workflow-acceptation-utilisateur)
|
||||
7. [APIs](#apis)
|
||||
8. [Interface Admin](#interface-admin)
|
||||
9. [Conformité RGPD](#conformité-rgpd)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Vue d'ensemble
|
||||
|
||||
### Problématique
|
||||
|
||||
Chaque collectivité déployant P'titsPas on-premise doit pouvoir :
|
||||
1. ✅ **Personnaliser** les CGU et la Politique de confidentialité
|
||||
2. ✅ **Versionner** les documents (traçabilité juridique)
|
||||
3. ✅ **Tracer** qui a accepté quelle version (RGPD)
|
||||
4. ✅ **Prouver** l'acceptation (IP, User-Agent, horodatage)
|
||||
5. ✅ **Empêcher** le retour en arrière (sécurité juridique)
|
||||
|
||||
### Solution
|
||||
|
||||
- **Documents génériques v1** fournis par défaut (rédigés avec juriste)
|
||||
- **Upload de nouvelles versions** par l'admin (PDF uniquement)
|
||||
- **Versioning automatique** (incrémentation sans retour arrière)
|
||||
- **Activation manuelle** (prévisualisation avant mise en prod)
|
||||
- **Traçabilité complète** (hash SHA-256, IP, User-Agent)
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
### Flux de données
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Workflow Documents │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 1. UPLOAD (Admin) │
|
||||
│ Admin ──▶ API ──▶ File System ──▶ BDD │
|
||||
│ /documents/legaux/ │
|
||||
│ cgu_v4_<timestamp>.pdf │
|
||||
│ │
|
||||
│ 2. ACTIVATION (Admin) │
|
||||
│ Admin ──▶ API ──▶ BDD (actif=true) │
|
||||
│ │
|
||||
│ 3. ACCEPTATION (Utilisateur) │
|
||||
│ User ──▶ Frontend ──▶ API ──▶ BDD │
|
||||
│ (inscription) (trace IP/UA) │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Composants
|
||||
|
||||
1. **Table `documents_legaux`** : Stockage versions + métadonnées
|
||||
2. **Table `acceptations_documents`** : Traçabilité acceptations
|
||||
3. **Service `DocumentsLegauxService`** : Upload, versioning, activation
|
||||
4. **API REST** : CRUD documents
|
||||
5. **Interface Admin** : Upload + activation
|
||||
6. **Interface Inscription** : Affichage + acceptation
|
||||
|
||||
---
|
||||
|
||||
## 📊 Tables BDD
|
||||
|
||||
### Table 1 : `documents_legaux`
|
||||
|
||||
```sql
|
||||
-- Table pour gérer les versions des documents légaux
|
||||
CREATE TABLE documents_legaux (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
type VARCHAR(50) NOT NULL, -- 'cgu' ou 'privacy'
|
||||
version INTEGER NOT NULL, -- Numéro de version (auto-incrémenté)
|
||||
fichier_nom VARCHAR(255) NOT NULL, -- Nom original du fichier
|
||||
fichier_path VARCHAR(500) NOT NULL, -- Chemin de stockage
|
||||
fichier_hash VARCHAR(64) NOT NULL, -- Hash SHA-256 pour intégrité
|
||||
actif BOOLEAN DEFAULT false, -- Version actuellement active
|
||||
televerse_par UUID REFERENCES utilisateurs(id), -- Qui a uploadé
|
||||
televerse_le TIMESTAMPTZ DEFAULT now(), -- Date d'upload
|
||||
active_le TIMESTAMPTZ, -- Date d'activation
|
||||
UNIQUE(type, version) -- Pas de doublon version
|
||||
);
|
||||
|
||||
-- Index pour performance
|
||||
CREATE INDEX idx_documents_legaux_type_actif ON documents_legaux(type, actif);
|
||||
CREATE INDEX idx_documents_legaux_version ON documents_legaux(type, version DESC);
|
||||
```
|
||||
|
||||
**Contraintes** :
|
||||
- ✅ Un seul document `actif=true` par type à la fois
|
||||
- ✅ Versioning auto-incrémenté (pas de gaps)
|
||||
- ✅ Hash SHA-256 pour vérifier l'intégrité du fichier
|
||||
|
||||
---
|
||||
|
||||
### Table 2 : `acceptations_documents`
|
||||
|
||||
```sql
|
||||
-- Table de traçabilité des acceptations (RGPD)
|
||||
CREATE TABLE acceptations_documents (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
id_utilisateur UUID REFERENCES utilisateurs(id) ON DELETE CASCADE,
|
||||
id_document UUID REFERENCES documents_legaux(id),
|
||||
type_document VARCHAR(50) NOT NULL, -- 'cgu' ou 'privacy'
|
||||
version_document INTEGER NOT NULL, -- Version acceptée
|
||||
accepte_le TIMESTAMPTZ DEFAULT now(), -- Date d'acceptation
|
||||
ip_address INET, -- IP de l'utilisateur (RGPD)
|
||||
user_agent TEXT -- Navigateur (preuve)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_acceptations_utilisateur ON acceptations_documents(id_utilisateur);
|
||||
CREATE INDEX idx_acceptations_document ON acceptations_documents(id_document);
|
||||
```
|
||||
|
||||
**Données capturées** :
|
||||
- ✅ **Qui** : `id_utilisateur`
|
||||
- ✅ **Quoi** : `type_document`, `version_document`
|
||||
- ✅ **Quand** : `accepte_le`
|
||||
- ✅ **Où** : `ip_address`
|
||||
- ✅ **Comment** : `user_agent`
|
||||
|
||||
---
|
||||
|
||||
### Modification table `utilisateurs`
|
||||
|
||||
```sql
|
||||
-- Ajouter colonnes pour référence rapide (optionnel)
|
||||
ALTER TABLE utilisateurs
|
||||
ADD COLUMN cgu_version_acceptee INTEGER,
|
||||
ADD COLUMN cgu_acceptee_le TIMESTAMPTZ,
|
||||
ADD COLUMN privacy_version_acceptee INTEGER,
|
||||
ADD COLUMN privacy_acceptee_le TIMESTAMPTZ;
|
||||
```
|
||||
|
||||
**Note** : Ces colonnes sont **redondantes** avec `acceptations_documents`, mais permettent un accès rapide sans JOIN.
|
||||
|
||||
---
|
||||
|
||||
### Seed initial
|
||||
|
||||
```sql
|
||||
-- Documents génériques v1 (fournis par défaut)
|
||||
INSERT INTO documents_legaux (type, version, fichier_nom, fichier_path, fichier_hash, actif, televerse_le, active_le) VALUES
|
||||
('cgu', 1, 'cgu_v1_default.pdf', '/documents/legaux/cgu_v1_default.pdf', 'a3f8b2c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2', true, now(), now()),
|
||||
('privacy', 1, 'privacy_v1_default.pdf', '/documents/legaux/privacy_v1_default.pdf', 'b4f9c3d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4', true, now(), now());
|
||||
```
|
||||
|
||||
**Fichiers à fournir** :
|
||||
- `/documents/legaux/cgu_v1_default.pdf` (rédigé avec juriste)
|
||||
- `/documents/legaux/privacy_v1_default.pdf` (conforme RGPD)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Service Documents Légaux
|
||||
|
||||
### Responsabilités
|
||||
|
||||
1. **Récupérer documents actifs** : `getDocumentsActifs()`
|
||||
2. **Uploader nouvelle version** : `uploadNouvelleVersion(type, file, userId)`
|
||||
3. **Activer une version** : `activerVersion(documentId)`
|
||||
4. **Lister versions** : `listerVersions(type)`
|
||||
5. **Télécharger document** : `telechargerDocument(documentId)`
|
||||
|
||||
### Implémentation (TypeScript)
|
||||
|
||||
```typescript
|
||||
// backend/src/documents-legaux/documents-legaux.service.ts
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { DocumentLegal } from './entities/document-legal.entity';
|
||||
import * as crypto from 'crypto';
|
||||
import * as fs from 'fs/promises';
|
||||
import * as path from 'path';
|
||||
|
||||
@Injectable()
|
||||
export class DocumentsLegauxService {
|
||||
private readonly UPLOAD_DIR = '/app/documents/legaux';
|
||||
|
||||
constructor(
|
||||
@InjectRepository(DocumentLegal)
|
||||
private docRepo: Repository<DocumentLegal>,
|
||||
) {}
|
||||
|
||||
// Récupérer les documents actifs
|
||||
async getDocumentsActifs(): Promise<{ cgu: DocumentLegal; privacy: DocumentLegal }> {
|
||||
const cgu = await this.docRepo.findOne({
|
||||
where: { type: 'cgu', actif: true },
|
||||
});
|
||||
|
||||
const privacy = await this.docRepo.findOne({
|
||||
where: { type: 'privacy', actif: true },
|
||||
});
|
||||
|
||||
if (!cgu || !privacy) {
|
||||
throw new Error('Documents légaux manquants');
|
||||
}
|
||||
|
||||
return { cgu, privacy };
|
||||
}
|
||||
|
||||
// Uploader une nouvelle version
|
||||
async uploadNouvelleVersion(
|
||||
type: 'cgu' | 'privacy',
|
||||
file: Express.Multer.File,
|
||||
userId: string,
|
||||
): Promise<DocumentLegal> {
|
||||
// 1. Calculer la prochaine version
|
||||
const lastDoc = await this.docRepo.findOne({
|
||||
where: { type },
|
||||
order: { version: 'DESC' },
|
||||
});
|
||||
const nouvelleVersion = (lastDoc?.version || 0) + 1;
|
||||
|
||||
// 2. Calculer le hash du fichier
|
||||
const fileBuffer = file.buffer;
|
||||
const hash = crypto.createHash('sha256').update(fileBuffer).digest('hex');
|
||||
|
||||
// 3. Générer le nom de fichier unique
|
||||
const timestamp = Date.now();
|
||||
const fileName = `${type}_v${nouvelleVersion}_${timestamp}.pdf`;
|
||||
const filePath = path.join(this.UPLOAD_DIR, fileName);
|
||||
|
||||
// 4. Sauvegarder le fichier
|
||||
await fs.mkdir(this.UPLOAD_DIR, { recursive: true });
|
||||
await fs.writeFile(filePath, fileBuffer);
|
||||
|
||||
// 5. Créer l'entrée en BDD
|
||||
const document = this.docRepo.create({
|
||||
type,
|
||||
version: nouvelleVersion,
|
||||
fichier_nom: file.originalname,
|
||||
fichier_path: filePath,
|
||||
fichier_hash: hash,
|
||||
actif: false, // Pas actif par défaut
|
||||
televerse_par: userId,
|
||||
televerse_le: new Date(),
|
||||
});
|
||||
|
||||
return await this.docRepo.save(document);
|
||||
}
|
||||
|
||||
// Activer une version
|
||||
async activerVersion(documentId: string): Promise<void> {
|
||||
const document = await this.docRepo.findOne({ where: { id: documentId } });
|
||||
|
||||
if (!document) {
|
||||
throw new Error('Document non trouvé');
|
||||
}
|
||||
|
||||
// Transaction : désactiver l'ancienne version, activer la nouvelle
|
||||
await this.docRepo.manager.transaction(async (manager) => {
|
||||
// Désactiver toutes les versions de ce type
|
||||
await manager.update(
|
||||
DocumentLegal,
|
||||
{ type: document.type, actif: true },
|
||||
{ actif: false },
|
||||
);
|
||||
|
||||
// Activer la nouvelle version
|
||||
await manager.update(
|
||||
DocumentLegal,
|
||||
{ id: documentId },
|
||||
{ actif: true, active_le: new Date() },
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Lister toutes les versions (pour l'admin)
|
||||
async listerVersions(type: 'cgu' | 'privacy'): Promise<DocumentLegal[]> {
|
||||
return await this.docRepo.find({
|
||||
where: { type },
|
||||
order: { version: 'DESC' },
|
||||
relations: ['televerse_par'],
|
||||
});
|
||||
}
|
||||
|
||||
// Télécharger un document (stream)
|
||||
async telechargerDocument(documentId: string): Promise<{ stream: Buffer; filename: string }> {
|
||||
const document = await this.docRepo.findOne({ where: { id: documentId } });
|
||||
|
||||
if (!document) {
|
||||
throw new Error('Document non trouvé');
|
||||
}
|
||||
|
||||
const fileBuffer = await fs.readFile(document.fichier_path);
|
||||
|
||||
return {
|
||||
stream: fileBuffer,
|
||||
filename: document.fichier_nom,
|
||||
};
|
||||
}
|
||||
|
||||
// Vérifier l'intégrité d'un document
|
||||
async verifierIntegrite(documentId: string): Promise<boolean> {
|
||||
const document = await this.docRepo.findOne({ where: { id: documentId } });
|
||||
|
||||
if (!document) {
|
||||
throw new Error('Document non trouvé');
|
||||
}
|
||||
|
||||
const fileBuffer = await fs.readFile(document.fichier_path);
|
||||
const hash = crypto.createHash('sha256').update(fileBuffer).digest('hex');
|
||||
|
||||
return hash === document.fichier_hash;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Workflow Upload & Activation
|
||||
|
||||
### Diagramme de séquence
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant A as Admin
|
||||
participant API as Backend API
|
||||
participant FS as File System
|
||||
participant DB as PostgreSQL
|
||||
|
||||
A->>API: POST /api/v1/documents-legaux<br/>{type: 'cgu', file: PDF}
|
||||
|
||||
API->>API: Validation fichier<br/>(PDF, max 10MB)
|
||||
API->>API: Calcul hash SHA-256
|
||||
|
||||
API->>DB: SELECT MAX(version)<br/>WHERE type='cgu'
|
||||
DB-->>API: version = 3
|
||||
|
||||
API->>API: Nouvelle version = 4
|
||||
|
||||
API->>FS: Enregistrer fichier<br/>/documents/legaux/cgu_v4_<timestamp>.pdf
|
||||
FS-->>API: ✅ Fichier sauvegardé
|
||||
|
||||
API->>DB: INSERT INTO documents_legaux<br/>(type, version=4, actif=false)
|
||||
DB-->>API: ✅ Document créé
|
||||
|
||||
API-->>A: 201 Created<br/>{id, version: 4, actif: false}
|
||||
|
||||
A->>A: Prévisualisation PDF
|
||||
A->>API: PATCH /api/v1/documents-legaux/{id}/activer
|
||||
|
||||
API->>DB: BEGIN TRANSACTION
|
||||
API->>DB: UPDATE documents_legaux<br/>SET actif=false WHERE type='cgu'
|
||||
API->>DB: UPDATE documents_legaux<br/>SET actif=true, active_le=now()<br/>WHERE id={id}
|
||||
API->>DB: COMMIT
|
||||
|
||||
API-->>A: ✅ CGU v4 activées
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📥 Workflow Acceptation Utilisateur
|
||||
|
||||
### Diagramme de séquence
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant U as Utilisateur
|
||||
participant App as Frontend
|
||||
participant API as Backend
|
||||
participant DB as PostgreSQL
|
||||
|
||||
U->>App: Inscription (étape CGU)
|
||||
|
||||
App->>API: GET /api/v1/documents-legaux/actifs
|
||||
API->>DB: SELECT * FROM documents_legaux<br/>WHERE actif=true
|
||||
DB-->>API: {cgu: v4, privacy: v2}
|
||||
API-->>App: {cgu: {version: 4, url: '...'}, privacy: {...}}
|
||||
|
||||
App->>App: Afficher liens PDF<br/>"CGU v4" et "Privacy v2"
|
||||
|
||||
U->>U: Lit les documents
|
||||
U->>U: Coche "J'accepte"
|
||||
|
||||
App->>API: POST /api/v1/auth/register<br/>{..., cgu_version: 4, privacy_version: 2, ip, user_agent}
|
||||
|
||||
API->>DB: BEGIN TRANSACTION
|
||||
|
||||
API->>DB: INSERT INTO utilisateurs<br/>(..., cgu_version_acceptee=4, privacy_version_acceptee=2)
|
||||
DB-->>API: id_utilisateur
|
||||
|
||||
API->>DB: INSERT INTO acceptations_documents<br/>(id_utilisateur, type='cgu', version=4, ip, user_agent)
|
||||
API->>DB: INSERT INTO acceptations_documents<br/>(id_utilisateur, type='privacy', version=2, ip, user_agent)
|
||||
|
||||
API->>DB: COMMIT
|
||||
|
||||
API-->>App: ✅ Inscription réussie
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔌 APIs
|
||||
|
||||
### API 1 : Récupérer documents actifs (Public)
|
||||
|
||||
```http
|
||||
GET /api/v1/documents-legaux/actifs
|
||||
```
|
||||
|
||||
**Réponse 200** :
|
||||
```json
|
||||
{
|
||||
"cgu": {
|
||||
"id": "uuid-cgu-v4",
|
||||
"type": "cgu",
|
||||
"version": 4,
|
||||
"url": "/api/v1/documents-legaux/uuid-cgu-v4/download",
|
||||
"active_le": "2025-11-20T14:30:00Z"
|
||||
},
|
||||
"privacy": {
|
||||
"id": "uuid-privacy-v2",
|
||||
"type": "privacy",
|
||||
"version": 2,
|
||||
"url": "/api/v1/documents-legaux/uuid-privacy-v2/download",
|
||||
"active_le": "2025-10-15T09:15:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### API 2 : Lister versions (Admin)
|
||||
|
||||
```http
|
||||
GET /api/v1/documents-legaux/:type/versions
|
||||
Authorization: Bearer <super_admin_token>
|
||||
```
|
||||
|
||||
**Paramètres** :
|
||||
- `type` : `cgu` | `privacy`
|
||||
|
||||
**Réponse 200** :
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "uuid-cgu-v4",
|
||||
"version": 4,
|
||||
"fichier_nom": "CGU_Mairie_Bezons_2025.pdf",
|
||||
"actif": true,
|
||||
"televerse_par": {
|
||||
"id": "uuid-admin",
|
||||
"prenom": "Lucas",
|
||||
"nom": "MOREAU"
|
||||
},
|
||||
"televerse_le": "2025-11-20T14:00:00Z",
|
||||
"active_le": "2025-11-20T14:30:00Z"
|
||||
},
|
||||
{
|
||||
"id": "uuid-cgu-v3",
|
||||
"version": 3,
|
||||
"fichier_nom": "CGU_v3.pdf",
|
||||
"actif": false,
|
||||
"televerse_par": {
|
||||
"id": "uuid-admin",
|
||||
"prenom": "Admin",
|
||||
"nom": "Système"
|
||||
},
|
||||
"televerse_le": "2025-10-15T09:00:00Z",
|
||||
"active_le": "2025-10-15T09:15:00Z"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### API 3 : Upload nouvelle version (Admin)
|
||||
|
||||
```http
|
||||
POST /api/v1/documents-legaux
|
||||
Authorization: Bearer <super_admin_token>
|
||||
Content-Type: multipart/form-data
|
||||
```
|
||||
|
||||
**Body** :
|
||||
```
|
||||
type: cgu
|
||||
file: <fichier PDF>
|
||||
```
|
||||
|
||||
**Réponse 201** :
|
||||
```json
|
||||
{
|
||||
"id": "uuid-nouveau-doc",
|
||||
"type": "cgu",
|
||||
"version": 5,
|
||||
"fichier_nom": "CGU_Mairie_Bezons_2025_v2.pdf",
|
||||
"actif": false,
|
||||
"televerse_le": "2025-11-25T10:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
**Erreurs** :
|
||||
- `400 Bad Request` : Fichier non PDF ou trop volumineux (>10MB)
|
||||
- `401 Unauthorized` : Token manquant ou invalide
|
||||
- `403 Forbidden` : Rôle insuffisant (pas super_admin)
|
||||
|
||||
---
|
||||
|
||||
### API 4 : Activer une version (Admin)
|
||||
|
||||
```http
|
||||
PATCH /api/v1/documents-legaux/:id/activer
|
||||
Authorization: Bearer <super_admin_token>
|
||||
```
|
||||
|
||||
**Réponse 200** :
|
||||
```json
|
||||
{
|
||||
"message": "Document activé avec succès",
|
||||
"documentId": "uuid-nouveau-doc",
|
||||
"type": "cgu",
|
||||
"version": 5
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### API 5 : Télécharger document (Public)
|
||||
|
||||
```http
|
||||
GET /api/v1/documents-legaux/:id/download
|
||||
```
|
||||
|
||||
**Réponse 200** :
|
||||
```
|
||||
Content-Type: application/pdf
|
||||
Content-Disposition: attachment; filename="CGU_v5.pdf"
|
||||
|
||||
<binary PDF data>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### API 6 : Historique acceptations utilisateur (Admin)
|
||||
|
||||
```http
|
||||
GET /api/v1/users/:userId/acceptations
|
||||
Authorization: Bearer <super_admin_token>
|
||||
```
|
||||
|
||||
**Réponse 200** :
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type_document": "cgu",
|
||||
"version_document": 4,
|
||||
"accepte_le": "2025-11-20T15:30:00Z",
|
||||
"ip_address": "192.168.1.100",
|
||||
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
|
||||
},
|
||||
{
|
||||
"type_document": "privacy",
|
||||
"version_document": 2,
|
||||
"accepte_le": "2025-11-20T15:30:00Z",
|
||||
"ip_address": "192.168.1.100",
|
||||
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💻 Interface Admin
|
||||
|
||||
### Écran Gestion Documents Légaux
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 📄 Gestion des Documents Légaux │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ [ CGU ] [ Politique de confidentialité ] │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📋 Conditions Générales d'Utilisation (CGU) │
|
||||
│ │
|
||||
│ Version active : v4 │
|
||||
│ Activée le : 20/11/2025 14:30 │
|
||||
│ Téléversée par : Lucas MOREAU │
|
||||
│ │
|
||||
│ [ 📥 Télécharger ] [ 👁️ Prévisualiser ] │
|
||||
│ │
|
||||
│ ───────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ 📤 Uploader une nouvelle version │
|
||||
│ │
|
||||
│ ⚠️ Attention : L'upload d'une nouvelle version │
|
||||
│ créera la version v5. Vous pourrez la prévisualiser│
|
||||
│ avant de l'activer. │
|
||||
│ │
|
||||
│ [ Choisir un fichier PDF ] (max 10MB) │
|
||||
│ │
|
||||
│ [ 📤 Uploader ] │
|
||||
│ │
|
||||
│ ───────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ 📜 Historique des versions │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────┐ │
|
||||
│ │ ✅ v4 (Active) │ │
|
||||
│ │ Activée le : 20/11/2025 14:30 │ │
|
||||
│ │ Par : Lucas MOREAU │ │
|
||||
│ │ Hash : a3f8b2c4...e0f1a2 ✓ │ │
|
||||
│ │ [ 📥 Télécharger ] [ 👁️ Voir ] │ │
|
||||
│ └───────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────┐ │
|
||||
│ │ v3 (Inactive) │ │
|
||||
│ │ Activée le : 15/10/2025 09:15 │ │
|
||||
│ │ Par : Admin Système │ │
|
||||
│ │ Hash : b4f9c3d6...f2a3b4 ✓ │ │
|
||||
│ │ [ 📥 Télécharger ] [ 👁️ Voir ] [🔄 Réactiver]│ │
|
||||
│ └───────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Conformité RGPD
|
||||
|
||||
### Données capturées
|
||||
|
||||
| Donnée | Justification RGPD | Durée conservation |
|
||||
|--------|-------------------|-------------------|
|
||||
| `id_utilisateur` | Traçabilité acceptation | Durée du compte |
|
||||
| `version_document` | Preuve version acceptée | Durée du compte |
|
||||
| `accepte_le` | Horodatage légal | Durée du compte |
|
||||
| `ip_address` | Preuve origine acceptation | 1 an (recommandé) |
|
||||
| `user_agent` | Preuve navigateur/appareil | 1 an (recommandé) |
|
||||
|
||||
### Droits utilisateur
|
||||
|
||||
#### Droit d'accès (Article 15)
|
||||
L'utilisateur peut demander :
|
||||
- Quelles versions il a acceptées
|
||||
- Quand il les a acceptées
|
||||
- Depuis quelle IP
|
||||
|
||||
**API** : `GET /api/v1/users/me/acceptations`
|
||||
|
||||
#### Droit à l'oubli (Article 17)
|
||||
Lors de la suppression du compte :
|
||||
- Suppression des données personnelles
|
||||
- Conservation des acceptations anonymisées (obligation légale)
|
||||
|
||||
**Implémentation** :
|
||||
```sql
|
||||
-- Anonymisation (pas suppression totale)
|
||||
UPDATE acceptations_documents
|
||||
SET ip_address = NULL,
|
||||
user_agent = NULL
|
||||
WHERE id_utilisateur = '<uuid>';
|
||||
|
||||
-- Puis suppression utilisateur
|
||||
DELETE FROM utilisateurs WHERE id = '<uuid>';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Références
|
||||
|
||||
### Documentation interne
|
||||
- [01_CAHIER-DES-CHARGES.md](./01_CAHIER-DES-CHARGES.md)
|
||||
- [10_DATABASE.md](./10_DATABASE.md)
|
||||
- [11_API.md](./11_API.md)
|
||||
- [21_CONFIGURATION-SYSTEME.md](./21_CONFIGURATION-SYSTEME.md)
|
||||
|
||||
### Documentation externe
|
||||
- [RGPD - Article 7 (Consentement)](https://www.cnil.fr/fr/reglement-europeen-protection-donnees/chapitre2#Article7)
|
||||
- [RGPD - Article 15 (Droit d'accès)](https://www.cnil.fr/fr/reglement-europeen-protection-donnees/chapitre3#Article15)
|
||||
- [RGPD - Article 17 (Droit à l'oubli)](https://www.cnil.fr/fr/reglement-europeen-protection-donnees/chapitre3#Article17)
|
||||
|
||||
---
|
||||
|
||||
**Dernière mise à jour** : 25 Novembre 2025
|
||||
**Version** : 1.0
|
||||
**Statut** : ✅ Document validé
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,568 @@
|
||||
# 📋 Décisions Projet - P'titsPas
|
||||
|
||||
**Version** : 1.0
|
||||
**Date** : 25 Novembre 2025
|
||||
**Auteur** : Équipe PtitsPas
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Objectif de ce document
|
||||
|
||||
Ce document trace toutes les **décisions importantes** prises lors de la conception du projet P'titsPas. Il sert de référence pour comprendre les choix techniques et fonctionnels.
|
||||
|
||||
---
|
||||
|
||||
## 📊 Décisions Architecture
|
||||
|
||||
### 1. Mono-repo vs Multi-repo
|
||||
|
||||
**Décision** : ✅ **Mono-repo**
|
||||
|
||||
**Justification** :
|
||||
- Code cohérent dans un seul dépôt Git
|
||||
- Commits atomiques (frontend + backend + BDD en même temps)
|
||||
- CI/CD simplifié (un seul webhook)
|
||||
- Facilite le travail collaboratif
|
||||
|
||||
**Structure** :
|
||||
```
|
||||
ptitspas-app/
|
||||
├── frontend/ # Application Flutter
|
||||
├── backend/ # API NestJS
|
||||
├── database/ # Migrations SQL/Prisma
|
||||
├── api-contracts/ # Contrats OpenAPI + Prisma
|
||||
├── docs/ # Documentation
|
||||
└── docker-compose.yml # Orchestration
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Déploiement On-Premise
|
||||
|
||||
**Décision** : ✅ **Application on-premise avec configuration dynamique**
|
||||
|
||||
**Justification** :
|
||||
- Chaque collectivité a son infrastructure (SMTP, domaines, ports)
|
||||
- Autonomie totale (pas de dépendance à notre infra)
|
||||
- Conformité aux politiques IT locales
|
||||
- Sécurité (données restent dans le SI de la collectivité)
|
||||
|
||||
**Solution technique** :
|
||||
- Table `configuration` en BDD (clé/valeur)
|
||||
- Setup Wizard à la première connexion
|
||||
- Configuration SMTP dynamique
|
||||
- Personnalisation (nom app, logo, URL)
|
||||
|
||||
**Référence** : [21_CONFIGURATION-SYSTEME.md](./21_CONFIGURATION-SYSTEME.md)
|
||||
|
||||
---
|
||||
|
||||
### 3. Gestion des fichiers uploadés
|
||||
|
||||
**Décision** : ✅ **Système de fichiers local avec volume Docker**
|
||||
|
||||
**Justification** :
|
||||
- Simplicité (pas de S3/MinIO pour on-premise)
|
||||
- Performance (accès direct au disque)
|
||||
- Coût (pas de service externe)
|
||||
|
||||
**Solution technique** :
|
||||
- Stockage dans `/uploads/photos/`
|
||||
- Volume Docker persistant
|
||||
- Service Upload avec Multer
|
||||
- Validation taille (depuis config)
|
||||
|
||||
**Alternatives rejetées** :
|
||||
- ❌ Base de données (BYTEA) : Mauvaise performance
|
||||
- ❌ S3/MinIO : Overkill pour on-premise
|
||||
|
||||
---
|
||||
|
||||
### 4. Documents légaux (CGU/Privacy)
|
||||
|
||||
**Décision** : ✅ **Versioning automatique avec traçabilité RGPD**
|
||||
|
||||
**Justification** :
|
||||
- Conformité juridique (preuve d'acceptation)
|
||||
- Flexibilité (chaque collectivité adapte ses CGU)
|
||||
- Traçabilité (hash SHA-256, IP, User-Agent)
|
||||
- Sécurité juridique (pas de retour en arrière)
|
||||
|
||||
**Solution technique** :
|
||||
- Table `documents_legaux` (versioning auto-incrémenté)
|
||||
- Table `acceptations_documents` (traçabilité RGPD)
|
||||
- Upload PDF par l'admin
|
||||
- Activation manuelle après prévisualisation
|
||||
- Documents génériques v1 fournis par défaut
|
||||
|
||||
**Référence** : [22_DOCUMENTS-LEGAUX.md](./22_DOCUMENTS-LEGAUX.md)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Décisions Fonctionnelles
|
||||
|
||||
### 5. Workflow inscription sans mot de passe
|
||||
|
||||
**Décision** : ✅ **Pas de mot de passe lors de l'inscription, lien email après validation**
|
||||
|
||||
**Justification** :
|
||||
- Simplifie l'inscription (moins de friction)
|
||||
- Adapté aux parents séparés/divorcés (communication difficile)
|
||||
- Sécurité (token UUID avec expiration)
|
||||
- Validation gestionnaire avant activation
|
||||
|
||||
**Workflow** :
|
||||
1. Parent/AM s'inscrit (sans MDP)
|
||||
2. Gestionnaire valide
|
||||
3. Email envoyé avec lien création MDP (valable 7 jours)
|
||||
4. Utilisateur crée son MDP
|
||||
5. Compte activé
|
||||
|
||||
**Référence** : [20_WORKFLOW-CREATION-COMPTE.md](./20_WORKFLOW-CREATION-COMPTE.md)
|
||||
|
||||
---
|
||||
|
||||
### 6. Genre enfant obligatoire (H/F)
|
||||
|
||||
**Décision** : ✅ **Genre obligatoire (H/F uniquement)**
|
||||
|
||||
**Justification** :
|
||||
- Contexte métier : Enfants à garder (pas de genre neutre)
|
||||
- Conformité CDC
|
||||
- Simplicité
|
||||
|
||||
**Implémentation** :
|
||||
- Champ `genre` ENUM('H', 'F') NOT NULL dans table `enfants`
|
||||
|
||||
---
|
||||
|
||||
### 7. Suppression champs téléphone
|
||||
|
||||
**Décision** : ✅ **Un seul champ "Téléphone" (mobile privilégié)**
|
||||
|
||||
**Justification** :
|
||||
- Simplification (plus besoin de "Mobile" et "Téléphone fixe")
|
||||
- Réalité terrain : Tout le monde a un mobile
|
||||
- Note dans l'interface : "(mobile privilégié)"
|
||||
|
||||
**Implémentation** :
|
||||
- Supprimer `mobile` et `telephone_fixe`
|
||||
- Garder uniquement `telephone`
|
||||
|
||||
---
|
||||
|
||||
### 8. NIR obligatoire pour Assistantes Maternelles
|
||||
|
||||
**Décision** : ✅ **NIR (Numéro de Sécurité sociale) obligatoire**
|
||||
|
||||
**Justification** :
|
||||
- Conformité CDC
|
||||
- Nécessaire pour génération automatique du contrat
|
||||
- Stockage sécurisé (chiffrement recommandé)
|
||||
|
||||
**Implémentation** :
|
||||
- Champ `nir_chiffre` VARCHAR(15) NOT NULL dans `assistantes_maternelles`
|
||||
- Validation : 15 chiffres exactement
|
||||
- Affichage masqué dans l'interface (XXX XX XX XX XXX 123)
|
||||
|
||||
---
|
||||
|
||||
### 9. Suppression notifications SMS
|
||||
|
||||
**Décision** : ✅ **Supprimer les notifications SMS, garder uniquement Email**
|
||||
|
||||
**Justification** :
|
||||
- Pas de plus-value identifiée
|
||||
- Coût supplémentaire (service SMS)
|
||||
- Complexité (intégration Twilio/OVH)
|
||||
- Email suffit largement
|
||||
|
||||
**Action** :
|
||||
- Amender le CDC v1.4
|
||||
- Remplacer "Email OU SMS" par "Email"
|
||||
- Supprimer toute mention de SMS
|
||||
|
||||
**Référence** : Ticket #57
|
||||
|
||||
---
|
||||
|
||||
## 🚫 Décisions Phase 2 (reportées)
|
||||
|
||||
### 10. Gestion erreurs SMTP (renvoyer email)
|
||||
|
||||
**Décision** : ⏸️ **Phase 2 ou cas par cas**
|
||||
|
||||
**Justification** :
|
||||
- Pas prioritaire pour MVP
|
||||
- Downtime SMTP rare (< 24h)
|
||||
- Recréation dossier acceptable en phase de test
|
||||
- Peut être ajouté plus tard si besoin terrain
|
||||
|
||||
---
|
||||
|
||||
### 11. Sauvegarde & Restauration automatique
|
||||
|
||||
**Décision** : ⏸️ **Phase finale (quand tout fonctionne)**
|
||||
|
||||
**Justification** :
|
||||
- Pas bloquant pour développement
|
||||
- Nécessite application stable
|
||||
- Script `pg_dump` simple à ajouter
|
||||
- Documentation pour admins sys
|
||||
|
||||
**À faire** :
|
||||
- Script `backup.sh` avec cron
|
||||
- Guide sauvegarde/restauration
|
||||
- Test restauration
|
||||
|
||||
---
|
||||
|
||||
### 12. RGPD avancé (droit à l'oubli, export données)
|
||||
|
||||
**Décision** : ⏸️ **Phase 2**
|
||||
|
||||
**Justification** :
|
||||
- Conformité de base assurée (consentement, traçabilité)
|
||||
- Droit à l'oubli : Peu de demandes en phase test
|
||||
- Export données : Peut être fait manuellement en phase test
|
||||
|
||||
**À faire** :
|
||||
- API suppression compte (soft delete)
|
||||
- API export données personnelles (JSON)
|
||||
- Anonymisation comptes inactifs
|
||||
|
||||
---
|
||||
|
||||
### 13. Statistiques dashboard
|
||||
|
||||
**Décision** : ⏸️ **Phase 2 (besoin d'utilisateurs d'abord)**
|
||||
|
||||
**Justification** :
|
||||
- Pas de données = pas de statistiques
|
||||
- Fonctionnalité importante pour vente
|
||||
- Nécessite application en production
|
||||
|
||||
**À faire** :
|
||||
- API statistiques (comptes, enfants, AM, validations)
|
||||
- Widgets dashboard (graphiques)
|
||||
- Export rapports
|
||||
|
||||
---
|
||||
|
||||
### 14. Migration de données
|
||||
|
||||
**Décision** : ❌ **Pas de migration prévue**
|
||||
|
||||
**Justification** :
|
||||
- Pas de système existant à migrer
|
||||
- Application nouvelle
|
||||
- Import CSV peut être ajouté cas par cas si besoin
|
||||
|
||||
---
|
||||
|
||||
### 15. Documentation utilisateur
|
||||
|
||||
**Décision** : ⏸️ **Phase 2 (formation présentiel prioritaire)**
|
||||
|
||||
**Justification** :
|
||||
- Premiers utilisateurs : Formation directe par l'équipe
|
||||
- Documentation nécessaire pour scalabilité
|
||||
- Vidéos tutoriels utiles mais pas bloquant
|
||||
|
||||
**À faire** :
|
||||
- Guide utilisateur gestionnaire
|
||||
- Guide utilisateur parent/AM
|
||||
- FAQ
|
||||
- Vidéos tutoriels
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Décisions Sécurité
|
||||
|
||||
### 16. Chiffrement mots de passe configuration
|
||||
|
||||
**Décision** : ✅ **AES-256-CBC pour mots de passe SMTP**
|
||||
|
||||
**Justification** :
|
||||
- Sécurité (mots de passe SMTP en clair = risque)
|
||||
- Conformité sécurité
|
||||
- Déchiffrement uniquement en mémoire
|
||||
|
||||
**Implémentation** :
|
||||
- Type `encrypted` dans table `configuration`
|
||||
- Clé de chiffrement dans `.env` (32 caractères)
|
||||
- Service ConfigService gère chiffrement/déchiffrement
|
||||
|
||||
---
|
||||
|
||||
### 17. Hash mots de passe utilisateurs
|
||||
|
||||
**Décision** : ✅ **Bcrypt avec 12 rounds**
|
||||
|
||||
**Justification** :
|
||||
- Standard industrie
|
||||
- Résistant aux attaques brute-force
|
||||
- Configurable (rounds dans config)
|
||||
|
||||
---
|
||||
|
||||
### 18. Tokens création mot de passe
|
||||
|
||||
**Décision** : ✅ **UUID avec expiration 7 jours**
|
||||
|
||||
**Justification** :
|
||||
- Sécurité (UUID impossible à deviner)
|
||||
- Expiration (limite fenêtre d'attaque)
|
||||
- Durée configurable (dans table `configuration`)
|
||||
|
||||
---
|
||||
|
||||
### 19. JWT sessions
|
||||
|
||||
**Décision** : ✅ **JWT avec expiration 24h**
|
||||
|
||||
**Justification** :
|
||||
- Stateless (pas de session en BDD)
|
||||
- Performance (pas de lookup BDD à chaque requête)
|
||||
- Durée configurable
|
||||
|
||||
---
|
||||
|
||||
## 📊 Décisions Base de Données
|
||||
|
||||
### 20. PostgreSQL vs autres SGBD
|
||||
|
||||
**Décision** : ✅ **PostgreSQL 17**
|
||||
|
||||
**Justification** :
|
||||
- Open-source
|
||||
- Robuste et performant
|
||||
- Support JSON (flexibilité)
|
||||
- Support UUID natif
|
||||
- Communauté active
|
||||
|
||||
---
|
||||
|
||||
### 21. ORM : Prisma vs TypeORM
|
||||
|
||||
**Décision** : ✅ **Prisma** (mais TypeORM déjà en place)
|
||||
|
||||
**Justification Prisma** :
|
||||
- Type-safety
|
||||
- Migrations claires
|
||||
- Génération client automatique
|
||||
|
||||
**Note** : Le projet YNOV utilise TypeORM. À évaluer si migration vers Prisma nécessaire.
|
||||
|
||||
---
|
||||
|
||||
### 22. Migrations versionnées
|
||||
|
||||
**Décision** : ✅ **Migrations SQL versionnées**
|
||||
|
||||
**Justification** :
|
||||
- Traçabilité des changements schéma
|
||||
- Rollback possible
|
||||
- Déploiement automatisé
|
||||
|
||||
**Implémentation** :
|
||||
- Fichiers `XX_nom_migration.sql`
|
||||
- Exécution via `prisma migrate deploy`
|
||||
- User `app_admin` pour DDL
|
||||
- User `app_user` pour DML (runtime)
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Décisions Tests
|
||||
|
||||
### 23. Stratégie de tests
|
||||
|
||||
**Décision** : ✅ **Tests unitaires + intégration + E2E**
|
||||
|
||||
**Justification** :
|
||||
- Qualité code
|
||||
- Confiance déploiement
|
||||
- Détection régression
|
||||
|
||||
**Couverture cible** :
|
||||
- Tests unitaires : > 80%
|
||||
- Tests intégration : Workflows complets
|
||||
- Tests E2E : Parcours utilisateurs critiques
|
||||
|
||||
---
|
||||
|
||||
## 📝 Décisions Documentation
|
||||
|
||||
### 24. Structure documentation
|
||||
|
||||
**Décision** : ✅ **Documentation centralisée dans `/docs/` avec numérotation**
|
||||
|
||||
**Justification** :
|
||||
- Lisibilité (ordre logique)
|
||||
- Maintenance (tout au même endroit)
|
||||
- Versioning (Git)
|
||||
|
||||
**Structure** :
|
||||
```
|
||||
docs/
|
||||
├── 00_INDEX.md
|
||||
├── 01_CAHIER-DES-CHARGES.md
|
||||
├── 02_ARCHITECTURE.md
|
||||
├── 03_DEPLOYMENT.md
|
||||
├── 10_DATABASE.md
|
||||
├── 11_API.md
|
||||
├── 20_WORKFLOW-CREATION-COMPTE.md
|
||||
├── 21_CONFIGURATION-SYSTEME.md
|
||||
├── 22_DOCUMENTS-LEGAUX.md
|
||||
├── 23_LISTE-TICKETS.md
|
||||
├── 24_DECISIONS-PROJET.md (ce document)
|
||||
├── 90_AUDIT.md
|
||||
└── test-data/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Décisions Workflow
|
||||
|
||||
### 25. Gitea + Webhook + Déploiement automatique
|
||||
|
||||
**Décision** : ✅ **Déploiement automatique sur push master**
|
||||
|
||||
**Justification** :
|
||||
- Productivité (pas de déploiement manuel)
|
||||
- Fiabilité (script testé)
|
||||
- Rapidité (feedback immédiat)
|
||||
|
||||
**Workflow** :
|
||||
1. Push sur `master`
|
||||
2. Webhook Gitea déclenché
|
||||
3. Script `deploy-ptitspas.sh` exécuté
|
||||
4. Git pull + Migrations + Docker rebuild + Restart
|
||||
|
||||
---
|
||||
|
||||
### 26. Branches Git
|
||||
|
||||
**Décision** : ✅ **Stratégie simple : master + feature branches**
|
||||
|
||||
**Justification** :
|
||||
- Simplicité (petite équipe)
|
||||
- Flexibilité
|
||||
|
||||
**Branches** :
|
||||
- `master` : Production
|
||||
- `archive/*` : Archives (ex: maquette initiale)
|
||||
- `migration/*` : Migrations (ex: intégration YNOV)
|
||||
- `feature/*` : Nouvelles fonctionnalités
|
||||
|
||||
---
|
||||
|
||||
## 🎫 Décisions Ticketing
|
||||
|
||||
### 27. Taille des tickets
|
||||
|
||||
**Décision** : ✅ **Tickets relativement petits (2-6h)**
|
||||
|
||||
**Justification** :
|
||||
- Granularité (suivi précis)
|
||||
- Motivation (tickets terminables rapidement)
|
||||
- Revue de code facilitée
|
||||
|
||||
---
|
||||
|
||||
### 28. Organisation tickets
|
||||
|
||||
**Décision** : ✅ **1 ticket = 1 fonctionnalité complète (Front + Back + BDD si nécessaire)**
|
||||
|
||||
**Justification** :
|
||||
- Cohérence (toute la feature développée ensemble)
|
||||
- Testable (end-to-end immédiatement)
|
||||
- Atomique (livraison de valeur fonctionnelle)
|
||||
|
||||
**Alternative rejetée** :
|
||||
- ❌ 1 ticket Front + 1 ticket Back + 1 ticket BDD = Dépendances complexes
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Décisions Déploiement
|
||||
|
||||
### 29. Docker Compose vs Kubernetes
|
||||
|
||||
**Décision** : ✅ **Docker Compose**
|
||||
|
||||
**Justification** :
|
||||
- Simplicité (on-premise petite/moyenne collectivité)
|
||||
- Pas de besoin de scalabilité horizontale
|
||||
- Maintenance facile
|
||||
|
||||
**Alternative rejetée** :
|
||||
- ❌ Kubernetes : Overkill pour on-premise mono-instance
|
||||
|
||||
---
|
||||
|
||||
### 30. Traefik comme reverse proxy
|
||||
|
||||
**Décision** : ✅ **Traefik**
|
||||
|
||||
**Justification** :
|
||||
- Configuration automatique (labels Docker)
|
||||
- SSL Let's Encrypt automatique
|
||||
- Dashboard intégré
|
||||
|
||||
---
|
||||
|
||||
## 📊 Logs & Monitoring
|
||||
|
||||
### 31. Système de logs
|
||||
|
||||
**Décision** : ✅ **Winston avec rotation quotidienne**
|
||||
|
||||
**Justification** :
|
||||
- Standard NestJS
|
||||
- Rotation automatique (pas de disque plein)
|
||||
- Niveaux de log (info, warn, error)
|
||||
- Transports multiples (console + fichier)
|
||||
|
||||
**Logs à capturer** :
|
||||
- Logs applicatifs (info, warn, error)
|
||||
- Logs emails (succès/échec SMTP)
|
||||
- Logs connexions (qui se connecte quand)
|
||||
- Logs validations (qui valide quoi)
|
||||
|
||||
---
|
||||
|
||||
## 📋 Résumé des décisions critiques
|
||||
|
||||
| # | Décision | Statut | Impact |
|
||||
|---|----------|--------|--------|
|
||||
| 1 | Mono-repo | ✅ Phase 1 | Architecture |
|
||||
| 2 | On-premise avec config dynamique | ✅ Phase 1 | Déploiement |
|
||||
| 3 | Système de fichiers pour uploads | ✅ Phase 1 | Stockage |
|
||||
| 4 | Versioning documents légaux | ✅ Phase 1 | RGPD |
|
||||
| 5 | Inscription sans MDP | ✅ Phase 1 | UX |
|
||||
| 6 | Genre enfant obligatoire (H/F) | ✅ Phase 1 | Métier |
|
||||
| 7 | Un seul champ téléphone | ✅ Phase 1 | Simplification |
|
||||
| 8 | NIR obligatoire AM | ✅ Phase 1 | Conformité |
|
||||
| 9 | Suppression SMS | ✅ Phase 1 | Simplification |
|
||||
| 10 | Renvoyer email | ⏸️ Phase 2 | Nice-to-have |
|
||||
| 11 | Sauvegarde auto | ⏸️ Phase finale | Ops |
|
||||
| 12 | RGPD avancé | ⏸️ Phase 2 | Conformité |
|
||||
| 13 | Statistiques | ⏸️ Phase 2 | Business |
|
||||
| 14 | Migration données | ❌ Rejeté | N/A |
|
||||
| 15 | Doc utilisateur | ⏸️ Phase 2 | Formation |
|
||||
| 31 | Logs Winston | ✅ Phase 1 | Monitoring |
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Historique des modifications
|
||||
|
||||
| Date | Version | Modifications |
|
||||
|------|---------|---------------|
|
||||
| 25/11/2025 | 1.0 | Création du document - Toutes les décisions initiales |
|
||||
|
||||
---
|
||||
|
||||
**Dernière mise à jour** : 25 Novembre 2025
|
||||
**Version** : 1.0
|
||||
**Statut** : ✅ Document validé
|
||||
|
||||
@@ -0,0 +1,433 @@
|
||||
# 📋 Backlog Phase 2 - P'titsPas
|
||||
|
||||
**Version** : 1.0
|
||||
**Date** : 25 Novembre 2025
|
||||
**Auteur** : Équipe PtitsPas
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Objectif de ce document
|
||||
|
||||
Ce document liste toutes les **fonctionnalités reportées en Phase 2**. Ces fonctionnalités ne sont pas bloquantes pour le MVP (Phase 1), mais apportent de la valeur ajoutée pour la production intensive.
|
||||
|
||||
---
|
||||
|
||||
## 📊 Vue d'ensemble
|
||||
|
||||
| Catégorie | Nombre de tickets | Estimation |
|
||||
|-----------|-------------------|------------|
|
||||
| **RGPD avancé** | 3 tickets | ~8h |
|
||||
| **Monitoring avancé** | 2 tickets | ~6h |
|
||||
| **Statistiques & Reporting** | 4 tickets | ~16h |
|
||||
| **Sauvegarde & Restauration** | 2 tickets | ~6h |
|
||||
| **Documentation utilisateur** | 3 tickets | ~12h |
|
||||
| **Améliorations UX** | 3 tickets | ~10h |
|
||||
| **TOTAL** | **17 tickets** | **~58h** |
|
||||
|
||||
---
|
||||
|
||||
## 🔒 RGPD avancé
|
||||
|
||||
### Ticket P2-01 : [Backend] API Suppression compte (soft delete)
|
||||
**Estimation** : 3h
|
||||
**Labels** : `backend`, `phase-2`, `rgpd`
|
||||
|
||||
**Description** :
|
||||
Implémenter le droit à l'oubli (RGPD Article 17) avec suppression logique des comptes.
|
||||
|
||||
**Tâches** :
|
||||
- [ ] Endpoint `DELETE /api/v1/users/:id` (soft delete)
|
||||
- [ ] Ajout champ `supprime_le` TIMESTAMPTZ dans `utilisateurs`
|
||||
- [ ] Anonymisation données personnelles (email, téléphone, adresse)
|
||||
- [ ] Conservation données légales (acceptations CGU)
|
||||
- [ ] Guards (super_admin only)
|
||||
- [ ] Tests unitaires
|
||||
|
||||
**Justification report Phase 2** :
|
||||
- Peu de demandes en phase test
|
||||
- Suppression manuelle possible en attendant
|
||||
|
||||
---
|
||||
|
||||
### Ticket P2-02 : [Backend] API Export données personnelles (RGPD)
|
||||
**Estimation** : 3h
|
||||
**Labels** : `backend`, `phase-2`, `rgpd`
|
||||
|
||||
**Description** :
|
||||
Implémenter le droit à la portabilité (RGPD Article 20) avec export JSON des données personnelles.
|
||||
|
||||
**Tâches** :
|
||||
- [ ] Endpoint `GET /api/v1/users/:id/export` (JSON)
|
||||
- [ ] Export données utilisateur + enfants + acceptations
|
||||
- [ ] Format JSON structuré
|
||||
- [ ] Guards (utilisateur lui-même ou admin)
|
||||
- [ ] Tests unitaires
|
||||
|
||||
**Justification report Phase 2** :
|
||||
- Export manuel SQL possible en phase test
|
||||
- Peu de demandes attendues
|
||||
|
||||
---
|
||||
|
||||
### Ticket P2-03 : [Backend] Cron anonymisation comptes inactifs
|
||||
**Estimation** : 2h
|
||||
**Labels** : `backend`, `phase-2`, `rgpd`, `cron`
|
||||
|
||||
**Description** :
|
||||
Anonymiser automatiquement les comptes inactifs après X mois (configurable).
|
||||
|
||||
**Tâches** :
|
||||
- [ ] Cron job quotidien
|
||||
- [ ] Détection comptes inactifs (dernière connexion > X mois)
|
||||
- [ ] Anonymisation automatique
|
||||
- [ ] Notification admin
|
||||
- [ ] Configuration durée inactivité (table `configuration`)
|
||||
- [ ] Tests
|
||||
|
||||
**Justification report Phase 2** :
|
||||
- Pas de comptes inactifs en phase test
|
||||
- Peut être fait manuellement
|
||||
|
||||
---
|
||||
|
||||
## 📊 Monitoring avancé
|
||||
|
||||
### Ticket P2-04 : [Backend] API Métriques système
|
||||
**Estimation** : 3h
|
||||
**Labels** : `backend`, `phase-2`, `monitoring`
|
||||
|
||||
**Description** :
|
||||
Exposer des métriques système (CPU, RAM, disque, BDD) pour monitoring.
|
||||
|
||||
**Tâches** :
|
||||
- [ ] Endpoint `GET /api/v1/metrics` (super_admin only)
|
||||
- [ ] Métriques système (CPU, RAM, disque)
|
||||
- [ ] Métriques BDD (connexions, taille, requêtes lentes)
|
||||
- [ ] Métriques application (requêtes/s, temps réponse)
|
||||
- [ ] Format Prometheus (optionnel)
|
||||
- [ ] Tests
|
||||
|
||||
**Justification report Phase 2** :
|
||||
- Pas critique pour MVP
|
||||
- Logs suffisent pour debugging initial
|
||||
|
||||
---
|
||||
|
||||
### Ticket P2-05 : [Frontend] Dashboard Monitoring
|
||||
**Estimation** : 3h
|
||||
**Labels** : `frontend`, `phase-2`, `monitoring`, `admin`
|
||||
|
||||
**Description** :
|
||||
Créer un dashboard de monitoring pour le super admin.
|
||||
|
||||
**Tâches** :
|
||||
- [ ] Page `/admin/monitoring` (super_admin only)
|
||||
- [ ] Graphiques temps réel (CPU, RAM, disque)
|
||||
- [ ] Alertes (seuils configurables)
|
||||
- [ ] Historique métriques (7 jours)
|
||||
|
||||
**Justification report Phase 2** :
|
||||
- Pas critique pour MVP
|
||||
- Monitoring serveur possible via outils système
|
||||
|
||||
---
|
||||
|
||||
## 📈 Statistiques & Reporting
|
||||
|
||||
### Ticket P2-06 : [Backend] API Statistiques dashboard
|
||||
**Estimation** : 4h
|
||||
**Labels** : `backend`, `phase-2`, `statistiques`
|
||||
|
||||
**Description** :
|
||||
Créer les endpoints pour récupérer les statistiques de l'application.
|
||||
|
||||
**Tâches** :
|
||||
- [ ] Endpoint `GET /api/v1/stats/overview`
|
||||
- [ ] Statistiques globales (comptes, enfants, AM, validations)
|
||||
- [ ] Statistiques temporelles (inscriptions par mois, validations par semaine)
|
||||
- [ ] Statistiques géographiques (par ville)
|
||||
- [ ] Cache (rafraîchissement toutes les heures)
|
||||
- [ ] Tests
|
||||
|
||||
**Justification report Phase 2** :
|
||||
- Pas de données = pas de statistiques
|
||||
- Nécessite application en production
|
||||
|
||||
---
|
||||
|
||||
### Ticket P2-07 : [Frontend] Widgets statistiques dashboard
|
||||
**Estimation** : 4h
|
||||
**Labels** : `frontend`, `phase-2`, `statistiques`, `gestionnaire`
|
||||
|
||||
**Description** :
|
||||
Afficher les statistiques dans le dashboard gestionnaire.
|
||||
|
||||
**Tâches** :
|
||||
- [ ] Widget "Comptes en attente" (nombre)
|
||||
- [ ] Widget "Comptes validés ce mois" (graphique)
|
||||
- [ ] Widget "Enfants inscrits" (nombre)
|
||||
- [ ] Widget "AM disponibles" (nombre)
|
||||
- [ ] Graphique évolution inscriptions (6 derniers mois)
|
||||
|
||||
**Justification report Phase 2** :
|
||||
- Besoin d'utilisateurs réels pour avoir des données
|
||||
- Fonctionnalité importante pour vente, mais pas bloquante pour MVP
|
||||
|
||||
---
|
||||
|
||||
### Ticket P2-08 : [Backend] API Export rapports (CSV/PDF)
|
||||
**Estimation** : 4h
|
||||
**Labels** : `backend`, `phase-2`, `reporting`
|
||||
|
||||
**Description** :
|
||||
Permettre l'export de rapports pour les gestionnaires.
|
||||
|
||||
**Tâches** :
|
||||
- [ ] Endpoint `GET /api/v1/reports/users` (CSV)
|
||||
- [ ] Endpoint `GET /api/v1/reports/validations` (CSV)
|
||||
- [ ] Endpoint `GET /api/v1/reports/summary` (PDF)
|
||||
- [ ] Génération PDF (librairie PDFKit)
|
||||
- [ ] Filtres (date, statut, rôle)
|
||||
- [ ] Tests
|
||||
|
||||
**Justification report Phase 2** :
|
||||
- Export manuel SQL possible en phase test
|
||||
- Nécessite données réelles
|
||||
|
||||
---
|
||||
|
||||
### Ticket P2-09 : [Frontend] Écran Rapports
|
||||
**Estimation** : 4h
|
||||
**Labels** : `frontend`, `phase-2`, `reporting`, `gestionnaire`
|
||||
|
||||
**Description** :
|
||||
Créer un écran de génération de rapports pour les gestionnaires.
|
||||
|
||||
**Tâches** :
|
||||
- [ ] Page `/admin/rapports` (gestionnaire/admin)
|
||||
- [ ] Sélection type de rapport (utilisateurs, validations, synthèse)
|
||||
- [ ] Filtres (date, statut, rôle)
|
||||
- [ ] Prévisualisation
|
||||
- [ ] Téléchargement (CSV/PDF)
|
||||
|
||||
**Justification report Phase 2** :
|
||||
- Pas prioritaire pour MVP
|
||||
- Nécessite données réelles
|
||||
|
||||
---
|
||||
|
||||
## 💾 Sauvegarde & Restauration
|
||||
|
||||
### Ticket P2-10 : [Infra] Script backup PostgreSQL automatique
|
||||
**Estimation** : 3h
|
||||
**Labels** : `infra`, `phase-2`, `backup`
|
||||
|
||||
**Description** :
|
||||
Créer un script de sauvegarde automatique de la base de données.
|
||||
|
||||
**Tâches** :
|
||||
- [ ] Script `backup.sh` avec `pg_dump`
|
||||
- [ ] Compression (gzip)
|
||||
- [ ] Rotation (garder 30 derniers jours)
|
||||
- [ ] Cron job quotidien (3h du matin)
|
||||
- [ ] Notification email en cas d'échec
|
||||
- [ ] Tests restauration
|
||||
|
||||
**Justification report Phase 2** :
|
||||
- Pas bloquant pour développement
|
||||
- Backup manuel possible en phase test
|
||||
- À faire avant mise en production
|
||||
|
||||
---
|
||||
|
||||
### Ticket P2-11 : [Doc] Guide sauvegarde & restauration
|
||||
**Estimation** : 3h
|
||||
**Labels** : `documentation`, `phase-2`, `backup`
|
||||
|
||||
**Description** :
|
||||
Documenter les procédures de sauvegarde et restauration pour les admins sys.
|
||||
|
||||
**Tâches** :
|
||||
- [ ] Procédure sauvegarde manuelle
|
||||
- [ ] Procédure restauration
|
||||
- [ ] Configuration cron
|
||||
- [ ] Troubleshooting
|
||||
- [ ] Exemples de commandes
|
||||
- [ ] Checklist pré-restauration
|
||||
|
||||
**Justification report Phase 2** :
|
||||
- Documentation technique, pas bloquante pour MVP
|
||||
- À faire avant mise en production
|
||||
|
||||
---
|
||||
|
||||
## 📚 Documentation utilisateur
|
||||
|
||||
### Ticket P2-12 : [Doc] Guide utilisateur Gestionnaire
|
||||
**Estimation** : 4h
|
||||
**Labels** : `documentation`, `phase-2`, `formation`
|
||||
|
||||
**Description** :
|
||||
Rédiger le guide utilisateur pour les gestionnaires.
|
||||
|
||||
**Tâches** :
|
||||
- [ ] Connexion et première utilisation
|
||||
- [ ] Consultation des demandes
|
||||
- [ ] Validation/Refus de comptes
|
||||
- [ ] Gestion des paramètres
|
||||
- [ ] FAQ gestionnaire
|
||||
- [ ] Captures d'écran
|
||||
|
||||
**Justification report Phase 2** :
|
||||
- Formation présentiel prioritaire pour premiers utilisateurs
|
||||
- Documentation nécessaire pour scalabilité
|
||||
|
||||
---
|
||||
|
||||
### Ticket P2-13 : [Doc] Guide utilisateur Parent/AM
|
||||
**Estimation** : 4h
|
||||
**Labels** : `documentation`, `phase-2`, `formation`
|
||||
|
||||
**Description** :
|
||||
Rédiger le guide utilisateur pour les parents et assistantes maternelles.
|
||||
|
||||
**Tâches** :
|
||||
- [ ] Inscription étape par étape
|
||||
- [ ] Création du mot de passe
|
||||
- [ ] Connexion
|
||||
- [ ] Utilisation de l'application
|
||||
- [ ] FAQ parent/AM
|
||||
- [ ] Captures d'écran
|
||||
|
||||
**Justification report Phase 2** :
|
||||
- Formation présentiel prioritaire
|
||||
- Documentation nécessaire pour scalabilité
|
||||
|
||||
---
|
||||
|
||||
### Ticket P2-14 : [Doc] Vidéos tutoriels
|
||||
**Estimation** : 4h
|
||||
**Labels** : `documentation`, `phase-2`, `formation`, `video`
|
||||
|
||||
**Description** :
|
||||
Créer des vidéos tutoriels pour les utilisateurs.
|
||||
|
||||
**Tâches** :
|
||||
- [ ] Vidéo "Inscription parent" (3-5 min)
|
||||
- [ ] Vidéo "Inscription AM" (3-5 min)
|
||||
- [ ] Vidéo "Validation comptes gestionnaire" (3-5 min)
|
||||
- [ ] Vidéo "Configuration initiale admin" (5-7 min)
|
||||
- [ ] Hébergement (YouTube privé ou serveur)
|
||||
|
||||
**Justification report Phase 2** :
|
||||
- Pas bloquant pour MVP
|
||||
- Utile pour scalabilité et autonomie utilisateurs
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Améliorations UX
|
||||
|
||||
### Ticket P2-15 : [Frontend] Mode sombre
|
||||
**Estimation** : 3h
|
||||
**Labels** : `frontend`, `phase-2`, `ux`
|
||||
|
||||
**Description** :
|
||||
Ajouter un mode sombre à l'application.
|
||||
|
||||
**Tâches** :
|
||||
- [ ] Thème sombre (couleurs, contrastes)
|
||||
- [ ] Toggle mode clair/sombre
|
||||
- [ ] Sauvegarde préférence utilisateur
|
||||
- [ ] Adaptation tous les écrans
|
||||
|
||||
**Justification report Phase 2** :
|
||||
- Nice-to-have, pas bloquant
|
||||
- Améliore confort utilisateur
|
||||
|
||||
---
|
||||
|
||||
### Ticket P2-16 : [Frontend] Notifications push (optionnel)
|
||||
**Estimation** : 4h
|
||||
**Labels** : `frontend`, `phase-2`, `ux`, `notifications`
|
||||
|
||||
**Description** :
|
||||
Ajouter des notifications push pour les événements importants.
|
||||
|
||||
**Tâches** :
|
||||
- [ ] Service Worker (PWA)
|
||||
- [ ] Notification "Compte validé"
|
||||
- [ ] Notification "Nouveau message" (si messagerie)
|
||||
- [ ] Gestion permissions
|
||||
- [ ] Paramètres notifications
|
||||
|
||||
**Justification report Phase 2** :
|
||||
- Nice-to-have, pas bloquant
|
||||
- Nécessite PWA ou app mobile
|
||||
|
||||
---
|
||||
|
||||
### Ticket P2-17 : [Frontend] Accessibilité (WCAG 2.1)
|
||||
**Estimation** : 3h
|
||||
**Labels** : `frontend`, `phase-2`, `ux`, `a11y`
|
||||
|
||||
**Description** :
|
||||
Améliorer l'accessibilité de l'application (conformité WCAG 2.1).
|
||||
|
||||
**Tâches** :
|
||||
- [ ] Audit accessibilité (Lighthouse, axe)
|
||||
- [ ] Correction contrastes
|
||||
- [ ] Attributs ARIA
|
||||
- [ ] Navigation clavier
|
||||
- [ ] Lecteur d'écran (test)
|
||||
|
||||
**Justification report Phase 2** :
|
||||
- Amélioration continue
|
||||
- Pas bloquant pour MVP
|
||||
- Important pour collectivités (obligation légale)
|
||||
|
||||
---
|
||||
|
||||
## 📋 Priorisation Phase 2
|
||||
|
||||
### Priorité Haute (à faire en premier)
|
||||
1. **Sauvegarde & Restauration** (Tickets P2-10, P2-11) → Avant mise en production
|
||||
2. **Statistiques** (Tickets P2-06, P2-07) → Argument de vente
|
||||
3. **Documentation utilisateur** (Tickets P2-12, P2-13) → Scalabilité
|
||||
|
||||
### Priorité Moyenne
|
||||
4. **RGPD avancé** (Tickets P2-01, P2-02, P2-03) → Conformité
|
||||
5. **Reporting** (Tickets P2-08, P2-09) → Utile pour gestionnaires
|
||||
|
||||
### Priorité Basse
|
||||
6. **Monitoring avancé** (Tickets P2-04, P2-05) → Nice-to-have
|
||||
7. **Améliorations UX** (Tickets P2-15, P2-16, P2-17) → Confort
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Critères de passage en Phase 2
|
||||
|
||||
La Phase 2 peut commencer quand :
|
||||
- ✅ Phase 1 terminée (61 tickets)
|
||||
- ✅ Application déployée en production (au moins 1 collectivité)
|
||||
- ✅ Utilisateurs réels (au moins 10 comptes validés)
|
||||
- ✅ Feedback terrain collecté
|
||||
- ✅ Bugs critiques corrigés
|
||||
|
||||
---
|
||||
|
||||
## 📊 Estimation globale Phase 2
|
||||
|
||||
**Total** : 17 tickets
|
||||
**Estimation** : ~58h de développement
|
||||
|
||||
**Planning suggéré** :
|
||||
- Sprint 1 (2 semaines) : Sauvegarde + Statistiques (26h)
|
||||
- Sprint 2 (2 semaines) : Documentation + RGPD (24h)
|
||||
- Sprint 3 (1 semaine) : Reporting + Améliorations UX (8h)
|
||||
|
||||
---
|
||||
|
||||
**Dernière mise à jour** : 25 Novembre 2025
|
||||
**Version** : 1.0
|
||||
**Statut** : ✅ Backlog Phase 2 défini
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
# 🕵️ Rapport d'Audit Technique & Fonctionnel - Projet P'titsPas (Ynov)
|
||||
|
||||
**Date** : 23 Novembre 2025
|
||||
**Auditeur** : Assistant IA (Deploy Infra V2)
|
||||
**Objet** : État des lieux avant reprise des développements pour finalisation.
|
||||
|
||||
---
|
||||
|
||||
## 🚨 Synthèse Exécutive
|
||||
|
||||
Le projet dispose d'une **base technique saine** (NestJS, PostgreSQL, Docker) et d'une structure de code propre. Cependant, **plusieurs fonctionnalités critiques du Cahier des Charges (CDC) sont manquantes ou incomplètes**, rendant l'application inutilisable en l'état pour le workflow principal (Inscription -> Validation -> Utilisation).
|
||||
|
||||
**Score d'avancement estimé : 25%**
|
||||
(Backend: 60%, Frontend: 10% [Coquille vide], Infra: 80%)
|
||||
|
||||
---
|
||||
|
||||
## 1. 🏗️ Infrastructure & Docker
|
||||
|
||||
### ✅ Points Positifs
|
||||
* **Stack propre** : Architecture micro-services (Backend, Frontend, Database, PgAdmin).
|
||||
* **Configuration Traefik** : Les labels et le routing (`ynov.ptits-pas.fr`) sont corrects.
|
||||
* **Images optimisées** : Utilisation de builds multi-stage.
|
||||
|
||||
### ⚠️ Problèmes & Correctifs
|
||||
1. **Processus Zombies (Critique)** :
|
||||
* **Constat** : Plus de 9000 processus zombies détectés.
|
||||
* **Cause** : Le conteneur Backend lance `node` en PID 1 sans gestionnaire de signaux (`init`).
|
||||
* **Action** : Ajouter `tini` ou `dumb-init` dans le `Dockerfile` Backend.
|
||||
2. **Base de Données (Seed)** :
|
||||
* **Constat** : Le script d'initialisation (`01_init.sql`) insère un administrateur avec le mot de passe `"admin123"` **en clair**.
|
||||
* **Impact** : Impossible de se connecter (le Backend attend un hash Bcrypt).
|
||||
* **Action** : Remplacer l'insertion SQL par un vrai hash ou un script de seed NestJS.
|
||||
|
||||
---
|
||||
|
||||
## 2. 🔙 Backend (NestJS)
|
||||
|
||||
### ✅ Points Positifs
|
||||
* **Architecture** : Modulaire (Auth, User, Parents, Enfants...).
|
||||
* **Qualité Code** : Typage fort, DTOs validés (`class-validator`), Entités TypeORM claires.
|
||||
|
||||
### ❌ Écarts Fonctionnels Majeurs
|
||||
| Fonctionnalité | État | Problème Identifié |
|
||||
| :--- | :---: | :--- |
|
||||
| **Envoi d'E-mails** | 🔴 **ABSENT** | Aucune librairie mail (Nodemailer) installée. Aucune logique d'envoi. |
|
||||
| **Inscription** | 🟠 **Incomplet** | L'utilisateur est créé, mais sa fiche métier (`Parents` ou `AssistanteMaternelle`) **n'est pas générée**. Elle n'est créée qu'à la validation, ce qui empêche le remplissage du profil en amont. |
|
||||
| **Validation Compte** | 🟠 **Partiel** | Le changement de statut fonctionne, mais **aucune notification mail** n'est envoyée (requis par CDC). |
|
||||
| **Gestionnaire** | ✅ **OK** | La route de création par SuperAdmin existe et est sécurisée. |
|
||||
|
||||
---
|
||||
|
||||
## 3. 📱 Frontend (Flutter)
|
||||
|
||||
### ✅ Points Positifs
|
||||
* Structure du projet cohérente.
|
||||
* Authentification (Login) implémentée.
|
||||
|
||||
### ❌ Écarts Fonctionnels Majeurs
|
||||
| Écran / Fonction | État | Problème Identifié |
|
||||
| :--- | :---: | :--- |
|
||||
| **Création Gestionnaire** | 🔴 **VIDE** | Le fichier `gestionnaires_create.dart` contient uniquement un texte placeholder. **Aucun formulaire.** |
|
||||
| **Dashboard Admin** | 🔴 **FAKE** | L'écran existe mais affiche des données simulées "en dur" (Mock). **Non connecté à l'API.** Impossible de valider les comptes. |
|
||||
| **Dashboard Parent** | 🔴 **FAKE** | L'écran existe, architecture propre (Service/Controller), mais toutes les données (Enfants, Contrats) sont mockées (`TODO: API Call`). |
|
||||
| **Dashboard AssMat** | 🔴 **INEXISTANT** | Aucun écran trouvé pour l'accueil des Assistantes Maternelles. |
|
||||
| **Contact Support** | 🔴 **Fake** | Bouton présent mais code vide (`// TODO`). |
|
||||
| **Signalement Bug** | 🔴 **Fake** | Idem, code non implémenté. |
|
||||
|
||||
---
|
||||
|
||||
## 4. 📝 Plan d'Action Prioritaire (Roadmap de Réparation)
|
||||
|
||||
Pour rendre l'application fonctionnelle selon le "Workflow attendu", voici les étapes techniques à réaliser dans l'ordre :
|
||||
|
||||
### Étape 1 : Réparation Socle (Infra & Data)
|
||||
1. **Fixer le Dockerfile Backend** (Tini pour les zombies).
|
||||
2. **Fixer le mot de passe Admin** : Créer un script pour mettre à jour le hash du mot de passe `admin123` en base de données.
|
||||
|
||||
### Étape 2 : Implémentation Backend (Mail & Workflow)
|
||||
3. **Installer `nodemailer`** et configurer le service SMTP (via le serveur mail Host).
|
||||
4. **Corriger `register`** : Créer l'entité `Parent`/`AssMat` dès l'inscription (vide mais existante).
|
||||
5. **Corriger `validateUser`** : Ajouter l'envoi de mail de notification (Validé/Refusé).
|
||||
|
||||
### Étape 3 : Implémentation Frontend (Écrans Manquants)
|
||||
6. **Développer l'écran "Créer Gestionnaire"** : Formulaire (Nom, Prénom, Email, MDP) + Appel API.
|
||||
7. **Vérifier/Finir le Dashboard Gestionnaire** : Liste des utilisateurs "En attente" + Boutons Valider/Refuser.
|
||||
|
||||
### Étape 4 : Connexion (Workflow Complet)
|
||||
8. Tester le cycle complet :
|
||||
* Login SuperAdmin -> Création Gestionnaire.
|
||||
* Login Gestionnaire -> Vue vide.
|
||||
* Inscription Parent -> Apparition dans la liste Gestionnaire.
|
||||
* Validation par Gestionnaire -> Mail reçu par Parent.
|
||||
* Login Parent -> Accès autorisé.
|
||||
|
||||
---
|
||||
*Ce document sert de référence pour la suite des travaux.*
|
||||
|
||||
@@ -0,0 +1,344 @@
|
||||
# 📐 Règles de Codage - Projet P'titsPas
|
||||
|
||||
**Version** : 1.0
|
||||
**Date** : 1er Décembre 2025
|
||||
**Statut** : ✅ Actif
|
||||
|
||||
---
|
||||
|
||||
## 🌍 Langue du Code
|
||||
|
||||
### Principe Général
|
||||
**Tout le code doit être écrit en FRANÇAIS**, sauf les termes techniques qui restent en **ANGLAIS**.
|
||||
|
||||
---
|
||||
|
||||
## ✅ Ce qui doit être en FRANÇAIS
|
||||
|
||||
### 1. Noms de variables
|
||||
```typescript
|
||||
// ✅ BON
|
||||
const utilisateurConnecte = await this.trouverUtilisateur(id);
|
||||
const enfantsEnregistres = [];
|
||||
const tokenCreationMotDePasse = crypto.randomUUID();
|
||||
|
||||
// ❌ MAUVAIS
|
||||
const loggedUser = await this.findUser(id);
|
||||
const savedChildren = [];
|
||||
const passwordCreationToken = crypto.randomUUID();
|
||||
```
|
||||
|
||||
### 2. Noms de fonctions/méthodes
|
||||
```typescript
|
||||
// ✅ BON
|
||||
async inscrireParentComplet(dto: DtoInscriptionParentComplet) { }
|
||||
async creerGestionnaire(dto: DtoCreationGestionnaire) { }
|
||||
async validerCompte(idUtilisateur: string) { }
|
||||
|
||||
// ❌ MAUVAIS
|
||||
async registerParentComplete(dto: RegisterParentCompleteDto) { }
|
||||
async createManager(dto: CreateManagerDto) { }
|
||||
async validateAccount(userId: string) { }
|
||||
```
|
||||
|
||||
### 3. Noms de classes/interfaces/types
|
||||
```typescript
|
||||
// ✅ BON
|
||||
export class DtoInscriptionParentComplet { }
|
||||
export class ServiceAuthentification { }
|
||||
export interface OptionsConfiguration { }
|
||||
export type StatutUtilisateur = 'actif' | 'en_attente' | 'suspendu';
|
||||
|
||||
// ❌ MAUVAIS
|
||||
export class RegisterParentCompleteDto { }
|
||||
export class AuthService { }
|
||||
export interface ConfigOptions { }
|
||||
export type UserStatus = 'active' | 'pending' | 'suspended';
|
||||
```
|
||||
|
||||
### 4. Noms de fichiers
|
||||
```typescript
|
||||
// ✅ BON
|
||||
inscription-parent-complet.dto.ts
|
||||
service-authentification.ts
|
||||
entite-utilisateurs.ts
|
||||
controleur-configuration.ts
|
||||
|
||||
// ❌ MAUVAIS
|
||||
register-parent-complete.dto.ts
|
||||
auth.service.ts
|
||||
users.entity.ts
|
||||
config.controller.ts
|
||||
```
|
||||
|
||||
### 5. Propriétés d'entités/DTOs
|
||||
```typescript
|
||||
// ✅ BON
|
||||
export class Enfants {
|
||||
@Column({ name: 'prenom' })
|
||||
prenom: string;
|
||||
|
||||
@Column({ name: 'date_naissance' })
|
||||
dateNaissance: Date;
|
||||
|
||||
@Column({ name: 'consentement_photo' })
|
||||
consentementPhoto: boolean;
|
||||
}
|
||||
|
||||
// ❌ MAUVAIS
|
||||
export class Children {
|
||||
@Column({ name: 'first_name' })
|
||||
firstName: string;
|
||||
|
||||
@Column({ name: 'birth_date' })
|
||||
birthDate: Date;
|
||||
|
||||
@Column({ name: 'consent_photo' })
|
||||
consentPhoto: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
### 6. Commentaires
|
||||
```typescript
|
||||
// ✅ BON
|
||||
// Créer Parent 1 + Parent 2 (si existe) + entités parents
|
||||
// Vérifier que l'email n'existe pas déjà
|
||||
// Transaction : Créer utilisateur + entité métier
|
||||
|
||||
// ❌ MAUVAIS
|
||||
// Create Parent 1 + Parent 2 (if exists) + parent entities
|
||||
// Check if email already exists
|
||||
// Transaction: Create user + business entity
|
||||
```
|
||||
|
||||
### 7. Messages d'erreur/succès
|
||||
```typescript
|
||||
// ✅ BON
|
||||
throw new ConflictException('Un compte avec cet email existe déjà');
|
||||
return { message: 'Inscription réussie. Votre dossier est en attente de validation.' };
|
||||
|
||||
// ❌ MAUVAIS
|
||||
throw new ConflictException('An account with this email already exists');
|
||||
return { message: 'Registration successful. Your application is pending validation.' };
|
||||
```
|
||||
|
||||
### 8. Logs
|
||||
```typescript
|
||||
// ✅ BON
|
||||
this.logger.log('📦 Chargement de 16 configurations en cache');
|
||||
this.logger.error('Erreur lors de la création du parent');
|
||||
|
||||
// ❌ MAUVAIS
|
||||
this.logger.log('📦 Loading 16 configurations in cache');
|
||||
this.logger.error('Error creating parent');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Ce qui RESTE en ANGLAIS (Termes Techniques)
|
||||
|
||||
### 1. Patterns de conception
|
||||
- `singleton`
|
||||
- `factory`
|
||||
- `repository`
|
||||
- `observer`
|
||||
- `decorator`
|
||||
|
||||
### 2. Architecture/Framework
|
||||
- `backend` / `frontend`
|
||||
- `controller`
|
||||
- `service`
|
||||
- `middleware`
|
||||
- `guard`
|
||||
- `interceptor`
|
||||
- `pipe`
|
||||
- `filter`
|
||||
- `module`
|
||||
- `provider`
|
||||
|
||||
### 3. Concepts techniques
|
||||
- `entity` (TypeORM)
|
||||
- `DTO` (Data Transfer Object)
|
||||
- `API` / `endpoint`
|
||||
- `token` (JWT)
|
||||
- `hash` (bcrypt)
|
||||
- `cache`
|
||||
- `query`
|
||||
- `transaction`
|
||||
- `migration`
|
||||
- `seed`
|
||||
|
||||
### 4. Bibliothèques/Technologies
|
||||
- `NestJS`
|
||||
- `TypeORM`
|
||||
- `PostgreSQL`
|
||||
- `Docker`
|
||||
- `Git`
|
||||
- `JWT`
|
||||
- `bcrypt`
|
||||
- `Multer`
|
||||
- `Nodemailer`
|
||||
|
||||
### 5. Mots-clés TypeScript/JavaScript
|
||||
- `async` / `await`
|
||||
- `const` / `let` / `var`
|
||||
- `function`
|
||||
- `class`
|
||||
- `interface`
|
||||
- `type`
|
||||
- `enum`
|
||||
- `import` / `export`
|
||||
- `return`
|
||||
- `throw`
|
||||
|
||||
---
|
||||
|
||||
## 📋 Exemples Complets
|
||||
|
||||
### Exemple 1 : Service d'authentification
|
||||
|
||||
```typescript
|
||||
// ✅ BON
|
||||
@Injectable()
|
||||
export class ServiceAuthentification {
|
||||
constructor(
|
||||
private readonly serviceUtilisateurs: ServiceUtilisateurs,
|
||||
private readonly serviceJwt: JwtService,
|
||||
@InjectRepository(Utilisateurs)
|
||||
private readonly depotUtilisateurs: Repository<Utilisateurs>,
|
||||
) {}
|
||||
|
||||
async inscrireParentComplet(dto: DtoInscriptionParentComplet) {
|
||||
// Vérifier que l'email n'existe pas
|
||||
const existe = await this.serviceUtilisateurs.trouverParEmail(dto.email);
|
||||
if (existe) {
|
||||
throw new ConflictException('Un compte avec cet email existe déjà');
|
||||
}
|
||||
|
||||
// Générer le token de création de mot de passe
|
||||
const tokenCreationMdp = crypto.randomUUID();
|
||||
const dateExpiration = new Date();
|
||||
dateExpiration.setDate(dateExpiration.getDate() + 7);
|
||||
|
||||
// Transaction : Créer parent + enfants
|
||||
const resultat = await this.depotUtilisateurs.manager.transaction(async (manager) => {
|
||||
const parent1 = new Utilisateurs();
|
||||
parent1.email = dto.email;
|
||||
parent1.prenom = dto.prenom;
|
||||
parent1.nom = dto.nom;
|
||||
parent1.tokenCreationMdp = tokenCreationMdp;
|
||||
|
||||
const parentEnregistre = await manager.save(Utilisateurs, parent1);
|
||||
|
||||
return { parent: parentEnregistre, token: tokenCreationMdp };
|
||||
});
|
||||
|
||||
return {
|
||||
message: 'Inscription réussie. Votre dossier est en attente de validation.',
|
||||
idParent: resultat.parent.id,
|
||||
statut: 'en_attente',
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Exemple 2 : Entité Enfants
|
||||
|
||||
```typescript
|
||||
// ✅ BON
|
||||
@Entity('enfants')
|
||||
export class Enfants {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ name: 'prenom', length: 100 })
|
||||
prenom: string;
|
||||
|
||||
@Column({ name: 'nom', length: 100 })
|
||||
nom: string;
|
||||
|
||||
@Column({
|
||||
type: 'enum',
|
||||
enum: TypeGenre,
|
||||
name: 'genre'
|
||||
})
|
||||
genre: TypeGenre;
|
||||
|
||||
@Column({ type: 'date', name: 'date_naissance', nullable: true })
|
||||
dateNaissance?: Date;
|
||||
|
||||
@Column({ type: 'date', name: 'date_prevue_naissance', nullable: true })
|
||||
datePrevueNaissance?: Date;
|
||||
|
||||
@Column({ name: 'photo_url', type: 'text', nullable: true })
|
||||
photoUrl?: string;
|
||||
|
||||
@Column({ name: 'consentement_photo', type: 'boolean', default: false })
|
||||
consentementPhoto: boolean;
|
||||
|
||||
@Column({ name: 'est_multiple', type: 'boolean', default: false })
|
||||
estMultiple: boolean;
|
||||
|
||||
@Column({
|
||||
type: 'enum',
|
||||
enum: StatutEnfantType,
|
||||
name: 'statut'
|
||||
})
|
||||
statut: StatutEnfantType;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Migration Progressive
|
||||
|
||||
### Stratégie
|
||||
1. ✅ **Nouveau code** : Appliquer la règle immédiatement
|
||||
2. ⏳ **Code existant** : Migrer progressivement lors des modifications
|
||||
3. ❌ **Ne PAS refactoriser** tout le code d'un coup
|
||||
|
||||
### Priorités de migration
|
||||
1. **Haute priorité** : Nouveaux fichiers, nouvelles fonctionnalités
|
||||
2. **Moyenne priorité** : Fichiers modifiés fréquemment
|
||||
3. **Basse priorité** : Code stable non modifié
|
||||
|
||||
### Exemple de migration progressive
|
||||
```typescript
|
||||
// Avant (ancien code - OK pour l'instant)
|
||||
export class Children { }
|
||||
|
||||
// Après modification (nouveau code - appliquer la règle)
|
||||
export class Enfants { }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚫 Exceptions
|
||||
|
||||
### Cas où l'anglais est toléré
|
||||
1. **Noms de colonnes en BDD** : Si la BDD existe déjà (ex: `first_name` en BDD → `prenom` en TypeScript)
|
||||
2. **APIs externes** : Noms imposés par des bibliothèques tierces
|
||||
3. **Standards** : `id`, `uuid`, `url`, `email`, `password` (termes universels)
|
||||
|
||||
---
|
||||
|
||||
## ✅ Checklist Avant Commit
|
||||
|
||||
- [ ] Noms de variables en français
|
||||
- [ ] Noms de fonctions/méthodes en français
|
||||
- [ ] Noms de classes/interfaces en français
|
||||
- [ ] Noms de fichiers en français
|
||||
- [ ] Propriétés d'entités/DTOs en français
|
||||
- [ ] Commentaires en français
|
||||
- [ ] Messages d'erreur/succès en français
|
||||
- [ ] Termes techniques restent en anglais
|
||||
- [ ] Pas de `console.log` (utiliser `this.logger`)
|
||||
- [ ] Pas de code commenté
|
||||
- [ ] Types TypeScript corrects (pas de `any`)
|
||||
- [ ] Imports propres (pas d'imports inutilisés)
|
||||
|
||||
---
|
||||
|
||||
**Dernière mise à jour** : 1er Décembre 2025
|
||||
**Auteur** : Équipe P'titsPas
|
||||
|
||||
@@ -0,0 +1,279 @@
|
||||
# 📊 Données de Test
|
||||
|
||||
Ce dossier contient les jeux de données de test pour l'application P'titsPas.
|
||||
|
||||
## 📁 Fichiers
|
||||
|
||||
### `utilisateurs-test.csv`
|
||||
|
||||
Fichier CSV contenant les utilisateurs de test pour valider le workflow de création de compte.
|
||||
|
||||
**Format** : CSV avec en-tête
|
||||
**Encodage** : UTF-8
|
||||
**Séparateur** : Virgule (`,`)
|
||||
|
||||
---
|
||||
|
||||
## 👥 Utilisateurs de test
|
||||
|
||||
### 1. Administrateur
|
||||
|
||||
| Nom | Prénom | Email | Téléphone | Mobile |
|
||||
|-----|--------|-------|-----------|--------|
|
||||
| BERNARD | Sophie | sophie.bernard@ptits-pas.fr | 01 39 98 45 67 | 06 78 12 34 56 |
|
||||
|
||||
**Rôle** : `administrateur`
|
||||
**Notes** : Responsable direction générale - Ancienneté 8 ans
|
||||
|
||||
---
|
||||
|
||||
### 2. Gestionnaire
|
||||
|
||||
| Nom | Prénom | Email | Téléphone | Mobile |
|
||||
|-----|--------|-------|-----------|--------|
|
||||
| MOREAU | Lucas | lucas.moreau@ptits-pas.fr | 01 39 98 56 78 | 06 87 23 45 67 |
|
||||
|
||||
**Rôle** : `gestionnaire`
|
||||
**Notes** : Service gestion administrative - Ancienneté 3 ans
|
||||
|
||||
---
|
||||
|
||||
### 3. Assistantes Maternelles (2)
|
||||
|
||||
#### Marie DUBOIS
|
||||
|
||||
| Nom | Prénom | Email | Téléphone | Mobile |
|
||||
|-----|--------|-------|-----------|--------|
|
||||
| DUBOIS | Marie | marie.dubois@ptits-pas.fr | 01 39 98 67 89 | 06 96 34 56 78 |
|
||||
|
||||
**Rôle** : `assistante_maternelle`
|
||||
**Spécialité** : Bébés 0-18 mois
|
||||
**Agrément** : 4 enfants
|
||||
**Places disponibles** : 2
|
||||
|
||||
#### Fatima EL MANSOURI
|
||||
|
||||
| Nom | Prénom | Email | Téléphone | Mobile |
|
||||
|-----|--------|-------|-----------|--------|
|
||||
| EL MANSOURI | Fatima | fatima.elmansouri@ptits-pas.fr | 01 39 98 78 90 | 06 75 45 67 89 |
|
||||
|
||||
**Rôle** : `assistante_maternelle`
|
||||
**Spécialité** : 1-3 ans
|
||||
**Agrément** : 3 enfants
|
||||
**Places disponibles** : 1
|
||||
|
||||
---
|
||||
|
||||
### 4. Parents (5)
|
||||
|
||||
#### Couple MARTIN (avec triplés)
|
||||
|
||||
**Claire MARTIN**
|
||||
|
||||
| Nom | Prénom | Email | Téléphone | Mobile |
|
||||
|-----|--------|-------|-----------|--------|
|
||||
| MARTIN | Claire | claire.martin@ptits-pas.fr | 01 39 98 89 01 | 06 89 56 78 90 |
|
||||
|
||||
**Profession** : Infirmière
|
||||
**Situation** : Mariée - triplés
|
||||
|
||||
**Thomas MARTIN**
|
||||
|
||||
| Nom | Prénom | Email | Téléphone | Mobile |
|
||||
|-----|--------|-------|-----------|--------|
|
||||
| MARTIN | Thomas | thomas.martin@ptits-pas.fr | 01 39 98 89 01 | 06 78 45 67 89 |
|
||||
|
||||
**Profession** : Ingénieur
|
||||
**Situation** : Marié - triplés
|
||||
|
||||
**Enfants** :
|
||||
- Emma MARTIN (née le 15/02/2023, 8 mois)
|
||||
- Noah MARTIN (né le 15/02/2023, 8 mois)
|
||||
- Léa MARTIN (née le 15/02/2023, 8 mois)
|
||||
|
||||
**Notes** : Couple avec triplés - Besoin garde multiple
|
||||
|
||||
---
|
||||
|
||||
#### Couple divorcé DURAND/ROUSSEAU
|
||||
|
||||
**Amélie DURAND**
|
||||
|
||||
| Nom | Prénom | Email | Téléphone | Mobile |
|
||||
|-----|--------|-------|-----------|--------|
|
||||
| DURAND | Amélie | amelie.durand@ptits-pas.fr | 01 39 98 90 12 | 06 67 78 89 90 |
|
||||
|
||||
**Profession** : Comptable
|
||||
**Situation** : Divorcée
|
||||
|
||||
**Julien ROUSSEAU**
|
||||
|
||||
| Nom | Prénom | Email | Téléphone | Mobile |
|
||||
|-----|--------|-------|-----------|--------|
|
||||
| ROUSSEAU | Julien | julien.rousseau@ptits-pas.fr | 01 39 98 01 23 | 06 56 67 78 89 |
|
||||
|
||||
**Profession** : Commercial
|
||||
**Situation** : Divorcé
|
||||
|
||||
**Enfants** (en commun) :
|
||||
- Chloé ROUSSEAU (née le 20/04/2022, 2 ans)
|
||||
- Hugo ROUSSEAU (né le 10/03/2024, 6 mois)
|
||||
|
||||
**Notes** :
|
||||
- Amélie : Garde principale des enfants
|
||||
- Julien : Garde alternée 1 weekend/2
|
||||
|
||||
---
|
||||
|
||||
#### Père célibataire
|
||||
|
||||
**David LECOMTE**
|
||||
|
||||
| Nom | Prénom | Email | Téléphone | Mobile |
|
||||
|-----|--------|-------|-----------|--------|
|
||||
| LECOMTE | David | david.lecomte@ptits-pas.fr | 01 39 98 12 34 | 06 45 56 67 78 |
|
||||
|
||||
**Profession** : Développeur web
|
||||
**Situation** : Père célibataire
|
||||
|
||||
**Enfants** :
|
||||
- Maxime LECOMTE (né le 15/04/2023, 1 an 5 mois)
|
||||
|
||||
**Notes** : Garde complète - Contact urgence : grand-mère paternelle
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Utilisation pour les tests
|
||||
|
||||
### Scénarios de test
|
||||
|
||||
#### Scénario 1 : Création de gestionnaire
|
||||
|
||||
```typescript
|
||||
// Créer Lucas MOREAU en tant que gestionnaire
|
||||
POST /api/v1/gestionnaires
|
||||
{
|
||||
"email": "lucas.moreau@ptits-pas.fr",
|
||||
"password": "Test1234!",
|
||||
"prenom": "Lucas",
|
||||
"nom": "MOREAU"
|
||||
}
|
||||
```
|
||||
|
||||
#### Scénario 2 : Inscription assistante maternelle
|
||||
|
||||
```typescript
|
||||
// Marie DUBOIS s'inscrit
|
||||
POST /api/v1/auth/register
|
||||
{
|
||||
"email": "marie.dubois@ptits-pas.fr",
|
||||
"password": "Test1234!",
|
||||
"prenom": "Marie",
|
||||
"nom": "DUBOIS",
|
||||
"telephone": "01 39 98 67 89",
|
||||
"mobile": "06 96 34 56 78",
|
||||
"role": "assistante_maternelle"
|
||||
}
|
||||
```
|
||||
|
||||
#### Scénario 3 : Inscription parent
|
||||
|
||||
```typescript
|
||||
// Claire MARTIN s'inscrit
|
||||
POST /api/v1/auth/register
|
||||
{
|
||||
"email": "claire.martin@ptits-pas.fr",
|
||||
"password": "Test1234!",
|
||||
"prenom": "Claire",
|
||||
"nom": "MARTIN",
|
||||
"telephone": "01 39 98 89 01",
|
||||
"mobile": "06 89 56 78 90",
|
||||
"role": "parent"
|
||||
}
|
||||
```
|
||||
|
||||
#### Scénario 4 : Validation par gestionnaire
|
||||
|
||||
```typescript
|
||||
// Lucas MOREAU valide Marie DUBOIS
|
||||
PATCH /api/v1/users/{marie_id}/valider
|
||||
Authorization: Bearer {lucas_token}
|
||||
{
|
||||
"comment": "Agrément vérifié - Profil complet"
|
||||
}
|
||||
```
|
||||
|
||||
#### Scénario 5 : Cas complexe - Triplés
|
||||
|
||||
Test du workflow complet avec le couple MARTIN ayant des triplés :
|
||||
1. Claire et Thomas s'inscrivent séparément
|
||||
2. Chacun déclare les 3 enfants
|
||||
3. Validation par le gestionnaire
|
||||
4. Recherche d'assistante maternelle avec capacité pour 3 enfants
|
||||
|
||||
#### Scénario 6 : Cas complexe - Garde alternée
|
||||
|
||||
Test du workflow avec le couple divorcé DURAND/ROUSSEAU :
|
||||
1. Amélie et Julien s'inscrivent séparément
|
||||
2. Chacun déclare les 2 enfants en commun
|
||||
3. Gestion de la garde alternée
|
||||
4. Coordination entre les 2 parents
|
||||
|
||||
---
|
||||
|
||||
## 📧 Emails de test
|
||||
|
||||
Tous les emails de test utilisent le domaine `@ptits-pas.fr`.
|
||||
|
||||
**Pour les tests en local**, vous pouvez utiliser :
|
||||
- [Mailtrap](https://mailtrap.io/) pour capturer les emails
|
||||
- [MailHog](https://github.com/mailhog/MailHog) pour un serveur SMTP local
|
||||
- [Thunderbird](https://www.thunderbird.net/) pour consulter les emails
|
||||
|
||||
**Configuration Thunderbird** :
|
||||
- Serveur IMAP : `mail.ptits-pas.fr`
|
||||
- Port : 993 (SSL/TLS)
|
||||
- Serveur SMTP : `mail.ptits-pas.fr`
|
||||
- Port : 587 (STARTTLS)
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Mots de passe de test
|
||||
|
||||
**Par défaut pour tous les utilisateurs de test** : `password`
|
||||
|
||||
**Note** : Ce mot de passe simple est utilisé uniquement pour les tests. En production, les règles suivantes s'appliquent :
|
||||
- Minimum 8 caractères
|
||||
- Au moins 1 majuscule
|
||||
- Au moins 1 chiffre
|
||||
- Au moins 1 caractère spécial (recommandé)
|
||||
|
||||
---
|
||||
|
||||
## 🗄️ Script d'import
|
||||
|
||||
Un script d'import sera créé pour charger automatiquement ces données de test en base.
|
||||
|
||||
**Fichier** : `backend/src/scripts/seed-test-data.ts`
|
||||
|
||||
**Utilisation** :
|
||||
```bash
|
||||
cd backend
|
||||
npm run seed:test
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Avertissement
|
||||
|
||||
**Ces données sont uniquement pour les tests !**
|
||||
|
||||
- Ne jamais utiliser en production
|
||||
- Les emails sont fictifs mais utilisent le domaine réel `@ptits-pas.fr`
|
||||
- Les numéros de téléphone sont fictifs
|
||||
- Les adresses sont à Bezons (95870) mais peuvent être fictives
|
||||
|
||||
---
|
||||
|
||||
**Dernière mise à jour** : 24 Novembre 2025
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
Type,Nom,Prenom,Email,Telephone,Mobile,Date_naissance,Adresse,Code_postal,Ville,Profession,Situation_familiale,Enfant_1_nom,Enfant_1_naissance,Enfant_1_age,Enfant_2_nom,Enfant_2_naissance,Enfant_2_age,Enfant_3_nom,Enfant_3_naissance,Enfant_3_age,Notes_particulieres
|
||||
ADMINISTRATEUR,BERNARD,Sophie,sophie.bernard@ptits-pas.fr,01 39 98 45 67,06 78 12 34 56,15/03/1978,"12 Avenue Gabriel Péri",95870,Bezons,Responsable administrative,Mariée,,,,,,,,,,Responsable direction générale - Ancienneté 8 ans
|
||||
GESTIONNAIRE,MOREAU,Lucas,lucas.moreau@ptits-pas.fr,01 39 98 56 78,06 87 23 45 67,22/09/1985,"8 Rue Jean Jaurès",95870,Bezons,Gestionnaire des placements,Célibataire,,,,,,,,,,Service gestion administrative - Ancienneté 3 ans
|
||||
ASSISTANTE_MATERNELLE,DUBOIS,Marie,marie.dubois@ptits-pas.fr,01 39 98 67 89,06 96 34 56 78,08/06/1980,"25 Rue de la République",95870,Bezons,Assistante maternelle,Mariée,,,,,,,,,,Agrément 4 enfants - Spécialité bébés 0-18 mois - 2 places disponibles
|
||||
ASSISTANTE_MATERNELLE,EL MANSOURI,Fatima,fatima.elmansouri@ptits-pas.fr,01 39 98 78 90,06 75 45 67 89,12/11/1975,"17 Boulevard Aristide Briand",95870,Bezons,Assistante maternelle,Mariée,,,,,,,,,,Agrément 3 enfants - Spécialité 1-3 ans - 1 place disponible
|
||||
PARENT,MARTIN,Claire,claire.martin@ptits-pas.fr,01 39 98 89 01,06 89 56 78 90,03/04/1990,"5 Avenue du Général de Gaulle",95870,Bezons,Infirmière,Mariée - triplés,Emma MARTIN,15/02/2023,8 mois,Noah MARTIN,15/02/2023,8 mois,Léa MARTIN,15/02/2023,8 mois,Couple avec triplés - Besoin garde multiple
|
||||
PARENT,MARTIN,Thomas,thomas.martin@ptits-pas.fr,01 39 98 89 01,06 78 45 67 89,18/07/1988,"5 Avenue du Général de Gaulle",95870,Bezons,Ingénieur,Marié - triplés,Emma MARTIN,15/02/2023,8 mois,Noah MARTIN,15/02/2023,8 mois,Léa MARTIN,15/02/2023,8 mois,Couple avec triplés - Besoin garde multiple
|
||||
PARENT,DURAND,Amélie,amelie.durand@ptits-pas.fr,01 39 98 90 12,06 67 78 89 90,14/12/1987,"23 Rue Victor Hugo",95870,Bezons,Comptable,Divorcée,Chloé ROUSSEAU,20/04/2022,2 ans,Hugo ROUSSEAU,10/03/2024,6 mois,,,,"Garde principale des enfants - Ex-conjoint : Julien ROUSSEAU - Nom de jeune fille : DURAND"
|
||||
PARENT,ROUSSEAU,Julien,julien.rousseau@ptits-pas.fr,01 39 98 01 23,06 56 67 78 89,29/08/1985,"14 Rue Pasteur",95870,Bezons,Commercial,Divorcé,Chloé ROUSSEAU,20/04/2022,2 ans,Hugo ROUSSEAU,10/03/2024,6 mois,,,,"Garde alternée 1 weekend/2 - Ex-conjointe : Amélie DURAND (née DURAND)"
|
||||
PARENT,LECOMTE,David,david.lecomte@ptits-pas.fr,01 39 98 12 34,06 45 56 67 78,07/10/1992,"31 Rue Émile Zola",95870,Bezons,Développeur web,Père célibataire,Maxime LECOMTE,15/04/2023,1 an 5 mois,,,,,,"Garde complète - Contact urgence : grand-mère paternelle"
|
||||
|
||||
|
@@ -0,0 +1,359 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Fiches d'identification - Utilisateurs de test</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
background-color: #2c5aa0;
|
||||
color: white;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.user-card {
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
border-left: 5px solid #2c5aa0;
|
||||
}
|
||||
.user-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 2px solid #eee;
|
||||
padding-bottom: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.user-name {
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
color: #2c5aa0;
|
||||
}
|
||||
.user-role {
|
||||
background-color: #2c5aa0;
|
||||
color: white;
|
||||
padding: 5px 15px;
|
||||
border-radius: 20px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 15px;
|
||||
}
|
||||
.info-section {
|
||||
background-color: #f8f9fa;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.info-title {
|
||||
font-weight: bold;
|
||||
color: #2c5aa0;
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding-bottom: 5px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.children-list {
|
||||
background-color: #e8f4f8;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.child-item {
|
||||
padding: 5px 0;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
.child-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.password-note {
|
||||
background-color: #fff3cd;
|
||||
border: 1px solid #ffeaa7;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
margin-top: 15px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1>🏡 Fiches d'identification - Utilisateurs de test</h1>
|
||||
<p>Système de gestion des assistantes maternelles - Bezons (95870)</p>
|
||||
<p><strong>Mot de passe universel :</strong> password</p>
|
||||
</div>
|
||||
|
||||
<!-- ADMINISTRATEUR -->
|
||||
<div class="user-card">
|
||||
<div class="user-header">
|
||||
<div class="user-name">Sophie BERNARD</div>
|
||||
<div class="user-role">ADMINISTRATEUR</div>
|
||||
</div>
|
||||
<div class="info-grid">
|
||||
<div class="info-section">
|
||||
<div class="info-title">Informations personnelles</div>
|
||||
<p><strong>Email :</strong> sophie.bernard@ptits-pas.fr</p>
|
||||
<p><strong>Téléphone :</strong> 01 39 98 45 67</p>
|
||||
<p><strong>Téléphone mobile :</strong> 06 78 12 34 56</p>
|
||||
<p><strong>Date de naissance :</strong> 15/03/1978</p>
|
||||
</div>
|
||||
<div class="info-section">
|
||||
<div class="info-title">Adresse</div>
|
||||
<p>12 Avenue Gabriel Péri<br>
|
||||
95870 Bezons<br>
|
||||
France</p>
|
||||
</div>
|
||||
<div class="info-section">
|
||||
<div class="info-title">Fonction</div>
|
||||
<p><strong>Poste :</strong> Responsable administrative</p>
|
||||
<p><strong>Service :</strong> Direction générale</p>
|
||||
<p><strong>Ancienneté :</strong> 8 ans</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- GESTIONNAIRE -->
|
||||
<div class="user-card">
|
||||
<div class="user-header">
|
||||
<div class="user-name">Lucas MOREAU</div>
|
||||
<div class="user-role">GESTIONNAIRE</div>
|
||||
</div>
|
||||
<div class="info-grid">
|
||||
<div class="info-section">
|
||||
<div class="info-title">Informations personnelles</div>
|
||||
<p><strong>Email :</strong> lucas.moreau@ptits-pas.fr</p>
|
||||
<p><strong>Téléphone :</strong> 01 39 98 56 78</p>
|
||||
<p><strong>Téléphone mobile :</strong> 06 87 23 45 67</p>
|
||||
<p><strong>Date de naissance :</strong> 22/09/1985</p>
|
||||
</div>
|
||||
<div class="info-section">
|
||||
<div class="info-title">Adresse</div>
|
||||
<p>8 Rue Jean Jaurès<br>
|
||||
95870 Bezons<br>
|
||||
France</p>
|
||||
</div>
|
||||
<div class="info-section">
|
||||
<div class="info-title">Fonction</div>
|
||||
<p><strong>Poste :</strong> Gestionnaire des placements</p>
|
||||
<p><strong>Service :</strong> Gestion administrative</p>
|
||||
<p><strong>Ancienneté :</strong> 3 ans</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ASSISTANTE MATERNELLE 1 -->
|
||||
<div class="user-card">
|
||||
<div class="user-header">
|
||||
<div class="user-name">Marie DUBOIS</div>
|
||||
<div class="user-role">ASSISTANTE MATERNELLE</div>
|
||||
</div>
|
||||
<div class="info-grid">
|
||||
<div class="info-section">
|
||||
<div class="info-title">Informations personnelles</div>
|
||||
<p><strong>Email :</strong> marie.dubois@ptits-pas.fr</p>
|
||||
<p><strong>Téléphone :</strong> 01 39 98 67 89</p>
|
||||
<p><strong>Téléphone mobile :</strong> 06 96 34 56 78</p>
|
||||
<p><strong>Date de naissance :</strong> 08/06/1980</p>
|
||||
</div>
|
||||
<div class="info-section">
|
||||
<div class="info-title">Adresse</div>
|
||||
<p>25 Rue de la République<br>
|
||||
95870 Bezons<br>
|
||||
France</p>
|
||||
</div>
|
||||
<div class="info-section">
|
||||
<div class="info-title">Profession</div>
|
||||
<p><strong>Agrément :</strong> 4 enfants max</p>
|
||||
<p><strong>Expérience :</strong> 12 ans</p>
|
||||
<p><strong>Spécialité :</strong> Bébés 0-18 mois</p>
|
||||
<p><strong>Places disponibles :</strong> 2</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ASSISTANTE MATERNELLE 2 -->
|
||||
<div class="user-card">
|
||||
<div class="user-header">
|
||||
<div class="user-name">Fatima EL MANSOURI</div>
|
||||
<div class="user-role">ASSISTANTE MATERNELLE</div>
|
||||
</div>
|
||||
<div class="info-grid">
|
||||
<div class="info-section">
|
||||
<div class="info-title">Informations personnelles</div>
|
||||
<p><strong>Email :</strong> fatima.elmansouri@ptits-pas.fr</p>
|
||||
<p><strong>Téléphone :</strong> 01 39 98 78 90</p>
|
||||
<p><strong>Téléphone mobile :</strong> 06 75 45 67 89</p>
|
||||
<p><strong>Date de naissance :</strong> 12/11/1975</p>
|
||||
</div>
|
||||
<div class="info-section">
|
||||
<div class="info-title">Adresse</div>
|
||||
<p>17 Boulevard Aristide Briand<br>
|
||||
95870 Bezons<br>
|
||||
France</p>
|
||||
</div>
|
||||
<div class="info-section">
|
||||
<div class="info-title">Profession</div>
|
||||
<p><strong>Agrément :</strong> 3 enfants max</p>
|
||||
<p><strong>Expérience :</strong> 15 ans</p>
|
||||
<p><strong>Spécialité :</strong> Enfants 1-3 ans</p>
|
||||
<p><strong>Places disponibles :</strong> 1</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- COUPLE PARENTS TRIPLÉS -->
|
||||
<div class="user-card">
|
||||
<div class="user-header">
|
||||
<div class="user-name">Claire & Thomas MARTIN</div>
|
||||
<div class="user-role">PARENTS - TRIPLÉS</div>
|
||||
</div>
|
||||
<div class="info-grid">
|
||||
<div class="info-section">
|
||||
<div class="info-title">Informations Claire</div>
|
||||
<p><strong>Email :</strong> claire.martin@ptits-pas.fr</p>
|
||||
<p><strong>Téléphone :</strong> 06 89 56 78 90</p>
|
||||
<p><strong>Date de naissance :</strong> 03/04/1990</p>
|
||||
<p><strong>Profession :</strong> Infirmière</p>
|
||||
</div>
|
||||
<div class="info-section">
|
||||
<div class="info-title">Informations Thomas</div>
|
||||
<p><strong>Email :</strong> thomas.martin@ptits-pas.fr</p>
|
||||
<p><strong>Téléphone :</strong> 06 78 45 67 89</p>
|
||||
<p><strong>Date de naissance :</strong> 18/07/1988</p>
|
||||
<p><strong>Profession :</strong> Ingénieur</p>
|
||||
</div>
|
||||
<div class="info-section">
|
||||
<div class="info-title">Adresse commune</div>
|
||||
<p>5 Avenue du Général de Gaulle<br>
|
||||
95870 Bezons<br>
|
||||
France<br>
|
||||
<strong>Tél. fixe :</strong> 01 39 98 89 01</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="children-list">
|
||||
<div class="info-title">👶 Leurs enfants (Triplés)</div>
|
||||
<div class="child-item"><strong>Emma MARTIN</strong> - Née le 15/02/2023 (8 mois)</div>
|
||||
<div class="child-item"><strong>Noah MARTIN</strong> - Né le 15/02/2023 (8 mois)</div>
|
||||
<div class="child-item"><strong>Léa MARTIN</strong> - Née le 15/02/2023 (8 mois)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- COUPLE PARENTS DIVORCÉS -->
|
||||
<div class="user-card">
|
||||
<div class="user-header">
|
||||
<div class="user-name">Amélie DURAND</div>
|
||||
<div class="user-role">PARENT - MÈRE</div>
|
||||
</div>
|
||||
<div class="info-grid">
|
||||
<div class="info-section">
|
||||
<div class="info-title">Informations personnelles</div>
|
||||
<p><strong>Email :</strong> amelie.durand@ptits-pas.fr</p>
|
||||
<p><strong>Téléphone :</strong> 06 67 78 89 90</p>
|
||||
<p><strong>Date de naissance :</strong> 14/12/1987</p>
|
||||
<p><strong>Profession :</strong> Comptable</p>
|
||||
<p><strong>Situation :</strong> Divorcée (nom de jeune fille : DURAND)</p>
|
||||
</div>
|
||||
<div class="info-section">
|
||||
<div class="info-title">Adresse</div>
|
||||
<p>23 Rue Victor Hugo<br>
|
||||
95870 Bezons<br>
|
||||
France<br>
|
||||
<strong>Tél. fixe :</strong> 01 39 98 90 12</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="children-list">
|
||||
<div class="info-title">👶 Ses enfants</div>
|
||||
<div class="child-item"><strong>Chloé ROUSSEAU</strong> - Née le 20/04/2022 (2 ans)</div>
|
||||
<div class="child-item"><strong>Hugo ROUSSEAU</strong> - Né le 10/03/2024 (6 mois)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="user-card">
|
||||
<div class="user-header">
|
||||
<div class="user-name">Julien ROUSSEAU</div>
|
||||
<div class="user-role">PARENT - PÈRE</div>
|
||||
</div>
|
||||
<div class="info-grid">
|
||||
<div class="info-section">
|
||||
<div class="info-title">Informations personnelles</div>
|
||||
<p><strong>Email :</strong> julien.rousseau@ptits-pas.fr</p>
|
||||
<p><strong>Téléphone :</strong> 06 56 67 78 89</p>
|
||||
<p><strong>Date de naissance :</strong> 29/08/1985</p>
|
||||
<p><strong>Profession :</strong> Commercial</p>
|
||||
<p><strong>Situation :</strong> Divorcé</p>
|
||||
</div>
|
||||
<div class="info-section">
|
||||
<div class="info-title">Adresse</div>
|
||||
<p>14 Rue Pasteur<br>
|
||||
95870 Bezons<br>
|
||||
France<br>
|
||||
<strong>Tél. fixe :</strong> 01 39 98 01 23</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="children-list">
|
||||
<div class="info-title">👶 Ses enfants (garde alternée)</div>
|
||||
<div class="child-item"><strong>Chloé ROUSSEAU</strong> - Née le 20/04/2022 (2 ans) - 1 weekend/2</div>
|
||||
<div class="child-item"><strong>Hugo ROUSSEAU</strong> - Né le 10/03/2024 (6 mois) - 1 weekend/2</div>
|
||||
<p><em>Ex-conjointe : Amélie DURAND (née DURAND)</em></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PAPA SEUL -->
|
||||
<div class="user-card">
|
||||
<div class="user-header">
|
||||
<div class="user-name">David LECOMTE</div>
|
||||
<div class="user-role">PARENT - PÈRE SEUL</div>
|
||||
</div>
|
||||
<div class="info-grid">
|
||||
<div class="info-section">
|
||||
<div class="info-title">Informations personnelles</div>
|
||||
<p><strong>Email :</strong> david.lecomte@ptits-pas.fr</p>
|
||||
<p><strong>Téléphone :</strong> 06 45 56 67 78</p>
|
||||
<p><strong>Date de naissance :</strong> 07/10/1992</p>
|
||||
<p><strong>Profession :</strong> Développeur web</p>
|
||||
<p><strong>Situation :</strong> Père célibataire</p>
|
||||
</div>
|
||||
<div class="info-section">
|
||||
<div class="info-title">Adresse</div>
|
||||
<p>31 Rue Émile Zola<br>
|
||||
95870 Bezons<br>
|
||||
France<br>
|
||||
<strong>Tél. fixe :</strong> 01 39 98 12 34</p>
|
||||
</div>
|
||||
<div class="info-section">
|
||||
<div class="info-title">Situation familiale</div>
|
||||
<p><strong>Garde :</strong> Complète</p>
|
||||
<p><strong>Contact d'urgence :</strong> Grand-mère paternelle</p>
|
||||
<p><strong>Besoin :</strong> Garde temps plein</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="children-list">
|
||||
<div class="info-title">👶 Son enfant</div>
|
||||
<div class="child-item"><strong>Maxime LECOMTE</strong> - Né le 15/04/2023 (1 an et 5 mois)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="password-note">
|
||||
🔐 Tous les comptes utilisent le mot de passe : <strong>password</strong><br>
|
||||
📧 Accès webmail : <a href="https://mail.ptits-pas.fr">mail.ptits-pas.fr</a>
|
||||
</div>
|
||||
|
||||
<footer style="text-align: center; margin-top: 30px; padding: 20px; color: #666;">
|
||||
<p>Fiches générées pour tests système - Données fictives - <?php echo date('d/m/Y H:i'); ?></p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user