Review: Caddy reverse-proxy block for mail.landscaping-assistant.app (v2)
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, containscaddy:sitespillar structure with domain/proxy_target/www_redirect keys for 3 existing sites - [x]
salt/states/caddy/Caddyfile.j2— verified: file exists, confirms hardcoded:443suffix andtls_server_nametransport for ALL upstreams. Ticket correctly identifies need forlocal: trueconditional 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.appreturns 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.