Railbase
GPTClaude

Architecture

The core, plugins, the vault data store, and the marketplace.

Updated

Video guide —watch on YouTube ↗

Railbase is one binary that supervises a small set of moving parts. Understanding them makes the install, update, and licensing flows obvious.

The big picture

                    your server
 ┌────────────────────────────────────────────────────┐
 │  Railbase core (the binary)                          │
 │   ├── HTTP server        :8095                        │
 │   │     /             public site SPA (optional)      │
 │   │     /_/           admin console + marketplace      │
 │   │     /api/*        core REST + auto-CRUD + verbs    │
 │   │     /api/_admin/* admin-console API                │
 │   │     /<slug>       a plugin's site frontend          │
 │   │     /_pm/*        plugin-manager endpoints          │
 │   ├── vault           single-file encrypted data store │
 │   ├── goja runtime    (runs plugin JS in-process)       │
 │   │     ├── plugin A   (decrypted JS+schema bundle)      │
 │   │     └── plugin B   (decrypted JS+schema bundle)      │
 │   └── plugin manager  (install/license/lifecycle)       │
 └────────────────────────────────────────────────────┘
              │ syncs with (catalog, licenses,
              ▼  bundles, payments)
        railbase.app  — vendor licensing & distribution

A plugin's verbs always live at /api/<slug>/…. A plugin is data the core runs, not a separate program: its encrypted JS+schema bundle lives in the core's _plugins Vault row and, once the license gate decrypts it, runs inside the core's own goja runtime — so its verbs are served by the core directly, in-process.

The core

The core is the always-on process. It owns the HTTP server, the data store, auth, the job runner, and the admin console. It boots in well under a second and runs happily on a small VPS.

Key routes:

  • / — the public site SPA (what end users see), optional.
  • /_/ — the admin console, including Marketplace at /_/marketplace.
  • /api/* — core REST, auto-CRUD, and plugin verbs.
  • /api/_admin/* — the admin-console API.
  • /<slug> — a plugin's end-user frontend, mounted on the site SPA from the plugin's bundle manifest automatically at install.
  • /_pm/* — plugin-manager and marketplace proxy endpoints (on by default; RAILBASE_PLUGIN_MANAGER=0 disables). Destructive actions require an admin session; the public admin UI is /_/marketplace.

Plugin verbs answer at /api/<slug>/…, served by the core directly: the plugin's bundle registers them on the core router (via $app.routerAdd) when its decrypted JS loads into the goja runtime. There is no per-plugin port and no proxy hop.

Plugins: data the core runs

A plugin ships as a data-resident bundle — encrypted JS plus a collection schema — not a standalone program. On purchase the marketplace installs that bundle into the core's _plugins Vault row (the JS is AES-256-GCM-encrypted at rest, so a copy of the .vault file never reveals plugin source). The license gate is the execution point: the core decrypts and loads a plugin's code only while its license permits it (active or trial); a dormant — unpaid, expired, or revoked — plugin is never decrypted and has zero behavior.

Once loaded, a plugin runs in-process in the core's goja runtime and reaches everything through mediated host capabilities — never the core's internals:

  • verbs via $app.routerAdd, served at /api/<slug>/…,
  • data via the tenant-scoped $app.dao (the platform's shared store — no per-plugin database),
  • events via $app.realtime to publish and $app.onEvent to consume,
  • background work via $jobs,
  • identity via e.auth (trusted server-side, never a client header),
  • plan and quota via $app.license.

A plugin's end-user UI ships inside the same bundle as bundle/manifest.json (manifest.ui.pages) and the core's site shell mounts it at /<slug> on install — one marketplace action delivers verbs, schema, and UI with no rebuild. Because plugin code is data the core executes, install, update, and remove happen at runtime by writing or flipping the Vault row — no subprocess to launch, no port to open, no redeploy. The full lifecycle is in How plugins work.

Internal dev/embedder workflows can compile a controlled host build for engineering use, but that is not a customer artifact and not a distribution channel. The single shipped, sold form is the data-resident bundle above.

The vault data store

Persistence is a single encrypted file (railbase.vault) managed by an in-process, MVCC document engine that stores CBOR documents — no SQL, no PostgreSQL, no connection strings, no sidecar. Tenant scoping is explicit: tenant-aware collections carry tenant_id, and production hot paths use declared secondary indexes rather than SQL queries. Each plugin gets its own namespaced collections inside the platform's shared Vault. See Data & multi-tenancy.

railbase.app: the vendor plane

Your instance is a client of railbase.app, the vendor's server. It reaches out to:

  • discover plugins and prices (catalog) and the vendor's signing key (pubkey),
  • complete a purchase (payment runs on railbase.app; your server is never a card processor),
  • download the signed, encrypted bundle for a plugin you're licensed for,
  • keep licenses fresh via a periodic license check (renewals, revocations).

The trust anchor is a pinned public key: the core only installs a bundle whose signature verifies against the key it has pinned for the vendor. This is why acquisition is marketplace-only — see How plugins work and Licensing & seats.

Was this page helpful?Thanks for your feedback!