Multi-tenant daemon skeleton #1
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
posta/server#1
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What to build
Refactor
posta-server servefrom a single-tenant daemon into a multi-tenant one. Introduce aDaemontype with anidentityRunnerregistry; existingapi.Server,inbox.Inbox,outbox.Loop,sse.Hub,*store.SQLitetypes stay verbatim, instantiated once per identity. Top-level mux dispatches requests byr.Hostto the right runner.Manifest at
/etc/posta/identities.tomlis the only source of identity configuration:Per-identity files live by convention at
/var/lib/posta/<slug>/{keys.json,inbox.db}. Empty manifest = daemon starts but 404s every Host.The
servecommand stops accepting--url,--keys,--db, and--nameflags. Manifest is the only path. Clean break, no backcompat.Acceptance criteria
internal/daemon/package withDaemontype +identityRunnerand identity registry keyed by Hostcmd/posta-server/serve.goreads the manifest and instantiates one runner per identityserveflags reduced to--listenand--manifest(default/etc/posta/identities.toml)r.Hostto the right runner; unknown Host returns 404arne.localandmarcus.localURLs serves both via/etc/hostsaliasesBlocked by
None - can start immediately
Agent Brief
Category: enhancement
Summary: Refactor the
servecommand into a multi-tenant daemon that hosts one runner per identity, dispatched by HTTPHostheader.Current behavior:
The
servecommand runs a single-tenant daemon. Identity is supplied via flags (--url,--keys,--db,--name) and a single set ofapi.Server,inbox.Inbox,outbox.Loop,sse.Hub, and*store.SQLiteinstances handles every request. There is no concept of multiple identities sharing one process.Desired behavior:
A single
serveinvocation hosts an arbitrary number of identities. The set of identities is defined entirely by a TOML manifest (default location/etc/posta/identities.toml). Each identity is fully isolated at the application layer: its own keypair, its own SQLite database, and its own instances of the existing per-identity types — no cross-identity state sharing. Incoming HTTP requests are routed to the right identity by theHostheader. An empty manifest must boot cleanly and reply 404 to every request.Manifest format:
Per-identity files live by convention at
/var/lib/posta/<slug>/{keys.json,inbox.db}. The convention is hard-coded — paths are derived fromslug, not configured per-identity.Key interfaces:
Daemontype in a newinternal/daemon/package owns anidentityRunnerregistry keyed by canonical Host. EachidentityRunnerwraps the existing per-identity types (api.Server,inbox.Inbox,outbox.Loop,sse.Hub,*store.SQLite) verbatim — they are instantiated once per identity, not refactored.github.com/BurntSushi/tomllives alongside the daemon and produces the registry input.servecobra command's flag surface is reduced:--url,--keys,--db,--nameare removed.--listenand--manifestare the canonical knobs (--manifestdefaults to/etc/posta/identities.toml). The--acl,--rate-per-minute, and--configflags remain as global, daemon-wide flags — they apply uniformly across all identities. Per-identity ACL/rate/config is explicitly out of scope.r.Host. If no identity matches, return 404.Acceptance criteria:
internal/daemon/package definesDaemonandidentityRunnerwith a Host-keyed registry.BurntSushi/toml.servecommand reads the manifest and instantiates exactly one runner per identity, wiring the existing per-identity types verbatim.serveno longer accepts--url,--keys,--db,--name. It accepts--listen,--manifest(default/etc/posta/identities.toml), and continues to accept--acl,--rate-per-minute,--configas global flags.Hostto the correct runner; unmatched Host returns 404.Hostvalues reach two distinct runners and stay isolated).arne.localandmarcus.localURLs serves both via/etc/hostsaliases.Out of scope:
api.Server,inbox.Inbox,outbox.Loop,sse.Hub,*store.SQLite. They are reused as-is.