Back to skills
extension
Category: Development & EngineeringNo API key required

constructive-deployment

Deploy the Constructive platform locally and to production using Docker Compose, pgpm, and the Constructive CLI. Use when asked to "deploy constructive", "set up docker compose", "run constructive locally", "deploy to production", or when working with the constructive monorepo's Docker and infrastructure files.

personAuthor: jakexiaohubgithub

Constructive Deployment

How to deploy the Constructive platform — local development with Docker Compose, database migrations with pgpm, and production container builds.

When to Apply

Use this skill when:

  • Setting up the Constructive monorepo for local development
  • Running Docker Compose services (Postgres, MinIO, API servers)
  • Building the Constructive Docker image
  • Deploying database migrations to local or remote Postgres
  • Understanding the Makefile targets and service architecture

Local Development Setup

Prerequisites

  • Docker and Docker Compose
  • Node.js 22+ with pnpm
  • pgpm CLI (available from the constructive monorepo)

Quick Start

# 1. Start Postgres and MinIO containers
make up
# OR: docker-compose up -d

# 2. Bootstrap database roles (ensure PG env vars are loaded — see pgpm skill, references/env.md)
pgpm admin-users bootstrap --yes

# 3. Deploy all database modules
pgpm deploy --createdb --workspace --all --yes

Stopping

# Stop and remove containers + volumes
make down
# OR: docker-compose down -v

Docker Compose Services

Core Services (docker-compose.yml)

| Service | Container | Image | Port | Purpose | |---------|-----------|-------|------|---------| | postgres | postgres | ghcr.io/constructive-io/docker/postgres-plus:17 | 5432 | PostgreSQL database | | minio | minio | minio/minio | 9000 | S3-compatible object storage |

Postgres credentials: postgres / password (local dev only)

Application Services (docker-compose.jobs.yml)

| Service | Container | Port | Purpose | |---------|-----------|------|---------| | constructive-admin-server | constructive-admin-server | 3002 | Internal admin GraphQL API (header-based routing) | | constructive-server | constructive-server | 3000 | Public GraphQL API (domain-based routing) | | send-email-link | send-email-link | — | Email function (invite, password reset, verification) |

Running Application Services

The application services require a built Docker image:

# Build the constructive image
docker-compose -f docker-compose.jobs.yml build

# Start all application services
docker-compose -f docker-compose.jobs.yml up -d

Postgres Images

| Image | Use Case | |-------|----------| | ghcr.io/constructive-io/docker/postgres-plus:17 | Recommended — includes all extensions needed by constructive | | pyramation/postgres:17 | Lightweight alternative with common extensions |

PostgreSQL 17+ is required for security_invoker views. Older images will fail with "unrecognized parameter security_invoker" errors.

Database Deployment

Deploy to Local Database

Prerequisite: Ensure PostgreSQL is running and PG env vars are loaded. See pgpm skill (references/docker.md) and pgpm skill (references/env.md).

pgpm deploy --createdb --workspace --all --yes

Deploy to Remote Database

Point pgpm at a remote Postgres instance via environment variables:

export PGHOST=remote-host.example.com
export PGPORT=5432
export PGUSER=postgres
export PGPASSWORD=secure-password
export PGDATABASE=constructive

pgpm deploy --workspace --all --yes

Verify Deployment

pgpm verify

Revert (Rollback)

# Revert last change
pgpm revert --yes

# Revert to a tagged release
pgpm revert --to @v1.0.0 --yes

# Revert everything
pgpm revert --all --yes

Docker Image Build

The Constructive monorepo builds a multi-stage Docker image:

Build Stages

  1. build stage — Node.js 22, installs pnpm, runs pnpm install --frozen-lockfile and pnpm run build
  2. constructive stage — Runtime image with built artifacts, PostgreSQL client, and CLI shims

CLI Shims

The Docker image exposes three CLI commands:

| Command | Maps To | |---------|---------| | constructive | node /app/packages/cli/dist/index.js | | cnc | node /app/packages/cli/dist/index.js | | pgpm | node /app/pgpm/pgpm/dist/index.js |

Building Locally

docker build -t constructive:dev .

Makefile Targets

| Target | Command | Purpose | |--------|---------|---------| | make up | docker-compose up -d | Start Postgres + MinIO | | make down | docker-compose down -v | Stop and clean up | | make ssh | docker exec -it postgres /bin/bash | Shell into Postgres container | | make roles | pgpm admin-users bootstrap/add | Bootstrap database roles | | make install | docker exec postgres /sql-bin/install.sh | Run install script in container |

Environment Variables

Server Configuration

| Variable | Description | Example | |----------|-------------|---------| | API_IS_PUBLIC | true for public API, false for admin (header-based) | true | | API_EXPOSED_SCHEMAS | Comma-separated schemas to expose via GraphQL | metaschema_public,services_public | | API_ANON_ROLE | PostgreSQL role for unauthenticated requests | anonymous | | API_ROLE_NAME | PostgreSQL role for authenticated requests | authenticated | | API_ENABLE_SERVICES | Enable services schema (admin only) | true | | API_META_SCHEMAS | Meta schemas for validation and routing | metaschema_public,services_public | | SERVER_HOST | Server bind address | 0.0.0.0 | | SERVER_ORIGIN | CORS origin | * | | SERVER_TRUST_PROXY | Trust reverse proxy headers | true | | SERVER_STRICT_AUTH | Enforce strict authentication | false |

Database Connection

| Variable | Description | Default | |----------|-------------|---------| | PGHOST | PostgreSQL host | localhost | | PGPORT | PostgreSQL port | 5432 | | PGUSER | PostgreSQL user | postgres | | PGPASSWORD | PostgreSQL password | password | | PGDATABASE | Target database name | — |

Admin vs Public API

The Constructive platform runs two API servers:

  • Admin server (API_IS_PUBLIC=false, port 3002) — uses header-based routing (X-Api-Name, X-Database-Id, X-Meta-Schema). Used internally by the Constructive admin UI.
  • Public server (API_IS_PUBLIC=true, port 3000) — uses domain-based routing. Serves external client applications.

Networking

All Docker Compose services share the constructive-net network, allowing inter-service communication by container name (e.g., postgres:5432 from within the constructive-server container).

Troubleshooting

| Issue | Cause | Fix | |-------|-------|-----| | Port 5432 in use | Another Postgres instance running | Stop it or change the port in docker-compose.yml | | security_invoker error | Postgres version < 17 | Use postgres-plus:17 or pyramation/postgres:17 image | | role "authenticated" does not exist | Missing bootstrap | Run pgpm admin-users bootstrap --yes | | Container not on network | Network mismatch | Check docker network ls for constructive-net | | Build fails at pnpm install | Lockfile mismatch | Run pnpm install locally first to update lockfile |