feat(db): add users, sessions_auth, auth_tokens tables
This commit is contained in:
@@ -78,8 +78,63 @@ export const attempts = sqliteTable(
|
||||
})
|
||||
);
|
||||
|
||||
export const users = sqliteTable(
|
||||
'users',
|
||||
{
|
||||
id: integer('id').primaryKey({ autoIncrement: true }),
|
||||
email: text('email').notNull().unique(),
|
||||
displayName: text('display_name').notNull(),
|
||||
passwordHash: text('password_hash'),
|
||||
role: text('role', { enum: ['user', 'sysadmin'] }).notNull().default('user'),
|
||||
isActive: integer('is_active', { mode: 'boolean' }).notNull().default(true),
|
||||
emailVerifiedAt: integer('email_verified_at'),
|
||||
pendingEmail: text('pending_email'),
|
||||
createdAt: integer('created_at').notNull().default(sql`(unixepoch())`),
|
||||
updatedAt: integer('updated_at').notNull().default(sql`(unixepoch())`),
|
||||
},
|
||||
(t) => ({ emailIdx: index('users_email_idx').on(t.email) })
|
||||
);
|
||||
|
||||
export const sessionsAuth = sqliteTable(
|
||||
'sessions_auth',
|
||||
{
|
||||
id: text('id').primaryKey(),
|
||||
userId: integer('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
|
||||
createdAt: integer('created_at').notNull().default(sql`(unixepoch())`),
|
||||
expiresAt: integer('expires_at').notNull(),
|
||||
lastUsedAt: integer('last_used_at').notNull().default(sql`(unixepoch())`),
|
||||
userAgent: text('user_agent'),
|
||||
ip: text('ip'),
|
||||
},
|
||||
(t) => ({
|
||||
userIdx: index('sessions_auth_user_idx').on(t.userId),
|
||||
expIdx: index('sessions_auth_expires_idx').on(t.expiresAt),
|
||||
})
|
||||
);
|
||||
|
||||
export const authTokens = sqliteTable(
|
||||
'auth_tokens',
|
||||
{
|
||||
id: integer('id').primaryKey({ autoIncrement: true }),
|
||||
userId: integer('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
|
||||
tokenHash: text('token_hash').notNull(),
|
||||
purpose: text('purpose', { enum: ['verify_email', 'password_reset', 'invite', 'change_email'] }).notNull(),
|
||||
payload: text('payload'),
|
||||
expiresAt: integer('expires_at').notNull(),
|
||||
usedAt: integer('used_at'),
|
||||
createdAt: integer('created_at').notNull().default(sql`(unixepoch())`),
|
||||
},
|
||||
(t) => ({
|
||||
hashIdx: index('auth_tokens_hash_idx').on(t.tokenHash),
|
||||
userPurposeIdx: index('auth_tokens_user_purpose_idx').on(t.userId, t.purpose),
|
||||
})
|
||||
);
|
||||
|
||||
export type LessonRow = typeof lessons.$inferSelect;
|
||||
export type CardRow = typeof cards.$inferSelect;
|
||||
export type CardProgressRow = typeof cardProgress.$inferSelect;
|
||||
export type SessionRow = typeof sessions.$inferSelect;
|
||||
export type AttemptRow = typeof attempts.$inferSelect;
|
||||
export type UserRow = typeof users.$inferSelect;
|
||||
export type SessionAuthRow = typeof sessionsAuth.$inferSelect;
|
||||
export type AuthTokenRow = typeof authTokens.$inferSelect;
|
||||
|
||||
Reference in New Issue
Block a user