140 lines
9.6 KiB
Markdown
140 lines
9.6 KiB
Markdown
# Feature Specification: Settings Foundation (Workspace + Optional Tenant Override)
|
|
|
|
**Feature Branch**: `097-settings-foundation`
|
|
**Created**: 2026-02-15
|
|
**Status**: Draft
|
|
**Input**: User description: "Settings Foundation (Workspace + optional Tenant override)"
|
|
|
|
## Spec Scope Fields *(mandatory)*
|
|
|
|
- **Scope**: workspace (with optional tenant overrides for future expansion)
|
|
- **Primary Routes**: Admin panel “Settings” page (workspace-scoped)
|
|
- **Data Ownership**: Workspace-owned settings records, with optional tenant override records that must belong to the same workspace
|
|
- **RBAC**: Workspace membership required (non-members see 404); capability-gated view vs manage (Owner/Manager manage; Operator/Readonly view)
|
|
|
|
## Clarifications
|
|
|
|
### Session 2026-02-15
|
|
|
|
- Q: Which role-to-capability mapping should this spec enforce for workspace settings? → A: Option A (Owner+Manager manage; Operator+Readonly view)
|
|
- Q: What should the system default be for `backup.retention_keep_last_default`? → A: Option A (`30`)
|
|
- Q: Should `SettingsResolver` implement cross-request caching in v1? → A: Option A (request-local cache only)
|
|
- Q: When a manager clicks “Reset to system default”, what should happen to the stored workspace override? → A: Option A (remove the override so resolution falls back to system default)
|
|
|
|
## User Scenarios & Testing *(mandatory)*
|
|
|
|
### User Story 1 - Manage workspace settings safely (Priority: P1)
|
|
|
|
Workspace administrators need a single, consistent place to configure workspace-wide defaults that are used by operational features and can be audited later.
|
|
|
|
**Why this priority**: Without a settings foundation, features will implement ad-hoc settings patterns that are inconsistent, hard to audit, and risky to operate.
|
|
|
|
**Independent Test**: A manager updates the pilot setting, sees the new value reflected, and the system uses it as the workspace default for relevant behavior.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** a workspace member with settings-manage capability, **When** they update the pilot setting value, **Then** the value is persisted for that workspace and an audit entry is recorded.
|
|
2. **Given** a workspace member with settings-manage capability and an existing workspace override, **When** they reset the pilot setting to the system default, **Then** the effective value becomes the system default and an audit entry is recorded.
|
|
|
|
---
|
|
|
|
### User Story 2 - View settings without the ability to change them (Priority: P2)
|
|
|
|
Read-only operators need to see what the workspace defaults are, without being able to modify them.
|
|
|
|
**Why this priority**: Visibility supports troubleshooting and governance without expanding write privileges.
|
|
|
|
**Independent Test**: A viewer can open the settings page and see values, but cannot persist any changes.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** a workspace member with settings-view capability but without settings-manage capability, **When** they open the settings page, **Then** they can view the current value but cannot save or reset settings.
|
|
2. **Given** a workspace member without settings-manage capability, **When** they attempt to submit a settings change by any means, **Then** the request is rejected with 403 and no setting is changed.
|
|
|
|
---
|
|
|
|
### User Story 3 - Tenant overrides take precedence (backend-ready) (Priority: P3)
|
|
|
|
Some settings may need tenant-specific overrides while still inheriting workspace defaults when no override exists.
|
|
|
|
**Why this priority**: Establishes a stable precedence model early, so future features can safely add tenant overrides without redefining rules.
|
|
|
|
**Independent Test**: For a chosen tenant in a workspace, resolving a setting returns tenant override when present, otherwise workspace override, otherwise system default.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** no stored values for a setting, **When** the system resolves it for a workspace (and optional tenant), **Then** the system default is returned.
|
|
2. **Given** a workspace override exists, **When** the system resolves the setting, **Then** the workspace value is returned.
|
|
3. **Given** a tenant override exists within the same workspace, **When** the system resolves the setting for that tenant, **Then** the tenant value is returned even if a workspace value exists.
|
|
|
|
### Edge Cases
|
|
|
|
- Unknown setting keys: write attempts are rejected and no changes are persisted.
|
|
- Invalid values (wrong type / out-of-range): write attempts are rejected and no changes are persisted.
|
|
- Tenant/workspace mismatch: the system rejects any attempt to store or resolve a tenant override for a tenant outside the workspace.
|
|
- Concurrent updates: the last accepted update wins, and each accepted mutation results in exactly one audit entry.
|
|
- Caching: within a single request, repeated reads for the same (workspace, optional tenant, domain, key) do not cause repeated database reads; across requests, no external cache is used in v1.
|
|
|
|
## Requirements *(mandatory)*
|
|
|
|
**Constitution alignment (required):** This feature introduces workspace-scoped settings mutations that intentionally do not create an operational run record. Each successful settings mutation MUST be auditable via an audit entry, including who changed what and when.
|
|
|
|
**Constitution alignment (RBAC-UX):**
|
|
|
|
- Authorization planes: workspace-scoped admin panel surface.
|
|
- 404 vs 403 semantics:
|
|
- non-member / not entitled to the workspace scope → 404 (deny-as-not-found)
|
|
- member but missing manage capability for mutations → 403
|
|
- Server-side enforcement: all setting mutations (update/reset) MUST be authorization-checked server-side; UI visibility/disabled states are not sufficient.
|
|
|
|
**Role mapping (clarified):**
|
|
|
|
- Owners and Managers MUST have settings-manage capability.
|
|
- Operators and Readonly members MUST have settings-view capability.
|
|
|
|
### Functional Requirements
|
|
|
|
- **FR-001**: System MUST provide a single settings substrate that can store workspace-wide defaults.
|
|
- **FR-002**: System MUST support optional tenant overrides that are always scoped to the same workspace.
|
|
- **FR-003**: System MUST resolve setting values using the precedence order: tenant override → workspace override → system default.
|
|
- **FR-004**: System MUST reject writes for unknown setting keys.
|
|
- **FR-005**: System MUST validate setting values against centrally-defined rules and reject invalid values.
|
|
- **FR-006**: System MUST ensure settings data cannot be read or written across workspace boundaries.
|
|
- **FR-007**: System MUST record an audit entry for each successful settings update and each successful reset-to-default.
|
|
- **FR-008**: System MUST provide a workspace-scoped Settings UI surface that supports viewing and managing settings based on capabilities.
|
|
- **FR-009**: System MUST include a pilot setting: `backup.retention_keep_last_default`.
|
|
- **FR-010**: The pilot setting MUST define a system default of `30` (preserves current behavior), and it MUST be overrideable at workspace scope.
|
|
- **FR-011**: When the pilot setting is used by backup scheduling/retention behavior, per-schedule overrides (if present) MUST continue to take precedence over workspace defaults.
|
|
- **FR-012**: The settings resolver MUST implement request-local caching for resolved values within a single request.
|
|
- **FR-013**: A reset-to-default MUST remove the stored override for the setting scope so future resolution falls back to the system default.
|
|
|
|
## 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 |
|
|
|---|---|---|---|---|---|---|---|---|---|---|
|
|
| Settings Page | Admin panel (workspace scope) | Save, Reset to system default | N/A | N/A | N/A | N/A | N/A | N/A | Yes | Reset is destructive-like and requires explicit confirmation; non-members get 404; members without manage get 403 on mutation |
|
|
|
|
### Key Entities *(include if feature involves data)*
|
|
|
|
- **Setting Definition**: A centrally-defined (domain, key) entry that declares the system default and validation constraints.
|
|
- **Workspace Setting Value**: A stored override for a (domain, key) at workspace scope.
|
|
- **Tenant Setting Value**: A stored override for a (domain, key) at tenant scope within the same workspace.
|
|
- **Settings Audit Entry**: An immutable record of a settings update or reset, including actor identity, target workspace/tenant, and before/after values.
|
|
|
|
### Non-Functional Requirements
|
|
|
|
- **NFR-001 (Security / Isolation)**: Non-members MUST receive deny-as-not-found (404) for workspace settings surfaces.
|
|
- **NFR-002 (Authorization)**: Members without the required capability MUST receive 403 for forbidden mutations.
|
|
- **NFR-003 (Auditability)**: 100% of successful updates and resets MUST create an audit entry including actor, scope, and before/after values.
|
|
- **NFR-004 (Data minimization)**: Audit entries MUST NOT include secrets or sensitive raw payloads.
|
|
- **NFR-005 (Performance)**: Within a single request, repeated resolutions of the same setting scope MUST not require repeated database reads.
|
|
|
|
## Success Criteria *(mandatory)*
|
|
|
|
### Measurable Outcomes
|
|
|
|
- **SC-001**: An authorized manager can update the pilot setting, and the Settings UI shows the new effective value after saving and persists it across a page reload.
|
|
- **SC-002**: A viewer can open the Settings UI and see current values, and cannot persist changes (mutation attempts are rejected).
|
|
- **SC-003**: Non-members cannot discover the Settings UI surface for a workspace (requests return 404).
|
|
- **SC-004**: 100% of successful setting updates/resets create an audit entry that includes actor, scope (workspace + optional tenant), and before/after values.
|