Nobody has started this yet — be first.
Business impact
Combining a tag filter with a search query (e.g. "my go-tagged bookmarks about concurrency") returns a flood of irrelevant results -- anything tagged go or merely matching the query -- instead of the narrow intersection the user asked for. Filtering is the core value of a bookmark manager once someone has more than a couple dozen links; a filter that gets less precise the more criteria you add teaches users not to trust it.
Problem
Store.List joins the active filter clauses together before appending them to the query. When both tag and q are given, the join currently produces OR semantics -- everything matching either condition -- instead of requiring both to match the same row.
Current behavior
GET /bookmarks?tag=go&q=concurrency returns bookmarks that only match one of the two filters, not just the ones matching both.
Expected behavior
tag and q, when both present, combine with AND: only bookmarks matching both conditions come back. Each filter alone (tag-only or query-only) is unaffected.
Steps to reproduce
Seed: "Go Concurrency Patterns" (tags go, programming), "Python Concurrency Patterns" (tags python, programming), "Go Testing Guide" (tags go, testing), "Unrelated Recipe" (tags cooking). curl -s "http://localhost:8081/bookmarks?tag=go&q=concurrency"
Why this matters
The project's own design intentionally builds the WHERE-clause list and the parameter-args slice "in lockstep" -- the single line combining the per-filter clauses with a boolean operator is exactly where a naive implementation goes wrong, without any type error to catch it. Parameterization itself is untouched and still correct.
Suggested approach
Look at the line in Store.List where clauses gets joined into the final WHERE text, and think about what "matches the tag AND matches the query" means as a boolean combination.
Acceptance criteria
Verification
go test ./practicetickets/... -run TestTicket02 -v
Hints (0/2)
Try it without hints first — the reading is the exercise.
Working on this ticket
Work on a branch named for the ticket — that's what you'll submit.
Branch off your fork
$git checkout -b fix/filter-combines-with-orFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/filter-combines-with-orSubmit it below
Paste your fork URL and the branch name, with a short write-up of the root cause.
Questions
Ask about anything unclear in the ticket — the maintainer and anyone who has solved it can answer. Please don't post full solutions.
Sign in to ask a question or reply.
Sign inmigrations/0001_init.sqlcurl http://localhost:8081/healthz
# {"status":"ok"}
To run without Docker, point the DB_* env vars from .env.example at a reachable Postgres and run go run ./cmd/server -- it applies the same migrations on startup.
The project's own test suite (go test ./...) is an integration suite against a real Postgres; it looks for one via BM_TEST_DB_HOST/BM_TEST_DB_PORT/BM_TEST_DB_USER/BM_TEST_DB_PASSWORD/BM_TEST_DB_NAME (defaults point at localhost:15433, database bookmarks_test) and skips cleanly rather than failing if that database is unreachable:
docker run -d --name bm_test_pg -e POSTGRES_PASSWORD=postgres \
-e POSTGRES_DB=bookmarks_test -p 15433:5432 postgres:16-alpine
Work the tickets in PRACTICE_TICKETS.md (TICKET-01 through TICKET-10, all in one file, ordered easy -> hard); each names one Go test under practicetickets/:
go test ./practicetickets/... -run TestTicket01 -v # a single ticket
./practice_tickets_run.sh # all 10, clean pass/fail summary table
Level 1
Fix a bug
Read existing behaviour, correct it.