TQ-Slator/config/packages/api_platform.yaml
Stephan Morand 9025c64c0b Socle complet de TQ-Slator : éditeur, API, CLI, administration
Système de gestion de traductions pensé en CMS headless : un back-office
pour ceux qui traduisent, une API pour ce qui consomme.

Architecture
- Symfony 7.4 / API Platform 4.3 / MariaDB 11.4, SPA React 19 servie en
  même origine — ce qui rend viable le cookie de session plutôt qu'un
  jeton en localStorage.
- Deux APIs séparées : Management (session ou clé) et Delivery
  (stateless, clé seule). Les fusionner ferait porter à chaque lecture de
  bundle le coût de la session.
- Stockage canonique en ICU MessageFormat, sérialisation par plateforme.
  Le format d'une plateforme ne contamine pas la base.
- Publication par releases immuables ; le déploiement est un déplacement
  de pointeur, donc le rollback aussi.
- Isolation multi-organisation par filtre Doctrine, avec un test
  d'architecture qui casse la CI si une entité échappe à l'invariant.

Éditeur, deux vues
- Par langue : source et cible, jamais douze colonnes. Grille virtualisée,
  saisie sans bouton « Enregistrer », panneau de contexte permanent.
- Par clé : une clé, toutes ses langues empilées et repliées. Répond à
  « ce libellé est-il prêt partout ? ».
- Mode Focus dans les deux : une file à vider, ⌘↵ pour enchaîner.
- Le traducteur ne voit jamais d'ICU : pastilles de variables, un champ
  par catégorie CLDR de la langue cible.

Administration
- Deux niveaux : projet (membres, clés API, plateformes) et organisation
  (annuaire des comptes, création de projets).
- Invitations par e-mail, jeton 256 bits stocké haché.
- Désactiver un compte coupe les sessions en cours, pas seulement les
  connexions suivantes.
- Les plateformes s'archivent ; ni elles ni les environnements ne se
  suppriment — la trace explique pourquoi telle clé existe.

CLI tqs
- PHAR autonome de 3 Mo, autoloader généré : le dépôt client ne dépend
  ni de Composer ni de la disponibilité de TQ-Slator.
- init / push / pull / status ; le sync est non destructif par défaut et
  son prune est scopé plateforme.

126 tests, PHPStan niveau 8.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 08:16:05 +02:00

64 lines
2.9 KiB
YAML

api_platform:
title: 'TQ-Slator — Management API'
version: '1.0.0'
description: |
API de gestion des traductions.
Deux APIs cohabitent et ne doivent pas être confondues :
- **Management API** (`/api/v1`, cette documentation) — création de clés,
saisie de traductions, administration. Authentification par session
(back-office) ou par clé API scopée (CLI, intégrations).
- **Delivery API** (`/delivery/v1`) — lecture des bundles publiés par les
applications en production. Immuable, cachable, clé API en lecture seule.
Le stockage des valeurs est **toujours** en ICU MessageFormat canonique.
Les formats propres aux plateformes (i18next…) sont produits à la
publication, jamais stockés.
formats:
# JSON-LD par défaut : il apporte hydra:totalItems et hydra:view, dont la
# grille virtualisée du back-office a besoin pour dimensionner sa barre de
# défilement. Le JSON nu renvoie un tableau sans métadonnée de pagination.
jsonld: ['application/ld+json']
# Disponible via Accept: application/json — c'est ce que consomment le CLI
# et les intégrations simples, qui n'ont que faire d'Hydra.
json: ['application/json']
docs_formats:
jsonopenapi: ['application/vnd.openapi+json']
html: ['text/html']
defaults:
# Combiné au préfixe /api du routing d'API Platform, les ressources
# sortent sous /api/v1/... — versionné dès le premier jour, parce
# qu'ajouter une version à une API déjà consommée est un chantier.
route_prefix: /v1
# `false` est imposé par le choix d'authentification par session
# (cookie SameSite + CSRF) plutôt que par jeton porteur : Symfony refuse
# de lire la session sur une requête déclarée sans état.
#
# Conséquence : les réponses de la Management API ne sont pas cachables
# publiquement. Ce n'est pas un problème — c'est la Delivery API qui
# porte la charge de lecture, et elle est stateless de bout en bout.
stateless: false
cache_headers:
vary: ['Content-Type', 'Authorization', 'Origin']
pagination_client_items_per_page: true
pagination_maximum_items_per_page: 500
pagination_items_per_page: 50
swagger:
# Déclare le schéma d'authentification pour que le bouton « Authorize »
# de la page de documentation soit fonctionnel. Sans lui, les endpoints
# sont documentés mais impossibles à essayer depuis un navigateur, ce qui
# vide la doc interactive de son intérêt.
api_keys:
cleApi:
name: Authorization
type: header
exception_to_status:
App\Translation\Format\Exception\MessageParseException: 422
App\Translation\Format\Exception\UnsupportedMessageFeatureException: 422