143 lines
6.4 KiB
Markdown
143 lines
6.4 KiB
Markdown
# Implementation Plan: 098 — Settings Slices v1 (Backup + Drift + Operations)
|
|
|
|
**Branch**: `098-settings-slices-v1-backup-drift-ops` | **Date**: 2026-02-16 | **Spec**: `specs/098-settings-slices-v1-backup-drift-ops/spec.md`
|
|
**Input**: Feature specification from `specs/098-settings-slices-v1-backup-drift-ops/spec.md`
|
|
|
|
## Summary
|
|
|
|
Extend the existing Settings Foundation to expose five additional workspace-level keys on the Workspace Settings page, with strict validation, per-setting reset-to-default (confirmed), and audit logging per key changed.
|
|
|
|
Apply those settings to three behavior paths:
|
|
|
|
- Backup retention: enforce a workspace-configurable retention default and a workspace-configurable retention floor (effective values clamped up to the floor).
|
|
- Drift severities: allow workspace-configurable `finding_type → severity` mapping (default `medium`, values normalized).
|
|
- Operations: allow workspace-configurable operation run retention days for pruning and store a “stuck run threshold” value (storage only; no new auto-remediation behavior).
|
|
|
|
## Technical Context
|
|
|
|
**Language/Version**: PHP 8.4 (Laravel 12)
|
|
**Primary Dependencies**: Filament v5, Livewire v4, Laravel Sail
|
|
**Storage**: PostgreSQL (Sail local)
|
|
**Testing**: Pest v4 (PHPUnit 12 runner)
|
|
**Target Platform**: Web app (Filament admin panel)
|
|
**Project Type**: Laravel monolith (Filament pages + services + jobs)
|
|
**Performance Goals**: Settings resolution should remain request-local cached (no repeated DB reads per key within a request).
|
|
**Constraints**:
|
|
- DB-only rendering for settings UI (no Graph calls as a render side-effect)
|
|
- Strict workspace isolation (non-member 404)
|
|
- Capability-gated mutations (member without capability 403)
|
|
- Destructive-like resets require confirmation
|
|
- Audit each successful mutation; multi-key save produces one audit entry per key changed
|
|
|
|
## Baselines to Preserve (When Unset)
|
|
|
|
These are the “no settings configured” behaviors that must remain unchanged and covered by regression tests.
|
|
|
|
Record the baseline values explicitly so “no change” remains mechanically verifiable over time:
|
|
|
|
- Backup retention default:
|
|
- When a schedule has no `retention_keep_last`, the job resolves `backup.retention_keep_last_default` and falls back to `30` if unresolved/non-numeric.
|
|
- Current clamp behavior: values < 1 are clamped up to 1.
|
|
- Source: `app/Jobs/ApplyBackupScheduleRetentionJob.php`.
|
|
- Current system default: `backup.retention_keep_last_default` is `30` in `app/Support/Settings/SettingsRegistry.php`.
|
|
- Drift default severity:
|
|
- Drift findings currently default to `Finding::SEVERITY_MEDIUM`.
|
|
- Source: `app/Services/Drift/DriftFindingGenerator.php`.
|
|
- Operation run pruning:
|
|
- Prune job default retention is `90` days (`new PruneOldOperationRunsJob()` with default constructor argument).
|
|
- Source: `app/Jobs/PruneOldOperationRunsJob.php` and schedule in `routes/console.php`.
|
|
- “Stuck run threshold”:
|
|
- No baseline behavior exists today; for this feature it remains storage-only (must not introduce auto-remediation).
|
|
|
|
## Constitution Check
|
|
|
|
*GATE: Must pass before implementation. Re-check after design/edits.*
|
|
|
|
- DB-only rendering: PASS (Workspace Settings UI is DB-only).
|
|
- Graph contract path: PASS (no Graph calls introduced).
|
|
- RBAC-UX semantics: PASS-BY-DESIGN (non-member 404; member missing capability 403; server-side still authoritative).
|
|
- Destructive-like confirmation: PASS-BY-DESIGN (per-setting reset actions must require confirmation).
|
|
- Auditability: PASS-BY-DESIGN (settings writes are audited per key).
|
|
- Filament Action Surface Contract: PASS (page-level action surface is explicitly declared in spec via UI Action Matrix).
|
|
|
|
## Project Structure
|
|
|
|
### Documentation (this feature)
|
|
|
|
```text
|
|
specs/098-settings-slices-v1-backup-drift-ops/
|
|
├── plan.md
|
|
├── spec.md
|
|
├── tasks.md
|
|
└── checklists/
|
|
└── requirements.md
|
|
```
|
|
|
|
### Source Code (repository root)
|
|
|
|
```text
|
|
app/
|
|
├── Filament/Pages/Settings/WorkspaceSettings.php
|
|
├── Jobs/
|
|
│ ├── ApplyBackupScheduleRetentionJob.php
|
|
│ └── PruneOldOperationRunsJob.php
|
|
├── Models/Finding.php
|
|
├── Services/Drift/DriftFindingGenerator.php
|
|
└── Support/
|
|
├── Badges/Domains/FindingSeverityBadge.php
|
|
└── Settings/SettingsRegistry.php
|
|
|
|
routes/console.php
|
|
|
|
tests/Feature/
|
|
├── BackupScheduling/BackupScheduleLifecycleTest.php
|
|
├── Drift/DriftPolicySnapshotDriftDetectionTest.php
|
|
├── Scheduling/PruneOldOperationRunsScheduleTest.php
|
|
└── SettingsFoundation/
|
|
├── WorkspaceSettingsManageTest.php
|
|
├── WorkspaceSettingsViewOnlyTest.php
|
|
└── WorkspaceSettingsNonMemberNotFoundTest.php
|
|
```
|
|
|
|
**Structure Decision**: Use existing Laravel structure only. No new top-level directories.
|
|
|
|
## Plan Phases
|
|
|
|
### Phase 0 — Align the Registry + UI primitives (shared)
|
|
|
|
- Ensure Settings registry rules match the spec (notably the backup max bounds).
|
|
- Refactor the Workspace Settings page to support:
|
|
- Per-setting reset actions (no global reset)
|
|
- Unset inputs with helper text showing the effective/default value
|
|
- Save semantics that can “unset” (delete override) for a single key
|
|
- Update the existing SettingsFoundation tests to reflect the new UX primitives.
|
|
|
|
### Phase 1 — US1 Backup slice (MVP)
|
|
|
|
- Add `backup.retention_min_floor` to the registry and UI.
|
|
- Apply floor clamping in the retention job to both schedule overrides and workspace defaults.
|
|
- Add/extend BackupScheduling + SettingsFoundation tests to cover both baseline behavior and clamping.
|
|
|
|
### Phase 2 — US2 Drift slice
|
|
|
|
- Add `drift.severity_mapping` to the registry and UI with strict JSON shape validation.
|
|
- Normalize severity values to lowercase on save; reject unsupported severities.
|
|
- Apply mapping in drift finding generation with default `medium` fallback.
|
|
- Add drift tests for default + mapped severity, and settings validation tests.
|
|
|
|
### Phase 3 — US3 Operations slice
|
|
|
|
- Add operations keys to the registry and UI.
|
|
- Wire pruning job to use the configured retention days when set (baseline otherwise).
|
|
- Ensure “stuck threshold” is stored only (no new behavior in this feature).
|
|
- Add pruning job/schedule tests and settings persistence tests.
|
|
|
|
### Phase 4 — Format + focused regression
|
|
|
|
- Run Pint for touched files.
|
|
- Run the focused test set for SettingsFoundation + BackupScheduling + Drift + Scheduling.
|
|
|
|
## Complexity Tracking
|
|
|
|
No constitution violations are required for this feature.
|