procyon-core
Versioned runtime shared by applications created from the Procyon template.
Applications depend on this module instead of owning copies of the framework
infrastructure. Upgrade an application with:
go get github.com/bartek5186/procyon-core@latest
go mod tidy
go test ./...
The application keeps ownership of domain models, stores, services,
controllers, routes and migrations.
Application runtime
The public runtime package owns framework bootstrap and shutdown:
configuration, logging, database, telemetry, authentication, RBAC, standard
HTTP servers and the complete plugin lifecycle. An application supplies a
small runtime.Application with its event handlers, policies, routes and an
optional shutdown callback. Its factory receives only stable framework
dependencies through runtime.Dependencies.
Framework routes are exposed through runtime.Routes: public and /v1 API
groups, optional authenticated and admin groups, upload and operations servers,
and the configured authentication, admin-key and permission middleware. The
standard Upload group keeps the /upload prefix; UploadRoot supports
applications whose dedicated upload server already owns its URL root. Standard
health, readiness, info, metrics, static and admin ping endpoints remain owned
by Core.
Applications can extend the runtime without copying framework infrastructure:
runtime.Options.Validator installs an application validator on every server,
while runtime.Application.Authorization supplies custom role normalization,
self-assignment rules and domain ownership checks. SetAuthorizer receives the
single framework-owned Casbin authorizer for use by application services.
Application migrations
The public migrations package owns the common GORM/Goose
execution path, driver selection, migration ledger configuration and SQL table
name validation. Applications retain their embedded SQL files, model list and
seed callbacks and pass them as a migrations.Plan.
Plugin lifecycle
The public plugins package composes project-owned and installed
compile-time plugins in one registry. It validates unique names, resolves
Requires dependencies topologically, and runs migrations, capabilities,
events, policies, routes, workers and reverse-order shutdown deterministically.
Plugins may register maintenance endpoints through the optional Operations
group on the separate admin server; Core exposes that group only when it can
pre-protect it with configured admin-key authentication.
The base Plugin interface remains compatible with existing modules. Optional
interfaces add DependencyDeclarer, CapabilityRegistrar, EventRegistrar,
MigrationProvider and Starter. Dependencies supplies the shared database,
logger, event bus, business metrics, UTC clock and capability registry.
Versioned plugin migrations use the shared plugin_schema_migrations ledger.
Legacy plugins can keep implementing their own Migrate method. See the
plugin runtime guide for the complete contract.
Runtime configuration is layered. config.Read loads the selected base JSON
file, expands ${NAME} and ${NAME:-fallback} values, and then composes plugin defaults from a sibling
plugins.generated.json. Explicit plugins.<name> values in the base file
override generated defaults. Each plugin keeps ownership of its typed config
structure and decodes only its namespaced JSON value. Applications with custom
top-level sections use Config.Decode to decode the already loaded JSON without
reading or expanding the configuration a second time.
Typed application events
The public events package provides synchronous, typed communication
between the application and compile-time plugins. It intentionally has no
worker, queue or persistence. A durable publisher remains responsible for
retrying a failed Publish call.
Applications create one bus, pass it to every plugin through
plugins.Dependencies.Events, call plugin RegisterEvents, register application
handlers, and call Seal before routes or background tasks start. Plugins must
not publish before the bus is sealed.
Topics are versioned contracts such as payment.purchase.completed.v1.
Handlers run sequentially, stop on the first error and must be idempotent.
See the event bus guide for contracts, lifecycle and
existing-project wiring.