What's fixed
🐛 Certificates displayed as "Expired" immediately after creation (#88)
JavaScript's null <= 0 evaluates to true, so any certificate whose validity information could not be read (parse failure, missing file) was shown as red Expired rather than a neutral unknown state. Stats counters, filter logic, table rows, and the detail panel were all affected.
All comparison sites now guard with days_until_expiry !== null && !== undefined before the <= 0 test.
🐛 Certificate renewal always reported as failure (#88)
The renewal API returns {message, domain, duration} — no success field. The UI checked result.success (always undefined → falsy) and branched to the error path even on HTTP 200. The certificate list was never reloaded after a successful renewal.
Response check now uses response.ok (HTTP 2xx).
✨ DNS Alias Mode configurable from the Web UI (#89)
The --domain-alias certbot flag (used for CNAME-based DNS delegation with RFC 2136 and other providers) was already supported by the backend but had no UI entry point.
A DNS Alias Domain text field is now available in Advanced Options on the certificate creation form.
🐛 API Keys and Deploy hooks tabs returning 404 (#90)
The Settings → API Keys tab called /api/keys (GET/POST/DELETE) and the Settings → Deploy tab called /api/deploy/config, /api/deploy/test/<id>, and /api/deploy/history — none of these routes existed in the web layer, producing 404 errors for every operation.
All missing routes are now registered and wired to the existing AuthManager and DeployManager implementations.
🐛 HashiCorp Vault / OpenBao address missing after save (#90)
Storage backend config was saved flat at the top level of certificate_storage (e.g. certificate_storage.vault_url) but the loader expected it nested under the backend key (certificate_storage.hashicorp_vault.vault_url), so the address disappeared from the form on the next page load.
collectStorageBackendSettings() now nests correctly. The loader also falls back to the legacy flat format for backward compatibility with existing config files.
165 tests passed, 10 skipped. No regressions.