Nobody has started this yet — be first.
Business impact
Search is the primary way a user with more than a handful of notes finds anything again. Right now, GET /notes?q=... only returns a note if the search term happens to appear in both the title and the content -- which real notes almost never satisfy (a title is a short label; content is the actual text). In practice this means search returns far fewer results than it should, or none at all, for completely reasonable queries. To a user this looks like their notes vanished. This is the kind of regression that generates "where did my note go?!" support tickets and makes people stop trusting the search box -- high priority even though the fix is small.
Problem
The README and the endpoint's own docstring both state that q matches (case-insensitively) against title or content substrings. The current query building does not implement "or" -- it applies two separate LIKE conditions to the same .filter() call, which SQLAlchemy (like plain SQL WHERE a AND b) combines with AND.
Current behavior
GET /notes?q=<term> returns [] for notes that only match in one field -- e.g. two notes each containing "paris" in exactly one of title/content return zero results, even though both should match.
Expected behavior
GET /notes?q=<term> returns every note where <term> appears in the title or the content (case-insensitively), matching the documented and previously-tested behavior.
Steps to reproduce
cd fastapi/notes_api
source .venv/bin/activate
uvicorn app.main:app --reload &
curl -s -X POST http://127.0.0.1:8000/notes -H "Content-Type: application/json"
-d '{"title":"Paris trip","content":"pack sunscreen and passport"}'
curl -s -X POST http://127.0.0.1:8000/notes -H "Content-Type: application/json"
-d '{"title":"Weekend errands","content":"pick up dry cleaning near Paris Ave"}'
curl -s "http://127.0.0.1:8000/notes?q=paris"
Why this matters
This is a list_notes query-construction bug, and it also happens to be already covered by two pre-existing tests in tests/test_notes.py (test_search_by_q_matches_title_and_content_case_insensitively and test_filter_by_tag_and_q_are_combinable), which currently fail because of it -- a good example of how the main suite is expected to catch some of these injected bugs on its own.
Suggested approach
Look at how query.filter(...) is called for the q branch in app/crud.py::list_notes, versus how a single .filter() call combines multiple positional conditions by default. SQLAlchemy has an explicit construct for "at least one of these conditions" -- it's already imported and used elsewhere in this project for exactly this kind of OR condition.
Acceptance criteria
Verification
.venv/bin/pytest practicetickets/test_ticket02_search_operator_flip.py -v && .venv/bin/pytest tests/test_notes.py -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/search-operator-flipFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/search-operator-flipSubmit 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 in./data/notes.dbOr run it via Docker instead:
cd fastapi/notes_api
docker compose up --build # API on http://127.0.0.1:8000, /docs included
SQLite data is written inside the container to /app/data/notes.db, backed by the notes-data named volume declared in docker-compose.yml -- it survives docker compose restart and re-running docker compose up after down (without -v).
Work the tickets in practicetickets/ (ticket01 through ticket07); each names one pytest file in the same directory, separate from the project's own tests/ suite:
.venv/bin/pytest practicetickets/test_ticket01_tag_length_boundary.py -v # a single ticket
./practicetickets/run_tickets.sh # all 7, pass/fail summary
./practicetickets/run_tickets.sh -v # summary + full output
Note: ticket 02's bug also breaks two pre-existing tests in tests/test_notes.py (test_search_by_q_matches_title_and_content_case_insensitively and test_filter_by_tag_and_q_are_combinable) -- that's expected, and fixing ticket 02 should bring tests/ back to fully green. Run the main suite with .venv/bin/pytest tests/ -v.
Level 1
Fix a bug
Read existing behaviour, correct it.