Skip to main content

Architecture

A high-level map of how Cobblr fits together.

The core

At the center is the modular kernel and a REST API, backed by Postgres. Every feature is a module that composes through shared primitives (items, fields, views, events). The web app is one client of the API; the CLI and integrations are others.

This is the part you self-host, source-available under the Functional Source License (see Contributing). It's built so that no data or PII ever needs to leave your system: no telemetry, no tracking, no analytics, no auto-updates phoning home. Your data is yours and stays on your box (see Self-hosting -> Privacy).

The module system

Every feature is a module, and modules are held to a shape the platform can rely on:

  • Isolation. A module never imports another module: not its types, its helpers, or its tables. Modules compose only through the platform contract (items, fields, views, events, actions) and explicit granted read paths, so any subset of modules works together and a new one can't break an existing one.
  • Capability or domain, encoded in the name. A domain is a kind of thing a user manages: a noun, a table, a nav entry, opt-in, with a bare name (inventory, machines, tracking). A capability is plumbing with no noun in the nav, named core-<thing> (core-views, core-scan), usually enabled automatically. The nav builds its top level by filtering out core-*, so the name is load-bearing: a domain misnamed core-something vanishes from the app.
  • A manifest, not wiring. A module declares what it is: its entity kinds and their fields, what it contributes (default views, wires, scan routing), and whether it can be instanced more than once. The platform does the composing.
  • One identifier pattern, namespaced by the module name:
ThingPatternExample
Package@cobblr/<name>@cobblr/tracking
Table prefix<name>_tracking_metrics
Entity kind<name>:<kind>tracking:metric
Event<name>.<noun>.<verb>tracking.measurement.logged
Action<name>:<verb-noun>tracking:log-measurement
Route/<name>/tracking

Multi-tenancy

One instance serves many workspaces, and the isolation between them is structural rather than a filter on shared tables. The data lives in two tiers:

  • A platform database holds the accounts, the workspaces, and who belongs to which workspace with what role. It's the thin routing layer.
  • Each workspace gets its own separate database for its actual data, created when the workspace is. A request is routed to the right one by workspace, and the connection credentials for each are encrypted at rest.

Modules add their own tables into a workspace's database when that workspace turns them on, so two workspaces on the same instance can have entirely different schemas in play. A user carries a role in each workspace they belong to (owner, admin, editor, member, guest), and what they can do is resolved per request from that role, with finer per-workspace grants on top.

See Workspaces for the same picture without the plumbing.

Talking to machines

When you self-host Cobblr on the same network as your machines, it talks to them directly. When it can't reach them (a firewall between them, machines at a different site, or software pinned to a specific PC like LightBurn), you run the edge bridge at your location and Cobblr connects through it. The bridge always dials outward, so nothing on your network is exposed, and its drivers handle the machine-specific protocols. See Digital fabrication for the usage side.

(Diagrams and the data model will be added.)