TenantAtlas/specs/077-workspace-nav-monitoring-hub/plan.md
ahmido fb1046c97a Spec 077: Workspace Global Mode + context bar redundancy cleanup (#94)
Implements Spec 077 refinements: workspace Global Mode and navigation/context-bar redundancy cleanup.

Summary
- Global Mode: `/admin/workspaces` is workspace-optional (lists only member workspaces); explicit allowlist in `EnsureWorkspaceSelected`.
- Navigation cleanup: workspace switching is topbar-only; no sidebar “Switch workspace”; removes redundant “Manage workspaces” entry from context-bar.
- Context bar: when no workspace selected, tenant picker is disabled with guidance; on tenant-scoped routes `/admin/t/{tenant}/…` the tenant indicator is read-only (Filament tenant menu remains primary).
- Authorization: workspace creation is policy-driven (`WorkspacePolicy::create()`), enforced in `ChooseWorkspace` via Gate.

Safety / Compliance
- Livewire v4.0+ compliant (Filament v5).
- Panel provider registration remains in `bootstrap/providers.php` (no changes required).
- Global search: no new globally searchable resources added; no behavior changes introduced.
- Destructive actions: none added/changed.
- Assets: no new assets registered; deploy process unchanged (if assets are registered elsewhere, ensure `php artisan filament:assets` runs in deploy as usual).

Tests
- `vendor/bin/sail bin pint --dirty`
- `vendor/bin/sail artisan test --compact tests/Feature/Workspaces tests/Feature/Monitoring tests/Feature/OpsUx tests/Feature/Filament/WorkspaceContextTopbarAndTenantSelectionTest.php`

Spec artifacts
- `specs/077-workspace-nav-monitoring-hub/{spec,plan,tasks}.md`
- `specs/077-workspace-nav-monitoring-hub/contracts/routes.md`

Co-authored-by: Ahmed Darrazi <ahmeddarrazi@MacBookPro.fritz.box>
Reviewed-on: #94
2026-02-06 22:14:53 +00:00

9.8 KiB
Raw Blame History

Implementation Plan: Workspace-first Navigation & Monitoring Hub

Branch: 077-workspace-nav-monitoring-hub | Date: 2026-02-06 | Spec: specs/077-workspace-nav-monitoring-hub/spec.md Input: Feature specification from specs/077-workspace-nav-monitoring-hub/spec.md

Note: This template is filled in by the /speckit.plan command. See .specify/scripts/ for helper scripts.

Summary

Resolve workspace navigation ambiguity and formalize a workspace-first context model:

  • Unambiguous labels: Switch workspace (/admin/choose-workspace) vs Manage workspaces (/admin/workspaces).
  • Monitoring → Operations remains canonical and tenantless (/admin/operations, /admin/operations/{run}).
  • Tenant context influences Operations only via server-side default filter state (removable), never via routing.
  • Strict non-leaking security semantics:
    • Non-member workspace scope → 404 (deny-as-not-found)
    • Workspace member missing capability (protected actions/screens) → 403
    • Accessing a workspace record outside membership → 404 (deny-as-not-found)

Supporting artifacts:

Technical Context

Language/Version: PHP 8.4.x
Primary Dependencies: Laravel 12, Filament v5, Livewire v4
Storage: PostgreSQL (Sail)
Testing: Pest v4
Target Platform: Web (Filament admin panels) Project Type: Laravel monolith
Performance Goals: Operations pages remain DB-only at render; list/detail stay fast on large run tables (pagination + indexed filters)
Constraints: Filament-native patterns only; canonical URLs must not depend on tenant context; strict 404/403 non-leakage semantics
Scale/Scope: Multi-workspace MSP use; many tenants and many operation runs

Constitution Check

GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.

  • Inventory-first: N/A (no inventory semantics changes)
  • Read/write separation: PASS (no write operations introduced)
  • Graph contract path: N/A (no Graph calls)
  • Deterministic capabilities: PASS (capability gating uses existing resolver/registry patterns)
  • RBAC-UX: PASS (explicit 404 vs 403 rules)
  • RBAC-UX destructive confirmation: N/A (no destructive actions introduced)
  • RBAC-UX global search: N/A (no new searchable resources; no changes to global search)
  • Tenant isolation: PASS (workspace membership is isolation boundary; tenant context auto-cleared when invalid)
  • Run observability: N/A (no new operations/jobs)
  • Automation: N/A
  • Data minimization: N/A
  • Badge semantics (BADGE-001): N/A

Project Structure

Documentation (this feature)

specs/077-workspace-nav-monitoring-hub/
├── spec.md
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
│   └── routes.md
└── checklists/
    └── requirements.md

Source Code (repository root)

app/
├── Filament/
│   ├── Pages/
│   │   └── ChooseWorkspace.php
│   └── Resources/
│       ├── OperationRunResource.php
│       └── OperationRunResource/
│           └── Pages/
│               └── ListOperationRuns.php
├── Http/
│   └── Middleware/
│       └── EnsureWorkspaceSelected.php
├── Providers/
│   └── Filament/
│       └── AdminPanelProvider.php
└── Support/
  └── Middleware/
    └── EnsureFilamentTenantSelected.php

resources/
└── views/
  └── filament/
    └── partials/
      └── workspace-switcher.blade.php

routes/
└── web.php

tests/
└── Feature/
  └── (new tests for navigation labels + 404/403 + operations default filter)

Structure Decision: Laravel monolith using Filament resources/pages and Laravel middleware.

Complexity Tracking

No constitution violations.

Phase 0 — Outline & Research (complete)

All unknowns/decisions have been resolved and recorded:

  • Repo reality + ambiguity sources + decisions D1D4: research.md
  • No remaining NEEDS CLARIFICATION items in the spec.

Phase 1 — Design & Contracts (complete)

  • Data model: no new tables/columns required; behavior is implemented via middleware + Filament config: data-model.md
  • Route/security contracts: contracts/routes.md
  • Manual validation steps + suggested test filters: quickstart.md

Phase 2 — Implementation Plan (ready for tasks)

Step 1 — Navigation labels: “one label, one meaning”

  • Update admin navigation to include:
    • Switch workspace (topbar context switcher) → /admin/choose-workspace
    • Manage workspaces (sidebar Settings) → /admin/workspaces
  • Remove/replace any navigation items labeled only “Workspaces”.

Implementation targets:

Step 2 — Enforce workspace-scoped RBAC semantics for /admin/workspaces

  • /admin/workspaces stays tenantless and is Global Mode (workspace-optional).
  • Enforce strict non-leakage semantics:
    • Non-member attempting to access a workspace record → 404 (deny-as-not-found)
    • Member missing required capability for protected actions/screens → 403

Implementation targets:

  • Scope the Workspaces query (index) to only workspaces the user is a member of.
  • Ensure WorkspacePolicy returns 404 semantics for non-members (record access).
  • Workspace creation is self-serve (policy-driven). Gate edit/membership-management behind canonical workspace capabilities (no raw strings).
  • Hide “Manage workspaces” navigation unless the user can manage something workspace-admin related (capability-based).

Step 3 — Workspace selection redirect + return-to-intended

Requirement: visiting any workspace-scoped page without a selected workspace MUST redirect to /admin/choose-workspace and then return to the originally requested URL.

Implementation targets:

Step 4 — Auto-clear invalid tenant context on workspace change

Requirement: if tenant context is active but does not belong to the current workspace, auto-clear tenant context and continue on tenantless workspace pages.

Implementation targets:

  • In app/Support/Middleware/EnsureFilamentTenantSelected.php (or a dedicated middleware used for tenantless pages):
    • Detect a persisted Filament tenant that does not match WorkspaceContext::currentWorkspaceId().
    • Clear the persisted Filament tenant context (confirm the correct Filament v5 mechanism during implementation).

Step 5 — Operations: move tenant scoping from query to removable default filter

Requirement: /admin/operations stays canonical; if tenant context is active, default to that tenant using server-side default filter state with a visible removable chip.

Implementation targets:

Step 6 — Tests (Pest) + formatting

Add/adjust tests to cover the strict semantics:

  • Navigation labels: “Switch workspace” vs “Manage workspaces” (no ambiguous “Workspaces”).
  • /admin/workspaces:
    • non-member record access → 404
    • member missing capability for a protected action/screen → 403
  • EnsureWorkspaceSelected:
    • visiting /admin/operations without workspace → redirects to choose-workspace
    • after selecting workspace → returns to intended URL
  • Operations default filter:
    • with tenant context active → tenant filter default set
    • clearing filter → shows workspace-wide results

Tooling:

  • Run ./vendor/bin/sail bin pint --dirty.
  • Run focused tests via ./vendor/bin/sail artisan test --compact --filter=....