Objects / Plan
Plan
Normalized plan definition capturing pricing, packaging, and entitlement metadata.
Generated from @oods/foundry 0.10.1
This object is marked beta.
Screens
Every screen below was generated from this object by OODS Foundry 0.10.1, in React and Vue, and shows the calls that made it and its content hash. Each runs as its generated app runs, in this site's brand, Aquex, in the theme you choose, with the sample records this object's own file carries. A value no record gives shows as a neutral one, such as an empty value or "Not recorded"; OODS Foundry invents none.
sha256:f4f2cc8d1be5…Open full size: Plan detail screen generated by OODS Foundry in Reactsha256:2d09ebfe461e…Open full size: Plan detail screen generated by OODS Foundry in Vuesha256:c0e65d1035b9…Open full size: Plan list screen generated by OODS Foundry in Reactsha256:e37fbc985d9a…Open full size: Plan list screen generated by OODS Foundry in Vuesha256:19177946e041…Open full size: Plan form screen generated by OODS Foundry in Reactsha256:3abc0cc85124…Open full size: Plan form screen generated by OODS Foundry in Vuesha256:cdcd891c97c1…Open full size: Plan timeline screen generated by OODS Foundry in Reactsha256:34ccacfa79c4…Open full size: Plan timeline screen generated by OODS Foundry in Vuesha256:50c03b1c0cd3…Open full size: Plan card screen generated by OODS Foundry in Reactsha256:0838fc45e1e2…Open full size: Plan card screen generated by OODS Foundry in Vuesha256:0a5bf65e2108…Open full size: Plan inline screen generated by OODS Foundry in Reactsha256:83c85edbcd89…Open full size: Plan inline screen generated by OODS Foundry in Vuesha256:cf422cd9d3b2…Open full size: Plan workflow screen generated by OODS Foundry in Reactsha256:d2cbf0fab0ea…Open full size: Plan workflow screen generated by OODS Foundry in VueWhat design_compose reported for every screen here:
OODS-V121Object 'Plan' has maturity 'beta' — composed output may change.
For this screen it also reported:
OODS-V122Object "Plan" has a single trait category group for context "detail". Consider using a single-section layout instead of tabs.
The calls that made the Plan detail apps, in React and Vue
design_compose {
"object": "Plan",
"context": "detail",
"preferences": {
"brand": "Aquex",
"theme": "light"
}
}
code_generate {
"schemaRef": "compose-c0aaeb96",
"framework": "react",
"profile": "build",
"options": {
"output": "application",
"brand": "Aquex",
"theme": "light",
"payloadMode": "file"
}
}
code_generate {
"schemaRef": "compose-c0aaeb96",
"framework": "vue",
"profile": "build",
"options": {
"output": "application",
"brand": "Aquex",
"theme": "light",
"payloadMode": "file"
}
}The React app's content hash: sha256:f4f2cc8d1be59cb335282752a07ca695c5182d16f760cd07c59d988f983701e6. Its src/ folder: App.tsx, GeneratedUI.tsx, app.css, main.tsx, oods-brand-aquex.css
The Vue app's content hash: sha256:2d09ebfe461e4d4532f5ed92901bcf13189ff24ac49197bee2fc946b38a29541. Its src/ folder: App.vue, GeneratedUI.vue, app.css, main.ts, oods-brand-aquex.css
The calls that made the Plan list apps, in React and Vue
design_compose {
"object": "Plan",
"context": "list",
"preferences": {
"brand": "Aquex",
"theme": "light"
}
}
code_generate {
"schemaRef": "compose-a97a41ea",
"framework": "react",
"profile": "build",
"options": {
"output": "application",
"brand": "Aquex",
"theme": "light",
"payloadMode": "file"
}
}
code_generate {
"schemaRef": "compose-a97a41ea",
"framework": "vue",
"profile": "build",
"options": {
"output": "application",
"brand": "Aquex",
"theme": "light",
"payloadMode": "file"
}
}The React app's content hash: sha256:c0e65d1035b993ee3dd33e9c57e4fc29f8fc9e3c4b32f34920e06960c38024fc. Its src/ folder: App.tsx, GeneratedUI.tsx, app.css, main.tsx, oods-brand-aquex.css
The Vue app's content hash: sha256:e37fbc985d9a594b78a2be09a841401871b2eb919fa845394654f95135d31afc. Its src/ folder: App.vue, GeneratedUI.vue, app.css, main.ts, oods-brand-aquex.css
For this screen it also reported:
OODS-V119No view_extensions found for context "form" in object "Plan". Available contexts: list, card, detail
The calls that made the Plan form apps, in React and Vue
design_compose {
"object": "Plan",
"context": "form",
"preferences": {
"brand": "Aquex",
"theme": "light"
}
}
code_generate {
"schemaRef": "compose-50871210",
"framework": "react",
"profile": "build",
"options": {
"output": "application",
"brand": "Aquex",
"theme": "light",
"payloadMode": "file"
}
}
code_generate {
"schemaRef": "compose-50871210",
"framework": "vue",
"profile": "build",
"options": {
"output": "application",
"brand": "Aquex",
"theme": "light",
"payloadMode": "file"
}
}The React app's content hash: sha256:19177946e041dc724bd3a0d812db1e12b16c0576de883ef1a431f7bef0cdc4be. Its src/ folder: App.tsx, GeneratedUI.tsx, app.css, main.tsx, oods-brand-aquex.css
The Vue app's content hash: sha256:3abc0cc8512462814f988b22e4b48f7bf88e848cb760e4356dd524ab3be70f58. Its src/ folder: App.vue, GeneratedUI.vue, app.css, main.ts, oods-brand-aquex.css
For this screen it also reported:
OODS-V119No view_extensions found for context "timeline" in object "Plan". Available contexts: list, card, detail
The calls that made the Plan timeline apps, in React and Vue
design_compose {
"object": "Plan",
"context": "timeline",
"preferences": {
"brand": "Aquex",
"theme": "light"
}
}
code_generate {
"schemaRef": "compose-dab79cb8",
"framework": "react",
"profile": "build",
"options": {
"output": "application",
"brand": "Aquex",
"theme": "light",
"payloadMode": "file"
}
}
code_generate {
"schemaRef": "compose-dab79cb8",
"framework": "vue",
"profile": "build",
"options": {
"output": "application",
"brand": "Aquex",
"theme": "light",
"payloadMode": "file"
}
}The React app's content hash: sha256:cdcd891c97c1ee5da073de238f67bab8ae078c18856e2e94375fa8cb34713680. Its src/ folder: App.tsx, GeneratedUI.tsx, app.css, main.tsx, oods-brand-aquex.css
The Vue app's content hash: sha256:34ccacfa79c4f52079878fca7a65ae231b81adf0b9cd853e5031150f81fa71b4. Its src/ folder: App.vue, GeneratedUI.vue, app.css, main.ts, oods-brand-aquex.css
The calls that made the Plan card apps, in React and Vue
design_compose {
"object": "Plan",
"context": "card",
"preferences": {
"brand": "Aquex",
"theme": "light"
}
}
code_generate {
"schemaRef": "compose-4dba6e5a",
"framework": "react",
"profile": "build",
"options": {
"output": "application",
"brand": "Aquex",
"theme": "light",
"payloadMode": "file"
}
}
code_generate {
"schemaRef": "compose-4dba6e5a",
"framework": "vue",
"profile": "build",
"options": {
"output": "application",
"brand": "Aquex",
"theme": "light",
"payloadMode": "file"
}
}The React app's content hash: sha256:50c03b1c0cd3b2ddf139070acde71e7e5daa3d4a8936cbf0897a950607015a9c. Its src/ folder: App.tsx, GeneratedUI.tsx, app.css, main.tsx, oods-brand-aquex.css
The Vue app's content hash: sha256:0838fc45e1e2dfbff88234c982beafb4d9a476b5f5bb68a220e4a9b133304c3e. Its src/ folder: App.vue, GeneratedUI.vue, app.css, main.ts, oods-brand-aquex.css
For this screen it also reported:
OODS-V119No view_extensions found for context "inline" in object "Plan". Available contexts: list, card, detail
The calls that made the Plan inline apps, in React and Vue
design_compose {
"object": "Plan",
"context": "inline",
"preferences": {
"brand": "Aquex",
"theme": "light"
}
}
code_generate {
"schemaRef": "compose-3158029f",
"framework": "react",
"profile": "build",
"options": {
"output": "application",
"brand": "Aquex",
"theme": "light",
"payloadMode": "file"
}
}
code_generate {
"schemaRef": "compose-3158029f",
"framework": "vue",
"profile": "build",
"options": {
"output": "application",
"brand": "Aquex",
"theme": "light",
"payloadMode": "file"
}
}The React app's content hash: sha256:0a5bf65e2108177341d760d5cd7f121118c6848da6290976a68879557dfadc9d. Its src/ folder: App.tsx, GeneratedUI.tsx, app.css, main.tsx, oods-brand-aquex.css
The Vue app's content hash: sha256:83c85edbcd89e418ad615d868be0e6006c9cca53d5a6b5b40ca892313d3e6401. Its src/ folder: App.vue, GeneratedUI.vue, app.css, main.ts, oods-brand-aquex.css
For this screen it also reported:
OODS-V121as above, 4 times in allOODS-V122Object "Plan" has a single trait category group for context "detail". Consider using a single-section layout instead of tabs.OODS-V119No view_extensions found for context "form" in object "Plan". Available contexts: list, card, detailOODS-V119No view_extensions found for context "timeline" in object "Plan". Available contexts: list, card, detail
The calls that made the Plan workflow apps, in React and Vue
design_compose {
"object": "Plan",
"context": "workflow",
"preferences": {
"brand": "Aquex",
"theme": "light"
}
}
code_generate {
"schemaRef": "compose-d8499e01",
"framework": "react",
"profile": "build",
"options": {
"output": "application",
"brand": "Aquex",
"theme": "light",
"payloadMode": "file"
}
}
code_generate {
"schemaRef": "compose-d8499e01",
"framework": "vue",
"profile": "build",
"options": {
"output": "application",
"brand": "Aquex",
"theme": "light",
"payloadMode": "file"
}
}The React app's content hash: sha256:cf422cd9d3b27044560947dc6f6b2f040c2659ee330183de21527d4b541037dc. Its src/ folder: App.tsx, actions.ts, app.css, application.ts, main.tsx, oods-brand-aquex.css, sample-data.ts, screens/, ssr.tsx, store.ts
The Vue app's content hash: sha256:d2cbf0fab0ea3081c99fb1e0fb8586d2abf78cbb83b15a6fad692d7ea287e1cf. Its src/ folder: App.vue, actions.ts, app.css, application.ts, main.ts, oods-brand-aquex.css, sample-data.ts, screens/, ssr.ts, store.ts
Fields
| Field | Type | Description |
|---|---|---|
plan_coderequired | string | Provider specific identifier for the plan or price. |
plan_namerequired | string | Human readable plan label rendered in list and detail contexts. |
billing_intervalrequired | string | Billing cadence name selected from supportedIntervals. |
interval_count | integer | Multiplier for interval (ex: 12 with monthly => yearly cadence). |
amount_minorrequired | integer | Contract value expressed in minor currency units. |
currencyrequired | string | ISO 4217 currency for the plan price. |
trial_period_days | integer | Length of introductory trial period in days. |
collection_method | string | How billing is collected (charge_automatically, send_invoice). |
billing_anchor_day | integer | Day of month used to anchor renewals when prorating. |
pricing_model | string | Price strategy (flat, per_unit, tiered, package). |
meter_namerequired | string | Friendly metered feature name shown in UI (ex: Analytics Seats). |
included_quantityrequired | integer | Quantity included in base plan before overages. |
consumed_quantityrequired | integer | Actual quantity consumed in the active period. |
unit_labelrequired | string | Label for display, defaults to the unit parameter. |
period_startrequired | date | Date the usage accumulation window began. |
period_endrequired | date | Date the usage accumulation window ends. |
rollover_strategy | string | Strategy for unused units (inherits rolloverStrategy parameter). |
overage_rate_minor | integer | Cost per additional unit expressed in minor currency units. |
projected_overage_minor | integer | Forecasted overage spend derived from consumption trends. |
samples | UsageSample[] | Rolling usage measurements for charts or anomaly detection. |
owner_idrequired | string | Identifier of the owning principal scoped by owner_type. |
owner_typerequired | string | Categorical owner type sourced from the ownerTypes parameter. |
ownership_role | string | Optional role name describing how the owner governs the entity. |
ownership_transferred_at | datetime | Timestamp recording when ownership was last transferred. |
plan_idrequired | string | Stable identifier for the plan within the billing domain. |
product_familyrequired | string | High level product family grouping for analytics and reporting. |
statusrequired | string (active, deprecated, private_beta, legacy) | Availability state of the plan (active, deprecated, private_beta). |
feature_matrix | FeatureDescriptor[] | Array of feature descriptors listing entitlement tiers. |
add_on_ids | string[] | Identifiers for add-ons commonly sold with this plan. |
upgrade_targets | string[] | Plans presented as upgrade destinations. |
downgrade_targets | string[] | Plans that can be downgraded to from this plan. |
notes | string | Internal commentary for packaging or finance teams. |
owner_name | string | Display name of the team that owns the plan. |
Traits
Each trait adds fields and behaviour. Every object with the trait gets the same.
Relationships
These arrows show declared relationships between object types. They don't join live records.
The object file
The Plan object definition in YAML: domains/saas-billing/objects/Plan.object.yaml
object:
name: Plan
version: 1.0.0
domain: saas.billing
description: Normalized plan definition capturing pricing, packaging, and entitlement metadata.
tags:
- billing
- plan
- packaging
traits:
- name: SaaSBillingBillable
alias: Pricing
- name: SaaSBillingMetered
alias: IncludedUsage
parameters:
unit: seats
rolloverStrategy: none
sampleWindowDays: 30
- name: structural/Ownerable
alias: PlanOwnership
schema:
plan_id:
type: string
required: true
description: Stable identifier for the plan within the billing domain.
product_family:
type: string
required: true
description: High level product family grouping for analytics and reporting.
status:
type: string
required: true
description: Availability state of the plan (active, deprecated, private_beta).
validation:
enum:
- active
- deprecated
- private_beta
- legacy
feature_matrix:
type: FeatureDescriptor[]
required: false
description: Array of feature descriptors listing entitlement tiers.
default: []
add_on_ids:
type: string[]
required: false
description: Identifiers for add-ons commonly sold with this plan.
default: []
upgrade_targets:
type: string[]
required: false
description: Plans presented as upgrade destinations.
default: []
downgrade_targets:
type: string[]
required: false
description: Plans that can be downgraded to from this plan.
default: []
notes:
type: string
required: false
description: Internal commentary for packaging or finance teams.
owner_name:
type: string
required: false
description: Display name of the team that owns the plan.
semantics:
plan_id:
semantic_type: billing.plan.id
token_mapping: tokenMap(billing.plan.id)
# The one-line summary under the plan's name in lists: the product family it belongs to.
product_family:
semantic_type: text.summary
token_mapping: tokenMap(billing.plan.product_family)
# structural/Ownerable's owner reference, named by owner_name.
owner_id:
semantic_type: ownership.owner.id
token_mapping: tokenMap(ownership.owner.id)
ui_hints:
component: OwnerReference
ownerTypeField: owner_type
displayLabelField: owner_name
status:
semantic_type: billing.plan.status
token_mapping: tokenMap(billing.plan.status)
feature_matrix:
semantic_type: billing.plan.feature_matrix
token_mapping: tokenMap(billing.plan.feature_matrix)
add_on_ids:
semantic_type: billing.plan.add_on_ids
token_mapping: tokenMap(billing.plan.add_on_ids)
upgrade_targets:
semantic_type: billing.plan.upgrade_targets
token_mapping: tokenMap(billing.plan.upgrade_targets)
downgrade_targets:
semantic_type: billing.plan.downgrade_targets
token_mapping: tokenMap(billing.plan.downgrade_targets)
notes:
semantic_type: billing.plan.notes
token_mapping: tokenMap(billing.plan.notes)
tokens:
billing.plan.id: "var(--cmp-text-strong)"
billing.plan.status: "var(--cmp-badge-text-info)"
billing.plan.product_family: "var(--cmp-text-subtle)"
metadata:
owners:
- product@oods.systems
- pricing@oods.systems
maturity: beta
references:
- R13.5 Canonical Model: Subscription and Invoice
# Authored type associations; no record join or referential-integrity claim.
relationships:
- target: Plan
via: upgrade_targets
cardinality: many-to-many
label: Upgrade destinations
- target: Plan
via: downgrade_targets
cardinality: many-to-many
label: Downgrade destinations
# Eight authored sample plans: the price book the sample subscriptions are on (their plan_code), plus a deprecated, a
# legacy and a private-beta plan. Prices are list prices in US dollars; the period is the price book the price belongs
# to, and each plan is owned by the team that prices it.
samples:
- plan_id: plan_starter_monthly
plan_code: starter-monthly
plan_name: Starter
product_family: Workspace plans
status: active
billing_interval: monthly
interval_count: 1
amount_minor: 1900
currency: USD
trial_period_days: 0
collection_method: charge_automatically
pricing_model: flat
meter_name: Seats
included_quantity: 3
overage_rate_minor: 500
period_start: '2026-01-01'
period_end: '2026-12-31'
upgrade_targets: [team-monthly]
downgrade_targets: []
add_on_ids: []
owner_id: team_pricing
owner_type: team
owner_name: Pricing and packaging
notes: Entry plan for single-location shops.
- plan_id: plan_team_monthly
plan_code: team-monthly
plan_name: Team
product_family: Workspace plans
status: active
billing_interval: monthly
interval_count: 1
amount_minor: 4900
currency: USD
trial_period_days: 14
collection_method: charge_automatically
pricing_model: flat
meter_name: Seats
included_quantity: 10
overage_rate_minor: 500
period_start: '2026-01-01'
period_end: '2026-12-31'
upgrade_targets: [business-monthly]
downgrade_targets: [starter-monthly]
add_on_ids: [analytics-addon-monthly]
owner_id: team_pricing
owner_type: team
owner_name: Pricing and packaging
notes: Most trials start here.
- plan_id: plan_business_monthly
plan_code: business-monthly
plan_name: Business
product_family: Workspace plans
status: active
billing_interval: monthly
interval_count: 1
amount_minor: 14900
currency: USD
trial_period_days: 14
collection_method: charge_automatically
pricing_model: flat
meter_name: Seats
included_quantity: 25
overage_rate_minor: 400
period_start: '2026-01-01'
period_end: '2026-12-31'
upgrade_targets: [enterprise-annual]
downgrade_targets: [team-monthly]
add_on_ids: [analytics-addon-monthly]
owner_id: team_pricing
owner_type: team
owner_name: Pricing and packaging
notes: Upgrades from Team are prorated and charged at once.
- plan_id: plan_team_annual
plan_code: team-annual
plan_name: Team (annual)
product_family: Workspace plans
status: deprecated
billing_interval: annual
interval_count: 1
amount_minor: 49000
currency: USD
trial_period_days: 14
collection_method: charge_automatically
pricing_model: flat
meter_name: Seats
included_quantity: 10
overage_rate_minor: 500
period_start: '2025-01-01'
period_end: '2025-12-31'
upgrade_targets: [business-monthly]
downgrade_targets: [team-monthly]
add_on_ids: []
owner_id: team_pricing
owner_type: team
owner_name: Pricing and packaging
notes: No longer sold; annual Team customers renew monthly from January 2026.
- plan_id: plan_enterprise_annual
plan_code: enterprise-annual
plan_name: Enterprise
product_family: Workspace plans
status: active
billing_interval: annual
interval_count: 1
amount_minor: 1200000
currency: USD
trial_period_days: 30
collection_method: send_invoice
pricing_model: flat
meter_name: Seats
included_quantity: 250
overage_rate_minor: 300
period_start: '2026-01-01'
period_end: '2026-12-31'
upgrade_targets: []
downgrade_targets: [business-monthly]
add_on_ids: [analytics-addon-monthly]
owner_id: team_enterprise_sales
owner_type: team
owner_name: Enterprise sales
notes: Invoiced yearly on net 30 terms; includes premium support.
- plan_id: plan_analytics_addon_monthly
plan_code: analytics-addon-monthly
plan_name: Analytics add-on
product_family: Add-ons
status: active
billing_interval: monthly
interval_count: 1
amount_minor: 3900
currency: USD
trial_period_days: 0
collection_method: charge_automatically
pricing_model: flat
meter_name: Dashboards
included_quantity: 20
overage_rate_minor: 200
period_start: '2026-01-01'
period_end: '2026-12-31'
upgrade_targets: []
downgrade_targets: []
add_on_ids: []
owner_id: team_analytics
owner_type: team
owner_name: Analytics product
notes: Sold with Team, Business and Enterprise.
- plan_id: plan_pro_monthly_2025
plan_code: pro-monthly
plan_name: Pro
product_family: Workspace plans
status: legacy
billing_interval: monthly
interval_count: 1
amount_minor: 9900
currency: USD
trial_period_days: 0
collection_method: charge_automatically
pricing_model: flat
meter_name: Seats
included_quantity: 15
overage_rate_minor: 500
period_start: '2025-01-01'
period_end: '2025-12-31'
upgrade_targets: [business-monthly]
downgrade_targets: [team-monthly]
add_on_ids: []
owner_id: team_pricing
owner_type: team
owner_name: Pricing and packaging
notes: Closed to new customers in October 2025; every Pro subscription moved to Business by April 2026.
- plan_id: plan_business_plus_monthly
plan_code: business-plus-monthly
plan_name: Business Plus
product_family: Workspace plans
status: private_beta
billing_interval: monthly
interval_count: 1
amount_minor: 24900
currency: USD
trial_period_days: 14
collection_method: charge_automatically
pricing_model: per_unit
meter_name: Seats
included_quantity: 50
overage_rate_minor: 350
period_start: '2026-09-01'
period_end: '2026-12-31'
upgrade_targets: [enterprise-annual]
downgrade_targets: [business-monthly]
add_on_ids: [analytics-addon-monthly]
owner_id: team_pricing
owner_type: team
owner_name: Pricing and packaging
notes: Invite-only beta for multi-location retailers.