Review: Add permanent Postmark inbound webhook endpoint via Tailscale funnel

review-2001-2026-08-04 Review

review needs-refinement

Verdict: NEEDS_REFINEMENT

Template Completeness

  • [x] Type -- Feature
  • [x] Lineage -- Standalone, follows PR #582
  • [x] Repo -- ldraney/pal-e-platform
  • [x] User Story -- As a platform operator / I want a permanent webhook endpoint / So that inbound emails are reliably processed
  • [x] Context -- Detailed background on Postmark inbound config, webhook.site expiry, security considerations
  • [x] File Targets -- 2 modify targets, 2 don't-touch targets
  • [x] Feature Flag -- none
  • [x] Acceptance Criteria -- 4 criteria
  • [x] Test Expectations -- 3 tests (manual + tofu plan)
  • [x] Constraints -- 5 constraints listed
  • [x] Checklist -- Standard PR/tests/no-unrelated
  • [x] Related -- References project page, arch note, PR #582

Traceability

  • [x] arch:deployment-postmark label -- arch-deployment-postmark note exists in pal-e-docs (architecture note covering SDK/MCP deployment pattern)
  • [x] arch note verified -- arch-deployment-postmark exists and is active
  • [x] story:postmark-email label -- label present on board item
  • [ ] story note MISSING -- [SCOPE] postmark-project-page user-stories section has keys: sdk, mcp, ci. No "email" story entry exists. Create user story entry on postmark-project-page user-stories section for story key "email" linking to a story-postmark-email note.
  • [x] Forgejo issue -- https://forgejo.tail5b443a.ts.net/ldraney/pal-e-platform/issues/583, open

File Targets

  • [x] terraform/modules/postmark/main.tf -- verified: file exists, currently contains only postmark_server and postmark_domain resources. Adding k8s resources here is consistent with the stated design decision.
  • [x] terraform/modules/postmark/variables.tf -- verified: file exists, currently has server_name, domain, return_path_subdomain variables.
  • [x] terraform/modules/networking/main.tf -- correctly listed as don't-touch. Funnel ingress pattern confirmed there (9 instances of tailscale.com/funnel annotation).
  • [x] terraform/dns.tf -- correctly listed as don't-touch.

Repo Placement

OK -- issue filed on ldraney/pal-e-platform, all file targets are in that repo. Single-repo change.

Dependencies

  • PR #582 (MX record + pillar secrets) -- stated as already merged. No blocker.
  • No other board items on board-platform-playbook appear related to this work.
  • Tailscale operator must be deployed (it is -- networking module manages it).

Acceptance Criteria

  • AC1: tofu plan shows resources -- agent-verifiable
  • AC2: webhook endpoint reachable at funnel URL -- requires deployed infrastructure (post-deployment validation)
  • AC3: InboundHookUrl points to funnel URL -- verifiable via tofu plan output
  • AC4: inbound emails queryable via search_inbound_messages -- requires real email flow (post-deployment validation)
AC2 and AC4 are post-deployment validation criteria, not agent-verifiable. This is appropriate for infrastructure work.

Blast Radius

CRITICAL: The postmark module is instantiated TWICE in terraform/main.tf:
  • module.postmark_iss (intelligentstaffingsystems.ai)
  • module.postmark_landscaping (landscaping-assistant.app)
Adding kubernetes_deployment_v1, kubernetes_service_v1, kubernetes_ingress_v1, and kubernetes_config_map_v1 directly to the module will create these resources for BOTH instances. The ticket only discusses the ISS domain inbound webhook. The agent needs clear guidance: either (a) add a boolean variable like enable_inbound_webhook to make the k8s resources conditional, or (b) confirm that both Postmark servers need inbound webhook endpoints.
Additionally, the module's versions.tf only declares the postmark provider (marcus-carey/postmark ~> 1.0). Adding Kubernetes resources requires the hashicorp/kubernetes provider. Terraform inherits it from the root module, but the module should declare it in its own required_providers for explicitness.

Decomposition Assessment

  • 2 file targets in 1 repo -- under threshold
  • 4 acceptance criteria -- under threshold
  • All changes in one module -- fits single agent pass
  • No decomposition needed.

Recommendation

  • [SCOPE] Create user story entry "email" on postmark-project-page user-stories section, and create backing note story-postmark-email.
  • [BODY] Address shared module blast radius: the postmark module is instantiated twice (postmark_iss, postmark_landscaping). Add guidance for the agent -- either add an enable_inbound_webhook boolean variable to conditionally create k8s resources, or state that both instances need the webhook. Without this, the agent will create duplicate deployments/ingresses for both domains.
  • [BODY] Add constraint: module versions.tf needs kubernetes provider added to required_providers since the module will now manage Kubernetes resources alongside Postmark API resources.