# Backend (Go) – Graph + Selection API

This service exposes a small HTTP API for:

- Building and caching a “graph snapshot” from AnzoGraph via SPARQL (`/api/graph`)
- Returning available “graph query” and “selection query” modes
- Running selection queries for the currently selected node IDs
- (Optionally) issuing raw SPARQL passthrough for debugging

## Run

Via Docker Compose (recommended):

```bash
docker compose up --build backend
```

The backend listens on `:8000` (configurable via `LISTEN_ADDR`).

## Configuration (env)

See `backend_go/config.go` for the full set.

Important variables:

- Snapshot limits:
  - `DEFAULT_NODE_LIMIT`, `DEFAULT_EDGE_LIMIT`
  - `MAX_NODE_LIMIT`, `MAX_EDGE_LIMIT`
- SPARQL connectivity:
  - `SPARQL_HOST` (default `http://anzograph:8080`) or `SPARQL_ENDPOINT`
  - `SPARQL_USER`, `SPARQL_PASS`
- Startup behavior:
  - `SPARQL_LOAD_ON_START`, `SPARQL_CLEAR_ON_START`
  - `SPARQL_DATA_FILE` (typically `file:///opt/shared-files/<file>.ttl`)
- Other:
  - `INCLUDE_BNODES` (include blank nodes in snapshots)
  - `CORS_ORIGINS`

## Endpoints

- `GET /api/health`
- `GET /api/stats`
- `GET /api/graph?node_limit=&edge_limit=&graph_query_id=`
- `GET /api/graph_queries`
- `GET /api/selection_queries`
- `POST /api/selection_query`
  - Body: `{"query_id":"neighbors","selected_ids":[1,2,3],"node_limit":...,"edge_limit":...,"graph_query_id":"default"}`
- `POST /api/sparql` (raw passthrough)
- `POST /api/neighbors` (legacy alias of `query_id="neighbors"`)

## Graph snapshots

Snapshots are built by:

1) Running a SPARQL edge query (controlled by `graph_query_id`)
2) Converting SPARQL bindings into dense integer node IDs + edge list
3) Computing a layout and fetching optional `rdfs:label`

Snapshots are cached in-memory keyed by:

- `node_limit`, `edge_limit`, `INCLUDE_BNODES`, `graph_query_id`

## Query registries

### Graph query modes (`graph_query_id`)

Stored under `backend_go/graph_queries/` and listed by `GET /api/graph_queries`.

Built-in modes:

- `default` – `rdf:type` (to `owl:Class`) + `rdfs:subClassOf`
- `hierarchy` – `rdfs:subClassOf` only
- `types` – `rdf:type` (to `owl:Class`) only

To add a new mode:

1) Add a new file under `backend_go/graph_queries/` that returns a SPARQL query selecting `?s ?p ?o`.
2) Register it in `backend_go/graph_queries/registry.go`.

### Selection query modes (`query_id`)

Stored under `backend_go/selection_queries/` and listed by `GET /api/selection_queries`.

Built-in modes:

- `neighbors` – type + subclass neighbors (both directions)
- `superclasses` – `?sel rdfs:subClassOf ?nbr`
- `subclasses` – `?nbr rdfs:subClassOf ?sel`

To add a new mode:

1) Add a new file under `backend_go/selection_queries/` that returns neighbor node IDs.
2) Register it in `backend_go/selection_queries/registry.go`.

## Performance notes

- Memory usage is dominated by the cached snapshot (`[]Node`, `[]Edge`) and the temporary SPARQL JSON unmarshalling step.
- Tune `DEFAULT_NODE_LIMIT`/`DEFAULT_EDGE_LIMIT` first if memory is too high.
