chore: planning docs + backend/frontend scaffold + MVP Prisma schema
- CLAUDE.md, ARCHITECTURE.md, TASKS.md per Lastenheft-Vorgabe - ApiCore-Backend: NestJS scaffold, Prisma 7 (DATABASE_URL via prisma.config.ts) - ApiCore-Frontend: Next.js App Router scaffold (TS, Tailwind, ESLint) - prisma/schema.prisma: alle MVP-Entitaeten aus Abschnitt 13/4.2-4.22/26, validiert und Client generiert Grundgeruest (TASKS.md #0) noch nicht vollstaendig: shadcn/ui, TanStack Query, PWA-Manifest, deploy/k8s/, Dockerfiles fehlen noch.
This commit is contained in:
commit
c4a2d0648e
255 files changed
+46918
No files matched your search
@@ -0,0 +1,626 @@
|
||||
// ApiCore MVP-Datenmodell – abgeleitet aus docs/lastenheft.md Abschnitt 13, 4.2-4.22, 26.
|
||||
// Prinzip: Historie statt Löschen (siehe ARCHITECTURE.md §4) – fachliche Haupttabellen
|
||||
// tragen `status` + `deactivatedAt` statt Hard-Delete. Beziehungen sind relationale FKs,
|
||||
// keine Freitextfelder, damit die Rückverfolgbarkeitskette (Abschnitt 16, 29) abfragbar bleibt.
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client"
|
||||
output = "../generated/prisma"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Benutzer / Auth / Audit (Abschnitt 3, 14, 15, 16)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
enum Role {
|
||||
ADMIN
|
||||
BEEKEEPER
|
||||
STAFF
|
||||
READONLY
|
||||
API_CLIENT
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
email String @unique
|
||||
passwordHash String
|
||||
name String
|
||||
role Role @default(STAFF)
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deactivatedAt DateTime?
|
||||
|
||||
refreshTokens RefreshToken[]
|
||||
|
||||
inspections Inspection[]
|
||||
varroaMeasurements VarroaMeasurement[]
|
||||
treatments Treatment[]
|
||||
feedings Feeding[]
|
||||
harvests Harvest[]
|
||||
extractions Extraction[]
|
||||
honeyMeasurements HoneyMeasurement[]
|
||||
stockMovements StockMovement[]
|
||||
assignedTasks Task[] @relation("TaskAssignee")
|
||||
createdTasks Task[] @relation("TaskCreator")
|
||||
colonyMoves ColonyApiaryHistory[]
|
||||
auditLogs AuditLog[]
|
||||
|
||||
@@index([role])
|
||||
}
|
||||
|
||||
model RefreshToken {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
tokenHash String @unique
|
||||
expiresAt DateTime
|
||||
createdAt DateTime @default(now())
|
||||
revokedAt DateTime?
|
||||
|
||||
@@index([userId])
|
||||
}
|
||||
|
||||
enum AuditAction {
|
||||
CREATE
|
||||
UPDATE
|
||||
DEACTIVATE
|
||||
DELETE
|
||||
}
|
||||
|
||||
model AuditLog {
|
||||
id String @id @default(cuid())
|
||||
entityType String
|
||||
entityId String
|
||||
action AuditAction
|
||||
userId String?
|
||||
user User? @relation(fields: [userId], references: [id])
|
||||
timestamp DateTime @default(now())
|
||||
beforeData Json?
|
||||
afterData Json?
|
||||
|
||||
@@index([entityType, entityId])
|
||||
@@index([timestamp])
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Bienenstände (Abschnitt 4.2)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
enum ApiaryStatus {
|
||||
ACTIVE
|
||||
INACTIVE
|
||||
}
|
||||
|
||||
model Apiary {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
description String?
|
||||
location String?
|
||||
latitude Float?
|
||||
longitude Float?
|
||||
address String?
|
||||
status ApiaryStatus @default(ACTIVE)
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deactivatedAt DateTime?
|
||||
|
||||
colonies Colony[]
|
||||
colonyMoves ColonyApiaryHistory[]
|
||||
harvests Harvest[]
|
||||
|
||||
@@index([status])
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Völkerverwaltung (Abschnitt 4.3, 4.4)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
enum ColonyType {
|
||||
PRODUCTION_COLONY
|
||||
NUCLEUS_COLONY
|
||||
YOUNG_COLONY
|
||||
CARETAKER_COLONY
|
||||
MATING_NUCLEUS
|
||||
RESERVE_COLONY
|
||||
}
|
||||
|
||||
enum ColonyStatus {
|
||||
ACTIVE
|
||||
WEAK
|
||||
CONSPICUOUS
|
||||
QUEENLESS
|
||||
DISSOLVED
|
||||
SOLD
|
||||
DECEASED
|
||||
MERGED
|
||||
}
|
||||
|
||||
model Colony {
|
||||
id String @id @default(cuid())
|
||||
code String @unique
|
||||
apiaryId String
|
||||
apiary Apiary @relation(fields: [apiaryId], references: [id])
|
||||
hiveType String?
|
||||
originText String?
|
||||
colonyType ColonyType
|
||||
status ColonyStatus @default(ACTIVE)
|
||||
strength Int?
|
||||
broodStatus String?
|
||||
feedStatus String?
|
||||
healthStatus String?
|
||||
notes String?
|
||||
currentQueenId String? @unique
|
||||
currentQueen Queen? @relation("ColonyCurrentQueen", fields: [currentQueenId], references: [id])
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deactivatedAt DateTime?
|
||||
|
||||
apiaryHistory ColonyApiaryHistory[]
|
||||
queenHistory QueenColonyHistory[]
|
||||
lineageAsSource ColonyLineage[] @relation("LineageFrom")
|
||||
lineageAsResult ColonyLineage[] @relation("LineageTo")
|
||||
inspections Inspection[]
|
||||
varroaMeasurements VarroaMeasurement[]
|
||||
treatments Treatment[]
|
||||
feedings Feeding[]
|
||||
harvests HarvestColony[]
|
||||
|
||||
@@index([apiaryId])
|
||||
@@index([status])
|
||||
}
|
||||
|
||||
// Verschiebung Volk <-> Bienenstand, historisch nachvollziehbar (Abschnitt 4.2)
|
||||
model ColonyApiaryHistory {
|
||||
id String @id @default(cuid())
|
||||
colonyId String
|
||||
colony Colony @relation(fields: [colonyId], references: [id])
|
||||
apiaryId String
|
||||
apiary Apiary @relation(fields: [apiaryId], references: [id])
|
||||
movedAt DateTime @default(now())
|
||||
movedByUserId String?
|
||||
movedByUser User? @relation(fields: [movedByUserId], references: [id])
|
||||
notes String?
|
||||
|
||||
@@index([colonyId])
|
||||
@@index([apiaryId])
|
||||
}
|
||||
|
||||
enum LineageType {
|
||||
SPLIT
|
||||
MERGE
|
||||
}
|
||||
|
||||
// Ableger bilden (SPLIT: from=Muttervolk, to=Ableger) und Völker vereinigen
|
||||
// (MERGE: mehrere from-Zeilen auf denselben to=Zielvolk) – Abschnitt 4.4.
|
||||
model ColonyLineage {
|
||||
id String @id @default(cuid())
|
||||
type LineageType
|
||||
fromColonyId String
|
||||
fromColony Colony @relation("LineageFrom", fields: [fromColonyId], references: [id])
|
||||
toColonyId String
|
||||
toColony Colony @relation("LineageTo", fields: [toColonyId], references: [id])
|
||||
date DateTime
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([fromColonyId])
|
||||
@@index([toColonyId])
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Königinnenverwaltung (Abschnitt 4.5)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
enum QueenStatus {
|
||||
ACTIVE
|
||||
RESERVE
|
||||
UNMATED
|
||||
MATED
|
||||
LOST
|
||||
REPLACED
|
||||
SOLD
|
||||
DECEASED
|
||||
}
|
||||
|
||||
model Queen {
|
||||
id String @id @default(cuid())
|
||||
code String @unique
|
||||
hatchYear Int?
|
||||
breed String?
|
||||
origin String?
|
||||
breeder String?
|
||||
markingColor String?
|
||||
markingNumber String?
|
||||
matingType String?
|
||||
matingStatus String?
|
||||
inseminationData String?
|
||||
motherLine String?
|
||||
fatherLine String?
|
||||
status QueenStatus @default(ACTIVE)
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deactivatedAt DateTime?
|
||||
|
||||
colony Colony? @relation("ColonyCurrentQueen")
|
||||
colonyHistory QueenColonyHistory[]
|
||||
|
||||
@@index([status])
|
||||
}
|
||||
|
||||
// Königinnenwechsel historisch nachvollziehbar (Abschnitt 4.5)
|
||||
model QueenColonyHistory {
|
||||
id String @id @default(cuid())
|
||||
queenId String
|
||||
queen Queen @relation(fields: [queenId], references: [id])
|
||||
colonyId String
|
||||
colony Colony @relation(fields: [colonyId], references: [id])
|
||||
startDate DateTime
|
||||
endDate DateTime?
|
||||
notes String?
|
||||
|
||||
@@index([queenId])
|
||||
@@index([colonyId])
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Durchsichten / digitale Stockkarte (Abschnitt 4.6, 4.7)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
model Inspection {
|
||||
id String @id @default(cuid())
|
||||
colonyId String
|
||||
colony Colony @relation(fields: [colonyId], references: [id])
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
date DateTime
|
||||
weather String?
|
||||
temperature Float?
|
||||
colonyStrength Int?
|
||||
broodAmount String?
|
||||
broodPattern Int?
|
||||
openBroodPresent Boolean?
|
||||
cappedBroodPresent Boolean?
|
||||
eggsPresent Boolean?
|
||||
queenSeen Boolean?
|
||||
queenCellsPresent Boolean?
|
||||
swarmMood Int?
|
||||
gentleness Int?
|
||||
combBehavior Int?
|
||||
feedStatus String?
|
||||
honeySuperStatus String?
|
||||
healthIssues String?
|
||||
varroaIssues String?
|
||||
measures String?
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
tasks Task[]
|
||||
|
||||
@@index([colonyId, date])
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Aufgabenmanagement (Abschnitt 4.8)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
enum TaskPriority {
|
||||
LOW
|
||||
NORMAL
|
||||
HIGH
|
||||
URGENT
|
||||
}
|
||||
|
||||
enum TaskStatus {
|
||||
OPEN
|
||||
IN_PROGRESS
|
||||
DONE
|
||||
CANCELLED
|
||||
}
|
||||
|
||||
enum TaskRelatedType {
|
||||
COLONY
|
||||
APIARY
|
||||
QUEEN
|
||||
HONEY_BATCH
|
||||
STORAGE
|
||||
GENERAL
|
||||
}
|
||||
|
||||
model Task {
|
||||
id String @id @default(cuid())
|
||||
title String
|
||||
description String?
|
||||
priority TaskPriority @default(NORMAL)
|
||||
dueDate DateTime?
|
||||
status TaskStatus @default(OPEN)
|
||||
assignedUserId String?
|
||||
assignedUser User? @relation("TaskAssignee", fields: [assignedUserId], references: [id])
|
||||
createdByUserId String?
|
||||
createdByUser User? @relation("TaskCreator", fields: [createdByUserId], references: [id])
|
||||
relatedType TaskRelatedType @default(GENERAL)
|
||||
relatedId String?
|
||||
sourceInspectionId String?
|
||||
sourceInspection Inspection? @relation(fields: [sourceInspectionId], references: [id])
|
||||
createdAt DateTime @default(now())
|
||||
completedAt DateTime?
|
||||
|
||||
@@index([status, dueDate])
|
||||
@@index([relatedType, relatedId])
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Varroamanagement (Abschnitt 4.10)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
enum VarroaMethod {
|
||||
NATURAL_MITE_FALL
|
||||
POWDERED_SUGAR
|
||||
WASHING_METHOD
|
||||
DRONE_BROOD_CONTROL
|
||||
}
|
||||
|
||||
model VarroaMeasurement {
|
||||
id String @id @default(cuid())
|
||||
colonyId String
|
||||
colony Colony @relation(fields: [colonyId], references: [id])
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
date DateTime
|
||||
method VarroaMethod
|
||||
durationMinutes Int?
|
||||
miteCount Int?
|
||||
calculatedValue Float?
|
||||
assessment String?
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([colonyId, date])
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Behandlung / Tierarzneimittel (Abschnitt 4.11)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
model Treatment {
|
||||
id String @id @default(cuid())
|
||||
colonyId String
|
||||
colony Colony @relation(fields: [colonyId], references: [id])
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
date DateTime
|
||||
startDate DateTime?
|
||||
endDate DateTime?
|
||||
product String
|
||||
activeIngredient String?
|
||||
amount String?
|
||||
method String?
|
||||
reason String?
|
||||
batchNumber String?
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([colonyId, date])
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Fütterung (Abschnitt 4.12)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
enum FeedType {
|
||||
SUGAR_WATER
|
||||
FEED_SYRUP
|
||||
FEED_PASTE
|
||||
OWN_HONEY
|
||||
OTHER
|
||||
}
|
||||
|
||||
model Feeding {
|
||||
id String @id @default(cuid())
|
||||
colonyId String
|
||||
colony Colony @relation(fields: [colonyId], references: [id])
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
date DateTime
|
||||
feedType FeedType
|
||||
product String?
|
||||
amount Float
|
||||
unit String
|
||||
batchNumber String?
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([colonyId, date])
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Ernte / Schleuderung / Honigcharge / Rückverfolgbarkeit (Abschnitt 4.13-4.17)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
model Harvest {
|
||||
id String @id @default(cuid())
|
||||
apiaryId String
|
||||
apiary Apiary @relation(fields: [apiaryId], references: [id])
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
date DateTime
|
||||
honeyType String?
|
||||
honeySuperCount Int?
|
||||
grossWeight Float?
|
||||
netWeight Float?
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
colonies HarvestColony[]
|
||||
extractions ExtractionHarvest[]
|
||||
|
||||
@@index([apiaryId, date])
|
||||
}
|
||||
|
||||
model HarvestColony {
|
||||
id String @id @default(cuid())
|
||||
harvestId String
|
||||
harvest Harvest @relation(fields: [harvestId], references: [id])
|
||||
colonyId String
|
||||
colony Colony @relation(fields: [colonyId], references: [id])
|
||||
|
||||
@@unique([harvestId, colonyId])
|
||||
@@index([colonyId])
|
||||
}
|
||||
|
||||
model Extraction {
|
||||
id String @id @default(cuid())
|
||||
date DateTime
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
amount Float?
|
||||
room String?
|
||||
waterContent Float?
|
||||
temperature Float?
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
harvests ExtractionHarvest[]
|
||||
honeyBatches HoneyBatch[]
|
||||
|
||||
@@index([date])
|
||||
}
|
||||
|
||||
model ExtractionHarvest {
|
||||
id String @id @default(cuid())
|
||||
extractionId String
|
||||
extraction Extraction @relation(fields: [extractionId], references: [id])
|
||||
harvestId String
|
||||
harvest Harvest @relation(fields: [harvestId], references: [id])
|
||||
|
||||
@@unique([extractionId, harvestId])
|
||||
@@index([harvestId])
|
||||
}
|
||||
|
||||
enum HoneyBatchStatus {
|
||||
RAW
|
||||
EXTRACTED
|
||||
CLARIFIED
|
||||
CREAMED
|
||||
STORED
|
||||
BOTTLED
|
||||
SOLD
|
||||
CONSUMED
|
||||
}
|
||||
|
||||
model HoneyBatch {
|
||||
id String @id @default(cuid())
|
||||
batchNumber String @unique
|
||||
extractionId String
|
||||
extraction Extraction @relation(fields: [extractionId], references: [id])
|
||||
honeyType String?
|
||||
amount Float?
|
||||
waterContent Float?
|
||||
storageContainerId String?
|
||||
storageContainer StorageContainer? @relation(fields: [storageContainerId], references: [id])
|
||||
status HoneyBatchStatus @default(RAW)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
measurements HoneyMeasurement[]
|
||||
|
||||
@@index([status])
|
||||
@@index([extractionId])
|
||||
}
|
||||
|
||||
// Honigmessungen (Abschnitt 4.17) – als Teil des HoneyBatch-Moduls im MVP,
|
||||
// siehe ARCHITECTURE.md Annahme 1.
|
||||
model HoneyMeasurement {
|
||||
id String @id @default(cuid())
|
||||
honeyBatchId String
|
||||
honeyBatch HoneyBatch @relation(fields: [honeyBatchId], references: [id])
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
waterContent Float
|
||||
measuredAt DateTime
|
||||
device String?
|
||||
temperature Float?
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([honeyBatchId])
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Lagerbehälter / grundlegende Lagerverwaltung (Abschnitt 4.18, 4.21)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
enum StorageContainerStatus {
|
||||
EMPTY
|
||||
FILLED
|
||||
CLEANING
|
||||
OUT_OF_SERVICE
|
||||
}
|
||||
|
||||
model StorageContainer {
|
||||
id String @id @default(cuid())
|
||||
code String @unique
|
||||
containerType String?
|
||||
capacity Float?
|
||||
currentAmount Float?
|
||||
location String?
|
||||
status StorageContainerStatus @default(EMPTY)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
honeyBatches HoneyBatch[]
|
||||
|
||||
@@index([status])
|
||||
}
|
||||
|
||||
enum StockCategory {
|
||||
HONEY
|
||||
CONSUMABLE
|
||||
EQUIPMENT_MATERIAL
|
||||
}
|
||||
|
||||
model StockItem {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
category StockCategory
|
||||
unit String
|
||||
quantity Float @default(0)
|
||||
minThreshold Float?
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
movements StockMovement[]
|
||||
|
||||
@@index([category])
|
||||
}
|
||||
|
||||
enum StockMovementType {
|
||||
IN
|
||||
OUT
|
||||
TRANSFER
|
||||
ADJUSTMENT
|
||||
}
|
||||
|
||||
model StockMovement {
|
||||
id String @id @default(cuid())
|
||||
stockItemId String
|
||||
stockItem StockItem @relation(fields: [stockItemId], references: [id])
|
||||
type StockMovementType
|
||||
quantity Float
|
||||
date DateTime @default(now())
|
||||
userId String?
|
||||
user User? @relation(fields: [userId], references: [id])
|
||||
relatedType String?
|
||||
relatedId String?
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([stockItemId, date])
|
||||
}
|
||||
Reference in new issue
Block a user