What Implements tenant-scoped backup scheduling end-to-end: schedules CRUD, minute-based dispatch, queued execution, run history, manual “Run now/Retry”, retention (keep last N), and auditability. Key changes Filament UI: Backup Schedules resource with tenant scoping + SEC-002 role gating. Scheduler + queue: tenantpilot:schedules:dispatch command wired in scheduler (runs every minute), creates idempotent BackupScheduleRun records and dispatches jobs. Execution: RunBackupScheduleJob syncs policies, creates immutable backup sets, updates run status, writes audit logs, applies retry/backoff mapping, and triggers retention. Run history: Relation manager + “View” modal rendering run details. UX polish: row actions grouped; bulk actions grouped (run now / retry / delete). Bulk dispatch writes DB notifications (shows in notifications panel). Validation: policy type hard-validation on save; unknown policy types handled safely at runtime (skipped/partial). Tests: comprehensive Pest coverage for CRUD/scoping/validation, idempotency, job outcomes, error mapping, retention, view modal, run-now/retry notifications, bulk delete (incl. operator forbidden). Files / Areas Filament: BackupScheduleResource.php and app/Filament/Resources/BackupScheduleResource/* Scheduling/Jobs: app/Console/Commands/TenantpilotDispatchBackupSchedules.php, app/Jobs/RunBackupScheduleJob.php, app/Jobs/ApplyBackupScheduleRetentionJob.php, console.php Models/Migrations: app/Models/BackupSchedule.php, app/Models/BackupScheduleRun.php, database/migrations/backup_schedules, backup_schedule_runs Notifications: BackupScheduleRunDispatchedNotification.php Specs: specs/032-backup-scheduling-mvp/* (tasks/checklist/quickstart updates) How to test (Sail) Run tests: ./vendor/bin/sail artisan test tests/Feature/BackupScheduling Run formatter: ./vendor/bin/sail php ./vendor/bin/pint --dirty Apply migrations: ./vendor/bin/sail artisan migrate Manual dispatch: ./vendor/bin/sail artisan tenantpilot:schedules:dispatch Notes Uses DB notifications for queued UI actions to ensure they appear in the notifications panel even under queue fakes in tests. Checklist gate for 032 is PASS; tasks updated accordingly. Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local> Reviewed-on: #34
3.6 KiB
Implementation Plan: Backup Scheduling MVP (032)
Branch: feat/032-backup-scheduling-mvp | Date: 2026-01-05 | Spec: specs/032-backup-scheduling-mvp/spec.md
Input: Feature specification from specs/032-backup-scheduling-mvp/spec.md
Summary
Implement tenant-scoped backup schedules that dispatch idempotent runs every minute via Laravel scheduler and queue workers. Each run syncs selected policy types from Graph into the local DB (via existing PolicySyncService) and creates an immutable BackupSet snapshot (via existing BackupService), with strict audit logging, fail-safe handling for unknown policy types, retention (keep last N), and Filament UI for managing schedules and viewing run history.
Technical Context
Language/Version: PHP 8.4.15
Primary Dependencies: Laravel 12, Filament v4, Livewire v3
Storage: PostgreSQL (Sail locally)
Testing: Pest v4
Target Platform: Containerized (Sail local), Dokploy deploy (staging/prod)
Project Type: Web application (Laravel monolith + Filament admin)
Performance Goals: Scheduler runs every minute; per-run work is queued; avoid long locks
Constraints: Idempotent dispatch (unique slot), per-schedule concurrency lock, no secrets/tokens in logs, “no catch-up” policy
Scale/Scope: Multi-tenant MSP use; schedules per tenant; runs stored for audit/history
Constitution Check
GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.
- Safety-First Restore: PASS (feature is backup-only; no restore scheduling)
- Auditability & Tenant Isolation: PASS (tenant_id everywhere; audit log entries for dispatch/run/retention)
- Graph Abstraction & Contracts: PASS (sync uses
GraphClientInterfaceviaPolicySyncService; unknown policy types fail-safe; no hardcoded endpoints) - Least Privilege: PASS (authorization via TenantRole matrix; no new scopes required beyond existing backup/sync)
- Spec-First Workflow: PASS (spec/plan/tasks/checklist in
specs/032-backup-scheduling-mvp/) - Quality Gates: PASS (tasks include Pest coverage per constitution and Pint)
Project Structure
Documentation (this feature)
specs/032-backup-scheduling-mvp/
├── plan.md # This file (/speckit.plan output)
├── research.md # Phase 0 output
├── data-model.md # Phase 1 output
├── quickstart.md # Phase 1 output
├── contracts/ # Phase 1 output
└── tasks.md # Phase 2 output (already present)
Source Code (repository root)
app/
├── Console/Commands/
├── Filament/Resources/
├── Jobs/
├── Models/
└── Services/
config/
database/migrations/
routes/console.php
tests/
Expected additions for this feature (at implementation time):
app/Console/Commands/TenantpilotDispatchBackupSchedules.php
app/Jobs/RunBackupScheduleJob.php
app/Jobs/ApplyBackupScheduleRetentionJob.php
app/Models/BackupSchedule.php
app/Models/BackupScheduleRun.php
app/Filament/Resources/BackupScheduleResource.php
database/migrations/*_create_backup_schedules_table.php
database/migrations/*_create_backup_schedule_runs_table.php
tests/Feature/BackupScheduling/*
tests/Unit/BackupScheduling/*
Structure Decision: Laravel monolith (Filament admin + queued jobs). No new top-level app folders.
Phase Outputs
- Phase 0 (Outline & Research):
research.md - Phase 1 (Design & Contracts):
data-model.md,contracts/*,quickstart.md - Phase 2 (Tasks):
tasks.mdalready exists; will be refined later via/speckit.tasksif needed - Phase 1 (Design & Contracts):
data-model.md,contracts/*,quickstart.md