Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 2m14s
Foundations:
- TranslationSegment model + migration f7e8d9c0b1a2 (segments, workspaces,
workspace_members, glossaries.workspace_id)
- SegmentRecorder injected into all 4 translators: unique (source,
translation) pairs captured per job and persisted (best-effort)
- set_segment_overrides: human-reviewed translations applied verbatim on
rebuild — top priority over TM and provider, zero API calls
Review API (routes/review_routes.py):
- GET /translations/{id}/segments (owner or job token)
- PATCH /segments/{id} edit/approve — feeds the per-user TM so approved
translations are reused in later jobs
- POST /translations/{id}/rebuild — rebuild document with reviewed text
- GET/POST /translations/{id}/xliff — XLIFF 1.2 export/import (edited
segments export their reviewed text)
Review editor (frontend /dashboard/reviews/[jobId]):
- side-by-side source/translation table, inline edit, approve (single or
all), rebuild & download (auth blob), XLIFF export/import, 13 locales
- 'Relire et corriger' link on the translation-complete screen
Team workspaces (routes/workspace_routes.py + /dashboard/teams):
- Workspace/WorkspaceMember models, roles owner/admin/member
- create (Business plan), list with seat usage, invite by email with
seat-limit enforcement (Business=5, Enterprise unlimited), removal
- shared glossaries: workspace members can use a glossary shared to their
workspace (access check extended)
Tests: 1184 passed / 0 failed (11 new: recorder, overrides, docx
capture->rebuild e2e, XLIFF structure/escaping, seats, workspace CRUD,
shared glossary access)
4.8 KiB
4.8 KiB
Chantier « fondations produit » — relecture, équipes, XLIFF (2026-08-29)
Décision de la session : aucune intégration DeepL. Tout ce qui suit est 100 % moteur maison/LLM existants.
1. Fondation : persistance des segments par job
- Modèle
TranslationSegment(database/models.py) : paires (source, traduction) par job et par utilisateur, avec statut de relecture (pending | approved | edited), texte relu, index, horodatages. - Migration
f7e8d9c0b1a2(alembic) :translation_segments,workspaces,workspace_members,glossaries.workspace_id. Appliquée et vérifiée sur base vierge (chaîne complète 001→tête) et sur la base de dev. - Capture (
translators/segments.py) : unSegmentRecorderest injecté par la route dans les 4 traducteurs (docx/xlsx/pptx/pdf). Il enregistre chaque paire unique dans l'ordre du document ; les paires identiques (non traduites) sont ignorées pour garder la liste actionnable. - Overrides :
set_segment_overrides()applique les traductions relues par l'humain mot pour mot lors de la reconstruction — priorité maximale (avant TM et provider), zéro appel API, zéro dérive. - Persistance : après un job réussi, la route stocke les segments en base (best-effort, n'échoue jamais le job).
2. API de relecture (routes/review_routes.py)
| Endpoint | Rôle |
|---|---|
GET /api/v1/translations/{job_id}/segments |
Liste des segments + compteurs (accès propriétaire ou token du job) |
PATCH /api/v1/segments/{id} |
Éditer (reviewed_text + status=edited) ou approuver — alimente aussi la TM par utilisateur (les traductions relues sont réutilisées dans les jobs suivants) |
POST /api/v1/translations/{job_id}/rebuild |
Reconstruit le document avec les segments approuvés/modifiés (le texte relu est appliqué tel quel) puis pointe le téléchargement dessus |
GET /api/v1/translations/{job_id}/xliff |
Export XLIFF 1.2 (les segments modifiés exportent leur texte relu) |
POST /api/v1/translations/{job_id}/xliff |
Import XLIFF : met à jour les segments (cible ≠ machine → edited, sinon approved) |
Note UX : la reconstruction nécessite le fichier source encore présent (rétention 30 min). Au-delà, le messageInvite à re-téléverser — et les segments approuvés étant dans la TM, la nouvelle traduction les réutilise automatiquement.
3. Éditeur de relecture (frontend)
/dashboard/reviews/[jobId]— tableau côte à côte Source | Traduction, édition inline, badges de statut, approbation unitaire ou « Tout approuver », Reconstruire et télécharger (blob authentifié), export/import XLIFF. Libellés 13 locales.- Lien « Relire et corriger la traduction » sur l'écran de fin de
traduction (
TranslationComplete).
4. Espaces de travail équipes (routes/workspace_routes.py)
- Modèles
Workspace/WorkspaceMember(rôlesowner | admin | member). - Endpoints : création (plan Business requis), liste (avec rôle, sièges utilisés/limite), ajout de membre par e-mail avec application de la limite de sièges du plan du propriétaire (Business = 5, Enterprise illimité), retrait (owner impossible à retirer).
- Glossaires partagés :
glossaries.workspace_id— le contrôle d'accès (get_glossary_terms,validate_glossary_access) accepte désormais le propriétaire et les membres du workspace. - Page
/dashboard/teams: création d'espace, liste des membres, invitation (e-mail + rôle), retrait, compteur de sièges, gate Business. - Facturation multi-sièges : v1 = application de la limite de sièges du plan. (La facturation au siège réel côté Stripe — subscription items — reste un chantier facturation à part.)
5. Tests & vérifications
- Nouveaux tests (
tests/test_review_foundation.py, 11) : recorder, overrides, capture→rebuild de bout en bout sur un vrai docx (le texte relu atterrit dans le fichier reconstruit, le reste reste machine), structure XLIFF + échappement XML, sièges, CRUD workspace, glossaire partagé (membre OK / extérieur refusé). - Suite backend complète : voir résultat final ci-dessous.
tsc --noEmitOK sur les deux frontends ; navigation « Équipe » (Pro+) et lien « Relire » ajoutés.
6. Non livré (justifié)
- IDML / DITA : spécifications de formats complètes à part entière (structure InDesign / arbres DITA) — nouveaux parseurs dédiés, à chiffrer séparément.
- Facturation Stripe au siège (mètre temps réel des sièges) : la limite plan est appliquée ; le mètre Stripe nécessite des subscription items et un webhooks sièges.
- Éditeur de relecture temps réel multi-utilisateur (verrouillage de segment, présence) : nécessite WebSocket + verrous — v1 = relecture solo/équipe asynchrone.