Files
Space-Banane 7e05dd918c
Deploy / Build (push) Successful in 28s
Deploy / Test & Lint (push) Failing after 29s
Deploy / Build and Push Docker Image (push) Has been skipped
Patchpass V1
2026-07-18 20:14:44 +02:00

215 lines
6.3 KiB
Plaintext

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])
}