Skip to content

PlanetScale

PlanetScale is the single database for all persistent state — replacing Supabase PostgreSQL. As an EngineeredSystem (IOF), it stores Information Bearing Entities carrying all persistent information: Process Records (commercial transactions), MaterialArtifact data, Measurement Data, ICEs (tags, assets, suggestions), Plan Specifications, Creative Act Reports, and Document Artifacts.

Cloudflare Hyperdrive provides optimized connectivity between Workers and PlanetScale:

  • Connection pooling — maintains persistent connections, avoiding per-request TCP/TLS setup
  • Query caching — optional, for read-heavy dashboard queries
  • Edge proximity — connections routed through Cloudflare’s network
wrangler.toml
[[hyperdrive]]
binding = "HYPERDRIVE"
id = "your-hyperdrive-id"
import { drizzle } from 'drizzle-orm/node-postgres';
export function getDb(env: Bindings) {
return drizzle(env.HYPERDRIVE.connectionString);
}

The rewrite continues using Drizzle ORM with the PostgreSQL dialect — same dialect as the current Supabase system, now targeting PlanetScale Postgres. Table and column names follow the ontological naming conventions:

import { pgTable, varchar, integer, timestamp, jsonb, boolean, text } from 'drizzle-orm/pg-core';
// MaterialArtifact (IOF) — physical products with causal unity
export const materialArtifact = pgTable('material_artifact', {
artifactIdentifier: varchar('artifact_identifier', { length: 64 }).primaryKey(),
title: text('title'),
tags: jsonb('tags').$type<string[]>(),
isActive: boolean('is_active').notNull().default(true),
lastSeen: timestamp('last_seen', { withTimezone: true }).notNull().defaultNow(),
});
// Measurement Datum (IAO) — daily sales on ratio scale
export const salesMeasurementDataset = pgTable('sales_measurement_dataset', {
artifactIdentifier: varchar('artifact_identifier', { length: 64 }).notNull(),
day: date('day').notNull(),
units: integer('units').notNull().default(0),
unitsNet: integer('units_net').notNull().default(0),
});

See Schema Design for the complete table definitions.

PlanetScale enforces system-level constraints that shape all pipeline ProcedureExecutions:

LimitValueDesign response
Rows per query100kCursor-based pagination
Rows per statement100kChunked batch writes
Result size64 MiBSelective column queries
Transaction timeout20sShort, independent transactions
Autocommit timeout900sBounded single statements

PlanetScale branching supports safe schema changes:

  1. Create dev branch from production
  2. Apply migrations via dbmate on the dev branch
  3. Create deploy request (PR-like review for schema changes)
  4. Merge — PlanetScale applies non-blocking DDL
  5. Rollback available (undo deployment without data loss)
Terminal window
# Migration workflow with dbmate
dbmate new add_document_artifact_table
# Edit migration SQL
dbmate up # apply on dev branch
# Create deploy request in PlanetScale dashboard

Per ADR-004, foreign keys are documented in the Drizzle schema for type safety but not enforced at the database level. This parallels ODR-002 — ontological relations (like IAO denotes between ICEs and MaterialArtifacts) are documented in naming conventions, not enforced by database constraints.

Application code enforces integrity, with periodic orphan detection in background ProcedureExecutions.

Per ADR-003, all business logic lives in application code. The 10+ Supabase RPCs (get_tag_categories(), upsert_tag_classification(), refresh_tag_performance_aggregate(), etc.) are migrated to TypeScript in the Workers.