athena_rs 2.0.2

Database gateway API
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
# 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.