feat: T4 wave 6 - reminders and morning digest, next steps UI, warnings and notifications UI

- In-app reminders: task due (skips rescheduled tasks, catch-up wording)
  and a per-user morning digest step in the daily job
- Frontend: "Als Nächstes" on the colony page, "Heute" on the dashboard,
  inspection-due card, season chip, apiary overview fields, cleanup
  sheet for ended colonies
- Frontend: plausibility warnings that stay until dismissed, withdrawal
  spans in the calendar, notification bell with categories and links,
  notification settings in the profile
- ARCHITECTURE.md: T4a sections 11.1-11.10, assumptions 31-41, handler
  table and daily job step order

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Opus 5.5 committed 2026-10-14 17:05:32 +02:00
1 parent ef33e5549b
commit 32c61c8e14
77 files changed
+5309 -142

No files matched your search

@@ -1,4 +1,5 @@
import type { ApiaryStatus } from "./types";
import type { NextStep, SeasonSegment } from "@/lib/autopilot/types";
import type { Colony, ColonyCondition, ColonyStatus } from "@/lib/colonies/types";
import type { Inspection } from "@/lib/inspections/types";
import type { Queen } from "@/lib/queens/types";
@@ -12,14 +13,24 @@ export interface ColonyOverviewRow {
code: string;
status: ColonyStatus;
strength: number | null;
occupiedFrames: number | null;
broodStatus: ColonyCondition | null;
feedStatus: ColonyCondition | null;
healthStatus: ColonyCondition | null;
/** ISO timestamp; always null when the caller may not read inspections. */
lastInspectionDate: string | null;
/** Unread WARNUNG notifications visible to the caller. */
/**
* The day the next inspection is due (YYYY-MM-DD); null in the winter
* rest, when the interval rule is off and without `inspections:read`.
*/
inspectionDueOn: string | null;
/** The season segment of the apiary today; null when it is unknown. */
segment: SeasonSegment | null;
/** Title of the first next step; null without one or without `tasks:read`. */
nextStepTitle: string | null;
/** Open suggestions of priority HIGH the caller may see. */
openWarnings: number;
/** Unread KRITISCH notifications visible to the caller. */
/** Open suggestions of priority URGENT the caller may see. */
openCritical: number;
}
@@ -54,6 +65,7 @@ export interface OfflinePackV1 {
| "colonyType"
| "hiveType"
| "strength"
| "occupiedFrames"
| "broodStatus"
| "feedStatus"
| "healthStatus"
@@ -80,4 +92,9 @@ export interface OfflinePackV1 {
| "relatedId"
>[]
| null;
/**
* The next steps per colony id (what `GET /colonies/:id/next-steps`
* returns as `steps`). Absent in packs cached before T4.
*/
nextSteps?: Record<string, NextStep[]>;
}
@@ -20,6 +20,7 @@ export function packColony(id: string, code: string, overrides: Partial<PackColo
colonyType: "PRODUCTION_COLONY",
hiveType: "Zander",
strength: 8,
occupiedFrames: 9,
broodStatus: "GOOD",
feedStatus: "GOOD",
healthStatus: "GOOD",
@@ -35,10 +36,14 @@ export function overviewRow(colony: PackColony, overrides: Partial<ColonyOvervie
code: colony.code,
status: colony.status,
strength: colony.strength,
occupiedFrames: colony.occupiedFrames,
broodStatus: colony.broodStatus,
feedStatus: colony.feedStatus,
healthStatus: colony.healthStatus,
lastInspectionDate: new Date().toISOString(),
inspectionDueOn: null,
segment: null,
nextStepTitle: null,
openWarnings: 0,
openCritical: 0,
...overrides,