⚡ VBWD
A sales platform for the digital world — SaaS subscriptions, CMS, shop, booking and a token economy on one self-hosted backend, two Vue front-ends and one plugin contract.

Architecture as a business advantage
Most SaaS codebases get slower as they grow — every feature touches the core, every client needs a fork, every release is a gamble. VBWD is built the opposite way: a small, hardened core with an open set of plugins around it. That one decision is what lets you move fast for years — ship a feature without touching the core, run a hundred tenants from one codebase, and onboard a client as a config diff instead of a fork.
A feature is a plugin, not a core change — backend, admin and customer surface in one coordinated trio. No "please rebuild the core" tickets.
One codebase, many deployments; each tenant loads only the plugins it enables, so footprint tracks need — not platform size.
Source-available under BSL, every payment rail interchangeable, your data in your own Postgres. Read the code →
Three runtimes. One contract. Plugins everywhere.
Every corner of VBWD is its own runtime with the same plugin contract. A feature lights up by shipping a coordinated trio — a backend plugin (API + data model), an fe-admin plugin (configuration UI) and an fe-user plugin (customer surface) — or any subset; they are independent.
vbwd-backendPython · Flask · PostgreSQL. REST API at
/api/v1/*, SQLAlchemy 2.0, dependency-injector, event
bus, Alembic. 292+ tests · Gunicorn · Redis cache.
vbwd-fe-adminVue 3 · Pinia · Vite. The back-office — users, plans, subscriptions, invoices, gateways, analytics, plugin manager. Port 8081 · Playwright E2E.
vbwd-fe-userVue 3 · PluginRegistry · IPlatformSDK. Customer portal + public surfaces. Topological dependency resolution. Port 8080 · 23+ plugins.
One source of truth for plugin state — enable/disable lives in
${VAR_DIR}/plugins/; the backend writes, both
front-ends mount it read-only. No localStorage drift.
The backend ships the core, then steps aside for plugins
- Flask blueprint auto-mounted at
/api/v1/<plugin>/*on enable, unmounted on disable. - SQLAlchemy 2.0 models + Alembic migrations tied to the plugin lifecycle.
register_event_handlers(bus)— subscribe to subscription, payment, checkout and security events. No polling.- Emit your own domain events; other plugins consume them without direct imports.
- Line-item handlers plug into checkout totals: discounts, taxes, shipping, token deductions.
- Shipping providers, categories + routing, declarative permission scopes in the RBAC matrix.
- Namespaced
get_config/set_config, JSON-schema-validated, secrets via env indirection only.
A finite, named set of aggregates — not "anything goes"
Every domain has a small, named set of SQLAlchemy 2.0 entities. Plugins add their own; the core never grows by accretion.
User, UserDetails, UserAccessLevel, Role, UserTokenBalance, FeatureUsage.
TarifPlan, TarifPlanCategory, Subscription, AddOn, AddOnSubscription.
Invoice, InvoiceLineItem, PaymentMethod, Tax, Country, Currency.
plugin_config, Webhook + delivery log, routing rules, categories, audit log.
A typed DI container. No globals. No accidental singletons.
dependency-injector wires repositories, services and
infrastructure (DB session, Redis, event bus, secrets). Every
consumer asks for what it needs through constructor injection;
in tests, providers are swapped for in-memory repositories, a
fake bus and a deterministic clock — no service knows it is
mocked.
AuthService,UserService,SubscriptionService,InvoiceService,RefundService,TokenService.PluginService,WebhookService,EmailService,EventDispatcher.- One repository per aggregate; multi-aggregate writes orchestrated in services, never in ORM session magic.
SOLID as contracts, not decoration
- S — routes validate, services orchestrate, repositories persist, models describe.
- O — extend by adding plugins, never by editing core.
- L — every payment provider is interchangeable; checkout never branches by provider.
- I — the plugin SDK is segregated: emitting events needs no knowledge of line items.
- D — services take interfaces; the container injects SQLAlchemy in prod, in-memory in tests.
- TDD-first — no tests, no merge. DRY — a bug fix happens once. Clean code — no abbreviations.
Defaults that don't get you breached on a Tuesday
- JWT bearer + refresh, per-deploy secret, rotatable without dropping live sessions.
- RBAC roles + access levels; plugins declare their own scopes.
- Per-IP / per-user rate limiting; stricter caps on login + password reset.
- Argon2id hashing; same response on bad-password and unknown-user — no enumeration.
- HMAC-signed outbound webhooks; inbound provider webhooks verified before any state change.
- Idempotency keys on order/capture/refund; full audit log; secrets never in
plugin_config.
Read the architecture, end to end
The marketing tour is the short version. The documentation has the full design — and the rest of the platform is one click away.
The full backend + front-end architecture, layer by layer.
How one plugin registers into all three runtimes at once.
The rule that keeps the core small — enforced by an AST test.
How plugins coordinate without importing each other.
The subscription engine, checkout and invoices, end to end.
Clean clone to live in under five minutes; a client is a config diff.