Additive, non-breaking schema prep for the Option D live-evaluation ACL: - Request gains keyUserId (FK) + @@index([keyUserId, method]) so token usage caps can be derived live by COUNTing allowed Requests, replacing the never-enforced mutable PolicyRule.currentUsageCount (derive-don't-count, per lnbits/nostr_bunker prior art). - SigningCondition gains createdAt/expiresAt/revokedAt so the manual-override layer carries its own lifecycle and runs through the same grantIsLive(now) predicate as token grants (D1: two typed sources, one shared rule). No behavior change yet; the ACL hot path and applyToken de-materialization follow in subsequent commits. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
137 lines
4.1 KiB
Text
137 lines
4.1 KiB
Text
generator client {
|
|
provider = "prisma-client-js"
|
|
binaryTargets = ["native", "linux-musl-openssl-3.0.x", "linux-musl-arm64-openssl-3.0.x"]
|
|
}
|
|
|
|
datasource db {
|
|
provider = "sqlite"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
model Request {
|
|
id String @id @default(uuid())
|
|
keyName String?
|
|
createdAt DateTime @default(now())
|
|
requestId String
|
|
remotePubkey String
|
|
method String
|
|
params String?
|
|
allowed Boolean?
|
|
// Bind each request to the KeyUser it was evaluated against so usage
|
|
// caps can be derived live by COUNTing allowed Requests, instead of
|
|
// maintaining a mutable PolicyRule.currentUsageCount that drifts.
|
|
// See aiolabs/nsecbunkerd#25 (Option D, derive-don't-count).
|
|
keyUserId Int?
|
|
KeyUser KeyUser? @relation(fields: [keyUserId], references: [id])
|
|
|
|
@@index([keyUserId, method])
|
|
}
|
|
|
|
model KeyUser {
|
|
id Int @id @default(autoincrement())
|
|
keyName String
|
|
userPubkey String
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @default(now()) @updatedAt
|
|
revokedAt DateTime?
|
|
lastUsedAt DateTime?
|
|
description String?
|
|
logs Log[]
|
|
signingConditions SigningCondition[]
|
|
Token Token[]
|
|
requests Request[]
|
|
|
|
@@unique([keyName, userPubkey], name: "unique_key_user")
|
|
}
|
|
|
|
model Key {
|
|
id Int @id @default(autoincrement())
|
|
keyName String @unique
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @default(now()) @updatedAt
|
|
deletedAt DateTime?
|
|
pubkey String
|
|
}
|
|
|
|
model User {
|
|
id Int @id @default(autoincrement())
|
|
username String @unique
|
|
domain String
|
|
password String
|
|
email String
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @default(now()) @updatedAt
|
|
deletedAt DateTime?
|
|
pubkey String
|
|
}
|
|
|
|
// The SigningCondition layer is the MANUAL-OVERRIDE source of truth
|
|
// (web-approval / add_signing_condition / create_account bootstrap) — it is
|
|
// no longer materialized from token policies (see aiolabs/nsecbunkerd#25:
|
|
// applyToken stopped photocopying; token grants are evaluated live off
|
|
// Token -> Policy -> PolicyRule). Under D1 the override layer carries its
|
|
// own lifecycle so it runs through the same grantIsLive(now) predicate as
|
|
// token grants.
|
|
model SigningCondition {
|
|
id Int @id @default(autoincrement())
|
|
method String?
|
|
kind String?
|
|
content String?
|
|
keyUserKeyName String?
|
|
allowed Boolean?
|
|
keyUserId Int?
|
|
createdAt DateTime @default(now())
|
|
expiresAt DateTime?
|
|
revokedAt DateTime?
|
|
KeyUser KeyUser? @relation(fields: [keyUserId], references: [id])
|
|
}
|
|
|
|
model Log {
|
|
id Int @id @default(autoincrement())
|
|
timestamp DateTime
|
|
type String
|
|
method String?
|
|
params String?
|
|
keyUserId Int?
|
|
KeyUser KeyUser? @relation(fields: [keyUserId], references: [id])
|
|
}
|
|
|
|
model Policy {
|
|
id Int @id @default(autoincrement())
|
|
name String
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @default(now()) @updatedAt
|
|
expiresAt DateTime?
|
|
deletedAt DateTime?
|
|
description String?
|
|
rules PolicyRule[]
|
|
Token Token[]
|
|
}
|
|
|
|
model PolicyRule {
|
|
id Int @id @default(autoincrement())
|
|
method String
|
|
kind String?
|
|
maxUsageCount Int?
|
|
currentUsageCount Int?
|
|
policyId Int?
|
|
Policy Policy? @relation(fields: [policyId], references: [id])
|
|
}
|
|
|
|
model Token {
|
|
id Int @id @default(autoincrement())
|
|
keyName String
|
|
token String @unique
|
|
clientName String
|
|
createdBy String
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @default(now()) @updatedAt
|
|
deletedAt DateTime?
|
|
expiresAt DateTime?
|
|
redeemedAt DateTime?
|
|
revokedAt DateTime?
|
|
keyUserId Int?
|
|
policyId Int?
|
|
policy Policy? @relation(fields: [policyId], references: [id])
|
|
KeyUser KeyUser? @relation(fields: [keyUserId], references: [id])
|
|
}
|