Files
openmail/docs/adr/0006-self-hosted-first.md
Karti TripathiandClaude Opus 5 a42b798a0e Scaffold tier 2 and 3, the schema, the website, and self-hosted-first
Store: the full Postgres schema as an embedded migration. UUIDv7 keys so
`ORDER BY id` is a free chronological index; raw MIME and attachments live
in object storage with only a key in the row; `pods` present from day one
because retrofitting tenancy costs more than an unused column. API keys are
stored as a SHA-256 hash — a database dump must not be a set of live
credentials.

API: the v0 route table, including `ingest`, which closes the
receive→thread→extract loop with zero mail infrastructure and is what makes
the agent layer testable in CI. Scopes are a closed enum rather than
strings, so "can send mail" and "can mint keys" are not one typo apart.
Internal errors are logged in full and reported as a bare string.

MCP: the tool catalogue, six tools. Adding a row here is the only way an
agent gains a capability — a new REST route is invisible until someone opts
it in. Three tests guard the rule that no tool can ever reach key
management; CI fails rather than production.

ADR 0006: enterprise self-hosted first. A hosted offering comes only after
we have run this ourselves long enough to have a deliverability record
worth selling. `pods` stays in the schema as the thing that keeps that path
open — do not remove it as dead code.

Also: multi-stage Dockerfile running as a non-root system user with no
shell in the runtime image, and the openmail.karti.ai static page.

17 tests, zero clippy warnings, fmt clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JkyvfNJGTshJNE9FtwPLk7
2026-09-02 13:20:51 -07:00

40 lines
1.9 KiB
Markdown

# ADR 0006 — Enterprise self-hosted first; SaaS only after we run it ourselves
**Status:** Accepted, 2026-09-02.
## Decision
The product is a **self-hostable server for enterprises, small businesses and
builders.** A hosted offering is not a v1 goal and may never exist. If it does,
it comes only after we have run OpenMail ourselves, in production, long enough
to have a deliverability track record worth selling.
## Why this ordering and not the reverse
- **Deliverability cannot be shortcut.** A hosted product's entire value is
inbox placement, which is months of IP warmup, feedback-loop enrolment and
suppression-list discipline. Selling that before we have it is selling
something we do not own.
- **Self-hosted is the differentiator.** Every competing agent-mailbox product
is hosted-only. Leading with a SaaS puts us on their ground, competing on the
thing they have already spent years on.
- **Auditability is the purchase condition.** Enterprises will not point MX at
a closed box. Public source under Apache-2.0 is why they can say yes, and the
self-hosted path is the one that requires no trust in us at all.
- **We become our own first serious user.** The bugs that matter in mail —
silent DANE downgrades, an MTA-STS policy cached wrong for a year — surface
only under real traffic. Running it ourselves before selling it is how we
find them on our own mail instead of a customer's.
## Consequences
- `pods` (tenancy) stays in the schema from v0.1 even though nothing uses it.
It is the piece that keeps the SaaS path open without a migration. **Do not
remove it as dead code.**
- No billing, no Stripe, no hosted control plane in the tree. When someone
proposes one, this ADR is the answer.
- Docs, defaults and error messages are written for an operator running one
box, not for a tenant of ours.
- The website (`website/`) sells self-hosting and links to the repo. It does
not collect signups for a product that does not exist.