feat: v2 rewrite — hexagonal arch, ActivityPub federation, NATS, deployment-ready (#1)
Some checks failed
lint / lint (push) Has been cancelled
test / unit (push) Has been cancelled
test / integration (push) Has been cancelled

This commit was merged in pull request #1.
This commit is contained in:
2026-05-16 09:42:40 +00:00
parent 071809bc3f
commit 9aee4ceb6d
224 changed files with 35418 additions and 1469 deletions

View File

@@ -0,0 +1,10 @@
[package]
name = "api-types"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = { workspace = true }
uuid = { workspace = true }
chrono = { workspace = true }
utoipa = { version = "5.5.0", features = ["uuid", "chrono"] }

View File

@@ -0,0 +1,2 @@
pub mod requests;
pub mod responses;

View File

@@ -0,0 +1,92 @@
use serde::Deserialize;
use uuid::Uuid;
pub const DEFAULT_PAGE: u64 = 1;
pub const DEFAULT_PER_PAGE: u64 = 20;
pub const MAX_PER_PAGE: u64 = 100;
#[derive(Deserialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct RegisterRequest {
/// Username (1-32 chars, alphanumeric + underscore)
pub username: String,
pub email: String,
pub password: String,
}
#[derive(Deserialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct LoginRequest {
pub email: String,
pub password: String,
}
#[derive(Deserialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct CreateThoughtRequest {
/// Up to 128 characters
pub content: String,
pub in_reply_to_id: Option<Uuid>,
/// One of: "public", "followers", "unlisted", "direct"
pub visibility: Option<String>,
pub content_warning: Option<String>,
pub sensitive: Option<bool>,
}
#[derive(Deserialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct EditThoughtRequest {
pub content: String,
}
#[derive(Deserialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct UpdateProfileRequest {
pub display_name: Option<String>,
pub bio: Option<String>,
pub avatar_url: Option<String>,
pub header_url: Option<String>,
pub custom_css: Option<String>,
}
#[derive(Deserialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct SetTopFriendsRequest {
/// Ordered list of user UUIDs, max 8
pub friend_ids: Vec<Uuid>,
}
#[derive(Deserialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct CreateApiKeyRequest {
pub name: String,
}
#[derive(Deserialize, utoipa::IntoParams)]
pub struct PaginationQuery {
pub page: Option<u64>,
pub per_page: Option<u64>,
}
impl PaginationQuery {
pub fn page(&self) -> u64 {
self.page.unwrap_or(DEFAULT_PAGE).max(DEFAULT_PAGE)
}
pub fn per_page(&self) -> u64 {
self.per_page.unwrap_or(DEFAULT_PER_PAGE).min(MAX_PER_PAGE)
}
}
#[derive(Deserialize, utoipa::IntoParams)]
pub struct SearchQuery {
pub q: String,
pub page: Option<u64>,
pub per_page: Option<u64>,
}
#[derive(serde::Deserialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct NotificationUpdateRequest {
pub read: bool,
}

View File

@@ -0,0 +1,137 @@
use chrono::{DateTime, Utc};
use serde::Serialize;
use uuid::Uuid;
#[derive(Serialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct AuthResponse {
pub token: String,
pub user: UserResponse,
}
#[derive(Serialize, Clone, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct UserResponse {
pub id: Uuid,
pub username: String,
pub display_name: Option<String>,
pub bio: Option<String>,
pub avatar_url: Option<String>,
pub header_url: Option<String>,
pub custom_css: Option<String>,
pub local: bool,
pub is_followed_by_viewer: bool,
#[serde(rename = "joinedAt")]
pub created_at: DateTime<Utc>,
}
#[derive(Serialize, Clone, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ThoughtResponse {
pub id: Uuid,
pub content: String,
pub author: UserResponse,
#[serde(rename = "replyToId")]
pub in_reply_to_id: Option<Uuid>,
#[serde(rename = "replyToUrl", skip_serializing_if = "Option::is_none")]
pub in_reply_to_url: Option<String>,
pub visibility: String,
pub content_warning: Option<String>,
pub sensitive: bool,
pub like_count: i64,
pub boost_count: i64,
pub reply_count: i64,
pub liked_by_viewer: bool,
pub boosted_by_viewer: bool,
pub created_at: DateTime<Utc>,
pub updated_at: Option<DateTime<Utc>>,
}
#[derive(Serialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct PagedResponse<T: Serialize + utoipa::ToSchema> {
pub items: Vec<T>,
pub total: i64,
pub page: u64,
pub per_page: u64,
}
#[derive(Serialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ApiKeyResponse {
pub id: Uuid,
pub name: String,
pub created_at: DateTime<Utc>,
}
#[derive(Serialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct NotificationResponse {
pub id: Uuid,
pub notification_type: String,
pub from_user: Option<UserResponse>,
pub thought_id: Option<Uuid>,
pub read: bool,
pub created_at: DateTime<Utc>,
}
#[derive(Serialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct TopFriendsResponse {
pub top_friends: Vec<UserResponse>,
}
#[derive(Serialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ErrorResponse {
pub error: String,
}
#[derive(Serialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct CreatedApiKeyResponse {
pub id: Uuid,
pub name: String,
/// Raw API key — shown only once at creation
pub key: String,
}
#[derive(Serialize, Clone, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ProfileField {
pub name: String,
pub value: String,
}
#[derive(Serialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct RemoteActorResponse {
pub handle: String,
pub display_name: Option<String>,
pub avatar_url: Option<String>,
pub url: String,
pub bio: Option<String>,
pub banner_url: Option<String>,
pub also_known_as: Option<String>,
pub outbox_url: Option<String>,
pub followers_url: Option<String>,
pub following_url: Option<String>,
pub attachment: Vec<ProfileField>,
}
#[derive(Serialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ActorConnectionResponse {
pub handle: String,
pub display_name: Option<String>,
pub avatar_url: Option<String>,
pub url: String,
}
#[derive(Serialize, utoipa::ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ActorConnectionPageResponse {
pub items: Vec<ActorConnectionResponse>,
pub page: u32,
pub has_more: bool,
}