Skip to content

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èreStatut
1Une interface permet de saisir les informations de connexion (nom, URL API, clé API)
2Les données sensibles (clé API) sont chiffrées en base ; jamais renvoyées en lecture
3En cas d'erreur d'authentification ou de test de connexion, un message explicite est affiché
4En cas de succès, la connexion est validée et ajoutée à une liste paginée

Détail fonctionnel des critères

  1. 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).
  2. 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.
  3. Erreurs explicites

    • Back : exceptions métier (401 clé invalide, 403 scope insuffisant, URL injoignable, réponse HTML = mauvaise URL, etc.).
    • Front : message API (response.data.message) ou fallback via useNotify.
  4. Succès

    • Avant persistance : appel GET {baseUrl}/connection-check avec x-api-key (endpoint Formulaires).
    • Statut ACTIVE, last_validated_at renseigné.
    • Liste rafraîchie après création ; notification « Connexion enregistrée avec succès. »

3. Périmètre fonctionnel

Base de données

FichierRôle
sql/tool_12_add_api_connections.sqlMigration : enum ApiConnectionStatus, table api_connections
back/prisma/schema.prismaModèle Prisma api_connections + relation enterprises

Backend

FichierRôle
back/src/domains/encryption/encryptHelper.tsChiffrement / déchiffrement (ENCRYPTION_KEY obligatoire)
back/src/api/connections/connections.module.tsModule NestJS
back/src/app.module.tsEnregistrement de ConnectionsModule
back/src/api/connections/connections.controller.tsPOST/GET /connections, GET /connections/:uuid
back/src/api/connections/connections.service.tsVérification, création, liste, détail, getDecryptedApiKey (usage interne)
back/src/api/connections/connection.presenter.tsMapping réponse publique (sans secrets)
back/src/api/connections/dto/connection.dto.tsDTO création + réponses paginées
back/src/exceptions/api-connection.exceptions.tsExceptions métier HTTP

Dépendance Formulaires (test de connexion)

FichierRôle
formulaires/back/src/api-keys/connection-check.controller.tsGET /connection-check — valide la clé API (header x-api-key)

Frontend

FichierRôle
front/src/pages/connections/ConnectionsPage.vueListe paginée, état vide, badges ACTIVE / ERROR
front/src/pages/connections/ConnectionCreatePage.vueFormulaire de création + validation URL
front/src/stores/connections-store.jsfetchConnections, createConnection
front/src/router/routes.jsRoutes /connections, /connections/create
front/src/router/adminGuard.jsAccès réservé aux admins (redirection /dossiers sinon)
front/src/layouts/MainLayout.vueLien navigation Connexions

4. Endpoints API (Outil BDD)

MéthodeCheminGuardsDescription
POST/connectionsAuthGuard, AdminGuardCrée une connexion (vérifie puis chiffre la clé)
GET/connectionsAuthGuard, AdminGuardListe paginée (page, limit ≤ 100)
GET/connections/:uuidAuthGuard, AdminGuardDé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_id du jeton.
    • super-admin : voit toutes les connexions (toutes entreprises).
  • Création
    • Utilisateur sans entreprise → ApiConnectionEnterpriseRequiredException.
    • baseUrl normalisée (trim, suppression du / final).
    • Test GET {baseUrl}/connection-check avant insert (timeout 15 s).
    • Réponse text/html → URL pointe vers le front, pas l'API.
  • Lecture
    • Soft delete via deleted_at (filtré dans les requêtes).
    • getDecryptedApiKey(uuid) réservé aux usages internes futurs (sync, jobs).
  • Statut
    • Enum ACTIVE | ERROR (+ error_message, last_validated_at) pour le suivi opérationnel (comme les sources).

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 à /connections et /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éseau
    • createConnection : chiffrement, pas de persistance si échec vérif
    • getConnections : filtre entreprise vs super-admin
    • getConnection / getDecryptedApiKey : happy path et 404

Backend (e2e)

  • back/test/e2e/connections-controller.e2e-spec.ts
    • POST /connections : 401, 403, 400, clé refusée, URL HTML, 201 sans secret
    • GET /connections : 401, 403, 200 paginé
    • GET /connections/:uuid : 401, 403, 400 UUID, 404, 200

Frontend (unitaires)

  • front/src/__tests__/stores/connections-store.spec.jsfetchConnections, createConnection
  • front/src/__tests__/pages/connections/ConnectionsPage.spec.js — liste, vide, pagination, navigation création
  • front/src/__tests__/pages/connections/ConnectionCreatePage.spec.js — formulaire, validation URL, succès / erreur API
  • front/src/__tests__/layouts/MainLayout.spec.js — entrée menu Connexions selon rôle
  • front/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 renvoyer api_key_encrypted / api_key_iv dans les presenters.
  • Évolutions possibles (tickets suivants) : édition / suppression, re-test manuel, statut ERROR après échec planifié, connecteur Console admin, champ type si 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).