Logotipo Hedhog

Get Hedhog updates in your inbox

New releases, fresh recipes, and breaking changes — no spam.

inbox Submodule

labels

Account-scoped labels (inbox_label) with optional system semantics, applied to messages via inbox_message_label, including a thread-wide toggle mode on the update endpoint.

Source path: libraries/inbox/src/label

Module file: label.module.ts

Introduction

The Labels submodule manages `inbox_label`, a per-account tagging catalog joined to messages through `inbox_message_label`. Each label has a `name` unique within its owning account (enforced at the service level with a `findFirst` + `ConflictException` check, not a database constraint), an optional `color`, and an optional `system_type` (`inbox` | `sent` | `archived` | `trash` | `spam`) that lets a label double as a semantic marker rather than a purely cosmetic tag — though nothing in the current service logic treats `system_type` specially beyond storing and sorting by it (`list` orders `system_type asc` before `id desc`, grouping system-typed labels first).

`PATCH /inbox/labels/:id` is dual-purpose, distinguished only by whether the request body includes a `threadId`. Without one, it behaves like an ordinary field update (name/color/systemType/accountId, all optional via `PartialType`). With a `threadId`, it ignores the other fields entirely and instead toggles the label's presence across every message in that thread (scoped to the caller's accessible accounts): it checks whether any message in the thread already carries the label via `inbox_message_label`, and if so removes it from all of them, otherwise adds it to all of them — a single idempotent "apply/remove this label to this thread" action rather than a granular per-message toggle. The response`s `toggled` field reflects the resulting state (`true` if the label was just applied, `false` if it was just removed), and `applied: false` is returned without any writes when the thread has no messages within the caller's accessible accounts.

Deleting a label is a soft delete on `inbox_label` only — the `inbox_message_label` join rows are left in place rather than being cleaned up, and the database-level `ON DELETE CASCADE` on that table's foreign key never fires because the label row itself is never physically deleted. This is safe because every downstream query that surfaces labels (the Threads submodule's thread list and thread detail queries in particular) explicitly filters `l.deleted_at IS NULL` when joining through `inbox_message_label`, so a soft-deleted label simply stops appearing anywhere in the UI without requiring a cleanup job.

HTTP Endpoints

4 endpoints

Paginated list of labels across the caller's accessible accounts, ordered by system_type then most recent.

Query
page, pageSize, search, accountId?

Create a new label for an account. Rejects with 409 if a label with the same name already exists on that account.

Body

FieldTypeRequiredNotes
accountIdintyes
namestring (max 120)yesMust be unique within the account
systemType"inbox" | "sent" | "archived" | "trash" | "spam"no
colorstring (max 32)no

Update a label's fields, OR — when threadId is provided — toggle the label's presence across an entire thread's messages (idempotent apply/remove).

Params
id (int)

Body

FieldTypeRequiredNotes
namestring (max 120)no
systemType"inbox" | "sent" | "archived" | "trash" | "spam"no
colorstring (max 32)no
accountIdintno
threadIdintnoWhen present, all other fields are ignored and the call instead toggles this label on every message of the given thread

Soft-delete a label. Existing inbox_message_label associations are left in place but are excluded from all label queries once the label is deleted.

Params
id (int)