- Guard total_count with `if not csv` ternary to avoid unnecessary
COUNT query on CSV export paths (10 files)
- Consolidate rewards.py from 3 COUNT queries to 1 (used for both
empty-check and response)
- Clean up scout_claims.py double `if limit is not None` block
- Normalize scout_opportunities.py from max(1,...) to max(0,...)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ensures the `count` field in JSON responses reflects total matching
records rather than the page size, consistent with the notifications
endpoint pattern from PR #150.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace 71 broad `except Exception` blocks in 19 router files with the
specific `peewee.DoesNotExist` exception. GET endpoints that call
`Model.get_by_id()` now only catch the expected DoesNotExist error,
allowing real DB failures (connection errors, etc.) to propagate as
500s rather than being masked as 404s.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace all logging.warning(f'Bad Token: {token}') calls with
logging.warning('Bad Token: [REDACTED]') across 30 router files.
Full bearer tokens were being written to log files on auth failures.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Moved logging.basicConfig() to app/main.py as the single source of truth.
Removed duplicate (no-op) calls from app/db_engine.py, app/dependencies.py,
and all 30 router files in app/routers_v2/. Removed the now-unused LOG_DATA
dict and date/log_level locals from dependencies.py and db_engine.py.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add db_session_middleware to main.py that opens the connection at the
start of each request and closes it in a try/finally block, ensuring
connections are always returned even on uncaught exceptions.
Remove all individual db.close() calls from 30 router files in
app/routers_v2/ — the middleware now handles all code paths.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add explicit ORDER BY id to all queries for consistent results across SQLite and PostgreSQL
- PostgreSQL does not guarantee row order without ORDER BY, unlike SQLite
- Skip table creation when DATABASE_TYPE=postgresql (production tables already exist)
- Fix datetime handling in notifications (PostgreSQL native datetime vs SQLite timestamp)
- Fix grouped query count() calls that don't work in PostgreSQL
- Update .gitignore to include storage/templates/ directory
This completes the PostgreSQL migration compatibility layer while maintaining
backwards compatibility with SQLite for local development.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Fix batstats.py and pitstats.py POST handlers to convert timestamps
- Fix Pydantic model defaults from *100000 to *1000 (wrong multiplier)
Found during second-pass audit.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Convert milliseconds to datetime for created filter in batstats.py
and pitstats.py GET endpoints.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>