- seasons[] bekommt segmentSince, reportedOn und note (NO_COORDINATES | WEATHER_GAPS | WEATHER_STALE). - Neues seasonCalendar: calendarFallback (8 Phasen, MM-DD), swarmSeason und winterVarroaWindow aus den Regel-Configs, auch bei inaktiver Regel. - Nur Zusätze, keine Migration, Recht bleibt colonies:read; SEASON_AUTOPILOT wird je Anfrage einmal gelesen. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
153 lines
5.3 KiB
TypeScript
153 lines
5.3 KiB
TypeScript
import { ApiProperty } from '@nestjs/swagger';
|
|
import { SuggestionIntent } from '../../../generated/prisma';
|
|
import {
|
|
PHASE_SOURCES,
|
|
PHENOLOGY_PHASES,
|
|
SEASON_SEGMENTS,
|
|
} from '../../season/season-types';
|
|
import type { ColonyNextSteps, NextStep } from '../next-step-ranking';
|
|
import type { AutopilotToday } from '../next-steps.service';
|
|
|
|
const FORMS = [
|
|
'inspection',
|
|
'varroa',
|
|
'feeding',
|
|
'treatment',
|
|
'winter-check',
|
|
] as const;
|
|
|
|
class NextStepActionDto {
|
|
@ApiProperty({ enum: ['CAPTURE', 'ACCEPT', 'CLEANUP', 'OPEN_TASK'] })
|
|
type!: NextStep['action']['type'];
|
|
@ApiProperty({ enum: FORMS, required: false }) form?: (typeof FORMS)[number];
|
|
@ApiProperty({ required: false }) href?: string;
|
|
@ApiProperty({ required: false }) suggestionId?: string;
|
|
@ApiProperty({ required: false }) taskId?: string;
|
|
}
|
|
|
|
export class NextStepDto {
|
|
@ApiProperty() key!: string;
|
|
@ApiProperty({ enum: ['TASK', 'SUGGESTION'] }) kind!: NextStep['kind'];
|
|
@ApiProperty({ enum: SuggestionIntent, nullable: true })
|
|
intent!: SuggestionIntent | null;
|
|
@ApiProperty() title!: string;
|
|
@ApiProperty({ type: [String] }) reasons!: string[];
|
|
@ApiProperty({ nullable: true, type: String }) dueOn!: string | null;
|
|
@ApiProperty({ enum: ['OVERDUE', 'TODAY', 'SOON', 'LATER', 'NONE'] })
|
|
urgency!: NextStep['urgency'];
|
|
@ApiProperty({ type: [String] }) suggestionIds!: string[];
|
|
@ApiProperty({ type: NextStepActionDto }) action!: NextStepActionDto;
|
|
@ApiProperty() dismissible!: boolean;
|
|
}
|
|
|
|
export class ColonyNextStepsDto {
|
|
@ApiProperty() colonyId!: string;
|
|
@ApiProperty({ enum: SEASON_SEGMENTS }) segment!: ColonyNextSteps['segment'];
|
|
@ApiProperty({ enum: PHENOLOGY_PHASES, nullable: true })
|
|
phase!: ColonyNextSteps['phase'];
|
|
@ApiProperty({ enum: PHASE_SOURCES, nullable: true })
|
|
phaseSource!: ColonyNextSteps['phaseSource'];
|
|
@ApiProperty({ nullable: true, type: String }) inspectionDueOn!:
|
|
string | null;
|
|
@ApiProperty({ nullable: true, type: String }) withdrawalUntil!:
|
|
string | null;
|
|
@ApiProperty({ type: [NextStepDto] }) steps!: NextStepDto[];
|
|
}
|
|
|
|
class TodayNextStepDto extends NextStepDto {
|
|
@ApiProperty() colonyId!: string;
|
|
@ApiProperty() colonyCode!: string;
|
|
}
|
|
|
|
class DueColonyDto {
|
|
@ApiProperty() id!: string;
|
|
@ApiProperty() code!: string;
|
|
@ApiProperty() dueOn!: string;
|
|
@ApiProperty() overdueDays!: number;
|
|
}
|
|
|
|
class InspectionDueDto {
|
|
@ApiProperty() apiaryId!: string;
|
|
@ApiProperty() apiaryName!: string;
|
|
@ApiProperty({ enum: SEASON_SEGMENTS })
|
|
segment!: AutopilotToday['seasons'][number]['segment'];
|
|
@ApiProperty({ nullable: true, type: Number }) intervalDays!: number | null;
|
|
@ApiProperty({ type: [DueColonyDto] }) colonies!: DueColonyDto[];
|
|
}
|
|
|
|
class SeasonOfApiaryDto {
|
|
@ApiProperty() apiaryId!: string;
|
|
@ApiProperty() apiaryName!: string;
|
|
@ApiProperty({ enum: SEASON_SEGMENTS })
|
|
segment!: AutopilotToday['seasons'][number]['segment'];
|
|
@ApiProperty({ enum: PHENOLOGY_PHASES, nullable: true })
|
|
phase!: AutopilotToday['seasons'][number]['phase'];
|
|
@ApiProperty({ enum: PHASE_SOURCES, nullable: true })
|
|
phaseSource!: AutopilotToday['seasons'][number]['phaseSource'];
|
|
@ApiProperty({ description: 'Day the current segment began (YYYY-MM-DD).' })
|
|
segmentSince!: string;
|
|
@ApiProperty({
|
|
nullable: true,
|
|
type: String,
|
|
format: 'date',
|
|
description:
|
|
'Day of the phase report the phase rests on; null without one.',
|
|
})
|
|
reportedOn!: string | null;
|
|
@ApiProperty({
|
|
enum: ['NO_COORDINATES', 'WEATHER_GAPS', 'WEATHER_STALE'],
|
|
nullable: true,
|
|
})
|
|
note!: AutopilotToday['seasons'][number]['note'];
|
|
}
|
|
|
|
class SwarmSeasonDto {
|
|
@ApiProperty({ enum: PHENOLOGY_PHASES })
|
|
from!: AutopilotToday['seasonCalendar']['swarmSeason']['from'];
|
|
@ApiProperty({ enum: PHENOLOGY_PHASES })
|
|
until!: AutopilotToday['seasonCalendar']['swarmSeason']['until'];
|
|
}
|
|
|
|
class MonthDayWindowDto {
|
|
@ApiProperty({ example: '11-15' }) from!: string;
|
|
@ApiProperty({ example: '12-20' }) to!: string;
|
|
}
|
|
|
|
/** Calendar day ('MM-DD') of each phenology phase. */
|
|
class CalendarFallbackDto implements Record<
|
|
(typeof PHENOLOGY_PHASES)[number],
|
|
string
|
|
> {
|
|
@ApiProperty({ example: '03-20' }) SALWEIDE!: string;
|
|
@ApiProperty({ example: '04-15' }) KIRSCHE!: string;
|
|
@ApiProperty({ example: '04-28' }) APFEL!: string;
|
|
@ApiProperty({ example: '05-30' }) HOLUNDER!: string;
|
|
@ApiProperty({ example: '06-20' }) LINDE!: string;
|
|
@ApiProperty({ example: '08-01' }) TRACHTENDE!: string;
|
|
@ApiProperty({ example: '09-15' }) HERBST!: string;
|
|
@ApiProperty({ example: '11-15' }) WINTER!: string;
|
|
}
|
|
|
|
class SeasonCalendarDto {
|
|
@ApiProperty({ type: CalendarFallbackDto })
|
|
calendarFallback!: CalendarFallbackDto;
|
|
@ApiProperty({ type: SwarmSeasonDto }) swarmSeason!: SwarmSeasonDto;
|
|
@ApiProperty({ type: MonthDayWindowDto })
|
|
winterVarroaWindow!: MonthDayWindowDto;
|
|
}
|
|
|
|
export class AutopilotTodayDto {
|
|
@ApiProperty({ type: TodayNextStepDto, nullable: true })
|
|
nextStep!: TodayNextStepDto | null;
|
|
@ApiProperty({
|
|
type: [InspectionDueDto],
|
|
description: 'Colonies whose inspection is due today or overdue.',
|
|
})
|
|
inspectionDue!: InspectionDueDto[];
|
|
@ApiProperty() suggestionsOpen!: number;
|
|
@ApiProperty({ type: [SeasonOfApiaryDto] }) seasons!: SeasonOfApiaryDto[];
|
|
@ApiProperty({ type: SeasonCalendarDto })
|
|
seasonCalendar!: SeasonCalendarDto;
|
|
@ApiProperty() tasksVisible!: boolean;
|
|
}
|