This repository has been archived on 2026-08-19. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
maple-brief-aggregator/prisma/schema.prisma
T
krisf 1010f27f44 MapleBrief: production Canadian news aggregator
Next.js 14 + TypeScript + Tailwind + Prisma/SQLite.
- LLM synthesis abstraction (OpenAI/Anthropic/Ollama) + admin settings UI
- RSS ingestion pipeline (parser + cheerio content) + node-cron worker
- AdSense AdUnit placements (header/in-feed/in-article/sidebar)
- Sources analysis attribution, nofollow links, canonical/OG, sitemap/robots
- Admin auth (ADMIN_API_KEY, timingSafeEqual, fail-closed 401)
- Multi-cell lady-ga-ga marker, sitemap, robots, legal pages
- Comprehensive README (setup, LLM config, AdSense, migrations, deploy)
2026-08-15 16:07:07 -04:00

80 lines
3.0 KiB
Plaintext

// MapleBrief — database schema
// SQLite by default for zero-config local dev. To switch provider:
// 1. change `provider` in datasource below
// 2. update DATABASE_URL in .env
// 3. run `prisma migrate dev` (see README)
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
// A configured news source (RSS/Atom feed).
model Feed {
id String @id @default(cuid())
name String @unique
url String @unique
slug String
category String @default("news")
enabled Boolean @default(true)
lastFetchedAt DateTime?
articles Article[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// A single synthesized news brief, built from one or more source stories.
model Article {
id String @id @default(cuid())
feedId String?
feed Feed? @relation(fields: [feedId], references: [id], onDelete: SetNull)
// Identity / dedup
guid String? @unique // feed item guid (primary dedup key)
dedupKey String // sha1 of normalized title (near-dup key)
sourceUrl String // original story URL (outbound link)
canonicalUrl String @unique // our canonical URL for this brief
siteName String // originating publisher, e.g. "CBC News"
// Source metadata
title String // original headline (kept for reference)
slug String @unique
category String @default("news") // mapped from the feed category
author String?
publishedAt DateTime?
image String? // original thumbnail URL
sources String? // JSON string[] of contributing publisher names
// Original content (kept for the "editor's notes" reference, NOT shown)
originalText String?
// Synthesized (original) output produced by the LLM
headline String? // rewritten original headline
body String? // 3 paragraphs, \n\n separated
takeaways String? // JSON string[] of key takeaways
tags String? // JSON string[]
llmProvider String? // provider that produced this brief
synthesizedAt DateTime?
status String @default("fetched") // fetched | synthesized | failed
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([category, publishedAt])
@@index([status, publishedAt])
@@index([dedupKey])
}
// Runtime configuration. The /admin/settings UI writes here; env vars act as
// fallbacks when a key is absent so the app boots with zero configuration.
model Setting {
key String @id
value String
isSecret Boolean @default(false)
updatedAt DateTime @updatedAt
}