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
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
# Phase 3: DNS Lifecycle Hooks
|
||||
|
||||
**Status:** ⬜ Not Started
|
||||
**Parent plan:** [PLAN.md](./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
|
||||
<!-- Filled in after completion -->
|
||||
Reference in New Issue
Block a user