This guide helps AI agents quickly navigate the Constructive monorepo. Constructive provides tooling for building secure, role-aware GraphQL APIs backed by PostgreSQL.
Most important packages to know first:
pgpm/core– PGPM engine: migrations, packaging, dependency resolution (guide)pgpm/pgpm– PGPM CLI: database/workspace commands (init/add/deploy/verify/etc)packages/cli– Constructive CLI (constructive/cnc), delegates PGPM commands and adds GraphQL workflows (guide)postgres/pgsql-test– PostgreSQL test harness and seed adapters (guide)graphql/server– Constructive GraphQL server (Express + PostGraphile)graphql/codegen– GraphQL code generation (types/ops/sdk)
Key classes and entry points:
PgpmPackage–pgpm/core/src/core/class/pgpm.tsPgpmMigrate–pgpm/core/src/migrate/client.tsGraphQLServer–graphql/server/src/server.ts
packages/*– Constructive CLI + misc packages (client,orm,query-builder,url-domains,server-utils, etc.)pgpm/*– PGPM engine + CLI + shared types/logger/envgraphql/*– GraphQL server, explorer, codegen, types/env, query/react utilitiespostgres/*– PostgreSQL tooling and tests (pg-ast,pg-codegen,introspectron,pgsql-test, etc.)streaming/*– S3 helpers and stream hashing utilitiesextensions/*– PGPM extension modules (Postgres extensions packaged as PGPM modules)graphile/*– Graphile/PostGraphile plugins (kept under their own namespace)jobs/*,functions/*– supporting systems and examples
- Router:
pgpm/pgpm/src/commands.ts - Executable:
pgpm/pgpm/src/index.ts - Command implementations:
pgpm/pgpm/src/commands/*
- Router:
packages/cli/src/commands.ts - Local GraphQL commands:
packages/cli/src/commands/* - Delegated PGPM commands: sourced from
pgpm/pgpm
- Entry:
graphql/server/src/index.ts - Server implementation:
graphql/server/src/server.ts - Schema wiring:
graphql/server/src/schema.ts
Database Operations (pgpm):
- Initialize workspace/module:
pgpm init workspace,pgpm init - Create a change:
pgpm add <change> - Deploy/verify/revert:
pgpm deploy,pgpm verify,pgpm revert - Install PGPM modules:
pgpm install <pkg@version>
GraphQL Operations (cnc/constructive):
- Start GraphQL server:
cnc server - Launch GraphiQL explorer:
cnc explorer - Generate types/SDK:
cnc codegen - Export schema SDL:
cnc get-graphql-schema
Always use the unified environment configuration system — never read process.env directly for config values.
- PGPM packages (
pgpm/*):import { getEnvOptions } from '@pgpmjs/env' - GraphQL/Constructive packages (
graphql/*,packages/cli):import { getEnvOptions } from '@constructive-io/graphql-env' - PostgreSQL tools (
postgres/*):import { getPgEnvOptions } from 'pg-env'or@pgpmjs/env
The system provides typed defaults, config file discovery (pgpm.json), env var parsing, and a clean merge hierarchy: defaults → config file → env vars → runtime overrides.
// GOOD
import { getEnvOptions } from '@pgpmjs/env';
const opts = getEnvOptions({ pg: { database: 'mydb' } });
// BAD — scattered, untyped, no defaults
const host = process.env.PGHOST || 'localhost';
const port = parseInt(process.env.PGPORT || '5432');Constructive provides a layered testing framework stack. Always use the appropriate framework — never manually create pg.Pool or pg.Client instances in tests.
| Scenario | Framework | Import |
|---|---|---|
| Raw SQL, RLS policies, database functions | pgsql-test |
import { getConnections } from 'pgsql-test' |
| PostGraphile schema, basic GraphQL queries | graphile-test |
import { getConnections } from 'graphile-test' |
| GraphQL with Constructive plugins (search, pgvector, etc.) | @constructive-io/graphql-test |
import { getConnections } from '@constructive-io/graphql-test' |
| HTTP endpoints, auth headers, middleware | @constructive-io/graphql-server-test |
import { getConnections } from '@constructive-io/graphql-server-test' |
Each layer builds on pgsql-test underneath — they all create isolated test databases with proper teardown.
Always include beforeEach/afterEach hooks to ensure test isolation via savepoints:
import { getConnections, PgTestClient } from 'pgsql-test';
let pg: PgTestClient;
let db: PgTestClient;
let teardown: () => Promise<void>;
beforeAll(async () => {
({ pg, db, teardown } = await getConnections());
});
afterAll(async () => {
await teardown();
});
beforeEach(async () => {
await pg.beforeEach();
await db.beforeEach();
});
afterEach(async () => {
await db.afterEach();
await pg.afterEach();
});- Never create
new pg.Pool()ornew pg.Client()in tests — usegetConnections()from the appropriate framework - Never use
getPgPool()frompg-cachein tests — that's for production connection pooling - Never manually create/drop databases in tests —
pgsql-testhandles this automatically - Never skip
beforeEach/afterEachhooks — tests will leak state to each other - Never construct connection strings manually — use the env configuration system
- Start with
pgpm/core/AGENTS.mdto understand the migration and plan model. - Use
packages/cli/AGENTS.mdto understand Constructive's command routing. - Use
postgres/pgsql-test/AGENTS.mdfor patterns around isolated test DBs and seeding.