HostAgentics Docs

HostAgentics Database

Last updated: 2026-08-06

This is an internal operational document describing the platform database: the Drizzle ORM schema, the schema domains, the migration workflow, and indexing conventions. The database is the control plane's system of record for identity, billing, runtimes, and platform operations. Customer-facing documentation never references schema internals; table names and column details here are for engineers and operators.

1. Stack

  • **Database**: PostgreSQL, accessed through Drizzle ORM (`packages/db`). TypeScript strict mode; all schema files live under `packages/db/src/`.
  • **Client**: `packages/db/src/client.ts` exposes the Drizzle client; `createDb(databaseUrl)` is the single entry point used by `apps/api` and `apps/worker`.
  • **Migrations**: generated and applied with `drizzle-kit`. Migrations are forward-only; schema changes ship as new migration files.
  • **Seed data**: `packages/db/src/seed.ts` inserts canonical plans/entitlements (mirror of `packages/pricing`), feature flags, and status components. Seeding runs once per environment as part of the release step, not on every deploy.
  • 2. Schema domains

    The schema is split into four files by domain, all re-exported from `packages/db/src/schema.ts`.

    Identity (`schema-identity.ts`)

    Better Auth owns the core auth tables (`users`, `accounts`, `sessions`, `verificationTokens`); HostAgentics stores organization structure alongside them:

  • `users` — email, verified flag, password hash (only when not using OAuth/magic link), `isAdmin` platform-operator flag.
  • `sessions` — Better Auth session model with expiry; revocation is delegated to Better Auth.
  • `accounts` — OAuth/credential provider accounts (credential, google, github).
  • `mfaMethods` — TOTP and recovery methods; TOTP secrets are stored as encrypted envelopes, never plaintext.
  • `organizations` — the tenant boundary; carries the Stripe customer ID.
  • `memberships` — org ↔ user with a role (`owner|admin|developer|operator|billing|viewer`). Unique on (org, user).
  • `invitations` — pending invites with hashed token, role, expiry, acceptance timestamp.
  • `featureFlags`, `adminNotes` — platform support tables. The `n8n_provisioning` flag lives here (see `docs/n8n-license-gate.md`).
  • Billing (`schema-billing.ts`)

    All money amounts are integer EUR cents. Prices are never trusted from the browser; the server maps canonical product keys to Stripe price IDs.

  • `products` — canonical product keys (`hostagentics_n8n_cloud`, `hostagentics_openclaw_cloud`, `hostagentics_hermes_cloud`, `hostagentics_complete`, `hostagentics_resource_boost`, `hostagentics_ai_credit_10/25/50/100`), kind (`subscription|addon|one_time`).
  • `plans` — a product × interval (monthly/annual) pair with its Stripe price ID and a `currentVersion` pointer.
  • `planVersions` — versioned entitlement snapshots; changing a plan never mutates history.
  • `planEntitlements` — per-runtime-kind entitlements (n8n/openclaw/hermes) for a plan version.
  • `subscriptions` / `subscriptionItems` — subscription lifecycle (active|past_due|grace_period|suspended|cancelled|retention|deleted); Resource Boost items are attributed to one explicit runtime.
  • `invoices` / `payments` / `refunds` — issued amounts, tax, payment outcomes.
  • `processedStripeEvents` — webhook event dedupe (primary key = Stripe event ID) for replay protection.
  • `aiCreditWallets` / `aiCreditTransactions` — one wallet per org; balance in cents, **never negative**; every grant, top-up, consumption, expiry, and refund is an append-only transaction with an idempotency key.
  • `aiProviderKeys` — managed and BYOK model-provider keys: encrypted secret envelope, display hint only, monthly spend limits, rotation version, revocation flag.
  • Runtime (`schema-runtime.ts`)

  • `infrastructureShards` — capacity units: a shard is a named set of provider projects in a region (`europe`, `north-america`, `asia-pacific`), with capacity accounting, health, and an accept-new-runtimes flag.
  • `runtimes` — the customer runtime record: kind (n8n|openclaw|hermes), unique subdomain, status (provisioning state machine), product key, region, update channel, safe-mode flag.
  • `providerResources` — **internal only**: maps each runtime to concrete provider resource IDs (service, volume, domain, database, deployment). These identifiers are never serialized into customer-facing responses; the provider-leak test enforces this.
  • `encryptedSecrets` — per-runtime secret scope: purpose (gateway-token, db-password, encryption-key, bot-token, webhook-secret, n8n-api-key), encrypted envelope, key version, rotation version. Unique on (runtime, purpose).
  • `runtimeOperations` / `operationSteps` — every lifecycle operation (provision, restart, pause, resume, update, backup, restore, repair, delete, apply-resources) with idempotency key, correlation ID, attempt/maxAttempts, safe message, internal HA-* diagnostic code, retryability, and per-step status.
  • `runtimeConfigurations` / `runtimeResources` — non-secret config (timezone, editor base URL) and the applied resource plan (CPU, memory, storage, transfer, concurrency, retention).
  • `runtimeVersions` / `runtimeDeployments` — the tested-only version catalog (digest-pinned, tested flag, security status, migration/rollback compatibility) and per-runtime deployment history.
  • `runtimeDomains` — managed (`*.runtime.hostagentics.com`) and future custom domains with certificate status.
  • `backups` / `restoreOperations` / `updateOperations` — provider snapshot manifests (manifest checksum, reported size, expiry) and gated completion records: a restore is completed only after health verification, an update only after stabilization. `encryptionKeyEnvelope` is reserved and unused for provider-native snapshots.
  • `healthChecks` / `metricSnapshots` / `usageSnapshots` / `limitEvents` / `logReferences` — monitoring data. Metric fields are nullable: a null value means data unavailable, and surfaces must display "Data unavailable" rather than an invented number. Limit events record the 70/85/95/100% thresholds.
  • Platform (`schema-platform.ts`)

  • Relay: `relayTokens` (hashed, hint only, scoped claims), `relayEvents`, `relayNonces` (single-use nonce store), `agentRuns` / `workflowRuns` (run task / trigger workflow records with idempotency keys), `webhookDeliveries`.
  • `notifications` / `notificationPreferences` — in-app and email notification records.
  • `auditEvents` / `securityEvents` — append-only audit trail (actor, action, target, correlation ID) and security telemetry (throttled logins, MFA failures, rate limiting).
  • `supportRequests` — support tickets with diagnostics flag and admin notes.
  • `statusComponents` / `incidents` — status page state (operational/degraded/partial_outage/major_outage/maintenance) and incident records with public updates.
  • `migrationImports` — validated imports from customers migrating existing n8n/OpenClaw/Hermes setups; payloads are validated before storage and applied only on explicit user action.
  • Internal cost accounting (`internalCostSnapshots`), competitor pricing intelligence (`competitorRecords`, `competitorPriceSnapshots`, `priceRecommendations`), and `blogPosts` metadata complete the platform schema.
  • 3. Migration workflow

    1. Schema changes are made in the domain files under `packages/db/src/`.

    2. Generate the migration: `pnpm --filter @hostagentics/db db:generate` (drizzle-kit). Review the generated SQL before committing.

    3. **Migrations run exactly once per release, in the release step, before new app code serves traffic** (`db:migrate` is wired as the release command on the API service and is idempotent). Never run migrations from two services concurrently; a second concurrent run is the most common cause of split-brain schema state.

    4. Because migrations are forward-only, a rollback across a schema change requires a forward fix or a restore from backup (see `docs/recovery-runbook.md`).

    4. Indexing notes

  • Membership lookups are the hottest path in authorization: `memberships_org_user_idx` (unique) and `memberships_user_idx`.
  • Runtime, backup, health, metric, and audit queries are always scoped by org or runtime and time-ordered; the indexes on `(runtimeId, createdAt)` / `(organizationId, createdAt)` match that access pattern.
  • Uniqueness constraints carry the integrity guarantees: subdomains, membership (org,user), encrypted secrets (runtime,purpose), usage snapshots (runtime,period), relay token hashes, processed Stripe event IDs, and idempotency keys.
  • `usageSnapshots` is unique per (runtime, periodStart) so the limit engine can upsert safely; `limitEvents` records each threshold crossing exactly once per runtime.
  • 5. Related documents

  • `docs/architecture.md` — where the database sits in the control plane
  • `docs/deployment.md` — release-step migration execution
  • `docs/security.md` — at-rest encryption of secret envelopes stored in this schema