// Full-text book search — demonstrates `.matching(...)` FTS + declarative // query result caching. // // DESCRIPTOR (browser-safe): NO node/database/server imports. The codegen // pulls this into rpcGroup.generated.ts, which the web client loads // value-level — so it must stay free of server-only modules. // // `cache` opts into server-side snapshot caching with auto-invalidation: the // framework caches the snapshot and drops it whenever a mutation writes any // table the query depends on (here, `books`). `scope` is REQUIRED and is a // security decision — this query is tenant-filtered (the `tenant()` mixin on // `books` AND-merges the caller's tenantId), so it depends on the caller → // `scope: 'subject'` (the cache key includes the subject id, no cross-tenant // leak). NEVER `global` on a subject-filtered query. // // The `cache` field is backend-agnostic: this snapshot lives in the // in-process `memory` cache by default and in Redis (cross-instance) the // moment you flip `CACHE_BACKEND=redis` / app.config `cache: 'redis'` — the // query code below does not change. `voltro add redis` wires that for you. import { defineQuery } from '@voltro/protocol' import { Schema } from 'effect' export const searchBooks = defineQuery({ name: 'books.search', source: 'books', // Open: full-text search over this template's own seeded book catalogue // (`seeds/catalog.seed.ts`), scoped to the request's tenant by `tenant()`. // Note that `cache.scope: 'subject'` below is a SEPARATE decision from this // one and stays right either way — the snapshot key includes the subject, so // an open procedure still cannot serve one caller's rows to another. openAccess: 'full-text search over the seeded demo book catalogue, tenant-scoped; the seed holds no ' + 'personal data. The result cache is `scope: \'subject\'`, so an open read still cannot ' + 'serve one caller a snapshot built for another.', input: Schema.Struct({ q: Schema.String }), output: Schema.Struct({ id: Schema.String, authorId: Schema.String, title: Schema.String, summary: Schema.String, genre: Schema.String, tags: Schema.Array(Schema.String), slug: Schema.String, tenantId: Schema.String, }), cache: { ttl: '30s', swr: '5m', scope: 'subject' }, })