generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}

model User {
  id          String   @id @default(uuid())
  pubkey      String   @unique
  role        String? // admin, moderator, writer. Null means Guest (no elevated role). SuperAdmin is env-sourced and never stored.
  displayName String?
  username    String?  @unique
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt
}

// Scoped API key for programmatic access. The raw key is shown to the creator
// only once; only its SHA-256 hash is stored. `permissions` is a JSON array of
// permission keys that gate what the key may do.
model ApiKey {
  id              String    @id @default(uuid())
  name            String
  prefix          String // leading characters of the raw key, for display
  keyHash         String    @unique // SHA-256 hex of the full key
  permissions     String // JSON array of permission keys
  createdByPubkey String
  lastUsedAt      DateTime?
  revokedAt       DateTime?
  createdAt       DateTime  @default(now())
}

// Maps an assignable role to a granted permission key. Editable at runtime.
// One row per (role, permission). SuperAdmin is never stored here; it bypasses
// all checks via the env list.
model RolePermission {
  role       String
  permission String
  createdAt  DateTime @default(now())

  @@id([role, permission])
}

model Organizer {
  id        String   @id @default(uuid())
  name      String
  slug      String   @unique
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  meetups   Meetup[]
}

model Meetup {
  id          String    @id @default(uuid())
  title       String
  description String
  date        String
  time        String
  location    String
  link        String?
  imageId     String?
  status      String    @default("DRAFT") // DRAFT, PUBLISHED, CANCELLED (Upcoming/Past derived from date)
  featured    Boolean   @default(false)
  visibility  String    @default("PUBLIC") // PUBLIC, HIDDEN
  organizerId String
  organizer   Organizer @relation(fields: [organizerId], references: [id], onDelete: Restrict)
  createdAt   DateTime  @default(now())
  updatedAt   DateTime  @updatedAt
}

model Media {
  id               String   @id // ULID, not auto-generated
  slug             String
  type             String   // "image" | "video"
  mimeType         String
  size             Int
  originalFilename String
  uploadedBy       String
  title            String?
  description      String?
  altText          String?
  createdAt        DateTime @default(now())
}

model Post {
  id            String         @id @default(uuid())
  nostrEventId  String         @unique
  naddr         String?
  title         String
  slug          String         @unique
  content       String         @default("")
  excerpt       String?
  authorPubkey  String
  authorName    String?
  featured      Boolean        @default(false)
  visible       Boolean        @default(true)
  publishedAt   DateTime
  createdAt     DateTime       @default(now())
  updatedAt     DateTime       @updatedAt
  categories    PostCategory[]
}

model Category {
  id        String         @id @default(uuid())
  name      String
  slug      String         @unique
  sortOrder Int            @default(0)
  createdAt DateTime       @default(now())
  posts     PostCategory[]
}

model PostCategory {
  postId     String
  categoryId String
  post       Post     @relation(fields: [postId], references: [id], onDelete: Cascade)
  category   Category @relation(fields: [categoryId], references: [id], onDelete: Cascade)

  @@id([postId, categoryId])
}

model HiddenContent {
  id           String   @id @default(uuid())
  nostrEventId String
  reason       String?
  hiddenBy     String
  createdAt    DateTime @default(now())
}

model BlockedPubkey {
  id        String   @id @default(uuid())
  pubkey    String
  reason    String?
  blockedBy String
  createdAt DateTime @default(now())
}

model Relay {
  id        String   @id @default(uuid())
  url       String   @unique
  priority  Int      @default(0)
  active    Boolean  @default(true)
  createdAt DateTime @default(now())
}

model UserRelay {
  id        String   @id @default(uuid())
  pubkey    String
  url       String
  read      Boolean  @default(true)
  write     Boolean  @default(true)
  createdAt DateTime @default(now())

  @@unique([pubkey, url])
}

model Setting {
  id        String   @id @default(uuid())
  key       String   @unique
  value     String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

model NostrEventCache {
  id        String   @id @default(uuid())
  eventId   String   @unique
  kind      Int
  pubkey    String
  content   String
  tags      String // JSON string
  createdAt Int // event timestamp
  cachedAt  DateTime @default(now())
}

model Submission {
  id           String   @id @default(uuid())
  eventId      String?
  naddr        String?
  title        String
  authorPubkey String
  status       String   @default("PENDING") // PENDING, APPROVED, REJECTED
  reviewedBy   String?
  reviewNote   String?
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt
}

model Faq {
  id             String   @id @default(uuid())
  question       String
  answer         String
  order          Int      @default(0)
  showOnHomepage Boolean  @default(true)
  createdAt      DateTime @default(now())
  updatedAt      DateTime @updatedAt
}

/// Pending Lightning invoice metadata (message is created only after payment via webhook).
model BoardInvoicePending {
  paymentHash String   @id
  content     String
  guestName   String?
  pubkey      String?
  profilePic  String?
  createdAt   DateTime @default(now())
}

/// Paid board message (LNbits payment confirmed).
model BoardMessage {
  id          String   @id @default(uuid())
  paymentHash String   @unique
  content     String
  authorName  String
  pubkey      String?
  profilePic  String?
  satsPaid    Int
  status      String   @default("active") // active, hidden, deleted
  likeCount   Int      @default(0)
  createdAt   DateTime @default(now())
}
