Skip to content

jedlsf/majik-subscription

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

4 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Majik Subscription

Majik Subscription is a fully-featured class representing a subscription-based offering in the Majik system, designed for recurring revenue modeling, cost tracking, and subscriber capacity planning. It provides utilities for computing MRR, ARR, revenue, profit, margins, Cost of Subscription (COS), and net income on a per-period basis. Chainable setter methods make it easy to construct and update subscriptions fluently.

Live Demo

Majik Runway Thumbnail

Click the image to try Majik Subscription inside Majik Runway's revenue stream.

Price Genie Thumbnail

Click the image to try Majik Subscription inside Price Genie.


Table of Contents


✨ Overview

MajikSubscription manages:

  • Metadata: name, category, type, description, SKU, photos, rate.
  • Settings: status, visibility, system restrictions.
  • Finance: revenue, income, profit, COS (gross & net).
  • Capacity Plan: Monthly subscriber or seat limits with adjustments.
  • Cost of Subscription: Infrastructure, licensing, support, and scaling costs.
  • Recurring Billing: Billing cycles, rate units, trials, and forecasting.
  • Serialization/Deserialization: Convert to/from JSON with full monetary safety via MajikMoney.


πŸ“¦ Installation

npm i @thezelijah/majik-subscription @thezelijah/majik-money@latest

Usage

Create a Subscription Instance

import { MajikSubscription } from "@thezelijah/majik-subscription";
import { MajikMoney } from "@thezelijah/majik-money";
import {
  SubscriptionType,
  RateUnit,
  BillingCycle,
} from "@thezelijah/majik-subscription/enums";

const subscription = MajikSubscription.initialize(
  "Pro SaaS Plan",
  SubscriptionType.RECURRING,
  {
    amount: MajikMoney.fromMajor(499, "PHP"),
    unit: RateUnit.PER_USER,
    billingCycle: BillingCycle.MONTHLY,
  },
  "Professional subscription tier",
  "SAAS-PRO-001"
);

Defaults: status β†’ ACTIVE visibility β†’ PRIVATE Empty COS Empty capacity plan Zeroed finance snapshot

Example Usage

import {
  SubscriptionType,
  RateUnit,
  BillingCycle,
  CapacityPeriodResizeMode,
} from "@thezelijah/majik-subscription/enums";

const proPlan = MajikSubscription.initialize(
  "Pro Plan",
  SubscriptionType.RECURRING,
  {
    amount: MajikMoney.fromMajor(29, "PHP"),
    unit: RateUnit.PER_USER,
    billingCycle: BillingCycle.MONTHLY,
  },
  "Advanced SaaS plan",
  "PRO-PLAN-001"
)
  .setDescriptionHTML("<p>Best plan for growing teams.</p>")
  .setDescriptionSEO("Pro SaaS subscription plan")
  .addCOS("Cloud Hosting", MajikMoney.fromMajor(300, "PHP"), 1, "per user")
  .addCOS("Customer Support", MajikMoney.fromMajor(100, "PHP"), 1, "per user")
  .generateCapacityPlan(12, 500) // 12 months, 500 subscribers
  .recomputeCapacityPeriod(
    "2025-01",
    "2025-12",
    CapacityPeriodResizeMode.DISTRIBUTE
  );

// Capacity insights
console.log("Total Capacity:", proPlan.totalCapacity);

// Monthly finance
const month = "2025-06";
console.log(`${month} Revenue:`, proPlan.getRevenue(month).value.toFormat());
console.log(`${month} COS:`, proPlan.getCOS(month).value.toFormat());
console.log(`${month} Profit:`, proPlan.getProfit(month).value.toFormat());
console.log(`${month} Margin:`, proPlan.getMargin(month).toFixed(2) + "%");

// Serialization
const json = proPlan.toJSON();
const restored = MajikSubscription.parseFromJSON(json);

console.log("Restored Subscription:", restored.metadata.description.text);

Metadata Helpers

Chainable methods to update Subscription metadata:

Method Description
setName(name: string) Updates subscription name and slug
setCategory(category: string) Updates subscription category
setType(type: SubscriptionType) Updates subscription type
setRate(rate: SubscriptionRate) Updates pricing & billing cycle
setDescriptionText(text: string) Updates plain text description
setDescriptionHTML(html: string) Updates HTML description
setDescriptionSEO(text: string) Updates SEO text
setPhotos(urls: string[]) Sets subscription photo URLs

COS Management

Manage the Cost of Subscription per item:

Method Description
addCOS(name, unitCost, quantity?, unit?) Add a new COS item
pushCOS(item: COSItem) Push externally created COS item
updateCOS(id, updates) Update COS item
removeCOS(id) Remove COS item
setCOS(items: COSItem[]) Replace COS list
clearCOS() Remove all COS items

Capacity Management

Capacity adjustments are useful for modeling churn, promotions, temporary expansions, or trials.

Manage monthly capacity and Subscription plan:

Method Description
addCapacity(month: YYYYMM, capacity, adjustment?) Add monthly capacity
updateCapacityUnits(month, units) Update capacity
updateCapacityAdjustment(month, adjustment?) Adjust capacity
removeCapacity(month) Remove month
clearCapacity() Remove all capacity
generateCapacityPlan(months, amount, growthRate?, startDate?) Auto-generate capacity plan
normalizeCapacityUnits(amount) Normalize capacity across months
recomputeCapacityPeriod(start, end, mode?) Resize / redistribute capacity

Capacity plan queries:

  • totalCapacity β†’ total units across all months
  • averageMonthlyCapacity β†’ average per month
  • maxCapacityMonth / minCapacityMonth β†’ highest/lowest monthly capacity

Finance Computation

All finance computations are normalized to monthly periods internally, regardless of billing cycle.

Method Description
getRevenue(month) Returns gross revenue for the specified month
getProfit(month) Returns profit for the specified month
getCOS(month) Returns total cost of Subscription for month
getMargin(month) Returns margin ratio

Calculates revenue, costs, and profits per month or across all months.

  • MRR, ARR
  • grossRevenue, grossCost, grossProfit β†’ totals across capacity plan
  • netRevenue(month, discounts?, returns?, allowances?) β†’ net per month
  • netProfit(month, operatingExpenses?, taxes?, discounts?, returns?, allowances?) β†’ net profit per month
  • getRevenue(month), getCOS(month), getProfit(month), getMargin(month) β†’ month-specific
  • averageMonthlyRevenue, averageMonthlyProfit β†’ averages

All computations use MajikMoney and respect currency.


Utilities

  • validateSelf(throwError?: boolean) β†’ validates all required fields
  • finalize() β†’ converts to JSON with auto-generated ID
  • toJSON() β†’ serialize with proper MajikMoney handling
  • parseFromJSON(json: string | object) β†’ reconstruct a MajikSubscription instance

Use Cases

MajikSubscription is designed for recurring-revenue businesses:

  1. SaaS & Software Products
  • MRR / ARR tracking
  • Unit economics
  • Subscriber forecasting
  1. Membership Platforms
  • Tiered plans
  • Seat-based pricing
  • Capacity enforcement
  1. Financial Forecasting
  • Revenue projections
  • Cost scaling
  • Margin analysis
  1. Data Integration
  • API serialization
  • Persistent finance models
  • Dashboard analytics

Best Practices

To maximize reliability, maintainability, and performance:

  1. Use Chainable Setters
  • Always modify subscriptions via setter methods (setRate, addCOS, setCapacity) to ensure timestamps and finance recalculations are handled automatically.
  1. Validate Before Finalization
  • Call validateSelf(true) before exporting or persisting the subscription to ensure all required fields are properly set.
  1. Maintain Currency Consistency
  • All monetary operations use MajikMoney. Avoid mixing currencies; setter methods validate against subscription Rate currency.
  1. Leverage Supply Plan Utilities
  • Use generateCapacityPlan, normalizeCapacityUnits, or recomputeCapacityPeriod to programmatically manage monthly supply rather than manually modifying arrays.
  1. Keep COS Accurate
  • Always ensure unitCost and subtotal calculations are correct. Prefer addCOS or pushCOS instead of direct array mutation.
  1. Minimize Finance Recomputations for Bulk Updates
  • When performing bulk updates to COS or supply, consider batching changes and calling recomputeFinance once at the end to avoid repeated expensive calculations.
  1. Use Snapshots for Reporting
  • Use getMonthlySnapshot(month) for consistent monthly financial reporting and dashboards.
  1. Error Handling
  • All setters throw on invalid input. Wrap critical updates in try/catch to handle edge cases gracefully.
  1. Serialization & Deserialization
  • Use toJSON / finalize for exporting, and parseFromJSON for reconstruction. Avoid manually modifying the serialized object to prevent integrity issues.

Conclusion

MajikSubscription provides a robust, financial-first approach to modeling subscriptions and recurring revenue, suitable for SaaS, memberships, and enterprise-grade forecasting systems.

Contributing

Contributions, bug reports, and suggestions are welcome! Feel free to fork and open a pull request.


License

ISC β€” free for personal and commercial use.


Author

Made with πŸ’™ by @thezelijah

About the Developer


Contact


About

Majik Subscription is a fully-featured class representing a subscription-based offering in the Majik system, designed for recurring revenue modeling, cost tracking, and subscriber capacity planning. It provides utilities for computing MRR, ARR, revenue, profit, margins, COS, and net income on a per-period basis.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors