datakeen-session-react 1.1.140-dev.71 → 1.1.140-dev.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +227 -0
- package/README.md +8 -8
- package/examples/sdk-configuration.ts +4 -4
- package/examples/test-updated-urls.ts +2 -2
- package/package.json +1 -1
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# CLAUDE.md — Client Sessions React SDK
|
|
2
|
+
|
|
3
|
+
## Vue d'ensemble
|
|
4
|
+
|
|
5
|
+
Librairie React TypeScript servant d'orchestrateur côté client pour les parcours d'onboarding Datakeen (journeys). Publiée sur npm sous `datakeen-session-react`. Elle gère la navigation entre nœuds, la collecte de données (formulaires, documents, biométrique), le polling asynchrone des analyses et l'historique de navigation.
|
|
6
|
+
|
|
7
|
+
**Stack :** React 18 (peer dep), TypeScript, Axios, i18next, Radix UI, TensorFlow (ML documents), Rollup (build ESM + CJS).
|
|
8
|
+
|
|
9
|
+
**Tests :** Jest + React Testing Library.
|
|
10
|
+
|
|
11
|
+
**Point d'entrée :** `src/components/DatakeenSession.tsx`
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Structure du projet
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
client-sessions-react-sdk/
|
|
19
|
+
├── src/
|
|
20
|
+
│ ├── components/
|
|
21
|
+
│ │ ├── session/ # Orchestration session (SessionContent, UserInputForm)
|
|
22
|
+
│ │ ├── template/ # Rendu nœuds (TemplateNodeRenderer, ConditionNodeHandler)
|
|
23
|
+
│ │ ├── document-collection/
|
|
24
|
+
│ │ ├── selfie/, id-check/, jdi/, signature-electronic/
|
|
25
|
+
│ │ ├── start-flow/, end-flow/
|
|
26
|
+
│ │ └── ui/ # Composants réutilisables internes
|
|
27
|
+
│ ├── hooks/
|
|
28
|
+
│ │ ├── useStepNavigation.ts # Historique + navigation (CRITIQUE)
|
|
29
|
+
│ │ ├── useSessionData.ts # Chargement et synchro données
|
|
30
|
+
│ │ ├── useTemplateLoader.ts # Résolution template
|
|
31
|
+
│ │ └── useStepCSS.ts # Styles dynamiques par nœud
|
|
32
|
+
│ ├── services/
|
|
33
|
+
│ │ ├── sessionService.ts # API session + getOrderedJourneySteps
|
|
34
|
+
│ │ ├── pollingService.ts # Polling analyses documentaires
|
|
35
|
+
│ │ ├── retryService.ts # Gestion retryCounts
|
|
36
|
+
│ │ └── ...
|
|
37
|
+
│ ├── context/
|
|
38
|
+
│ │ ├── SessionContext.tsx # État session global
|
|
39
|
+
│ │ ├── ConfigContext.tsx
|
|
40
|
+
│ │ └── DocumentContext.tsx
|
|
41
|
+
│ ├── types/
|
|
42
|
+
│ │ ├── session.ts # SessionTemplateNode, SessionTemplateEdge, CustomField
|
|
43
|
+
│ │ └── ...
|
|
44
|
+
│ ├── utils/
|
|
45
|
+
│ │ ├── conditionEvaluator.ts # Évaluation conditions
|
|
46
|
+
│ │ ├── cssLoader.ts # Injection CSS dynamique
|
|
47
|
+
│ │ └── documentLabels.ts
|
|
48
|
+
│ └── i18n/
|
|
49
|
+
│ ├── fr.json, en.json
|
|
50
|
+
│ └── country/, documents/
|
|
51
|
+
├── docs/ # Documentation — LIRE EN PREMIER
|
|
52
|
+
├── rollup.config.js # Build production (ESM + CJS)
|
|
53
|
+
└── dist/ # Artefacts buildés (ne pas modifier)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Règles impératives
|
|
59
|
+
|
|
60
|
+
### Avant de coder
|
|
61
|
+
|
|
62
|
+
**Lire `docs/`** en premier :
|
|
63
|
+
- `POLLING_SYSTEM.md` — spec complète polling v2.0.0
|
|
64
|
+
- `navigation-history.md` — pièges navigation
|
|
65
|
+
- `multi-runs.md` — convention `_list`
|
|
66
|
+
- `JOURNEY_NODE_BUILDER.md` — checklist ajout nœud
|
|
67
|
+
- `sdk_integration_guide.md` — intégration consommateur
|
|
68
|
+
|
|
69
|
+
### Navigation entre nœuds
|
|
70
|
+
|
|
71
|
+
Le fichier central est `src/hooks/useStepNavigation.ts`. Respecter strictement l'API :
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
// ✅ Avancer vers le prochain nœud (résout via les edges du graphe)
|
|
75
|
+
goToNextStep(nodeId, template, handle?)
|
|
76
|
+
|
|
77
|
+
// ✅ Revenir en arrière (dépile l'historique)
|
|
78
|
+
goBack()
|
|
79
|
+
|
|
80
|
+
// ✅ Naviguer directement (cas spéciaux uniquement)
|
|
81
|
+
setStep(n, skipHistory?)
|
|
82
|
+
|
|
83
|
+
// ❌ Ne jamais faire ça
|
|
84
|
+
setStep(step - 1) // arithmétique manuelle = bugs de navigation
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Index de navigation :**
|
|
88
|
+
- `step=0` : écran de démarrage
|
|
89
|
+
- `step=0.5` : QR code (si configuré)
|
|
90
|
+
- `step≥1` : nœuds du template (1-indexed, triés par `order`)
|
|
91
|
+
|
|
92
|
+
### Types de nœuds
|
|
93
|
+
|
|
94
|
+
| Type | Description | Sorties |
|
|
95
|
+
|------|-------------|---------|
|
|
96
|
+
| `information-input` | Formulaires avec champs optionnellement verrouillés | 1 |
|
|
97
|
+
| `document-selection` | Choix de document | 1 |
|
|
98
|
+
| `document-collection` | Upload document + polling | 1 |
|
|
99
|
+
| `controle-jdi` | Analyse JDI avec polling | 1 |
|
|
100
|
+
| `selfie-capture` / `biometric-capture` | Biométrie | 1 |
|
|
101
|
+
| `condition` | Branchement conditionnel (évalue `conditionTokens`) | 2 : `true` / `false` |
|
|
102
|
+
| `end` | Fin de session | 0 |
|
|
103
|
+
|
|
104
|
+
Le dispatcher est `src/components/template/TemplateNodeRenderer.tsx`.
|
|
105
|
+
|
|
106
|
+
**Checklist ajout d'un nœud :**
|
|
107
|
+
1. Ajouter le type dans `src/types/session.ts`
|
|
108
|
+
2. Créer le composant dans `src/components/`
|
|
109
|
+
3. Ajouter le case dans `TemplateNodeRenderer.tsx`
|
|
110
|
+
4. Ajouter les traductions FR/EN dans `src/i18n/`
|
|
111
|
+
5. Gérer `goToNextStep` à la complétion du nœud
|
|
112
|
+
6. Gérer `goBack()` si le nœud a un bouton retour
|
|
113
|
+
7. Tester avec les cas : nœud auto-exécutant → doit être sauté par `goBack()`
|
|
114
|
+
|
|
115
|
+
### Système de polling
|
|
116
|
+
|
|
117
|
+
Codes de résultat d'une analyse documentaire :
|
|
118
|
+
|
|
119
|
+
| Code | Signification | Action |
|
|
120
|
+
|------|---------------|--------|
|
|
121
|
+
| `1.0` | Approuvé | `goToNextStep` |
|
|
122
|
+
| `2.0` | Rejeté | Retry possible |
|
|
123
|
+
| `3.0` | Erreur | Retry possible |
|
|
124
|
+
| `4.0` | En vérification manuelle | Attendre |
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// Pattern polling
|
|
128
|
+
pollingService.poll(analysisId, {
|
|
129
|
+
onProgress: (pct) => setProgress(pct), // 50% → analysisId absent, 100% → résultat
|
|
130
|
+
onComplete: (code, message) => handleResult(code),
|
|
131
|
+
interval: 2000,
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Champs verrouillés (`lockedFromApi`)
|
|
136
|
+
|
|
137
|
+
Définis dans `CustomField.lockedFromApi`. Le SDK **ne doit pas les afficher** à l'utilisateur :
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
// Dans CustomFormFields.tsx — filtrer avant rendu
|
|
141
|
+
const visibleFields = fields.filter(f => !f.lockedFromApi);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Le backend réinjecte la valeur originale via `stripLockedFields()` (protection côté serveur contre la manipulation). Ne jamais contourner ce mécanisme.
|
|
145
|
+
|
|
146
|
+
### Multi-runs (convention `_list`)
|
|
147
|
+
|
|
148
|
+
Cas : session avec plusieurs bénéficiaires passés à la création.
|
|
149
|
+
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"userInput": {
|
|
153
|
+
"_list": [
|
|
154
|
+
{ "firstName": "Alice", "lastName": "Dupont" },
|
|
155
|
+
{ "firstName": "Bob", "lastName": "Martin" }
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
- `session.retryCounts[nodeId]` = index du run courant (0-indexed)
|
|
162
|
+
- Incrémenté automatiquement par `ConditionNodeHandler` en mode boucle
|
|
163
|
+
- SDK sélectionne `_list[runIndex]` pour pré-remplir les formulaires
|
|
164
|
+
- Si hors borne → formulaire vide (comportement attendu)
|
|
165
|
+
|
|
166
|
+
### Historique de navigation (reconstruction)
|
|
167
|
+
|
|
168
|
+
Au rechargement, l'historique est reconstruit depuis `initialStep` via `reconstructHistoryToStep()` dans `sessionService.ts`. La reconstruction suit la **première edge sortante** de chaque nœud — elle **ne reconnaît pas** les branches conditionnelles complexes. C'est une limitation connue et documentée.
|
|
169
|
+
|
|
170
|
+
### Internationalisation
|
|
171
|
+
|
|
172
|
+
- Toutes les chaînes visibles dans `src/i18n/fr.json` et `en.json`.
|
|
173
|
+
- Ne jamais hardcoder de texte affiché à l'utilisateur.
|
|
174
|
+
|
|
175
|
+
### Styles dynamiques
|
|
176
|
+
|
|
177
|
+
- CSS chargé via `cssLoader.ts` selon `node.styles` (injection dynamique).
|
|
178
|
+
- Fallback sur Tailwind pour les composants par défaut.
|
|
179
|
+
- Ne pas utiliser de style inline.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Build et publication
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
# Build de la librairie (ESM + CJS)
|
|
187
|
+
npm run build # ou pnpm build
|
|
188
|
+
|
|
189
|
+
# Tests
|
|
190
|
+
npm test
|
|
191
|
+
|
|
192
|
+
# Développement avec watch
|
|
193
|
+
npm run dev
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Rollup génère deux artifacts dans `dist/` :
|
|
197
|
+
- `dist/esm/index.js` — pour les bundlers modernes (import)
|
|
198
|
+
- `dist/cjs/index.js` — pour CommonJS (require)
|
|
199
|
+
- `dist/types/index.d.ts` — typages TypeScript
|
|
200
|
+
|
|
201
|
+
**Ne jamais modifier `dist/` manuellement** — régénéré à chaque build.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Fichiers critiques
|
|
206
|
+
|
|
207
|
+
| Fichier | Rôle |
|
|
208
|
+
|---------|------|
|
|
209
|
+
| `src/components/DatakeenSession.tsx` | Point d'entrée public de la librairie |
|
|
210
|
+
| `src/hooks/useStepNavigation.ts` | Navigation + historique (NE PAS casser l'API) |
|
|
211
|
+
| `src/hooks/useSessionData.ts` | Chargement et synchro état session |
|
|
212
|
+
| `src/components/template/TemplateNodeRenderer.tsx` | Dispatcher de rendu par type de nœud |
|
|
213
|
+
| `src/services/sessionService.ts` | API session + `getOrderedJourneySteps` + `reconstructHistoryToStep` |
|
|
214
|
+
| `src/services/pollingService.ts` | Polling analyses (voir `docs/POLLING_SYSTEM.md`) |
|
|
215
|
+
| `src/utils/conditionEvaluator.ts` | Évaluation des conditions de branchement |
|
|
216
|
+
| `src/types/session.ts` | Contrats de données principaux |
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## À ne jamais faire
|
|
221
|
+
|
|
222
|
+
- Utiliser `setStep(step - 1)` pour le retour — utiliser `goBack()`.
|
|
223
|
+
- Appeler `setStep` directement pour avancer — utiliser `goToNextStep`.
|
|
224
|
+
- Afficher un champ avec `lockedFromApi: true`.
|
|
225
|
+
- Modifier les fichiers dans `dist/` — ils sont générés.
|
|
226
|
+
- Introduire une dépendance directe vers le backend ou le frontend Datakeen — le SDK est agnostique.
|
|
227
|
+
- Ajouter des dépendances `dependencies` qui devraient être en `peerDependencies` (React, Axios).
|
package/README.md
CHANGED
|
@@ -90,7 +90,7 @@ const VerificationPage = () => {
|
|
|
90
90
|
const { SessionComponent } = useSession(
|
|
91
91
|
"votre-session-id",
|
|
92
92
|
{ selfie: false, requireMobile: false }, // optionnel
|
|
93
|
-
"https://app
|
|
93
|
+
"https://app.datakeen.co/backend" // optionnel
|
|
94
94
|
);
|
|
95
95
|
|
|
96
96
|
return <div>{SessionComponent}</div>;
|
|
@@ -106,7 +106,7 @@ const VerificationPage = () => (
|
|
|
106
106
|
<DatakeenSession
|
|
107
107
|
sessionId="votre-session-id"
|
|
108
108
|
sessionConfig={{ selfie: false, requireMobile: false }}
|
|
109
|
-
apiBaseUrl="https://app
|
|
109
|
+
apiBaseUrl="https://app.datakeen.co/backend"
|
|
110
110
|
/>
|
|
111
111
|
);
|
|
112
112
|
```
|
|
@@ -117,7 +117,7 @@ const VerificationPage = () => (
|
|
|
117
117
|
import { DatakeenSession, ConfigProvider } from "datakeen-session-react";
|
|
118
118
|
|
|
119
119
|
const App = () => (
|
|
120
|
-
<ConfigProvider apiBaseUrl="https://app
|
|
120
|
+
<ConfigProvider apiBaseUrl="https://app.datakeen.co/backend">
|
|
121
121
|
<DatakeenSession sessionId="votre-session-id" />
|
|
122
122
|
</ConfigProvider>
|
|
123
123
|
);
|
|
@@ -164,7 +164,7 @@ import { DatakeenSession } from "datakeen-session-react";
|
|
|
164
164
|
<DatakeenSession
|
|
165
165
|
sessionId="votre-session-id"
|
|
166
166
|
sessionConfig={{ selfie: true }}
|
|
167
|
-
apiBaseUrl="https://app
|
|
167
|
+
apiBaseUrl="https://app.datakeen.co/backend"
|
|
168
168
|
/>
|
|
169
169
|
```
|
|
170
170
|
|
|
@@ -177,7 +177,7 @@ Gère automatiquement : loading/erreur/expiration, layouts mobile/desktop, coule
|
|
|
177
177
|
```tsx
|
|
178
178
|
import { ConfigProvider } from "datakeen-session-react";
|
|
179
179
|
|
|
180
|
-
<ConfigProvider apiBaseUrl="https://app
|
|
180
|
+
<ConfigProvider apiBaseUrl="https://app.datakeen.co/backend">
|
|
181
181
|
{/* Tous les DatakeenSession enfants utilisent cette URL */}
|
|
182
182
|
<DatakeenSession sessionId="session-1" />
|
|
183
183
|
</ConfigProvider>
|
|
@@ -191,7 +191,7 @@ import { ConfigProvider } from "datakeen-session-react";
|
|
|
191
191
|
import { configureApiBaseURL } from "datakeen-session-react";
|
|
192
192
|
|
|
193
193
|
// À appeler une fois au démarrage de l'application
|
|
194
|
-
configureApiBaseURL("https://app
|
|
194
|
+
configureApiBaseURL("https://app.datakeen.co/backend");
|
|
195
195
|
```
|
|
196
196
|
|
|
197
197
|
---
|
|
@@ -322,7 +322,7 @@ Le SDK résout l'URL API dans cet ordre de priorité :
|
|
|
322
322
|
import { configureApiBaseURL } from "datakeen-session-react";
|
|
323
323
|
|
|
324
324
|
const urls = {
|
|
325
|
-
production: "https://app
|
|
325
|
+
production: "https://app.datakeen.co/backend",
|
|
326
326
|
staging: "https://app.staging.datakeen.co/backend",
|
|
327
327
|
development:"https://app.dev.datakeen.co/backend",
|
|
328
328
|
};
|
|
@@ -333,7 +333,7 @@ configureApiBaseURL(urls[process.env.NODE_ENV] ?? urls.development);
|
|
|
333
333
|
### Via `.env` (Vite)
|
|
334
334
|
|
|
335
335
|
```env
|
|
336
|
-
VITE_API_BASE_URL=https://app
|
|
336
|
+
VITE_API_BASE_URL=https://app.datakeen.co/backend
|
|
337
337
|
```
|
|
338
338
|
|
|
339
339
|
Commande de setup rapide :
|
|
@@ -16,7 +16,7 @@ export const configureSDKForEnvironment = () => {
|
|
|
16
16
|
|
|
17
17
|
switch (environment) {
|
|
18
18
|
case "production":
|
|
19
|
-
apiBaseURL = "https://app
|
|
19
|
+
apiBaseURL = "https://app.datakeen.co/backend";
|
|
20
20
|
break;
|
|
21
21
|
|
|
22
22
|
case "staging":
|
|
@@ -64,9 +64,9 @@ export const configureSDKDynamically = () => {
|
|
|
64
64
|
|
|
65
65
|
let apiBaseURL: string;
|
|
66
66
|
|
|
67
|
-
if (hostname.includes("app
|
|
67
|
+
if (hostname.includes("app.datakeen.co")) {
|
|
68
68
|
// Production
|
|
69
|
-
apiBaseURL = "https://app
|
|
69
|
+
apiBaseURL = "https://app.datakeen.co/backend";
|
|
70
70
|
} else if (hostname.includes("app.staging.datakeen.co")) {
|
|
71
71
|
// Staging
|
|
72
72
|
apiBaseURL = "https://app.staging.datakeen.co/backend";
|
|
@@ -115,7 +115,7 @@ export const configureSDKAdvanced = (options: {
|
|
|
115
115
|
if (!apiBaseURL && environment) {
|
|
116
116
|
switch (environment) {
|
|
117
117
|
case "production":
|
|
118
|
-
apiBaseURL = "https://app
|
|
118
|
+
apiBaseURL = "https://app.datakeen.co/backend";
|
|
119
119
|
break;
|
|
120
120
|
case "staging":
|
|
121
121
|
apiBaseURL = "https://app.staging.datakeen.co/backend";
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
|
|
14
14
|
// URLs attendues pour chaque environnement
|
|
15
15
|
const EXPECTED_URLS = {
|
|
16
|
-
production: "https://app
|
|
16
|
+
production: "https://app.datakeen.co/backend/session",
|
|
17
17
|
staging: "https://app.staging.datakeen.co/backend/session",
|
|
18
18
|
development: "https://app.dev.datakeen.co/backend/session",
|
|
19
19
|
localhost: "http://localhost:8888/backend/session",
|
|
@@ -63,7 +63,7 @@ const testDynamicConfiguration = () => {
|
|
|
63
63
|
const originalLocation = window.location;
|
|
64
64
|
|
|
65
65
|
const testCases = [
|
|
66
|
-
{ hostname: "app
|
|
66
|
+
{ hostname: "app.datakeen.co", expected: EXPECTED_URLS.production },
|
|
67
67
|
{ hostname: "app.staging.datakeen.co", expected: EXPECTED_URLS.staging },
|
|
68
68
|
{ hostname: "app.dev.datakeen.co", expected: EXPECTED_URLS.development },
|
|
69
69
|
{ hostname: "localhost", expected: EXPECTED_URLS.localhost },
|
package/package.json
CHANGED