@@ -60,7 +60,6 @@ pub struct FeedEntryDto {
|
||||
#[derive(Debug, Clone, Deserialize, utoipa::IntoParams)]
|
||||
#[into_params(parameter_in = Query)]
|
||||
pub struct ExportQueryParams {
|
||||
/// Output format: `csv` (default) or `json`
|
||||
#[serde(default = "default_export_format")]
|
||||
pub format: String,
|
||||
}
|
||||
|
||||
@@ -17,13 +17,9 @@ pub struct SessionStateResponse {
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
pub struct ApiFieldMapping {
|
||||
/// Column name in the source file
|
||||
pub source_column: String,
|
||||
/// Domain field: title | release_year | director | rating | watched_at | comment | external_metadata_id
|
||||
pub domain_field: String,
|
||||
/// For rating fields: multiply raw value by this factor (e.g. 0.5 for 10-point → 5-point scale)
|
||||
pub rating_scale: Option<f64>,
|
||||
/// For watched_at fields: strftime format hint (e.g. "%d/%m/%Y")
|
||||
pub date_format: Option<String>,
|
||||
}
|
||||
|
||||
@@ -34,15 +30,12 @@ pub struct ApplyMappingRequest {
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
pub struct ConfirmRequest {
|
||||
/// Indices (0-based) of rows from the mapping preview to import
|
||||
pub confirmed_indices: Vec<usize>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
pub struct SaveProfileRequest {
|
||||
/// Session UUID whose current field_mappings to save
|
||||
pub session_id: String,
|
||||
/// Human-readable profile name (e.g. "Letterboxd")
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
|
||||
57
crates/api-types/src/insights.rs
Normal file
57
crates/api-types/src/insights.rs
Normal file
@@ -0,0 +1,57 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// One conservative, baseline-relative statement about the user's viewing
|
||||
/// behavior. Tagged by `kind` so the SPA can switch on it; every variant
|
||||
/// carries `sample_count` so the UI can explain a thin sample.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
||||
#[serde(tag = "kind", rename_all = "snake_case")]
|
||||
pub enum InsightDto {
|
||||
/// `genre`'s average rating sits `delta` stars from the user's own
|
||||
/// average (first-time watches only).
|
||||
RatingLift {
|
||||
genre: String,
|
||||
genre_avg: f64,
|
||||
user_avg: f64,
|
||||
delta: f64,
|
||||
sample_count: u32,
|
||||
},
|
||||
/// `genre`'s share of watches in `month` (1–12) is `multiplier` times the
|
||||
/// user's own share of watches in that month.
|
||||
Seasonality {
|
||||
genre: String,
|
||||
month: u32,
|
||||
multiplier: f64,
|
||||
sample_count: u32,
|
||||
},
|
||||
/// `medium`'s weekend share of watches is `multiplier` times the user's
|
||||
/// overall weekend share.
|
||||
MediumTiming {
|
||||
medium: String,
|
||||
multiplier: f64,
|
||||
weekend_share: f64,
|
||||
baseline_share: f64,
|
||||
sample_count: u32,
|
||||
},
|
||||
/// Watching concentrates in a 3-hour window starting `peak_hour_start`
|
||||
/// (0–23) on `top_days` (Mon=1 … Sun=7).
|
||||
Rhythm {
|
||||
peak_hour_start: u32,
|
||||
peak_hour_end: u32,
|
||||
top_days: Vec<u32>,
|
||||
sample_count: u32,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
||||
pub struct InsightsResponse {
|
||||
pub insights: Vec<InsightDto>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, utoipa::IntoParams)]
|
||||
#[into_params(parameter_in = Query)]
|
||||
pub struct InsightsQueryParams {
|
||||
/// IANA time zone (e.g. `Europe/Warsaw`) months, weekdays and hours are
|
||||
/// bucketed in. Defaults to UTC.
|
||||
pub tz: Option<String>,
|
||||
}
|
||||
@@ -3,6 +3,7 @@ pub mod common;
|
||||
pub mod diary;
|
||||
pub mod goals;
|
||||
pub mod import;
|
||||
pub mod insights;
|
||||
pub mod movies;
|
||||
pub mod rendering;
|
||||
pub mod search;
|
||||
@@ -17,6 +18,7 @@ pub use common::*;
|
||||
pub use diary::*;
|
||||
pub use goals::*;
|
||||
pub use import::*;
|
||||
pub use insights::*;
|
||||
pub use movies::*;
|
||||
pub use rendering::*;
|
||||
pub use social::*;
|
||||
|
||||
@@ -10,11 +10,8 @@ use crate::common::SocialFeedResponse;
|
||||
pub struct MoviesQueryParams {
|
||||
pub limit: Option<u32>,
|
||||
pub offset: Option<u32>,
|
||||
/// Optional title filter (case-insensitive substring match)
|
||||
pub search: Option<String>,
|
||||
/// Filter by genre name (case-insensitive)
|
||||
pub genre: Option<String>,
|
||||
/// Filter by ISO language code (e.g. "en")
|
||||
pub language: Option<String>,
|
||||
}
|
||||
|
||||
|
||||
@@ -6,21 +6,13 @@ pub use crate::common::{PaginatedMovieHits, PaginatedPersonHits};
|
||||
|
||||
#[derive(Debug, Deserialize, IntoParams)]
|
||||
pub struct SearchQueryParams {
|
||||
/// Free-text query matched across title, cast, crew, genres and keywords.
|
||||
pub q: Option<String>,
|
||||
/// Filter by genre name (exact match, case-sensitive).
|
||||
pub genre: Option<String>,
|
||||
/// Filter by release year.
|
||||
pub year: Option<u16>,
|
||||
/// Filter by person ID (UUID).
|
||||
pub person_id: Option<Uuid>,
|
||||
/// Filter crew results by department (e.g. "Directing", "Writing").
|
||||
pub department: Option<String>,
|
||||
/// Filter by original language code (e.g. "en", "fr").
|
||||
pub language: Option<String>,
|
||||
/// Max results to return (default 20).
|
||||
pub limit: Option<u32>,
|
||||
/// Offset for pagination (default 0).
|
||||
pub offset: Option<u32>,
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ pub struct RemoteActorDto {
|
||||
pub handle: String,
|
||||
pub display_name: Option<String>,
|
||||
pub url: String,
|
||||
/// `Some` for local actors, so the SPA can link internally to `/users/{id}`.
|
||||
pub user_id: Option<Uuid>,
|
||||
pub avatar_url: Option<String>,
|
||||
}
|
||||
@@ -79,12 +78,11 @@ pub struct PendingCountResponse {
|
||||
pub count: usize,
|
||||
}
|
||||
|
||||
//todo: move out to separate file
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// Task 7's SPA zod schema parses these exact lowercase literals —
|
||||
/// a casing or naming drift here breaks the SPA at runtime.
|
||||
#[test]
|
||||
fn follow_state_dto_serializes_to_lowercase_strings() {
|
||||
assert_eq!(
|
||||
|
||||
@@ -23,7 +23,6 @@ pub struct UsersResponse {
|
||||
#[derive(Debug, Clone, Deserialize, utoipa::IntoParams)]
|
||||
#[into_params(parameter_in = Query)]
|
||||
pub struct UserProfileQueryParams {
|
||||
/// One of: `recent` (default), `ratings`, `history`, `trends`
|
||||
pub view: Option<String>,
|
||||
pub limit: Option<u32>,
|
||||
pub offset: Option<u32>,
|
||||
|
||||
Reference in New Issue
Block a user