Skip to content

feat(store,api): conversation tags + single-Agent assignee (HT-29, HT-31) - #28

Merged
zaridan merged 1 commit into
mainfrom
feat/ht-29-tags-assignee
Jul 12, 2026
Merged

feat(store,api): conversation tags + single-Agent assignee (HT-29, HT-31)#28
zaridan merged 1 commit into
mainfrom
feat/ht-29-tags-assignee

Conversation

@zaridan

@zaridan zaridan commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Why

Fourth v1.1 increment — two tickets in one PR, deliberately: HT-29 (tags) and HT-31 (assignee) touch identical regions (summary shape, router, the summary-returning UPDATE pattern, the same test tails), so separate PRs would have guaranteed another conflict-and-rebase cycle like #27's, with no isolation benefit. Every line traces to one of the two named tickets. Spec: §4e/§4f (v1.1, #24).

What

Migration 006

  • tags jsonb NOT NULL DEFAULT '[]' — replace-set storage, no side table (v1 has no tag-filtered listing per spec §4e; a tag table would be structure with no query to serve).
  • assignee text + CHECK (assignee IS NULL OR assignee = 'me') — single-Agent by construction; a future multi-Agent migration must widen it explicitly.
  • No backfill: both defaults are already correct for every existing row.

Store

  • setConversationTags / setConversationAssignee — summary-returning UPDATEs; neither bumps updated_at (metadata, not activity — spec), proven by tests.
  • The RETURNING clause status/tags/assignee share is now one helper, so every summary-shaped write maps through the same mapper.

API

  • PUT …/tags: normalization in the handler (trim → lowercase → dedupe preserving first occurrence), validation on the trimmed value (1–40 chars); [] clears.
  • PUT …/assignee: { assignee: 'me' | null } — property must be present; anything else 400.
  • tags/assignee on every wire summary and detail; router gains the two PUT-only routes with correct Allow behavior.

Evidence

  • 369/369 tests pass (11 new): migration-006 upgrade over a seeded pre-006 database (defaults land, CHECK live and rejecting), replace-set round-trips + clear, no-updated_at-bump proofs for both writes, wire normalization (' Bug '+'bug'['bug']), validation matrices for both bodies, the missing/deleted/non-UUID 404 trio on both routes, 405 Allow: PUT, 401.
  • Typecheck + Biome clean. No mail-path changes.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added conversation tags with support for replacing, clearing, and normalized tag values.
    • Added assignee controls to claim or release conversations.
    • Conversation list and detail views now include tags and assignee information.
    • Added API validation and clear error responses for invalid or unavailable conversations.
  • Bug Fixes

    • Existing conversations are safely initialized with empty tags and no assignee during upgrades.

…-31)

One PR for two sibling v1.1 increments that share every touchpoint
(summary shape, router, summary-returning UPDATEs) — separate PRs
would have guaranteed a conflict-and-rebase cycle with no isolation
benefit.

Migration 006: tags jsonb NOT NULL DEFAULT '[]' (no side table — v1
has no tag-filtered listing, spec §4e) and nullable assignee text
CHECKed to 'me' (single-Agent by construction, spec §4f). No backfill
needed: both defaults are correct for every existing row.

Store: setConversationTags (persists verbatim; HTTP layer normalizes)
and setConversationAssignee — neither bumps updated_at (metadata, not
activity, per spec). The summary RETURNING clause is now one shared
helper across status/tags/assignee so all summary-shaped UPDATEs map
identically.

API: PUT /conversations/{id}/tags (trim -> lowercase -> dedupe
preserving order; 1-40 chars after trim, else 400) and PUT
/conversations/{id}/assignee ({assignee: 'me' | null}, property
required). tags/assignee on every wire summary and detail.

369/369 tests: migration 006 upgrade path + CHECK enforcement,
replace-set round-trips with no-bump proof, normalization on the wire,
validation matrices, 404 trio, Allow headers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@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: b0a9a022-3102-4e01-8ac7-b9f434c162d9

📥 Commits

Reviewing files that changed from the base of the PR and between 96ebf7f and d5a299f.

📒 Files selected for processing (8)
  • src/api/conversations.ts
  • src/api/index.test.ts
  • src/api/index.ts
  • src/api/router.ts
  • src/db/migrate.test.ts
  • src/db/migrate.ts
  • src/store/conversations.test.ts
  • src/store/conversations.ts

📝 Walkthrough

Walkthrough

Conversation records now support normalized tags and nullable assignee metadata across migrations, storage, API routing, update handlers, responses, and tests. New PUT endpoints replace tags or claim/release assignees.

Changes

Conversation metadata

Layer / File(s) Summary
Schema and persistence
src/db/migrate.ts, src/db/migrate.test.ts, src/store/conversations.ts, src/store/conversations.test.ts
Migration 006 adds tags and assignee; storage reads, writes, maps, and tests the new fields and update operations.
API routes and update handlers
src/api/router.ts, src/api/index.ts, src/api/conversations.ts
Adds tags and assignee routes, request dispatch, payload validation, update handlers, and extended conversation summaries.
API behavior coverage
src/api/index.test.ts
Tests normalization, clearing, validation, missing resources, response fields, method handling, and authentication.

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

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant InboxApi
  participant Router
  participant ConversationHandlers
  participant ConversationStore
  participant Database
  Client->>InboxApi: PUT tags or assignee
  InboxApi->>Router: Match request route
  Router-->>InboxApi: Return conversation route
  InboxApi->>ConversationHandlers: Dispatch update
  ConversationHandlers->>ConversationStore: Update metadata
  ConversationStore->>Database: Persist and return summary
  Database-->>ConversationStore: Updated summary
  ConversationStore-->>ConversationHandlers: Summary or null
  ConversationHandlers-->>Client: API response
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: conversation tags and single-agent assignee support across store and API.
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-29-tags-assignee

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

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