8.0 KiB
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)
- T001 Re-run SpecKit prerequisites and confirm FEATURE_DIR via .specify/scripts/bash/check-prerequisites.sh
- T002 Review RBAC-UX enforcement patterns in app/Support/Rbac/WorkspaceUiEnforcement.php
- T003 Review existing capability registry + caching patterns in app/Support/Auth/Capabilities.php and app/Services/Auth/WorkspaceCapabilityResolver.php
- 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.
- T005 Add settings capabilities in app/Support/Auth/Capabilities.php (WORKSPACE_SETTINGS_VIEW, WORKSPACE_SETTINGS_MANAGE)
- T006 Map new capabilities to roles in app/Services/Auth/WorkspaceRoleCapabilityMap.php (Owner/Manager manage; Operator/Readonly view)
- T007 Create workspace_settings table migration in database/migrations/*_create_workspace_settings_table.php (workspace-owned: MUST NOT include tenant_id)
- T008 [P] Create tenant_settings table migration in database/migrations/*_create_tenant_settings_table.php (tenant-owned: MUST include tenant_id NOT NULL)
- T009 [P] Add Eloquent models in app/Models/WorkspaceSetting.php and app/Models/TenantSetting.php
- T010 [P] Add model factories in database/factories/WorkspaceSettingFactory.php and database/factories/TenantSettingFactory.php
- T011 Add policy for settings writes in app/Policies/WorkspaceSettingPolicy.php (view/manage using WorkspaceCapabilityResolver)
- 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)
- T013 [P] [US1] Add manage workflow tests in tests/Feature/SettingsFoundation/WorkspaceSettingsManageTest.php
- T014 [P] [US1] Add audit logging tests in tests/Feature/SettingsFoundation/WorkspaceSettingsAuditTest.php
- T015 [P] [US1] Add resolver caching tests in tests/Unit/SettingsFoundation/SettingsResolverCacheTest.php
- T016 [P] [US1] Add pilot integration test for retention fallback in tests/Feature/SettingsFoundation/RetentionFallbackUsesWorkspaceDefaultTest.php
- T038 [P] [US1] Add per-schedule override precedence test (schedule override wins) in tests/Feature/SettingsFoundation/RetentionScheduleOverrideWinsTest.php
- T039 [P] [US1] Add validation negative-path test: unknown setting key is rejected; no changes persisted; no audit entry created
- 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
- T017 [P] [US1] Create setting definition DTO in app/Support/Settings/SettingDefinition.php
- T018 [P] [US1] Create registry for known settings in app/Support/Settings/SettingsRegistry.php (include backup.retention_keep_last_default default=30 + validation)
- T019 [P] [US1] Implement resolver with precedence + request-local cache in app/Services/Settings/SettingsResolver.php
- T020 [P] [US1] Add stable audit action IDs in app/Support/Audit/AuditActionId.php (workspace_setting.updated, workspace_setting.reset)
- T021 [US1] Implement writer (validate, persist, reset deletes row, audit before/after) in app/Services/Settings/SettingsWriter.php
- T022 [US1] Add Filament workspace Settings page shell in app/Filament/Pages/Settings/WorkspaceSettings.php (uses WorkspaceUiEnforcement)
- T023 [US1] Register the Settings page in the admin panel navigation in app/Providers/Filament/AdminPanelProvider.php
- T024 [US1] Implement Save action via Action::make(...)->action(...) in app/Filament/Pages/Settings/WorkspaceSettings.php
- T025 [US1] Implement Reset action with ->requiresConfirmation() and ->action(...) in app/Filament/Pages/Settings/WorkspaceSettings.php
- 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)
- T027 [P] [US2] Add view-only access tests (view OK, mutation forbidden) in tests/Feature/SettingsFoundation/WorkspaceSettingsViewOnlyTest.php
- T037 [P] [US2] Add non-member deny-as-not-found tests (404) in tests/Feature/SettingsFoundation/WorkspaceSettingsNonMemberNotFoundTest.php
Implementation
- T028 [US2] Gate page access by view capability and gate mutations by manage capability in app/Filament/Pages/Settings/WorkspaceSettings.php
- 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)
- T030 [P] [US3] Add tenant precedence tests (default/workspace/tenant) in tests/Unit/SettingsFoundation/SettingsResolverTenantPrecedenceTest.php
- T031 [P] [US3] Add tenant/workspace mismatch rejection test in tests/Feature/SettingsFoundation/TenantOverrideScopeSafetyTest.php
Implementation
- T032 [US3] Extend resolver to read tenant overrides from tenant_settings (same workspace) in app/Services/Settings/SettingsResolver.php
- T033 [US3] Add tenant override write/reset methods (backend-ready) in app/Services/Settings/SettingsWriter.php
Phase 6: Polish & Cross-Cutting Concerns
- T034 [P] Run formatting for changed files via vendor/bin/sail bin pint --dirty (see specs/097-settings-foundation/quickstart.md)
- T035 Run focused tests for this feature via vendor/bin/sail artisan test --compact tests/Feature/SettingsFoundation (see specs/097-settings-foundation/quickstart.md)
- 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.