backend
This commit is contained in:
parent
81df52b785
commit
081b33466f
139
docs/API.md
139
docs/API.md
@ -1,139 +0,0 @@
|
|||||||
# Documentation API - 4NK IA Lecoffre.io
|
|
||||||
|
|
||||||
## Vue d'ensemble
|
|
||||||
|
|
||||||
L'application 4NK IA Lecoffre.io communique uniquement avec le backend interne pour toutes les
|
|
||||||
fonctionnalités (upload, extraction, analyse, contexte, conseil).
|
|
||||||
|
|
||||||
## API Backend Principal
|
|
||||||
|
|
||||||
### Base URL
|
|
||||||
|
|
||||||
```text
|
|
||||||
http://localhost:8000 (développement)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Endpoints
|
|
||||||
|
|
||||||
#### Upload de document
|
|
||||||
|
|
||||||
```http
|
|
||||||
POST /api/notary/upload
|
|
||||||
Content-Type: multipart/form-data
|
|
||||||
|
|
||||||
Body: FormData avec le fichier
|
|
||||||
```
|
|
||||||
|
|
||||||
Réponse attendue (champs utilisés par le front) :
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"document_id": "doc_123456",
|
|
||||||
"mime_type": "application/pdf",
|
|
||||||
"functional_type": "CNI"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Mappage front en `Document` :
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"id": "doc_123456",
|
|
||||||
"name": "acte_vente.pdf",
|
|
||||||
"mimeType": "application/pdf",
|
|
||||||
"functionalType": "CNI",
|
|
||||||
"size": 1024000,
|
|
||||||
"uploadDate": "<date locale>",
|
|
||||||
"status": "completed",
|
|
||||||
"previewUrl": "blob:..."
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Extraction de données
|
|
||||||
|
|
||||||
```http
|
|
||||||
GET /api/notary/documents/{documentId}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Analyse du document
|
|
||||||
|
|
||||||
```http
|
|
||||||
GET /api/documents/{documentId}/analyze
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Données contextuelles
|
|
||||||
|
|
||||||
```http
|
|
||||||
GET /api/documents/{documentId}/context
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Conseil IA
|
|
||||||
|
|
||||||
```http
|
|
||||||
GET /api/documents/{documentId}/conseil
|
|
||||||
```
|
|
||||||
|
|
||||||
## APIs Externes
|
|
||||||
|
|
||||||
Les APIs externes (Cadastre, Géorisques, Géofoncier, BODACC, Infogreffe) sont appelées côté backend
|
|
||||||
uniquement. Aucun appel direct côté front.
|
|
||||||
|
|
||||||
## Gestion d'erreur
|
|
||||||
|
|
||||||
### Codes d'erreur HTTP
|
|
||||||
|
|
||||||
- 200 : Succès
|
|
||||||
- 400 : Requête malformée
|
|
||||||
- 404 : Ressource non trouvée
|
|
||||||
- 405 : Méthode non autorisée
|
|
||||||
- 500 : Erreur serveur interne
|
|
||||||
|
|
||||||
### Erreurs de connexion
|
|
||||||
|
|
||||||
- ERR_NETWORK : Erreur de réseau
|
|
||||||
- ERR_CONNECTION_REFUSED : Connexion refusée
|
|
||||||
- ERR_TIMEOUT : Timeout de la requête
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### Variables d'environnement
|
|
||||||
|
|
||||||
```env
|
|
||||||
VITE_API_URL=http://localhost:8000
|
|
||||||
VITE_USE_OPENAI=false
|
|
||||||
VITE_OPENAI_API_KEY=
|
|
||||||
VITE_OPENAI_BASE_URL=https://api.openai.com/v1
|
|
||||||
VITE_OPENAI_MODEL=gpt-4o-mini
|
|
||||||
```
|
|
||||||
|
|
||||||
## Mode OpenAI (fallback)
|
|
||||||
|
|
||||||
Quand `VITE_USE_OPENAI=true`, le frontend bascule sur un mode de secours basé sur OpenAI:
|
|
||||||
|
|
||||||
- Upload: simulé côté client (le fichier n’est pas envoyé à OpenAI)
|
|
||||||
- Extraction/Analyse/Conseil/Contexte: appels `chat.completions` sur `VITE_OPENAI_MODEL`
|
|
||||||
- Détection de type: heuristique simple côté client
|
|
||||||
|
|
||||||
Ce mode est utile pour démo/diagnostic quand le backend n’est pas disponible.
|
|
||||||
|
|
||||||
### Configuration Axios
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
const apiClient = axios.create({
|
|
||||||
baseURL: BASE_URL,
|
|
||||||
timeout: 60000
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
## Authentification
|
|
||||||
|
|
||||||
### Headers requis
|
|
||||||
|
|
||||||
```http
|
|
||||||
Authorization: Bearer {token}
|
|
||||||
Content-Type: application/json
|
|
||||||
```
|
|
||||||
|
|
||||||
## Rate Limiting
|
|
||||||
|
|
||||||
- Limites gérées par le backend
|
|
||||||
@ -1,282 +0,0 @@
|
|||||||
# Architecture de l'application 4NK IA Lecoffre.io
|
|
||||||
|
|
||||||
## Vue d'ensemble
|
|
||||||
|
|
||||||
L'application 4NK IA Lecoffre.io est une interface web moderne construite avec React et TypeScript,
|
|
||||||
conçue pour l'analyse intelligente de documents notariaux.
|
|
||||||
|
|
||||||
## Stack technique
|
|
||||||
|
|
||||||
### Frontend
|
|
||||||
|
|
||||||
- **React 18** : Framework UI avec hooks et composants fonctionnels
|
|
||||||
- **TypeScript 5.6** : Typage statique pour la robustesse du code
|
|
||||||
- **Vite 7** : Build tool rapide avec HMR (Hot Module Replacement)
|
|
||||||
- **Material-UI v6** : Bibliothèque de composants UI professionnels
|
|
||||||
|
|
||||||
### Gestion d'état
|
|
||||||
|
|
||||||
- **Redux Toolkit** : Gestion d'état centralisée et prévisible
|
|
||||||
- **React Redux** : Liaison React-Redux avec hooks
|
|
||||||
- **Async Thunks** : Gestion des actions asynchrones
|
|
||||||
|
|
||||||
### Routing et navigation
|
|
||||||
|
|
||||||
- **React Router v6** : Navigation côté client avec code splitting
|
|
||||||
- **Lazy loading** : Chargement à la demande des composants
|
|
||||||
|
|
||||||
### HTTP et API
|
|
||||||
|
|
||||||
- **Axios** : Client HTTP avec intercepteurs
|
|
||||||
- **Intercepteurs** : Gestion centralisée des erreurs et authentification
|
|
||||||
|
|
||||||
### Tests
|
|
||||||
|
|
||||||
- **Vitest** : Framework de test rapide et moderne
|
|
||||||
- **Testing Library** : Tests d'intégration React
|
|
||||||
- **JSDOM** : Environnement DOM simulé
|
|
||||||
- **Coverage V8** : Rapport de couverture de code
|
|
||||||
|
|
||||||
### Qualité de code
|
|
||||||
|
|
||||||
- **ESLint** : Linting avec règles strictes
|
|
||||||
- **Prettier** : Formatage automatique du code
|
|
||||||
- **markdownlint** : Validation des fichiers Markdown
|
|
||||||
|
|
||||||
## Structure du projet
|
|
||||||
|
|
||||||
```text
|
|
||||||
src/
|
|
||||||
├── components/ # Composants réutilisables
|
|
||||||
│ ├── Layout.tsx # Layout principal avec AppBar et navigation
|
|
||||||
│ └── NavigationTabs.tsx # Composant de navigation par onglets
|
|
||||||
├── views/ # Vues principales de l'application
|
|
||||||
│ ├── UploadView.tsx # Upload et gestion des documents
|
|
||||||
│ ├── ExtractionView.tsx # Affichage des données extraites
|
|
||||||
│ ├── AnalyseView.tsx # Analyse et score de vraisemblance
|
|
||||||
│ ├── ContexteView.tsx # Données contextuelles externes
|
|
||||||
│ └── ConseilView.tsx # Conseil IA et recommandations
|
|
||||||
├── store/ # Gestion d'état Redux
|
|
||||||
│ ├── index.ts # Configuration du store Redux
|
|
||||||
│ ├── appSlice.ts # État global de l'application
|
|
||||||
│ └── documentSlice.ts # État des documents et opérations
|
|
||||||
├── services/ # Services et API
|
|
||||||
│ └── api.ts # Client API et endpoints
|
|
||||||
├── types/ # Types et interfaces TypeScript
|
|
||||||
│ └── index.ts # Définitions de types centralisées
|
|
||||||
├── main.tsx # Point d'entrée de l'application
|
|
||||||
└── App.tsx # Composant racine avec routing
|
|
||||||
```
|
|
||||||
|
|
||||||
## Architecture des composants
|
|
||||||
|
|
||||||
### Layout et navigation
|
|
||||||
|
|
||||||
- **Layout** : Composant wrapper avec AppBar et navigation
|
|
||||||
- **NavigationTabs** : Navigation par onglets avec React Router
|
|
||||||
- **AppBar** : Barre de navigation principale
|
|
||||||
|
|
||||||
### Vues principales
|
|
||||||
|
|
||||||
#### UploadView
|
|
||||||
|
|
||||||
- **Dropzone** : Zone de glisser-déposer pour les fichiers
|
|
||||||
- **FileList** : Liste des documents uploadés
|
|
||||||
- **Status indicators** : Indicateurs de statut des documents
|
|
||||||
|
|
||||||
#### ExtractionView
|
|
||||||
|
|
||||||
- **DataDisplay** : Affichage des données extraites
|
|
||||||
- **ObjectLists** : Listes d'identités, adresses, biens, contrats
|
|
||||||
- **Confidence scores** : Scores de confiance des extractions
|
|
||||||
|
|
||||||
#### AnalyseView
|
|
||||||
|
|
||||||
- **CredibilityScore** : Score de vraisemblance du document
|
|
||||||
- **Recommendations** : Liste des recommandations
|
|
||||||
- **Summary** : Synthèse de l'analyse
|
|
||||||
|
|
||||||
#### ContexteView
|
|
||||||
|
|
||||||
- **ExternalData** : Données des APIs externes
|
|
||||||
- **StatusCards** : Cartes de statut pour chaque source
|
|
||||||
- **LastUpdated** : Horodatage des dernières mises à jour
|
|
||||||
|
|
||||||
#### ConseilView
|
|
||||||
|
|
||||||
- **LLMAnalysis** : Analyse générée par l'IA
|
|
||||||
- **RiskAssessment** : Évaluation des risques
|
|
||||||
- **NextSteps** : Prochaines étapes recommandées
|
|
||||||
|
|
||||||
## Gestion d'état Redux
|
|
||||||
|
|
||||||
### Structure du store
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
interface RootState {
|
|
||||||
app: AppState // État global de l'application
|
|
||||||
document: DocumentState // État des documents et opérations
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### AppState
|
|
||||||
|
|
||||||
- **status** : État global ('idle' | 'loading' | 'succeeded' | 'failed')
|
|
||||||
- **error** : Messages d'erreur globaux
|
|
||||||
|
|
||||||
### DocumentState
|
|
||||||
|
|
||||||
- **documents** : Liste des documents uploadés
|
|
||||||
- **currentDocument** : Document actuellement sélectionné
|
|
||||||
- **extractionResult** : Résultats d'extraction
|
|
||||||
- **analysisResult** : Résultats d'analyse
|
|
||||||
- **contextResult** : Données contextuelles
|
|
||||||
- **conseilResult** : Conseil IA
|
|
||||||
- **loading** : État de chargement
|
|
||||||
- **error** : Messages d'erreur
|
|
||||||
|
|
||||||
### Actions asynchrones
|
|
||||||
|
|
||||||
- **uploadDocument** : Upload d'un document
|
|
||||||
- **extractDocument** : Extraction des données
|
|
||||||
- **analyzeDocument** : Analyse du document
|
|
||||||
- **getContextData** : Récupération des données contextuelles
|
|
||||||
- **getConseil** : Génération du conseil IA
|
|
||||||
|
|
||||||
## Services API
|
|
||||||
|
|
||||||
### Configuration Axios
|
|
||||||
|
|
||||||
- **Base URL** : Configuration via variables d'environnement
|
|
||||||
- **Timeout** : 60 secondes pour les opérations longues
|
|
||||||
- **Intercepteurs** : Gestion d'erreur et fallback automatique
|
|
||||||
|
|
||||||
### Endpoints
|
|
||||||
|
|
||||||
- `POST /api/documents/upload` : Upload de document
|
|
||||||
- `GET /api/documents/{id}/extract` : Extraction de données
|
|
||||||
- `GET /api/documents/{id}/analyze` : Analyse du document
|
|
||||||
- `GET /api/documents/{id}/context` : Données contextuelles
|
|
||||||
- `GET /api/documents/{id}/conseil` : Conseil IA
|
|
||||||
|
|
||||||
### Gestion d'erreur
|
|
||||||
|
|
||||||
- **Intercepteurs** : Détection automatique des erreurs
|
|
||||||
- **Fallback** : Données de démonstration en cas d'erreur
|
|
||||||
- **Codes gérés** : 404, 405, ERR_NETWORK, ERR_CONNECTION_REFUSED
|
|
||||||
|
|
||||||
## Types et interfaces
|
|
||||||
|
|
||||||
### Document
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
interface Document {
|
|
||||||
id: string
|
|
||||||
name: string
|
|
||||||
type: string
|
|
||||||
size: number
|
|
||||||
uploadDate: Date
|
|
||||||
status: 'uploading' | 'processing' | 'completed' | 'error'
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### ExtractionResult
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
interface ExtractionResult {
|
|
||||||
documentId: string
|
|
||||||
text: string
|
|
||||||
language: string
|
|
||||||
documentType: string
|
|
||||||
identities: Identity[]
|
|
||||||
addresses: Address[]
|
|
||||||
properties: Property[]
|
|
||||||
contracts: Contract[]
|
|
||||||
signatures: string[]
|
|
||||||
confidence: number
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### AnalysisResult
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
interface AnalysisResult {
|
|
||||||
documentId: string
|
|
||||||
documentType: string
|
|
||||||
isCNI: boolean
|
|
||||||
credibilityScore: number
|
|
||||||
summary: string
|
|
||||||
recommendations: string[]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Mode démonstration
|
|
||||||
|
|
||||||
### Fonctionnement
|
|
||||||
|
|
||||||
- **Détection automatique** : Vérification de la disponibilité du backend
|
|
||||||
- **Fallback gracieux** : Basculement vers des données de démonstration
|
|
||||||
- **Données réalistes** : Exemples d'actes notariaux authentiques
|
|
||||||
- **Fonctionnalités complètes** : Toutes les vues opérationnelles
|
|
||||||
|
|
||||||
### Données de démonstration
|
|
||||||
|
|
||||||
- **Documents** : Exemples d'actes de vente, CNI, etc.
|
|
||||||
- **Identités** : Personnes avec informations complètes
|
|
||||||
- **Adresses** : Adresses françaises réalistes
|
|
||||||
- **Biens** : Propriétés avec références cadastrales
|
|
||||||
- **Contrats** : Clauses et montants réalistes
|
|
||||||
|
|
||||||
## Performance et optimisation
|
|
||||||
|
|
||||||
### Code splitting
|
|
||||||
|
|
||||||
- **Lazy loading** : Chargement à la demande des vues
|
|
||||||
- **Suspense** : Gestion des états de chargement
|
|
||||||
- **Bundle optimization** : Optimisation de la taille des bundles
|
|
||||||
|
|
||||||
### Caching
|
|
||||||
|
|
||||||
- **Redux state** : Mise en cache des données dans le store
|
|
||||||
- **API responses** : Cache des réponses API
|
|
||||||
- **Component memoization** : Optimisation des re-renders
|
|
||||||
|
|
||||||
### Build optimization
|
|
||||||
|
|
||||||
- **Vite** : Build rapide avec optimisations automatiques
|
|
||||||
- **Tree shaking** : Élimination du code mort
|
|
||||||
- **Minification** : Compression du code de production
|
|
||||||
|
|
||||||
## Sécurité
|
|
||||||
|
|
||||||
### Validation
|
|
||||||
|
|
||||||
- **TypeScript** : Validation de types à la compilation
|
|
||||||
- **Runtime validation** : Validation des données API
|
|
||||||
- **Input sanitization** : Nettoyage des entrées utilisateur
|
|
||||||
|
|
||||||
### CORS et CSP
|
|
||||||
|
|
||||||
- **CORS** : Configuration des en-têtes Cross-Origin
|
|
||||||
- **CSP** : Content Security Policy pour la sécurité
|
|
||||||
- **HTTPS** : Communication sécurisée en production
|
|
||||||
|
|
||||||
## Déploiement
|
|
||||||
|
|
||||||
### Environnements
|
|
||||||
|
|
||||||
- **Développement** : Serveur local avec HMR
|
|
||||||
- **Staging** : Environnement de test
|
|
||||||
- **Production** : Déploiement optimisé
|
|
||||||
|
|
||||||
### Variables d'environnement
|
|
||||||
|
|
||||||
- **VITE_API_URL** : URL de l'API backend
|
|
||||||
- **VITE_*_API_URL** : URLs des APIs externes
|
|
||||||
- **NODE_ENV** : Environnement d'exécution
|
|
||||||
|
|
||||||
### Build de production
|
|
||||||
|
|
||||||
- **Optimisation** : Minification et compression
|
|
||||||
- **Assets** : Optimisation des images et CSS
|
|
||||||
- **Bundle analysis** : Analyse de la taille des bundles
|
|
||||||
@ -1,554 +0,0 @@
|
|||||||
# Guide de déploiement - Lecoffre.io
|
|
||||||
|
|
||||||
## Vue d'ensemble
|
|
||||||
|
|
||||||
Ce guide couvre le déploiement de l'application 4NK IALecoffre.io dans différents environnements.
|
|
||||||
|
|
||||||
## Notes de version 0.1.2
|
|
||||||
|
|
||||||
### Changements principaux
|
|
||||||
|
|
||||||
- Suppression du « mode démo » côté frontend et des fallbacks
|
|
||||||
- Routage des APIs externes exclusivement via le backend `4NK_IA_back`
|
|
||||||
- Exigence Node.js ≥ 20.19 pour la compilation
|
|
||||||
|
|
||||||
### Impact déploiement
|
|
||||||
|
|
||||||
- Variables `.env` front simplifiées (uniquement `VITE_API_URL`)
|
|
||||||
- Build requis avec Node.js ≥ 20.19
|
|
||||||
|
|
||||||
### Étapes recommandées
|
|
||||||
|
|
||||||
1. Mettre à jour l’environnement: variables `.env.*` si nécessaire
|
|
||||||
2. Rebuilder l’application
|
|
||||||
3. Synchroniser `dist/` vers le serveur web et recharger Nginx
|
|
||||||
|
|
||||||
Exemple de séquence côté serveur (Nginx):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /var/www/4nk-ia-front
|
|
||||||
git fetch --all --prune
|
|
||||||
git checkout dev
|
|
||||||
git pull --ff-only
|
|
||||||
npm ci
|
|
||||||
npm run build
|
|
||||||
sudo systemctl reload nginx
|
|
||||||
```
|
|
||||||
|
|
||||||
## Prérequis
|
|
||||||
|
|
||||||
### Environnement de développement
|
|
||||||
|
|
||||||
- **Node.js** : >= 20.19.0 (ou >= 22.12.0)
|
|
||||||
- **npm** : >= 10.0.0
|
|
||||||
- **nvm** : recommandé, le projet fournit `.nvmrc`
|
|
||||||
- **Git** : Pour la gestion des versions
|
|
||||||
|
|
||||||
### Environnement de production
|
|
||||||
|
|
||||||
- **Serveur web** : Nginx ou Apache
|
|
||||||
- **HTTPS** : Certificat SSL valide
|
|
||||||
- **CDN** : Optionnel pour les assets statiques
|
|
||||||
|
|
||||||
## Configuration des environnements
|
|
||||||
|
|
||||||
### Variables d'environnement
|
|
||||||
|
|
||||||
#### Développement (.env.development)
|
|
||||||
|
|
||||||
```env
|
|
||||||
NODE_ENV=development
|
|
||||||
VITE_API_URL=http://localhost:8000
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Staging (.env.staging)
|
|
||||||
|
|
||||||
```env
|
|
||||||
NODE_ENV=staging
|
|
||||||
VITE_API_URL=https://api-staging.4nkweb.com
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Production (.env.production)
|
|
||||||
|
|
||||||
```env
|
|
||||||
NODE_ENV=production
|
|
||||||
VITE_API_URL=https://api.4nkweb.com
|
|
||||||
```
|
|
||||||
|
|
||||||
## Build de production
|
|
||||||
|
|
||||||
### Script de build
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Build standard
|
|
||||||
npm run build
|
|
||||||
|
|
||||||
# Build avec analyse
|
|
||||||
npm run build -- --analyze
|
|
||||||
|
|
||||||
# Build pour un environnement spécifique
|
|
||||||
npm run build -- --mode production
|
|
||||||
```
|
|
||||||
|
|
||||||
### Optimisations automatiques
|
|
||||||
|
|
||||||
- **Minification** : Code JavaScript et CSS minifié
|
|
||||||
- **Tree shaking** : Élimination du code mort
|
|
||||||
- **Code splitting** : Division en chunks optimaux
|
|
||||||
- **Asset optimization** : Optimisation des images et fonts
|
|
||||||
|
|
||||||
### Structure du build
|
|
||||||
|
|
||||||
```text
|
|
||||||
dist/
|
|
||||||
├── index.html # Point d'entrée HTML
|
|
||||||
├── assets/
|
|
||||||
│ ├── index-[hash].js # Bundle principal
|
|
||||||
│ ├── index-[hash].css # Styles principaux
|
|
||||||
│ ├── [chunk]-[hash].js # Chunks de code splitting
|
|
||||||
│ └── [asset]-[hash].[ext] # Assets optimisés
|
|
||||||
└── favicon.ico # Icône du site
|
|
||||||
```
|
|
||||||
|
|
||||||
## Déploiement sur serveur
|
|
||||||
|
|
||||||
### Configuration Nginx
|
|
||||||
### Déploiement via Docker
|
|
||||||
|
|
||||||
#### Construction et push de l'image
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Construire l'image (tag par défaut: commit SHA court)
|
|
||||||
./scripts/docker-build.sh
|
|
||||||
|
|
||||||
# Construire avec tag explicite
|
|
||||||
IMAGE_TAG=0.1.3 ./scripts/docker-build.sh
|
|
||||||
|
|
||||||
# Pousser vers git.4nkweb.com (authentification requise)
|
|
||||||
IMAGE_TAG=0.1.3 ./scripts/docker-push.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Lancement de l'image
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run -d --name 4nk-ia-front -p 8080:80 git.4nkweb.com/4nk/4nk-ia-front:0.1.3
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Fichier de configuration
|
|
||||||
|
|
||||||
```nginx
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
listen [::]:80;
|
|
||||||
server_name app.4nkweb.com;
|
|
||||||
return 301 https://$server_name$request_uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen 443 ssl http2;
|
|
||||||
listen [::]:443 ssl http2;
|
|
||||||
server_name app.4nkweb.com;
|
|
||||||
|
|
||||||
# Certificats SSL
|
|
||||||
ssl_certificate /path/to/certificate.crt;
|
|
||||||
ssl_certificate_key /path/to/private.key;
|
|
||||||
|
|
||||||
# Configuration SSL
|
|
||||||
ssl_protocols TLSv1.2 TLSv1.3;
|
|
||||||
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
|
|
||||||
ssl_prefer_server_ciphers off;
|
|
||||||
|
|
||||||
# HSTS
|
|
||||||
add_header Strict-Transport-Security "max-age=63072000" always;
|
|
||||||
|
|
||||||
# Root directory
|
|
||||||
root /var/www/4nk-ia-front/dist;
|
|
||||||
index index.html;
|
|
||||||
|
|
||||||
# Gestion des routes SPA
|
|
||||||
location / {
|
|
||||||
try_files $uri $uri/ /index.html;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Cache des assets statiques
|
|
||||||
location /assets/ {
|
|
||||||
expires 1y;
|
|
||||||
add_header Cache-Control "public, immutable";
|
|
||||||
}
|
|
||||||
|
|
||||||
# Sécurité
|
|
||||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
||||||
add_header X-Content-Type-Options "nosniff" always;
|
|
||||||
add_header X-XSS-Protection "1; mode=block" always;
|
|
||||||
|
|
||||||
# Compression
|
|
||||||
gzip on;
|
|
||||||
gzip_vary on;
|
|
||||||
gzip_min_length 1024;
|
|
||||||
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Configuration Apache
|
|
||||||
|
|
||||||
#### Fichier .htaccess
|
|
||||||
|
|
||||||
```apache
|
|
||||||
RewriteEngine On
|
|
||||||
|
|
||||||
# Redirection HTTPS
|
|
||||||
RewriteCond %{HTTPS} off
|
|
||||||
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
|
|
||||||
|
|
||||||
# Gestion des routes SPA
|
|
||||||
RewriteCond %{REQUEST_FILENAME} !-f
|
|
||||||
RewriteCond %{REQUEST_FILENAME} !-d
|
|
||||||
RewriteRule . /index.html [L]
|
|
||||||
|
|
||||||
# Cache des assets
|
|
||||||
<FilesMatch "\.(css|js|png|jpg|jpeg|gif|ico|svg)$">
|
|
||||||
ExpiresActive On
|
|
||||||
ExpiresDefault "access plus 1 year"
|
|
||||||
Header set Cache-Control "public, immutable"
|
|
||||||
</FilesMatch>
|
|
||||||
|
|
||||||
# Compression
|
|
||||||
<IfModule mod_deflate.c>
|
|
||||||
AddOutputFilterByType DEFLATE text/plain
|
|
||||||
AddOutputFilterByType DEFLATE text/html
|
|
||||||
AddOutputFilterByType DEFLATE text/xml
|
|
||||||
AddOutputFilterByType DEFLATE text/css
|
|
||||||
AddOutputFilterByType DEFLATE application/xml
|
|
||||||
AddOutputFilterByType DEFLATE application/xhtml+xml
|
|
||||||
AddOutputFilterByType DEFLATE application/rss+xml
|
|
||||||
AddOutputFilterByType DEFLATE application/javascript
|
|
||||||
AddOutputFilterByType DEFLATE application/x-javascript
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
# Sécurité
|
|
||||||
Header always set X-Frame-Options "SAMEORIGIN"
|
|
||||||
Header always set X-Content-Type-Options "nosniff"
|
|
||||||
Header always set X-XSS-Protection "1; mode=block"
|
|
||||||
Header always set Strict-Transport-Security "max-age=63072000"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Déploiement avec Docker
|
|
||||||
|
|
||||||
### Dockerfile
|
|
||||||
|
|
||||||
```dockerfile
|
|
||||||
# Build stage
|
|
||||||
FROM node:22.12-alpine AS builder
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
COPY package*.json ./
|
|
||||||
RUN npm ci --only=production
|
|
||||||
|
|
||||||
COPY . .
|
|
||||||
RUN npm run build
|
|
||||||
|
|
||||||
# Production stage
|
|
||||||
FROM nginx:alpine
|
|
||||||
|
|
||||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
|
||||||
COPY nginx.conf /etc/nginx/nginx.conf
|
|
||||||
|
|
||||||
EXPOSE 80
|
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
|
||||||
```
|
|
||||||
|
|
||||||
### docker-compose.yml
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
version: '3.8'
|
|
||||||
|
|
||||||
services:
|
|
||||||
frontend:
|
|
||||||
build: .
|
|
||||||
ports:
|
|
||||||
- "80:80"
|
|
||||||
- "443:443"
|
|
||||||
volumes:
|
|
||||||
- ./ssl:/etc/nginx/ssl:ro
|
|
||||||
environment:
|
|
||||||
- NODE_ENV=production
|
|
||||||
restart: unless-stopped
|
|
||||||
```
|
|
||||||
|
|
||||||
### Script de déploiement
|
|
||||||
|
|
||||||
```bash
|
|
||||||
#!/bin/bash
|
|
||||||
# deploy.sh
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
echo "Building application..."
|
|
||||||
docker build -t 4nk-ia-front .
|
|
||||||
|
|
||||||
echo "Stopping existing container..."
|
|
||||||
docker stop 4nk-ia-front || true
|
|
||||||
docker rm 4nk-ia-front || true
|
|
||||||
|
|
||||||
echo "Starting new container..."
|
|
||||||
docker run -d \
|
|
||||||
--name 4nk-ia-front \
|
|
||||||
-p 80:80 \
|
|
||||||
-p 443:443 \
|
|
||||||
-v /path/to/ssl:/etc/nginx/ssl:ro \
|
|
||||||
4nk-ia-front
|
|
||||||
|
|
||||||
echo "Deployment completed!"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Déploiement avec CI/CD
|
|
||||||
|
|
||||||
### GitHub Actions
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: Deploy
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [release]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
deploy:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: '22.12'
|
|
||||||
cache: 'npm'
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm ci
|
|
||||||
|
|
||||||
- name: Run tests
|
|
||||||
run: npm run test
|
|
||||||
|
|
||||||
- name: Build application
|
|
||||||
run: npm run build
|
|
||||||
env:
|
|
||||||
NODE_ENV: production
|
|
||||||
VITE_API_URL: ${{ secrets.API_URL }}
|
|
||||||
|
|
||||||
- name: Deploy to server
|
|
||||||
uses: appleboy/ssh-action@v0.1.5
|
|
||||||
with:
|
|
||||||
host: ${{ secrets.HOST }}
|
|
||||||
username: ${{ secrets.USERNAME }}
|
|
||||||
key: ${{ secrets.SSH_KEY }}
|
|
||||||
script: |
|
|
||||||
cd /var/www/4nk-ia-front
|
|
||||||
git pull origin release
|
|
||||||
npm ci
|
|
||||||
npm run build
|
|
||||||
sudo systemctl reload nginx
|
|
||||||
```
|
|
||||||
|
|
||||||
### GitLab CI
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
stages:
|
|
||||||
- test
|
|
||||||
- build
|
|
||||||
- deploy
|
|
||||||
|
|
||||||
test:
|
|
||||||
stage: test
|
|
||||||
image: node:22.12-alpine
|
|
||||||
script:
|
|
||||||
- npm ci
|
|
||||||
- npm run test
|
|
||||||
only:
|
|
||||||
- merge_requests
|
|
||||||
- release
|
|
||||||
|
|
||||||
build:
|
|
||||||
stage: build
|
|
||||||
image: node:22.12-alpine
|
|
||||||
script:
|
|
||||||
- npm ci
|
|
||||||
- npm run build
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- dist/
|
|
||||||
expire_in: 1 hour
|
|
||||||
only:
|
|
||||||
- release
|
|
||||||
|
|
||||||
deploy:
|
|
||||||
stage: deploy
|
|
||||||
image: alpine:latest
|
|
||||||
before_script:
|
|
||||||
- apk add --no-cache openssh-client
|
|
||||||
- eval $(ssh-agent -s)
|
|
||||||
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
|
|
||||||
- mkdir -p ~/.ssh
|
|
||||||
- chmod 700 ~/.ssh
|
|
||||||
script:
|
|
||||||
- scp -r dist/* $DEPLOY_USER@$DEPLOY_HOST:/var/www/4nk-ia-front/
|
|
||||||
- ssh $DEPLOY_USER@$DEPLOY_HOST "sudo systemctl reload nginx"
|
|
||||||
only:
|
|
||||||
- release
|
|
||||||
```
|
|
||||||
|
|
||||||
## Monitoring et surveillance
|
|
||||||
|
|
||||||
### Métriques de performance
|
|
||||||
|
|
||||||
- **Temps de chargement** : Mesure du First Contentful Paint
|
|
||||||
- **Taille des bundles** : Surveillance de la taille des assets
|
|
||||||
- **Erreurs JavaScript** : Tracking des erreurs côté client
|
|
||||||
|
|
||||||
### Outils de monitoring
|
|
||||||
|
|
||||||
- **Google Analytics** : Analytics et performance
|
|
||||||
- **Sentry** : Monitoring des erreurs
|
|
||||||
- **Lighthouse** : Audit de performance
|
|
||||||
|
|
||||||
### Configuration Sentry
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import * as Sentry from "@sentry/react";
|
|
||||||
|
|
||||||
Sentry.init({
|
|
||||||
dsn: "YOUR_SENTRY_DSN",
|
|
||||||
environment: process.env.NODE_ENV,
|
|
||||||
tracesSampleRate: 1.0,
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## Rollback et récupération
|
|
||||||
|
|
||||||
### Stratégie de rollback
|
|
||||||
|
|
||||||
```bash
|
|
||||||
#!/bin/bash
|
|
||||||
# rollback.sh
|
|
||||||
|
|
||||||
PREVIOUS_VERSION=$1
|
|
||||||
|
|
||||||
if [ -z "$PREVIOUS_VERSION" ]; then
|
|
||||||
echo "Usage: ./rollback.sh <version>"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Rolling back to version $PREVIOUS_VERSION..."
|
|
||||||
|
|
||||||
# Restaurer la version précédente
|
|
||||||
git checkout $PREVIOUS_VERSION
|
|
||||||
npm ci
|
|
||||||
npm run build
|
|
||||||
|
|
||||||
# Redéployer
|
|
||||||
sudo systemctl reload nginx
|
|
||||||
|
|
||||||
echo "Rollback completed!"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Sauvegarde
|
|
||||||
|
|
||||||
```bash
|
|
||||||
#!/bin/bash
|
|
||||||
# backup.sh
|
|
||||||
|
|
||||||
BACKUP_DIR="/backups/4nk-ia-front"
|
|
||||||
DATE=$(date +%Y%m%d_%H%M%S)
|
|
||||||
|
|
||||||
# Créer le répertoire de sauvegarde
|
|
||||||
mkdir -p $BACKUP_DIR
|
|
||||||
|
|
||||||
# Sauvegarder les fichiers
|
|
||||||
tar -czf $BACKUP_DIR/backup_$DATE.tar.gz /var/www/4nk-ia-front
|
|
||||||
|
|
||||||
# Nettoyer les anciennes sauvegardes (garder 7 jours)
|
|
||||||
find $BACKUP_DIR -name "backup_*.tar.gz" -mtime +7 -delete
|
|
||||||
|
|
||||||
echo "Backup completed: backup_$DATE.tar.gz"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Sécurité
|
|
||||||
|
|
||||||
### Headers de sécurité
|
|
||||||
|
|
||||||
- **CSP** : Content Security Policy
|
|
||||||
- **HSTS** : HTTP Strict Transport Security
|
|
||||||
- **X-Frame-Options** : Protection contre le clickjacking
|
|
||||||
- **X-Content-Type-Options** : Protection contre MIME sniffing
|
|
||||||
|
|
||||||
### Configuration CSP
|
|
||||||
|
|
||||||
```html
|
|
||||||
<meta http-equiv="Content-Security-Policy" content="
|
|
||||||
default-src 'self';
|
|
||||||
script-src 'self' 'unsafe-inline' 'unsafe-eval';
|
|
||||||
style-src 'self' 'unsafe-inline';
|
|
||||||
img-src 'self' data: https:;
|
|
||||||
connect-src 'self' https://api.4nkweb.com;
|
|
||||||
font-src 'self' data:;
|
|
||||||
">
|
|
||||||
```
|
|
||||||
|
|
||||||
### Audit de sécurité
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Audit des dépendances
|
|
||||||
npm audit
|
|
||||||
|
|
||||||
# Audit de sécurité avec Snyk
|
|
||||||
npx snyk test
|
|
||||||
|
|
||||||
# Scan de vulnérabilités
|
|
||||||
npx audit-ci --config audit-ci.json
|
|
||||||
```
|
|
||||||
|
|
||||||
## Maintenance
|
|
||||||
|
|
||||||
### Mise à jour des dépendances
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Vérifier les mises à jour
|
|
||||||
npm outdated
|
|
||||||
|
|
||||||
# Mettre à jour les dépendances
|
|
||||||
npm update
|
|
||||||
|
|
||||||
# Mise à jour majeure
|
|
||||||
npx npm-check-updates -u
|
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
### Nettoyage
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Nettoyer le cache npm
|
|
||||||
npm cache clean --force
|
|
||||||
|
|
||||||
# Nettoyer les node_modules
|
|
||||||
rm -rf node_modules package-lock.json
|
|
||||||
npm install
|
|
||||||
|
|
||||||
# Nettoyer le build
|
|
||||||
rm -rf dist
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
|
|
||||||
### Logs et debugging
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Logs Nginx
|
|
||||||
sudo tail -f /var/log/nginx/access.log
|
|
||||||
sudo tail -f /var/log/nginx/error.log
|
|
||||||
|
|
||||||
# Logs de l'application
|
|
||||||
sudo journalctl -u nginx -f
|
|
||||||
|
|
||||||
# Debug des erreurs
|
|
||||||
sudo nginx -t # Test de configuration
|
|
||||||
```
|
|
||||||
627
docs/TESTING.md
627
docs/TESTING.md
@ -1,627 +0,0 @@
|
|||||||
# Guide de tests - 4NK IA Lecoffre.io
|
|
||||||
|
|
||||||
## Vue d'ensemble
|
|
||||||
|
|
||||||
Ce guide couvre la stratégie de tests pour l'application 4NK IA Lecoffre.io, incluant les tests unitaires,
|
|
||||||
d'intégration et end-to-end.
|
|
||||||
|
|
||||||
## Stack de test
|
|
||||||
|
|
||||||
### Outils principaux
|
|
||||||
|
|
||||||
- **Vitest** : Framework de test rapide et moderne
|
|
||||||
- **Testing Library** : Tests d'intégration React
|
|
||||||
- **JSDOM** : Environnement DOM simulé
|
|
||||||
- **MSW** : Mock Service Worker pour les APIs
|
|
||||||
- **Coverage V8** : Rapport de couverture de code
|
|
||||||
|
|
||||||
### Configuration
|
|
||||||
|
|
||||||
#### vitest.config.ts
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { defineConfig } from 'vitest/config'
|
|
||||||
import react from '@vitejs/plugin-react'
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
plugins: [react()],
|
|
||||||
test: {
|
|
||||||
environment: 'jsdom',
|
|
||||||
globals: true,
|
|
||||||
coverage: {
|
|
||||||
provider: 'v8',
|
|
||||||
reporter: ['text', 'json', 'html'],
|
|
||||||
exclude: [
|
|
||||||
'node_modules/',
|
|
||||||
'dist/',
|
|
||||||
'**/*.d.ts',
|
|
||||||
'**/*.config.*',
|
|
||||||
'**/setup.*'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
#### setup.test.ts
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { expect, afterEach } from 'vitest'
|
|
||||||
import { cleanup } from '@testing-library/react'
|
|
||||||
import * as matchers from '@testing-library/jest-dom/matchers'
|
|
||||||
|
|
||||||
// Étendre les matchers de testing-library
|
|
||||||
expect.extend(matchers)
|
|
||||||
|
|
||||||
// Nettoyer après chaque test
|
|
||||||
afterEach(() => {
|
|
||||||
cleanup()
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
## Types de tests
|
|
||||||
|
|
||||||
### Tests unitaires
|
|
||||||
|
|
||||||
#### Composants React
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// tests/components/Layout.test.tsx
|
|
||||||
import { render, screen } from '@testing-library/react'
|
|
||||||
import { BrowserRouter } from 'react-router-dom'
|
|
||||||
import { Provider } from 'react-redux'
|
|
||||||
import { store } from '../../src/store'
|
|
||||||
import { Layout } from '../../src/components/Layout'
|
|
||||||
|
|
||||||
const renderWithProviders = (ui: React.ReactElement) => {
|
|
||||||
return render(
|
|
||||||
<Provider store={store}>
|
|
||||||
<BrowserRouter>
|
|
||||||
{ui}
|
|
||||||
</BrowserRouter>
|
|
||||||
</Provider>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('Layout', () => {
|
|
||||||
it('should render the application title', () => {
|
|
||||||
renderWithProviders(<Layout><div>Test content</div></Layout>)
|
|
||||||
|
|
||||||
expect(screen.getByText('4NK IA - Lecoffre.io')).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render navigation tabs', () => {
|
|
||||||
renderWithProviders(<Layout><div>Test content</div></Layout>)
|
|
||||||
|
|
||||||
expect(screen.getByRole('tablist')).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Services API
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// tests/services/api.test.ts
|
|
||||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
||||||
import { documentApi } from '../../src/services/api'
|
|
||||||
import axios from 'axios'
|
|
||||||
|
|
||||||
// Mock axios
|
|
||||||
vi.mock('axios')
|
|
||||||
const mockedAxios = vi.mocked(axios)
|
|
||||||
|
|
||||||
describe('documentApi', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
vi.clearAllMocks()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('upload', () => {
|
|
||||||
it('should upload a document successfully', async () => {
|
|
||||||
const mockResponse = {
|
|
||||||
data: {
|
|
||||||
id: 'doc_123',
|
|
||||||
name: 'test.pdf',
|
|
||||||
type: 'application/pdf',
|
|
||||||
size: 1024,
|
|
||||||
uploadDate: new Date(),
|
|
||||||
status: 'completed'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mockedAxios.create.mockReturnValue({
|
|
||||||
post: vi.fn().mockResolvedValue(mockResponse)
|
|
||||||
} as any)
|
|
||||||
|
|
||||||
const file = new File(['content'], 'test.pdf', { type: 'application/pdf' })
|
|
||||||
const result = await documentApi.upload(file)
|
|
||||||
|
|
||||||
expect(result.id).toBe('doc_123')
|
|
||||||
expect(result.name).toBe('test.pdf')
|
|
||||||
expect(result.status).toBe('completed')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should return demo data on error', async () => {
|
|
||||||
mockedAxios.create.mockReturnValue({
|
|
||||||
post: vi.fn().mockRejectedValue(new Error('Network error'))
|
|
||||||
} as any)
|
|
||||||
|
|
||||||
const file = new File(['content'], 'test.pdf', { type: 'application/pdf' })
|
|
||||||
const result = await documentApi.upload(file)
|
|
||||||
|
|
||||||
expect(result.id).toMatch(/^demo-/)
|
|
||||||
expect(result.name).toBe('test.pdf')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Redux Slices
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// tests/store/documentSlice.test.ts
|
|
||||||
import { describe, it, expect } from 'vitest'
|
|
||||||
import documentReducer, { setCurrentDocument } from '../../src/store/documentSlice'
|
|
||||||
import { uploadDocument } from '../../src/store/documentSlice'
|
|
||||||
|
|
||||||
describe('documentSlice', () => {
|
|
||||||
const initialState = {
|
|
||||||
documents: [],
|
|
||||||
currentDocument: null,
|
|
||||||
extractionResult: null,
|
|
||||||
analysisResult: null,
|
|
||||||
contextResult: null,
|
|
||||||
conseilResult: null,
|
|
||||||
loading: false,
|
|
||||||
error: null
|
|
||||||
}
|
|
||||||
|
|
||||||
it('should handle setCurrentDocument', () => {
|
|
||||||
const document = {
|
|
||||||
id: 'doc_123',
|
|
||||||
name: 'test.pdf',
|
|
||||||
type: 'application/pdf',
|
|
||||||
size: 1024,
|
|
||||||
uploadDate: new Date(),
|
|
||||||
status: 'completed' as const
|
|
||||||
}
|
|
||||||
|
|
||||||
const action = setCurrentDocument(document)
|
|
||||||
const newState = documentReducer(initialState, action)
|
|
||||||
|
|
||||||
expect(newState.currentDocument).toEqual(document)
|
|
||||||
expect(newState.extractionResult).toBeNull()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle uploadDocument.pending', () => {
|
|
||||||
const action = { type: uploadDocument.pending.type }
|
|
||||||
const newState = documentReducer(initialState, action)
|
|
||||||
|
|
||||||
expect(newState.loading).toBe(true)
|
|
||||||
expect(newState.error).toBeNull()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
### Tests d'intégration
|
|
||||||
|
|
||||||
#### Vues complètes
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// tests/views/UploadView.test.tsx
|
|
||||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
|
|
||||||
import userEvent from '@testing-library/user-event'
|
|
||||||
import { Provider } from 'react-redux'
|
|
||||||
import { BrowserRouter } from 'react-router-dom'
|
|
||||||
import { store } from '../../src/store'
|
|
||||||
import { UploadView } from '../../src/views/UploadView'
|
|
||||||
|
|
||||||
const renderWithProviders = (ui: React.ReactElement) => {
|
|
||||||
return render(
|
|
||||||
<Provider store={store}>
|
|
||||||
<BrowserRouter>
|
|
||||||
{ui}
|
|
||||||
</BrowserRouter>
|
|
||||||
</Provider>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('UploadView', () => {
|
|
||||||
it('should render upload area', () => {
|
|
||||||
renderWithProviders(<UploadView />)
|
|
||||||
|
|
||||||
expect(screen.getByText(/glisser-déposer/i)).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle file upload', async () => {
|
|
||||||
const user = userEvent.setup()
|
|
||||||
renderWithProviders(<UploadView />)
|
|
||||||
|
|
||||||
const file = new File(['content'], 'test.pdf', { type: 'application/pdf' })
|
|
||||||
const input = screen.getByLabelText(/sélectionner des fichiers/i)
|
|
||||||
|
|
||||||
await user.upload(input, file)
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(screen.getByText('test.pdf')).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should display document list after upload', async () => {
|
|
||||||
const user = userEvent.setup()
|
|
||||||
renderWithProviders(<UploadView />)
|
|
||||||
|
|
||||||
const file = new File(['content'], 'test.pdf', { type: 'application/pdf' })
|
|
||||||
const input = screen.getByLabelText(/sélectionner des fichiers/i)
|
|
||||||
|
|
||||||
await user.upload(input, file)
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(screen.getByRole('list')).toBeInTheDocument()
|
|
||||||
expect(screen.getByText('test.pdf')).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Navigation
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// tests/navigation.test.tsx
|
|
||||||
import { render, screen } from '@testing-library/react'
|
|
||||||
import userEvent from '@testing-library/user-event'
|
|
||||||
import { BrowserRouter } from 'react-router-dom'
|
|
||||||
import { Provider } from 'react-redux'
|
|
||||||
import { store } from '../src/store'
|
|
||||||
import App from '../src/App'
|
|
||||||
|
|
||||||
const renderWithProviders = (ui: React.ReactElement) => {
|
|
||||||
return render(
|
|
||||||
<Provider store={store}>
|
|
||||||
<BrowserRouter>
|
|
||||||
{ui}
|
|
||||||
</BrowserRouter>
|
|
||||||
</Provider>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('Navigation', () => {
|
|
||||||
it('should navigate between tabs', async () => {
|
|
||||||
const user = userEvent.setup()
|
|
||||||
renderWithProviders(<App />)
|
|
||||||
|
|
||||||
// Vérifier que l'onglet Upload est actif par défaut
|
|
||||||
expect(screen.getByText('Upload')).toHaveAttribute('aria-selected', 'true')
|
|
||||||
|
|
||||||
// Cliquer sur l'onglet Extraction
|
|
||||||
await user.click(screen.getByText('Extraction'))
|
|
||||||
|
|
||||||
expect(screen.getByText('Extraction')).toHaveAttribute('aria-selected', 'true')
|
|
||||||
expect(screen.getByText('Upload')).toHaveAttribute('aria-selected', 'false')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
### Tests d'API avec MSW
|
|
||||||
|
|
||||||
#### Configuration MSW
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// tests/mocks/handlers.ts
|
|
||||||
import { http, HttpResponse } from 'msw'
|
|
||||||
|
|
||||||
export const handlers = [
|
|
||||||
// Upload de document
|
|
||||||
http.post('/api/documents/upload', () => {
|
|
||||||
return HttpResponse.json({
|
|
||||||
id: 'doc_123',
|
|
||||||
name: 'test.pdf',
|
|
||||||
type: 'application/pdf',
|
|
||||||
size: 1024,
|
|
||||||
uploadDate: new Date().toISOString(),
|
|
||||||
status: 'completed'
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
|
|
||||||
// Extraction de données
|
|
||||||
http.get('/api/documents/:id/extract', () => {
|
|
||||||
return HttpResponse.json({
|
|
||||||
documentId: 'doc_123',
|
|
||||||
text: 'Texte extrait du document...',
|
|
||||||
language: 'fr',
|
|
||||||
documentType: 'Acte de vente',
|
|
||||||
identities: [
|
|
||||||
{
|
|
||||||
id: '1',
|
|
||||||
type: 'person',
|
|
||||||
firstName: 'Jean',
|
|
||||||
lastName: 'Dupont',
|
|
||||||
birthDate: '1980-05-15',
|
|
||||||
nationality: 'Française',
|
|
||||||
confidence: 0.95
|
|
||||||
}
|
|
||||||
],
|
|
||||||
addresses: [],
|
|
||||||
properties: [],
|
|
||||||
contracts: [],
|
|
||||||
signatures: [],
|
|
||||||
confidence: 0.92
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
|
|
||||||
// Erreur de connexion
|
|
||||||
http.get('/api/documents/:id/analyze', () => {
|
|
||||||
return HttpResponse.error()
|
|
||||||
})
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Tests avec MSW
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// tests/integration/api.test.tsx
|
|
||||||
import { setupServer } from 'msw/node'
|
|
||||||
import { handlers } from '../mocks/handlers'
|
|
||||||
import { documentApi } from '../../src/services/api'
|
|
||||||
|
|
||||||
const server = setupServer(...handlers)
|
|
||||||
|
|
||||||
beforeAll(() => server.listen())
|
|
||||||
afterEach(() => server.resetHandlers())
|
|
||||||
afterAll(() => server.close())
|
|
||||||
|
|
||||||
describe('API Integration', () => {
|
|
||||||
it('should extract document data', async () => {
|
|
||||||
const result = await documentApi.extract('doc_123')
|
|
||||||
|
|
||||||
expect(result.documentId).toBe('doc_123')
|
|
||||||
expect(result.identities).toHaveLength(1)
|
|
||||||
expect(result.identities[0].firstName).toBe('Jean')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle API errors gracefully', async () => {
|
|
||||||
const result = await documentApi.analyze('doc_123')
|
|
||||||
|
|
||||||
// Devrait retourner des données de démonstration
|
|
||||||
expect(result.documentId).toBe('doc_123')
|
|
||||||
expect(result.credibilityScore).toBeDefined()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
## Tests de performance
|
|
||||||
|
|
||||||
### Tests de rendu
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// tests/performance/render.test.tsx
|
|
||||||
import { render } from '@testing-library/react'
|
|
||||||
import { Provider } from 'react-redux'
|
|
||||||
import { BrowserRouter } from 'react-router-dom'
|
|
||||||
import { store } from '../../src/store'
|
|
||||||
import App from '../../src/App'
|
|
||||||
|
|
||||||
describe('Performance', () => {
|
|
||||||
it('should render app within acceptable time', () => {
|
|
||||||
const start = performance.now()
|
|
||||||
|
|
||||||
render(
|
|
||||||
<Provider store={store}>
|
|
||||||
<BrowserRouter>
|
|
||||||
<App />
|
|
||||||
</BrowserRouter>
|
|
||||||
</Provider>
|
|
||||||
)
|
|
||||||
|
|
||||||
const end = performance.now()
|
|
||||||
const renderTime = end - start
|
|
||||||
|
|
||||||
// Le rendu initial devrait prendre moins de 100ms
|
|
||||||
expect(renderTime).toBeLessThan(100)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
### Tests de mémoire
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// tests/performance/memory.test.tsx
|
|
||||||
import { render, cleanup } from '@testing-library/react'
|
|
||||||
import { Provider } from 'react-redux'
|
|
||||||
import { BrowserRouter } from 'react-router-dom'
|
|
||||||
import { store } from '../../src/store'
|
|
||||||
import { UploadView } from '../../src/views/UploadView'
|
|
||||||
|
|
||||||
describe('Memory Management', () => {
|
|
||||||
it('should not leak memory on multiple renders', () => {
|
|
||||||
const initialMemory = (performance as any).memory?.usedJSHeapSize || 0
|
|
||||||
|
|
||||||
// Rendre et nettoyer plusieurs fois
|
|
||||||
for (let i = 0; i < 10; i++) {
|
|
||||||
render(
|
|
||||||
<Provider store={store}>
|
|
||||||
<BrowserRouter>
|
|
||||||
<UploadView />
|
|
||||||
</BrowserRouter>
|
|
||||||
</Provider>
|
|
||||||
)
|
|
||||||
cleanup()
|
|
||||||
}
|
|
||||||
|
|
||||||
const finalMemory = (performance as any).memory?.usedJSHeapSize || 0
|
|
||||||
const memoryIncrease = finalMemory - initialMemory
|
|
||||||
|
|
||||||
// L'augmentation de mémoire devrait être raisonnable
|
|
||||||
expect(memoryIncrease).toBeLessThan(10 * 1024 * 1024) // 10MB
|
|
||||||
})
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
## Tests d'accessibilité
|
|
||||||
|
|
||||||
### Tests avec jest-axe
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// tests/accessibility/a11y.test.tsx
|
|
||||||
import { render } from '@testing-library/react'
|
|
||||||
import { axe, toHaveNoViolations } from 'jest-axe'
|
|
||||||
import { Provider } from 'react-redux'
|
|
||||||
import { BrowserRouter } from 'react-router-dom'
|
|
||||||
import { store } from '../../src/store'
|
|
||||||
import { Layout } from '../../src/components/Layout'
|
|
||||||
|
|
||||||
expect.extend(toHaveNoViolations)
|
|
||||||
|
|
||||||
describe('Accessibility', () => {
|
|
||||||
it('should not have accessibility violations', async () => {
|
|
||||||
const { container } = render(
|
|
||||||
<Provider store={store}>
|
|
||||||
<BrowserRouter>
|
|
||||||
<Layout>
|
|
||||||
<div>Test content</div>
|
|
||||||
</Layout>
|
|
||||||
</BrowserRouter>
|
|
||||||
</Provider>
|
|
||||||
)
|
|
||||||
|
|
||||||
const results = await axe(container)
|
|
||||||
expect(results).toHaveNoViolations()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should have proper ARIA labels', () => {
|
|
||||||
render(
|
|
||||||
<Provider store={store}>
|
|
||||||
<BrowserRouter>
|
|
||||||
<Layout>
|
|
||||||
<div>Test content</div>
|
|
||||||
</Layout>
|
|
||||||
</BrowserRouter>
|
|
||||||
</Provider>
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(screen.getByRole('banner')).toBeInTheDocument()
|
|
||||||
expect(screen.getByRole('tablist')).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
## Scripts de test
|
|
||||||
|
|
||||||
### package.json
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"scripts": {
|
|
||||||
"test": "vitest",
|
|
||||||
"test:ui": "vitest --ui",
|
|
||||||
"test:run": "vitest run",
|
|
||||||
"test:coverage": "vitest run --coverage",
|
|
||||||
"test:watch": "vitest --watch",
|
|
||||||
"test:debug": "vitest --inspect-brk"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Exécution des tests
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Tests en mode watch
|
|
||||||
npm run test
|
|
||||||
|
|
||||||
# Tests avec interface graphique
|
|
||||||
npm run test:ui
|
|
||||||
|
|
||||||
# Tests une seule fois
|
|
||||||
npm run test:run
|
|
||||||
|
|
||||||
# Tests avec couverture
|
|
||||||
npm run test:coverage
|
|
||||||
|
|
||||||
# Tests en mode debug
|
|
||||||
npm run test:debug
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration CI/CD
|
|
||||||
|
|
||||||
### GitHub Actions
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: Tests
|
|
||||||
|
|
||||||
on: [push, pull_request]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: '22.12'
|
|
||||||
cache: 'npm'
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm ci
|
|
||||||
|
|
||||||
- name: Run tests
|
|
||||||
run: npm run test:coverage
|
|
||||||
|
|
||||||
- name: Upload coverage
|
|
||||||
uses: codecov/codecov-action@v3
|
|
||||||
with:
|
|
||||||
file: ./coverage/lcov.info
|
|
||||||
```
|
|
||||||
|
|
||||||
## Bonnes pratiques
|
|
||||||
|
|
||||||
### Organisation des tests
|
|
||||||
|
|
||||||
- **Un fichier de test par composant** : `Component.test.tsx`
|
|
||||||
- **Tests groupés par fonctionnalité** : `describe` blocks
|
|
||||||
- **Tests isolés** : Chaque test doit être indépendant
|
|
||||||
- **Noms descriptifs** : `it('should do something specific')`
|
|
||||||
|
|
||||||
### Mocking
|
|
||||||
|
|
||||||
- **Mock des dépendances externes** : APIs, services
|
|
||||||
- **Mock des hooks** : React hooks personnalisés
|
|
||||||
- **Mock des modules** : Modules Node.js
|
|
||||||
|
|
||||||
### Assertions
|
|
||||||
|
|
||||||
- **Assertions spécifiques** : Éviter les assertions génériques
|
|
||||||
- **Tests de régression** : Vérifier les bugs corrigés
|
|
||||||
- **Tests de cas limites** : Valeurs nulles, erreurs
|
|
||||||
|
|
||||||
### Performance
|
|
||||||
|
|
||||||
- **Tests rapides** : Éviter les tests lents
|
|
||||||
- **Parallélisation** : Utiliser `--threads` pour Vitest
|
|
||||||
- **Cache** : Utiliser le cache des dépendances
|
|
||||||
|
|
||||||
## Métriques de qualité
|
|
||||||
|
|
||||||
### Couverture de code
|
|
||||||
|
|
||||||
- **Minimum 80%** : Couverture globale
|
|
||||||
- **Minimum 90%** : Composants critiques
|
|
||||||
- **100%** : Fonctions utilitaires
|
|
||||||
|
|
||||||
### Types de couverture
|
|
||||||
|
|
||||||
- **Statements** : Instructions exécutées
|
|
||||||
- **Branches** : Branches conditionnelles
|
|
||||||
- **Functions** : Fonctions appelées
|
|
||||||
- **Lines** : Lignes de code exécutées
|
|
||||||
|
|
||||||
### Rapport de couverture
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Générer le rapport
|
|
||||||
npm run test:coverage
|
|
||||||
|
|
||||||
# Ouvrir le rapport HTML
|
|
||||||
open coverage/index.html
|
|
||||||
```
|
|
||||||
@ -1,153 +0,0 @@
|
|||||||
# Analyse du système de détection CNI - Recherche CANTU/NICOLAS
|
|
||||||
|
|
||||||
## 📋 Résumé de l'analyse
|
|
||||||
|
|
||||||
Cette analyse a été effectuée pour rechercher les informations concernant **CANTU**, **NICOLAS** et le **code de vérification de la CNI** dans le projet 4NK_IA_front.
|
|
||||||
|
|
||||||
## 🔍 Système de détection identifié
|
|
||||||
|
|
||||||
### 1. Configuration OCR spécialisée
|
|
||||||
|
|
||||||
Le système contient une configuration OCR sophistiquée spécifiquement optimisée pour détecter les noms **NICOLAS** et **CANTU** avec correction des erreurs OCR courantes.
|
|
||||||
|
|
||||||
**Fichier principal :** `/backend/server.js` (lignes 130-151)
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Corrections pour "Nicolas"
|
|
||||||
'N1colas': 'Nicolas', 'Nicol@s': 'Nicolas', 'Nico1as': 'Nicolas',
|
|
||||||
'Nico1@s': 'Nicolas', 'N1co1as': 'Nicolas', 'N1co1@s': 'Nicolas',
|
|
||||||
|
|
||||||
// Corrections pour "Cantu"
|
|
||||||
'C@ntu': 'Cantu', 'CantU': 'Cantu', 'C@ntU': 'Cantu',
|
|
||||||
'Cant0': 'Cantu', 'C@nt0': 'Cantu', 'CantU': 'Cantu',
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Patterns de détection spécialisés
|
|
||||||
|
|
||||||
**Fichier :** `/backend/server.js` (lignes 171-189)
|
|
||||||
|
|
||||||
Le système utilise des expressions régulières sophistiquées pour détecter "Nicolas Cantu" même avec des erreurs OCR :
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Patterns spécifiques pour "Nicolas Cantu" avec variations OCR
|
|
||||||
/(N[il][cç][o0][l1][a@][s5]\s+[Cc][a@][n][t][u])/gi,
|
|
||||||
/(N[il][cç][o0][l1][a@][s5]\s+[Cc][a@][n][t][u])/gi,
|
|
||||||
// Recherche de "Nicolas" seul
|
|
||||||
/(N[il][cç][o0][l1][a@][s5])/gi,
|
|
||||||
// Recherche de "Cantu" seul
|
|
||||||
/([Cc][a@][n][t][u])/gi
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Système de détection des numéros CNI
|
|
||||||
|
|
||||||
**Fichier :** `/backend/server.js` (lignes 231-234)
|
|
||||||
|
|
||||||
Le système détecte les numéros de carte d'identité avec le pattern : `([A-Z]{2}\d{6})` (2 lettres + 6 chiffres).
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const cniPattern = /([A-Z]{2}\d{6})/g
|
|
||||||
for (const match of text.matchAll(cniPattern)) {
|
|
||||||
entities.cniNumbers.push({
|
|
||||||
id: `cni-${entities.cniNumbers.length}`,
|
|
||||||
number: match[1],
|
|
||||||
confidence: 0.95
|
|
||||||
})
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🖼️ Images de test disponibles
|
|
||||||
|
|
||||||
### Images analysées :
|
|
||||||
- `IMG_20250902_162159.jpg` (1052.7 KB)
|
|
||||||
- `IMG_20250902_162210.jpg` (980.8 KB)
|
|
||||||
|
|
||||||
**Localisation :** `/test-files/`
|
|
||||||
|
|
||||||
## 🧪 Tests effectués
|
|
||||||
|
|
||||||
### 1. Test d'extraction OCR directe
|
|
||||||
|
|
||||||
**Script créé :** `test-cni-direct.cjs`
|
|
||||||
|
|
||||||
**Résultats :**
|
|
||||||
- ✅ Images accessibles via le serveur
|
|
||||||
- ❌ Qualité OCR insuffisante sur les images test
|
|
||||||
- ❌ Aucune détection de "NICOLAS" ou "CANTU"
|
|
||||||
- ❌ Aucun numéro CNI détecté
|
|
||||||
|
|
||||||
### 2. Test avec configurations OCR multiples
|
|
||||||
|
|
||||||
**Script créé :** `test-cni-enhanced.cjs`
|
|
||||||
|
|
||||||
**Configurations testées :**
|
|
||||||
- Français + Anglais (défaut)
|
|
||||||
- Français uniquement
|
|
||||||
- Lettres et chiffres uniquement
|
|
||||||
- Mode page simple
|
|
||||||
|
|
||||||
**Résultats :**
|
|
||||||
- ❌ Toutes les configurations ont échoué à extraire du texte lisible
|
|
||||||
- ⚠️ Les images semblent être de mauvaise qualité ou corrompues
|
|
||||||
- ⚠️ Messages d'erreur : "Image too small to scale!! (2x36 vs min width of 3)"
|
|
||||||
|
|
||||||
## 🔧 Services backend disponibles
|
|
||||||
|
|
||||||
### Endpoints identifiés :
|
|
||||||
- `POST /api/extract` - Extraction OCR avec upload de fichier
|
|
||||||
- `GET /api/health` - Vérification de l'état du serveur
|
|
||||||
- `GET /api/test-files` - Accès aux fichiers de test
|
|
||||||
|
|
||||||
**Port :** 3001 (configurable via `PORT`)
|
|
||||||
|
|
||||||
## 📊 État du système
|
|
||||||
|
|
||||||
### ✅ Fonctionnalités opérationnelles :
|
|
||||||
- Serveur backend fonctionnel
|
|
||||||
- Système de correction OCR configuré
|
|
||||||
- Patterns de détection spécialisés implémentés
|
|
||||||
- Interface frontend accessible
|
|
||||||
|
|
||||||
### ❌ Problèmes identifiés :
|
|
||||||
- Qualité des images de test insuffisante pour l'OCR
|
|
||||||
- Extraction de texte corrompue
|
|
||||||
- Aucune détection réussie des noms cibles
|
|
||||||
|
|
||||||
## 🎯 Recommandations
|
|
||||||
|
|
||||||
### 1. Amélioration de la qualité des images
|
|
||||||
- Vérifier la résolution et la netteté des images
|
|
||||||
- Tester avec des images de meilleure qualité
|
|
||||||
- Ajuster les paramètres de préprocessing
|
|
||||||
|
|
||||||
### 2. Optimisation OCR
|
|
||||||
- Tester avec des paramètres OCR différents
|
|
||||||
- Implémenter un préprocessing d'image (contraste, netteté)
|
|
||||||
- Utiliser des modèles OCR spécialisés pour les documents d'identité
|
|
||||||
|
|
||||||
### 3. Tests supplémentaires
|
|
||||||
- Tester avec des images de CNI réelles de bonne qualité
|
|
||||||
- Valider les patterns de détection avec des données connues
|
|
||||||
- Implémenter des tests unitaires pour les fonctions de correction
|
|
||||||
|
|
||||||
## 📁 Fichiers créés/modifiés
|
|
||||||
|
|
||||||
### Scripts de test créés :
|
|
||||||
- `test-cni-direct.cjs` - Test d'extraction OCR directe
|
|
||||||
- `test-cni-enhanced.cjs` - Test avec configurations multiples
|
|
||||||
|
|
||||||
### Documentation :
|
|
||||||
- `docs/analyse-cni-cantu-nicolas.md` - Ce rapport d'analyse
|
|
||||||
|
|
||||||
## 🔍 Conclusion
|
|
||||||
|
|
||||||
Le système de détection CNI est **techniquement bien configuré** avec des patterns spécialisés pour détecter "NICOLAS CANTU" et les numéros de CNI. Cependant, les **images de test actuelles ne permettent pas une extraction OCR de qualité suffisante** pour valider le fonctionnement du système.
|
|
||||||
|
|
||||||
**Prochaines étapes recommandées :**
|
|
||||||
1. Obtenir des images de CNI de meilleure qualité
|
|
||||||
2. Tester avec l'interface frontend (http://localhost:5174)
|
|
||||||
3. Valider les patterns avec des données connues
|
|
||||||
4. Optimiser les paramètres OCR pour les documents d'identité
|
|
||||||
|
|
||||||
---
|
|
||||||
*Analyse effectuée le 15 septembre 2025*
|
|
||||||
*Projet : 4NK_IA_front*
|
|
||||||
@ -1,322 +0,0 @@
|
|||||||
# Architecture Backend pour le Traitement des Documents
|
|
||||||
|
|
||||||
## Vue d'ensemble
|
|
||||||
|
|
||||||
L'application utilise maintenant une architecture backend qui traite les données (OCR, NER) et renvoie du JSON au frontend. Cette approche améliore les performances et centralise le traitement des documents.
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
### 🏗️ Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
4NK_IA_front/
|
|
||||||
├── backend/ # Serveur backend Express
|
|
||||||
│ ├── server.js # Serveur principal
|
|
||||||
│ ├── package.json # Dépendances backend
|
|
||||||
│ └── uploads/ # Fichiers temporaires
|
|
||||||
├── src/ # Frontend React
|
|
||||||
│ ├── services/
|
|
||||||
│ │ ├── backendApi.ts # API backend
|
|
||||||
│ │ ├── openai.ts # Fallback local
|
|
||||||
│ │ └── ruleNer.ts # Règles NER
|
|
||||||
│ └── store/
|
|
||||||
│ └── documentSlice.ts # Redux avec backend
|
|
||||||
└── test-files/ # Fichiers de test
|
|
||||||
```
|
|
||||||
|
|
||||||
### 🔄 Flux de Données
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
graph TD
|
|
||||||
A[Frontend React] --> B[Backend Express]
|
|
||||||
B --> C[Tesseract.js OCR]
|
|
||||||
B --> D[Règles NER]
|
|
||||||
C --> E[Texte extrait]
|
|
||||||
D --> F[Entités extraites]
|
|
||||||
E --> G[JSON Response]
|
|
||||||
F --> G
|
|
||||||
G --> A
|
|
||||||
```
|
|
||||||
|
|
||||||
## Backend (Express.js)
|
|
||||||
|
|
||||||
### 🚀 Serveur Principal
|
|
||||||
|
|
||||||
**Fichier**: `backend/server.js`
|
|
||||||
|
|
||||||
**Port**: 3001
|
|
||||||
|
|
||||||
**Endpoints**:
|
|
||||||
- `POST /api/extract` - Extraction de documents
|
|
||||||
- `GET /api/test-files` - Liste des fichiers de test
|
|
||||||
- `GET /api/health` - Health check
|
|
||||||
|
|
||||||
### 📄 Traitement des Documents
|
|
||||||
|
|
||||||
#### 1. Upload et Validation
|
|
||||||
```javascript
|
|
||||||
// Configuration multer
|
|
||||||
const upload = multer({
|
|
||||||
storage: multer.diskStorage({...}),
|
|
||||||
limits: { fileSize: 10 * 1024 * 1024 }, // 10MB max
|
|
||||||
fileFilter: (req, file, cb) => {
|
|
||||||
const allowedTypes = ['image/jpeg', 'image/png', 'image/tiff', 'application/pdf']
|
|
||||||
// Validation des types de fichiers
|
|
||||||
}
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 2. Extraction OCR Optimisée
|
|
||||||
```javascript
|
|
||||||
async function extractTextFromImage(imagePath) {
|
|
||||||
const worker = await createWorker('fra+eng')
|
|
||||||
|
|
||||||
// Configuration optimisée pour cartes d'identité
|
|
||||||
const params = {
|
|
||||||
tessedit_pageseg_mode: '6',
|
|
||||||
tessedit_char_whitelist: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ...',
|
|
||||||
tessedit_ocr_engine_mode: '1', // LSTM
|
|
||||||
textord_min_xheight: '6', // Petits textes
|
|
||||||
// ... autres paramètres
|
|
||||||
}
|
|
||||||
|
|
||||||
await worker.setParameters(params)
|
|
||||||
const { data } = await worker.recognize(imagePath)
|
|
||||||
return { text: data.text, confidence: data.confidence }
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 3. Extraction NER par Règles
|
|
||||||
```javascript
|
|
||||||
function extractEntitiesFromText(text) {
|
|
||||||
const entities = {
|
|
||||||
identities: [],
|
|
||||||
addresses: [],
|
|
||||||
cniNumbers: [],
|
|
||||||
dates: [],
|
|
||||||
documentType: 'Document'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Patterns pour cartes d'identité
|
|
||||||
const namePatterns = [
|
|
||||||
/(Vendeur|Acheteur|...)\s*:\s*([A-Z][a-zà-öø-ÿ'\-]+\s+[A-Z][a-zà-öø-ÿ'\-]+)/gi,
|
|
||||||
/^([A-Z][A-ZÀ-ÖØ-öø-ÿ\s\-']{2,30})$/gm,
|
|
||||||
// ... autres patterns
|
|
||||||
]
|
|
||||||
|
|
||||||
// Extraction des entités...
|
|
||||||
return entities
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 📊 Réponse JSON
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"success": true,
|
|
||||||
"documentId": "doc-1234567890",
|
|
||||||
"fileName": "IMG_20250902_162159.jpg",
|
|
||||||
"fileSize": 1077961,
|
|
||||||
"mimeType": "image/jpeg",
|
|
||||||
"processing": {
|
|
||||||
"ocr": {
|
|
||||||
"text": "Texte extrait par OCR...",
|
|
||||||
"confidence": 85.5,
|
|
||||||
"wordCount": 25
|
|
||||||
},
|
|
||||||
"ner": {
|
|
||||||
"identities": [...],
|
|
||||||
"addresses": [...],
|
|
||||||
"cniNumbers": [...],
|
|
||||||
"dates": [...],
|
|
||||||
"documentType": "CNI"
|
|
||||||
},
|
|
||||||
"globalConfidence": 87.2
|
|
||||||
},
|
|
||||||
"extractedData": {
|
|
||||||
"documentType": "CNI",
|
|
||||||
"identities": [...],
|
|
||||||
"addresses": [...],
|
|
||||||
"cniNumbers": [...],
|
|
||||||
"dates": [...]
|
|
||||||
},
|
|
||||||
"timestamp": "2025-09-15T23:30:00.000Z"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Frontend (React)
|
|
||||||
|
|
||||||
### 🔌 Service Backend
|
|
||||||
|
|
||||||
**Fichier**: `src/services/backendApi.ts`
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
export async function extractDocumentBackend(
|
|
||||||
documentId: string,
|
|
||||||
file?: File,
|
|
||||||
hooks?: { onOcrProgress?: (progress: number) => void; onLlmProgress?: (progress: number) => void }
|
|
||||||
): Promise<ExtractionResult> {
|
|
||||||
|
|
||||||
const formData = new FormData()
|
|
||||||
formData.append('document', file)
|
|
||||||
|
|
||||||
const response = await fetch(`${BACKEND_URL}/api/extract`, {
|
|
||||||
method: 'POST',
|
|
||||||
body: formData
|
|
||||||
})
|
|
||||||
|
|
||||||
const result: BackendExtractionResult = await response.json()
|
|
||||||
|
|
||||||
// Conversion vers le format frontend
|
|
||||||
return convertBackendToFrontend(result)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 🔄 Redux Store
|
|
||||||
|
|
||||||
**Fichier**: `src/store/documentSlice.ts`
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
export const extractDocument = createAsyncThunk(
|
|
||||||
'document/extract',
|
|
||||||
async (documentId: string, thunkAPI) => {
|
|
||||||
// Vérifier si le backend est disponible
|
|
||||||
const backendAvailable = await checkBackendHealth()
|
|
||||||
|
|
||||||
if (backendAvailable) {
|
|
||||||
// Utiliser le backend
|
|
||||||
return await backendDocumentApi.extract(documentId, file, progressHooks)
|
|
||||||
} else {
|
|
||||||
// Fallback vers le mode local
|
|
||||||
return await openaiDocumentApi.extract(documentId, file, progressHooks)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Démarrage
|
|
||||||
|
|
||||||
### 🚀 Backend
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Option 1: Script automatique
|
|
||||||
./start-backend.sh
|
|
||||||
|
|
||||||
# Option 2: Manuel
|
|
||||||
cd backend
|
|
||||||
npm install
|
|
||||||
node server.js
|
|
||||||
```
|
|
||||||
|
|
||||||
### 🌐 Frontend
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
### 🧪 Test de l'Architecture
|
|
||||||
|
|
||||||
```bash
|
|
||||||
node test-backend-architecture.cjs
|
|
||||||
```
|
|
||||||
|
|
||||||
## Avantages
|
|
||||||
|
|
||||||
### 🚀 Performance
|
|
||||||
- **Traitement centralisé** : OCR et NER sur le serveur
|
|
||||||
- **Optimisations** : Paramètres OCR optimisés pour les cartes d'identité
|
|
||||||
- **Cache** : Possibilité de mettre en cache les résultats
|
|
||||||
|
|
||||||
### 🔧 Maintenabilité
|
|
||||||
- **Séparation des responsabilités** : Backend pour le traitement, frontend pour l'UI
|
|
||||||
- **API REST** : Interface claire entre frontend et backend
|
|
||||||
- **Fallback** : Mode local en cas d'indisponibilité du backend
|
|
||||||
|
|
||||||
### 📊 Monitoring
|
|
||||||
- **Logs détaillés** : Traçabilité complète du traitement
|
|
||||||
- **Health check** : Vérification de l'état du backend
|
|
||||||
- **Métriques** : Confiance OCR, nombre d'entités extraites
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### 🔧 Variables d'Environnement
|
|
||||||
|
|
||||||
**Backend**:
|
|
||||||
- `PORT=3001` - Port du serveur backend
|
|
||||||
|
|
||||||
**Frontend**:
|
|
||||||
- `VITE_BACKEND_URL=http://localhost:3001` - URL du backend
|
|
||||||
- `VITE_USE_RULE_NER=true` - Mode règles locales (fallback)
|
|
||||||
- `VITE_DISABLE_LLM=true` - Désactiver LLM
|
|
||||||
|
|
||||||
### 📁 Structure des Fichiers
|
|
||||||
|
|
||||||
```
|
|
||||||
backend/
|
|
||||||
├── server.js # Serveur Express
|
|
||||||
├── package.json # Dépendances
|
|
||||||
└── uploads/ # Fichiers temporaires (auto-créé)
|
|
||||||
|
|
||||||
src/services/
|
|
||||||
├── backendApi.ts # API backend
|
|
||||||
├── openai.ts # Fallback local
|
|
||||||
└── ruleNer.ts # Règles NER
|
|
||||||
|
|
||||||
docs/
|
|
||||||
└── architecture-backend.md # Cette documentation
|
|
||||||
```
|
|
||||||
|
|
||||||
## Dépannage
|
|
||||||
|
|
||||||
### ❌ Problèmes Courants
|
|
||||||
|
|
||||||
#### Backend non accessible
|
|
||||||
```bash
|
|
||||||
# Vérifier que le backend est démarré
|
|
||||||
curl http://localhost:3001/api/health
|
|
||||||
|
|
||||||
# Vérifier les logs
|
|
||||||
cd backend && node server.js
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Erreurs OCR
|
|
||||||
- Vérifier la taille des images (minimum 3x3 pixels)
|
|
||||||
- Ajuster les paramètres `textord_min_xheight`
|
|
||||||
- Vérifier les types de fichiers supportés
|
|
||||||
|
|
||||||
#### Erreurs de communication
|
|
||||||
- Vérifier que les ports 3001 (backend) et 5176 (frontend) sont libres
|
|
||||||
- Vérifier la configuration CORS
|
|
||||||
- Vérifier les variables d'environnement
|
|
||||||
|
|
||||||
### 🔍 Logs
|
|
||||||
|
|
||||||
**Backend**:
|
|
||||||
```
|
|
||||||
🚀 Serveur backend démarré sur le port 3001
|
|
||||||
📡 API disponible sur: http://localhost:3001/api
|
|
||||||
[OCR] Début de l'extraction pour: uploads/document-123.jpg
|
|
||||||
[OCR] Extraction terminée - Confiance: 85.5%
|
|
||||||
[NER] Extraction terminée: 2 identités, 1 adresse, 1 CNI
|
|
||||||
```
|
|
||||||
|
|
||||||
**Frontend**:
|
|
||||||
```
|
|
||||||
🚀 [STORE] Utilisation du backend pour l'extraction
|
|
||||||
📊 [PROGRESS] OCR doc-123: 30%
|
|
||||||
📊 [PROGRESS] NER doc-123: 50%
|
|
||||||
🎉 [BACKEND] Extraction terminée avec succès
|
|
||||||
```
|
|
||||||
|
|
||||||
## Évolutions Futures
|
|
||||||
|
|
||||||
### 🔮 Améliorations Possibles
|
|
||||||
|
|
||||||
1. **Base de données** : Stockage des résultats d'extraction
|
|
||||||
2. **Cache Redis** : Mise en cache des résultats OCR
|
|
||||||
3. **Queue système** : Traitement asynchrone des gros volumes
|
|
||||||
4. **API GraphQL** : Interface plus flexible
|
|
||||||
5. **Microservices** : Séparation OCR et NER
|
|
||||||
6. **Docker** : Containerisation pour le déploiement
|
|
||||||
7. **Monitoring** : Métriques et alertes
|
|
||||||
8. **Tests automatisés** : Suite de tests complète
|
|
||||||
@ -1,140 +0,0 @@
|
|||||||
# Chargement Dynamique des Fichiers de Test
|
|
||||||
|
|
||||||
## Vue d'ensemble
|
|
||||||
|
|
||||||
Le système de chargement dynamique des fichiers de test permet à l'application de charger automatiquement tous les fichiers présents dans le dossier `test-files/` au lieu d'utiliser une liste de fichiers codée en dur.
|
|
||||||
|
|
||||||
## Fonctionnalités
|
|
||||||
|
|
||||||
### 🔄 Chargement Automatique
|
|
||||||
- **Détection automatique** : L'application parcourt le dossier `test-files/` au démarrage
|
|
||||||
- **Filtrage intelligent** : Seuls les fichiers supportés sont chargés
|
|
||||||
- **Logs détaillés** : Chaque étape du chargement est loggée dans la console
|
|
||||||
|
|
||||||
### 📁 Types de Fichiers Supportés
|
|
||||||
- **PDF** : `.pdf`
|
|
||||||
- **Images** : `.jpg`, `.jpeg`, `.png`, `.tiff`
|
|
||||||
- **Texte** : `.txt`, `.md`
|
|
||||||
- **Documents** : `.docx`
|
|
||||||
|
|
||||||
### 🎯 Avantages
|
|
||||||
- **Flexibilité** : Ajoutez simplement des fichiers dans `test-files/` pour les tester
|
|
||||||
- **Maintenance** : Plus besoin de modifier le code pour ajouter de nouveaux fichiers de test
|
|
||||||
- **Développement** : Facilite les tests avec différents types de documents
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
### Fichiers Modifiés
|
|
||||||
|
|
||||||
#### `src/services/testFilesApi.ts` (Nouveau)
|
|
||||||
```typescript
|
|
||||||
// API pour gérer les fichiers de test
|
|
||||||
export interface TestFileInfo {
|
|
||||||
name: string
|
|
||||||
size: number
|
|
||||||
type: string
|
|
||||||
lastModified: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getTestFilesList(): Promise<TestFileInfo[]>
|
|
||||||
export async function loadTestFile(fileName: string): Promise<File | null>
|
|
||||||
export function filterSupportedFiles(files: TestFileInfo[]): TestFileInfo[]
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `src/views/UploadView.tsx` (Modifié)
|
|
||||||
- Remplacement de la liste codée en dur par un chargement dynamique
|
|
||||||
- Ajout de logs détaillés pour le debugging
|
|
||||||
- Gestion d'erreurs améliorée
|
|
||||||
|
|
||||||
### Flux de Chargement
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
graph TD
|
|
||||||
A[Démarrage de l'application] --> B[Vérification mode DEV]
|
|
||||||
B --> C[Appel getTestFilesList()]
|
|
||||||
C --> D[Vérification de chaque fichier]
|
|
||||||
D --> E[Filtrage des fichiers supportés]
|
|
||||||
E --> F[Chargement des fichiers valides]
|
|
||||||
F --> G[Création des objets Document]
|
|
||||||
G --> H[Ajout au store Redux]
|
|
||||||
H --> I[Déclenchement de l'extraction]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Utilisation
|
|
||||||
|
|
||||||
### Ajouter de Nouveaux Fichiers de Test
|
|
||||||
|
|
||||||
1. **Placez vos fichiers** dans le dossier `test-files/`
|
|
||||||
2. **Redémarrez l'application** (ou rechargez la page)
|
|
||||||
3. **Vérifiez les logs** dans la console du navigateur
|
|
||||||
|
|
||||||
### Exemple de Logs
|
|
||||||
|
|
||||||
```
|
|
||||||
🔄 [BOOTSTRAP] Chargement des fichiers de test...
|
|
||||||
📁 [BOOTSTRAP] Fichiers trouvés: ["IMG_20250902_162159.jpg", "sample.pdf", ...]
|
|
||||||
✅ [BOOTSTRAP] Fichiers supportés: ["IMG_20250902_162159.jpg", "sample.pdf", ...]
|
|
||||||
📄 [BOOTSTRAP] Chargement de IMG_20250902_162159.jpg...
|
|
||||||
✅ [BOOTSTRAP] IMG_20250902_162159.jpg chargé (1052.7 KB)
|
|
||||||
🎉 [BOOTSTRAP] 5 fichiers chargés avec succès
|
|
||||||
🔍 [BOOTSTRAP] Déclenchement de l'extraction pour IMG_20250902_162159.jpg
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### Variables d'Environnement
|
|
||||||
- `VITE_DISABLE_LLM=true` : Désactive l'utilisation des LLM
|
|
||||||
- `VITE_USE_RULE_NER=true` : Active l'extraction par règles
|
|
||||||
- `VITE_LLM_CLASSIFY_ONLY=false` : Désactive la classification LLM
|
|
||||||
|
|
||||||
### Mode Développement
|
|
||||||
Le chargement dynamique ne s'active qu'en mode développement (`import.meta.env.DEV`).
|
|
||||||
|
|
||||||
## Tests
|
|
||||||
|
|
||||||
### Script de Test
|
|
||||||
Un script de test est disponible : `test-dynamic-files.cjs`
|
|
||||||
|
|
||||||
```bash
|
|
||||||
node test-dynamic-files.cjs
|
|
||||||
```
|
|
||||||
|
|
||||||
### Vérifications Automatiques
|
|
||||||
- ✅ Existence du dossier `test-files/`
|
|
||||||
- ✅ Liste des fichiers disponibles
|
|
||||||
- ✅ Filtrage des fichiers supportés
|
|
||||||
- ✅ Accessibilité via le serveur de développement
|
|
||||||
- ✅ Chargement des fichiers individuels
|
|
||||||
|
|
||||||
## Dépannage
|
|
||||||
|
|
||||||
### Problèmes Courants
|
|
||||||
|
|
||||||
#### Aucun fichier chargé
|
|
||||||
- Vérifiez que le dossier `test-files/` existe
|
|
||||||
- Vérifiez que les fichiers ont des extensions supportées
|
|
||||||
- Consultez les logs de la console
|
|
||||||
|
|
||||||
#### Fichiers non accessibles
|
|
||||||
- Vérifiez que le serveur de développement est démarré
|
|
||||||
- Vérifiez les permissions des fichiers
|
|
||||||
- Testez l'accès direct via l'URL : `http://localhost:5174/test-files/nom-du-fichier`
|
|
||||||
|
|
||||||
#### Erreurs de chargement
|
|
||||||
- Vérifiez la taille des fichiers (limite de mémoire du navigateur)
|
|
||||||
- Vérifiez le format des fichiers
|
|
||||||
- Consultez les logs d'erreur dans la console
|
|
||||||
|
|
||||||
## Évolutions Futures
|
|
||||||
|
|
||||||
### Améliorations Possibles
|
|
||||||
- **API serveur** : Créer une vraie API pour lister les fichiers
|
|
||||||
- **Cache** : Mettre en cache la liste des fichiers
|
|
||||||
- **Filtres** : Permettre de filtrer par type de document
|
|
||||||
- **Métadonnées** : Ajouter des métadonnées aux fichiers de test
|
|
||||||
- **Interface** : Créer une interface pour gérer les fichiers de test
|
|
||||||
|
|
||||||
### Intégration CI/CD
|
|
||||||
- **Tests automatisés** : Intégrer les tests dans la pipeline CI
|
|
||||||
- **Validation** : Valider automatiquement les nouveaux fichiers de test
|
|
||||||
- **Documentation** : Générer automatiquement la documentation des fichiers de test
|
|
||||||
@ -1,125 +0,0 @@
|
|||||||
# Correction des Méthodes Dépréciées de Tesseract.js
|
|
||||||
|
|
||||||
## Problème Identifié
|
|
||||||
|
|
||||||
L'application affichait des warnings de dépréciation dans la console :
|
|
||||||
|
|
||||||
```
|
|
||||||
fileExtract.ts:113 `load` is depreciated and should be removed from code (workers now come pre-loaded)
|
|
||||||
fileExtract.ts:115 `loadLanguage` is depreciated and should be removed from code (workers now come with language pre-loaded)
|
|
||||||
fileExtract.ts:117 `initialize` is depreciated and should be removed from code (workers now come pre-initialized)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Cause
|
|
||||||
|
|
||||||
Tesseract.js a été mis à jour et les méthodes suivantes sont maintenant dépréciées :
|
|
||||||
- `worker.load()` - Les workers viennent maintenant pré-chargés
|
|
||||||
- `worker.loadLanguage()` - Les workers viennent avec les langues pré-chargées
|
|
||||||
- `worker.initialize()` - Les workers viennent pré-initialisés
|
|
||||||
|
|
||||||
## Solution Appliquée
|
|
||||||
|
|
||||||
### Avant (Code Déprécié)
|
|
||||||
```typescript
|
|
||||||
const worker = await createWorker()
|
|
||||||
try {
|
|
||||||
worker.setLogger?.((m: any) => {
|
|
||||||
if (m?.progress != null) console.info('[OCR]', Math.round(m.progress * 100) + '%')
|
|
||||||
})
|
|
||||||
await worker.load() // ❌ Déprécié
|
|
||||||
await worker.loadLanguage('fra+eng') // ❌ Déprécié
|
|
||||||
await worker.initialize('fra+eng') // ❌ Déprécié
|
|
||||||
// ... reste du code
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Après (Code Corrigé)
|
|
||||||
```typescript
|
|
||||||
const worker = await createWorker('fra+eng') // ✅ Langues directement dans createWorker
|
|
||||||
try {
|
|
||||||
worker.setLogger?.((m: any) => {
|
|
||||||
if (m?.progress != null) console.info('[OCR]', Math.round(m.progress * 100) + '%')
|
|
||||||
})
|
|
||||||
// ✅ Plus besoin de load, loadLanguage, initialize
|
|
||||||
// ... reste du code
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Changements Effectués
|
|
||||||
|
|
||||||
### Fichier Modifié : `src/services/fileExtract.ts`
|
|
||||||
|
|
||||||
1. **Suppression des méthodes dépréciées** :
|
|
||||||
- `await worker.load()`
|
|
||||||
- `await worker.loadLanguage('fra+eng')`
|
|
||||||
- `await worker.initialize('fra+eng')`
|
|
||||||
|
|
||||||
2. **Modification de createWorker** :
|
|
||||||
- Avant : `createWorker()`
|
|
||||||
- Après : `createWorker('fra+eng')`
|
|
||||||
|
|
||||||
3. **Préservation des méthodes nécessaires** :
|
|
||||||
- `worker.setLogger()` - Configuration du logger
|
|
||||||
- `worker.setParameters()` - Configuration des paramètres OCR
|
|
||||||
- `worker.recognize()` - Reconnaissance du texte
|
|
||||||
- `worker.terminate()` - Nettoyage du worker
|
|
||||||
|
|
||||||
## Avantages de la Correction
|
|
||||||
|
|
||||||
### 🚀 Performance
|
|
||||||
- **Démarrage plus rapide** : Plus besoin d'attendre le chargement des langues
|
|
||||||
- **Moins d'appels API** : Réduction des appels asynchrones
|
|
||||||
- **Initialisation simplifiée** : Processus d'initialisation plus direct
|
|
||||||
|
|
||||||
### 🧹 Code Plus Propre
|
|
||||||
- **Moins de code** : Suppression de 3 lignes dépréciées
|
|
||||||
- **Moins de warnings** : Console plus propre
|
|
||||||
- **Meilleure maintenabilité** : Code aligné avec les dernières pratiques
|
|
||||||
|
|
||||||
### 🔧 Compatibilité
|
|
||||||
- **Version récente** : Compatible avec Tesseract.js v5.1.0+
|
|
||||||
- **Future-proof** : Prêt pour les futures versions
|
|
||||||
- **Standards modernes** : Suit les recommandations officielles
|
|
||||||
|
|
||||||
## Tests de Validation
|
|
||||||
|
|
||||||
### ✅ Vérifications Effectuées
|
|
||||||
1. **Compilation** : Le projet compile sans erreurs
|
|
||||||
2. **Serveur** : Le serveur de développement fonctionne
|
|
||||||
3. **Méthodes supprimées** : Aucune méthode dépréciée restante
|
|
||||||
4. **Méthodes préservées** : Toutes les méthodes nécessaires sont présentes
|
|
||||||
5. **Fonctionnalité** : L'OCR fonctionne toujours correctement
|
|
||||||
|
|
||||||
### 🧪 Script de Test
|
|
||||||
Un script de validation a été créé pour vérifier :
|
|
||||||
- Absence des méthodes dépréciées
|
|
||||||
- Présence des méthodes nécessaires
|
|
||||||
- Configuration correcte de createWorker
|
|
||||||
|
|
||||||
## Impact sur l'Utilisateur
|
|
||||||
|
|
||||||
### 🎯 Transparent
|
|
||||||
- **Aucun changement visible** : L'interface utilisateur reste identique
|
|
||||||
- **Performance améliorée** : OCR potentiellement plus rapide
|
|
||||||
- **Console plus propre** : Moins de warnings dans les logs
|
|
||||||
|
|
||||||
### 📊 Métriques
|
|
||||||
- **Réduction des warnings** : 100% des warnings de dépréciation supprimés
|
|
||||||
- **Code simplifié** : 3 lignes de code supprimées
|
|
||||||
- **Compatibilité** : 100% compatible avec Tesseract.js v5.1.0+
|
|
||||||
|
|
||||||
## Recommandations
|
|
||||||
|
|
||||||
### 🔄 Mise à Jour Continue
|
|
||||||
- **Surveiller les mises à jour** : Vérifier régulièrement les changements de Tesseract.js
|
|
||||||
- **Tests réguliers** : Tester l'OCR après chaque mise à jour
|
|
||||||
- **Documentation** : Maintenir la documentation à jour
|
|
||||||
|
|
||||||
### 🚀 Optimisations Futures
|
|
||||||
- **Configuration avancée** : Explorer les nouvelles options de configuration
|
|
||||||
- **Performance** : Optimiser les paramètres OCR pour de meilleures performances
|
|
||||||
- **Langues multiples** : Ajouter le support de langues supplémentaires si nécessaire
|
|
||||||
|
|
||||||
## Conclusion
|
|
||||||
|
|
||||||
Cette correction élimine les warnings de dépréciation tout en améliorant les performances et la maintenabilité du code. L'application est maintenant alignée avec les dernières pratiques de Tesseract.js et prête pour les futures évolutions.
|
|
||||||
196
docs/extact_model.json
Normal file
196
docs/extact_model.json
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
{
|
||||||
|
"document": {
|
||||||
|
"id": "doc-1757976015681",
|
||||||
|
"fileName": "facture_4NK_08-2025_04.pdf",
|
||||||
|
"fileSize": 85819,
|
||||||
|
"mimeType": "application/pdf",
|
||||||
|
"uploadTimestamp": "2025-09-15T22:40:15.681Z"
|
||||||
|
},
|
||||||
|
"classification": {
|
||||||
|
"documentType": "Facture",
|
||||||
|
"confidence": 0.95,
|
||||||
|
"subType": "Facture de prestation",
|
||||||
|
"language": "fr",
|
||||||
|
"pageCount": 1
|
||||||
|
},
|
||||||
|
"extraction": {
|
||||||
|
"text": {
|
||||||
|
"raw": "Janin Consulting - EURL au capital de 500 Euros...",
|
||||||
|
"processed": "Janin Consulting - EURL au capital de 500 Euros...",
|
||||||
|
"wordCount": 165,
|
||||||
|
"characterCount": 1197,
|
||||||
|
"confidence": 0.95
|
||||||
|
},
|
||||||
|
"entities": {
|
||||||
|
"persons": [
|
||||||
|
{
|
||||||
|
"id": "person-1",
|
||||||
|
"type": "contact",
|
||||||
|
"firstName": "Anthony",
|
||||||
|
"lastName": "Janin",
|
||||||
|
"role": "Gérant",
|
||||||
|
"email": "ja.janin.anthony@gmail.com",
|
||||||
|
"phone": "33 (0)6 71 40 84 13",
|
||||||
|
"confidence": 0.9,
|
||||||
|
"source": "rule-based"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"companies": [
|
||||||
|
{
|
||||||
|
"id": "company-1",
|
||||||
|
"name": "Janin Consulting",
|
||||||
|
"legalForm": "EURL",
|
||||||
|
"siret": "815 322 912 00040",
|
||||||
|
"rcs": "815 322 912 NANTERRE",
|
||||||
|
"tva": "FR64 815 322 912",
|
||||||
|
"capital": "500 Euros",
|
||||||
|
"role": "Fournisseur",
|
||||||
|
"confidence": 0.95,
|
||||||
|
"source": "rule-based"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "company-2",
|
||||||
|
"name": "4NK",
|
||||||
|
"tva": "FR79913422994",
|
||||||
|
"role": "Client",
|
||||||
|
"confidence": 0.9,
|
||||||
|
"source": "rule-based"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"addresses": [
|
||||||
|
{
|
||||||
|
"id": "address-1",
|
||||||
|
"type": "siège_social",
|
||||||
|
"street": "177 rue du Faubourg Poissonnière",
|
||||||
|
"city": "Paris",
|
||||||
|
"postalCode": "75009",
|
||||||
|
"country": "France",
|
||||||
|
"company": "Janin Consulting",
|
||||||
|
"confidence": 0.9,
|
||||||
|
"source": "rule-based"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "address-2",
|
||||||
|
"type": "facturation",
|
||||||
|
"street": "4 SQUARE DES GOELANDS",
|
||||||
|
"city": "MONT-SAINT-AIGNAN",
|
||||||
|
"postalCode": "76130",
|
||||||
|
"country": "France",
|
||||||
|
"company": "4NK",
|
||||||
|
"confidence": 0.9,
|
||||||
|
"source": "rule-based"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"financial": {
|
||||||
|
"amounts": [
|
||||||
|
{
|
||||||
|
"id": "amount-1",
|
||||||
|
"type": "prestation",
|
||||||
|
"description": "Prestation du mois d'Août 2025",
|
||||||
|
"quantity": 10,
|
||||||
|
"unitPrice": 550.00,
|
||||||
|
"totalHT": 5500.00,
|
||||||
|
"currency": "EUR",
|
||||||
|
"confidence": 0.95
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totals": {
|
||||||
|
"totalHT": 5500.00,
|
||||||
|
"totalTVA": 1100.00,
|
||||||
|
"totalTTC": 6600.00,
|
||||||
|
"tvaRate": 0.20,
|
||||||
|
"currency": "EUR"
|
||||||
|
},
|
||||||
|
"payment": {
|
||||||
|
"terms": "30 jours après émission",
|
||||||
|
"penaltyRate": "Taux BCE + 7 points",
|
||||||
|
"bankDetails": {
|
||||||
|
"bank": "CAISSE D'EPARGNE D'ILE DE FRANCE",
|
||||||
|
"accountHolder": "Janin Anthony",
|
||||||
|
"address": "1 rue Pasteur (78800)",
|
||||||
|
"rib": "17515006000800309088884"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dates": [
|
||||||
|
{
|
||||||
|
"id": "date-1",
|
||||||
|
"type": "facture",
|
||||||
|
"value": "29-août-25",
|
||||||
|
"formatted": "2025-08-29",
|
||||||
|
"confidence": 0.9,
|
||||||
|
"source": "rule-based"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "date-2",
|
||||||
|
"type": "période",
|
||||||
|
"value": "août-25",
|
||||||
|
"formatted": "2025-08",
|
||||||
|
"confidence": 0.9,
|
||||||
|
"source": "rule-based"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"contractual": {
|
||||||
|
"clauses": [
|
||||||
|
{
|
||||||
|
"id": "clause-1",
|
||||||
|
"type": "paiement",
|
||||||
|
"content": "Le paiement se fera (maximum) 30 jours après l'émission de la facture.",
|
||||||
|
"confidence": 0.9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "clause-2",
|
||||||
|
"type": "intérêts_retard",
|
||||||
|
"content": "Tout retard de paiement d'une quelconque facture fait courir, immédiatement et de plein droit, des intérêts de retard calculés au taux directeur de la BCE majoré de 7 points jusqu'au paiement effectif et intégral.",
|
||||||
|
"confidence": 0.9
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"signatures": [
|
||||||
|
{
|
||||||
|
"id": "signature-1",
|
||||||
|
"type": "électronique",
|
||||||
|
"present": false,
|
||||||
|
"signatory": null,
|
||||||
|
"date": null,
|
||||||
|
"confidence": 0.8
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"id": "ref-1",
|
||||||
|
"type": "facture",
|
||||||
|
"number": "4NK_4",
|
||||||
|
"confidence": 0.95
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"processing": {
|
||||||
|
"engine": "4NK_IA_Backend",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"processingTime": "2.5s",
|
||||||
|
"ocrEngine": "pdf-parse",
|
||||||
|
"nerEngine": "rule-based",
|
||||||
|
"preprocessing": {
|
||||||
|
"applied": false,
|
||||||
|
"reason": "PDF direct text extraction"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"quality": {
|
||||||
|
"globalConfidence": 0.95,
|
||||||
|
"textExtractionConfidence": 0.95,
|
||||||
|
"entityExtractionConfidence": 0.90,
|
||||||
|
"classificationConfidence": 0.95
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"success": true,
|
||||||
|
"errors": [],
|
||||||
|
"warnings": [
|
||||||
|
"Aucune signature détectée"
|
||||||
|
],
|
||||||
|
"timestamp": "2025-09-15T22:40:15.681Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,166 +0,0 @@
|
|||||||
# Intégration du préprocessing d'image dans le backend
|
|
||||||
|
|
||||||
## 📋 Résumé
|
|
||||||
|
|
||||||
Le préprocessing d'image a été intégré avec succès dans le backend pour améliorer considérablement la qualité de l'extraction OCR et la détection des entités dans les documents d'identité.
|
|
||||||
|
|
||||||
## 🔧 Implémentation
|
|
||||||
|
|
||||||
### 1. Module de préprocessing créé
|
|
||||||
|
|
||||||
**Fichier :** `/backend/imagePreprocessing.js`
|
|
||||||
|
|
||||||
**Fonctionnalités :**
|
|
||||||
- Redimensionnement intelligent des images
|
|
||||||
- Conversion en niveaux de gris
|
|
||||||
- Amélioration du contraste et de la luminosité
|
|
||||||
- Amélioration de la netteté avec filtres spécialisés
|
|
||||||
- Réduction du bruit avec filtre médian
|
|
||||||
- Binarisation optionnelle
|
|
||||||
|
|
||||||
### 2. Intégration dans le serveur backend
|
|
||||||
|
|
||||||
**Fichier :** `/backend/server.js`
|
|
||||||
|
|
||||||
**Modifications apportées :**
|
|
||||||
- Import du module de préprocessing
|
|
||||||
- Intégration dans la fonction `extractTextFromImage()`
|
|
||||||
- Préprocessing automatique avant l'OCR
|
|
||||||
- Nettoyage automatique des fichiers temporaires
|
|
||||||
|
|
||||||
## 📊 Résultats de l'intégration
|
|
||||||
|
|
||||||
### **Image test :** `IMG_20250902_162159.jpg`
|
|
||||||
|
|
||||||
#### **Avant le préprocessing :**
|
|
||||||
- ❌ NICOLAS : Non détecté
|
|
||||||
- ❌ CANTU : Non détecté
|
|
||||||
- ❌ Numéros CNI : 0 détecté
|
|
||||||
- ❌ Qualité OCR : Très dégradée
|
|
||||||
|
|
||||||
#### **Après le préprocessing :**
|
|
||||||
- ✅ **NICOLAS** : Détecté dans le texte
|
|
||||||
- ✅ **CANTU** : Détecté dans le texte
|
|
||||||
- ✅ **Numéros CNI** : 2 détectés (`LK093008`, `NC801211`)
|
|
||||||
- ✅ **Type de document** : CNI identifié
|
|
||||||
- ✅ **Qualité OCR** : Considérablement améliorée
|
|
||||||
|
|
||||||
### **Texte extrait avec préprocessing :**
|
|
||||||
```
|
|
||||||
RÉPUBLIQUE FRANCATSEN
|
|
||||||
CARTE NATIONALE DIDENTITE Ne : 180193155156 - es
|
|
||||||
184 JC Nom: CANTY
|
|
||||||
Fe - 0 Mele: 33 12 198
|
|
||||||
LL ee
|
|
||||||
5 IDFRACANTUCCKKLLLLKLLLLLLLLLLLK093008
|
|
||||||
4 1801931551563NICOLASSFRANC8012115M8
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🎯 Améliorations apportées
|
|
||||||
|
|
||||||
### **1. Détection des noms :**
|
|
||||||
- **NICOLAS** : Détecté dans `"4 1801931551563NICOLASSFRANC8012115M8"`
|
|
||||||
- **CANTU** : Détecté dans `"JC Nom: CANTY"` et `"IDFRACANTUCCKKLLLLKLLLLLLLLLLLK093008"`
|
|
||||||
|
|
||||||
### **2. Détection des numéros CNI :**
|
|
||||||
- **LK093008** : Format 2 lettres + 6 chiffres
|
|
||||||
- **NC801211** : Format 2 lettres + 6 chiffres
|
|
||||||
|
|
||||||
### **3. Identification du type de document :**
|
|
||||||
- **Type détecté** : CNI (Carte Nationale d'Identité)
|
|
||||||
- **Confiance** : 60% globale
|
|
||||||
|
|
||||||
## 🔧 Configuration du préprocessing
|
|
||||||
|
|
||||||
### **Paramètres optimisés :**
|
|
||||||
```javascript
|
|
||||||
{
|
|
||||||
width: 2000, // Redimensionnement à 2000px
|
|
||||||
contrast: 1.5, // Augmentation du contraste
|
|
||||||
brightness: 1.1, // Légère augmentation de la luminosité
|
|
||||||
grayscale: true, // Conversion en niveaux de gris
|
|
||||||
sharpen: true, // Amélioration de la netteté
|
|
||||||
denoise: true, // Réduction du bruit
|
|
||||||
format: 'png', // Format PNG pour meilleure qualité
|
|
||||||
quality: 100 // Qualité maximale
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🚀 API Backend
|
|
||||||
|
|
||||||
### **Endpoint :** `POST /api/extract`
|
|
||||||
|
|
||||||
**Utilisation :**
|
|
||||||
```bash
|
|
||||||
curl -X POST -F "document=@image.jpg" http://localhost:3001/api/extract
|
|
||||||
```
|
|
||||||
|
|
||||||
**Réponse JSON :**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"success": true,
|
|
||||||
"documentId": "doc-1757975495705",
|
|
||||||
"fileName": "IMG_20250902_162159.jpg",
|
|
||||||
"processing": {
|
|
||||||
"ocr": {
|
|
||||||
"text": "RÉPUBLIQUE FRANCATSEN\nCARTE NATIONALE DIDENTITE...",
|
|
||||||
"confidence": 41,
|
|
||||||
"wordCount": 27
|
|
||||||
},
|
|
||||||
"ner": {
|
|
||||||
"identities": [...],
|
|
||||||
"cniNumbers": [
|
|
||||||
{"id": "cni-0", "number": "LK093008", "confidence": 0.95},
|
|
||||||
{"id": "cni-1", "number": "NC801211", "confidence": 0.95}
|
|
||||||
],
|
|
||||||
"documentType": "CNI"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📈 Performance
|
|
||||||
|
|
||||||
### **Amélioration des résultats :**
|
|
||||||
- **Détection NICOLAS** : +100% (de 0% à 100%)
|
|
||||||
- **Détection CANTU** : +100% (de 0% à 100%)
|
|
||||||
- **Détection CNI** : +100% (de 0 à 2 numéros)
|
|
||||||
- **Qualité OCR** : +300% (texte lisible vs corrompu)
|
|
||||||
|
|
||||||
### **Temps de traitement :**
|
|
||||||
- **Préprocessing** : ~2-3 secondes
|
|
||||||
- **OCR** : ~4-5 secondes
|
|
||||||
- **Total** : ~6-8 secondes par image
|
|
||||||
|
|
||||||
## 🔍 Détails techniques
|
|
||||||
|
|
||||||
### **Pipeline de traitement :**
|
|
||||||
1. **Upload** de l'image via l'API
|
|
||||||
2. **Analyse** des métadonnées de l'image
|
|
||||||
3. **Préprocessing** avec Sharp.js
|
|
||||||
4. **OCR** avec Tesseract.js (multi-stratégies)
|
|
||||||
5. **Extraction NER** avec patterns de règles
|
|
||||||
6. **Nettoyage** des fichiers temporaires
|
|
||||||
7. **Retour** des résultats JSON
|
|
||||||
|
|
||||||
### **Fichiers temporaires :**
|
|
||||||
- Création automatique d'images préprocessées
|
|
||||||
- Nettoyage automatique après traitement
|
|
||||||
- Gestion des erreurs et timeouts
|
|
||||||
|
|
||||||
## 🎉 Conclusion
|
|
||||||
|
|
||||||
L'intégration du préprocessing d'image dans le backend a été un **succès complet**. Le système peut maintenant :
|
|
||||||
|
|
||||||
✅ **Détecter NICOLAS et CANTU** dans les images de CNI
|
|
||||||
✅ **Extraire les numéros de CNI** au format correct
|
|
||||||
✅ **Identifier le type de document** (CNI)
|
|
||||||
✅ **Fournir une API robuste** pour le traitement d'images
|
|
||||||
✅ **Gérer automatiquement** le préprocessing et le nettoyage
|
|
||||||
|
|
||||||
Le système est maintenant prêt pour la production et peut traiter efficacement les documents d'identité avec une qualité d'extraction considérablement améliorée.
|
|
||||||
|
|
||||||
---
|
|
||||||
*Documentation créée le 15 septembre 2025*
|
|
||||||
*Projet : 4NK_IA_front*
|
|
||||||
*Version : 1.0.0*
|
|
||||||
@ -171,7 +171,7 @@ const HEALTH_CHECK_CACHE_DURATION = 5000 // 5 secondes
|
|||||||
*/
|
*/
|
||||||
export async function checkBackendHealth(): Promise<boolean> {
|
export async function checkBackendHealth(): Promise<boolean> {
|
||||||
const now = Date.now()
|
const now = Date.now()
|
||||||
|
|
||||||
// Utiliser le cache si disponible et récent
|
// Utiliser le cache si disponible et récent
|
||||||
if (backendHealthCache && (now - backendHealthCache.timestamp) < HEALTH_CHECK_CACHE_DURATION) {
|
if (backendHealthCache && (now - backendHealthCache.timestamp) < HEALTH_CHECK_CACHE_DURATION) {
|
||||||
return backendHealthCache.isHealthy
|
return backendHealthCache.isHealthy
|
||||||
@ -183,17 +183,17 @@ export async function checkBackendHealth(): Promise<boolean> {
|
|||||||
|
|
||||||
const isHealthy = result.status === 'OK'
|
const isHealthy = result.status === 'OK'
|
||||||
console.log('🏥 [BACKEND] Health check:', result.status)
|
console.log('🏥 [BACKEND] Health check:', result.status)
|
||||||
|
|
||||||
// Mettre en cache le résultat
|
// Mettre en cache le résultat
|
||||||
backendHealthCache = { isHealthy, timestamp: now }
|
backendHealthCache = { isHealthy, timestamp: now }
|
||||||
|
|
||||||
return isHealthy
|
return isHealthy
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ [BACKEND] Backend non accessible:', error)
|
console.error('❌ [BACKEND] Backend non accessible:', error)
|
||||||
|
|
||||||
// Mettre en cache le résultat négatif
|
// Mettre en cache le résultat négatif
|
||||||
backendHealthCache = { isHealthy: false, timestamp: now }
|
backendHealthCache = { isHealthy: false, timestamp: now }
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user