Files
office_translator/_bmad-output/implementation-artifacts/4-8-page-translation-progress-download.md
Sepehr Ramezani 26bd096a06 feat: production deployment - full update with providers, admin, glossaries, pricing, tests
Major changes across backend, frontend, infrastructure:
- Provider system with model selection (Google, DeepL, OpenAI, Ollama, Google Cloud)
- Admin panel: user management, pricing, settings
- Glossary system with CSV import/export
- Subscription and tier quota management
- Security hardening (rate limiting, API key auth, path traversal fixes)
- Docker compose for dev, prod, and IONOS deployment
- Alembic migrations for new tables
- Frontend: dashboard, pricing page, landing page, i18n (en/fr)
- Test suite and verification scripts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-25 15:01:47 +02:00

190 lines
9.5 KiB
Markdown

# Story 4.8: Page Translation - Progress & Download
Status: done
## Story
En tant qu'**utilisateur**,
Je veux **voir la progression de la traduction en temps réel et télécharger le fichier traduit**,
de sorte que **je sache quand mon fichier est prêt et puisse l'utiliser**.
## Acceptance Criteria
1. **Submit Translation**: Au clic sur "Translate", POST vers `/api/v1/translate` avec `file`, `source_lang`, `target_lang`, `mode`, `provider` (si LLM)
2. **Job ID Storage**: Stocker le `job_id` retourné (202 response: `{data: {id, status: "processing"}, meta: {...}}`)
3. **Progress Polling**: Poll `GET /api/v1/translations/{job_id}` toutes les 2 secondes pendant `status === "processing"`
4. **Progress Display**: Afficher progress bar (0-100%), `current_step`, et temps restant estimé (`meta.estimated_remaining_seconds`)
5. **Status Transitions**: `processing``completed` (succès) ou `failed` (erreur)
6. **Error Display**: Si `failed`, afficher `error_message` du backend avec toast notification
7. **Download Button**: Quand `completed`, afficher bouton "Download" qui GET `/api/v1/download/{job_id}`
8. **Download Filename**: Header `Content-Disposition` fourni par backend → `{original_name}_translated.{ext}`
9. **Success Toast**: Afficher confirmation après téléchargement réussi
10. **State Reset**: Option "New Translation" pour réinitialiser et uploader un nouveau fichier
11. **Merge Directive**: UI Progress depuis `frontend/src/components/file-uploader.tsx` (lignes 592-609)
12. **Colocation**: Composants/hooks/types dans `frontend/src/app/dashboard/translate/`
## Tasks / Subtasks
- [x] **Task 1: Étendre types.ts** (AC: #1, #2)
- [x] 1.1 Ajouter `TranslationJob`, `TranslationStatus`, `TranslationProgress`
- [x] 1.2 Ajouter `UseTranslationSubmitReturn` interface
- [x] **Task 2: Créer useTranslationSubmit.ts hook** (AC: #1, #2, #3, #4, #5)
- [x] 2.1 State: `jobId`, `status`, `progress`, `currentStep`, `error`, `estimatedRemaining`
- [x] 2.2 `submitTranslation(file, config)`: POST `/api/v1/translate` → return job_id
- [x] 2.3 `pollProgress()`: setInterval 2s → GET `/api/v1/translations/{job_id}`
- [x] 2.4 Cleanup interval on unmount ou quand status !== "processing"
- [x] 2.5 Return: `{ submitTranslation, jobId, status, progress, currentStep, error, estimatedRemaining, reset }`
- [x] **Task 3: Créer TranslationProgress.tsx** (AC: #4, #6)
- [x] 3.1 Props: `progress`, `currentStep`, `estimatedRemaining`, `error`
- [x] 3.2 Progress bar avec pourcentage (shadcn/ui Progress)
- [x] 3.3 Afficher `current_step` textuel (ex: "Translating slide 5/10")
- [x] 3.4 Afficher temps restant formaté (ex: "2 min remaining")
- [x] 3.5 Error state: message rouge si `status === "failed"`
- [x] 3.6 Copier styles depuis `file-uploader.tsx` (lignes 592-609)
- [x] **Task 4: Créer TranslationComplete.tsx** (AC: #7, #8, #9)
- [x] 4.1 Props: `jobId`, `fileName`, `onNewTranslation`
- [x] 4.2 Download button: GET `/api/v1/download/{job_id}` → trigger browser download
- [x] 4.3 Success toast après download
- [x] 4.4 "New Translation" button → callback `onNewTranslation`
- [x] 4.5 Checkmark icon + message "Translation Complete!"
- [x] 4.6 Copier styles depuis `file-uploader.tsx` (lignes 627-649)
- [x] **Task 5: Modifier page.tsx pour intégrer le flow complet** (AC: #1, #10)
- [x] 5.1 State flow: Upload → Config → Submit → Progress → Complete
- [x] 5.2 Intégrer `useTranslationSubmit` hook
- [x] 5.3 Conditionnel: afficher Progress si `status === "processing"`
- [x] 5.4 Conditionnel: afficher Complete si `status === "completed"`
- [x] 5.5 Conditionnel: afficher Error si `status === "failed"`
- [x] 5.6 `handleTranslate``submitTranslation(file, config.getConfig())`
- [x] 5.7 `handleNewTranslation` → reset all states
- [x] **Task 6: Vérifier le build et tester** (AC: Tous)
- [x] 6.1 `npm run build` → 0 erreurs TypeScript
- [x] 6.2 Tester submit translation → job_id retourné
- [x] 6.3 Tester polling progress → progress bar updates
- [x] 6.4 Tester download → fichier téléchargé
- [x] 6.5 Tester error handling → message affiché
- [x] 6.6 Tester new translation → reset complet
## Dev Notes
### 🏗️ Stack Technique
| Technologie | Version |
|-------------|---------|
| Next.js | 16.0.6 (App Router) |
| React | 19.2.0 |
| TanStack Query | v5.90.21 (optionnel - polling manuel OK) |
| Tailwind CSS | configuré |
| Lucide React | disponible |
| shadcn/ui | Progress, Button, Card, Toast |
### 📁 Structure Cible (Colocation Pattern)
```
frontend/src/app/dashboard/translate/
├── page.tsx # Existant — à modifier
├── types.ts # Existant — à étendre
├── useFileUpload.ts # Existant — pas de modif
├── FileDropZone.tsx # Existant — pas de modif
├── FilePreview.tsx # Existant — pas de modif
├── useTranslationConfig.ts # Existant — pas de modif
├── LanguageSelector.tsx # Existant — pas de modif
├── TranslationModeToggle.tsx # Existant — pas de modif
├── ProviderSelector.tsx # Existant — pas de modif
├── useTranslationSubmit.ts # 🆕 Hook submit + polling
├── TranslationProgress.tsx # 🆕 Progress bar + status
└── TranslationComplete.tsx # 🆕 Download + success
```
**⚠️ Règle absolue (architecture.md):**
```
🚨 FICHIERS SPÉCIAUX: page.tsx, layout.tsx → TOUJOURS minuscules
🚨 COLOCATION: Components/hooks/types dans le dossier de leur page
```
### 🔗 API Endpoints Backend (Déjà implémentés)
| Endpoint | Méthode | Request | Response |
|----------|---------|---------|----------|
| `/api/v1/translate` | POST | FormData: file, source_lang, target_lang, mode, provider | 202: `{data: {id, status: "processing"}, meta: {rate_limit_remaining}}` |
| `/api/v1/translations/{job_id}` | GET | — | `{data: {id, status, progress_percent, current_step, ...}, meta: {estimated_remaining_seconds}}` |
| `/api/v1/download/{job_id}` | GET | — | Binary file + Content-Disposition header |
### References
- [Source: _bmad-output/planning-artifacts/epics.md#Story-4.8] — Story requirements
- [Source: _bmad-output/planning-artifacts/architecture.md#Frontend-Architecture] — TanStack Query + colocation
- [Source: _bmad-output/planning-artifacts/architecture.md#API-Response-Formats] — Format réponse API
- [Source: routes/translate_routes.py#L1064-1151] — GET /api/v1/translations/{job_id} endpoint
- [Source: routes/translate_routes.py#L1188-1317] — GET /api/v1/download/{job_id} endpoint
- [Source: frontend/src/components/file-uploader.tsx#L592-649] — UI Progress + Download patterns
- [Source: _bmad-output/implementation-artifacts/4-7-page-translation-configuration.md] — Context config, types existants
## Dev Agent Record
### Agent Model Used
Claude Sonnet 4 (claude-sonnet-4@20250514)
### Debug Log References
N/A
### Completion Notes List
- ✅ Étendu types.ts avec TranslationStatus, TranslationJob, TranslationSubmitResponse, TranslationStatusResponse, UseTranslationSubmitReturn
- ✅ Créé useTranslationSubmit.ts hook avec submitTranslation, pollProgress (2s interval), cleanup on unmount, reset
- ✅ Créé TranslationProgress.tsx avec progress bar (shadcn/ui Progress), current_step display, temps restant formaté, error state
- ✅ Créé TranslationComplete.tsx avec download button (GET /api/v1/download), success toast, "New Translation" button
- ✅ Modifié page.tsx pour intégrer le flow complet: Upload → Config → Submit → Progress → Complete/Failed
- ✅ Build Next.js réussi (0 erreurs TypeScript)
### File List
**Fichiers créés:**
- frontend/src/app/dashboard/translate/useTranslationSubmit.ts
- frontend/src/app/dashboard/translate/TranslationProgress.tsx
- frontend/src/app/dashboard/translate/TranslationComplete.tsx
**Fichiers modifiés:**
- frontend/src/app/dashboard/translate/types.ts
- frontend/src/app/dashboard/translate/page.tsx
- _bmad-output/implementation-artifacts/sprint-status.yaml (in-progress → review)
## Senior Developer Review (AI)
**Reviewer:** Code Review Agent
**Date:** 2026-02-23
**Outcome:** Changes Requested → Fixed → Approved
**Issues Found:** 9 (3 High, 4 Medium, 2 Low)
### Critical Issues Fixed
1. **AC #6 Not Fully Implemented** (HIGH) - Error toast notification added in page.tsx useEffect
2. **Silent Polling Failures** (HIGH) - Polling failures now tracked and surfaced to user after 3 consecutive failures
3. **Race Condition** (HIGH) - Added `isPollingRef` to prevent overlapping poll requests
### Medium Issues Fixed
4. **Memory Leak** (MEDIUM) - Blob URL now properly managed with useRef and cleanup on unmount
5. **No Upload Progress** (MEDIUM) - Submit button now shows "Uploading..." with spinner during file upload
6. **No Retry Tracking** (MEDIUM) - Added `pollingFailures` state and `MAX_POLLING_FAILURES` constant
7. **Accessibility** (MEDIUM) - Added ARIA attributes to Progress component and error alerts
### Code Quality Improvements Applied
- Added `isPolling` and `pollingFailures` to hook return type
- Enhanced error messages for network failures
- Added visual indicator when connection is lost during translation
- Proper cleanup of intervals and blob URLs on component unmount
## Change Log
- 2026-02-23: Story created - ready for development
- 2026-02-23: Implementation complete - all 6 tasks completed, build successful, ready for review
- 2026-02-23: Code review complete - 9 issues identified and fixed, all HIGH/MEDIUM issues resolved