Skip to documentation
OrbitMeshDocs
Browse documentation
Docs/Engineering Specs

ENGINEERING SPECS

Tenant Plan Subscription

Tenant Plan Subscription defines the commercial and resource boundary of a tenant.
View source

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, and tenant_subscriptions are modeled in Ent.
  • quota_policies can record plan-derived source metadata through source_type, source_subscription_id, and source_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 using GET /api/v1/tenants for 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/platform now 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 & Billing displays 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_access quotas; BYOH traffic is not billed as platform-borne traffic.
  • Existing seeded client_access plan quotas are removed by docs/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.
  • trialing and active are usable states.
  • past_due may allow read-only or grace-period behavior.
  • canceled may remain usable until current_period_end.
  • expired and suspended block 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:

  • implemented entitlements can participate in effective entitlement calculation, API validation, quota synchronization, compiler decisions, and Console display.
  • planned entitlements can appear in internal documentation and seeds, but Console must not present them as enabled tenant capabilities.
  • reserved entitlements 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 = plan or equivalent metadata.
  • stable source reference to tenant_plan_subscription_id and plan_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_total is exceeded.
  • Client Access Subscription creation is blocked after traffic.max_client_access_subscriptions is 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.
OrbitMesh DocumentationContent follows the repository's main branch.