Review: Caddy reverse-proxy block for mail.landscaping-assistant.app (v2)

review-1734-2026-07-04-v2 Review

review approved

Verdict: APPROVED

Re-review of board item #1734. Previous review (review-1734-2026-07-04) returned NEEDS_REFINEMENT with three issues. All three have been resolved in the current issue body.

Template Completeness

  • [x] Type: Feature
  • [x] Lineage
  • [x] Repo
  • [x] User Story
  • [x] Context
  • [x] File Targets
  • [x] Feature Flag (none)
  • [x] Acceptance Criteria
  • [x] Test Expectations
  • [x] Constraints
  • [x] Checklist
  • [x] Related
All required sections present.

Traceability

  • [x] story:self-hosted label — "As platform admin, I want zero third-party email dependencies so I control deliverability and avoid Gmail app password rotation"
  • [x] story note verified — found in project-stalwart-email user-stories section (key: self-hosted, role: Platform Admin)
  • [x] arch:edge-vps label — Hetzner Edge VPS component
  • [x] arch note verified — arch-edge-vps note exists in pal-e-docs (title: "Architecture: Hetzner Edge VPS", project: stalwart-email)
  • [x] Forgejo issue — ldraney/pal-e-platform#499, state: open

File Targets

  • [x] salt/pillar/caddy.sls — verified: file exists at expected path, contains caddy:sites pillar structure with domain/proxy_target/www_redirect keys for 3 existing sites
  • [x] salt/states/caddy/Caddyfile.j2 — verified: file exists, confirms hardcoded :443 suffix and tls_server_name transport for ALL upstreams. Ticket correctly identifies need for local: true conditional to skip these for localhost targets
Previous issue resolved: Caddyfile.j2 now listed as file target with clear description of required template changes.

Repo Placement

Correct. Issue filed on ldraney/pal-e-platform, which contains both salt/pillar/caddy.sls and salt/states/caddy/Caddyfile.j2. Single-repo fix.

Dependencies

  • Blocking: Issue #498 (Stalwart install) — board item #1733, currently in next_up. Stalwart must be installed and running on port 8080 before the reverse proxy can route to it.
  • Dependency is documented in the issue Lineage section: "Depends on: Stalwart install issue (same repo)."

Acceptance Criteria

4 AC + 1 test expectation. All verifiable by an agent post-implementation:
  • "https://mail.landscaping-assistant.app loads Stalwart web admin" — curl + status code check
  • "TLS auto-provisioned by Caddy (Let's Encrypt)" — cert issuer check via openssl s_client
  • "Admin protected by Stalwart's built-in auth (no public registration)" — verify unauthenticated access returns 401/redirect
  • "Existing sites (palinks.app, landscaping-assistant.app, westsidekingsandqueens.com) continue to resolve and serve HTTPS after Caddyfile.j2 template change" — regression curl checks on all 3 domains
  • Test: curl -I https://mail.landscaping-assistant.app returns 200/302
Previous issue resolved: Regression criterion for existing sites now present.

Blast Radius

The Caddyfile.j2 template renders ALL sites (currently 3: palinks.app, landscaping-assistant.app, westsidekingsandqueens.com). The local: true conditional approach uses site.get('local', false) pattern, which defaults to false for existing sites — preserving their current behavior. Regression AC explicitly covers verification of existing sites post-change.

Decomposition Assessment

  • 2 file targets in 1 repo — acceptable
  • 4 acceptance criteria + 1 test — under threshold
  • Estimated agent work: under 5 minutes (1 pillar entry + 1 Jinja conditional)
  • No decomposition needed

Context Verification

Previous issue resolved: The Context section now specifies the exact pillar schema with local: true flag:
This gives the implementing agent unambiguous guidance on the pillar structure extension.

Recommendation

No action needed. All previous NEEDS_REFINEMENT issues have been addressed. Ticket is ready for implementation.