Profils OPCO
Qu'est-ce qu'un profil ?
Un profil est une description declarative de la maniere dont l'API d'un OPCO differe du schema normalise Opcovia. Chaque OPCO a ses particularites : fautes de frappe dans les enums, formats de date differents, champs obligatoires supplementaires, wrappers autour des reponses, etc.
Au lieu d'ecrire un adapter TypeScript par OPCO, on declare un profil avec le DSL. Le profil est un ensemble de routes, chacune associant un endpoint Opcovia a un endpoint upstream avec ses transforms.
Pourquoi des profils ?
Chaque OPCO expose une API differente. Exemples de divergences reelles :
| Probleme | Exemple OPCO EP |
|---|---|
| Typos dans les enums | RUTPURE au lieu de RUPTURE |
| Format de date non standard | ISO datetime au lieu de YYYY-MM-DD |
| Noms en majuscules exiges | apprenti.nom doit etre uppercase |
| Crash sur null | L'API plante si un champ est null |
| Reponse non paginee | Array brut au lieu d'un objet pagine |
| Durees en string | Heures/minutes attendues comme string, pas number |
Le profil absorbe ces differences. Le code metier ne les voit jamais.
Architecture
Profil OPCO
┌──────────────────┐
│ defineProfile() │
│ ├── route GET │
│ ├── route POST │
│ └── ... │
└──────────────────┘
│
▼
ProfileAdapter
(implements OpcoAdapter)Flux request
Corps JSON client
│
▼
requestOps[] t.transform('nom', cleanName)
(appliques t.stripNulls()
sequentiellement)
│
▼
Corps JSON OPCO → envoi a l'API upstreamFlux response
Reponse JSON OPCO
│
▼
responseOps[] t.mapDeep('etat', corrections)
(appliques t.editData(normaliserPagination)
sequentiellement)
│
▼
Reponse normalisee → renvoyee au clientPipeline de transformation DSL
Concepts cles
defineRoute
Definit une route simple : un endpoint Opcovia mappe a un endpoint upstream.
defineRoute('/dossiers', 'POST', {
dest: '/v1/dossiers',
cacheTtl: 600,
rateLimit: { maxPerMinute: 60 },
requestTransform: (t) => { /* ops sur la requete */ },
responseTransform: (t) => { /* ops sur la reponse */ },
})defineCompositeRoute
Definit une route composite : plusieurs appels upstream enchaines, avec passage de donnees entre etapes via t.next() / t.previous().
defineProfile
Assemble les routes en un profil complet.
defineProfile('opco-ep', {
sync: { batchSize: 50 },
poll: { intervalMs: 300_000 },
routes: [routeGet, routePost, ...],
})FieldTransform (t.xxx())
Transforms chainables et immutables sur une valeur. Stockables dans des variables pour reutilisation.
const cleanName = t.trim().uppercase()
// reutilisable sur N champs
t.transform('apprenti.nom', cleanName)
t.transform('apprenti.prenom', cleanName)Structure des fichiers
profiles/
field-transform.ts — FieldTransform chainable + factory t
dsl.ts — defineRoute, defineProfile, TransformBuilder
engine.ts — applyOps() execute les operations
adapter.ts — ProfileAdapter implements OpcoAdapter
types.ts — Op, RouteDefinition, ProfileDefinition
opco-ep/ — 1 fichier par route
opco-mock/ — profil mock pour les tests
__tests__/ — tests unitaires et integration