Files
ss-tools/specs/031-maintenance-banner/plan.md
busya ec6421de35 rename ss-tools to superset-tools across the entire project
- Replace all occurrences of 'ss-tools' with 'superset-tools' in 104 files
- Rename git bundle file ss-tools.bundle → superset-tools.bundle
- Update .gitignore pattern accordingly
- Preserve variable names (hasSsTools etc.) and code identifiers
2026-06-16 11:15:19 +03:00

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; superset-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 superset-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:

  1. Chart placement via direct API (not export-import)
  2. Module placement per ADR-0001
  3. SQL parsing via sqlparse with regex fallback
  4. Async orchestration via existing TaskManager
  5. Dedicated DB tables (not AppConfigRecord JSON)
  6. Svelte 5 runes with ADR-0007 compliance
  7. 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