Skip to content

feat(search): add notes/comment text search filter - #239

Merged
patrickrb merged 1 commit into
mainfrom
optio/task-3c899f18-0155-428a-8812-3cc3573992af
Jul 24, 2026
Merged

feat(search): add notes/comment text search filter#239
patrickrb merged 1 commit into
mainfrom
optio/task-3c899f18-0155-428a-8812-3cc3573992af

Conversation

@patrickrb

Copy link
Copy Markdown
Owner

Problem

The contact search lets operators filter by callsign, name, QTH, grid, band, mode, date range, DXCC entity, and QSL status — but not by the notes/comment text on a QSO. That's where operators record the things they most often want to find a contact by later: POTA/SOTA park references (K-1234, W7A/...), contest exchanges, special-event details, and personal reminders. Without notes search, finding "that POTA activation from last month" means paging through results by hand.

Solution

Adds a notes filter, wired end-to-end and matching the existing text-field behavior (case-insensitive LIKE '%value%' contains match):

  • src/lib/contact-search.ts — new notes? field on ContactSearchFilters and a case 'notes' in the WHERE-clause builder. The predicate binds through the same bind() helper, so placeholder numbering stays in lockstep with the params array (the invariant the existing tests guard).
  • src/app/api/contacts/search/route.ts — reads the notes query param and passes it to the builder.
  • src/app/search/page.tsx — a Notes input in the Advanced Filters section, plus the matching SearchFilters field, initial/clear-all defaults, and an active-filter chip. Chip removal already routes through the default ('') case, so no handler change was needed.

The filter participates in the existing debounced search and in ADIF export of search results (both build their query string from the same filter object), so exporting a notes-filtered result set works automatically.

Testing

  • tests/contact-search.spec.ts — added a focused test asserting notes produces UPPER(notes) LIKE UPPER($2) with ['%POTA K-1234%'], and extended the full-filter-set test to include notes and verify placeholder/param alignment stays correct with the extra bound value. All 14 builder tests pass.
  • npm run typecheck — clean
  • npm run lint — clean
  • npm run build — compiles successfully

Backwards compatibility

Purely additive. The notes param is optional; existing searches, saved links, and the /api/contacts/search contract are unchanged when it's absent.

Future follow-up

  • The search query params (gridLocator, startDate, notes, …) remain camelCase, consistent with the existing surface that CLAUDE.md flags for a later snake_case sweep. This PR intentionally matches the current convention rather than expanding that drift.

🤖 Generated with Claude Code

Operators routinely record POTA/SOTA park references, contest exchanges,
and personal remarks in a contact's notes field, but there was no way to
search them — you could find a QSO by callsign, name, QTH, grid, band,
mode, date, DXCC, or QSL status, but not by what you actually wrote down.

Adds a `notes` filter that does the same case-insensitive contains match
as the other text fields, wired end-to-end: the WHERE-clause builder, the
GET /api/contacts/search route, and the search page (input in Advanced
Filters, active-filter chip, clear-all reset).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nodelog Ready Ready Preview, Comment Jul 24, 2026 5:07am

Request Review

@patrickrb
patrickrb merged commit 3bf9ede into main Jul 24, 2026
5 checks passed
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