Get Hedhog updates in your inbox
New releases, fresh recipes, and breaking changes — no spam.
inbox Submodule
drafts
Autosaved, standalone compose drafts (inbox_draft) — not linked to a thread or message until explicitly sent.
Source path: libraries/inbox/src/draft
Module file: draft.module.ts
Introduction
The Drafts submodule manages `inbox_draft`, a table intentionally decoupled from `inbox_thread` and `inbox_message`: a draft has no `thread_id` or `message_id` foreign key, only an `account_id` and a `created_by_user_id`. This means composing and autosaving a draft never touches the thread/message tables at all, and sending a message (via the Messages submodule's `POST /inbox/messages/send`) does not consume, convert, or delete a draft automatically — the two are related only by convention in the client UI, not by a database relationship. A draft the user later sends manually still has to be deleted separately if the client wants it removed from the drafts list.
Every create and update call stamps `last_saved_at` with the current server time, which is the field the list endpoint sorts by (`orderBy: last_saved_at desc`) — this is what gives the drafts list its autosave-friendly ordering, where the most recently edited draft (not necessarily the most recently created one) always sorts first. The recipient fields (`to`, `cc`, `bcc`, `replyTo`) reuse the same `RecipientDto` shape as the Messages submodule's send endpoint, and `attachmentsSnapshot` is an untyped JSON blob intended to hold a client-side snapshot of attached-but-not-yet-uploaded files between autosaves; the service does no validation on its shape.
Access control follows the same per-account pattern as Threads and Messages: `create` validates access to the target `accountId` up front, and `update` only re-validates access if the request is actually moving the draft to a different account (`body.accountId !== existing.account_id`), avoiding a redundant access check on every keystroke-triggered autosave. Deletion is soft (`deleted_at`), consistent with the rest of the module's entities.
HTTP Endpoints
5 endpoints
Paginated list of drafts across the caller's accessible accounts, ordered by most recently saved.
- Query
- page, pageSize, search, accountId?
Get a single draft by ID.
- Params
- id (int)
Create a new draft. Sets last_saved_at to the current time.
Body
| Field | Type | Required | Notes |
|---|---|---|---|
| accountId | int | yes | — |
| to | RecipientDto[] ({ email, name? }) | yes | — |
| cc | RecipientDto[] ({ email, name? }) | no | — |
| bcc | RecipientDto[] ({ email, name? }) | no | — |
| replyTo | RecipientDto[] ({ email, name? }) | no | — |
| subject | string (max 255) | no | — |
| textBody | string | no | — |
| htmlBody | string | no | — |
| attachmentsSnapshot | unknown (JSON) | no | Client-side snapshot of pending attachments |
Update a draft (partial update, same fields as create). Re-validates account access only if accountId is changing. Refreshes last_saved_at.
- Params
- id (int)
Soft-delete a draft.
- Params
- id (int)