LM-Kit OneDocs2026.8.10lm-kit.com
Search & RAG/The Search Engine

Search: Access Model

Reference for who can reach what in Search: the four nouns (cluster, tenant, collection, API key), the caller model, the two kinds of grants, the discovery endpoints, and the security properties the API guarantees. Deciding WHERE your boundaries go (one tenant or many, one cluster or many) is Clusters, Tenants, Collections; this page is how the boundaries are enforced.


1The four nouns#

Noun What it is Created by Analogy
Cluster One physical search backend (a PostgreSQL database, or an app-level store such as SQLite, SQL Server, MySQL) with its own connections and schema. Addressed by an operator-chosen cluster_id. Operator, in the admin panel's Search section. Never through the public API. The database server
Tenant The isolation and configuration boundary inside a cluster: embedding model, search modes, OCR, normalization are all tenant-wide, and access is granted per tenant. Addressed by a server-generated GUID. API (POST /lmkit/v1/search/tenants) or the admin panel. The database schema
Collection A dataset inside a tenant. Documents are indexed into collections; a search targets one or several (collection_ids). Addressed by a caller-chosen GUID. API (POST /lmkit/v1/search/collections), idempotent. The table
API key The caller identity. Grants attach to the key id, so every key carries exactly the reach it was given. Operator, in the admin panel's Access section. The database role

The rule that decides where a boundary goes: the tenant is the smallest unit you will ever grant or revoke independently. Anything below that granularity is a collection (scoped at query time) or a metadata filter (a convenience, never a security boundary: filters are supplied by the caller).

2The caller model#

Every tenant-access decision runs on one of exactly three caller shapes:

Caller Who Reach
Key caller A request authenticated with an API key The tenants its key was granted, inside the clusters its key may address
Operator The admin panel; also any keyless request while the server permits anonymous access, which requires loopback-only listeners, so the caller is on the server's own machine Everything
Nobody A keyless request anywhere else, including credentials that carry no key id (provider-issued tokens) Nothing

There is no fourth shape. A blank or missing key id can never be interpreted as operator reach, and every storage backend answers these three shapes identically.

3Tenant grants (what a key reaches)#

A key reaches a tenant only through an explicit grant on the pair (tenant, key). There is no tenant ownership: the key that creates a tenant is granted it, and any other key needs its own grant. Grants are managed per tenant in the admin panel's Search section, or per key in the Access section, and on PostgreSQL clusters they are additionally enforced by row-level security in the database itself.

Everything a key does inside a tenant (index, search, fetch, configure) requires the grant; knowing a tenant's GUID confers nothing.

4Cluster grants (where a key may operate)#

A key also carries a cluster-grant setting that bounds which clusters it may address at all: route requests to, list its granted tenants in, and provision tenants into.

Stored value Meaning
Empty list No clusters. This is what a newly minted key starts with unless access is chosen at creation: least privilege by default.
List of ids Exactly those clusters.
Null (the open setting) Any configured cluster. Keys minted before cluster grants existed keep this, so upgrades change nothing for deployed callers.

The cluster boundary is hard: a tenant grant inside a cluster the key may not address is unreachable until cluster access is restored (the admin panel warns before creating that state). A cluster the caller may not address answers exactly like one that does not exist, so probing ids can never map which clusters a server hosts.

5Discovery: what can I reach?#

Two grant-scoped endpoints answer the question without the caller knowing any identifier up front. Both list projections of the caller's own grants, never the server's topology, and both return empty lists (not errors) for a key with nothing.

GET /lmkit/v1/search/clusters

Lists the clusters the key holds tenant grants in, plus clusters its key was explicitly granted (so a fresh key can discover where it may provision before it holds any tenant). Each entry carries id, full_text_store, and is_default.

GET /lmkit/v1/search/collections

Lists every collection the caller can reach across clusters, each entry carrying the cluster_id, tenant_id, tenant_name, collection_id, collection_name, and document_count needed to address it. Produced under the same grant checks as every read and write, so it can never name a collection the caller could not otherwise use.

GET /lmkit/v1/search/clusters/{clusterId}/tenants remains the per-cluster tenant listing, scoped the same way. GET /lmkit/v1/search/status reports availability and counts only the clusters the caller may address.

6Onboarding a caller#

Mapping an existing design onto clusters, tenants, and collections (schema-per-program, per-customer isolation, compliance domains) is worked through in Clusters, Tenants, Collections. Once the shape is decided, a minimal onboarding for one service:

  1. Operator mints a key in the admin panel's Access section, choosing the cluster and granting the right tenants directly in the create dialog (or creates the tenant first from the Search section).
  2. The service calls GET /search/collections to discover what it can reach, then indexes and searches with the ids it found.
  3. Adding a second audience later is a new key plus grants; nothing about the data moves.

7Security properties, stated plainly#

  • Least privilege at the mint. A new key reaches nothing in Search until granted.
  • No topology disclosure. Discovery lists only the caller's own reach; a denied cluster is indistinguishable from a missing one; the status probe counts only addressable clusters.
  • Fail closed. An unknown, revoked, or deleted key loses cluster access immediately; the default caller value reaches nothing; keyless credentials hold no grants and reach no tenant.
  • Defense in depth on PostgreSQL. The grant check runs in the query predicate and again in row-level security, so an application-layer mistake cannot widen reach.
  • Provisioning is bounded. Creating a tenant requires a caller that could reach it afterwards, inside a cluster its key may address.
  • The operator allowance is explicit. Keyless callers act as the operator only while the server permits anonymous access, which is automatically withdrawn the moment any listener goes beyond loopback.