Service map
A pointer-only inventory of the route + service files behind every major feature, so an agent can find them without grep.
This page is a pointer-only inventory. Each line: feature → primary route / service paths → gotcha or deep-dive pointer. The four major subsystems (Auth, Realtime, Query API, Hybrid schema) have their own guides; this list is everything else.
Data plane
Section titled “Data plane”- Full-text & hybrid search (
services/fts.ts, DDL inpackages/db/schema-applier.ts::ensureFtsObjects) — keyword index maintained by the item-write hooks (services/items/write.ts); thePOST /:slug/searchroute +?q=upgrade live inroutes/items.ts, the backfill inroutes/collections.ts. Hybrid fuses FTS + vector with RRF. Managed collections only. Deep dive:docs/full-text-search.md. - Revisions (
routes/revisions.ts,services/revisions.ts) — change history per item.routes/items.tsalready snapshots before mutating, don’t double-write. - Comments (
routes/comments.ts) — item-scoped threads, permission-checked via the parent collection (no separate permission row). - Activity log (
routes/activity.ts,services/activity.ts) — central audit trail. Mutating routes calllogActivity(...)after success. Add it when introducing new write endpoints. The MCP dispatcher writes its ownmcp.*rows viamcp/audit.ts(which tool, which mount, refused or not) — the REST row alone can’t say an agent was involved. - Storage + folders (
routes/storage.ts,routes/folders.ts,services/storage/*) — uploads, folder tree, signed serves, on-the-fly image transforms. Seedocs/storage.md.
Query surfaces
Section titled “Query surfaces”- GraphQL (
routes/graphql.ts,routes/graphql.openapi.ts,services/graphql.ts) — schema auto-generated from collections. Uses the L1 permission cache so deep queries don’t N+1 the resolver. Seedocs/graphql.md. - OpenAPI (
routes/openapi.ts,routes/openapi-metadata.ts,services/openapi-dynamic.ts) — spec generated dynamically from collection schemas + per-route.openapi(...)decorators (@hono/zod-openapi); a new route shows up automatically if you decorate it. - Public surfaces (
routes/i18n-public.ts,routes/shared-public.ts,routes/shared-links.ts,services/shared-links.ts) — unauthenticated endpoints used by signed share-link URLs and the public i18n bundle. Never applyrequirePermissionhere; gate via the share-link token instead. - i18n strings (
routes/i18n.ts,services/i18n.ts,services/i18n-translate.ts) — content-translation system (multilingual values for user-managed collections), distinct from the admin SPA’s Lingui chrome translations.
Automation
Section titled “Automation”-
Webhooks (
routes/webhooks.ts,routes/webhook-trigger.ts,services/webhooks.ts) — outbound delivery with retry. Each delivery is signed three ways: legacyX-Backlex-Signature(HMAC of body) plus the replay-safeX-Backlex-Signature-V2over{timestamp}.{body}withX-Backlex-Timestamp.applyDeliveryOutcomeis the auto-disable circuit breaker (15 consecutive failures →active=false+disabled_reason+ broadcast notification; reset on success or manual resume). SDK receiver helper:verifyWebhookfrombacklex/webhook. The trigger route is the inbound side that flows/functions hook into. Seedocs/webhooks.md. -
Payments (
routes/payments.ts,routes/payments-public.ts,services/payments.ts,@backlex/integrations/payments) — inbound sync from Stripe / Polar / Lemon Squeezy, the mirror image of Webhooks above. The public receiver verifies the provider HMAC over the RAW body, dedupes on the provider’s event id via a unique index, and upserts throughingestRowsinto four MANAGED collections (payment_customers,payment_subscriptions,payment_invoices,payment_transactions) rather than system tables — so billing data inherits permissions, GraphQL, realtime and the BI panels.reconcileProvideris the pull side (cursor-paged, resumable); a six-hourly sweep enqueues onepayments.reconcilejob per connected provider. Mirrored across REST, the SDK (client.payments.*), GraphQL, MCP (payments.*) and the CLI. Seedocs/payments.md. -
Flows (
routes/flows.ts,services/flows.ts) — visual workflow builder. Trigger keys areevent/cron/webhook/manual; operations are a serialized DSL evaluated server-side. Admin-scoped CRUD + run is mirrored across REST, the SDK (client.flows.*), GraphQL (runFlowet al.), MCP (flows.*), and the CLI. Seedocs/flows.md. -
AI agents + chat rooms (
routes/agents.ts,services/agents/{store,runner,memory,mentions,send,async-run}.ts) — reason→act AI agents over the MCP tool registry. An agent definition, plus rooms (agent_threads) that host several agents at once, their membership (agent_thread_agents), and oneagent_runsrow per turn — which is also the per-agent lock, so two agents answer in parallel but one can’t run twice.send.tsis the single entry point every surface funnels through: it persists the message once, then decides who answers.mentions.tsresolves@handles and the room’s routing mode (mention/default/auto). Only user messages route, so agents can’t trigger each other.runner.tsexecutes one agent’s turn, calling allow-listed tools through an identity-carrying in-process sub-fetch and streaming steps overagent:thread:<id>.async-run.tsis the background path ({"async": true}): anagent.turnjob enqueued withmaxAttempts: 1, started inline viawaitUntil, with aqueued-only status guard so a non-idempotent turn is never replayed. Detached tool calls authenticate with a short-lived agent-run token (lib/jwt.ts) that carries no roles.- Optional two-tier memory in
memory.ts: episodic (per-(thread, agent) vector namespace, retrieved by similarity blended with recency) and semantic (durable facts distilled by a queuedagent.distill_memoryjob into theagent_memoriestable, so they can be listed, taught, and forgotten).agents.memory_scopedecides whether facts stay in their thread or pool per agent.
Admin-scoped CRUD + rooms + run are mirrored across REST, the SDK (
client.agents.*), GraphQL (runAgentet al.), MCP (agents.*), and the CLI. Admin UI:pages/agents.tsx(definitions) +pages/chat.tsx(rooms), sharingpages/_agents-shared.tsx. Seedocs/agents.md. -
Functions (
routes/functions.ts,services/functions.ts,services/sandbox/*,routes/sandbox-rpc.ts) — sandboxed JS execution. Provider picked by runtime: QuickJS on Workers, Bun Worker on self-host, optional HTTP executor. The sandbox calls back into the host (e.g.email.send,db.query) throughsandbox-rpc.ts— RPC surface, not direct imports. Seedocs/sandbox.md. -
Scheduler (
services/scheduler.ts,services/scheduled-tasks.ts) — cron expression parsing + delayed-task ledger. Driven by thescheduledWorker entry and the Vercel/Netlify cron routes. -
Job queue (
routes/jobs.ts,services/jobs.ts) — durable background jobs (function/webhook.deliver) with exponential backoff, dead-letter, andrunAtscheduling.processJobsdrains thejobstable inside the samecronTick; webhook dispatch enqueues here for retry. Seedocs/jobs.md. -
Resumable uploads (
routes/uploads.ts,services/uploads.ts) — TUS 1.0.0 chunked uploads at/api/uploads, backed by native object-store multipart (R2/S3) or fs offset-append. Theuploadstable tracks session offset + parts;sweepExpiredUploadsaborts stale sessions insidecronTick. Seedocs/resumable-uploads.md. -
Offline sync (
routes/items/changes.ts+/revisions,services/items/changefeed.ts,services/items/shape.ts,packages/client/src/sync.ts) — incremental changefeed (keyset onupdated_at,id, tombstones via_deleted) + revisions endpoint.runChangefeedis the ONE implementation behind REST, the SDK,<collection>Changes(GraphQL),collections.changes(MCP) andbacklex items changes(CLI). Ashape(flat filter) replicates a subset; rows leaving it come back as{ id, _shape_exit: true }— computed as a SELECT-list expression, not a WHERE clause, so move-outs stay observable. The clientsyncmodule pulls into a pluggable local store (memory / IndexedDB / SQLite), stays live over SSE with local shape matching, and queues offline writes with a configurable conflict policy (LWW by default;server-wins/client-wins/merge/manualsend a per-opifUnmodifiedSinceprecondition through the batch endpoint). Soft-delete bumpsupdated_atso deletes reach the feed. Seedocs/offline-sync.md. -
Feature flags (
routes/feature-flags.ts,services/feature-flags.ts) — per-workspace/global flags + remote config in thefeature_flagstable;evaluateFlagsresolves rollout % + permission-DSL targeting per caller; public read at/api/flags, admin CRUD at/api/admin/feature-flags. Seedocs/feature-flags.md. -
Draft / publish (
routes/items.tspublish handler,services/items/scheduled-publish.ts,draftFilterinservices/items/sql-helpers.ts) — versioned collections get_status/_published_at/_publish_at; reads hide drafts from callers without thepublish/updatepermission;publishDueItemsapplies scheduled publishes insidecronTick. Seedocs/draft-publish.md. -
Notifications (
routes/notifications.ts) — in-app notification feed; activity/flows write into it. -
Email templates (
routes/email-templates.ts) — per-tenant overrides for transactional templates; pairs with the per-workspace email config indocs/api-keys-and-email.md. -
Direct messaging (
routes/messaging.ts,services/messaging.ts) — dispatch-only push + SMS, no in-app row.dispatchPush/dispatchSmsare the single source of truth the REST route and the GraphQL mutations both call, so validation and the admin-or-self gate cannot drift between them. -
Push (
routes/device-tokens.ts,routes/push-config.ts,routes/push-templates.ts,services/push.ts) — device registry, per-workspace transport, andsendTemplatedPush, the twin ofsendTemplatedEmail: a key resolves tenant-then-global and literal title/body are its fallback. Seedocs/push-messaging.md. -
SMS (
routes/phone-numbers.ts,routes/sms-config.ts,services/sms.ts) — number registry read at send time bysendSmsToUsers, and cleaned up byservices/erasure.ts. Seedocs/sms-messaging.md.
Workspace admin
Section titled “Workspace admin”- App users + tenants (
routes/app-users.ts,routes/tenants.ts,routes/tenant-auth.ts) — multi-tenant end-user pool (distinct from the control-plane admin pool): invite flow, tenant switching, per-tenant sign-in routes. - App organizations (
routes/app-orgs.ts,routes/app-orgs-public.ts,services/app-orgs.ts) — the B2B grouping level inside a workspace: orgs, membership (owner/admin/ member), org-scoped workspace roles, invitations, and the active-org resolution that binds$org.idfor the permission DSL. Admin routes under/api/app-orgs; end-user self-service under/api/t/{slug}/orgs. See docs/app-organizations.md. - Settings + workspace config (
routes/settings.ts,services/settings.ts,routes/workspace-config.ts,services/workspace-config.ts) —settingsis theapp_settingswhitelist (i18n defaults, timezone, …);workspace-configis per-tenant overrides for runtime knobs. - Roles admin + collection rename (
routes/roles.ts,services/collection-rename.ts) — roles admin is the editor for the permission DSL.collection-renameis the only safe path to rename a collection (renames the physical table + updates permission rows in one transaction). - Advisor (
routes/advisor.ts,services/advisor.ts,services/advisor-insights.ts) — security / performance / config rule checks surfaced in the admin UI with fix recommendations. Performance covers both static schema-derived rules and traffic-derived ones computed from recorded spans;POST /applycarries out a finding’s remediation by re-deriving the statement server-side. Seedocs/advisor.md. - Product analytics + crash reporting (
routes/analytics.ts,routes/analytics-ingest.ts,services/analytics.ts) — the tracked-event stream plus fingerprinted error groups. Ingest is append-only and authenticated by a publishablealk_key, an API key or a session; the admin reads (overview / funnel / retention / errors) are admin-only. Funnel + retention are CTE chains with one dialect branch (timestamp shape). Pruned byservices/scheduler.ts. Seedocs/product-analytics.md. - Panels (
routes/panels.ts) — dashboard widget definitions. Theanalyticskind runs throughservices/dashboards.ts::runAnalyticsPanel, shared with the dashboard runner + public embed. - Metrics (
routes/metrics.ts) — request / error counters + time-series rollups for the admin dashboard. - Realtime admin + DB admin (
routes/realtime-admin.ts,routes/db-admin.ts) — subscriber counts + test-publish, and schema introspection + diagnostics. Realtime admin is admin-only; the DB admin routes that span the whole database (/sql/run,/tables,/migrations) require the instance operator, not the workspaceadminrole — see the system-roles section ofdocs/permissions.md. - Backup / restore (
services/backup.ts) — logical JSONL dumps (runBackup), additiverestoreBackup(ON CONFLICT DO NOTHING, recreates missingc_*tables), and the scheduled-backup sweep + retention (maybeRunScheduledBackups, hooked intoservices/scheduler.ts). Routes inroutes/db-admin.ts:/backups,/backups/now,/backups/{id}/download,/backups/{id}/restore(confirm-gated),/backups/config(GET/PUT schedule). Seedocs/backup-restore.md. - Per-collection export / import (
routes/items.ts+services/items/csv.ts) —GET /:slug/export?format=json|csv(reuses the list read-filter stack) andPOST /:slug/import(per-rowperformCreate, system columns stripped, errors captured). SDKexportItems/importItems. - External-DB migration (
routes/migrate.ts+services/migrate.ts+services/migrate-ingest.ts) —POST /api/admin/migrate/ingest/:slug(bulk, PK-preserving, idempotent, side-effect-free row copy; D1 param-budget chunking; the CLI pump’s write path) + the server-side connector:/sourcesCRUD (URL encrypted at rest + SSRF guard),/sources/:id/tables|plan,/runslifecycle. Runs advance on the scheduler tick in lease-reclaimed, cursor-resumable slices. Full parity: SDKclient.migrate.*, GraphQLmigrate*, MCPmigrate.*, CLIbacklex import-db, admin Data → Database import. Seedocs/migrating-in.md.
Cross-cutting helpers worth knowing
Section titled “Cross-cutting helpers worth knowing”services/permissions-cache.ts— per-request L1 cache on top of the permissions resolver. Bulk loops hit it for free, no opt-in needed.services/cors-origins.ts— per-tenant allow-list reused by SAML relayState validation as the open-redirect guard.