You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

35 lines
1.5 KiB

import { index, integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
export const users = sqliteTable("users", {
id: integer().primaryKey(),
username: text().notNull().unique(),
email: text(), // unique index added via migration
nickname: text(),
password: text().notNull(),
avatar: text(),
role: text().notNull().default("user"),
status: text().notNull().default("active"),
createdAt: integer("created_at", { mode: "timestamp_ms" }).defaultNow().notNull(),
updatedAt: integer("updated_at", { mode: "timestamp_ms" })
.defaultNow()
.$onUpdate(() => new Date())
.notNull(),
// --- auth fields ---
emailVerified: integer("email_verified", { mode: "boolean" }).default(false).notNull(),
passwordHistory: text("password_history").default("[]").notNull(),
failedLoginAttempts: integer("failed_login_attempts").default(0).notNull(),
lockoutUntil: integer("lockout_until", { mode: "timestamp_ms" }),
lastLoginAt: integer("last_login_at", { mode: "timestamp_ms" }),
lastLoginIp: text("last_login_ip"),
});
export const userSessions = sqliteTable("user_sessions", {
id: text().primaryKey(),
userId: integer("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
refreshTokenHash: text("refresh_token_hash").notNull(),
userAgent: text("user_agent"),
ip: text(),
createdAt: integer("created_at", { mode: "timestamp_ms" }).defaultNow().notNull(),
expiresAt: integer("expires_at", { mode: "timestamp_ms" }).notNull(),
revokedAt: integer("revoked_at", { mode: "timestamp_ms" }),
});