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

68 lines
2.9 KiB
Markdown

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