Spec: 5 user stories (P1-P3), 17 FRs, 7 SCs, 12 edge cases, RBAC matrix Plan: 7 research decisions, 15 semantic contracts (C1-C4) Data: 4 SQLAlchemy models (Banner entity enforces one-chart-per-dashboard) UX: async-only API, banner template with optional variables, admin settings UI Tasks: 64 tasks across 8 phases, 12 reused frontend components Workflow: component reuse scan mandated in speckit.plan/tasks + semantics-svelte Constitution: filled with 7 architecture principles from ADRs
8.1 KiB
Implementation Plan: Maintenance Banner for Dashboards
Branch: 031-maintenance-banner | Date: 2026-05-21 | Spec: spec.md
Input: Feature specification from /specs/031-maintenance-banner/spec.md
Summary
Service for automatically adding/removing maintenance warning banners on Superset dashboards during ETL table updates. External tools call async API endpoints to start/end maintenance events; ss-tools discovers affected dashboards (by matching table names against datasets), creates markdown charts at the top of each dashboard via Superset REST API, and provides a management UI for manual control and configuration. All operations are RBAC-gated (operator/admin roles) and traceable via TaskManager.
Technical Context
Language/Version: Python 3.13+ (backend), JavaScript/TypeScript (frontend Svelte 5 runes) Primary Dependencies: FastAPI 0.126, SQLAlchemy 2.0, APScheduler 3.11 (backend); SvelteKit 2.x, Svelte 5.43, Vite 7.x, Tailwind CSS 3.x (frontend) Storage: PostgreSQL 16 (dedicated ss-tools DB — not Superset metadata DB per ADR-0003) Testing: pytest (backend), vitest + @testing-library/svelte (frontend) Target Platform: Linux server (Docker), modern browsers Project Type: web application (FastAPI REST + WebSocket backend, SvelteKit SPA frontend) Performance Goals: /start returns task_id within 1s; banner placement within 60s for up to 50 dashboards; /end within 30s for up to 50 dashboards Constraints: RBAC enforcement (operator/admin per ADR-0005), Svelte 5 runes only (per ADR-0006), no fromStore + $derived (per ADR-0007), offline-capable Docker bundle Scale/Scope: 1 maintenance event typically affects 5-50 dashboards; up to 5 concurrent active events; table lists up to 100 entries
Constitution Check
GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.
| Principle | Status | Evidence |
|---|---|---|
| ADR-0001 (Module Layout) | ✅ PASS | All planned files follow canonical layout: backend/src/api/routes/maintenance/, backend/src/services/maintenance_service.py, backend/src/models/maintenance.py, frontend/src/routes/maintenance/, frontend/src/lib/components/ |
| ADR-0002 (Semantic Protocol) | ✅ PASS | All C3+ contracts carry @PURPOSE, @RELATION; C4 contracts add @PRE/@POST/@SIDE_EFFECT + belief runtime |
| ADR-0003 (Orchestrator Pattern) | ✅ PASS | Feature operates as external orchestrator, not integrated into Superset. Uses Superset REST API only. |
| ADR-0004 (Plugin Architecture) | ✅ PASS | Maintenance is a core feature in services/ (stateless, in-process), not a subprocess-isolated plugin per ADR-0004. Justified in research.md R2. |
| ADR-0005 (Auth RBAC) | ✅ PASS | FR-014: operator/admin roles for mutations; admin for settings |
| ADR-0006 (Frontend Architecture) | ✅ PASS | Svelte 5 runes, SPA mode (adapter-static), Tailwind CSS, requestApi wrapper |
| ADR-0007 (fromStore REJECTED) | ✅ PASS | Maintenance store uses $effect(() => subscribe(...)) pattern, not fromStore + $derived |
| Module <400 LOC | ✅ PASS | Each planned file: routes ~150 LOC, service ~250 LOC, components ~150 LOC each |
| CC ≤ 10 per contract | ✅ PASS | All contract functions are small, focused operations |
Verdict: ✅ No blocking conflicts. Proceed to Phase 0/1.
Project Structure
Documentation (this feature)
specs/031-maintenance-banner/
├── plan.md # This file
├── research.md # Phase 0: 7 resolved decisions
├── data-model.md # Phase 1: SQLAlchemy models, Pydantic schemas, state transitions
├── quickstart.md # Phase 1: Verification commands
├── contracts/
│ └── modules.md # Phase 1: 14 semantic contracts (C1-C4)
├── spec.md # Feature specification
├── ux_reference.md # UX interaction reference
├── checklists/
│ └── requirements.md # Requirements validation checklist
└── tasks.md # Phase 2 output (NOT created by /speckit.plan)
Source Code (repository root)
backend/
├── src/
│ ├── api/routes/maintenance/ # NEW: package-based route module
│ │ ├── __init__.py
│ │ ├── _router.py # APIRouter assembly
│ │ ├── _routes.py # Route handlers
│ │ └── _schemas.py # Pydantic schemas
│ ├── core/superset_client/
│ │ └── _dashboards_write.py # NEW: SupersetClient write mixin
│ ├── models/
│ │ └── maintenance.py # NEW: SQLAlchemy models
│ └── services/
│ ├── maintenance_service.py # NEW: Core business logic
│ └── sql_table_extractor.py # NEW: SQL table name parser
├── tests/
│ ├── test_maintenance_service.py # Unit/integration tests
│ ├── test_sql_table_extractor.py # SQL parsing tests
│ └── test_maintenance_api.py # API endpoint tests
frontend/
├── src/
│ ├── routes/maintenance/
│ │ └── +page.svelte # NEW: Management page
│ ├── lib/
│ │ ├── components/
│ │ │ ├── MaintenanceSettingsPanel.svelte # NEW
│ │ │ ├── MaintenanceEventsTable.svelte # NEW
│ │ │ └── DashboardMaintenanceBadge.svelte # NEW
│ │ ├── stores/
│ │ │ └── maintenance.svelte.js # NEW
│ │ └── api/
│ │ └── maintenance.js # NEW
│ └── routes/dashboards/
│ └── +page.svelte # MODIFIED: add maintenance badge column
└── tests/
├── maintenance.test.ts # Component tests
└── maintenance-store.test.ts # Store tests
Structure Decision: Package-based route for maintenance/ mirrors existing dashboards/ pattern. Backend service in services/ (stateless, request-scoped) per ADR-0001 boundary rule #3. Superset client extension in core/superset_client/ as singleton mixin.
Semantic Contract Guidance
All 15 contracts defined in contracts/modules.md:
- Complexity 1 (4): MaintenanceEvent, MaintenanceDashboardBanner, MaintenanceDashboardState, MaintenanceSettings models, Pydantic schemas
- Complexity 2 (3): SqlTableExtractor, MaintenanceRouter, MaintenanceApiClient, DashboardMaintenanceBadge
- Complexity 3 (5): MaintenanceRoutes, MaintenanceStore, MaintenanceBannerPage, MaintenanceSettingsPanel, MaintenanceEventsTable
- Complexity 4 (3): SupersetDashboardsWriteMixin, MaintenanceService (start/end/end_all methods)
C4 contracts require @PRE, @POST, @SIDE_EFFECT plus belief runtime instrumentation per semantics-python skill.
Complexity Tracking
No constitutional violations to justify. All module placements and complexity levels follow ADR-0001 guidelines.
| Aspect | Rationale |
|---|---|
Package-based route (maintenance/) |
Mirrors dashboards/ pattern; 3 files <200 LOC each |
Service in services/ not core/ |
Stateless, request-scoped per ADR-0001 rule #3 |
SupersetClient mixin in core/ |
Singleton, app-scoped per ADR-0001 rule #2 |
| Not a plugin | Maintenance is core infrastructure, not user-configurable |
Phase 0 Outputs
See research.md for 7 resolved decisions:
- Chart placement via direct API (not export-import)
- Module placement per ADR-0001
- SQL parsing via sqlparse with regex fallback
- Async orchestration via existing TaskManager
- Dedicated DB tables (not AppConfigRecord JSON)
- Svelte 5 runes with ADR-0007 compliance
- Existing RBAC reuse (operator + admin roles)
Phase 1 Outputs
| Artifact | Path | Description |
|---|---|---|
| Data Model | data-model.md | 3 SQLAlchemy models, 10 Pydantic schemas, ER diagram, state transitions |
| Contracts | contracts/modules.md | 14 semantic contracts (C1-C4) with relations, pre/post, rationale |
| Quickstart | quickstart.md | Verification commands for backend/frontend/lint |