349 lines
9.6 KiB
Rust
349 lines
9.6 KiB
Rust
//! SQLite 控制面 Phase 1 的最小数据模型。
|
|||
|
|
|
||
|
|
use serde::{Deserialize, Serialize};
|
||
|
|
use sha2::{Digest, Sha256};
|
||
|
|
|
||
|
|
pub type EntityId = String;
|
||
|
|
pub type Timestamp = String;
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct UserRecord {
|
||
|
|
pub id: EntityId,
|
||
|
|
pub email: Option<String>,
|
||
|
|
pub username: String,
|
||
|
|
pub display_name: String,
|
||
|
|
pub role: String,
|
||
|
|
pub status: String,
|
||
|
|
pub created_at: Timestamp,
|
||
|
|
pub updated_at: Timestamp,
|
||
|
|
pub revision: i64,
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn session_token_hash(raw_token: &str) -> String {
|
||
|
|
let mut hasher = Sha256::new();
|
||
|
|
hasher.update(raw_token.as_bytes());
|
||
|
|
hex::encode(hasher.finalize())
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn password_hash_v1(password: &str) -> String {
|
||
|
|
let mut hasher = Sha256::new();
|
||
|
|
hasher.update(b"mnote-password-v1:");
|
||
|
|
hasher.update(password.as_bytes());
|
||
|
|
format!("sha256-v1:{}", hex::encode(hasher.finalize()))
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn share_token_hash_v1(token: &str) -> String {
|
||
|
|
let mut hasher = Sha256::new();
|
||
|
|
hasher.update(b"mnote-share-token-v1:");
|
||
|
|
hasher.update(token.as_bytes());
|
||
|
|
format!("sha256-v1:{}", hex::encode(hasher.finalize()))
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct UpsertUserInput {
|
||
|
|
pub id: Option<EntityId>,
|
||
|
|
pub email: Option<String>,
|
||
|
|
pub username: String,
|
||
|
|
pub display_name: String,
|
||
|
|
pub role: Option<String>,
|
||
|
|
pub password_hash: Option<String>,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct CreatePasswordIdentityInput {
|
||
|
|
pub user_id: EntityId,
|
||
|
|
pub email: Option<String>,
|
||
|
|
pub username: String,
|
||
|
|
pub password: String,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct AuthenticatePasswordInput {
|
||
|
|
pub account: String,
|
||
|
|
pub password: String,
|
||
|
|
pub session_id: Option<EntityId>,
|
||
|
|
pub token_hash: String,
|
||
|
|
pub user_agent: Option<String>,
|
||
|
|
pub ip_hash: Option<String>,
|
||
|
|
pub expires_at: Option<Timestamp>,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct AuthSessionRecord {
|
||
|
|
pub id: EntityId,
|
||
|
|
pub user_id: EntityId,
|
||
|
|
pub token_hash: String,
|
||
|
|
pub user_agent: Option<String>,
|
||
|
|
pub ip_hash: Option<String>,
|
||
|
|
pub created_at: Timestamp,
|
||
|
|
pub expires_at: Timestamp,
|
||
|
|
pub revoked_at: Option<Timestamp>,
|
||
|
|
pub last_seen_at: Timestamp,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct CreateSessionInput {
|
||
|
|
pub id: Option<EntityId>,
|
||
|
|
pub user_id: EntityId,
|
||
|
|
pub token_hash: String,
|
||
|
|
pub user_agent: Option<String>,
|
||
|
|
pub ip_hash: Option<String>,
|
||
|
|
pub expires_at: Option<Timestamp>,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct ResolvedAuthSession {
|
||
|
|
pub session: AuthSessionRecord,
|
||
|
|
pub user: UserRecord,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct WorkspaceRecord {
|
||
|
|
pub id: EntityId,
|
||
|
|
pub owner_user_id: EntityId,
|
||
|
|
pub name: String,
|
||
|
|
pub kind: String,
|
||
|
|
pub root_uri: String,
|
||
|
|
pub root_path: String,
|
||
|
|
pub source_kind: String,
|
||
|
|
pub status: String,
|
||
|
|
pub created_at: Timestamp,
|
||
|
|
pub updated_at: Timestamp,
|
||
|
|
pub revision: i64,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct DirectoryGrantRecord {
|
||
|
|
pub id: EntityId,
|
||
|
|
pub user_id: EntityId,
|
||
|
|
pub workspace_id: Option<EntityId>,
|
||
|
|
pub root_uri: String,
|
||
|
|
pub root_path: String,
|
||
|
|
pub permission: String,
|
||
|
|
pub recursive: bool,
|
||
|
|
pub capabilities_json: String,
|
||
|
|
pub source: String,
|
||
|
|
pub status: String,
|
||
|
|
pub created_by: Option<EntityId>,
|
||
|
|
pub created_at: Timestamp,
|
||
|
|
pub updated_at: Timestamp,
|
||
|
|
pub revision: i64,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct DirectoryGrantLookup {
|
||
|
|
pub grant_id: Option<EntityId>,
|
||
|
|
pub user_id: Option<EntityId>,
|
||
|
|
pub root_uri: Option<String>,
|
||
|
|
pub include_revoked: bool,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct DirectoryGrantInput {
|
||
|
|
pub user_id: EntityId,
|
||
|
|
pub workspace_id: Option<EntityId>,
|
||
|
|
pub root_uri: String,
|
||
|
|
pub root_path: String,
|
||
|
|
pub permission: String,
|
||
|
|
pub recursive: bool,
|
||
|
|
pub capabilities: Vec<String>,
|
||
|
|
pub source: String,
|
||
|
|
pub created_by: Option<EntityId>,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct ResolvedAccess {
|
||
|
|
pub user_id: EntityId,
|
||
|
|
pub root_uri: String,
|
||
|
|
pub permission: String,
|
||
|
|
pub grant_ids: Vec<EntityId>,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct OutboxEventRecord {
|
||
|
|
pub id: EntityId,
|
||
|
|
pub topic: String,
|
||
|
|
pub event_type: String,
|
||
|
|
pub payload_json: String,
|
||
|
|
pub created_at: Timestamp,
|
||
|
|
pub delivered_at: Option<Timestamp>,
|
||
|
|
pub attempts: i64,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct OutboxEventInput {
|
||
|
|
pub topic: String,
|
||
|
|
pub event_type: String,
|
||
|
|
pub payload_json: String,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct AiPolicyRecord {
|
||
|
|
pub id: EntityId,
|
||
|
|
pub user_id: Option<EntityId>,
|
||
|
|
pub workspace_id: Option<EntityId>,
|
||
|
|
pub allowed_roots_json: String,
|
||
|
|
pub model_policy_json: String,
|
||
|
|
pub quota_json: String,
|
||
|
|
pub created_at: Timestamp,
|
||
|
|
pub updated_at: Timestamp,
|
||
|
|
pub revision: i64,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct UpsertAiPolicyInput {
|
||
|
|
pub id: Option<EntityId>,
|
||
|
|
pub user_id: Option<EntityId>,
|
||
|
|
pub workspace_id: Option<EntityId>,
|
||
|
|
pub allowed_roots_json: String,
|
||
|
|
pub model_policy_json: String,
|
||
|
|
pub quota_json: String,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct SyncStateRecord {
|
||
|
|
pub id: EntityId,
|
||
|
|
pub workspace_id: EntityId,
|
||
|
|
pub remote_kind: String,
|
||
|
|
pub remote_id: Option<String>,
|
||
|
|
pub cursor: Option<String>,
|
||
|
|
pub last_synced_at: Option<Timestamp>,
|
||
|
|
pub status: String,
|
||
|
|
pub error_json: Option<String>,
|
||
|
|
pub updated_at: Timestamp,
|
||
|
|
pub revision: i64,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct UpsertSyncStateInput {
|
||
|
|
pub id: Option<EntityId>,
|
||
|
|
pub workspace_id: EntityId,
|
||
|
|
pub remote_kind: String,
|
||
|
|
pub remote_id: Option<String>,
|
||
|
|
pub cursor: Option<String>,
|
||
|
|
pub last_synced_at: Option<Timestamp>,
|
||
|
|
pub status: String,
|
||
|
|
pub error_json: Option<String>,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct AiRuntimeRunRecord {
|
||
|
|
pub id: EntityId,
|
||
|
|
pub user_id: EntityId,
|
||
|
|
pub workspace_id: Option<EntityId>,
|
||
|
|
pub document_id: Option<String>,
|
||
|
|
pub session_id: EntityId,
|
||
|
|
pub run_id: EntityId,
|
||
|
|
pub title: Option<String>,
|
||
|
|
pub profile: String,
|
||
|
|
pub acp_runtime: String,
|
||
|
|
pub trace_id: Option<String>,
|
||
|
|
pub status: String,
|
||
|
|
pub runtime_json: String,
|
||
|
|
pub payload_json: String,
|
||
|
|
pub deleted_at: Option<Timestamp>,
|
||
|
|
pub created_at: Timestamp,
|
||
|
|
pub updated_at: Timestamp,
|
||
|
|
pub revision: i64,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct UpsertAiRuntimeRunInput {
|
||
|
|
pub id: Option<EntityId>,
|
||
|
|
pub user_id: EntityId,
|
||
|
|
pub workspace_id: Option<EntityId>,
|
||
|
|
pub document_id: Option<String>,
|
||
|
|
pub session_id: EntityId,
|
||
|
|
pub run_id: EntityId,
|
||
|
|
pub title: Option<String>,
|
||
|
|
pub profile: String,
|
||
|
|
pub acp_runtime: String,
|
||
|
|
pub trace_id: Option<String>,
|
||
|
|
pub status: String,
|
||
|
|
pub runtime_json: String,
|
||
|
|
pub payload_json: String,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct AiRuntimeEventRecord {
|
||
|
|
pub id: EntityId,
|
||
|
|
pub user_id: EntityId,
|
||
|
|
pub workspace_id: Option<EntityId>,
|
||
|
|
pub document_id: Option<String>,
|
||
|
|
pub session_id: EntityId,
|
||
|
|
pub run_id: EntityId,
|
||
|
|
pub profile: String,
|
||
|
|
pub acp_runtime: String,
|
||
|
|
pub event_type: String,
|
||
|
|
pub payload_json: String,
|
||
|
|
pub created_at: Timestamp,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct AppendAiRuntimeEventInput {
|
||
|
|
pub id: Option<EntityId>,
|
||
|
|
pub user_id: EntityId,
|
||
|
|
pub workspace_id: Option<EntityId>,
|
||
|
|
pub document_id: Option<String>,
|
||
|
|
pub session_id: EntityId,
|
||
|
|
pub run_id: EntityId,
|
||
|
|
pub profile: String,
|
||
|
|
pub acp_runtime: String,
|
||
|
|
pub event_type: String,
|
||
|
|
pub payload_json: String,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct ShareLinkRecord {
|
||
|
|
pub id: EntityId,
|
||
|
|
pub workspace_id: EntityId,
|
||
|
|
pub resource_kind: String,
|
||
|
|
pub resource_id: String,
|
||
|
|
pub token_hash: String,
|
||
|
|
pub permission: String,
|
||
|
|
pub created_by: EntityId,
|
||
|
|
pub expires_at: Option<Timestamp>,
|
||
|
|
pub revoked_at: Option<Timestamp>,
|
||
|
|
pub created_at: Timestamp,
|
||
|
|
pub updated_at: Timestamp,
|
||
|
|
pub revision: i64,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct CreateShareLinkInput {
|
||
|
|
pub id: Option<EntityId>,
|
||
|
|
pub workspace_id: EntityId,
|
||
|
|
pub resource_kind: String,
|
||
|
|
pub resource_id: String,
|
||
|
|
pub token: Option<String>,
|
||
|
|
pub permission: String,
|
||
|
|
pub created_by: EntityId,
|
||
|
|
pub expires_at: Option<Timestamp>,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct CreatedShareLink {
|
||
|
|
pub link: ShareLinkRecord,
|
||
|
|
pub token: String,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct AuditLogRecord {
|
||
|
|
pub id: EntityId,
|
||
|
|
pub actor_user_id: Option<EntityId>,
|
||
|
|
pub action: String,
|
||
|
|
pub target_kind: String,
|
||
|
|
pub target_id: Option<EntityId>,
|
||
|
|
pub metadata_json: String,
|
||
|
|
pub created_at: Timestamp,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
|
pub struct AppendAuditInput {
|
||
|
|
pub actor_user_id: Option<EntityId>,
|
||
|
|
pub action: String,
|
||
|
|
pub target_kind: String,
|
||
|
|
pub target_id: Option<EntityId>,
|
||
|
|
pub metadata_json: String,
|
||
|
|
}
|