Implements Spec 098: workspace-level settings slices for Backup retention, Drift severity mapping, and Operations retention/threshold. Spec - specs/098-settings-slices-v1-backup-drift-ops/spec.md What changed - Workspace Settings page: grouped Backup/Drift/Operations sections, unset-input UX w/ helper text, per-setting reset actions (confirmed) - Settings registry: adds/updates validation + normalization (incl. drift severity mapping normalization to lowercase) - Backup retention: adds workspace default + floor clamp; job clamps effective keep-last up to floor - Drift findings: optional workspace severity mapping; adds `critical` severity support + badge mapping - Operations pruning: retention computed per workspace via settings; scheduler unchanged; stuck threshold is storage-only Safety / Compliance notes - Filament v5 / Livewire v4: no Livewire v3 usage; relies on existing Filament v5 + Livewire v4 stack - Provider registration unchanged (Laravel 11+/12 uses bootstrap/providers.php) - Destructive actions: per-setting reset uses Filament actions with confirmation - Global search: not affected (no resource changes) - Assets: no new assets registered; no `filament:assets` changes Tests - vendor/bin/sail artisan test --compact tests/Feature/SettingsFoundation/WorkspaceSettingsManageTest.php \ tests/Feature/SettingsFoundation/WorkspaceSettingsViewOnlyTest.php \ tests/Feature/BackupScheduling/BackupScheduleLifecycleTest.php \ tests/Feature/Drift/DriftPolicySnapshotDriftDetectionTest.php \ tests/Feature/Scheduling/PruneOldOperationRunsScheduleTest.php \ tests/Unit/Badges/FindingBadgesTest.php Formatting - vendor/bin/sail bin pint --dirty Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #120
161 lines
12 KiB
Markdown
161 lines
12 KiB
Markdown
# Feature Specification: 098 — Settings Slices v1 (Backup + Drift + Operations)
|
|
|
|
**Feature Branch**: `098-settings-slices-v1-backup-drift-ops`
|
|
**Created**: 2026-02-16
|
|
**Status**: Draft
|
|
**Input**: Workspace-level settings slices for Backup, Drift severity mapping, and Operations retention/thresholds with safe defaults.
|
|
|
|
## Spec Scope Fields *(mandatory)*
|
|
|
|
- **Scope**: workspace
|
|
- **Primary Routes**: Workspace Settings screen (admin UI)
|
|
- **Data Ownership**: workspace-owned settings values (key/value) + audit log entries for setting changes
|
|
- **RBAC**: workspace membership required; view vs manage capability-gated; deny-as-not-found for non-members
|
|
|
|
## Clarifications
|
|
|
|
### Session 2026-02-16
|
|
|
|
- Q: Which “Reset to default” scope do you want on the Workspace Settings UI? → A: Per-setting reset (each key individually).
|
|
- Q: When an admin clicks “Save” and multiple settings change at once, how should audit logging behave? → A: One audit log entry per key changed.
|
|
- Q: Should we enforce a validation constraint between `backup.retention_keep_last_default` and `backup.retention_min_floor`? → A: Allow any values; effective retention is always clamped to `backup.retention_min_floor`.
|
|
- Q: For settings that are currently unset (so the system uses defaults), how should the UI present them? → A: Leave input unset, show helper text with the default/effective value.
|
|
- Q: In `drift.severity_mapping`, should severity values be case-sensitive? → A: Case-insensitive; normalize to lowercase on save.
|
|
|
|
## User Scenarios & Testing *(mandatory)*
|
|
|
|
### User Story 1 - Configure backup retention defaults (Priority: P1)
|
|
|
|
As a workspace admin, I want to configure workspace-wide defaults for backup retention so that enterprise workspaces can tune policy without code/config changes.
|
|
|
|
**Why this priority**: Backup retention is a common enterprise requirement and impacts storage cost and governance.
|
|
|
|
**Independent Test**: Can be tested by setting/unsetting workspace settings and verifying backup retention behavior remains unchanged by default and changes deterministically when configured.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** no workspace settings exist for backup retention, **When** a backup retention decision is made, **Then** behavior matches the current baseline (no change).
|
|
2. **Given** a workspace default retention value is configured, **When** a backup retention decision is made without a more specific override, **Then** the configured default is used.
|
|
3. **Given** a retention “floor” value is configured, **When** any calculated retention value is below the floor, **Then** the effective retention is clamped up to the floor.
|
|
4. **Given** a per-schedule override is configured, **When** that override is below the configured floor, **Then** the override is clamped up to the floor.
|
|
|
|
---
|
|
|
|
### User Story 2 - Configure drift severity mapping (Priority: P2)
|
|
|
|
As a workspace admin, I want to map drift finding types to severities so that findings align with enterprise risk posture and triage practices.
|
|
|
|
**Why this priority**: Severity directly affects how teams triage drift; a one-size-fits-all default is too rigid for enterprise.
|
|
|
|
**Independent Test**: Can be tested by saving a mapping, generating findings for mapped/unmapped types, and verifying severities are assigned correctly.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** no drift severity mapping exists, **When** a drift finding is produced, **Then** its severity defaults to “medium”.
|
|
2. **Given** a mapping exists for a specific finding type, **When** a drift finding with that type is produced, **Then** the mapped severity is applied.
|
|
3. **Given** a mapping contains an unknown/unsupported severity value, **When** an admin attempts to save it, **Then** the save is rejected and no invalid values are persisted.
|
|
|
|
---
|
|
|
|
### User Story 3 - Configure operations retention and stuck threshold (Priority: P3)
|
|
|
|
As a workspace admin, I want to configure retention for operations/run records and store a “stuck run” threshold so that data lifecycle and operational heuristics are workspace-tunable.
|
|
|
|
**Why this priority**: Retention policies and operational thresholds vary widely between organizations and audit requirements.
|
|
|
|
**Independent Test**: Can be tested by saving retention/threshold settings and verifying the retention cutoff used by pruning changes accordingly while no new automatic actions occur.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** no operations retention setting exists, **When** operations/run pruning is executed, **Then** the cutoff matches the current baseline (no change).
|
|
2. **Given** an operations retention setting exists, **When** pruning is executed, **Then** the cutoff is derived from the configured retention days.
|
|
3. **Given** a stuck threshold is configured, **When** the Workspace Settings screen is re-opened, **Then** the configured value is shown exactly as saved.
|
|
4. **Given** a stuck threshold is configured, **When** operations/run behavior is observed, **Then** no automatic remediation or auto-handling is performed in this feature scope.
|
|
|
|
### Edge Cases
|
|
|
|
- Attempting to save invalid numeric ranges (too low/high) is rejected and does not persist.
|
|
- Attempting to save invalid JSON (malformed) for drift mapping is rejected.
|
|
- Attempting to save drift mapping with non-string keys is rejected.
|
|
- Two admins editing settings concurrently results in deterministic persisted state (last write wins) and both attempts are auditable.
|
|
- A user without manage capability can view settings (read-only) but cannot submit changes.
|
|
- A non-member cannot discover the Workspace Settings screen or any values (deny-as-not-found).
|
|
|
|
## Requirements *(mandatory)*
|
|
|
|
**Constitution alignment (required):** This feature MUST remain DB-only for screen rendering and MUST NOT introduce Microsoft Graph calls as part of rendering or saving these settings. Any setting mutation MUST be auditable.
|
|
|
|
### Dependencies & Assumptions
|
|
|
|
- This feature depends on an existing workspace settings foundation that provides: workspace-scoped storage, consistent defaults, centralized validation, RBAC capability enforcement, and audit logging for changes.
|
|
- No tenant-specific override UI is included in v1; only workspace-wide configuration is in scope.
|
|
- The default values for all settings keys match the current baseline behavior at the time this feature ships.
|
|
|
|
**Constitution alignment (RBAC-UX):**
|
|
|
|
- Authorization planes involved: workspace-scoped admin UI.
|
|
- Non-member / not entitled to workspace scope → 404 (deny-as-not-found).
|
|
- Member but missing manage capability → 403 on mutation attempts; UI remains read-only.
|
|
|
|
**Constitution alignment (OPS/observability):** This feature does not introduce a new long-running operation type; it changes which configuration values are used by existing behavior. All admin-initiated mutations MUST produce audit log entries.
|
|
|
|
### Functional Requirements
|
|
|
|
- **FR-001**: System MUST support workspace-level configuration for the following setting keys:
|
|
- `backup.retention_keep_last_default`
|
|
- `backup.retention_min_floor`
|
|
- `drift.severity_mapping`
|
|
- `operations.operation_run_retention_days`
|
|
- `operations.stuck_run_threshold_minutes`
|
|
- **FR-002**: System MUST preserve existing behavior when none of the above settings are configured (defaults MUST match the current baseline).
|
|
- **FR-003**: System MUST validate and reject invalid setting values, ensuring no invalid configuration is silently persisted.
|
|
- **FR-004**: Workspace Settings UI MUST present the above keys grouped into three sections (Backup, Drift, Operations) and MUST be fully functional without any external API calls.
|
|
- **FR-004a**: For any setting key that is currently unset, the UI MUST keep the input in an “unset” state and MUST display helper text indicating the default (currently effective) value.
|
|
- **FR-005**: Users with view capability MUST be able to view current effective settings but MUST NOT be able to change them.
|
|
- **FR-006**: Users with manage capability MUST be able to change settings and reset individual settings back to defaults.
|
|
- **FR-007**: Resetting a setting to default MUST be a confirmed (destructive-like) action.
|
|
- **FR-008**: System MUST write audit log entries for each settings update and reset-to-default event including: workspace identity, actor identity, setting key, old value, new value, and timestamp.
|
|
- **FR-008a**: When a single save operation changes multiple keys, the system MUST write one audit log entry per key changed.
|
|
|
|
#### Backup slice requirements
|
|
|
|
- **FR-009**: `backup.retention_keep_last_default` MUST be an integer between 1 and 365.
|
|
- **FR-010**: `backup.retention_min_floor` MUST be an integer between 1 and 365.
|
|
- **FR-011**: Effective backup retention MUST never be lower than `backup.retention_min_floor` (applies to defaults and any more specific overrides).
|
|
- **FR-011a**: The system MUST NOT reject configuration solely because `backup.retention_min_floor` exceeds `backup.retention_keep_last_default`; instead, the effective retention MUST be clamped to the floor.
|
|
|
|
#### Drift slice requirements
|
|
|
|
- **FR-012**: `drift.severity_mapping` MUST be a JSON object mapping `finding_type` (string) → severity.
|
|
- **FR-013**: Allowed severity values MUST be limited to: `low`, `medium`, `high`, `critical`.
|
|
- **FR-013a**: Severity values MUST be accepted case-insensitively and normalized to lowercase when persisted.
|
|
- **FR-014**: If a finding type has no mapping entry, severity MUST default to `medium`.
|
|
|
|
#### Operations slice requirements
|
|
|
|
- **FR-015**: `operations.operation_run_retention_days` MUST be an integer between 7 and 3650.
|
|
- **FR-016**: Pruning of operations/run records MUST use the configured retention days when set; otherwise it MUST behave as the baseline.
|
|
- **FR-017**: `operations.stuck_run_threshold_minutes` MUST be an integer between 0 and 10080.
|
|
- **FR-018**: `operations.stuck_run_threshold_minutes` MUST be a stored configuration value only; it MUST NOT introduce auto-remediation or auto-handling behavior in this feature scope.
|
|
|
|
## UI Action Matrix *(mandatory when Filament is changed)*
|
|
|
|
| Surface | Location | Header Actions | Inspect Affordance (List/Table) | Row Actions (max 2 visible) | Bulk Actions (grouped) | Empty-State CTA(s) | View Header Actions | Create/Edit Save+Cancel | Audit log? | Notes / Exemptions |
|
|
|---|---|---|---|---|---|---|---|---|---|---|
|
|
| Page | Workspace Settings (admin UI) | Save; Reset setting to default (per-setting, confirmed) | N/A | N/A | N/A | N/A | N/A | Save + Cancel | Yes | View capability: read-only fields; Manage capability: editable + submit; Non-member: 404 |
|
|
|
|
### Key Entities *(include if feature involves data)*
|
|
|
|
- **Workspace Setting**: A workspace-owned key/value configuration item with validation rules and a default.
|
|
- **Audit Log Entry**: An immutable record of a settings update or reset-to-default event.
|
|
- **Drift Finding Type**: A classification string used to identify the type of drift finding for severity mapping.
|
|
|
|
## Success Criteria *(mandatory)*
|
|
|
|
### Measurable Outcomes
|
|
|
|
- **SC-001**: When no settings are configured for these keys, backup retention behavior, drift severity behavior, and operations pruning behavior match the baseline in automated regression tests.
|
|
- **SC-002**: An authorized workspace admin can update each of the 5 settings and observe the new effective value reflected in the Workspace Settings screen immediately after save.
|
|
- **SC-003**: 100% of settings updates and reset-to-default actions produce an audit log entry with key, old value, and new value.
|
|
- **SC-004**: Invalid configuration attempts (out-of-range numbers, invalid JSON, unsupported severities) are rejected and do not change persisted settings.
|