Files
tiny-forge/plans/cloudflare-dns-management/phase-3-dns-hooks.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

3.1 KiB

Phase 3: DNS Lifecycle Hooks

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

Objective

Hook DNS record management into the deployer and standalone proxy manager so that DNS records are automatically created/updated/deleted in sync with proxy consumers.

Tasks

  • Task 1: Create dns_records table for tracking managed records
    • Columns: id, fqdn, provider_record_id, consumer_type (instance/standalone), consumer_id, created_at, updated_at
    • Store queries: CreateDNSRecord, DeleteDNSRecord, GetDNSRecordByFQDN, ListDNSRecords, GetDNSRecordsByConsumer
  • Task 2: Add DNS provider to Deployer struct
    • Accept dns.Provider in constructor (can be nil for wildcard mode)
    • Helper: ensureDNS(ctx, fqdn, deployID) — calls provider.EnsureRecord + saves to dns_records
    • Helper: removeDNS(ctx, fqdn, deployID) — calls provider.DeleteRecord + removes from dns_records
  • Task 3: Hook into deployer — instance creation
    • After configureProxy succeeds in deployer.go and bluegreen.go → call ensureDNS
    • FQDN = subdomain + "." + settings.Domain
  • Task 4: Hook into deployer — instance removal
    • In removeInstance after NPM proxy deletion → call removeDNS
    • In rollback after NPM proxy deletion → call removeDNS
  • Task 5: Hook into standalone proxy manager
    • CreateProxy → after NPM host created, call ensureDNS
    • UpdateProxy → if domain changed, removeDNS(old) + ensureDNS(new)
    • DeleteProxy → call removeDNS
  • Task 6: Wire DNS provider into main.go
    • Read settings on startup, create provider if non-wildcard
    • Pass provider to Deployer and proxy Manager constructors
    • Handle provider being nil (wildcard mode = no DNS ops)
  • Task 7: Add DNSRecord model to internal/store/models.go

Files to Modify/Create

  • internal/store/models.go — add DNSRecord struct
  • internal/store/store.go — add dns_records table migration
  • internal/store/dns_records.go — CRUD queries
  • internal/deployer/deployer.go — add DNS hooks
  • internal/deployer/bluegreen.go — add DNS hooks
  • internal/deployer/rollback.go — add DNS cleanup
  • internal/proxy/manager.go — add DNS hooks
  • cmd/server/main.go — wire DNS provider

Acceptance Criteria

  • DNS records created when proxy consumers are created (if non-wildcard mode)
  • DNS records deleted when proxy consumers are removed
  • DNS records updated when standalone proxy domain changes
  • All DNS operations are best-effort (log warning on failure, don't block)
  • dns_records table tracks all managed records
  • Wildcard mode (default) skips all DNS operations

Notes

  • DNS operations must be wrapped in error handling that logs but doesn't fail the deploy
  • The dns_records table is the local source of truth for reconciliation (Phase 6)
  • Provider can be nil — all hooks must check for nil before calling

Review Checklist

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

Handoff to Next Phase