1f1c984184
- 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>
166 lines
6.6 KiB
SQL
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());
|