Skip to main content

Module Lifecycle

Two layers decide what runs in any given Orkestra instance.

Layer 1 — Build time

Which addons are installable in this binary is decided at compile time. Each addon's wiring lives in cmd/server/catalog_<addon>.go, gated by a Go build tag:

//go:build !no_addons || addon_<name>

Default builds compile every addon (enterprise SKU). A targeted build like -tags "no_addons addon_billing addon_documents" ships a curated subset. The Makefile defines named profiles (make build-starter|minimal|billing|ai|saas|enterprise) and CI builds the full matrix on every PR.

Layer 2 — Runtime

All optional modules that compiled in are instantiated, initialized, and routed at boot — regardless of enabled state. Routes for disabled modules are gated by ModuleGate middleware (returns 503 Service Unavailable). Only enabled modules have their Start() method called.

Enabling and disabling at runtime

The admin API (PATCH /v1/admin/modules/{name}) calls StartModule() / StopModule() on the registry. The module starts or stops immediately — no restart required. Dependency constraints are enforced: you cannot disable a module that another running module depends on (returns 409 Conflict).

First-boot seeding

On the first boot of a brand-new install, the module_configs document is seeded from each module's ConfigSchema().EnvVar. If ORKESTRA_PROFILE is set (typically by docker-compose.<profile>.yml), the seeder additionally pre-enables that SKU's addons. Subsequent boots ignore ORKESTRA_PROFILE — admin-set values are authoritative.

Initialization order

The registry topologically sorts modules by Dependencies(), so initialization order is always correct regardless of how they're declared.