& so it begins
This commit is contained in:
52
packages/db/schema/auth.schema.ts
Normal file
52
packages/db/schema/auth.schema.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import {
|
||||
integer,
|
||||
json,
|
||||
pgTable,
|
||||
text,
|
||||
timestamp,
|
||||
varchar,
|
||||
} from "drizzle-orm/pg-core";
|
||||
import { user } from "./better.auth.schema";
|
||||
import { relations } from "drizzle-orm";
|
||||
|
||||
export const twoFactor = pgTable("two_factor", {
|
||||
id: text("id").primaryKey(),
|
||||
secret: text("secret").notNull(),
|
||||
backupCodes: json("backup_codes").$type<string[]>(),
|
||||
userId: text("user_id")
|
||||
.notNull()
|
||||
.references(() => user.id, { onDelete: "cascade" }),
|
||||
createdAt: timestamp("created_at").notNull(),
|
||||
updatedAt: timestamp("updated_at").notNull(),
|
||||
});
|
||||
|
||||
export const twofaSessions = pgTable("twofa_sessions", {
|
||||
id: text("id").primaryKey(),
|
||||
userId: text("user_id")
|
||||
.notNull()
|
||||
.references(() => user.id, { onDelete: "cascade" }),
|
||||
sessionId: text("session_id").notNull(), // Better Auth session ID
|
||||
|
||||
// Verification Tracking
|
||||
verificationToken: text("verification_token").notNull().unique(), // Unique nonce for this attempt
|
||||
codeUsed: text("code_used"), // The TOTP code submitted (prevent replay)
|
||||
status: varchar("status", { length: 16 }).notNull(), // "pending" | "verified" | "failed" | "expired"
|
||||
|
||||
attempts: integer("attempts").default(0).notNull(),
|
||||
maxAttempts: integer("max_attempts").default(5).notNull(),
|
||||
|
||||
verifiedAt: timestamp("verified_at"),
|
||||
expiresAt: timestamp("expires_at").notNull(),
|
||||
createdAt: timestamp("created_at").notNull(),
|
||||
|
||||
// Security Audit
|
||||
ipAddress: text("ip_address").default(""),
|
||||
userAgent: text("user_agent").default(""),
|
||||
});
|
||||
|
||||
export const twofaSessionsRelations = relations(twofaSessions, ({ one }) => ({
|
||||
userAccount: one(user, {
|
||||
fields: [twofaSessions.userId],
|
||||
references: [user.id],
|
||||
}),
|
||||
}));
|
||||
75
packages/db/schema/better.auth.schema.ts
Normal file
75
packages/db/schema/better.auth.schema.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { boolean, index, pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
||||
import { relations } from "drizzle-orm";
|
||||
|
||||
export const user = pgTable("user", {
|
||||
id: text("id").primaryKey(),
|
||||
name: text("name").notNull(),
|
||||
email: text("email").notNull().unique(),
|
||||
emailVerified: boolean("email_verified").default(false).notNull(),
|
||||
image: text("image"),
|
||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updated_at")
|
||||
.defaultNow()
|
||||
.$onUpdate(() => /* @__PURE__ */ new Date())
|
||||
.notNull(),
|
||||
username: text("username").unique(),
|
||||
displayUsername: text("display_username"),
|
||||
role: text("role"),
|
||||
banned: boolean("banned").default(false),
|
||||
banReason: text("ban_reason"),
|
||||
banExpires: timestamp("ban_expires"),
|
||||
onboardingDone: boolean("onboarding_done").default(false),
|
||||
last2FAVerifiedAt: timestamp("last2_fa_verified_at"),
|
||||
parentId: text("parent_id"),
|
||||
});
|
||||
|
||||
export const account = pgTable(
|
||||
"account",
|
||||
{
|
||||
id: text("id").primaryKey(),
|
||||
accountId: text("account_id").notNull(),
|
||||
providerId: text("provider_id").notNull(),
|
||||
userId: text("user_id")
|
||||
.notNull()
|
||||
.references(() => user.id, { onDelete: "cascade" }),
|
||||
accessToken: text("access_token"),
|
||||
refreshToken: text("refresh_token"),
|
||||
idToken: text("id_token"),
|
||||
accessTokenExpiresAt: timestamp("access_token_expires_at"),
|
||||
refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
|
||||
scope: text("scope"),
|
||||
password: text("password"),
|
||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updated_at")
|
||||
.$onUpdate(() => /* @__PURE__ */ new Date())
|
||||
.notNull(),
|
||||
},
|
||||
(table) => [index("account_userId_idx").on(table.userId)],
|
||||
);
|
||||
|
||||
export const verification = pgTable(
|
||||
"verification",
|
||||
{
|
||||
id: text("id").primaryKey(),
|
||||
identifier: text("identifier").notNull(),
|
||||
value: text("value").notNull(),
|
||||
expiresAt: timestamp("expires_at").notNull(),
|
||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updated_at")
|
||||
.defaultNow()
|
||||
.$onUpdate(() => /* @__PURE__ */ new Date())
|
||||
.notNull(),
|
||||
},
|
||||
(table) => [index("verification_identifier_idx").on(table.identifier)],
|
||||
);
|
||||
|
||||
export const userRelations = relations(user, ({ many }) => ({
|
||||
accounts: many(account),
|
||||
}));
|
||||
|
||||
export const accountRelations = relations(account, ({ one }) => ({
|
||||
user: one(user, {
|
||||
fields: [account.userId],
|
||||
references: [user.id],
|
||||
}),
|
||||
}));
|
||||
49
packages/db/schema/general.schema.ts
Normal file
49
packages/db/schema/general.schema.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import {
|
||||
boolean,
|
||||
json,
|
||||
pgTable,
|
||||
serial,
|
||||
text,
|
||||
timestamp,
|
||||
varchar,
|
||||
} from "drizzle-orm/pg-core";
|
||||
import { user } from "./better.auth.schema";
|
||||
import { relations } from "drizzle-orm";
|
||||
|
||||
export const notifications = pgTable("notifications", {
|
||||
id: serial("id").primaryKey(),
|
||||
|
||||
title: text("title").notNull(),
|
||||
body: text("body").notNull(),
|
||||
priority: varchar("priority", { length: 12 }).default("normal").notNull(), // "low", "normal", "high", "urgent"
|
||||
|
||||
type: varchar("type", { length: 12 }).notNull(),
|
||||
category: varchar("category", { length: 64 }),
|
||||
|
||||
isRead: boolean("is_read").default(false).notNull(),
|
||||
isArchived: boolean("is_archived").default(false).notNull(),
|
||||
|
||||
actionUrl: text("action_url"), // URL to navigate to when clicked
|
||||
actionType: varchar("action_type", { length: 16 }), // Type of action ("link", "function", etc.)
|
||||
actionData: json("action_data"), // Any additional data for the action
|
||||
|
||||
icon: varchar("icon", { length: 64 }), // Optional icon identifier
|
||||
|
||||
userId: text("user_id")
|
||||
.notNull()
|
||||
.references(() => user.id, { onDelete: "cascade" }),
|
||||
|
||||
// Lifecycle management
|
||||
sentAt: timestamp("sent_at").notNull(),
|
||||
readAt: timestamp("read_at"),
|
||||
expiresAt: timestamp("expires_at"),
|
||||
createdAt: timestamp("created_at").notNull(),
|
||||
updatedAt: timestamp("updated_at").notNull(),
|
||||
});
|
||||
|
||||
export const notificationsRelations = relations(notifications, ({ one }) => ({
|
||||
userAccount: one(user, {
|
||||
fields: [notifications.userId],
|
||||
references: [user.id],
|
||||
}),
|
||||
}));
|
||||
3
packages/db/schema/index.ts
Normal file
3
packages/db/schema/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from "./auth.schema";
|
||||
export * from "./better.auth.schema";
|
||||
export * from "./general.schema";
|
||||
Reference in New Issue
Block a user