docs: sessions, accounts, trusted senders, conversations, themes and the new reader

README: what the webmail now does, the architecture roles, a short guide with the
shortcuts, testing with a real database, and an honest list of what is not
finished. New docs/WEBMAIL.md as the reference for each feature and for the
colour system. OPERATIONS: sessions and trusted senders. DEPLOYMENT: the
two-step release as API calls, and what to expect when upgrading. MAILBOX-CORE:
the conversation invariants and migrations 0015 to 0018.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas RayanandClaude Sonnet 5.5 committed 2026-10-23 06:24:36 -03:00
1 parent c00134f2eb
commit 58d6f8e9e2
5 files changed
+471 -17

No files matched your search

+32
View File
@@ -12,6 +12,9 @@ the rules and the data code; none of them has its own copy.
| Credentials (password, app password, scopes) | `usecase/credentials.go` |
| Sending, and the copy filed in Sent | `ProcessOutboundEmail.Submit` (`FileSentCopy`) |
| Default folders of a mailbox | SQL function `provision_default_folders` (migration 0014) |
| Which conversation a message joins | `resolveThread`, called by `persistOne` (`conversation_thread.go`), at delivery |
| Conversation lists, answered state | `conversations.go` (read side only) |
| Whether a trusted sender's mail skips Junk | `usecase/trusted_delivery.go`; the list is `trusted_senders` |
The IMAP repositories, the webmail repository and the TS auth service are thin
adapters: they translate their protocol and call the code above.
@@ -45,12 +48,41 @@ operation must follow the same order.
2. Make the adapters call it.
3. Add it to the contract test and run it through both paths.
## Conversations
Every message filed through `persistOne` - delivery, the Sent copy, a draft -
gets a `thread_id` and an `in_reply_to`. The order that decides it is in
[docs/WEBMAIL.md](WEBMAIL.md#conversations). The invariants:
- `thread_id` NULL means "a conversation of its own" and is read as
`COALESCE(thread_id, id)`. Nothing may assume it is set.
- A **copy** keeps its source's conversation (`copyOne` copies
`COALESCE(thread_id, id)`), or the same message in two folders would be two
conversations.
- Delivery computes the subject key in Go and does **not** call the SQL helpers
from migration 0017: the end-to-end tests apply only migration 0001, and
delivery must work on a schema that has not been migrated yet.
`TestGoAndSQLAgreeOnTheSubjectKey` keeps the Go and SQL spellings equal.
- Reading a conversation is scoped by mailbox in the SQL, and another mailbox's
conversation id answers "not found" exactly like one that does not exist.
`conversation_thread_test.go` runs each of these against Postgres.
## Migration 0014
Creates `provision_default_folders`, creates the missing default folders of
existing mailboxes, and recomputes folder counters and `used_bytes` from the
messages. It is idempotent and runs with the other migrations at deploy.
## Migrations after 0014
| | |
| :--- | :--- |
| 0015 | BIMI certificate |
| 0016 | `trusted_senders` |
| 0017 | Conversation grouping: `lm_subject_key`, `lm_has_reply_prefix`, a one-time backfill by subject, and the index the list uses |
| 0018 | `mailboxes.conversation_view` |
## Not done
IMAP `APPEND` is still a stub. When it is implemented, drop a client-appended