feat(backend): Wahl-Phasen, Verantwortliche-Invites, Auth fixes

- New VerantwortlicheInvite model: LT-issued invites so a person can
  register as Gemeinde Verantwortliche(r) for a specific Gemeinde,
  skipping the self-registration approval step.
- Wahl/Workshop/Teilnehmer gain phase support (phasenAnzahl,
  beschreibung), mirroring the WP plugin's multi-phase elections.
  Teilnehmer unique constraint now scoped per phase.
- Auth: team login + guest auth adjustments, spec coverage.
- sync.service.ts: register VerantwortlicheInvite as a synced model.
- wahl.service.ts: submitTeilnehmer updated for the new phase-scoped
  unique key.
- client: login/home screen rework, new theme.dart, FCM web tweaks.
- .gitignore: ignore .DS_Store.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-11 18:00:18 +02:00
co-authored by Claude Sonnet 5
parent cfa0070eab
commit 2f76790135
12 changed files with 403 additions and 40 deletions
@@ -0,0 +1,43 @@
-- DropIndex
DROP INDEX "Teilnehmer_wahlId_guestAccountId_key";
-- AlterTable
ALTER TABLE "Wahl" ADD COLUMN "beschreibung" TEXT,
ADD COLUMN "phasenAnzahl" INTEGER NOT NULL DEFAULT 1;
-- AlterTable
ALTER TABLE "Workshop" ADD COLUMN "beschreibung" TEXT,
ADD COLUMN "phase" INTEGER NOT NULL DEFAULT 1;
-- AlterTable
ALTER TABLE "Teilnehmer" ADD COLUMN "phase" INTEGER NOT NULL DEFAULT 1;
-- CreateTable
CREATE TABLE "VerantwortlicheInvite" (
"id" TEXT NOT NULL,
"kcId" TEXT NOT NULL,
"gemeindeId" TEXT NOT NULL,
"token" TEXT NOT NULL,
"email" TEXT,
"maxUses" INTEGER,
"usedCount" INTEGER NOT NULL DEFAULT 0,
"expiresAt" TIMESTAMP(3),
"revokedAt" TIMESTAMP(3),
"createdByUserId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "VerantwortlicheInvite_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "VerantwortlicheInvite_token_key" ON "VerantwortlicheInvite"("token");
-- CreateIndex
CREATE UNIQUE INDEX "Teilnehmer_wahlId_guestAccountId_phase_key" ON "Teilnehmer"("wahlId", "guestAccountId", "phase");
-- AddForeignKey
ALTER TABLE "VerantwortlicheInvite" ADD CONSTRAINT "VerantwortlicheInvite_kcId_fkey" FOREIGN KEY ("kcId") REFERENCES "Kc"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "VerantwortlicheInvite" ADD CONSTRAINT "VerantwortlicheInvite_gemeindeId_fkey" FOREIGN KEY ("gemeindeId") REFERENCES "Gemeinde"("id") ON DELETE CASCADE ON UPDATE CASCADE;