appcore-gateway 1.0.0

Multi-tenant Gateway capability for the AppCore Runtime.
Documentation

AppCore Gateway

English guide | Guia em português | Guide français

This crate implements the Gateway Capability of the AppCore Runtime.

The Gateway provides multi-tenant secure Internet access to AppCore application workers without directly exposing the workers.

Architecture

Browser / Client
      │
HTTPS / WebSocket (JSON PeerRpcEnvelope / PeerRpcResponse)
      │
*.<deployment-domain>
      │
AppCore Gateway
      │
WebSocket / RPC / mesh-relay
      │
Workers

The gateway domain is deployment-specific. Each deployer configures its own domain_suffix through GatewayConfig::new(bind_address, "gateway.example.com"). An incoming request to tenant-a.gateway.example.com resolves to TenantId("tenant-a").

Runtime composition

appcore-bin is the composition root. A deployment enables this crate with the existing adapter map:

[adapters.gateway]
provider_id = "appcore-gateway"
settings = { bind_address = "127.0.0.1:8080", domain_suffix = "gateway.example.com", heartbeat_interval_ms = "30000", heartbeat_timeout_ms = "90000" }
secret_refs = {}

Cluster deployments must also point every Gateway instance at the same process-safe replay file at an absolute path on a shared writable volume:

paths = { gateway_replay = "/shared/appcore/gateway-connection-jti.json" }

The adapter accepts only the four settings above. It rejects endpoints, secret references, unknown settings and attempts to configure authentication. Authentication always remains enabled for manifest-composed instances.

During bootstrap, the host adds the owner-defined runtime.gateway capability to the catalog, authorizes it through RuntimeCapabilityPolicy, reuses the Runtime security provider and registers the Gateway as a critical Supervisor-managed service. Invalid configuration or a bind failure aborts startup; omitting adapters.gateway creates no listener or task.

Key Responsibilities

  1. Connection Management: Multiplexes and holds WebSocket connections from workers and clients.
  2. Authentication: Validates workers and clients cryptographically using appcore-security and appcore-types (Tenant boundaries).
  3. Multi-Tenant Routing: Partitions all lookups and connections strictly by TenantId. Connections never cross tenant boundaries.
  4. Presence and Heartbeats: Tracks active workers and capability registrations. Prunes stale nodes.
  5. Mesh Relay: Carries logical Peer RPC HTTP requests over outbound-only worker connections.
  6. Bounded Backpressure: Uses fixed outbound frame queues per connection.
  7. No Business Logic: Only acts as a secure envelope relay, knowing nothing of business schemas, databases, or application logic.

Connection authentication

Authenticated upgrades accept credentials only through the Authorization: Bearer ... header. Query-string credentials are rejected. A worker supplies cluster, installation, core and bounded capabilities; a client supplies cluster and device. Use worker_connection_hash or client_connection_hash as the request_hash of a short-lived peer token issued with a unique jti. The token is single-use and may live for at most 60 seconds. The resulting socket expires with the token.

The mesh relay parses only the Peer RPC transport envelope. It checks request ID, tenant, target Core, cluster, capability, payload digest and signed request hash before selecting a worker. It never interprets the opaque application payload.

Frames and messages are limited to 4 MiB. Tenant, connection, capability, pending-request, timeout, queue and concurrent-routing limits fail closed. Heartbeat text must exactly match the versioned heartbeat JSON shape.

Scope

mesh-relay is a peer transport profile for Cores that can make outbound Gateway connections but cannot expose stable ports or IPs. This crate is not a consensus system, TLS terminator or production secret manager. Gateway clustering, edge relays and alternative transports remain future provider/transport work and must preserve Peer RPC authentication, expiry, nonce and replay protection.

The Runtime host persists one-use connection identities through the process-safe FilePeerNonceStore. Standalone uses private Runtime storage; cluster mode requires an absolute paths.gateway_replay on one shared writable volume and fails closed when it is absent or unavailable. Active sockets expire with their credentials after at most 60 seconds. Direct embedders use a process-local bounded store by default or inject a durable/shared PeerNonceStore through GatewayState::with_replay_store or GatewayRuntime::with_replay_store. Source-IP rate limiting and TLS termination remain deployment/edge controls.

GatewayRuntime owns the listener, runtime thread, router and heartbeat pruner. stop first requests graceful shutdown, then drops the server future before the deadline to force-close incomplete connections and joins the runtime thread. Orphaned remains a defensive quarantine state for an unexpected thread-level failure, not the normal timeout path. Its snapshot never exposes credentials or token material. Lower-level embedders that call spawn_heartbeat_pruner directly own and must await its returned join handle.

Worker and client connection hashes use canonical V2 binary framing and carry a v2: marker. Earlier unversioned hashes are not interchangeable; token issuers and Gateway consumers must be upgraded together.