TenantAtlas/specs/110-ops-ux-enforcement/plan.md
2026-02-23 22:48:30 +01:00

7.3 KiB

Implementation Plan: Ops-UX Enforcement & Cleanup (Enterprise Standard Rollout)

Branch: 110-ops-ux-enforcement | Date: 2026-02-23 | Spec: specs/110-ops-ux-enforcement/spec.md Input: Feature specification from /specs/110-ops-ux-enforcement/spec.md

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

Summary

Enforce the Ops-UX “3-surface contract” by removing non-canonical operation-run status/outcome transitions and banning queued/running DB notifications across in-scope operation flows.

Implementation is split into:

  • Cleanup: move all terminal transitions to OperationRunService, remove job-level sendToDatabase() completion/queued notifications, and delete the legacy RunStatusChangedNotification.
  • Enforcement: add Pest guard tests (filesystem scans) that fail CI when these patterns reappear.
  • Verification: add focused regression tests asserting “exactly one terminal OperationRunCompleted notification for initiator; none for system runs; and zero queued/running notifications”.

Technical Context

Language/Version: PHP 8.4.x
Primary Dependencies: Laravel 12, Filament v5, Livewire v4
Storage: PostgreSQL (Sail)
Testing: Pest v4 (vendor/bin/sail artisan test --compact)
Target Platform: Docker via Laravel Sail (local); Dokploy (staging/prod)
Project Type: Laravel monolith (Filament admin panel)
Performance Goals: Guard tests run in < 1s locally; overall targeted test pack < 30s
Constraints:

  • No schema changes and no new routes.
  • Terminal DB notification is initiator-only and emitted exactly once.
  • No queued/running DB notifications anywhere (including OperationRunQueued).
  • Existing RBAC/capability gates for starting operations remain unchanged.

Scale/Scope: Repo-wide enforcement via guard tests; remediation limited to enumerated violating flows in the spec.

Constitution Check

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

This spec is a cleanup/enforcement layer and does not introduce new screens, Graph calls, or operation types.

  • Inventory-first / Read-write separation: PASS (no new inventory/backups semantics; no new write UX)
  • Graph contract path: PASS (no Graph call additions)
  • Deterministic capabilities: PASS (no capability model changes)
  • RBAC-UX / isolation: PASS (no new routes or cross-plane access)
  • Run observability: PASS (this spec strengthens dedupe + terminal notifications by removing ad-hoc notifications)
  • Automation: PASS (no scheduling behavior changes; only notification/transition handling)
  • Data minimization: PASS (removes notification spam; no payload storage changes)
  • Badge semantics: PASS (no new badges)
  • Filament UI contracts: PASS (no new screens; targeted updates to existing start surfaces only). The spec includes a mandatory UI Action Matrix.

Project Structure

Documentation (this feature)

specs/110-ops-ux-enforcement/
├── plan.md              # This file (/speckit.plan command output)
├── research.md          # Phase 0 output (/speckit.plan command)
├── data-model.md        # Phase 1 output (/speckit.plan command)
├── quickstart.md        # Phase 1 output (/speckit.plan command)
├── contracts/           # Phase 1 output (/speckit.plan command)
└── tasks.md             # Phase 2 output (/speckit.tasks command - NOT created by /speckit.plan)

Source Code (repository root)

app/
├── Jobs/
├── Notifications/
├── Services/
└── Support/

config/

database/
├── migrations/
└── factories/

resources/
├── views/
└── css/

routes/

tests/
└── Feature/

Structure Decision: Laravel monolith. Enforcement is implemented as:

  • Targeted production code edits under app/ (jobs/services/notifications).
  • Guard + regression tests under tests/Feature/OpsUx/**.

Complexity Tracking

Fill ONLY if Constitution Check has violations that must be justified

Violation Why Needed Simpler Alternative Rejected Because
[e.g., 4th project] [current need] [why 3 projects insufficient]
[e.g., Repository pattern] [specific problem] [why direct DB access insufficient]

Phase 0 — Outline & Research

Inputs: specs/110-ops-ux-enforcement/spec.md, constitution

Research is captured in specs/110-ops-ux-enforcement/research.md and resolves:

  • Guard-test heuristics (regex/scan approach) to keep false positives low.
  • Where/how queued DB notifications are emitted today, and how to disable them by default.
  • Preferred test strategy for “exactly once terminal notification”.

Phase 1 — Design & Contracts

Design artifacts are captured in:

Design highlights:

  • The only terminal DB notification is OperationRunCompleted, emitted from OperationRunService when an initiator exists.
  • Guard A scans app/**/*.php for ->update([...]) arrays that include status and/or outcome keys, excluding OperationRunService.
  • Guard B scans app/**/*.php for files that both reference an OperationRun signal and emit DB notifications (sendToDatabase( or ->notify(), with a strict allowlist.
  • Guard C ensures the legacy notification class is fully removed.

Phase 2 — Execution Plan (Implementation)

Work is implemented in small, reviewable steps:

  1. P0 fixes (silent completions): replace direct terminal updates with OperationRunService transitions in the enumerated services/jobs.
  2. P0 fixes (notification spam): remove queued/running and custom completion DB notifications from the enumerated jobs.
  3. P0 fixes (legacy removal): delete RunStatusChangedNotification and remove any invocation.
  4. Enforcement: add Pest guard tests (A/B/C) + minimal allowlist.
  5. Verification: add focused regression tests for the key flows (inventory sync, retention, backup schedule run) proving the “exactly once terminal notification” contract.

Out of scope: new UI pages, schema changes, new operation types, Graph contract changes.

Constitution Check (Post-Phase 1 Re-check)

  • PASS: No new routes, no Graph calls, no new Filament screens.
  • PASS: Strengthens Run Observability by centralizing terminal notification emission.
  • PASS: RBAC-UX/isolation unaffected (no new access paths).