TenantAtlas/specs/246-support-request-context/plan.md
ahmido 6e3736a53f
Some checks failed
Main Confidence / confidence (push) Failing after 1m29s
Add in-app support request with context (#285)
## Summary
- add the first in-app support request flow with an immutable `SupportRequest` record, canonical context builder, submission service, and generated internal reference
- expose contextual support-request actions from the tenant dashboard and operation run surfaces, including audit logging and support-safe diagnostic capture rules
- add Pest coverage plus the `specs/246-support-request-context` artifacts for the new support-request slice

## Testing
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/SupportRequests/OperationRunSupportRequestActionTest.php tests/Feature/SupportRequests/SupportRequestAuditTest.php tests/Feature/SupportRequests/SupportRequestAuthorizationTest.php tests/Feature/SupportRequests/TenantSupportRequestActionTest.php tests/Unit/Support/SupportRequests/SupportRequestContextBuilderTest.php tests/Unit/Support/SupportRequests/SupportRequestReferenceTest.php`

## Notes
- this PR supersedes the earlier session-branch PR opened from `246-support-request-context-session-1777289015`

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #285
2026-04-27 12:51:39 +00:00

18 KiB

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
  1. Optional submitted fields: reproduction notes, contact name, contact email, attached diagnostic snapshot when allowed
  2. 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
  1. 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
  2. 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)

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

Source Code (repository root)

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.