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,16 @@
use api_types::{
requests::CreateApiKeyRequest,
responses::{ApiKeyResponse, CreatedApiKeyResponse},
};
use utoipa::OpenApi;
#[derive(OpenApi)]
#[openapi(
paths(
crate::handlers::api_keys::get_api_keys,
crate::handlers::api_keys::post_api_key,
crate::handlers::api_keys::delete_api_key_handler,
),
components(schemas(CreateApiKeyRequest, ApiKeyResponse, CreatedApiKeyResponse))
)]
pub struct ApiKeysDoc;

View File

@@ -0,0 +1,15 @@
use api_types::{
requests::{LoginRequest, RegisterRequest},
responses::{AuthResponse, ErrorResponse},
};
use utoipa::OpenApi;
#[derive(OpenApi)]
#[openapi(
paths(
crate::handlers::auth::post_register,
crate::handlers::auth::post_login
),
components(schemas(RegisterRequest, LoginRequest, AuthResponse, ErrorResponse))
)]
pub struct AuthDoc;

View File

@@ -0,0 +1,11 @@
use utoipa::OpenApi;
#[derive(OpenApi)]
#[openapi(paths(
crate::handlers::feed::home_feed,
crate::handlers::feed::public_feed,
crate::handlers::feed::search_handler,
crate::handlers::feed::user_thoughts_handler,
crate::handlers::feed::tag_thoughts_handler,
))]
pub struct FeedDoc;

View File

@@ -0,0 +1,5 @@
use utoipa::OpenApi;
#[derive(OpenApi)]
#[openapi(paths(crate::handlers::health::health_handler))]
pub struct HealthDoc;

View File

@@ -0,0 +1,61 @@
mod api_keys;
mod auth;
mod feed;
mod health;
mod notifications;
mod social;
mod thoughts;
mod users;
use axum::Router;
use utoipa::{
openapi::security::{ApiKey, ApiKeyValue, Http, HttpAuthScheme, SecurityScheme},
Modify, OpenApi,
};
use utoipa_scalar::{Scalar, Servable};
use utoipa_swagger_ui::SwaggerUi;
struct SecurityAddon;
impl Modify for SecurityAddon {
fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
let components = openapi.components.get_or_insert_with(Default::default);
components.add_security_scheme(
"bearer_auth",
SecurityScheme::Http(Http::new(HttpAuthScheme::Bearer)),
);
components.add_security_scheme(
"api_key",
SecurityScheme::ApiKey(ApiKey::Header(ApiKeyValue::new("X-Api-Key"))),
);
}
}
fn build() -> utoipa::openapi::OpenApi {
let mut api = auth::AuthDoc::openapi();
api.info = utoipa::openapi::InfoBuilder::new()
.title("Thoughts API")
.version("2.0.0")
.description(Some(
"Federated social network API. Authenticate via `POST /auth/login` to get a Bearer token, \
or use `X-Api-Key` header with a key from `POST /api-keys`."
))
.build();
api.merge(users::UsersDoc::openapi());
api.merge(thoughts::ThoughtsDoc::openapi());
api.merge(feed::FeedDoc::openapi());
api.merge(social::SocialDoc::openapi());
api.merge(notifications::NotificationsDoc::openapi());
api.merge(api_keys::ApiKeysDoc::openapi());
api.merge(health::HealthDoc::openapi());
SecurityAddon.modify(&mut api);
api
}
pub fn serve<S: Clone + Send + Sync + 'static>(router: Router<S>) -> Router<S> {
tracing::info!("API docs at /docs (Swagger UI) and /scalar (Scalar)");
let spec = build();
router
.merge(SwaggerUi::new("/docs").url("/openapi.json", spec.clone()))
.merge(Scalar::with_url("/scalar", spec))
}

View File

@@ -0,0 +1,9 @@
use utoipa::OpenApi;
#[derive(OpenApi)]
#[openapi(paths(
crate::handlers::notifications::list_notifications,
crate::handlers::notifications::mark_notification_read,
crate::handlers::notifications::mark_all_read,
))]
pub struct NotificationsDoc;

View File

@@ -0,0 +1,20 @@
use api_types::requests::SetTopFriendsRequest;
use utoipa::OpenApi;
#[derive(OpenApi)]
#[openapi(
paths(
crate::handlers::social::post_like,
crate::handlers::social::delete_like,
crate::handlers::social::post_boost,
crate::handlers::social::delete_boost,
crate::handlers::social::post_follow,
crate::handlers::social::delete_follow,
crate::handlers::social::post_block,
crate::handlers::social::delete_block,
crate::handlers::social::put_top_friends,
crate::handlers::social::get_top_friends_handler,
),
components(schemas(SetTopFriendsRequest))
)]
pub struct SocialDoc;

View File

@@ -0,0 +1,18 @@
use api_types::{
requests::{CreateThoughtRequest, EditThoughtRequest},
responses::ErrorResponse,
};
use utoipa::OpenApi;
#[derive(OpenApi)]
#[openapi(
paths(
crate::handlers::thoughts::post_thought,
crate::handlers::thoughts::get_thought_handler,
crate::handlers::thoughts::patch_thought,
crate::handlers::thoughts::delete_thought_handler,
crate::handlers::thoughts::get_thread_handler,
),
components(schemas(CreateThoughtRequest, EditThoughtRequest, ErrorResponse))
)]
pub struct ThoughtsDoc;

View File

@@ -0,0 +1,16 @@
use api_types::{
requests::UpdateProfileRequest,
responses::{ErrorResponse, UserResponse},
};
use utoipa::OpenApi;
#[derive(OpenApi)]
#[openapi(
paths(
crate::handlers::users::get_me,
crate::handlers::users::get_user,
crate::handlers::users::patch_profile,
),
components(schemas(UserResponse, UpdateProfileRequest, ErrorResponse))
)]
pub struct UsersDoc;