# Implementation Plan: Findings Operator Inbox V1

**Branch**: `221-findings-operator-inbox` | **Date**: 2026-04-20 | **Spec**: `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/221-findings-operator-inbox/spec.md`
**Input**: Feature specification from `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/221-findings-operator-inbox/spec.md`

**Note**: This plan keeps the work inside the existing admin workspace shell, tenant-owned `Finding` truth, and current tenant finding detail surface. The intended implementation is one new canonical `/admin` page plus one small workspace overview signal. It does not add persistence, capabilities, workflow states, queue automation, or a second mutation lane.

## Summary

Add one canonical admin-plane inbox at `/admin/findings/my-work` that shows the current user's open assigned findings across visible, capability-eligible tenants, keeps urgency first with a deterministic overdue-then-reopened ordering, and drills into the existing tenant finding detail with a preserved return path. Reuse existing `Finding` lifecycle and responsibility semantics, `CanonicalAdminTenantFilterState` for active-tenant prefiltering and applied-scope metadata, `CanonicalNavigationContext` for queue-to-detail continuity, and extend `WorkspaceOverviewBuilder` plus the workspace overview Blade view with one compact `Assigned to me` signal that exposes open and overdue counts with a single CTA into the inbox.

## Technical Context

**Language/Version**: PHP 8.4.15, Laravel 12, Filament v5, Livewire v4, Blade  
**Primary Dependencies**: Filament admin panel pages, `Finding`, `FindingResource`, `WorkspaceOverviewBuilder`, `WorkspaceContext`, `WorkspaceCapabilityResolver`, `CapabilityResolver`, `CanonicalAdminTenantFilterState`, and `CanonicalNavigationContext`  
**Storage**: PostgreSQL via existing `findings`, `tenants`, `tenant_memberships`, and workspace context session state; no schema changes planned  
**Testing**: Pest v4 feature tests with Livewire/Filament page assertions  
**Validation Lanes**: fast-feedback, confidence
**Target Platform**: Dockerized Laravel web application via Sail locally and Linux containers in deployment  
**Project Type**: Laravel monolith inside the `wt-plattform` monorepo  
**Performance Goals**: Keep inbox and overview rendering DB-only, eager-load tenant/owner/assignee display context, avoid N+1 queries, and keep the first operator scan within the 10-second acceptance target  
**Constraints**: No Graph calls, no new `OperationRun`, no new workflow states or owner semantics, no new capabilities, no new queue mutations, no hidden-tenant leakage, no duplicate personal-work truth between inbox and overview, and no new assets  
**Scale/Scope**: One admin page, one workspace overview signal, one derived cross-tenant personal-assignment query, three focused feature suites, and one focused extension to existing route-alignment coverage

## UI / Surface Guardrail Plan

- **Guardrail scope**: changed surfaces
- **Native vs custom classification summary**: native Filament page, table, empty-state, badge, and Blade summary primitives only
- **Shared-family relevance**: findings workflow family and workspace overview summary family
- **State layers in scope**: shell, page, detail, URL-query
- **Handling modes by drift class or surface**: review-mandatory
- **Repository-signal treatment**: review-mandatory
- **Special surface test profiles**: global-context-shell
- **Required tests or manual smoke**: functional-core, state-contract
- **Exception path and spread control**: none; the inbox remains a standard read-first admin page and the overview signal stays an embedded summary, not a second queue
- **Active feature PR close-out entry**: Guardrail

## Constitution Check

*GATE: Passed before Phase 0 research. Re-check after Phase 1 design.*

| Principle | Pre-Research | Post-Design | Notes |
|-----------|--------------|-------------|-------|
| Inventory-first / snapshots-second | PASS | PASS | The feature reads live `Finding` assignment and lifecycle truth only; no new snapshot or backup semantics are introduced |
| Read/write separation | PASS | PASS | The inbox and overview signal are read-only; existing finding lifecycle mutations remain on tenant finding detail |
| Graph contract path | PASS | PASS | No Graph client, contract-registry, or external API work is added |
| Deterministic capabilities / RBAC-UX | PASS | PASS | Workspace membership gates the admin page, missing workspace context follows the existing chooser or resume flow, tenant entitlement plus existing findings capability gate row visibility, filter values, summary counts, overview counts, and detail drilldown, and non-members remain `404` |
| Workspace / tenant isolation | PASS | PASS | Admin-plane inbox is workspace-scoped while drilldown stays on `/admin/t/{tenant}/findings/{finding}` with tenant-safe continuity |
| Run observability / Ops-UX | PASS | PASS | No long-running work, no `OperationRun`, and no notification or progress-surface changes are introduced |
| Proportionality / no premature abstraction | PASS | PASS | The plan keeps the query logic inside the new page and existing workspace builder seams; no new shared registry or durable abstraction is required |
| Persisted truth / few layers | PASS | PASS | Inbox rows and overview counts remain direct derivations of existing `Finding`, tenant membership, and workspace context data |
| Badge semantics (BADGE-001) | PASS | PASS | Severity, lifecycle, and urgency cues reuse existing findings badge semantics rather than introducing local status language |
| Filament-native UI (UI-FIL-001) | PASS | PASS | Implementation stays within Filament page, table, header action, empty-state, and existing Blade summary composition |
| Action surface / inspect model | PASS | PASS | The inbox keeps one inspect model, full-row open to finding detail, no redundant `View`, and no dangerous queue actions |
| Decision-first / OPSURF | PASS | PASS | The inbox is the primary decision surface and the overview signal stays secondary with one CTA |
| Test governance (TEST-GOV-001) | PASS | PASS | Proof remains in three focused feature suites plus one focused extension to existing route-alignment coverage, with no browser or heavy-governance promotion |
| Filament v5 / Livewire v4 compliance | PASS | PASS | The design uses existing Filament v5 page patterns and Livewire v4-compatible page/table behavior only |
| Provider registration / global search / assets | PASS | PASS | Panel providers already live in `apps/platform/bootstrap/providers.php`; the new page extends `AdminPanelProvider` only, `FindingResource` global search behavior is unchanged and already has a View page, and no new assets are required |

## Test Governance Check

- **Test purpose / classification by changed surface**: `Feature` for the admin inbox page, authorization boundary behavior, and workspace overview signal
- **Affected validation lanes**: `fast-feedback`, `confidence`
- **Why this lane mix is the narrowest sufficient proof**: The feature is proven by visible operator behavior, capability-safe tenant filtering, continuity into existing tenant detail, empty-state fallback behavior, and overview-to-inbox truth alignment. Focused feature tests cover that without adding unit seams, browser automation, or heavy-governance breadth.
- **Narrowest proving command(s)**:
  - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Findings/MyWorkInboxTest.php tests/Feature/Authorization/MyWorkInboxAuthorizationTest.php`
  - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Dashboard/MyFindingsSignalTest.php`
  - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/WorkspaceOverviewNavigationTest.php`
- **Fixture / helper / factory / seed / context cost risks**: Moderate. The tests need one workspace, multiple visible and hidden tenants, owner-versus-assignee combinations, open and terminal findings, and explicit workspace plus active-tenant session context.
- **Expensive defaults or shared helper growth introduced?**: no; the new suites should reuse existing `createUserWithTenant(...)` and `Finding::factory()` flows and keep any inbox-specific fixture helper local to the new tests
- **Heavy-family additions, promotions, or visibility changes**: none
- **Surface-class relief / special coverage rule**: named special profile `global-context-shell` is required because the inbox depends on workspace context, active tenant continuity, and admin-to-tenant drilldown behavior
- **Closing validation and reviewer handoff**: Reviewers should rely on the exact commands above and verify that hidden-tenant or capability-blocked findings never leak into rows, filter options, or counts, owner-only findings stay out of the queue, the active tenant prefilter is clearable without removing personal scope, the empty state offers the correct fallback CTA, and the detail page exposes a working return path to the inbox.
- **Budget / baseline / trend follow-up**: none
- **Review-stop questions**: Did the implementation stay read-only? Did the overview signal remain a signal instead of a second queue? Did any shared query abstraction appear without clear reuse pressure beyond this feature? Did row drilldown preserve tenant-safe continuity?
- **Escalation path**: document-in-feature unless a second cross-tenant findings surface or a new shared query framework is proposed, in which case split or follow up with a dedicated spec
- **Active feature PR close-out entry**: Guardrail
- **Why no dedicated follow-up spec is needed**: The feature remains bounded to one queue surface and one overview signal, with no new persistence, workflow family, or reusable platform abstraction

## Project Structure

### Documentation (this feature)

```text
specs/221-findings-operator-inbox/
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
│   └── findings-operator-inbox.logical.openapi.yaml
├── checklists/
│   └── requirements.md
└── tasks.md
```

### Source Code (repository root)

```text
apps/platform/
├── app/
│   ├── Filament/
│   │   ├── Pages/
│   │   │   └── Findings/
│   │   │       └── MyFindingsInbox.php
│   │   └── Resources/
│   │       └── FindingResource.php
│   ├── Providers/
│   │   └── Filament/
│   │       └── AdminPanelProvider.php
│   └── Support/
│       ├── Filament/
│       │   └── CanonicalAdminTenantFilterState.php
│       ├── Navigation/
│       │   └── CanonicalNavigationContext.php
│       └── Workspaces/
│           └── WorkspaceOverviewBuilder.php
├── resources/
│   └── views/
│       └── filament/
│           └── pages/
│               ├── findings/
│               │   └── my-findings-inbox.blade.php
│               └── workspace-overview.blade.php
└── tests/
    └── Feature/
        ├── Authorization/
        │   └── MyWorkInboxAuthorizationTest.php
        ├── Dashboard/
        │   └── MyFindingsSignalTest.php
    ├── Filament/
    │   └── WorkspaceOverviewNavigationTest.php
        └── Findings/
            └── MyWorkInboxTest.php
```

**Structure Decision**: Standard Laravel monolith. The feature stays inside the existing admin panel provider, finding domain model, workspace overview builder, and focused Pest feature suites. No new base directory, package, or persistent model is required.

## Complexity Tracking

| Violation | Why Needed | Simpler Alternative Rejected Because |
|-----------|------------|-------------------------------------|
| none | — | — |

## Proportionality Review

- **Current operator problem**: Assignee-based finding work exists in the data model but not as a trustworthy cross-tenant start-of-day surface.
- **Existing structure is insufficient because**: The tenant-local findings list can filter to `My assigned work`, but it still forces users to guess the correct tenant first and does not create one canonical admin-plane queue.
- **Narrowest correct implementation**: Add one admin page and one small workspace overview signal, both derived directly from existing finding assignment, lifecycle, due-date, severity, and entitlement truth.
- **Ownership cost created**: One new page/view pair, one small overview payload addition, three focused feature suites, and one focused extension to existing route-alignment coverage.
- **Alternative intentionally rejected**: A broader cross-tenant findings register, owner-plus-assignee mixed queue, or new shared findings query service. Those would increase semantics and maintenance cost beyond the current release need.
- **Release truth**: Current-release truth. The work operationalizes the already-shipped assignee concept now rather than preparing future queue or notification systems.

## Phase 0 Research

Research outcomes are captured in `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/221-findings-operator-inbox/research.md`.

Key decisions:

- Implement the inbox as an admin panel page with slug `findings/my-work` under the existing `AdminPanelProvider`, not as a tenant resource variant and not as a standalone controller route.
- Keep the cross-tenant personal queue fully derived from `Finding` plus existing workspace and tenant entitlements, using `Finding::openStatusesForQuery()` and eager-loaded tenant/owner/assignee relationships.
- Reuse `CanonicalAdminTenantFilterState` to apply the active tenant as the default prefilter, expose the applied-scope state, and preserve the clear-filter behavior without inventing a second context mechanism.
- Use `CanonicalNavigationContext` when building row drilldowns so tenant finding detail can expose `Back to my findings` with tenant-safe continuity.
- Add the workspace signal as a dedicated overview payload rendered in the existing `/admin` Blade page rather than overloading generic summary metrics, because the signal must show open count, overdue count, and one explicit CTA.
- Prove the feature with three focused Pest feature suites plus one focused extension to existing route-alignment coverage.

## Phase 1 Design

Design artifacts are created under `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/221-findings-operator-inbox/`:

- `research.md`: routing, query, continuity, and workspace-signal decisions
- `data-model.md`: existing entities plus derived inbox row and workspace signal projections
- `contracts/findings-operator-inbox.logical.openapi.yaml`: internal logical contract for the inbox, overview signal, and detail continuity inputs
- `quickstart.md`: focused validation workflow for implementation and review

Design decisions:

- No schema migration is required; the inbox and overview signal remain fully derived.
- The canonical implementation seam is one new admin page plus one existing workspace overview builder/view extension, not a new shared findings-query subsystem.
- Active tenant context stays canonical through `CanonicalAdminTenantFilterState`, while detail continuity stays canonical through `CanonicalNavigationContext`.
- Existing tenant finding detail remains the only mutation surface for assignment and workflow actions.

## Phase 1 Agent Context Update

Run:

- `.specify/scripts/bash/update-agent-context.sh copilot`

## Constitution Check — Post-Design Re-evaluation

- PASS — the design remains read-surface only, adds no writes, no Graph calls, no `OperationRun`, no new capability family, and no new assets.
- PASS — Livewire v4.0+ and Filament v5 constraints remain satisfied, panel provider registration stays in `apps/platform/bootstrap/providers.php`, and no global-search or destructive-action behavior changes are introduced.

## Implementation Strategy

### Phase A — Add The Canonical Admin Inbox Surface

**Goal**: Create one workspace-scoped personal findings queue under `/admin/findings/my-work`.

| Step | File | Change |
|------|------|--------|
| A.1 | `apps/platform/app/Filament/Pages/Findings/MyFindingsInbox.php` | Add a new Filament admin page with slug `findings/my-work`, `HasTable`, workspace membership access checks, and fixed assignee/open-status scope |
| A.2 | `apps/platform/resources/views/filament/pages/findings/my-findings-inbox.blade.php` | Render the page shell, page description, native Filament table, and branch-specific calm empty-state CTAs: clear the tenant prefilter when it alone excludes rows, otherwise open tenant findings for the active tenant or `/admin/choose-tenant` when no tenant context exists |
| A.3 | `apps/platform/app/Providers/Filament/AdminPanelProvider.php` | Register the new page in the existing admin panel; do not move provider registration because it already lives in `apps/platform/bootstrap/providers.php` |

### Phase B — Derive Queue Truth From Existing Findings Semantics

**Goal**: Keep inclusion, urgency, and owner-versus-assignee behavior aligned with Specs 111 and 219.

| Step | File | Change |
|------|------|--------|
| B.1 | `apps/platform/app/Filament/Pages/Findings/MyFindingsInbox.php` | Build the table query and derived inbox counts from `Finding`, restricted to the current workspace, visible capability-eligible tenants, `assignee_user_id = auth()->id()`, and `Finding::openStatusesForQuery()` |
| B.2 | `apps/platform/app/Filament/Pages/Findings/MyFindingsInbox.php` and `apps/platform/app/Filament/Resources/FindingResource.php` | Reuse or mirror existing severity, lifecycle, overdue, reopened, and owner context presentation helpers without inventing new badge semantics |
| B.3 | `apps/platform/app/Filament/Pages/Findings/MyFindingsInbox.php` | Add the available-filters contract for fixed assignee scope, tenant, overdue, reopened, and high-severity filters, capability-safe tenant filter options, applied-scope metadata, summary counts, and deterministic urgency sorting with due-date and finding-ID tie-breakers while keeping personal assignment scope fixed and non-removable |

### Phase C — Honor Active Tenant Context And Queue-to-Detail Continuity

**Goal**: Make the inbox feel canonical inside the existing admin shell instead of a detached register.

| Step | File | Change |
|------|------|--------|
| C.1 | `apps/platform/app/Filament/Pages/Findings/MyFindingsInbox.php` | Reuse `CanonicalAdminTenantFilterState` so the active tenant becomes the default prefilter and can be cleared via one header action |
| C.2 | `apps/platform/app/Filament/Pages/Findings/MyFindingsInbox.php` | Build row URLs to tenant finding detail with `CanonicalNavigationContext` carrying `Back to my findings` continuity |
| C.3 | `apps/platform/app/Filament/Resources/FindingResource.php` or existing detail page seam | Ensure the tenant detail page consumes the navigation context and exposes the inbox return link without changing mutation semantics |

### Phase D — Add The Workspace Overview Signal Without Creating A Second Queue

**Goal**: Make `/admin` show whether personal findings work exists and link into the inbox in one click.

| Step | File | Change |
|------|------|--------|
| D.1 | `apps/platform/app/Support/Workspaces/WorkspaceOverviewBuilder.php` | Add a small `my_findings_signal` payload with visible capability-safe open assigned count, overdue count, calm state, and CTA URL |
| D.2 | `apps/platform/resources/views/filament/pages/workspace-overview.blade.php` | Render one compact assigned-to-me summary block ahead of the broader workspace metrics |
| D.3 | Existing workspace navigation helpers | Keep the CTA pointed at the canonical inbox route and avoid duplicating queue logic or urgency semantics in the overview itself |

### Phase E — Protect The Feature With Focused Regression Coverage

**Goal**: Lock down visibility, prioritization, tenant safety, and overview-to-inbox truth alignment.

| Step | File | Change |
|------|------|--------|
| E.1 | `apps/platform/tests/Feature/Findings/MyWorkInboxTest.php` | Cover capability-safe visible rows only, owner-context rendering when owner differs from assignee, the full available-filters contract truth for fixed assignee scope plus tenant, overdue, reopened, and high-severity filters, tenant filter option truth, owner-only exclusion, deterministic urgency ordering with due-date and finding-ID tie-breakers, clearable tenant prefilter, applied-scope and summary-count truth, zero-visible-work and tenant-prefilter empty-state branches, and drilldown continuity |
| E.2 | `apps/platform/tests/Feature/Authorization/MyWorkInboxAuthorizationTest.php` | Cover admin-plane workspace recovery behavior for missing workspace context, member-without-capability disclosure boundaries, protected-destination `403`, and deny-as-not-found boundaries for non-members |
| E.3 | `apps/platform/tests/Feature/Dashboard/MyFindingsSignalTest.php` | Cover overview signal counts, calm state, capability-safe suppression, and CTA alignment with inbox truth |
| E.4 | `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` plus the focused Pest commands above | Run formatting and the narrowest proving suites before closing implementation |