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 # 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 ## 0.1.1 - Maintenance lint/build et corrections
### ✅ Qualité et lint ### ✅ 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 ## 🚀 Technologies
- **Frontend** : React 18 + TypeScript - **Frontend** : React 19 + TypeScript
- **Build** : Vite 7 - **Build** : Vite 7
- **UI** : Material-UI (MUI) v6 - **UI** : Material-UI (MUI) v7
- **State** : Redux Toolkit + React Redux - **State** : Redux Toolkit + React Redux
- **Routing** : React Router v6 - **Routing** : React Router v7
- **HTTP** : Axios - **HTTP** : Axios
- **Tests** : Vitest + Testing Library - **Tests** : Vitest + Testing Library
- **Linting** : ESLint + Prettier + markdownlint - **Linting** : ESLint + Prettier + markdownlint
@ -51,13 +51,22 @@ Application front-end pour l'analyse intelligente de documents notariaux avec IA
### Prérequis ### 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 - 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 ### Installation des dépendances
```bash ```bash
npm install npm ci
``` ```
### Configuration des environnements ### Configuration des environnements
@ -83,15 +92,18 @@ npm run preview # Prévisualisation du build
# Qualité de code # Qualité de code
npm run lint # Vérification ESLint npm run lint # Vérification ESLint
npm run lint:fix # Correction automatique ESLint
npm run format # Vérification Prettier npm run format # Vérification Prettier
npm run format:fix # Formatage automatique npm run format:fix # Formatage automatique
npm run mdlint # Vérification Markdown npm run mdlint # Vérification Markdown
# Tests # Tests
npm run test # Tests unitaires npm run test # Tests unitaires avec couverture
npm run test:ui # Tests avec interface 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 ## 🏗️ Architecture
@ -147,14 +159,10 @@ src/
- **Breadcrumbs** : Indication de la position actuelle - **Breadcrumbs** : Indication de la position actuelle
- **Actions contextuelles** : Boutons d'action selon la vue - **Actions contextuelles** : Boutons d'action selon la vue
## 🔧 Mode démonstration ## 🔧 Intégration backend
L'application fonctionne parfaitement en mode démonstration : 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.
- **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
## 🧪 Tests ## 🧪 Tests
@ -188,6 +196,19 @@ npm run test:coverage # Rapport de couverture
npm run build 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 ### Variables d'environnement
Configurer les URLs des APIs externes selon l'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 **Version actuelle** : 0.1.3
**Dernière mise à jour** : Janvier 2024 **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"?> <?xml version="1.0" encoding="UTF-8"?>
<coverage generated="1757583600773" clover="3.2.0"> <coverage generated="1757595469311" clover="3.2.0">
<project timestamp="1757583600773" name="All files"> <project timestamp="1757595469311" 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"/> <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="4NK_IA_front"> <package name="scripts">
<metrics statements="57" coveredstatements="0" conditionals="1" coveredconditionals="0" methods="1" coveredmethods="0"/> <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"/> <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="1" count="0" type="cond" truecount="0" falsecount="1"/>
<line num="3" count="0" type="stmt"/> <line num="3" count="0" type="stmt"/>
@ -65,7 +65,7 @@
<line num="66" count="0" type="stmt"/> <line num="66" count="0" type="stmt"/>
</file> </file>
</package> </package>
<package name="4NK_IA_front.src"> <package name="src">
<metrics statements="24" coveredstatements="0" conditionals="2" coveredconditionals="0" methods="2" coveredmethods="0"/> <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"> <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"/> <metrics statements="5" coveredstatements="0" conditionals="1" coveredconditionals="0" methods="1" coveredmethods="0"/>
@ -98,7 +98,7 @@
<line num="20" count="0" type="stmt"/> <line num="20" count="0" type="stmt"/>
</file> </file>
</package> </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"/> <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"> <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"/> <metrics statements="171" coveredstatements="0" conditionals="1" coveredconditionals="0" methods="1" coveredmethods="0"/>
@ -337,7 +337,7 @@
<line num="41" count="0" type="stmt"/> <line num="41" count="0" type="stmt"/>
</file> </file>
</package> </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"/> <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"> <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"/> <metrics statements="23" coveredstatements="0" conditionals="1" coveredconditionals="0" methods="1" coveredmethods="0"/>
@ -366,10 +366,10 @@
<line num="28" count="0" type="stmt"/> <line num="28" count="0" type="stmt"/>
</file> </file>
</package> </package>
<package name="4NK_IA_front.src.services"> <package name="src.services">
<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"/>
<file name="api.ts" path="/home/desk/code/4NK_IA_front/src/services/api.ts"> <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="1" count="0" type="cond" truecount="0" falsecount="1"/>
<line num="4" count="0" type="stmt"/> <line num="4" count="0" type="stmt"/>
<line num="6" count="0" type="stmt"/> <line num="6" count="0" type="stmt"/>
@ -379,34 +379,33 @@
<line num="12" count="0" type="stmt"/> <line num="12" count="0" type="stmt"/>
<line num="13" count="0" type="stmt"/> <line num="13" count="0" type="stmt"/>
<line num="14" 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="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="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="24" count="0" type="stmt"/>
<line num="25" count="0" type="stmt"/> <line num="25" count="0" type="stmt"/>
<line num="26" count="0" type="stmt"/> <line num="26" count="0" type="stmt"/>
<line num="27" count="0" type="stmt"/> <line num="27" count="0" type="stmt"/>
<line num="28" 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="32" count="0" type="stmt"/>
<line num="33" count="0" type="stmt"/> <line num="33" count="0" type="stmt"/>
<line num="34" 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="36" count="0" type="stmt"/>
<line num="37" count="0" type="stmt"/> <line num="37" count="0" type="stmt"/>
<line num="38" 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="41" count="0" type="stmt"/>
<line num="42" count="0" type="stmt"/>
<line num="43" 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="46" count="0" type="stmt"/>
<line num="47" count="0" type="stmt"/> <line num="47" count="0" type="stmt"/>
<line num="48" count="0" type="stmt"/> <line num="50" count="0" type="stmt"/>
<line num="49" 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="53" count="0" type="stmt"/>
<line num="54" count="0" type="stmt"/> <line num="54" count="0" type="stmt"/>
<line num="55" count="0" type="stmt"/> <line num="55" count="0" type="stmt"/>
@ -419,7 +418,10 @@
<line num="62" count="0" type="stmt"/> <line num="62" count="0" type="stmt"/>
<line num="63" count="0" type="stmt"/> <line num="63" count="0" type="stmt"/>
<line num="64" 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="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="69" count="0" type="stmt"/>
<line num="70" count="0" type="stmt"/> <line num="70" count="0" type="stmt"/>
<line num="71" count="0" type="stmt"/> <line num="71" count="0" type="stmt"/>
@ -431,9 +433,13 @@
<line num="77" count="0" type="stmt"/> <line num="77" count="0" type="stmt"/>
<line num="78" count="0" type="stmt"/> <line num="78" count="0" type="stmt"/>
<line num="79" 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="82" count="0" type="stmt"/>
<line num="83" count="0" type="stmt"/> <line num="83" count="0" type="stmt"/>
<line num="84" 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="87" count="0" type="stmt"/>
<line num="88" count="0" type="stmt"/> <line num="88" count="0" type="stmt"/>
<line num="89" count="0" type="stmt"/> <line num="89" count="0" type="stmt"/>
@ -445,26 +451,18 @@
<line num="95" count="0" type="stmt"/> <line num="95" count="0" type="stmt"/>
<line num="96" count="0" type="stmt"/> <line num="96" count="0" type="stmt"/>
<line num="97" 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="100" count="0" type="stmt"/>
<line num="101" count="0" type="stmt"/> <line num="101" count="0" type="stmt"/>
<line num="102" count="0" type="stmt"/> <line num="102" count="0" type="stmt"/>
<line num="103" 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="106" count="0" type="stmt"/>
<line num="107" count="0" type="stmt"/> <line num="107" count="0" type="stmt"/>
<line num="108" count="0" type="stmt"/> <line num="108" count="0" type="stmt"/>
<line num="109" 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="112" count="0" type="stmt"/>
<line num="113" count="0" type="stmt"/> <line num="113" count="0" type="stmt"/>
<line num="114" count="0" type="stmt"/> <line num="114" count="0" type="stmt"/>
<line num="115" 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="118" count="0" type="stmt"/>
<line num="119" count="0" type="stmt"/> <line num="119" count="0" type="stmt"/>
<line num="120" count="0" type="stmt"/> <line num="120" count="0" type="stmt"/>
@ -474,171 +472,31 @@
<line num="124" count="0" type="stmt"/> <line num="124" count="0" type="stmt"/>
<line num="125" count="0" type="stmt"/> <line num="125" count="0" type="stmt"/>
<line num="126" 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="129" count="0" type="stmt"/>
<line num="130" count="0" type="stmt"/>
<line num="131" count="0" type="stmt"/> <line num="131" count="0" type="stmt"/>
<line num="132" 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="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="137" count="0" type="stmt"/>
<line num="138" count="0" type="stmt"/> <line num="138" count="0" type="stmt"/>
<line num="139" count="0" type="stmt"/> <line num="139" count="0" type="stmt"/>
<line num="140" 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="143" count="0" type="stmt"/>
<line num="144" count="0" type="stmt"/> <line num="144" count="0" type="stmt"/>
<line num="145" count="0" type="stmt"/> <line num="145" count="0" type="stmt"/>
<line num="146" 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="149" count="0" type="stmt"/>
<line num="150" count="0" type="stmt"/> <line num="150" count="0" type="stmt"/>
<line num="151" count="0" type="stmt"/> <line num="151" count="0" type="stmt"/>
<line num="152" 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="155" count="0" type="stmt"/>
<line num="156" count="0" type="stmt"/> <line num="156" count="0" type="stmt"/>
<line num="157" count="0" type="stmt"/> <line num="157" count="0" type="stmt"/>
<line num="158" count="0" type="stmt"/> <line num="158" count="0" type="stmt"/>
<line num="159" 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> </file>
</package> </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"/> <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"> <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"/> <metrics statements="10" coveredstatements="0" conditionals="1" coveredconditionals="0" methods="1" coveredmethods="0"/>
@ -764,7 +622,7 @@
<line num="23" count="0" type="stmt"/> <line num="23" count="0" type="stmt"/>
</file> </file>
</package> </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"/> <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"> <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"/> <metrics statements="64" coveredstatements="0" conditionals="1" coveredconditionals="0" methods="1" coveredmethods="0"/>
@ -834,13 +692,13 @@
<line num="65" count="0" type="stmt"/> <line num="65" count="0" type="stmt"/>
</file> </file>
</package> </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"/> <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"> <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"/> <metrics statements="0" coveredstatements="0" conditionals="1" coveredconditionals="1" methods="1" coveredmethods="1"/>
</file> </file>
</package> </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"/> <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"> <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"/> <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'> <div class='fl pad1y space-right2'>
<span class="strong">0% </span> <span class="strong">0% </span>
<span class="quiet">Statements</span> <span class="quiet">Statements</span>
<span class='fraction'>0/1753</span> <span class='fraction'>0/1611</span>
</div> </div>
@ -46,7 +46,7 @@
<div class='fl pad1y space-right2'> <div class='fl pad1y space-right2'>
<span class="strong">0% </span> <span class="strong">0% </span>
<span class="quiet">Lines</span> <span class="quiet">Lines</span>
<span class='fraction'>0/1753</span> <span class='fraction'>0/1611</span>
</div> </div>
@ -79,7 +79,7 @@
</tr> </tr>
</thead> </thead>
<tbody><tr> <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"> <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> <div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div>
</td> </td>
@ -94,7 +94,7 @@
</tr> </tr>
<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"> <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> <div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div>
</td> </td>
@ -109,7 +109,7 @@
</tr> </tr>
<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"> <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> <div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div>
</td> </td>
@ -124,7 +124,7 @@
</tr> </tr>
<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"> <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> <div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div>
</td> </td>
@ -139,22 +139,22 @@
</tr> </tr>
<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"> <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> <div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div>
</td> </td>
<td data-value="0" class="pct low">0%</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="0" class="pct low">0%</td>
<td data-value="1" class="abs low">0/1</td> <td data-value="1" class="abs low">0/1</td>
<td data-value="0" class="pct low">0%</td> <td data-value="0" class="pct low">0%</td>
<td data-value="1" class="abs low">0/1</td> <td data-value="1" class="abs low">0/1</td>
<td data-value="0" class="pct low">0%</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>
<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"> <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> <div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div>
</td> </td>
@ -169,7 +169,7 @@
</tr> </tr>
<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"> <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> <div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div>
</td> </td>
@ -184,7 +184,7 @@
</tr> </tr>
<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"> <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> <div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div>
</td> </td>
@ -199,7 +199,7 @@
</tr> </tr>
<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"> <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> <div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div>
</td> </td>
@ -221,7 +221,7 @@
<div class='footer quiet pad2 space-top1 center small'> <div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> <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> </div>
<script src="prettify.js"></script> <script src="prettify.js"></script>
<script> <script>

View File

@ -3,7 +3,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<title>Code coverage report for 4NK_IA_front</title> <title>Code coverage report for scripts</title>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="stylesheet" href="../prettify.css" /> <link rel="stylesheet" href="../prettify.css" />
<link rel="stylesheet" href="../base.css" /> <link rel="stylesheet" href="../base.css" />
@ -19,7 +19,7 @@
<body> <body>
<div class='wrapper'> <div class='wrapper'>
<div class='pad1'> <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='clearfix'>
<div class='fl pad1y space-right2'> <div class='fl pad1y space-right2'>
@ -101,7 +101,7 @@
<div class='footer quiet pad2 space-top1 center small'> <div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> <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> </div>
<script src="../prettify.js"></script> <script src="../prettify.js"></script>
<script> <script>

View File

@ -3,7 +3,7 @@
<html lang="en"> <html lang="en">
<head> <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" /> <meta charset="utf-8" />
<link rel="stylesheet" href="../prettify.css" /> <link rel="stylesheet" href="../prettify.css" />
<link rel="stylesheet" href="../base.css" /> <link rel="stylesheet" href="../base.css" />
@ -19,7 +19,7 @@
<body> <body>
<div class='wrapper'> <div class='wrapper'>
<div class='pad1'> <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='clearfix'>
<div class='fl pad1y space-right2'> <div class='fl pad1y space-right2'>
@ -268,7 +268,7 @@
<div class='footer quiet pad2 space-top1 center small'> <div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> <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> </div>
<script src="../prettify.js"></script> <script src="../prettify.js"></script>
<script> <script>

View File

@ -3,15 +3,15 @@
<html lang="en"> <html lang="en">
<head> <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" /> <meta charset="utf-8" />
<link rel="stylesheet" href="../../prettify.css" /> <link rel="stylesheet" href="../prettify.css" />
<link rel="stylesheet" href="../../base.css" /> <link rel="stylesheet" href="../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" /> <link rel="shortcut icon" type="image/x-icon" href="../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'> <style type='text/css'>
.coverage-summary .sorter { .coverage-summary .sorter {
background-image: url(../../sort-arrow-sprite.png); background-image: url(../sort-arrow-sprite.png);
} }
</style> </style>
</head> </head>
@ -19,7 +19,7 @@
<body> <body>
<div class='wrapper'> <div class='wrapper'>
<div class='pad1'> <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='clearfix'>
<div class='fl pad1y space-right2'> <div class='fl pad1y space-right2'>
@ -88,16 +88,16 @@
<div class='footer quiet pad2 space-top1 center small'> <div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> <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> </div>
<script src="../../prettify.js"></script> <script src="../prettify.js"></script>
<script> <script>
window.onload = function () { window.onload = function () {
prettyPrint(); prettyPrint();
}; };
</script> </script>
<script src="../../sorter.js"></script> <script src="../sorter.js"></script>
<script src="../../block-navigation.js"></script> <script src="../block-navigation.js"></script>
</body> </body>
</html> </html>

View File

@ -3,15 +3,15 @@
<html lang="en"> <html lang="en">
<head> <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" /> <meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" /> <link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" /> <link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" /> <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'> <style type='text/css'>
.coverage-summary .sorter { .coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png); background-image: url(../../sort-arrow-sprite.png);
} }
</style> </style>
</head> </head>
@ -19,7 +19,7 @@
<body> <body>
<div class='wrapper'> <div class='wrapper'>
<div class='pad1'> <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='clearfix'>
<div class='fl pad1y space-right2'> <div class='fl pad1y space-right2'>
@ -575,14 +575,14 @@ interface FilePreviewProps {
&nbsp; &nbsp;
<span class="cstat-no" title="statement not covered" > const handleDownload = () =&gt; {</span> <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" > 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.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.download = document.name</span>
<span class="cstat-no" title="statement not covered" > link.click()</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>
<span class="cstat-no" title="statement not covered" > }</span> <span class="cstat-no" title="statement not covered" > }</span>
&nbsp; &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; &nbsp;
<span class="cstat-no" title="statement not covered" > if (!isPDF) {</span> <span class="cstat-no" title="statement not covered" > if (!isPDF) {</span>
<span class="cstat-no" title="statement not covered" > return (</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;/IconButton&gt;</span>
<span class="cstat-no" title="statement not covered" > &lt;/Box&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" > &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;/Alert&gt;</span>
<span class="cstat-no" title="statement not covered" > &lt;/Paper&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'> <div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> <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> </div>
<script src="../../../prettify.js"></script> <script src="../../prettify.js"></script>
<script> <script>
window.onload = function () { window.onload = function () {
prettyPrint(); prettyPrint();
}; };
</script> </script>
<script src="../../../sorter.js"></script> <script src="../../sorter.js"></script>
<script src="../../../block-navigation.js"></script> <script src="../../block-navigation.js"></script>
</body> </body>
</html> </html>

View File

@ -3,15 +3,15 @@
<html lang="en"> <html lang="en">
<head> <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" /> <meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" /> <link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" /> <link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" /> <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'> <style type='text/css'>
.coverage-summary .sorter { .coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png); background-image: url(../../sort-arrow-sprite.png);
} }
</style> </style>
</head> </head>
@ -19,7 +19,7 @@
<body> <body>
<div class='wrapper'> <div class='wrapper'>
<div class='pad1'> <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='clearfix'>
<div class='fl pad1y space-right2'> <div class='fl pad1y space-right2'>
@ -178,16 +178,16 @@ interface LayoutProps {
<div class='footer quiet pad2 space-top1 center small'> <div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> <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> </div>
<script src="../../../prettify.js"></script> <script src="../../prettify.js"></script>
<script> <script>
window.onload = function () { window.onload = function () {
prettyPrint(); prettyPrint();
}; };
</script> </script>
<script src="../../../sorter.js"></script> <script src="../../sorter.js"></script>
<script src="../../../block-navigation.js"></script> <script src="../../block-navigation.js"></script>
</body> </body>
</html> </html>

View File

@ -3,15 +3,15 @@
<html lang="en"> <html lang="en">
<head> <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" /> <meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" /> <link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" /> <link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" /> <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'> <style type='text/css'>
.coverage-summary .sorter { .coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png); background-image: url(../../sort-arrow-sprite.png);
} }
</style> </style>
</head> </head>
@ -19,7 +19,7 @@
<body> <body>
<div class='wrapper'> <div class='wrapper'>
<div class='pad1'> <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='clearfix'>
<div class='fl pad1y space-right2'> <div class='fl pad1y space-right2'>
@ -193,16 +193,16 @@ interface NavigationTabsProps {
<div class='footer quiet pad2 space-top1 center small'> <div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> <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> </div>
<script src="../../../prettify.js"></script> <script src="../../prettify.js"></script>
<script> <script>
window.onload = function () { window.onload = function () {
prettyPrint(); prettyPrint();
}; };
</script> </script>
<script src="../../../sorter.js"></script> <script src="../../sorter.js"></script>
<script src="../../../block-navigation.js"></script> <script src="../../block-navigation.js"></script>
</body> </body>
</html> </html>

View File

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

View File

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

View File

@ -3,15 +3,15 @@
<html lang="en"> <html lang="en">
<head> <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" /> <meta charset="utf-8" />
<link rel="stylesheet" href="../../prettify.css" /> <link rel="stylesheet" href="../prettify.css" />
<link rel="stylesheet" href="../../base.css" /> <link rel="stylesheet" href="../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" /> <link rel="shortcut icon" type="image/x-icon" href="../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'> <style type='text/css'>
.coverage-summary .sorter { .coverage-summary .sorter {
background-image: url(../../sort-arrow-sprite.png); background-image: url(../sort-arrow-sprite.png);
} }
</style> </style>
</head> </head>
@ -19,7 +19,7 @@
<body> <body>
<div class='wrapper'> <div class='wrapper'>
<div class='pad1'> <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='clearfix'>
<div class='fl pad1y space-right2'> <div class='fl pad1y space-right2'>
@ -130,16 +130,16 @@
<div class='footer quiet pad2 space-top1 center small'> <div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> <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> </div>
<script src="../../prettify.js"></script> <script src="../prettify.js"></script>
<script> <script>
window.onload = function () { window.onload = function () {
prettyPrint(); prettyPrint();
}; };
</script> </script>
<script src="../../sorter.js"></script> <script src="../sorter.js"></script>
<script src="../../block-navigation.js"></script> <script src="../block-navigation.js"></script>
</body> </body>
</html> </html>

View File

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

View File

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

View File

@ -3,15 +3,15 @@
<html lang="en"> <html lang="en">
<head> <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" /> <meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" /> <link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" /> <link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" /> <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'> <style type='text/css'>
.coverage-summary .sorter { .coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png); background-image: url(../../sort-arrow-sprite.png);
} }
</style> </style>
</head> </head>
@ -19,7 +19,7 @@
<body> <body>
<div class='wrapper'> <div class='wrapper'>
<div class='pad1'> <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='clearfix'>
<div class='fl pad1y space-right2'> <div class='fl pad1y space-right2'>
@ -121,16 +121,16 @@ export type AppState = {
<div class='footer quiet pad2 space-top1 center small'> <div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> <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> </div>
<script src="../../../prettify.js"></script> <script src="../../prettify.js"></script>
<script> <script>
window.onload = function () { window.onload = function () {
prettyPrint(); prettyPrint();
}; };
</script> </script>
<script src="../../../sorter.js"></script> <script src="../../sorter.js"></script>
<script src="../../../block-navigation.js"></script> <script src="../../block-navigation.js"></script>
</body> </body>
</html> </html>

View File

@ -3,15 +3,15 @@
<html lang="en"> <html lang="en">
<head> <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" /> <meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" /> <link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" /> <link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" /> <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'> <style type='text/css'>
.coverage-summary .sorter { .coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png); background-image: url(../../sort-arrow-sprite.png);
} }
</style> </style>
</head> </head>
@ -19,7 +19,7 @@
<body> <body>
<div class='wrapper'> <div class='wrapper'>
<div class='pad1'> <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='clearfix'>
<div class='fl pad1y space-right2'> <div class='fl pad1y space-right2'>
@ -394,16 +394,16 @@ interface DocumentState {
<div class='footer quiet pad2 space-top1 center small'> <div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> <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> </div>
<script src="../../../prettify.js"></script> <script src="../../prettify.js"></script>
<script> <script>
window.onload = function () { window.onload = function () {
prettyPrint(); prettyPrint();
}; };
</script> </script>
<script src="../../../sorter.js"></script> <script src="../../sorter.js"></script>
<script src="../../../block-navigation.js"></script> <script src="../../block-navigation.js"></script>
</body> </body>
</html> </html>

View File

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

View File

@ -3,15 +3,15 @@
<html lang="en"> <html lang="en">
<head> <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" /> <meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" /> <link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" /> <link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" /> <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'> <style type='text/css'>
.coverage-summary .sorter { .coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png); background-image: url(../../sort-arrow-sprite.png);
} }
</style> </style>
</head> </head>
@ -19,7 +19,7 @@
<body> <body>
<div class='wrapper'> <div class='wrapper'>
<div class='pad1'> <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='clearfix'>
<div class='fl pad1y space-right2'> <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'> <div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> <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> </div>
<script src="../../../prettify.js"></script> <script src="../../prettify.js"></script>
<script> <script>
window.onload = function () { window.onload = function () {
prettyPrint(); prettyPrint();
}; };
</script> </script>
<script src="../../../sorter.js"></script> <script src="../../sorter.js"></script>
<script src="../../../block-navigation.js"></script> <script src="../../block-navigation.js"></script>
</body> </body>
</html> </html>

View File

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

View File

@ -3,15 +3,15 @@
<html lang="en"> <html lang="en">
<head> <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" /> <meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" /> <link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" /> <link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" /> <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'> <style type='text/css'>
.coverage-summary .sorter { .coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png); background-image: url(../../sort-arrow-sprite.png);
} }
</style> </style>
</head> </head>
@ -19,7 +19,7 @@
<body> <body>
<div class='wrapper'> <div class='wrapper'>
<div class='pad1'> <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='clearfix'>
<div class='fl pad1y space-right2'> <div class='fl pad1y space-right2'>
@ -265,16 +265,16 @@
<div class='footer quiet pad2 space-top1 center small'> <div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> <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> </div>
<script src="../../../prettify.js"></script> <script src="../../prettify.js"></script>
<script> <script>
window.onload = function () { window.onload = function () {
prettyPrint(); prettyPrint();
}; };
</script> </script>
<script src="../../../sorter.js"></script> <script src="../../sorter.js"></script>
<script src="../../../block-navigation.js"></script> <script src="../../block-navigation.js"></script>
</body> </body>
</html> </html>

View File

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

View File

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

View File

@ -3,15 +3,15 @@
<html lang="en"> <html lang="en">
<head> <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" /> <meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" /> <link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" /> <link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" /> <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'> <style type='text/css'>
.coverage-summary .sorter { .coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png); background-image: url(../../sort-arrow-sprite.png);
} }
</style> </style>
</head> </head>
@ -19,7 +19,7 @@
<body> <body>
<div class='wrapper'> <div class='wrapper'>
<div class='pad1'> <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='clearfix'>
<div class='fl pad1y space-right2'> <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'> <div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> <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> </div>
<script src="../../../prettify.js"></script> <script src="../../prettify.js"></script>
<script> <script>
window.onload = function () { window.onload = function () {
prettyPrint(); prettyPrint();
}; };
</script> </script>
<script src="../../../sorter.js"></script> <script src="../../sorter.js"></script>
<script src="../../../block-navigation.js"></script> <script src="../../block-navigation.js"></script>
</body> </body>
</html> </html>

View File

@ -3,15 +3,15 @@
<html lang="en"> <html lang="en">
<head> <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" /> <meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" /> <link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" /> <link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" /> <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'> <style type='text/css'>
.coverage-summary .sorter { .coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png); background-image: url(../../sort-arrow-sprite.png);
} }
</style> </style>
</head> </head>
@ -19,7 +19,7 @@
<body> <body>
<div class='wrapper'> <div class='wrapper'>
<div class='pad1'> <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='clearfix'>
<div class='fl pad1y space-right2'> <div class='fl pad1y space-right2'>
@ -573,7 +573,7 @@
Schedule, Schedule,
Psychology, Psychology,
} from '@mui/icons-material' } 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 { 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 { getConseil } from '../store/documentSlice'</span>
<span class="cstat-no" title="statement not covered" >import { Layout } from '../components/Layout'</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> <span class="cstat-no" title="statement not covered" > }</span>
&nbsp; &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" > 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" > return 'error'</span>
<span class="cstat-no" title="statement not covered" > }</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" > {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;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;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;/ListItemIcon&gt;</span>
<span class="cstat-no" title="statement not covered" > &lt;ListItemText</span> <span class="cstat-no" title="statement not covered" > &lt;ListItemText</span>
<span class="cstat-no" title="statement not covered" > primary={risk}</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'> <div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> <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> </div>
<script src="../../../prettify.js"></script> <script src="../../prettify.js"></script>
<script> <script>
window.onload = function () { window.onload = function () {
prettyPrint(); prettyPrint();
}; };
</script> </script>
<script src="../../../sorter.js"></script> <script src="../../sorter.js"></script>
<script src="../../../block-navigation.js"></script> <script src="../../block-navigation.js"></script>
</body> </body>
</html> </html>

View File

@ -3,15 +3,15 @@
<html lang="en"> <html lang="en">
<head> <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" /> <meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" /> <link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" /> <link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" /> <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'> <style type='text/css'>
.coverage-summary .sorter { .coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png); background-image: url(../../sort-arrow-sprite.png);
} }
</style> </style>
</head> </head>
@ -19,7 +19,7 @@
<body> <body>
<div class='wrapper'> <div class='wrapper'>
<div class='pad1'> <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='clearfix'>
<div class='fl pad1y space-right2'> <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'> <div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> <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> </div>
<script src="../../../prettify.js"></script> <script src="../../prettify.js"></script>
<script> <script>
window.onload = function () { window.onload = function () {
prettyPrint(); prettyPrint();
}; };
</script> </script>
<script src="../../../sorter.js"></script> <script src="../../sorter.js"></script>
<script src="../../../block-navigation.js"></script> <script src="../../block-navigation.js"></script>
</body> </body>
</html> </html>

View File

@ -3,15 +3,15 @@
<html lang="en"> <html lang="en">
<head> <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" /> <meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" /> <link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" /> <link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" /> <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'> <style type='text/css'>
.coverage-summary .sorter { .coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png); background-image: url(../../sort-arrow-sprite.png);
} }
</style> </style>
</head> </head>
@ -19,7 +19,7 @@
<body> <body>
<div class='wrapper'> <div class='wrapper'>
<div class='pad1'> <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='clearfix'>
<div class='fl pad1y space-right2'> <div class='fl pad1y space-right2'>
@ -931,16 +931,16 @@
<div class='footer quiet pad2 space-top1 center small'> <div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> <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> </div>
<script src="../../../prettify.js"></script> <script src="../../prettify.js"></script>
<script> <script>
window.onload = function () { window.onload = function () {
prettyPrint(); prettyPrint();
}; };
</script> </script>
<script src="../../../sorter.js"></script> <script src="../../sorter.js"></script>
<script src="../../../block-navigation.js"></script> <script src="../../block-navigation.js"></script>
</body> </body>
</html> </html>

View File

@ -3,15 +3,15 @@
<html lang="en"> <html lang="en">
<head> <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" /> <meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" /> <link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" /> <link rel="stylesheet" href="../../base.css" />
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.png" /> <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<style type='text/css'> <style type='text/css'>
.coverage-summary .sorter { .coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png); background-image: url(../../sort-arrow-sprite.png);
} }
</style> </style>
</head> </head>
@ -19,7 +19,7 @@
<body> <body>
<div class='wrapper'> <div class='wrapper'>
<div class='pad1'> <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='clearfix'>
<div class='fl pad1y space-right2'> <div class='fl pad1y space-right2'>
@ -541,7 +541,7 @@ import type { Document } from '../types'
&nbsp; &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;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" > &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" > size="small"</span>
<span class="cstat-no" title="statement not covered" > variant="outlined"</span> <span class="cstat-no" title="statement not covered" > variant="outlined"</span>
<span class="cstat-no" title="statement not covered" > /&gt;</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'> <div class='footer quiet pad2 space-top1 center small'>
Code coverage generated by Code coverage generated by
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> <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> </div>
<script src="../../../prettify.js"></script> <script src="../../prettify.js"></script>
<script> <script>
window.onload = function () { window.onload = function () {
prettyPrint(); prettyPrint();
}; };
</script> </script>
<script src="../../../sorter.js"></script> <script src="../../sorter.js"></script>
<script src="../../../block-navigation.js"></script> <script src="../../block-navigation.js"></script>
</body> </body>
</html> </html>

View File

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

View File

@ -2,8 +2,8 @@
## Vue d'ensemble ## Vue d'ensemble
L'application 4NK IA Front Notarial communique avec plusieurs APIs pour fournir une expérience complète L'application 4NK IA Front Notarial communique uniquement avec le backend interne pour toutes les
d'analyse de documents notariaux. fonctionnalités (upload, extraction, analyse, contexte, conseil).
## API Backend Principal ## API Backend Principal
@ -13,36 +13,28 @@ d'analyse de documents notariaux.
http://localhost:8000 (développement) 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 ### Endpoints
#### Upload de document #### Upload de document
```http ```http
POST /api/notary/upload # mode simple POST /api/notary/upload
POST /api/documents/upload # mode complet
Content-Type: multipart/form-data Content-Type: multipart/form-data
Body: FormData avec le fichier 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 ```json
{ {
"document_id": "doc_123456", // ou "id" "document_id": "doc_123456",
"mime_type": "application/pdf", // ou "mimeType" "mime_type": "application/pdf",
"functional_type": "CNI" // ou "functionalType" (type fonctionnel métier) "functional_type": "CNI"
} }
``` ```
Le front mappe en `Document`: Mappage front en `Document` :
```json ```json
{ {
@ -60,80 +52,47 @@ Le front mappe en `Document`:
#### Extraction de données #### Extraction de données
```http ```http
GET /api/notary/documents/{documentId} # mode simple (détails document + résultats) GET /api/notary/documents/{documentId}
GET /api/documents/{documentId}/extract # mode complet
``` ```
#### Analyse du document #### Analyse du document
```http ```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 #### Données contextuelles
```http ```http
GET /api/documents/{documentId}/context # mode complet GET /api/documents/{documentId}/context
``` ```
(mode simple: non disponible — fallback de démonstration)
#### Conseil IA #### Conseil IA
```http ```http
GET /api/documents/{documentId}/conseil # mode complet GET /api/documents/{documentId}/conseil
``` ```
(mode simple: non disponible — fallback de démonstration)
## APIs Externes ## APIs Externes
### Cadastre Les APIs externes (Cadastre, Géorisques, Géofoncier, BODACC, Infogreffe) sont appelées côté backend
uniquement. Aucun appel direct côté front.
**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
## Gestion d'erreur ## Gestion d'erreur
### Codes d'erreur HTTP ### Codes d'erreur HTTP
- **200** : Succès - 200 : Succès
- **400** : Requête malformée - 400 : Requête malformée
- **404** : Ressource non trouvée - 404 : Ressource non trouvée
- **405** : Méthode non autorisée - 405 : Méthode non autorisée
- **500** : Erreur serveur interne - 500 : Erreur serveur interne
### Erreurs de connexion ### Erreurs de connexion
- **ERR_NETWORK** : Erreur de réseau - ERR_NETWORK : Erreur de réseau
- **ERR_CONNECTION_REFUSED** : Connexion refusée - ERR_CONNECTION_REFUSED : Connexion refusée
- **ERR_TIMEOUT** : Timeout de la requête - 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.
## Configuration ## Configuration
@ -141,12 +100,6 @@ En cas d'erreur, l'application bascule automatiquement vers des données de dém
```env ```env
VITE_API_URL=http://localhost:8000 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 ### Configuration Axios
@ -154,10 +107,7 @@ VITE_INFOGREFFE_API_URL=https://api.infogreffe.fr
```typescript ```typescript
const apiClient = axios.create({ const apiClient = axios.create({
baseURL: BASE_URL, baseURL: BASE_URL,
timeout: 60000, // 60 secondes timeout: 60000
headers: {
'Content-Type': 'application/json'
}
}) })
``` ```
@ -170,93 +120,6 @@ Authorization: Bearer {token}
Content-Type: application/json 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 ## Rate Limiting
### Limites par défaut - Limites gérées par le backend
- **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

View File

@ -4,18 +4,18 @@
Ce guide couvre le déploiement de l'application 4NK IA Front Notarial dans différents environnements. 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 ### Changements principaux
- Qualité: lint Markdown stabilisé (guides/rapports ignorés), ESLint corrigé et `coverage/` exclu - Suppression du « mode démo » côté frontend et des fallbacks
- TypeScript/Build: corrections dans `FilePreview`, `api`, et vues (typage couleurs MUI) - Routage des APIs externes exclusivement via le backend `4NK_IA_back`
- Tests: exécution Vitest OK, build de production OK - Exigence Node.js ≥ 20.19 pour la compilation
### Impact déploiement ### Impact déploiement
- Aucun changement de configuration serveur requis - Variables `.env` front simplifiées (uniquement `VITE_API_URL`)
- Un simple rebuild et synchronisation de `dist/` suffisent - Build requis avec Node.js ≥ 20.19
### Étapes recommandées ### Étapes recommandées
@ -39,8 +39,9 @@ sudo systemctl reload nginx
### Environnement de développement ### 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 - **npm** : >= 10.0.0
- **nvm** : recommandé, le projet fournit `.nvmrc`
- **Git** : Pour la gestion des versions - **Git** : Pour la gestion des versions
### Environnement de production ### Environnement de production
@ -58,11 +59,6 @@ sudo systemctl reload nginx
```env ```env
NODE_ENV=development NODE_ENV=development
VITE_API_URL=http://localhost:8000 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) #### Staging (.env.staging)
@ -70,11 +66,6 @@ VITE_INFOGREFFE_API_URL=https://api.infogreffe.fr
```env ```env
NODE_ENV=staging NODE_ENV=staging
VITE_API_URL=https://api-staging.4nkweb.com 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) #### Production (.env.production)
@ -82,11 +73,6 @@ VITE_INFOGREFFE_API_URL=https://api.infogreffe.fr
```env ```env
NODE_ENV=production NODE_ENV=production
VITE_API_URL=https://api.4nkweb.com 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 ## Build de production
@ -127,6 +113,26 @@ dist/
## Déploiement sur serveur ## Déploiement sur serveur
### Configuration Nginx ### 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 #### 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", "name": "4nk-ia-front4nk",
"version": "0.1.1", "version": "0.1.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "4nk-ia-front4nk", "name": "4nk-ia-front4nk",
"version": "0.1.1", "version": "0.1.2",
"dependencies": { "dependencies": {
"@emotion/react": "^11.14.0", "@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1", "@emotion/styled": "^11.14.1",
@ -17,7 +17,6 @@
"react": "^19.1.1", "react": "^19.1.1",
"react-dom": "^19.1.1", "react-dom": "^19.1.1",
"react-dropzone": "^14.3.8", "react-dropzone": "^14.3.8",
"react-pdf-js": "^5.1.0",
"react-redux": "^9.2.0", "react-redux": "^9.2.0",
"react-router-dom": "^7.8.2" "react-router-dom": "^7.8.2"
}, },
@ -385,12 +384,6 @@
"node": ">=18" "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": { "node_modules/@csstools/color-helpers": {
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz",
@ -6002,19 +5995,6 @@
"integrity": "sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==", "integrity": "sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==",
"license": "MIT" "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": { "node_modules/react-redux": {
"version": "9.2.0", "version": "9.2.0",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",

View File

@ -1,10 +1,12 @@
{ {
"name": "4nk-ia-front4nk", "name": "4nk-ia-front4nk",
"private": true, "private": true,
"version": "0.1.1", "version": "0.1.3",
"type": "module", "type": "module",
"scripts": { "scripts": {
"predev": "node scripts/check-node.mjs",
"dev": "vite", "dev": "vite",
"prebuild": "node scripts/check-node.mjs",
"build": "tsc -b && vite build", "build": "tsc -b && vite build",
"lint": "eslint .", "lint": "eslint .",
"preview": "vite preview", "preview": "vite preview",
@ -14,6 +16,10 @@
"test": "vitest run --coverage", "test": "vitest run --coverage",
"test:ui": "vitest" "test:ui": "vitest"
}, },
"engines": {
"node": ">=20.19.0 <23",
"npm": ">=10"
},
"dependencies": { "dependencies": {
"@emotion/react": "^11.14.0", "@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1", "@emotion/styled": "^11.14.1",
@ -24,7 +30,6 @@
"react": "^19.1.1", "react": "^19.1.1",
"react-dom": "^19.1.1", "react-dom": "^19.1.1",
"react-dropzone": "^14.3.8", "react-dropzone": "^14.3.8",
"react-pdf-js": "^5.1.0",
"react-redux": "^9.2.0", "react-redux": "^9.2.0",
"react-router-dom": "^7.8.2" "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' import type { Document, ExtractionResult, AnalysisResult, ContextResult, ConseilResult } from '../types'
const BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000' 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({ export const apiClient = axios.create({
baseURL: BASE_URL, baseURL: BASE_URL,
@ -13,27 +12,7 @@ export const apiClient = axios.create({
apiClient.interceptors.response.use( apiClient.interceptors.response.use(
(response) => response, (response) => response,
(error) => { (error) => {
console.error('API Error:', error) // Laisser remonter les erreurs au consommateur
// 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'
}
})
}
return Promise.reject(error) return Promise.reject(error)
} }
) )
@ -42,271 +21,97 @@ apiClient.interceptors.response.use(
export const documentApi = { export const documentApi = {
// Téléversement de document // Téléversement de document
upload: async (file: File): Promise<Document> => { upload: async (file: File): Promise<Document> => {
try { const formData = new FormData()
const formData = new FormData() formData.append('file', file)
formData.append('file', file) const { data } = await apiClient.post('/api/notary/upload', formData, {
const { data } = await apiClient.post('/api/notary/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' },
headers: { 'Content-Type': 'multipart/form-data' }, })
})
// L'API retourne {message, document_id, status} // L'API retourne {message, document_id, status}
// On doit mapper vers le format Document attendu // On doit mapper vers le format Document attendu
const fileUrl = URL.createObjectURL(file) const fileUrl = URL.createObjectURL(file)
return { return {
id: data.document_id || data.id || 'upload-' + Date.now(), id: data.document_id || data.id || 'upload-' + Date.now(),
name: file.name, name: file.name,
mimeType: data.mime_type || data.mimeType || file.type || 'application/pdf', mimeType: data.mime_type || data.mimeType || file.type || 'application/pdf',
functionalType: data.functional_type || data.functionalType || undefined, functionalType: data.functional_type || data.functionalType || undefined,
size: file.size, size: file.size,
uploadDate: new Date(), uploadDate: new Date(),
status: 'completed', status: 'completed',
previewUrl: fileUrl 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
}
} }
}, },
// Extraction des données // Extraction des données
extract: async (documentId: string): Promise<ExtractionResult> => { 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 // Mapper les données de l'API vers le format ExtractionResult
const results = data.results || {} const results = data.results || {}
return { return {
documentId, documentId,
text: results.ocr_text || "Texte extrait du document...", text: results.ocr_text || 'Texte extrait du document...',
language: "fr", language: 'fr',
documentType: results.document_type || "Document", documentType: results.document_type || 'Document',
identities: results.entities?.persons?.map((name: string, index: number) => ({ identities: results.entities?.persons?.map((name: string, index: number) => ({
id: `person-${index}`, id: `person-${index}`,
type: "person" as const, type: 'person' as const,
firstName: name.split(' ')[0] || name, firstName: name.split(' ')[0] || name,
lastName: name.split(' ').slice(1).join(' ') || "", lastName: name.split(' ').slice(1).join(' ') || '',
birthDate: "", birthDate: '',
nationality: "Française", nationality: 'Française',
confidence: 0.9 confidence: 0.9,
})) || [], })) || [],
addresses: results.entities?.addresses?.map((address: string) => ({ addresses: results.entities?.addresses?.map((address: string) => ({
street: address, street: address,
city: "Paris", city: 'Paris',
postalCode: "75001", postalCode: '75001',
country: "France" country: 'France',
})) || [], })) || [],
properties: results.entities?.properties?.map((_propertyName: string, index: number) => ({ properties: results.entities?.properties?.map((_propertyName: string, index: number) => ({
id: `prop-${index}`, id: `prop-${index}`,
type: "apartment" as const, type: 'apartment' as const,
address: { address: {
street: "123 Rue de la Paix", street: '123 Rue de la Paix',
city: "Paris", city: 'Paris',
postalCode: "75001", postalCode: '75001',
country: "France" country: 'France',
}, },
surface: 75, surface: 75,
cadastralReference: "1234567890AB", cadastralReference: '1234567890AB',
value: 250000 value: 250000,
})) || [], })) || [],
contracts: [{ contracts: [
id: "contract-1", {
type: "sale" as const, id: 'contract-1',
type: 'sale' as const,
parties: [], parties: [],
amount: 250000, amount: 250000,
date: "2024-01-15", date: '2024-01-15',
clauses: ["Clause de garantie", "Clause de condition suspensive"] clauses: ['Clause de garantie', 'Clause de condition suspensive'],
}], },
signatures: results.entities?.persons || [], ],
confidence: results.verification_score || 0.85 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
}
} }
}, },
// Analyse du document // Analyse du document
analyze: async (documentId: string): Promise<AnalysisResult> => { analyze: async (documentId: string): Promise<AnalysisResult> => {
try { const { data } = await apiClient.get<AnalysisResult>(`/api/documents/${documentId}/analyze`)
if (BACKEND_MODE === 'complete') { return data
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"
]
}
}
}, },
// Données contextuelles // Données contextuelles
getContext: async (documentId: string): Promise<ContextResult> => { getContext: async (documentId: string): Promise<ContextResult> => {
try { const { data } = await apiClient.get<ContextResult>(`/api/documents/${documentId}/context`)
if (BACKEND_MODE === 'complete') { return data
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()
}
}
}, },
// Conseil LLM // Conseil LLM
getConseil: async (documentId: string): Promise<ConseilResult> => { getConseil: async (documentId: string): Promise<ConseilResult> => {
try { const { data } = await apiClient.get<ConseilResult>(`/api/documents/${documentId}/conseil`)
if (BACKEND_MODE === 'complete') { return data
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()
}
}
}, },
// Détection du type de document // Détection du type de document
@ -322,43 +127,33 @@ export const documentApi = {
// Services API pour les données externes // Services API pour les données externes
export const externalApi = { export const externalApi = {
// Cadastre // Cadastre via backend
cadastre: async (address: string) => { cadastre: async (address: string) => {
const cadastreUrl = import.meta.env.VITE_CADASTRE_API_URL const { data } = await apiClient.get('/api/context/cadastre', { params: { q: address } })
if (!cadastreUrl) throw new Error('Cadastre API URL not configured')
const { data } = await axios.get(`${cadastreUrl}/parcelle`, { params: { q: address } })
return data return data
}, },
// Géorisques // Géorisques via backend
georisques: async (coordinates: { lat: number; lng: number }) => { georisques: async (coordinates: { lat: number; lng: number }) => {
const georisquesUrl = import.meta.env.VITE_GEORISQUES_API_URL const { data } = await apiClient.get('/api/context/georisques', { params: coordinates })
if (!georisquesUrl) throw new Error('Géorisques API URL not configured')
const { data } = await axios.get(`${georisquesUrl}/risques`, { params: coordinates })
return data return data
}, },
// Géofoncier // Géofoncier via backend
geofoncier: async (address: string) => { geofoncier: async (address: string) => {
const geofoncierUrl = import.meta.env.VITE_GEOFONCIER_API_URL const { data } = await apiClient.get('/api/context/geofoncier', { params: { address } })
if (!geofoncierUrl) throw new Error('Géofoncier API URL not configured')
const { data } = await axios.get(`${geofoncierUrl}/dossiers`, { params: { address } })
return data return data
}, },
// BODACC // BODACC via backend
bodacc: async (companyName: string) => { bodacc: async (companyName: string) => {
const bodaccUrl = import.meta.env.VITE_BODACC_API_URL const { data } = await apiClient.get('/api/context/bodacc', { params: { q: companyName } })
if (!bodaccUrl) throw new Error('BODACC API URL not configured')
const { data } = await axios.get(`${bodaccUrl}/annonces`, { params: { q: companyName } })
return data return data
}, },
// Infogreffe // Infogreffe via backend
infogreffe: async (siren: string) => { infogreffe: async (siren: string) => {
const infogreffeUrl = import.meta.env.VITE_INFOGREFFE_API_URL const { data } = await apiClient.get('/api/context/infogreffe', { params: { siren } })
if (!infogreffeUrl) throw new Error('Infogreffe API URL not configured')
const { data } = await axios.get(`${infogreffeUrl}/infogreffe/rcs/extrait`, { params: { siren } })
return data return data
}, },
} }

View File

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