docs: design specs for search-service (backend + sync-worker + frontend)#114
docs: design specs for search-service (backend + sync-worker + frontend)#114
Conversation
Context, goals, architecture, data flow, query construction, and wire schemas for the new NATS request/reply search-service. Part 2 (file layout, config, testing, ops) follows. https://claude.ai/code/session_01JbAWPnNedoBwQL3usoPtS3
…tension companion spec - Appends file layout, pkg/ additions, config, error handling, observability, docker-local (Valkey + Kibana), testing strategy incl. CCS integration test, known MVP parity gaps, and decision log to the search-service spec. - Adds the prerequisite sync-worker extension spec covering user-room restrictedRooms schema, painless script updates, and *int64 HistorySharedSince in pkg/model.InboxMemberEvent / MemberAddEvent. https://claude.ai/code/session_01JbAWPnNedoBwQL3usoPtS3
…hape Query builder had a hardcoded 'now-1y' that contradicted the configurable SEARCH_RECENT_WINDOW env var. Replaced with placeholder that derives from the configured duration at runtime. https://claude.ai/code/session_01JbAWPnNedoBwQL3usoPtS3
Covers the frontend consumer of the new search-service: top-header global search bar with debounced search-as-you-type, dropdown preview, tabbed full results (Rooms paginated, Messages lazy), and Ctrl+F in-room message search scoped via roomIds. Matches existing React/hook/subjects conventions. https://claude.ai/code/session_01JbAWPnNedoBwQL3usoPtS3
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 39 minutes and 51 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThis PR introduces three comprehensive design specifications for a chat platform search feature: a frontend global search UX consuming backend NATS endpoints, a backend search-service implementation using Elasticsearch and Valkey caching, and sync-worker extensions for managing user-room restricted access. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~30 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@docs/superpowers/specs/2026-04-21-search-service-sync-worker-extension-design.md`:
- Line 35: Update the spec to resolve the *int64 vs painless sentinel ambiguity
by either (A) documenting in the Behavioral Properties that HistorySharedSince =
&0 is canonically treated as unrestricted and publishers must not emit &0 for
genuinely restricted rooms (reference HistorySharedSince and the Behavioral
Properties section), or (B) change the decision note for HistorySharedSince to
state explicitly that the disambiguation only exists at the Go layer and the
painless translation intentionally maps nil and &0 to hss = 0 (reference the
painless script mapping of hss). Pick one option and update both the decision
table entry for HistorySharedSince and the related painless translation
discussion (lines around the hss mapping) so the spec and examples are
consistent.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d0bdc56c-0232-4710-96fa-6a51c434b7c6
📒 Files selected for processing (3)
docs/superpowers/specs/2026-04-21-chat-frontend-search-design.mddocs/superpowers/specs/2026-04-21-search-service-design.mddocs/superpowers/specs/2026-04-21-search-service-sync-worker-extension-design.md
Addresses CodeRabbit feedback on PR #114: - Expand the HistorySharedSince decision rationale to state the Go-layer disambiguation does NOT carry through to painless (both nil and &0 map to hss=0). - Add a 5th Behavioral Property codifying the publisher contract: emit nil for unrestricted, never &0 or a non-positive timestamp. https://claude.ai/code/session_01JbAWPnNedoBwQL3usoPtS3
PR #115 implements tshow indexing as part of the sync-worker prerequisite work. Update both specs to reflect: - sync-worker-ext spec: add tshow to goals; add pkg/model.Message + MessageSearchIndex field additions; add messages_test.go + model_test.go test cases covering round-trip true and omitempty behavior. - search-service spec: drop tshow from non-goals; restore Clause B1 (tshow=true) in the restricted-room per-room thread-reply branch; remove tshow from MVP parity gaps; update decision log to note the targeted exception. Restricted-user thread-reply parity now matches the old Rocket.Chat semantic. https://claude.ai/code/session_01JbAWPnNedoBwQL3usoPtS3
PR #115 discovered that message-worker/store_cassandra.go was not binding the tshow column in SaveMessage or SaveThreadMessage, even though the column already existed in the DDL and UDT struct. Without this fix the tshow value is always persisted as NULL, which breaks the downstream ES index population and defeats the Clause B1 restricted-room query branch. Spec updates: - Goal #5 expanded to call out the message-worker binding fix. - New "message-worker/store_cassandra.go — bind tshow in inserts" section with the three concrete INSERT rewrites and integration test coverage. No DDL or UDT struct change — the column was already declared. https://claude.ai/code/session_01JbAWPnNedoBwQL3usoPtS3
…ictedRooms map
Extends the user-room ES doc with a `restrictedRooms` map (rid → historySharedSince
millis) alongside the existing `rooms[]`, so search-service can enforce
restricted-room history windows directly from ES without a query-time
MongoDB lookup.
- `pkg/model.InboxMemberEvent` / `MemberAddEvent`: `HistorySharedSince`
changes from `int64` to `*int64` with `omitempty` to disambiguate
"unrestricted" (nil) from "restricted-since-timestamp". Publishers must
emit nil for unrestricted rooms — the Go↔painless sentinel treats any
`hss <= 0` as unrestricted.
- `search-sync-worker/user_room.go`: add-script routes by `params.hss`;
remove-script evicts from both `rooms[]` and `restrictedRooms{}`.
Template gains `restrictedRooms` as `flattened`.
- `search-sync-worker/spotlight.go`: MVP skip lifted from `!= 0` to
`!= nil` — spotlight still does not index restricted rooms.
- `room-worker`: publisher builds `*int64` from `req.Timestamp` only when
`History.Mode == None`.
- `inbox-worker`: handler checks `!= nil` before dereferencing.
- Tests: model round-trip covers nil/non-nil wire shape; publisher tests
assert pointer propagation and wire-omission; integration test updated
to expect restricted bulk lands in `restrictedRooms{}` instead of no-op.
Prerequisite for PR #114 (search-service). No behavior change for
unrestricted rooms.
https://claude.ai/code/session_018uJCyUSaHiPnmnyfUDeQUj
Summary
Adds three design specs for a new NATS request/reply
search-serviceand the surrounding work:2026-04-21-search-service-design.md— the new NATS request/reply search service.chat.user.{account}.request.search.messagesand…search.rooms.messages-*,*:messages-*) — messages only; spotlight + user-room are local.user-roomdoc on miss).pkg/natsrouter, flat service layout perCLAUDE.md.pkg/searchengine.Search/GetDoc,pkg/subjectbuilders,pkg/modelrequest/response types, newpkg/valkeyutilpackage.docker-local.2026-04-21-search-service-sync-worker-extension-design.md(prerequisite) — extendssearch-sync-workerso the user-room ES doc carries both unrestricted (rooms []string) and restricted (restrictedRooms map[rid]hss) memberships.pkg/model.InboxMemberEventandMemberAddEventHistorySharedSincefromint64→*int64withomitemptyto disambiguate "unrestricted" from "restricted-since-epoch-0".2026-04-21-chat-frontend-search-design.md— the React/Vite UI consumer.roomIds: [selectedRoom.id].nats.ws; newuseDebounceanduseSearchhooks; newsubjects.searchRooms/subjects.searchMessagesbuilders.Brainstorming context
Designed via the
superpowers:brainstormingskill across multiple iterations covering: schema gap analysis vs PR #109 indexes (collapsed to MVP-first), CCS approach (native ES wildcard alias vs client-side fan-out), restricted-room state location (ES doc vs Mongo at query time), Valkey caching, and frontend UX scope decomposition. Several MVP parity gaps are documented explicitly with post-MVP follow-ups (tshow, hidden, archived, prid, fname/sidebarname, ls sort, scope=app, push cache invalidation).Implementation order
The three specs are independent but have a clear dependency chain. Plans will be written and executed in this order:
restrictedRooms{}until the worker writes it).Test plan
https://claude.ai/code/session_01JbAWPnNedoBwQL3usoPtS3
Summary by CodeRabbit
Release Notes