# 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()](../../reference/RecapClient.md#recap.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:

``` bash
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.

``` yaml
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:

``` bash
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:

``` bash
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:

``` text
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.

``` text
[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:

``` 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](../../docs/how-to/quick-start-create-and-store-data-locally.md). Use [RecapClient.from_url()](../../reference/RecapClient.md#recap.RecapClient.from_url) in place of [RecapClient.from_sqlite()](../../reference/RecapClient.md#recap.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:

``` text
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:

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

See [Authentication and Authorization](../../docs/explanation/authentication-authorization.md) for policy evaluation details and [REST Query and Command Architecture](../../docs/explanation/rest-query-architecture.md) for transport behavior.


## Multi-user authorization status

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

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

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

``` yaml
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
```

``` text
[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:

``` bash
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](../../docs/how-to/use-remote-authentication.md).
