feat: sync calendar entries to a Microsoft 365 group calendar
Adds a one-way push (ApiCore -> M365) of Aufgaben/Durchsichten/ Behandlungen/Fütterungen/Ernten/Königinnen-Zuordnungen into the calendar of a Microsoft 365 group, via the Graph API. - CalendarSyncModule (app-only client-credentials Graph auth, separate from the interactive SSO app registration; new env vars M365_CALENDAR_TENANT_ID/_CLIENT_ID/_CLIENT_SECRET). - Outbox + minute-interval cron worker (CalendarSyncOutboxEntry) instead of a synchronous push, since Graph calls are too slow/flaky to block a domain create request on; failed syncs retry up to 5 times. - Per-source-type toggle plus a group-ID field, configurable in Verwaltung > Automatisierung > Kalender-Sync (Verwaltung > Backup, an env var still wins on those fields where one applies to related config). - Hooked into Tasks/Inspections/Treatments/Feedings/Harvests/Queens at their existing create (and Task update/complete) points; entries render as all-day Graph events to avoid timezone ambiguity. - Documents the design decision in ARCHITECTURE.md (Annahme 9), since this is a net-new capability the lastenheft doesn't scope. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
1 parent
28ae0a2723
commit
e7b157ec35
35 files changed
+1760
-7
No files matched your search
@@ -0,0 +1,42 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "CalendarSyncSourceType" AS ENUM ('TASK', 'INSPECTION', 'TREATMENT', 'FEEDING', 'HARVEST', 'QUEEN_ASSIGNMENT');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "CalendarSyncStatus" AS ENUM ('PENDING', 'SYNCED', 'FAILED', 'SKIPPED');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "CalendarSyncSettings" (
|
||||
"id" TEXT NOT NULL DEFAULT 'singleton',
|
||||
"enabled" BOOLEAN NOT NULL DEFAULT false,
|
||||
"groupId" TEXT,
|
||||
"syncTask" BOOLEAN NOT NULL DEFAULT true,
|
||||
"syncInspection" BOOLEAN NOT NULL DEFAULT true,
|
||||
"syncTreatment" BOOLEAN NOT NULL DEFAULT true,
|
||||
"syncFeeding" BOOLEAN NOT NULL DEFAULT true,
|
||||
"syncHarvest" BOOLEAN NOT NULL DEFAULT true,
|
||||
"syncQueenAssignment" BOOLEAN NOT NULL DEFAULT true,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "CalendarSyncSettings_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "CalendarSyncOutboxEntry" (
|
||||
"id" TEXT NOT NULL,
|
||||
"sourceType" "CalendarSyncSourceType" NOT NULL,
|
||||
"sourceId" TEXT NOT NULL,
|
||||
"status" "CalendarSyncStatus" NOT NULL DEFAULT 'PENDING',
|
||||
"graphEventId" TEXT,
|
||||
"attempts" INTEGER NOT NULL DEFAULT 0,
|
||||
"lastError" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "CalendarSyncOutboxEntry_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "CalendarSyncOutboxEntry_status_idx" ON "CalendarSyncOutboxEntry"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "CalendarSyncOutboxEntry_sourceType_sourceId_key" ON "CalendarSyncOutboxEntry"("sourceType", "sourceId");
|
||||
Reference in new issue
Block a user