Skip to main content

Data storage

Releval persists three categories of state:

  • Application data: endpoints, evaluations, judgments, members, and everything else modelled in the API. Stored in PostgreSQL.
  • User behavior events: high-volume click and impression streams powering the User Behavior Insights Workspace. Stored in ClickHouse, which is optional — without it, User Behavior Insights is disabled and the rest of Releval runs normally.
  • Uploaded files: query sets and judgment lists. Stored on local disk by default, or in AWS S3.

An optional Redis instance provides a distributed cache and real-time messaging backplane. It is required for multi-container deployments.

PostgreSQL

PostgreSQL stores all application data for Releval, and is configured with a connection string.

VariableDefault
ConnectionStrings__Postgres(none)
environment:
- ConnectionStrings__Postgres=Host=<hostname>;Port=<port>;Database=<database>;Username=<user>;Password=<password>

ClickHouse

ClickHouse is an OLAP analytical database used to store user behavior insights (UBI) events and queries.

User Behavior Insights is an optional capability enabled when a connection string for ClickHouse is supplied.

Info

When ClickHouse is not configured, User Behavior Insights APIs return 404, the gRPC tracking service returns NotFound, and the UI indicates the feature is not enabled. Everything else in Releval behaves the same either way.

VariableDefault
ConnectionStrings__ClickHouse(none)
ConnectionStrings__ClickHouseReadonly(none)

Releval uses two ClickHouse connections when User Behavior Insights is enabled. The ingestion one is required; the read-only one is strongly recommended - without it the workspace query path falls back to the ingestion connection and runs arbitrary member SQL with full privileges (Releval logs a warning at startup). ConnectionStrings__ClickHouse ingests events and queries and creates the two UBI tables, so it reads and writes. ConnectionStrings__ClickHouseReadonly runs the SQL a member types into the Workspace; because that query is arbitrary, it should be a dedicated read-only user that can do nothing but read the UBI tables (see Least-privilege users below).

environment:
- ConnectionStrings__ClickHouse=Host=<hostname>;Port=<port>;Database=<database>;Username=<ingest-user>;Password=<password>;Compression=<true|false>
- ConnectionStrings__ClickHouseReadonly=Host=<hostname>;Port=<port>;Database=<database>;Username=<query-user>;Password=<password>;Compression=<true|false>

Least-privilege users

Releval only reads from and writes to two tables in the configured database: ubi_events and ubi_queries. Use two dedicated ClickHouse users so an exposed credential cannot reach anything else in the cluster, and so the Workspace, which runs arbitrary member SQL, is confined to reading UBI data.

Create them from a ClickHouse admin session:

-- Dedicated database for UBI data. Use the same name in both connection strings (Database=releval).
CREATE DATABASE IF NOT EXISTS releval;

-- Ingestion user, for ConnectionStrings__ClickHouse: reads and writes the two UBI tables.
-- Replace every password with a strong value from your secrets manager.
CREATE USER releval IDENTIFIED WITH sha256_password BY 'replace-with-strong-password';
GRANT CREATE TABLE ON releval.* TO releval; -- bootstrap; Releval creates the tables on first run
GRANT SELECT, INSERT, SHOW ON releval.ubi_events TO releval;
GRANT SELECT, INSERT, SHOW ON releval.ubi_queries TO releval;

-- Query user, for ConnectionStrings__ClickHouseReadonly: read-only, used by the Workspace.
-- readonly = 2 lets the driver set the response format but still blocks writes and DDL; the profile
-- caps resources and disables introspection; and granting only SELECT keeps it away from system.*,
-- the url()/file()/remote() sources, and every other database.
CREATE SETTINGS PROFILE IF NOT EXISTS releval_query_profile SETTINGS
readonly = 2,
allow_introspection_functions = 0 CONST,
max_execution_time = 30 CONST,
max_result_rows = 100000 CONST,
max_rows_to_read = 100000000 CONST,
max_memory_usage = 2000000000 CONST;
CREATE USER releval_query IDENTIFIED WITH sha256_password BY 'replace-with-strong-password'
SETTINGS PROFILE 'releval_query_profile';
GRANT SELECT ON releval.* TO releval_query;

After the first successful Releval startup the two tables exist; if you want to tighten further you can either leave the CREATE TABLE grant in place (harmless once the tables exist) or pre-create the tables yourself and revoke the grant; Releval will not try to recreate them.

Neither user can reach another database or table, so ingestion and Workspace queries are both confined to ubi_events and ubi_queries. The bundled Docker Compose files provision the read-only user automatically with a ClickHouse init script, so this manual step is only needed when you run your own ClickHouse.

File storage

Uploaded files default to local disk and can be redirected to S3 by setting a bucket name. The first matching configuration wins: if FileStorage__Aws__BucketName is set, S3 is used; otherwise the local provider runs.

Local disk (default)

VariableDefaultDescription
FileStorage__Local__Directory/app/filesDirectory path for file uploads

In Docker deployments, mount a volume to persist files across container restarts:

services:
releval:
volumes:
- releval-files:/app/files

volumes:
releval-files:

AWS S3

To store files in S3, set the bucket name. Releval automatically switches to the S3 provider when a bucket is configured.

VariableDefaultDescription
FileStorage__Aws__BucketName(none)S3 bucket name (enables S3 storage)
FileStorage__Aws__Regionus-east-1AWS region
FileStorage__Aws__KeyPrefix(none)Prefix for all object keys in the bucket
FileStorage__Aws__AccessKeyId(none)AWS access key (optional if using IAM roles)
FileStorage__Aws__SecretAccessKey(none)AWS secret key (optional if using IAM roles)

With IAM credentials

environment:
- FileStorage__Aws__BucketName=my-releval-bucket
- FileStorage__Aws__Region=us-west-2
- FileStorage__Aws__KeyPrefix=uploads/
- FileStorage__Aws__AccessKeyId=AKIAIOSFODNN7EXAMPLE
- FileStorage__Aws__SecretAccessKey=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

With IAM roles

When running on AWS (EC2, ECS, EKS), use IAM instance profiles or task roles instead of explicit credentials:

environment:
- FileStorage__Aws__BucketName=my-releval-bucket
- FileStorage__Aws__Region=us-west-2

Redis

Redis is an in-memory data structure store used as a database, cache, message broker, and streaming engine.

VariableDefault
ConnectionStrings__Redis(none)

Releval uses it for:

  • Distributed cache: shared L2 cache across application instances with automatic cache invalidation.
  • Real-time messaging backplane: broadcasts notifications (evaluation progress, task updates) to clients connected to any instance.
Info

Redis is required for multi-container deployments where multiple Releval instances run behind a load balancer. Without it, each instance maintains its own cache and can only deliver real-time notifications to directly connected clients.

Without Redis, caching and real-time messaging are handled in-process, which works for single-instance deployments but means clients only receive notifications from the instance they are connected to.

environment:
- ConnectionStrings__Redis=redis:6379