feat(tickets): add DELETE /tickets/{id} so E2E cleans up its company (PMS-149) #133
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/pms-149-ticket-delete-route"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
The E2E suite leaked a company on every run.
e2e/tests/tickets.spec.tscreates a run-tagged company and a ticket under it, but the tickets module exposed no DELETE route anddelete_company(src/modules/contacts/service.rs:642) hard-refuses while any ticket references the company (400 "Cannot delete company with existing tickets").global.teardown.ts's company DELETE therefore returned 400, was logged ascompanies failed=1, and the company plus its ticket stayed in the dedicated E2E tenant forever (the 24h stale sweep hit the same FK refusal every later run).Change
TicketService::delete_ticket: tenant-scoped,404when the ticket is absent, mutation + audit row in one transaction (mirrorsdelete_company, PMS-117 audit convention).ticket_notes,ticket_status_history, andsla_trackingare removed by their existingON DELETE CASCADEFKs (migrations/005_tickets.sql).DELETE /api/v1/tickets/{id}behindRequireAuthinticket_routes, returning the sameAppResult<()>(200) convention asdelete_company.global.teardown.ts: sweep tickets before contacts and companies (delete order matters for the FK guard), and extend the name matcher to read a ticket'stitle.tickets.spec.ts: hard-delete the ticket then the company inline so the happy path exercises the new route; teardown still backstops failed runs.e2e/README.md.Verification
cargo fmt --all --check,cargo clippy --all-targets, andtsc --noEmit(e2e) all clean (run via the org rust-builder image; host has no toolchain).Closes PMS-149.
The E2E tickets spec creates a run-tagged company plus a ticket under it, but the tickets module exposed no DELETE route and `delete_company` hard-refuses while any ticket references the company ("Cannot delete company with existing tickets"). Teardown's company DELETE therefore 400'd and one company plus its ticket leaked into the dedicated E2E tenant on every run, accumulating forever (the 24h stale sweep hit the same FK refusal). Add `TicketService::delete_ticket` (tenant-scoped, 404 when absent, mutation + audit row in one transaction mirroring `delete_company`; ticket_notes / status-history / sla_tracking cascade via their existing ON DELETE CASCADE FKs) and wire `DELETE /api/v1/tickets/{id}` behind `RequireAuth`. Update `global.teardown.ts` to sweep tickets before contacts and companies, extend the name-based matcher to read a ticket's `title`, and delete the ticket + company inline in `tickets.spec.ts` so the happy path exercises the new route. Refresh the stale "no DELETE route" notes in the teardown header and e2e/README.md. #PMS-149 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>Code review of the new DELETE /tickets/{id} caught that delete_ticket deleted blindly and relied on cascade, but several FKs to tickets(id) use the default RESTRICT, not ON DELETE CASCADE: time_entries (006_time_tracking.sql), child tickets via parent_ticket_id (005_tickets.sql:119), and billing rows (010_billing.sql:68). Deleting a production ticket that has time logged or a sub-ticket raised SQLSTATE 23503, which the blanket sqlx::Error -> AppError conversion (only 23505 is special-cased) turned into a generic 500 "Database operation failed" - inconsistent with the sibling delete_company, which returns a clean 400. Catch 23503 on the ticket DELETE and return AppError::BadRequest with an actionable message; the transaction rolls back on the early return. This is localized to delete_ticket (covers every present and future referencing table without changing repo-wide error mapping) and keeps the endpoint's contract consistent with delete_company. The E2E path is unaffected: a freshly created test ticket has no time entries, sub-tickets, or billing, so the cascade still removes its notes/status-history. Doc comment corrected to describe the real FK graph. #PMS-149 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>