Set Up a RECAP Server

RECAP can run behind a local or remote server. In both cases, the server owns the database and clients connect with RecapClient.from_url(). Authenticated REST query endpoints serve reads and counts; REST command endpoints handle creates, updates, and copies.

This guide documents the currently runnable single-user API-key deployment. Multi-user authorization configuration is described separately as an implementation gap because its server startup wiring is not complete.

Install the server

Install the server extra on the host that owns the RECAP database:

pip install "pyrecap[server]"

The server extra includes Uvicorn, FastAPI integration, PostgreSQL support, and server configuration dependencies.

Configure a single-user server

Create a configuration file on the server. Keep the API key in a secret manager or provision the file with restricted permissions; do not commit the key to source control.

server:
  db_path: /data/recap/recap.db
  host: 127.0.0.1
  port: 8000
  authentication_mode: single-user
  api_key: replace-with-secret

Exactly one of db_path and database_uri is required. Use database_uri for a non-file database such as PostgreSQL. Single-user mode requires a non-empty api_key.

For a local server, start directly against SQLite:

pip install "pyrecap[server]"
recap-server --db /path/to/recap.db --port 8000

The direct --db form uses server configuration defaults. Configure its API key through the supported server configuration or environment settings rather than placing credentials in command arguments.

For a configured deployment, start with:

recap-server --config /etc/recap/recap-server.yaml

Run a remote server

For a remote deployment, install the server extra on the host that owns the database and run recap-server under your chosen hosting platform. A typical provider-neutral boundary is:

Client -> HTTPS endpoint or reverse proxy -> recap-server -> database

The deployment platform is intentionally outside RECAP’s scope. Configure its process manager, network access, TLS termination, backups, and secrets using your organization’s standards.

[Deployment-specific: add reverse-proxy and TLS configuration.]
[Deployment-specific: add process-manager configuration and restart policy.]
[Deployment-specific: add database backup and restore procedure.]
[Deployment-specific: add secret provisioning and rotation procedure.]

Connect a remote client

Connect to the reachable base URL from Python:

from recap.client import RecapClient

client = RecapClient.from_url(
    "http://localhost:8000",
    api_key="your-api-key",
)
namespace = client.namespace("beamline/amx")

Once connected, follow Quick Start: Create and Store Data Locally. Use RecapClient.from_url() in place of RecapClient.from_sqlite(); the namespace, builders, queries, and provenance workflow are the same.

Remote clients use authenticated POST /api/v1/query for reads and POST /api/v1/query/count for counts. Creates, updates, and resource copies use REST command endpoints. Applications do not need direct access to the server’s database filesystem. Query payloads and results are ordinary JSON envelopes; local and remote QueryDSL behavior remains aligned.

Authentication and authorization

The current runnable server authentication mode uses one configured API key. The client sends this exact header on REST requests:

Authorization: Apikey your-api-key

Missing, malformed, or invalid credentials return 401 before query or command execution. Credentials are compared using constant-time comparison and are redacted from client representations and connection errors.

The single-user actor currently receives all defined scopes and has no namespace restriction. The runnable server therefore permits this actor to access every namespace. Namespace-specific grants, ancestor visibility, and cross-namespace authorization rules require multi-user server startup wiring, which is not yet available.

Inspect effective permissions from a client:

permissions = client.namespace("beamline/amx").permissions()
print(permissions.effective_scopes)
print(permissions.matched_namespace_paths)

See Authentication and Authorization for policy evaluation details and REST Query and Command Architecture for transport behavior.

Multi-user authorization status

The authorization compiler can convert a YAML source file into an immutable SQLite entitlement snapshot:

recap-authz-compile authorization.yml entitlement-snapshot.db

The source format binds provider identities to groups, roles, scopes, and namespace paths:

source_revision: revision-42

roles:
  reader:
    scopes:
      - namespace:read
      - resource:read

groups:
  scientists:
    identities:
      - provider: oidc
        subject: user@example.org

namespaces:
  beamline/amx:
    groups:
      - name: scientists
        role: reader
[Code gap: ServerConfig accepts multi-user snapshot settings, but
recap-server currently does not pass authentication_mode,
entitlement_snapshot_path, or entitlement_snapshot_max_age_seconds into
create_app(). Do not use multi-user mode in production until server wiring and
end-to-end startup tests exist.]

Snapshot loading is fail-closed when the snapshot is missing, stale, corrupt, has an unsupported format, or fails its integrity check.

Verify and troubleshoot

Send an authenticated REST query after starting the server:

curl https://recap.example.org/api/v1/query \
  -H 'Authorization: Apikey your-api-key' \
  -H 'Content-Type: application/json' \
  --data '{"entity":"namespace","projection":"full","namespace_path":"beamline/amx","spec":{}}'

Use responses as follows:

  • 200: request authenticated and query completed.
  • 401: credential is missing, malformed, or invalid.
  • 403: request is rejected by an authorization policy in a future multi-user deployment.
  • 404: requested resource or namespace does not exist; a future multi-user policy may also conceal it.
  • 503: authorization snapshot is unavailable in a future multi-user deployment.

Use the X-Request-ID response header when reporting server-side failures.

For client credential details, see Authenticate a Remote Client.