Initial human archive app
Some checks failed
Build and publish Docker image / docker (push) Failing after 2m33s

This commit is contained in:
2026-06-26 21:31:46 +02:00
parent ee2a0202d7
commit f29339cf12
38 changed files with 3644 additions and 112 deletions

View File

@@ -0,0 +1,244 @@
-- CreateEnum
CREATE TYPE "Role" AS ENUM ('VISITOR', 'MEMBER', 'ADMIN');
-- CreateEnum
CREATE TYPE "Language" AS ENUM ('DE', 'EN');
-- CreateEnum
CREATE TYPE "TrustLevel" AS ENUM ('UNKNOWN', 'LOW', 'MEDIUM', 'HIGH', 'PRIMARY');
-- CreateEnum
CREATE TYPE "EntryStatus" AS ENUM ('DRAFT', 'PUBLISHED', 'BLOCKED', 'ARCHIVED');
-- CreateEnum
CREATE TYPE "ContributionStatus" AS ENUM ('PENDING', 'APPROVED', 'REJECTED', 'NEEDS_ADMIN_REVIEW');
-- CreateEnum
CREATE TYPE "ModerationOutcome" AS ENUM ('APPROVE', 'REJECT', 'ESCALATE');
-- CreateEnum
CREATE TYPE "ContributionOrigin" AS ENUM ('COMMUNITY', 'AI_RESEARCH', 'ADMIN');
-- CreateTable
CREATE TABLE "User" (
"id" TEXT NOT NULL,
"name" TEXT,
"email" TEXT,
"emailVerified" TIMESTAMP(3),
"image" TEXT,
"passwordHash" TEXT,
"role" "Role" NOT NULL DEFAULT 'MEMBER',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Account" (
"id" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"type" TEXT NOT NULL,
"provider" TEXT NOT NULL,
"providerAccountId" TEXT NOT NULL,
"refresh_token" TEXT,
"access_token" TEXT,
"expires_at" INTEGER,
"token_type" TEXT,
"scope" TEXT,
"id_token" TEXT,
"session_state" TEXT,
CONSTRAINT "Account_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Session" (
"id" TEXT NOT NULL,
"sessionToken" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"expires" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Session_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "VerificationToken" (
"identifier" TEXT NOT NULL,
"token" TEXT NOT NULL,
"expires" TIMESTAMP(3) NOT NULL
);
-- CreateTable
CREATE TABLE "Source" (
"id" TEXT NOT NULL,
"title" TEXT NOT NULL,
"url" TEXT NOT NULL,
"author" TEXT,
"institution" TEXT,
"license" TEXT,
"language" "Language" NOT NULL,
"retrievedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"trustLevel" "TrustLevel" NOT NULL DEFAULT 'UNKNOWN',
"notes" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Source_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "KnowledgeEntry" (
"id" TEXT NOT NULL,
"title" TEXT NOT NULL,
"slug" TEXT NOT NULL,
"language" "Language" NOT NULL,
"summary" TEXT NOT NULL,
"content" JSONB NOT NULL,
"timelineStart" TIMESTAMP(3),
"timelineEnd" TIMESTAMP(3),
"tags" TEXT[],
"status" "EntryStatus" NOT NULL DEFAULT 'DRAFT',
"version" INTEGER NOT NULL DEFAULT 1,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "KnowledgeEntry_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "KnowledgeEntrySource" (
"entryId" TEXT NOT NULL,
"sourceId" TEXT NOT NULL,
"note" TEXT,
CONSTRAINT "KnowledgeEntrySource_pkey" PRIMARY KEY ("entryId","sourceId")
);
-- CreateTable
CREATE TABLE "Contribution" (
"id" TEXT NOT NULL,
"origin" "ContributionOrigin" NOT NULL,
"status" "ContributionStatus" NOT NULL DEFAULT 'PENDING',
"title" TEXT NOT NULL,
"language" "Language" NOT NULL,
"proposedContent" JSONB NOT NULL,
"rationale" TEXT,
"authorId" TEXT,
"entryId" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Contribution_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "ContributionSource" (
"contributionId" TEXT NOT NULL,
"sourceId" TEXT NOT NULL,
CONSTRAINT "ContributionSource_pkey" PRIMARY KEY ("contributionId","sourceId")
);
-- CreateTable
CREATE TABLE "ModerationDecision" (
"id" TEXT NOT NULL,
"contributionId" TEXT NOT NULL,
"outcome" "ModerationOutcome" NOT NULL,
"riskCategories" TEXT[],
"confidence" DOUBLE PRECISION NOT NULL,
"reasoning" TEXT NOT NULL,
"model" TEXT NOT NULL,
"promptVersion" TEXT NOT NULL,
"rawResponse" JSONB,
"overriddenById" TEXT,
"overrideReason" TEXT,
"overriddenAt" TIMESTAMP(3),
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "ModerationDecision_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "QuestionAnswer" (
"id" TEXT NOT NULL,
"question" TEXT NOT NULL,
"language" "Language" NOT NULL,
"answer" TEXT NOT NULL,
"model" TEXT NOT NULL,
"tokenCount" INTEGER,
"costCents" INTEGER,
"entryId" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "QuestionAnswer_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "AnswerSource" (
"answerId" TEXT NOT NULL,
"sourceId" TEXT NOT NULL,
CONSTRAINT "AnswerSource_pkey" PRIMARY KEY ("answerId","sourceId")
);
-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
-- CreateIndex
CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId");
-- CreateIndex
CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken");
-- CreateIndex
CREATE UNIQUE INDEX "VerificationToken_token_key" ON "VerificationToken"("token");
-- CreateIndex
CREATE UNIQUE INDEX "VerificationToken_identifier_token_key" ON "VerificationToken"("identifier", "token");
-- CreateIndex
CREATE INDEX "Source_language_trustLevel_idx" ON "Source"("language", "trustLevel");
-- CreateIndex
CREATE UNIQUE INDEX "Source_url_language_key" ON "Source"("url", "language");
-- CreateIndex
CREATE INDEX "KnowledgeEntry_status_language_idx" ON "KnowledgeEntry"("status", "language");
-- CreateIndex
CREATE UNIQUE INDEX "KnowledgeEntry_slug_language_key" ON "KnowledgeEntry"("slug", "language");
-- CreateIndex
CREATE INDEX "Contribution_status_origin_idx" ON "Contribution"("status", "origin");
-- CreateIndex
CREATE INDEX "ModerationDecision_outcome_createdAt_idx" ON "ModerationDecision"("outcome", "createdAt");
-- AddForeignKey
ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "KnowledgeEntrySource" ADD CONSTRAINT "KnowledgeEntrySource_entryId_fkey" FOREIGN KEY ("entryId") REFERENCES "KnowledgeEntry"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "KnowledgeEntrySource" ADD CONSTRAINT "KnowledgeEntrySource_sourceId_fkey" FOREIGN KEY ("sourceId") REFERENCES "Source"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Contribution" ADD CONSTRAINT "Contribution_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Contribution" ADD CONSTRAINT "Contribution_entryId_fkey" FOREIGN KEY ("entryId") REFERENCES "KnowledgeEntry"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ContributionSource" ADD CONSTRAINT "ContributionSource_contributionId_fkey" FOREIGN KEY ("contributionId") REFERENCES "Contribution"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ContributionSource" ADD CONSTRAINT "ContributionSource_sourceId_fkey" FOREIGN KEY ("sourceId") REFERENCES "Source"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ModerationDecision" ADD CONSTRAINT "ModerationDecision_contributionId_fkey" FOREIGN KEY ("contributionId") REFERENCES "Contribution"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ModerationDecision" ADD CONSTRAINT "ModerationDecision_overriddenById_fkey" FOREIGN KEY ("overriddenById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "QuestionAnswer" ADD CONSTRAINT "QuestionAnswer_entryId_fkey" FOREIGN KEY ("entryId") REFERENCES "KnowledgeEntry"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "AnswerSource" ADD CONSTRAINT "AnswerSource_answerId_fkey" FOREIGN KEY ("answerId") REFERENCES "QuestionAnswer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "AnswerSource" ADD CONSTRAINT "AnswerSource_sourceId_fkey" FOREIGN KEY ("sourceId") REFERENCES "Source"("id") ON DELETE CASCADE ON UPDATE CASCADE;

228
prisma/schema.prisma Normal file
View File

@@ -0,0 +1,228 @@
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
enum Role {
VISITOR
MEMBER
ADMIN
}
enum Language {
DE
EN
}
enum TrustLevel {
UNKNOWN
LOW
MEDIUM
HIGH
PRIMARY
}
enum EntryStatus {
DRAFT
PUBLISHED
BLOCKED
ARCHIVED
}
enum ContributionStatus {
PENDING
APPROVED
REJECTED
NEEDS_ADMIN_REVIEW
}
enum ModerationOutcome {
APPROVE
REJECT
ESCALATE
}
enum ContributionOrigin {
COMMUNITY
AI_RESEARCH
ADMIN
}
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
passwordHash String?
role Role @default(MEMBER)
accounts Account[]
sessions Session[]
contributions Contribution[]
moderationOverrides ModerationDecision[] @relation("ModerationOverride")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String? @db.Text
access_token String? @db.Text
expires_at Int?
token_type String?
scope String?
id_token String? @db.Text
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
}
model Session {
id String @id @default(cuid())
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model VerificationToken {
identifier String
token String @unique
expires DateTime
@@unique([identifier, token])
}
model Source {
id String @id @default(cuid())
title String
url String
author String?
institution String?
license String?
language Language
retrievedAt DateTime @default(now())
trustLevel TrustLevel @default(UNKNOWN)
notes String?
entryLinks KnowledgeEntrySource[]
contributionLinks ContributionSource[]
answerLinks AnswerSource[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([url, language])
@@index([language, trustLevel])
}
model KnowledgeEntry {
id String @id @default(cuid())
title String
slug String
language Language
summary String
content Json
timelineStart DateTime?
timelineEnd DateTime?
tags String[]
status EntryStatus @default(DRAFT)
version Int @default(1)
sources KnowledgeEntrySource[]
contributions Contribution[]
answers QuestionAnswer[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([slug, language])
@@index([status, language])
}
model KnowledgeEntrySource {
entryId String
sourceId String
note String?
entry KnowledgeEntry @relation(fields: [entryId], references: [id], onDelete: Cascade)
source Source @relation(fields: [sourceId], references: [id], onDelete: Cascade)
@@id([entryId, sourceId])
}
model Contribution {
id String @id @default(cuid())
origin ContributionOrigin
status ContributionStatus @default(PENDING)
title String
language Language
proposedContent Json
rationale String?
authorId String?
entryId String?
author User? @relation(fields: [authorId], references: [id], onDelete: SetNull)
entry KnowledgeEntry? @relation(fields: [entryId], references: [id], onDelete: SetNull)
sources ContributionSource[]
moderationDecisions ModerationDecision[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([status, origin])
}
model ContributionSource {
contributionId String
sourceId String
contribution Contribution @relation(fields: [contributionId], references: [id], onDelete: Cascade)
source Source @relation(fields: [sourceId], references: [id], onDelete: Cascade)
@@id([contributionId, sourceId])
}
model ModerationDecision {
id String @id @default(cuid())
contributionId String
outcome ModerationOutcome
riskCategories String[]
confidence Float
reasoning String
model String
promptVersion String
rawResponse Json?
overriddenById String?
overrideReason String?
overriddenAt DateTime?
contribution Contribution @relation(fields: [contributionId], references: [id], onDelete: Cascade)
overriddenBy User? @relation("ModerationOverride", fields: [overriddenById], references: [id], onDelete: SetNull)
createdAt DateTime @default(now())
@@index([outcome, createdAt])
}
model QuestionAnswer {
id String @id @default(cuid())
question String
language Language
answer String
model String
tokenCount Int?
costCents Int?
entryId String?
entry KnowledgeEntry? @relation(fields: [entryId], references: [id], onDelete: SetNull)
sources AnswerSource[]
createdAt DateTime @default(now())
}
model AnswerSource {
answerId String
sourceId String
answer QuestionAnswer @relation(fields: [answerId], references: [id], onDelete: Cascade)
source Source @relation(fields: [sourceId], references: [id], onDelete: Cascade)
@@id([answerId, sourceId])
}