- Gateway, Trips, Fitness Dockerfiles: run as non-root (appuser)
- Added HEALTHCHECK to gateway, trips, fitness
- Used --chown=appuser on COPY for correct file permissions
- Created data dirs with proper ownership before USER switch
- Trips Dockerfile no longer copies whole context (only server.py)
Partial fix for #10 — Node services (inventory, budget, frontend) not yet hardened.
- Switch HTTPServer to ThreadingHTTPServer (concurrent request handling)
- Replace SHA-256 password hashing with bcrypt (auth.py, database.py)
- Add bcrypt to Dockerfile
- Move qBittorrent env vars to config.py
- Move _booklore_token state out of config into booklore.py
- Remove dead fitness_token variable in command.py
- Fix OpenAI call to use default SSL context instead of no-verify ctx
- Log swallowed budget fetch error in dashboard.py