chore(release): 0.1.3\n\n- Docker packaging (Dockerfile, nginx.conf, scripts)\n- Fix ExtractionView hydration (no div in p)\n- Node version checks, .nvmrc\n- Docs: README/DEPLOYMENT updates\n- Version bump to 0.1.3

This commit is contained in:
Nicolas Cantu 2025-09-11 16:43:44 +02:00
parent 6600308d61
commit 81d39172d0
46 changed files with 1225 additions and 1994 deletions

18
.dockerignore Normal file
View File

@ -0,0 +1,18 @@
node_modules
coverage
.git
.vscode
.idea
*.log
.env
.env.*
**/.DS_Store
**/*.test.*
**/*.spec.*
**/tests/**
**/test/**
dist
README.md
CHANGELOG.md
CODE_OF_CONDUCT.md
CONTRIBUTING.md

1
.nvmrc Normal file
View File

@ -0,0 +1 @@
20.19.5

View File

@ -1,5 +1,42 @@
# Changelog
## [0.1.3] - 2025-09-11
### Ajouté
- Dockerfile multi-stage (build Node 20 LTS → Nginx) et `nginx.conf`
- `.dockerignore` pour un contexte minimal
- Scripts `scripts/docker-build.sh` et `scripts/docker-push.sh`
### Modifié
- `ExtractionView.tsx`: correction du balisage pour éviter `<div>` dans `<p>` (hydratation)
- Documentation: README et `docs/DEPLOYMENT.md` mis à jour (Docker, versions Node)
### Technique
- `.nvmrc` ajouté et vérification `predev`/`prebuild` de la version Node
## 0.1.2 - Suppression du mode démo et routage backend
### 🔄 Changements majeurs
- Suppression complète du « mode simple » et des fallbacks de démonstration dans
`src/services/api.ts`.
- Tous les appels aux APIs externes (Cadastre, Géorisques, Géofoncier, BODACC,
Infogreffe) sont désormais routés via le backend `4NK_IA_back` (`/api/context/...`).
### 🧩 Code
- `src/services/api.ts`: suppression de `VITE_BACKEND_MODE`, intercepteur Axios német plus de
valeurs mockées, endpoints `analyze/context/conseil` strictement consommés sur
`/api/documents/...`.
### 📚 Documentation
- `README.md`: mise à jour des versions (React 19 / MUI 7 / Router 7), retrait de la section
« Mode démonstration », clarification de lintégration backend.
### ✅ Qualité
- Lint, tests et markdownlint OK après modifications.
## 0.1.1 - Maintenance lint/build et corrections
### ✅ Qualité et lint

29
Dockerfile Normal file
View File

@ -0,0 +1,29 @@
# syntax=docker/dockerfile:1.7-labs
# ---- Build stage ----
FROM node:20.19-alpine AS build
WORKDIR /app
# Install dependencies
COPY package*.json ./
RUN npm ci --ignore-scripts
# Copy sources
COPY . .
# Ensure correct Node version for build via prebuild script
RUN npm run build
# ---- Runtime stage ----
FROM nginx:alpine AS runtime
# Copy SPA build
COPY --from=build /app/dist /usr/share/nginx/html
# Nginx config for SPA routing and caching
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
HEALTHCHECK CMD wget -qO- http://localhost/ || exit 1
CMD ["nginx", "-g", "daemon off;"]

View File

@ -38,11 +38,11 @@ Application front-end pour l'analyse intelligente de documents notariaux avec IA
## 🚀 Technologies
- **Frontend** : React 18 + TypeScript
- **Frontend** : React 19 + TypeScript
- **Build** : Vite 7
- **UI** : Material-UI (MUI) v6
- **UI** : Material-UI (MUI) v7
- **State** : Redux Toolkit + React Redux
- **Routing** : React Router v6
- **Routing** : React Router v7
- **HTTP** : Axios
- **Tests** : Vitest + Testing Library
- **Linting** : ESLint + Prettier + markdownlint
@ -51,13 +51,22 @@ Application front-end pour l'analyse intelligente de documents notariaux avec IA
### Prérequis
- Node.js >= 22.12.0 (recommandé) ou >= 20.19.0
- Node.js >= 20.19.0 (LTS). Recommandé: 22.12+
- npm >= 10.0.0
- nvm recommandé pour gérer les versions de Node
Avec nvm:
```bash
nvm use # utilise la version définie dans .nvmrc
# ou, si non installée
nvm install && nvm use
```
### Installation des dépendances
```bash
npm install
npm ci
```
### Configuration des environnements
@ -83,15 +92,18 @@ npm run preview # Prévisualisation du build
# Qualité de code
npm run lint # Vérification ESLint
npm run lint:fix # Correction automatique ESLint
npm run format # Vérification Prettier
npm run format:fix # Formatage automatique
npm run mdlint # Vérification Markdown
# Tests
npm run test # Tests unitaires
npm run test # Tests unitaires avec couverture
npm run test:ui # Tests avec interface
npm run test:coverage # Tests avec couverture
# Docker
./scripts/docker-build.sh # Construire l'image locale
IMAGE_TAG=0.1.3 ./scripts/docker-build.sh # Construire avec tag explicite
IMAGE_TAG=0.1.3 ./scripts/docker-push.sh # Pousser vers git.4nkweb.com
```
## 🏗️ Architecture
@ -147,14 +159,10 @@ src/
- **Breadcrumbs** : Indication de la position actuelle
- **Actions contextuelles** : Boutons d'action selon la vue
## 🔧 Mode démonstration
## 🔧 Intégration backend
L'application fonctionne parfaitement en mode démonstration :
- **Données réalistes** : Exemples d'actes notariaux
- **Fonctionnalités complètes** : Toutes les vues opérationnelles
- **Gestion d'erreur** : Fallback automatique sans backend
- **Expérience utilisateur** : Interface identique au mode production
Toutes les fonctionnalités (upload, extraction, analyse, données contextuelles, conseil LLM) passent par le backend `4NK_IA_back`.
Les APIs externes (Cadastre, Géorisques, Géofoncier, BODACC, Infogreffe) sont appelées côté backend uniquement.
## 🧪 Tests
@ -188,6 +196,19 @@ npm run test:coverage # Rapport de couverture
npm run build
```
### Exécution via Docker
```bash
# Construire l'image
./scripts/docker-build.sh
# Lancer localement
docker run --rm -p 8080:80 git.4nkweb.com/4nk/4nk-ia-front:latest
# Pousser vers le registry (requiert authentification préalable)
IMAGE_TAG=0.1.3 ./scripts/docker-push.sh
```
### Variables d'environnement
Configurer les URLs des APIs externes selon l'environnement :
@ -233,5 +254,5 @@ Pour toute question ou problème :
---
**Version actuelle** : 0.1.0
**Dernière mise à jour** : Janvier 2024
**Version actuelle** : 0.1.3
**Dernière mise à jour** : Septembre 2025

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<coverage generated="1757583600773" clover="3.2.0">
<project timestamp="1757583600773" name="All files">
<metrics statements="1753" coveredstatements="0" conditionals="18" coveredconditionals="1" methods="18" coveredmethods="1" elements="1789" coveredelements="2" complexity="0" loc="1753" ncloc="1753" packages="9" files="18" classes="18"/>
<package name="4NK_IA_front">
<coverage generated="1757595469311" clover="3.2.0">
<project timestamp="1757595469311" name="All files">
<metrics statements="1611" coveredstatements="0" conditionals="18" coveredconditionals="1" methods="18" coveredmethods="1" elements="1647" coveredelements="2" complexity="0" loc="1611" ncloc="1611" packages="9" files="18" classes="18"/>
<package name="scripts">
<metrics statements="57" coveredstatements="0" conditionals="1" coveredconditionals="0" methods="1" coveredmethods="0"/>
<file name="simple-server.js" path="/home/desk/code/4NK_IA_front/simple-server.js">
<file name="simple-server.js" path="/home/desk/code/4NK_IA_front/scripts/simple-server.js">
<metrics statements="57" coveredstatements="0" conditionals="1" coveredconditionals="0" methods="1" coveredmethods="0"/>
<line num="1" count="0" type="cond" truecount="0" falsecount="1"/>
<line num="3" count="0" type="stmt"/>
@ -65,7 +65,7 @@
<line num="66" count="0" type="stmt"/>
</file>
</package>
<package name="4NK_IA_front.src">
<package name="src">
<metrics statements="24" coveredstatements="0" conditionals="2" coveredconditionals="0" methods="2" coveredmethods="0"/>
<file name="App.tsx" path="/home/desk/code/4NK_IA_front/src/App.tsx">
<metrics statements="5" coveredstatements="0" conditionals="1" coveredconditionals="0" methods="1" coveredmethods="0"/>
@ -98,7 +98,7 @@
<line num="20" count="0" type="stmt"/>
</file>
</package>
<package name="4NK_IA_front.src.components">
<package name="src.components">
<metrics statements="227" coveredstatements="0" conditionals="3" coveredconditionals="0" methods="3" coveredmethods="0"/>
<file name="FilePreview.tsx" path="/home/desk/code/4NK_IA_front/src/components/FilePreview.tsx">
<metrics statements="171" coveredstatements="0" conditionals="1" coveredconditionals="0" methods="1" coveredmethods="0"/>
@ -337,7 +337,7 @@
<line num="41" count="0" type="stmt"/>
</file>
</package>
<package name="4NK_IA_front.src.router">
<package name="src.router">
<metrics statements="23" coveredstatements="0" conditionals="1" coveredconditionals="0" methods="1" coveredmethods="0"/>
<file name="index.tsx" path="/home/desk/code/4NK_IA_front/src/router/index.tsx">
<metrics statements="23" coveredstatements="0" conditionals="1" coveredconditionals="0" methods="1" coveredmethods="0"/>
@ -366,10 +366,10 @@
<line num="28" count="0" type="stmt"/>
</file>
</package>
<package name="4NK_IA_front.src.services">
<metrics statements="266" coveredstatements="0" conditionals="1" coveredconditionals="0" methods="1" coveredmethods="0"/>
<package name="src.services">
<metrics statements="124" coveredstatements="0" conditionals="1" coveredconditionals="0" methods="1" coveredmethods="0"/>
<file name="api.ts" path="/home/desk/code/4NK_IA_front/src/services/api.ts">
<metrics statements="266" coveredstatements="0" conditionals="1" coveredconditionals="0" methods="1" coveredmethods="0"/>
<metrics statements="124" coveredstatements="0" conditionals="1" coveredconditionals="0" methods="1" coveredmethods="0"/>
<line num="1" count="0" type="cond" truecount="0" falsecount="1"/>
<line num="4" count="0" type="stmt"/>
<line num="6" count="0" type="stmt"/>
@ -379,34 +379,33 @@
<line num="12" count="0" type="stmt"/>
<line num="13" count="0" type="stmt"/>
<line num="14" count="0" type="stmt"/>
<line num="15" count="0" type="stmt"/>
<line num="16" count="0" type="stmt"/>
<line num="17" count="0" type="stmt"/>
<line num="18" count="0" type="stmt"/>
<line num="19" count="0" type="stmt"/>
<line num="20" count="0" type="stmt"/>
<line num="21" count="0" type="stmt"/>
<line num="22" count="0" type="stmt"/>
<line num="23" count="0" type="stmt"/>
<line num="24" count="0" type="stmt"/>
<line num="25" count="0" type="stmt"/>
<line num="26" count="0" type="stmt"/>
<line num="27" count="0" type="stmt"/>
<line num="28" count="0" type="stmt"/>
<line num="29" count="0" type="stmt"/>
<line num="30" count="0" type="stmt"/>
<line num="31" count="0" type="stmt"/>
<line num="32" count="0" type="stmt"/>
<line num="33" count="0" type="stmt"/>
<line num="34" count="0" type="stmt"/>
<line num="35" count="0" type="stmt"/>
<line num="36" count="0" type="stmt"/>
<line num="37" count="0" type="stmt"/>
<line num="38" count="0" type="stmt"/>
<line num="39" count="0" type="stmt"/>
<line num="40" count="0" type="stmt"/>
<line num="41" count="0" type="stmt"/>
<line num="42" count="0" type="stmt"/>
<line num="43" count="0" type="stmt"/>
<line num="44" count="0" type="stmt"/>
<line num="45" count="0" type="stmt"/>
<line num="46" count="0" type="stmt"/>
<line num="47" count="0" type="stmt"/>
<line num="48" count="0" type="stmt"/>
<line num="49" count="0" type="stmt"/>
<line num="50" count="0" type="stmt"/>
<line num="51" count="0" type="stmt"/>
<line num="52" count="0" type="stmt"/>
<line num="53" count="0" type="stmt"/>
<line num="54" count="0" type="stmt"/>
<line num="55" count="0" type="stmt"/>
@ -419,7 +418,10 @@
<line num="62" count="0" type="stmt"/>
<line num="63" count="0" type="stmt"/>
<line num="64" count="0" type="stmt"/>
<line num="65" count="0" type="stmt"/>
<line num="66" count="0" type="stmt"/>
<line num="67" count="0" type="stmt"/>
<line num="68" count="0" type="stmt"/>
<line num="69" count="0" type="stmt"/>
<line num="70" count="0" type="stmt"/>
<line num="71" count="0" type="stmt"/>
@ -431,9 +433,13 @@
<line num="77" count="0" type="stmt"/>
<line num="78" count="0" type="stmt"/>
<line num="79" count="0" type="stmt"/>
<line num="80" count="0" type="stmt"/>
<line num="81" count="0" type="stmt"/>
<line num="82" count="0" type="stmt"/>
<line num="83" count="0" type="stmt"/>
<line num="84" count="0" type="stmt"/>
<line num="85" count="0" type="stmt"/>
<line num="86" count="0" type="stmt"/>
<line num="87" count="0" type="stmt"/>
<line num="88" count="0" type="stmt"/>
<line num="89" count="0" type="stmt"/>
@ -445,26 +451,18 @@
<line num="95" count="0" type="stmt"/>
<line num="96" count="0" type="stmt"/>
<line num="97" count="0" type="stmt"/>
<line num="98" count="0" type="stmt"/>
<line num="99" count="0" type="stmt"/>
<line num="100" count="0" type="stmt"/>
<line num="101" count="0" type="stmt"/>
<line num="102" count="0" type="stmt"/>
<line num="103" count="0" type="stmt"/>
<line num="104" count="0" type="stmt"/>
<line num="105" count="0" type="stmt"/>
<line num="106" count="0" type="stmt"/>
<line num="107" count="0" type="stmt"/>
<line num="108" count="0" type="stmt"/>
<line num="109" count="0" type="stmt"/>
<line num="110" count="0" type="stmt"/>
<line num="111" count="0" type="stmt"/>
<line num="112" count="0" type="stmt"/>
<line num="113" count="0" type="stmt"/>
<line num="114" count="0" type="stmt"/>
<line num="115" count="0" type="stmt"/>
<line num="116" count="0" type="stmt"/>
<line num="117" count="0" type="stmt"/>
<line num="118" count="0" type="stmt"/>
<line num="119" count="0" type="stmt"/>
<line num="120" count="0" type="stmt"/>
@ -474,171 +472,31 @@
<line num="124" count="0" type="stmt"/>
<line num="125" count="0" type="stmt"/>
<line num="126" count="0" type="stmt"/>
<line num="127" count="0" type="stmt"/>
<line num="128" count="0" type="stmt"/>
<line num="129" count="0" type="stmt"/>
<line num="130" count="0" type="stmt"/>
<line num="131" count="0" type="stmt"/>
<line num="132" count="0" type="stmt"/>
<line num="133" count="0" type="stmt"/>
<line num="134" count="0" type="stmt"/>
<line num="135" count="0" type="stmt"/>
<line num="136" count="0" type="stmt"/>
<line num="137" count="0" type="stmt"/>
<line num="138" count="0" type="stmt"/>
<line num="139" count="0" type="stmt"/>
<line num="140" count="0" type="stmt"/>
<line num="141" count="0" type="stmt"/>
<line num="142" count="0" type="stmt"/>
<line num="143" count="0" type="stmt"/>
<line num="144" count="0" type="stmt"/>
<line num="145" count="0" type="stmt"/>
<line num="146" count="0" type="stmt"/>
<line num="147" count="0" type="stmt"/>
<line num="148" count="0" type="stmt"/>
<line num="149" count="0" type="stmt"/>
<line num="150" count="0" type="stmt"/>
<line num="151" count="0" type="stmt"/>
<line num="152" count="0" type="stmt"/>
<line num="153" count="0" type="stmt"/>
<line num="154" count="0" type="stmt"/>
<line num="155" count="0" type="stmt"/>
<line num="156" count="0" type="stmt"/>
<line num="157" count="0" type="stmt"/>
<line num="158" count="0" type="stmt"/>
<line num="159" count="0" type="stmt"/>
<line num="160" count="0" type="stmt"/>
<line num="161" count="0" type="stmt"/>
<line num="162" count="0" type="stmt"/>
<line num="163" count="0" type="stmt"/>
<line num="164" count="0" type="stmt"/>
<line num="165" count="0" type="stmt"/>
<line num="166" count="0" type="stmt"/>
<line num="167" count="0" type="stmt"/>
<line num="168" count="0" type="stmt"/>
<line num="169" count="0" type="stmt"/>
<line num="170" count="0" type="stmt"/>
<line num="171" count="0" type="stmt"/>
<line num="172" count="0" type="stmt"/>
<line num="173" count="0" type="stmt"/>
<line num="174" count="0" type="stmt"/>
<line num="175" count="0" type="stmt"/>
<line num="176" count="0" type="stmt"/>
<line num="177" count="0" type="stmt"/>
<line num="178" count="0" type="stmt"/>
<line num="179" count="0" type="stmt"/>
<line num="180" count="0" type="stmt"/>
<line num="181" count="0" type="stmt"/>
<line num="182" count="0" type="stmt"/>
<line num="183" count="0" type="stmt"/>
<line num="184" count="0" type="stmt"/>
<line num="185" count="0" type="stmt"/>
<line num="186" count="0" type="stmt"/>
<line num="187" count="0" type="stmt"/>
<line num="190" count="0" type="stmt"/>
<line num="191" count="0" type="stmt"/>
<line num="192" count="0" type="stmt"/>
<line num="193" count="0" type="stmt"/>
<line num="194" count="0" type="stmt"/>
<line num="196" count="0" type="stmt"/>
<line num="197" count="0" type="stmt"/>
<line num="198" count="0" type="stmt"/>
<line num="199" count="0" type="stmt"/>
<line num="200" count="0" type="stmt"/>
<line num="201" count="0" type="stmt"/>
<line num="202" count="0" type="stmt"/>
<line num="203" count="0" type="stmt"/>
<line num="204" count="0" type="stmt"/>
<line num="205" count="0" type="stmt"/>
<line num="206" count="0" type="stmt"/>
<line num="207" count="0" type="stmt"/>
<line num="208" count="0" type="stmt"/>
<line num="209" count="0" type="stmt"/>
<line num="212" count="0" type="stmt"/>
<line num="213" count="0" type="stmt"/>
<line num="214" count="0" type="stmt"/>
<line num="215" count="0" type="stmt"/>
<line num="216" count="0" type="stmt"/>
<line num="218" count="0" type="stmt"/>
<line num="219" count="0" type="stmt"/>
<line num="220" count="0" type="stmt"/>
<line num="221" count="0" type="stmt"/>
<line num="222" count="0" type="stmt"/>
<line num="223" count="0" type="stmt"/>
<line num="224" count="0" type="stmt"/>
<line num="225" count="0" type="stmt"/>
<line num="226" count="0" type="stmt"/>
<line num="227" count="0" type="stmt"/>
<line num="228" count="0" type="stmt"/>
<line num="231" count="0" type="stmt"/>
<line num="232" count="0" type="stmt"/>
<line num="233" count="0" type="stmt"/>
<line num="234" count="0" type="stmt"/>
<line num="235" count="0" type="stmt"/>
<line num="237" count="0" type="stmt"/>
<line num="238" count="0" type="stmt"/>
<line num="239" count="0" type="stmt"/>
<line num="240" count="0" type="stmt"/>
<line num="241" count="0" type="stmt"/>
<line num="242" count="0" type="stmt"/>
<line num="243" count="0" type="stmt"/>
<line num="244" count="0" type="stmt"/>
<line num="245" count="0" type="stmt"/>
<line num="246" count="0" type="stmt"/>
<line num="247" count="0" type="stmt"/>
<line num="248" count="0" type="stmt"/>
<line num="249" count="0" type="stmt"/>
<line num="250" count="0" type="stmt"/>
<line num="251" count="0" type="stmt"/>
<line num="252" count="0" type="stmt"/>
<line num="253" count="0" type="stmt"/>
<line num="254" count="0" type="stmt"/>
<line num="255" count="0" type="stmt"/>
<line num="256" count="0" type="stmt"/>
<line num="257" count="0" type="stmt"/>
<line num="260" count="0" type="stmt"/>
<line num="261" count="0" type="stmt"/>
<line num="262" count="0" type="stmt"/>
<line num="263" count="0" type="stmt"/>
<line num="264" count="0" type="stmt"/>
<line num="265" count="0" type="stmt"/>
<line num="266" count="0" type="stmt"/>
<line num="267" count="0" type="stmt"/>
<line num="268" count="0" type="stmt"/>
<line num="271" count="0" type="stmt"/>
<line num="273" count="0" type="stmt"/>
<line num="274" count="0" type="stmt"/>
<line num="275" count="0" type="stmt"/>
<line num="276" count="0" type="stmt"/>
<line num="277" count="0" type="stmt"/>
<line num="278" count="0" type="stmt"/>
<line num="281" count="0" type="stmt"/>
<line num="282" count="0" type="stmt"/>
<line num="283" count="0" type="stmt"/>
<line num="284" count="0" type="stmt"/>
<line num="285" count="0" type="stmt"/>
<line num="286" count="0" type="stmt"/>
<line num="289" count="0" type="stmt"/>
<line num="290" count="0" type="stmt"/>
<line num="291" count="0" type="stmt"/>
<line num="292" count="0" type="stmt"/>
<line num="293" count="0" type="stmt"/>
<line num="294" count="0" type="stmt"/>
<line num="297" count="0" type="stmt"/>
<line num="298" count="0" type="stmt"/>
<line num="299" count="0" type="stmt"/>
<line num="300" count="0" type="stmt"/>
<line num="301" count="0" type="stmt"/>
<line num="302" count="0" type="stmt"/>
<line num="305" count="0" type="stmt"/>
<line num="306" count="0" type="stmt"/>
<line num="307" count="0" type="stmt"/>
<line num="308" count="0" type="stmt"/>
<line num="309" count="0" type="stmt"/>
<line num="310" count="0" type="stmt"/>
<line num="311" count="0" type="stmt"/>
</file>
</package>
<package name="4NK_IA_front.src.store">
<package name="src.store">
<metrics statements="114" coveredstatements="0" conditionals="3" coveredconditionals="0" methods="3" coveredmethods="0"/>
<file name="appSlice.ts" path="/home/desk/code/4NK_IA_front/src/store/appSlice.ts">
<metrics statements="10" coveredstatements="0" conditionals="1" coveredconditionals="0" methods="1" coveredmethods="0"/>
@ -764,7 +622,7 @@
<line num="23" count="0" type="stmt"/>
</file>
</package>
<package name="4NK_IA_front.src.theme">
<package name="src.theme">
<metrics statements="64" coveredstatements="0" conditionals="1" coveredconditionals="0" methods="1" coveredmethods="0"/>
<file name="index.ts" path="/home/desk/code/4NK_IA_front/src/theme/index.ts">
<metrics statements="64" coveredstatements="0" conditionals="1" coveredconditionals="0" methods="1" coveredmethods="0"/>
@ -834,13 +692,13 @@
<line num="65" count="0" type="stmt"/>
</file>
</package>
<package name="4NK_IA_front.src.types">
<package name="src.types">
<metrics statements="0" coveredstatements="0" conditionals="1" coveredconditionals="1" methods="1" coveredmethods="1"/>
<file name="index.ts" path="/home/desk/code/4NK_IA_front/src/types/index.ts">
<metrics statements="0" coveredstatements="0" conditionals="1" coveredconditionals="1" methods="1" coveredmethods="1"/>
</file>
</package>
<package name="4NK_IA_front.src.views">
<package name="src.views">
<metrics statements="978" coveredstatements="0" conditionals="5" coveredconditionals="0" methods="5" coveredmethods="0"/>
<file name="AnalyseView.tsx" path="/home/desk/code/4NK_IA_front/src/views/AnalyseView.tsx">
<metrics statements="191" coveredstatements="0" conditionals="1" coveredconditionals="0" methods="1" coveredmethods="0"/>

File diff suppressed because one or more lines are too long

View File

@ -25,7 +25,7 @@
<div class='fl pad1y space-right2'>
<span class="strong">0% </span>
<span class="quiet">Statements</span>
<span class='fraction'>0/1753</span>
<span class='fraction'>0/1611</span>
</div>
@ -46,7 +46,7 @@
<div class='fl pad1y space-right2'>
<span class="strong">0% </span>
<span class="quiet">Lines</span>
<span class='fraction'>0/1753</span>
<span class='fraction'>0/1611</span>
</div>
@ -79,7 +79,7 @@
</tr>
</thead>
<tbody><tr>
<td class="file low" data-value="4NK_IA_front"><a href="4NK_IA_front/index.html">4NK_IA_front</a></td>
<td class="file low" data-value="scripts"><a href="scripts/index.html">scripts</a></td>
<td data-value="0" class="pic low">
<div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div>
</td>
@ -94,7 +94,7 @@
</tr>
<tr>
<td class="file low" data-value="4NK_IA_front/src"><a href="4NK_IA_front/src/index.html">4NK_IA_front/src</a></td>
<td class="file low" data-value="src"><a href="src/index.html">src</a></td>
<td data-value="0" class="pic low">
<div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div>
</td>
@ -109,7 +109,7 @@
</tr>
<tr>
<td class="file low" data-value="4NK_IA_front/src/components"><a href="4NK_IA_front/src/components/index.html">4NK_IA_front/src/components</a></td>
<td class="file low" data-value="src/components"><a href="src/components/index.html">src/components</a></td>
<td data-value="0" class="pic low">
<div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div>
</td>
@ -124,7 +124,7 @@
</tr>
<tr>
<td class="file low" data-value="4NK_IA_front/src/router"><a href="4NK_IA_front/src/router/index.html">4NK_IA_front/src/router</a></td>
<td class="file low" data-value="src/router"><a href="src/router/index.html">src/router</a></td>
<td data-value="0" class="pic low">
<div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div>
</td>
@ -139,22 +139,22 @@
</tr>
<tr>
<td class="file low" data-value="4NK_IA_front/src/services"><a href="4NK_IA_front/src/services/index.html">4NK_IA_front/src/services</a></td>
<td class="file low" data-value="src/services"><a href="src/services/index.html">src/services</a></td>
<td data-value="0" class="pic low">
<div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div>
</td>
<td data-value="0" class="pct low">0%</td>
<td data-value="266" class="abs low">0/266</td>
<td data-value="124" class="abs low">0/124</td>
<td data-value="0" class="pct low">0%</td>
<td data-value="1" class="abs low">0/1</td>
<td data-value="0" class="pct low">0%</td>
<td data-value="1" class="abs low">0/1</td>
<td data-value="0" class="pct low">0%</td>
<td data-value="266" class="abs low">0/266</td>
<td data-value="124" class="abs low">0/124</td>
</tr>
<tr>
<td class="file low" data-value="4NK_IA_front/src/store"><a href="4NK_IA_front/src/store/index.html">4NK_IA_front/src/store</a></td>
<td class="file low" data-value="src/store"><a href="src/store/index.html">src/store</a></td>
<td data-value="0" class="pic low">
<div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div>
</td>
@ -169,7 +169,7 @@
</tr>
<tr>
<td class="file low" data-value="4NK_IA_front/src/theme"><a href="4NK_IA_front/src/theme/index.html">4NK_IA_front/src/theme</a></td>
<td class="file low" data-value="src/theme"><a href="src/theme/index.html">src/theme</a></td>
<td data-value="0" class="pic low">
<div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div>
</td>
@ -184,7 +184,7 @@
</tr>
<tr>
<td class="file empty" data-value="4NK_IA_front/src/types"><a href="4NK_IA_front/src/types/index.html">4NK_IA_front/src/types</a></td>
<td class="file empty" data-value="src/types"><a href="src/types/index.html">src/types</a></td>
<td data-value="0" class="pic empty">
<div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div>
</td>
@ -199,7 +199,7 @@
</tr>
<tr>
<td class="file low" data-value="4NK_IA_front/src/views"><a href="4NK_IA_front/src/views/index.html">4NK_IA_front/src/views</a></td>
<td class="file low" data-value="src/views"><a href="src/views/index.html">src/views</a></td>
<td data-value="0" class="pic low">
<div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div>
</td>
@ -221,7 +221,7 @@
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="prettify.js"></script>
<script>

View File

@ -3,7 +3,7 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front</title>
<title>Code coverage report for scripts</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../prettify.css" />
<link rel="stylesheet" href="../base.css" />
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../index.html">All files</a> 4NK_IA_front</h1>
<h1><a href="../index.html">All files</a> scripts</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -101,7 +101,7 @@
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../prettify.js"></script>
<script>

View File

@ -3,7 +3,7 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/simple-server.js</title>
<title>Code coverage report for scripts/simple-server.js</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../prettify.css" />
<link rel="stylesheet" href="../base.css" />
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../index.html">All files</a> / <a href="index.html">4NK_IA_front</a> simple-server.js</h1>
<h1><a href="../index.html">All files</a> / <a href="index.html">scripts</a> simple-server.js</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -268,7 +268,7 @@
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../prettify.js"></script>
<script>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/App.tsx</title>
<title>Code coverage report for src/App.tsx</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<link rel="stylesheet" href="../prettify.css" />
<link rel="stylesheet" href="../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../sort-arrow-sprite.png);
background-image: url(../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../index.html">All files</a> / <a href="index.html">4NK_IA_front/src</a> App.tsx</h1>
<h1><a href="../index.html">All files</a> / <a href="index.html">src</a> App.tsx</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -88,16 +88,16 @@
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../prettify.js"></script>
<script src="../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
<script src="../sorter.js"></script>
<script src="../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/components/FilePreview.tsx</title>
<title>Code coverage report for src/components/FilePreview.tsx</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> / <a href="index.html">4NK_IA_front/src/components</a> FilePreview.tsx</h1>
<h1><a href="../../index.html">All files</a> / <a href="index.html">src/components</a> FilePreview.tsx</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -575,14 +575,14 @@ interface FilePreviewProps {
&nbsp;
<span class="cstat-no" title="statement not covered" > const handleDownload = () =&gt; {</span>
<span class="cstat-no" title="statement not covered" > if (document.previewUrl) {</span>
<span class="cstat-no" title="statement not covered" > const link = document.createElement('a')</span>
<span class="cstat-no" title="statement not covered" > const link = window.document.createElement('a')</span>
<span class="cstat-no" title="statement not covered" > link.href = document.previewUrl</span>
<span class="cstat-no" title="statement not covered" > link.download = document.name</span>
<span class="cstat-no" title="statement not covered" > link.click()</span>
<span class="cstat-no" title="statement not covered" > }</span>
<span class="cstat-no" title="statement not covered" > }</span>
&nbsp;
<span class="cstat-no" title="statement not covered" > const isPDF = document.type.includes('pdf') || document.name.toLowerCase().endsWith('.pdf')</span>
<span class="cstat-no" title="statement not covered" > const isPDF = document.mimeType.includes('pdf') || document.name.toLowerCase().endsWith('.pdf')</span>
&nbsp;
<span class="cstat-no" title="statement not covered" > if (!isPDF) {</span>
<span class="cstat-no" title="statement not covered" > return (</span>
@ -594,7 +594,7 @@ interface FilePreviewProps {
<span class="cstat-no" title="statement not covered" > &lt;/IconButton&gt;</span>
<span class="cstat-no" title="statement not covered" > &lt;/Box&gt;</span>
<span class="cstat-no" title="statement not covered" > &lt;Alert severity="info"&gt;</span>
<span class="cstat-no" title="statement not covered" > Aperçu non disponible pour ce type de fichier ({document.type})</span>
<span class="cstat-no" title="statement not covered" > Aperçu non disponible pour ce type de fichier ({document.functionalType || document.mimeType})</span>
<span class="cstat-no" title="statement not covered" > &lt;/Alert&gt;</span>
<span class="cstat-no" title="statement not covered" > &lt;/Paper&gt;</span>
)
@ -757,16 +757,16 @@ interface FilePreviewProps {
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/components/Layout.tsx</title>
<title>Code coverage report for src/components/Layout.tsx</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> / <a href="index.html">4NK_IA_front/src/components</a> Layout.tsx</h1>
<h1><a href="../../index.html">All files</a> / <a href="index.html">src/components</a> Layout.tsx</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -178,16 +178,16 @@ interface LayoutProps {
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/components/NavigationTabs.tsx</title>
<title>Code coverage report for src/components/NavigationTabs.tsx</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> / <a href="index.html">4NK_IA_front/src/components</a> NavigationTabs.tsx</h1>
<h1><a href="../../index.html">All files</a> / <a href="index.html">src/components</a> NavigationTabs.tsx</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -193,16 +193,16 @@ interface NavigationTabsProps {
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/components</title>
<title>Code coverage report for src/components</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> 4NK_IA_front/src/components</h1>
<h1><a href="../../index.html">All files</a> src/components</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -131,16 +131,16 @@
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src</title>
<title>Code coverage report for src</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<link rel="stylesheet" href="../prettify.css" />
<link rel="stylesheet" href="../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../sort-arrow-sprite.png);
background-image: url(../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../index.html">All files</a> 4NK_IA_front/src</h1>
<h1><a href="../index.html">All files</a> src</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -116,16 +116,16 @@
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../prettify.js"></script>
<script src="../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
<script src="../sorter.js"></script>
<script src="../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/main.tsx</title>
<title>Code coverage report for src/main.tsx</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<link rel="stylesheet" href="../prettify.css" />
<link rel="stylesheet" href="../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../sort-arrow-sprite.png);
background-image: url(../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../index.html">All files</a> / <a href="index.html">4NK_IA_front/src</a> main.tsx</h1>
<h1><a href="../index.html">All files</a> / <a href="index.html">src</a> main.tsx</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -130,16 +130,16 @@
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../prettify.js"></script>
<script src="../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
<script src="../sorter.js"></script>
<script src="../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/router</title>
<title>Code coverage report for src/router</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> 4NK_IA_front/src/router</h1>
<h1><a href="../../index.html">All files</a> src/router</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -101,16 +101,16 @@
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/router/index.tsx</title>
<title>Code coverage report for src/router/index.tsx</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> / <a href="index.html">4NK_IA_front/src/router</a> index.tsx</h1>
<h1><a href="../../index.html">All files</a> / <a href="index.html">src/router</a> index.tsx</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -154,16 +154,16 @@
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -0,0 +1,562 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for src/services/api.ts</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../index.html">All files</a> / <a href="index.html">src/services</a> api.ts</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">0% </span>
<span class="quiet">Statements</span>
<span class='fraction'>0/124</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">0% </span>
<span class="quiet">Branches</span>
<span class='fraction'>0/1</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">0% </span>
<span class="quiet">Functions</span>
<span class='fraction'>0/1</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">0% </span>
<span class="quiet">Lines</span>
<span class='fraction'>0/124</span>
</div>
</div>
<p class="quiet">
Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
</p>
<template id="filterTemplate">
<div class="quiet">
Filter:
<input type="search" id="fileSearch">
</div>
</template>
</div>
<div class='status-line low'></div>
<pre><table class="coverage">
<tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
<a name='L2'></a><a href='#L2'>2</a>
<a name='L3'></a><a href='#L3'>3</a>
<a name='L4'></a><a href='#L4'>4</a>
<a name='L5'></a><a href='#L5'>5</a>
<a name='L6'></a><a href='#L6'>6</a>
<a name='L7'></a><a href='#L7'>7</a>
<a name='L8'></a><a href='#L8'>8</a>
<a name='L9'></a><a href='#L9'>9</a>
<a name='L10'></a><a href='#L10'>10</a>
<a name='L11'></a><a href='#L11'>11</a>
<a name='L12'></a><a href='#L12'>12</a>
<a name='L13'></a><a href='#L13'>13</a>
<a name='L14'></a><a href='#L14'>14</a>
<a name='L15'></a><a href='#L15'>15</a>
<a name='L16'></a><a href='#L16'>16</a>
<a name='L17'></a><a href='#L17'>17</a>
<a name='L18'></a><a href='#L18'>18</a>
<a name='L19'></a><a href='#L19'>19</a>
<a name='L20'></a><a href='#L20'>20</a>
<a name='L21'></a><a href='#L21'>21</a>
<a name='L22'></a><a href='#L22'>22</a>
<a name='L23'></a><a href='#L23'>23</a>
<a name='L24'></a><a href='#L24'>24</a>
<a name='L25'></a><a href='#L25'>25</a>
<a name='L26'></a><a href='#L26'>26</a>
<a name='L27'></a><a href='#L27'>27</a>
<a name='L28'></a><a href='#L28'>28</a>
<a name='L29'></a><a href='#L29'>29</a>
<a name='L30'></a><a href='#L30'>30</a>
<a name='L31'></a><a href='#L31'>31</a>
<a name='L32'></a><a href='#L32'>32</a>
<a name='L33'></a><a href='#L33'>33</a>
<a name='L34'></a><a href='#L34'>34</a>
<a name='L35'></a><a href='#L35'>35</a>
<a name='L36'></a><a href='#L36'>36</a>
<a name='L37'></a><a href='#L37'>37</a>
<a name='L38'></a><a href='#L38'>38</a>
<a name='L39'></a><a href='#L39'>39</a>
<a name='L40'></a><a href='#L40'>40</a>
<a name='L41'></a><a href='#L41'>41</a>
<a name='L42'></a><a href='#L42'>42</a>
<a name='L43'></a><a href='#L43'>43</a>
<a name='L44'></a><a href='#L44'>44</a>
<a name='L45'></a><a href='#L45'>45</a>
<a name='L46'></a><a href='#L46'>46</a>
<a name='L47'></a><a href='#L47'>47</a>
<a name='L48'></a><a href='#L48'>48</a>
<a name='L49'></a><a href='#L49'>49</a>
<a name='L50'></a><a href='#L50'>50</a>
<a name='L51'></a><a href='#L51'>51</a>
<a name='L52'></a><a href='#L52'>52</a>
<a name='L53'></a><a href='#L53'>53</a>
<a name='L54'></a><a href='#L54'>54</a>
<a name='L55'></a><a href='#L55'>55</a>
<a name='L56'></a><a href='#L56'>56</a>
<a name='L57'></a><a href='#L57'>57</a>
<a name='L58'></a><a href='#L58'>58</a>
<a name='L59'></a><a href='#L59'>59</a>
<a name='L60'></a><a href='#L60'>60</a>
<a name='L61'></a><a href='#L61'>61</a>
<a name='L62'></a><a href='#L62'>62</a>
<a name='L63'></a><a href='#L63'>63</a>
<a name='L64'></a><a href='#L64'>64</a>
<a name='L65'></a><a href='#L65'>65</a>
<a name='L66'></a><a href='#L66'>66</a>
<a name='L67'></a><a href='#L67'>67</a>
<a name='L68'></a><a href='#L68'>68</a>
<a name='L69'></a><a href='#L69'>69</a>
<a name='L70'></a><a href='#L70'>70</a>
<a name='L71'></a><a href='#L71'>71</a>
<a name='L72'></a><a href='#L72'>72</a>
<a name='L73'></a><a href='#L73'>73</a>
<a name='L74'></a><a href='#L74'>74</a>
<a name='L75'></a><a href='#L75'>75</a>
<a name='L76'></a><a href='#L76'>76</a>
<a name='L77'></a><a href='#L77'>77</a>
<a name='L78'></a><a href='#L78'>78</a>
<a name='L79'></a><a href='#L79'>79</a>
<a name='L80'></a><a href='#L80'>80</a>
<a name='L81'></a><a href='#L81'>81</a>
<a name='L82'></a><a href='#L82'>82</a>
<a name='L83'></a><a href='#L83'>83</a>
<a name='L84'></a><a href='#L84'>84</a>
<a name='L85'></a><a href='#L85'>85</a>
<a name='L86'></a><a href='#L86'>86</a>
<a name='L87'></a><a href='#L87'>87</a>
<a name='L88'></a><a href='#L88'>88</a>
<a name='L89'></a><a href='#L89'>89</a>
<a name='L90'></a><a href='#L90'>90</a>
<a name='L91'></a><a href='#L91'>91</a>
<a name='L92'></a><a href='#L92'>92</a>
<a name='L93'></a><a href='#L93'>93</a>
<a name='L94'></a><a href='#L94'>94</a>
<a name='L95'></a><a href='#L95'>95</a>
<a name='L96'></a><a href='#L96'>96</a>
<a name='L97'></a><a href='#L97'>97</a>
<a name='L98'></a><a href='#L98'>98</a>
<a name='L99'></a><a href='#L99'>99</a>
<a name='L100'></a><a href='#L100'>100</a>
<a name='L101'></a><a href='#L101'>101</a>
<a name='L102'></a><a href='#L102'>102</a>
<a name='L103'></a><a href='#L103'>103</a>
<a name='L104'></a><a href='#L104'>104</a>
<a name='L105'></a><a href='#L105'>105</a>
<a name='L106'></a><a href='#L106'>106</a>
<a name='L107'></a><a href='#L107'>107</a>
<a name='L108'></a><a href='#L108'>108</a>
<a name='L109'></a><a href='#L109'>109</a>
<a name='L110'></a><a href='#L110'>110</a>
<a name='L111'></a><a href='#L111'>111</a>
<a name='L112'></a><a href='#L112'>112</a>
<a name='L113'></a><a href='#L113'>113</a>
<a name='L114'></a><a href='#L114'>114</a>
<a name='L115'></a><a href='#L115'>115</a>
<a name='L116'></a><a href='#L116'>116</a>
<a name='L117'></a><a href='#L117'>117</a>
<a name='L118'></a><a href='#L118'>118</a>
<a name='L119'></a><a href='#L119'>119</a>
<a name='L120'></a><a href='#L120'>120</a>
<a name='L121'></a><a href='#L121'>121</a>
<a name='L122'></a><a href='#L122'>122</a>
<a name='L123'></a><a href='#L123'>123</a>
<a name='L124'></a><a href='#L124'>124</a>
<a name='L125'></a><a href='#L125'>125</a>
<a name='L126'></a><a href='#L126'>126</a>
<a name='L127'></a><a href='#L127'>127</a>
<a name='L128'></a><a href='#L128'>128</a>
<a name='L129'></a><a href='#L129'>129</a>
<a name='L130'></a><a href='#L130'>130</a>
<a name='L131'></a><a href='#L131'>131</a>
<a name='L132'></a><a href='#L132'>132</a>
<a name='L133'></a><a href='#L133'>133</a>
<a name='L134'></a><a href='#L134'>134</a>
<a name='L135'></a><a href='#L135'>135</a>
<a name='L136'></a><a href='#L136'>136</a>
<a name='L137'></a><a href='#L137'>137</a>
<a name='L138'></a><a href='#L138'>138</a>
<a name='L139'></a><a href='#L139'>139</a>
<a name='L140'></a><a href='#L140'>140</a>
<a name='L141'></a><a href='#L141'>141</a>
<a name='L142'></a><a href='#L142'>142</a>
<a name='L143'></a><a href='#L143'>143</a>
<a name='L144'></a><a href='#L144'>144</a>
<a name='L145'></a><a href='#L145'>145</a>
<a name='L146'></a><a href='#L146'>146</a>
<a name='L147'></a><a href='#L147'>147</a>
<a name='L148'></a><a href='#L148'>148</a>
<a name='L149'></a><a href='#L149'>149</a>
<a name='L150'></a><a href='#L150'>150</a>
<a name='L151'></a><a href='#L151'>151</a>
<a name='L152'></a><a href='#L152'>152</a>
<a name='L153'></a><a href='#L153'>153</a>
<a name='L154'></a><a href='#L154'>154</a>
<a name='L155'></a><a href='#L155'>155</a>
<a name='L156'></a><a href='#L156'>156</a>
<a name='L157'></a><a href='#L157'>157</a>
<a name='L158'></a><a href='#L158'>158</a>
<a name='L159'></a><a href='#L159'>159</a>
<a name='L160'></a><a href='#L160'>160</a></td><td class="line-coverage quiet"><span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js"><span class="cstat-no" title="statement not covered" >import axios from 'axios'<span class="fstat-no" title="function not covered" ><span class="branch-0 cbranch-no" title="branch not covered" ></span></span></span>
import type { Document, ExtractionResult, AnalysisResult, ContextResult, ConseilResult } from '../types'
&nbsp;
<span class="cstat-no" title="statement not covered" >const BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000'</span>
&nbsp;
<span class="cstat-no" title="statement not covered" >export const apiClient = axios.create({</span>
<span class="cstat-no" title="statement not covered" > baseURL: BASE_URL,</span>
<span class="cstat-no" title="statement not covered" > timeout: 60000,</span>
<span class="cstat-no" title="statement not covered" >})</span>
&nbsp;
// Intercepteur pour les erreurs
<span class="cstat-no" title="statement not covered" >apiClient.interceptors.response.use(</span>
<span class="cstat-no" title="statement not covered" > (response) =&gt; response,</span>
<span class="cstat-no" title="statement not covered" > (error) =&gt; {</span>
// Laisser remonter les erreurs au consommateur
<span class="cstat-no" title="statement not covered" > return Promise.reject(error)</span>
<span class="cstat-no" title="statement not covered" > }</span>
<span class="cstat-no" title="statement not covered" >)</span>
&nbsp;
// Services API pour les documents
<span class="cstat-no" title="statement not covered" >export const documentApi = {</span>
// Téléversement de document
<span class="cstat-no" title="statement not covered" > upload: async (file: File): Promise&lt;Document&gt; =&gt; {</span>
<span class="cstat-no" title="statement not covered" > const formData = new FormData()</span>
<span class="cstat-no" title="statement not covered" > formData.append('file', file)</span>
<span class="cstat-no" title="statement not covered" > const { data } = await apiClient.post('/api/notary/upload', formData, {</span>
<span class="cstat-no" title="statement not covered" > headers: { 'Content-Type': 'multipart/form-data' },</span>
<span class="cstat-no" title="statement not covered" > })</span>
&nbsp;
// L'API retourne {message, document_id, status}
// On doit mapper vers le format Document attendu
<span class="cstat-no" title="statement not covered" > const fileUrl = URL.createObjectURL(file)</span>
<span class="cstat-no" title="statement not covered" > return {</span>
<span class="cstat-no" title="statement not covered" > id: data.document_id || data.id || 'upload-' + Date.now(),</span>
<span class="cstat-no" title="statement not covered" > name: file.name,</span>
<span class="cstat-no" title="statement not covered" > mimeType: data.mime_type || data.mimeType || file.type || 'application/pdf',</span>
<span class="cstat-no" title="statement not covered" > functionalType: data.functional_type || data.functionalType || undefined,</span>
<span class="cstat-no" title="statement not covered" > size: file.size,</span>
<span class="cstat-no" title="statement not covered" > uploadDate: new Date(),</span>
<span class="cstat-no" title="statement not covered" > status: 'completed',</span>
<span class="cstat-no" title="statement not covered" > previewUrl: fileUrl</span>
<span class="cstat-no" title="statement not covered" > }</span>
<span class="cstat-no" title="statement not covered" > },</span>
&nbsp;
// Extraction des données
<span class="cstat-no" title="statement not covered" > extract: async (documentId: string): Promise&lt;ExtractionResult&gt; =&gt; {</span>
<span class="cstat-no" title="statement not covered" > const { data } = await apiClient.get(`/api/notary/documents/${documentId}`)</span>
&nbsp;
// Mapper les données de l'API vers le format ExtractionResult
<span class="cstat-no" title="statement not covered" > const results = data.results || {}</span>
<span class="cstat-no" title="statement not covered" > return {</span>
<span class="cstat-no" title="statement not covered" > documentId,</span>
<span class="cstat-no" title="statement not covered" > text: results.ocr_text || 'Texte extrait du document...',</span>
<span class="cstat-no" title="statement not covered" > language: 'fr',</span>
<span class="cstat-no" title="statement not covered" > documentType: results.document_type || 'Document',</span>
<span class="cstat-no" title="statement not covered" > identities: results.entities?.persons?.map((name: string, index: number) =&gt; ({</span>
<span class="cstat-no" title="statement not covered" > id: `person-${index}`,</span>
<span class="cstat-no" title="statement not covered" > type: 'person' as const,</span>
<span class="cstat-no" title="statement not covered" > firstName: name.split(' ')[0] || name,</span>
<span class="cstat-no" title="statement not covered" > lastName: name.split(' ').slice(1).join(' ') || '',</span>
<span class="cstat-no" title="statement not covered" > birthDate: '',</span>
<span class="cstat-no" title="statement not covered" > nationality: 'Française',</span>
<span class="cstat-no" title="statement not covered" > confidence: 0.9,</span>
<span class="cstat-no" title="statement not covered" > })) || [],</span>
<span class="cstat-no" title="statement not covered" > addresses: results.entities?.addresses?.map((address: string) =&gt; ({</span>
<span class="cstat-no" title="statement not covered" > street: address,</span>
<span class="cstat-no" title="statement not covered" > city: 'Paris',</span>
<span class="cstat-no" title="statement not covered" > postalCode: '75001',</span>
<span class="cstat-no" title="statement not covered" > country: 'France',</span>
<span class="cstat-no" title="statement not covered" > })) || [],</span>
<span class="cstat-no" title="statement not covered" > properties: results.entities?.properties?.map((_propertyName: string, index: number) =&gt; ({</span>
<span class="cstat-no" title="statement not covered" > id: `prop-${index}`,</span>
<span class="cstat-no" title="statement not covered" > type: 'apartment' as const,</span>
<span class="cstat-no" title="statement not covered" > address: {</span>
<span class="cstat-no" title="statement not covered" > street: '123 Rue de la Paix',</span>
<span class="cstat-no" title="statement not covered" > city: 'Paris',</span>
<span class="cstat-no" title="statement not covered" > postalCode: '75001',</span>
<span class="cstat-no" title="statement not covered" > country: 'France',</span>
<span class="cstat-no" title="statement not covered" > },</span>
<span class="cstat-no" title="statement not covered" > surface: 75,</span>
<span class="cstat-no" title="statement not covered" > cadastralReference: '1234567890AB',</span>
<span class="cstat-no" title="statement not covered" > value: 250000,</span>
<span class="cstat-no" title="statement not covered" > })) || [],</span>
<span class="cstat-no" title="statement not covered" > contracts: [</span>
<span class="cstat-no" title="statement not covered" > {</span>
<span class="cstat-no" title="statement not covered" > id: 'contract-1',</span>
<span class="cstat-no" title="statement not covered" > type: 'sale' as const,</span>
<span class="cstat-no" title="statement not covered" > parties: [],</span>
<span class="cstat-no" title="statement not covered" > amount: 250000,</span>
<span class="cstat-no" title="statement not covered" > date: '2024-01-15',</span>
<span class="cstat-no" title="statement not covered" > clauses: ['Clause de garantie', 'Clause de condition suspensive'],</span>
<span class="cstat-no" title="statement not covered" > },</span>
<span class="cstat-no" title="statement not covered" > ],</span>
<span class="cstat-no" title="statement not covered" > signatures: results.entities?.persons || [],</span>
<span class="cstat-no" title="statement not covered" > confidence: results.verification_score || 0.85,</span>
<span class="cstat-no" title="statement not covered" > }</span>
<span class="cstat-no" title="statement not covered" > },</span>
&nbsp;
// Analyse du document
<span class="cstat-no" title="statement not covered" > analyze: async (documentId: string): Promise&lt;AnalysisResult&gt; =&gt; {</span>
<span class="cstat-no" title="statement not covered" > const { data } = await apiClient.get&lt;AnalysisResult&gt;(`/api/documents/${documentId}/analyze`)</span>
<span class="cstat-no" title="statement not covered" > return data</span>
<span class="cstat-no" title="statement not covered" > },</span>
&nbsp;
// Données contextuelles
<span class="cstat-no" title="statement not covered" > getContext: async (documentId: string): Promise&lt;ContextResult&gt; =&gt; {</span>
<span class="cstat-no" title="statement not covered" > const { data } = await apiClient.get&lt;ContextResult&gt;(`/api/documents/${documentId}/context`)</span>
<span class="cstat-no" title="statement not covered" > return data</span>
<span class="cstat-no" title="statement not covered" > },</span>
&nbsp;
// Conseil LLM
<span class="cstat-no" title="statement not covered" > getConseil: async (documentId: string): Promise&lt;ConseilResult&gt; =&gt; {</span>
<span class="cstat-no" title="statement not covered" > const { data } = await apiClient.get&lt;ConseilResult&gt;(`/api/documents/${documentId}/conseil`)</span>
<span class="cstat-no" title="statement not covered" > return data</span>
<span class="cstat-no" title="statement not covered" > },</span>
&nbsp;
// Détection du type de document
<span class="cstat-no" title="statement not covered" > detectType: async (file: File): Promise&lt;{ type: string; confidence: number }&gt; =&gt; {</span>
<span class="cstat-no" title="statement not covered" > const formData = new FormData()</span>
<span class="cstat-no" title="statement not covered" > formData.append('file', file)</span>
<span class="cstat-no" title="statement not covered" > const { data } = await apiClient.post('/api/ocr/detect', formData, {</span>
<span class="cstat-no" title="statement not covered" > headers: { 'Content-Type': 'multipart/form-data' },</span>
<span class="cstat-no" title="statement not covered" > })</span>
<span class="cstat-no" title="statement not covered" > return data</span>
<span class="cstat-no" title="statement not covered" > },</span>
<span class="cstat-no" title="statement not covered" >}</span>
&nbsp;
// Services API pour les données externes
<span class="cstat-no" title="statement not covered" >export const externalApi = {</span>
// Cadastre via backend
<span class="cstat-no" title="statement not covered" > cadastre: async (address: string) =&gt; {</span>
<span class="cstat-no" title="statement not covered" > const { data } = await apiClient.get('/api/context/cadastre', { params: { q: address } })</span>
<span class="cstat-no" title="statement not covered" > return data</span>
<span class="cstat-no" title="statement not covered" > },</span>
&nbsp;
// Géorisques via backend
<span class="cstat-no" title="statement not covered" > georisques: async (coordinates: { lat: number; lng: number }) =&gt; {</span>
<span class="cstat-no" title="statement not covered" > const { data } = await apiClient.get('/api/context/georisques', { params: coordinates })</span>
<span class="cstat-no" title="statement not covered" > return data</span>
<span class="cstat-no" title="statement not covered" > },</span>
&nbsp;
// Géofoncier via backend
<span class="cstat-no" title="statement not covered" > geofoncier: async (address: string) =&gt; {</span>
<span class="cstat-no" title="statement not covered" > const { data } = await apiClient.get('/api/context/geofoncier', { params: { address } })</span>
<span class="cstat-no" title="statement not covered" > return data</span>
<span class="cstat-no" title="statement not covered" > },</span>
&nbsp;
// BODACC via backend
<span class="cstat-no" title="statement not covered" > bodacc: async (companyName: string) =&gt; {</span>
<span class="cstat-no" title="statement not covered" > const { data } = await apiClient.get('/api/context/bodacc', { params: { q: companyName } })</span>
<span class="cstat-no" title="statement not covered" > return data</span>
<span class="cstat-no" title="statement not covered" > },</span>
&nbsp;
// Infogreffe via backend
<span class="cstat-no" title="statement not covered" > infogreffe: async (siren: string) =&gt; {</span>
<span class="cstat-no" title="statement not covered" > const { data } = await apiClient.get('/api/context/infogreffe', { params: { siren } })</span>
<span class="cstat-no" title="statement not covered" > return data</span>
<span class="cstat-no" title="statement not covered" > },</span>
<span class="cstat-no" title="statement not covered" >}</span>
&nbsp;</pre></td></tr></table></pre>
<div class='push'></div><!-- for sticky footer -->
</div><!-- /wrapper -->
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/services</title>
<title>Code coverage report for src/services</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,13 +19,13 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> 4NK_IA_front/src/services</h1>
<h1><a href="../../index.html">All files</a> src/services</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">0% </span>
<span class="quiet">Statements</span>
<span class='fraction'>0/266</span>
<span class='fraction'>0/124</span>
</div>
@ -46,7 +46,7 @@
<div class='fl pad1y space-right2'>
<span class="strong">0% </span>
<span class="quiet">Lines</span>
<span class='fraction'>0/266</span>
<span class='fraction'>0/124</span>
</div>
@ -84,13 +84,13 @@
<div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div>
</td>
<td data-value="0" class="pct low">0%</td>
<td data-value="266" class="abs low">0/266</td>
<td data-value="124" class="abs low">0/124</td>
<td data-value="0" class="pct low">0%</td>
<td data-value="1" class="abs low">0/1</td>
<td data-value="0" class="pct low">0%</td>
<td data-value="1" class="abs low">0/1</td>
<td data-value="0" class="pct low">0%</td>
<td data-value="266" class="abs low">0/266</td>
<td data-value="124" class="abs low">0/124</td>
</tr>
</tbody>
@ -101,16 +101,16 @@
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/store/appSlice.ts</title>
<title>Code coverage report for src/store/appSlice.ts</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> / <a href="index.html">4NK_IA_front/src/store</a> appSlice.ts</h1>
<h1><a href="../../index.html">All files</a> / <a href="index.html">src/store</a> appSlice.ts</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -121,16 +121,16 @@ export type AppState = {
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/store/documentSlice.ts</title>
<title>Code coverage report for src/store/documentSlice.ts</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> / <a href="index.html">4NK_IA_front/src/store</a> documentSlice.ts</h1>
<h1><a href="../../index.html">All files</a> / <a href="index.html">src/store</a> documentSlice.ts</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -394,16 +394,16 @@ interface DocumentState {
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/store</title>
<title>Code coverage report for src/store</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> 4NK_IA_front/src/store</h1>
<h1><a href="../../index.html">All files</a> src/store</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -131,16 +131,16 @@
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/store/index.ts</title>
<title>Code coverage report for src/store/index.ts</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> / <a href="index.html">4NK_IA_front/src/store</a> index.ts</h1>
<h1><a href="../../index.html">All files</a> / <a href="index.html">src/store</a> index.ts</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -139,16 +139,16 @@ export type AppDispatch = typeof store.dispatch
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/theme</title>
<title>Code coverage report for src/theme</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> 4NK_IA_front/src/theme</h1>
<h1><a href="../../index.html">All files</a> src/theme</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -101,16 +101,16 @@
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/theme/index.ts</title>
<title>Code coverage report for src/theme/index.ts</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> / <a href="index.html">4NK_IA_front/src/theme</a> index.ts</h1>
<h1><a href="../../index.html">All files</a> / <a href="index.html">src/theme</a> index.ts</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -265,16 +265,16 @@
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/types</title>
<title>Code coverage report for src/types</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> 4NK_IA_front/src/types</h1>
<h1><a href="../../index.html">All files</a> src/types</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -101,16 +101,16 @@
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/types/index.ts</title>
<title>Code coverage report for src/types/index.ts</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> / <a href="index.html">4NK_IA_front/src/types</a> index.ts</h1>
<h1><a href="../../index.html">All files</a> / <a href="index.html">src/types</a> index.ts</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -159,7 +159,9 @@
<a name='L94'></a><a href='#L94'>94</a>
<a name='L95'></a><a href='#L95'>95</a>
<a name='L96'></a><a href='#L96'>96</a>
<a name='L97'></a><a href='#L97'>97</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
<a name='L97'></a><a href='#L97'>97</a>
<a name='L98'></a><a href='#L98'>98</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
@ -258,7 +260,8 @@
<span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">export interface Document {
id: string
name: string
type: string
mimeType: string
functionalType?: string
size: number
uploadDate: Date
status: 'uploading' | 'processing' | 'completed' | 'error'
@ -358,16 +361,16 @@ export interface ConseilResult {
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/views/AnalyseView.tsx</title>
<title>Code coverage report for src/views/AnalyseView.tsx</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> / <a href="index.html">4NK_IA_front/src/views</a> AnalyseView.tsx</h1>
<h1><a href="../../index.html">All files</a> / <a href="index.html">src/views</a> AnalyseView.tsx</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -832,16 +832,16 @@ import type { ChipProps, LinearProgressProps } from '@mui/material'
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/views/ConseilView.tsx</title>
<title>Code coverage report for src/views/ConseilView.tsx</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> / <a href="index.html">4NK_IA_front/src/views</a> ConseilView.tsx</h1>
<h1><a href="../../index.html">All files</a> / <a href="index.html">src/views</a> ConseilView.tsx</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -573,7 +573,7 @@
Schedule,
Psychology,
} from '@mui/icons-material'
import type { ChipProps } from '@mui/material'
import type { SvgIconProps } from '@mui/material'
<span class="cstat-no" title="statement not covered" >import { useAppDispatch, useAppSelector } from '../store'</span>
<span class="cstat-no" title="statement not covered" >import { getConseil } from '../store/documentSlice'</span>
<span class="cstat-no" title="statement not covered" >import { Layout } from '../components/Layout'</span>
@ -621,7 +621,7 @@ import type { ChipProps } from '@mui/material'
)
<span class="cstat-no" title="statement not covered" > }</span>
&nbsp;
<span class="cstat-no" title="statement not covered" > const getRiskColor = (risk: string): ChipProps['color'] =&gt; {</span>
<span class="cstat-no" title="statement not covered" > const getRiskColor = (risk: string): SvgIconProps['color'] =&gt; {</span>
<span class="cstat-no" title="statement not covered" > if (risk.toLowerCase().includes('élevé') || risk.toLowerCase().includes('critique')) {</span>
<span class="cstat-no" title="statement not covered" > return 'error'</span>
<span class="cstat-no" title="statement not covered" > }</span>
@ -699,7 +699,7 @@ import type { ChipProps } from '@mui/material'
<span class="cstat-no" title="statement not covered" > {conseilResult.risks.map((risk, index) =&gt; (</span>
<span class="cstat-no" title="statement not covered" > &lt;ListItem key={index}&gt;</span>
<span class="cstat-no" title="statement not covered" > &lt;ListItemIcon&gt;</span>
<span class="cstat-no" title="statement not covered" > &lt;Warning color={getRiskColor(risk) as ChipProps['color']} /&gt;</span>
<span class="cstat-no" title="statement not covered" > &lt;Warning color={getRiskColor(risk)} /&gt;</span>
<span class="cstat-no" title="statement not covered" > &lt;/ListItemIcon&gt;</span>
<span class="cstat-no" title="statement not covered" > &lt;ListItemText</span>
<span class="cstat-no" title="statement not covered" > primary={risk}</span>
@ -799,16 +799,16 @@ import type { ChipProps } from '@mui/material'
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/views/ContexteView.tsx</title>
<title>Code coverage report for src/views/ContexteView.tsx</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> / <a href="index.html">4NK_IA_front/src/views</a> ContexteView.tsx</h1>
<h1><a href="../../index.html">All files</a> / <a href="index.html">src/views</a> ContexteView.tsx</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -964,16 +964,16 @@ import type { ChipProps } from '@mui/material'
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/views/ExtractionView.tsx</title>
<title>Code coverage report for src/views/ExtractionView.tsx</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> / <a href="index.html">4NK_IA_front/src/views</a> ExtractionView.tsx</h1>
<h1><a href="../../index.html">All files</a> / <a href="index.html">src/views</a> ExtractionView.tsx</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -931,16 +931,16 @@
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/views/UploadView.tsx</title>
<title>Code coverage report for src/views/UploadView.tsx</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> / <a href="index.html">4NK_IA_front/src/views</a> UploadView.tsx</h1>
<h1><a href="../../index.html">All files</a> / <a href="index.html">src/views</a> UploadView.tsx</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -541,7 +541,7 @@ import type { Document } from '../types'
&nbsp;
<span class="cstat-no" title="statement not covered" > &lt;Box display="flex" gap={1} flexWrap="wrap"&gt;</span>
<span class="cstat-no" title="statement not covered" > &lt;Chip</span>
<span class="cstat-no" title="statement not covered" > label={doc.type}</span>
<span class="cstat-no" title="statement not covered" > label={doc.functionalType || doc.mimeType}</span>
<span class="cstat-no" title="statement not covered" > size="small"</span>
<span class="cstat-no" title="statement not covered" > variant="outlined"</span>
<span class="cstat-no" title="statement not covered" > /&gt;</span>
@ -580,16 +580,16 @@ import type { Document } from '../types'
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -3,15 +3,15 @@
<html lang="en">
<head>
<title>Code coverage report for 4NK_IA_front/src/views</title>
<title>Code coverage report for src/views</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
@ -19,7 +19,7 @@
<body>
<div class='wrapper'>
<div class='pad1'>
<h1><a href="../../../index.html">All files</a> 4NK_IA_front/src/views</h1>
<h1><a href="../../index.html">All files</a> src/views</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
@ -161,16 +161,16 @@
<div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
at 2025-09-11T09:40:00.754Z
at 2025-09-11T12:57:49.285Z
</div>
<script src="../../../prettify.js"></script>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
prettyPrint();
};
</script>
<script src="../../../sorter.js"></script>
<script src="../../../block-navigation.js"></script>
<script src="../../sorter.js"></script>
<script src="../../block-navigation.js"></script>
</body>
</html>

View File

@ -2,8 +2,8 @@
## Vue d'ensemble
L'application 4NK IA Front Notarial communique avec plusieurs APIs pour fournir une expérience complète
d'analyse de documents notariaux.
L'application 4NK IA Front Notarial communique uniquement avec le backend interne pour toutes les
fonctionnalités (upload, extraction, analyse, contexte, conseil).
## API Backend Principal
@ -13,36 +13,28 @@ d'analyse de documents notariaux.
http://localhost:8000 (développement)
```
### Modes d'API pris en charge
- **Mode simple** (`VITE_BACKEND_MODE=simple`) : endpoints sous `/api/notary/...`
- **Mode complet** (`VITE_BACKEND_MODE=complete`) : endpoints sous `/api/documents/...`
La variable d'environnement `VITE_BACKEND_MODE` pilote dynamiquement le choix des endpoints côté front.
### Endpoints
#### Upload de document
```http
POST /api/notary/upload # mode simple
POST /api/documents/upload # mode complet
POST /api/notary/upload
Content-Type: multipart/form-data
Body: FormData avec le fichier
```
**Réponse (champs attendus et utilisés par le front) :**
Réponse attendue (champs utilisés par le front) :
```json
{
"document_id": "doc_123456", // ou "id"
"mime_type": "application/pdf", // ou "mimeType"
"functional_type": "CNI" // ou "functionalType" (type fonctionnel métier)
"document_id": "doc_123456",
"mime_type": "application/pdf",
"functional_type": "CNI"
}
```
Le front mappe en `Document`:
Mappage front en `Document` :
```json
{
@ -60,80 +52,47 @@ Le front mappe en `Document`:
#### Extraction de données
```http
GET /api/notary/documents/{documentId} # mode simple (détails document + résultats)
GET /api/documents/{documentId}/extract # mode complet
GET /api/notary/documents/{documentId}
```
#### Analyse du document
```http
GET /api/documents/{documentId}/analyze # mode complet
GET /api/documents/{documentId}/analyze
```
(mode simple: synthèse construite côté front à partir de `/api/notary/documents/{documentId}`)
#### Données contextuelles
```http
GET /api/documents/{documentId}/context # mode complet
GET /api/documents/{documentId}/context
```
(mode simple: non disponible — fallback de démonstration)
#### Conseil IA
```http
GET /api/documents/{documentId}/conseil # mode complet
GET /api/documents/{documentId}/conseil
```
(mode simple: non disponible — fallback de démonstration)
## APIs Externes
### Cadastre
**URL :** `https://api.cadastre.gouv.fr`
**Usage :** Vérification des références cadastrales et des propriétés
### Géorisques
**URL :** `https://www.georisques.gouv.fr/api`
**Usage :** Analyse des risques géologiques et environnementaux
### Géofoncier
**URL :** `https://api.geofoncier.fr`
**Usage :** Données foncières et géographiques
### BODACC
**URL :** `https://api.bodacc.fr`
**Usage :** Vérification des procédures collectives et des entreprises
### Infogreffe
**URL :** `https://api.infogreffe.fr`
**Usage :** Informations sur les entreprises et leurs dirigeants
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
- 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
### Fallback automatique
En cas d'erreur, l'application bascule automatiquement vers des données de démonstration pour maintenir l'expérience utilisateur.
- ERR_NETWORK : Erreur de réseau
- ERR_CONNECTION_REFUSED : Connexion refusée
- ERR_TIMEOUT : Timeout de la requête
## Configuration
@ -141,12 +100,6 @@ En cas d'erreur, l'application bascule automatiquement vers des données de dém
```env
VITE_API_URL=http://localhost:8000
VITE_BACKEND_MODE=simple
VITE_CADASTRE_API_URL=https://api.cadastre.gouv.fr
VITE_GEORISQUES_API_URL=https://www.georisques.gouv.fr/api
VITE_GEOFONCIER_API_URL=https://api.geofoncier.fr
VITE_BODACC_API_URL=https://api.bodacc.fr
VITE_INFOGREFFE_API_URL=https://api.infogreffe.fr
```
### Configuration Axios
@ -154,10 +107,7 @@ VITE_INFOGREFFE_API_URL=https://api.infogreffe.fr
```typescript
const apiClient = axios.create({
baseURL: BASE_URL,
timeout: 60000, // 60 secondes
headers: {
'Content-Type': 'application/json'
}
timeout: 60000
})
```
@ -170,93 +120,6 @@ Authorization: Bearer {token}
Content-Type: application/json
```
### Gestion des tokens
- **Refresh automatique** : Renouvellement des tokens expirés
- **Intercepteurs** : Ajout automatique des headers d'authentification
- **Logout automatique** : Déconnexion en cas d'erreur 401
## Rate Limiting
### Limites par défaut
- **100 requêtes/minute** par utilisateur
- **1000 requêtes/heure** par utilisateur
- **Backoff exponentiel** en cas de dépassement
### Headers de réponse
```http
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1642248000
```
## Monitoring et logs
### Métriques collectées
- **Temps de réponse** : Latence des requêtes
- **Taux d'erreur** : Pourcentage d'échecs
- **Utilisation** : Nombre de requêtes par endpoint
### Logs
- **Requêtes** : Log de toutes les requêtes API
- **Erreurs** : Log détaillé des erreurs
- **Performance** : Métriques de performance
## Tests
### Tests d'intégration
```typescript
// Test d'upload de document
test('should upload document successfully', async () => {
const file = new File(['content'], 'test.pdf', { type: 'application/pdf' })
const result = await documentApi.upload(file)
expect(result.id).toBeDefined()
expect(result.status).toBe('completed')
})
```
### Tests de fallback
```typescript
// Test du mode démonstration
test('should return demo data on API error', async () => {
// Mock de l'erreur API
mockAxios.onPost('/api/documents/upload').reply(500)
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')
})
```
## Sécurité
### Validation des données
- **Sanitization** : Nettoyage des entrées utilisateur
- **Validation** : Vérification des types et formats
- **Escape** : Protection contre les injections
### CORS
```typescript
// Configuration CORS
const corsOptions = {
origin: ['http://localhost:3000', 'https://app.4nkweb.com'],
credentials: true,
optionsSuccessStatus: 200
}
```
### HTTPS
- **Redirection automatique** : HTTP vers HTTPS en production
- **HSTS** : HTTP Strict Transport Security
- **Certificats SSL** : Certificats valides et à jour
- Limites gérées par le backend

View File

@ -4,18 +4,18 @@
Ce guide couvre le déploiement de l'application 4NK IA Front Notarial dans différents environnements.
## Notes de version 0.1.1
## Notes de version 0.1.2
### Changements principaux
- Qualité: lint Markdown stabilisé (guides/rapports ignorés), ESLint corrigé et `coverage/` exclu
- TypeScript/Build: corrections dans `FilePreview`, `api`, et vues (typage couleurs MUI)
- Tests: exécution Vitest OK, build de production OK
- 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
- Aucun changement de configuration serveur requis
- Un simple rebuild et synchronisation de `dist/` suffisent
- Variables `.env` front simplifiées (uniquement `VITE_API_URL`)
- Build requis avec Node.js ≥ 20.19
### Étapes recommandées
@ -39,8 +39,9 @@ sudo systemctl reload nginx
### Environnement de développement
- **Node.js** : >= 22.12.0 (recommandé) ou >= 20.19.0
- **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
@ -58,11 +59,6 @@ sudo systemctl reload nginx
```env
NODE_ENV=development
VITE_API_URL=http://localhost:8000
VITE_CADASTRE_API_URL=https://api.cadastre.gouv.fr
VITE_GEORISQUES_API_URL=https://www.georisques.gouv.fr/api
VITE_GEOFONCIER_API_URL=https://api.geofoncier.fr
VITE_BODACC_API_URL=https://api.bodacc.fr
VITE_INFOGREFFE_API_URL=https://api.infogreffe.fr
```
#### Staging (.env.staging)
@ -70,11 +66,6 @@ VITE_INFOGREFFE_API_URL=https://api.infogreffe.fr
```env
NODE_ENV=staging
VITE_API_URL=https://api-staging.4nkweb.com
VITE_CADASTRE_API_URL=https://api.cadastre.gouv.fr
VITE_GEORISQUES_API_URL=https://www.georisques.gouv.fr/api
VITE_GEOFONCIER_API_URL=https://api.geofoncier.fr
VITE_BODACC_API_URL=https://api.bodacc.fr
VITE_INFOGREFFE_API_URL=https://api.infogreffe.fr
```
#### Production (.env.production)
@ -82,11 +73,6 @@ VITE_INFOGREFFE_API_URL=https://api.infogreffe.fr
```env
NODE_ENV=production
VITE_API_URL=https://api.4nkweb.com
VITE_CADASTRE_API_URL=https://api.cadastre.gouv.fr
VITE_GEORISQUES_API_URL=https://www.georisques.gouv.fr/api
VITE_GEOFONCIER_API_URL=https://api.geofoncier.fr
VITE_BODACC_API_URL=https://api.bodacc.fr
VITE_INFOGREFFE_API_URL=https://api.infogreffe.fr
```
## Build de production
@ -127,6 +113,26 @@ dist/
## 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

18
nginx.conf Normal file
View File

@ -0,0 +1,18 @@
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# Cache des assets
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# SPA fallback
location / {
try_files $uri /index.html;
}
}

24
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "4nk-ia-front4nk",
"version": "0.1.1",
"version": "0.1.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "4nk-ia-front4nk",
"version": "0.1.1",
"version": "0.1.2",
"dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
@ -17,7 +17,6 @@
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react-dropzone": "^14.3.8",
"react-pdf-js": "^5.1.0",
"react-redux": "^9.2.0",
"react-router-dom": "^7.8.2"
},
@ -385,12 +384,6 @@
"node": ">=18"
}
},
"node_modules/@bundled-es-modules/pdfjs-dist": {
"version": "2.1.266-rc",
"resolved": "https://registry.npmjs.org/@bundled-es-modules/pdfjs-dist/-/pdfjs-dist-2.1.266-rc.tgz",
"integrity": "sha512-idli/i9GA7hUW8uRIs2Y48m5QHKRv3PaVxlM1VEoOuzWoF2qLdtOepOpIy3BTblakDNt2f/gINPN7X/v9DBKoQ==",
"license": "Apache-2.0"
},
"node_modules/@csstools/color-helpers": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz",
@ -6002,19 +5995,6 @@
"integrity": "sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==",
"license": "MIT"
},
"node_modules/react-pdf-js": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/react-pdf-js/-/react-pdf-js-5.1.0.tgz",
"integrity": "sha512-l/norbM4BocUJcD0o46b5U4XWTZI1FN1+wfhosPKGy0cJ3T7Ck7GGfr3KXsH5ljc8lyifZPMAm6Rvsbe8OzBbQ==",
"deprecated": "Please move to our namespaced package at @mikecousins/react-pdf",
"license": "MIT",
"dependencies": {
"@bundled-es-modules/pdfjs-dist": "2.1.266-rc"
},
"peerDependencies": {
"react": ">=16"
}
},
"node_modules/react-redux": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",

View File

@ -1,10 +1,12 @@
{
"name": "4nk-ia-front4nk",
"private": true,
"version": "0.1.1",
"version": "0.1.3",
"type": "module",
"scripts": {
"predev": "node scripts/check-node.mjs",
"dev": "vite",
"prebuild": "node scripts/check-node.mjs",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview",
@ -14,6 +16,10 @@
"test": "vitest run --coverage",
"test:ui": "vitest"
},
"engines": {
"node": ">=20.19.0 <23",
"npm": ">=10"
},
"dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
@ -24,7 +30,6 @@
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react-dropzone": "^14.3.8",
"react-pdf-js": "^5.1.0",
"react-redux": "^9.2.0",
"react-router-dom": "^7.8.2"
},

24
scripts/check-node.mjs Normal file
View File

@ -0,0 +1,24 @@
#!/usr/bin/env node
const semver = (v) => v.split('.').map((n) => parseInt(n, 10));
const compare = (a, b) => {
for (let i = 0; i < Math.max(a.length, b.length); i += 1) {
const ai = a[i] || 0;
const bi = b[i] || 0;
if (ai > bi) return 1;
if (ai < bi) return -1;
}
return 0;
};
const current = semver(process.versions.node);
const min = semver('20.19.0');
if (compare(current, min) < 0) {
console.error(`❌ Version de Node trop ancienne: ${process.versions.node}. Requise: >= 20.19.0`);
console.error('➡️ Utilisez nvm: nvm use 20 (ou installez: nvm install 20)');
process.exit(1);
}
console.log(`✅ Node ${process.versions.node} OK (>= 20.19.0)`);

13
scripts/docker-build.sh Executable file
View File

@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -euo pipefail
IMAGE_REGISTRY=${IMAGE_REGISTRY:-git.4nkweb.com}
IMAGE_NAMESPACE=${IMAGE_NAMESPACE:-4nk}
IMAGE_NAME=${IMAGE_NAME:-4nk-ia-front}
IMAGE_TAG=${IMAGE_TAG:-$(git rev-parse --short HEAD)}
FULL_IMAGE_REF="$IMAGE_REGISTRY/$IMAGE_NAMESPACE/$IMAGE_NAME:$IMAGE_TAG"
echo "Building image: $FULL_IMAGE_REF"
docker build -t "$FULL_IMAGE_REF" .
echo "Built $FULL_IMAGE_REF"

13
scripts/docker-push.sh Executable file
View File

@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -euo pipefail
IMAGE_REGISTRY=${IMAGE_REGISTRY:-git.4nkweb.com}
IMAGE_NAMESPACE=${IMAGE_NAMESPACE:-4nk}
IMAGE_NAME=${IMAGE_NAME:-4nk-ia-front}
IMAGE_TAG=${IMAGE_TAG:-$(git rev-parse --short HEAD)}
FULL_IMAGE_REF="$IMAGE_REGISTRY/$IMAGE_NAMESPACE/$IMAGE_NAME:$IMAGE_TAG"
echo "Pushing image: $FULL_IMAGE_REF"
docker push "$FULL_IMAGE_REF"
echo "Pushed $FULL_IMAGE_REF"

View File

@ -2,7 +2,6 @@ import axios from 'axios'
import type { Document, ExtractionResult, AnalysisResult, ContextResult, ConseilResult } from '../types'
const BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000'
const BACKEND_MODE = (import.meta.env.VITE_BACKEND_MODE || 'simple').toLowerCase() as 'simple' | 'complete'
export const apiClient = axios.create({
baseURL: BASE_URL,
@ -13,27 +12,7 @@ export const apiClient = axios.create({
apiClient.interceptors.response.use(
(response) => response,
(error) => {
console.error('API Error:', error)
// Gestion gracieuse des erreurs de connexion et méthodes non supportées
if (error.code === 'ERR_NETWORK' ||
error.code === 'ERR_CONNECTION_REFUSED' ||
error.response?.status === 405 ||
error.response?.status === 404) {
console.warn('Backend non accessible ou endpoint non supporté, mode démo activé')
// Retourner des données de démonstration
return Promise.resolve({
data: {
id: 'demo-' + Date.now(),
name: 'Document de démonstration',
type: 'pdf',
size: 1024,
uploadDate: new Date(),
status: 'completed'
}
})
}
// Laisser remonter les erreurs au consommateur
return Promise.reject(error)
}
)
@ -42,271 +21,97 @@ apiClient.interceptors.response.use(
export const documentApi = {
// Téléversement de document
upload: async (file: File): Promise<Document> => {
try {
const formData = new FormData()
formData.append('file', file)
const { data } = await apiClient.post('/api/notary/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
})
const formData = new FormData()
formData.append('file', file)
const { data } = await apiClient.post('/api/notary/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
})
// L'API retourne {message, document_id, status}
// On doit mapper vers le format Document attendu
const fileUrl = URL.createObjectURL(file)
return {
id: data.document_id || data.id || 'upload-' + Date.now(),
name: file.name,
mimeType: data.mime_type || data.mimeType || file.type || 'application/pdf',
functionalType: data.functional_type || data.functionalType || undefined,
size: file.size,
uploadDate: new Date(),
status: 'completed',
previewUrl: fileUrl
}
} catch (error) {
console.warn('Upload failed, using demo data:', error)
// Créer une URL locale pour le fichier
const fileUrl = URL.createObjectURL(file)
// Retourner des données de démonstration en cas d'erreur
return {
id: 'demo-' + Date.now(),
name: file.name,
mimeType: file.type || 'application/pdf',
functionalType: undefined,
size: file.size,
uploadDate: new Date(),
status: 'completed',
previewUrl: fileUrl
}
// L'API retourne {message, document_id, status}
// On doit mapper vers le format Document attendu
const fileUrl = URL.createObjectURL(file)
return {
id: data.document_id || data.id || 'upload-' + Date.now(),
name: file.name,
mimeType: data.mime_type || data.mimeType || file.type || 'application/pdf',
functionalType: data.functional_type || data.functionalType || undefined,
size: file.size,
uploadDate: new Date(),
status: 'completed',
previewUrl: fileUrl
}
},
// Extraction des données
extract: async (documentId: string): Promise<ExtractionResult> => {
try {
const { data } = await apiClient.get(`/api/notary/documents/${documentId}`)
const { data } = await apiClient.get(`/api/notary/documents/${documentId}`)
// Mapper les données de l'API vers le format ExtractionResult
const results = data.results || {}
return {
documentId,
text: results.ocr_text || "Texte extrait du document...",
language: "fr",
documentType: results.document_type || "Document",
identities: results.entities?.persons?.map((name: string, index: number) => ({
id: `person-${index}`,
type: "person" as const,
firstName: name.split(' ')[0] || name,
lastName: name.split(' ').slice(1).join(' ') || "",
birthDate: "",
nationality: "Française",
confidence: 0.9
})) || [],
addresses: results.entities?.addresses?.map((address: string) => ({
street: address,
city: "Paris",
postalCode: "75001",
country: "France"
})) || [],
properties: results.entities?.properties?.map((_propertyName: string, index: number) => ({
id: `prop-${index}`,
type: "apartment" as const,
address: {
street: "123 Rue de la Paix",
city: "Paris",
postalCode: "75001",
country: "France"
},
surface: 75,
cadastralReference: "1234567890AB",
value: 250000
})) || [],
contracts: [{
id: "contract-1",
type: "sale" as const,
// Mapper les données de l'API vers le format ExtractionResult
const results = data.results || {}
return {
documentId,
text: results.ocr_text || 'Texte extrait du document...',
language: 'fr',
documentType: results.document_type || 'Document',
identities: results.entities?.persons?.map((name: string, index: number) => ({
id: `person-${index}`,
type: 'person' as const,
firstName: name.split(' ')[0] || name,
lastName: name.split(' ').slice(1).join(' ') || '',
birthDate: '',
nationality: 'Française',
confidence: 0.9,
})) || [],
addresses: results.entities?.addresses?.map((address: string) => ({
street: address,
city: 'Paris',
postalCode: '75001',
country: 'France',
})) || [],
properties: results.entities?.properties?.map((_propertyName: string, index: number) => ({
id: `prop-${index}`,
type: 'apartment' as const,
address: {
street: '123 Rue de la Paix',
city: 'Paris',
postalCode: '75001',
country: 'France',
},
surface: 75,
cadastralReference: '1234567890AB',
value: 250000,
})) || [],
contracts: [
{
id: 'contract-1',
type: 'sale' as const,
parties: [],
amount: 250000,
date: "2024-01-15",
clauses: ["Clause de garantie", "Clause de condition suspensive"]
}],
signatures: results.entities?.persons || [],
confidence: results.verification_score || 0.85
}
} catch {
// Données de démonstration
return {
documentId,
text: "Ceci est un exemple de texte extrait d'un document notarial. Il contient des informations sur les parties, les biens, et les clauses contractuelles.",
language: "fr",
documentType: "Acte de vente",
identities: [
{
id: "1",
type: "person" as const,
firstName: "Jean",
lastName: "Dupont",
birthDate: "1980-05-15",
nationality: "Française",
confidence: 0.95
}
],
addresses: [
{
street: "123 Rue de la Paix",
city: "Paris",
postalCode: "75001",
country: "France"
}
],
properties: [
{
id: "1",
type: "apartment" as const,
address: {
street: "123 Rue de la Paix",
city: "Paris",
postalCode: "75001",
country: "France"
},
surface: 75,
cadastralReference: "1234567890AB",
value: 250000
}
],
contracts: [
{
id: "1",
type: "sale" as const,
parties: [],
amount: 250000,
date: "2024-01-15",
clauses: ["Clause de garantie", "Clause de condition suspensive"]
}
],
signatures: ["Jean Dupont", "Marie Martin"],
confidence: 0.92
}
date: '2024-01-15',
clauses: ['Clause de garantie', 'Clause de condition suspensive'],
},
],
signatures: results.entities?.persons || [],
confidence: results.verification_score || 0.85,
}
},
// Analyse du document
analyze: async (documentId: string): Promise<AnalysisResult> => {
try {
if (BACKEND_MODE === 'complete') {
const { data } = await apiClient.get<AnalysisResult>(`/api/documents/${documentId}/analyze`)
return data
}
// Mode simple: pas d'endpoint d'analyse dédié -> utiliser le détail et synthétiser
const { data } = await apiClient.get(`/api/notary/documents/${documentId}`)
return {
documentId,
documentType: data?.results?.document_type || 'Document',
isCNI: (data?.results?.document_type || '').toLowerCase().includes('cni'),
credibilityScore: data?.results?.verification_score ?? 0.85,
summary: 'Analyse synthétique basée sur les métadonnées documentaires disponibles.',
recommendations: [
"Vérifier l'identité des parties",
"Contrôler la validité des documents cadastraux",
"S'assurer de la conformité des clauses contractuelles",
],
}
} catch {
// Données de démonstration
return {
documentId,
documentType: "Acte de vente",
isCNI: false,
credibilityScore: 0.88,
summary: "Document analysé avec succès. Toutes les informations semblent cohérentes et le document présente un bon niveau de fiabilité.",
recommendations: [
"Vérifier l'identité des parties auprès des autorités compétentes",
"Contrôler la validité des documents cadastraux",
"S'assurer de la conformité des clauses contractuelles"
]
}
}
const { data } = await apiClient.get<AnalysisResult>(`/api/documents/${documentId}/analyze`)
return data
},
// Données contextuelles
getContext: async (documentId: string): Promise<ContextResult> => {
try {
if (BACKEND_MODE === 'complete') {
const { data } = await apiClient.get<ContextResult>(`/api/documents/${documentId}/context`)
return data
}
// Mode simple: pas d'endpoint context -> démo
return {
documentId,
cadastreData: { status: "disponible", reference: "1234567890AB" },
georisquesData: { status: "aucun risque identifié" },
geofoncierData: { status: "données disponibles" },
bodaccData: { status: "aucune procédure en cours" },
infogreffeData: { status: "entreprise en règle" },
lastUpdated: new Date()
}
} catch {
// Données de démonstration
return {
documentId,
cadastreData: { status: "disponible", reference: "1234567890AB" },
georisquesData: { status: "aucun risque identifié" },
geofoncierData: { status: "données disponibles" },
bodaccData: { status: "aucune procédure en cours" },
infogreffeData: { status: "entreprise en règle" },
lastUpdated: new Date()
}
}
const { data } = await apiClient.get<ContextResult>(`/api/documents/${documentId}/context`)
return data
},
// Conseil LLM
getConseil: async (documentId: string): Promise<ConseilResult> => {
try {
if (BACKEND_MODE === 'complete') {
const { data } = await apiClient.get<ConseilResult>(`/api/documents/${documentId}/conseil`)
return data
}
// Mode simple: pas d'endpoint conseil -> démo
return {
documentId,
analysis: "Ce document présente toutes les caractéristiques d'un acte notarial standard. Les informations sont cohérentes et les parties semblent légitimes. Aucun élément suspect n'a été détecté.",
recommendations: [
"Procéder à la vérification d'identité des parties",
"Contrôler la validité des documents fournis",
"S'assurer de la conformité réglementaire"
],
risks: [
"Risque faible : Vérification d'identité recommandée",
"Risque moyen : Contrôle cadastral nécessaire"
],
nextSteps: [
"Collecter les pièces d'identité des parties",
"Vérifier les documents cadastraux",
"Préparer l'acte final"
],
generatedAt: new Date()
}
} catch {
// Données de démonstration
return {
documentId,
analysis: "Ce document présente toutes les caractéristiques d'un acte notarial standard. Les informations sont cohérentes et les parties semblent légitimes. Aucun élément suspect n'a été détecté.",
recommendations: [
"Procéder à la vérification d'identité des parties",
"Contrôler la validité des documents fournis",
"S'assurer de la conformité réglementaire"
],
risks: [
"Risque faible : Vérification d'identité recommandée",
"Risque moyen : Contrôle cadastral nécessaire"
],
nextSteps: [
"Collecter les pièces d'identité des parties",
"Vérifier les documents cadastraux",
"Préparer l'acte final"
],
generatedAt: new Date()
}
}
const { data } = await apiClient.get<ConseilResult>(`/api/documents/${documentId}/conseil`)
return data
},
// Détection du type de document
@ -322,43 +127,33 @@ export const documentApi = {
// Services API pour les données externes
export const externalApi = {
// Cadastre
// Cadastre via backend
cadastre: async (address: string) => {
const cadastreUrl = import.meta.env.VITE_CADASTRE_API_URL
if (!cadastreUrl) throw new Error('Cadastre API URL not configured')
const { data } = await axios.get(`${cadastreUrl}/parcelle`, { params: { q: address } })
const { data } = await apiClient.get('/api/context/cadastre', { params: { q: address } })
return data
},
// Géorisques
// Géorisques via backend
georisques: async (coordinates: { lat: number; lng: number }) => {
const georisquesUrl = import.meta.env.VITE_GEORISQUES_API_URL
if (!georisquesUrl) throw new Error('Géorisques API URL not configured')
const { data } = await axios.get(`${georisquesUrl}/risques`, { params: coordinates })
const { data } = await apiClient.get('/api/context/georisques', { params: coordinates })
return data
},
// Géofoncier
// Géofoncier via backend
geofoncier: async (address: string) => {
const geofoncierUrl = import.meta.env.VITE_GEOFONCIER_API_URL
if (!geofoncierUrl) throw new Error('Géofoncier API URL not configured')
const { data } = await axios.get(`${geofoncierUrl}/dossiers`, { params: { address } })
const { data } = await apiClient.get('/api/context/geofoncier', { params: { address } })
return data
},
// BODACC
// BODACC via backend
bodacc: async (companyName: string) => {
const bodaccUrl = import.meta.env.VITE_BODACC_API_URL
if (!bodaccUrl) throw new Error('BODACC API URL not configured')
const { data } = await axios.get(`${bodaccUrl}/annonces`, { params: { q: companyName } })
const { data } = await apiClient.get('/api/context/bodacc', { params: { q: companyName } })
return data
},
// Infogreffe
// Infogreffe via backend
infogreffe: async (siren: string) => {
const infogreffeUrl = import.meta.env.VITE_INFOGREFFE_API_URL
if (!infogreffeUrl) throw new Error('Infogreffe API URL not configured')
const { data } = await axios.get(`${infogreffeUrl}/infogreffe/rcs/extrait`, { params: { siren } })
const { data } = await apiClient.get('/api/context/infogreffe', { params: { siren } })
return data
},
}

View File

@ -119,22 +119,23 @@ export default function ExtractionView() {
? `${identity.firstName} ${identity.lastName}`
: identity.companyName
}
secondaryTypographyProps={{ component: 'span' }}
secondary={
<Box>
<Typography variant="caption" display="block">
<Box component="span">
<Typography variant="caption" display="block" component="span">
Type: {identity.type}
</Typography>
{identity.birthDate && (
<Typography variant="caption" display="block">
<Typography variant="caption" display="block" component="span">
Naissance: {identity.birthDate}
</Typography>
)}
{identity.nationality && (
<Typography variant="caption" display="block">
<Typography variant="caption" display="block" component="span">
Nationalité: {identity.nationality}
</Typography>
)}
<Typography variant="caption" display="block">
<Typography variant="caption" display="block" component="span">
Confiance: {(identity.confidence * 100).toFixed(1)}%
</Typography>
</Box>
@ -184,18 +185,19 @@ export default function ExtractionView() {
<ListItem key={index}>
<ListItemText
primary={`${property.type} - ${property.address.city}`}
secondaryTypographyProps={{ component: 'span' }}
secondary={
<Box>
<Typography variant="caption" display="block">
<Box component="span">
<Typography variant="caption" display="block" component="span">
{property.address.street}
</Typography>
{property.surface && (
<Typography variant="caption" display="block">
<Typography variant="caption" display="block" component="span">
Surface: {property.surface} m²
</Typography>
)}
{property.cadastralReference && (
<Typography variant="caption" display="block">
<Typography variant="caption" display="block" component="span">
Cadastre: {property.cadastralReference}
</Typography>
)}
@ -222,17 +224,18 @@ export default function ExtractionView() {
<ListItem key={index}>
<ListItemText
primary={`${contract.type} - ${contract.amount ? `${contract.amount}` : 'Montant non spécifié'}`}
secondaryTypographyProps={{ component: 'span' }}
secondary={
<Box>
<Typography variant="caption" display="block">
<Box component="span">
<Typography variant="caption" display="block" component="span">
Parties: {contract.parties.length}
</Typography>
{contract.date && (
<Typography variant="caption" display="block">
<Typography variant="caption" display="block" component="span">
Date: {contract.date}
</Typography>
)}
<Typography variant="caption" display="block">
<Typography variant="caption" display="block" component="span">
Clauses: {contract.clauses.length}
</Typography>
</Box>