QueryLayer Architecture
Understand the site-local runtime, trust boundaries, data model, and delivery path.
Status: Authoritative. This document describes the product QueryLayer is. Where older documents conflict with this one, this document wins.
#The product
QueryLayer is an open-source, WordPress-like CMS for search-driven Astro websites. It is installed per website, on infrastructure that website's owner controls, and operates entirely from that installation:
<managed-site.example>
├── Public Astro website
├── /admin — site-local QueryLayer administration
├── Site-local authentication (local auth service; local administrator accounts)
├── Site-owned database (Postgres, installation-local)
├── Revision and publishing services (immutable revisions, pointers, preflight)
├── Background workers/scheduler (pg_cron → local edge functions)
├── Agent API/MCP endpoint (/api/functions/v1/querylayer-mcp)
└── Site-owned secrets and integrations (Vault + local edge-function env)
There is no QueryLayer Cloud account, no querylayer.dev login, and no
company-operated service in any runtime path. An optional hosted service
(managed hosting, updates, backups, multi-site overview, remote monitoring)
may exist later as an add-on — never as a runtime, authentication,
licensing, or availability dependency.
#Runtime composition
An installation is a single Docker Compose stack (reference distribution
under install/):
| Layer | Component | Notes |
|---|---|---|
| Gateway | QueryLayer web gateway (install/gateway) |
Serves the admin build at /admin, injects runtime configuration, proxies /api/* to the platform, serves the managed site's static build |
| Platform | Self-hosted Supabase stack (Apache-2.0), pinned to self-hosted/v0.8.0 images |
Postgres + GoTrue auth + PostgREST + Storage + Realtime + Edge Runtime behind Envoy, bound to the internal network |
| Data | The QueryLayer SQL schema (supabase/migrations) |
~160 migrations; identical logic to the original hosted project, now applied locally |
| Functions | 11 Deno edge functions (supabase/functions) |
MCP, publish dispatcher, forms, connectors; run in the local Edge Runtime |
| Scheduler | pg_cron jobs (created by migrations) | Invoke local edge functions through the installation's own public URL via Vault-stored config |
| Admin | Static Astro admin build (src/) |
Served by the gateway at /admin; runtime config comes from /admin/config.js, never baked into assets |
| Site | Operator's Astro site (e.g. Backup Generator Guide) | Built by the operator; content fetched from the installation's own /api at build time |
#Identity, authentication, and authorization
- Human authentication is installation-local (GoTrue inside the stack). The first owner account is created by the installer directly via the local admin API — no invite email, no external identity provider.
- All row-level-security logic derives identity from the local
auth.*schema (auth.uid(),auth.sessions). Nothing about the code assumes a QueryLayer-operated project; it assumes an installation-local auth service. - Agents authenticate with governed bearer grants (
ql_agent_…), resolved server-side byauthenticate_agent_connectioninto installation/site-scoped permissions. Agents never hold database-owner credentials. - The governance contract is unchanged and non-negotiable: autonomous planning orchestrates; typed governed proposals authorize mutations; server-side execution performs approved mutations.
#Delivery (publishing)
request_content_publish → publish_jobs → scheduler → delivery provider.
The delivery provider is pluggable:
- Today's implemented provider is a Vercel Deploy Hook (used by the pilot).
- An installation with no provider configured still completes publication inside QueryLayer (immutable pointer advance, audit, preflight) and records the delivery outcome independently.
#Boundary classification (Phase 1 audit result)
| Class | Components |
|---|---|
| Installation-local (now) | Local auth service; local Postgres + RLS; local edge functions; local pg_cron scheduler; local Vault-backed secrets; /admin gateway + admin build; local MCP endpoint |
| Reusable unchanged | Immutable revision model; draft/published pointers; revision-scoped SEO metadata; scheduling/unpublish/rollback; audit ledger; claims/evidence; agent identities, proposals, approvals, runs, durable tasks; harness-neutral MCP contract; @querylayer/client + @querylayer/astro; integrations (GSC, GA4, Bing, IndexNow, Resend, Turnstile) |
| Optional hosted service (later) | Managed hosting; remote monitoring; multi-site overview; update service |
| Must be removed (done in this correction) | Mandatory querylayer.dev administration; central Supabase project identity as a runtime dependency; central OAuth-callback defaults as the only path; org/membership bootstrap requiring a central account; "self-hosted as metadata" setup UI; private-release licensing posture |
Pilot-specific data (hardcoded site UUIDs, domains, Vercel project IDs) is
excluded from fresh installations: pilot migrations are never applied
(scripts/install-site.mjs maintains the exclusion list, mirrored in
.gitattributes for public archives), and generic migrations that once
embedded pilot rows are guarded to no-op when the pilot site is absent.
#Non-goals for the installable core
- No requirement for a company-operated account at any lifecycle stage (install, upgrade, operate, or restore).
- No shared control plane in the runtime path.
- No agent mutation authority beyond typed governed proposals and explicit installation-owner policy (including "no autonomous publishing" by default).
#Acceptance contract
The corrected architecture is proven by
scripts/acceptance-single-site.mjs:
admin at /admin, local sign-in, RLS-scoped workspace, immutable draft,
exact-revision preview, site-local publishing, governed agent connection to
the local MCP endpoint, and zero requests to company-operated services.
A clean-room installation must pass this test before any release.