# Tasks: Settings Foundation (Workspace + Optional Tenant Override) (097)

**Input**: Design documents from `specs/097-settings-foundation/` (spec.md, plan.md, research.md, data-model.md, contracts/)
**Prerequisites**: specs/097-settings-foundation/plan.md (required), specs/097-settings-foundation/spec.md (required for user stories)

**Tests**: REQUIRED (Pest) for all runtime behavior changes in this repo.
**RBAC**: Enforce 404 vs 403 semantics via canonical helpers + capability registry (no raw strings).
**Audit**: DB-only mutations intentionally skip OperationRun; every successful update/reset MUST write a workspace-scoped audit entry.

## Phase 1: Setup (Shared Infrastructure)

- [X] T001 Re-run SpecKit prerequisites and confirm FEATURE_DIR via .specify/scripts/bash/check-prerequisites.sh
- [X] T002 Review RBAC-UX enforcement patterns in app/Support/Rbac/WorkspaceUiEnforcement.php
- [X] T003 Review existing capability registry + caching patterns in app/Support/Auth/Capabilities.php and app/Services/Auth/WorkspaceCapabilityResolver.php
- [X] T004 Review workspace audit patterns + stable action IDs in app/Services/Audit/WorkspaceAuditLogger.php and app/Support/Audit/AuditActionId.php

---

## Phase 2: Foundational (Blocking Prerequisites)

**Purpose**: Shared primitives (capabilities, persistence, policies) needed by all stories.

- [X] T005 Add settings capabilities in app/Support/Auth/Capabilities.php (WORKSPACE_SETTINGS_VIEW, WORKSPACE_SETTINGS_MANAGE)
- [X] T006 Map new capabilities to roles in app/Services/Auth/WorkspaceRoleCapabilityMap.php (Owner/Manager manage; Operator/Readonly view)
- [X] T007 Create workspace_settings table migration in database/migrations/*_create_workspace_settings_table.php (workspace-owned: MUST NOT include tenant_id)
- [X] T008 [P] Create tenant_settings table migration in database/migrations/*_create_tenant_settings_table.php (tenant-owned: MUST include tenant_id NOT NULL)
- [X] T009 [P] Add Eloquent models in app/Models/WorkspaceSetting.php and app/Models/TenantSetting.php
- [X] T010 [P] Add model factories in database/factories/WorkspaceSettingFactory.php and database/factories/TenantSettingFactory.php
- [X] T011 Add policy for settings writes in app/Policies/WorkspaceSettingPolicy.php (view/manage using WorkspaceCapabilityResolver)
- [X] T012 Register policy mapping in app/Providers/AuthServiceProvider.php

**Checkpoint**: Capabilities + persistence + policies exist; user story work can begin.

---

## Phase 3: User Story 1 — Manage workspace settings safely (Priority: P1) 🎯 MVP

**Goal**: Workspace managers can update/reset the pilot setting with validation + audit logging.

**Independent Test**: A manager changes backup.retention_keep_last_default, sees it reflected, and the retention fallback uses it when schedule retention is null.

### Tests (write first)

- [X] T013 [P] [US1] Add manage workflow tests in tests/Feature/SettingsFoundation/WorkspaceSettingsManageTest.php
- [X] T014 [P] [US1] Add audit logging tests in tests/Feature/SettingsFoundation/WorkspaceSettingsAuditTest.php
- [X] T015 [P] [US1] Add resolver caching tests in tests/Unit/SettingsFoundation/SettingsResolverCacheTest.php
- [X] T016 [P] [US1] Add pilot integration test for retention fallback in tests/Feature/SettingsFoundation/RetentionFallbackUsesWorkspaceDefaultTest.php
- [X] T038 [P] [US1] Add per-schedule override precedence test (schedule override wins) in tests/Feature/SettingsFoundation/RetentionScheduleOverrideWinsTest.php
- [X] T039 [P] [US1] Add validation negative-path test: unknown setting key is rejected; no changes persisted; no audit entry created
- [X] T040 [P] [US1] Add validation negative-path test: invalid value (wrong type/out-of-range) is rejected; no changes persisted; no audit entry created

### Implementation

- [X] T017 [P] [US1] Create setting definition DTO in app/Support/Settings/SettingDefinition.php
- [X] T018 [P] [US1] Create registry for known settings in app/Support/Settings/SettingsRegistry.php (include backup.retention_keep_last_default default=30 + validation)
- [X] T019 [P] [US1] Implement resolver with precedence + request-local cache in app/Services/Settings/SettingsResolver.php
- [X] T020 [P] [US1] Add stable audit action IDs in app/Support/Audit/AuditActionId.php (workspace_setting.updated, workspace_setting.reset)
- [X] T021 [US1] Implement writer (validate, persist, reset deletes row, audit before/after) in app/Services/Settings/SettingsWriter.php
- [X] T022 [US1] Add Filament workspace Settings page shell in app/Filament/Pages/Settings/WorkspaceSettings.php (uses WorkspaceUiEnforcement)
- [X] T023 [US1] Register the Settings page in the admin panel navigation in app/Providers/Filament/AdminPanelProvider.php
- [X] T024 [US1] Implement Save action via Action::make(...)->action(...) in app/Filament/Pages/Settings/WorkspaceSettings.php
- [X] T025 [US1] Implement Reset action with ->requiresConfirmation() and ->action(...) in app/Filament/Pages/Settings/WorkspaceSettings.php
- [X] T026 [US1] Wire retention fallback to resolver when schedule retention is null in app/Jobs/ApplyBackupScheduleRetentionJob.php

---

## Phase 4: User Story 2 — View settings without the ability to change them (Priority: P2)

**Goal**: Workspace operators/readonly can view settings but cannot save/reset; server-side 403 on mutation.

**Independent Test**: A view-only member opens the Settings page and can see values, but attempts to save/reset return 403 and no audit entry is created.

### Tests (write first)

- [X] T027 [P] [US2] Add view-only access tests (view OK, mutation forbidden) in tests/Feature/SettingsFoundation/WorkspaceSettingsViewOnlyTest.php
- [X] T037 [P] [US2] Add non-member deny-as-not-found tests (404) in tests/Feature/SettingsFoundation/WorkspaceSettingsNonMemberNotFoundTest.php

### Implementation

- [X] T028 [US2] Gate page access by view capability and gate mutations by manage capability in app/Filament/Pages/Settings/WorkspaceSettings.php
- [X] T029 [US2] Ensure Save/Reset actions cannot execute for view-only users (server-side enforcement) in app/Filament/Pages/Settings/WorkspaceSettings.php

---

## Phase 5: User Story 3 — Tenant overrides take precedence (backend-ready) (Priority: P3)

**Goal**: Resolver supports tenant overrides; tenant override wins over workspace override; rejects tenant/workspace mismatch.

**Independent Test**: With tenant override present, resolving returns tenant value; without it, returns workspace; without either, returns system default.

### Tests (write first)

- [X] T030 [P] [US3] Add tenant precedence tests (default/workspace/tenant) in tests/Unit/SettingsFoundation/SettingsResolverTenantPrecedenceTest.php
- [X] T031 [P] [US3] Add tenant/workspace mismatch rejection test in tests/Feature/SettingsFoundation/TenantOverrideScopeSafetyTest.php

### Implementation

- [X] T032 [US3] Extend resolver to read tenant overrides from tenant_settings (same workspace) in app/Services/Settings/SettingsResolver.php
- [X] T033 [US3] Add tenant override write/reset methods (backend-ready) in app/Services/Settings/SettingsWriter.php

---

## Phase 6: Polish & Cross-Cutting Concerns

- [X] T034 [P] Run formatting for changed files via vendor/bin/sail bin pint --dirty (see specs/097-settings-foundation/quickstart.md)
- [X] T035 Run focused tests for this feature via vendor/bin/sail artisan test --compact tests/Feature/SettingsFoundation (see specs/097-settings-foundation/quickstart.md)
- [X] T036 Run the full suite via vendor/bin/sail artisan test --compact (see specs/097-settings-foundation/quickstart.md)

---

## Dependencies & Execution Order

### User Story Dependency Graph

- Setup → Foundational
- Foundational → US1
- US1 → US2
- US1 → US3

### Parallel Opportunities (examples)

- US1: T013–T016 (tests) and T017–T020 (core classes + enum) can be executed in parallel.
- Foundational: T007–T012 can be split across DB/model/policy work in parallel.

Example: In US1, execute T013, T014, T017, and T018 concurrently (different files; no dependencies).

## MVP Scope Suggestion

- MVP = Phases 1–3 (through US1) to ship a workspace settings foundation with the pilot setting wired into retention fallback.
