feat: improve setup wizard and DDNS UX
Unit Tests / test (push) Successful in 7m29s

Setup wizard (Issue 1 — UI):
- pic.ngo subdomain input now uses the same split-field style as DuckDNS:
  input + static '.pic.ngo' suffix in a flex row, availability status below

Setup wizard (Issue 2 — Caddy not regenerating after completion):
- complete_setup route now fires IDENTITY_CHANGED after a successful wizard
  submission so CaddyManager regenerates the Caddyfile immediately; users
  no longer need to press 'Renew Certificate' to start ACME

Settings — DDNS status (Issue 2 — domain status missing):
- New GET /api/ddns/status endpoint: returns registered flag, domain_name,
  public_ip (ipify with 30s cache), last_ip from heartbeat
- Settings DDNS section for pic_ngo now shows a live status row with
  color-coded dot (green=registered+current, yellow=registered+stale,
  gray=not registered), current public IP, and a Check button
- Status auto-refreshes on mount and after each successful re-registration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-09 00:36:47 -04:00
parent fb0326dae7
commit 40f9d90fad
5 changed files with 114 additions and 14 deletions
+13
View File
@@ -88,6 +88,19 @@ def complete_setup():
payload = request.get_json(silent=True) or {}
result = sm.complete_setup(payload)
if result.get('success'):
try:
from app import config_manager, service_bus, EventType
identity = config_manager.configs.get('_identity', {})
service_bus.publish_event(EventType.IDENTITY_CHANGED, 'setup', {
'cell_name': identity.get('cell_name'),
'domain': identity.get('domain'),
'domain_name': identity.get('domain_name'),
'domain_mode': identity.get('domain_mode'),
'effective_domain': config_manager.get_effective_domain(),
})
except Exception as exc:
logger.warning(f'Failed to publish IDENTITY_CHANGED after setup: {exc}')
status_code = 200 if result.get('success') else 400
return jsonify(result), status_code