Documentation
¶
Overview ¶
Package api is the single-binary server surface for Atlas: it embeds one engine.Processor behind an HTTP API and serves an embedded web UI, so a single self-contained binary can deploy BPMN models, run instances, and (as the UI grows) view them in a browser. See ADR-0011.
Respecting the single-writer invariant ¶
The engine is a single-writer partition (invariant I3): exactly one goroutine may touch a partition's processor and state. HTTP handlers, by contrast, run concurrently. The Server bridges the two by owning a run loop goroutine that is the sole toucher of the processor; handlers submit closures to it via do and block for the result. No processor method is ever called from a handler goroutine directly.
Scope of the skeleton ¶
This is the Milestone S skeleton (ROADMAP.md): deploy XML, create an instance, read stats, health, and a static UI shell. Deployments are durable via an on-disk sidecar store (ADR-0019) reloaded on startup, so diagrams, versions, and recovered instances survive a restart; the eventual event-sourced deployment path arrives with the Milestone 4 public API. One honest limitation remains: there is no streaming job-worker transport yet (that follows the gRPC job protocol, ADR-0007), so an instance parks at its service task — exactly the "waiting token" the live viewer shows. Such a parked job can be finished by hand over HTTP (POST /jobs/{key}/complete, the operator mirror of .../fail from the incident model), but that is a synchronous operator affordance, not the leased, at-least-once worker protocol.
Index ¶
- Constants
- Variables
- func ApplyPendingRestore(dataDir string) (bool, error)
- type BuildInfo
- type LogBuffer
- type Option
- func WithAuth() Option
- func WithCheckpointRetention(keep int) Option
- func WithCheckpoints(every time.Duration) Option
- func WithCollabKeepaliveInterval(d time.Duration) Option
- func WithInboundBatchLimit(n int) Option
- func WithInboundPollInterval(d time.Duration) Option
- func WithLogBuffer(b *LogBuffer) Option
- func WithOpenSearchExportInterval(d time.Duration) Option
- func WithOpenSearchExporter(cfg opensearch.Config) Option
- func WithRetention(maxAge time.Duration) Option
- func WithRetentionBatch(n int) Option
- func WithRetentionInterval(d time.Duration) Option
- func WithScriptWorker(jobType int32, exec script.Exec) Option
- func WithSystemProcesses() Option
- func WithUserProvisioning() Option
- func WithWALCompaction() Option
- func WithoutDocs() Option
- func WithoutMetrics() Option
- func WithoutVault() Option
- type ResetPasswordOptions
- type ResetPasswordResult
- type Server
- type User
Constants ¶
const ( VisibilityPrivate = "private" )
Visibility values for a project scope. A private project is visible only to its owner (and admins); a shared project additionally grants each listed member their role. The set is intentionally small and open: an org/public value can join later without reshaping the field (ADR-0071).
const ( ScopeRoleViewer = "viewer" ScopeRoleEditor = "editor" ScopeRoleOwner = "owner" )
Scope roles, lowest to highest privilege. viewer reads, editor reads+writes, owner additionally manages membership, visibility, transfer, and deletion. owner is implicit (it is the project's OwnerID), never stored in Members. The list mirrors ADR-0044's "roles are a list, only some values enforced now" discipline, so richer roles cost no reshaping.
const ( // DefaultRetentionInterval is the default cadence of the history-retention sweep. // Exported so the CLI can show it as the default of --retention-interval rather // than restate a number that would drift from this one. DefaultRetentionInterval = time.Minute // DefaultRetentionBatch bounds how many finished instances one sweep tick evaluates, // so the scan never blocks the run loop (ADR-0115 / ADR-0085 no-full-scan rule). // Together the two bound the drain rate of a backlog: DefaultRetentionBatch per // DefaultRetentionInterval. Exported for the CLI, like DefaultRetentionInterval. DefaultRetentionBatch = 1000 )
const ( RoleAdmin = "admin" RoleUser = "user" )
Well-known roles. Roles are a free-form list on the user, not a single "admin" bool, so richer RBAC can grow here without reshaping the record (ADR-0044). The MVP only enforces RoleAdmin (managing users requires it); every other role is stored and returned but not yet consulted.
const PrincipalTypeUser = "user"
PrincipalTypeUser is the only member reference type Phase 1 implements. The type field exists so groups ("group") slot in later without a migration (ADR-0071/0044 follow-up).
const RoleDeployAgent = "deploy-agent"
RoleDeployAgent marks the principal a deploy token resolves to: a peer Atlas publishing a bundle here (ADR-0129). It is deliberately not a user role — no account carries it, it cannot be assigned, and it grants nothing on its own. What it may reach is decided by deployAgentAllowed below.
const (
SourceLocal = "local"
)
Identity sources. A user authenticates either against a locally stored password (SourceLocal) or, in a future enterprise build, against an external identity provider (OIDC/SAML/LDAP) that maps its subject onto User.ExternalID. Storing the source now — rather than assuming "local" everywhere — is what lets external identities coexist later without a migration (ADR-0044).
Variables ¶
var Version = "0.2.0-dev"
Version is the Atlas product version reported to the UI and the CLI. It is UI/display metadata only and unrelated to a deployment's process version.
It is a var, not a const, so a release build can stamp the tag into it with
go build -ldflags "-X github.com/pblumer/atlas/api.Version=0.2.0"
A plain checkout build keeps the "-dev" suffix; the exact commit is always available from the embedded VCS metadata (see buildInfo).
Functions ¶
func ApplyPendingRestore ¶
ApplyPendingRestore applies a staged full-snapshot restore, if one is present and complete, into dataDir — replacing each staged top-level entry and dropping the materialized state so recovery rebuilds it from the restored WAL. It MUST run before the WAL and state stores are opened (the engine holds them under the single-writer invariant), i.e. at the very start of a boot. It returns whether it applied anything.
Each staged entry is moved (rename) into place and the staging directory removed only once every entry is in place. The marker is removed last with the staging, so a crash mid-apply re-runs on the next boot: an entry already moved is simply absent from the staging and skipped, so the apply is idempotent.
Types ¶
type BuildInfo ¶
type BuildInfo struct {
Version string // product version (api.Version), stampable via -ldflags
Revision string // git commit, "" if built outside a VCS checkout
Time string // commit time (RFC3339), "" if unknown
Modified bool // true if built from a dirty working tree
Go string // Go toolchain version
}
BuildInfo is the exported view of the running binary's version and embedded VCS build metadata, for callers outside this package — the `atlas version` command. The GET /api/v1/info endpoint reports the same values.
type LogBuffer ¶
type LogBuffer struct {
// contains filtered or unexported fields
}
LogBuffer is a bounded, concurrency-safe ring of the most recent process log lines. The command tees the standard logger into it (log.SetOutput(io.MultiWriter(os.Stderr, buf))) and hands it to the server via WithLogBuffer, so an operator can read recent server logs over the web — e.g. to check the script-worker startup lines — without shell access to the host.
It only retains the last max lines, so it is a diagnostic tail, not durable storage; it holds no secrets beyond whatever the process already logs.
func NewLogBuffer ¶
NewLogBuffer creates a LogBuffer retaining the last max lines (defaulting to 1000 when max <= 0).
type Option ¶
type Option func(*Server)
Option configures a Server at construction. Options are applied in New before the run loop starts, so they set fields that are read-only afterwards.
func WithAuth ¶
func WithAuth() Option
WithAuth turns on authentication enforcement: /api/v1 requires a valid session (except the login call, product info, and the OpenAPI doc), and managing users requires the admin role. Off by default, so an existing single-binary deployment is unaffected until an operator opts in (ADR-0044).
func WithCheckpointRetention ¶ added in v0.2.0
WithCheckpointRetention sets how many published checkpoints are kept (ADR-0131). A checkpoint hard-links the SSTables it captured, so keeping every one would pin every file the store ever wrote; keeping a few leaves a fallback if the newest is corrupt. A non-positive value restores the default.
func WithCheckpoints ¶ added in v0.2.0
WithCheckpoints enables periodic recovery checkpoints at the given cadence (ADR-0131). Each one snapshots the applied state, so a restart replays only the log past it rather than from genesis — recovery time becomes a function of the cadence instead of the log's whole length.
It is purely additive: nothing is deleted, the WAL stays the source of truth, and a missing, failed, or corrupt checkpoint only makes the next recovery slower (invariant I2). A non-positive cadence leaves checkpointing off.
func WithCollabKeepaliveInterval ¶
WithCollabKeepaliveInterval sets how often an idle collaboration SSE stream writes a keepalive comment, the mechanism that detects a half-open browser connection so its session participant is reaped (ADR-0140). A non-positive value restores the default (15s). Tests pass a short interval to exercise it.
func WithInboundBatchLimit ¶
WithInboundBatchLimit caps how many clio events one poll of a subscription reads and republishes (ADR-0075). A non-positive value restores the default. It bounds the burst a single poll hands the run loop; a large backlog then drains as bounded catch-up across ticks instead of one unbounded publish storm.
func WithInboundPollInterval ¶
WithInboundPollInterval sets the clio inbound bridge's poll cadence (ADR-0075). A non-positive interval disables the bridge (useful in tests that drive it directly). The default is 2s.
func WithLogBuffer ¶
WithLogBuffer wires the server's recent-log tail, exposed at GET /api/v1/logs, so an operator can read server logs from the web UI. The command builds the buffer, tees the standard logger into it, and passes it here.
func WithOpenSearchExportInterval ¶ added in v0.2.0
WithOpenSearchExportInterval sets how often the exporter polls the log for newly durable records (ADR-0114). A non-positive value restores the default (5s). Tests pass a short interval to exercise the loop.
func WithOpenSearchExporter ¶ added in v0.2.0
func WithOpenSearchExporter(cfg opensearch.Config) Option
WithOpenSearchExporter enables the OpenSearch event exporter (ADR-0114): a WAL-tailing sink that mirrors the durable event log into an OpenSearch index so history stays searchable and can outlive engine-side retention. It is opt-in — a config with an empty URL leaves the exporter off. The endpoint, credentials, and index live in server config, never in a model.
func WithRetention ¶ added in v0.2.0
WithRetention enables history retention (ADR-0115): a finished instance whose terminal event is older than maxAge and whose events are already exported (its terminal position is at or below the safe position) is hard-deleted from the state store. A non-positive maxAge leaves the server with no default age — the opt-in default — and retention then applies only to definitions declaring their own atlas:historyTtl (ADR-0144).
func WithRetentionBatch ¶ added in v0.2.0
WithRetentionBatch caps how many finished instances one retention sweep tick evaluates and purges (ADR-0115), bounding the work a single tick does on the run loop; a larger backlog then drains as bounded catch-up across ticks. A non-positive value restores the default.
func WithRetentionInterval ¶ added in v0.2.0
WithRetentionInterval sets the retention sweep cadence (ADR-0115). A non-positive value restores the default. Tests pass a short interval to exercise the sweep.
func WithScriptWorker ¶
WithScriptWorker registers the interpreter for one script language (identified by its reserved job-type index, e.g. compiler.PwshJobTypeIndex), so a deployed script task in that language actually runs instead of parking on its job (ADR-0047). It executes arbitrary interpreter code on the server host, so register only the languages whose trust boundary is acceptable (the eventual isolation boundary is an external worker in the customer's environment). exec is the interpreter seam — pass script.New(script.Python) etc., or a fake in tests.
func WithSystemProcesses ¶ added in v0.2.0
func WithSystemProcesses() Option
WithSystemProcesses bootstrap-deploys Atlas's own embedded platform processes (user intake, access review, offboarding) into the protected system project at startup (ADR-0122). Opt-in — the installed binary (cmd/atlas) enables it, while the engine tests construct servers without it so a fresh instance still starts with no deployments.
func WithUserProvisioning ¶ added in v0.2.0
func WithUserProvisioning() Option
WithUserProvisioning enables the in-process user-provisioning connector (create/set-password/disable Atlas logins) for the protected system project's processes (ADR-0123). Opt-in and off by default: it deliberately, and narrowly, reopens the ADR-0044/0049 boundary that no automated identity may manage users — so an instance keeps the human-in-the-loop ADR-0122 behavior until an operator turns this on. When off, a userConnector job has no worker and parks.
func WithWALCompaction ¶ added in v0.2.0
func WithWALCompaction() Option
WithWALCompaction deletes the WAL segments a recovery checkpoint and every consumer watermark make redundant (ADR-0131), bounding the log's disk instead of letting it grow with all history. It has no effect without WithCheckpoints: the cut is derived from a checkpoint, and compaction runs on the tick that takes one.
It is opt-in, unlike checkpointing, for the same reason history retention is (ADR-0115): this is the one step here that destroys data. The cut itself is conservative — the newest **fully verified** checkpoint (manifest and state files) at or below the store, floored by every consumer watermark, with a corrupt, foreign, or ahead-of-store checkpoint licensing no deletion at all — but a conservative cut is still a deletion, and an operator should choose it.
func WithoutDocs ¶
func WithoutDocs() Option
WithoutDocs disables the OpenAPI document at /api/v1/openapi.json and the Scalar API explorer at /api/docs, which are otherwise served by default. Pass it when the interactive, mutating "Try it out" surface should not be exposed (ADR-0043).
func WithoutMetrics ¶ added in v0.2.0
func WithoutMetrics() Option
WithoutMetrics turns off the Prometheus exposition at /metrics (ADR-0142). It is served by default — a system meant to be operated should be observable without extra configuration, and the exposition carries only bounded-cardinality aggregates — so this is for an operator who does not want the surface open at all.
func WithoutVault ¶
func WithoutVault() Option
WithoutVault disables the engine-internal encrypted secret vault, which is otherwise on by default (ADR-0070). With it disabled the secret endpoints return 503 and connector credentials resolve only from the environment (ADR-0041 A2). Pass it when Atlas must not custody a key or ciphertext at all.
type ResetPasswordOptions ¶
type ResetPasswordOptions struct {
// DataDir is the server's data directory (the same --data-dir the server
// runs with). The user store lives in its "users" subdirectory.
DataDir string
// Username identifies the account to reset, matched case-insensitively.
Username string
// NewPassword is the replacement password. It must meet the same minimum
// length the API enforces.
NewPassword string
// CreateAdmin, when set, creates a fresh enabled admin with Username if no
// such user exists yet — a bootstrap escape hatch for an instance that has
// users but no reachable admin. It never duplicates or re-roles an account
// that already exists.
CreateAdmin bool
// Now is the unix-seconds timestamp stamped into the record, matching the
// server's own UpdatedAt/CreatedAt unit. Injected so the operation is
// deterministic and testable.
Now int64
}
ResetPasswordOptions configures a single operator-driven password reset.
type ResetPasswordResult ¶
type ResetPasswordResult struct {
UserID string
Username string
// Created is true when a new admin account was created (CreateAdmin), false
// when an existing account's password was replaced.
Created bool
}
ResetPasswordResult reports what a reset did.
func ResetPassword ¶
func ResetPassword(opts ResetPasswordOptions) (ResetPasswordResult, error)
ResetPassword sets a new local password for a user in the store under opts.DataDir. It replaces only the password (and UpdatedAt); roles, email, and the Disabled flag are left as they are, so a reset re-grants access without silently changing what the account can do. With CreateAdmin and no matching user, it instead creates a fresh enabled admin.
It touches the same files the running server uses. Login reads the store from disk on every attempt, so a reset takes effect on the next sign-in without a restart; running it against a live server is safe (writes are atomic), though stopping the server first is never wrong.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server hosts the engine behind an HTTP surface. Construct it with New, mount Handler on an http.Server, and call Close to stop the run loop.
func New ¶
func New(proc *engine.Processor, store *state.Store, dataDir string, opts ...Option) (*Server, error)
New builds a Server over an already-recovered processor and its store and starts the run-loop goroutine. dataDir is the base data directory; the durable deployment and draft sidecar stores live in its "deployments" and "drafts" subdirectories (ADR-0019). New reloads any deployments found there, re-registering them with the processor so recovered instances resolve their definition and the UI can render diagrams again. The caller retains ownership of proc and store (Close here stops only the loop, not the engine).
func (*Server) Close ¶
func (s *Server) Close()
Close stops the run-loop goroutine. It does not close the processor, log, or store — the caller owns those.
func (*Server) Handler ¶
Handler returns the HTTP handler: JSON API under /api/v1, /healthz, the embedded web UI at the root, and — when docs are enabled (WithDocs) — the OpenAPI document at /api/v1/openapi.json and the Scalar API explorer at /api/docs.
func (*Server) InternalToken ¶
InternalToken returns the internal service token used by the in-process MCP adapter to authenticate its loopback calls (ADR-0049). It is empty unless auth is enabled. It is never served over any endpoint; only the constructing process reads it, to hand to its own MCP client.
type User ¶
type User struct {
ID string `json:"id"`
Username string `json:"username"`
Email string `json:"email,omitempty"`
DisplayName string `json:"displayName,omitempty"`
Roles []string `json:"roles"`
Disabled bool `json:"disabled,omitempty"`
Source string `json:"source"`
ExternalID string `json:"externalId,omitempty"`
PasswordHash string `json:"passwordHash,omitempty"`
CreatedAt int64 `json:"createdAt"`
UpdatedAt int64 `json:"updatedAt"`
}
User is a person (or, later, an external identity) known to this Atlas instance. It is operator/config data, not engine state: it never flows through the WAL or the processor, so it lives in a durable sidecar store like forms and projects (ADR-0019/0028/0044) and touches none of the six engine invariants.
The field set is deliberately chosen so the enterprise trajectory (SSO, RBAC, deactivation, later multi-tenancy) needs no breaking change:
- ID is a stable, opaque, never-reused primary key, decoupled from Username and Email so either can change (or be reassigned by an external IdP) without rewriting references to the user.
- Roles is a list (RBAC-ready), not a boolean flag.
- Source + ExternalID are the hook for external identity providers.
- Disabled deactivates a user for lockout/offboarding without destroying the record (and the audit trail it anchors).
- PasswordHash is a bcrypt hash for local users and empty for external ones.
Source Files
¶
- appimport.go
- appsource.go
- appsource_http.go
- auth.go
- backup.go
- buildinfo.go
- callactivities.go
- calloverridestore.go
- checkpointstatus.go
- collabsession_http.go
- connectorkinds.go
- connectors.go
- connectorstore.go
- csvupload.go
- decisionops.go
- decisions.go
- deploystore.go
- deploytokens.go
- deploytokenstore.go
- dmnrefs.go
- dmnrefstore.go
- dmnupload.go
- dmnvalidate.go
- draftstore.go
- forms.go
- formstore.go
- handlers.go
- inbound.go
- inboundbridge.go
- inboundsubstore.go
- logbuf.go
- marketplace.go
- marketplacestore.go
- metrics.go
- openapi.go
- passwordreset.go
- principals.go
- projectdeploy.go
- projects.go
- projectstore.go
- promote.go
- publiclinks.go
- publiclinkstore.go
- ratelimit.go
- readyz.go
- releases.go
- releasestore.go
- scopes.go
- scriptrun.go
- secrets.go
- server.go
- settings.go
- settingsstore.go
- snapshot.go
- systemprocesses.go
- systemproject.go
- targetstore.go
- userconnector.go
- users.go
- userstore.go
- validate.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package collab implements the first slice of ADR-0140: live collaborative modeling sessions.
|
Package collab implements the first slice of ADR-0140: live collaborative modeling sessions. |
|
Package httpapi holds the primitives every Atlas HTTP handler is written against: how a response is written, who the caller is, and where the request came from.
|
Package httpapi holds the primitives every Atlas HTTP handler is written against: how a response is written, who the caller is, and where the request came from. |
|
Package layout generates BPMN diagram interchange (BPMN-DI) for models that carry none, and regenerates it for models whose layout a user has tangled.
|
Package layout generates BPMN diagram interchange (BPMN-DI) for models that carry none, and regenerates it for models whose layout a user has tangled. |
|
Package processdoc serves process documentation (ADR-0143): a published BPMN process as a stored PDF plus the element prose it describes, its version history, and the revocable public link a reader without an account follows.
|
Package processdoc serves process documentation (ADR-0143): a published BPMN process as a stored PDF plus the element prose it describes, its version history, and the revocable public link a reader without an account follows. |
|
Package runloop carries Atlas's single-writer boundary for design-time and API state.
|
Package runloop carries Atlas's single-writer boundary for design-time and API state. |
|
Package sidecar is the durable-file discipline Atlas's design-time stores share.
|
Package sidecar is the durable-file discipline Atlas's design-time stores share. |
|
Package token mints and validates Atlas's opaque share tokens.
|
Package token mints and validates Atlas's opaque share tokens. |
|
Package vault is Atlas's engine-internal encrypted secret store: connector credentials sealed at rest with AES-256-GCM under a master key that never leaves the operator's control (ADR-0069), on by default with a generated key file when no operator key is supplied (ADR-0070).
|
Package vault is Atlas's engine-internal encrypted secret store: connector credentials sealed at rest with AES-256-GCM under a master key that never leaves the operator's control (ADR-0069), on by default with a generated key file when no operator key is supplied (ADR-0070). |