# Athena RS 1.3.0
current version: `2.0.2`
## Table of Contents
- [Overview](#overview)
- [Quickstart](#quickstart)
- [Architecture](#architecture)
- [API Reference](#api-reference)
- [CLI Tools](#cli-tools)
- [SDK](#sdk)
- [Supported Drivers](#supported-drivers)
- [Configuration](#configuration)
- [WebSocket Gateway](#websocket-gateway)
- [Web Explorer](#web-explorer)
- [Docker](#docker)
- [Testing & Linting](#testing--linting)
- [Contributing](#contributing)
## Overview
Athena is a lightweight database gateway that proxies and executes queries across Athena/ScyllaDB, PostgreSQL, and Supabase backends. The Actix-powered API normalizes headers, shapes JSON payloads, and exposes helper utilities so API consumers, dashboards, and embedded tooling all speak the same surface.
Key features:
- **Gateway surface:** `/gateway/fetch`, `/gateway/update`, `/gateway/insert`, `/gateway/delete`, and `/gateway/query` accept structured payloads, route via `X-Athena-Client`, and normalize camelCase / snake_case when configured.
- **Online client catalog:** `x-athena-client` resolution now supports both legacy `config.yaml` entries and database-backed client rows stored in the `athena_logging` database, with a local in-memory registry for hot-path performance.
- **Post-processing:** Fetch/update responses honor optional `group_by`, `time_granularity`, `aggregation_column`, `aggregation_strategy`, and `aggregation_dedup`. When those fields are present, the response includes a `post_processing.grouped` array with labels, rows, and aggregation metadata.
- **SQL executor:** `/query/sql` reroutes raw SQL to Athena/Scylla, PostgreSQL pools (SQLx), or Supabase while sharing the same `X-Athena-Client` routing registry.
- **Proxy helpers:** `proxy_request` forwards arbitrary REST calls with auth header management and caching helpers in `api::cache`.
- **Cache layer:** Built on `moka` with optional Redis write-through and TTL management.
- **Admin control plane:** `/admin/clients*` manages client creation, editing, freeze/unfreeze, removal, and aggregated client statistics traced from the existing gateway log tables; `/admin/provision` and `/admin/backups*` handle schema bootstrap plus S3-based backups/restores.
- **Configuration:** `config.yaml` still bootstraps the server, logging/auth clients, Redis caching, and the camel-to-snake toggle; download the synced HTTP spec via `GET /openapi.yaml` and the WebSocket contract via `GET /openapi-wss.yaml` (covers `/wss/gateway`, `/wss/info`, `/health`, and `/ready` for the Bun proxy) so you can import both into OpenAPI tooling.
## Quickstart
### Prerequisites
- Rust 1.85+ (edition 2024). On Linux, install `libssl-dev` and `pkg-config` for `openssl-sys`.
- Node.js 18+ if you plan to run the Web Explorer (`apps/web`) or the TypeScript CLI (`cli/`).
- Docker (optional) for the bundled Postgres/Redis services: `docker compose up -d postgres redis`.
### Start the API locally
1. Populate `config.yaml`, point each `postgres_clients` entry to `${ENV_VAR}` values, and export the env vars to keep credentials out of version control.
2. (Optional) start local services with `docker compose up -d postgres redis` and set `POSTGRES_ATHENA_LOGGING_URI="postgres://athena:athena@localhost:5433/athena_logging"`.
3. Start the server with `cargo run -- --api-only` (or `cargo run -- server`) to boot Actix, load `openapi.yaml`, and serve `/openapi-wss.yaml`; the API no longer boots automatically unless `--api-only` or `server` is passed.
4. Use the `X-Athena-Client` header to select a Postgres pool for `/gateway/`\*, `/query/sql`, and the schema endpoints; the same header drives pipelines and diagnostics.
### Feature flags
CDC (Change Data Capture) is enabled by default. To build without CDC (smaller binary, no WebSocket server or `cdc` subcommand), use `cargo build --no-default-features`.
## Architecture
Athena follows a three-tier architecture that keeps the HTTP gateway separated from the driver glue and the downstream databases:
1. **API Layer:** The Actix `Core Service` validates headers, shapes requests, starts CLI helpers, and emits the standard response envelope (`status`, `message`, `data`/`error`).
2. **Driver Layer:** Router logic hands off translated queries to either SQLx-managed PostgreSQL pools, the native Scylla driver, or the Supabase REST translator, and each driver tracks health/circuit-breaking before executing.
3. **Database Backends:** The driver layer spans PostgreSQL (SQLx), ScyllaDB (native CQL), and Supabase (REST / Supabase RPC).
### Client catalog flow
Performance is the first priority in the new client catalog. Athena loads clients once during bootstrap, reconciles `config.yaml` with the `athena_clients` table in the `athena_logging` database, and serves request-time lookups from the local registry instead of round-tripping to Postgres on every request.
```mermaid
flowchart LR
A["config.yaml"] --> B["Bootstrap"]
C["athena_logging.athena_clients"] --> B
B --> D["In-memory client registry"]
D --> E["X-Athena-Client lookup"]
E --> F["Gateway route"]
F --> G["SQLx pool / driver"]
```
### Bootstrap reconciliation
```mermaid
sequenceDiagram
participant S as Server start
participant C as config.yaml
participant L as athena_logging
participant R as Local registry
S->>C: Load postgres_clients
S->>R: Connect legacy config pools
S->>L: Upsert config-only clients into athena_clients
L-->>S: Return database-backed clients
S->>R: Merge active clients and freeze deleted/frozen ones
R-->>S: Hot-path registry ready
```
### Statistics lineage
```mermaid
flowchart TD
A["Gateway request"] --> B["gateway_request_log"]
A --> C["gateway_operation_log"]
B --> D["client_statistics"]
C --> D
C --> E["client_table_statistics"]
D --> F["/admin/clients/statistics"]
E --> G["/admin/clients/{client}/statistics"]
```
Component relationships:
- The **Core Service** is the API gateway, CLI host, and cache coordinator.
- The **Web UI** (`apps/web`) consumes the gateway, schema, and registry APIs, and it also ships Athena headers via `NEXT_PUBLIC`\_\* env vars.
- The **TypeScript CLI** talks directly to Supabase (via `get_full_schema_json`) to bootstrap seed files, constraints, and Drizzle registries; it does not run through the Actix gateway but outputs SQL/CQL for Athena to execute later.
Request flow:
1. A client (Web UI, Rust CLI, or HTTP caller) hits `/gateway/`\*/`/query/sql`/`/pipelines` with the required headers.
2. The API Layer validates the `X-Athena-Client`, resolves the target backend (Postgres/Scylla/Supabase), and forwards the normalized payload to the Driver Layer.
3. The Driver Layer translates the request into SQL or CQL, executes it, enforces health/circuit-breakers, and returns rows plus metadata.
4. The API Layer wraps the return value in the shared response envelope before sending it back.
Supported database backends:
- **PostgreSQL (SQLx):** pooled SQL execution and schema discovery via `information_schema`.
- **ScyllaDB (native driver):** CQL execution against Scylla clusters using the `scylla` crate and health-aware host tracking.
- **Supabase (REST API):** Supabase REST endpoints with RPC helpers, health tracking, and optional override headers (`x-supabase-url`, `x-supabase-key`).
```
┌────────────┐
│ Clients │
│ (Web UI, │
│ CLI, Postman) │
└──────┬─────┘
│
▼
┌─────────────────┐
│ Core Service │
│ (Actix Gateway, │
│ Cache, CLI) │
└──────┬──────────┘
┌────────────┼────────────┐
│ │ │
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ SQLx │ │ Scylla │ │ Supabase │
│ PostgreSQL │ │ CQL Driver │ │ REST + RPC │
└────────────┘ └────────────┘ └────────────┘
```
<!-- cargo-rdme start -->
Athena
A lightweight Database Gateway that proxies and executes queries across multiple backends
(Athena/ScyllaDB, PostgreSQL, and Supabase) with simple caching and routing.
- Provides REST endpoints for executing SQL against supported drivers
- Proxies arbitrary requests while handling auth headers and basic response shaping
- Exposes a small set of utilities for driver execution and routing
<!-- cargo-rdme end -->
## API Reference
### Gateway Endpoints
#### `POST /gateway/fetch`
Fetch data with filtering, pagination, grouping, and aggregations. Send conditions, pagination fields, and the optional `group_by` / `aggregation_*` payload. Responses include `data.rows` plus a `post_processing.grouped` array when grouping is enabled.
Example request:
```json
POST /gateway/fetch
Headers:
X-Athena-Client: reporting
X-User-Id: user-123
apikey: ${ATHENA_APIKEY}
Body:
{
"table_name": "events",
"columns": ["id", "user_id", "value", "created_at"],
"conditions": [{"eq_column": "status", "eq_value": "active"}],
"limit": 50,
"group_by": "user_id",
"time_granularity": "hour",
"aggregation_column": "value",
"aggregation_strategy": "cumulative_sum",
"aggregation_dedup": true
}
```
Sample response (success envelope):
```json
{
"status": "success",
"message": "Fetched 6 rows",
"data": {
"rows": [...],
"post_processing": {
"grouped": [
{"label": "user-1", "rows": [...], "aggregation": 42}
]
}
}
}
```
#### `POST /gateway/update`
Reuses the same payload as `/gateway/fetch` but allows updates instead of raw reads. Include `columns`, `conditions`, and any aggregation metadata you need.
#### `PUT /gateway/insert`
Insert (and optionally upsert) a row. Provide the target table, the `insert_body`, and `update_body` to apply when conflicts occur. Required headers include `X-User-Id`, `X-Company-Id`, `X-Organization-Id`, and `apikey`. The optional `X-Publish-Event` header toggles telemetry events.
Example body:
```json
{
"table_name": "users",
"insert_body": { "email": "new@athena.io", "status": "active" },
"update_body": { "status": "active" }
}
```
#### `DELETE /gateway/delete`
Delete a row by `table_name` and `resource_id`. The request must carry `X-User-Id`, `X-Company-Id`, and `X-Organization-Id` along with `apikey` and `X-Athena-Client`.
#### `POST /gateway/query`
Execute raw SQL through the selected Postgres pool. The request body is simply `{ "query": "SELECT ..." }`; the `X-Athena-Client` header selects the pool.
### Query & Pipeline Endpoints
#### `POST /query/sql`
Dispatch raw SQL to a specific driver. The request requires `query`, `driver` (`athena`, `postgresql`, or `supabase`), and `db_name` (the logical Postgres pool from `X-Athena-Client`). Responses use the standard envelope and include columns/rows.
Example:
```json
{
"query": "SELECT COUNT(*) FROM users",
"driver": "postgresql",
"db_name": "reporting"
}
```
#### `POST /pipelines`
Run config-driven ETL-like pipelines that follow a **source → transform → sink** pattern. Supply `pipeline` to reference a definition from `config/pipelines.yaml` (see the `example_copy` entry in the repo) or provide inline `source`/`transform`/`sink` overrides.
Transform options:
- `group_by`: column name used for grouping.
- `time_granularity`: one of `day`, `hour`, or `minute`.
- `aggregation_column`, `aggregation_strategy` (only `cumulative_sum` today), and `aggregation_dedup`.
Example pipeline request:
```json
{
"pipeline": "example_copy",
"source": {
"table_name": "users",
"columns": ["id", "email"],
"conditions": []
},
"transform": {
"group_by": "region",
"aggregation_column": "score",
"aggregation_strategy": "cumulative_sum"
},
"sink": { "table_name": "users_backup" }
}
```
Responses contain a `data` array documenting inserted rows along with the pipeline status.
### Schema & Utility Endpoints
- `GET /schema/clients`: lists `clients` (the Postgres pools registered under `config/clients.json`).
- `GET /schema/tables`: requires `X-Athena-Client`; returns table metadata from `information_schema`.
- `GET /schema/columns`: requires `X-Athena-Client` plus `table_name` query parameter; returns column definitions.
- `GET /registry` and `GET /registry/{api_registry_id}`: read API registry data from Supabase; include `Cache-Control: no-cache` to bypass in-memory caching.
- `GET /`: health check that reports `message`, `version`, backend statuses (`athena_api`, `athena_deadpool`, `athena_scylladb`), and available routes.
- `GET /docs`: redirects to the hosted Athena documentation.
- `GET /openapi.yaml`: serves the bundled OpenAPI spec used to generate this reference.
- `GET /openapi-wss.yaml`: serves the bundled WebSocket OpenAPI contract for `/wss/gateway` requests.
### Authentication & Headers
- **API keys:** Provide `apikey` (or the mirror `x-api-key`) on every gateway, query, and pipeline request.
- **Routing:** `X-Athena-Client` chooses the Postgres pool. When the client resolves to `custom_supabase`, also send `x-supabase-url` and `x-supabase-key` to hit the supabase instance directly.
- **Audit headers:** `X-User-Id`, `X-Company-Id`, and `X-Organization-Id` are required for `insert` and `delete` operations and strongly encouraged elsewhere to provide traceability.
- **Optional helpers:** `X-Strip-Nulls` drops null values from the returned payload, `X-Publish-Event` toggles telemetry events (set to `true` to emit), and `Cache-Control: no-cache` skips cached registry responses.
- **Standard response envelope:** All endpoints wrap payloads in `{ "status": "success" | "error", "message": "...", "data": {...}?, "error": "..."? }`. Use `api_success` and `api_error` helpers in code to produce this schema.
### API Keys
Athena persists API keys in the `api_keys` family of tables. The master record is `api_keys`, which stores `public_id`, `name`, `description`, an optional `client_name`, and the salt/hash for the secret. Columns like `api_keys_id`, `created_at`, and `updated_at` are generated in the database, and `api_keys_id` is the UUID returned to callers while the internal bigint `id` backs foreign keys. `api_key_rights` names the allowed capability strings, `api_key_right_grants` bridges keys to rights, `api_key_config` keeps global enforcement, `api_key_client_config` holds per-client overrides, and `api_key_auth_log` records every authentication attempt (request metadata, presented hash, granted rights, failure reason, etc.).
All of the `/admin/*` surfaces and the protected `/schema/clients` + `/clients` endpoints require the static admin key stored in the `ATHENA_KEY_12` environment variable. Provide that key through `Authorization: Bearer <key>`, `apikey`, `x-api-key`, `x-athena-key`, or the `?api_key=` query string when invoking these routes.
When you hit `POST /admin/api-keys`, Athena generates a `public_id`, secrets (salt/hash), and returns the plaintext credential as `ath_{public}.{secret}`. Capture the secret at creation time; it cannot be retrieved later. Rights can be assigned at creation or updated later by supplying the `rights` array.
#### Admin API key routes
- `GET /admin/api-keys` – list all API key records plus granted rights.
- `POST /admin/api-keys` – create a new API key by providing `name`, optional `description`, optional `client_name`, optional `expires_at` timestamp, and optional `rights`.
- `PATCH /admin/api-keys/{id}` – adjust an existing key (name, description, client, expiry, active flag, rights).
- `DELETE /admin/api-keys/{id}` – archive the key.
- `GET /admin/api-key-rights` – list every right string that can be granted.
- `POST /admin/api-key-rights` – create a new right (name + optional description).
- `PATCH /admin/api-key-rights/{id}` – rename/describe a right.
- `DELETE /admin/api-key-rights/{id}` – remove a right (cascades via `api_key_right_grants`).
- `GET /admin/api-key-config` – read the global enforcement setting plus the client overrides.
- `PUT /admin/api-key-config` – flip the global `enforce_api_keys` flag.
- `GET /admin/api-key-clients` – list the per-client overrides.
- `PUT /admin/api-key-clients/{client_name}` – upsert a per-client override.
- `DELETE /admin/api-key-clients/{client_name}` – remove a client override and fall back to the global setting.
### Client Catalog Admin Routes
Athena stores scalable client definitions in the `athena_clients` table inside the `athena_logging` database. Each row can reference either a direct `pg_uri` or a `pg_uri_env_var`, and bootstrap will also seed config-only clients into the table so old installs migrate forward without duplicate entries.
- `GET /admin/clients` – list the database catalog plus the current runtime registry snapshot.
- `POST /admin/clients` – create a database-managed client by sending `client_name` and either `pg_uri` or `pg_uri_env_var`.
- `PATCH /admin/clients/{client_name}` – update connection settings, description, or active state.
- `PUT /admin/clients/{client_name}/freeze` – freeze or unfreeze a client without deleting its catalog row.
- `DELETE /admin/clients/{client_name}` – soft-delete a client from the database catalog and remove it from the runtime registry.
- `GET /admin/clients/statistics` – list aggregated request and operation counts per client.
- `POST /admin/clients/statistics/refresh` – rebuild `client_statistics` and `client_table_statistics` from the existing log tables.
- `GET /admin/clients/{client_name}/statistics` – inspect totals plus per-table operation counts for one client.
Frozen or deleted database rows are removed from the hot-path registry, so request handlers keep using local memory instead of querying the catalog table for every call.
Every admin response is described in `openapi.yaml`, so use that spec if you need payload samples, response codes, or schema definitions.
Success example:
```json
{
"status": "success",
"message": "Fetched 10 rows",
"data": {"rows": [...]}
}
```
Error example:
```json
{
"status": "error",
"message": "Invalid request",
"error": "Missing table_name"
}
```
## CLI Tools
### Rust CLI
The `athena_rs` binary exposes CLI helpers alongside the HTTP API. Global flags apply to every subcommand:
- `--config` / `--config-path <PATH>` override `config.yaml` (default: `config.yaml`).
- `--pipelines <PATH>` overrides the default pipeline definitions file (`config/pipelines.yaml`).
- `--port <PORT>` overrides the API port when booting the server.
- `--api-only` boots the server (same as `server`).
Configuration load order (searched in this order and logged when missing):
1. `%APPDATA%/athena`
2. `%LOCALAPPDATA%/athena`
3. `%USERPROFILE%/.athena`
4. `$XDG_CONFIG_HOME/athena`
5. `$HOME/.config/athena`
6. `$HOME/.athena`
7. `~/Library/Application Support/athena` (macOS)
8. Current working directory
If no config file is found, Athena copies the bundled `config.yaml` into the first writable directory before loading it. Errors list every inspected location so you can troubleshoot missing configs.
Commands:
- `server` (or `--api-only`): start the Actix Web server. Respect `--port`, `--config`, and `--pipelines` overrides.
- `pipeline`: run an inline pipeline with `--client <NAME>`, `--payload-json`, `--payload-file`, and `--pipeline <NAME>` to reference prebuilt definitions.
- `clients` subcommands (`list`, `add`, `remove`, `set-default`): mutate `config/clients.json` that stores reusable Postgres connection names.
- `fetch`: proxy a gateway fetch request to `https://athena-db.com/gateway/fetch` (or the URL supplied via `--url`). Use `--client` to pick a saved client and `--body-json` / `--body-file` to supply the payload.
- `diag`: print OS, architecture, CPU count, Rust version, hostname, and locale metadata.
- `version`: show the build version (`cargo run -- --version` works too).
### TypeScript CLI
The CLI in `cli/` generates SQL/CQL artifacts from Supabase schema metadata.
Installation:
```bash
cd cli
npm install
npm run build
```
Commands:
- `seed` (default). Generates SQL `CREATE TABLE` scripts and optional CQL artifacts. Flags:
- `--sql=<PATH>`, `--cql=<PATH>` (destinations for SQL/CQL files).
- `--if-not-exist-table` to wrap tables with `CREATE TABLE IF NOT EXISTS`.
- `--include-constraints-sql` to emit constraint SQL alongside the seeds.
- `--supabase-url`, `--supabase-key` to override credentials.
- `--supabase-config=<PATH>` to load a JSON file (supports a `database` block).
- `--db-config-output=<PATH>` to dump the resolved database config.
- `constraints`: emit constraint SQL from Supabase schema metadata (supports the same Supabase overrides).
- `table-registry`: builds a Drizzle table registry from `lib/db/schema.ts`. Flags: `--registry-schema-path=<PATH>` and `--registry-path=<PATH>`.
- `help`: prints the available commands and their flags.
Flags and env vars:
- `resolveSupabaseConfig` respects `ATHENA_SUPABASE_URL`, `ATHENA_SUPABASE_ANON_KEY`, `SUPABASE_URL`, and `SUPABASE_ANON_KEY`.
- The CLI requires the Supabase RPC `get_full_schema_json`—make sure the RPC is defined before running `seed` or `constraints`.
## SDK
The `AthenaClient` SDK offers a builder-based interface that works across Supabase, PostgreSQL, Scylla, and other backends in a single surface.
### Initialization patterns
- `AthenaClient::new(url, key)` defaults to the native SQL backend.
- `AthenaClient::new_with_backend(url, key, BackendType)` picks a specific backend.
- `AthenaClient::builder()` returns an `AthenaClientBuilder` for granular control (see `backend`, `url`, `key`, `ssl`, `port`, `database`, `max_connections`, `min_connections`, `connection_timeout`, `idle_timeout`, `health_tracking`, `circuit_breaker_*`).
### Query builders
```rust
use athena_rs::{AthenaClient, BackendType, client::query_builder::OrderDirection};
let client = AthenaClient::builder()
.backend(BackendType::Supabase)
.url("https://project.supabase.co")
.key("service-role-key")
.health_tracking(true)
.build()
.await?;
let rows = client
.select("users")
.columns(["id", "email"])
.where_eq("status", "active")
.where_gt("created_at", "2025-01-01")
.order_by("created_at", OrderDirection::Desc)
.limit(10)
.offset(0)
.execute()
.await?;
client
.insert("logs")
.payload(json!({ "message": "SDK initialized" }))
.execute()
.await?;
```
Beyond `select`, the SDK exposes `insert`, `update`, and `delete` builders. Advanced filters include `where_eq`, `where_gt`, `where_in`, `order_by`, `limit`, and `offset`.
### Raw execution
- `execute_sql("SELECT ...")` for backend-agnostic SQL.
- `execute_cql("SELECT ...")` when speaking Cassandra/Scylla.
### Configuration objects
- `ConnectionConfig`: holds `url`, optional `key`, `ssl`, `port`, and `database`.
- `PoolConfig`: controls `max_connections`, `min_connections`, `connection_timeout`, and `idle_timeout` (defaults: 50/5/5s/300s).
- `HealthConfig`: toggles health tracking, `check_interval`, `circuit_breaker_threshold`, and `circuit_breaker_timeout` (defaults: enabled, 30s interval, threshold 5, timeout 60s).
### Health tracking
The Supabase backend wraps the Supabase client in `HealthAwareSupabaseClient`, which implements a circuit breaker. Use `is_offline()` to check if the host is blocked, `force_offline(duration)` for testing, and `reset_health()` to clear failures.
### Environment initialization
Supabase backends can also be built from the environment:
```rust
let backend = SupabaseBackend::from_env("ATHENA_SUPABASE_URL", "ATHENA_SUPABASE_KEY")?;
let client = AthenaClient::builder()
.backend(BackendType::Supabase)
.url(backend.config().connection.url.clone())
.key(backend.config().connection.key.clone().unwrap())
.build()
.await?;
```
### Supported backend types
`BackendType` enumerates: `Native`, `Supabase`, `Postgrest`, `Scylla`, `Neon`, and `PostgreSQL`. `/query/sql` accepts the same driver names, and the builder exposes `new_with_backend_name("supabase")` for quick scripts.
## Supported Drivers
### PostgreSQL driver (SQLx)
Connection strings follow `postgres://user:password@host:port/db`. The driver uses SQLx pools, honors `PoolConfig`, and maps `X-Athena-Client` values to different entries in `config/clients.json`.
### ScyllaDB driver
The Scylla backend (`scylla::Session`) accepts host/port pairs and executes CQL. Use it for Cassandra-compatible workloads; it supports `execute_cql` and health tracking via the shared tracker.
### Supabase driver
Supabase is backed by `supabase_rs` and requires a `SupabaseConnectionInfo` (URL and API key). Use `x-supabase-url`/`x-supabase-key` headers to route a gateway request to a custom Supabase project. The driver enforces HTTP retries, circuit-breaking, and exposes `is_offline()`, `force_offline()`, and `reset_health()` helpers.
Driver selection happens either through the `driver` field in `/query/sql` or via the SDK builder (`backend(BackendType::Scylla)`), so the same API surface can switch between Postgres, Scylla, and Supabase at runtime.
## Configuration
`config.yaml` still defines core server settings, Redis caches (`ATHENA_REDIS_URL`), the `athena_logging`/auth clients, and any legacy Postgres pools you want to bootstrap from environment variables. Replace literal URIs in `postgres_clients` with `${ENV_VAR}` tokens and export the env vars or the CLI will fail to start.
For scalable installs, use `athena_clients` in the `athena_logging` database as the primary client catalog:
- Config-backed clients are auto-synced into the table on startup if they do not exist yet.
- Client names are de-duplicated in the catalog, so the same `X-Athena-Client` cannot exist twice.
- Request-time routing still happens against the in-memory registry, not the catalog database.
- `config.yaml` remains required for server bootstrap and for the logging/auth database, but it no longer needs to carry every client once the catalog is populated.
Pipeline definitions live in `config/pipelines.yaml` (`example_copy` demonstrates a `source`/`sink` pair) and can be referenced by the Rust CLI pipeline helper or `/pipelines` API.
## WebSocket Gateway
`src/wss/` contains the first-pass WebSocket gateway contract. The Bun proxy in `apps/wss-gateway` serves `/openapi-wss.yaml`, `/wss/info`, and the upgrade endpoint at `/wss/gateway`, plus `/health` and `/ready` probes. The request/response envelopes mirror the HTTP gateway actions (`gateway.fetch`, `gateway.insert`, `gateway.update`, `gateway.delete`, `gateway.query`) and return connection metadata on join (`started_at`, `api_base`) alongside upstream responses.
Use `openapi-wss.yaml` when documenting or prototyping clients that want to multiplex Athena gateway operations over a persistent WebSocket connection; it includes examples for the connection ack, upstream proxy responses, and timeout/error envelopes.
## Web Explorer
The Next.js app in `apps/web` hosts the Athena Explorer UI (`apps/web/app/page.tsx`). Install and run it locally with:
```bash
cd apps/web
npm install
npm run dev
```
Point the UI at `https://athena-db.com` or override the backend with `NEXT_PUBLIC_ATHENA_BASE_URL`. Provide `NEXT_PUBLIC_ATHENA_CLIENT`, `NEXT_PUBLIC_ATHENA_USER_ID`, `NEXT_PUBLIC_ATHENA_COMPANY_ID`, and `NEXT_PUBLIC_ATHENA_ORGANIZATION_ID` so the frontend can issue insert/delete requests. The datagrid relies on `/schema/clients`, `/schema/tables`, `/schema/columns`, `/gateway/fetch`, `/query/sql`, and the gateway `insert/delete` endpoints to render table data, schema metadata, and DDL actions.
## Docker
1. Pre-pull the optional Redis cache image: `docker pull redis:8.2.4-alpine3.22`.
2. Run `docker compose up --build` to start the `athena` API and `redis` cache together.
3. Athena listens on `http://localhost:4052`; caching activates when you set `ATHENA_REDIS_URL=redis://redis:6379` in the environment.
4. Stop everything with `docker compose down`; the `redis-data` volume preserves cache contents between runs.
## Testing & Linting
Rust API checks:
```bash
cargo fmt --check
cargo clippy --all-targets --all-features
cargo test --verbose
```
Web Explorer linting:
```bash
cd apps/web
npm run lint
```
## Contributing
Please open issues for bugs or feature requests. Contributions are welcome via pull requests—run `cargo fmt`/`npm run lint` where appropriate, add tests if possible, and describe your changes in the PR. Check `.github/workflows` for the automated checks that run on each branch and follow the repository conventions.