# Phase 6: DNS Sync & Reconciliation

**Status:** ⬜ Not Started
**Parent plan:** [PLAN.md](./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
<!-- Filled in after completion -->
