TenantAtlas/specs/032-backup-scheduling-mvp/spec.md
ahmido beffbfca4c feat/032-backup-scheduling-mvp (#33)
Ziel: MVP-Spezifikation für “Automatisierte Backups per Zeitplan (pro Tenant)” als Grundlage für die Implementierung (Spec-first).
Scope (MVP):
Tenant-scoped backup_schedules + backup_schedule_runs
Dispatcher erstellt idempotente Runs (Unique Slot) + Queue-Job führt Run aus
“Run now” / “Retry”, Run-History, Retention (keep last N)
No catch-up für verpasste Slots
Wichtige Klarstellungen (aus Constitution abgeleitet):
Jede Operation ist tenant-scoped und schreibt Audit Logs (Dispatcher/Run/Retention; keine Secrets/Tokens)
Graph-Aufrufe laufen über die bestehende Abstraktion (keine Hardcodings)
Retry/Backoff: Throttling → Backoff; 401/403 → kein Retry
Authorization (MVP):
TenantRole-Matrix (readonly/operator/manager/owner) statt neuer Permission-Registry
Nicht im MVP:
Kein Restore-Scheduling
Kein Cross-Tenant Bulk Scheduling / Templates
Kein Catch-up von missed runs
Review-Fokus:
Semantik “1 Run = 1 BackupSet”
Concurrency/Lock-Verhalten (bei laufendem Run → skipped)
DST/Timezone-Regeln + Slot-Minutenpräzision
Artefakte:
spec.md
plan.md
tasks.md
requirements.md

Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local>
Reviewed-on: #33
2026-01-04 23:54:56 +00:00

118 lines
5.5 KiB
Markdown

# Feature Specification: Backup Scheduling MVP (032)
**Feature**: Automatisierte Backups per Zeitplan (pro Tenant)
**Created**: 2026-01-05
**Status**: Ready for implementation (MVP)
**Risk**: Medium (Backup-only, no restore scheduling)
**Dependencies**: Tenant Portfolio + Tenant Context Switch ✅
## Context
TenantPilot unterstützt manuelle Backups. Kunden/MSPs benötigen regelmäßige, zuverlässige Backups pro Tenant (z. B. nightly), inkl. nachvollziehbarer Runs, Fehlercodes und Retention.
## Goals
- Pro Tenant können 1..n Backup Schedules angelegt werden.
- Schedules laufen automatisch via Queue/Worker.
- Jeder Lauf wird als Run auditierbar gespeichert (Status, Counts, Fehler).
- Retention löscht alte Backups nach Policy.
- Filament UI: Schedules verwalten, Run-History ansehen, “Run now”, “Retry”.
## Non-Goals (MVP)
- Kein Kalender-UI als Pflicht (kann später ergänzt werden).
- Kein Cross-Tenant Bulk Scheduling (MSP-Templates später).
- Kein “drift-triggered scheduling” (kommt nach Drift-MVP).
- Kein Restore via Scheduling (nur Backup).
## Definitions
- **Schedule**: Wiederkehrender Plan (daily/weekly, timezone).
- **Run**: Konkrete Ausführung eines Schedules (scheduled_for + status).
- **BackupSet**: Ergebniscontainer eines Runs.
**MVP Semantik**: **1 Run = 1 neues BackupSet** (kein Rolling-Reuse im MVP).
## Requirements
### Functional Requirements
- **FR-001**: Schedules sind tenant-scoped via `tenant_id` (FK auf `tenants.id`).
- **FR-002**: Dispatcher erkennt “due” schedules und erstellt genau einen Run pro Zeit-Slot (idempotent).
- **FR-003**: Run nutzt bestehende Services:
- Sync Policies (nur selektierte policy types)
- Create BackupSet aus lokalen Policy-IDs (inkl. Foundations optional)
- **FR-004**: Run schreibt `backup_schedule_runs` mit Status + Summary + Error-Codes.
- **FR-005**: “Run now” erzeugt sofort einen Run (scheduled_for=now) und dispatcht Job.
- **FR-006**: “Retry” erzeugt einen neuen Run für denselben Schedule.
- **FR-007**: Retention hält nur die letzten N Runs/BackupSets pro Schedule (soft delete BackupSets).
- **FR-008**: Concurrency: Pro Schedule darf nur ein Run gleichzeitig laufen. Wenn bereits ein Run läuft, wird ein neuer Run nicht parallel gestartet und stattdessen als `skipped` markiert (mit Fehlercode).
### UX Requirements (Filament)
- **UX-001**: Schedule-Liste zeigt Enabled, Frequency, Time+Timezone, Policy Types Summary, Retention, Last Run, Next Run.
- **UX-002**: Run-History pro Schedule zeigt scheduled_for, status, duration, counts, error_code/message, Link zum BackupSet.
- **UX-003**: “Run now” und “Retry” sind nur mit passenden Rechten verfügbar.
### Security / Authorization
- **SEC-001**: Tenant Isolation: User sieht/managt nur Schedules des aktuellen Tenants.
- **SEC-002 (MVP)**: Authorization erfolgt über TenantRole (wie Tenant Portfolio):
- `readonly`: Schedules ansehen + Runs ansehen
- `operator`: zusätzlich “Run now” / “Retry”
- `manager` / `owner`: zusätzlich Schedules verwalten (CRUD)
- **SEC-003**: Dispatcher, Run-Execution und Retention schreiben tenant-scoped Audit Logs (keine Secrets/Tokens), inkl. Run-Start/Run-Ende und Retention-Ergebnis (z. B. Anzahl gelöschter BackupSets).
### Reliability / Non-Functional Requirements
- **NFR-001**: Idempotency durch Unique Slot-Constraint (`backup_schedule_id` + `scheduled_for`).
- **NFR-002**: Klare Fehlercodes (z. B. TOKEN_EXPIRED, PERMISSION_MISSING, GRAPH_THROTTLE, UNKNOWN).
- **NFR-003**: Retries: Throttling (z. B. 429/503) → Backoff; 401/403 → kein Retry; Unknown → begrenzte Retries und danach failed.
- **NFR-004**: Missed runs policy (MVP): **No catch-up** — wenn offline, wird nicht nachgeholt, nur nächster Slot.
### Scheduling Semantics
- `scheduled_for` ist **minute-basiert** (Slot), in UTC gespeichert. Due-Berechnung erfolgt in der Schedule-Timezone.
- DST (MVP): Bei ungültiger lokaler Zeit wird der Slot übersprungen (Run `skipped`). Bei ambiger lokaler Zeit wird die erste Occurrence verwendet.
## Data Model
### backup_schedules
- `id` bigint
- `tenant_id` FK tenants.id
- `name` string
- `is_enabled` bool default true
- `timezone` string default 'UTC'
- `frequency` string enum: daily|weekly
- `time_of_day` time
- `days_of_week` json nullable (array<int>, weekly only; 1=Mon..7=Sun)
- `policy_types` jsonb (array<string>)
- `include_foundations` bool default true
- `retention_keep_last` int default 30
- `last_run_at` datetime nullable
- `last_run_status` string nullable
- `next_run_at` datetime nullable
- timestamps
Indexes:
- (tenant_id, is_enabled)
- (next_run_at) optional
### backup_schedule_runs
- `id` bigint
- `backup_schedule_id` FK
- `tenant_id` FK (denormalisiert)
- `scheduled_for` datetime
- `started_at` datetime nullable
- `finished_at` datetime nullable
- `status` string enum: running|success|partial|failed|canceled|skipped
- `summary` jsonb (policies_total, policies_backed_up, errors_count, type_breakdown, warnings)
- `error_code` string nullable
- `error_message` text nullable
- `backup_set_id` FK nullable
- timestamps
Indexes:
- (backup_schedule_id, scheduled_for)
- (tenant_id, created_at)
- **Unique**: (backup_schedule_id, scheduled_for)
## Acceptance Criteria
- User kann pro Tenant einen Schedule anlegen (daily/weekly, time, timezone, policy types, retention).
- Dispatcher erstellt Runs zur geplanten Zeit (Queue Worker vorausgesetzt).
- UI zeigt Last Run + Next Run + Run-History.
- Run now startet sofort.
- Fehlerfälle (Token/Permission/Throttle) werden als failed/partial markiert mit error_code.
- Retention hält nur die letzten N BackupSets pro Schedule.