feat: T4 waves 1-2 - rule configs, schema, suggestions core, season, rule forms
- Rule configs with typed parsers and registry; Berlin day helpers - Schema: T4 enums, Suggestion table, feed vocabulary (feedStatus as ColonyCondition with legacy text mapping), split queen source, varroa sample size; migration harness for data migrations - SuggestionsService: propose/refresh/resolve/obsolete/expire, accept/dismiss/reopen incl. bulk, lock order, concurrency e2e - SeasonService: phenology-based segments, inspection/varroa due dates, queen age; TimeEventsStep with JobPartialFailure - Frontend: per-rule settings forms with visible value sources Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
7097fcd97c
commit
d99a697739
116 files changed
+11239
-801
No files matched your search
@@ -115,6 +115,7 @@ model User {
|
||||
stockMovements StockMovement[]
|
||||
assignedTasks Task[] @relation("TaskAssignee")
|
||||
createdTasks Task[] @relation("TaskCreator")
|
||||
decidedSuggestions Suggestion[] @relation("SuggestionDecider")
|
||||
assignedTaskTemplates TaskTemplate[] @relation("TaskTemplateAssignee")
|
||||
createdTaskTemplates TaskTemplate[] @relation("TaskTemplateCreator")
|
||||
colonyMoves ColonyApiaryHistory[]
|
||||
@@ -312,6 +313,7 @@ model Colony {
|
||||
feedings Feeding[]
|
||||
harvests HarvestColony[]
|
||||
queenEvaluations QueenEvaluation[]
|
||||
suggestions Suggestion[]
|
||||
|
||||
@@index([apiaryId])
|
||||
@@index([status])
|
||||
@@ -340,16 +342,23 @@ enum LineageType {
|
||||
|
||||
// Ableger bilden (SPLIT: from=Muttervolk, to=Ableger) und Völker vereinigen
|
||||
// (MERGE: mehrere from-Zeilen auf denselben to=Zielvolk) – Abschnitt 4.4.
|
||||
enum SplitQueenSource {
|
||||
RAISE_OWN
|
||||
QUEEN_CELL
|
||||
QUEEN
|
||||
}
|
||||
|
||||
model ColonyLineage {
|
||||
id String @id @default(cuid())
|
||||
id String @id @default(cuid())
|
||||
type LineageType
|
||||
fromColonyId String
|
||||
fromColony Colony @relation("LineageFrom", fields: [fromColonyId], references: [id])
|
||||
fromColony Colony @relation("LineageFrom", fields: [fromColonyId], references: [id])
|
||||
toColonyId String
|
||||
toColony Colony @relation("LineageTo", fields: [toColonyId], references: [id])
|
||||
toColony Colony @relation("LineageTo", fields: [toColonyId], references: [id])
|
||||
date DateTime
|
||||
queenSource SplitQueenSource?
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([fromColonyId])
|
||||
@@index([toColonyId])
|
||||
@@ -447,11 +456,11 @@ model QueenColonyHistory {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
model Inspection {
|
||||
id String @id @default(cuid())
|
||||
id String @id @default(cuid())
|
||||
colonyId String
|
||||
colony Colony @relation(fields: [colonyId], references: [id])
|
||||
colony Colony @relation(fields: [colonyId], references: [id])
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
date DateTime
|
||||
weather String?
|
||||
temperature Float?
|
||||
@@ -467,13 +476,13 @@ model Inspection {
|
||||
swarmMood Int?
|
||||
gentleness Int?
|
||||
combBehavior Int?
|
||||
feedStatus String?
|
||||
feedStatus ColonyCondition?
|
||||
honeySuperStatus String?
|
||||
healthIssues String?
|
||||
varroaIssues String?
|
||||
measures String?
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
tasks Task[]
|
||||
|
||||
@@ -529,12 +538,99 @@ model Task {
|
||||
// rule see that it already left an open task for the same object instead
|
||||
// of piling up a duplicate on every further trigger.
|
||||
sourceAutomationTrigger AutomationTriggerType?
|
||||
// Set when the task was created by accepting a suggestion.
|
||||
sourceSuggestionId String?
|
||||
sourceSuggestion Suggestion? @relation(fields: [sourceSuggestionId], references: [id], onDelete: SetNull)
|
||||
createdAt DateTime @default(now())
|
||||
completedAt DateTime?
|
||||
|
||||
@@index([status, dueDate])
|
||||
@@index([relatedType, relatedId])
|
||||
@@index([sourceAutomationTrigger, relatedType, relatedId, status])
|
||||
@@index([sourceSuggestionId])
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Vorschlaege (T4): Regeln, Ketten und der Saison-Autopilot schlagen vor, der
|
||||
// Imker entscheidet. Uebernehmen legt eine Aufgabe an (Task.sourceSuggestionId).
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
enum SuggestionStatus {
|
||||
OPEN
|
||||
ACCEPTED
|
||||
DISMISSED
|
||||
RESOLVED
|
||||
EXPIRED
|
||||
OBSOLETE
|
||||
}
|
||||
|
||||
enum SuggestionMode {
|
||||
PLAN
|
||||
DO
|
||||
}
|
||||
|
||||
enum SuggestionSource {
|
||||
RULE
|
||||
CHAIN
|
||||
AUTOPILOT
|
||||
}
|
||||
|
||||
enum SuggestionIntent {
|
||||
INSPECT
|
||||
SWARM_CHECK
|
||||
QUEEN_CHECK
|
||||
QUEEN_ACCEPTANCE
|
||||
QUEEN_REPLACE
|
||||
SPLIT_PLAN
|
||||
VARROA_MEASURE
|
||||
VARROA_RECHECK
|
||||
VARROA_TREAT
|
||||
SUMMER_TREATMENT
|
||||
FEED
|
||||
HONEY_SUPER
|
||||
WINTER_CHECK
|
||||
HEALTH_CHECK
|
||||
FOLLOW_UP
|
||||
STOCK_REORDER
|
||||
CLEANUP
|
||||
}
|
||||
|
||||
model Suggestion {
|
||||
id String @id @default(cuid())
|
||||
ruleKey AutomationTriggerType
|
||||
source SuggestionSource
|
||||
mode SuggestionMode
|
||||
intent SuggestionIntent
|
||||
status SuggestionStatus @default(OPEN)
|
||||
priority TaskPriority @default(NORMAL)
|
||||
relatedType TaskRelatedType
|
||||
relatedId String?
|
||||
colonyId String?
|
||||
colony Colony? @relation(fields: [colonyId], references: [id])
|
||||
reasonCode String
|
||||
// Only IDs, numbers and YYYY-MM-DD.
|
||||
evidence Json
|
||||
// e.g. 'varroa:read'; without that permission the suggestion is invisible.
|
||||
requiredPermission String?
|
||||
dueDate DateTime?
|
||||
expiresAt DateTime?
|
||||
// PLAN with several dates: [{ step, offsetDays, windowDays? }]
|
||||
plan Json?
|
||||
// '<ruleKey>:<relatedId|none>:<anchor>'; EXPIRED/RESOLVED clear it.
|
||||
dedupeKey String? @unique
|
||||
sourceEventId String?
|
||||
decidedAt DateTime?
|
||||
decidedByUserId String?
|
||||
decidedByUser User? @relation("SuggestionDecider", fields: [decidedByUserId], references: [id])
|
||||
decisionNote String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
tasks Task[]
|
||||
|
||||
@@index([status, colonyId])
|
||||
@@index([status, dueDate])
|
||||
@@index([ruleKey, relatedType, relatedId, status])
|
||||
}
|
||||
|
||||
enum TaskTemplateRecurrenceType {
|
||||
@@ -589,6 +685,7 @@ model VarroaMeasurement {
|
||||
method VarroaMethod
|
||||
durationMinutes Int?
|
||||
miteCount Int?
|
||||
sampleBees Int?
|
||||
calculatedValue Float?
|
||||
assessment String?
|
||||
notes String?
|
||||
@@ -1172,6 +1269,8 @@ enum BatchMovementType {
|
||||
// Rohstoff in einer Herstellungscharge verbraucht (minus) bzw. beim
|
||||
// Loeschen einer irrtuemlich angelegten Charge zurueckgegeben (plus).
|
||||
CONSUMPTION
|
||||
// Abfuellung entnimmt Honig aus der Charge (Task 23: Bewegungsbuch)
|
||||
BOTTLING
|
||||
}
|
||||
|
||||
enum WithdrawalReason {
|
||||
@@ -1358,6 +1457,15 @@ enum AutomationTriggerType {
|
||||
RAW_MATERIAL_LOT_NUMBER_FORMAT
|
||||
PRODUCTION_BATCH_NUMBER_FORMAT
|
||||
RAW_MATERIAL_LOW
|
||||
INSPECTION_INTERVAL
|
||||
QUEEN_CELLS_SWARM_CHECK
|
||||
QUEEN_ACCEPTANCE_CHECK
|
||||
SPLIT_SCHEDULE
|
||||
COLONY_ENDED_CLEANUP
|
||||
WITHDRAWAL_ENDED
|
||||
HONEY_WATER_CONTENT
|
||||
SEASON_AUTOPILOT
|
||||
PHENOLOGY
|
||||
}
|
||||
|
||||
model AutomationRule {
|
||||
@@ -1446,6 +1554,7 @@ enum CalendarSyncSourceType {
|
||||
FEEDING
|
||||
HARVEST
|
||||
QUEEN_ASSIGNMENT
|
||||
WITHDRAWAL
|
||||
}
|
||||
|
||||
enum CalendarSyncStatus {
|
||||
|
||||
Reference in new issue
Block a user