2026-03-25 09:21:17 +08:00
|
|
|
import { integer, real, sqliteTable, text } from "drizzle-orm/sqlite-core";
|
2026-03-22 02:51:57 +08:00
|
|
|
|
|
|
|
|
export const users = sqliteTable("users", {
|
|
|
|
|
id: text("id").primaryKey(),
|
|
|
|
|
username: text("username").notNull().unique(),
|
2026-05-13 18:47:54 +08:00
|
|
|
passwordHash: text("password_hash"),
|
2026-04-22 18:10:04 +08:00
|
|
|
role: text("role").notNull().default("user"),
|
2026-03-25 01:13:25 +08:00
|
|
|
team: text("team").notNull().default("Default"),
|
2026-03-22 02:51:57 +08:00
|
|
|
mustChangePassword: integer("must_change_password", { mode: "boolean" }).notNull().default(true),
|
2026-05-13 18:47:54 +08:00
|
|
|
authProvider: text("auth_provider").notNull().default("local"),
|
|
|
|
|
externalId: text("external_id"),
|
|
|
|
|
email: text("email"),
|
2026-03-25 09:21:17 +08:00
|
|
|
createdAt: integer("created_at", { mode: "timestamp" })
|
|
|
|
|
.notNull()
|
|
|
|
|
.$defaultFn(() => new Date()),
|
|
|
|
|
updatedAt: integer("updated_at", { mode: "timestamp" })
|
|
|
|
|
.notNull()
|
|
|
|
|
.$defaultFn(() => new Date()),
|
2026-04-22 19:00:15 +08:00
|
|
|
analyticsEnabled: integer("analytics_enabled", { mode: "boolean" }),
|
|
|
|
|
analyticsConsentShownAt: integer("analytics_consent_shown_at", { mode: "timestamp" }),
|
|
|
|
|
analyticsConsentRemindAt: integer("analytics_consent_remind_at", { mode: "timestamp" }),
|
2026-03-25 09:21:17 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const teams = sqliteTable("teams", {
|
|
|
|
|
id: text("id").primaryKey(),
|
|
|
|
|
name: text("name").notNull().unique(),
|
|
|
|
|
createdAt: integer("created_at", { mode: "timestamp" })
|
|
|
|
|
.notNull()
|
|
|
|
|
.$defaultFn(() => new Date()),
|
2026-03-22 02:51:57 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const sessions = sqliteTable("sessions", {
|
|
|
|
|
id: text("id").primaryKey(),
|
2026-03-25 09:21:17 +08:00
|
|
|
userId: text("user_id")
|
|
|
|
|
.notNull()
|
|
|
|
|
.references(() => users.id, { onDelete: "cascade" }),
|
2026-03-22 02:51:57 +08:00
|
|
|
expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
|
2026-05-13 18:47:54 +08:00
|
|
|
idToken: text("id_token"),
|
2026-03-25 09:21:17 +08:00
|
|
|
createdAt: integer("created_at", { mode: "timestamp" })
|
|
|
|
|
.notNull()
|
|
|
|
|
.$defaultFn(() => new Date()),
|
2026-03-22 02:51:57 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const settings = sqliteTable("settings", {
|
|
|
|
|
key: text("key").primaryKey(),
|
|
|
|
|
value: text("value").notNull(),
|
2026-03-25 09:21:17 +08:00
|
|
|
updatedAt: integer("updated_at", { mode: "timestamp" })
|
|
|
|
|
.notNull()
|
|
|
|
|
.$defaultFn(() => new Date()),
|
2026-03-22 02:51:57 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const jobs = sqliteTable("jobs", {
|
|
|
|
|
id: text("id").primaryKey(),
|
|
|
|
|
type: text("type").notNull(),
|
2026-03-25 09:21:17 +08:00
|
|
|
status: text("status", { enum: ["queued", "processing", "completed", "failed"] })
|
|
|
|
|
.notNull()
|
|
|
|
|
.default("queued"),
|
2026-03-22 02:51:57 +08:00
|
|
|
progress: real("progress").notNull().default(0),
|
|
|
|
|
inputFiles: text("input_files").notNull(),
|
|
|
|
|
outputPath: text("output_path"),
|
|
|
|
|
settings: text("settings"),
|
|
|
|
|
error: text("error"),
|
2026-03-25 09:21:17 +08:00
|
|
|
createdAt: integer("created_at", { mode: "timestamp" })
|
|
|
|
|
.notNull()
|
|
|
|
|
.$defaultFn(() => new Date()),
|
2026-03-22 02:51:57 +08:00
|
|
|
completedAt: integer("completed_at", { mode: "timestamp" }),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const apiKeys = sqliteTable("api_keys", {
|
|
|
|
|
id: text("id").primaryKey(),
|
2026-03-25 09:21:17 +08:00
|
|
|
userId: text("user_id")
|
|
|
|
|
.notNull()
|
|
|
|
|
.references(() => users.id, { onDelete: "cascade" }),
|
2026-03-22 02:51:57 +08:00
|
|
|
keyHash: text("key_hash").notNull(),
|
2026-03-24 21:38:06 +08:00
|
|
|
keyPrefix: text("key_prefix"),
|
2026-03-22 02:51:57 +08:00
|
|
|
name: text("name").notNull().default("Default API Key"),
|
2026-04-22 18:10:04 +08:00
|
|
|
permissions: text("permissions"),
|
2026-03-25 09:21:17 +08:00
|
|
|
createdAt: integer("created_at", { mode: "timestamp" })
|
|
|
|
|
.notNull()
|
|
|
|
|
.$defaultFn(() => new Date()),
|
2026-03-22 02:51:57 +08:00
|
|
|
lastUsedAt: integer("last_used_at", { mode: "timestamp" }),
|
2026-04-22 18:10:04 +08:00
|
|
|
expiresAt: integer("expires_at", { mode: "timestamp" }),
|
2026-03-22 02:51:57 +08:00
|
|
|
});
|
2026-03-22 04:41:51 +08:00
|
|
|
|
|
|
|
|
export const pipelines = sqliteTable("pipelines", {
|
|
|
|
|
id: text("id").primaryKey(),
|
2026-03-24 21:38:06 +08:00
|
|
|
userId: text("user_id").references(() => users.id, { onDelete: "cascade" }),
|
2026-03-22 04:41:51 +08:00
|
|
|
name: text("name").notNull(),
|
|
|
|
|
description: text("description"),
|
|
|
|
|
steps: text("steps").notNull(), // JSON array of { toolId, settings }
|
2026-03-25 09:21:17 +08:00
|
|
|
createdAt: integer("created_at", { mode: "timestamp" })
|
|
|
|
|
.notNull()
|
|
|
|
|
.$defaultFn(() => new Date()),
|
2026-03-22 04:41:51 +08:00
|
|
|
});
|
2026-03-25 01:13:25 +08:00
|
|
|
|
2026-04-22 18:10:04 +08:00
|
|
|
export const auditLog = sqliteTable("audit_log", {
|
|
|
|
|
id: text("id").primaryKey(),
|
|
|
|
|
actorId: text("actor_id").references(() => users.id, { onDelete: "set null" }),
|
|
|
|
|
actorUsername: text("actor_username").notNull(),
|
|
|
|
|
action: text("action").notNull(),
|
|
|
|
|
targetType: text("target_type"),
|
|
|
|
|
targetId: text("target_id"),
|
|
|
|
|
details: text("details"),
|
|
|
|
|
ipAddress: text("ip_address"),
|
|
|
|
|
createdAt: integer("created_at", { mode: "timestamp" })
|
|
|
|
|
.notNull()
|
|
|
|
|
.$defaultFn(() => new Date()),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const roles = sqliteTable("roles", {
|
|
|
|
|
id: text("id").primaryKey(),
|
|
|
|
|
name: text("name").notNull().unique(),
|
|
|
|
|
description: text("description").notNull().default(""),
|
|
|
|
|
permissions: text("permissions").notNull(),
|
|
|
|
|
isBuiltin: integer("is_builtin", { mode: "boolean" }).notNull().default(false),
|
|
|
|
|
createdBy: text("created_by").references(() => users.id, { onDelete: "set null" }),
|
|
|
|
|
createdAt: integer("created_at", { mode: "timestamp" })
|
|
|
|
|
.notNull()
|
|
|
|
|
.$defaultFn(() => new Date()),
|
|
|
|
|
updatedAt: integer("updated_at", { mode: "timestamp" })
|
|
|
|
|
.notNull()
|
|
|
|
|
.$defaultFn(() => new Date()),
|
|
|
|
|
});
|
|
|
|
|
|
2026-03-25 01:13:25 +08:00
|
|
|
export const userFiles = sqliteTable("user_files", {
|
|
|
|
|
id: text("id").primaryKey(),
|
|
|
|
|
userId: text("user_id").references(() => users.id, { onDelete: "cascade" }),
|
|
|
|
|
originalName: text("original_name").notNull(),
|
|
|
|
|
storedName: text("stored_name").notNull(),
|
|
|
|
|
mimeType: text("mime_type").notNull(),
|
|
|
|
|
size: integer("size").notNull(),
|
|
|
|
|
width: integer("width"),
|
|
|
|
|
height: integer("height"),
|
|
|
|
|
version: integer("version").notNull().default(1),
|
|
|
|
|
parentId: text("parent_id"),
|
|
|
|
|
toolChain: text("tool_chain"),
|
2026-03-25 09:21:17 +08:00
|
|
|
createdAt: integer("created_at", { mode: "timestamp" })
|
|
|
|
|
.notNull()
|
|
|
|
|
.$defaultFn(() => new Date()),
|
2026-03-25 01:13:25 +08:00
|
|
|
});
|