Terraform Infrastructure Encoding — 2 March 2026¶
What Was Built¶
Created ucca-infra repo (uccaonline/ucca-infra, private) containing Terraform declarations for all UCCA Cloudflare infrastructure. Audited every resource via the Cloudflare API, declared it in .tf files, and imported existing state.
116 resources imported, zero drift. Full technical documentation at docs.ucca.online/surfaces/infrastructure/terraform.
Key Decisions¶
- Terraform manages infra only — zones, DNS, storage, zone settings, Pages projects. Worker deployment stays in ucca-surfaces via wrangler. No overlap between tools.
- Cloudflare provider v5 (5.18.0) — significant schema differences from v4. Import IDs use simplified
zone_id/record_idformat, zones useaccount = { id = ... }instead ofaccount_id, individualcloudflare_zone_settingresources instead of the v4cloudflare_zone_settings_overridemonolith. - Terraform 1.5.7 — last open-source release before the BSL license change. Native import blocks (no
terraform importCLI commands needed). - Local state —
terraform.tfstateis gitignored. Migrate to remote backend when team access is needed. - Repo location:
infra/ucca-infra/in the workspace, matching theengine/,surfaces/,docs/pattern.
What Was Learned¶
- Cloudflare's API returns different record data than external DNS lookups. Proxied records show Cloudflare edge IPs via
dig, but the actual records are AAAA100::(Workers), CNAMEs to.pages.dev(Pages), and CNAMEs topublic.r2.dev(R2). Always use the API for record data. - Provider v5 documentation is sparse. Used
terraform providers schema -jsonto introspect the actual schema when docs were wrong or missing. - DKIM TXT records are truncated in API listings. The full keys only appear during
terraform planwhen the provider reads the actual record content. Declared values must match exactly or Terraform will try to overwrite them. - CAA records use a
datablock (flags/tag/value), not thecontentstring format used by other record types. - API token permissions are granular — Pages requires a separate "Cloudflare Pages: Read" permission that isn't included in zone or DNS scopes.
Resources Under Management¶
| Category | Count | Notes |
|---|---|---|
| Zones | 10 | 7 active, 3 pending (dlongglobal) |
| DNS records | 83 | Across 6 zones (rignold.com is empty) |
| Zone settings | 16 | 8 settings x 2 zones (ucca.online, rtopacks.com.au) |
| Pages projects | 2 | ucca-docs, ucca-knowledge (GitHub-connected) |
| Pages domains | 2 | docs.ucca.online, knowledge.ucca.online |
| D1 database | 1 | rtopacks-db |
| R2 bucket | 1 | rtopacks-media (APAC) |
| KV namespace | 1 | LEADS |
Infrastructure Issues Noted During Audit¶
- api.ucca.online — CNAME pointing to ucca.online, returns 522 (no Worker behind it). Orphaned DNS record.
- ucca.com.au — has two SPF TXT records (Google + Mailchimp). Only one SPF record per domain is valid per RFC 7208. Potential mail delivery issue.
- dlongglobal.com/net/org — 3 zones in "pending" status. Nameservers not yet pointed to Cloudflare.
- Security headers — ucca.online and rtopacks.com.au have full hardened headers. ops/docs/knowledge surfaces are missing some (CSP, Permissions-Policy).
Documentation Standards Established¶
Same session established documentation standards in CLAUDE.md:
- All docs on both surfaces require YAML frontmatter header (title, author, created, updated, status, description)
- All docs require a version history footer table
- Two documentation surfaces: docs.ucca.online (technical/operational) and knowledge.ucca.online (product knowledge/company context)
- Document at milestones, not every commit
Version History¶
| Version | Date | Change | Author |
|---|---|---|---|
| 1.0 | 2026-03-02 | Initial creation | Claude Code |