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 }