feat: initial commit

Axum/Postgres server with auth, migrations, and Docker setup.
This commit is contained in:
2026-08-13 13:08:13 +02:00
commit 9617f4415c
33 changed files with 3974 additions and 0 deletions

173
src/model.rs Normal file
View File

@@ -0,0 +1,173 @@
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Claims {
pub sub: String,
pub exp: usize,
}
// ── Enums ────────────────────────────────────────────────────────────────────
#[derive(Debug, Deserialize, Serialize, sqlx::Type)]
#[sqlx(type_name = "auth_token_kind", rename_all = "snake_case")]
pub enum AuthTokenKind {
PasswordReset,
EmailVerification,
RefreshToken,
}
#[derive(Debug, Deserialize, Serialize, sqlx::Type)]
#[sqlx(type_name = "workspace_role", rename_all = "snake_case")]
pub enum WorkspaceRole {
Owner,
Admin,
Member,
}
#[derive(Debug, Deserialize, Serialize, sqlx::Type)]
#[sqlx(type_name = "conversation_kind", rename_all = "snake_case")]
pub enum ConversationKind {
Dm,
Group,
Channel,
}
// ── Tables ───────────────────────────────────────────────────────────────────
#[derive(Debug, Deserialize, Serialize, sqlx::FromRow)]
pub struct User {
pub id: Uuid,
pub email: String,
pub password_hash: String,
pub username: String,
pub display_name: String,
pub avatar_url: Option<String>,
pub bio: Option<String>,
pub email_verified: bool,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
pub deleted_at: Option<chrono::DateTime<chrono::Utc>>,
}
#[derive(Debug, Serialize)]
pub struct UserResponse {
pub id: Uuid,
pub email: String,
pub username: String,
pub display_name: String,
pub avatar_url: Option<String>,
pub bio: Option<String>,
pub email_verified: bool,
pub created_at: chrono::DateTime<chrono::Utc>,
}
impl From<User> for UserResponse {
fn from(u: User) -> Self {
Self {
id: u.id,
email: u.email,
username: u.username,
display_name: u.display_name,
avatar_url: u.avatar_url,
bio: u.bio,
email_verified: u.email_verified,
created_at: u.created_at,
}
}
}
#[derive(Debug, Deserialize, Serialize, sqlx::FromRow)]
pub struct AuthToken {
pub id: Uuid,
pub user_id: Uuid,
pub token_hash: String,
pub kind: AuthTokenKind,
pub expires_at: chrono::DateTime<chrono::Utc>,
pub used_at: Option<chrono::DateTime<chrono::Utc>>,
pub created_at: chrono::DateTime<chrono::Utc>,
}
#[derive(Debug, Deserialize, Serialize, sqlx::FromRow)]
pub struct Workspace {
pub id: Uuid,
pub name: String,
pub slug: String,
pub owner_id: Uuid,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
pub deleted_at: Option<chrono::DateTime<chrono::Utc>>,
}
#[derive(Debug, Deserialize, Serialize, sqlx::FromRow)]
pub struct WorkspaceMember {
pub workspace_id: Uuid,
pub user_id: Uuid,
pub role: WorkspaceRole,
pub display_name: Option<String>,
pub avatar_url: Option<String>,
pub joined_at: chrono::DateTime<chrono::Utc>,
}
#[derive(Debug, Deserialize, Serialize, sqlx::FromRow)]
pub struct WorkspaceInvitation {
pub id: Uuid,
pub workspace_id: Uuid,
pub created_by: Uuid,
pub token: String,
pub max_uses: Option<i32>,
pub use_count: i32,
pub expires_at: Option<chrono::DateTime<chrono::Utc>>,
pub created_at: chrono::DateTime<chrono::Utc>,
}
#[derive(Debug, Deserialize, Serialize, sqlx::FromRow)]
pub struct Conversation {
pub id: Uuid,
pub workspace_id: Option<Uuid>,
pub kind: ConversationKind,
pub name: Option<String>,
pub is_public: bool,
pub created_by: Uuid,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
pub deleted_at: Option<chrono::DateTime<chrono::Utc>>,
}
#[derive(Debug, Deserialize, Serialize, sqlx::FromRow)]
pub struct ConversationMember {
pub conversation_id: Uuid,
pub user_id: Uuid,
pub joined_at: chrono::DateTime<chrono::Utc>,
}
#[derive(Debug, Deserialize, Serialize, sqlx::FromRow)]
pub struct Message {
pub id: Uuid,
pub conversation_id: Uuid,
pub user_id: Uuid,
pub content: String,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
pub deleted_at: Option<chrono::DateTime<chrono::Utc>>,
}
#[derive(Debug, Deserialize, Serialize, sqlx::FromRow)]
pub struct Attachment {
pub id: Uuid,
pub message_id: Uuid,
pub url: String,
pub filename: String,
pub mime_type: String,
pub size_bytes: i64,
pub created_at: chrono::DateTime<chrono::Utc>,
}
#[derive(Debug, Deserialize, Serialize, sqlx::FromRow)]
pub struct Reaction {
pub id: Uuid,
pub message_id: Uuid,
pub user_id: Uuid,
pub emoji: String,
pub created_at: chrono::DateTime<chrono::Utc>,
}