diff --git a/pgpm/constructive-platform-seed/constructive-platform-seed.control b/pgpm/constructive-platform-seed/constructive-platform-seed.control new file mode 100644 index 00000000..126738ec --- /dev/null +++ b/pgpm/constructive-platform-seed/constructive-platform-seed.control @@ -0,0 +1,7 @@ +# constructive-platform-seed extension +comment = 'Platform metadata seed: database, schemas, compute API, domain, and site' +default_version = '0.1.0' +module_pathname = '$libdir/constructive-platform-seed' +requires = 'plpgsql,metaschema-schema,services' +relocatable = false +superuser = false diff --git a/pgpm/constructive-platform-seed/deploy/fixtures/seed_compute_api.sql b/pgpm/constructive-platform-seed/deploy/fixtures/seed_compute_api.sql new file mode 100644 index 00000000..a60558b7 --- /dev/null +++ b/pgpm/constructive-platform-seed/deploy/fixtures/seed_compute_api.sql @@ -0,0 +1,35 @@ +-- Deploy: fixtures/seed_compute_api +-- made with <3 @ constructive.io + +-- requires: fixtures/seed_schemas +-- requires: services:schemas/services_public/tables/apis/table +-- requires: services:schemas/services_public/tables/api_schemas/table + +BEGIN; + +-- Create the compute API (mirrors how constructive-db provisions per-database APIs). +INSERT INTO services_public.apis (database_id, name, role_name, anon_role, is_public) +VALUES ('00000000-0000-0000-0000-000000000000', 'compute', 'authenticated', 'anonymous', true) +ON CONFLICT (database_id, name) DO NOTHING; + +-- Link all public schemas to the compute API. +INSERT INTO services_public.api_schemas (database_id, api_id, schema_id) +SELECT + '00000000-0000-0000-0000-000000000000', + a.id, + s.id +FROM services_public.apis a +CROSS JOIN metaschema_public.schema s +WHERE a.database_id = '00000000-0000-0000-0000-000000000000' + AND a.name = 'compute' + AND s.database_id = '00000000-0000-0000-0000-000000000000' + AND s.schema_name IN ( + 'constructive_infra_public', + 'constructive_store_public', + 'constructive_objects_public', + 'constructive_fbp_public', + 'constructive_storage_public' + ) +ON CONFLICT (api_id, schema_id) DO NOTHING; + +COMMIT; diff --git a/pgpm/constructive-platform-seed/deploy/fixtures/seed_database.sql b/pgpm/constructive-platform-seed/deploy/fixtures/seed_database.sql new file mode 100644 index 00000000..350ad462 --- /dev/null +++ b/pgpm/constructive-platform-seed/deploy/fixtures/seed_database.sql @@ -0,0 +1,16 @@ +-- Deploy: fixtures/seed_database +-- made with <3 @ constructive.io + +-- requires: metaschema-schema:schemas/metaschema_public/tables/database/table + +BEGIN; + +INSERT INTO metaschema_public.database (id, name, schema_hash) +VALUES ( + '00000000-0000-0000-0000-000000000000', + current_database(), + 'constructive-functions-local' +) +ON CONFLICT (schema_hash) DO NOTHING; + +COMMIT; diff --git a/pgpm/constructive-platform-seed/deploy/fixtures/seed_domain.sql b/pgpm/constructive-platform-seed/deploy/fixtures/seed_domain.sql new file mode 100644 index 00000000..c23f2987 --- /dev/null +++ b/pgpm/constructive-platform-seed/deploy/fixtures/seed_domain.sql @@ -0,0 +1,22 @@ +-- Deploy: fixtures/seed_domain +-- made with <3 @ constructive.io + +-- requires: fixtures/seed_compute_api +-- requires: services:schemas/services_public/tables/domains/table + +BEGIN; + +-- Create a domain routing to the compute API. +-- In production, the upstream provisioning system sets real subdomain/domain values. +INSERT INTO services_public.domains (database_id, api_id, subdomain, domain) +SELECT + '00000000-0000-0000-0000-000000000000', + a.id, + 'compute', + 'localhost' +FROM services_public.apis a +WHERE a.database_id = '00000000-0000-0000-0000-000000000000' + AND a.name = 'compute' +ON CONFLICT (subdomain, domain) DO NOTHING; + +COMMIT; diff --git a/pgpm/constructive-platform-seed/deploy/fixtures/seed_schemas.sql b/pgpm/constructive-platform-seed/deploy/fixtures/seed_schemas.sql new file mode 100644 index 00000000..e9651efa --- /dev/null +++ b/pgpm/constructive-platform-seed/deploy/fixtures/seed_schemas.sql @@ -0,0 +1,21 @@ +-- Deploy: fixtures/seed_schemas +-- made with <3 @ constructive.io + +-- requires: fixtures/seed_database +-- requires: metaschema-schema:schemas/metaschema_public/tables/schema/table + +BEGIN; + +-- Register all module public schemas in metaschema so the API can resolve them. +-- Uses the well-known database ID from seed_database. + +INSERT INTO metaschema_public.schema (database_id, name, schema_name, category, is_public) +VALUES + ('00000000-0000-0000-0000-000000000000', 'constructive_infra_public', 'constructive_infra_public', 'app', true), + ('00000000-0000-0000-0000-000000000000', 'constructive_store_public', 'constructive_store_public', 'app', true), + ('00000000-0000-0000-0000-000000000000', 'constructive_objects_public', 'constructive_objects_public', 'app', true), + ('00000000-0000-0000-0000-000000000000', 'constructive_fbp_public', 'constructive_fbp_public', 'app', true), + ('00000000-0000-0000-0000-000000000000', 'constructive_storage_public', 'constructive_storage_public', 'app', true) +ON CONFLICT (schema_name) DO NOTHING; + +COMMIT; diff --git a/pgpm/constructive-platform-seed/deploy/fixtures/seed_site.sql b/pgpm/constructive-platform-seed/deploy/fixtures/seed_site.sql new file mode 100644 index 00000000..41c6cfc3 --- /dev/null +++ b/pgpm/constructive-platform-seed/deploy/fixtures/seed_site.sql @@ -0,0 +1,30 @@ +-- Deploy: fixtures/seed_site +-- made with <3 @ constructive.io + +-- requires: fixtures/seed_database +-- requires: services:schemas/services_public/tables/sites/table +-- requires: services:schemas/services_public/tables/domains/table + +BEGIN; + +-- Create a platform site for branding/metadata resolution. +INSERT INTO services_public.sites (database_id, title, description) +VALUES ( + '00000000-0000-0000-0000-000000000000', + 'Constructive Functions', + 'Serverless compute platform' +) +ON CONFLICT DO NOTHING; + +-- Create a site domain (site-level routing, separate from the API domain). +INSERT INTO services_public.domains (database_id, site_id, subdomain, domain) +SELECT + '00000000-0000-0000-0000-000000000000', + s.id, + 'app', + 'localhost' +FROM services_public.sites s +WHERE s.database_id = '00000000-0000-0000-0000-000000000000' +ON CONFLICT (subdomain, domain) DO NOTHING; + +COMMIT; diff --git a/pgpm/constructive-platform-seed/pgpm.plan b/pgpm/constructive-platform-seed/pgpm.plan new file mode 100644 index 00000000..7d621010 --- /dev/null +++ b/pgpm/constructive-platform-seed/pgpm.plan @@ -0,0 +1,9 @@ +%syntax-version=1.0.0 +%project=constructive-platform-seed +%uri=constructive-platform-seed + +fixtures/seed_database [metaschema-schema:schemas/metaschema_public/tables/database/table] 2026-06-08T05:00:00Z Constructive # seed platform database row +fixtures/seed_schemas [fixtures/seed_database metaschema-schema:schemas/metaschema_public/tables/schema/table] 2026-06-08T05:00:00Z Constructive # register public schemas in metaschema +fixtures/seed_compute_api [fixtures/seed_schemas services:schemas/services_public/tables/apis/table services:schemas/services_public/tables/api_schemas/table] 2026-06-08T05:00:00Z Constructive # create compute API and link schemas +fixtures/seed_domain [fixtures/seed_compute_api services:schemas/services_public/tables/domains/table] 2026-06-08T05:00:00Z Constructive # create compute domain +fixtures/seed_site [fixtures/seed_database services:schemas/services_public/tables/sites/table services:schemas/services_public/tables/domains/table] 2026-06-08T05:00:00Z Constructive # create platform site and site domain diff --git a/pgpm/constructive-platform-seed/revert/fixtures/seed_compute_api.sql b/pgpm/constructive-platform-seed/revert/fixtures/seed_compute_api.sql new file mode 100644 index 00000000..ecd7eca0 --- /dev/null +++ b/pgpm/constructive-platform-seed/revert/fixtures/seed_compute_api.sql @@ -0,0 +1,17 @@ +-- Revert: fixtures/seed_compute_api + +BEGIN; + +DELETE FROM services_public.api_schemas +WHERE database_id = '00000000-0000-0000-0000-000000000000' + AND api_id IN ( + SELECT id FROM services_public.apis + WHERE database_id = '00000000-0000-0000-0000-000000000000' + AND name = 'compute' + ); + +DELETE FROM services_public.apis +WHERE database_id = '00000000-0000-0000-0000-000000000000' + AND name = 'compute'; + +COMMIT; diff --git a/pgpm/constructive-platform-seed/revert/fixtures/seed_database.sql b/pgpm/constructive-platform-seed/revert/fixtures/seed_database.sql new file mode 100644 index 00000000..c272a60e --- /dev/null +++ b/pgpm/constructive-platform-seed/revert/fixtures/seed_database.sql @@ -0,0 +1,8 @@ +-- Revert: fixtures/seed_database + +BEGIN; + +DELETE FROM metaschema_public.database +WHERE id = '00000000-0000-0000-0000-000000000000'; + +COMMIT; diff --git a/pgpm/constructive-platform-seed/revert/fixtures/seed_domain.sql b/pgpm/constructive-platform-seed/revert/fixtures/seed_domain.sql new file mode 100644 index 00000000..90d844bb --- /dev/null +++ b/pgpm/constructive-platform-seed/revert/fixtures/seed_domain.sql @@ -0,0 +1,8 @@ +-- Revert: fixtures/seed_domain + +BEGIN; + +DELETE FROM services_public.domains +WHERE subdomain = 'compute' AND domain = 'localhost'; + +COMMIT; diff --git a/pgpm/constructive-platform-seed/revert/fixtures/seed_schemas.sql b/pgpm/constructive-platform-seed/revert/fixtures/seed_schemas.sql new file mode 100644 index 00000000..5412679f --- /dev/null +++ b/pgpm/constructive-platform-seed/revert/fixtures/seed_schemas.sql @@ -0,0 +1,15 @@ +-- Revert: fixtures/seed_schemas + +BEGIN; + +DELETE FROM metaschema_public.schema +WHERE database_id = '00000000-0000-0000-0000-000000000000' + AND schema_name IN ( + 'constructive_infra_public', + 'constructive_store_public', + 'constructive_objects_public', + 'constructive_fbp_public', + 'constructive_storage_public' + ); + +COMMIT; diff --git a/pgpm/constructive-platform-seed/revert/fixtures/seed_site.sql b/pgpm/constructive-platform-seed/revert/fixtures/seed_site.sql new file mode 100644 index 00000000..03ffc86c --- /dev/null +++ b/pgpm/constructive-platform-seed/revert/fixtures/seed_site.sql @@ -0,0 +1,11 @@ +-- Revert: fixtures/seed_site + +BEGIN; + +DELETE FROM services_public.domains +WHERE subdomain = 'app' AND domain = 'localhost'; + +DELETE FROM services_public.sites +WHERE database_id = '00000000-0000-0000-0000-000000000000'; + +COMMIT; diff --git a/pgpm/constructive-platform-seed/verify/fixtures/seed_compute_api.sql b/pgpm/constructive-platform-seed/verify/fixtures/seed_compute_api.sql new file mode 100644 index 00000000..cc5e30d3 --- /dev/null +++ b/pgpm/constructive-platform-seed/verify/fixtures/seed_compute_api.sql @@ -0,0 +1,16 @@ +-- Verify: fixtures/seed_compute_api + +BEGIN; + +SELECT a.id, a.name, a.role_name, a.anon_role, a.is_public +FROM services_public.apis a +WHERE a.database_id = '00000000-0000-0000-0000-000000000000' + AND a.name = 'compute'; + +SELECT aps.id, aps.api_id, aps.schema_id +FROM services_public.api_schemas aps +JOIN services_public.apis a ON a.id = aps.api_id +WHERE a.database_id = '00000000-0000-0000-0000-000000000000' + AND a.name = 'compute'; + +ROLLBACK; diff --git a/pgpm/constructive-platform-seed/verify/fixtures/seed_database.sql b/pgpm/constructive-platform-seed/verify/fixtures/seed_database.sql new file mode 100644 index 00000000..d638caa7 --- /dev/null +++ b/pgpm/constructive-platform-seed/verify/fixtures/seed_database.sql @@ -0,0 +1,9 @@ +-- Verify: fixtures/seed_database + +BEGIN; + +SELECT id, name, schema_hash +FROM metaschema_public.database +WHERE id = '00000000-0000-0000-0000-000000000000'; + +ROLLBACK; diff --git a/pgpm/constructive-platform-seed/verify/fixtures/seed_domain.sql b/pgpm/constructive-platform-seed/verify/fixtures/seed_domain.sql new file mode 100644 index 00000000..d19fcca4 --- /dev/null +++ b/pgpm/constructive-platform-seed/verify/fixtures/seed_domain.sql @@ -0,0 +1,9 @@ +-- Verify: fixtures/seed_domain + +BEGIN; + +SELECT d.id, d.database_id, d.api_id, d.subdomain, d.domain +FROM services_public.domains d +WHERE d.subdomain = 'compute' AND d.domain = 'localhost'; + +ROLLBACK; diff --git a/pgpm/constructive-platform-seed/verify/fixtures/seed_schemas.sql b/pgpm/constructive-platform-seed/verify/fixtures/seed_schemas.sql new file mode 100644 index 00000000..416b028e --- /dev/null +++ b/pgpm/constructive-platform-seed/verify/fixtures/seed_schemas.sql @@ -0,0 +1,16 @@ +-- Verify: fixtures/seed_schemas + +BEGIN; + +SELECT id, database_id, name, schema_name +FROM metaschema_public.schema +WHERE database_id = '00000000-0000-0000-0000-000000000000' + AND schema_name IN ( + 'constructive_infra_public', + 'constructive_store_public', + 'constructive_objects_public', + 'constructive_fbp_public', + 'constructive_storage_public' + ); + +ROLLBACK; diff --git a/pgpm/constructive-platform-seed/verify/fixtures/seed_site.sql b/pgpm/constructive-platform-seed/verify/fixtures/seed_site.sql new file mode 100644 index 00000000..91745293 --- /dev/null +++ b/pgpm/constructive-platform-seed/verify/fixtures/seed_site.sql @@ -0,0 +1,13 @@ +-- Verify: fixtures/seed_site + +BEGIN; + +SELECT s.id, s.database_id, s.title, s.description +FROM services_public.sites s +WHERE s.database_id = '00000000-0000-0000-0000-000000000000'; + +SELECT d.id, d.site_id, d.subdomain, d.domain +FROM services_public.domains d +WHERE d.subdomain = 'app' AND d.domain = 'localhost'; + +ROLLBACK; diff --git a/scripts/up.sh b/scripts/up.sh index 83148634..ed460103 100755 --- a/scripts/up.sh +++ b/scripts/up.sh @@ -144,9 +144,37 @@ done rm -f "$DEPLOY_LOG" -# ─── Step 5: Deploy constructive-infra-seed ────────────────────────────────── +# ─── Step 5: Deploy platform metadata seed ─────────────────────────────────── -step 5 "Deploying constructive-infra-seed (function + secret definitions)" +step 5 "Deploying constructive-platform-seed (database + schemas + compute API + domain + site)" + +SEED_RC=0 +pgpm deploy --yes --database "$DB_NAME" --package constructive-platform-seed > "$DEPLOY_LOG" 2>&1 || SEED_RC=$? +if [ $SEED_RC -eq 0 ]; then + ok "constructive-platform-seed deployed" +else + fail "constructive-platform-seed — deploy output:" + sed 's/^/ /' "$DEPLOY_LOG" +fi +rm -f "$DEPLOY_LOG" + +# ─── Step 6: Deploy constructive-infra-services ────────────────────────────── + +step 6 "Deploying constructive-infra-services (function module registration)" + +SVC_RC=0 +pgpm deploy --yes --database "$DB_NAME" --package constructive-infra-services > "$DEPLOY_LOG" 2>&1 || SVC_RC=$? +if [ $SVC_RC -eq 0 ]; then + ok "constructive-infra-services deployed" +else + fail "constructive-infra-services — deploy output:" + sed 's/^/ /' "$DEPLOY_LOG" +fi +rm -f "$DEPLOY_LOG" + +# ─── Step 7: Deploy constructive-infra-seed ────────────────────────────────── + +step 7 "Deploying constructive-infra-seed (function + secret definitions)" SEED_RC=0 pgpm deploy --yes --database "$DB_NAME" --package constructive-infra-seed > "$DEPLOY_LOG" 2>&1 || SEED_RC=$? @@ -160,9 +188,9 @@ rm -f "$DEPLOY_LOG" cd "$ROOT_DIR" -# ─── Step 6: Start MinIO ──────────────────────────────────────────────────── +# ─── Step 8: Start MinIO ──────────────────────────────────────────────────── -step 6 "Starting MinIO (object storage)" +step 8 "Starting MinIO (object storage)" MINIO_UP=$(docker ps --filter "name=minio" --filter "status=running" --format "{{.Names}}" 2>/dev/null | head -1) @@ -184,15 +212,15 @@ fi echo " API: http://localhost:9000" echo " Console: http://localhost:9001 (minioadmin/minioadmin)" -# ─── Step 7: Verify ───────────────────────────────────────────────────────── +# ─── Step 9: Verify ───────────────────────────────────────────────────────── -step 7 "Verifying platform" +step 9 "Verifying platform" "$SCRIPT_DIR/verify-platform.sh" "$DB_NAME" -# ─── Step 8: Check .env ───────────────────────────────────────────────────── +# ─── Step 10: Check .env ──────────────────────────────────────────────────── -step 8 "Loading .env into platform" +step 10 "Loading .env into platform" if [ -f "$ROOT_DIR/.env" ]; then "$SCRIPT_DIR/load-platform-env.sh" "$ROOT_DIR/.env" "$DB_NAME" || true