feat(reports): Task Status Center — unified /reports dashboard

Страница /reports трансформирована в Центр статусов задач:

Backend:
- GET /api/reports/summary — агрегированные счётчики тип×статус (5 корзин)
- GET/PUT /api/settings/reports — глобальные настройки отчётов
- _filter_tasks_by_rbac() — row-level фильтрация по роли
- normalize_task_report: LLM-валидация с ошибками → FAILED/PARTIAL
- get_summary(): 5 корзин pending/running/awaiting_input/success/failed

Frontend:
- TaskCenterModel.svelte.ts (400 строк) — Screen Model
- SummaryPanel — сводная панель с цветовым кодированием и active filter
- ReportCard — humanized labels, duration, task_id, failed border
- FilterBar — search + sort + time range с label'ами
- Pagination — showingText, уникальные id для select
- Quick views: «Упавшие», «В работе», «Успешные»
- TaskDrawer: scroll-to-error, footer скрыт для terminal, «Н/Д» fix

Тесты: 48 backend + 38 frontend (2521 всего)
Build:   Console errors: 0
This commit is contained in:
2026-07-02 18:53:58 +03:00
parent 8c10632494
commit 33ee976c48
33 changed files with 3536 additions and 218 deletions

View File

@@ -0,0 +1,174 @@
# Implementation Plan: Task Status Center
**Branch**: `034-task-status-center` | **Date**: 2026-07-02 | **Spec**: [spec.md](./spec.md)
**Input**: Feature specification from `/specs/034-task-status-center/spec.md`
## Summary
Transform the existing `/reports` page into a real-time Task Status Center — a unified monitoring dashboard for all background tasks in superset-tools. The page gains:
1. **Summary dashboard** (P1) — aggregated task counts by type × status, updated in real-time via existing WebSocket infrastructure.
2. **Enhanced filtering** (P2) — multi-select type/status filters, text search, time range, clickable summary cards that auto-apply filters.
3. **Task drill-down** (P3) — click any task to open Task Drawer with logs; hover tooltips with key details.
4. **RBAC enforcement** (TSC-FR-009) — admin/analyst/viewer see only authorized tasks.
**Technical approach**: Reuses existing `/ws/task-events` WebSocket for real-time updates. Adds `GET /api/reports/summary` REST endpoint for initial load. Frontend follows model-first pattern: `TaskCenterModel.svelte.ts` Screen Model isolates all state, the page becomes a thin render layer. Zero DB schema changes — all data flows through the in-memory TaskManager.
## Technical Context
**Language/Version**: Python 3.13+ (backend), TypeScript (frontend Svelte 5 runes-only)
**Primary Dependencies**: FastAPI, SQLAlchemy, APScheduler (backend); SvelteKit 2.x, Vite 7.x, Tailwind CSS 3.x (frontend)
**Storage**: PostgreSQL 16 (no schema changes needed)
**Testing**: pytest (backend), vitest (L1 model tests without render + L2 UX tests with @testing-library/svelte)
**Target Platform**: Linux server (Docker), modern browsers
**Project Type**: web application (FastAPI REST + WebSocket backend, SvelteKit SPA frontend)
**Frontend Architecture**: TypeScript-first, model-first (Screen Models via `.svelte.ts`), runes-only (`$state`, `$derived`, `$effect`)
**Performance Goals**: SC-001: summary load ≤1s; SC-002: WS event-to-DOM ≤2s; SC-004: 30fps at 100+ tasks
**Constraints**: RBAC enforcement (TSC-FR-009), WebSocket reconnect ≤5s (SC-005), no new DB schema
**Scale/Scope**: 3 user stories, 10 FRs, ~12 files created/modified
## Constitution Check
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
| Principle | Status | Evidence |
|-----------|:------:|----------|
| **I. Semantic Contract First** | ✅ PASS | All C3+ modules have `#region` contracts in `contracts/modules.md`. Backend schemas carry `@DATA_CONTRACT`. Frontend DTOs carry cross-stack `@RELATION`. No naked code. |
| **II. Decision Memory** | ✅ PASS | All 10 research decisions in `research.md` carry `@RATIONALE`/`@REJECTED`. ADR-0004, ADR-0005, ADR-0006, ADR-0010, ADR-0011 referenced. |
| **III. External Orchestrator** | ✅ PASS | Feature extends existing task infrastructure without modifying Superset. Follows ADR-0003 orchestrator pattern. |
| **IV. Module Discipline** | ✅ PASS | New Model ≤300 lines (well below 400-line INV_7). All files placed in canonical directories per ADR-0001. No cyclic imports. |
| **V. RBAC Enforcement** | ✅ PASS | TSC-FR-009 enforced via `_filter_tasks_by_rbac()` in service layer. Uses existing `User.roles` and `has_permission("tasks", "READ")`. |
| **VI. Svelte 5 Runes Only** | ✅ PASS | `TaskCenterModel` uses `$state`/`$derived`. No legacy Svelte 4 syntax. No `writable` stores created. Model uses `.svelte.ts` extension. |
| **VII. Test-Driven for C3+** | ✅ PASS | All C4 contracts will have tests verifying `@PRE`/`@POST`/`@INVARIANT`. Rejected-path regression tests for RBAC filtering. |
| **VIII. Attention-Optimized Contracts** | ✅ PASS | All contracts use hierarchical IDs (`Reports.SummaryService`, `TaskCenterModel`). `@SEMANTICS` keywords shared within domain. Contract files ≤150 lines. |
| **ATTN_1 (CSA 4×)** | ✅ PASS | First anchor line packs `[C:N] [TYPE] [SEMANTICS]` on one line. |
| **ATTN_2 (HCA 128×)** | ✅ PASS | IDs use `Domain.Sub.Name` pattern (2-3 levels). |
| **ATTN_3 (DSA Indexer)** | ✅ PASS | Same-domain contracts share primary `@SEMANTICS` keyword (`task-status-center`). |
| **ATTN_4 (Sliding Window)** | ✅ PASS | All contracts ≤150 lines. Modules ≤400 lines. |
**Gate Result**: ✅ ALL PRINCIPLES PASS — no blocking conflicts. Proceed to Phase 0.
### Re-check After Phase 1 Design
| Check | Status |
|-------|:------:|
| `TaskCenterModel` estimated lines: ~250 | ✅ Below 400-line gate |
| `contracts/modules.md` estimated lines: 280 | ✅ Acceptable for a C5 ADR |
| Cross-stack `@DATA_CONTRACT` bridges present | ✅ 9 bridge pairs documented |
| RBAC filtering path rejections documented | ✅ `@REJECTED` in R4 |
| WebSocket reuse documented | ✅ R2 in research.md |
## Project Structure
### Documentation (this feature)
```text
specs/034-task-status-center/
├── spec.md # Feature specification
├── ux_reference.md # UX interaction reference
├── plan.md # This file
├── research.md # Phase 0 — 10 research decisions
├── data-model.md # Phase 1 — schemas, DTOs, cross-stack bridge
├── quickstart.md # Phase 1 — developer setup & verification
├── contracts/
│ └── modules.md # Phase 1 — GRACE contracts (backend + frontend)
├── checklists/
│ └── requirements.md # Spec quality validation
└── tasks.md # Phase 2 — task decomposition (/speckit.tasks)
```
### Source Code (repository root)
```text
backend/
├── src/
│ ├── api/routes/
│ │ └── reports.py # MODIFY: add /summary endpoint, RBAC enhancement
│ ├── models/
│ │ └── report.py # MODIFY: add TaskSummary schemas
│ └── services/reports/
│ └── report_service.py # MODIFY: add get_summary(), _filter_tasks_by_rbac()
└── tests/
├── api/routes/
│ └── test_reports.py # MODIFY: add summary + RBAC tests
└── services/reports/
└── test_report_service.py # MODIFY: add RBAC filter tests
frontend/
├── src/
│ ├── routes/reports/
│ │ ├── +page.svelte # REWRITE: thin render layer
│ │ └── +page.ts # NEW: load function (URL query parsing)
│ ├── lib/
│ │ ├── models/
│ │ │ └── TaskCenterModel.svelte.ts # NEW: Screen Model
│ │ ├── components/reports/
│ │ │ ├── SummaryPanel.svelte # NEW: summary dashboard
│ │ │ ├── FilterBar.svelte # NEW: filter controls
│ │ │ ├── TaskList.svelte # MODIFY: pagination, sort
│ │ │ └── reportTypeProfiles.ts # MODIFY: add clean_release
│ │ └── api/
│ │ └── reports.ts # MODIFY: add getReportsSummary(), types
│ └── types/
│ └── reports.ts # NEW: TypeScript DTOs
└── tests/
└── lib/
├── models/
│ └── TaskCenterModel.test.ts # NEW: model unit tests
└── components/reports/
├── SummaryPanel.test.ts # NEW: component UX tests
└── FilterBar.test.ts # NEW: component UX tests
```
## Complexity Tracking
No violations to justify. All contracts are within their appropriate complexity tiers per the semantic protocol:
| Contract | Tier | Rationale |
|----------|:----:|-----------|
| `Reports.SummaryRouter` | C4 | Multi-step: RBAC + load + normalize + aggregate |
| `Reports.SummaryService` | C4 | Stateful: accesses TaskManager, applies authorization |
| `Reports.ListEnhanced` | C4 | Enhanced from C3 with RBAC row-filtering |
| `Reports.RbacTaskFilter` | C3 | Pure function: input tasks → output filtered tasks |
| `TaskCenterModel` | C4 | Stateful: 15+ atoms, WebSocket lifecycle, side effects |
| `SummaryPanel` | C4 | WebSocket-reactive derived display, UX states |
| `FilterBar` | C3 | Multi-select inputs, no side effects beyond model mutation |
| `TaskList` | C4 | Pagination, sort, click→drawer, UX states |
| `TaskCenterReportsPage` | C4 | Page orchestration: Model init, UX state machine |
| `ReportsTypes` | C2 | DTO definitions only |
| `ReportsApiClient` | C3 | Typed fetch wrappers |
## Phase Artifacts
| Artifact | Status | Description |
|----------|:------:|-------------|
| `research.md` | ✅ Done | 10 research decisions (R1-R10) |
| `data-model.md` | ✅ Done | Pydantic schemas, TypeScript DTOs, cross-stack bridge |
| `contracts/modules.md` | ✅ Done | 12 GRACE contracts with complexity anchors |
| `quickstart.md` | ✅ Done | Developer setup & verification |
| `plan.md` | ✅ Done | This file |
## Validation Against UX Reference
| UX Promise | Implementation | Status |
|------------|----------------|:------:|
| `@UX_STATE: idle` | `TaskCenterModel.screenState = 'ready'` | ✅ |
| `@UX_STATE: loading` | Skeleton in `SummaryPanel` + `TaskList` | ✅ |
| `@UX_STATE: empty` | Empty state in `TaskList` | ✅ |
| `@UX_STATE: disconnected` | Reconnect banner in `TaskCenterReportsPage` | ✅ |
| `@UX_STATE: reconnecting` | Yellow indicator in model-driven UI | ✅ |
| `@UX_STATE: error` | Error banner + retry button | ✅ |
| `@UX_FEEDBACK: status change` | Animated badge via CSS transition | ✅ |
| `@UX_FEEDBACK: new task` | Slide-in animation (TaskList) | ✅ |
| `@UX_FEEDBACK: task completion` | Row highlight + summary count update | ✅ |
| `@UX_RECOVERY: WS disconnect` | Auto-reconnect + manual button | ✅ |
| `@UX_RECOVERY: load error` | Retry button | ✅ |
| `@UX_RECOVERY: empty search` | Clear filters button | ✅ |
| `@UX_REACTIVITY: Model-driven` | TaskCenterModel `$state` + `$derived` | ✅ |
| Screen Model presence | `TaskCenterModel.svelte.ts` with `@STATE`/`@ACTION`/`@INVARIANT` | ✅ |
## Next Steps
Run `/speckit.tasks` to generate the task decomposition (`tasks.md`).
#endregion PlanDoc