//! 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, 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, pub email: Option, pub username: String, pub display_name: String, pub role: Option, pub password_hash: Option, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct CreatePasswordIdentityInput { pub user_id: EntityId, pub email: Option, 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, pub token_hash: String, pub user_agent: Option, pub ip_hash: Option, pub expires_at: Option, } #[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, pub ip_hash: Option, pub created_at: Timestamp, pub expires_at: Timestamp, pub revoked_at: Option, pub last_seen_at: Timestamp, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct CreateSessionInput { pub id: Option, pub user_id: EntityId, pub token_hash: String, pub user_agent: Option, pub ip_hash: Option, pub expires_at: Option, } #[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, 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, 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, pub user_id: Option, pub root_uri: Option, pub include_revoked: bool, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct DirectoryGrantInput { pub user_id: EntityId, pub workspace_id: Option, pub root_uri: String, pub root_path: String, pub permission: String, pub recursive: bool, pub capabilities: Vec, pub source: String, pub created_by: Option, } #[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, } #[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, 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, pub workspace_id: Option, 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, pub user_id: Option, pub workspace_id: Option, 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, pub cursor: Option, pub last_synced_at: Option, pub status: String, pub error_json: Option, pub updated_at: Timestamp, pub revision: i64, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct UpsertSyncStateInput { pub id: Option, pub workspace_id: EntityId, pub remote_kind: String, pub remote_id: Option, pub cursor: Option, pub last_synced_at: Option, pub status: String, pub error_json: Option, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct AiRuntimeRunRecord { pub id: EntityId, pub user_id: EntityId, pub workspace_id: Option, pub document_id: Option, pub session_id: EntityId, pub run_id: EntityId, pub title: Option, pub profile: String, pub acp_runtime: String, pub trace_id: Option, pub status: String, pub runtime_json: String, pub payload_json: String, pub deleted_at: Option, pub created_at: Timestamp, pub updated_at: Timestamp, pub revision: i64, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct UpsertAiRuntimeRunInput { pub id: Option, pub user_id: EntityId, pub workspace_id: Option, pub document_id: Option, pub session_id: EntityId, pub run_id: EntityId, pub title: Option, pub profile: String, pub acp_runtime: String, pub trace_id: Option, 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, pub document_id: Option, 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, pub user_id: EntityId, pub workspace_id: Option, pub document_id: Option, 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, pub revoked_at: Option, pub created_at: Timestamp, pub updated_at: Timestamp, pub revision: i64, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct CreateShareLinkInput { pub id: Option, pub workspace_id: EntityId, pub resource_kind: String, pub resource_id: String, pub token: Option, pub permission: String, pub created_by: EntityId, pub expires_at: Option, } #[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, pub action: String, pub target_kind: String, pub target_id: Option, pub metadata_json: String, pub created_at: Timestamp, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct AppendAuditInput { pub actor_user_id: Option, pub action: String, pub target_kind: String, pub target_id: Option, pub metadata_json: String, }