Liking cljdoc? Tell your friends :D

wagoe.platform.core.authorization

The permission registry, built from what modules declare (ADR-041 §1–2).

A module contributes under :authorization:

{:permissions {:orders/refund {:label "Refund orders"}} :roles {:orders/viewer {:description "…" :permissions #{:orders/read}}} :scopes {:domain-id {:label "Domain" :entity :domains}} :scope-sources {:user/department {:label "The member's department" :resolve (fn [user] #{7})}}}

<module>/read and <module>/write exist for every module without being declared, and so do the code roles <module>/viewer and <module>/editor holding them, unless the module declares its own. What a scope means is ADR-041 §4, core.scope.

The permission registry, built from what modules declare (ADR-041 §1–2).

A module contributes under `:authorization`:

  {:permissions {:orders/refund {:label "Refund orders"}}
   :roles       {:orders/viewer {:description "…" :permissions #{:orders/read}}}
   :scopes      {:domain-id {:label "Domain" :entity :domains}}
   :scope-sources {:user/department {:label   "The member's department"
                                     :resolve (fn [user] #{7})}}}

`<module>/read` and `<module>/write` exist for every module without being
declared, and so do the code roles `<module>/viewer` and `<module>/editor`
holding them, unless the module declares its own. What a scope means is
ADR-041 §4, `core.scope`.
raw docstring

wagoe.platform.core.circuit-breaker

When to stop calling a service that keeps failing.

Retries bound the damage of one call; this bounds the damage of many. A service that is down still receives every request until each one times out, and every caller pays that timeout. Declining to call is the only thing that stops both.

FC/IS: pure. The state lives elsewhere — see …shell.breaker, which keeps it in the cache so replicas share one breaker rather than each discovering the outage separately.

When to stop calling a service that keeps failing.

Retries bound the damage of one call; this bounds the damage of many. A
service that is down still receives every request until each one times out,
and every caller pays that timeout. Declining to call is the only thing that
stops both.

FC/IS: pure. The state lives elsewhere — see `…shell.breaker`, which
keeps it in the cache so replicas share one breaker rather than each
discovering the outage separately.
raw docstring

wagoe.platform.core.csrf

Pure CSRF token functions — synchronizer token bound to a session.

The token is a signed double-submit value:

token = base64url(nonce) "." base64url(HMAC-SHA256(secret, nonce || binding))

The binding is the value the token is tied to: the user's session token for authenticated requests, or a per-request pre-session cookie value for the login form (which has no session yet). A token is only valid when presented together with the same binding it was signed against, which is what defeats CSRF: an attacker can forge a cross-site request but cannot read the victim's binding to produce a matching token.

Functional Core: these functions are pure and deterministic. The CSPRNG nonce and the secret are produced in the shell and passed in as arguments — nothing here performs I/O or reads ambient state.

Safety parity with ring-anti-forgery: validation uses buddy's mac/verify, which performs a constant-time comparison of the recomputed HMAC, so token checks do not leak timing information.

Enforcement is opt-in at the interceptor level (default off); see wagoe.platform.shell.http.interceptors/http-csrf-protection. Emit the token with hidden-field (server forms) or hx-headers (HTMX elements), or via the

<meta name="csrf-token"> tag + the ui-style init.js htmx:configRequest listener.

Pure CSRF token functions — synchronizer token bound to a session.

The token is a signed double-submit value:

    token = base64url(nonce) "." base64url(HMAC-SHA256(secret, nonce || binding))

The `binding` is the value the token is tied to: the user's session token for
authenticated requests, or a per-request pre-session cookie value for the login
form (which has no session yet). A token is only valid when presented together
with the same binding it was signed against, which is what defeats CSRF: an
attacker can forge a cross-site request but cannot read the victim's binding to
produce a matching token.

Functional Core: these functions are pure and deterministic. The CSPRNG nonce
and the secret are produced in the shell and passed in as arguments — nothing
here performs I/O or reads ambient state.

Safety parity with ring-anti-forgery: validation uses buddy's `mac/verify`,
which performs a constant-time comparison of the recomputed HMAC, so token
checks do not leak timing information.

Enforcement is opt-in at the interceptor level (default off); see
`wagoe.platform.shell.http.interceptors/http-csrf-protection`. Emit the token
with `hidden-field` (server forms) or `hx-headers` (HTMX elements), or via the
<meta name="csrf-token"> tag + the ui-style init.js htmx:configRequest listener.
raw docstring

wagoe.platform.core.http.access

Who may reach a route, and what a refused caller is told.

Every route requires a signed-in user unless its route data carries :public true (BOU-568). A refusal has the shape the user module's require-authenticated interceptor answers with, so a client sees one 401 whichever layer refused it: the one error body of wagoe.platform.core.http.errors (BOU-586). No Content-Type: muuntaja encodes a map body only when none is set (ZZP-120). What needs no HTTP stack lives in wagoe.core.http.access (BOU-930).

Who may reach a route, and what a refused caller is told.

Every route requires a signed-in user unless its route data carries
`:public true` (BOU-568). A refusal has the shape the user module's
`require-authenticated` interceptor answers with, so a client sees one 401
whichever layer refused it: the one error body of
`wagoe.platform.core.http.errors` (BOU-586). No Content-Type: muuntaja encodes a map body
only when none is set (ZZP-120). What needs no HTTP stack lives in
`wagoe.core.http.access` (BOU-930).
raw docstring

wagoe.platform.core.http.client-ip

The address a request came from, as opposed to the proxy that delivered it.

:remote-addr is the peer, which behind a reverse proxy is the proxy. Any client can send X-Forwarded-For, so it is read only when the peer is a trusted proxy, and from the right: each proxy appends the address it saw, so the first hop that is not one of ours is the client.

The address a request came from, as opposed to the proxy that delivered it.

`:remote-addr` is the peer, which behind a reverse proxy is the proxy. Any
client can send X-Forwarded-For, so it is read only when the peer is a
trusted proxy, and from the right: each proxy appends the address it saw,
so the first hop that is not one of ours is the client.
raw docstring

wagoe.platform.core.http.error-pages

What a browser is shown for an error body: a page for a /web request, a toast for an htmx one. An API caller, or a script asking for JSON, keeps the body of wagoe.platform.core.http.errors.

What a browser is shown for an error body: a page for a /web request, a
toast for an htmx one. An API caller, or a script asking for JSON, keeps the
body of `wagoe.platform.core.http.errors`.
raw docstring

wagoe.platform.core.http.errors

The one JSON error body (BOU-586):

{"error": {"type": "not-found", "message": "User not found", "details": {...}, ; optional "correlation-id": "...", ; optional "dev": {...}}} ; optional, dev only (WGE code)

Everything about the failure sits inside error, so a client reads one key. type is a string: the :type keyword of the ex-info, without its colon. The pure part lives in wagoe.core.http.errors (BOU-930); this namespace adds what needs JSON.

The one JSON error body (BOU-586):

  {"error": {"type":           "not-found",
             "message":        "User not found",
             "details":        {...},    ; optional
             "correlation-id": "...",  ; optional
             "dev":            {...}}}   ; optional, dev only (WGE code)

Everything about the failure sits inside `error`, so a client reads one
key. `type` is a string: the `:type` keyword of the ex-info, without its
colon. The pure part lives in `wagoe.core.http.errors` (BOU-930); this
namespace adds what needs JSON.
raw docstring

wagoe.platform.core.http.nav

The sidebar navigation modules contribute, as data.

A module's route contribution may carry :nav, groups by id:

{:user {:label [:t :user/nav-title] :icon :users :entities [:users] ; admin entities this module owns :items [{:href "/web/audit" :label .. :icon :file-text :access :platform-admin :description ..}]}} ; optional, for dashboard cards

An item with :entity (the admin contributes one per entity) is placed by module: its :module, else the group whose :entities names it, else :other. Other items stay in the group that declared them.

The platform binds *nav* around each request, so a page renders the whole sidebar without depending on the modules in it.

The sidebar navigation modules contribute, as data.

A module's route contribution may carry `:nav`, groups by id:

  {:user {:label    [:t :user/nav-title]
          :icon     :users
          :entities [:users]          ; admin entities this module owns
          :items    [{:href "/web/audit" :label .. :icon :file-text
                      :access :platform-admin
                      :description ..}]}}  ; optional, for dashboard cards

An item with `:entity` (the admin contributes one per entity) is placed by
module: its `:module`, else the group whose `:entities` names it, else
`:other`. Other items stay in the group that declared them.

The platform binds `*nav*` around each request, so a page renders the whole
sidebar without depending on the modules in it.
raw docstring

wagoe.platform.core.http.pages

Whether a page is mounted, for layouts deciding what to link to.

Whether a page is mounted, for layouts deciding what to link to.
raw docstring

wagoe.platform.core.http.problem-details

Exceptions to error responses, and the :type -> status table.

The name is historical: these were RFC 7807 bodies until BOU-586 made every JSON error the one shape of wagoe.platform.core.http.errors.

Exceptions to error responses, and the `:type` -> status table.

The name is historical: these were RFC 7807 bodies until BOU-586 made every
JSON error the one shape of `wagoe.platform.core.http.errors`.
raw docstring

wagoe.platform.core.pagination.pagination

Pure functions for pagination logic.

This namespace provides pure functional implementations for pagination calculations, following the Functional Core pattern. All functions are deterministic and side-effect free.

Supports:

  • Offset-based pagination (simple, familiar)
  • Cursor-based pagination (high performance, stable results)
  • Parameter validation
  • Metadata calculation

Pure: All functions return data, no side effects.

Pure functions for pagination logic.

This namespace provides pure functional implementations for pagination calculations,
following the Functional Core pattern. All functions are deterministic and side-effect free.

Supports:
- Offset-based pagination (simple, familiar)
- Cursor-based pagination (high performance, stable results)
- Parameter validation
- Metadata calculation

Pure: All functions return data, no side effects.
raw docstring

wagoe.platform.core.pagination.versioning

Pure functions for API versioning logic.

This namespace provides pure functional implementations for API version management, following the Functional Core pattern. All functions are deterministic and side-effect free.

Supports:

  • Version parsing and comparison
  • Version lifecycle management (experimental → stable → deprecated → sunset)
  • Version validation
  • Migration path tracking

Pure: All functions return data, no side effects.

Pure functions for API versioning logic.

This namespace provides pure functional implementations for API version
management, following the Functional Core pattern. All functions are
deterministic and side-effect free.

Supports:
- Version parsing and comparison
- Version lifecycle management (experimental → stable → deprecated → sunset)
- Version validation
- Migration path tracking

Pure: All functions return data, no side effects.
raw docstring

wagoe.platform.core.privacy

Pure halves of data export and retention: the export document, and which retention policies run with which cutoff.

Pure halves of data export and retention: the export document, and which
retention policies run with which cutoff.
raw docstring

wagoe.platform.core.retry

How long to wait between attempts, and how long a whole run of them can take.

Shared by the RPC client and the libs/external adapters, so a flaky third-party API and a flaky internal service get one policy. Which failures are worth retrying is the caller's call; it knows what a second attempt could repeat.

FC/IS: pure.

How long to wait between attempts, and how long a whole run of them can take.

Shared by the RPC client and the libs/external adapters, so a flaky
third-party API and a flaky internal service get one policy. Which failures
are worth retrying is the caller's call; it knows what a second attempt
could repeat.

FC/IS: pure.
raw docstring

wagoe.platform.core.rpc

Pure RPC envelope handling for the remote-port adapter.

A cross-module call goes through a protocol (ports.clj). Slicing a module into its own process means implementing that same protocol with something that makes a network call instead — the seam is already there, only the adapter is missing (BOU-90, scaling.adoc → Functional decomposition).

This namespace is the wire contract and nothing else: building an envelope, reading one, and turning a remote failure into the error shape callers already handle. No I/O — see wagoe.platform.shell.rpc.client and …rpc.server for that.

FC/IS: pure. Everything here is data in, data out.

Pure RPC envelope handling for the remote-port adapter.

A cross-module call goes through a protocol (`ports.clj`). Slicing a module
into its own process means implementing that same protocol with something
that makes a network call instead — the seam is already there, only the
adapter is missing (BOU-90, scaling.adoc → Functional decomposition).

This namespace is the wire contract and nothing else: building an envelope,
reading one, and turning a remote failure into the error shape callers
already handle. No I/O — see `wagoe.platform.shell.rpc.client` and
`…rpc.server` for that.

FC/IS: pure. Everything here is data in, data out.
raw docstring

wagoe.platform.core.scope

Scopes on rights (ADR-041 §4).

The user module hands over a user's rights as [{:permission kw :scope nil-or-{key value}}], each value fixed or a :user/<name> source. Resolved (shell.authorization/resolve-rights), a scope is {key #{value}}, and {} holds everywhere. Rights add up: a permission is held in each of its scopes.

Safe by default: a scope admits only where every one of its keys is checked.

Scopes on rights (ADR-041 §4).

The user module hands over a user's rights as
`[{:permission kw :scope nil-or-{key value}}]`, each value fixed or a
`:user/<name>` source. Resolved (`shell.authorization/resolve-rights`), a
scope is `{key #{value}}`, and `{}` holds everywhere. Rights add up: a
permission is held in each of its scopes.

Safe by default: a scope admits only where every one of its keys is checked.
raw docstring

wagoe.platform.core.system-selection

Cut an Integrant config down to the modules one service runs.

Modules are already gated by :enabled?, and the router mounts only the routes it is handed, so a process can run a subset — there was just no way to say which subset (BOU-91). This is that, as a pure transformation: config in, smaller config out.

The whole difficulty is refs. Dropping :wagoe/tenant-service leaves :wagoe/http-handler pointing at a key that no longer exists, and Integrant refuses to build a config with a dangling ref — so the refs have to go with the keys, and they have to go first, or the closure that works out what is still needed follows them straight back to everything.

FC/IS: pure. Nothing here starts, stops or reads anything.

Cut an Integrant config down to the modules one service runs.

Modules are already gated by `:enabled?`, and the router mounts only the
routes it is handed, so a process *can* run a subset — there was just no way
to say which subset (BOU-91). This is that, as a pure transformation:
config in, smaller config out.

The whole difficulty is refs. Dropping `:wagoe/tenant-service` leaves
`:wagoe/http-handler` pointing at a key that no longer exists, and Integrant
refuses to build a config with a dangling ref — so the refs have to go with
the keys, and they have to go *first*, or the closure that works out what is
still needed follows them straight back to everything.

FC/IS: pure. Nothing here starts, stops or reads anything.
raw docstring

wagoe.platform.ports.authorization

The permission registry: every permission, code role and scope key the enabled modules declare or derive. Built once at boot as :wagoe/permission-registry; nothing outside it can be granted.

The permission registry: every permission, code role and scope key the
enabled modules declare or derive. Built once at boot as
`:wagoe/permission-registry`; nothing outside it can be granted.
raw docstring

wagoe.platform.ports.http

The HTTP server port.

Routing is not a port: modules emit Reitit route data and the platform compiles it (ADR-037). The server is — a Ring handler is handed to whatever implements this protocol.

The HTTP server port.

Routing is not a port: modules emit Reitit route data and the platform
compiles it (ADR-037). The server is — a Ring handler is handed to whatever
implements this protocol.
raw docstring

wagoe.platform.resilience

Retry and circuit breaker for outbound calls — the RPC client and the libs/external adapters both go through here.

Outside shell/ for the reason wagoe.platform.database is: other modules call it, and reaching into platform's shell is what bb check:ports refuses.

Both take predicates over a result rather than deciding what counts as a failure. Only the caller knows whether a second attempt could run something twice.

Retry and circuit breaker for outbound calls — the RPC client and the
libs/external adapters both go through here.

Outside `shell/` for the reason `wagoe.platform.database` is: other modules
call it, and reaching into platform's shell is what `bb check:ports` refuses.

Both take predicates over a result rather than deciding what counts as a
failure. Only the caller knows whether a second attempt could run something
twice.
raw docstring

wagoe.platform.shell.adapters.filesystem.core

File system adapter implementation for local filesystem operations.

Provides concrete implementation of IFileSystemAdapter protocol using Java I/O for local filesystem access.

File system adapter implementation for local filesystem operations.

Provides concrete implementation of IFileSystemAdapter protocol
using Java I/O for local filesystem access.
raw docstring

wagoe.platform.shell.adapters.filesystem.protocols

Protocol defining the common interface for filesystem adapters.

This protocol abstracts filesystem operations to enable testing with in-memory implementations and support different storage backends (local FS, cloud storage, etc.).

Design Philosophy:

  • Protocol defines generic file operations
  • Implementations handle specific storage backends
  • Enables testing without actual filesystem I/O
  • Supports multiple storage strategies (local, cloud, in-memory)
Protocol defining the common interface for filesystem adapters.

This protocol abstracts filesystem operations to enable testing
with in-memory implementations and support different storage
backends (local FS, cloud storage, etc.).

Design Philosophy:
- Protocol defines generic file operations
- Implementations handle specific storage backends
- Enables testing without actual filesystem I/O
- Supports multiple storage strategies (local, cloud, in-memory)
raw docstring

wagoe.platform.shell.authorization

:wagoe/permission-registry: the registry core.authorization builds, behind IPermissionRegistry, the scope check of a route (ADR-041 §4) and the authorization interceptor that runs both (§5). Read it at the REPL with

(ports/permissions (get (wagoe.platform.shell.system.wiring/system) :wagoe/permission-registry))

`:wagoe/permission-registry`: the registry `core.authorization` builds,
behind `IPermissionRegistry`, the scope check of a route (ADR-041 §4) and
the authorization interceptor that runs both (§5).
Read it at the REPL with

  (ports/permissions (get (wagoe.platform.shell.system.wiring/system)
                          :wagoe/permission-registry))
raw docstring

wagoe.platform.shell.breaker

Circuit-breaker state, kept where every replica can see it.

A breaker in one JVM's atom protects that JVM. With N replicas a failing service gets N breakers, each of which has to trip on its own, so it still takes N times the load — and when the window elapses, all N probe at once, which is the stampede the breaker was meant to prevent. Keeping the state in the cache port makes it one breaker.

The cache adapter decides how far that goes: Redis shares it across replicas, the in-memory one does not. That is the same trade the rate limiter makes, and it is a property of the adapter rather than of this namespace.

circuit names what is being protected: the RPC client passes rpc: plus the service URL, the external adapters their kind and host.

Circuit-breaker state, kept where every replica can see it.

A breaker in one JVM's atom protects that JVM. With N replicas a failing
service gets N breakers, each of which has to trip on its own, so it still
takes N times the load — and when the window elapses, all N probe at once,
which is the stampede the breaker was meant to prevent. Keeping the state in
the cache port makes it one breaker.

The cache adapter decides how far that goes: Redis shares it across
replicas, the in-memory one does not. That is the same trade the rate
limiter makes, and it is a property of the adapter rather than of this
namespace.

`circuit` names what is being protected: the RPC client passes `rpc:` plus
the service URL, the external adapters their kind and host.
raw docstring

wagoe.platform.shell.feature-flags

Reading feature flags from the process environment.

wagoe.core.config.feature-flags decides what a flag means, given an environment map. This namespace is the one line that fetches the map, and it lives in a shell because reading System/getenv is I/O — ambient input that changes the answer without changing the arguments.

Both halves used to be in the core namespace, whose docstring promised no side effects while five of its functions called (System/getenv) in a convenience arity (BOU-302).

Reading feature flags from the process environment.

`wagoe.core.config.feature-flags` decides what a flag means, given an
environment map. This namespace is the one line that fetches the map, and it
lives in a shell because reading `System/getenv` is I/O — ambient input that
changes the answer without changing the arguments.

Both halves used to be in the core namespace, whose docstring promised no
side effects while five of its functions called `(System/getenv)` in a
convenience arity (BOU-302).
raw docstring

wagoe.platform.shell.http.flash

Ring flash in a cookie, not the Ring session: :session is the user module's database session. Unsigned, since only toast text is read back.

Ring flash in a cookie, not the Ring session: `:session` is the user
module's database session. Unsigned, since only toast text is read back.
raw docstring

wagoe.platform.shell.http.interceptors

HTTP interceptor pipeline for Ring request/response processing.

This namespace provides an HTTP-specific interceptor chain that runs over Ring handlers, giving Pedestal-like enter/leave/error semantics while maintaining Ring compatibility.

Key Benefits:

  • Consistent cross-layer observability (HTTP → service → persistence)
  • Declarative per-route policies (auth, rate-limit, auditing)
  • Clean separation of concerns (routing vs cross-cutting logic)
  • Reusable interceptor components across routes

HTTP Context Model: {:request Ring request map :response Ring response map (built up through pipeline) :route Route metadata from Reitit match :path-params Extracted path parameters :query-params Extracted query parameters :system Observability services {:logger :metrics-emitter :error-reporter} :attrs Additional attributes set by interceptors :correlation-id Unique request ID :started-at Request start timestamp}

Interceptor Shape: {:name :my-interceptor :enter (fn [context] ...) ; Process request, modify context :leave (fn [context] ...) ; Process response, modify context :error (fn [context] ...)} ; Handle exceptions, produce safe response

Usage: ;; As Ring middleware (global) (def handler (-> app-handler (wrap-http-interceptors [logging metrics error-reporting])))

;; Per-route via Reitit :middleware {:get {:handler my-handler :middleware [(interceptor-middleware [auth rate-limit])]}}

Route data may also carry an :interceptors vector; when the routes are compiled, it becomes :middleware running through this same runner.

HTTP interceptor pipeline for Ring request/response processing.

This namespace provides an HTTP-specific interceptor chain that runs over Ring handlers,
giving Pedestal-like enter/leave/error semantics while maintaining Ring compatibility.

Key Benefits:
- Consistent cross-layer observability (HTTP → service → persistence)
- Declarative per-route policies (auth, rate-limit, auditing)
- Clean separation of concerns (routing vs cross-cutting logic)
- Reusable interceptor components across routes

HTTP Context Model:
{:request       Ring request map
 :response      Ring response map (built up through pipeline)
 :route         Route metadata from Reitit match
 :path-params   Extracted path parameters
 :query-params  Extracted query parameters
 :system        Observability services {:logger :metrics-emitter :error-reporter}
 :attrs         Additional attributes set by interceptors
 :correlation-id Unique request ID
 :started-at    Request start timestamp}

Interceptor Shape:
{:name   :my-interceptor
 :enter  (fn [context] ...) ; Process request, modify context
 :leave  (fn [context] ...) ; Process response, modify context
 :error  (fn [context] ...)} ; Handle exceptions, produce safe response

Usage:
;; As Ring middleware (global)
(def handler
  (-> app-handler
      (wrap-http-interceptors [logging metrics error-reporting])))

;; Per-route via Reitit :middleware
{:get {:handler my-handler
       :middleware [(interceptor-middleware [auth rate-limit])]}}

Route data may also carry an :interceptors vector; when the routes are
compiled, it becomes :middleware running through this same runner.
raw docstring

wagoe.platform.shell.http.pages

Asks the request's router which pages are mounted.

Asks the request's router which pages are mounted.
raw docstring

wagoe.platform.shell.http.reitit-router

Compiles the application's route data into a Ring handler.

Modules emit Reitit route data and this namespace hands it to Reitit (ADR-037), so what is left here is behaviour rather than translation: exception handling, the coercion error shape, the OpenAPI routes, gzip, and the interceptor stack each route is decorated with.

Compiles the application's route data into a Ring handler.

Modules emit Reitit route data and this namespace hands it to Reitit
(ADR-037), so what is left here is behaviour rather than translation:
exception handling, the coercion error shape, the OpenAPI routes, gzip, and
the interceptor stack each route is decorated with.
raw docstring

wagoe.platform.shell.http.ring-jetty-server

Ring+Jetty server adapter - manages HTTP server lifecycle using Ring and Jetty.

This adapter implements the IHttpServer protocol to start and stop Jetty-based HTTP servers with Ring handlers.

Ring+Jetty server adapter - manages HTTP server lifecycle using Ring and Jetty.

This adapter implements the IHttpServer protocol to start and stop Jetty-based
HTTP servers with Ring handlers.
raw docstring

wagoe.platform.shell.http.versioning

HTTP API versioning support - wraps routes with version prefixes and headers.

SIDE EFFECTS:

  • Route transformation
  • Response header modification
  • Logging

Provides URL-based versioning (/api/v1/users, /api/v2/users) with:

  • Automatic version prefix wrapping
  • Version header injection (X-API-Version, X-API-Latest, X-API-Deprecated)
  • Backward compatibility (/api/users → /api/v1/users redirect)
  • Multiple version support concurrently
HTTP API versioning support - wraps routes with version prefixes and headers.

SIDE EFFECTS:
- Route transformation
- Response header modification
- Logging

Provides URL-based versioning (/api/v1/users, /api/v2/users) with:
- Automatic version prefix wrapping
- Version header injection (X-API-Version, X-API-Latest, X-API-Deprecated)
- Backward compatibility (/api/users → /api/v1/users redirect)
- Multiple version support concurrently
raw docstring

wagoe.platform.shell.interceptors

Universal interceptors for cross-cutting concerns.

These interceptors handle common infrastructure concerns like logging, metrics, error handling, and context management across all modules.

Universal interceptors for cross-cutting concerns.

These interceptors handle common infrastructure concerns like logging,
metrics, error handling, and context management across all modules.
raw docstring

wagoe.platform.shell.interfaces.cli.commands

No vars found in this namespace.

wagoe.platform.shell.interfaces.cli.main

No vars found in this namespace.

wagoe.platform.shell.interfaces.cli.middleware

CLI middleware for command execution with enhanced error context (imperative shell).

This namespace provides reusable CLI middleware that can be used across different modules and applications for consistent observability and error handling in command-line interfaces.

Middleware functions handle CLI boundaries: command execution interception, context generation, logging, and exception handling with enhanced context preservation for debugging.

Features:

  • Command correlation ID generation
  • Tenant and user context extraction from config/environment
  • Structured command execution logging with observability context
  • Command timing and error reporting with enhanced context
  • Error reporting breadcrumb integration
CLI middleware for command execution with enhanced error context (imperative shell).

This namespace provides reusable CLI middleware that can be used across
different modules and applications for consistent observability and
error handling in command-line interfaces.

Middleware functions handle CLI boundaries: command execution interception,
context generation, logging, and exception handling with enhanced context
preservation for debugging.

Features:
- Command correlation ID generation
- Tenant and user context extraction from config/environment
- Structured command execution logging with observability context
- Command timing and error reporting with enhanced context
- Error reporting breadcrumb integration
raw docstring

wagoe.platform.shell.interfaces.cli.parsing

No vars found in this namespace.

wagoe.platform.shell.interfaces.http.common

Common HTTP utilities: error responses in the one error shape (wagoe.platform.core.http.errors) and health checks.

The pure transformations are in wagoe.platform.core.http.problem-details.

Common HTTP utilities: error responses in the one error shape
(`wagoe.platform.core.http.errors`) and health checks.

The pure transformations are in wagoe.platform.core.http.problem-details.
raw docstring

wagoe.platform.shell.interfaces.web.sse

No vars found in this namespace.

wagoe.platform.shell.interfaces.web.websockets

No vars found in this namespace.

wagoe.platform.shell.modules

Module registry and composition helpers for the Wagoe shell.

This namespace provides utilities to:

  • Determine which modules are enabled based on configuration.
  • Compose route definitions from multiple modules.
  • Dispatch CLI commands to module-specific runners.

For now, only the :user module is supported.

Module registry and composition helpers for the Wagoe shell.

This namespace provides utilities to:
- Determine which modules are enabled based on configuration.
- Compose route definitions from multiple modules.
- Dispatch CLI commands to module-specific runners.

For now, only the `:user` module is supported.
raw docstring

wagoe.platform.shell.pagination.cursor

Shell layer cursor encoding/decoding for cursor-based pagination.

SIDE EFFECTS:

  • JSON encoding/decoding
  • Base64 encoding/decoding
  • Exception throwing on invalid cursors

Cursors are opaque tokens that encode:

  • Item ID (for stable ordering)
  • Sort field value (for comparison)
  • Sort direction (asc/desc)
  • Optional timestamp (for expiry)

Format: Base64(JSON({:id ... :sort-value ... :sort-field ... :sort-direction ...}))

Shell layer cursor encoding/decoding for cursor-based pagination.

SIDE EFFECTS:
- JSON encoding/decoding
- Base64 encoding/decoding
- Exception throwing on invalid cursors

Cursors are opaque tokens that encode:
- Item ID (for stable ordering)
- Sort field value (for comparison)
- Sort direction (asc/desc)
- Optional timestamp (for expiry)

Format: Base64(JSON({:id ... :sort-value ... :sort-field ... :sort-direction ...}))
raw docstring

wagoe.platform.shell.pagination.link-headers

Shell layer RFC 5988 Link header generation for pagination.

RFC 5988: Web Linking https://datatracker.ietf.org/doc/html/rfc5988

SIDE EFFECTS:

  • String building and URL encoding
  • Logging

Link headers provide hypermedia controls for pagination navigation. They allow clients to discover next, prev, first, and last pages without parsing response bodies.

Format: Link: </api/v1/users?limit=20&offset=20>; rel="next", </api/v1/users?limit=20&offset=0>; rel="first", </api/v1/users?limit=20&offset=980>; rel="last"

Supported Relations:

  • first: First page of results
  • last: Last page of results (offset pagination only)
  • prev: Previous page
  • next: Next page
  • self: Current page
Shell layer RFC 5988 Link header generation for pagination.

RFC 5988: Web Linking
https://datatracker.ietf.org/doc/html/rfc5988

SIDE EFFECTS:
- String building and URL encoding
- Logging

Link headers provide hypermedia controls for pagination navigation.
They allow clients to discover next, prev, first, and last pages without
parsing response bodies.

Format:
Link: </api/v1/users?limit=20&offset=20>; rel="next",
      </api/v1/users?limit=20&offset=0>; rel="first",
      </api/v1/users?limit=20&offset=980>; rel="last"

Supported Relations:
- first: First page of results
- last: Last page of results (offset pagination only)
- prev: Previous page
- next: Next page
- self: Current page
raw docstring

wagoe.platform.shell.persistence-interceptors

Persistence-level interceptors for database operations.

This namespace provides interceptor pipelines specifically designed for persistence layer operations, eliminating manual observability calls and providing consistent error handling, logging, and error reporting across all database operations.

Key Benefits:

  • Eliminates 40+ manual observability calls from persistence methods
  • Provides consistent database error handling patterns
  • Automatic timing and logging for all database operations
  • Single point of control for persistence-level cross-cutting concerns

Usage: (execute-persistence-operation :find-user-by-id {:user-id user-id} db-impl-fn {:system system})

Architecture:

  • Persistence interceptors wrap database operations
  • Context carries operation metadata and database context
  • Interceptors handle all database-related cross-cutting concerns automatically
Persistence-level interceptors for database operations.

This namespace provides interceptor pipelines specifically designed for persistence layer operations,
eliminating manual observability calls and providing consistent error handling, logging, and 
error reporting across all database operations.

Key Benefits:
- Eliminates 40+ manual observability calls from persistence methods
- Provides consistent database error handling patterns
- Automatic timing and logging for all database operations
- Single point of control for persistence-level cross-cutting concerns

Usage:
  (execute-persistence-operation 
    :find-user-by-id 
    {:user-id user-id}
    db-impl-fn
    {:system system})

Architecture:
- Persistence interceptors wrap database operations
- Context carries operation metadata and database context
- Interceptors handle all database-related cross-cutting concerns automatically
raw docstring

wagoe.platform.shell.privacy

Data export and retention over what modules contribute: :data-export exporters and :retention policies (wagoe.platform.ports.privacy).

Retention is off until :wagoe/privacy :retention names a policy, and then runs as the recurring job retention-job-type on :wagoe/jobs:

:wagoe/privacy {:retention {:user/audit-log {:retain "P2Y"}} :retention-schedule {:cron "0 3 * * *" :zone "UTC"}}

Data export and retention over what modules contribute: `:data-export`
exporters and `:retention` policies (`wagoe.platform.ports.privacy`).

Retention is off until `:wagoe/privacy :retention` names a policy, and then
runs as the recurring job `retention-job-type` on `:wagoe/jobs`:

  :wagoe/privacy {:retention          {:user/audit-log {:retain "P2Y"}}
                  :retention-schedule {:cron "0 3 * * *" :zone "UTC"}}
raw docstring

wagoe.platform.shell.reported-errors

The throwables already sent to the error tracker, so a 5xx that crosses a service and then the HTTP layer is reported once (BOU-714). Keys are weak: remembering a throwable does not keep it alive.

The throwables already sent to the error tracker, so a 5xx that crosses a
service and then the HTTP layer is reported once (BOU-714). Keys are weak:
remembering a throwable does not keep it alive.
raw docstring

wagoe.platform.shell.rpc.client

Generic remote-port adapter: implement any module protocol over HTTP.

Cross-module calls go through a protocol, so slicing a module into its own process needs one thing the codebase did not have — an implementation of that protocol that makes a network call. This builds one for an arbitrary protocol, so the caller keeps calling (ports/create-checkout-session svc …) and does not learn that the answer now comes over a socket (BOU-90).

Modelled on libs/external's outbound adapters: clj-http, :throw-exceptions false, errors as data rather than exceptions.

FC/IS: shell. The wire contract is pure and lives in wagoe.platform.core.rpc.

Generic remote-port adapter: implement any module protocol over HTTP.

Cross-module calls go through a protocol, so slicing a module into its own
process needs one thing the codebase did not have — an implementation of
that protocol that makes a network call. This builds one for an arbitrary
protocol, so the caller keeps calling `(ports/create-checkout-session svc …)`
and does not learn that the answer now comes over a socket (BOU-90).

Modelled on libs/external's outbound adapters: clj-http, `:throw-exceptions
false`, errors as data rather than exceptions.

FC/IS: shell. The wire contract is pure and lives in
`wagoe.platform.core.rpc`.
raw docstring

wagoe.platform.shell.rpc.server

Expose a module's protocol over HTTP, so another process can call it.

The counterpart to …rpc.client: that turns protocol calls into requests, this turns requests back into protocol calls against the local implementation. Together they are what lets a module run as its own service without its callers changing (BOU-90).

FC/IS: shell. The envelope contract is pure and lives in wagoe.platform.core.rpc.

Expose a module's protocol over HTTP, so another process can call it.

The counterpart to `…rpc.client`: that turns protocol calls into requests,
this turns requests back into protocol calls against the local
implementation. Together they are what lets a module run as its own service
without its callers changing (BOU-90).

FC/IS: shell. The envelope contract is pure and lives in
`wagoe.platform.core.rpc`.
raw docstring

wagoe.platform.shell.service-interceptors

Service-level interceptors for business logic operations.

This namespace provides interceptor pipelines specifically designed for service layer operations, eliminating manual observability calls and providing consistent error handling, logging, metrics, and error reporting across all service methods.

Key Benefits:

  • Eliminates 50+ manual observability calls from service methods
  • Provides consistent error handling and reporting patterns
  • Automatic timing, logging, and metrics collection
  • Single point of control for service-level cross-cutting concerns

Usage: (execute-service-operation :register-user {:user-data user-data :tenant-id tenant-id} service-impl-fn {:system system})

Architecture:

  • Service interceptors wrap pure business logic functions
  • Context carries operation metadata and observability services
  • Interceptors handle all cross-cutting concerns automatically
Service-level interceptors for business logic operations.

This namespace provides interceptor pipelines specifically designed for service layer operations,
eliminating manual observability calls and providing consistent error handling, logging, metrics,
and error reporting across all service methods.

Key Benefits:
- Eliminates 50+ manual observability calls from service methods
- Provides consistent error handling and reporting patterns
- Automatic timing, logging, and metrics collection
- Single point of control for service-level cross-cutting concerns

Usage:
  (execute-service-operation 
    :register-user 
    {:user-data user-data :tenant-id tenant-id}
    service-impl-fn
    {:system system})

Architecture:
- Service interceptors wrap pure business logic functions
- Context carries operation metadata and observability services
- Interceptors handle all cross-cutting concerns automatically
raw docstring

wagoe.platform.shell.system.authorization-report

authz-report: the route table as :wagoe/authorization :enforce would judge it, printed without serving. Builds :wagoe/http-handler and what it depends on, never :wagoe/http-server, so it binds no port; the database and the modules still start, as the routes need them, and so do the migrations a config runs at start.

`authz-report`: the route table as `:wagoe/authorization :enforce` would
judge it, printed without serving. Builds `:wagoe/http-handler` and what it
depends on, never `:wagoe/http-server`, so it binds no port; the database
and the modules still start, as the routes need them, and so do the
migrations a config runs at start.
raw docstring

wagoe.platform.shell.system.config

Assemble an Integrant system from a loaded configuration map.

This is the half of wagoe.system-config that is the same in every application: the components every Wagoe app has (database, HTTP, router, observability, i18n), the framework modules its config switches on, and the modules bb scaffold generate produced. What is left for the application is what only it knows — see the generated config.clj.

Before BOU-326 this lived in the generated file, 404 lines of it, and a second copy lived in this repository's own src/wagoe/system_config.clj. Neither copy wired :wagoe/workflow-db-schema, so wagoe add workflow produced a module whose tables were never created.

Usage: (system-config (config/load-config) {:base-ns "shop"})

Assemble an Integrant system from a loaded configuration map.

This is the half of `wagoe.system-config` that is the same in every
application: the components every Wagoe app has (database, HTTP, router,
observability, i18n), the framework modules its config switches on, and the
modules `bb scaffold generate` produced. What is left for the application is
what only it knows — see the generated `config.clj`.

Before BOU-326 this lived in the generated file, 404 lines of it, and a
second copy lived in this repository's own `src/wagoe/system_config.clj`.
Neither copy wired `:wagoe/workflow-db-schema`, so `wagoe add workflow`
produced a module whose tables were never created.

Usage:
  (system-config (config/load-config) {:base-ns "shop"})
raw docstring

wagoe.platform.shell.system.wiring

Integrant system lifecycle management for Wagoe application.

This namespace defines init-key and halt-key! multimethods for all system components, providing proper lifecycle management and dependency injection for the entire application.

Components:

  • :wagoe/db-context - Database connection pool and adapter
  • :wagoe/user-repository - User data persistence
  • :wagoe/session-repository - Session data persistence
  • :wagoe/user-service - User business logic orchestration
  • :wagoe/logging - Structured logging and audit trails
  • :wagoe/metrics - Application and business metrics collection
  • :wagoe/error-reporting - Error tracking and alerting
  • :wagoe/http-handler - HTTP request routing and handling
  • :wagoe/http-server - Jetty HTTP server

Usage: (require '[wagoe.config :as config]) (require '[wagoe.system-config :as sys-config]) ; your application's (require '[integrant.core :as ig]) (def cfg (sys-config/ig-config (config/load-config))) (def system (ig/init cfg)) (ig/halt! system)

Integrant system lifecycle management for Wagoe application.

This namespace defines init-key and halt-key! multimethods for all
system components, providing proper lifecycle management and dependency
injection for the entire application.

Components:
- :wagoe/db-context - Database connection pool and adapter
- :wagoe/user-repository - User data persistence
- :wagoe/session-repository - Session data persistence
- :wagoe/user-service - User business logic orchestration
- :wagoe/logging - Structured logging and audit trails
- :wagoe/metrics - Application and business metrics collection
- :wagoe/error-reporting - Error tracking and alerting
- :wagoe/http-handler - HTTP request routing and handling
- :wagoe/http-server - Jetty HTTP server

Usage:
  (require '[wagoe.config :as config])
  (require '[wagoe.system-config :as sys-config])   ; your application's
  (require '[integrant.core :as ig])
  (def cfg (sys-config/ig-config (config/load-config)))
  (def system (ig/init cfg))
  (ig/halt! system)
raw docstring

wagoe.platform.shell.utils.error-handling

Error handling utilities for enhanced context preservation and structured error responses.

This namespace provides middleware and utilities for capturing rich error context across HTTP and CLI interfaces, enabling better debugging and observability.

Error handling utilities for enhanced context preservation and structured error responses.

This namespace provides middleware and utilities for capturing rich error context
across HTTP and CLI interfaces, enabling better debugging and observability.
raw docstring

wagoe.platform.shell.utils.logging

No vars found in this namespace.

wagoe.platform.shell.utils.metrics

No vars found in this namespace.

wagoe.platform.shell.utils.monitoring

No vars found in this namespace.

wagoe.platform.shell.utils.port-manager

Port management utilities for development environment.

Provides port conflict resolution, environment detection, and intelligent port allocation for different development scenarios.

Port management utilities for development environment.

Provides port conflict resolution, environment detection,
and intelligent port allocation for different development scenarios.
raw docstring

wagoe.platform.shell.utils.time

The clock, read once per library rather than once per namespace.

current-timestamp was defined identically in utils.error-handling and interfaces.http.middleware (BOU-302).

A shell namespace, because reading a clock is the shell's job: core functions take the instant as an argument.

The clock, read once per library rather than once per namespace.

`current-timestamp` was defined identically in `utils.error-handling` and
`interfaces.http.middleware` (BOU-302).

A shell namespace, because reading a clock is the shell's job: core
functions take the instant as an argument.
raw docstring

wagoe.platform.shell.validation-registry

Stateful in-process registry of validation rules.

Holds mutable process state (the rule registry and execution-tracking atoms), so it lives in the shell — the functional core (wagoe.core.validation.registry) keeps only the pure rule-shape and conflict helpers. Provides registration, lookup, and coverage tracking for validation rules across modules.

Rule format: see wagoe.core.validation.registry.

Stateful in-process registry of validation rules.

Holds mutable process state (the rule registry and execution-tracking atoms),
so it lives in the shell — the functional core
(wagoe.core.validation.registry) keeps only the pure rule-shape and
conflict helpers. Provides registration, lookup, and coverage tracking for
validation rules across modules.

Rule format: see wagoe.core.validation.registry.
raw docstring

wagoe.platform.shell.web.table

Shared helpers for table sorting, pagination, and basic search filters across web UIs.

This namespace centralizes parsing of table-related query parameters so that all modules use the same semantics for sorting and paging. It also provides small helpers for generic search/filter parameters that feature modules can interpret according to their own needs.

TableQuery shape: {:sort :name ; keyword column identifier (or default) :dir :asc ; :asc or :desc :page 1 ; 1-based page index :page-size 20 ; items per page :offset 0 ; derived from page/page-size :limit 20} ; derived from page-size

Shared helpers for table sorting, pagination, and basic search filters across web UIs.

This namespace centralizes parsing of table-related query parameters so that
all modules use the same semantics for sorting and paging. It also provides
small helpers for generic search/filter parameters that feature modules can
interpret according to their own needs.

TableQuery shape:
{:sort      :name        ; keyword column identifier (or default)
 :dir       :asc         ; :asc or :desc
 :page      1            ; 1-based page index
 :page-size 20           ; items per page
 :offset    0            ; derived from page/page-size
 :limit     20}         ; derived from page-size
raw docstring

wagoe.platform.system

Reading the running system — platform's introspection API.

The sanctioned surface for a tool that needs to know what is running. Development tooling used to answer that from integrant.repl.state/system, which only a REPL (go) fills, so a server started by wagoe.main was invisible to it: the dev dashboard reported three components for a system of forty-three (BOU-400). The system has always been recorded — in wagoe.platform.shell.system.wiring, which is platform's shell, and naming it from another module is the violation bb check:ports exists to catch.

Same shape as wagoe.platform.database, and for the same reason: a narrow non-shell namespace over machinery that stays internal (BOU-303).

Read-only on purpose. Starting and stopping a system is a composition root's job — wagoe.main and the REPL both call wiring/start! directly, and they are the two places allowed to.

Reading the running system — platform's introspection API.

The sanctioned surface for a tool that needs to know what is running.
Development tooling used to answer that from `integrant.repl.state/system`,
which only a REPL `(go)` fills, so a server started by `wagoe.main` was
invisible to it: the dev dashboard reported three components for a system of
forty-three (BOU-400). The system has always been recorded — in
`wagoe.platform.shell.system.wiring`, which is platform's shell, and naming
it from another module is the violation `bb check:ports` exists to catch.

Same shape as `wagoe.platform.database`, and for the same reason: a narrow
non-shell namespace over machinery that stays internal (BOU-303).

Read-only on purpose. Starting and stopping a system is a composition root's
job — `wagoe.main` and the REPL both call `wiring/start!` directly, and they
are the two places allowed to.
raw docstring

wagoe.platform.throttle

Logging a repeating event once per interval, by key. Outside shell/ so other modules can call it, as wagoe.platform.database.

Logging a repeating event once per interval, by key. Outside `shell/` so
other modules can call it, as `wagoe.platform.database`.
raw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close