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>
190 lines
9.5 KiB
Markdown
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
|