Developer Docs · 03

The Plugin System

Every business feature is a plugin. A plugin is a Python package with a class, a blueprint, models, services and migrations.

Enabling and configuring plugins in admin settings.
Enabling and configuring plugins in admin settings.

The plugin class

A plugin subclasses BasePlugin and is defined in the package's __init__.py (it must be defined there, not re-exported):

from src.plugins.base import BasePlugin, PluginMetadata

class MyPlugin(BasePlugin):
    @property
    def metadata(self):
        return PluginMetadata(name="my-plugin", version="1.0.0",
                              dependencies=[])

    def initialize(self, config=None):
        merged = {**DEFAULT_CONFIG, **(config or {})}
        super().initialize(merged)

    def get_blueprint(self):
        from plugins.my.my.routes import my_bp
        return my_bp

    def get_url_prefix(self):
        return "/api/v1/my"

    def on_enable(self): ...
    def on_disable(self): ...

Lifecycle

A plugin moves through discovered → initialized → enabled. initialize() merges config; on_enable() is where you register DI providers, event handlers, data exchangers and permissions; on_disable() tears them down. The framework auto-discovers plugins from the plugins/ directory and enables those marked enabled: true in plugins.json.

File layout (new convention)

plugins/<name>/
  __init__.py            # the Plugin class lives here
  <name>/                # source dir = the plugin id
    models/              # SQLAlchemy models (extend BaseModel)
    repositories/        # data access
    services/            # business logic
    routes.py            # Flask blueprint
  migrations/versions/   # plugin-owned Alembic migrations
  tests/                 # unit + integration with own conftest.py
  populate_db.py         # idempotent demo data
  config.json            # default config (+ debug_mode toggle)
  admin-config.json      # admin settings schema

Registration

  • Add the plugin to plugins/plugins.json (enabled: true) and its config to plugins/config.json.
  • Put migrations in plugins/<name>/migrations/versions/ — they are auto-discovered by alembic/env.py (no alembic.ini edit needed).
  • Every plugin ships its own public VBWD-platform/vbwd-plugin-<name> repository.

Declare cross-plugin dependencies in PluginMetadata.dependencies — e.g. tarot and meinchat both depend on subscription.