TenantAtlas/specs/032-backup-scheduling-mvp/plan.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

2.9 KiB

Plan: Backup Scheduling MVP (032)

Date: 2026-01-05 Input: spec.md

Architecture / Reuse

  • Reuse existing services:
    • PolicySyncService::syncPoliciesWithReport() for selected policy types
    • BackupService::createBackupSet() to create immutable snapshots + items (include_foundations supported)
  • Store selection as policy_types (config keys), not free-form categories.
  • Use tenant scoping (tenant_id) consistent with existing tables (backup_sets, backup_items).

Scheduling Mechanism

  • Add Artisan command: tenantpilot:schedules:dispatch.
  • Scheduler integration (Laravel 12): schedule the command every minute via routes/console.php + ops configuration (Dokploy cron schedule:run or long-running schedule:work).
  • Dispatcher algorithm:
    1. load enabled schedules
    2. compute whether due for the current minute in schedule timezone
    3. create run with scheduled_for slot (minute precision) using DB unique constraint
    4. dispatch RunBackupScheduleJob(schedule_id, run_id)
  • Concurrency:
    • Cache lock per schedule (lock:backup_schedule:{id}) plus DB unique slot constraint for idempotency.
    • If lock is held: mark run as skipped with a clear error_code (no parallel execution).

Run Execution

  • RunBackupScheduleJob:
    1. load schedule + tenant
    2. preflight: tenant active; Graph/auth errors mapped to error_code
    3. sync policies for selected types (collect report)
    4. select policy IDs from local DB for those types (exclude ignored)
    5. create backup set:
      • name: {schedule_name} - {Y-m-d H:i}
      • includeFoundations: schedule flag
    6. set run status:
      • success if backup_set.status == completed
      • partial if backup_set.status == partial OR sync had failures but backup succeeded
      • failed if nothing backed up / hard error
    7. update schedule last_run_* and compute/persist next_run_at
    8. dispatch retention job
    9. audit logs:
    • log run start + completion (status, counts, error_code; no secrets)

Retry / Backoff

  • Configure job retry behavior based on error classification:
    • Throttling/transient (e.g. 429/503): backoff + retry
    • Auth/permission (401/403): no retry
    • Unknown: limited retries

Retention

  • ApplyBackupScheduleRetentionJob(schedule_id):
    • identify runs ordered newest→oldest
    • keep last N runs that created a backup_set_id
    • for older ones: soft-delete referenced BackupSets (and cascade soft-delete items)
    • audit log: number of deleted BackupSets

Filament UX

  • Tenant-scoped resources:
    • BackupScheduleResource
    • Runs UI via RelationManager under schedule (or a dedicated resource if needed)
  • Actions: enable/disable, run now, retry
  • Notifications: persist via ->sendToDatabase($user) for the DB info panel.
    • MVP notification scope: only interactive actions notify the acting user; scheduled runs rely on Run history.

Ops / Deployment Notes

  • Requires queue worker.
  • Requires scheduler running.
  • Missed runs policy (MVP): no catch-up.