// Boot-lifecycle seed — a few articles so search returns results the moment // `voltro dev` boots. Idempotent via `upsertByUnique` (+ the fingerprint // ledger), so re-running on every boot is safe. // // The seed store is the RAW store (no authenticated subject), so the `tenant()` // auto-fill doesn't fire — we pass `tenantId` explicitly and seed the demo // tenant row first, under `acme` (the dev AuthMiddleware's default tenant). import { defineSeed } from '@voltro/database' const TENANT_ID = 'acme' export default defineSeed({ id: 'articles', name: 'Demo articles for search', lifecycle: 'boot', steps: ({ step }) => [ step('tenant', async ({ upsertByUnique }) => { await upsertByUnique( 'tenants', { id: TENANT_ID }, { id: TENANT_ID, name: 'Acme', createdAt: new Date() }, ) return { rowsTouched: 1 } }), step('articles', async ({ upsertByUnique }) => { const now = new Date() const rows = [ { id: 'art_voltro', title: 'Getting started with Voltro', body: 'Reactive end-to-end, multi-tenant by design — scaffold an app and ship.', tag: 'guide' }, { id: 'art_search', title: 'Full-text search that stays in sync', body: 'The search plugin mirrors every write into the index via the post-commit change tap.', tag: 'guide' }, { id: 'art_tenant', title: 'Tenant isolation', body: 'Queries auto-filter to the caller tenant — search results included, no leakage.', tag: 'concept' }, { id: 'art_effect', title: 'Effect under the hood', body: 'Handlers compose with Effect for typed errors, retries, and timeouts.', tag: 'concept' }, ] for (const r of rows) { await upsertByUnique('articles', { id: r.id }, { ...r, tenantId: TENANT_ID, createdAt: now }) } return { rowsTouched: rows.length } }), ], })