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

18 KiB

phase, verified, status, score, covered_files, covered_digest, behavior_unverified, overrides_applied, human_verification
phase verified status score covered_files covered_digest behavior_unverified overrides_applied human_verification
quick-261008-dts 2026-10-08T11:25:00Z human_needed 7/7 must-haves verified
.planning/quick/261008-dts-modul-domains-autodns-anbindung-kontakte/261008-dts-PLAN.md
.planning/quick/261008-dts-modul-domains-autodns-anbindung-kontakte/261008-dts-SUMMARY.md
CHANGELOG.md
apps/api/prisma/migrations/20261008120000_domains_autodns/migration.sql
apps/api/prisma/schema.prisma
apps/api/src/app.module.ts
apps/api/src/domains/autodns-client.spec.ts
apps/api/src/domains/autodns-client.ts
apps/api/src/domains/autodns-parse.spec.ts
apps/api/src/domains/autodns-parse.ts
apps/api/src/domains/domain-name.spec.ts
apps/api/src/domains/domain-name.ts
apps/api/src/domains/domains-cache.ts
apps/api/src/domains/domains-directory.service.spec.ts
apps/api/src/domains/domains-directory.service.ts
apps/api/src/domains/domains-orders.service.spec.ts
apps/api/src/domains/domains-orders.service.ts
apps/api/src/domains/domains-settings.service.spec.ts
apps/api/src/domains/domains-settings.service.ts
apps/api/src/domains/domains.controller.spec.ts
apps/api/src/domains/domains.controller.ts
apps/api/src/domains/domains.module.ts
apps/api/src/domains/domains.seed.ts
apps/api/src/domains/domains.types.ts
apps/api/src/domains/dto/domains-contact.dto.ts
apps/api/src/domains/dto/domains-customer.dto.ts
apps/api/src/domains/dto/domains-order.dto.ts
apps/api/src/domains/dto/domains-settings.dto.ts
apps/api/src/module-registry/module-manage-handlers.spec.ts
apps/web/src/app/(portal)/modules/domains/components/ContactForm.test.tsx
apps/web/src/app/(portal)/modules/domains/components/ContactForm.tsx
apps/web/src/app/(portal)/modules/domains/components/ContactsTab.tsx
apps/web/src/app/(portal)/modules/domains/components/CustomersTab.tsx
apps/web/src/app/(portal)/modules/domains/components/DomainsTab.tsx
apps/web/src/app/(portal)/modules/domains/components/EnvironmentBadge.tsx
apps/web/src/app/(portal)/modules/domains/components/OrdersTab.test.tsx
apps/web/src/app/(portal)/modules/domains/components/OrdersTab.tsx
apps/web/src/app/(portal)/modules/domains/components/RegisterTab.test.tsx
apps/web/src/app/(portal)/modules/domains/components/RegisterTab.tsx
apps/web/src/app/(portal)/modules/domains/components/SettingsTab.tsx
apps/web/src/app/(portal)/modules/domains/domains-page.test.tsx
apps/web/src/app/(portal)/modules/domains/layout.tsx
apps/web/src/app/(portal)/modules/domains/page.tsx
apps/web/src/app/(portal)/modules/module-layouts.test.tsx
apps/web/src/components/domains/group-by-customer.test.ts
apps/web/src/components/domains/group-by-customer.ts
apps/web/src/components/domains/order-status.test.ts
apps/web/src/components/domains/order-status.ts
apps/web/src/components/domains/ui-classes.ts
apps/web/src/components/modules/module-tile.tsx
apps/web/src/lib/domains-api.ts
apps/web/src/lib/module-identity.ts
apps/web/src/lib/module-loader.ts
apps/web/src/lib/stores/nav-store.ts
apps/web/src/messages/de.json
apps/web/src/messages/en.json
apps/web/src/messages/umlaut-dictionary.ts
docs/anleitung-administration.md
docs/anleitung-anwender.md
docs/mandantentrennung-zugriffsklassifikation.md
v3:sha256:cbd9180b81679f6e773368c9acac6050b8ea89f07a2ceb0a6717989336115fdf 0 0
test expected why_human
Demo-Kontext und Verbindungstest (A1, A2/A6/A9): Demo-Zugangsdaten eintragen, Kontext 4 (sonst 1), je Versuch genau einmal auf 'Verbindung testen' klicken 'Verbindung erfolgreich. AutoDNS hat die Anmeldung bestätigt.' Welcher Demo-Kontext funktioniert, wird in die Handbücher übernommen Braucht das echte AutoDNS-Demo-System und echte Zugangsdaten; Tests laufen nur gegen einen nachgebauten Aufruf
test expected why_human
Kontakte anlegen (A2): Person und Organisation mit Telefon +49 30 123456 anlegen, danach 'Aus AutoDNS neu einlesen' Meldung 'Der Kontakt wurde bei AutoDNS angelegt', Kontakt erscheint in der Liste. Feldsatz und Telefonformat werden von AutoDNS angenommen Die Form des POST /contact-Bodys ist nur gegen die echte API belegbar
test expected why_human
Verfügbarkeit (A3, Umlaut): freie, belegte (z. B. denic.de) und Umlautdomain prüfen Frei mit Preis, belegt mit WHOIS-Status, Umlautdomain als Punycode gesucht; ein fehlender Preis zeigt 'Preis nicht ermittelbar' Antwortform von POST /domainstudio (WHOIS-Status, Preisfundstelle) ist nur gegen das echte System prüfbar
test expected why_human
Registrierung im Demo-System (A4, A5, A8): Zusammenfassung, Häkchen, 'Jetzt verbindlich registrieren' für eine freie .de-Domain mit Standard-Nameservern Auftrag 'In Bearbeitung' mit Auftragsnummer, Kontaktverweis { id } wird akzeptiert, Nameserver-Prüfung besteht. Danach 'Aktualisieren' bis 'Registriert' (Job SUCCESS); Doppelklick erzeugt genau einen Auftrag POST /domain ist asynchron; Job-Fundstelle, Kontaktverweis und Nameserver-Prüfung sind nur am Demo-System belegbar
test expected why_human
Domainliste nach Registrierung (D-J) und Abgleich unklarer Aufträge Domain erscheint mit Inhaber, Ablaufdatum und Status (registryStatus vorhanden); GET /domain/{name} liefert für Unbekanntes einen business-Fehler, damit 'Verwerfen' nach einem Abgleich freigeschaltet wird registryStatus-Werte, cancelationStatus-Werte und die Antwort auf unbekannte Domains sind Annahmen über die echte API
test expected why_human
Rechte im Browser (optional, dunkler Modus): mit einem Benutzer nur mit 'Benutzen' anmelden Reiter Domains, Kontakte, Kunden, Aufträge sichtbar; kein Registrieren, kein Einstellungen, keine Schreibknöpfe; die API antwortet bei Schreibrouten 403 Die API-Metadaten und Oberflächen-Tests sind grün; ein echter Benutzen-Benutzer wurde in dieser Prüfung nicht angelegt (kein Eingriff in lokale Benutzer)

Quick-Task 261008-dts: Modul Domains (AutoDNS) Verification Report

Task Goal: Neues Modul "Domains" mit Anbindung an AutoDNS/InterNetX JSON-API: Einstellungen (verschlüsselter Zugang, Demo/Live, Kontext, Standard-Nameserver, Verbindungstest), Kontakte (lesen, anlegen, Kunden zuordnen, filtern/gruppieren), Domain registrieren (Verfügbarkeit, Kontakte, Nameserver, Zusammenfassung + ausdrückliche Bestätigung, keine Doppelbestellung, Job-Status), Domainliste. Ansehen mit "Benutzen", Ändern mit "Verwalten" oder Admin. Tests mit gemockter API. UI Deutsch, siezen, keine Mandant-Begriffe. CHANGELOG + Anleitungen. Verified: 2026-10-08 Status: human_needed Re-verification: No, initial verification

Alle sieben Wahrheiten sind im Code belegt. Es gibt keine Lücken. Offen sind nur Prüfungen, die das echte AutoDNS-Demo-System brauchen (gemäß Auftrag human_needed, keine Lücke).

Goal Achievement

Observable Truths

# Truth Status Evidence
1 Reiter je Recht; API antwortet auf Schreib-/Verwalten-Routen mit 403 für Benutzen VERIFIED domains.controller.ts: Klasse @UseModule('domains'); 12 Handler mit @ModuleManage('domains') (GET/PUT settings, connection-test, POST customers, PUT/DELETE customers/:id, POST contacts, contacts/assign, availability, orders, orders/:id/submit, orders/:id/cancel); GET status/customers/contacts/domains/orders und POST orders/refresh nur Klasse. Kein @Roles( (grep leer). domains.controller.spec.ts und module-manage-handlers.spec.ts grün (Metadaten, Deklarationsreihenfolge). page.tsx: useCanManageModule('domains') === true steuert Registrieren/Einstellungen; Reihenfolge Domains, Kontakte, Kunden, Registrieren, Aufträge, Einstellungen. Live-Stack: Admin erhält 200 auf alle Benutzen-Routen.
2 Zugang je System verschlüsselt, Demo/Live mit Bestätigung, ein GET /hello VERIFIED Migration/Schema: getrennte Spalten demo*/live*. domains-settings.service.ts: crypto.encrypt beim Speichern, leeres Passwort behält Wert, Antwort nur hasPassword, Entschlüsselungsfehler wirft InternalServerErrorException. Live-Stack: GET /settings ohne Passwortfeld; PUT {environment:LIVE} ohne confirmLive gibt 400 confirmLiveRequired. testConnection genau ein autodnsRequest(GET /hello); Spec prüft literalen Basic-Header YXBpLXVzZXI6Z2VoZWlt, URL, Kontext-Header. Neuer Stand startet auf DEMO. Verbindungstest ohne Zugang: {ok:false,kind:'not-configured'} (live bestätigt).
3 Kontakte: live aus AutoDNS, "Nicht zugeordnet", neu einlesen, anlegen, zuordnen, eigene Firma, Filter/Gruppierung VERIFIED domains-directory.service.ts: fetchAll seitenweise (100, max 2000, sequentiell), 60-s-TtlCache, Zuordnung je aktivem System, createContact, assignContacts, isOwnCompany löst Markierung bei anderen. Web: ContactsTab, ContactForm, CustomersTab, group-by-customer.ts. 27 Directory-Tests, ContactForm-/Gruppierungs-/Seitentests grün. Live: GET contacts ohne Zugang gibt 409 notConfigured. Echte AutoDNS-Antwort siehe Human-Punkte.
4 Domainliste mit Kunde (über Inhaber-Kontakt), Inhaber, Ablauf, Status VERIFIED listDomains nutzt POST /domain/_search?keys[]=expire&keys[]=ownerc, Inhabername und Kunde über Zuordnung des aktiven Systems, cancelationPending. DomainsTab.tsx mit Filter/Gruppierung; Seitentest prüft Gruppen, "Nicht zugeordnet" zuletzt, dd.mm.yyyy.
5 Registrieren: DomainStudio FREE, vier Kontakte, 2-6 Nameserver, Zusammenfassung, ausdrückliche Bestätigung, höchstens ein POST /domain, 409 bei Zweitbestätigung/Systemwechsel, UNKNOWN statt Raten VERIFIED domains-orders.service.ts submitOrder (Zeilen 456-534): Zugang vorab, Lesen, dann updateMany where {id, tenantId, status:'DRAFT', environment}; bei count !== 1 kein Netzaufruf, 404/409 environmentChanged/alreadySubmitted; genau ein callRaw('POST','/domain') ohne Query und ohne Schleife; Ausgang: Job → SUBMITTED, auth/forbidden/rate-limit/business → FAILED (openKey null), alles andere (Zeitablauf, Netz, TLS, umschlaglos) → UNKNOWN, nie zurück auf DRAFT. createOrder prüft Verfügbarkeit serverseitig neu (notAvailable 409), Nameserver 2-6, Kontakte gegen Liste. Migration: @@unique(tenantId, environment, openKey). Verhaltensbelegt: Test "zwei gleichzeitige Bestätigungen" (Spec 519-545, Promise.allSettled, Lese-Barriere, In-Memory-updateMany wertet where aus) endet mit einem Erfolg, einem alreadySubmitted, genau einem POST; Systemwechsel-Tests ohne Fetch. RegisterTab.tsx: useRef-Sperre, Häkchen Pflicht. Alle 66 Tests grün.
6 Auftragsstatus folgt dem Job; unklarer Auftrag erst nach Abgleich verwerfbar VERIFIED refreshOpenOrders (max 20, älteste Prüfung zuerst, SUBMITTING älter 120 s → UNKNOWN), refreshFromJob (SUCCESS/FAILED/CANCELED/Rest bleibt SUBMITTED mit jobStatus), reconcile (GET /domain/{name}, dann POST /job/_search; ein Fehler beim Nachsehen setzt lastCheckedAt nicht), cancelOrder (UNKNOWN ohne lastCheckedAt → 409 checkFirst). OrdersTab: Abgleich beim Öffnen, 30-s-Intervall nur bei offenen Aufträgen. Live: POST orders/refresh 201. Reale Job-Antwortform: Human-Punkt.
7 Ein Client, feste Hosts, 350 ms, 20 s, kein Retry, status.type ERROR = Fehler, AutoDNS-Login als 502 VERIFIED autodns-client.ts: AUTODNS_BASE_URLS Konstante, redirect:'error', AutodnsRateLimiter(350), AUTODNS_TIMEOUT_MS=20_000, 5-MiB-Deckel, kein Retry, Pfadprüfung, status.type==='ERROR' → business. domains.types.ts autodnsFailureToHttp: auth/forbidden → BadGatewayException autodnsAuth (nie 401/403), Zeit/Netz/TLS → 504. Alle Aufrufer (Settings, Directory, Orders) gehen durch autodnsRequest. 313-Zeilen-Spec mit literalen Werten grün.

Score: 7/7 Wahrheiten verifiziert (0 present, behavior-unverified; die Verhaltens-Wahrheit 5 ist durch einen benannten, bestehenden Test belegt)

Required Artifacts

Artifact Expected Status Details
apps/api/prisma/migrations/20261008120000_domains_autodns/migration.sql 4 Tabellen, 2 Enums, RLS VERIFIED Vier Tabellen mit ENABLE + FORCE + tenant_isolation_policy; migrate status "up to date", migrate diff --exit-code "No difference"
apps/api/src/domains/autodns-client.ts Client, Parser, Limiter VERIFIED Exporte AUTODNS_BASE_URLS, autodnsRequest, parseAutodnsEnvelope, AutodnsRateLimiter vorhanden
domains-settings.service.ts verschlüsselt, maskiert, Test VERIFIED 323 Zeilen, crypto.encrypt(, decryptPassword laut
domains-directory.service.ts Kunden, Listen, Zuordnung VERIFIED 585 Zeilen, Rest siehe Wahrheit 3/4
domains-orders.service.ts Anspruch, Abgleich VERIFIED 782 Zeilen, Anspruch mit status: 'DRAFT'
.../modules/domains/page.tsx Badge, 6 Reiter VERIFIED useCanManageModule('domains') steuert Reiter
.../components/RegisterTab.tsx Verfügbarkeit bis Bestätigung VERIFIED submittingRef, Checkbox, gesperrter Knopf
From To Via Status Details
submitOrder domainsOrder.updateMany DRAFT, dann POST /domain claim.count !== 1 vor dem Netz WIRED Zeilen 480-511
Settings-Dienst CryptoService crypto.encrypt( je System WIRED Zeilen 200-201
listDomains Zuordnung des aktiven Systems Inhaber-Kontakt-Id → Kunde WIRED loadAssignments(tenantId, environment)
Controller ModuleGuard @UseModule('domains') + @ModuleManage('domains') WIRED 12 Verwalten-Handler, kein Rollen-Decorator
page.tsx useCanManageModule('domains') Reiter/Schreibknöpfe WIRED Zeile 36
Modul-Registrierung Seed, Loader, Icon, Navtitel, Layout-Test, app.module.ts WIRED Log "Domains module seeded in registry"; Routen orders/refresh vor orders/:id/submit

Data-Flow Trace (Level 4)

Artifact Variable Source Real Data Status
DomainsTab Domainliste GET /modules/domains/domains → POST /domain/_search (AutoDNS live) Ja (gegen Mock getestet) FLOWING
ContactsTab Kontakte POST /contact/_search + lokale Zuordnung Ja FLOWING
OrdersTab Aufträge DomainsOrder aus der Datenbank, Abgleich mit AutoDNS-Job Ja FLOWING
EnvironmentBadge System/Status GET status (live: DEMO, nicht eingerichtet) Ja FLOWING

Behavioral Spot-Checks

Behavior Command Result Status
Domains-, RLS- und Rechte-Specs vitest run src/domains rls-coverage rls-access-inventory module-manage-handlers 10 Dateien, 267 Tests grün PASS
Vollständige API-Suite pnpm --filter @tessera/api test 133 Dateien, 2423 Tests grün PASS
Vollständige Web-Suite pnpm --filter @tessera/web test 132 Dateien, 1455 Tests grün PASS
Web Domains/Meldungen/Layouts vitest run modules/domains components/domains module-layouts src/messages 10 Dateien, 98 Tests grün PASS
Typprüfung tsc --noEmit api und web beide ohne Ausgabe PASS
Lint biome lint auf Domains-Dateien 42 Dateien, keine Funde PASS
Migration ohne Abweichung prisma migrate status / migrate diff --exit-code "up to date" / "No difference" PASS
Live-Stack (Admin) curl status/settings/customers/orders; connection-test; PUT LIVE ohne confirmLive 200 / maskiert / 200 [] / not-configured / 400 confirmLiveRequired PASS
Wortlaut de/en domains.*-Schlüssel, Suche Mandant/Tenant/Lizenz in Texten, CHANGELOG, Handbücher 207 = 207, gleiche Schlüssel, keine Treffer PASS

Probe Execution

Step 7c: übersprungen, der Plan deklariert keine Probe-Skripte.

Requirements Coverage

Requirement Source Plan Description Status Evidence
QUICK-261008-dts (L-01 bis L-12) 261008-dts-PLAN.md Modul Domains SATISFIED im Code Wahrheiten 1-7; CHANGELOG-Eintrag unter "Unveröffentlicht / Neu"; ### Domains in anleitung-anwender.md und Inhaltsverzeichnis; ### Domains: AutoDNS anbinden in anleitung-administration.md; keine Transfer-/Kündigungs-/Zonenfunktion (L-07), generischer autodnsRequest vorhanden. Gegenprobe gegen echtes System: Human-Punkte

Anti-Patterns Found

File Line Pattern Severity Impact
(alle geänderten Dateien) TBD/FIXME/XXX/TODO/HACK keiner Suche ohne Treffer
domains.controller.ts POST connection-test antwortet mit HTTP 201 statt 200 (Nest-Standard für POST) Info Plan sagt "immer 200 mit { ok, kind, message }". Der Inhalt stimmt, der Browser wertet jedes 2xx gleich. Kein Eingriff nötig
autodns-client.ts 150-155 HTTP-Fehler mit lesbarer Hülle zählt als business, also als ausdrückliche Ablehnung (FAILED) Info Ein Gateway, das JSON mit messages liefert, könnte fälschlich als FAILED statt UNKNOWN gelten. Gateway-Seiten ohne Hülle gehen korrekt auf UNKNOWN. Geringes, hinnehmbares Restrisiko

Human Verification Required

Die Punkte stehen oben im Frontmatter (human_verification). Sie decken die elf Annahmen aus der SUMMARY-Checkliste ab, die nur das echte AutoDNS-Demo-System schließen kann: Demo-Kontext (A1), Anmeldung ohne 2FA, Kontaktfelder und Telefonformat (A2), DomainStudio-Antwort und Preis (A3), Job-Rückgabe und Kontaktverweis (A4/A5), Job bis SUCCESS, registryStatus/cancelationStatus, Nameserver-Prüfung für .de (A8), Auftragssuche und GET /domain/{name} für Unbekanntes sowie Umlautdomains. Dazu kommt eine optionale Browser-Prüfung mit einem reinen "Benutzen"-Benutzer.

Gaps Summary

Keine Lücken. Der Code erreicht das Ziel: Migration ohne Abweichung, Client, drei Dienste, Controller mit durchgängigem @ModuleManage und ohne Rollen-Decorator, sechs Reiter mit Rechtesteuerung, Doppelbestell-Schutz durch atomaren Anspruch (durch einen benannten Nebenläufigkeits-Test belegt), Tests mit gemockter API, deutsche Texte ohne verbotene Begriffe, CHANGELOG und beide Handbücher. Der lokale Stack läuft mit dem Modul. Offen sind nur die Annahmen über die echte AutoDNS-API, die laut Auftrag als human_needed zählen.


Verified: 2026-10-08 Verifier: Claude (gsd-verifier)