Files
ss-tools/specs/028-llm-datasource-supeset/contracts/modules.md
2026-06-08 14:14:38 +03:00

26 KiB

Semantic Contracts: LLM Table Translation Service

Feature Branch: 028-llm-datasource-supeset (актуальная: 032-translate-requests-httpx)
Date: 2026-06-07 (updated to match implementation)
Protocol: GRACE-Poly v2.6


Backend Contracts (Python / FastAPI)

[DEF:TranslatePlugin:Module]

backend/src/plugins/translate/plugin.py @COMPLEXITY 2 @PURPOSE Plugin entry point implementing PluginBase for the translation service. Serves as registration artifact for plugin_loader auto-discovery. All business logic delegated to independent service classes. @RELATION INHERITS -> [PluginBase:Class] @RATIONALE Separate plugin avoids bloating LLMAnalysisPlugin beyond fractal limit (<400 lines). C2 because plugin.py is a registration skeleton; all execution logic lives in service classes. @REJECTED Extending LLMAnalysisPlugin would conflate two distinct feature domains (dashboard validation vs table translation). Executing business logic through PluginBase.execute() was rejected in favor of service-layer architecture for testability and route flexibility. [/DEF:TranslatePlugin:Module]

[DEF:TranslationOrchestrator:Class]

backend/src/plugins/translate/orchestrator.py @COMPLEXITY 5 @PURPOSE Central coordinator for translation run lifecycle: validates preconditions, manages preview quality gate, dispatches to executor, generates safe SQL, submits to Superset SQL Lab API, manages retry, records events, enforces retention. @PRE Job configuration is saved and valid. Superset datasource is accessible. LLM provider is configured and reachable. For manual runs: preview session must be accepted. For scheduled runs: at least one prior successful manual run exists. @POST TranslationRun created with translation_status and insert_status. INSERT SQL generated (safe dialect) and submitted to Superset /api/v1/sqllab/execute/. Superset query reference recorded. Structured events recorded for all lifecycle transitions. @SIDE_EFFECT Creates TranslationRun, TranslationBatch, TranslationRecord, TranslationEvent, MetricSnapshot rows. Calls LLM provider API (token consumption). Calls Superset SQL Lab API. @DATA_CONTRACT Input: TranslationJob (config snapshot) + datasource rows → Output: TranslationRun (result) + Superset query reference @INVARIANT A run must transition through states: pending → running → (completed|partial|failed|cancelled|skipped). insert_status transitions: not_started → (submitted → running → succeeded|failed | skipped). No other state transitions allowed. Snapshot isolation: in-progress runs use config snapshot; config edits affect future runs only. @RELATION CALLS -> [TranslationPreview:Class] @RELATION CALLS -> [TranslationExecutor:Class] @RELATION CALLS -> [SQLGenerator:Class] @RELATION CALLS -> [SupersetSqlLabExecutor:Class] @RELATION CALLS -> [TranslationEventLog:Class] @RELATION CALLS -> [LLMProviderService:Module] @RELATION CALLS -> [SupersetClient:Module] @RATIONALE Centralized orchestrator is needed because preview gating, execution, SQL generation, Superset API submission, event logging, and retry share state (run_id, config snapshot) and must coordinate within a single transaction boundary for consistency. @REJECTED Distributed actor model (Celery tasks per batch) was rejected because it introduces eventual-consistency challenges for run status tracking without proportional benefit at the expected scale. Synchronous batch processing provides simpler debugging and deterministic retry. UPDATE statements are never generated — all modifications use INSERT/UPSERT per PostgreSQL dialect. [/DEF:TranslationOrchestrator:Class]

[DEF:TranslateJobService:Class]

backend/src/plugins/translate/service.py @COMPLEXITY 4 @PURPOSE Central service layer for job CRUD, inline corrections with context capture, and bulk find-and-replace operations. Coordinates between routes, dictionary manager, and event log. @PRE Job configuration is saved and valid. For corrections: run record must exist with translated values. @POST Job CRUD operations reflected in database. Inline corrections create/update DictionaryEntry with context_data, usage_notes, origin tracking. Bulk find-and-replace updates TranslationLanguage.final_value for matched rows. @SIDE_EFFECT Creates/updates DictionaryEntry rows. Updates TranslationLanguage.final_value. Logs correction events. @RELATION CALLS -> [DictionaryManager:Class] @RELATION CALLS -> [TranslationEventLog:Class] @RELATION CALLS -> [ContextAwarePromptBuilder:Class] @RELATION CALLS -> [BulkFindReplaceService:Class] @RATIONALE C4 warranted because service coordinates multiple domains (jobs, corrections, bulk operations) with stateful side effects and origin tracking. [/DEF:TranslateJobService:Class]

[DEF:TranslationPreview:Class]

backend/src/plugins/translate/preview.py @COMPLEXITY 4 @PURPOSE Fetch a configurable sample of source rows (1-100), send to LLM with configured context and per-batch filtered dictionary, return per-language translations side-by-side for quality gate. Creates persistent PreviewSession and PreviewRecord rows. Supports multi-target: single LLM call for ALL target languages. @PRE Job configuration is saved with target_languages (list, min 1). Datasource is accessible. Sample size configured (default 10, range 1-100). @POST PreviewSession created with config_hash and dict_snapshot_hash. PreviewRecord rows created with per-language TranslationPreviewLanguage entries. Accepting preview gates full execution. No data persisted to target table. For sample_size >30, cost warning displayed. @SIDE_EFFECT Calls LLM provider API (token consumption). Creates PreviewSession, PreviewRecord, TranslationPreviewLanguage rows. @RELATION CALLS -> [LLMProviderService:Module] @RELATION CALLS -> [SupersetClient:Module] @RELATION CALLS -> [DictionaryManager:Class] [/DEF:TranslationPreview:Class]

[DEF:TranslationExecutor:Class]

backend/src/plugins/translate/executor.py @COMPLEXITY 4 @PURPOSE Process source rows in auto-sized batches through LLM, request translations for ALL target languages in single structured JSON response, parse multi-language results, create per-language TranslationLanguage entries. Features: translation cache via source_hash, preview edit carry-forward, new-key-only filtering, dictionary enforcement post-processing. @PRE Run exists with translation_status running. Source rows fetched. Batch size configured. LLM provider configured. @POST All processable rows have TranslationRecord + TranslationLanguage entries. Each batch has TranslationBatch record with statistics. Run statistics updated per language via TranslationRunLanguageStats. @SIDE_EFFECT Calls LLM provider API (token consumption). Creates TranslationBatch, TranslationRecord, TranslationLanguage rows. @RELATION CALLS -> [LLMProviderService:Module] @RELATION CALLS -> [DictionaryManager:Class] @RELATION CALLS -> [ContextAwarePromptBuilder:Class] [/DEF:TranslationExecutor:Class]

[DEF:SQLGenerator:Class]

backend/src/plugins/translate/sql_generator.py @COMPLEXITY 3 @PURPOSE Generate safe dialect-appropriate INSERT/UPSERT SQL from TranslationRecord/TranslationLanguage rows, keyed by configured target key columns. Supports PostgreSQL/Greenplum (ON CONFLICT) and ClickHouse (plain INSERT). Pure function — no I/O, no mutation. @PRE TranslationRecord rows exist with translated/final values. Target table schema validated at configuration time. @POST Returns a syntactically valid, injection-safe SQL INSERT/UPSERT statement for the detected dialect. @SIDE_EFFECT None — pure function. @RELATION CALLS -> [SupersetClient:Module] @RATIONALE C3 (not C4 as originally planned) because SQLGenerator is a pure function with no state, no I/O, and no external side effects. [/DEF:SQLGenerator:Class]

[DEF:SupersetSqlLabExecutor:Class]

backend/src/plugins/translate/superset_executor.py @COMPLEXITY 3 @PURPOSE Submit generated SQL to Superset SQL Lab API /api/v1/sqllab/execute/ with fallback to /api/v1/sql_lab/execute/ (underscore variant). Poll /api/v1/query/{id} for completion. Supports multiple Superset response formats. Record Superset query reference, status, and error details. @PRE TranslationRun exists with translation_status completed/partial. SQL is generated and syntactically valid. Superset is accessible. @POST TranslationRun.insert_status updated (submitted → running → succeeded|failed). Superset query reference, error details, rows_affected stored. @SIDE_EFFECT Calls Superset API (SQL execution, database write). Updates TranslationRun row. @RELATION CALLS -> [SupersetClient:Module] @RELATION CALLS -> [TranslationEventLog:Class] [/DEF:SupersetSqlLabExecutor:Class]

[DEF:DictionaryManager:Class]

backend/src/plugins/translate/dictionary.py @COMPLEXITY 4 @PURPOSE CRUD for TerminologyDictionary and DictionaryEntry with language-pair-aware unique constraint (dictionary_id, source_term_normalized, source_language, target_language). CSV/TSV import with conflict detection. Per-batch language-pair-filtered term extraction for LLM prompts. @PRE Dictionary model exists. User has required permissions. @POST CRUD operations reflected in database. Filtered term list returned for batch with language-pair matching. @SIDE_EFFECT Creates/updates/deletes DictionaryEntry rows. May read TranslationRun for origin tracking. @RELATION CALLS -> [DictionaryEntry:Class] @RELATION CALLS -> [TranslationJobDictionary:Class] @RELATION CALLS -> [ContextAwarePromptBuilder:Class] [/DEF:DictionaryManager:Class]

[DEF:ContextAwarePromptBuilder:Class]

backend/src/plugins/translate/prompt_builder.py @COMPLEXITY 3 @PURPOSE Construct LLM prompts with context-aware dictionary entries. For entries with has_context=True, render context annotations with format: "source_term" (context: key=value, ...) → "target_term". Compute Jaccard similarity between entry context_data and incoming row context columns to flag priority_context entries (>50% overlap). Cap context rendering at ~500 tokens per entry. @RELATION DEPENDS_ON -> [DictionaryManager:Class] @RELATION DEPENDS_ON -> [LLMProviderService:Module] [/DEF:ContextAwarePromptBuilder:Class]

[DEF:TranslationScheduler:Class]

backend/src/plugins/translate/scheduler.py @COMPLEXITY 4 @PURPOSE Manage translation job schedules with timezone and concurrency policy support: create/update/delete, register with APScheduler, handle trigger dispatch with skip/queue, enforce new-key-only strategy with baseline_expired fallback (>90 days), failure notification dispatch. @PRE SchedulerService is running. Job has configuration. For execution bypass: at least one prior successful manual run exists. @POST Schedule registered with APScheduler or removed. On trigger: new TranslationRun created with trigger_type=scheduled. New-key-only filter applied. On failure: NotificationService called. Schedule remains enabled. @SIDE_EFFECT Creates TranslationRun rows. Calls SchedulerService. Emits schedule_triggered/skipped/failed events. @RELATION CALLS -> [SchedulerService:Class] @RELATION CALLS -> [TranslationOrchestrator:Class] @RELATION CALLS -> [TranslationEventLog:Class] @RELATION CALLS -> [NotificationService:Module] [/DEF:TranslationScheduler:Class]

[DEF:TranslationEventLog:Class]

backend/src/plugins/translate/events.py @COMPLEXITY 5 @PURPOSE Structured event logging: write immutable events, enforce invariants (exactly one run_started + one terminal event per run), query for audit/dashboard, enforce 90-day retention pruning with MetricSnapshot persistence before deletion. @PRE TranslationEvent table exists. Event type recognized from VALID_EVENT_TYPES. For run-scoped events: run exists. @POST Event row created with type-specific payload. Pruning job persists MetricSnapshot, then removes events/records older than 90 days. @SIDE_EFFECT Creates TranslationEvent rows. Creates MetricSnapshot rows at pruning time. Deletes expired rows. @DATA_CONTRACT Input: (run_id?, job_id, event_type, payload: dict) → Output: TranslationEvent @INVARIANT Every created run MUST have exactly one run_started event and exactly one terminal event among: run_succeeded, run_partial, run_failed, run_cancelled, run_skipped. Events are immutable after creation. Cumulative metrics survive pruning via MetricSnapshot. @RELATION CALLS -> [TranslationEvent:Class] @RELATION CALLS -> [MetricSnapshot:Class] @RATIONALE C5 warranted: event log is single source of truth for observability, metrics, and audit. Immutability, retention, and metric continuity invariants must be enforced to prevent data loss or tampering. @REJECTED stdout-only logging lacks structured payload integrity and cannot enforce terminal-event invariant. Event-sourced metrics without snapshots would lose cumulative data after pruning. [/DEF:TranslationEventLog:Class]

[DEF:TranslationMetrics:Class]

backend/src/plugins/translate/metrics.py @COMPLEXITY 3 @PURPOSE Aggregate per-job metrics from live TranslationEvent log AND persistent MetricSnapshot table. For recent data (<90 days): compute from events. For cumulative totals: read latest MetricSnapshot + recent events. Includes per-language breakdown from per_language_metrics JSON. @RELATION CALLS -> [TranslationEventLog:Class] @RELATION CALLS -> [MetricSnapshot:Class] [/DEF:TranslationMetrics:Class]

[DEF:TranslateRoutes:Package]

backend/src/api/routes/translate/ @COMPLEXITY 4 @PURPOSE FastAPI route handlers organized as package with 13 sub-modules: job CRUD (285 строк), run execution (205), run edit (200), run list (359), run history (133), preview (194), dictionary (391), correction (100), schedule (239), metrics (65), helpers (70). All endpoints enforce RBAC per access-control matrix. Runs execute in background threads with isolated DB sessions. @RELATION CALLS -> [TranslationOrchestrator:Class] @RELATION CALLS -> [TranslateJobService:Class] @RELATION CALLS -> [DictionaryManager:Class] @RELATION CALLS -> [TranslationScheduler:Class] @RELATION CALLS -> [TranslationEventLog:Class] @RELATION CALLS -> [TranslationMetrics:Class] @RELATION BINDS_TO -> [PermissionChecker:Dependency] @RATIONALE C4 because routes package spans 13 files, coordinates 6+ service dependencies, and enforces RBAC across 13 permission strings. Split into sub-modules by domain to respect fractal limit (<400 lines per file, except _dictionary_routes.py at 391 and _run_list_routes.py at 359). @REJECTED Single translate.py file rejected — would exceed fractal limit at 2 296 lines. Multiple route files with shared state would couple domains. [/DEF:TranslateRoutes:Package]

[DEF:TranslateModels:Module]

backend/src/models/translate.py @COMPLEXITY 2 @PURPOSE 15 SQLAlchemy ORM models: TranslationJob, TranslationRun, TranslationBatch, TranslationRecord, TranslationLanguage, TranslationEvent, TranslationPreviewSession, TranslationPreviewRecord, TranslationPreviewLanguage, TerminologyDictionary, DictionaryEntry, TranslationJobDictionary, TranslationSchedule, MetricSnapshot, TranslationRunLanguageStats. [/DEF:TranslateModels:Module]

[DEF:TranslateSchemas:Module]

backend/src/schemas/translate.py @COMPLEXITY 2 @PURPOSE 35+ Pydantic v2 request/response schemas for translation API endpoints including multi-language, context-aware, and bulk operations. [/DEF:TranslateSchemas:Module]

[DEF:BulkFindReplaceService:Class]

backend/src/plugins/translate/service.py (extended) @COMPLEXITY 3 @PURPOSE Apply find-and-replace across translated values in a completed run. Supports regex or literal patterns, filtered by target language. Generates preview of affected rows before atomic apply. Optionally submits corrections to dictionary with context capture. @PRE Run must be completed. Pattern must be valid regex (if regex flag set). @POST All matching cells updated. Optional dictionary entries created with context_source="bulk". @SIDE_EFFECT Updates TranslationLanguage.final_value. Optionally creates DictionaryEntry rows. @RELATION DEPENDS_ON -> [InlineCorrectionService:Class] [/DEF:BulkFindReplaceService:Class]


Frontend Contracts (Svelte 5 / SvelteKit)

[DEF:TranslateJobList:Component]

frontend/src/routes/translate/+page.svelte @COMPLEXITY 3 @PURPOSE SvelteKit page listing all translation jobs with status/schedule indicators, target languages as badges, create/duplicate/delete actions. @UX_STATE idle, loading, empty, populated, error [/DEF:TranslateJobList:Component]

[DEF:TranslationJobConfig:Component]

frontend/src/routes/translate/[id]/+page.svelte @COMPLEXITY 4 @PURPOSE Tabbed page with Configuration, Preview, Run, and Schedule sections. Multi-language target selection, datasource column mapping, composite key support, LLM provider/dictionary attachment with priority ordering, sample size slider (1-100), inline correction, bulk find-replace. @UX_STATE idle, loading, configured, saving, validation_error, datasource_unavailable @UX_REACTIVITY Column list $derived from datasource; dictionary list filtered by target_language; per-language columns in preview/run results @UX_FEEDBACK Cost warning at sample size >30; per-language statistics on run completion [/DEF:TranslationJobConfig:Component]

[DEF:TranslationPreview:Component]

frontend/src/lib/components/translate/TranslationPreview.svelte @COMPLEXITY 4 @PURPOSE Side-by-side per-language preview of source rows with LLM translations, per-language approve/edit/reject, bulk approve, configurable sample size slider, cost estimate card, carry-forward edits to full run. @UX_STATE idle, loading, preview_loaded, preview_error, accepted, rejected, stale_config @UX_FEEDBACK Spinner during LLM call; visual distinction for LLM-generated vs user-edited vs "und" warning @UX_RECOVERY Retry preview; re-fetch with updated config; individual row re-translate [/DEF:TranslationPreview:Component]

[DEF:TranslationRunProgress:Component]

frontend/src/lib/components/translate/TranslationRunProgress.svelte @COMPLEXITY 4 @PURPOSE Live progress display: progress bar, per-language batch counter, success/failure counts, cancel button. WebSocket-driven for real-time updates. @UX_STATE idle, running, cancelling, cancelled, completed, partial, failed, insert_pending, insert_running, insert_failed @UX_FEEDBACK Per-language progress $derived; real-time batch/insert status @UX_RECOVERY Retry failed batches; cancel run; download skipped rows as CSV [/DEF:TranslationRunProgress:Component]

[DEF:TranslationRunResult:Component]

frontend/src/lib/components/translate/TranslationRunResult.svelte @COMPLEXITY 4 @PURPOSE Completion summary with per-language statistics, Superset execution status/reference, generated SQL (audit/debug), inline feedback-loop correction controls. @UX_STATE completed, partial, failed, insert_failed @UX_FEEDBACK Superset execution status badge; per-language statistics section; SQL block for audit @UX_RECOVERY Retry failed rows; retry insert; submit corrections; bulk find & replace @RELATION CALLS -> [TermCorrectionPopup:Component] @RELATION CALLS -> [CorrectionCell:Component] [/DEF:TranslationRunResult:Component]

[DEF:CorrectionCell:Component]

frontend/src/lib/components/translate/CorrectionCell.svelte @COMPLEXITY 3 @PURPOSE Inline-editable cell for translation results. Click to edit, shows "Submit to Dictionary" button after edit. Auto-fills language pair from row metadata. Supports context capture and usage notes. @UX_STATE view, editing, submitting, submitted, error @UX_FEEDBACK Toast on submit success/error; "Dictionary ✓" badge on corrected rows @UX_RECOVERY Retry button on submit failure; edit persists locally @RELATION DEPENDS_ON -> [TranslateApiClient:Module] @RELATION BINDS_TO -> [translateStore:Store] [/DEF:CorrectionCell:Component]

[DEF:BulkReplaceModal:Component]

frontend/src/lib/components/translate/BulkReplaceModal.svelte @COMPLEXITY 3 @PURPOSE Modal for bulk find-and-replace across translated values. Pattern input (regex toggle), target language selection, preview table with "N rows affected", apply with confirmation. Optional "Submit to dictionary with context" with usage notes. @UX_STATE closed, configuring, previewing, applying, applied, error @UX_FEEDBACK Preview table showing before/after; counter of affected rows; warning at >50 rows @UX_REACTIVITY Preview list $derived from pattern + run data @RELATION DEPENDS_ON -> [TranslateApiClient:Module] [/DEF:BulkReplaceModal:Component]

[DEF:TermCorrectionPopup:Component]

frontend/src/lib/components/translate/TermCorrectionPopup.svelte @COMPLEXITY 3 @PURPOSE Popup for submitting corrections: source term (pre-filled), incorrect translation, corrected translation, source language (auto), target language (auto), dictionary selector (filtered by language pair), context_data preview (editable/removable), usage notes textarea. Conflict dialog (overwrite/keep/cancel). @UX_STATE closed, selecting, editing, submitting, conflict_detected, submitted [/DEF:TermCorrectionPopup:Component]

[DEF:BulkCorrectionSidebar:Component]

frontend/src/lib/components/translate/BulkCorrectionSidebar.svelte @COMPLEXITY 3 @PURPOSE Sidebar for bulk correction: collect multiple selected terms across rows, per-term correction inputs, submit all to dictionary atomically. @UX_STATE closed, collecting, reviewing, submitting, submitted @UX_REACTIVITY Selected terms list $state [/DEF:BulkCorrectionSidebar:Component]

[DEF:ScheduleConfig:Component]

frontend/src/lib/components/translate/ScheduleConfig.svelte @COMPLEXITY 3 @PURPOSE Schedule panel: type selector (cron/interval/once), cron expression with validation, interval input, timezone selector, next-3-executions preview, concurrency policy (skip/queue), enable/disable toggle. Warns if no prior successful manual run. @UX_STATE idle, editing, validating, enabled, disabled, no_prior_run_warning @UX_REACTIVITY Next execution times $derived with timezone display [/DEF:ScheduleConfig:Component]

[DEF:DictionaryEditor:Component]

frontend/src/routes/translate/dictionaries/[id]/+page.svelte @COMPLEXITY 3 @PURPOSE Inline term editor with per-row language pair: add/edit/delete entries, CSV/TSV import with conflict preview (overwrite/keep), export, context_data + usage_notes display in expandable rows, context_source badges. @UX_STATE idle, loading, editing, importing, import_preview, import_conflict, saving [/DEF:DictionaryEditor:Component]

[DEF:DictionaryList:Component]

frontend/src/routes/translate/dictionaries/+page.svelte @COMPLEXITY 3 @PURPOSE SvelteKit page listing dictionaries with name, term count, attached job count, create/delete actions. Blocks deletion of attached dictionaries. @UX_STATE idle, loading, empty, populated, delete_blocked [/DEF:DictionaryList:Component]

[DEF:TranslationHistory:Component]

frontend/src/routes/translate/history/+page.svelte @COMPLEXITY 3 @PURPOSE Filterable run history: datasource, target table, per-language row counts, translation_status, insert_status, date, user. Detail view with config snapshot, prompt, per-language translations with edit marks, INSERT SQL, Superset execution reference. Pruned runs show metadata only with "data unavailable" markers. @UX_STATE idle, loading, empty, populated, detail_open, pruned [/DEF:TranslationHistory:Component]

[DEF:TranslationMetricsDashboard:Component]

frontend/src/lib/components/translate/TranslationMetricsDashboard.svelte @COMPLEXITY 2 @PURPOSE Admin dashboard displaying per-job metrics: run counts, success/failure ratio, cumulative tokens, cumulative cost, average latency, per-language breakdown. @UX_STATE idle, loading, populated, error [/DEF:TranslationMetricsDashboard:Component]

[DEF:TranslationRunGlobalIndicator:Component]

frontend/src/lib/components/translate/TranslationRunGlobalIndicator.svelte @COMPLEXITY 2 @PURPOSE Global indicator showing active translation runs with progress. Polls or WebSocket-driven. @UX_STATE hidden, active, completed [/DEF:TranslationRunGlobalIndicator:Component]

[DEF:TranslateApiClient:Module]

frontend/src/lib/api/translate.js @COMPLEXITY 2 @PURPOSE API client wrapping requestApi/fetchApi for all translate endpoints: jobs, runs, preview, dictionaries, entries, corrections, schedules, metrics, bulk replace. [/DEF:TranslateApiClient:Module]

[DEF:translateStore:Store]

frontend/src/lib/stores/translationRun.svelte.ts @COMPLEXITY 3 @PURPOSE Svelte 5 rune store for translation feature state: run progress, WebSocket connection status, per-language progress. @RELATION BINDS_TO -> [TranslateApiClient:Module] @RELATION BINDS_TO -> [TaskWebSocket:Module] [/DEF:translateStore:Store]


Integration Contracts (Existing System — Reused)

Contract ID What It Provides How Translation Uses It
[LLMProviderService:Module] LLM API call with provider selection, key encryption, retry/fallback Sends batches with constructed prompts; receives structured JSON translations for all target languages
[SupersetClient:Module] Superset API: datasource schema, SQL Lab execution, column metadata Fetch column metadata, submit SQL to /api/v1/sqllab/execute/, poll status
[SchedulerService:Class] APScheduler lifecycle, add_job/remove_job, cron/interval/date triggers Translation schedules registered as APScheduler jobs; load_schedules discovers active TranslationSchedule rows
[NotificationService:Module] Email/Telegram/Slack notification dispatch Scheduled run failure notifications with job name, failure reason, run link
[PermissionChecker:Dependency] FastAPI dependency for RBAC enforcement with ownership scoping Route handlers annotated per 13-permission access-control matrix
[TaskWebSocket:Module] WebSocket for real-time task progress streaming Translation run progress events (per-language) streamed to frontend store
[TaskContext:Class] Background task lifecycle context with structured logging Orchestrator runs as async background task with source-tagged log entries

Updated Contracts (2026-05-17 — aligned with implementation)

[DEF:TranslationLanguage:Class]

backend/src/models/translate.py @COMPLEXITY 1 @PURPOSE Per-language translation storage for a TranslationRecord. One row per (record_id, language_code). Fields: language_code, source_language_detected (BCP-47), translated_value, user_edit, final_value, status. @RELATION DEPENDS_ON -> [TranslationRecord:Class] [/DEF:TranslationLanguage:Class]

[DEF:TranslationPreviewLanguage:Class]

backend/src/models/translate.py @COMPLEXITY 1 @PURPOSE Per-language preview results. Mirrors TranslationLanguage structure for preview records. @RELATION DEPENDS_ON -> [TranslationPreviewRecord:Class] [/DEF:TranslationPreviewLanguage:Class]

[DEF:TranslationRunLanguageStats:Class]

backend/src/models/translate.py @COMPLEXITY 1 @PURPOSE Per-language statistics for a translation run: total_rows, translated_rows, failed_rows, skipped_rows, token_count, estimated_cost per language_code. @RELATION DEPENDS_ON -> [TranslationRun:Class] [/DEF:TranslationRunLanguageStats:Class]