Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Oc Cumuluscore Plugin Laravel Package

initbiz/oc-cumuluscore-plugin

CumulusCore is the foundation plugin for building SaaS applications on October CMS, providing shared models, services, and backend components for multi-tenant setups, plans, subscriptions, and related core functionality. It is designed to be extended by Cumulus-based plugins and custom projects.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the plugin and its billing sibling (if you need Stripe) via Composer:

composer require initbiz/oc-cumuluscore-plugin
php artisan october:migrate

Then do these three things, in order — they are the real "hello world" of Cumulus:

  1. Extend your User model with the Cumulus trait so it can own a plan and expose feature helpers:
    // plugins/acme/site/models/User.php
    use CumulusCore\Traits\CumulusUser;
    class User extends \October\Rain\Auth\Models\User
    {
        use CumulusUser;
    }
    
  2. Declare features in config/cumulus/features.php (or publish via php artisan vendor:publish --provider="CumulusCore\ServiceProvider"). Every gate you will ever use is keyed off this array — a feature is either boolean (max_users → true/false) or limited (max_projects → integer).
  3. Create plans in the backend (Cumulus → Plans) and attach one to a test user. Without a plan, every feature check returns false/0 by default and you'll chase phantom bugs.

First use case worth wiring: gate a customer dashboard page. Register the plugin's middleware in your theme's routes.php or page settings, then in Twig:

{% if hasFeature('dashboard') %}
    {% partial 'dashboard' %}
{% else %}
    {{ 'Upgrade required'|_ }}
{% endif %}

That single check — hasFeature() — is the workhorse you'll reach for 80% of the time.

Implementation Patterns

Twig gating (the everyday pattern). Cumulus registers three Twig functions you will use constantly:

  • hasFeature('key') → boolean, respects plan + feature flag.
  • limitFeature('key') → integer limit, ideal for {% for %} caps and progress bars.
  • canUseFeature('key') → considers current usage vs. limit (pair with a Usage recorded via the API below).
{% set max = limitFeature('max_projects') %}
{% for project in projects|slice(0, max) %}{# ... #}{% endfor %}
<p>{{ projects|length }} / {{ max }} projects used</p>

Route/page middleware. Register CumulusCore\Classes\Middleware\CumulusMiddleware in a route group when the whole area requires a paid plan. It redirects (not 403) unauthenticated/unsubscribed users to a configurable upgrade page — good for UX, but see Gotchas.

Programmatic checks in PHP. Use the trait methods inside controllers/components:

if ($this->user->hasFeature('api_access')) { ... }
$limit = $this->user->getFeatureLimit('max_projects');

Track consumption with $this->user->addUsage('max_projects', 1) (or your own Usage record keyed on the feature row) so canUseFeature() has real numbers to work with.

Hook into lifecycle events. Extend without forking by listening for the plugin's events — e.g. cumulus.user.attached.to.plan and cumulus.subscription.activated. Typical job: send a welcome email or seed starter data when a user first gets a plan.

Event::listen('cumulus.user.attached.to.plan', function ($user, $plan) {
    \Acme\Site\Models\Workspace::createFor($user);
});

Billing integration. If you're selling plans, add initbiz/oc-cumulusbilling-plugin (Stripe) and let it own plan changes — Cumulus Core is the feature-gate layer, Stripe is the money layer. Keep those responsibilities separate; don't mutate plan_id by hand in production.

Custom feature providers. When a limit isn't a plain integer (e.g. "storage in GB" or "seats per team"), extend the feature model or add a provider class in config/cumulus/features.php so getLimit() reads from your own source. This is the cleanest extension point Cumulus exposes.

Backend reporting. Cumulus ships backend lists for Plans, Features, and Users-with-plans. For a SaaS admin dashboard, extend those controllers (PlanController::extendListColumns) rather than building a parallel UI.

Gotchas and Tips

  • Order of migrations matters. Cumulus assumes users exists. If you install it into a fresh project before running October's base migrations, its foreign keys fail. Run october:migrate on October first, then install Cumulus.
  • No trait = no features. Every hasFeature() silently returns false on a User model missing CumulusUser. Symptom: "it works in tinker but not on the site" usually means a different User class (a custom auth model, or an extended one in a plugin) didn't get the trait.
  • Cache the config, not the state. Feature definitions and plan-to-feature mappings are cached. After editing features.php or a plan in the backend, run php artisan cache:clear — otherwise you'll debug stale limits for an hour.
  • Middleware redirects, not 403s. CumulusMiddleware needs cumulus_upgrade_page (or equivalent) configured. On an API route that means a client gets HTML or a redirect instead of JSON — write your own middleware for API surfaces.
  • Feature-flag semantics are per-plan, not per-user. If you need a per-user override (beta features, grandfathering), don't hack the plan model. Add a user-level feature_overrides column and wrap the trait methods, or you'll fight every upgrade path.
  • Plan deletion cascades. Removing a plan unsubscribes its users — there is no "soft retire" by default. Deactivate the plan in the backend instead of deleting it if real money is attached.
  • Missing plan = zero, not unlimited. New users with no plan hit every gate. If your onboarding creates users before assigning a plan, wire the cumulus.user.registered flow so they land on a default free plan immediately.
  • Numbers are strings from the DB. getFeatureLimit() can return "5" rather than 5 — cast before arithmetic, especially when computing remaining = limit - used.
  • Extend via events, not by editing the plugin. Composer updates wipe manual changes; use the cumulus.* events and the backend controller extend* hooks for anything custom. Fork only if you need new Twig functions — and then PR them upstream, since the plugin is small (15 stars) and unlikely to gain them otherwise.
  • Test with real plans, not hasFeature mocks. Create three plans (free/pro/enterprise) with overlapping features and use those in feature tests; mocking the trait misses caching and DB-relationship bugs that only show up against real plan rows.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle