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>
64 lines
2.9 KiB
YAML
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
|