# Xentra — complete library (all audiences)

_Generated whole-library download. See `agent-manifest.json` → `library` for discovery._

## Table of contents

- **Overview** (`00-overview`, developers)
- **Overview** (`00-overview`, builders)
- **Getting Started** (`01-getting-started`, developers)
- **Getting Started** (`01-getting-started`, builders)
- **Vision and GA** (`02-vision-and-ga`, developers)
- **Vision and GA** (`02-vision-and-ga`, builders)
- **Gaps** (`03-gaps`, developers)
- **Gaps** (`03-gaps`, builders)
- **Implementation Target** (`04-implementation-target`, developers)
- **Implementation Target** (`04-implementation-target`, builders)
- **Use Cases** (`05-use-cases`, developers)
- **User Stories** (`06-user-stories`, developers)
- **User Stories** (`06-user-stories`, builders)
- **Next Release Contract** (`07-next-release`, developers)
- **Next Release Contract** (`07-next-release`, builders)

---

# Overview — developers

# Overview — Developers
**Audience:** Engineers embedding or calling Xentra.
**Twin:** [Operators version](../builders/BOOK.md)
**Package:** `@x12i/xentra-*` · **Docs:** https://docs.xentra.x12i.com · **Status:** Work In Progress

---

## Work In Progress status

**This documentation release (0.2.0) is Work In Progress.**

**Product:** Treat Xentra as a developer preview control plane — usable for integration, not GA-complete.

**Technical:** P0 security and P1 operability are done in-repo. External production blockers and remaining P2 polish are tracked in book **03-gaps**. Until those close, site branding, footer, and home page must say Work In Progress.

| Layer | Today |
|-------|-------|
| npm libraries | Usable |
| HTTP API | Developer preview |
| Admin UI | Scaffold (manual JWT) |
| Docs | **WIP** — gaps required |

Next version **must** remove WIP labeling only after gaps are closed — see book **07-next-release**.

## What Xentra is

Xentra is the shared foundation for x12i agentic products: accounts, members, roles, permission checks, agents, delegations, approvals, and audit.

**Keycloak** handles human login. **Authix** handles token signing. **Xentra owns everything in between.**

```
Keycloak ──JWT──► Xentra (5 capabilities) ◄── Authix
```

## Five owned capabilities

| # | Capability | You get |
|---|------------|---------|
| 1 | Multi-tenant data model | Accounts, workspaces, teams, members, roles |
| 2 | Permission evaluation | `access/check` — allow, deny, or needs approval |
| 3 | Agent governance | Agents, tool allow-lists, delegations, invoke gateway |
| 4 | Approval policies | Auto-intercept, request queue, notifications (log-only today) |
| 5 | Audit | Structured history of checks, mutations, tokens, approvals |

**Not Xentra:** login (Keycloak), token cryptography (Authix), product business logic, feature flags.

## Repository and packages

| Package | Role |
|---------|------|
| `@x12i/xentra-types` | Contracts and Zod schemas |
| `@x12i/xentra-core` | Pure domain logic |
| `@x12i/xentra-store` / `-store-mongo` | Persistence |
| `@x12i/xentra-identity` / `-identity-keycloak` | IdP adapter |
| `@x12i/xentra-permissions` | `can()` + Cerbos |
| `@x12i/xentra-agentic` | Agents, tools, delegations |
| `@x12i/xentra-approvals` | Policies and requests |
| `@x12i/xentra-audit` | Audit events |
| `@x12i/xentra-api` | HTTP API |
| `@x12i/xentra-sdk` / `-react` | Client + UI helpers |
| `@x12i/xentra-openapi` | OpenAPI 3.1 |
| `@x12i/xentra-docs` | This knowledge package (devDependency) |
| `@x12i/xentra-admin` | Admin scaffold (private) |

## Documentation map

| Need | Book |
|------|------|
| Integrate today | 01-getting-started |
| What is missing | **03-gaps (required)** |
| GA target product | 02-vision-and-ga |
| Prod ops target | 04-implementation-target |
| Scenarios | 05-use-cases |
| INVEST stories | 06-user-stories |
| Exit WIP | **07-next-release** |

Humans: `npm run docs` or https://docs.xentra.x12i.com. Agents: `npm i -D @x12i/xentra-docs`.

---

# Overview — builders

# Overview — Operators
**Audience:** Platform/SRE operators running the control plane.
**Twin:** [Developers version](../developers/BOOK.md)
**Package:** `@x12i/xentra-*` · **Docs:** https://docs.xentra.x12i.com · **Status:** Work In Progress

---

## Work In Progress status

**This documentation release (0.2.0) is Work In Progress.**

Operators must assume production blockers in **03-gaps** are open: managed Mongo, Keycloak realm ops, published Authix image, K8s secrets, observability, Cerbos TLS, and security sign-off.

Do not run a customer GA on this docs version until **07-next-release** exit criteria are met and WIP labeling is removed.

## What Xentra is

Xentra is the IAM and approvals control plane for x12i agentic products. You operate:

- `@x12i/xentra-api` (compose or K8s)
- MongoDB for tenant data
- Cerbos with `policies/*.yaml`
- Keycloak for human JWTs
- Authix (separate repo) for agent tokens

## Five owned capabilities

Same five capabilities as the developers twin: multi-tenant model, permission evaluation, agent governance, approval policies, audit. Your job is keeping dependencies healthy so those capabilities stay available.

## Repository and packages

Monorepo `apps/api` + `packages/*`. Local stack: `docker compose up -d` (mongo, keycloak, cerbos, xentra-api). Authix is never inside this repo.

## Documentation map

Operators: start **01-getting-started** (builders) → **03-gaps** → **04-implementation-target** → **07-next-release**.

---

# Getting Started — developers

# Getting Started — Developers
**Audience:** Engineers integrating the developer preview API/SDK.
**Twin:** [Operators version](../builders/BOOK.md)
**Package:** `@x12i/xentra-*` · **Docs:** https://docs.xentra.x12i.com · **Status:** Work In Progress

---

## Prerequisites

- Node.js ≥ 20, npm ≥ 10 (workspaces)
- Clone `xentra`, `npm install`, `npm run build`
- For full stack: Docker Compose
- For token routes: Authix from https://github.com/x12i/authix

## Local quick start

```bash
cp .env.example .env
docker compose up -d
bash scripts/stack-smoke.sh
```

API listens on port **8787**. Dev Keycloak: realm `xentra`, client `xentra-api`, secret `xentra-api-dev-secret`, user `testuser` / `test`.

## Environment variables

Every environment variable for `@x12i/xentra-api`, with defaults, dev behavior, and production requirements.

**Product:** Configure dependencies so the API can authenticate callers, persist tenant data, evaluate permissions, and issue tokens.

**Technical:** Source of truth: [`apps/api/src/config.ts`](../../../apps/api/src/config.ts) and [`.env.example`](../../../.env.example).

---

### Server

| Variable | Default | Dev | Production |
|----------|---------|-----|------------|
| `PORT` | `8787` | optional | optional |
| `HOST` | `0.0.0.0` | optional | optional |
| `NODE_ENV` | `development` | `development` / `test` | **`production`** |
| `LOG_LEVEL` | `info` | trace/debug ok | info/warn |
| `TRUST_PROXY` | `false` | `true` behind LB | **`true`** behind ingress |

---

### MongoDB

| Variable | Default | Dev | Production |
|----------|---------|-----|------------|
| `MONGODB_URI` | unset | In-memory store if unset | **Required** |
| `MONGODB_DB_NAME` | `xentra` | optional | optional |

Compose sets `mongodb://mongo:27017`.

---

### Keycloak

| Variable | Default | Dev | Production |
|----------|---------|-----|------------|
| `KEYCLOAK_BASE_URL` | unset | Dev JWT decode if unset | **Required** |
| `KEYCLOAK_REALM` | unset | — | **Required** |
| `KEYCLOAK_CLIENT_ID` | unset | — | **Required** |
| `KEYCLOAK_CLIENT_SECRET` | unset | — | **Required** |
| `KEYCLOAK_JWKS_URI` | auto from base+realm | optional override | optional |

**Dev realm** (compose import): realm `xentra`, client `xentra-api`, secret `xentra-api-dev-secret`, user `testuser`/`test`.

---

### Authix

| Variable | Default | Dev | Production |
|----------|---------|-----|------------|
| `AUTHIX_BASE_URL` | unset | Token routes **503** if unset | **Required** |
| `AUTHIX_API_KEY` | unset | Token routes **503** if unset | **Required** |
| `AUTHIX_ISSUER` | unset | optional | optional |

**Legacy aliases** (mapped automatically): `AUTHX_BASE_URL`, `AUTHX_API_KEY`, `AUTHX_CLIENT_SECRET`, `AUTHX_CLIENT_ID`, `AUTHX_ISSUER`.

Authix service env (separate process): `AUTHIX_STORE`, `MONGODB_URI` (if mongo store), `PORT`, `AUTHIX_API_KEY`.

---

### Cerbos

| Variable | Default | Dev | Production |
|----------|---------|-----|------------|
| `CERBOS_ADDRESS` | `localhost:3593` | gRPC to local/compose Cerbos | **Required** |

Compose/K8s: `cerbos:3593`. Policies mounted from [`policies/`](../../../policies/).

**Production behavior:** Cerbos gRPC failure → deny (`cerbos_unavailable`), no in-process fallback.

**Dev/test:** Falls back to in-process permission engine if Cerbos unreachable.

---

### API security

| Variable | Default | Dev | Production |
|----------|---------|-----|------------|
| `XENTRA_SERVICE_API_KEYS` | unset | optional (no service auth) | **Required** (comma-separated) |
| `CORS_ALLOWED_ORIGINS` | unset | all origins in dev/test | **Required** (comma-separated) |

Service keys are sent as `Authorization: Bearer <key>`.

---

### Docker Compose service map

| Service | Port | Purpose |
|---------|------|---------|
| `mongo` | 27017 | Persistence |
| `keycloak` | 8080 | IdP + realm import |
| `cerbos` | 3592/3593 | HTTP / gRPC PDP |
| `xentra-api` | 8787 | This API |

**Authix** is not in compose. Run from [github.com/x12i/authix](https://github.com/x12i/authix) and point `AUTHIX_BASE_URL` at it (e.g. `http://host.docker.internal:3100` when API is in Docker).

---

### Kubernetes (`deploy/k8s/`)

| Resource | Key values |
|----------|------------|
| `configmap.yaml` | `CERBOS_ADDRESS=cerbos:3593`, `AUTHIX_BASE_URL=http://authix:3100` |
| `secret.yaml` | `KEYCLOAK_CLIENT_SECRET`, `AUTHIX_API_KEY`, `XENTRA_SERVICE_API_KEYS`, `MONGODB_URI` |
| `kustomization.yaml` | Generates `cerbos-policies` ConfigMap from `policies/` |
| `cerbos.yaml` | Cerbos Deployment + Service |
| `authix.yaml` | Authix Deployment + Service (image `authix:latest` — build/push separately) |

---

### Production validation

On `NODE_ENV=production`, missing any of these causes startup exit:

`MONGODB_URI`, `KEYCLOAK_BASE_URL`, `KEYCLOAK_REALM`, `KEYCLOAK_CLIENT_ID`, `KEYCLOAK_CLIENT_SECRET`, `CERBOS_ADDRESS`, `AUTHIX_BASE_URL`, `AUTHIX_API_KEY`, `XENTRA_SERVICE_API_KEYS`, `CORS_ALLOWED_ORIGINS`

---

### Related

- [gaps/current-state.md](../../gaps/current-state.md) — what each dependency is used for
- [deployment.md](./deployment.md) — runbook
- [integration-guide.md](./integration-guide.md) — auth examples

## Authentication

How to integrate with the **implemented** Xentra API (v0.1 developer preview).

**Product:** Connect your product backend to Xentra for tenant IAM, permission checks, agent tokens, approvals, and audit.

**Technical:** Prerequisites, auth, pagination, curl examples, SDK snippet. Route matrix: [gaps/current-state.md](../../gaps/current-state.md).

---

### Prerequisites

- Running API (local: `npm run start -w @x12i/xentra-api` or `docker compose up`)
- Bearer token: Keycloak JWT **or** service API key from `XENTRA_SERVICE_API_KEYS`
- For token routes: Authix at `AUTHIX_BASE_URL` with matching `AUTHIX_API_KEY`

---

### Authentication

| Flow | Header | Notes |
|------|--------|-------|
| **Human user** | `Authorization: Bearer <keycloak-jwt>` | JWKS validation when Keycloak configured |
| **Service / backend** | `Authorization: Bearer <service-api-key>` | Actor type `serviceAccount` |
| **Dev only** | Unsigned JWT (alg `none`) | When Keycloak unset; **disabled in production** |

First `GET /v1/users/me` provisions a Xentra user from Keycloak `sub`.

#### `/access/check` and actor binding

The request body may include `actor`, but for **user JWTs** the API uses the authenticated identity — you cannot spoof another user. **Service accounts** may pass `actor` in the body for impersonation (recorded in audit metadata).

---

#

## First integration loop

1. Obtain Bearer JWT (Keycloak) or service key (`XENTRA_SERVICE_API_KEYS`)
2. `GET /v1/users/me` (provisions user from `sub`)
3. `POST /v1/accounts` (service account in production)
4. `POST /v1/accounts/:id/access/check`
5. Optional: members, agents, delegations, tools, approvals, tokens (Authix)

How to integrate with the **implemented** Xentra API (v0.1 developer preview).

**Product:** Connect your product backend to Xentra for tenant IAM, permission checks, agent tokens, approvals, and audit.

**Technical:** Prerequisites, auth, pagination, curl examples, SDK snippet. Route matrix: [gaps/current-state.md](../../gaps/current-state.md).

---

### Prerequisites

- Running API (local: `npm run start -w @x12i/xentra-api` or `docker compose up`)
- Bearer token: Keycloak JWT **or** service API key from `XENTRA_SERVICE_API_KEYS`
- For token routes: Authix at `AUTHIX_BASE_URL` with matching `AUTHIX_API_KEY`

---

### Authentication

| Flow | Header | Notes |
|------|--------|-------|
| **Human user** | `Authorization: Bearer <keycloak-jwt>` | JWKS validation when Keycloak configured |
| **Service / backend** | `Authorization: Bearer <service-api-key>` | Actor type `serviceAccount` |
| **Dev only** | Unsigned JWT (alg `none`) | When Keycloak unset; **disabled in production** |

First `GET /v1/users/me` provisions a Xentra user from Keycloak `sub`.

#### `/access/check` and actor binding

The request body may include `actor`, but for **user JWTs** the API uses the authenticated identity — you cannot spoof another user. **Service accounts** may pass `actor` in the body for impersonation (recorded in audit metadata).

---

### Health

| Endpoint | Auth | Response |
|----------|------|----------|
| `GET /health` | None | `{ status: "ok", service: "xentra-api" }` |
| `GET /ready` | None | `{ status, checks: { mongo, authix, cerbos } }` — 503 if not ready |
| `GET /metrics` | None | Prometheus text |

---

### Pagination

List endpoints support `?limit=` (default 50, max 200) and `?cursor=` (offset as string):

```json
{
  "data": {
    "items": [ ... ],
    "nextCursor": "50"
  }
}
```

Applies to: members, agents, tokens, approval-requests, approval-policies, audit.

---

### Core flows

#### 1. Create account (service account in production)

```bash
curl -s -X POST "$API/v1/accounts" \
  -H "Authorization: Bearer $SERVICE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Acme","slug":"acme","ownerUserId":"user_abc"}'
```

#### 2. Permission check

```bash
curl -s -X POST "$API/v1/accounts/$ACCOUNT_ID/access/check" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "actor": { "type": "user", "id": "ignored-for-user-jwt" },
    "action": "read",
    "resource": { "resourceType": "account", "resourceId": "'"$ACCOUNT_ID"'" },
    "context": { "accountId": "'"$ACCOUNT_ID"'" }
  }'
```

Use Cerbos action names: `read`, `create`, `issue`, `approve`, etc. (see [gaps/current-state.md](../../gaps/current-state.md)).

#### 3. Issue agent token (requires Authix)

```bash
curl -s -X POST "$API/v1/accounts/$ACCOUNT_ID/tokens/issue" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "appId": "my-product",
    "actor": { "type": "agent", "id": "agent_1" },
    "scope": { "accountIds": ["'"$ACCOUNT_ID"'"] }
  }'
```

#### 4. Approval policy

```bash
curl -s -X POST "$API/v1/accounts/$ACCOUNT_ID/approval-policies" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Export requires approval",
    "actions": ["data.export"],
    "resourceTypes": ["dataset"]
  }'
```

#### 4. Delegate user → agent

```bash
curl -s -X POST "$API/v1/accounts/$ACCOUNT_ID/delegations" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fromActor": { "type": "user", "id": "user_1" },
    "toActor": { "type": "agent", "id": "agent_1" },
    "allowedActions": ["tools.invoke"],
    "expiresAt": "2026-06-02T00:00:00Z"
  }'
```

#### 5. Change member role

```bash
curl -s -X PATCH "$API/v1/accounts/$ACCOUNT_ID/members/$MEMBER_ID" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "roleKey": "admin" }'
```

#### 6. Tool invoke (tool must exist in store)

```bash
curl -s -X POST "$API/v1/accounts/$ACCOUNT_ID/tools/invoke" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "agentId": "agent_1",
    "toolId": "slack",
    "payload": { }
  }'
```

---

### Not implemented (dev preview)

Admin OIDC login, real approval notifications, audit SIEM export. See [gaps/product-backlog.md](../../gaps/product-backlog.md).

---

### SDK

```typescript
import { createXentraClient } from "@x12i/xentra-sdk";

const client = createXentraClient({
  baseUrl: process.env.XENTRA_API_URL!,
  apiKey: process.env.XENTRA_SERVICE_API_KEY,
});

const { user, accounts } = await client.users.me();
const check = await client.permissions.can(accounts[0]!.id, {
  actor: { type: "user", id: user.id },
  action: "read",
  resource: { resourceType: "account", resourceId: accounts[0]!.id },
  context: { accountId: accounts[0]!.id },
});

await client.members.updateRole(accountId, memberId, { roleKey: "admin" });
await client.agents.update(accountId, agentId, { allowedToolIds: ["slack"] });
```

List methods return `{ items, nextCursor }` paginated envelopes.

---

### OpenAPI

Package `@x12i/xentra-openapi` — paths with `x-status: experimental` are implemented; `x-internal` are not.

---

### Local full stack

```bash
cp .env.example .env
docker compose up -d
```

**Authix (optional, for tokens):** in a separate terminal, from your authix checkout:

```bash
cd ../authix
AUTHIX_API_KEY=dev-key npm run dev:service
```

Set in xentra `.env`: `AUTHIX_BASE_URL=http://localhost:3100`, `AUTHIX_API_KEY=dev-key`.

---

### Related

- [configuration.md](./configuration.md)
- [deployment.md](./deployment.md)
- [gaps/current-state.md](../../gaps/current-state.md)

## SDK and OpenAPI

```bash
npm i @x12i/xentra-sdk
```

Use paginated list envelopes (`{ data: { items, nextCursor } }`). OpenAPI package: `@x12i/xentra-openapi`. Admin UI and some polish remain WIP — see Gaps.

## Health ready metrics

| Endpoint | Auth | Notes |
|----------|------|-------|
| `GET /health` | None | liveness |
| `GET /ready` | None | mongo, authix, cerbos — 503 if not ready |
| `GET /metrics` | None | Prometheus |

---

# Getting Started — builders

# Getting Started — Operators
**Audience:** Operators bringing up the local and staging stack.
**Twin:** [Developers version](../developers/BOOK.md)
**Package:** `@x12i/xentra-*` · **Docs:** https://docs.xentra.x12i.com · **Status:** Work In Progress

---

## Prerequisites

Docker, Node ≥ 20 for smoke scripts, access to Authix repo for token routes.

## Local quick start

```bash
cp .env.example .env
docker compose up -d          # mongo, keycloak, cerbos, xentra-api
bash scripts/stack-smoke.sh
```

Compose map: mongo 27017, keycloak 8080, cerbos 3592/3593, api 8787. Authix is **not** in compose — set `AUTHIX_BASE_URL` / `AUTHIX_API_KEY` when needed.

## Environment variables

Every environment variable for `@x12i/xentra-api`, with defaults, dev behavior, and production requirements.

**Product:** Configure dependencies so the API can authenticate callers, persist tenant data, evaluate permissions, and issue tokens.

**Technical:** Source of truth: [`apps/api/src/config.ts`](../../../apps/api/src/config.ts) and [`.env.example`](../../../.env.example).

---

### Server

| Variable | Default | Dev | Production |
|----------|---------|-----|------------|
| `PORT` | `8787` | optional | optional |
| `HOST` | `0.0.0.0` | optional | optional |
| `NODE_ENV` | `development` | `development` / `test` | **`production`** |
| `LOG_LEVEL` | `info` | trace/debug ok | info/warn |
| `TRUST_PROXY` | `false` | `true` behind LB | **`true`** behind ingress |

---

### MongoDB

| Variable | Default | Dev | Production |
|----------|---------|-----|------------|
| `MONGODB_URI` | unset | In-memory store if unset | **Required** |
| `MONGODB_DB_NAME` | `xentra` | optional | optional |

Compose sets `mongodb://mongo:27017`.

---

### Keycloak

| Variable | Default | Dev | Production |
|----------|---------|-----|------------|
| `KEYCLOAK_BASE_URL` | unset | Dev JWT decode if unset | **Required** |
| `KEYCLOAK_REALM` | unset | — | **Required** |
| `KEYCLOAK_CLIENT_ID` | unset | — | **Required** |
| `KEYCLOAK_CLIENT_SECRET` | unset | — | **Required** |
| `KEYCLOAK_JWKS_URI` | auto from base+realm | optional override | optional |

**Dev realm** (compose import): realm `xentra`, client `xentra-api`, secret `xentra-api-dev-secret`, user `testuser`/`test`.

---

### Authix

| Variable | Default | Dev | Production |
|----------|---------|-----|------------|
| `AUTHIX_BASE_URL` | unset | Token routes **503** if unset | **Required** |
| `AUTHIX_API_KEY` | unset | Token routes **503** if unset | **Required** |
| `AUTHIX_ISSUER` | unset | optional | optional |

**Legacy aliases** (mapped automatically): `AUTHX_BASE_URL`, `AUTHX_API_KEY`, `AUTHX_CLIENT_SECRET`, `AUTHX_CLIENT_ID`, `AUTHX_ISSUER`.

Authix service env (separate process): `AUTHIX_STORE`, `MONGODB_URI` (if mongo store), `PORT`, `AUTHIX_API_KEY`.

---

### Cerbos

| Variable | Default | Dev | Production |
|----------|---------|-----|------------|
| `CERBOS_ADDRESS` | `localhost:3593` | gRPC to local/compose Cerbos | **Required** |

Compose/K8s: `cerbos:3593`. Policies mounted from [`policies/`](../../../policies/).

**Production behavior:** Cerbos gRPC failure → deny (`cerbos_unavailable`), no in-process fallback.

**Dev/test:** Falls back to in-process permission engine if Cerbos unreachable.

---

### API security

| Variable | Default | Dev | Production |
|----------|---------|-----|------------|
| `XENTRA_SERVICE_API_KEYS` | unset | optional (no service auth) | **Required** (comma-separated) |
| `CORS_ALLOWED_ORIGINS` | unset | all origins in dev/test | **Required** (comma-separated) |

Service keys are sent as `Authorization: Bearer <key>`.

---

### Docker Compose service map

| Service | Port | Purpose |
|---------|------|---------|
| `mongo` | 27017 | Persistence |
| `keycloak` | 8080 | IdP + realm import |
| `cerbos` | 3592/3593 | HTTP / gRPC PDP |
| `xentra-api` | 8787 | This API |

**Authix** is not in compose. Run from [github.com/x12i/authix](https://github.com/x12i/authix) and point `AUTHIX_BASE_URL` at it (e.g. `http://host.docker.internal:3100` when API is in Docker).

---

### Kubernetes (`deploy/k8s/`)

| Resource | Key values |
|----------|------------|
| `configmap.yaml` | `CERBOS_ADDRESS=cerbos:3593`, `AUTHIX_BASE_URL=http://authix:3100` |
| `secret.yaml` | `KEYCLOAK_CLIENT_SECRET`, `AUTHIX_API_KEY`, `XENTRA_SERVICE_API_KEYS`, `MONGODB_URI` |
| `kustomization.yaml` | Generates `cerbos-policies` ConfigMap from `policies/` |
| `cerbos.yaml` | Cerbos Deployment + Service |
| `authix.yaml` | Authix Deployment + Service (image `authix:latest` — build/push separately) |

---

### Production validation

On `NODE_ENV=production`, missing any of these causes startup exit:

`MONGODB_URI`, `KEYCLOAK_BASE_URL`, `KEYCLOAK_REALM`, `KEYCLOAK_CLIENT_ID`, `KEYCLOAK_CLIENT_SECRET`, `CERBOS_ADDRESS`, `AUTHIX_BASE_URL`, `AUTHIX_API_KEY`, `XENTRA_SERVICE_API_KEYS`, `CORS_ALLOWED_ORIGINS`

---

### Related

- [gaps/current-state.md](../../gaps/current-state.md) — what each dependency is used for
- [deployment.md](./deployment.md) — runbook
- [integration-guide.md](./integration-guide.md) — auth examples

## Authentication

Humans: Keycloak JWT. Services: `XENTRA_SERVICE_API_KEYS`. Production fails closed without required env (Mongo, Keycloak, Cerbos, Authix, service keys, CORS).

## Health ready metrics

Watch `/ready` checks for mongo, authix, cerbos. Use `/metrics` for Prometheus scrape. Local deploy details also live under Implementation Target for GA hardening.

---

# Vision and GA — developers

# Vision and GA — Developers
**Audience:** Product and backend engineers planning GA.
**Twin:** [Operators version](../builders/BOOK.md)
**Package:** `@x12i/xentra-*` · **Docs:** https://docs.xentra.x12i.com · **Status:** Work In Progress

---

## Platform narrative

**Audience:** Product engineers building agentic SaaS at x12i.

**Timeframe:** This document describes the platform **as shipped** — Keycloak, Xentra, and Authix running together in production. Read it as the story of how your product plugs in on day one.

For the modular GA reference see [full-reference.md](./full-reference.md). For today's developer preview see [gaps/current-state.md](../gaps/current-state.md).

---

### The platform in one picture

Every x12i agentic product sits on the same three-layer stack:

```
┌─────────────────────────────────────────────────────────────────┐
│  Your product (CRM, docs, agents, …)                            │
│  Business logic · UI · Stripe · feature flags (yours)           │
└───────────────┬───────────────────────────────┬─────────────────┘
                │ Keycloak JWT (humans)          │ Authix JWT (agents)
                ▼                                ▼
┌─────────────────────────── XENTRA ──────────────────────────────┐
│  Accounts · roles · access/check · agents · approvals · audit   │
│  Grant records in Mongo · policy via Cerbos                     │
└───────────────┬───────────────────────────────┬─────────────────┘
                │                               │
         ┌──────▼──────┐                 ┌──────▼──────┐
         │  Keycloak   │                 │   Authix    │
         │  human SSO  │                 │ token sign  │
         └─────────────┘                 └─────────────┘
```

**Keycloak** — users log in.  
**Xentra** — tenants, permissions, agents, approvals, audit.  
**Authix** — signed credentials for agents and services.

You never call Authix directly from a product backend for agent tokens. You call **Xentra**; Xentra calls Authix and keeps the grant ledger.

---

### What you skip building

| Without the platform | With Xentra + Authix |
|----------------------|----------------------|
| Org/user/membership tables per product | Shared accounts, teams, workspaces, roles |
| RBAC middleware in every service | One `access/check` before sensitive work |
| Rolling your own agent API keys | Scoped Authix tokens with grant + audit |
| “Manager must approve” state machines | Approval policies with auto-intercept + notifications |
| Cross-product “same customer, different apps” | One Keycloak user → one Xentra account everywhere |

Billing (Stripe) and feature flags stay **in your product**. Xentra holds `plan` / `billingCustomerId` on the account if you want to link them — it does not process payments.

---

### Day-one integration

#### Humans

1. User signs in via **Keycloak OIDC** in your app.
2. Your frontend sends `Authorization: Bearer <keycloak-access-token>` to Xentra.
3. First `GET /v1/users/me` creates the Xentra user from Keycloak `sub` and returns their accounts.
4. Before any mutation, your backend calls `POST .../access/check`.

#### Agents

1. Register the agent in Xentra (`POST .../agents`).
2. Register tools and set the agent allow-list.
3. User delegates specific actions with an expiry (`POST .../delegations`).
4. Your backend issues a token **through Xentra** (`POST .../tokens/issue`).
5. Agent runtime uses the returned Authix JWT; verify/introspect also goes through Xentra.
6. Revoke via `POST .../tokens/revoke` — Authix invalidates the token; Xentra marks the grant revoked and writes audit.

---

### The Authix bridge (why tokens go through Xentra)

Authix is excellent at **signing and verifying** tokens. It does not know your tenant model, your approval policies, or your audit requirements.

Xentra's bridge (`apps/api/src/authix/bridge.ts`) sits in the middle:

```
Product  →  POST /tokens/issue  →  Xentra
                                      │
                    ┌─────────────────┼─────────────────┐
                    │                 │                 │
              Cerbos allow?     Create grant      Authix.issueToken()
              (issue/token)     in Mongo          (cryptography)
                    │                 │                 │
                    └─────────────────┴─────────────────┘
                                      │
                              audit: token.issued
                                      │
                    ← { grant, token } ── product gives token to agent
```

**On issue:** Xentra checks permission → maps actor/scope to Authix → persists `XentraTokenGrant` with `authxTokenId` → appends audit → returns JWT to caller.

**On verify:** Xentra asks Authix → optionally enriches with the Mongo grant (account, actor, scope, on-behalf-of).

**On revoke:** Xentra revokes in Authix → updates grant status → audit.

Products get **one integration surface** (Xentra API/SDK). Platform ops run Authix as a shared service with published images, health checks in `/ready`, and rotated API keys.

---

### End-to-end: agent acts on behalf of a user

**Scenario:** A docs product has an agent that can post to Slack on behalf of an admin, but only after policy allows it.

```
1. Admin logs in (Keycloak)
2. Admin delegates tools.invoke to agent_7 for 24h (Xentra delegations)
3. Backend issues agent token (Xentra → Authix), scope = account + onBehalfOf user
4. Agent calls POST .../tools/invoke with Authix JWT
5. Xentra checks: Cerbos invoke + allow-list + delegation not expired
6. Audit: tools.invoke success
7. Product calls Slack with its own connector
```

If an approval policy matches the action earlier in the flow, step 4 never happens until a human approves — `access/check` returns `requires_human_approval`, the product creates an approval request, approvers get notified, and only then does execution continue.

---

### End-to-end: service-to-service

Backend jobs use **Xentra service API keys** (machine identity) for account provisioning and permission checks. Agent workers use **Authix tokens** issued via Xentra grants. Humans use **Keycloak JWTs**. All three actor types appear in audit with the same schema.

| Caller | Credential | Typical use |
|--------|------------|-------------|
| Human | Keycloak JWT | UI-driven CRUD, invites |
| Product backend | Service API key | Provision tenant, impersonate in checks (audited) |
| Agent runtime | Authix token from Xentra grant | Tool invoke, delegated actions |

---

### SDK — production usage

```typescript
import { createXentraClient } from "@x12i/xentra-sdk";

const xentra = createXentraClient({
  baseUrl: "https://api.xentra.x12i.io",
  getToken: () => keycloak.getAccessToken(), // human flows
});

// Backend provisioning (service key variant)
const admin = createXentraClient({
  baseUrl: "https://api.xentra.x12i.io",
  apiKey: process.env.XENTRA_SERVICE_API_KEY!,
});

// --- Tenant ---
const { data: account } = await admin.accounts.create({
  name: "Acme Corp",
  slug: "acme",
});

// --- Permission gate ---
const { data: check } = await xentra.permissions.can(account.id, {
  action: "documents.publish",
  resource: { resourceType: "document", resourceId: docId },
  context: { accountId: account.id },
});
if (!check.allowed) {
  if (check.reason === "requires_human_approval") {
    await xentra.approvals.createRequest(account.id, { /* … */ });
  }
  throw new ForbiddenError(check.reason);
}

// --- Agent token (never call Authix directly) ---
const { data: issued } = await xentra.tokens.issue(account.id, {
  appId: "docs-agent",
  actor: { type: "agent", id: agentId },
  onBehalfOf: { type: "user", id: userId },
  scope: { accountIds: [account.id] },
  expiresAt: new Date(Date.now() + 3600_000).toISOString(),
});
// issued.grant → Mongo record
// issued.token → Authix JWT for the agent runtime

// --- Revoke on incident ---
await xentra.tokens.revoke(account.id, issued.grant.id);
```

List endpoints return `{ items, nextCursor }`. OpenAPI is published at `https://api.xentra.x12i.io/openapi.json` with no internal-only paths.

---

### Token grant model

Every issued token has a **Xentra grant** row:

| Field | Meaning |
|-------|---------|
| `accountId` | Tenant scope |
| `actor` | Who the token represents (usually an agent) |
| `onBehalfOf` | Optional human context |
| `appId` | Your product's Authix application id |
| `scope.accountIds` / `workspaceIds` | Where the token is valid |
| `authxTokenId` | Link to Authix for revoke/verify |
| `status` | `active` \| `revoked` |
| `expiresAt` | Optional TTL |

`GET .../tokens` lists active grants for an account. Security and support teams query audit for `token.issued` / `token.revoked` without touching Authix logs directly.

---

### Operations (platform team)

Production runs as a managed stack:

| Service | URL (example) | Health |
|---------|---------------|--------|
| Xentra API | `https://api.xentra.x12i.io` | `/health`, `/ready`, `/metrics` |
| Keycloak | `https://auth.x12i.io/realms/xentra` | IdP status page |
| Authix | `https://authix.x12i.io` | Included in Xentra `/ready` |
| Cerbos | internal TLS gRPC | Included in Xentra `/ready` |
| MongoDB | replica set | Included in Xentra `/ready` |

`/ready` returns 503 if **any** dependency is down — products should backoff and retry. Token routes return `503 authix_unavailable` when Authix is misconfigured or unreachable.

Secrets (`KEYCLOAK_*`, `AUTHIX_*`, `XENTRA_SERVICE_API_KEYS`) live in the platform secrets manager; products receive per-environment API keys and Authix `appId` values during onboarding.

---

### Onboarding checklist (product team)

**Platform gives you:**
- [ ] Keycloak client(s) for your SPA/backend
- [ ] Authix `appId` registered for your product
- [ ] Xentra service API key in secrets
- [ ] Staging + production base URLs

**You ship:**
- [ ] `@x12i/xentra-sdk` in backend
- [ ] Action vocabulary documented (`yourproduct.action`)
- [ ] `access/check` on every sensitive mutation
- [ ] Agent tokens only via `tokens/issue`
- [ ] Approval policies for risky actions (if agentic)
- [ ] Audit spot-check in staging

**Launch:**
- [ ] Rotate keys from staging to prod
- [ ] Load-test `/access/check`
- [ ] Subscribe to status page

---

### The division of labour (memorize this)

| Question | Who answers |
|----------|-------------|
| Who logged in? | **Keycloak** |
| Which account and role? | **Xentra** |
| Can they do this action? | **Xentra** (`access/check`) |
| Can this agent use this tool? | **Xentra** (governance + invoke) |
| Must a human approve first? | **Xentra** (approval policies) |
| Sign this agent JWT | **Authix** (via Xentra only) |
| What happened? | **Xentra** (audit) |
| Are they paying? | **Your product** (Stripe) |
| Is this feature rolled out? | **Your product** (flags) |

---

### Related

- [full-reference.md](./full-reference.md) — complete GA reference (routes, config, use cases)
- [product-overview.md](./product-overview.md) — five things Xentra owns
- [architecture.md](./architecture.md) — route matrix and stack detail
- [Authix repo](https://github.com/x12i/authix) — token service source
- [implementation/target/integration-guide.md](../implementation/target/integration-guide.md) — curl flows

## Architecture at GA

Full Xentra stack when all gaps are closed.

**Identity:** Human users authenticate via **Keycloak** (OIDC). Agent tokens are signed by **Authix**. Xentra sits between them and owns five capabilities: multi-tenant data model, permission evaluation, agent governance, approval policies, and audit. Keycloak and Authix integration are thin bridges — load-bearing in production.

---

### Product level

Xentra is deployed as a **managed control plane**: products call one HTTP API (or embed libraries) for tenant IAM, permissions, agents, approvals, and audit. Humans authenticate via Keycloak; agents receive scoped tokens via Authix; every decision is logged.

---

### Technical level

#### Stack diagram

```
Product apps / Admin UI (Keycloak OIDC)
        │ HTTPS + JWT / service API key
        ▼
   Xentra API (:8787)
        ├── MongoDB — tenant data, grants, audit
        ├── Cerbos (TLS gRPC) — policies from policies/
        ├── Keycloak — human OIDC + Admin REST
        └── Authix (HTTPS) — token mint/verify
```

| Component | Owner | Role |
|-----------|-------|------|
| Xentra monorepo | x12i | IAM, agents, approvals, audit, API |
| Authix | Separate repo | Token signing |
| Keycloak | Ops / IdP team | Login, user directory |
| Cerbos | Xentra policies | Authorization PDP |

---

### HTTP API — complete route matrix (GA)

All routes except `/health`, `/ready`, `/metrics` require `Authorization: Bearer <jwt-or-service-key>`.

| Method | Path | Authz (Cerbos) |
|--------|------|----------------|
| GET | `/health` | — |
| GET | `/ready` | — (mongo, authix, cerbos) |
| GET | `/metrics` | — |
| GET/POST | `/v1/accounts` | Membership / service account |
| GET/PATCH/DELETE | `/v1/accounts/:accountId` | `account` actions |
| GET | `/v1/users/me` | User JWT |
| GET | `/v1/users/:userId` | Membership-scoped |
| GET/POST | `.../members` | `read`, `invite_member` |
| PATCH/DELETE | `.../members/:memberId` | `change_member_role`, `remove_member` |
| POST | `.../access/check` | Authenticated; actor from JWT |
| GET/POST | `.../teams` | Team CRUD |
| GET/PATCH/DELETE | `.../teams/:teamId` | Team CRUD |
| GET/POST | `.../workspaces` | Workspace CRUD |
| GET/PATCH/DELETE | `.../workspaces/:workspaceId` | Workspace CRUD |
| GET/POST | `.../agents` | `agent` read/create |
| PATCH/DELETE | `.../agents/:agentId` | `update`, `delete`, `deactivate` |
| GET/POST | `.../delegations` | Delegation CRUD |
| DELETE | `.../delegations/:delegationId` | Revoke delegation |
| POST | `.../tools/invoke` | `tools` / `invoke` |
| POST/GET | `.../tokens/issue`, `.../tokens`, etc. | `token` actions + Authix |
| POST | `.../tokens/revoke` | `revoke` |
| GET | `.../audit` | `read` / `audit` |
| GET/POST | `.../approval-requests` | Approval workflow |
| POST | `.../approval-requests/:id/approve` | `approve` |
| POST | `.../approval-requests/:id/reject` | `reject` |
| GET/POST/PATCH/DELETE | `.../approval-policies` | Policy CRUD |

#### Pagination

List endpoints: `?limit=` (max 200), `?cursor=` → `{ data: { items, nextCursor } }`.

#### Cerbos vocabulary

Policies in [`policies/`](../../policies/). Resource types: `account`, `agent`, `token`, `approval`, `audit`, `admin`, `tools`, `team`, `workspace`.

Default roles per account: `owner`, `admin`, `member`, `viewer`, `agent-admin`, `security-admin`, `serviceAccount`.

---

### Dev preview delta

Routes marked **No** in [gaps/current-state.md](../gaps/current-state.md) are the delta from this target.

---

### Related

- [product-overview.md](./product-overview.md)
- [implementation/target/integration-guide.md](../implementation/target/integration-guide.md)

## Product overview at GA

### Product level

#### The problem it solves

Every multi-tenant SaaS product eventually needs: customer accounts, team members, roles, “can this user do X?”, and — for agentic products — rules for what AI agents may do and when a human must approve. Most teams rebuild that from scratch. Xentra is the answer to not doing that again.

#### What Xentra is

Xentra is the **shared foundation** for x12i agentic products. **Keycloak** handles human login. **Authix** handles token signing. **Xentra owns everything in between.**

#### What Xentra owns (five things)

| # | Capability | You get |
|---|------------|---------|
| 1 | **Multi-tenant data model** | Accounts, workspaces, teams, members, roles |
| 2 | **Permission evaluation** | `access/check` — allow, deny, or needs approval |
| 3 | **Agent governance** | Agents, tool allow-lists, delegations, invoke gateway |
| 4 | **Approval policies** | Auto-intercept, request queue, notifications |
| 5 | **Audit** | Structured history of checks, mutations, tokens, approvals |

Everything else is **delegated** (Keycloak login, Authix cryptography) or a **thin bridge** (JWT validation, grant bookkeeping). Product teams integrate the five capabilities — not the bridges.

```
Keycloak ──JWT──► Xentra (5 things) ◄── Authix
```

#### What Xentra is not

- Not a login system — **Keycloak** (required)
- Not a token signer — **Authix** (required for agent tokens)
- Not a replacement for product business logic
- Not feature flags

See [full-reference.md](./full-reference.md) for the complete GA-target reference.

#### How to integrate

0. Users log in via **Keycloak**; pass JWT to Xentra
1. Create an account per tenant
2. Name your actions (`documents.sign`, …)
3. Call `access/check` before sensitive operations
4. Issue agent tokens **through Xentra** (Authix bridge)

---

### Technical level

#### Core concepts

| Concept | Description |
|---------|-------------|
| **Account** | Top-level tenancy with members and roles |
| **Permission check** | `can(actor, action, resource)` — engine behind `access/check` |
| **Agent** | Non-human actor with tool allow-list |
| **Approval** | Policy-gated human sign-off |
| **Audit** | Immutable log of checks and mutations |
| **Keycloak bridge** | JWKS validation, user provisioning from JWT `sub` |
| **Authix bridge** | Grant rows in Mongo + audit around token mint/revoke |

See [architecture.md](./architecture.md) for stack and routes.

---

### Related

- [full-reference.md](./full-reference.md)
- [architecture.md](./architecture.md)
- [external-positioning.md](./external-positioning.md)
- [gaps/current-state.md](../gaps/current-state.md)

## External positioning

How to present Xentra to x12i product teams, partners, security, SRE, and executives at GA.

---

### Product level

#### Elevator pitch

**Xentra** is the shared identity, access, and agent-governance layer for x12i agentic SaaS products:

- Multi-tenant accounts — organisations, workspaces, teams, memberships, roles
- Permission checks — `can(actor, action, resource)` with roles, rules, delegations
- Agentic IAM — agent identities, tool allow-lists, human-to-agent delegations
- Human-in-the-loop — approval policies and workflows with notifications
- Scoped tokens — via Authix; Xentra manages grants and audit
- Audit trail — structured events for security and compliance

**One-liner for executives:** Xentra is the control plane for who and what can act inside x12i agentic products.

#### Differentiators

- Built for **agents**, not just humans
- Native **Authix** token scoping for multi-product platforms
- **Open contracts** — TypeScript types, Zod, OpenAPI for codegen

#### What Xentra is not

| Not… | Instead… |
|------|----------|
| Full UI product | Admin UI for governance; products bring product UI |
| Keycloak replacement | Keycloak remains IdP |
| Authix replacement | Authix issues tokens; Xentra manages policy + grants |
| Feature flags | IAM only |

---

### Technical level

#### Audience messaging

**Product engineering:** One permission model, one agent model, one audit format — integrate via SDK or HTTP.

**Security / compliance:** Central audit; delegation expiry; SoD via approval policies; Authix scoped tokens; Keycloak credentials.

**Platform / SRE:** Stateless API; scale horizontally; status page per dependency (API, Mongo, Keycloak, Authix, Cerbos).

#### SLA placeholders (define before GA)

| Tier | Availability | Support |
|------|--------------|---------|
| Internal staging | Best effort | Slack #xentra |
| Production | TBD (e.g. 99.9%) | TBD on-call |

#### Versioning policy

- HTTP: `/v1/` → breaking changes require `/v2/`
- npm: semver via Changesets
- 30-day notice before breaking API removal

#### Branding

| Item | Value |
|------|--------|
| Product name | **Xentra** |
| npm scope | `@x12i/xentra-*` |
| Production API | `https://api.xentra.x12i.io` |
| Tagline | Agentic IAM for x12i products |

Consistent terms: **Xentra account**, **actor**, **grant**, **delegation**.

#### GA deliverables

| Artifact | Channel |
|----------|---------|
| Getting started | docs.x12i.io/xentra |
| OpenAPI / Redoc | `/openapi.json` |
| SDK reference | npm |
| Action key registry | internal wiki |
| Status page | incidents |
| Changelog | GitHub releases |

#### Launch post outline

1. Problem: IAM for agentic SaaS differs from human-only IAM
2. Solution: Xentra + Authix + Keycloak
3. Capabilities: accounts, permissions, agents, approvals, audit
4. Integration: SDK snippet
5. How to get access

#### Legal outline (complete with legal)

- Data: account metadata, user ids/emails, roles, agent configs, audit, grant metadata
- Residency: MongoDB region
- Subprocessors: MongoDB host, Keycloak, Authix, cloud provider

---

### Related

- [product-overview.md](./product-overview.md)
- [implementation/target/service-guide.md](../implementation/target/service-guide.md)
- [gaps/production-blockers.md](../gaps/production-blockers.md)

## Quality bar

GA docs and product must not carry Work In Progress labeling. Blockers in Gaps must be closed. See Next Release Contract.

---

# Vision and GA — builders

# Vision and GA — Operators
**Audience:** Operators planning production-ready posture.
**Twin:** [Developers version](../developers/BOOK.md)
**Package:** `@x12i/xentra-*` · **Docs:** https://docs.xentra.x12i.com · **Status:** Work In Progress

---

## Platform narrative

**Audience:** Product engineers building agentic SaaS at x12i.

**Timeframe:** This document describes the platform **as shipped** — Keycloak, Xentra, and Authix running together in production. Read it as the story of how your product plugs in on day one.

For the modular GA reference see [full-reference.md](./full-reference.md). For today's developer preview see [gaps/current-state.md](../gaps/current-state.md).

---

### The platform in one picture

Every x12i agentic product sits on the same three-layer stack:

```
┌─────────────────────────────────────────────────────────────────┐
│  Your product (CRM, docs, agents, …)                            │
│  Business logic · UI · Stripe · feature flags (yours)           │
└───────────────┬───────────────────────────────┬─────────────────┘
                │ Keycloak JWT (humans)          │ Authix JWT (agents)
                ▼                                ▼
┌─────────────────────────── XENTRA ──────────────────────────────┐
│  Accounts · roles · access/check · agents · approvals · audit   │
│  Grant records in Mongo · policy via Cerbos                     │
└───────────────┬───────────────────────────────┬─────────────────┘
                │                               │
         ┌──────▼──────┐                 ┌──────▼──────┐
         │  Keycloak   │                 │   Authix    │
         │  human SSO  │                 │ token sign  │
         └─────────────┘                 └─────────────┘
```

**Keycloak** — users log in.  
**Xentra** — tenants, permissions, agents, approvals, audit.  
**Authix** — signed credentials for agents and services.

You never call Authix directly from a product backend for agent tokens. You call **Xentra**; Xentra calls Authix and keeps the grant ledger.

---

### What you skip building

| Without the platform | With Xentra + Authix |
|----------------------|----------------------|
| Org/user/membership tables per product | Shared accounts, teams, workspaces, roles |
| RBAC middleware in every service | One `access/check` before sensitive work |
| Rolling your own agent API keys | Scoped Authix tokens with grant + audit |
| “Manager must approve” state machines | Approval policies with auto-intercept + notifications |
| Cross-product “same customer, different apps” | One Keycloak user → one Xentra account everywhere |

Billing (Stripe) and feature flags stay **in your product**. Xentra holds `plan` / `billingCustomerId` on the account if you want to link them — it does not process payments.

---

### Day-one integration

#### Humans

1. User signs in via **Keycloak OIDC** in your app.
2. Your frontend sends `Authorization: Bearer <keycloak-access-token>` to Xentra.
3. First `GET /v1/users/me` creates the Xentra user from Keycloak `sub` and returns their accounts.
4. Before any mutation, your backend calls `POST .../access/check`.

#### Agents

1. Register the agent in Xentra (`POST .../agents`).
2. Register tools and set the agent allow-list.
3. User delegates specific actions with an expiry (`POST .../delegations`).
4. Your backend issues a token **through Xentra** (`POST .../tokens/issue`).
5. Agent runtime uses the returned Authix JWT; verify/introspect also goes through Xentra.
6. Revoke via `POST .../tokens/revoke` — Authix invalidates the token; Xentra marks the grant revoked and writes audit.

---

### The Authix bridge (why tokens go through Xentra)

Authix is excellent at **signing and verifying** tokens. It does not know your tenant model, your approval policies, or your audit requirements.

Xentra's bridge (`apps/api/src/authix/bridge.ts`) sits in the middle:

```
Product  →  POST /tokens/issue  →  Xentra
                                      │
                    ┌─────────────────┼─────────────────┐
                    │                 │                 │
              Cerbos allow?     Create grant      Authix.issueToken()
              (issue/token)     in Mongo          (cryptography)
                    │                 │                 │
                    └─────────────────┴─────────────────┘
                                      │
                              audit: token.issued
                                      │
                    ← { grant, token } ── product gives token to agent
```

**On issue:** Xentra checks permission → maps actor/scope to Authix → persists `XentraTokenGrant` with `authxTokenId` → appends audit → returns JWT to caller.

**On verify:** Xentra asks Authix → optionally enriches with the Mongo grant (account, actor, scope, on-behalf-of).

**On revoke:** Xentra revokes in Authix → updates grant status → audit.

Products get **one integration surface** (Xentra API/SDK). Platform ops run Authix as a shared service with published images, health checks in `/ready`, and rotated API keys.

---

### End-to-end: agent acts on behalf of a user

**Scenario:** A docs product has an agent that can post to Slack on behalf of an admin, but only after policy allows it.

```
1. Admin logs in (Keycloak)
2. Admin delegates tools.invoke to agent_7 for 24h (Xentra delegations)
3. Backend issues agent token (Xentra → Authix), scope = account + onBehalfOf user
4. Agent calls POST .../tools/invoke with Authix JWT
5. Xentra checks: Cerbos invoke + allow-list + delegation not expired
6. Audit: tools.invoke success
7. Product calls Slack with its own connector
```

If an approval policy matches the action earlier in the flow, step 4 never happens until a human approves — `access/check` returns `requires_human_approval`, the product creates an approval request, approvers get notified, and only then does execution continue.

---

### End-to-end: service-to-service

Backend jobs use **Xentra service API keys** (machine identity) for account provisioning and permission checks. Agent workers use **Authix tokens** issued via Xentra grants. Humans use **Keycloak JWTs**. All three actor types appear in audit with the same schema.

| Caller | Credential | Typical use |
|--------|------------|-------------|
| Human | Keycloak JWT | UI-driven CRUD, invites |
| Product backend | Service API key | Provision tenant, impersonate in checks (audited) |
| Agent runtime | Authix token from Xentra grant | Tool invoke, delegated actions |

---

### SDK — production usage

```typescript
import { createXentraClient } from "@x12i/xentra-sdk";

const xentra = createXentraClient({
  baseUrl: "https://api.xentra.x12i.io",
  getToken: () => keycloak.getAccessToken(), // human flows
});

// Backend provisioning (service key variant)
const admin = createXentraClient({
  baseUrl: "https://api.xentra.x12i.io",
  apiKey: process.env.XENTRA_SERVICE_API_KEY!,
});

// --- Tenant ---
const { data: account } = await admin.accounts.create({
  name: "Acme Corp",
  slug: "acme",
});

// --- Permission gate ---
const { data: check } = await xentra.permissions.can(account.id, {
  action: "documents.publish",
  resource: { resourceType: "document", resourceId: docId },
  context: { accountId: account.id },
});
if (!check.allowed) {
  if (check.reason === "requires_human_approval") {
    await xentra.approvals.createRequest(account.id, { /* … */ });
  }
  throw new ForbiddenError(check.reason);
}

// --- Agent token (never call Authix directly) ---
const { data: issued } = await xentra.tokens.issue(account.id, {
  appId: "docs-agent",
  actor: { type: "agent", id: agentId },
  onBehalfOf: { type: "user", id: userId },
  scope: { accountIds: [account.id] },
  expiresAt: new Date(Date.now() + 3600_000).toISOString(),
});
// issued.grant → Mongo record
// issued.token → Authix JWT for the agent runtime

// --- Revoke on incident ---
await xentra.tokens.revoke(account.id, issued.grant.id);
```

List endpoints return `{ items, nextCursor }`. OpenAPI is published at `https://api.xentra.x12i.io/openapi.json` with no internal-only paths.

---

### Token grant model

Every issued token has a **Xentra grant** row:

| Field | Meaning |
|-------|---------|
| `accountId` | Tenant scope |
| `actor` | Who the token represents (usually an agent) |
| `onBehalfOf` | Optional human context |
| `appId` | Your product's Authix application id |
| `scope.accountIds` / `workspaceIds` | Where the token is valid |
| `authxTokenId` | Link to Authix for revoke/verify |
| `status` | `active` \| `revoked` |
| `expiresAt` | Optional TTL |

`GET .../tokens` lists active grants for an account. Security and support teams query audit for `token.issued` / `token.revoked` without touching Authix logs directly.

---

### Operations (platform team)

Production runs as a managed stack:

| Service | URL (example) | Health |
|---------|---------------|--------|
| Xentra API | `https://api.xentra.x12i.io` | `/health`, `/ready`, `/metrics` |
| Keycloak | `https://auth.x12i.io/realms/xentra` | IdP status page |
| Authix | `https://authix.x12i.io` | Included in Xentra `/ready` |
| Cerbos | internal TLS gRPC | Included in Xentra `/ready` |
| MongoDB | replica set | Included in Xentra `/ready` |

`/ready` returns 503 if **any** dependency is down — products should backoff and retry. Token routes return `503 authix_unavailable` when Authix is misconfigured or unreachable.

Secrets (`KEYCLOAK_*`, `AUTHIX_*`, `XENTRA_SERVICE_API_KEYS`) live in the platform secrets manager; products receive per-environment API keys and Authix `appId` values during onboarding.

---

### Onboarding checklist (product team)

**Platform gives you:**
- [ ] Keycloak client(s) for your SPA/backend
- [ ] Authix `appId` registered for your product
- [ ] Xentra service API key in secrets
- [ ] Staging + production base URLs

**You ship:**
- [ ] `@x12i/xentra-sdk` in backend
- [ ] Action vocabulary documented (`yourproduct.action`)
- [ ] `access/check` on every sensitive mutation
- [ ] Agent tokens only via `tokens/issue`
- [ ] Approval policies for risky actions (if agentic)
- [ ] Audit spot-check in staging

**Launch:**
- [ ] Rotate keys from staging to prod
- [ ] Load-test `/access/check`
- [ ] Subscribe to status page

---

### The division of labour (memorize this)

| Question | Who answers |
|----------|-------------|
| Who logged in? | **Keycloak** |
| Which account and role? | **Xentra** |
| Can they do this action? | **Xentra** (`access/check`) |
| Can this agent use this tool? | **Xentra** (governance + invoke) |
| Must a human approve first? | **Xentra** (approval policies) |
| Sign this agent JWT | **Authix** (via Xentra only) |
| What happened? | **Xentra** (audit) |
| Are they paying? | **Your product** (Stripe) |
| Is this feature rolled out? | **Your product** (flags) |

---

### Related

- [full-reference.md](./full-reference.md) — complete GA reference (routes, config, use cases)
- [product-overview.md](./product-overview.md) — five things Xentra owns
- [architecture.md](./architecture.md) — route matrix and stack detail
- [Authix repo](https://github.com/x12i/authix) — token service source
- [implementation/target/integration-guide.md](../implementation/target/integration-guide.md) — curl flows

## Architecture at GA

Full Xentra stack when all gaps are closed.

**Identity:** Human users authenticate via **Keycloak** (OIDC). Agent tokens are signed by **Authix**. Xentra sits between them and owns five capabilities: multi-tenant data model, permission evaluation, agent governance, approval policies, and audit. Keycloak and Authix integration are thin bridges — load-bearing in production.

---

### Product level

Xentra is deployed as a **managed control plane**: products call one HTTP API (or embed libraries) for tenant IAM, permissions, agents, approvals, and audit. Humans authenticate via Keycloak; agents receive scoped tokens via Authix; every decision is logged.

---

### Technical level

#### Stack diagram

```
Product apps / Admin UI (Keycloak OIDC)
        │ HTTPS + JWT / service API key
        ▼
   Xentra API (:8787)
        ├── MongoDB — tenant data, grants, audit
        ├── Cerbos (TLS gRPC) — policies from policies/
        ├── Keycloak — human OIDC + Admin REST
        └── Authix (HTTPS) — token mint/verify
```

| Component | Owner | Role |
|-----------|-------|------|
| Xentra monorepo | x12i | IAM, agents, approvals, audit, API |
| Authix | Separate repo | Token signing |
| Keycloak | Ops / IdP team | Login, user directory |
| Cerbos | Xentra policies | Authorization PDP |

---

### HTTP API — complete route matrix (GA)

All routes except `/health`, `/ready`, `/metrics` require `Authorization: Bearer <jwt-or-service-key>`.

| Method | Path | Authz (Cerbos) |
|--------|------|----------------|
| GET | `/health` | — |
| GET | `/ready` | — (mongo, authix, cerbos) |
| GET | `/metrics` | — |
| GET/POST | `/v1/accounts` | Membership / service account |
| GET/PATCH/DELETE | `/v1/accounts/:accountId` | `account` actions |
| GET | `/v1/users/me` | User JWT |
| GET | `/v1/users/:userId` | Membership-scoped |
| GET/POST | `.../members` | `read`, `invite_member` |
| PATCH/DELETE | `.../members/:memberId` | `change_member_role`, `remove_member` |
| POST | `.../access/check` | Authenticated; actor from JWT |
| GET/POST | `.../teams` | Team CRUD |
| GET/PATCH/DELETE | `.../teams/:teamId` | Team CRUD |
| GET/POST | `.../workspaces` | Workspace CRUD |
| GET/PATCH/DELETE | `.../workspaces/:workspaceId` | Workspace CRUD |
| GET/POST | `.../agents` | `agent` read/create |
| PATCH/DELETE | `.../agents/:agentId` | `update`, `delete`, `deactivate` |
| GET/POST | `.../delegations` | Delegation CRUD |
| DELETE | `.../delegations/:delegationId` | Revoke delegation |
| POST | `.../tools/invoke` | `tools` / `invoke` |
| POST/GET | `.../tokens/issue`, `.../tokens`, etc. | `token` actions + Authix |
| POST | `.../tokens/revoke` | `revoke` |
| GET | `.../audit` | `read` / `audit` |
| GET/POST | `.../approval-requests` | Approval workflow |
| POST | `.../approval-requests/:id/approve` | `approve` |
| POST | `.../approval-requests/:id/reject` | `reject` |
| GET/POST/PATCH/DELETE | `.../approval-policies` | Policy CRUD |

#### Pagination

List endpoints: `?limit=` (max 200), `?cursor=` → `{ data: { items, nextCursor } }`.

#### Cerbos vocabulary

Policies in [`policies/`](../../policies/). Resource types: `account`, `agent`, `token`, `approval`, `audit`, `admin`, `tools`, `team`, `workspace`.

Default roles per account: `owner`, `admin`, `member`, `viewer`, `agent-admin`, `security-admin`, `serviceAccount`.

---

### Dev preview delta

Routes marked **No** in [gaps/current-state.md](../gaps/current-state.md) are the delta from this target.

---

### Related

- [product-overview.md](./product-overview.md)
- [implementation/target/integration-guide.md](../implementation/target/integration-guide.md)

## Product overview at GA

### Product level

#### The problem it solves

Every multi-tenant SaaS product eventually needs: customer accounts, team members, roles, “can this user do X?”, and — for agentic products — rules for what AI agents may do and when a human must approve. Most teams rebuild that from scratch. Xentra is the answer to not doing that again.

#### What Xentra is

Xentra is the **shared foundation** for x12i agentic products. **Keycloak** handles human login. **Authix** handles token signing. **Xentra owns everything in between.**

#### What Xentra owns (five things)

| # | Capability | You get |
|---|------------|---------|
| 1 | **Multi-tenant data model** | Accounts, workspaces, teams, members, roles |
| 2 | **Permission evaluation** | `access/check` — allow, deny, or needs approval |
| 3 | **Agent governance** | Agents, tool allow-lists, delegations, invoke gateway |
| 4 | **Approval policies** | Auto-intercept, request queue, notifications |
| 5 | **Audit** | Structured history of checks, mutations, tokens, approvals |

Everything else is **delegated** (Keycloak login, Authix cryptography) or a **thin bridge** (JWT validation, grant bookkeeping). Product teams integrate the five capabilities — not the bridges.

```
Keycloak ──JWT──► Xentra (5 things) ◄── Authix
```

#### What Xentra is not

- Not a login system — **Keycloak** (required)
- Not a token signer — **Authix** (required for agent tokens)
- Not a replacement for product business logic
- Not feature flags

See [full-reference.md](./full-reference.md) for the complete GA-target reference.

#### How to integrate

0. Users log in via **Keycloak**; pass JWT to Xentra
1. Create an account per tenant
2. Name your actions (`documents.sign`, …)
3. Call `access/check` before sensitive operations
4. Issue agent tokens **through Xentra** (Authix bridge)

---

### Technical level

#### Core concepts

| Concept | Description |
|---------|-------------|
| **Account** | Top-level tenancy with members and roles |
| **Permission check** | `can(actor, action, resource)` — engine behind `access/check` |
| **Agent** | Non-human actor with tool allow-list |
| **Approval** | Policy-gated human sign-off |
| **Audit** | Immutable log of checks and mutations |
| **Keycloak bridge** | JWKS validation, user provisioning from JWT `sub` |
| **Authix bridge** | Grant rows in Mongo + audit around token mint/revoke |

See [architecture.md](./architecture.md) for stack and routes.

---

### Related

- [full-reference.md](./full-reference.md)
- [architecture.md](./architecture.md)
- [external-positioning.md](./external-positioning.md)
- [gaps/current-state.md](../gaps/current-state.md)

## External positioning

How to present Xentra to x12i product teams, partners, security, SRE, and executives at GA.

---

### Product level

#### Elevator pitch

**Xentra** is the shared identity, access, and agent-governance layer for x12i agentic SaaS products:

- Multi-tenant accounts — organisations, workspaces, teams, memberships, roles
- Permission checks — `can(actor, action, resource)` with roles, rules, delegations
- Agentic IAM — agent identities, tool allow-lists, human-to-agent delegations
- Human-in-the-loop — approval policies and workflows with notifications
- Scoped tokens — via Authix; Xentra manages grants and audit
- Audit trail — structured events for security and compliance

**One-liner for executives:** Xentra is the control plane for who and what can act inside x12i agentic products.

#### Differentiators

- Built for **agents**, not just humans
- Native **Authix** token scoping for multi-product platforms
- **Open contracts** — TypeScript types, Zod, OpenAPI for codegen

#### What Xentra is not

| Not… | Instead… |
|------|----------|
| Full UI product | Admin UI for governance; products bring product UI |
| Keycloak replacement | Keycloak remains IdP |
| Authix replacement | Authix issues tokens; Xentra manages policy + grants |
| Feature flags | IAM only |

---

### Technical level

#### Audience messaging

**Product engineering:** One permission model, one agent model, one audit format — integrate via SDK or HTTP.

**Security / compliance:** Central audit; delegation expiry; SoD via approval policies; Authix scoped tokens; Keycloak credentials.

**Platform / SRE:** Stateless API; scale horizontally; status page per dependency (API, Mongo, Keycloak, Authix, Cerbos).

#### SLA placeholders (define before GA)

| Tier | Availability | Support |
|------|--------------|---------|
| Internal staging | Best effort | Slack #xentra |
| Production | TBD (e.g. 99.9%) | TBD on-call |

#### Versioning policy

- HTTP: `/v1/` → breaking changes require `/v2/`
- npm: semver via Changesets
- 30-day notice before breaking API removal

#### Branding

| Item | Value |
|------|--------|
| Product name | **Xentra** |
| npm scope | `@x12i/xentra-*` |
| Production API | `https://api.xentra.x12i.io` |
| Tagline | Agentic IAM for x12i products |

Consistent terms: **Xentra account**, **actor**, **grant**, **delegation**.

#### GA deliverables

| Artifact | Channel |
|----------|---------|
| Getting started | docs.x12i.io/xentra |
| OpenAPI / Redoc | `/openapi.json` |
| SDK reference | npm |
| Action key registry | internal wiki |
| Status page | incidents |
| Changelog | GitHub releases |

#### Launch post outline

1. Problem: IAM for agentic SaaS differs from human-only IAM
2. Solution: Xentra + Authix + Keycloak
3. Capabilities: accounts, permissions, agents, approvals, audit
4. Integration: SDK snippet
5. How to get access

#### Legal outline (complete with legal)

- Data: account metadata, user ids/emails, roles, agent configs, audit, grant metadata
- Residency: MongoDB region
- Subprocessors: MongoDB host, Keycloak, Authix, cloud provider

---

### Related

- [product-overview.md](./product-overview.md)
- [implementation/target/service-guide.md](../implementation/target/service-guide.md)
- [gaps/production-blockers.md](../gaps/production-blockers.md)

## Quality bar

GA docs and product must not carry Work In Progress labeling. Blockers in Gaps must be closed. See Next Release Contract.

---

# Gaps — developers

# Gaps — Developers
**Audience:** Required reading while documentation is Work In Progress.
**Twin:** [Operators version](../builders/BOOK.md)
**Package:** `@x12i/xentra-*` · **Docs:** https://docs.xentra.x12i.com · **Status:** Work In Progress

---

## Developer preview maturity

**Last updated:** 2026-06-01

Canonical reference for what Xentra **has today** in the developer preview. For missing work see [product-backlog.md](./product-backlog.md). For how to use it see [implementation/current/](../implementation/current/).

---

### Maturity summary

| Layer | Status | Notes |
|-------|--------|-------|
| **npm libraries** (`types`, `core`, `store`, `permissions`, …) | Usable | Embed in your app or call HTTP API |
| **MongoDB store** | Implemented | Transactions, Testcontainers in CI |
| **Cerbos PDP** | Implemented | Policies in `policies/`; fail-closed in production |
| **HTTP API** | Developer preview | Auth + Cerbos on routes; not GA |
| **Authix integration** | Wired | External service via `@x12i/authix-client` |
| **Keycloak** | Partial | JWKS + Admin REST; realm import for dev |
| **Admin UI** | Scaffold | Manual JWT login; no OIDC redirect yet |
| **SDK / React** | Usable | Paginated list envelopes aligned with API |

---

### Architecture (today)

```
Product app
  → Xentra API (or embedded @x12i/xentra-* libraries)
      → MongoDB (tenant data)
      → Cerbos (authorization PDP)
      → Keycloak (human identity / JWT)
      → Authix (token mint/verify — separate repo)
```

| Component | Repo / package | Xentra owns |
|-----------|----------------|-------------|
| Tenant IAM, agents, approvals, audit | This monorepo | Yes |
| Token signing | [authix](https://github.com/x12i/authix) | No — client + bridge only |
| Human login | **Keycloak** (required) | Yes — JWKS + optional Admin sync |
| Policy decisions | Cerbos + `policies/*.yaml` | Yes (policy files) |

---

### Use cases — supported today

| Use case | How | Limitations |
|----------|-----|-------------|
| **Multi-tenant accounts** | `POST/GET /v1/accounts` | List scoped to memberships (users) or all (service accounts) |
| **Members & roles** | Members API + role PATCH | — |
| **Permission check before action** | `POST .../access/check` | Actor bound to JWT; approval auto-intercept when policy matches |
| **Cerbos-enforced mutations** | `requirePermission` middleware | Dev: in-process fallback if Cerbos down; prod: fail-closed |
| **Agent registration** | `POST/PATCH/DELETE .../agents` | Deactivate revokes delegations |
| **Delegations** | `GET/POST/DELETE .../delegations` | — |
| **Teams & workspaces** | `GET/POST/PATCH/DELETE .../teams`, `.../workspaces` | — |
| **Tool invoke gateway** | `POST .../tools/invoke` | Register tool via `POST .../tools` first |
| **Scoped agent tokens** | `POST .../tokens/issue` → Authix | Requires `AUTHIX_*`; 503 if unset |
| **Token revoke + grant audit** | `POST .../tokens/revoke`, Mongo grants | Verify enriched with grant when Authix returns `tokenId` |
| **Approval workflow** | Approval requests + approve/reject | Policies via HTTP; notifier is log-only |
| **Approval policies** | CRUD on `.../approval-policies` | Auto-intercept on `access/check` when policy matches |
| **Audit trail** | Writes on mutations + permission checks | Query via `GET .../audit` with filters |
| **Service-to-service API** | `XENTRA_SERVICE_API_KEYS` as Bearer | Long-lived shared keys — rotate in prod |
| **Local stack** | `docker compose` + `scripts/stack-smoke.sh` | Authix optional — separate repo |
| **Embed libraries** | `@x12i/xentra-permissions`, `store`, etc. | You bring persistence and IdP |

Unsupported use cases: [product-backlog.md](./product-backlog.md).

---

## What works today

Canonical route matrix and supported use cases (developer preview):

**Last updated:** 2026-06-01

Canonical reference for what Xentra **has today** in the developer preview. For missing work see [product-backlog.md](./product-backlog.md). For how to use it see [implementation/current/](../implementation/current/).

---

### Maturity summary

| Layer | Status | Notes |
|-------|--------|-------|
| **npm libraries** (`types`, `core`, `store`, `permissions`, …) | Usable | Embed in your app or call HTTP API |
| **MongoDB store** | Implemented | Transactions, Testcontainers in CI |
| **Cerbos PDP** | Implemented | Policies in `policies/`; fail-closed in production |
| **HTTP API** | Developer preview | Auth + Cerbos on routes; not GA |
| **Authix integration** | Wired | External service via `@x12i/authix-client` |
| **Keycloak** | Partial | JWKS + Admin REST; realm import for dev |
| **Admin UI** | Scaffold | Manual JWT login; no OIDC redirect yet |
| **SDK / React** | Usable | Paginated list envelopes aligned with API |

---

### Architecture (today)

```
Product app
  → Xentra API (or embedded @x12i/xentra-* libraries)
      → MongoDB (tenant data)
      → Cerbos (authorization PDP)
      → Keycloak (human identity / JWT)
      → Authix (token mint/verify — separate repo)
```

| Component | Repo / package | Xentra owns |
|-----------|----------------|-------------|
| Tenant IAM, agents, approvals, audit | This monorepo | Yes |
| Token signing | [authix](https://github.com/x12i/authix) | No — client + bridge only |
| Human login | **Keycloak** (required) | Yes — JWKS + optional Admin sync |
| Policy decisions | Cerbos + `policies/*.yaml` | Yes (policy files) |

---

### Use cases — supported today

| Use case | How | Limitations |
|----------|-----|-------------|
| **Multi-tenant accounts** | `POST/GET /v1/accounts` | List scoped to memberships (users) or all (service accounts) |
| **Members & roles** | Members API + role PATCH | — |
| **Permission check before action** | `POST .../access/check` | Actor bound to JWT; approval auto-intercept when policy matches |
| **Cerbos-enforced mutations** | `requirePermission` middleware | Dev: in-process fallback if Cerbos down; prod: fail-closed |
| **Agent registration** | `POST/PATCH/DELETE .../agents` | Deactivate revokes delegations |
| **Delegations** | `GET/POST/DELETE .../delegations` | — |
| **Teams & workspaces** | `GET/POST/PATCH/DELETE .../teams`, `.../workspaces` | — |
| **Tool invoke gateway** | `POST .../tools/invoke` | Register tool via `POST .../tools` first |
| **Scoped agent tokens** | `POST .../tokens/issue` → Authix | Requires `AUTHIX_*`; 503 if unset |
| **Token revoke + grant audit** | `POST .../tokens/revoke`, Mongo grants | Verify enriched with grant when Authix returns `tokenId` |
| **Approval workflow** | Approval requests + approve/reject | Policies via HTTP; notifier is log-only |
| **Approval policies** | CRUD on `.../approval-policies` | Auto-intercept on `access/check` when policy matches |
| **Audit trail** | Writes on mutations + permission checks | Query via `GET .../audit` with filters |
| **Service-to-service API** | `XENTRA_SERVICE_API_KEYS` as Bearer | Long-lived shared keys — rotate in prod |
| **Local stack** | `docker compose` + `scripts/stack-smoke.sh` | Authix optional — separate repo |
| **Embed libraries** | `@x12i/xentra-permissions`, `store`, etc. | You bring persistence and IdP |

Unsupported use cases: [product-backlog.md](./product-backlog.md).

---

### HTTP API — route matrix

All routes except `/health`, `/ready`, `/metrics` require `Authorization: Bearer <jwt-or-service-key>`.

| Method | Path | Authz (Cerbos) | Implemented |
|--------|------|----------------|-------------|
| GET | `/health` | — | Yes |
| GET | `/ready` | — | Yes (mongo, authix, cerbos) |
| GET | `/metrics` | — | Yes (Prometheus) |
| GET | `/v1/accounts` | Membership-scoped | Yes |
| POST | `/v1/accounts` | Service account in prod | Yes |
| GET | `/v1/accounts/:accountId` | `read` / `account` | Yes |
| PATCH | `/v1/accounts/:accountId` | `update` / `account` | Yes |
| DELETE | `/v1/accounts/:accountId` | `delete` / `account` | Yes |
| GET | `/v1/users/me` | User JWT only | Yes |
| GET | `/v1/users/:userId` | Membership-scoped | Yes |
| GET | `.../members` | `read` / `account` | Yes (paginated) |
| POST | `.../members` | `invite_member` / `account` | Yes |
| PATCH | `.../members/:memberId` | `change_member_role` / `account` | Yes |
| DELETE | `.../members/:memberId` | `remove_member` / `account` | Yes |
| POST | `.../access/check` | Authenticated; actor from JWT | Yes |
| GET | `.../agents` | `read` / `agent` | Yes (paginated) |
| POST | `.../agents` | `create` / `agent` | Yes |
| PATCH | `.../agents/:id` | `update` / `agent` | Yes |
| DELETE | `.../agents/:id` | `deactivate` / `agent` | Yes |
| GET/POST | `.../delegations` | `read`/`update` / `account` | Yes |
| DELETE | `.../delegations/:delegationId` | `update` / `account` | Yes |
| GET/POST | `.../tools` | `read`/`create` / `tools` | Yes (paginated list) |
| POST | `.../tools/invoke` | `invoke` / `tools` + allow-list | Yes |
| GET/POST | `.../teams` | `read`/`create` / `team` | Yes (paginated list) |
| PATCH/DELETE | `.../teams/:teamId` | `update`/`delete` / `team` | Yes |
| GET/POST | `.../workspaces` | `read`/`create` / `workspace` | Yes (paginated list) |
| PATCH/DELETE | `.../workspaces/:workspaceId` | `update`/`delete` / `workspace` | Yes |
| GET/PATCH/DELETE | `.../approval-policies/:policyId` | `read` / `create` / `approval` | Yes |
| POST | `.../tokens/issue` | `issue` / `token` + Authix | Yes |
| POST | `.../tokens/verify` | `list` / `token` + Authix | Yes |
| POST | `.../tokens/introspect` | `list` / `token` + Authix | Yes |
| POST | `.../tokens/revoke` | `revoke` / `token` + Authix | Yes |
| GET | `.../tokens` | `list` / `token` + Authix | Yes (paginated) |
| GET | `.../audit` | `read` / `audit` | Yes (paginated + filters) |
| GET/POST | `.../approval-requests` | `read` / `create` / `approval` | Yes (paginated list) |
| POST | `.../approval-requests/:id/approve` | `approve` / `approval` | Yes |
| POST | `.../approval-requests/:id/reject` | `reject` / `approval` | Yes |
| GET/POST | `.../approval-policies` | `read` / `create` / `approval` | Yes (paginated list) |

#### Pagination

List endpoints accept `?limit=` (max 200, default 50) and `?cursor=` (numeric offset as string). Response:

```json
{ "data": { "items": [ ... ], "nextCursor": "50" } }
```

Applies to: members, agents, tokens, approval-requests, approval-policies, audit, delegations, teams, workspaces, tools.

#### `/access/check` body

Request schema includes `actor`, but the API **binds the actor to the JWT** for user callers. Service accounts may pass a different `actor` in the body (audited as impersonation).

---

### Cerbos policy vocabulary

Policies live in [`policies/`](../../policies/). Roles are **membership role keys** on the account (`owner`, `admin`, `member`, …).

#### Roles (seeded per account)

| Role key | Purpose |
|----------|---------|
| `owner` | Full access (`*` on resources) |
| `admin` | Manage account, members, agents, tokens, approvals |
| `member` | Read + invite + create agents + issue tokens |
| `viewer` | Read-only |
| `billing-admin` | Read (placeholder) |
| `agent-admin` | Agent CRUD actions |
| `security-admin` | Audit/tokens/approvals/admin console |
| `agent` | Agent actor type (delegation context) |
| `serviceAccount` | Machine callers |

#### Resource types and actions

| Resource (`resourceType`) | Actions in policies |
|---------------------------|---------------------|
| `account` | `read`, `update`, `delete`, `invite_member`, `remove_member`, `change_member_role`, `*` (owner) |
| `agent` | `read`, `create`, `update`, `delete`, `deactivate` |
| `token` | `issue`, `revoke`, `list` |
| `approval` | `read`, `create`, `approve`, `reject` |
| `audit` | `read` |
| `admin` | `access` (admin UI `PermissionGate`) |
| `tools` | `read`, `create`, `invoke` |
| `team` | `read`, `create`, `update`, `delete` |
| `workspace` | `read`, `create`, `update`, `delete` |

---

### Auth model

| Caller | Bearer token | Behavior |
|--------|--------------|----------|
| **Human user** | Keycloak JWT | JWKS verify (prod); dev unsigned JWT if Keycloak unset |
| **Service** | Keycloak JWT or `XENTRA_SERVICE_API_KEYS` entry | `serviceAccount` actor; list all accounts; impersonate in access/check |
| **Unauthenticated** | — | 401 on all `/v1/*` routes |

Production **requires** Keycloak config — dev JWT decode is rejected.

---

### Authix (tokens)

| Item | Value |
|------|--------|
| Service repo | [github.com/x12i/authix](https://github.com/x12i/authix) |
| Client npm | `@x12i/authix-client` |
| Types npm | `@x12i/authx-token-types` (rename pending) |
| Xentra bridge | `apps/api/src/authix/bridge.ts` |
| Token routes without Authix | **503** `authix_unavailable` |

---

### Keycloak (dev defaults)

Imported via `deploy/keycloak/realm-xentra.json` when using compose `--import-realm`:

| Item | Value |
|------|--------|
| Realm | `xentra` |
| API client | `xentra-api` (confidential) |
| Dev client secret | `xentra-api-dev-secret` |
| Admin UI client | `xentra-admin-ui` (public) |
| Test user | `testuser` / `test` |

---

### Admin UI (`apps/admin`)

| Screen | Data source | Auth |
|--------|-------------|------|
| Accounts, members, agents, tokens, approvals, audit | SDK → API | Manual JWT / API key paste |
| Route guard | `PermissionGate` `access` on `admin` | Must pass Cerbos check via SDK |

---

### CI and testing

| Check | Where |
|-------|--------|
| Unit / API tests | `npm test` |
| Cerbos compile | `.github/workflows/ci.yml` |
| Stack smoke | `.github/workflows/stack-smoke.yml` |
| Mongo Testcontainers | `packages/store-mongo` (CI only unless `FORCE_TESTCONTAINERS=1`) |

---

### Related

- [package-status.md](./package-status.md) — per-package status
- [implementation/current/integration-guide.md](../implementation/current/integration-guide.md) — API examples
- [implementation/current/configuration.md](../implementation/current/configuration.md) — env vars

## Package status

**Last updated:** 2026-06-01

Per-package implementation status for the developer preview. ✅ implemented · ⚠️ partial · ❌ not yet.

For route-level detail see [current-state.md](./current-state.md). For future stories see [user-stories/](../user-stories/).

---

### `@x12i/xentra-types` ✅

- ✅ Shared entity types and Zod schemas
- ✅ JSON Schema export for OpenAPI

---

### `@x12i/xentra-core` ✅

- ✅ Pure account/membership/role models
- ✅ Delegation and tool access validation helpers

---

### `@x12i/xentra-store` ✅

- ✅ `XentraStoreBundle` interface
- ✅ `createMemoryStore()` + in-memory transactions

---

### `@x12i/xentra-store-mongo` ✅

- ✅ `createMongoStore()` with indexes
- ✅ Mongo transactions (`store.transaction()`)
- ✅ Testcontainers contract tests in CI
- ⚠️ Cursor tokens (offset only)

---

### `@x12i/xentra-identity` / `identity-keycloak` ⚠️

- ✅ JWKS JWT validation, Admin REST (groups, users)
- ⚠️ `KeycloakIdentityAdapter` — many methods still stub
- ❌ Full bidirectional IdP sync automation

---

### `@x12i/xentra-permissions` ✅

- ✅ In-process `can()` with reason codes
- ✅ Cerbos gRPC adapter; fail-closed in production
- ⚠️ Cerbos TLS not configured

---

### `@x12i/xentra-agentic` ✅

- ✅ Agent CRUD in library
- ✅ Tool allow-lists, delegations in library
- ✅ HTTP delegations, tools (register/list/invoke)

---

### `@x12i/xentra-api` ✅

- ✅ Auth on all `/v1/*` routes
- ✅ Cerbos on reads and writes
- ✅ Full IAM surface: accounts, members, agents, delegations, teams, workspaces, tools, tokens, audit, approvals, policies
- ✅ `GET /v1/users/:userId`, approval auto-intercept on access/check
---

### `@x12i/xentra-approvals` ✅

- ✅ Policies + requests in library
- ✅ HTTP for approval-requests and approval-policies
- ✅ `matchesPolicy` wired into `access/check` (auto-intercept)
- ❌ Real email/push notifications (log-only)

---

### `@x12i/xentra-audit` ✅

- ✅ Append + list by account/actor/target
- ✅ API audit route with filters + pagination
- ✅ Writes on account, member, agent, approval mutations

---

### Authix (external) ✅

- ✅ `@x12i/authix-client` in API
- ✅ Bridge: issue/revoke + Mongo grants + audit
- ⚠️ Types npm name still `@x12i/authx-token-types`
- ❌ Published Authix container image

---

### `@x12i/xentra-sdk` / `react` ✅

- ✅ Client for core routes; paginated list envelopes
- ✅ `members.updateRole`, `agents.update`, `agents.deactivate`, `users.get`
- ✅ `PermissionGate`, hooks (thin)

---

### `@x12i/xentra-admin` ⚠️

- ✅ Screens for accounts, members, agents, tokens, approvals, audit
- ⚠️ Manual JWT / API-key login
- ❌ Keycloak OIDC redirect

---

### `@x12i/xentra-openapi` ✅

- ✅ OpenAPI 3.1 aligned with implemented routes

---

### Cross-cutting product stories (today)

| Story | Status | Notes |
|-------|--------|-------|
| Create tenant + default roles | ✅ | `POST /v1/accounts`; Mongo transaction when available |
| Check permission before mutation | ✅ | `access/check` + route middleware |
| Register agent + allow-list tools | ✅ | PATCH agent for allow-list |
| Delegate user → agent | ✅ | `POST .../delegations` |
| Human approval for risky action | ✅ | Auto-intercept on `access/check`; requests API |
| Issue scoped agent token | ✅ | Requires Authix |
| Investigate audit trail | ✅ | `GET .../audit` |
| Admin console governance | ⚠️ | Scaffold; no OIDC |

---

### Related

- [product-backlog.md](./product-backlog.md) — what closes each ❌
- [test-coverage-gaps.md](./test-coverage-gaps.md) — QA matrix

## External production blockers

**Last updated:** 2026-06-01

For **what works today** see [current-state.md](./current-state.md). For **P2 product work** see [product-backlog.md](./product-backlog.md).

---

### Executive summary

| Area | Status |
|------|--------|
| API security (P0) | **Done in-repo** |
| Mongo store + transactions | **Done** |
| Compose local stack | mongo + keycloak + cerbos + xentra-api |
| K8s scaffolds | Cerbos + Authix + policy ConfigMap |
| Approval policies HTTP | **Done** |
| Pagination | members, agents, tokens, approvals, policies, audit |
| Documentation | Reorganized under `docs/` five-folder layout |

**Still blocked for GA:** prod Mongo/Keycloak/Authix ops, secrets, observability, Cerbos TLS, security sign-off, P2 product routes.

---

### Done (P0 + P1)

**Product:** Core security and operability for a developer preview — authenticated API, durable storage option, local stack, CI smoke tests.

**Technical:** Security hardening, Mongo + transactions, Cerbos adapter, Authix client bridge, compose/K8s scaffolds, pagination, approval-policies API, stack-smoke CI, comprehensive docs.

---

### Local stack

```bash
cp .env.example .env
docker compose up -d          # mongo, keycloak, cerbos, xentra-api
bash scripts/stack-smoke.sh   # mongo + cerbos + api (no Authix required)
```

**Authix** runs from its [own repo](https://github.com/x12i/authix) — never inside xentra. For token routes, start Authix separately and set `AUTHIX_BASE_URL` / `AUTHIX_API_KEY` in `.env` (use `http://host.docker.internal:3100` if the API runs in Docker).

---

### External blockers (GA)

#### Prod MongoDB operations

**Product:** Tenant data must survive restarts, failovers, and restore drills before any production customer.

**Technical:** Managed MongoDB with replica set, backups, restore runbook, connection string in secrets manager (`MONGODB_URI`).

#### Prod Keycloak realm operations

**Product:** Human login and JWT validation must be production-grade with proper realm lifecycle.

**Technical:** Realm per environment, client secrets rotated, JWKS URI configured, Admin REST for user sync where needed.

#### Authix deployment and image publish

**Product:** Agent and service tokens cannot be issued in production without a reliable Authix service.

**Technical:** Published Authix container image (not `authix:latest` placeholder), `AUTHIX_BASE_URL` + `AUTHIX_API_KEY` in secrets, health checks in `/ready`.

#### K8s secrets and container registry

**Product:** Production deploy cannot rely on placeholder secrets in git.

**Technical:** Fill `deploy/k8s/secret.yaml` from secrets manager; push images to private registry; wire ingress TLS.

#### Observability and alerting

**Product:** SRE must detect outages and degradation before customers do.

**Technical:** Alerts on `/ready` 503, error rate, latency; structured logs; optional tracing; status page dependencies (API, Mongo, Keycloak, Authix, Cerbos).

#### Cerbos TLS in production

**Product:** Policy decisions must not traverse plaintext gRPC in production networks.

**Technical:** TLS-enabled Cerbos client in `@x12i/xentra-permissions`; `CERBOS_ADDRESS` with TLS credentials.

#### Security review sign-off

**Product:** External GA requires formal security approval.

**Technical:** Threat model review, pen test or equivalent, sign-off recorded; see [test-coverage-gaps.md](./test-coverage-gaps.md) security section.

---

### Definition of done — production ready

- [x] Read/write Cerbos enforcement
- [x] `/access/check` actor binding
- [x] Cerbos fail-closed in production
- [x] Mongo transactions for account bootstrap
- [x] Approval-policies API
- [x] Compose + CI stack smoke
- [x] Documentation (vision, gaps, implementation, use-cases, user-stories)
- [ ] Prod dependencies deployed with TLS
- [ ] Security review
- [ ] P2 IAM polish (admin OIDC, notifications, SIEM) if in GA scope — see [product-backlog.md](./product-backlog.md)

---

### Related

- [product-backlog.md](./product-backlog.md) — in-repo P2 work
- [current-state.md](./current-state.md) — route matrix and maturity
- [implementation/current/deployment.md](../implementation/current/deployment.md) — deploy runbook

## P2 product backlog

**Last updated:** 2026-06-01

In-repo product work remaining before GA-complete IAM surface. For external infra blockers see [production-blockers.md](./production-blockers.md). For today's route matrix see [current-state.md](./current-state.md).

**Closed in-repo (2026-06-01):** member role PATCH, agent PATCH/deactivate, `GET /v1/users/:userId`, delegations HTTP, tool invoke gateway, tool registration HTTP, teams/workspaces HTTP, approval auto-intercept, SDK pagination parity, OpenAPI for implemented routes.

---

### Admin Keycloak OIDC login

**Product:** Admin operators must paste JWTs manually — not acceptable for production governance UI.

**Technical:** Keycloak OIDC redirect in `apps/admin`; client `xentra-admin-ui` from realm import; `PermissionGate` unchanged.

---

### Real approval notifications

**Product:** Approvers are not notified when approval requests are created — log-only notifier.

**Technical:** Replace log notifier in `apps/api/src/services.ts` with email/push/webhook adapter; configurable per account.

---

### Audit export / SIEM connectors

**Product:** Security teams cannot stream audit events to SIEM without custom polling.

**Technical:** Export API or webhook; optional S3/batch export; document retention policy.

---

### Out of scope (not backlog)

| Item | Reason |
|------|--------|
| Cross-product SSO UI | Keycloak handles login |
| Feature flags | Not Xentra's job |
| Client-only security | Anti-pattern — server must enforce |

---

### Related

- [production-blockers.md](./production-blockers.md)
- [use-cases/](../use-cases/) — target scenarios when backlog closes
- [user-stories/](../user-stories/) — acceptance stories for each item

## Test coverage gaps

**Last updated:** 2026-06-01

QA goals and technical test matrix — organized by layer. Items reflect **actual** routes and naming (Authix, `approval-requests`, `tokens/revoke`).

> **Code naming:** `createAccountModel`, `allowedToolIds`, `users.findByIdentityProvider`, `memberships.listByAccount`, `approvals.createRequest`, deny reason `missing_permission`.

---

### Product-level QA goals (GA)

| Goal | Status | Notes |
|------|--------|-------|
| Tenant isolation — no cross-account data leakage | Partial | API security tests exist; expand nightly |
| All `/v1/*` require authentication | Done | 401 without Bearer |
| Permission checks enforced server-side on mutations | Done | Cerbos middleware |
| Token lifecycle audited end-to-end | Partial | Issue/revoke; expand E2E |
| Approval workflow E2E with notifications | Gap | Log-only notifier today |
| Delegation + tool invoke E2E | Partial | HTTP routes + `p2-routes.test.ts`; expand nightly |
| SIEM / audit export | Gap | Backlog |
| Production infra failover drills | Gap | Manual pre-release |

---

### Technical level — by layer

#### 1. `xentra-types` — schema validation

- [ ] Valid `Account` input passes Zod schema
- [ ] Missing `slug` fails with clear error
- [ ] `PermissionCheckRequest` with unknown `actor.type` fails
- [ ] JSON Schema export matches Zod shape

#### 2. `xentra-core` — pure functions

- [ ] `createAccountModel` seeds default roles
- [ ] `validateDelegation` rejects expired/revoked
- [ ] `validateAgentToolAccess` respects allow-list and inactive agent

#### 3. `xentra-store` / `xentra-store-mongo` — contract

- [ ] Full CRUD contract for accounts, users, memberships, agents, delegations, approvals, audit, tokenGrants
- [ ] Mongo: duplicate slug → typed error; transactions; Testcontainers in CI

#### 4. `xentra-permissions` — engine

- [ ] Role allow/deny with reason codes
- [ ] Delegation allow/expiry
- [ ] Approval policy → `requires_human_approval`
- [ ] Production: Cerbos fail-closed when unavailable

#### 5. Authix client (`@x12i/authix-client`)

- [ ] `issue` / `verify` / `revoke` against Authix service
- [ ] Unreachable Authix → typed connection error
- [ ] Legacy `AUTHX_*` env aliases still mapped

#### 6. `xentra-api` — HTTP routes (implemented today)

#### Health
- [ ] `GET /health` → 200, no auth
- [ ] `GET /ready` → 200 when mongo + authix + cerbos ok; 503 otherwise
- [ ] `GET /metrics` → Prometheus text

#### Accounts / members
- [ ] `POST/GET/PATCH/DELETE /v1/accounts` with auth
- [ ] `GET/POST/DELETE .../members` paginated
- [ ] Unauthenticated → 401

#### Permission check
- [ ] `POST .../access/check` — allowed/denied with `reason`
- [x] Approval policy auto-intercept → `requires_human_approval` (`p2-routes.test.ts`)
- [ ] User JWT: actor bound to token (no spoofing)
- [ ] Service account: impersonation audited

#### Agents (dev preview scope)
- [ ] `POST/GET .../agents` — create and list
- [x] `PATCH/DELETE .../agents/:id` — update allow-list, deactivate (`p2-routes.test.ts`)

#### Delegations
- [x] `GET/POST/DELETE .../delegations` — create, list, revoke (`p2-routes.test.ts`)
- [ ] Cross-tenant isolation on delegations

#### Tools
- [x] `GET/POST .../tools` — register and list (`p2-routes.test.ts`)
- [x] `POST .../tools/invoke` — Cerbos + allow-list gate (`p2-routes.test.ts`)

#### Teams / workspaces
- [x] `GET/POST/PATCH/DELETE .../teams` (`p2-routes.test.ts`)
- [x] `GET/POST .../workspaces` (`p2-routes.test.ts`)

#### Tokens
- [ ] `POST .../tokens/issue` → 201 (requires Authix)
- [ ] `POST .../tokens/revoke` — idempotent revoke
- [ ] `GET .../tokens` — paginated active grants
- [ ] Authix unset → 503 on token routes

#### Approvals
- [ ] `GET/POST .../approval-requests` — list/create
- [ ] `POST .../approval-requests/:id/approve` / `reject`
- [ ] `GET/POST/PATCH/DELETE .../approval-policies`

#### Audit
- [ ] `GET .../audit` with filters and pagination
- [ ] No cross-tenant events in results

#### Users
- [ ] `GET /v1/users/me` provisions user from JWT `sub`
- [x] `GET /v1/users/:userId` — membership-scoped lookup (`p2-routes.test.ts`)

#### Members
- [x] `PATCH .../members/:memberId` — role change (`p2-routes.test.ts`)

#### 7. Auth middleware

- [ ] Valid Keycloak JWT → continues
- [ ] Expired/invalid JWT → 401
- [ ] Valid service API key → `serviceAccount` actor
- [ ] `/health`, `/ready` exempt

#### 8. Security tests

- [ ] Cross-tenant isolation on members, access/check, audit
- [ ] CORS: allowed vs disallowed origins
- [ ] No secrets in `/health` or 500 responses in production
- [ ] Rate limiting — **verify if implemented** (checklist aspirational)

#### 9. End-to-end flows (target)

#### Flow 1: New tenant onboarding
- [ ] Create account → invite member → permission checks for allowed/denied actions

#### Flow 2: Agent with delegation
- [x] Register agent → delegate → access/check via delegation (`p2-routes.test.ts`)
- [ ] Expiry denies after `expiresAt`

#### Flow 3: Approval-gated action (auto-intercept)
- [x] Policy defined → check returns `requires_human_approval` (`p2-routes.test.ts`)
- [ ] Approve → re-check allowed

#### Flow 4: Token lifecycle
- [ ] Issue → verify → revoke → verify invalid

#### Flow 5: Audit completeness
- [ ] Each mutation type produces audit event with actor, action, accountId, timestamp

#### 10. SDK / React

- [ ] SDK sends Bearer on every request
- [x] Paginated list envelopes — SDK aligned (2026-06-01)
- [ ] `PermissionGate` hides content when denied

#### 11. Infrastructure (pre-release)

- [ ] `/ready` stable 24h staging
- [ ] Rollout and rollback without prolonged 503
- [ ] Mongo failover → `/ready` 503 within 10s

---

### Summary

| Layer | Run in |
|-------|--------|
| Types, core, store, permissions | Unit — every PR |
| Mongo store | Testcontainers — CI |
| API routes + auth | Integration — every PR |
| Security + E2E | Nightly + pre-release |
| Infra drills | Manual pre-release |

---

### Related

- [current-state.md](./current-state.md) — implemented routes
- [product-backlog.md](./product-backlog.md) — tests blocked on missing features
- [package-status.md](./package-status.md)

## Definition of done

From production blockers — production ready means:

- [x] Read/write Cerbos enforcement
- [x] `/access/check` actor binding
- [x] Cerbos fail-closed in production
- [x] Mongo transactions for account bootstrap
- [x] Approval-policies API
- [x] Compose + CI stack smoke
- [x] Documentation structure (now on Docify as WIP)
- [ ] Prod dependencies deployed with TLS
- [ ] Security review
- [ ] P2 IAM polish (admin OIDC, notifications, SIEM) if in GA scope

**Until unchecked items close, docs remain Work In Progress.**

---

# Gaps — builders

# Gaps — Operators
**Audience:** Required reading while documentation is Work In Progress.
**Twin:** [Developers version](../developers/BOOK.md)
**Package:** `@x12i/xentra-*` · **Docs:** https://docs.xentra.x12i.com · **Status:** Work In Progress

---

## Developer preview maturity

**Last updated:** 2026-06-01

Canonical reference for what Xentra **has today** in the developer preview. For missing work see [product-backlog.md](./product-backlog.md). For how to use it see [implementation/current/](../implementation/current/).

---

### Maturity summary

| Layer | Status | Notes |
|-------|--------|-------|
| **npm libraries** (`types`, `core`, `store`, `permissions`, …) | Usable | Embed in your app or call HTTP API |
| **MongoDB store** | Implemented | Transactions, Testcontainers in CI |
| **Cerbos PDP** | Implemented | Policies in `policies/`; fail-closed in production |
| **HTTP API** | Developer preview | Auth + Cerbos on routes; not GA |
| **Authix integration** | Wired | External service via `@x12i/authix-client` |
| **Keycloak** | Partial | JWKS + Admin REST; realm import for dev |
| **Admin UI** | Scaffold | Manual JWT login; no OIDC redirect yet |
| **SDK / React** | Usable | Paginated list envelopes aligned with API |

---

### Architecture (today)

```
Product app
  → Xentra API (or embedded @x12i/xentra-* libraries)
      → MongoDB (tenant data)
      → Cerbos (authorization PDP)
      → Keycloak (human identity / JWT)
      → Authix (token mint/verify — separate repo)
```

| Component | Repo / package | Xentra owns |
|-----------|----------------|-------------|
| Tenant IAM, agents, approvals, audit | This monorepo | Yes |
| Token signing | [authix](https://github.com/x12i/authix) | No — client + bridge only |
| Human login | **Keycloak** (required) | Yes — JWKS + optional Admin sync |
| Policy decisions | Cerbos + `policies/*.yaml` | Yes (policy files) |

---

### Use cases — supported today

| Use case | How | Limitations |
|----------|-----|-------------|
| **Multi-tenant accounts** | `POST/GET /v1/accounts` | List scoped to memberships (users) or all (service accounts) |
| **Members & roles** | Members API + role PATCH | — |
| **Permission check before action** | `POST .../access/check` | Actor bound to JWT; approval auto-intercept when policy matches |
| **Cerbos-enforced mutations** | `requirePermission` middleware | Dev: in-process fallback if Cerbos down; prod: fail-closed |
| **Agent registration** | `POST/PATCH/DELETE .../agents` | Deactivate revokes delegations |
| **Delegations** | `GET/POST/DELETE .../delegations` | — |
| **Teams & workspaces** | `GET/POST/PATCH/DELETE .../teams`, `.../workspaces` | — |
| **Tool invoke gateway** | `POST .../tools/invoke` | Register tool via `POST .../tools` first |
| **Scoped agent tokens** | `POST .../tokens/issue` → Authix | Requires `AUTHIX_*`; 503 if unset |
| **Token revoke + grant audit** | `POST .../tokens/revoke`, Mongo grants | Verify enriched with grant when Authix returns `tokenId` |
| **Approval workflow** | Approval requests + approve/reject | Policies via HTTP; notifier is log-only |
| **Approval policies** | CRUD on `.../approval-policies` | Auto-intercept on `access/check` when policy matches |
| **Audit trail** | Writes on mutations + permission checks | Query via `GET .../audit` with filters |
| **Service-to-service API** | `XENTRA_SERVICE_API_KEYS` as Bearer | Long-lived shared keys — rotate in prod |
| **Local stack** | `docker compose` + `scripts/stack-smoke.sh` | Authix optional — separate repo |
| **Embed libraries** | `@x12i/xentra-permissions`, `store`, etc. | You bring persistence and IdP |

Unsupported use cases: [product-backlog.md](./product-backlog.md).

---

## What works today

Canonical route matrix and supported use cases (developer preview):

**Last updated:** 2026-06-01

Canonical reference for what Xentra **has today** in the developer preview. For missing work see [product-backlog.md](./product-backlog.md). For how to use it see [implementation/current/](../implementation/current/).

---

### Maturity summary

| Layer | Status | Notes |
|-------|--------|-------|
| **npm libraries** (`types`, `core`, `store`, `permissions`, …) | Usable | Embed in your app or call HTTP API |
| **MongoDB store** | Implemented | Transactions, Testcontainers in CI |
| **Cerbos PDP** | Implemented | Policies in `policies/`; fail-closed in production |
| **HTTP API** | Developer preview | Auth + Cerbos on routes; not GA |
| **Authix integration** | Wired | External service via `@x12i/authix-client` |
| **Keycloak** | Partial | JWKS + Admin REST; realm import for dev |
| **Admin UI** | Scaffold | Manual JWT login; no OIDC redirect yet |
| **SDK / React** | Usable | Paginated list envelopes aligned with API |

---

### Architecture (today)

```
Product app
  → Xentra API (or embedded @x12i/xentra-* libraries)
      → MongoDB (tenant data)
      → Cerbos (authorization PDP)
      → Keycloak (human identity / JWT)
      → Authix (token mint/verify — separate repo)
```

| Component | Repo / package | Xentra owns |
|-----------|----------------|-------------|
| Tenant IAM, agents, approvals, audit | This monorepo | Yes |
| Token signing | [authix](https://github.com/x12i/authix) | No — client + bridge only |
| Human login | **Keycloak** (required) | Yes — JWKS + optional Admin sync |
| Policy decisions | Cerbos + `policies/*.yaml` | Yes (policy files) |

---

### Use cases — supported today

| Use case | How | Limitations |
|----------|-----|-------------|
| **Multi-tenant accounts** | `POST/GET /v1/accounts` | List scoped to memberships (users) or all (service accounts) |
| **Members & roles** | Members API + role PATCH | — |
| **Permission check before action** | `POST .../access/check` | Actor bound to JWT; approval auto-intercept when policy matches |
| **Cerbos-enforced mutations** | `requirePermission` middleware | Dev: in-process fallback if Cerbos down; prod: fail-closed |
| **Agent registration** | `POST/PATCH/DELETE .../agents` | Deactivate revokes delegations |
| **Delegations** | `GET/POST/DELETE .../delegations` | — |
| **Teams & workspaces** | `GET/POST/PATCH/DELETE .../teams`, `.../workspaces` | — |
| **Tool invoke gateway** | `POST .../tools/invoke` | Register tool via `POST .../tools` first |
| **Scoped agent tokens** | `POST .../tokens/issue` → Authix | Requires `AUTHIX_*`; 503 if unset |
| **Token revoke + grant audit** | `POST .../tokens/revoke`, Mongo grants | Verify enriched with grant when Authix returns `tokenId` |
| **Approval workflow** | Approval requests + approve/reject | Policies via HTTP; notifier is log-only |
| **Approval policies** | CRUD on `.../approval-policies` | Auto-intercept on `access/check` when policy matches |
| **Audit trail** | Writes on mutations + permission checks | Query via `GET .../audit` with filters |
| **Service-to-service API** | `XENTRA_SERVICE_API_KEYS` as Bearer | Long-lived shared keys — rotate in prod |
| **Local stack** | `docker compose` + `scripts/stack-smoke.sh` | Authix optional — separate repo |
| **Embed libraries** | `@x12i/xentra-permissions`, `store`, etc. | You bring persistence and IdP |

Unsupported use cases: [product-backlog.md](./product-backlog.md).

---

### HTTP API — route matrix

All routes except `/health`, `/ready`, `/metrics` require `Authorization: Bearer <jwt-or-service-key>`.

| Method | Path | Authz (Cerbos) | Implemented |
|--------|------|----------------|-------------|
| GET | `/health` | — | Yes |
| GET | `/ready` | — | Yes (mongo, authix, cerbos) |
| GET | `/metrics` | — | Yes (Prometheus) |
| GET | `/v1/accounts` | Membership-scoped | Yes |
| POST | `/v1/accounts` | Service account in prod | Yes |
| GET | `/v1/accounts/:accountId` | `read` / `account` | Yes |
| PATCH | `/v1/accounts/:accountId` | `update` / `account` | Yes |
| DELETE | `/v1/accounts/:accountId` | `delete` / `account` | Yes |
| GET | `/v1/users/me` | User JWT only | Yes |
| GET | `/v1/users/:userId` | Membership-scoped | Yes |
| GET | `.../members` | `read` / `account` | Yes (paginated) |
| POST | `.../members` | `invite_member` / `account` | Yes |
| PATCH | `.../members/:memberId` | `change_member_role` / `account` | Yes |
| DELETE | `.../members/:memberId` | `remove_member` / `account` | Yes |
| POST | `.../access/check` | Authenticated; actor from JWT | Yes |
| GET | `.../agents` | `read` / `agent` | Yes (paginated) |
| POST | `.../agents` | `create` / `agent` | Yes |
| PATCH | `.../agents/:id` | `update` / `agent` | Yes |
| DELETE | `.../agents/:id` | `deactivate` / `agent` | Yes |
| GET/POST | `.../delegations` | `read`/`update` / `account` | Yes |
| DELETE | `.../delegations/:delegationId` | `update` / `account` | Yes |
| GET/POST | `.../tools` | `read`/`create` / `tools` | Yes (paginated list) |
| POST | `.../tools/invoke` | `invoke` / `tools` + allow-list | Yes |
| GET/POST | `.../teams` | `read`/`create` / `team` | Yes (paginated list) |
| PATCH/DELETE | `.../teams/:teamId` | `update`/`delete` / `team` | Yes |
| GET/POST | `.../workspaces` | `read`/`create` / `workspace` | Yes (paginated list) |
| PATCH/DELETE | `.../workspaces/:workspaceId` | `update`/`delete` / `workspace` | Yes |
| GET/PATCH/DELETE | `.../approval-policies/:policyId` | `read` / `create` / `approval` | Yes |
| POST | `.../tokens/issue` | `issue` / `token` + Authix | Yes |
| POST | `.../tokens/verify` | `list` / `token` + Authix | Yes |
| POST | `.../tokens/introspect` | `list` / `token` + Authix | Yes |
| POST | `.../tokens/revoke` | `revoke` / `token` + Authix | Yes |
| GET | `.../tokens` | `list` / `token` + Authix | Yes (paginated) |
| GET | `.../audit` | `read` / `audit` | Yes (paginated + filters) |
| GET/POST | `.../approval-requests` | `read` / `create` / `approval` | Yes (paginated list) |
| POST | `.../approval-requests/:id/approve` | `approve` / `approval` | Yes |
| POST | `.../approval-requests/:id/reject` | `reject` / `approval` | Yes |
| GET/POST | `.../approval-policies` | `read` / `create` / `approval` | Yes (paginated list) |

#### Pagination

List endpoints accept `?limit=` (max 200, default 50) and `?cursor=` (numeric offset as string). Response:

```json
{ "data": { "items": [ ... ], "nextCursor": "50" } }
```

Applies to: members, agents, tokens, approval-requests, approval-policies, audit, delegations, teams, workspaces, tools.

#### `/access/check` body

Request schema includes `actor`, but the API **binds the actor to the JWT** for user callers. Service accounts may pass a different `actor` in the body (audited as impersonation).

---

### Cerbos policy vocabulary

Policies live in [`policies/`](../../policies/). Roles are **membership role keys** on the account (`owner`, `admin`, `member`, …).

#### Roles (seeded per account)

| Role key | Purpose |
|----------|---------|
| `owner` | Full access (`*` on resources) |
| `admin` | Manage account, members, agents, tokens, approvals |
| `member` | Read + invite + create agents + issue tokens |
| `viewer` | Read-only |
| `billing-admin` | Read (placeholder) |
| `agent-admin` | Agent CRUD actions |
| `security-admin` | Audit/tokens/approvals/admin console |
| `agent` | Agent actor type (delegation context) |
| `serviceAccount` | Machine callers |

#### Resource types and actions

| Resource (`resourceType`) | Actions in policies |
|---------------------------|---------------------|
| `account` | `read`, `update`, `delete`, `invite_member`, `remove_member`, `change_member_role`, `*` (owner) |
| `agent` | `read`, `create`, `update`, `delete`, `deactivate` |
| `token` | `issue`, `revoke`, `list` |
| `approval` | `read`, `create`, `approve`, `reject` |
| `audit` | `read` |
| `admin` | `access` (admin UI `PermissionGate`) |
| `tools` | `read`, `create`, `invoke` |
| `team` | `read`, `create`, `update`, `delete` |
| `workspace` | `read`, `create`, `update`, `delete` |

---

### Auth model

| Caller | Bearer token | Behavior |
|--------|--------------|----------|
| **Human user** | Keycloak JWT | JWKS verify (prod); dev unsigned JWT if Keycloak unset |
| **Service** | Keycloak JWT or `XENTRA_SERVICE_API_KEYS` entry | `serviceAccount` actor; list all accounts; impersonate in access/check |
| **Unauthenticated** | — | 401 on all `/v1/*` routes |

Production **requires** Keycloak config — dev JWT decode is rejected.

---

### Authix (tokens)

| Item | Value |
|------|--------|
| Service repo | [github.com/x12i/authix](https://github.com/x12i/authix) |
| Client npm | `@x12i/authix-client` |
| Types npm | `@x12i/authx-token-types` (rename pending) |
| Xentra bridge | `apps/api/src/authix/bridge.ts` |
| Token routes without Authix | **503** `authix_unavailable` |

---

### Keycloak (dev defaults)

Imported via `deploy/keycloak/realm-xentra.json` when using compose `--import-realm`:

| Item | Value |
|------|--------|
| Realm | `xentra` |
| API client | `xentra-api` (confidential) |
| Dev client secret | `xentra-api-dev-secret` |
| Admin UI client | `xentra-admin-ui` (public) |
| Test user | `testuser` / `test` |

---

### Admin UI (`apps/admin`)

| Screen | Data source | Auth |
|--------|-------------|------|
| Accounts, members, agents, tokens, approvals, audit | SDK → API | Manual JWT / API key paste |
| Route guard | `PermissionGate` `access` on `admin` | Must pass Cerbos check via SDK |

---

### CI and testing

| Check | Where |
|-------|--------|
| Unit / API tests | `npm test` |
| Cerbos compile | `.github/workflows/ci.yml` |
| Stack smoke | `.github/workflows/stack-smoke.yml` |
| Mongo Testcontainers | `packages/store-mongo` (CI only unless `FORCE_TESTCONTAINERS=1`) |

---

### Related

- [package-status.md](./package-status.md) — per-package status
- [implementation/current/integration-guide.md](../implementation/current/integration-guide.md) — API examples
- [implementation/current/configuration.md](../implementation/current/configuration.md) — env vars

## Package status

**Last updated:** 2026-06-01

Per-package implementation status for the developer preview. ✅ implemented · ⚠️ partial · ❌ not yet.

For route-level detail see [current-state.md](./current-state.md). For future stories see [user-stories/](../user-stories/).

---

### `@x12i/xentra-types` ✅

- ✅ Shared entity types and Zod schemas
- ✅ JSON Schema export for OpenAPI

---

### `@x12i/xentra-core` ✅

- ✅ Pure account/membership/role models
- ✅ Delegation and tool access validation helpers

---

### `@x12i/xentra-store` ✅

- ✅ `XentraStoreBundle` interface
- ✅ `createMemoryStore()` + in-memory transactions

---

### `@x12i/xentra-store-mongo` ✅

- ✅ `createMongoStore()` with indexes
- ✅ Mongo transactions (`store.transaction()`)
- ✅ Testcontainers contract tests in CI
- ⚠️ Cursor tokens (offset only)

---

### `@x12i/xentra-identity` / `identity-keycloak` ⚠️

- ✅ JWKS JWT validation, Admin REST (groups, users)
- ⚠️ `KeycloakIdentityAdapter` — many methods still stub
- ❌ Full bidirectional IdP sync automation

---

### `@x12i/xentra-permissions` ✅

- ✅ In-process `can()` with reason codes
- ✅ Cerbos gRPC adapter; fail-closed in production
- ⚠️ Cerbos TLS not configured

---

### `@x12i/xentra-agentic` ✅

- ✅ Agent CRUD in library
- ✅ Tool allow-lists, delegations in library
- ✅ HTTP delegations, tools (register/list/invoke)

---

### `@x12i/xentra-api` ✅

- ✅ Auth on all `/v1/*` routes
- ✅ Cerbos on reads and writes
- ✅ Full IAM surface: accounts, members, agents, delegations, teams, workspaces, tools, tokens, audit, approvals, policies
- ✅ `GET /v1/users/:userId`, approval auto-intercept on access/check
---

### `@x12i/xentra-approvals` ✅

- ✅ Policies + requests in library
- ✅ HTTP for approval-requests and approval-policies
- ✅ `matchesPolicy` wired into `access/check` (auto-intercept)
- ❌ Real email/push notifications (log-only)

---

### `@x12i/xentra-audit` ✅

- ✅ Append + list by account/actor/target
- ✅ API audit route with filters + pagination
- ✅ Writes on account, member, agent, approval mutations

---

### Authix (external) ✅

- ✅ `@x12i/authix-client` in API
- ✅ Bridge: issue/revoke + Mongo grants + audit
- ⚠️ Types npm name still `@x12i/authx-token-types`
- ❌ Published Authix container image

---

### `@x12i/xentra-sdk` / `react` ✅

- ✅ Client for core routes; paginated list envelopes
- ✅ `members.updateRole`, `agents.update`, `agents.deactivate`, `users.get`
- ✅ `PermissionGate`, hooks (thin)

---

### `@x12i/xentra-admin` ⚠️

- ✅ Screens for accounts, members, agents, tokens, approvals, audit
- ⚠️ Manual JWT / API-key login
- ❌ Keycloak OIDC redirect

---

### `@x12i/xentra-openapi` ✅

- ✅ OpenAPI 3.1 aligned with implemented routes

---

### Cross-cutting product stories (today)

| Story | Status | Notes |
|-------|--------|-------|
| Create tenant + default roles | ✅ | `POST /v1/accounts`; Mongo transaction when available |
| Check permission before mutation | ✅ | `access/check` + route middleware |
| Register agent + allow-list tools | ✅ | PATCH agent for allow-list |
| Delegate user → agent | ✅ | `POST .../delegations` |
| Human approval for risky action | ✅ | Auto-intercept on `access/check`; requests API |
| Issue scoped agent token | ✅ | Requires Authix |
| Investigate audit trail | ✅ | `GET .../audit` |
| Admin console governance | ⚠️ | Scaffold; no OIDC |

---

### Related

- [product-backlog.md](./product-backlog.md) — what closes each ❌
- [test-coverage-gaps.md](./test-coverage-gaps.md) — QA matrix

## External production blockers

**Last updated:** 2026-06-01

For **what works today** see [current-state.md](./current-state.md). For **P2 product work** see [product-backlog.md](./product-backlog.md).

---

### Executive summary

| Area | Status |
|------|--------|
| API security (P0) | **Done in-repo** |
| Mongo store + transactions | **Done** |
| Compose local stack | mongo + keycloak + cerbos + xentra-api |
| K8s scaffolds | Cerbos + Authix + policy ConfigMap |
| Approval policies HTTP | **Done** |
| Pagination | members, agents, tokens, approvals, policies, audit |
| Documentation | Reorganized under `docs/` five-folder layout |

**Still blocked for GA:** prod Mongo/Keycloak/Authix ops, secrets, observability, Cerbos TLS, security sign-off, P2 product routes.

---

### Done (P0 + P1)

**Product:** Core security and operability for a developer preview — authenticated API, durable storage option, local stack, CI smoke tests.

**Technical:** Security hardening, Mongo + transactions, Cerbos adapter, Authix client bridge, compose/K8s scaffolds, pagination, approval-policies API, stack-smoke CI, comprehensive docs.

---

### Local stack

```bash
cp .env.example .env
docker compose up -d          # mongo, keycloak, cerbos, xentra-api
bash scripts/stack-smoke.sh   # mongo + cerbos + api (no Authix required)
```

**Authix** runs from its [own repo](https://github.com/x12i/authix) — never inside xentra. For token routes, start Authix separately and set `AUTHIX_BASE_URL` / `AUTHIX_API_KEY` in `.env` (use `http://host.docker.internal:3100` if the API runs in Docker).

---

### External blockers (GA)

#### Prod MongoDB operations

**Product:** Tenant data must survive restarts, failovers, and restore drills before any production customer.

**Technical:** Managed MongoDB with replica set, backups, restore runbook, connection string in secrets manager (`MONGODB_URI`).

#### Prod Keycloak realm operations

**Product:** Human login and JWT validation must be production-grade with proper realm lifecycle.

**Technical:** Realm per environment, client secrets rotated, JWKS URI configured, Admin REST for user sync where needed.

#### Authix deployment and image publish

**Product:** Agent and service tokens cannot be issued in production without a reliable Authix service.

**Technical:** Published Authix container image (not `authix:latest` placeholder), `AUTHIX_BASE_URL` + `AUTHIX_API_KEY` in secrets, health checks in `/ready`.

#### K8s secrets and container registry

**Product:** Production deploy cannot rely on placeholder secrets in git.

**Technical:** Fill `deploy/k8s/secret.yaml` from secrets manager; push images to private registry; wire ingress TLS.

#### Observability and alerting

**Product:** SRE must detect outages and degradation before customers do.

**Technical:** Alerts on `/ready` 503, error rate, latency; structured logs; optional tracing; status page dependencies (API, Mongo, Keycloak, Authix, Cerbos).

#### Cerbos TLS in production

**Product:** Policy decisions must not traverse plaintext gRPC in production networks.

**Technical:** TLS-enabled Cerbos client in `@x12i/xentra-permissions`; `CERBOS_ADDRESS` with TLS credentials.

#### Security review sign-off

**Product:** External GA requires formal security approval.

**Technical:** Threat model review, pen test or equivalent, sign-off recorded; see [test-coverage-gaps.md](./test-coverage-gaps.md) security section.

---

### Definition of done — production ready

- [x] Read/write Cerbos enforcement
- [x] `/access/check` actor binding
- [x] Cerbos fail-closed in production
- [x] Mongo transactions for account bootstrap
- [x] Approval-policies API
- [x] Compose + CI stack smoke
- [x] Documentation (vision, gaps, implementation, use-cases, user-stories)
- [ ] Prod dependencies deployed with TLS
- [ ] Security review
- [ ] P2 IAM polish (admin OIDC, notifications, SIEM) if in GA scope — see [product-backlog.md](./product-backlog.md)

---

### Related

- [product-backlog.md](./product-backlog.md) — in-repo P2 work
- [current-state.md](./current-state.md) — route matrix and maturity
- [implementation/current/deployment.md](../implementation/current/deployment.md) — deploy runbook

## P2 product backlog

**Last updated:** 2026-06-01

In-repo product work remaining before GA-complete IAM surface. For external infra blockers see [production-blockers.md](./production-blockers.md). For today's route matrix see [current-state.md](./current-state.md).

**Closed in-repo (2026-06-01):** member role PATCH, agent PATCH/deactivate, `GET /v1/users/:userId`, delegations HTTP, tool invoke gateway, tool registration HTTP, teams/workspaces HTTP, approval auto-intercept, SDK pagination parity, OpenAPI for implemented routes.

---

### Admin Keycloak OIDC login

**Product:** Admin operators must paste JWTs manually — not acceptable for production governance UI.

**Technical:** Keycloak OIDC redirect in `apps/admin`; client `xentra-admin-ui` from realm import; `PermissionGate` unchanged.

---

### Real approval notifications

**Product:** Approvers are not notified when approval requests are created — log-only notifier.

**Technical:** Replace log notifier in `apps/api/src/services.ts` with email/push/webhook adapter; configurable per account.

---

### Audit export / SIEM connectors

**Product:** Security teams cannot stream audit events to SIEM without custom polling.

**Technical:** Export API or webhook; optional S3/batch export; document retention policy.

---

### Out of scope (not backlog)

| Item | Reason |
|------|--------|
| Cross-product SSO UI | Keycloak handles login |
| Feature flags | Not Xentra's job |
| Client-only security | Anti-pattern — server must enforce |

---

### Related

- [production-blockers.md](./production-blockers.md)
- [use-cases/](../use-cases/) — target scenarios when backlog closes
- [user-stories/](../user-stories/) — acceptance stories for each item

## Test coverage gaps

**Last updated:** 2026-06-01

QA goals and technical test matrix — organized by layer. Items reflect **actual** routes and naming (Authix, `approval-requests`, `tokens/revoke`).

> **Code naming:** `createAccountModel`, `allowedToolIds`, `users.findByIdentityProvider`, `memberships.listByAccount`, `approvals.createRequest`, deny reason `missing_permission`.

---

### Product-level QA goals (GA)

| Goal | Status | Notes |
|------|--------|-------|
| Tenant isolation — no cross-account data leakage | Partial | API security tests exist; expand nightly |
| All `/v1/*` require authentication | Done | 401 without Bearer |
| Permission checks enforced server-side on mutations | Done | Cerbos middleware |
| Token lifecycle audited end-to-end | Partial | Issue/revoke; expand E2E |
| Approval workflow E2E with notifications | Gap | Log-only notifier today |
| Delegation + tool invoke E2E | Partial | HTTP routes + `p2-routes.test.ts`; expand nightly |
| SIEM / audit export | Gap | Backlog |
| Production infra failover drills | Gap | Manual pre-release |

---

### Technical level — by layer

#### 1. `xentra-types` — schema validation

- [ ] Valid `Account` input passes Zod schema
- [ ] Missing `slug` fails with clear error
- [ ] `PermissionCheckRequest` with unknown `actor.type` fails
- [ ] JSON Schema export matches Zod shape

#### 2. `xentra-core` — pure functions

- [ ] `createAccountModel` seeds default roles
- [ ] `validateDelegation` rejects expired/revoked
- [ ] `validateAgentToolAccess` respects allow-list and inactive agent

#### 3. `xentra-store` / `xentra-store-mongo` — contract

- [ ] Full CRUD contract for accounts, users, memberships, agents, delegations, approvals, audit, tokenGrants
- [ ] Mongo: duplicate slug → typed error; transactions; Testcontainers in CI

#### 4. `xentra-permissions` — engine

- [ ] Role allow/deny with reason codes
- [ ] Delegation allow/expiry
- [ ] Approval policy → `requires_human_approval`
- [ ] Production: Cerbos fail-closed when unavailable

#### 5. Authix client (`@x12i/authix-client`)

- [ ] `issue` / `verify` / `revoke` against Authix service
- [ ] Unreachable Authix → typed connection error
- [ ] Legacy `AUTHX_*` env aliases still mapped

#### 6. `xentra-api` — HTTP routes (implemented today)

#### Health
- [ ] `GET /health` → 200, no auth
- [ ] `GET /ready` → 200 when mongo + authix + cerbos ok; 503 otherwise
- [ ] `GET /metrics` → Prometheus text

#### Accounts / members
- [ ] `POST/GET/PATCH/DELETE /v1/accounts` with auth
- [ ] `GET/POST/DELETE .../members` paginated
- [ ] Unauthenticated → 401

#### Permission check
- [ ] `POST .../access/check` — allowed/denied with `reason`
- [x] Approval policy auto-intercept → `requires_human_approval` (`p2-routes.test.ts`)
- [ ] User JWT: actor bound to token (no spoofing)
- [ ] Service account: impersonation audited

#### Agents (dev preview scope)
- [ ] `POST/GET .../agents` — create and list
- [x] `PATCH/DELETE .../agents/:id` — update allow-list, deactivate (`p2-routes.test.ts`)

#### Delegations
- [x] `GET/POST/DELETE .../delegations` — create, list, revoke (`p2-routes.test.ts`)
- [ ] Cross-tenant isolation on delegations

#### Tools
- [x] `GET/POST .../tools` — register and list (`p2-routes.test.ts`)
- [x] `POST .../tools/invoke` — Cerbos + allow-list gate (`p2-routes.test.ts`)

#### Teams / workspaces
- [x] `GET/POST/PATCH/DELETE .../teams` (`p2-routes.test.ts`)
- [x] `GET/POST .../workspaces` (`p2-routes.test.ts`)

#### Tokens
- [ ] `POST .../tokens/issue` → 201 (requires Authix)
- [ ] `POST .../tokens/revoke` — idempotent revoke
- [ ] `GET .../tokens` — paginated active grants
- [ ] Authix unset → 503 on token routes

#### Approvals
- [ ] `GET/POST .../approval-requests` — list/create
- [ ] `POST .../approval-requests/:id/approve` / `reject`
- [ ] `GET/POST/PATCH/DELETE .../approval-policies`

#### Audit
- [ ] `GET .../audit` with filters and pagination
- [ ] No cross-tenant events in results

#### Users
- [ ] `GET /v1/users/me` provisions user from JWT `sub`
- [x] `GET /v1/users/:userId` — membership-scoped lookup (`p2-routes.test.ts`)

#### Members
- [x] `PATCH .../members/:memberId` — role change (`p2-routes.test.ts`)

#### 7. Auth middleware

- [ ] Valid Keycloak JWT → continues
- [ ] Expired/invalid JWT → 401
- [ ] Valid service API key → `serviceAccount` actor
- [ ] `/health`, `/ready` exempt

#### 8. Security tests

- [ ] Cross-tenant isolation on members, access/check, audit
- [ ] CORS: allowed vs disallowed origins
- [ ] No secrets in `/health` or 500 responses in production
- [ ] Rate limiting — **verify if implemented** (checklist aspirational)

#### 9. End-to-end flows (target)

#### Flow 1: New tenant onboarding
- [ ] Create account → invite member → permission checks for allowed/denied actions

#### Flow 2: Agent with delegation
- [x] Register agent → delegate → access/check via delegation (`p2-routes.test.ts`)
- [ ] Expiry denies after `expiresAt`

#### Flow 3: Approval-gated action (auto-intercept)
- [x] Policy defined → check returns `requires_human_approval` (`p2-routes.test.ts`)
- [ ] Approve → re-check allowed

#### Flow 4: Token lifecycle
- [ ] Issue → verify → revoke → verify invalid

#### Flow 5: Audit completeness
- [ ] Each mutation type produces audit event with actor, action, accountId, timestamp

#### 10. SDK / React

- [ ] SDK sends Bearer on every request
- [x] Paginated list envelopes — SDK aligned (2026-06-01)
- [ ] `PermissionGate` hides content when denied

#### 11. Infrastructure (pre-release)

- [ ] `/ready` stable 24h staging
- [ ] Rollout and rollback without prolonged 503
- [ ] Mongo failover → `/ready` 503 within 10s

---

### Summary

| Layer | Run in |
|-------|--------|
| Types, core, store, permissions | Unit — every PR |
| Mongo store | Testcontainers — CI |
| API routes + auth | Integration — every PR |
| Security + E2E | Nightly + pre-release |
| Infra drills | Manual pre-release |

---

### Related

- [current-state.md](./current-state.md) — implemented routes
- [product-backlog.md](./product-backlog.md) — tests blocked on missing features
- [package-status.md](./package-status.md)

## Definition of done

From production blockers — production ready means:

- [x] Read/write Cerbos enforcement
- [x] `/access/check` actor binding
- [x] Cerbos fail-closed in production
- [x] Mongo transactions for account bootstrap
- [x] Approval-policies API
- [x] Compose + CI stack smoke
- [x] Documentation structure (now on Docify as WIP)
- [ ] Prod dependencies deployed with TLS
- [ ] Security review
- [ ] P2 IAM polish (admin OIDC, notifications, SIEM) if in GA scope

**Until unchecked items close, docs remain Work In Progress.**

---

# Implementation Target — developers

# Implementation Target — Developers
**Audience:** GA-target configuration, integration, and operations.
**Twin:** [Operators version](../builders/BOOK.md)
**Package:** `@x12i/xentra-*` · **Docs:** https://docs.xentra.x12i.com · **Status:** Work In Progress

---

## Target integration path

At GA: Keycloak login → Xentra account → named actions → `access/check` → agent tokens through Xentra/Authix → approvals → audit. Full curl and auth caller details below.

## Production configuration

**Product:** Production Xentra requires hardened dependencies — TLS everywhere, secrets in a manager, no dev fallbacks.

**Technical:** All variables from [current/configuration.md](../current/configuration.md) plus GA requirements below.

---

### Production requirements (all required)

| Variable | GA requirement |
|----------|----------------|
| `NODE_ENV` | `production` |
| `MONGODB_URI` | Replica set URI from secrets manager |
| `KEYCLOAK_*` | Production realm; JWKS URI verified |
| `CERBOS_ADDRESS` | TLS gRPC endpoint |
| `AUTHIX_BASE_URL` | HTTPS; published Authix deployment |
| `AUTHIX_API_KEY` | Rotated; stored in secrets manager |
| `XENTRA_SERVICE_API_KEYS` | Comma-separated; rotated per product |
| `CORS_ALLOWED_ORIGINS` | Explicit product origins only |
| `TRUST_PROXY` | `true` behind ingress |

Startup fails if any production-required variable is missing.

---

### Cerbos TLS

**Product:** Policy decisions must not traverse plaintext on production networks.

**Technical:** Configure Cerbos with TLS certificates; update `@x12i/xentra-permissions` Cerbos client for TLS credentials; verify fail-closed on connection errors.

---

### Authix

**Product:** All agent and service tokens flow through Authix with Xentra grant bookkeeping.

**Technical:**
- Published container image in private registry
- `AUTHIX_ISSUER` matches token validation
- Shared `AUTHIX_API_KEY` between Xentra and Authix deployment
- Health check included in Xentra `/ready`

---

### Admin UI (OIDC)

**Product:** Operators sign in via Keycloak, not pasted JWTs.

**Technical:**
- Keycloak client `xentra-admin-ui` (public, PKCE)
- Admin SPA env: `VITE_KEYCLOAK_*` pointing to realm
- Cerbos `admin` / `access` for route guard

---

### Observability

**Product:** SRE can detect and respond to outages.

**Technical:**
- Prometheus scrape `/metrics`
- Alerts: `/ready` 503, 5xx rate, p99 latency on `/access/check`
- Structured JSON logs with `requestId`
- Optional: audit export webhook URL (when implemented)

---

### Kubernetes (GA)

All secrets from external secrets operator or cloud secrets manager — never placeholder values in git.

Network policies: API pods reach only Mongo, Keycloak, Cerbos, Authix.

---

### Related

- [deployment.md](./deployment.md)
- [gaps/production-blockers.md](../../gaps/production-blockers.md)

## Full API flows

**Product:** Products integrate via four steps — account, action vocabulary, access/check, tokens through Xentra — plus teams, delegations, and approvals as they mature.

**Technical:** Complete HTTP API usage at GA. Dev preview subset: [current/integration-guide.md](../current/integration-guide.md).

---

### Authentication (GA)

| Caller | Method | Use case |
|--------|--------|----------|
| Product backend | Service API key or Authix client credentials | Server-side checks, token issue |
| Product frontend | Keycloak OIDC → Bearer JWT | User-scoped calls |
| Agent runtime | Authix token from Xentra grant | Tool invocation on behalf of user |
| Admin UI | Keycloak OIDC + elevated roles | Account administration |

**Security rules:**
- Never trust client-supplied `actor` without binding to validated token
- Permission checks on client are advisory; **server must enforce**
- Rotate API keys via platform; revoke tokens via `POST .../tokens/revoke`

---

### Core flows

#### Permission check (with approval auto-intercept)

When an approval policy matches, `access/check` returns `requires_human_approval` before the product creates a request.

```bash
curl -s -X POST "$API/v1/accounts/$ACCOUNT_ID/access/check" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "data.export",
    "resource": { "resourceType": "dataset", "resourceId": "ds_1" },
    "context": { "accountId": "'"$ACCOUNT_ID"'" }
  }'
```

#### Delegate user → agent

```bash
curl -s -X POST "$API/v1/accounts/$ACCOUNT_ID/delegations" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fromActor": { "type": "user", "id": "user_1" },
    "toActor": { "type": "agent", "id": "agent_1" },
    "allowedActions": ["tools.invoke"],
    "expiresAt": "2026-06-02T00:00:00Z"
  }'
```

#### Change member role

```bash
curl -s -X PATCH "$API/v1/accounts/$ACCOUNT_ID/members/$MEMBER_ID" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "roleKey": "admin" }'
```

#### Tool invoke gateway

```bash
curl -s -X POST "$API/v1/accounts/$ACCOUNT_ID/tools/invoke" \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "agentId": "agent_1",
    "toolId": "slack",
    "payload": { }
  }'
```

---

### Complete route surface

See [vision/architecture.md](../../vision/architecture.md) for the full GA route matrix.

Includes today’s routes. Remaining GA delta: admin OIDC, real approval notifications, audit SIEM export — see [product-backlog.md](../../gaps/product-backlog.md).

---

### SDK (GA)

```typescript
import { createXentraClient } from "@x12i/xentra-sdk";

const xentra = createXentraClient({
  baseUrl: "https://api.xentra.x12i.io",
  getToken: () => keycloakAccessToken,
});

const result = await xentra.permissions.can(accountId, {
  actor: { type: "agent", id: agentId },
  action: "tools.invoke",
  resource: { resourceType: "tool", resourceId: "slack" },
  context: { accountId },
});

const { items, nextCursor } = await xentra.members.list(accountId, { limit: 50 });
```

All list methods return paginated envelopes.

---

### Error format

```json
{
  "error": "missing_permission",
  "message": "Human-readable description",
  "requestId": "uuid"
}
```

Success wrapper: `{ "data": { } }`

---

### OpenAPI

Published at deploy time from `@x12i/xentra-openapi`. No `x-internal` paths at GA.

---

### Related

- [use-cases/](../../use-cases/)
- [gaps/product-backlog.md](../../gaps/product-backlog.md) — delta from today

## Deployment go-live

**Product:** Xentra runs as a managed, horizontally scalable API with independent health for each dependency.

**Technical:** Production go-live after all [gaps/production-blockers.md](../../gaps/production-blockers.md) close.

---

### Architecture

```
Product apps / Admin UI (OIDC)
        │ HTTPS + JWT / API key
        ▼
   Xentra API (HPA, PDB)
        ├── MongoDB (replica set, backups)
        ├── Cerbos (TLS gRPC, policy ConfigMap)
        ├── Keycloak (OIDC, realm per env)
        └── Authix (HTTPS, published image)
```

---

### Go-live checklist

- [ ] All [configuration.md](./configuration.md) production vars set from secrets manager
- [ ] `/ready` 200 for 24h in staging (mongo, authix, cerbos)
- [ ] Cerbos policies reviewed (`cerbos compile policies/`)
- [ ] Service API keys rotated; CORS locked
- [ ] Keycloak realm/clients match environment
- [ ] Authix token issue/revoke smoke test
- [ ] Mongo backup + restore drill
- [ ] Alerts on `/ready` 503, error rate, latency
- [ ] Security review sign-off
- [ ] P2 routes deployed if in GA scope
- [ ] Admin UI OIDC verified
- [ ] Status page live with dependency breakdown
- [ ] Onboarding checklist tested with pilot product

---

### Kubernetes

```bash
kubectl apply -k deploy/k8s/
```

- Secrets from external store (not git placeholders)
- Ingress TLS termination
- HPA on CPU/request rate
- PDB for rolling updates
- NetworkPolicy: API → Mongo, Keycloak, Cerbos, Authix only

---

### Rollback

`kubectl rollout undo deployment/xentra-api` — verify `/ready` within 30 seconds.

---

### Related

- [service-guide.md](./service-guide.md) — onboarding and incidents
- [../current/deployment.md](../current/deployment.md) — local dev preview phases

## Service contract

**Product:** External communication for a GA hosted Xentra service — onboarding, contracts, support, incidents.

**Technical:** Auth model, flow diagrams, checklists, templates. Dev preview messaging: [current/service-guide.md](../current/service-guide.md).

---

### Public API contract

#### Source of truth

1. Implemented authenticated behavior on deployed environment
2. OpenAPI from `@x12i/xentra-openapi` (no `x-internal` at GA)
3. `@x12i/xentra-sdk` method signatures

#### Versioning

| Layer | Scheme | Breaking changes |
|-------|--------|------------------|
| HTTP API | `/v1/` prefix | New major `/v2/` |
| npm packages | Semver | Changesets + changelog |
| OpenAPI | Matches API version | Published alongside deploy |

Communicate breaking changes **30 days** before removal.

---

### Authentication model

| Caller | Method | Use case |
|--------|--------|----------|
| Product backend | Service API key or Authix client credentials | Permission checks, token issue |
| Product frontend | Keycloak OIDC → Bearer JWT | User-scoped calls |
| Agent runtime | Authix token from Xentra grant | Tool invocation |
| Admin UI | Keycloak OIDC + elevated roles | Administration |

---

### Core integration flows

#### Permission check before action

```
Product Backend                    Xentra API
      │  POST /access/check             │
      │────────────────────────────────►│
      │◄────────────────────────────────│
      │  { allowed, reason }            │
      │  if allowed → perform action    │
```

#### Agent token issue

```
Agent Service          Xentra API              Authix
      │ POST /tokens/issue  │                    │
      │────────────────────►│───────────────────►│
      │◄────────────────────│◄───────────────────│
      │ { grant, token }    │                    │
```

#### Approval-gated action

```
Agent → Product → Xentra (check) → requires_human_approval
                                 → create approval request → notify approver
Human → Admin UI → approve
Agent → Product → Xentra (check) → allowed → execute
```

---

### Onboarding checklist (new product team)

#### Access provisioning

- [ ] Keycloak realm/client configured
- [ ] Xentra account created (`slug` agreed)
- [ ] Owner user assigned
- [ ] Authix `appId` registered
- [ ] Service API key in secrets manager
- [ ] Staging + production base URLs shared

#### Integration

- [ ] SDK installed: `@x12i/xentra-sdk`
- [ ] Permission actions documented
- [ ] Agents registered (if agentic)
- [ ] Approval policies defined
- [ ] Audit verified in staging

#### Launch

- [ ] Production credentials rotated from staging
- [ ] Load test on `/access/check`
- [ ] Runbook shared with on-call
- [ ] Status page subscription enabled

---

### Support and escalation

| Severity | Example | Response target |
|----------|---------|-----------------|
| S1 | API down, auth broken | 15 min acknowledge |
| S2 | Degraded permission checks | 1 hour |
| S3 | Docs / SDK bug | Next business day |
| S4 | Feature request | Backlog |

---

### Incident communication template

```
Subject: [Xentra] Incident — <short title>

Status: Investigating | Identified | Monitoring | Resolved
Impact: <who cannot do what>
Start time: <UTC>
Workaround: <if any>

Timeline:
- HH:MM UTC — ...

Next update: <time>
```

---

### Documentation deliverables (GA)

| Artifact | Channel |
|----------|---------|
| Getting started guide | docs.x12i.io/xentra |
| OpenAPI / Redoc | `/openapi.json` |
| SDK reference | npm + typedoc |
| Action key registry | internal wiki |
| Approval policy cookbook | docs |
| Changelog | GitHub releases |

---

### Related

- [vision/external-positioning.md](../../vision/external-positioning.md)
- [implementation/target/deployment.md](./deployment.md)

## Delta from developer preview

Preview vs GA: Cerbos TLS, published Authix image, secrets manager (no git placeholders), admin OIDC, real notifications, SIEM export, observability/alerting, security sign-off. Track open items in Gaps.

---

# Implementation Target — builders

# Implementation Target — Operators
**Audience:** GA-target configuration, integration, and operations.
**Twin:** [Developers version](../developers/BOOK.md)
**Package:** `@x12i/xentra-*` · **Docs:** https://docs.xentra.x12i.com · **Status:** Work In Progress

---

## Target integration path

At GA: Keycloak login → Xentra account → named actions → `access/check` → agent tokens through Xentra/Authix → approvals → audit. Full curl and auth caller details below.

## Production configuration

**Product:** Production Xentra requires hardened dependencies — TLS everywhere, secrets in a manager, no dev fallbacks.

**Technical:** All variables from [current/configuration.md](../current/configuration.md) plus GA requirements below.

---

### Production requirements (all required)

| Variable | GA requirement |
|----------|----------------|
| `NODE_ENV` | `production` |
| `MONGODB_URI` | Replica set URI from secrets manager |
| `KEYCLOAK_*` | Production realm; JWKS URI verified |
| `CERBOS_ADDRESS` | TLS gRPC endpoint |
| `AUTHIX_BASE_URL` | HTTPS; published Authix deployment |
| `AUTHIX_API_KEY` | Rotated; stored in secrets manager |
| `XENTRA_SERVICE_API_KEYS` | Comma-separated; rotated per product |
| `CORS_ALLOWED_ORIGINS` | Explicit product origins only |
| `TRUST_PROXY` | `true` behind ingress |

Startup fails if any production-required variable is missing.

---

### Cerbos TLS

**Product:** Policy decisions must not traverse plaintext on production networks.

**Technical:** Configure Cerbos with TLS certificates; update `@x12i/xentra-permissions` Cerbos client for TLS credentials; verify fail-closed on connection errors.

---

### Authix

**Product:** All agent and service tokens flow through Authix with Xentra grant bookkeeping.

**Technical:**
- Published container image in private registry
- `AUTHIX_ISSUER` matches token validation
- Shared `AUTHIX_API_KEY` between Xentra and Authix deployment
- Health check included in Xentra `/ready`

---

### Admin UI (OIDC)

**Product:** Operators sign in via Keycloak, not pasted JWTs.

**Technical:**
- Keycloak client `xentra-admin-ui` (public, PKCE)
- Admin SPA env: `VITE_KEYCLOAK_*` pointing to realm
- Cerbos `admin` / `access` for route guard

---

### Observability

**Product:** SRE can detect and respond to outages.

**Technical:**
- Prometheus scrape `/metrics`
- Alerts: `/ready` 503, 5xx rate, p99 latency on `/access/check`
- Structured JSON logs with `requestId`
- Optional: audit export webhook URL (when implemented)

---

### Kubernetes (GA)

All secrets from external secrets operator or cloud secrets manager — never placeholder values in git.

Network policies: API pods reach only Mongo, Keycloak, Cerbos, Authix.

---

### Related

- [deployment.md](./deployment.md)
- [gaps/production-blockers.md](../../gaps/production-blockers.md)

## Full API flows

**Product:** Products integrate via four steps — account, action vocabulary, access/check, tokens through Xentra — plus teams, delegations, and approvals as they mature.

**Technical:** Complete HTTP API usage at GA. Dev preview subset: [current/integration-guide.md](../current/integration-guide.md).

---

### Authentication (GA)

| Caller | Method | Use case |
|--------|--------|----------|
| Product backend | Service API key or Authix client credentials | Server-side checks, token issue |
| Product frontend | Keycloak OIDC → Bearer JWT | User-scoped calls |
| Agent runtime | Authix token from Xentra grant | Tool invocation on behalf of user |
| Admin UI | Keycloak OIDC + elevated roles | Account administration |

**Security rules:**
- Never trust client-supplied `actor` without binding to validated token
- Permission checks on client are advisory; **server must enforce**
- Rotate API keys via platform; revoke tokens via `POST .../tokens/revoke`

---

### Core flows

#### Permission check (with approval auto-intercept)

When an approval policy matches, `access/check` returns `requires_human_approval` before the product creates a request.

```bash
curl -s -X POST "$API/v1/accounts/$ACCOUNT_ID/access/check" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "data.export",
    "resource": { "resourceType": "dataset", "resourceId": "ds_1" },
    "context": { "accountId": "'"$ACCOUNT_ID"'" }
  }'
```

#### Delegate user → agent

```bash
curl -s -X POST "$API/v1/accounts/$ACCOUNT_ID/delegations" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fromActor": { "type": "user", "id": "user_1" },
    "toActor": { "type": "agent", "id": "agent_1" },
    "allowedActions": ["tools.invoke"],
    "expiresAt": "2026-06-02T00:00:00Z"
  }'
```

#### Change member role

```bash
curl -s -X PATCH "$API/v1/accounts/$ACCOUNT_ID/members/$MEMBER_ID" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "roleKey": "admin" }'
```

#### Tool invoke gateway

```bash
curl -s -X POST "$API/v1/accounts/$ACCOUNT_ID/tools/invoke" \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "agentId": "agent_1",
    "toolId": "slack",
    "payload": { }
  }'
```

---

### Complete route surface

See [vision/architecture.md](../../vision/architecture.md) for the full GA route matrix.

Includes today’s routes. Remaining GA delta: admin OIDC, real approval notifications, audit SIEM export — see [product-backlog.md](../../gaps/product-backlog.md).

---

### SDK (GA)

```typescript
import { createXentraClient } from "@x12i/xentra-sdk";

const xentra = createXentraClient({
  baseUrl: "https://api.xentra.x12i.io",
  getToken: () => keycloakAccessToken,
});

const result = await xentra.permissions.can(accountId, {
  actor: { type: "agent", id: agentId },
  action: "tools.invoke",
  resource: { resourceType: "tool", resourceId: "slack" },
  context: { accountId },
});

const { items, nextCursor } = await xentra.members.list(accountId, { limit: 50 });
```

All list methods return paginated envelopes.

---

### Error format

```json
{
  "error": "missing_permission",
  "message": "Human-readable description",
  "requestId": "uuid"
}
```

Success wrapper: `{ "data": { } }`

---

### OpenAPI

Published at deploy time from `@x12i/xentra-openapi`. No `x-internal` paths at GA.

---

### Related

- [use-cases/](../../use-cases/)
- [gaps/product-backlog.md](../../gaps/product-backlog.md) — delta from today

## Deployment go-live

**Product:** Xentra runs as a managed, horizontally scalable API with independent health for each dependency.

**Technical:** Production go-live after all [gaps/production-blockers.md](../../gaps/production-blockers.md) close.

---

### Architecture

```
Product apps / Admin UI (OIDC)
        │ HTTPS + JWT / API key
        ▼
   Xentra API (HPA, PDB)
        ├── MongoDB (replica set, backups)
        ├── Cerbos (TLS gRPC, policy ConfigMap)
        ├── Keycloak (OIDC, realm per env)
        └── Authix (HTTPS, published image)
```

---

### Go-live checklist

- [ ] All [configuration.md](./configuration.md) production vars set from secrets manager
- [ ] `/ready` 200 for 24h in staging (mongo, authix, cerbos)
- [ ] Cerbos policies reviewed (`cerbos compile policies/`)
- [ ] Service API keys rotated; CORS locked
- [ ] Keycloak realm/clients match environment
- [ ] Authix token issue/revoke smoke test
- [ ] Mongo backup + restore drill
- [ ] Alerts on `/ready` 503, error rate, latency
- [ ] Security review sign-off
- [ ] P2 routes deployed if in GA scope
- [ ] Admin UI OIDC verified
- [ ] Status page live with dependency breakdown
- [ ] Onboarding checklist tested with pilot product

---

### Kubernetes

```bash
kubectl apply -k deploy/k8s/
```

- Secrets from external store (not git placeholders)
- Ingress TLS termination
- HPA on CPU/request rate
- PDB for rolling updates
- NetworkPolicy: API → Mongo, Keycloak, Cerbos, Authix only

---

### Rollback

`kubectl rollout undo deployment/xentra-api` — verify `/ready` within 30 seconds.

---

### Related

- [service-guide.md](./service-guide.md) — onboarding and incidents
- [../current/deployment.md](../current/deployment.md) — local dev preview phases

## Service contract

**Product:** External communication for a GA hosted Xentra service — onboarding, contracts, support, incidents.

**Technical:** Auth model, flow diagrams, checklists, templates. Dev preview messaging: [current/service-guide.md](../current/service-guide.md).

---

### Public API contract

#### Source of truth

1. Implemented authenticated behavior on deployed environment
2. OpenAPI from `@x12i/xentra-openapi` (no `x-internal` at GA)
3. `@x12i/xentra-sdk` method signatures

#### Versioning

| Layer | Scheme | Breaking changes |
|-------|--------|------------------|
| HTTP API | `/v1/` prefix | New major `/v2/` |
| npm packages | Semver | Changesets + changelog |
| OpenAPI | Matches API version | Published alongside deploy |

Communicate breaking changes **30 days** before removal.

---

### Authentication model

| Caller | Method | Use case |
|--------|--------|----------|
| Product backend | Service API key or Authix client credentials | Permission checks, token issue |
| Product frontend | Keycloak OIDC → Bearer JWT | User-scoped calls |
| Agent runtime | Authix token from Xentra grant | Tool invocation |
| Admin UI | Keycloak OIDC + elevated roles | Administration |

---

### Core integration flows

#### Permission check before action

```
Product Backend                    Xentra API
      │  POST /access/check             │
      │────────────────────────────────►│
      │◄────────────────────────────────│
      │  { allowed, reason }            │
      │  if allowed → perform action    │
```

#### Agent token issue

```
Agent Service          Xentra API              Authix
      │ POST /tokens/issue  │                    │
      │────────────────────►│───────────────────►│
      │◄────────────────────│◄───────────────────│
      │ { grant, token }    │                    │
```

#### Approval-gated action

```
Agent → Product → Xentra (check) → requires_human_approval
                                 → create approval request → notify approver
Human → Admin UI → approve
Agent → Product → Xentra (check) → allowed → execute
```

---

### Onboarding checklist (new product team)

#### Access provisioning

- [ ] Keycloak realm/client configured
- [ ] Xentra account created (`slug` agreed)
- [ ] Owner user assigned
- [ ] Authix `appId` registered
- [ ] Service API key in secrets manager
- [ ] Staging + production base URLs shared

#### Integration

- [ ] SDK installed: `@x12i/xentra-sdk`
- [ ] Permission actions documented
- [ ] Agents registered (if agentic)
- [ ] Approval policies defined
- [ ] Audit verified in staging

#### Launch

- [ ] Production credentials rotated from staging
- [ ] Load test on `/access/check`
- [ ] Runbook shared with on-call
- [ ] Status page subscription enabled

---

### Support and escalation

| Severity | Example | Response target |
|----------|---------|-----------------|
| S1 | API down, auth broken | 15 min acknowledge |
| S2 | Degraded permission checks | 1 hour |
| S3 | Docs / SDK bug | Next business day |
| S4 | Feature request | Backlog |

---

### Incident communication template

```
Subject: [Xentra] Incident — <short title>

Status: Investigating | Identified | Monitoring | Resolved
Impact: <who cannot do what>
Start time: <UTC>
Workaround: <if any>

Timeline:
- HH:MM UTC — ...

Next update: <time>
```

---

### Documentation deliverables (GA)

| Artifact | Channel |
|----------|---------|
| Getting started guide | docs.x12i.io/xentra |
| OpenAPI / Redoc | `/openapi.json` |
| SDK reference | npm + typedoc |
| Action key registry | internal wiki |
| Approval policy cookbook | docs |
| Changelog | GitHub releases |

---

### Related

- [vision/external-positioning.md](../../vision/external-positioning.md)
- [implementation/target/deployment.md](./deployment.md)

## Delta from developer preview

Preview vs GA: Cerbos TLS, published Authix image, secrets manager (no git placeholders), admin OIDC, real notifications, SIEM export, observability/alerting, security sign-off. Track open items in Gaps.

---

# Use Cases — developers

# Use Cases — Developers
**Audience:** End-to-end GA scenarios (status tracked in Gaps).
**Package:** `@x12i/xentra-*` · **Docs:** https://docs.xentra.x12i.com · **Status:** Work In Progress

---

## Multi-tenant IAM

### Product level

**Actors:** Platform operator, account owner, invited members.

**Trigger:** A new organisation signs up for an x12i product.

**Outcome:** The organisation has an isolated Xentra account with default roles. Members are invited, roles can be changed, and every sensitive action is gated by `access/check`. Owners manage the account; members operate within their role; viewers read only.

**Value:** Products stop building custom tenant and role models.

---

### Technical level

#### Flow

1. Platform creates account: `POST /v1/accounts` (service API key)
2. Owner mapped from Keycloak on first `GET /v1/users/me`
3. Owner invites member: `POST .../members`
4. Admin changes role: `PATCH .../members/:memberId` with `roleKey`
5. Before any mutation, product calls `POST .../access/check` with Cerbos action (e.g. `read`, `invite_member`, `change_member_role`)

#### Cerbos actions

| Action | Resource |
|--------|----------|
| `read`, `update`, `delete` | `account` |
| `invite_member`, `remove_member`, `change_member_role` | `account` |

#### Teams and workspaces (GA)

- Teams group members within an account: `POST .../teams`
- Workspaces scope resources: `POST .../workspaces`
- Permission checks include `context.workspaceId` / `context.teamId` when relevant

---

### Related

- [cross-product-identity.md](./cross-product-identity.md)
- [user-stories/product-backend.md](../user-stories/product-backend.md)

## Agent governance

### Product level

**Actors:** End user, registered agent, product backend, agent runtime.

**Trigger:** Product runs an AI agent that can invoke external tools on behalf of users.

**Outcome:** Each agent has a stable identity and explicit tool allow-list. Users delegate time-bound permissions to agents. Agents receive scoped tokens only through Xentra. Tool invocations are checked and audited. Nothing outside the allow-list runs.

**Value:** Safe agentic automation with accountability.

---

### Technical level

#### Flow

1. Register agent: `POST .../agents` with `allowedToolIds`
2. User delegates: `POST .../delegations` with `allowedActions`, `expiresAt`
3. Agent requests token: `POST .../tokens/issue` → Authix
4. Before tool call: `POST .../access/check` with action `tools.invoke` or `POST .../tools/invoke`
5. Agent runtime uses Authix token; product logs action to audit

#### Data flow

```
User → Delegation → Agent → access/check → tools/invoke → External API
                              ↓
                           Audit log
```

#### Revocation

- Deactivate agent: `DELETE .../agents/:id`
- Revoke token: `POST .../tokens/revoke`
- Delegation expires automatically at `expiresAt`

---

### Related

- [human-in-the-loop.md](./human-in-the-loop.md)
- [user-stories/product-backend.md](../user-stories/product-backend.md)

## Human-in-the-loop

### Product level

**Actors:** User or agent attempting action, security admin approver.

**Trigger:** A high-risk operation is attempted (e.g. data export, bulk delete, external payment).

**Outcome:** Xentra blocks execution until a designated human approves. Approvers receive notifications. Approved actions proceed; rejected actions remain denied. Full trail in audit.

**Value:** Consequential actions never run unattended.

---

### Technical level

#### Flow

1. Define policy: `POST .../approval-policies` with `actions`, `resourceTypes`, approver roles
2. Actor attempts action → `POST .../access/check` returns `requires_human_approval`
3. Product creates request: `POST .../approval-requests`
4. Notifier sends email/push to approvers
5. Approver: `POST .../approval-requests/:id/approve` or `reject`
6. Re-check `access/check` → `allowed` with reason `allowed_by_approval`

#### Diagram

```
Agent → Product → access/check → requires_human_approval
              → approval-request → notify approver
Approver → Admin UI → approve
Agent → Product → access/check → allowed → execute
```

#### Cerbos

Approval policies evaluated inside permission engine; reason codes: `requires_human_approval`, `allowed_by_approval`, `denied_by_approval_rejection`.

---

### Related

- [compliance-audit.md](./compliance-audit.md)
- [user-stories/security-compliance.md](../user-stories/security-compliance.md)

## Cross-product identity

### Product level

**Actors:** Same human user across multiple x12i products (e.g. CRM + document agent + billing).

**Trigger:** User already has a Keycloak identity and Xentra account; a second product onboards.

**Outcome:** The user’s Xentra account, memberships, and roles are shared. Permissions defined once apply consistently. Audit spans products. No duplicate IAM per product.

**Value:** Platform coherence and reduced admin burden.

---

### Technical level

#### Integration pattern

1. Each product registers an Authix `appId` under the same Xentra account
2. User authenticates via Keycloak (same realm/sub)
3. `GET /v1/users/me` returns user + account memberships
4. Each product calls `access/check` with product-specific action strings but shared account context
5. Audit queries filter by `accountId` across all product actions

#### Action vocabulary

Products namespace actions: `crm.deals.delete`, `docs.sign`, `agent.invoke_tool`. Xentra stores opaque strings; Cerbos policies map roles to action patterns.

#### Not in scope

Cross-product SSO UI — Keycloak handles login screens.

---

### Related

- [multi-tenant-iam.md](./multi-tenant-iam.md)
- [vision/product-overview.md](../vision/product-overview.md)

## Compliance audit

### Product level

**Actors:** Security analyst, compliance officer, incident responder.

**Trigger:** Security review, regulatory audit, or incident investigation.

**Outcome:** Complete, trustworthy record of who did what and when — permission checks, token issue/revoke, membership changes, approvals, agent actions. Events exportable to SIEM.

**Value:** Compliance without per-product logging implementations.

---

### Technical level

#### Query API

`GET /v1/accounts/:accountId/audit` with filters:

- `from`, `to` — time range
- `actorId` — who
- `action` — what
- `targetType`, `targetId` — resource
- Pagination: `limit`, `cursor`

#### Automatic writes

Audit appended on: account/member/agent mutations, permission checks (configurable), token issue/revoke, approval state changes.

#### GA export (target)

- Webhook stream to SIEM
- Batch export to object storage
- Retention policy per account tier

#### Investigation flow

1. Identify account and time window
2. Filter by actor or action
3. Correlate with Keycloak session (external)
4. Revoke active grants if compromise suspected: `POST .../tokens/revoke`

---

### Related

- [human-in-the-loop.md](./human-in-the-loop.md)
- [user-stories/security-compliance.md](../user-stories/security-compliance.md)

---

# User Stories — developers

# User Stories — Developers
**Audience:** INVEST stories by persona. Implementation status lives in Gaps.
**Twin:** [Operators version](../builders/BOOK.md)
**Package:** `@x12i/xentra-*` · **Docs:** https://docs.xentra.x12i.com · **Status:** Work In Progress

---

## Story format

INVEST-style stories for the **target** product — no ✅/❌ status markers. Status tracking lives in [gaps/package-status.md](../gaps/package-status.md).

### Story format

Each story follows:

> **As a** [role], **I want** [capability], **so that** [outcome].

Stories include **Product** acceptance criteria (user-visible) and **Technical** acceptance criteria (API, packages, tests).

### Documents

| Document | Persona |
|----------|---------|
| [platform-engineer.md](./platform-engineer.md) | Deploy, configure TLS, rotate keys, observability |
| [product-backend.md](./product-backend.md) | access/check, tokens, approvals, delegations HTTP |
| [security-compliance.md](./security-compliance.md) | Audit, SoD, token revoke, investigations |
| [admin-operator.md](./admin-operator.md) | OIDC admin, member roles, agent lifecycle |

### Related

- **Scenario narratives:** [use-cases/index.md](../use-cases/index.md)
- **Package status today:** [gaps/package-status.md](../gaps/package-status.md)

## Platform engineer

Future-state INVEST stories for deploying and operating Xentra at GA.

---

### Deploy production stack

**As a** platform engineer, **I want** to deploy Xentra API with Mongo, Keycloak, Cerbos (TLS), and Authix on Kubernetes, **so that** product teams have a reliable shared IAM service.

**Product acceptance:**
- Staging and production environments isolated
- `/ready` reports healthy dependencies
- Rollback completes within 30 seconds

**Technical acceptance:**
- All [configuration](../implementation/target/configuration.md) production vars from secrets manager
- `kubectl apply -k deploy/k8s/` with real images
- NetworkPolicy restricts egress to dependencies only
- HPA and PDB configured

---

### Configure Cerbos TLS

**As a** platform engineer, **I want** Cerbos gRPC encrypted in production, **so that** policy decisions are not exposed on the network.

**Technical acceptance:**
- Cerbos serves TLS on gRPC port
- `@x12i/xentra-permissions` client uses TLS credentials
- Cerbos unreachable → deny (fail-closed), not fallback

---

### Rotate service API keys

**As a** platform engineer, **I want** to rotate `XENTRA_SERVICE_API_KEYS` without downtime, **so that** compromised keys can be revoked safely.

**Technical acceptance:**
- Multiple keys accepted simultaneously during rotation window
- Old key removed after all products updated
- Audit log records service account actions per key id (metadata)

---

### Observability and alerting

**As a** platform engineer, **I want** alerts when Xentra or dependencies degrade, **so that** incidents are detected before customers report them.

**Technical acceptance:**
- Prometheus scrapes `/metrics`
- Alerts: `/ready` 503, 5xx rate, p99 on `/access/check`
- Status page lists API, Mongo, Keycloak, Authix, Cerbos independently

---

### Related

- [use-cases/index.md](../use-cases/index.md)
- [gaps/production-blockers.md](../gaps/production-blockers.md)

## Product backend

Future-state stories for teams integrating products with Xentra HTTP API / SDK.

---

### Permission check before mutation

**As a** product backend developer, **I want** to call `access/check` before every sensitive operation, **so that** unauthorized users and agents cannot mutate data.

**Product acceptance:**
- Denied actions return 403 to client
- Approval-required actions trigger workflow, not silent allow

**Technical acceptance:**
- `POST /v1/accounts/:id/access/check` with Cerbos action strings
- Actor bound to JWT for user callers
- Server-side enforcement on all mutation routes (never client-only)

---

### Issue agent token through Xentra

**As a** product backend developer, **I want** to issue agent tokens via Xentra (not direct Authix), **so that** grants and audit stay consistent.

**Technical acceptance:**
- `POST .../tokens/issue` with `appId`, actor, scope
- Grant persisted in Mongo
- Audit event on issue
- Direct Authix bypass rejected by platform policy

---

### Delegate to agent

**As a** product backend developer, **I want** users to delegate specific actions to agents for a limited time, **so that** agents act on behalf of users without permanent elevated access.

**Technical acceptance:**
- `POST .../delegations` with `allowedActions`, `expiresAt`
- `access/check` returns `allowed_by_delegation` when valid
- Expired delegation → denied

---

### Paginated member list in SDK

**As a** product backend developer, **I want** the SDK to return paginated list envelopes, **so that** I can iterate large tenant member lists reliably.

**Technical acceptance:**
- `client.members.list()` returns `{ items, nextCursor }`
- Matches REST `GET .../members?limit=&cursor=`

---

### Related

- [use-cases/agent-governance.md](../use-cases/agent-governance.md)
- [use-cases/multi-tenant-iam.md](../use-cases/multi-tenant-iam.md)

## Security compliance

Future-state stories for security and compliance teams.

---

### Investigate audit trail

**As a** security analyst, **I want** to query audit events by account, actor, action, and time range, **so that** I can investigate incidents and support audits.

**Technical acceptance:**
- `GET .../audit?from=&to=&actorId=&action=`
- Paginated results; no cross-tenant leakage
- Events immutable (no update/delete API)

---

### Enforce separation of duties

**As a** compliance officer, **I want** high-risk actions to require approval from a different role than the requester, **so that** no single actor can execute consequential operations alone.

**Technical acceptance:**
- Approval policies define required approver roles
- `access/check` returns `requires_human_approval` until approved
- Rejection recorded; re-check denies

---

### Revoke compromised token

**As a** security analyst, **I want** to revoke an agent token immediately, **so that** a compromised credential cannot be reused.

**Technical acceptance:**
- `POST .../tokens/revoke` invalidates grant
- Authix verify/introspect returns invalid after revoke
- Audit event records revoker and reason

---

### Export audit to SIEM

**As a** compliance officer, **I want** audit events streamed to our SIEM, **so that** we meet retention and monitoring requirements without custom product logging.

**Technical acceptance:**
- Export webhook or batch API (GA target)
- Configurable retention per account
- Documented event schema

---

### Related

- [use-cases/compliance-audit.md](../use-cases/compliance-audit.md)
- [use-cases/human-in-the-loop.md](../use-cases/human-in-the-loop.md)

## Admin operator

Future-state stories for operators using the Xentra admin console.

---

### Sign in with Keycloak

**As an** account admin, **I want** to sign in to the admin UI with my corporate SSO (Keycloak), **so that** I do not paste JWTs manually.

**Technical acceptance:**
- OIDC PKCE flow with client `xentra-admin-ui`
- Session refresh handled by SPA
- `PermissionGate` checks Cerbos `admin` / `access`

---

### Change member role

**As an** account admin, **I want** to promote or demote a member’s role via the admin UI, **so that** access changes without re-inviting users.

**Technical acceptance:**
- UI calls `PATCH .../members/:memberId`
- Cerbos `change_member_role` enforced
- Audit event on role change

---

### Manage agent lifecycle

**As an** account admin, **I want** to deactivate an agent and update its tool allow-list, **so that** retired agents cannot invoke tools.

**Technical acceptance:**
- `PATCH .../agents/:id` for allow-list updates
- `DELETE .../agents/:id` deactivates and revokes delegations
- List view shows active vs inactive agents

---

### Approve pending request

**As a** security admin, **I want** to approve or reject approval requests in the admin UI, **so that** gated actions proceed only after my sign-off.

**Technical acceptance:**
- Pending queue from `GET .../approval-requests?status=pending`
- Approve/reject actions call API
- Notification received when request created (email/push)

---

### Related

- [use-cases/human-in-the-loop.md](../use-cases/human-in-the-loop.md)
- [use-cases/multi-tenant-iam.md](../use-cases/multi-tenant-iam.md)

---

# User Stories — builders

# User Stories — Operators
**Audience:** INVEST stories by persona. Implementation status lives in Gaps.
**Twin:** [Developers version](../developers/BOOK.md)
**Package:** `@x12i/xentra-*` · **Docs:** https://docs.xentra.x12i.com · **Status:** Work In Progress

---

## Story format

INVEST-style stories for the **target** product — no ✅/❌ status markers. Status tracking lives in [gaps/package-status.md](../gaps/package-status.md).

### Story format

Each story follows:

> **As a** [role], **I want** [capability], **so that** [outcome].

Stories include **Product** acceptance criteria (user-visible) and **Technical** acceptance criteria (API, packages, tests).

### Documents

| Document | Persona |
|----------|---------|
| [platform-engineer.md](./platform-engineer.md) | Deploy, configure TLS, rotate keys, observability |
| [product-backend.md](./product-backend.md) | access/check, tokens, approvals, delegations HTTP |
| [security-compliance.md](./security-compliance.md) | Audit, SoD, token revoke, investigations |
| [admin-operator.md](./admin-operator.md) | OIDC admin, member roles, agent lifecycle |

### Related

- **Scenario narratives:** [use-cases/index.md](../use-cases/index.md)
- **Package status today:** [gaps/package-status.md](../gaps/package-status.md)

## Platform engineer

Future-state INVEST stories for deploying and operating Xentra at GA.

---

### Deploy production stack

**As a** platform engineer, **I want** to deploy Xentra API with Mongo, Keycloak, Cerbos (TLS), and Authix on Kubernetes, **so that** product teams have a reliable shared IAM service.

**Product acceptance:**
- Staging and production environments isolated
- `/ready` reports healthy dependencies
- Rollback completes within 30 seconds

**Technical acceptance:**
- All [configuration](../implementation/target/configuration.md) production vars from secrets manager
- `kubectl apply -k deploy/k8s/` with real images
- NetworkPolicy restricts egress to dependencies only
- HPA and PDB configured

---

### Configure Cerbos TLS

**As a** platform engineer, **I want** Cerbos gRPC encrypted in production, **so that** policy decisions are not exposed on the network.

**Technical acceptance:**
- Cerbos serves TLS on gRPC port
- `@x12i/xentra-permissions` client uses TLS credentials
- Cerbos unreachable → deny (fail-closed), not fallback

---

### Rotate service API keys

**As a** platform engineer, **I want** to rotate `XENTRA_SERVICE_API_KEYS` without downtime, **so that** compromised keys can be revoked safely.

**Technical acceptance:**
- Multiple keys accepted simultaneously during rotation window
- Old key removed after all products updated
- Audit log records service account actions per key id (metadata)

---

### Observability and alerting

**As a** platform engineer, **I want** alerts when Xentra or dependencies degrade, **so that** incidents are detected before customers report them.

**Technical acceptance:**
- Prometheus scrapes `/metrics`
- Alerts: `/ready` 503, 5xx rate, p99 on `/access/check`
- Status page lists API, Mongo, Keycloak, Authix, Cerbos independently

---

### Related

- [use-cases/index.md](../use-cases/index.md)
- [gaps/production-blockers.md](../gaps/production-blockers.md)

## Product backend

Future-state stories for teams integrating products with Xentra HTTP API / SDK.

---

### Permission check before mutation

**As a** product backend developer, **I want** to call `access/check` before every sensitive operation, **so that** unauthorized users and agents cannot mutate data.

**Product acceptance:**
- Denied actions return 403 to client
- Approval-required actions trigger workflow, not silent allow

**Technical acceptance:**
- `POST /v1/accounts/:id/access/check` with Cerbos action strings
- Actor bound to JWT for user callers
- Server-side enforcement on all mutation routes (never client-only)

---

### Issue agent token through Xentra

**As a** product backend developer, **I want** to issue agent tokens via Xentra (not direct Authix), **so that** grants and audit stay consistent.

**Technical acceptance:**
- `POST .../tokens/issue` with `appId`, actor, scope
- Grant persisted in Mongo
- Audit event on issue
- Direct Authix bypass rejected by platform policy

---

### Delegate to agent

**As a** product backend developer, **I want** users to delegate specific actions to agents for a limited time, **so that** agents act on behalf of users without permanent elevated access.

**Technical acceptance:**
- `POST .../delegations` with `allowedActions`, `expiresAt`
- `access/check` returns `allowed_by_delegation` when valid
- Expired delegation → denied

---

### Paginated member list in SDK

**As a** product backend developer, **I want** the SDK to return paginated list envelopes, **so that** I can iterate large tenant member lists reliably.

**Technical acceptance:**
- `client.members.list()` returns `{ items, nextCursor }`
- Matches REST `GET .../members?limit=&cursor=`

---

### Related

- [use-cases/agent-governance.md](../use-cases/agent-governance.md)
- [use-cases/multi-tenant-iam.md](../use-cases/multi-tenant-iam.md)

## Security compliance

Future-state stories for security and compliance teams.

---

### Investigate audit trail

**As a** security analyst, **I want** to query audit events by account, actor, action, and time range, **so that** I can investigate incidents and support audits.

**Technical acceptance:**
- `GET .../audit?from=&to=&actorId=&action=`
- Paginated results; no cross-tenant leakage
- Events immutable (no update/delete API)

---

### Enforce separation of duties

**As a** compliance officer, **I want** high-risk actions to require approval from a different role than the requester, **so that** no single actor can execute consequential operations alone.

**Technical acceptance:**
- Approval policies define required approver roles
- `access/check` returns `requires_human_approval` until approved
- Rejection recorded; re-check denies

---

### Revoke compromised token

**As a** security analyst, **I want** to revoke an agent token immediately, **so that** a compromised credential cannot be reused.

**Technical acceptance:**
- `POST .../tokens/revoke` invalidates grant
- Authix verify/introspect returns invalid after revoke
- Audit event records revoker and reason

---

### Export audit to SIEM

**As a** compliance officer, **I want** audit events streamed to our SIEM, **so that** we meet retention and monitoring requirements without custom product logging.

**Technical acceptance:**
- Export webhook or batch API (GA target)
- Configurable retention per account
- Documented event schema

---

### Related

- [use-cases/compliance-audit.md](../use-cases/compliance-audit.md)
- [use-cases/human-in-the-loop.md](../use-cases/human-in-the-loop.md)

## Admin operator

Future-state stories for operators using the Xentra admin console.

---

### Sign in with Keycloak

**As an** account admin, **I want** to sign in to the admin UI with my corporate SSO (Keycloak), **so that** I do not paste JWTs manually.

**Technical acceptance:**
- OIDC PKCE flow with client `xentra-admin-ui`
- Session refresh handled by SPA
- `PermissionGate` checks Cerbos `admin` / `access`

---

### Change member role

**As an** account admin, **I want** to promote or demote a member’s role via the admin UI, **so that** access changes without re-inviting users.

**Technical acceptance:**
- UI calls `PATCH .../members/:memberId`
- Cerbos `change_member_role` enforced
- Audit event on role change

---

### Manage agent lifecycle

**As an** account admin, **I want** to deactivate an agent and update its tool allow-list, **so that** retired agents cannot invoke tools.

**Technical acceptance:**
- `PATCH .../agents/:id` for allow-list updates
- `DELETE .../agents/:id` deactivates and revokes delegations
- List view shows active vs inactive agents

---

### Approve pending request

**As a** security admin, **I want** to approve or reject approval requests in the admin UI, **so that** gated actions proceed only after my sign-off.

**Technical acceptance:**
- Pending queue from `GET .../approval-requests?status=pending`
- Approve/reject actions call API
- Notification received when request created (email/push)

---

### Related

- [use-cases/human-in-the-loop.md](../use-cases/human-in-the-loop.md)
- [use-cases/multi-tenant-iam.md](../use-cases/multi-tenant-iam.md)

---

# Next Release Contract — developers

# Next Release Contract — Developers
**Audience:** Maintainers and coding agents preparing the next Xentra version.
**Twin:** [Operators version](../builders/BOOK.md)
**Package:** `@x12i/xentra-*` · **Docs:** https://docs.xentra.x12i.com · **Status:** Work In Progress

---

## Mandatory next release rules

When the **next** Xentra version is released after 0.2.0:

1. **Close gaps** listed in book 03-gaps (external blockers required for GA; P2 items if in scope).
2. **Re-docify properly** — update books so content reflects the completed product, not a preview.
3. **Remove Work In Progress** from `data/site.json` brand/footer, product-home/docs-home kickers, book kickers in `catalog.json`, and any WIP callouts in Overview/Gaps.
4. **Do not ship** another WIP docs release unless intentional and explicitly labeled; the default next release is **complete documentation without work left / gaps chrome**.
5. Keep `@x12i/xentra-docs` and the Cloudflare site in sync with the tagged release.

## Documentation exit criteria

| Criterion | Done when |
|-----------|-----------|
| External blockers | All GA blockers in Gaps checked off or explicitly deferred with product sign-off |
| P2 in GA scope | Admin OIDC, real notifications, SIEM — done or cut from GA |
| Site branding | No "Work In Progress" / WIP kickers on home or catalog |
| Gaps book | Either retired, or reframed as historical/closed with no open GA blockers |
| Next Release book | Updated or removed once contract is satisfied |
| Validate/build | `docify validate` + `docs:verify` green |
| Publish | npm `@x12i/xentra-docs` + Cloudflare production smoke paths pass |

## Agent instructions

Coding agents preparing the next release **must**:

- Read 03-gaps and this book before claiming docs are complete.
- Update Docify content (not only `docs/` pointers).
- Bump package versions, CHANGELOG, tag, publish npm + docify, push git.
- Fail the release if WIP labeling remains while claiming GA.

---

# Next Release Contract — builders

# Next Release Contract — Operators
**Audience:** Release owners verifying docs and ops readiness.
**Twin:** [Developers version](../developers/BOOK.md)
**Package:** `@x12i/xentra-*` · **Docs:** https://docs.xentra.x12i.com · **Status:** Work In Progress

---

## Mandatory next release rules

Same contract as developers: next version must close Gaps, re-docify without WIP, publish complete docs. Do not promote `docs.xentra.x12i.com` as GA while brand still says Work In Progress.

## Documentation exit criteria

Ops sign-off: prod Mongo/Keycloak/Authix/Cerbos TLS/secrets/observability/security review complete per Gaps DoD; Docify site republished without WIP chrome; smokePaths green.

## Agent instructions

Operators coordinating a release should require the Gaps DoD checklist and this book's exit criteria before cutting the tag.
