Files
tiny-forge/plans/cloudflare-dns-management/phase-6-dns-sync.md
T
alexei.dolgolyov c730cfaa45 feat: Cloudflare DNS management with automatic record sync
Add flexible DNS management to Docker Watcher. By default, wildcard DNS
is assumed (current behavior). When disabled, users can configure a
Cloudflare DNS provider with API token and zone selection. DNS A records
are automatically created/updated/deleted in sync with proxy consumers
(deployed instances and standalone proxies).

- Settings: wildcard_dns toggle, dns_provider, cloudflare credentials
- Cloudflare client: Provider interface with EnsureRecord/DeleteRecord/ListRecords
- DNS lifecycle hooks in deployer and proxy manager (best-effort)
- Settings UI: DNS config section with provider picker, zone selector, test button
- DNS Records page at /dns with filtering, sync status, reconciliation
- Records visible in both wildcard and managed modes
- Cleanup on provider change: removes old records when switching modes
2026-04-02 14:49:21 +03:00

2.6 KiB

Phase 6: DNS Sync & Reconciliation

Status: Not Started Parent plan: PLAN.md Domain: backend

Objective

Implement reconciliation logic that compares expected DNS records (from active consumers) with actual Cloudflare records, and provides a sync endpoint to fix discrepancies.

Tasks

  • Task 1: Add POST /api/dns/sync endpoint
    • Computes expected records from: active instances with proxy + standalone proxies
    • Fetches actual records from Cloudflare via ListRecords
    • Creates missing records (consumer exists, no CF record)
    • Deletes orphaned records (CF record exists, no consumer) — only for records in dns_records table
    • Updates dns_records table to reflect current state
    • Returns sync report: created N, deleted N, already_synced N
  • Task 2: Add helper to compute expected records
    • Query all instances where npm_proxy_id > 0 and status = "running" → extract FQDN
    • Query all standalone proxies → extract domain
    • Return list of expected FQDNs
  • Task 3: Add DELETE /api/dns/records/{fqdn} endpoint
    • Manual deletion of a specific DNS record (for orphan cleanup)
    • Calls provider.DeleteRecord + removes from dns_records
  • Task 4: Wire sync endpoint in internal/api/dns.go and router
  • Task 5: Add frontend sync button handler in DNS Records page
    • Call POST /api/dns/sync
    • Show sync report (toast or inline)
    • Refresh records list after sync

Files to Modify/Create

  • internal/api/dns.go — add sync + delete endpoints
  • internal/api/router.go — register new routes
  • internal/store/dns_records.go — add helper queries (list consumers with FQDNs)
  • web/src/lib/api.ts — add syncDnsRecords(), deleteDnsRecord() functions
  • web/src/routes/dns/+page.svelte — wire sync button

Acceptance Criteria

  • POST /api/dns/sync creates missing and removes orphaned records
  • Sync report returned with counts
  • Manual delete endpoint works for individual records
  • Frontend sync button triggers reconciliation and refreshes view
  • Only records tracked in dns_records table are candidates for orphan deletion (don't delete unrelated Cloudflare records)

Notes

  • Safety: only delete Cloudflare records that are tracked in our dns_records table (never touch records we didn't create)
  • Rate limiting: Cloudflare API has rate limits, batch operations where possible
  • Expected records query needs to join instances + standalone_proxies with settings.domain

Review Checklist

  • All tasks completed
  • Code follows project conventions
  • No unintended side effects
  • Build passes
  • Tests pass (new + existing)

Handoff to Next Phase