ISNAD Scientific Platform

Documentation Center
V1 · Référence officielle

Architecture

Atelier des ouvrages — architecture, configuration et exploitation

7 min de lectureMis à jour le 29 octobre 2026
Sur cette page

Module d'administration /{locale}/admin/book-workshop (story E14-S07). Espace privé de préparation d'un ouvrage arabe et de sa traduction française : téléverser, structurer, traduire, corriger l'arabe, réviser, décider.

État. Code intégré, désactivé par défaut. La migration est une candidate non appliquée (supabase/candidates/book-workshop/). Aucun ouvrage n'est chargé, aucun fournisseur n'a été appelé, rien n'est publié. L'activation, le chargement d'un ouvrage et l'import public sont trois décisions séparées.

1. Principes#

  • L'arabe documentaire est la référence ; le texte brut n'est jamais réécrit. Une correction de l'arabe est journalisée (motif obligatoire) et rend périmée la traduction liée.
  • Une traduction est une donnée dérivée et versionnée ; les versions sont en ajout seul.
  • Une relecture par IA n'est jamais une validation humaine. Une validation humaine est une décision : explicite, attribuée à l'administrateur de la session, journalisée, et elle crée une nouvelle version.
  • Préparer un ouvrage n'est pas le publier.

2. Architecture#

CoucheContenu
src/app/api/admin/book-workshop/**routes minces : elles délèguent à bookWorkshopApi()
src/app/[locale]/(site)/admin/book-workshop/**pages (client) ; garde de session et de drapeau dans layout.tsx
src/features/book-workshop/**interface FR/AR (i18n existante), client HTTP authentifié
src/domain/book-workshop/**logique pure : segmentation, contrôles, filiation des unités, contrat du chargement d'état, profils supportés, erreurs
src/server/book-workshop/**services : configuration, cas d'usage HTTP (api.ts), boucle d'exécution des lots (worker.ts), composition
src/infrastructure/book-workshop/**adaptateurs : SQL (postgres/), connexion propre (postgres/pool.ts), fournisseurs de traduction

Les services serveur ne contiennent aucun SQL. Le navigateur n'appelle que /api/admin/book-workshop/* avec le jeton de session ; il n'accède ni à la base ni au fournisseur.

Chaque requête suit l'ordre : drapeau → administrateur → contrat d'entrée → magasin. Une requête refusée n'atteint ni le stockage de l'atelier ni un fournisseur.

3. Variables d'environnement (serveur uniquement)#

VariableRôleDéfaut
BOOK_WORKSHOP_ENABLEDactive le module ; seule la valeur littérale true activedésactivé
BOOK_WORKSHOP_DATABASE_URLconnexion propre à l'atelier ; aucun repli sur une autre variable—
BOOK_WORKSHOP_DB_CA_CERTautorité de certification (PEM) quand le certificat du serveur n'est pas signé par une autorité publiqueautorités du système
BOOK_WORKSHOP_PUBLIC_IMPORT_ENABLEDautorise « Importer dans ISNAD » ; indépendant de l'activationdésactivé
OPENAI_API_KEY, ISNAD_TRANSLATION_MODEL_NORMAL, ISNAD_TRANSLATION_MODEL_ESCALATED, BOOK_WORKSHOP_MODELSmoteur de traduction E14 existant et modèles proposés—
BOOK_WORKSHOP_PRICING_JSONtarif par modèle ; sans lui le coût est « inconnu », jamais inventéinconnu
BOOK_WORKSHOP_PROVIDER=simulationfournisseur simulé pour les tests ; interdit en production sauf BOOK_WORKSHOP_ALLOW_SIMULATION=true—
BOOK_WORKSHOP_PROVIDER_TIMEOUT_MSdélai d'un appel fournisseur90 000
BOOK_WORKSHOP_MARKDOWN_MAX_BYTES, BOOK_WORKSHOP_LAYOUT_MAX_BYTES, BOOK_WORKSHOP_PDF_MAX_BYTESlimites de téléversement4 Mo / 3 Mo / 3 Mo
BOOK_WORKSHOP_LEASE_SECONDS, BOOK_WORKSHOP_WORKER_TIME_BUDGET_MSbail d'un lot ; durée d'un passage180 ; 240 000

Aucune valeur de secret n'est renvoyée au navigateur ni écrite dans un journal.

Connexion. La vérification du certificat TLS est toujours active pour un hôte distant ; elle n'est jamais désactivée pour faire fonctionner une connexion. Le rôle de cette connexion n'est pas présumé limité : son choix et ses privilèges minimaux sont décrits dans supabase/candidates/book-workshop/README.md et décidés au gate d'activation.

4. Drapeau désactivé#

  • Les routes de l'atelier répondent 503 DISABLED à un administrateur, sans ouvrir de connexion.
  • Les pages de l'atelier affichent « module désactivé » ; le lien de l'administration est masqué.
  • Le cockpit /admin/translations est exactement le cockpit des notices.
  • L'absence du schéma n'empêche rien de se charger.

5. Cockpit des traductions#

Quand l'atelier est activé, ses ouvrages apparaissent dans Administration → Traductions à côté des notices. Le magasin de l'atelier est secondaire : s'il échoue (schéma absent, base injoignable), les notices restent servies, la réponse porte degraded et l'interface dit que les ouvrages privés sont indisponibles et que les comptages ne les incluent pas. Une panne n'est jamais transformée en liste vide ni en « introuvable », et une décision portant sur un ouvrage n'est jamais redirigée vers les notices.

6. Décisions de revue#

Un seul service de décision pour l'écran de révision de l'atelier et pour le cockpit (executeReviewCommand → BookWorkshopCockpitPort.recordReview) : acteur issu de la session, contrôle de la version retenue, décision journalisée (review_decisions), nouvelle version, transaction unique, clé d'idempotence (une demande répétée est rejouée, jamais enregistrée deux fois).

  • Valider : possible seulement sur une traduction retenue, à jour, déclarée complète, non simulée.
  • Corriger : qualité de la version remplacée et motif obligatoires.
  • Une unité sans traduction peut recevoir une première rédaction humaine ; elle est attribuée et non validée.

7. Profil documentaire#

La liste des profils pris en charge est fermée (SupportedBookProfiles.ts). Le profil d'un ouvrage est déclaré explicitement par un administrateur, à la première traduction ou au premier chargement ; il n'y a pas de profil par défaut, et un profil non pris en charge est refusé.

8. Restructuration#

Une nouvelle segmentation (autre mise en page OCR, autre version du segmenteur) ne reporte rien sur la seule foi d'un identifiant. La filiation est décidée d'après l'empreinte du texte brut (UnitLineage.ts) :

ÉtatConditionReporté
UNCHANGEDmême identifiant, même type, même texte brut, unique des deux côtésidentité de revue, corrections de l'arabe, traduction retenue, validation humaine
SOURCE_CHANGEDmême identifiant et type, arabe différentidentité et traduction (épinglée sur l'ancien arabe : périmée) ; pas la validation humaine
AMBIGUOUScorrespondance non établie (texte partagé, identifiant réattribué, autre type)rien
NEWaucune unité antérieurerien

Une unité divisée ou fusionnée ne reçoit jamais de validation humaine. Les segmentations précédentes restent intactes et consultables (versions, corrections, décisions) dans l'historique de l'unité.

9. Charger un état de traduction produit hors site#

Tableau de bord de l'ouvrage → « Charger un état de traduction » : corpus isnad-book-corpus-v1 (JSONL) et, s'il existe, journal des corrections OCR. Les fichiers sont compressés par le navigateur (4 Mo au plus compressés, 40 Mo au plus décompressés).

Refusé avant toute écriture : format inconnu, identifiants en double, identifiants absents de la segmentation active, statut de relecture inconnu, validation ou origine humaine déclarée dans le fichier. Une complétude absente est enregistrée unknown : la traduction ne peut pas être validée telle quelle.

Le chargement est une transaction unique, sérialisée par ouvrage : en cas d'erreur rien n'est conservé. « Vérifier » exécute le même traitement et l'annule. Un chargement dont une partie a été écartée (correction inapplicable, traduction épinglée sur un autre arabe) est déclaré incomplet. Recharger le même état ne crée ni version ni décision. Une version humaine retenue n'est jamais remplacée.

10. Exécution des lots de traduction#

POST /api/admin/book-workshop/worker par un administrateur, un passage à la fois. Aucun planificateur, aucun secret partagé, aucun GET : rien n'est traduit sans demande explicite. L'état durable (travaux, lots, tentatives, budget) vit dans le schéma privé.

11. Import vers ISNAD (désactivé par défaut)#

« Vérifier l'import » et « Importer dans ISNAD » écrivent dans le modèle commentary_*, dont les sources et éditions sont lisibles publiquement : importer rend visibles le titre et les métadonnées de l'ouvrage. L'action est donc refusée par le serveur tant que BOOK_WORKSHOP_PUBLIC_IMPORT_ENABLED n'est pas true, et l'interface ne l'affiche pas. PUBLISHED n'est jamais écrit par l'atelier.

Constats de la certification T03 (base isolée) — à résoudre avant toute autorisation de l'import public :

  • l'import écrit dans public.commentary_* par la connexion de l'atelier : le rôle applicatif limité (book_workshop_app) n'y a aucun droit, l'import échoue donc (503 STORE_UNAVAILABLE) ; lui accorder ces droits élargirait la posture privée de cette connexion ;
  • l'import n'est pas atomique : une erreur en cours laisse dans les tables publiques la source, l'édition et une partie des passages et traductions (une nouvelle exécution complète l'import, mais l'état intermédiaire est public) ;
  • les métadonnées publiées de la source et de l'édition contiennent des identifiants internes de l'atelier (ouvrage, segmentation, empreinte du Markdown) et une clé dérivée du nom du fichier téléversé ;
  • anon lit la source (titres, auteur, statuts) et l'édition ; il ne lit ni les passages ni les traductions.

12. Tests#

npm run test:book-workshop:unit   # domaine, fournisseur, configuration
npm run test:book-workshop        # intégration PGlite : téléversement → décisions → chargement d'état
npm run test:book-workshop-t02    # régressions : drapeau, autorisations, panne, import public, filiation, contrats
npm run test:book-workshop-t03    # certification : filiation (arabe changé, texte déplacé, fusion), notes, rechargement des corrections
npm run test:book-workshop-pg     # PostgreSQL réel : rôles et droits effectifs, RLS, ajout seul, concurrence, atomicité, retour arrière (CI)

La fixture est synthétique (scripts/validation/fixtures/book-workshop/build-synthetic-fixture.mjs) ; le fournisseur est simulé. Aucun secret ni appel réseau n'est nécessaire.

13. Avant toute activation#

  1. Certification T03, puis promotion et application de la migration candidate (acte autorisé séparément).
  2. Choix du rôle de connexion et de l'autorité de certification. Ni le rôle postgres (il contourne la RLS) ni service_role ne conviennent ; book_workshop_app n'existe pas encore en production. Lu en production le 2026-10-03 : la chaîne de certificats du pooler Supabase n'est pas vérifiable avec les autorités du système, donc BOOK_WORKSHOP_DB_CA_CERT sera nécessaire.
  3. Approbation du schéma book_workshop au regard de la taxonomie (ADR-0002).
  4. Activation du drapeau ; le chargement d'un ouvrage et l'import public restent des décisions distinctes.