feat: add user_stats, audit_logs and verification tokens schema
Made-with: Cursor
This commit is contained in:
18
src/db/schema/auditLogs.ts
Normal file
18
src/db/schema/auditLogs.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { pgTable, uuid, varchar, timestamp } from 'drizzle-orm/pg-core';
|
||||||
|
import { jsonb } from 'drizzle-orm/pg-core';
|
||||||
|
import { users } from './users.js';
|
||||||
|
|
||||||
|
export const auditLogs = pgTable('audit_logs', {
|
||||||
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
|
adminId: uuid('admin_id')
|
||||||
|
.notNull()
|
||||||
|
.references(() => users.id, { onDelete: 'cascade' }),
|
||||||
|
action: varchar('action', { length: 100 }).notNull(),
|
||||||
|
targetType: varchar('target_type', { length: 50 }).notNull(),
|
||||||
|
targetId: uuid('target_id').notNull(),
|
||||||
|
details: jsonb('details').$type<Record<string, unknown>>(),
|
||||||
|
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type AuditLog = typeof auditLogs.$inferSelect;
|
||||||
|
export type NewAuditLog = typeof auditLogs.$inferInsert;
|
||||||
@@ -7,3 +7,7 @@ export * from './testQuestions.js';
|
|||||||
export * from './questionBank.js';
|
export * from './questionBank.js';
|
||||||
export * from './questionCacheMeta.js';
|
export * from './questionCacheMeta.js';
|
||||||
export * from './questionReports.js';
|
export * from './questionReports.js';
|
||||||
|
export * from './userStats.js';
|
||||||
|
export * from './auditLogs.js';
|
||||||
|
export * from './userQuestionLog.js';
|
||||||
|
export * from './verificationTokens.js';
|
||||||
|
|||||||
17
src/db/schema/userQuestionLog.ts
Normal file
17
src/db/schema/userQuestionLog.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { pgTable, uuid, timestamp } from 'drizzle-orm/pg-core';
|
||||||
|
import { users } from './users.js';
|
||||||
|
import { questionBank } from './questionBank.js';
|
||||||
|
|
||||||
|
export const userQuestionLog = pgTable('user_question_log', {
|
||||||
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
|
userId: uuid('user_id')
|
||||||
|
.notNull()
|
||||||
|
.references(() => users.id, { onDelete: 'cascade' }),
|
||||||
|
questionBankId: uuid('question_bank_id')
|
||||||
|
.notNull()
|
||||||
|
.references(() => questionBank.id, { onDelete: 'cascade' }),
|
||||||
|
seenAt: timestamp('seen_at', { withTimezone: true }).notNull().defaultNow(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type UserQuestionLog = typeof userQuestionLog.$inferSelect;
|
||||||
|
export type NewUserQuestionLog = typeof userQuestionLog.$inferInsert;
|
||||||
26
src/db/schema/userStats.ts
Normal file
26
src/db/schema/userStats.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { pgTable, uuid, integer, timestamp } from 'drizzle-orm/pg-core';
|
||||||
|
import { unique } from 'drizzle-orm/pg-core';
|
||||||
|
import { stackEnum, levelEnum } from './enums.js';
|
||||||
|
import { users } from './users.js';
|
||||||
|
|
||||||
|
export const userStats = pgTable(
|
||||||
|
'user_stats',
|
||||||
|
{
|
||||||
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
|
userId: uuid('user_id')
|
||||||
|
.notNull()
|
||||||
|
.references(() => users.id, { onDelete: 'cascade' }),
|
||||||
|
stack: stackEnum('stack').notNull(),
|
||||||
|
level: levelEnum('level').notNull(),
|
||||||
|
totalQuestions: integer('total_questions').notNull().default(0),
|
||||||
|
correctAnswers: integer('correct_answers').notNull().default(0),
|
||||||
|
testsTaken: integer('tests_taken').notNull().default(0),
|
||||||
|
lastTestAt: timestamp('last_test_at', { withTimezone: true }),
|
||||||
|
},
|
||||||
|
(t) => ({
|
||||||
|
userStackLevelUnique: unique().on(t.userId, t.stack, t.level),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
export type UserStat = typeof userStats.$inferSelect;
|
||||||
|
export type NewUserStat = typeof userStats.$inferInsert;
|
||||||
22
src/db/schema/verificationTokens.ts
Normal file
22
src/db/schema/verificationTokens.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { pgTable, uuid, varchar, timestamp } from 'drizzle-orm/pg-core';
|
||||||
|
import { users } from './users.js';
|
||||||
|
|
||||||
|
export const emailVerificationCodes = pgTable('email_verification_codes', {
|
||||||
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
|
userId: uuid('user_id')
|
||||||
|
.notNull()
|
||||||
|
.references(() => users.id, { onDelete: 'cascade' }),
|
||||||
|
code: varchar('code', { length: 10 }).notNull(),
|
||||||
|
expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
|
||||||
|
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const passwordResetTokens = pgTable('password_reset_tokens', {
|
||||||
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
|
userId: uuid('user_id')
|
||||||
|
.notNull()
|
||||||
|
.references(() => users.id, { onDelete: 'cascade' }),
|
||||||
|
tokenHash: varchar('token_hash', { length: 255 }).notNull(),
|
||||||
|
expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
|
||||||
|
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user