Files
ApiCore/ApiCore-Backend/src/automation/rule-config/default-rules.ts
T
Nick SzaunigandClaude Opus 5.5 d99a697739 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]>
2026-10-14 13:42:32 +02:00

73 lines
3.0 KiB
TypeScript

import type { AutomationTriggerType } from '../../../generated/prisma';
import { RULE_CONFIG_PARSERS } from './rule-config.registry';
export interface RuleDefaults {
config: Record<string, unknown>;
actionTemplate: string;
/** Rules without a sensible built-in setting start switched off. */
active?: boolean;
}
/** Texts of the rules that create a task; the new rules have none yet. */
const ACTION_TEMPLATES: Record<AutomationTriggerType, string> = {
QUEENLESS_NO_EGGS:
'Kontrolle empfohlen: Königin nicht gesehen und keine Stifte vorhanden.',
VARROA_THRESHOLD: 'Behandlung prüfen: Varroa-Schwellenwert überschritten.',
FEED_STATUS_CRITICAL: 'Fütterung erforderlich: Futterstatus kritisch.',
SWARM_MOOD_HIGH:
'Schwarmkontrolle dringend: hohe Schwarmstimmung festgestellt.',
COLONY_HEALTH_CRITICAL: 'Kontrolle erforderlich: Gesundheitsstatus kritisch.',
STOCK_ITEM_LOW: 'Nachbestellung prüfen: Lagerartikel unter Mindestbestand.',
// Not task-generating rules like the ones above - `active` here toggles
// whether HoneyBatchesService/BottlingService auto-fill the batch/lot
// number from `config.format` instead of requiring manual entry.
HONEY_BATCH_NUMBER_FORMAT: '',
BOTTLING_LOT_NUMBER_FORMAT: '',
RAW_MATERIAL_LOT_NUMBER_FORMAT: '',
PRODUCTION_BATCH_NUMBER_FORMAT: '',
RAW_MATERIAL_LOW: 'Rohstoff unter Mindestmenge: Nachschub einplanen.',
TREATMENT_FOLLOW_UP: 'Behandlungserfolg kontrollieren',
FEEDING_FOLLOW_UP: 'Futterabnahme und Futtervorrat kontrollieren',
INSPECTION_INTERVAL: '',
QUEEN_CELLS_SWARM_CHECK: '',
QUEEN_ACCEPTANCE_CHECK: '',
SPLIT_SCHEDULE: '',
COLONY_ENDED_CLEANUP: '',
WITHDRAWAL_ENDED: '',
HONEY_WATER_CONTENT: '',
SEASON_AUTOPILOT: '',
PHENOLOGY: '',
};
// - RAW_MATERIAL_LOW: raw material lots carry no minimum of their own, so
// the minimum per kind (config.minGrams) lives on the rule - and without
// one there is nothing to compare, hence off by default.
// - Follow-up checks: how many days after a treatment or feeding a check
// makes sense depends on the product and the season, so there is no
// built-in interval - the beekeeper switches the rule on and sets
// config.dueInDays.
const INACTIVE_BY_DEFAULT: ReadonlySet<AutomationTriggerType> = new Set([
'RAW_MATERIAL_LOW',
'TREATMENT_FOLLOW_UP',
'FEEDING_FOLLOW_UP',
]);
function defaultsOf(trigger: AutomationTriggerType): RuleDefaults {
return {
config: structuredClone(RULE_CONFIG_PARSERS[trigger].defaults) as Record<
string,
unknown
>,
actionTemplate: ACTION_TEMPLATES[trigger],
...(INACTIVE_BY_DEFAULT.has(trigger) ? { active: false } : {}),
};
}
/** The rule rows created on first use; the config is the parser's default. */
export const DEFAULT_RULES: Record<AutomationTriggerType, RuleDefaults> =
Object.fromEntries(
(Object.keys(ACTION_TEMPLATES) as AutomationTriggerType[]).map(
(trigger) => [trigger, defaultsOf(trigger)],
),
) as Record<AutomationTriggerType, RuleDefaults>;