Tenant isolation
Every piece of data in Neureus is scoped to a tenant. This is enforced at the database level, not the application level.
The rule
Every nr_* table includes a tenant_id column. Every query filters by it. No exceptions.
-- Every SELECT includes tenant_idSELECT * FROM nr_agents WHERE tenant_id = ? AND id = ?
-- Every INSERT includes tenant_idINSERT INTO nr_agents (tenant_id, name, ...) VALUES (?, ?, ...)This is ADR-4 — a foundational architectural decision that cannot be waived.
Authentication boundary
tenantMiddleware verifies the Bearer token and sets tenantId on the Hono request context. Route handlers read tenantId only from the verified context — never from request headers or body.
Bearer token → SessionManager.verify() → tenantId on context ↓ Route handler uses ctx.get('tenantId')Storage isolation
| Store | Isolation mechanism |
|---|---|
| D1 | tenant_id column on every table |
| R2 | Key prefix neureus/{tenantId}/ (enforced via r2Key() helper) |
| KV | Keys namespaced with tenantId |
| Vectorize | Metadata filter on tenantId |
What’s not tenant-scoped
nr_models — the model catalog is platform-global. All tenants share the same model list.
Auth-boundary lookups (nr_api_keys by key_hash) are exempt and use tenant_id != '' as a sentinel to satisfy the constraint without filtering on a specific tenant.