Files
office_translator/_bmad-output/implementation-artifacts/2-11-progress-feedback-temps-reel.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

350 lines
13 KiB
Markdown

# Story 2.11: Progress Feedback Temps Reel
Status: done
## Story
As a **user**,
I want **to see real-time progress during translation**,
So that **I know the status of my translation**.
## Acceptance Criteria
1. **AC1: Progress Endpoint** - GET /api/v1/translations/{id} returns `{data: {id, status, progress_percent, current_step}, meta: {...}}`
2. **AC2: Real-time Latency** - Progress updates within 500ms of actual progress (NFR3)
3. **AC3: Status Values** - Status can be: "queued", "processing", "completed", "failed"
4. **AC4: LLM Progress Details** - For LLM mode, progress shows "translating slide X/Y" or "processing cell X/Y"
5. **AC5: Progress Percentage** - progress_percent field shows 0-100 based on completion
6. **AC6: Current Step** - current_step field describes what's being processed (e.g., "Validating file", "Translating sheet 1", "Generating output")
7. **AC7: Error State** - Failed translations return status "failed" with error_message in response
8. **AC8: Job Not Found** - Invalid job ID returns 404 with error "NOT_FOUND"
## Tasks / Subtasks
- [x] **Task 1: Extend Job Data Model** (AC: 1, 5, 6)
- [x] 1.1 Add `progress_percent` (int 0-100) to job dict
- [x] 1.2 Add `current_step` (str) to job dict
- [x] 1.3 Add `total_items` and `processed_items` for granular tracking
- [x] 1.4 Add `error_message` field for failed jobs
- [x] **Task 2: Create Progress Tracker Service** (AC: 2, 4)
- [x] 2.1 Create `ProgressTracker` class with callback mechanism
- [x] 2.2 Implement `update_progress(job_id, percent, step)` method
- [x] 2.3 Support item-based progress: `update_item(job_id, current, total, item_name)`
- [x] 2.4 Store progress in Redis or in-memory dict (consistent with existing pattern)
- [x] **Task 3: Update Translation Processors** (AC: 4)
- [x] 3.1 Modify `excel_translator.py` to report progress per sheet/cell batch
- [x] 3.2 Modify `word_translator.py` to report progress per paragraph/section
- [x] 3.3 Modify `pptx_translator.py` to report progress per slide
- [x] 3.4 Add `progress_callback` parameter to translator functions
- [x] **Task 4: Update Translation Job Processor** (AC: 2, 4)
- [x] 4.1 Modify `_run_translation_job()` to use ProgressTracker
- [x] 4.2 Set initial status "queued" before processing starts
- [x] 4.3 Update to "processing" with progress during translation
- [x] 4.4 Pass progress_callback to translators
- [x] **Task 5: Enhance Status Endpoint** (AC: 1, 3, 7, 8)
- [x] 5.1 Update `GET /api/v1/translations/{job_id}` to include all new fields
- [x] 5.2 Return proper 404 for non-existent jobs
- [x] 5.3 Include error_message for failed status
- [x] 5.4 Add response schema with all fields documented
- [x] **Task 6: Create Response Schemas** (AC: 1)
- [x] 6.1 Create `TranslationStatusResponse` Pydantic model
- [x] 6.2 Create `TranslationStatusData` with all progress fields
- [x] 6.3 Create `TranslationStatusMeta` for metadata
- [x] **Task 7: Add Unit Tests** (AC: All)
- [x] 7.1 Test progress updates are reflected correctly
- [x] 7.2 Test status transitions (queued → processing → completed/failed)
- [x] 7.3 Test 404 for non-existent job
- [x] 7.4 Test error state includes error_message
- [x] 7.5 Test LLM mode progress shows item details
- [x] **Task 8: Update OpenAPI Documentation** (AC: All)
- [x] 8.1 Document all response fields
- [x] 8.2 Add example responses for each status
- [x] 8.3 Document error codes
## Dev Notes
### Previous Story Intelligence (Story 2.10)
**Existing Job Storage Pattern:**
```python
# In translate_routes.py
_translation_jobs: dict[str, dict] = {}
# Job structure (current):
_translation_jobs[job_id] = {
"id": job_id,
"status": "processing",
"file_name": original_filename,
"source_lang": source_lang,
"target_lang": target_lang,
"created_at": datetime.now(timezone.utc).isoformat(),
"user_id": user_id,
"input_path": str(input_path),
"file_extension": file_extension,
"provider": provider or mode,
"webhook_url": webhook_url,
"custom_prompt": custom_prompt,
"glossary_id": glossary_id,
}
```
**Existing Status Endpoint (needs enhancement):**
```python
@router_v1.get("/translations/{job_id}")
async def get_translation_status(job_id: str, ...):
job = _translation_jobs.get(job_id)
if not job:
return JSONResponse(status_code=404, ...)
# Currently returns: id, status, file_name, source_lang, target_lang, created_at
# NEEDS: progress_percent, current_step, error_message
```
**Background Processing Pattern:**
```python
asyncio.create_task(
_run_translation_job(
job_id=job_id,
input_path=input_path,
...
)
)
```
### Architecture Compliance
Per `_bmad-output/planning-artifacts/architecture.md`:
**Response Format (Success):**
```json
{
"data": {
"id": "tr_abc123",
"status": "processing",
"progress_percent": 45,
"current_step": "Translating sheet 2/5",
"file_name": "report.xlsx",
"source_lang": "en",
"target_lang": "fr",
"created_at": "2024-01-15T10:30:00Z"
},
"meta": {
"estimated_remaining_seconds": 8
}
}
```
**Response Format (Completed):**
```json
{
"data": {
"id": "tr_abc123",
"status": "completed",
"progress_percent": 100,
"current_step": "Translation complete",
"file_name": "report.xlsx",
"created_at": "2024-01-15T10:30:00Z",
"completed_at": "2024-01-15T10:30:45Z"
},
"meta": {}
}
```
**Response Format (Failed):**
```json
{
"data": {
"id": "tr_abc123",
"status": "failed",
"progress_percent": 30,
"current_step": "Error during translation",
"error_message": "Provider unavailable: timeout after 30s",
"file_name": "report.xlsx",
"created_at": "2024-01-15T10:30:00Z",
"failed_at": "2024-01-15T10:30:15Z"
},
"meta": {}
}
```
**Response Format (Not Found):**
```json
{
"error": "NOT_FOUND",
"message": "Job de traduction non trouve.",
"details": {"job_id": "tr_nonexistent"}
}
```
### Naming Conventions (Per Architecture)
| Element | Convention | Example |
|---------|------------|---------|
| Variables | snake_case | `progress_percent`, `current_step` |
| JSON fields | snake_case | `progress_percent`, `current_step`, `error_message` |
| Classes | PascalCase | `ProgressTracker`, `TranslationStatusResponse` |
| Functions | snake_case | `update_progress()`, `get_translation_status()` |
### Implementation Approach
**ProgressTracker Class Design:**
```python
class ProgressTracker:
"""Track translation progress with callback support."""
def __init__(self, job_id: str, storage: dict):
self.job_id = job_id
self.storage = storage # Reference to _translation_jobs
def update(self, percent: int, step: str) -> None:
"""Update progress percentage and current step."""
job = self.storage.get(self.job_id)
if job:
job["progress_percent"] = min(100, max(0, percent))
job["current_step"] = step
def update_item(self, current: int, total: int, item_name: str) -> None:
"""Update progress based on item count (e.g., slides, sheets)."""
percent = int((current / total) * 100) if total > 0 else 0
step = f"{item_name} {current}/{total}"
self.update(percent, step)
```
**Translator Integration Pattern:**
```python
# In translators/excel_translator.py
def translate_file(
self,
input_path: Path,
output_path: Path,
target_lang: str,
source_lang: str = "auto",
progress_callback: Optional[Callable[[int, str], None]] = None
) -> None:
# ... validation ...
total_sheets = len(workbook.sheetnames)
for idx, sheet_name in enumerate(workbook.sheetnames):
# Process sheet...
if progress_callback:
progress = int((idx + 1) / total_sheets * 100)
progress_callback(progress, f"Translating sheet {idx + 1}/{total_sheets}")
```
### Project Structure Notes
**Files to Modify:**
- `routes/translate_routes.py` - Update job storage, status endpoint
- `translators/excel_translator.py` - Add progress callback
- `translators/word_translator.py` - Add progress callback
- `translators/pptx_translator.py` - Add progress callback
**Files to Create:**
- `services/progress_tracker.py` - ProgressTracker class (optional, can be inline)
### Git Intelligence - Recent Patterns
From recent commits:
- Translation cache implemented (5000 entry LRU cache)
- OpenRouter provider with DeepSeek support
- Parallel processing optimizations
- Redis sessions for production
### Dependencies on Previous Stories
| Story | Dependency |
|-------|------------|
| 2.10 | Job storage pattern (`_translation_jobs` dict) |
| 2.7 | ExcelProcessor structure for progress hooks |
| 2.8 | WordProcessor structure for progress hooks |
| 2.9 | PowerPointProcessor structure for progress hooks |
### Anti-Patterns to Avoid
1. **Don't use blocking calls** - Progress updates must be fast, non-blocking
2. **Don't exceed 500ms latency** - NFR3 requirement
3. **Don't log file content** - Only progress metadata (NFR11, NFR16)
4. **Don't break existing API contract** - Extend, don't modify existing response fields
5. **Don't create tight coupling** - Progress callback should be optional parameter
### Performance Considerations
- Progress updates should be O(1) - simple dict updates
- Avoid polling Redis on every progress update if using Redis
- Consider throttling updates (max 10 per second) for high-frequency operations
- Use in-memory dict for MVP (already established pattern in Story 2.10)
### Testing Strategy
```bash
# Unit tests
pytest tests/test_progress_tracking.py -v
# Integration tests
pytest tests/test_translate_endpoint.py -v -k "progress"
# With coverage
pytest tests/ --cov=routes/translate_routes --cov=translators -v
```
### References
- [Source: _bmad-output/planning-artifacts/epics.md#Story 2.11]
- [Source: _bmad-output/planning-artifacts/architecture.md#API Response Formats]
- [Source: _bmad-output/planning-artifacts/prd.md#FR47 Real-time progress]
- [Source: _bmad-output/planning-artifacts/prd.md#NFR3 Progress latency < 500ms]
- [Source: _bmad-output/implementation-artifacts/2-10-endpoint-post-api-v1-translate-core.md - Previous story]
- [Source: routes/translate_routes.py - Current job storage and status endpoint]
- [Source: services/translation_service.py - Translation batch processing pattern]
## Dev Agent Record
### Agent Model Used
glm-5
### Debug Log References
None
### Completion Notes List
1. **Task 1 Complete**: Extended job data model with progress_percent (0-100), current_step (str), total_items, processed_items, and error_message fields. Job status now starts as "queued" and transitions to "processing" when work begins.
2. **Task 2 Complete**: Created `services/progress_tracker.py` with ProgressTracker class. Includes `update()`, `update_item()`, `set_error()`, and `set_completed()` methods. Thread-safe with throttling (50ms min interval) to meet NFR3 <500ms latency requirement.
3. **Task 3 Complete**: All translators (excel, word, pptx) already have progress_callback support. Updated `_run_translation_job()` to create and pass progress callback to translators.
4. **Task 4 Complete**: Modified `_run_translation_job()` to use ProgressTracker. Sets initial status "queued", transitions to "processing", and passes progress_callback to translators. Uses `set_completed()` and `set_error()` for final states.
5. **Task 5 Complete**: Enhanced `GET /api/v1/translations/{job_id}` to include progress_percent, current_step, and error_message fields. Returns 404 for non-existent jobs with proper error format.
6. **Task 6 Complete**: Created Pydantic response schemas: TranslationStatusData, TranslationStatusMeta, TranslationStatusResponse with all progress fields documented.
7. **Task 7 Complete**: Created `tests/test_progress_tracking.py` with 18 comprehensive tests covering ProgressTracker class, job data model, status endpoint behavior, status transitions, and LLM progress details. All 18 tests pass.
8. **Task 8 Complete**: Added comprehensive OpenAPI documentation in the status endpoint docstring with example responses for each status (processing, completed, failed, not found).
### File List
**Created files:**
- `services/progress_tracker.py` - ProgressTracker class with update(), update_item(), set_error(), set_completed() methods
- `tests/test_progress_tracking.py` - 18 unit tests for progress tracking
**Modified files:**
- `routes/translate_routes.py` - Added progress fields to job creation, integrated ProgressTracker, enhanced status endpoint with new fields, added response schemas, job cleanup mechanism, estimated_remaining_seconds calculation
- `translators/excel_translator.py` - Standardized progress callback keys (current, total)
- `translators/word_translator.py` - Standardized progress callback keys, added granular progress during translation phase
- `translators/pptx_translator.py` - Standardized progress callback keys (current, total)
## Change Log
- 2026-02-21: Code Review Fixes - Fixed race condition in ProgressTracker throttling, added job cleanup mechanism (TTL 1h), implemented estimated_remaining_seconds calculation, standardized progress callback keys across all translators, added granular progress for Word translation, fixed type hints
- 2026-02-21: Implemented Story 2.11 - Real-time progress feedback with ProgressTracker service, extended job data model, enhanced status endpoint, comprehensive tests (18/18 passing)