Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .agents/skills/constructive-setup/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,6 @@ pnpm test:watch # watch mode

For testing patterns and frameworks, see the **constructive-testing** skill.

## Local Email Services

Start Mailpit, Admin GraphQL, send-email-link, and job-service for local email testing.

See [local-email-services.md](./references/local-email-services.md) for Docker Compose setup, port reference, and troubleshooting.

## Monorepo Layout

| Directory | Contents |
Expand Down
159 changes: 0 additions & 159 deletions .agents/skills/constructive-setup/references/local-email-services.md

This file was deleted.

2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ This guide helps AI agents quickly navigate the Constructive monorepo. Construct
- **`streaming/*`** – S3 helpers and stream hashing utilities
- **`extensions/*`** – PGPM extension modules (Postgres extensions packaged as PGPM modules)
- **`graphile/*`** – Graphile/PostGraphile plugins (kept under their own namespace)
- **`jobs/*`**, **`functions/*`** – supporting systems and examples
- **`jobs/*`** – Knative job scheduling (worker, scheduler, service) and examples

## Entry Points

Expand Down
3 changes: 1 addition & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,7 @@ React Query Hooks or Prisma-like ORM Client
| `postgres/` | PostgreSQL utilities - introspection, testing (pgsql-test), seeding, AST, query context |
| `packages/` | Shared utilities - CLI (`cnc`), ORM base, query builder, server utils, client |
| `uploads/` | File streaming - S3/MinIO, ETags, content-type detection, UUID hashing |
| `jobs/` | Knative job scheduling - worker, scheduler, service, functions |
| `functions/` | Knative cloud functions (e.g., send-verification-link, send-email) |
| `jobs/` | Knative job scheduling - worker, scheduler, service |

### Key Packages & CLIs

Expand Down
31 changes: 16 additions & 15 deletions __fixtures__/seed/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,16 @@ Composable SQL seed layers for integration testing. Each layer builds on the pre
| Layer | Files | What it provides |
|-------|-------|-----------------|
| **base** | `base/setup.sql` | `uuid-ossp` extension, `stamps` schema + `timestamps()` trigger |
| **services (real modules)** | `seed.pgpm(repoRoot)` | Real `@pgpm/metaschema-modules` (+ deps: `@pgpm/services`, `@pgpm/metaschema-schema`, ...) installed into the gitignored root `extensions/` — see `.agents/skills/ephemeral-pgpm-fixtures/SKILL.md`; run `pnpm fixtures:install` first |
| **services data** | `services/test-data.sql` | Example database (`simple-pets`), 3 schemas, 5 APIs, 2 domains, API→schema linkage, animals metaschema entries |
| **scoped data** | `scoped/resolver.sql`, `scoped/test-data.sql` | Same `simple-pets` tenant expressed on the new schema-only modules (`@constructive-db/{catalog,routing,apps}`): catalog apis/domains, routing apis/api_schemas/domains/routes + compiled hostname/route bindings, apps + app_components — plus the `resolve_route()` resolver the schema-only routing module does not ship |
| **routing (real modules)** | `seed.pgpm(repoRoot)` | Real `@pgpm/metaschema-modules` (+ deps: `@constructive-db/{catalog,routing,apps}`, `@pgpm/metaschema-schema`, ...) installed into the gitignored root `extensions/` — see `.agents/skills/ephemeral-pgpm-fixtures/SKILL.md`; run `pnpm fixtures:install` first |
| **scoped data** | `scoped/resolver.sql`, `scoped/test-data.sql` | Example database (`simple-pets`) on the schema-only modules (`@constructive-db/{catalog,routing,apps}`): catalog apis/domains, routing apis/api_schemas/domains/routes + compiled hostname/route bindings, apps + app_components — plus the `resolve_route()` resolver the schema-only routing module does not ship |
| **app-schemas** | `app-schemas/simple-pets/schema.sql` | `simple-pets-*` schemas, animals table with constraints/indexes/triggers |
| **app data** | `app-schemas/simple-pets/test-data.sql` | 5 test animals (Buddy, Max, Whiskers, Mittens, Tweety) |

> **Note:** Roles (`administrator`, `authenticated`, `anonymous`) are created upstream by `pgsql-test`'s `createBaseRoles()` — seed SQL should never create roles.

## Usage with pgsql-test

### Non-services tests (no metaschema)
### Static tests (no metaschema)

```typescript
const SEED = path.resolve(__dirname, '../../../__fixtures__/seed');
Expand All @@ -28,19 +27,21 @@ seed.sqlfile([
])
```

### Services-enabled tests (metaschema + domain resolution)
### Scoped-routing tests (metaschema + host route resolution)

Real module DDL comes from the pinned `@pgpm/*` modules installed at the repo
root (`pgpm.json` dependencies, populated by `pnpm fixtures:install`):
Real module DDL comes from the pinned `@pgpm/*` / `@constructive-db/*` modules
installed at the repo root (`pgpm.json` dependencies, populated by
`pnpm fixtures:install`):

```typescript
const REPO_ROOT = path.resolve(__dirname, '../../..');

[
seed.pgpm(REPO_ROOT), // all installed @pgpm/* modules
seed.pgpm(REPO_ROOT), // all installed modules
seed.sqlfile([
`${SEED}/app-schemas/simple-pets/schema.sql`, // app tables
`${SEED}/services/test-data.sql`, // API + domain rows
`${SEED}/scoped/resolver.sql`, // resolve_route() stand-in
`${SEED}/scoped/test-data.sql`, // routing/catalog/apps rows
`${SEED}/app-schemas/simple-pets/test-data.sql`, // test animals
]),
]
Expand All @@ -51,10 +52,9 @@ const REPO_ROOT = path.resolve(__dirname, '../../..');
Pick only the layers you need:

- **Base only** (extensions + stamps, no metaschema): `base/setup.sql` + your own schema/data
- **Metaschema + services only** (no app tables): `seed.pgpm(repoRoot)` + `services/test-data.sql`
- **Full stack with app data**: `seed.pgpm(repoRoot)` + `app-schemas/*` + `services/test-data.sql` + `app-schemas/*/test-data.sql`
- **Custom app schema**: `seed.pgpm(repoRoot)` + `services/test-data.sql` + your own schema/data SQL
- **Scoped routing plane** (catalog/routing/apps instead of services_public): `seed.pgpm(repoRoot)` + `app-schemas/*` + `scoped/resolver.sql` + `scoped/test-data.sql` + `app-schemas/*/test-data.sql`
- **Metaschema + routing only** (no app tables): `seed.pgpm(repoRoot)` + `scoped/resolver.sql` + `scoped/test-data.sql`
- **Full stack with app data**: `seed.pgpm(repoRoot)` + `app-schemas/*` + `scoped/resolver.sql` + `scoped/test-data.sql` + `app-schemas/*/test-data.sql`
- **Custom app schema**: `seed.pgpm(repoRoot)` + `scoped/resolver.sql` + `scoped/test-data.sql` + your own schema/data SQL

The installed modules grant `administrator`/`authenticated` — there are no
`anonymous` grants anywhere (matching production). Server plugins resolve
Expand All @@ -67,9 +67,10 @@ These test files use the shared fixtures:

| Test file | Shared fixtures used |
|-----------|---------------------|
| `graphql/server-test/__tests__/server.integration.test.ts` | `base/*` (simple-seed), `services/*` + `app-schemas/*` (services scenarios) |
| `graphql/server-test/__tests__/server.integration.test.ts` | `base/*` (simple-seed static), `scoped/*` + `app-schemas/*` (simple-seed-scoped) |
| `graphql/server-test/__tests__/scoped-routing.integration.test.ts` | `scoped/*` + `app-schemas/*` (simple-seed-scoped) |
| `graphql/server-test/__tests__/express-context.integration.test.ts` | `services/*` + `app-schemas/*` |
| `graphql/server-test/__tests__/express-context.integration.test.ts` | `scoped/*` + `app-schemas/*` |
| `graphql/server-test/__tests__/fn-routes.integration.test.ts` | `scoped/*` + `compute/*` + `app-schemas/*` |
| `graphql/server-test/__tests__/upload.integration.test.ts` | `seed.pgpm` modules (storage schemas/data are local) |
| `graphql/server-test/__tests__/cli-e2e.test.ts` | `base/*` + `app-schemas/*` (animals), `base/*` (search) |
| `graphql/server-test/__tests__/search.integration.test.ts` | `base/*` |
Expand Down
2 changes: 1 addition & 1 deletion __fixtures__/seed/compute/setup.sql
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
-- on the invocation and that binding points at the invocation's
-- `function_definition_id`.
--
-- Depends on: seed.pgpm('@pgpm/metaschema-modules'), services/grants.sql
-- Depends on: seed.pgpm('@pgpm/metaschema-modules') (roles + metaschema tables)

-- =====================================================
-- COMPUTE SCHEMA + GENERATED TABLES
Expand Down
2 changes: 1 addition & 1 deletion __fixtures__/seed/compute/test-data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
-- plus one binding on the "public" API (28199444-da40-40b1-8a4c-53edbf91c738)
-- that must not be exposed on the "app" API.
--
-- Depends on: services/setup.sql, services/test-data.sql, compute/setup.sql
-- Depends on: scoped/test-data.sql, compute/setup.sql

SET session_replication_role TO replica;

Expand Down
12 changes: 5 additions & 7 deletions __fixtures__/seed/scoped/test-data.sql
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
-- Shared fixture: metaschema + scoped catalog/routing/apps test data
--
-- Scoped-plane equivalent of `services/test-data.sql`: it models the SAME
-- "simple-pets" tenant (same database id, same APIs, same domains, same
-- api -> schema linkage) but expressed as rows in the new schema-only modules
-- Scoped routing plane test data: models the "simple-pets" tenant as rows in
-- the schema-only modules
-- - @constructive-db/catalog -> constructive_catalog_public
-- - @constructive-db/routing -> constructive_routing_public
-- - @constructive-db/apps -> constructive_apps_public
-- instead of services_public.
--
-- The metaschema block below is identical to `services/test-data.sql` so this
-- file can be composed standalone (routing.api_schemas.schema_id FKs
-- The metaschema block below seeds metaschema_public directly so this file can
-- be composed standalone (routing.api_schemas.schema_id FKs
-- metaschema_public.schema).
--
-- `constructive_routing_public.{hostname_bindings,route_bindings}` are the
Expand Down Expand Up @@ -167,7 +165,7 @@ VALUES
('a2e6098f-2c11-4f2a-b481-c19175bc62ef', '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', 'auth', current_database(), 'authenticated', 'anonymous', true)
ON CONFLICT (id) DO NOTHING;

-- API -> schema linkage (mirrors services_public.api_schemas)
-- API -> schema linkage
INSERT INTO constructive_routing_public.api_schemas (id, database_id, schema_id, api_id)
VALUES
-- app API schemas (public + pets_public)
Expand Down
Loading
Loading