first commit
This commit is contained in:
139
prisma/schema.prisma
Normal file
139
prisma/schema.prisma
Normal file
@@ -0,0 +1,139 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
}
|
||||
|
||||
enum Role {
|
||||
USER
|
||||
ADMIN
|
||||
}
|
||||
|
||||
enum QrStatus {
|
||||
PENDING
|
||||
SCANNED
|
||||
CONFIRMED
|
||||
EXPIRED
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
email String @unique
|
||||
phone String? @unique
|
||||
passwordHash String? @map("password_hash")
|
||||
displayName String? @map("display_name")
|
||||
avatarUrl String? @map("avatar_url")
|
||||
role Role @default(USER)
|
||||
isActive Boolean @default(true) @map("is_active")
|
||||
emailVerifiedAt DateTime? @map("email_verified_at")
|
||||
phoneVerifiedAt DateTime? @map("phone_verified_at")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
ownedClients Client[] @relation("ClientOwner")
|
||||
sessions Session[]
|
||||
auditLogs AuditLog[]
|
||||
verificationCodes VerificationCode[]
|
||||
qrSessions QrSession[]
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
|
||||
model Client {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
name String
|
||||
description String?
|
||||
clientId String @unique @map("client_id")
|
||||
clientSecret String? @map("client_secret")
|
||||
redirectUris String[] @map("redirect_uris")
|
||||
grants String[]
|
||||
isConfidential Boolean @default(true) @map("is_confidential")
|
||||
ownerId String? @map("owner_id") @db.Uuid
|
||||
logoUrl String? @map("logo_url")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
owner User? @relation("ClientOwner", fields: [ownerId], references: [id], onDelete: SetNull)
|
||||
sessions Session[]
|
||||
|
||||
@@map("clients")
|
||||
}
|
||||
|
||||
model Session {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
userId String @map("user_id") @db.Uuid
|
||||
clientId String? @map("client_id") @db.Uuid
|
||||
ip String?
|
||||
userAgent String? @map("user_agent")
|
||||
isActive Boolean @default(true) @map("is_active")
|
||||
expiresAt DateTime @map("expires_at")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
lastUsedAt DateTime @default(now()) @map("last_used_at")
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
client Client? @relation(fields: [clientId], references: [id], onDelete: SetNull)
|
||||
refreshTokens RefreshToken[]
|
||||
|
||||
@@map("sessions")
|
||||
}
|
||||
|
||||
model RefreshToken {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
tokenHash String @unique @map("token_hash")
|
||||
sessionId String @map("session_id") @db.Uuid
|
||||
expiresAt DateTime @map("expires_at")
|
||||
revoked Boolean @default(false)
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
session Session @relation(fields: [sessionId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@map("refresh_tokens")
|
||||
}
|
||||
|
||||
model VerificationCode {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
userId String? @map("user_id") @db.Uuid
|
||||
target String
|
||||
channel String
|
||||
code String
|
||||
purpose String @default("AUTH")
|
||||
expiresAt DateTime @map("expires_at")
|
||||
usedAt DateTime? @map("used_at")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@map("verification_codes")
|
||||
}
|
||||
|
||||
model QrSession {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
sessionId String @unique @map("session_id")
|
||||
userId String? @map("user_id") @db.Uuid
|
||||
status QrStatus @default(PENDING)
|
||||
qrData String? @map("qr_data")
|
||||
deviceInfo String? @map("device_info")
|
||||
expiresAt DateTime @map("expires_at")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
confirmedAt DateTime? @map("confirmed_at")
|
||||
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
|
||||
|
||||
@@map("qr_sessions")
|
||||
}
|
||||
|
||||
model AuditLog {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
userId String? @map("user_id") @db.Uuid
|
||||
action String
|
||||
details Json?
|
||||
ip String?
|
||||
userAgent String? @map("user_agent")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
|
||||
|
||||
@@map("audit_logs")
|
||||
}
|
||||
49
prisma/seed.ts
Normal file
49
prisma/seed.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { PrismaClient, Role } from "@prisma/client";
|
||||
import * as argon2 from "argon2";
|
||||
import { randomBytes } from "node:crypto";
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const prisma = new PrismaClient({ datasourceUrl: process.env.DATABASE_URL });
|
||||
|
||||
const adminEmail = "admin@sso.local";
|
||||
const adminPassword = "admin123!";
|
||||
|
||||
const existingAdmin = await prisma.user.findUnique({ where: { email: adminEmail } });
|
||||
if (!existingAdmin) {
|
||||
const passwordHash = await argon2.hash(adminPassword);
|
||||
await prisma.user.create({
|
||||
data: {
|
||||
email: adminEmail,
|
||||
passwordHash,
|
||||
displayName: "SSO Admin",
|
||||
role: Role.ADMIN,
|
||||
},
|
||||
});
|
||||
console.log(`Admin user created: ${adminEmail} / ${adminPassword}`);
|
||||
}
|
||||
|
||||
const testClientId = "test-client";
|
||||
const existingClient = await prisma.client.findUnique({ where: { clientId: testClientId } });
|
||||
if (!existingClient) {
|
||||
const clientSecret = randomBytes(32).toString("hex");
|
||||
await prisma.client.create({
|
||||
data: {
|
||||
name: "Test OAuth Client",
|
||||
clientId: testClientId,
|
||||
clientSecret,
|
||||
redirectUris: ["http://localhost:5173/callback", "http://localhost:3000/callback"],
|
||||
grants: ["authorization_code", "client_credentials", "refresh_token"],
|
||||
isConfidential: true,
|
||||
},
|
||||
});
|
||||
console.log(`OAuth client created: ${testClientId} / ${clientSecret}`);
|
||||
}
|
||||
|
||||
console.log("Seed complete.");
|
||||
await prisma.$disconnect();
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error("Seed failed:", e);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user