Commit Graph

7 Commits

Author SHA1 Message Date
bvandeusen 8647f9ebe0 feat(api): radio uses similarity pool with exclude param + M3 fallback
Wire LoadCandidatesFromSimilarity as the primary candidate loader with
an ?exclude= query param for comma-separated UUID filtering; fall back
to LoadCandidates on error. Thread SimilarityWeight into ScoringWeights
and update testHandlers recCfg accordingly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 08:47:31 -04:00
bvandeusen 284271c190 feat(api): radio handler reads current session vector + threads ContextWeight
Wire contextual scoring end-to-end: add ContextWeight to RecommendationConfig
(struct + Default()), fetch the user's current session vector in handleRadio
via loadCurrentSessionVector (cold-start returns Seed sentinel), and pass it
as the 6th arg to LoadCandidates so ContextualMatchScore flows into Shuffle.
2026-04-27 20:55:25 -04:00
bvandeusen 08591debee feat(api): rewrite /api/radio with weighted shuffle v1
Validates seed_track + optional limit (default cfg.Recommendation.RadioSize,
clamped to RadioSizeMax). Calls recommendation.LoadCandidates +
recommendation.Shuffle. Prepends seed to result. Server seeds a
math/rand source at startup; handlers package threads that as a
func() float64 so tests inject deterministic RNGs.

Mount + server.New gain a RecommendationConfig parameter.
2026-04-27 08:08:10 -04:00
bvandeusen f4e73b81b4 feat(api): add POST /api/events handler
Discriminated-union JSON over three event types: play_started,
play_ended, play_skipped. Auth via existing RequireUser. play_started
returns play_event_id + session_id; the other two return { ok: true }.
Validates ownership: play_ended/play_skipped on another user's row
returns 403. Mount signature now takes EventsConfig and constructs
the playevents.Writer; server.New propagates it through.
2026-04-26 00:12:06 -04:00
bvandeusen 1e5c8b5ab7 fix(api): trim whitespace from bearer token in logout
sessionTokenFromHTTP now matches extractBearerToken's trimming
behavior. Without this, a bearer header with trailing whitespace
(e.g. a buggy client or proxy) authenticates via RequireUser but
hashes the padded value on logout, silently no-oping and leaving
the server-side session alive.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 22:32:12 -04:00
bvandeusen 8537821d29 feat(api): POST /api/auth/logout
Deletes the session row keyed by the cookie/bearer token and
clears the cookie on the client. Best-effort DB delete — logout
still succeeds for the client if the row's already gone.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 22:07:16 -04:00
bvandeusen 2f2dfa86df feat(api): POST /api/auth/login
Verifies bcrypt password hash, mints a session token, stores its
sha256 in the sessions table, and returns the token in both the
response body (for Flutter) and an httpOnly/SameSite=Strict
cookie (for the web SPA).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 21:25:52 -04:00