TenantAtlas/specs/032-backup-scheduling-mvp/spec.md
2026-01-05 05:15:47 +01:00

7.0 KiB
Raw Blame History

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”.

Clarifications

Session 2026-01-05

  • Q: Wie sollen wir mit policy_types umgehen, die nicht in config('tenantpilot.supported_policy_types') enthalten sind? → A: Beim Speichern hart validieren und ablehnen; zur Laufzeit defensiv re-checken (Legacy/DB), unknown types skippen und Run als partial markieren mit error_code=UNKNOWN_POLICY_TYPE und Liste betroffener Types.
  • Q: Wenn zur Laufzeit alle policy_types unbekannt sind (0 valid types nach Skip) welcher Status? → A: skipped (fail-safe).

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-003a: policy_types sind ausschließlich Keys aus config('tenantpilot.supported_policy_types').
  • FR-003b: UI/Server-side Validation verhindert das Speichern unbekannter policy_types.
  • FR-003c: Laufzeit-Validierung (defensiv): Unbekannte policy_types werden geskippt; wenn mindestens ein gültiger Type verarbeitet wurde, wird der Run als partial markiert und error_code=UNKNOWN_POLICY_TYPE gesetzt (inkl. Liste der betroffenen Types in summary).
  • FR-003d: Wenn zur Laufzeit nach dem Skip 0 gültige Types verbleiben, wird kein BackupSet erzeugt und der Run als skipped markiert (mit error_code=UNKNOWN_POLICY_TYPE und Liste der betroffenen Types in summary).
  • 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 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, weekly only; 1=Mon..7=Sun)
  • policy_types jsonb (array)
  • 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.
  • Unbekannte policy_types können nicht gespeichert werden; falls Legacy-Daten vorkommen, werden sie zur Laufzeit geskippt: mit valid types → partial, ohne valid types → skipped (jeweils error_code=UNKNOWN_POLICY_TYPE).
  • Retention hält nur die letzten N BackupSets pro Schedule.