Appearance
BDD-114 — Connexion à l'API Formulaires (connexions API)
1. User Story
En tant qu'administrateur,
je veux connecter dans l'Outil BDD les accès API vers des applications externes (focus sur l'application Formulaires) de façon sécurisée,
afin de pouvoir accéder aux données des formulaires.
2. Critères d'acceptation
| # | Critère | Statut |
|---|---|---|
| 1 | Une interface permet de saisir les informations de connexion (nom, URL API, clé API) | ✅ |
| 2 | Les données sensibles (clé API) sont chiffrées en base ; jamais renvoyées en lecture | ✅ |
| 3 | En cas d'erreur d'authentification ou de test de connexion, un message explicite est affiché | ✅ |
| 4 | En cas de succès, la connexion est validée et ajoutée à une liste paginée | ✅ |
Détail fonctionnel des critères
Interface
- Liste :
/connections(admin / super-admin). - Création :
/connections/create(formulaire nom, URL, clé API masquée). - Entrée menu latéral Connexions (visible si
isAdmin).
- Liste :
Chiffrement
- Clé stockée via
encrypt()(AES-256-CTR,ENCRYPTION_KEY). - Colonnes
api_key_encrypted,api_key_iv,api_key_prefix(16 premiers caractères pour affichage). - Les réponses API exposent
apiKeyPrefix, jamais la clé complète.
- Clé stockée via
Erreurs explicites
- Back : exceptions métier (
401clé invalide,403scope insuffisant, URL injoignable, réponse HTML = mauvaise URL, etc.). - Front : message API (
response.data.message) ou fallback viauseNotify.
- Back : exceptions métier (
Succès
- Avant persistance : appel
GET {baseUrl}/connection-checkavecx-api-key(endpoint Formulaires). - Statut
ACTIVE,last_validated_atrenseigné. - Liste rafraîchie après création ; notification « Connexion enregistrée avec succès. »
- Avant persistance : appel
3. Périmètre fonctionnel
Base de données
| Fichier | Rôle |
|---|---|
sql/tool_12_add_api_connections.sql | Migration : enum ApiConnectionStatus, table api_connections |
back/prisma/schema.prisma | Modèle Prisma api_connections + relation enterprises |
Backend
| Fichier | Rôle |
|---|---|
back/src/domains/encryption/encryptHelper.ts | Chiffrement / déchiffrement (ENCRYPTION_KEY obligatoire) |
back/src/api/connections/connections.module.ts | Module NestJS |
back/src/app.module.ts | Enregistrement de ConnectionsModule |
back/src/api/connections/connections.controller.ts | POST/GET /connections, GET /connections/:uuid |
back/src/api/connections/connections.service.ts | Vérification, création, liste, détail, getDecryptedApiKey (usage interne) |
back/src/api/connections/connection.presenter.ts | Mapping réponse publique (sans secrets) |
back/src/api/connections/dto/connection.dto.ts | DTO création + réponses paginées |
back/src/exceptions/api-connection.exceptions.ts | Exceptions métier HTTP |
Dépendance Formulaires (test de connexion)
| Fichier | Rôle |
|---|---|
formulaires/back/src/api-keys/connection-check.controller.ts | GET /connection-check — valide la clé API (header x-api-key) |
Frontend
| Fichier | Rôle |
|---|---|
front/src/pages/connections/ConnectionsPage.vue | Liste paginée, état vide, badges ACTIVE / ERROR |
front/src/pages/connections/ConnectionCreatePage.vue | Formulaire de création + validation URL |
front/src/stores/connections-store.js | fetchConnections, createConnection |
front/src/router/routes.js | Routes /connections, /connections/create |
front/src/router/adminGuard.js | Accès réservé aux admins (redirection /dossiers sinon) |
front/src/layouts/MainLayout.vue | Lien navigation Connexions |
4. Endpoints API (Outil BDD)
| Méthode | Chemin | Guards | Description |
|---|---|---|---|
POST | /connections | AuthGuard, AdminGuard | Crée une connexion (vérifie puis chiffre la clé) |
GET | /connections | AuthGuard, AdminGuard | Liste paginée (page, limit ≤ 100) |
GET | /connections/:uuid | AuthGuard, AdminGuard | Détail d'une connexion (sans secrets) |
Corps POST /connections
json
{
"name": "API Formulaires prod",
"baseUrl": "https://api.formulaires.example",
"apiKey": "heriade_frm_..."
}Réponse publique (extrait)
json
{
"uuid": "...",
"name": "API Formulaires prod",
"baseUrl": "https://api.formulaires.example",
"apiKeyPrefix": "heriade_frm_xxxx",
"status": "ACTIVE",
"errorMessage": null,
"lastValidatedAt": "2026-05-18T10:00:00.000Z",
"createdAt": "...",
"updatedAt": "..."
}5. Règles métier implémentées
- Périmètre entreprise
administrateur: création + lecture limitées àenterprise_iddu jeton.super-admin: voit toutes les connexions (toutes entreprises).
- Création
- Utilisateur sans entreprise →
ApiConnectionEnterpriseRequiredException. baseUrlnormalisée (trim, suppression du/final).- Test
GET {baseUrl}/connection-checkavant insert (timeout 15 s). - Réponse
text/html→ URL pointe vers le front, pas l'API.
- Utilisateur sans entreprise →
- Lecture
- Soft delete via
deleted_at(filtré dans les requêtes). getDecryptedApiKey(uuid)réservé aux usages internes futurs (sync, jobs).
- Soft delete via
- Statut
- Enum
ACTIVE|ERROR(+error_message,last_validated_at) pour le suivi opérationnel (comme lessources).
- Enum
6. Variables d'environnement
ini
# back/.env — obligatoire pour chiffrer les clés API
ENCRYPTION_KEY=<secret-32-chars-min>À exécuter côté base tool :
bash
psql "$DATABASE_URL_TOOL" -f sql/tool_12_add_api_connections.sql
npx prisma generate # depuis back/7. Points de vérification
- Seuls les admins accèdent à
/connectionset/connections/create. - La clé API n'apparaît jamais en liste ni en détail (seulement le préfixe).
- Création avec clé invalide → message explicite, pas d'enregistrement en base.
- Création avec URL front (HTML) → message « pas une API ».
- Création réussie → ligne en liste, badge Active, préfixe clé visible.
- Pagination fonctionnelle si plus de 10 connexions.
- Menu Connexions visible pour admin, masqué pour client externe.
8. Tests associés
Backend (unitaires)
back/src/api/connections/connections.service.spec.ts- normalisation URL, préfixe clé,
buildVerifyUrl verifyConnection: headers, 401, 403, HTML, réseaucreateConnection: chiffrement, pas de persistance si échec vérifgetConnections: filtre entreprise vs super-admingetConnection/getDecryptedApiKey: happy path et 404
- normalisation URL, préfixe clé,
Backend (e2e)
back/test/e2e/connections-controller.e2e-spec.tsPOST /connections: 401, 403, 400, clé refusée, URL HTML, 201 sans secretGET /connections: 401, 403, 200 paginéGET /connections/:uuid: 401, 403, 400 UUID, 404, 200
Frontend (unitaires)
front/src/__tests__/stores/connections-store.spec.js—fetchConnections,createConnectionfront/src/__tests__/pages/connections/ConnectionsPage.spec.js— liste, vide, pagination, navigation créationfront/src/__tests__/pages/connections/ConnectionCreatePage.spec.js— formulaire, validation URL, succès / erreur APIfront/src/__tests__/layouts/MainLayout.spec.js— entrée menu Connexions selon rôlefront/src/__tests__/router/routes.spec.js— routes/connections,/connections/create+adminGuard
Frontend (e2e Playwright)
front/e2e/pages/connections/connections.spec.js- liste vide / connexion ACTIVE / ERROR
- navigation sidebar
- happy path création
- URL invalide, erreur API 400
- Annuler / Retour
- non-admin redirigé
9. Notes d'implémentation
- Phase 1 = fondation : enregistrement + liste + test de connexion. La consommation des connexions (sync formulaires → sources, jobs, etc.) est hors périmètre de ce ticket.
- Extensibilité : pas de colonne
type; le premier cas d'usage est Formulaires via/connection-check. - Sécurité : ne jamais logger
apiKey; ne pas renvoyerapi_key_encrypted/api_key_ivdans les presenters. - Évolutions possibles (tickets suivants) : édition / suppression, re-test manuel, statut
ERRORaprès échec planifié, connecteur Console admin, champtypesi besoin de formulaires différents par connecteur.
10. Hors périmètre (explicitement)
- Synchronisation des données Formulaires vers les sources BDD.
- Gestion multi-connecteurs avec écrans dédiés par type.
- Rotation / mise à jour de clé sur une connexion existante (UI).
