# Implementation Plan: In-App Support Request with Context

**Branch**: `246-support-request-context` | **Date**: 2026-04-27 | **Spec**: `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/246-support-request-context/spec.md`
**Input**: Feature specification from `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/246-support-request-context/spec.md`

## Summary

- Add one bounded `SupportRequest` product truth that captures structured support intake from two existing support-aware surfaces: the tenant dashboard and the canonical operation detail viewer.
- Reuse the existing support-diagnostics bundle to attach a redacted, machine-readable context envelope when the creator is allowed to view diagnostics, and fall back to a safe canonical reference set when they are not.
- Keep the slice synchronous, Livewire v4-compatible, Filament v5-native, and free of external ticket adapters, `OperationRun` side effects, global-search changes, destructive actions, or asset changes.

## Technical Context

**Language/Version**: PHP 8.4 (Laravel 12)  
**Primary Dependencies**: Laravel 12 + Filament v5 + Livewire v4 + Pest; existing `SupportDiagnosticBundleBuilder`, `WorkspaceAuditLogger`, `UiEnforcement`, `CapabilityResolver`, and canonical tenant/run support surfaces  
**Storage**: PostgreSQL tenant-owned `support_requests` table with required not-null `workspace_id` and `tenant_id`, plus immutable redacted context JSON  
**Testing**: Pest unit + feature tests  
**Validation Lanes**: fast-feedback, confidence  
**Target Platform**: Sail-backed Laravel admin panel under `/admin`  
**Project Type**: web  
**Performance Goals**: create the support request synchronously inside ordinary admin-request latency with no outbound HTTP and no background jobs  
**Constraints**: no external ticketing provider, no support inbox or resource, no new system panel, no raw payload persistence, no `OperationRun`, and no asset changes  
**Scale/Scope**: one migration, one model and factory, one bounded support-request context builder or submission service, one generated reference path, two header actions, and focused unit plus feature proof only

## First-Slice Request Contract

The first slice is locked to the following request shape:

1. **Primary contexts**: `tenant` and `operation_run` only
2. **Required submitted fields**: severity, summary, creator identity, workspace, tenant, primary context
3. **Severity values**:
  - `low` = Low
  - `normal` = Normal (default)
  - `high` = High
  - `blocking` = Blocking
4. **Optional submitted fields**: reproduction notes, contact name, contact email, attached diagnostic snapshot when allowed
5. **Attachment modes**:
  - `diagnostic_snapshot_attached` when the creator also passes `support_diagnostics.view`
  - `canonical_context_only` when the creator can create the request but cannot attach support diagnostics
6. **Duplicate submissions**: repeated submits are intentionally allowed in v1 and must always create a fresh support request row plus a fresh internal support reference with no hidden merge or dedupe behavior
7. **Returned reference**: one immutable internal support reference shown back immediately in success feedback, formatted as `SR-<ULID>`

Any support inbox, lifecycle state machine, external ticket reference, file upload, or customer-facing support portal is deferred by design.

## UI / Surface Guardrail Plan

- **Guardrail scope**: changed surfaces
- **Native vs custom classification summary**: native Filament + shared support primitives
- **Shared-family relevance**: header actions, support capture, support diagnostics, audit feedback
- **State layers in scope**: page, detail, action form
- **Audience modes in scope**: operator-MSP, support-platform
- **Decision/diagnostic/raw hierarchy plan**: decision-first form, diagnostics-second, support-raw omitted from persistence
- **Raw/support gating plan**: capability-gated attachment, raw payloads never persisted
- **One-primary-action / duplicate-truth control**: the request form keeps one dominant action, `Submit support request`, and reuses the support-diagnostics bundle summary instead of introducing local case language. On the operation detail page, both support actions (`Open support diagnostics`, `Request support`) stay grouped in secondary placement under `More`.
- **Handling modes by drift class or surface**: review-mandatory
- **Repository-signal treatment**: review-mandatory
- **Special surface test profiles**: standard-native-filament, monitoring-state-page
- **Required tests or manual smoke**: functional-core, state-contract
- **Exception path and spread control**: existing tenant dashboard action-surface exemption remains bounded to the two support-aware actions only
- **Active feature PR close-out entry**: Guardrail

## Shared Pattern & System Fit

- **Cross-cutting feature marker**: yes
- **Systems touched**: `App\Filament\Pages\TenantDashboard`, `App\Filament\Pages\Operations\TenantlessOperationRunViewer`, `App\Support\SupportDiagnostics\SupportDiagnosticBundleBuilder`, `App\Support\Auth\Capabilities`, `App\Services\Auth\RoleCapabilityMap`, and `App\Services\Audit\WorkspaceAuditLogger`
- **Shared abstractions reused**: support-diagnostics bundle composition, existing capability gating through `UiEnforcement`, existing audit-log writing, and the current support-aware tenant and run action surfaces
- **New abstraction introduced? why?**: one bounded `SupportRequestContextBuilder` or `SupportRequestSubmissionService` is justified because the slice needs one canonical place to shape immutable request context and reference generation without duplicating tenant/run logic
- **Why the existing abstraction was sufficient or insufficient**: the existing abstractions are sufficient for safe context and audit patterns, but insufficient for persisted support-request truth and immutable reference generation
- **Bounded deviation / spread control**: no ticket-provider adapter, no support queue, no page-local context builders, and no second support-summary vocabulary

## OperationRun UX Impact

- **Touches OperationRun start/completion/link UX?**: no
- **Central contract reused**: N/A
- **Delegated UX behaviors**: N/A
- **Surface-owned behavior kept local**: the run-context action reads the current run only as request context
- **Queued DB-notification policy**: N/A
- **Terminal notification path**: N/A
- **Exception path**: none

## Provider Boundary & Portability Fit

- **Shared provider/platform boundary touched?**: yes
- **Provider-owned seams**: translated provider reasons and provider-connection state already carried by the support-diagnostics bundle
- **Platform-core seams**: support request record, support reference, severity, primary context labels, attachment mode
- **Neutral platform terms / contracts preserved**: support request, support reference, attached context, redacted diagnostic snapshot, canonical reference set
- **Retained provider-specific semantics and why**: provider-specific reasons remain inside the redacted support-diagnostics bundle because they are already modeled as provider-owned evidence
- **Bounded extraction or follow-up path**: external ticketing remains a follow-up spec and must consume the neutral support-request truth instead of reshaping provider-specific evidence inline

## Constitution Check

*GATE: Must pass before implementation begins. Re-check after design changes.*

- Inventory-first / snapshots-second: PASS - the request stores immutable submitted context and does not replace canonical diagnostic truth
- Read/write separation: PASS - the action form is the pre-submit preview surface, creation is explicit, and the write is audited and tested
- Graph contract path: PASS - no new Graph calls are introduced
- Deterministic capabilities: PASS - capability derivation stays in the canonical registry and role map
- RBAC-UX / workspace isolation / tenant isolation: PASS - the feature remains on `/admin`, keeps non-member and non-entitled access as 404, and uses tenant-safe action surfaces only
- Global search rule: PASS - no resource or global-search change is introduced
- Run observability / Ops UX: PASS - request creation is DB-only and intentionally creates no `OperationRun`
- Proportionality / `PROP-001`, `ABSTR-001`, `PERSIST-001`, `STATE-001`, `BLOAT-001`: PASS - one persisted request truth and one small severity family are justified by structured support intake and no narrower path preserves immutable request context
- Shared pattern reuse / `XCUT-001`: PASS - support-diagnostics and audit seams are reused explicitly
- Provider boundary / `PROV-001`: PASS - provider-specific semantics stay inside the existing redacted bundle only
- Filament-native UI / `UI-FIL-001`: PASS - the slice uses native Filament action forms only
- Livewire v4 / Filament v5 compliance: PASS - the plan stays entirely within the current Filament v5 + Livewire v4 stack
- Provider registration location: PASS - no provider registration changes are introduced; Laravel 11+ provider registration remains in `bootstrap/providers.php`
- Destructive actions: PASS - none added, so no `->requiresConfirmation()` path is introduced here
- Asset strategy: PASS - no new assets are required, so deployment behavior for `cd apps/platform && php artisan filament:assets` remains unchanged
- Test governance / `TEST-GOV-001`: PASS - proof remains in narrow unit plus feature lanes only

## Test Governance Check

- **Test purpose / classification by changed surface**: Unit for context-shape and internal-reference rules; Feature for tenant and run action behavior, authorization, and audit
- **Affected validation lanes**: fast-feedback, confidence
- **Why this lane mix is the narrowest sufficient proof**: the feature is server-driven, synchronous, and action-form based; browser automation would only duplicate behavior already provable through unit and Filament feature tests
- **Narrowest proving command(s)**:
  - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/SupportRequests/SupportRequestContextBuilderTest.php tests/Unit/Support/SupportRequests/SupportRequestReferenceTest.php`
  - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/SupportRequests/TenantSupportRequestActionTest.php tests/Feature/SupportRequests/OperationRunSupportRequestActionTest.php tests/Feature/SupportRequests/SupportRequestAuthorizationTest.php tests/Feature/SupportRequests/SupportRequestAuditTest.php`
- **Fixture / helper / factory / seed / context cost risks**: add one `SupportRequest` factory; reuse existing workspace, tenant, run, provider, finding, report, review, and audit fixtures; keep support-request helpers local to the feature namespace
- **Expensive defaults or shared helper growth introduced?**: no
- **Heavy-family additions, promotions, or visibility changes**: none
- **Surface-class relief / special coverage rule**: standard-native-filament relief applies to the tenant action; the operation detail action keeps the monitoring-state-page contract already established on the viewer
- **Closing validation and reviewer handoff**: reviewers should re-run the listed unit and feature commands, verify immutable context persistence, verify 404 versus 403 boundaries, and verify that no outbound HTTP or `OperationRun` side effect occurs
- **Budget / baseline / trend follow-up**: none expected beyond ordinary feature-local upkeep
- **Review-stop questions**: did implementation add an outbound adapter, a request status workflow, a support inbox, or raw diagnostic persistence; did it broaden entry points beyond the two approved surfaces?
- **Escalation path**: `reject-or-split` if the slice expands into external sync, a support queue, or lifecycle management
- **Active feature PR close-out entry**: Guardrail
- **Why no dedicated follow-up spec is needed**: the planned cost stays local to support-request creation; only external ticketing or request-lifecycle expansion would justify a follow-up spec

## Project Structure

### Documentation (this feature)

```text
specs/246-support-request-context/
├── checklists/
│   └── requirements.md
├── spec.md
├── plan.md
└── tasks.md
```

### Source Code (repository root)

```text
apps/platform/
├── app/
│   ├── Filament/
│   │   └── Pages/
│   │       ├── Operations/
│   │       │   └── TenantlessOperationRunViewer.php
│   │       └── TenantDashboard.php
│   ├── Models/
│   │   └── SupportRequest.php
│   ├── Services/
│   │   ├── Audit/WorkspaceAuditLogger.php
│   │   └── Auth/RoleCapabilityMap.php
│   └── Support/
│       ├── Audit/AuditActionId.php
│       ├── Auth/Capabilities.php
│       ├── SupportDiagnostics/SupportDiagnosticBundleBuilder.php
│       └── SupportRequests/
│           ├── SupportRequestContextBuilder.php
│           └── SupportRequestReferenceGenerator.php
├── database/
│   ├── factories/SupportRequestFactory.php
│   └── migrations/
└── tests/
    ├── Feature/SupportRequests/
    │   ├── OperationRunSupportRequestActionTest.php
    │   ├── SupportRequestAuditTest.php
    │   ├── SupportRequestAuthorizationTest.php
    │   └── TenantSupportRequestActionTest.php
    └── Unit/Support/SupportRequests/
        ├── SupportRequestContextBuilderTest.php
        └── SupportRequestReferenceTest.php
```

**Structure Decision**: Single Laravel application. The implementation adds one bounded support-request model plus one small support namespace and reuses existing tenant and run surfaces.

## Complexity Tracking

No additional constitution violations are required. The new persisted support-request truth and small severity family are already justified in the proportionality review and remain bounded to the first slice.

## Proportionality Review

- **Current operator problem**: support intake still starts outside structured product context even though the product can already explain the current tenant or run problem safely
- **Existing structure is insufficient because**: support diagnostics is read-only and cannot provide an immutable, auditable support request or internal support reference
- **Narrowest correct implementation**: one immutable `SupportRequest` record plus one bounded context builder that reuses existing support diagnostics when allowed
- **Ownership cost**: migration, model, factory, capability, audit action, bounded support-request support namespace, and focused tests
- **Alternative intentionally rejected**: outbound-only ticket adapters, a multi-provider helpdesk registry, and a request status workflow were rejected because no concrete second use case or provider foundation exists yet
- **Why this is current-release truth**: the support-request record is directly useful now even without external sync because it preserves structured intake, returns a support reference, and captures immutable context

## Rollout & Risk Controls

- Start on exactly two existing surfaces only: the tenant dashboard and the canonical operation detail viewer
- Keep request truth immutable after creation; lifecycle management is explicitly out of scope
- Persist only redacted context JSON; raw payloads, secrets, and unrestricted provider bodies remain excluded
- Keep the reference internal-only in v1; external ticket references are deferred until a later ticketing spec exists
- Reuse the existing support-diagnostics capability when attaching diagnostics so the feature can safely support reduced attachment mode without creating a second diagnostic access path

## Implementation Outline

- Add the `SupportRequest` model, migration, and factory as the new persisted support-intake truth
- Add `support_requests.create` to the canonical capability registry and role map
- Add a bounded support-request context builder plus internal reference generator that can build tenant-context and run-context envelopes from the existing support-diagnostics bundle and canonical references
- Add an audit action identifier and `WorkspaceAuditLogger` path for support-request creation
- Add `Request support` action forms to `TenantDashboard` and `TenantlessOperationRunViewer`
- Return the generated support reference in success feedback and keep the action synchronous and DB-only

## Implementation Phases

1. **Foundation**: migration, model, factory, capability, audit action, internal reference generation, and shared context builder
2. **Tenant entry point**: tenant dashboard action, reduced-attachment logic, tenant-context feature proof
3. **Run entry point**: canonical operation detail action, entitled-tenant resolution, run-context feature proof
4. **Safety hardening**: immutable context persistence, authorization edge cases, audit proof, and no-side-effect verification

## Guardrail Close-Out

- Livewire v4 compliance remained unchanged and the feature shipped through native Filament v5 action forms only.
- Provider registration location stayed unchanged; Laravel 11+ provider registration remains in `bootstrap/providers.php`.
- No global-search behavior changed because no resource or global-search surface was introduced.
- No destructive action was added, so no new confirmation flow was required.
- No asset strategy changed; deployment remains unchanged, including `cd apps/platform && php artisan filament:assets` when registered Filament assets are present elsewhere.
- Browser smoke confirmed both approved entry points on the live app: the tenant dashboard visible `Request support` action and the tenantless operation viewer grouped `More` > `Request support` action both submitted successfully and returned `Support request submitted` with `Reference SR-...`.
- The tenant dashboard action-surface exception stayed bounded to the existing support-aware pair (`Request support`, `Open support diagnostics`), while the operation viewer kept both support actions grouped under `More` to avoid competing with its primary navigation and utility actions.
