feat: platform backbone and field capture, first part (checkpoint)
Platform backbone (plan 2026-10-13-plattform-rueckgrat), reviewed tasks: - run roles api/worker/job/all with shared startup checks (Task 1) - schema and migration for DomainEvent, deliveries, JobRun, ThrottlerHit (Task 2) - audit, notifications and domain events written in the same transaction (Task 3) - dispatcher with SKIP LOCKED claims, retries and stale release (Task 4) - worker building blocks: tick, LISTEN/NOTIFY wake-up, health (Task 5) - worker process and entry points (Task 6) - throttler counters in Postgres (Task 19) - separate keys per purpose with key ring (Task 20) - public origin page without exact location (Task 22) - shop keys split into read and write (Task 23) - Kustomize base, components, overlay encry, CI validation (Task 26) Field capture T3 (plan 2026-10-13-t3-erfassung-am-stand), reviewed tasks: - brood frames, read endpoints, apiary overview and offline pack - network basics, offline queue v3, navigation sheets, form building blocks - new inspection with last-time hints and weather, varroa per day, treatment prefill, apiary page with round - inspection photo (Task 10) is implemented, review pending Not rolled out. Remaining tasks follow in later commits. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
10cbe9bf2d
commit
c01a38835a
340 files changed
+25695
-1808
No files matched your search
@@ -0,0 +1,139 @@
|
||||
-- Platform backbone: domain-event outbox (DomainEvent + per-handler
|
||||
-- DomainEventDelivery), webhook delivery queue, cron job run history and
|
||||
-- throttler counters, plus two small columns (Apiary.publicLocationLabel,
|
||||
-- SiteSettings.originCountry).
|
||||
-- ThrottlerHit is UNLOGGED on purpose: no WAL, emptied after a crash - only
|
||||
-- rate-limit counters get lost. DomainEvent.dedupeKey is a nullable UNIQUE
|
||||
-- (not a partial index) so the schema and the database cannot drift apart.
|
||||
-- CreateEnum
|
||||
CREATE TYPE "DomainEventStatus" AS ENUM ('PENDING', 'PROCESSING', 'DONE', 'FAILED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "DomainEventDeliveryStatus" AS ENUM ('PENDING', 'DONE', 'FAILED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "WebhookDeliveryStatus" AS ENUM ('PENDING', 'PROCESSING', 'DELIVERED', 'FAILED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "JobRunStatus" AS ENUM ('RUNNING', 'SUCCEEDED', 'FAILED');
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Apiary" ADD COLUMN "publicLocationLabel" TEXT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "SiteSettings" ADD COLUMN "originCountry" TEXT NOT NULL DEFAULT 'Deutschland';
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "DomainEvent" (
|
||||
"id" TEXT NOT NULL,
|
||||
"type" TEXT NOT NULL,
|
||||
"aggregateType" TEXT NOT NULL,
|
||||
"aggregateId" TEXT NOT NULL,
|
||||
"payload" JSONB NOT NULL,
|
||||
"actorUserId" TEXT,
|
||||
"correlationId" TEXT NOT NULL,
|
||||
"dedupeKey" TEXT,
|
||||
"occurredAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"status" "DomainEventStatus" NOT NULL DEFAULT 'PENDING',
|
||||
"attempts" INTEGER NOT NULL DEFAULT 0,
|
||||
"availableAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"claimedAt" TIMESTAMP(3),
|
||||
"processedAt" TIMESTAMP(3),
|
||||
"lastError" TEXT,
|
||||
|
||||
CONSTRAINT "DomainEvent_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "DomainEventDelivery" (
|
||||
"id" TEXT NOT NULL,
|
||||
"eventId" TEXT NOT NULL,
|
||||
"handler" TEXT NOT NULL,
|
||||
"status" "DomainEventDeliveryStatus" NOT NULL DEFAULT 'PENDING',
|
||||
"attempts" INTEGER NOT NULL DEFAULT 0,
|
||||
"lastError" TEXT,
|
||||
"completedAt" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "DomainEventDelivery_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "WebhookDelivery" (
|
||||
"id" TEXT NOT NULL,
|
||||
"subscriptionId" TEXT NOT NULL,
|
||||
"event" TEXT NOT NULL,
|
||||
"body" TEXT NOT NULL,
|
||||
"status" "WebhookDeliveryStatus" NOT NULL DEFAULT 'PENDING',
|
||||
"attempts" INTEGER NOT NULL DEFAULT 0,
|
||||
"availableAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"claimedAt" TIMESTAMP(3),
|
||||
"lastStatusCode" INTEGER,
|
||||
"lastError" TEXT,
|
||||
"deliveredAt" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "WebhookDelivery_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "JobRun" (
|
||||
"id" TEXT NOT NULL,
|
||||
"job" TEXT NOT NULL,
|
||||
"status" "JobRunStatus" NOT NULL DEFAULT 'RUNNING',
|
||||
"startedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"finishedAt" TIMESTAMP(3),
|
||||
"result" JSONB,
|
||||
"error" TEXT,
|
||||
|
||||
CONSTRAINT "JobRun_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE UNLOGGED TABLE "ThrottlerHit" (
|
||||
"key" TEXT NOT NULL,
|
||||
"throttlerName" TEXT NOT NULL,
|
||||
"hits" INTEGER NOT NULL,
|
||||
"expiresAt" TIMESTAMP(3) NOT NULL,
|
||||
"blockedUntil" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "ThrottlerHit_pkey" PRIMARY KEY ("key","throttlerName")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "DomainEvent_dedupeKey_key" ON "DomainEvent"("dedupeKey");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "DomainEvent_status_availableAt_idx" ON "DomainEvent"("status", "availableAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "DomainEvent_correlationId_idx" ON "DomainEvent"("correlationId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "DomainEvent_aggregateType_aggregateId_idx" ON "DomainEvent"("aggregateType", "aggregateId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "DomainEventDelivery_eventId_handler_key" ON "DomainEventDelivery"("eventId", "handler");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "WebhookDelivery_status_availableAt_idx" ON "WebhookDelivery"("status", "availableAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "WebhookDelivery_subscriptionId_createdAt_idx" ON "WebhookDelivery"("subscriptionId", "createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "JobRun_job_startedAt_idx" ON "JobRun"("job", "startedAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "JobRun_status_idx" ON "JobRun"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ThrottlerHit_expiresAt_idx" ON "ThrottlerHit"("expiresAt");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "DomainEventDelivery" ADD CONSTRAINT "DomainEventDelivery_eventId_fkey" FOREIGN KEY ("eventId") REFERENCES "DomainEvent"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "WebhookDelivery" ADD CONSTRAINT "WebhookDelivery_subscriptionId_fkey" FOREIGN KEY ("subscriptionId") REFERENCES "WebhookSubscription"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE "Inspection" ADD COLUMN "broodFrames" INTEGER;
|
||||
Reference in new issue
Block a user