Patchpass V1
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Enums
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
enum UserRole {
|
||||
ADMIN
|
||||
USER
|
||||
}
|
||||
|
||||
enum RequestState {
|
||||
PENDING
|
||||
CHANGES_REQUESTED
|
||||
APPROVED
|
||||
REJECTED
|
||||
EXPIRED
|
||||
CONSUMED
|
||||
CANCELLED
|
||||
}
|
||||
|
||||
enum NotificationType {
|
||||
REQUEST_CREATED
|
||||
REQUEST_UPDATED
|
||||
REQUEST_APPROVED
|
||||
REQUEST_REJECTED
|
||||
CHANGES_REQUESTED
|
||||
REQUEST_CONSUMED
|
||||
REQUEST_CANCELLED
|
||||
REQUEST_EXPIRED
|
||||
AGENT_DISABLED
|
||||
ADMIN_ACTION
|
||||
SETTINGS_CHANGED
|
||||
}
|
||||
|
||||
enum GlobalSettingType {
|
||||
registration_enabled
|
||||
requests_enabled
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Models
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// A global (admin-only) platform setting, keyed by type.
|
||||
model GlobalSetting {
|
||||
type GlobalSettingType @id
|
||||
value String
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
/// A human account. The first registered user becomes ADMIN.
|
||||
model User {
|
||||
id Int @id @default(autoincrement())
|
||||
/// Normalized (lowercased) username — enforces case-insensitive uniqueness.
|
||||
username String @unique
|
||||
/// Original-cased display handle shown in the UI.
|
||||
displayName String
|
||||
password String
|
||||
role UserRole @default(USER)
|
||||
|
||||
// Optional TOTP two-factor auth
|
||||
totpSecret String?
|
||||
totpEnabled Boolean @default(false)
|
||||
|
||||
// Admin can disable a human account entirely
|
||||
disabled Boolean @default(false)
|
||||
|
||||
// Auto-delete of old change requests (opt-in, min 7 days, default 30)
|
||||
autoDeleteEnabled Boolean @default(false)
|
||||
autoDeleteDays Int @default(30)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
sessions Session[]
|
||||
agents Agent[]
|
||||
changeRequests ChangeRequest[] @relation("Owner")
|
||||
decisions ChangeRequest[] @relation("Approver")
|
||||
notifications Notification[]
|
||||
auditLogs AuditLog[] @relation("AuditActor")
|
||||
}
|
||||
|
||||
/// A browser session for a human account (cookie-based auth).
|
||||
model Session {
|
||||
id Int @id @default(autoincrement())
|
||||
hash String @unique
|
||||
userId Int
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([userId])
|
||||
}
|
||||
|
||||
/// An AGENT account. Fully managed by a human owner. Holds exactly one API key.
|
||||
model Agent {
|
||||
id Int @id @default(autoincrement())
|
||||
name String
|
||||
description String?
|
||||
website String?
|
||||
iconUrl String?
|
||||
/// The single API key the agent authenticates with.
|
||||
apiKey String @unique
|
||||
disabled Boolean @default(false)
|
||||
/// Max simultaneous pending requests (1..10, human-configurable, default 5).
|
||||
maxPendingRequests Int @default(5)
|
||||
|
||||
ownerId Int
|
||||
owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
changeRequests ChangeRequest[]
|
||||
|
||||
@@index([ownerId])
|
||||
}
|
||||
|
||||
/// A structured change request submitted by an agent for human approval.
|
||||
model ChangeRequest {
|
||||
id Int @id @default(autoincrement())
|
||||
/// Public UUID (v4) exposed to agents as request_id.
|
||||
publicId String @unique @default(uuid())
|
||||
|
||||
title String
|
||||
description String?
|
||||
/// Normalized changes array (diffs normalized, canonical ordering).
|
||||
changes Json
|
||||
/// Original changes exactly as submitted (audit trail).
|
||||
rawChanges Json
|
||||
metadata Json?
|
||||
/// SHA-256 hash over the canonical (title + description + normalized changes).
|
||||
contentHash String
|
||||
|
||||
state RequestState @default(PENDING)
|
||||
|
||||
expiresAt DateTime
|
||||
|
||||
// Decision fields
|
||||
comment String?
|
||||
decidedAt DateTime?
|
||||
approverId Int?
|
||||
approver User? @relation("Approver", fields: [approverId], references: [id], onDelete: SetNull)
|
||||
/// HMAC-SHA256 signature of the approval receipt (platform-signed decision).
|
||||
signature String?
|
||||
receiptIssuedAt DateTime?
|
||||
|
||||
consumedAt DateTime?
|
||||
cancelledAt DateTime?
|
||||
|
||||
// Update tracking for the CHANGES_REQUESTED → resubmit loop
|
||||
updateCount Int @default(0)
|
||||
/// True after an agent resubmits following a CHANGES_REQUESTED decision.
|
||||
resubmitted Boolean @default(false)
|
||||
lastAgentUpdateAt DateTime?
|
||||
|
||||
agentId Int
|
||||
agent Agent @relation(fields: [agentId], references: [id], onDelete: Cascade)
|
||||
|
||||
// The human who owns/reviews this request (the agent's owner at creation time).
|
||||
userId Int
|
||||
user User @relation("Owner", fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([userId, state])
|
||||
@@index([agentId, state])
|
||||
@@index([createdAt])
|
||||
}
|
||||
|
||||
/// An in-app notification for a human account.
|
||||
model Notification {
|
||||
id Int @id @default(autoincrement())
|
||||
type NotificationType
|
||||
title String
|
||||
message String
|
||||
/// Optional link to a change request (publicId).
|
||||
requestPublicId String?
|
||||
read Boolean @default(false)
|
||||
|
||||
userId Int
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([userId, read])
|
||||
@@index([userId, createdAt])
|
||||
}
|
||||
|
||||
/// An audit log entry. Records privileged/admin actions and payload views.
|
||||
model AuditLog {
|
||||
id Int @id @default(autoincrement())
|
||||
action String
|
||||
/// Human-readable detail / JSON string of context.
|
||||
detail String?
|
||||
/// Optional target references.
|
||||
targetType String?
|
||||
targetId String?
|
||||
|
||||
actorId Int?
|
||||
actor User? @relation("AuditActor", fields: [actorId], references: [id], onDelete: SetNull)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([createdAt])
|
||||
@@index([actorId])
|
||||
}
|
||||
Reference in New Issue
Block a user