🤖 Generated by the Daily AI Engineer
Roadmap: bring the home UniFi network under declarative management
Reconciled 2026-07-18. This epic had drifted badly: it described the repo as an empty
OpenTofu/Terraform tenant awaiting import-first onboarding, but the repo carries no .tf files at
all — its desired state is now Crossplane managed resources, and several themes below were either
delivered in a different form or retired outright. Rewritten against the repo's actual contents so
the roadmap of record stops pointing at an architecture that no longer exists. Everything asserted
here was checked against main today; see Evidence at the end.
Where the product is. devantler-tech/unifi holds the home network's desired state as
Crossplane managed resources, reconciled against the UniFi controller API by
provider-upjet-unifi:
wireguard-vpn-client.yaml — a vpn.../Client (the gateway dials the cluster's WireGuard server,
so the dynamic residential IP never needs to be reachable) plus its TrafficRoute.
admin-dns.yaml — dns.../Records pointing the admin hostnames at the in-tunnel VIP.
kustomization.yaml — what the platform reconciles.
CI (Validate (Crossplane manifests)) builds with kustomize and validates with kubeconform.
Onboarding an object that already exists in the controller is adopt-first — set
crossplane.io/external-name to its UniFi id — which is the Crossplane successor to the old
import-first rule, and is documented in docs/runbook.md.
Where it should be. The whole home network — L3 networks/VLANs, WLANs, firewall rules,
port-forwards, DNS — under the same declarative management, reproducible and drift-corrected, with
the VPN path actually carrying traffic.
Themes
T1 — Onboard the live network (the core mission). Partially delivered. The VPN client, its
traffic route, and the admin DNS records are authored as managed resources. The rest of the network —
core L3 networks/VLANs, WLANs/SSIDs, firewall rules + port-forwards — is still unmanaged, and each
category is an independent adopt-first PR: write the resource, set crossplane.io/external-name to
the existing object's id, and confirm reconciliation is a no-op before changing anything.
T2 — Safe reconcile & CI quality. Delivered in its current form: manifests are schema-validated in
CI on every PR. The old Terraform-era guards (the static import-first check and tflint) were retired
along with the .tf files they scanned — they are not a gap to reinstate. The remaining piece is a
pre-apply drift/no-op signal so a reviewer can see what a change would do to the live controller
before it merges.
T3 — Crossplane steady state. ✅ Delivered. This was gated on
monorepo #1860 ("build the real-CRD
Crossplane provider"), which closed as completed on 2026-07-03; the provider exists, is actively
developed, and is what reconciles this repo today. Ongoing work is provider currency rather than
migration — a provider release can change resource schemas, so a bump gets its changelog read and the
manifests re-validated.
T4 — Documentation & operability. ✅ Delivered. README.md, AGENTS.md and docs/runbook.md
describe the adopt-first Crossplane flow, so adding a resource is a checklist.
The one real blocker
Three values in wireguard-vpn-client.yaml are still placeholders, and all three resolve only once the
platform-side WireGuard server is provisioned — it is a devantler-tech/platform dependency, not
work this repo can do:
REPLACE_WITH_CONTROL_PLANE_PUBLIC_IP — the peer endpoint.
REPLACE_WITH_VPN_CLIENT_NETWORK_ID — the client's UniFi network id.
- the admin-DNS VIP, which needs the in-tunnel gateway to exist.
Until then the VPN path cannot carry traffic, and the admin DNS records would point at an address that
answers nothing. The categories in T1 that do not touch the tunnel (VLANs, WLANs, firewall,
port-forwards) are NOT blocked by this and are the available work.
Checklist
Evidence for this reconciliation
Checked against main on 2026-07-18: the repo tree contains 0 files ending in .tf; the tracked
manifests are wireguard-vpn-client.yaml, admin-dns.yaml and kustomization.yaml; .github/workflows/ci.yaml
runs kustomize build + kubeconform -strict; the three REPLACE_WITH_…/VIP placeholders are present
in the manifests as quoted above; and monorepo #1860 reports state: CLOSED, stateReason: COMPLETED,
closed 2026-07-03.
Problem → direction → rough size per child. The unblocked T1 categories are the highest-value
available work; the tunnel-dependent items wait on the platform.
Roadmap: bring the home UniFi network under declarative management
Where the product is.
devantler-tech/unifiholds the home network's desired state asCrossplane managed resources, reconciled against the UniFi controller API by
provider-upjet-unifi:wireguard-vpn-client.yaml— avpn.../Client(the gateway dials the cluster's WireGuard server,so the dynamic residential IP never needs to be reachable) plus its
TrafficRoute.admin-dns.yaml—dns.../Records pointing the admin hostnames at the in-tunnel VIP.kustomization.yaml— what the platform reconciles.CI (
Validate (Crossplane manifests)) builds withkustomizeand validates withkubeconform.Onboarding an object that already exists in the controller is adopt-first — set
crossplane.io/external-nameto its UniFi id — which is the Crossplane successor to the oldimport-first rule, and is documented in
docs/runbook.md.Where it should be. The whole home network — L3 networks/VLANs, WLANs, firewall rules,
port-forwards, DNS — under the same declarative management, reproducible and drift-corrected, with
the VPN path actually carrying traffic.
Themes
T1 — Onboard the live network (the core mission). Partially delivered. The VPN client, its
traffic route, and the admin DNS records are authored as managed resources. The rest of the network —
core L3 networks/VLANs, WLANs/SSIDs, firewall rules + port-forwards — is still unmanaged, and each
category is an independent adopt-first PR: write the resource, set
crossplane.io/external-nametothe existing object's id, and confirm reconciliation is a no-op before changing anything.
T2 — Safe reconcile & CI quality. Delivered in its current form: manifests are schema-validated in
CI on every PR. The old Terraform-era guards (the static import-first check and
tflint) were retiredalong with the
.tffiles they scanned — they are not a gap to reinstate. The remaining piece is apre-apply drift/no-op signal so a reviewer can see what a change would do to the live controller
before it merges.
T3 — Crossplane steady state. ✅ Delivered. This was gated on
monorepo #1860 ("build the real-CRD
Crossplane provider"), which closed as completed on 2026-07-03; the provider exists, is actively
developed, and is what reconciles this repo today. Ongoing work is provider currency rather than
migration — a provider release can change resource schemas, so a bump gets its changelog read and the
manifests re-validated.
T4 — Documentation & operability. ✅ Delivered.
README.md,AGENTS.mdanddocs/runbook.mddescribe the adopt-first Crossplane flow, so adding a resource is a checklist.
The one real blocker
Three values in
wireguard-vpn-client.yamlare still placeholders, and all three resolve only once theplatform-side WireGuard server is provisioned — it is a
devantler-tech/platformdependency, notwork this repo can do:
REPLACE_WITH_CONTROL_PLANE_PUBLIC_IP— the peer endpoint.REPLACE_WITH_VPN_CLIENT_NETWORK_ID— the client's UniFi network id.Until then the VPN path cannot carry traffic, and the admin DNS records would point at an address that
answers nothing. The categories in T1 that do not touch the tunnel (VLANs, WLANs, firewall,
port-forwards) are NOT blocked by this and are the available work.
Checklist
kustomize+kubeconform)Evidence for this reconciliation
Checked against
mainon 2026-07-18: the repo tree contains 0 files ending in.tf; the trackedmanifests are
wireguard-vpn-client.yaml,admin-dns.yamlandkustomization.yaml;.github/workflows/ci.yamlruns
kustomize build+kubeconform -strict; the threeREPLACE_WITH_…/VIP placeholders are presentin the manifests as quoted above; and monorepo #1860 reports
state: CLOSED,stateReason: COMPLETED,closed 2026-07-03.
Problem → direction → rough size per child. The unblocked T1 categories are the highest-value
available work; the tunnel-dependent items wait on the platform.