---
estimated_steps: 28
estimated_files: 1
skills_used: []
---

# T02: Deploy to ub01, run migration, and verify end-to-end

Push code to ub01, rebuild containers, run the Alembic migration, and verify the full flow with real HTTP requests.

## Steps

1. Commit changes locally and push to origin (the repo is at `/vmPool/r/repos/xpltdco/chrysopedia` on ub01):
   - `git add backend/models.py backend/schemas.py backend/routers/search.py alembic/versions/013_add_search_log.py`
   - `git commit -m 'feat: search query logging + popular searches endpoint (M015/S01)'`
   - `git push origin main`

2. SSH to ub01 and deploy:
   - `ssh ub01 'cd /vmPool/r/repos/xpltdco/chrysopedia && git pull && docker compose build chrysopedia-api chrysopedia-worker && docker compose up -d'`
   - Wait for containers to be healthy

3. Run Alembic migration:
   - `ssh ub01 'docker exec chrysopedia-api alembic upgrade head'`
   - Verify migration applied: `ssh ub01 "docker exec chrysopedia-db psql -U chrysopedia -c '\d search_log'"`

4. Restart web container (KNOWLEDGE: nginx stale DNS after rebuild):
   - `ssh ub01 'docker compose restart chrysopedia-web-8096'`

5. Verify search logging:
   - `curl -s 'http://ub01:8096/api/v1/search?q=reverb&scope=all'` — should return search results
   - `ssh ub01 "docker exec chrysopedia-db psql -U chrysopedia -c \"SELECT * FROM search_log ORDER BY created_at DESC LIMIT 5;\""` — should show the logged query

6. Verify popular endpoint:
   - `curl -s 'http://ub01:8096/api/v1/search/popular' | python3 -m json.tool` — should return JSON with items array
   - Run a few more searches with different terms, wait, then re-check popular (cache TTL is 5 min, so first call goes to DB)

## Must-Haves

- [ ] search_log table exists in PostgreSQL on ub01
- [ ] Real search request creates a row in search_log
- [ ] GET /api/v1/search/popular returns valid JSON with items array
- [ ] Empty search query does NOT create a search_log row

## Verification

- `curl -sf 'http://ub01:8096/api/v1/search/popular' | python3 -c "import sys,json; d=json.load(sys.stdin); assert 'items' in d; print('OK')"` succeeds
- `ssh ub01 "docker exec chrysopedia-db psql -U chrysopedia -t -c 'SELECT count(*) FROM search_log;'"` returns > 0 after a search

## Inputs

- ``backend/models.py` — SearchLog model from T01`
- ``backend/schemas.py` — PopularSearchesResponse from T01`
- ``backend/routers/search.py` — logging hook and /popular endpoint from T01`
- ``alembic/versions/013_add_search_log.py` — migration from T01`

## Expected Output

- ``alembic/versions/013_add_search_log.py` — migration applied on ub01 (no file change, operational state)`

## Verification

curl -sf 'http://ub01:8096/api/v1/search/popular' | python3 -c "import sys,json; d=json.load(sys.stdin); assert 'items' in d; print('POPULAR OK')" && ssh ub01 "docker exec chrysopedia-db psql -U chrysopedia -t -c 'SELECT count(*) FROM search_log;'" | grep -q '[1-9]' && echo 'LOGGING OK'
