Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
16 KiB
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 |
|
complete |
|
|
|
|
|
|
|
|
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:
submitOrderführtupdateManymitid, tenantId, status: 'DRAFT', environment: <aktiv>aus. Nur beicount === 1geht genau einPOST /domain(ohne Query, ohne Wiederholung) hinaus. Wercount !== 1bekommt, lädt die Zeile neu und erhält 404, 409environmentChangedoder 409alreadySubmitted. - Ausgang: Auftragsnummer vorhanden gleich SUBMITTED. Ausdrückliche AutoDNS-Ablehnung (auth, forbidden, rate-limit, business, auch HTTP 200 mit
status.typeERROR) gleich FAILED mitopenKeynull. 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}, dannPOST /job/_search. - Verwerfen: Entwurf jederzeit; UNKNOWN erst nach einem Abgleich mit Ergebnis (
lastCheckedAtgesetzt), 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 400contactNotFound. 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.transportbekam das FeldtimeoutMs(nur für Tests), damit der Zeitablauf-Fall mit 20 ms getestet werden kann; im Betrieb bleibt es leer (20 s).HOSTNAME_PATTERNwird 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
lastCheckedAtnicht, 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 (
statusin derwhere-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.tsin 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.
- Aktivieren: Marktplatz, Modul „Domains“ aktivieren. Erwartet: Modul in der Seitenleiste (Gruppe Domains), Erde-Symbol.
- 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.
- 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.
- 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.
- 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 …“.
- Domains: Liste, Gruppen pro Kunde mit „Nicht zugeordnet“ zuletzt, Kundenfilter blendet andere Gruppen aus, Datum als TT.MM.JJJJ.
- 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.
- 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 statusals hinzugefügt bestätigt). - Commits vorhanden:
1f1c984,450218f,d332246liegen in der Historie von HEAD (git rev-list --count 6b0f840..HEADgleich 3).