Review: Stalwart: Create domains + SMTP accounts via API
Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type — Feature
- [x] Lineage — "Depends on: pal-e-platform#498 (Stalwart install)"
- [x] Repo — present (but incorrect, see below)
- [x] User Story — present
- [x] Context — good detail on both domains and SMTP-only accounts
- [x] File Targets — present (but wrong targets, see below)
- [x] Feature Flag — "none"
- [x] Acceptance Criteria — 5 criteria
- [x] Test Expectations — swaks test command
- [x] Constraints — present
- [x] Checklist — present
- [x] Related — present
Traceability
- [x] story:self-hosted label — "As platform admin, I want zero third-party email dependencies so I control deliverability"
- [x] story note verified — found in project-stalwart-email user-stories section
- [x] arch:stalwart label — references Stalwart Mail Server component
- [x] arch note verified — arch-stalwart note exists in pal-e-docs with full architecture diagram
- [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/ldraney/pal-e-services/issues/164, open
File Targets
- [ ]
terraform/keycloak.tf— ISSUE: This file exists in pal-e-services and contains the dynamic smtp_server block (lines 47-60), but it is for DOWNSTREAM work (configuring Keycloak to use Stalwart). This ticket's scope is creating domains/accounts IN Stalwart, not configuring Keycloak to connect. - [ ] "Document SMTP account credentials in Salt GPG pillar or secrets pipeline" — ISSUE: Vague. Per arch-stalwart note, the actual target should be
salt/pillar/stalwart.slsin pal-e-platform (domains, accounts, DKIM keys). This file does not exist yet (created by #498).
Repo Placement
MISMATCH. Issue filed on
ldraney/pal-e-services but:- Title says "via API" — implies Stalwart REST API calls (admin action on edge VPS, not code in pal-e-services)
- Per arch-stalwart: "SaltStack managed: Declarative state in salt/states/stalwart/; pillar-driven config" — Salt files live in
pal-e-platform - If automated via Salt pillar, repo should be
ldraney/pal-e-platform - If manual API calls, this is more of a Task type (no code files to modify)
- keycloak.tf in pal-e-services is the consumer of the credentials, not where they are created
Dependencies
- Blocked by #1733 (pal-e-platform#498): "Salt: Install Stalwart binary + systemd service on edge VPS" — currently in backlog, state OPEN. Stalwart must exist before domains can be created on it.
- Blocks #1737 (pal-e-services#165): DNS SPF/DKIM/DMARC for landscaping-assistant.app — needs DKIM public key output from this ticket
- Blocks #1738 (pal-e-services#166): DNS SPF/DKIM/DMARC for westsidekingsandqueens.com — needs DKIM public key output from this ticket
- Dependencies are partially documented (Lineage mentions #498; Related mentions "Blocked by: pal-e-platform#498"). Downstream blockers (#1737, #1738) are not documented in this issue but are captured on the board.
Acceptance Criteria
5 criteria — at the boundary but acceptable. All are verifiable:
- Domain existence: verifiable via Stalwart admin API GET
- Account auth: verifiable via swaks (test command provided)
- DKIM export: verifiable by checking key file exists
Missing criterion: "SMTP credentials stored in secrets pipeline / Salt pillar for downstream Keycloak config." This bridges to the downstream work.
Blast Radius
Low risk. This is a configuration action on a new service (Stalwart). No existing services are modified. The only downstream consumers are:
- DNS tickets (#1737, #1738) need the DKIM public keys as output
- Keycloak realm SMTP config (separate ticket needed) needs the account credentials
Decomposition Assessment
5 acceptance criteria, 1 repo (actual work is API calls or Salt pillar), estimated agent time <5 minutes once Stalwart is running. No decomposition needed.
Recommendations
[BODY]Fix File Targets — removeterraform/keycloak.tfreference (downstream Keycloak config, not this ticket's scope). Replace with: (a) If Salt-managed:salt/pillar/stalwart.slsin pal-e-platform — add domain/account entries; or (b) If API-driven: document that this is a manual/scripted Stalwart admin API action with credential output stored in secrets pipeline.[BODY]Fix Repo — if Salt-based automation, change toldraney/pal-e-platform. If manual API action, change Type to Task and replace File Targets with a Scope section describing the admin workflow.[BODY]Add output artifact — acceptance criteria should include "DKIM public keys written to a known location (e.g.,~/secrets/stalwart/dkim/) for downstream DNS tickets to consume."[LABEL]Consider addingstory:custom-domainas secondary label — this ticket directly enables per-domain sending (the custom-domain story), in addition to the self-hosted story.