Package-based Usage Quotas (Plan Limits)
Overview
Plan Limits is the mechanism that caps how many resources each organization may create —
audiences, concurrently active workflows, templates, custom attributes, and the right to use
audience auto-refresh. The defaults are platform-wide values that can be overridden per
organization through the organization.plan_limits JSONB column.
This module has no routes of its own: RegisterRoutes is intentionally a no-op. It is a
provider-only module that other modules call at creation time to check whether a quota has
already been reached.
Business Flow
- A user attempts to create a new audience, workflow, or template.
- That module's service asks
planlimitsfor the organization's effective limits:- Read
organization.plan_limits(JSONB); if the key is present, use that value. - Otherwise fall back to
DefaultPlanLimits. maxChannelsis a special case: it always comes from the legacyorganization.max_channelcolumn (a varchar) and has no entry in the default constant.- A value of
-1means unlimited.
- Read
- The current count, taken from that module's own table, is compared against the limit.
- If the quota is exceeded, an error is returned so cms-web can tell the user they have hit their package ceiling.
- Platform admins adjust limits through
PUT /api/org-module-setting/:orgId/limits.
Defaults in DefaultPlanLimits
| Key | Default | Meaning |
|---|---|---|
maxSegments | 5 | Maximum number of audiences/segments |
maxActiveWorkflows | 3 | Workflows that may be active at once |
maxTemplates | 20 | Number of message templates |
maxAttributes | 30 | Number of custom attributes |
autoRefresh | false | Whether audience auto-refresh is permitted |
maxChannels | From organization.max_channel | Number of LINE OAs that may be created |
Key Files & Functions
The code lives in internal/modules/planlimits/, consisting of service.go, constant.go,
and controller.go.
controller.go—RegisterRoutesis a deliberate no-op, since this is a provider-only module, matching the original NestJS implementation which had no controller.constant.go— definesDefaultPlanLimits.service.go—GetEffectiveLimitsplus per-resource quota-check helpers.
According to the doc comments in the code, the modules that consume planlimits are lineoa,
audience, audiencefilter, workflow, templatemessage, attributemaster,
and orgmodulesetting.
Connections to Other Services
- Permissions — no routes, therefore no guards; authorization is enforced by the calling module.
- Tables —
organization, specifically theplan_limits(JSONB) andmax_channel(varchar) columns - CLS — reads
organizationIdfor scoping - Configured by — the per-organization module and quota settings console
- Consumed by — audience management, workflows, message templates, attribute master, and LINE OA management