QDG Knowledge Base Read-only viewer QWebHub
user-guide

User Guide

Version 1 · New setup/operating guide derived from CLAUDE.md, README.md, and repository scripts

User Guide

Audience

Anyone setting up, running, or operating this API for the first time — locally for development, or as a standing Windows service.

Prerequisites

  • Python 3.x with pip
  • Network access to a MySQL/MariaDB instance holding race, run, courses (and, if you want to persist stats, write access to a target DB for meeting_stats_payloads)
  • Real DB credentials — ask Thilina or Ryan; never put real credentials in config.example.json (see overview → Security notes)

First-time setup

  1. Install dependencies:
    pip install -r requirements.txt
    
    (or, per CLAUDE.md: pip install fastapi uvicorn pymysql pydantic python-multipart)
  2. Copy the config template and fill in real values:
    copy config.example.json config.json
    
    Edit database.host/port/user/password/source_db/target_db. Leave external_api.enabled as false unless you're specifically testing the external-API bypass path (see architecture).
  3. Verify DB connectivity:
    python test_db_connection.py
    

Running for development

uvicorn trainer_stats_api:app --host 0.0.0.0 --port 8006 --reload

or

python trainer_stats_api.py

Then check:

  • http://127.0.0.1:8006/health → {"status": "ok"}
  • http://127.0.0.1:8006/ → dashboard UI
  • http://127.0.0.1:8006/docs → Swagger UI
  • http://127.0.0.1:8006/api-docs → hand-written reference with "Try it" buttons
  • http://127.0.0.1:8006/api-test → manual API tester

Using the dashboard

/ serves a searchable trainer/jockey grid with filters (search, sort, min starts, min win %, last-win filter) and a detail panel. It calls the API using the shared static token (tds-stats-secure-token-2026) client-side. Without a live DB, regenerate_sample.py can regenerate trainers_complete.json — sample data for exercising the UI without a database.

Calling the API directly

See api-reference for the full endpoint list and request/response shapes. Quick smoke test:

curl "http://127.0.0.1:8006/trainerStats?date=2026-06-03&courseId=116" \
  -H "Authorization: Bearer tds-stats-secure-token-2026"

Running as a persistent Windows service

.\.venv\Scripts\python.exe run_service.py
# or: .\run_service.bat

Install/uninstall (run as Administrator):

install_service.bat
uninstall_service.bat

Testing

Script Purpose
test_db_connection.py Verifies DB connectivity using config.json
test_api.py Exercises API endpoints
quick_test.py Basic smoke test
regenerate_sample.py Regenerates trainers_complete.json sample data for local UI testing without a DB

Troubleshooting

  • RuntimeError: Config file not found: config.json — you haven't copied config.example.json → config.json yet (or DB_CONFIG_PATH points somewhere wrong).
  • 401 on any endpoint except /, /health, /login — missing or wrong token; supply Authorization: Bearer tds-stats-secure-token-2026, ?token=..., or ?sso_token=....
  • Empty trainer/jockey list from /trainer-stats with courseName set (no courseId) — see the known SQL quirk in database before assuming there's no data for that date.
  • /saved-stats always returns {"status": "not_found"} — either nothing has been saved for that date/course yet, or the target DB's meeting_stats_payloads table doesn't exist yet (both cases look identical to the caller — see database).
  • Server logs — logger is configured at INFO level to stdout; server_error.log in the repo root holds a historical error log from a prior run.

Verification checklist after a config or code change

  1. python test_db_connection.py succeeds.
  2. GET /health returns {"status": "ok"}.
  3. A real GET /trainerStats?date=...&courseId=... call (with a date/course known to have race data) returns a non-empty trainers array.
  4. If you changed persistence: POST /save-stats followed by a matching GET /saved-stats returns the same payload back.
Updated by Claude on Aug. 12, 2026, 9:50 a.m. · Task: updatewiki create project documentation