Cloudflare control plane
D1 is WiseWig’s small, indexed platform control plane. It does not hold rendered pages or mutable draft documents; those remain tenant-local in TenantWorkspaceDO.
The initial D1 schema contains:
- tenants and agency memberships;
- sites and verified hostname-to-site routing;
- current client site-role assignments;
- tenant Worker release/pinning, domain verification, provisioning metadata, lifecycle events, and deletion requests;
- a shared-platform command ledger and append-only audit for membership, domain, tenant-status, and erasure effects.
D1ControlPlane resolves a normalized, verified hostname to { tenantId, siteId, slug }, checks tenant membership, and returns only valid current site roles. A malformed hostname is rejected before it reaches D1. All dynamic values are prepared-statement bindings.
The Worker uses this control-plane lookup before any private command or tenant Durable Object call. A public cache hit should avoid it entirely; on a miss, the lookup finds the published site route without exposing draft or membership data.
Managed platform commands
Managed content, media, theme, plugin selection, publication, backup, and recovery state belong to the selected tenant Worker and its script-specific SQLite Durable Object. Memberships, verified domains, tenant routing status, and erasure requests necessarily span the platform, so they remain in D1 and never pass through tenant theme or plugin code.
The dispatcher intercepts every /_wisewig/platform/* path before user-Worker dispatch. It resolves scope from the verified hostname, authenticates the platform session, reloads authoritative roles, checks the exact permission, and uses fixed framework paths that accept no tenant/site selector. The browser bridge forwards only the session cookie, origin, idempotency key, and confirmation value; caller-supplied WiseWig routing headers are discarded.
Migration 0008_platform_commands.sql provides platform_command_ledger and platform_command_audit. A command key is scoped by tenant, site, actor, command, and caller idempotency key; its SHA-256 input digest prevents the same key from being reused with changed input. The first caller obtains an exclusive claim, concurrent callers receive COMMAND_IN_PROGRESS, completed retries receive the stored bounded JSON result, and a failed handler releases its claim for retry. Success, failure, and replay are audited. A five-minute stale claim may be reclaimed with compare-and-swap, so each effect must also be intrinsically retry-safe: invitations and removals are convergent, domain requests verify an existing row belongs to the same site, status writes set an absolute value, and erasure uses an upsert.
These endpoints are private and no-store. Public traffic and public MCP have no route to them. Stable error codes are returned without D1, provider, identity, or script details.