Skip to content

feat(store,api): soft-delete endpoint — DELETE /conversations/{id} (HT-30) - #27

Merged
zaridan merged 1 commit into
mainfrom
feat/ht-30-soft-delete
Jul 12, 2026
Merged

feat(store,api): soft-delete endpoint — DELETE /conversations/{id} (HT-30)#27
zaridan merged 1 commit into
mainfrom
feat/ht-30-soft-delete

Conversation

@zaridan

@zaridan zaridan commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Why

Third v1.1 increment (HT-30) — the designed UI's two-step-arm delete needs its endpoint. Spec: agent-inbox-v1.md §4d (v1.1, merged in #24).

What

Store — deleteConversation(id): Promise<boolean>

  • One UPDATE ... SET status = 'deleted' WHERE id = $1 AND status <> 'deleted' RETURNING id — a repeat delete is a miss, matching the API's already-deleted → 404.
  • Deliberately no updated_at bump: the row is never surfaced again, and it stays an exact record of its last live activity.
  • Soft, permanently: rows + threads survive in storage (charter invariant HT-3: clean-room protocol doc #1). Every public path already treated 'deleted' as nonexistent (reads, list, append, PATCH), so the method is just the flag flip.

API

  • DELETE joins the item route (Allow: GET, PATCH, DELETE now); new noContent() helper → 204, empty body, still Cache-Control: no-store.
  • Missing / already-deleted / non-UUID ids: one identical generic 404 (§5 no-existence-leak).

Evidence

  • 349/349 tests pass; 9 new/updated: 204 + empty body + no-store; post-delete invisibility across GET/list/PATCH/reply; the §4a replay-vs-delete rule (a keyed replay of a previously-successful reply returns 404 after the delete, not the original 201); double-delete → 404; unauthenticated DELETE deletes nothing; router coverage for the new method and the updated Allow list; store-level proof the threads remain in storage after the soft delete.
  • Typecheck + Biome clean. No mail-path changes.

Note

Sibling PR #26 (HT-27) branches from the same main and touches neighboring test regions — whichever merges second may need a trivial rebase; no semantic overlap.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added conversation deletion to the API.
    • Deletion is soft: deleted conversations are hidden from normal viewing, updating, and reply flows.
    • Successful deletions return 204 No Content with Cache-Control: no-store; subsequent deletes, missing, or non-UUID ids return 404.
  • Security & Compatibility

    • Delete requests require authentication.
    • Method handling was updated so unsupported methods clearly advertise the allowed set (GET, PATCH, DELETE).

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e43fe38d-6258-43be-ac88-db447c9549f7

📥 Commits

Reviewing files that changed from the base of the PR and between ec302d4 and 12a38b6.

📒 Files selected for processing (8)
  • src/api/conversations.ts
  • src/api/index.test.ts
  • src/api/index.ts
  • src/api/responses.ts
  • src/api/router.test.ts
  • src/api/router.ts
  • src/store/conversations.test.ts
  • src/store/conversations.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/api/responses.ts
  • src/store/conversations.ts
  • src/api/router.ts
  • src/store/conversations.test.ts
  • src/api/conversations.ts
  • src/api/index.test.ts

📝 Walkthrough

Walkthrough

Adds soft-delete storage semantics and exposes them through authenticated DELETE /api/v1/conversations/{id} handling, routing, standardized 204 responses, and comprehensive API and store tests.

Changes

Conversation deletion

Layer / File(s) Summary
ConversationStore soft-delete semantics
src/store/conversations.ts, src/store/conversations.test.ts
Live conversations are marked deleted without updating timestamps; repeated or missing deletions return false, while stored rows and threads remain persisted.
DELETE routing and response flow
src/api/router.ts, src/api/conversations.ts, src/api/index.ts, src/api/responses.ts, src/api/router.test.ts
The item route accepts DELETE, dispatches to the new handler, validates UUID-shaped IDs, returns generic 404 errors for misses, and returns 204 with Cache-Control: no-store on success.
End-to-end DELETE API validation
src/api/index.test.ts
HTTP tests cover deletion responses, post-deletion behavior, repeated and invalid deletes, idempotency replay, authentication, and method routing.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant matchRoute
  participant handleDeleteConversation
  participant ConversationStore
  Client->>matchRoute: DELETE /api/v1/conversations/{id}
  matchRoute->>handleDeleteConversation: conversation-delete with id
  handleDeleteConversation->>ConversationStore: deleteConversation(id)
  ConversationStore-->>handleDeleteConversation: true or false
  handleDeleteConversation-->>Client: 204 No Content or 404 not_found
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main change: adding a soft-delete DELETE endpoint for conversations.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ht-30-soft-delete

Comment @coderabbitai help to get the list of available commands.

…T-30)

Store: deleteConversation() — a single UPDATE to status 'deleted',
scoped to exclude already-deleted rows so a second delete reports a
miss. No updated_at bump (never surfaced again; the row stays an exact
record of its last live activity). Soft, permanently: rows and threads
survive in storage (charter invariant #1) — every public path already
treats 'deleted' as nonexistent, so only the flag flips.

API: DELETE joins GET/PATCH on the item route (Allow header updated);
204 with an empty body via a new noContent() helper (still no-store);
missing, already-deleted, and non-UUID ids are one identical 404 (§5
no-existence-leak).

Per specs/api/agent-inbox-v1.md §4d (v1.1, HT-25). 349/349 tests,
including post-delete invisibility across every endpoint, the §4a
replay-vs-delete rule (a keyed replay of a successful send 404s after
the delete), and proof the mail itself stays in storage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@zaridan
zaridan force-pushed the feat/ht-30-soft-delete branch from ec302d4 to 12a38b6 Compare July 12, 2026 16:33
@zaridan
zaridan merged commit 96ebf7f into main Jul 12, 2026
5 checks passed
@zaridan
zaridan deleted the feat/ht-30-soft-delete branch August 2, 2026 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant