Aufgabe mit Typ, Status, Priorität, Aufwand, Fälligkeit und Herkunft; Projekt als eigene Klammer darum. Zwei Entwurfsentscheidungen: - Die Inbox ist kein eigener Zustand, sondern schlicht eine Aufgabe ohne Bereich. Einsortieren heißt: einen Bereich setzen. Ein zusätzliches Feld könnte mit der Zuordnung auseinanderlaufen. - Projekt ist ein eigenes Modell, kein Aufgabentyp. Ein Projekt hat selbst weder Aufwand noch Fälligkeit, sondern leitet beides aus dem ab, was drinsteckt. ARBEITSPAKET und MEILENSTEIN sind Typen der Aufgaben *innerhalb* eines Projekts. @@unique([quelle, quelleRef]) ist die Grundlage für die Integrationen ab M6: sie upserten darüber, statt zu doppeln. Von Hand erfasste Aufgaben tragen quelleRef = null; PostgreSQL sieht NULL-Werte als verschieden an, sie behindern sich also nicht. Verworfene Aufgaben zählen bewusst gar nicht in den Fortschritt eines Projekts — sonst sähe es fertig aus, weil die Hälfte gestrichen wurde. Fälligkeit wird in Kalendertagen in Europe/Berlin gerechnet, nicht in 24-Stunden-Schritten: was heute um 23:00 fällig ist, ist heute fällig. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
81 lines
2.6 KiB
SQL
81 lines
2.6 KiB
SQL
-- CreateEnum
|
|
CREATE TYPE "AufgabenTyp" AS ENUM ('AUFGABE', 'IDEE', 'ARBEITSPAKET', 'MEILENSTEIN', 'SPIEGEL');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "AufgabenStatus" AS ENUM ('OFFEN', 'GEPLANT', 'WARTET', 'ERLEDIGT', 'VERWORFEN');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "Quelle" AS ENUM ('MANUELL', 'ZAMMAD', 'WARTUNGSPLANER', 'TELEGRAM', 'SPIEGEL', 'MAIL', 'API', 'MCP');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "ProjektStatus" AS ENUM ('AKTIV', 'PAUSIERT', 'ABGESCHLOSSEN', 'VERWORFEN');
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "projekt" (
|
|
"id" TEXT NOT NULL,
|
|
"name" TEXT NOT NULL,
|
|
"beschreibung" TEXT,
|
|
"status" "ProjektStatus" NOT NULL DEFAULT 'AKTIV',
|
|
"bereichId" TEXT,
|
|
"zielAm" TIMESTAMP(3),
|
|
"erstelltAm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"aktualisiertAm" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "projekt_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "aufgabe" (
|
|
"id" TEXT NOT NULL,
|
|
"titel" TEXT NOT NULL,
|
|
"notiz" TEXT,
|
|
"typ" "AufgabenTyp" NOT NULL DEFAULT 'AUFGABE',
|
|
"status" "AufgabenStatus" NOT NULL DEFAULT 'OFFEN',
|
|
"prioritaet" INTEGER NOT NULL DEFAULT 3,
|
|
"aufwandMinuten" INTEGER,
|
|
"faelligAm" TIMESTAMP(3),
|
|
"erledigtAm" TIMESTAMP(3),
|
|
"bereichId" TEXT,
|
|
"projektId" TEXT,
|
|
"quelle" "Quelle" NOT NULL DEFAULT 'MANUELL',
|
|
"quelleUrl" TEXT,
|
|
"quelleRef" TEXT,
|
|
"erstelltAm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"aktualisiertAm" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "aufgabe_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "projekt_status_idx" ON "projekt"("status");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "projekt_bereichId_idx" ON "projekt"("bereichId");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "projekt_name_key" ON "projekt"("name");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "aufgabe_status_faelligAm_idx" ON "aufgabe"("status", "faelligAm");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "aufgabe_bereichId_status_idx" ON "aufgabe"("bereichId", "status");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "aufgabe_projektId_idx" ON "aufgabe"("projektId");
|
|
|
|
-- CreateIndex
|
|
CREATE INDEX "aufgabe_typ_status_idx" ON "aufgabe"("typ", "status");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "aufgabe_quelle_quelleRef_key" ON "aufgabe"("quelle", "quelleRef");
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "projekt" ADD CONSTRAINT "projekt_bereichId_fkey" FOREIGN KEY ("bereichId") REFERENCES "bereich"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "aufgabe" ADD CONSTRAINT "aufgabe_bereichId_fkey" FOREIGN KEY ("bereichId") REFERENCES "bereich"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "aufgabe" ADD CONSTRAINT "aufgabe_projektId_fkey" FOREIGN KEY ("projektId") REFERENCES "projekt"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|