feat: initial commit
Axum/Postgres server with auth, migrations, and Docker setup.
This commit is contained in:
173
src/model.rs
Normal file
173
src/model.rs
Normal 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>,
|
||||
}
|
||||
Reference in New Issue
Block a user