docs: ajout documentation technique complète (configuration, documents légaux, tickets, décisions, backlog Phase 2)
This commit is contained in:
@@ -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é
|
||||
|
||||
Reference in New Issue
Block a user