Files
tessera-ctl/apps/api/prisma/migrations/20261008120000_domains_autodns/migration.sql
T
schalli 1f1c984184 feat(domains): Modul Domains mit AutoDNS-Zugang, Verbindungstest und Einstellungen
- Migration mit vier Tabellen (Einstellungen, Kunden, Kontaktzuordnung, Bestellungen), Zeilenschutz je Organisation
- AutoDNS-Client mit festen Demo-/Live-Adressen, Takt-Begrenzer, 20 s Zeitlimit, ohne Wiederholung
- Zugang je System verschluesselt gespeichert, Live-Wechsel nur mit Bestaetigung, Verbindungstest
- Modulseite mit Systemkennzeichnung und Reiter Einstellungen (nur Verwalten)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 10:35:21 +02:00

166 lines
6.6 KiB
SQL

-- 261008-dts — Modul "Domains" (AutoDNS / InterNetX Domainrobot).
--
-- Zweck: vier neue Tabellen und zwei Aufzaehlungen.
-- * "DomainsConfig": Einstellungen der Organisation (Singleton), getrennte
-- Zugaenge fuer das Demo- und das Live-System, Passwoerter AES-verschluesselt
-- (CryptoService), Standard-Nameserver.
-- * "DomainsCustomer": Kunden, denen AutoDNS-Kontakte zugeordnet werden;
-- eine Zeile darf als "Eigene Firma" markiert sein (Pruefung im Dienst).
-- * "DomainsContactAssignment": Zuordnung AutoDNS-Kontakt -> Kunde. Die
-- Umgebung (DEMO/LIVE) gehoert zum Schluessel, weil Kontakt-Ids beider
-- Systeme kollidieren. Kontakte und Domains selbst werden NICHT gespiegelt,
-- AutoDNS bleibt die Quelle der Wahrheit.
-- * "DomainsOrder": Domain-Bestellungen (Geldsicherheit). "openKey" traegt den
-- Domainnamen, solange die Bestellung offen ist (DRAFT, SUBMITTING,
-- SUBMITTED, UNKNOWN, SUCCESS) und ist bei FAILED/CANCELED NULL. Die
-- Unique-Regel (tenantId, environment, openKey) verhindert zwei offene
-- Bestellungen derselben Domain; NULLs wiederholen sich in Postgres
-- beliebig. SUCCESS behaelt den Schluessel mit Absicht: kurz nach der
-- Registrierung kann ein verzoegerter WHOIS noch "frei" melden.
--
-- AutoDNS-Kontakt- und Job-Ids stehen als TEXT (opake Dezimalzahlen).
--
-- Von Hand geschrieben (Vorbild 20261002130000_handelsware_datev); der
-- DDL-Teil stammt aus `prisma migrate diff`, damit der Stand ohne Abweichung
-- zum Schema passt.
--
-- Zeilenschutz (Pflicht — sonst schlaegt rls-coverage.spec.ts fehl): alle
-- Tabellen tragen `tenantId` und `tenant_isolation_policy` OHNE
-- Benutzerdimension (`USING ("tenantId" = current_tenant_id())`) — das sind
-- Verwaltungsdaten der Organisation, keine persoenlichen Daten eines
-- Benutzers. Keine `system_read_policy`: es gibt keinen Hintergrunddienst, der
-- diese Tabellen ueber alle Organisationen liest (Auftragsstatus wird beim
-- Oeffnen der Seite abgefragt, nicht per Zeitplan).
--
-- Rechte fuer die Anwendungsrolle tessera_app kommen automatisch ueber
-- ALTER DEFAULT PRIVILEGES aus 20260909130000_rls_app_role — hier nichts zu
-- tun.
--
-- WICHTIG: wie alle bisherigen RLS-Migrationen wirken diese Regeln erst,
-- wenn die Anwendung als Rolle ohne Umgehungsrecht verbindet (Schalter
-- heute AUS, siehe docs/mandantentrennung-datenbankrolle.md).
-- CreateEnum
CREATE TYPE "AutodnsEnvironment" AS ENUM ('DEMO', 'LIVE');
-- CreateEnum
CREATE TYPE "DomainOrderStatus" AS ENUM ('DRAFT', 'SUBMITTING', 'SUBMITTED', 'SUCCESS', 'FAILED', 'UNKNOWN', 'CANCELED');
-- CreateTable
CREATE TABLE "DomainsConfig" (
"id" TEXT NOT NULL,
"tenantId" TEXT NOT NULL,
"environment" "AutodnsEnvironment" NOT NULL DEFAULT 'DEMO',
"demoUser" TEXT,
"demoEncryptedPassword" TEXT,
"demoContext" INTEGER,
"liveUser" TEXT,
"liveEncryptedPassword" TEXT,
"liveContext" INTEGER,
"defaultNameServers" TEXT[] DEFAULT ARRAY[]::TEXT[],
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "DomainsConfig_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "DomainsCustomer" (
"id" TEXT NOT NULL,
"tenantId" TEXT NOT NULL,
"name" TEXT NOT NULL,
"isOwnCompany" BOOLEAN NOT NULL DEFAULT false,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "DomainsCustomer_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "DomainsContactAssignment" (
"id" TEXT NOT NULL,
"tenantId" TEXT NOT NULL,
"environment" "AutodnsEnvironment" NOT NULL,
"autodnsContactId" TEXT NOT NULL,
"customerId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "DomainsContactAssignment_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "DomainsOrder" (
"id" TEXT NOT NULL,
"tenantId" TEXT NOT NULL,
"environment" "AutodnsEnvironment" NOT NULL,
"domainName" TEXT NOT NULL,
"openKey" TEXT,
"status" "DomainOrderStatus" NOT NULL DEFAULT 'DRAFT',
"payload" JSONB NOT NULL,
"jobId" TEXT,
"jobStatus" TEXT,
"errorText" TEXT,
"createdByUserId" TEXT NOT NULL,
"confirmedByUserId" TEXT,
"confirmedByUsername" TEXT,
"confirmedAt" TIMESTAMP(3),
"lastCheckedAt" TIMESTAMP(3),
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "DomainsOrder_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "DomainsConfig_tenantId_key" ON "DomainsConfig"("tenantId");
-- CreateIndex
CREATE INDEX "DomainsConfig_tenantId_idx" ON "DomainsConfig"("tenantId");
-- CreateIndex
CREATE INDEX "DomainsCustomer_tenantId_idx" ON "DomainsCustomer"("tenantId");
-- CreateIndex
CREATE UNIQUE INDEX "DomainsCustomer_tenantId_name_key" ON "DomainsCustomer"("tenantId", "name");
-- CreateIndex
CREATE INDEX "DomainsContactAssignment_tenantId_idx" ON "DomainsContactAssignment"("tenantId");
-- CreateIndex
CREATE INDEX "DomainsContactAssignment_customerId_idx" ON "DomainsContactAssignment"("customerId");
-- CreateIndex
CREATE UNIQUE INDEX "DomainsContactAssignment_tenantId_environment_autodnsContac_key" ON "DomainsContactAssignment"("tenantId", "environment", "autodnsContactId");
-- CreateIndex
CREATE INDEX "DomainsOrder_tenantId_idx" ON "DomainsOrder"("tenantId");
-- CreateIndex
CREATE UNIQUE INDEX "DomainsOrder_tenantId_environment_openKey_key" ON "DomainsOrder"("tenantId", "environment", "openKey");
-- AddForeignKey
ALTER TABLE "DomainsContactAssignment" ADD CONSTRAINT "DomainsContactAssignment_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "DomainsCustomer"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- Zeilenschutz
ALTER TABLE "DomainsConfig" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "DomainsConfig" FORCE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation_policy ON "DomainsConfig"
USING ("tenantId" = current_tenant_id());
ALTER TABLE "DomainsCustomer" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "DomainsCustomer" FORCE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation_policy ON "DomainsCustomer"
USING ("tenantId" = current_tenant_id());
ALTER TABLE "DomainsContactAssignment" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "DomainsContactAssignment" FORCE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation_policy ON "DomainsContactAssignment"
USING ("tenantId" = current_tenant_id());
ALTER TABLE "DomainsOrder" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "DomainsOrder" FORCE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation_policy ON "DomainsOrder"
USING ("tenantId" = current_tenant_id());