Review: Wire up palinks.app custom domain via Hetzner edge proxy (re-review)
Verdict: APPROVED
Re-review of board item #1392. Previous review (
review-1392-2026-06-13) flagged 4 items -- all 4 have been addressed.Previous Findings Resolution
- [x] [DECOMPOSE] -- Resolved. Umbrella #28 now has 3 sub-tickets: #50 (DNS), pal-e-platform #425 (Caddy), #51 (Rails + Keycloak)
- [x] [BODY] Missing Caddy path -- Resolved. Sub-ticket #425 specifies
/etc/caddy/Caddyfileandsalt/states/caddy/with both manual SSH and Salt state options - [x] [BODY] Keycloak mechanism -- Resolved. Sub-ticket #51 specifies Terraform via
terraform/k3s.tfvarswithtofu plan/tofu apply - [x] [LABEL] Points mismatch -- Resolved. Board item updated from 1 to 5 points
Template Completeness
- [x] Type
- [x] Lineage
- [x] Repo -- correctly declares Multi-repo umbrella
- [x] User Story
- [x] Context
- [x] Sub-Tickets -- new section listing execution order with repo and scope per sub-ticket
- [x] File Targets -- defers to sub-tickets with summary pointers
- [x] Feature Flag
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist -- maps to sub-ticket completion
- [x] Related
All required sections for
template-issue-feature are present. The umbrella format with a Sub-Tickets table is a good pattern for multi-repo work.Traceability
- [x] story:custom-domain label -- "Route palinks.app to production"
- [x] story note verified -- found in project-palinks user-stories section
- [x] arch:palinks label -- palinks architecture component
- [ ] arch note MISSING --
arch-palinksnot found in pal-e-docs. This has been flagged in multiple prior reviews (review-1400, review-1381, review-1377, etc.) and remains an open [SCOPE] item. However, this is a persistent platform-level gap, not a blocker for this specific ticket's scope. - [x] Forgejo issue -- ldraney/palinks#28, state: open
Sub-Ticket Verification
- [x] #50 (GoDaddy DNS) -- well-scoped manual task, clear AC (
digverification), no code changes - [x] pal-e-platform #425 (Caddy config) -- concrete file paths, includes Caddyfile template from architecture doc, offers both manual SSH and Salt state options
- [x] #51 (Rails + Keycloak) -- specifies
config/environments/production.rbandterraform/k3s.tfvarswith clear instructions
Minor issue in #425: Constraints section references "palinks #49" as the DNS dependency, but the DNS sub-ticket is actually #50. Issue #49 is an unrelated closed bug ("Open external links in new tabs"). This is cosmetic -- the dependency logic is correct, just the reference number is wrong.
File Targets
- [x]
config/environments/production.rb-- verified: file exists,config.hostsis commented out at lines 63-66. Development.rb shows the pattern:config.hosts << "hostname" - [x]
docs/custom-domain.md-- verified: file exists with Remaining Work section (5 items) to be updated - [x]
/etc/caddy/Caddyfileon edge-proxy -- correctly specified in #425 with sample Caddyfile content - [x]
terraform/k3s.tfvarsin pal-e-services -- specified in #51 with clear instructions on which arrays to update
Repo Placement
Umbrella is correctly filed on palinks (the primary app). Sub-tickets are filed on correct repos: #50 on palinks (manual task), #425 on pal-e-platform (Caddy infra), #51 on palinks (Rails changes + cross-repo Terraform). The multi-repo scope is now properly decomposed so each sub-ticket can be executed by an agent cloned into the correct repo.
Dependencies
- [x] pal-e-platform #419 (Hetzner edge provisioning) -- done, on board in done column (item #1417)
- [x] Spike #15 (custom domain routing) -- done, on board in done column (item #1377)
- [x] Execution order documented: #50 (DNS) before #425 (Caddy TLS), #51 independent but must deploy before e2e
Acceptance Criteria
5 AC on the umbrella, each is an end-to-end verification. Sub-tickets have their own per-component AC. The umbrella AC serves as the final integration gate. All are verifiable with
curl and browser testing. This is well-structured.Blast Radius
docs/custom-domain.mdlists landscaping-assistant.app and westsidekingsandqueens.com as future domains using the same pattern. This ticket establishes the reusable template.- No downstream consumers affected beyond the app itself.
- Keycloak redirect URI change: sub-ticket #51 correctly specifies adding to existing arrays, not replacing.
Decomposition Assessment
Already decomposed into 3 sub-tickets across 2 repos + 1 manual task. Each sub-ticket is appropriately scoped for a single agent pass. The umbrella serves as a coordination and verification checkpoint. No further decomposition needed.
Recommendations
- [BODY] Fix cross-reference in pal-e-platform #425: Constraints says "palinks #49" but should be "palinks #50" (DNS sub-ticket). Minor cosmetic issue, not a blocker.
- [SCOPE] Create architecture note
arch-palinks-- persistent gap flagged across 5+ reviews. Not blocking this ticket but should be addressed as platform housekeeping.
Neither recommendation is a blocker. The ticket is well-scoped and ready for execution.