TenantAtlas/specs/097-settings-foundation/plan.md
ahmido e241e27853 Settings foundation: workspace controls (#119)
Implements the Settings foundation workspace controls.

Includes:
- Settings foundation UI/controls scoped to workspace context
- Related onboarding/consent flow adjustments as included in branch history

Testing:
- `vendor/bin/sail artisan test --compact --no-ansi --filter=SettingsFoundation`

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #119
2026-02-16 01:11:24 +00:00

144 lines
8.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Implementation Plan: Settings Foundation (Workspace + Optional Tenant Override)
**Branch**: `097-settings-foundation` | **Date**: 2026-02-15 | **Spec**: `/specs/097-settings-foundation/spec.md`
**Input**: Feature specification from `/specs/097-settings-foundation/spec.md`
**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/scripts/` for helper scripts.
## Summary
Implement a workspace-scoped settings substrate with a canonical registry + validation, a resolver that applies precedence (tenant override → workspace override → system default), a workspace Settings page in Filament, and audit logging for each successful mutation.
For v1, the pilot setting is `backup.retention_keep_last_default` (system default `30`), stored as a workspace override and later consumed by backup retention behavior when a schedule has no explicit `retention_keep_last`.
## 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)
**Target Platform**: Web app (Filament admin panel)
**Project Type**: Laravel monolith (Filament pages + services + jobs)
**Performance Goals**: settings resolution is request-local cached; repeated resolves for the same (workspace, optional tenant, domain, key) do not issue repeated DB reads
**Constraints**: strict workspace isolation (non-member 404), capability-gated mutations (member without capability 403), audit each successful mutation, no secrets in audit metadata
**Scale/Scope**: low-volume admin configuration with high auditability and correctness requirements
## Constitution Check
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
- Inventory-first: clarify what is “last observed” vs snapshots/backups
- Read/write separation: any writes require preview + confirmation + audit + tests
- Graph contract path: Graph calls only via `GraphClientInterface` + `config/graph_contracts.php`
- Deterministic capabilities: capability derivation is testable (snapshot/golden tests)
- RBAC-UX: two planes (/admin vs /system) remain separated; cross-plane is 404; tenant-context routes (/admin/t/{tenant}/...) are tenant-scoped; canonical workspace-context routes under /admin remain tenant-safe; non-member tenant/workspace access is 404; member-but-missing-capability is 403; authorization checks use Gates/Policies + capability registries (no raw strings, no role-string checks)
- Workspace isolation: non-member workspace access is 404; tenant-plane routes require an established workspace context; workspace context switching is separate from Filament Tenancy
- RBAC-UX: destructive-like actions require `->requiresConfirmation()` and clear warning text
- RBAC-UX: global search is tenant-scoped; non-members get no hints; inaccessible results are treated as not found (404 semantics)
- Tenant isolation: all reads/writes tenant-scoped; cross-tenant views are explicit and access-checked
- Run observability: long-running/remote/queued work creates/reuses `OperationRun`; start surfaces enqueue-only; Monitoring is DB-only; DB-only <2s actions may skip runs but security-relevant ones still audit-log; auth handshake exception OPS-EX-AUTH-001 allows synchronous outbound HTTP on `/auth/*` without `OperationRun`
- Automation: queued/scheduled ops use locks + idempotency; handle 429/503 with backoff+jitter
- Data minimization: Inventory stores metadata + whitelisted meta; logs contain no secrets/tokens
- Badge semantics (BADGE-001): status-like badges use `BadgeCatalog` / `BadgeRenderer`; no ad-hoc mappings; new values include tests
- Filament UI Action Surface Contract: for any new/modified Filament Resource/RelationManager/Page, define Header/Row/Bulk/Empty-State actions, ensure every List/Table has a record inspection affordance (prefer `recordUrl()` clickable rows; do not render a lone View row action), keep max 2 visible row actions with the rest in More”, group bulk actions, require confirmations for destructive actions (typed confirmation for large/bulk where applicable), write audit logs for mutations, enforce RBAC via central helpers (non-member 404, member missing capability 403), and ensure CI blocks merges if the contract is violated or not explicitly exempted
**Result (pre-Phase 0)**: PASS.
- This feature is DB-only and completes in <2s; it intentionally does not create an `OperationRun`, but MUST emit workspace-scoped audit entries on each successful mutation.
- No Graph calls are introduced.
- RBAC enforcement must use the canonical capability registry (`App\Support\Auth\Capabilities`) and workspace UI enforcement helper (`App\Support\Rbac\WorkspaceUiEnforcement`) for Filament surfaces.
## Project Structure
### Documentation (this feature)
```text
specs/097-settings-foundation/
├── plan.md # This file (/speckit.plan command output)
├── research.md # Phase 0 output (/speckit.plan command)
├── data-model.md # Phase 1 output (/speckit.plan command)
├── quickstart.md # Phase 1 output (/speckit.plan command)
├── contracts/ # Phase 1 output (/speckit.plan command)
└── tasks.md # Phase 2 output (/speckit.tasks command - NOT created by /speckit.plan)
```
### Source Code (repository root)
```text
app/
├── Filament/
│ └── Pages/
│ └── Settings/
├── Models/
├── Policies/
├── Providers/
├── Services/
└── Support/
├── Audit/
├── Auth/
├── Rbac/
└── Settings/
config/
database/migrations/
tests/
```
Expected additions (at implementation time):
```text
app/Support/Settings/SettingDefinition.php
app/Support/Settings/SettingsRegistry.php
app/Services/Settings/SettingsResolver.php
app/Services/Settings/SettingsWriter.php
app/Models/WorkspaceSetting.php
app/Models/TenantSetting.php
app/Filament/Pages/Settings/WorkspaceSettings.php
app/Policies/WorkspaceSettingPolicy.php
database/migrations/*_create_workspace_settings_table.php
database/migrations/*_create_tenant_settings_table.php
tests/Feature/SettingsFoundation/*
tests/Unit/SettingsFoundation/*
```
**Structure Decision**: Laravel monolith (Filament admin + Eloquent models + services + Pest tests). No new top-level directories.
## Phase 0 — Outline & Research
Deliverable: `research.md` with all implementation decisions resolved.
Key questions resolved in research:
- Which existing RBAC enforcement helper to use for workspace-scoped Filament pages.
- Which audit logger to use for workspace-scoped audit events and how to represent stable action IDs.
- How to model workspace defaults + tenant overrides while staying compliant with the constitutions scope/ownership rules.
## Phase 1 — Design & Contracts
Deliverables: `data-model.md`, `contracts/*`, `quickstart.md`.
- Data model defines workspace settings and tenant overrides with strict workspace isolation.
- Contracts define the conceptual read/write/reset operations (even if the first implementation is driven via Filament/Livewire).
- Quickstart defines how to run migrations, format, and execute focused tests.
## Phase 2 — Planning
Implementation sequence (high-level):
1. Add capability constants in `App\Support\Auth\Capabilities` and map them in `App\Services\Auth\WorkspaceRoleCapabilityMap`.
2. Add settings registry + validation (`SettingDefinition`, `SettingsRegistry`) including the pilot setting.
3. Add storage + resolver + writer services with request-local caching.
4. Add audit action IDs (stable) and emit workspace audit entries for update/reset.
5. Add Filament workspace Settings page with Save + Reset actions, gated using `WorkspaceUiEnforcement`.
6. Add Pest tests for precedence, RBAC (404/403), validation, caching behavior, and audit entries.
**Constitution re-check (post-design)**: expected PASS (DB-only mutations audited; strict 404/403 semantics; capability registry is canonical).
## Complexity Tracking
> **Fill ONLY if Constitution Check has violations that must be justified**
| Violation | Why Needed | Simpler Alternative Rejected Because |
|-----------|------------|-------------------------------------|
| None | N/A | N/A |