Initial public release v0.1.0

This commit is contained in:
thakares committed 2026-06-21 20:05:29 +05:30
commit 6c39e0bfbf
87 files changed
+10867

No files matched your search

+20
View File
@@ -0,0 +1,20 @@
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
/// A personal access token row from the `api_tokens` table.
///
/// `token_hash` is the BLAKE3 hex-encoded hash of the raw `nx9_pat_...` token.
/// The raw token is displayed exactly once at creation time and never stored.
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct ApiToken {
pub id: String,
pub user_id: String,
pub name: String,
/// BLAKE3 hex hash — never expose in API responses.
#[serde(skip_serializing)]
pub token_hash: String,
pub last_used_at: Option<String>,
pub expires_at: Option<String>,
pub created_at: String,
pub revoked: bool,
}
+13
View File
@@ -0,0 +1,13 @@
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct Application {
pub id: String,
pub tenant_id: String,
pub name: String,
pub slug: String,
pub enabled: bool,
pub created_at: String,
pub updated_at: String,
}
+55
View File
@@ -0,0 +1,55 @@
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
/// Audit event severity level.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum AuditSeverity {
Info,
Warning,
Critical,
}
impl AuditSeverity {
pub fn as_str(self) -> &'static str {
match self {
Self::Info => "info",
Self::Warning => "warning",
Self::Critical => "critical",
}
}
}
impl std::str::FromStr for AuditSeverity {
type Err = std::convert::Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"warning" => Ok(Self::Warning),
"critical" => Ok(Self::Critical),
_ => Ok(Self::Info),
}
}
}
impl std::fmt::Display for AuditSeverity {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
/// A row from the `audit_logs` table.
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct AuditLog {
pub id: String,
pub actor_user_id: Option<String>,
pub target_user_id: Option<String>,
pub action: String,
pub resource_type: String,
pub resource_id: Option<String>,
pub severity: String,
pub ip_address: Option<String>,
pub user_agent: Option<String>,
pub metadata_json: Option<String>,
pub created_at: String,
}
+20
View File
@@ -0,0 +1,20 @@
pub mod api_token;
pub mod application;
pub mod audit_log;
pub mod permission;
pub mod role;
pub mod service_account;
pub mod session;
pub mod tenant;
pub mod user;
pub use api_token::ApiToken;
pub use application::Application;
pub use audit_log::{AuditLog, AuditSeverity};
#[allow(unused_imports)]
pub use permission::Permission;
pub use role::Role;
pub use service_account::ServiceAccount;
pub use session::Session;
pub use tenant::Tenant;
pub use user::{User, UserStatus};
+9
View File
@@ -0,0 +1,9 @@
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct Permission {
pub id: String,
pub name: String,
pub description: Option<String>,
}
+9
View File
@@ -0,0 +1,9 @@
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct Role {
pub id: String,
pub name: String,
pub description: Option<String>,
}
+13
View File
@@ -0,0 +1,13 @@
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct ServiceAccount {
pub id: String,
pub tenant_id: String,
pub name: String,
pub description: Option<String>,
pub enabled: bool,
pub created_at: String,
pub updated_at: String,
}
+23
View File
@@ -0,0 +1,23 @@
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
/// A session row from the `sessions` table.
///
/// `token_hash` is the BLAKE3 hex-encoded hash of the raw session token.
/// The raw token is stored in a cookie and never persisted.
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct Session {
pub id: String,
pub user_id: String,
/// BLAKE3 hex hash of the raw cookie value.
#[serde(skip_serializing)]
pub token_hash: String,
pub ip_address: Option<String>,
pub user_agent: Option<String>,
pub created_at: String,
/// Absolute expiry — the session is dead after this regardless of activity.
pub expires_at: String,
/// Idle timeout — updated on each authenticated request.
pub last_seen_at: String,
pub revoked: bool,
}
+17
View File
@@ -0,0 +1,17 @@
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct Tenant {
pub id: String,
pub name: String,
pub slug: String,
pub enabled: bool,
pub created_at: String,
pub updated_at: String,
}
impl Tenant {
pub const DEFAULT_ID: &'static str = "00000000-0000-0000-0000-000000000001";
pub const DEFAULT_SLUG: &'static str = "default";
}
+68
View File
@@ -0,0 +1,68 @@
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
/// User account status.
///
/// Stored as INTEGER in SQLite: 1 = Active, 2 = Disabled, 3 = Locked.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum UserStatus {
Active = 1,
Disabled = 2,
Locked = 3,
}
impl UserStatus {
pub fn from_i32(v: i32) -> Self {
match v {
2 => Self::Disabled,
3 => Self::Locked,
_ => Self::Active,
}
}
pub fn as_i32(self) -> i32 {
self as i32
}
pub fn as_str(self) -> &'static str {
match self {
Self::Active => "active",
Self::Disabled => "disabled",
Self::Locked => "locked",
}
}
}
impl std::fmt::Display for UserStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
/// A user account row from the `users` table.
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct User {
pub id: String,
pub tenant_id: String,
pub username: String,
/// Argon2id PHC string — never expose in API responses.
#[serde(skip_serializing)]
pub password_hash: String,
/// Raw integer status — use `status()` for the typed enum.
pub status: i32,
pub last_login_at: Option<String>,
pub created_at: String,
pub updated_at: String,
}
impl User {
/// Typed status accessor.
pub fn status(&self) -> UserStatus {
UserStatus::from_i32(self.status)
}
pub fn is_active(&self) -> bool {
self.status() == UserStatus::Active
}
}