Glossary¶
Beacon's shared vocabulary — its ubiquitous language. This is the one place we agree on what a word means, so the same concept doesn't end up named three ways across passes. Define each term once here, keep the definition to a sentence or two, and link to the page that owns the concept; the depth lives there, not here.
If you're new to Beacon, read it as a story rather than an A–Z list. An Organization (a customer) buys a Plan, which gives it a Subscription with some number of Seats. When the org changes plan mid-cycle it's charged a prorated difference. When a payment fails, the subscription goes past due and dunning tries to recover it before it's canceled. Separately, the org sends messages to its customers; each send produces a write-once delivery event recording whether it arrived.
flowchart LR
org[Organization] -->|subscribes to| plan[Plan]
plan -->|grants| sub[Subscription]
sub -->|measured in| seat[Seat]
sub -->|failed payment| pastdue[Past due]
pastdue -->|recover or cancel| dunning[Dunning]
org -->|sends| msg[Message]
msg -->|records| de[Delivery event]
The terms below run business → technical: the first line is the plain-language meaning anyone can use; anything deeper is for engineers and links to the canonical page. Two distinctions show up again and again, so keep them straight:
- Accounts vs. Billing. Who exists and how many seats they have is accounts truth (accounts-service); what they pay for and are entitled to is billing truth (billing-service). Each domain owns its own facts and reads the other's over an API — neither caches the other as long-term truth.
- Beacon's customer vs. their customers. An Organization is Beacon's customer. The people that org sends messages to are its customers — Beacon never models them as accounts. "Customer-messaging SaaS" is exactly this two-level relationship.
For a hover tooltip on a term anywhere in the docs, also add a one-line
*[term]: short def to includes/abbreviations.md (auto-appended to every page).
Campaign message¶
A message sent to many recipients as a batch — a newsletter or announcement — as opposed to a one-off transactional message triggered by a single event. Both flow through the same send pipeline in messaging-service and both produce delivery events; the distinction is why the send happened, not how. See: messaging-service.
Channel¶
How a message physically leaves Beacon — the transport. Email is the live
channel today; SMS and push are part of the messaging domain's remit but, in
practice, only legacy sms delivery events exist and no new ones
are written. Recorded as the channel field on each delivery event. See:
Delivery event.
SMS is legacy-only
channel: "sms" rows survive from the retired SMS feature; treat email as the
only channel current code produces. Details on
Delivery event.
Delivery event¶
A write-once record of one message send attempt and its outcome —
delivered, failed, or bounced — owned by
messaging-service and stored in MongoDB
(messaging.delivery_events). High-volume and append-only: there's one document per
attempt and it's never updated. Because the collection is schemaless, older documents
lack fields that were added later (provider_id, region, attempts), so every
consumer must code defensively. See: Delivery event.
Dunning¶
The automated retry-and-notify process that runs after a payment fails, while a
subscription sits in past due, trying to recover the
charge before the subscription is canceled. It's the grace period between "your card
was declined" and "your account is off." Driven by
billing-service. See:
Subscription (the past_due state).
Event¶
An asynchronous message published to RabbitMQ that one service emits and another
reacts to — Beacon's way of decoupling domains. The canonical example:
billing-service emits subscription.upgraded, and
messaging-service consumes it to send a confirmation,
then emits message.delivered / message.failed of its own. Events carry the
what-happened, not commands; a consumer chooses how (or whether) to react. Billing's
HTTP surface is specified in OpenAPI; the event surface is specified in AsyncAPI. See:
messaging-service,
billing-service.
Invoice¶
A bill generated for a subscription — what the org owes for a billing period, including any prorated adjustments from a mid-cycle plan change. Invoices are owned by billing-service and are the one relationship in the Subscription model backed by a real database foreign key (one subscription → many invoices). A failed invoice payment is what pushes a subscription to past due and into dunning. See: Subscription.
Message¶
Something an organization sends to its own customers through Beacon — the product's whole reason to exist. A message is either transactional (triggered by one event) or a campaign (sent to many at once), goes out over a channel, and leaves behind a delivery event recording what happened. Templates and scheduling for messages live in messaging-service (PostgreSQL); the send itself goes through an external provider. The messaging flow starts at "send" and ends at "delivered/failed." See: messaging-service.
Organization¶
A customer account — the top-level tenant that users belong to and
that holds a subscription. It's the identity boundary every other
domain keys off: a subscription, a seat, and a delivery event all carry an org_id.
Owned by accounts-service (Java/Spring on MySQL,
accounts.organizations), which is the sole writer — billing and messaging read
org data over the API and must not cache it as long-term truth. An org's status
(active / suspended) is a DB-enforced enum; a suspended org can still sign in but
can't send. See: Organization.
Past due¶
The state a subscription enters when its latest payment fails
(status = past_due). It's not yet canceled: it kicks off dunning, and
from there it either reverts to active if payment recovers or is canceled if dunning
gives up. The legal states and transitions are enforced in application code
(Billing::Subscription::StateMachine), not by the database. See:
Subscription.
Plan¶
The package an organization pays for — its price, billing
interval, seat limit, and feature set. A subscription
references exactly one plan via plan_id, and a plan's seat limit is what flows over
to the org's seat_limit when the plan changes. Owned by
billing-service. See: Plan.
Proration¶
Charging the prorated difference when a plan changes mid-cycle, so the
org pays only for what it actually used at each price — the credit-and-recharge that
makes a plan upgrade fair within a billing period. The
amount is computed in billing-service
(Billing::Proration), not by the database or the payment provider; the contract
exposes the result but not the formula. See: Plan upgrade.
Customers sometimes expect upgrades to be free until renewal
The help center has said an upgrade is free until the next cycle, but the code charges the prorated difference immediately. Code wins. Tracked on Plan upgrade.
Seat¶
One paid-for user slot on a subscription. A subscription buys some number of seats; changing that count is billed prorated. Keep two counts apart:
- Seats — how many the org has paid for (
seats, a plain column). - Seats in use — how many are actually assigned to users
(
seats_in_use, view-derived fromactive_subscriptions_v, not a stored column).
The rule that seats in use can't exceed seats is enforced in application code, not the database. "Seats in use" is what drives the near-the-limit warnings admins see. See: Subscription.
Subscription¶
What an organization is currently paying for: a plan, a
billing cycle, and a lifecycle status. It's the authority on what a customer is
entitled to — owned by billing-service
(billing.subscriptions, partly view-backed) and read by other services as the source
of truth for entitlement. Its status moves through
trialing → active → past_due ↔ active → canceled, with transitions enforced in app
code rather than the database. Each subscription links to one org (org_id,
cross-store, no foreign key), one plan (plan_id, app-only), and many
invoices (a real DB foreign key). See: Subscription.
Suspended¶
An organization status (the other being active) set by an admin
for non-payment or abuse. A suspended org can still sign in but can't send
messages: messaging-service checks org
status before each send and rejects when it's suspended. It's reversible — unsuspend
flips the status back to active and deletes nothing. Distinct from a
canceled subscription, which is a billing state.
See: Suspend an organization.
Tenant¶
The isolation boundary that keeps one customer's data separate from another's — in
Beacon, the Organization. When you see org_id threaded through a
subscription, a seat, or a delivery event, that's the tenant key tying a row back to
the customer it belongs to. accounts-service is the
tenant/identity layer every other domain reads from. See:
Organization.
Transactional message¶
A message triggered by a single event for a single recipient — a receipt,
a confirmation, a password reset — as opposed to a bulk campaign.
The plan-upgrade confirmation is the canonical example: billing emits
subscription.upgraded, and messaging-service renders
and sends the transactional confirmation. See:
messaging-service.
User¶
A person inside an organization — part of the accounts/identity
layer, owned by accounts-service (one org → many users,
a real DB foreign key). Assigning a user consumes a seat; a user is not a
customer the org sends messages to. The dedicated User page isn't written
yet. See: accounts-service.
Confidence: 85/100 · Last reviewed: 2026-06-14 · Status: active