ENGINEERING SPECS
Tenant Plan Subscription
1. Goal
Tenant Plan Subscription defines the commercial and resource boundary of a tenant.
It answers:
- Which plan is this tenant using?
- Which capabilities are enabled?
- How many nodes, members, runtime bindings, domains, and client access subscriptions can the tenant create?
- How much included traffic does the tenant have in the current period?
- Which quota policies are derived from the plan?
- Which account and security features are available?
This document is the source of truth for tenant-level subscription plans.
Current Implementation Status
The first Control Plane slice is implemented:
plans,plan_versions,plan_entitlement_definitions,plan_entitlements,plan_quota_templates, andtenant_subscriptionsare modeled in Ent.quota_policiescan record plan-derived source metadata throughsource_type,source_subscription_id, andsource_template_id.- Default Free and Pro plan seeds are created at Control Plane startup.
- Platform operator APIs are exposed under
/api/v1/platform/.... - Platform operator tenant listing is exposed as
GET /api/v1/platform/tenants; tenant Console keeps usingGET /api/v1/tenantsfor membership-scoped tenant switching. - Effective entitlement read path is available for platform operators.
- Plan quota templates can be synchronized into plan-derived quota policies.
- Platform operator access uses
users.platform_role. apps/platformnow has the first operator UI slice for plan catalog viewing, tenant plan assignment, effective entitlement review, and plan quota sync.- Shared plan contracts live in
orbitmesh/v1/plan.proto; plan resources are no longer modeled as Platform Console-specific messages. - Authenticated users can list active public plans through
GET /api/v1/plans. - Active tenant members can read the current tenant plan and effective
entitlements through
GET /api/v1/tenants/{tenant_id}/plan. - Tenant Console
Settings / Plan & Billingdisplays the current plan, subscription period, plan-derived usage limits, effective entitlements, and available public plans. - Free and Pro seeds do not create plan-derived
client_accessquotas; BYOH traffic is not billed as platform-borne traffic. - Existing seeded
client_accessplan quotas are removed bydocs/schemas/20260710-remove-byoh-plan-traffic-quota.mysql.sql.
Still planned:
- automatic default tenant plan subscription creation for new tenants.
- resource creation enforcement from effective entitlements.
- dedicated managed traffic metering, capacity assignment, and plan quota templates.
- Platform Console plan catalog write APIs for plan/version/entitlement/quota template management.
- account-level billing, payment provider integration, invoices, addons, and enterprise contract overrides.
2. Terminology
Plan
Human-facing package, such as Free, Personal, Pro, Team, Enterprise.
Plan Version
Immutable entitlement and quota definition for a plan.
Tenant Plan Subscription
Tenant's subscription to a plan version.
Entitlement
A feature flag, numeric limit, enum list, or configuration value granted by a plan version.
Plan Quota Template
A quota rule template attached to a plan version.
Effective Entitlement
Runtime view of plan entitlements, quota templates, addons, overrides, and enterprise contract settings.
Client Access Subscription
A user-owned client subscription link and protocol credential.
Use explicit names. Do not call both tenant plan subscriptions and client access subscriptions subscriptions.
2.1 API Ownership
PlanService
Tenant and client-facing read APIs.
PlatformService
Platform operator plan assignment and quota materialization APIs.
Current read endpoints:
GET /api/v1/plans
GET /api/v1/tenants/{tenant_id}/plan
The tenant plan endpoint returns 200 with an empty subscription when the
tenant has not been assigned a plan. An unassigned plan is a valid business
state, not a transport-level 404.
3. Account Hierarchy
The plan model must align with the future account system:
Account
-> Tenant
-> Tenant Membership
-> User
Recommended meanings:
Account
Billing owner, legal owner, or commercial account.
Tenant
Product workspace and Control Plane resource boundary.
User
Login identity.
Tenant Membership
User role and membership status inside a tenant.
MVP can keep one account per tenant implicitly, but the schema should not prevent multiple tenants under one account later.
4. Roles
Recommended tenant roles:
owner
admin
operator
developer
billing
viewer
member
Role expectations:
owner: full tenant ownership, billing, destructive actions.admin: tenant administration except ownership transfer.operator: node, runtime, endpoint, and deployment operations.developer: client subscriptions, traffic policies, and development workflows.billing: plan, usage, invoice, and payment visibility.viewer: read-only access.member: minimal user access.
Plan entitlements can enable or limit RBAC features:
rbac.enabled
rbac.custom_roles.enabled
service_accounts.enabled
service_accounts.max
sso.enabled
oidc.enabled
ldap.enabled
audit.enabled
5. Plan Metadata
Logical model:
plans
- id
- code
- name
- tier
- status
- visibility
- description
- created_at
- updated_at
Recommended values:
tier:
- free
- personal
- pro
- team
- enterprise
status:
- draft
- active
- deprecated
- archived
visibility:
- public
- invite_only
- internal
- enterprise_only
Plan metadata is mutable. Runtime behavior should depend on plan version, not directly on mutable plan metadata.
6. Plan Version
Logical model:
plan_versions
- id
- plan_id
- version
- status
- billing_interval
- price_amount
- currency
- effective_from
- effective_to
- created_at
- updated_at
Recommended values:
status:
- draft
- active
- deprecated
- archived
billing_interval:
- free
- monthly
- yearly
- custom
Plan versions are immutable after activation. Changes create a new version.
7. Tenant Plan Subscription
Logical model:
tenant_plan_subscriptions
- id
- tenant_id
- plan_id
- plan_version_id
- status
- current_period_start
- current_period_end
- trial_ends_at
- started_at
- canceled_at
- expires_at
- suspended_at
- renewal_policy
- created_at
- updated_at
Recommended values:
status:
- trialing
- active
- past_due
- canceled
- expired
- suspended
renewal_policy:
- auto
- manual
- none
Rules:
- A tenant should have at most one effective plan subscription at a time.
trialingandactiveare usable states.past_duemay allow read-only or grace-period behavior.canceledmay remain usable untilcurrent_period_end.expiredandsuspendedblock new resource creation.
8. Entitlement Model
Use a key/value entitlement model instead of hardcoding every column on plans.
Logical model:
plan_entitlements
- id
- plan_version_id
- key
- value_type
- value_json
- description
- created_at
- updated_at
Recommended value types:
boolean
integer
decimal
string
string_list
json
The effective entitlement engine must validate the value type against the entitlement key definition.
9. Entitlement Definitions And Maturity
Entitlement keys must be declared before they are used by plan versions.
Logical model:
plan_entitlement_definitions
- id
- key
- category
- value_type
- maturity
- default_value_json
- description
- created_at
- updated_at
Recommended maturity values:
implemented
Current code enforces, compiles, or displays this entitlement.
planned
Product direction is accepted, but current code must not treat it as available.
reserved
Naming reservation for future product direction. It must not affect API decisions, quota, compiler output, or Console capability display.
Execution rules:
implementedentitlements can participate in effective entitlement calculation, API validation, quota synchronization, compiler decisions, and Console display.plannedentitlements can appear in internal documentation and seeds, but Console must not present them as enabled tenant capabilities.reservedentitlements are namespace placeholders only.- unknown entitlement keys should be rejected when creating or activating a plan version.
- unknown entitlement keys in already persisted development data should be fixed with SQL migration instead of hidden by fallback logic.
Maturity is attached to the definition, not to a tenant's selected plan. A plan version may include planned or reserved keys for catalog completeness, but runtime behavior must only consume implemented keys.
10. Entitlement Key Catalog
Entitlement keys should be namespaced.
10.1 Account And Tenant
account.max_tenants
tenant.max_members
tenant.max_admins
tenant.audit.enabled
tenant.audit.retention_days
tenant.rbac.enabled
tenant.rbac.custom_roles.enabled
tenant.service_accounts.enabled
tenant.service_accounts.max
tenant.api_tokens.enabled
10.2 Node Access
node.max_total
node.max_online
node.max_byoh
node.max_recommended_vps
node.max_managed
node.allowed_sources
node.allowed_os
node.allowed_arch
node.max_runtime_bindings_per_node
node.owner_user_required
Recommended source values:
byoh
recommended_vps
managed
Node ownership:
nodes.owner_user_id nullable
The plan limits the tenant resource pool. Per-user node limits are not part of the MVP; they can be added later as tenant resource policies.
10.3 Capability
capability.traffic.enabled
capability.mesh.enabled
capability.gateway.enabled
capability.tunnel.enabled
capability.allowed_runtime_kinds
capability.runtime_marketplace.enabled
capability.custom_runtime_plugin.enabled
Runtime values can include:
sing-box
xray
easytier
tailscale
netbird
traefik
frp
nginx
envoy
wireguard
10.4 Traffic
traffic.max_client_access_subscriptions
traffic.max_entry_endpoints
traffic.max_exit_nodes
traffic.max_policies
traffic.max_rules
traffic.allowed_protocols
traffic.allowed_client_formats
traffic.managed_traffic.enabled
traffic.managed_traffic.included_bytes
traffic.managed_traffic.period
traffic.managed_traffic.overage.enabled
traffic.managed_traffic.overage.price_per_gb
Recommended protocol values:
trojan
shadowsocks
hysteria
vless
vmess
Recommended client format values:
clash
surge
shadowrocket
sing-box
plain
BYOH traffic runs on tenant-owned infrastructure and does not count toward a
platform plan traffic quota. client_access remains the attribution point for
tenant-defined quota policies, but must not be used as a platform billing meter
for all tenant traffic.
Future managed traffic entitlement should use a dedicated meter:
metering_point = managed_traffic
direction = total
scope_type = tenant
period = month
Do not create a managed traffic plan quota until the metering catalog, collector, and capacity assignment can distinguish platform-borne traffic from BYOH traffic.
10.5 Domain, TLS, Gateway, And Tunnel
domain.platform_domains.enabled
domain.custom_domains.enabled
domain.custom_domains.max
tls.managed.enabled
tls.tenant_acme.enabled
tls.wildcard_certificate.enabled
tls.certificates.max
gateway.ingress_endpoints.max
tunnel.public_endpoints.max
10.6 Observability And Operations
observability.metrics.retention_days
observability.logs.retention_days
observability.alerts.enabled
observability.notification_channels
health.check_interval_seconds
diagnostics.advanced.enabled
remote_shell.enabled
config_history.retention_days
desired_state_history.retention_days
10.7 Security And Enterprise
security.ip_allowlist.enabled
security.sso.enabled
security.oidc.enabled
security.scim.enabled
security.private_deployment.enabled
enterprise.dedicated_control_plane.enabled
enterprise.private_region.enabled
enterprise.ha.enabled
enterprise.sla
support.level
11. Plan Quota Templates
Plan quota templates represent executable quota granted by a plan.
Logical model:
plan_quota_templates
- id
- plan_version_id
- name
- scope_type
- metering_point
- period
- total_bytes_limit
- upload_bytes_limit
- download_bytes_limit
- action
- priority
- status
- created_at
- updated_at
Future managed traffic values:
scope_type = tenant
metering_point = managed_traffic
period = month
total_bytes_limit = managed_traffic.included_bytes
action = disable
Do not use plan quota templates for raw runtime metrics. Quota templates are product enforcement rules.
12. Effective Entitlement
Effective entitlement is the merged runtime view used by API, Console, compiler, and Edge Runtime workflows.
MVP source order:
plan entitlements
plan quota templates
manual quota policies
Future source order:
plan entitlements
plan quota templates
addons
manual overrides
enterprise contract overrides
temporary credits
Conflict rules:
- boolean features are enabled only when effective value is true.
- numeric limits use the strictest limit unless an override explicitly raises it.
- string lists are intersected by default for safety.
- quota enforcement uses the strictest active blocking quota.
- disabled manual quota policies are not effective.
13. Relationship With Existing Quota Policy
Current quota policy remains the enforcement primitive:
quota_policies
quota_enforcements
usage_adjustments
MVP plan integration should create or synchronize plan-derived quota policies:
tenant_plan_subscription
-> active plan_version
-> plan_quota_templates
-> plan-derived quota_policies
Plan-derived quota policy requirements:
source_type = planor equivalent metadata.- stable source reference to
tenant_plan_subscription_idandplan_quota_template_id. - not directly deleted as a manual policy.
- refreshed when tenant changes plan or period.
- disabled when tenant plan is expired or suspended.
Manual quota policies remain available for tenant-specific overrides and tests.
14. Resource Limit Checks
APIs that create tenant resources must check effective entitlements.
Required MVP checks:
create enrollment token:
node.max_total
node.allowed_sources
capability.*.enabled
register node:
node.max_total
node.allowed_sources
create runtime binding:
node.max_runtime_bindings_per_node
capability.allowed_runtime_kinds
capability.*.enabled
create client access subscription:
traffic.max_client_access_subscriptions
traffic.allowed_client_formats
create traffic policy:
traffic.max_policies
traffic.max_rules
create custom domain:
domain.custom_domains.enabled
domain.custom_domains.max
Expired or suspended plan subscriptions must block new resource creation.
Existing resources should normally remain readable. Destructive shutdown should be an explicit policy decision, not the default MVP behavior.
15. Default Plan Seeds
MVP seed plans should be simple and conservative.
Free
tenant.max_members = 1
node.max_total = 1
node.allowed_sources = [byoh]
traffic.max_client_access_subscriptions = 1
traffic.managed_traffic.enabled = false
capability.traffic.enabled = true
capability.mesh.enabled = false
capability.gateway.enabled = false
capability.tunnel.enabled = false
observability.metrics.retention_days = 7
Pro
tenant.max_members = 5
node.max_total = 5
node.allowed_sources = [byoh, recommended_vps]
traffic.max_client_access_subscriptions = 20
traffic.managed_traffic.enabled = false
capability.traffic.enabled = true
capability.mesh.enabled = true
capability.gateway.enabled = false
capability.tunnel.enabled = false
observability.metrics.retention_days = 30
Team
tenant.max_members = 20
node.max_total = 20
node.allowed_sources = [byoh, recommended_vps, managed]
traffic.max_client_access_subscriptions = 100
traffic.managed_traffic.enabled = true
traffic.managed_traffic.included_bytes = product-defined
capability.traffic.enabled = true
capability.mesh.enabled = true
capability.gateway.enabled = true
capability.tunnel.enabled = true
observability.metrics.retention_days = 90
Enterprise
tenant.max_members = custom
node.max_total = custom
traffic.managed_traffic.included_bytes = contract-defined
all core capabilities enabled
sso.enabled = true
audit.enabled = true
enterprise.private_deployment.enabled = true
Numbers are seed defaults, not pricing commitments.
16. Console Information Architecture
Tenant admin Console should expose:
Settings
Plan & Billing
MVP page sections:
- Current Plan.
- Plan Status.
- Current Period.
- Enabled Capabilities.
- Included Traffic.
- Current Client Access Usage.
- Node Limit.
- Member Limit.
- Client Access Subscription Limit.
- Runtime Binding Limit.
- Plan-Derived Quota State.
- Manual Quota Overrides.
Billing-role users can view this page. Only owner/admin can change plan in MVP internal tooling.
17. API Shape
Recommended MVP APIs:
GET /api/v1/platform/plans
GET /api/v1/platform/tenants/{tenant_id}/plan-subscription
PUT /api/v1/platform/tenants/{tenant_id}/plan-subscription
GET /api/v1/platform/tenants/{tenant_id}/effective-entitlements
POST /api/v1/platform/tenants/{tenant_id}/plan-subscription/sync-quota
Admin-only APIs can be added later:
POST /api/v1/platform/plans
POST /api/v1/platform/plan-versions
POST /api/v1/platform/plan-entitlements
POST /api/v1/platform/plan-quota-templates
MVP can seed plans instead of exposing plan catalog mutation in Console.
18. State Machine
Tenant Plan Subscription state:
trialing -> active
trialing -> expired
active -> past_due
active -> canceled
active -> expired
active -> suspended
past_due -> active
past_due -> suspended
canceled -> expired
suspended -> active
Behavior:
trialing: usable.active: usable.past_due: usable during grace period; block upgrades and optional new resource creation.canceled: usable until period end.expired: block new resource creation and client access if configured.suspended: block new resource creation and optionally block client access.
19. Development Phases
Phase 1: Documentation And Schema
- Add plan schema. Implemented.
- Add entitlement schema. Implemented.
- Add plan quota template schema. Implemented.
- Add tenant plan subscription schema. Implemented.
- Seed default plans. Implemented for Free and Pro.
Phase 2: Effective Entitlement Read Path
- Load tenant active plan. Implemented.
- Resolve entitlements. Implemented.
- Resolve quota templates. Implemented.
- Expose effective entitlements API. Implemented under Platform API.
- Expose tenant-facing plan catalog and current tenant plan API. Implemented.
- Show current tenant Plan & Billing state in Tenant Console. Implemented.
- Keep plan catalog, plan version, plan term, and tenant assignment workflows in
Platform Console under
apps/platform.
Phase 3: Resource Limit Enforcement
- Check node enrollment.
- Check runtime binding creation.
- Check client access subscription creation.
- Check traffic policy creation.
Phase 4: Plan-Derived Quota
- Sync plan quota templates into quota policies. Implemented.
- Mark plan-derived policies. Implemented with plan source metadata.
- Show plan-derived quota separately from manual quota.
- Verify quota enforcement and restoration.
Phase 5: Account System Expansion
- Account table.
- Tenant-to-account relationship.
- Billing role.
- Service accounts.
- RBAC expansion.
20. Acceptance Checklist
- A new tenant receives a default tenant plan subscription.
- Plan catalog returns active plans and versions.
- Effective entitlements return typed values.
- Console shows current plan and resource limits.
- Node enrollment is blocked after
node.max_totalis exceeded. - Client Access Subscription creation is blocked after
traffic.max_client_access_subscriptionsis exceeded. - Capability creation is blocked when the capability entitlement is false.
- Plan quota template creates or resolves tenant monthly client access quota.
- Plan-derived quota enforcement blocks runtime credentials when exceeded.
- Manual quota policies can coexist with plan-derived quota.
- Expired or suspended tenant plan blocks new resource creation.