- Add Prisma schema for AdminUser, Source, Article, SearchRule, SearchRun, and encrypted ApiKey storage. - Implement JWT session middleware and admin login/logout. - Add AES-256-GCM encryption helpers for API keys. - Seed default news sources and admin credentials. - Create admin shell layout and login page.
128 lines
3.2 KiB
Plaintext
128 lines
3.2 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "sqlite"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
model AdminUser {
|
|
id String @id @default(cuid())
|
|
username String @unique
|
|
passwordHash String
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
model Source {
|
|
id String @id @default(cuid())
|
|
name String
|
|
baseUrl String?
|
|
apiCode String @unique
|
|
defaultBias Bias?
|
|
credibilityScore Float @default(5)
|
|
active Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
articles Article[]
|
|
}
|
|
|
|
model Article {
|
|
id String @id @default(cuid())
|
|
title String
|
|
summary String?
|
|
url String @unique
|
|
sourceId String
|
|
source Source @relation(fields: [sourceId], references: [id])
|
|
imageUrl String?
|
|
publishedAt DateTime?
|
|
fetchedAt DateTime @default(now())
|
|
primaryBias Bias
|
|
biasConfidence Float @default(0)
|
|
politicalTags String @default("[]")
|
|
rankScore Float @default(0)
|
|
credibilityScore Float @default(5)
|
|
status ArticleStatus @default(DRAFT)
|
|
topics String @default("[]")
|
|
rawData String @default("{}")
|
|
aiExplanation String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([primaryBias, status])
|
|
@@index([status, publishedAt])
|
|
@@index([rankScore])
|
|
}
|
|
|
|
model ApiKey {
|
|
id String @id @default(cuid())
|
|
provider ApiProvider
|
|
encryptedKey String
|
|
label String?
|
|
isActive Boolean @default(true)
|
|
lastUsedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([provider, isActive])
|
|
}
|
|
|
|
model SearchRule {
|
|
id String @id @default(cuid())
|
|
name String
|
|
query String
|
|
sources String @default("[]")
|
|
schedule String @default("0 */6 * * *")
|
|
maxResults Int @default(20)
|
|
autoPublish Boolean @default(false)
|
|
minRankScore Float @default(5)
|
|
isActive Boolean @default(true)
|
|
aiProvider ApiProvider @default(KIMI)
|
|
aiModel String?
|
|
lastRunAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
runs SearchRun[]
|
|
}
|
|
|
|
model SearchRun {
|
|
id String @id @default(cuid())
|
|
ruleId String
|
|
rule SearchRule @relation(fields: [ruleId], references: [id], onDelete: Cascade)
|
|
status RunStatus @default(RUNNING)
|
|
stage String? // e.g. "FETCHING", "ANALYZING", "SAVING"
|
|
progress String? // human-readable progress, e.g. "3 of 12"
|
|
articlesFound Int @default(0)
|
|
error String?
|
|
startedAt DateTime @default(now())
|
|
endedAt DateTime?
|
|
}
|
|
|
|
enum Bias {
|
|
LEFT
|
|
CENTER
|
|
RIGHT
|
|
}
|
|
|
|
enum ArticleStatus {
|
|
DRAFT
|
|
PUBLISHED
|
|
ARCHIVED
|
|
}
|
|
|
|
enum ApiProvider {
|
|
NEWSAPI
|
|
GNEWS
|
|
KIMI
|
|
WEBSEARCH
|
|
NEWSDATA
|
|
BRAVE
|
|
}
|
|
|
|
enum RunStatus {
|
|
RUNNING
|
|
SUCCESS
|
|
ERROR
|
|
}
|