Logotipo Hedhog

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

FieldTypeRequiredNotes
accountIdintyes
toRecipientDto[] ({ email, name? })yes
ccRecipientDto[] ({ email, name? })no
bccRecipientDto[] ({ email, name? })no
replyToRecipientDto[] ({ email, name? })no
subjectstring (max 255)no
textBodystringno
htmlBodystringno
attachmentsSnapshotunknown (JSON)noClient-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)