Files
tessera-ctl/.planning/quick/261008-dts-modul-domains-autodns-anbindung-kontakte/261008-dts-SUMMARY.md
T
2026-10-08 11:34:16 +02:00

16 KiB
Raw Blame History

phase, plan, subsystem, tags, status, requires, provides, affects, tech-stack, key-files, decisions, metrics, actuals, plan_head_before, plan_head_after
phase plan subsystem tags status requires provides affects tech-stack key-files decisions metrics actuals plan_head_before plan_head_after
quick-261008-dts 01 domains
autodns
domains
nestjs
nextjs
prisma
rls
money-safety
complete
module-registry (ModuleGuard, UseModule, ModuleManage)
crypto (CryptoService, global)
prisma tenant extension (forTenant)
Modul Domains (Slug domains) mit AutoDNS-Anbindung Demo/Live
Kunden, Kontakt-Zuordnung, Domainliste, Verfügbarkeit, Registrierung, Aufträge
docs/mandantentrennung-zugriffsklassifikation.md
CHANGELOG.md, docs/anleitung-anwender.md, docs/anleitung-administration.md
added patterns
atomarer Anspruch (updateMany where status DRAFT, count === 1) vor dem Netzaufruf
ein Client für alle AutoDNS-Aufrufe (feste Hosts, Takt 350 ms, kein Retry)
Pull-Abgleich offener Aufträge statt Cron
created modified
apps/api/src/domains/autodns-client.ts
apps/api/src/domains/autodns-parse.ts
apps/api/src/domains/domain-name.ts
apps/api/src/domains/domains-settings.service.ts
apps/api/src/domains/domains-directory.service.ts
apps/api/src/domains/domains-orders.service.ts
apps/api/prisma/migrations/20261008120000_domains_autodns/migration.sql
apps/web/src/app/(portal)/modules/domains/page.tsx
apps/web/src/app/(portal)/modules/domains/components/RegisterTab.tsx
apps/web/src/app/(portal)/modules/domains/components/OrdersTab.tsx
apps/api/src/domains/domains.controller.ts
CHANGELOG.md
Aufträge des nicht aktiven Systems werden beim Abgleich nicht angefasst (Zugangsdaten gehören zum aktiven System); nur der SUBMITTING-zu-UNKNOWN-Übergang gilt für alle.
Beim Abschicken wird der Entwurf VOR dem Anspruch gelesen, damit genau der bestätigte Inhalt hinausgeht; der Zugang wird vor dem Anspruch geladen, damit ein fehlender Zugang nie einen Auftrag in SUBMITTING stehen lässt.
HTTP-Antwort ohne Umschlag (Gateway 502/504) zählt als UNKNOWN, nicht als FAILED; FAILED nur bei ausdrücklicher AutoDNS-Ablehnung (auth, forbidden, rate-limit, business).
UNKNOWN wird beim Abschicken ohne lastCheckedAt gespeichert; erst ein Abgleich mit Ergebnis setzt es und schaltet das Verwerfen frei. Ein Fehler beim Nachsehen setzt es nicht.
Auftragssuche beim Abgleich nimmt nur Aufträge mit lesbarer Anlagezeit ab 5 Minuten vor der Bestätigung; ohne Zeit zählt ein Auftrag nicht (lieber UNKNOWN als ein falscher Treffer).
tasks completed
3 2026-10-08
tokens tasks commits
109600 3 3
6b0f840c1c d332246bde

Phase quick-261008-dts Plan 01: Modul Domains (AutoDNS) Summary

Neues Modul „Domains“ mit verschlüsselter Demo-/Live-Anbindung an AutoDNS, Kunden- und Kontaktzuordnung, Domainliste und einer Registrierung, die pro Auftrag höchstens einmal an AutoDNS geht und bei unklarem Ausgang auf „Ergebnis ungeklärt“ stehen bleibt, statt zu raten.

Commits

Aufgabe Commit Inhalt
1 (Tracer) 1f1c984 Migration (4 Tabellen mit Zeilenschutz), AutoDNS-Client, Einstellungen, Verbindungstest, Modulseite mit Reiter Einstellungen, Registrierungen (Loader, Icon, Navigationstitel)
2 450218f Kunden, Kontakte live aus AutoDNS (Seiten, 60-s-Zwischenspeicher), Zuordnung, Kontakt anlegen, Domainliste, Reiter Domains/Kontakte/Kunden
3 d332246 Verfügbarkeit, Entwurf, verbindliches Abschicken mit atomarem Anspruch, Auftragsverfolgung und Abgleich, Reiter Registrieren/Aufträge, Changelog, Anwender- und Administrationshandbuch, Mandantenschutz-Inventar

Nichts gepusht. Docs-Artefakte (PLAN, RESEARCH, SUMMARY, STATE) sind nicht committet.

Aufgabe 3 im Detail (Geldsicherheit)

  • Anspruch vor dem Netz: submitOrder führt updateMany mit id, tenantId, status: 'DRAFT', environment: <aktiv> aus. Nur bei count === 1 geht genau ein POST /domain (ohne Query, ohne Wiederholung) hinaus. Wer count !== 1 bekommt, lädt die Zeile neu und erhält 404, 409 environmentChanged oder 409 alreadySubmitted.
  • Ausgang: Auftragsnummer vorhanden gleich SUBMITTED. Ausdrückliche AutoDNS-Ablehnung (auth, forbidden, rate-limit, business, auch HTTP 200 mit status.type ERROR) gleich FAILED mit openKey null. Zeitablauf, Netz, TLS, unlesbare oder umschlaglose Antwort gleich UNKNOWN, nie zurück auf DRAFT.
  • Eindeutigkeit: openKey (Domain) mit @@unique([tenantId, environment, openKey]); FAILED und CANCELED geben ihn frei, SUCCESS behält ihn bewusst.
  • Abgleich: Pull beim Öffnen des Reiters „Aufträge“, bei „Aktualisieren“ und alle 30 s bei offenen Aufträgen und sichtbarer Seite; höchstens 20 Aufträge je Lauf, am längsten ungeprüfte zuerst; ein Fehler bei einem Auftrag hält die anderen nicht auf. SUBMITTING älter als 120 s wird UNKNOWN. UNKNOWN: erst GET /domain/{name}, dann POST /job/_search.
  • Verwerfen: Entwurf jederzeit; UNKNOWN erst nach einem Abgleich mit Ergebnis (lastCheckedAt gesetzt), im Browser mit zusätzlicher Warnung.
  • Browser: useRef-Sperre gegen Doppelklick; nach einem Fehler beim Abschicken bleibt der Knopf gesperrt, bis „Zurück“ gewählt wird (der Auftrag könnte angekommen sein).

Messwerte der Prüfkette (Aufgabe 3)

Segment Ergebnis
pnpm --filter @tessera/api test 133 Dateien, 2423 Tests grün
pnpm --filter @tessera/web test 132 Dateien, 1455 Tests grün
tsc --noEmit api und web grün
biome check (alle angefassten Dateien) grün
rls-coverage, rls-access-inventory 35 Tests grün (domains: 0/30/0, Paare 104)
Rollen-Decorator im Controller keiner
de/en-Schlüsselgleichheit domains.*, Wortprüfung (Mandant, Lizenz) 207 Schlüssel, gleich, ohne Treffer
CHANGELOG-/Handbuch-Greps ok
Neuaufbau docker compose up -d --build api web api, web, db laufen; „Domains module seeded in registry“; Routen orders/refresh vor orders/:id/submit; keine ausstehenden Migrationen; GET customers und GET orders geben []; POST availability ohne Zugang gibt 409 notConfigured
Gegenprobe Doppelbestellung Anspruchsprüfung testweise ausgebaut: Test „zwei gleichzeitige Bestätigungen“ und Test „Systemwechsel zwischen Lesen und Anspruch“ schlugen fehl; danach zurückgebaut

Abweichungen vom Plan

Automatisch behoben und ergänzt

1. [Regel 2 - Fehlende Absicherung] Kontakt-Prüfung beim Entwurf

  • Ort: createOrder
  • Problem: Ohne Prüfung könnte ein Entwurf Kontaktnummern enthalten, die bei AutoDNS nicht (mehr) existieren.
  • Lösung: Alle vier Kontaktnummern werden gegen die Kontaktliste geprüft (findContactsByIds), sonst 400 contactNotFound. Grenze: bei mehr als 2000 Kontakten kann ein vorhandener Kontakt außerhalb der gelesenen Liste fälschlich abgelehnt werden; die Meldung rät zum Neu-Einlesen.

2. [Regel 3 - Blockierend] Zeitlimit im Test einstellbar

  • DomainsSettingsService.transport bekam das Feld timeoutMs (nur für Tests), damit der Zeitablauf-Fall mit 20 ms getestet werden kann; im Betrieb bleibt es leer (20 s). HOSTNAME_PATTERN wird exportiert und im Auftragsdienst wiederverwendet.

3. [Regel 1 - Fehler im eigenen Entwurf] Zusätzliche Absicherungen im Abgleich

  • Ein Fehler beim Nachsehen (Anmeldung, Zeitablauf, Gateway) setzt lastCheckedAt nicht, damit „Verwerfen“ nie auf einer Prüfung beruht, die nichts geprüft hat. Nur eine ausdrückliche AutoDNS-Antwort „gibt es nicht“ (Fehlerart business) zählt als Ergebnis.
  • Alle Schreibzugriffe des Abgleichs sind an den erwarteten Zustand gebunden (status in der where-Klausel), damit zwei gleichzeitige Abgleiche sich nicht überschreiben.

4. [Hinweis] Reiter Aufträge für alle, auch ohne Einrichtung

  • Der Reiter ist immer sichtbar (Liste kommt aus der Datenbank); der Abgleich überspringt ihn still, wenn das aktive System nicht eingerichtet ist.

5. [Aufräumen] Versehentliche Fremdformatierung rückgängig gemacht

  • Ein Formatierungslauf hatte module-manage-handlers.spec.ts in unbeteiligten Zeilen umgebrochen; die Datei wurde zurückgesetzt und nur um die sechs Handlernamen ergänzt.

Nicht behoben (vorbestehend)

Keine fehlschlagenden Tests. biome organizeImports meldet in module-manage-handlers.spec.ts eine bereits vor dieser Arbeit vorhandene Importreihenfolge; bewusst nicht angefasst.

Threat-Status

ID Stand
T-dts-01 Passwort umgesetzt (Aufgabe 1); Antworten tragen nur hasPassword
T-dts-02 Rechte alle Schreib- und Verwalten-Wege tragen @ModuleManage('domains'), kein Rollen-Decorator; Controller- und Handler-Spec grün
T-dts-03 Doppelbestellung umgesetzt und mit Gegenprobe belegt (siehe oben)
T-dts-04 SSRF feste Hosts, redirect: 'error', Pfadprüfung
T-dts-05 Organisationstrennung forTenant überall, RLS-Gates grün
T-dts-06 Abfragegrenze Takt 350 ms, höchstens 20 Aufträge je Abgleich, Verbindungstest ein Aufruf
T-dts-07 Demo/Live System in Anspruch und Zuordnung, Wechsel nur mit Bestätigung
T-dts-08 Routen-Reihenfolge orders/refresh vor orders/:id/..., Spec prüft
T-dts-09 Eingaben normalizeDomainName, Validatoren, ParseUUIDPipe
T-dts-10 Fehlertexte nur messages[].text, gekürzt; AutoDNS 401/403 als 502

Bekannte Stubs

Keine. Die Anzeige „Preis nicht ermittelbar“ ist gewollt (AutoDNS nennt keinen Preis).

Prüfung gegen AutoDNS-Demo

Voraussetzung: Demo-Zugangsdaten eintragen (Domains, Einstellungen, Zugang Demo-System, Benutzername, Passwort, Kontext). System bleibt auf „Demo-System“. Jeder Punkt schließt eine offene Annahme aus der Recherche.

Nr. Annahme Prüfung in der Oberfläche Wenn es abweicht
1 A1: Welcher Demo-Kontext funktioniert (1 oder 4) Einstellungen, Zugang Demo-System: Kontext 4 eintragen, speichern, „Verbindung testen“; bei Fehler 1 versuchen. Je Versuch genau einmal klicken (Sperrgefahr) Wert merken und in die Handbücher übernehmen
2 A6/A9: Anmeldung ohne Zwei-Faktor, Test gelingt „Verbindung testen“ zeigt „Verbindung erfolgreich“ bei Anmeldefehler Benutzer ohne 2FA verwenden
3 A2: Kontaktfelder und Telefonformat Reiter Kontakte, „Neuer Kontakt“: erst Person, dann Organisation anlegen (Telefon +49 30 123456). Meldung „Der Kontakt wurde bei AutoDNS angelegt“, Kontakt erscheint nach „Aus AutoDNS neu einlesen“ Fehlermeldung von AutoDNS lesen (steht im Formular); Pflichtfelder oder Telefonformat anpassen
4 A3: Verfügbarkeitsprüfung liefert genau die gefragte Domain mit WHOIS-Status und Preis Reiter Registrieren: eine sicher freie Domain (zufälliger Name) und eine belegte (zum Beispiel denic.de) prüfen. Frei zeigt „… ist frei“ mit Preis; belegt zeigt „nicht frei“ mit Status. Außerdem eine Umlautdomain prüfen Steht immer „nicht frei“ mit Status „NO_RESULT“, liefert DomainStudio den Namen anders (Suchwort, Endung) und parseDomainStudio oder die Anfrage ist anzupassen. Fehlt nur der Preis, erscheint „Preis nicht ermittelbar“: Preisform prüfen
5 A4/A5: Registrierung liefert Auftragsnummer, { id } genügt als Kontaktverweis Zusammenfassung erstellen, Häkchen setzen, „Jetzt verbindlich registrieren“. Erwartet: „wird bearbeitet“, Reiter Aufträge zeigt „In Bearbeitung“ „Fehlgeschlagen“ mit Text von AutoDNS: Text lesen (Kontaktverweis, Nameserver, Pflichtfelder). Steht ein Auftrag ohne Nummer auf „In Bearbeitung“ und ändert sich nie, ist die Fundstelle der Nummer anders (extractJobFromSubmit)
6 Auftrag erreicht SUCCESS, Tessera folgt Reiter Aufträge, „Aktualisieren“ (oder 30 s warten): Stand wechselt auf „Registriert“ bleibt er „In Bearbeitung“, in AutoDNS den Auftrag ansehen; „Rückfrage nötig“ heißt Status SUPPORT
7 D-J: Domainliste mit Inhaber, Ablaufdatum, registryStatus Reiter Domains, „Aus AutoDNS neu laden“: die neue Domain erscheint mit Inhaber, Ablaufdatum und Status (Aktiv, In Bearbeitung …). Kunde nach Zuordnung des Inhaber-Kontakts Status als Rohwert angezeigt: registryStatus hat andere Werte, Beschriftungen nachziehen. Ablaufdatum „–“: Feld expire fehlt in der Antwort
8 A8: .de mit Standard-Nameservern besteht die Nameserver-Prüfung Standard-Nameserver in den Einstellungen eintragen (bei AutoDNS eingerichtete), eine freie .de-Domain registrieren „Fehlgeschlagen“ mit Nameserver-Meldung: Nameserver einrichten oder korrigieren
9 Neu in Aufgabe 3: Auftragssuche (POST /job/_search, Filter object, Anlagezeit) und GET /domain/{name} für nicht Gefundenes Schwer künstlich auszulösen. Wenn ein Auftrag je auf „Ergebnis ungeklärt“ steht: „Aktualisieren“ klicken. Erwartet: Tessera findet die Domain (Registriert), einen Auftrag (In Bearbeitung) oder setzt die Prüfung (dann ist „Verwerfen“ möglich) Bleibt „Verwerfen“ trotz Abgleich gesperrt, liefert GET /domain/{name} für Unbekanntes keinen business-Fehler; Antwortform prüfen
10 Neu in Aufgabe 3: Umlautdomain wird als Punycode gesucht und bestellt Umlautdomain prüfen; Anzeige zeigt die Umlautform DomainStudio erwartet ggf. die Unicode-Form im Suchwort
11 D-J: Wert für „Kündigung vorgemerkt“ Eine Domain mit vorgemerkter Kündigung in der Liste ansehen (falls vorhanden) Werte von cancelationStatus prüfen (NONE und NOT_SET gelten als „keine“)

Browser-Prüfschritte für den Orchestrator (dunkler Modus bevorzugt)

Lokal: http://localhost:3000, Anmeldung admin / admin123. Playwright-Prüfung mit Theme-Knopf auf dunkel.

  1. Aktivieren: Marktplatz, Modul „Domains“ aktivieren. Erwartet: Modul in der Seitenleiste (Gruppe Domains), Erde-Symbol.
  2. Freigabe Benutzen gegen Verwalten: Mit einem normalen Benutzer mit „Benutzen“ anmelden: Reiter Domains, Kontakte, Kunden, Aufträge sichtbar; kein Registrieren, kein Einstellungen, kein „Neuer Kontakt“, keine Zuordnung, keine Kunden-Knöpfe. Mit Admin oder „Verwalten“: zusätzlich Registrieren und Einstellungen.
  3. Einstellungen: Ohne Zugang zeigt die Kopfzeile „AutoDNS nicht eingerichtet“ mit Hinweis und Knopf „Zu den Einstellungen“. Passwort eintragen, speichern, Seite neu laden: Passwortfeld leer mit Platzhalter „Gespeichert – leer lassen …“. Live-Kontext ist mit 4 vorbelegt. Auswahl „Live-System“: Bestätigungsfeld erscheint; „Abbrechen“ stellt Demo zurück; erst „Live-System verwenden“ speichert, Kopfzeile zeigt dann „Live-System – Registrierungen kosten Geld“. Wieder auf Demo zurückstellen. Nameserver (zwei) eintragen und speichern.
  4. Kontakte: Liste, Suche, Filter „Nicht zugeordnet“, „Nach Kunde gruppieren“; Kontakte ankreuzen, Kunden wählen, „Zuordnen“; „Zuordnung entfernen“; „Neuer Kontakt“ mit ungültiger E-Mail und mit Telefon ohne „+“ (Fehler sichtbar), dann gültig speichern.
  5. Kunden: Kunden anlegen, einen als „Eigene Firma“ markieren (Kennzeichnung erscheint, bei einem zweiten wandert sie); Kunden mit Kontakten löschen: Meldung „Diesem Kunden sind noch Kontakte zugeordnet …“.
  6. Domains: Liste, Gruppen pro Kunde mit „Nicht zugeordnet“ zuletzt, Kundenfilter blendet andere Gruppen aus, Datum als TT.MM.JJJJ.
  7. Registrieren: Ungültiger Name zeigt Meldung; freie und belegte Domain; Kontaktauswahl gruppiert nach Kunde, Voreinstellung Admin gleich Inhaber, Technik/Zone gleich eigene Firma; Nameserver hinzufügen/entfernen (2 bis 6); „Zusammenfassung anzeigen“ zeigt System-Kennzeichnung, Preis oder „Preis nicht ermittelbar“; „Jetzt verbindlich registrieren“ bleibt gesperrt bis zum Häkchen; Doppelklick auf den Knopf darf nur einen Auftrag erzeugen (Reiter Aufträge zeigt eine Zeile, Server-Log zeigt ein einziges „Registrierung abgeschickt“). Vorsicht: Mit Demo-Zugang ohne echte Daten antwortet AutoDNS mit einem Fehler, die Zeile steht dann auf „Fehlgeschlagen“ oder „Ergebnis ungeklärt“; beides ist ein gültiger Ausgang.
  8. Aufträge: Reiter zeigt Zeilen mit System (Demo/Live), Stand, Bestätigt von/am, Fehlertext; „Aktualisieren“; „Verwerfen“ nur für Verwalter bei Entwurf und geprüftem unklarem Auftrag, mit Rückfrage.

Self-Check: PASSED

  • Dateien vorhanden: domain-name.ts, domains-orders.service.ts, dto/domains-order.dto.ts, RegisterTab.tsx, OrdersTab.tsx, order-status.ts (alle von git status als hinzugefügt bestätigt).
  • Commits vorhanden: 1f1c984, 450218f, d332246 liegen in der Historie von HEAD (git rev-list --count 6b0f840..HEAD gleich 3).