Some checks failed
Main Confidence / confidence (push) Failing after 1m29s
## 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
227 lines
18 KiB
Markdown
227 lines
18 KiB
Markdown
# 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.
|