fix(07): UAT fixes — SMTP test email, DKV routing, Exchange domain field
Tessera CI/CD / Lint & Type Check (push) Waiting to run
Tessera CI/CD / Tests (push) Blocked by required conditions
Tessera CI/CD / Build & Deploy (push) Blocked by required conditions

- SMTP: add test-to field, send real email via sendMail() instead of verify()
- SMTP: fix no_auth warning shown as error for open-relay servers
- DKV: register dkv-fleet in MODULE_REGISTRY (fixes "Modul nicht gefunden")
- DKV: add dynamic [category]/[moduleSlug]/settings + vehicles sub-routes
- DKV: settings/vehicles links use useParams for consistent URLs
- DKV: add gear icon settings link to module main page
- DKV: rename module to "DKV-Rechnung" in seed + translations
- DKV: add optional domain field for Exchange (WebCredentials 3rd arg)
- DKV: hide IMAP-only fields (Port/Verschlüsselung/Ordner) when Exchange selected
- DKV: hide Exchange-only field (Domain) when IMAP selected
- Prisma: add domain column to DkvModuleConfig

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-28 21:58:26 +02:00
parent 4de87a8ea2
commit 01ff137f43
43 changed files with 5765 additions and 90 deletions
@@ -51,6 +51,7 @@ export function SmtpSettingsForm() {
const t = useTranslations('settings');
const [form, setForm] = useState<FormState>(DEFAULT_FORM);
const [testTo, setTestTo] = useState('');
const [isSaving, setIsSaving] = useState(false);
const [isTesting, setIsTesting] = useState(false);
const [showPassword, setShowPassword] = useState(false);
@@ -114,10 +115,10 @@ export function SmtpSettingsForm() {
setIsTesting(true);
setTestFeedback({ type: 'loading', message: t('smtp.testTesting') });
try {
const result = await testSmtp(buildPayload());
if (result.success && result.warning === 'no_auth') {
setTestFeedback({ type: 'error', message: t('smtp.testNoAuth') });
} else if (result.success) {
const payload = buildPayload();
if (testTo.trim()) payload.testTo = testTo.trim();
const result = await testSmtp(payload);
if (result.success) {
setTestFeedback({ type: 'success', message: t('smtp.testSuccess') });
} else {
setTestFeedback({ type: 'error', message: t('smtp.testFailed') });
@@ -126,7 +127,6 @@ export function SmtpSettingsForm() {
setTestFeedback({ type: 'error', message: t('smtp.testFailed') });
} finally {
setIsTesting(false);
// Auto-clear after 6 seconds
clearTimerRef.current = setTimeout(() => setTestFeedback(null), 6000);
}
};
@@ -300,6 +300,24 @@ export function SmtpSettingsForm() {
</p>
</div>
{/* Test-E-Mail Empfänger */}
<div>
<label htmlFor="smtp-test-to" className={labelClass}>
{t('smtp.testToLabel')}
</label>
<input
id="smtp-test-to"
type="email"
placeholder={t('smtp.testToPlaceholder')}
className={inputClass}
value={testTo}
onChange={(e) => setTestTo(e.target.value)}
/>
<p className="mt-1 text-xs text-muted-foreground">
{t('smtp.testToHelp')}
</p>
</div>
{/* Action row */}
<div className="flex gap-3 pt-2">
<button