Skip to main content

usage-rules.md

# arcadic usage rules

_A framework-agnostic Elixir client for ArcadeDB over the HTTP Cypher command API._

## What arcadic is (and is not)

- **Is:** a thin transport. Sends Cypher/SQL to ArcadeDB's HTTP command API,
  manages connections and session transactions, normalizes responses.
- **Is not:** Ash-aware, tenant-aware, or classification-aware. Never put
  multitenancy or sensitive-data logic here — that is `ash_arcadic`'s job.

## Public surface

- **`Arcadic`** — `connect/3`, `with_database/2`; `query/4` + `query!/4`
  (idempotent read endpoint), `command/4` + `command!/4` (write endpoint),
  `command_async/4` (fire-and-forget, returns `:ok` on 202); `transaction/3` and
  `rollback/2` for session transactions. Non-bang calls return `{:ok, rows}` or
  `{:error, %Arcadic.Error{} | %Arcadic.TransportError{}}`. Default language is
  `"cypher"`; opt into `sql`/`gremlin`/`graphql`/`mongo`/`sqlscript` per call.
- **`Arcadic.Conn`** — a pure-data connection handle (no process). Its `Inspect`
  redacts auth and session id.
- **`Arcadic.Server`** — server admin: `create_database/2` (+ `!`),
  `drop_database/2` (+ `!`), `database_exists?/2`, `list_databases/1`, `ready?/1`.
- **Migrations** — `Arcadic.Migration` (behaviour: `version/0`, `up/1`, `down/1`),
  `Arcadic.MigrationRegistry` (`use` + `migrations [...]`), `Arcadic.Migrator`
  (`migrate/2`, `status/2`, `rollback/3`, `reset/2`, `pending_migrations/2`),
  tracking applied versions in `_arcadic_migrations`.
- **`Arcadic.Transport`** — the transport behaviour seam; `Arcadic.Transport.HTTP`
  (Req/Finch) is the default, `Arcadic.Transport.Bolt` is the optional Bolt one.
- **`Arcadic.Error` / `Arcadic.TransportError`** — the typed error taxonomy.
- **`Arcadic.Telemetry`** — value-free `:telemetry.span/3` spans.
- **`Arcadic.Identifier`** — allowlist identifier validation.

## Non-negotiable rules

- **Parameters only.** Every dynamic value goes into the request `params` map and
  is referenced as `$name` in the statement. Never interpolate a value into a
  Cypher/SQL string — that is a query-injection defect. This holds for
  `query/4`, `command/4`, `command_async/4`, and inside `transaction/3`.
- **Redact at the boundary.** Errors and logs carry structure only.
  `Arcadic.Error` exposes a typed `reason`, `http_status`, and `exception` class;
  its `detail` field is quarantined (absent from `message/1` and `inspect/1`).
  `Arcadic.TransportError` carries only the value-free reason atom. Never surface
  raw parameter values or response rows.
- **Validate identifiers.** Database names and other identifiers reaching a URL
  path or statement go through `Arcadic.Identifier.validate/1` first (a failure
  carries the invalid-shape fact only, never the offending string). Values are
  never identifiers — they ride `params`.

## Bolt transport (optional)

The `Arcadic.Transport.Bolt` adapter (optional `boltx` dependency) runs the query
hot path over Bolt. Start it with `Arcadic.Transport.Bolt.start_link/1`, which
pins Bolt to **v4** (`versions: [4.4, 4.3, 4.2, 4.1]` — ArcadeDB speaks v4;
boltx defaults to v5), uses the non-TLS **`bolt` scheme** (ArcadeDB Bolt is
TLS-disabled by default), and takes `username`/`password`. Pass the connection
reference as `transport: Arcadic.Transport.Bolt, transport_options: [bolt: ref]`.
**Server admin (create/drop/list database) is HTTP-only** — use an HTTP conn for
admin even when queries run over Bolt.

See `AGENTS.md` for the full working rules and the verified ArcadeDB HTTP contract.