TenantAtlas/specs/097-settings-foundation/research.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

57 lines
3.6 KiB
Markdown
Raw 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.

# Research — Settings Foundation (Workspace + Optional Tenant Override) (097)
## Decisions
### Decision 1 — Canonical capability registry + role mapping
- **Chosen**: Add new workspace capabilities as constants in `App\Support\Auth\Capabilities`, and map them in `App\Services\Auth\WorkspaceRoleCapabilityMap`.
- `Capabilities::WORKSPACE_SETTINGS_VIEW`
- `Capabilities::WORKSPACE_SETTINGS_MANAGE`
- **Rationale**: The repo already enforces “no raw strings” and uses `Capabilities::isKnown()` checks in `WorkspaceCapabilityResolver`.
- **Alternatives considered**:
- Using raw strings (rejected: violates RBAC-UX-006).
### Decision 2 — Workspace RBAC-UX enforcement for Filament actions
- **Chosen**: Use `App\Support\Rbac\WorkspaceUiEnforcement` for Filament page actions.
- **Rationale**: This helper already implements the exact semantics required by the constitution:
- non-member → `abort(404)` (deny-as-not-found)
- member missing capability → `abort(403)`
- defense-in-depth server-side guard via `before()`.
- **Alternatives considered**:
- Ad-hoc `abort()` checks in each action (rejected: inconsistent and easier to regress).
### Decision 3 — Audit logging sink + stable action IDs
- **Chosen**:
- Workspace-scoped audit entries: `App\Services\Audit\WorkspaceAuditLogger` (writes `audit_logs` with `workspace_id`, `tenant_id = null`).
- Stable action identifiers: extend `App\Support\Audit\AuditActionId` enum with two new cases:
- `WorkspaceSettingUpdated = 'workspace_setting.updated'`
- `WorkspaceSettingReset = 'workspace_setting.reset'`
- **Rationale**: The repo already has a stable-action-id convention and tests around audit redaction and scoping; using the existing audit logger preserves sanitizer behavior (no secrets).
- **Alternatives considered**:
- Introducing a new audit sink (rejected: violates “use existing audit sinks” precedent and increases inconsistency risk).
- Using un-enumed string action IDs (possible, but rejected in favor of stronger standardization).
### Decision 4 — Storage model for workspace defaults + tenant overrides
- **Chosen**: Use two tables (scope-pure) rather than a single polymorphic table:
- `workspace_settings` (workspace-owned; includes `workspace_id`; no `tenant_id`)
- `tenant_settings` (tenant-owned; includes `workspace_id` and `tenant_id` NOT NULL)
- **Rationale**: Aligns with the constitutions scope/ownership rule:
- “Workspace-owned tables MUST include workspace_id and MUST NOT include tenant_id.”
- “Tenant-owned tables MUST include workspace_id and tenant_id as NOT NULL.”
- **Alternatives considered**:
- Single `workspace_settings` table with nullable `tenant_id` (rejected: risks violating the constitution and blurs ownership).
### Decision 5 — Resolver precedence + caching
- **Chosen**:
- Precedence: tenant override → workspace override → system default.
- Caching: request-local only, implemented in-memory inside the resolver (no cross-request cache store in v1).
- **Rationale**: Matches the clarified spec requirements and mirrors existing request-local caching patterns (e.g., capability resolver).
- **Alternatives considered**:
- Cross-request cache with TTL (rejected for v1: adds invalidation complexity and isnt required).
## Notes on existing repo patterns (evidence)
- Canonical capability registry exists: `App\Support\Auth\Capabilities`.
- Workspace capability checks and request-local caching exist: `App\Services\Auth\WorkspaceCapabilityResolver`.
- Workspace RBAC-UX enforcement helper exists: `App\Support\Rbac\WorkspaceUiEnforcement`.
- Workspace audit logger exists (with sanitizer): `App\Services\Audit\WorkspaceAuditLogger`.