TenantAtlas/specs/056-remove-legacy-bulkops/plan.md
ahmido a97beefda3 056-remove-legacy-bulkops (#65)
Kurzbeschreibung

Versteckt die Rerun-Row-Action für archivierte (soft-deleted) RestoreRuns und verhindert damit fehlerhafte Neu-Starts aus dem Archiv; ergänzt einen Regressionstest.
Änderungen

Code: RestoreRunResource.php — Sichtbarkeit der rerun-Action geprüft auf ! $record->trashed() und defensive Abbruchprüfung im Action-Handler.
Tests: RestoreRunRerunTest.php — neuer Test rerun action is hidden for archived restore runs.
Warum

Archivierte RestoreRuns durften nicht neu gestartet werden; UI zeigte trotzdem die Option. Das führte zu verwirrendem Verhalten und möglichen Fehlern beim Enqueueing.
Verifikation / QA

Unit/Feature:
./vendor/bin/sail artisan test tests/Feature/RestoreRunRerunTest.php
Stil/format:
./vendor/bin/pint --dirty
Manuell (UI):
Als Tenant-Admin Filament → Restore Runs öffnen.
Filter Archived aktivieren (oder Trashed filter auswählen).
Sicherstellen, dass für archivierte Einträge die Rerun-Action nicht sichtbar ist.
Auf einem aktiven (nicht-archivierten) Run prüfen, dass Rerun sichtbar bleibt und wie erwartet eine neue RestoreRun erzeugt.
Wichtige Hinweise

Kein DB-Migration required.
Diese PR enthält nur den UI-/Filament-Fix; die zuvor gemachten operative Fixes für Queue/adapter-Reconciliation bleiben ebenfalls auf dem Branch (z. B. frühere commits während der Debugging-Session).
T055 (Schema squash) wurde bewusst zurückgestellt und ist nicht Teil dieses PRs.
Merge-Checklist

 Tests lokal laufen (RestoreRunRerunTest grünt)
 Pint läuft ohne ungepatchte Fehler
 Branch gepusht: 056-remove-legacy-bulkops (PR-URL: https://git.cloudarix.de/ahmido/TenantAtlas/compare/dev...056-remove-legacy-bulkops)

Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local>
Reviewed-on: #65
2026-01-19 23:27:52 +00:00

164 lines
7.2 KiB
Markdown

# Implementation Plan: Remove Legacy BulkOperationRun & Canonicalize Operations (v1.0)
**Branch**: `056-remove-legacy-bulkops` | **Date**: 2026-01-18 | **Spec**: [specs/056-remove-legacy-bulkops/spec.md](./spec.md)
**Input**: Feature specification from `/specs/056-remove-legacy-bulkops/spec.md`
**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/scripts/` for helper scripts.
## Summary
Unify all bulk/operational work onto `OperationRun` (canonical run model + Monitoring surface) by migrating all legacy `BulkOperationRun` workflows to OperationRun-backed orchestration, removing the legacy stack (model/service/table/UI), and adding guardrails that prevent reintroduction.
## Technical Context
**Language/Version**: PHP 8.4.x
**Primary Dependencies**: Laravel 12, Filament v4, Livewire v3
**Storage**: PostgreSQL (JSONB in `operation_runs.context`, `operation_runs.summary_counts`)
**Testing**: Pest (PHPUnit 12)
**Target Platform**: Docker via Laravel Sail (local); Dokploy (staging/prod)
**Project Type**: Web application (Laravel monolith)
**Performance Goals**: Calm polling UX for Monitoring; bulk orchestration chunked and resilient to throttling; per-scope concurrency default=1
**Constraints**: Tenant isolation; no secrets in run failures/notifications; no remote work during UI render; Monitoring is DB-only
**Scale/Scope**: Bulk actions may target large selections; orchestration must remain idempotent and debounced by run identity
## Constitution Check
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
- Inventory-first: N/A (this feature is operations plumbing; no inventory semantics change)
- Read/write separation: PASS (bulk actions remain enqueue-only; write paths are job-backed and auditable)
- Graph contract path: PASS (no new render-side Graph calls; any remote work stays behind queue + existing Graph client boundary)
- Deterministic capabilities: PASS (no capability derivation changes)
- Tenant isolation: PASS (OperationRun is tenant-scoped; bulk dedupe is tenant-wide; selection identity is deterministic)
- Run observability: PASS (bulk is always OperationRun-backed; DB-only <2s actions remain audit-only)
- Automation: PASS (locks + idempotency required; per-target concurrency is config-driven default=1)
- Data minimization: PASS (failure summaries stay sanitized; no secrets in run records)
## Project Structure
### Documentation (this feature)
```text
specs/056-remove-legacy-bulkops/
├── 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)
```text
app/
├── Filament/
│ ├── Resources/
│ └── Pages/
├── Jobs/
├── Models/
├── Notifications/
├── Services/
└── Support/
config/
├── tenantpilot.php
└── graph_contracts.php
database/
├── migrations/
└── factories/
resources/
└── views/
routes/
└── web.php
tests/
├── Feature/
└── Unit/
```
**Structure Decision**: Laravel web application (monolith). Feature changes are expected primarily under `app/` (runs, jobs, Filament actions), `database/migrations/` (dropping legacy tables), and `tests/` (Pest guardrails).
## Complexity Tracking
> **Fill ONLY if Constitution Check has violations that must be justified**
| Violation | Why Needed | Simpler Alternative Rejected Because |
|-----------|------------|-------------------------------------|
| None | N/A | N/A |
## Constitution Check (Post-Design)
*Re-check after Phase 1 outputs are complete.*
- Monitoring remains DB-only at render time.
- Start surfaces remain enqueue-only.
- Bulk work is always OperationRun-backed.
- Per-target scope concurrency is config-driven (default=1).
- Bulk idempotency uses hybrid selection identity.
## Phase 0 — Outline & Research (output: research.md)
### Discovery signals (repo sweep)
Legacy bulk-run usage exists and must be migrated/removed:
- Jobs using legacy run/service include:
- `app/Jobs/BulkPolicySyncJob.php`
- `app/Jobs/BulkPolicyDeleteJob.php`
- `app/Jobs/BulkBackupSetDeleteJob.php`
- `app/Jobs/BulkPolicyVersionPruneJob.php`
- `app/Jobs/BulkPolicyVersionForceDeleteJob.php`
- `app/Jobs/BulkRestoreRunDeleteJob.php`
- `app/Jobs/BulkTenantSyncJob.php`
- `app/Jobs/CapturePolicySnapshotJob.php`
- `app/Jobs/GenerateDriftFindingsJob.php` (mixed: legacy + OperationRun)
Legacy data layer present:
- Model: `app/Models/BulkOperationRun.php`
- Service: `app/Services/BulkOperationService.php`
- Migrations: `database/migrations/*_create_bulk_operation_runs_table.php`, `*_add_idempotency_key_to_bulk_operation_runs_table.php`, `*_increase_bulk_operation_runs_status_length.php`
- Factory/Seeder: `database/factories/BulkOperationRunFactory.php`, `database/seeders/BulkOperationsTestSeeder.php`
Existing canonical run patterns to reuse:
- `app/Services/OperationRunService.php` provides tenant-wide active-run dedupe and safe dispatch semantics.
- `app/Support/OperationCatalog.php` centralizes labels/durations and allowed summary keys.
- `app/Support/OpsUx/OperationSummaryKeys.php` + `SummaryCountsNormalizer` enforce summary_counts contract.
Concurrency/idempotency patterns already exist and should be adapted:
- `app/Services/Inventory/InventoryConcurrencyLimiter.php` uses per-scope cache locks with config-driven defaults.
- `app/Services/Inventory/InventorySyncService.php` uses selection hashing + selection locks to prevent duplicate work.
### Research outputs (decisions)
- Per-target scope concurrency is configuration-driven with default=1.
- Bulk selection identity is hybrid (IDs-hash when explicit IDs; query-hash when select all via filter/query”).
- Legacy bulk-run history is not imported into OperationRun (default path).
## Phase 1 — Design & Contracts (outputs: data-model.md, contracts/*, quickstart.md)
### Design topics
- Define the canonical bulk orchestration shape around OperationRun (orchestrator + workers) while preserving the constitution feedback surfaces.
- Define the minimal run context contract for directory-targeted runs (target scope fields + idempotency fingerprint fields).
- Extend operation type catalog for newly migrated bulk operations.
### Contract artifacts
- JSON schema for `operation_runs.context` for bulk operations (target scope + selection identity + idempotency).
- OpenAPI sketch for internal operation-triggering endpoints (if applicable) as a stable contract for enqueue-only start surfaces.
## Phase 2 — Planning (implementation outline; detailed tasks live in tasks.md)
- Perform required discovery sweep and create a migration report.
- Migrate each legacy bulk workflow to OperationRun-backed orchestration.
- Remove legacy model/service/table/UI surfaces.
- Add hard guardrails (CI/test) to forbid legacy references and verify run-backed behavior.
- Add targeted Pest tests for bulk actions, per-scope throttling default=1, and summary key normalization.