feat(prefs): user_ai_prefs surface — GET/PUT /prefs, GET /timezones (#126)
- GET /prefs (JWT): current row or empty {voice, library, display_tz,
updated_at} shape — snake_case, 200 with nulls when no row
- PUT /prefs (JWT): three-state partial update (omitted=unchanged,
explicit null=clear, value=set) via hand-rolled TriState deserializer —
serde derive conflates omitted with explicit null on Option<Option<T>>
- display_tz validated against chrono-tz before any write; invalid → 400,
nothing written. tz_offset_minutes (frozen legacy) preserved verbatim
- GET /timezones (public): chrono_tz::TZ_VARIANTS — exactly the domain
Tz::from_str accepts, so picker list and validation can't drift
- No migration; existing columns only. capture_prefs (POST /reels) untouched
- 14 tests: 3 GET /prefs, 7 PUT /prefs (incl. auth-gate), 2 /timezones,
2 pure merge_patch. Full suite 1436 passed / 0 failed
This commit is contained in:
1 parent
7f348022d4
commit
2258a0eab5
3 files changed
+732
No files matched your search
@@ -68,6 +68,7 @@ mod knowledge;
|
||||
mod memories;
|
||||
mod otel;
|
||||
mod personas;
|
||||
mod prefs;
|
||||
mod reels;
|
||||
mod service;
|
||||
#[cfg(test)]
|
||||
@@ -374,6 +375,12 @@ fn main() -> std::io::Result<()> {
|
||||
.service(reels::reel_video_handler)
|
||||
.service(reels::precomputed_reel_handler)
|
||||
.service(reels::precomputed_video_handler)
|
||||
.service(
|
||||
web::resource("/prefs")
|
||||
.route(web::get().to(prefs::get_prefs))
|
||||
.route(web::put().to(prefs::put_prefs)),
|
||||
)
|
||||
.service(web::resource("/timezones").route(web::get().to(prefs::list_timezones)))
|
||||
.service(ai::generate_insight_handler)
|
||||
.service(ai::generate_agentic_insight_handler)
|
||||
.service(ai::generation_status_handler)
|
||||
|
||||
Reference in new issue
Block a user