Phase 28 of ui/PLAN.md needs a persistent player-to-player mail channel; the existing `mail` package is a transactional email outbox and the `notification` catalog is one-way platform events. Stage A lands the schema (diplomail_messages / _recipients / _translations), a single-recipient personal send/read/delete service path, a `diplomail.message.received` push kind plumbed through the notification pipeline, and an unread-counts endpoint that drives the lobby badge. Admin / system mail, lifecycle hooks, paid-tier broadcast, multi-game broadcast, bulk purge and language detection / translation cache come in stages B–D. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Backend migrations
Goose migrations embedded into the backend binary by embed.go. Applied
at startup before any listener opens (see internal/postgres).
Pre-production single-file rule
While the platform is not yet in production, every schema change goes
into the existing 00001_init.sql file rather than a new
00002_*-prefixed file. The intent is to keep the schema in one
canonical place so reviewers and developers do not have to reconstruct
the latest shape from a chain of incremental migrations.
Operationally this means that pulling a branch with schema changes requires a fresh database — the only consumer today is local development and integration tests, both of which spin up disposable Postgres instances.
Remove this rule before the first production deployment. From that point on every schema change must be a new migration file with a monotonically increasing prefix, and
00001_init.sqlbecomes immutable history.
If you need to make a change, edit 00001_init.sql directly. Down
migrations should still be kept in sync (they live at the bottom of the
file — currently a single DROP SCHEMA backend CASCADE).