feat: JWT auth, /api prefix, SPA serving, OpenAPI, lean main.rs

- auth: register/login/refresh/logout w/ JWT+Argon2, protected mutations
- domain: User, RefreshSession, auth ports, Unauthorized/Forbidden errors
- presentation: context/state/factory/errors/extractors/openapi modules
- routes behind /api, SPA served from root w/ fallback
- OpenAPI Scalar at /docs
- frontend ssr:false, single-binary Dockerfile
This commit is contained in:
2026-07-11 21:28:52 +02:00
parent 13031347cc
commit 7bd27d9b9c
50 changed files with 1604 additions and 213 deletions

View File

@@ -5,3 +5,4 @@ edition = "2024"
[dependencies]
serde = { workspace = true }
utoipa = { version = "5", features = ["axum_extras"] }

View File

@@ -1,31 +1,70 @@
use serde::{Deserialize, Serialize};
use utoipa::{IntoParams, ToSchema};
#[derive(Deserialize)]
#[derive(Deserialize, ToSchema)]
pub struct ParseRequest {
pub source: Option<String>,
pub html: Option<String>,
}
#[derive(Serialize)]
#[derive(Serialize, ToSchema)]
pub struct ErrorResponse {
pub error: String,
}
#[derive(Deserialize)]
#[derive(Deserialize, ToSchema, IntoParams)]
pub struct ListQuery {
pub q: Option<String>,
pub sort: Option<String>,
pub order: Option<String>,
}
#[derive(Deserialize)]
#[derive(Deserialize, ToSchema)]
pub struct UpdateSongRequest {
pub title: Option<String>,
pub artist: Option<String>,
pub original_key: Option<String>,
}
#[derive(Deserialize)]
#[derive(Deserialize, ToSchema, IntoParams)]
pub struct GetSongQuery {
pub apply_capo: Option<bool>,
}
#[derive(Deserialize, ToSchema)]
pub struct LoginRequest {
pub email: String,
pub password: String,
}
#[derive(Serialize, ToSchema)]
pub struct LoginResponse {
pub token: String,
pub refresh_token: String,
pub user_id: String,
pub expires_at: String,
}
#[derive(Deserialize, ToSchema)]
pub struct RegisterRequest {
pub email: String,
pub username: String,
pub password: String,
}
#[derive(Deserialize, ToSchema)]
pub struct RefreshRequest {
pub refresh_token: String,
}
#[derive(Serialize, ToSchema)]
pub struct RefreshResponse {
pub token: String,
pub refresh_token: String,
pub expires_at: String,
}
#[derive(Deserialize, ToSchema)]
pub struct LogoutRequest {
pub refresh_token: String,
}