Skip to content

Quick Start ​

Run a Manager on your own machine with Docker Compose, then run the Go backend and the Vue frontend directly for development. The Configuration page explains every setting used here.

The whole platform

pfy dev up starts Manager, database, Pocket ID and proxy together and pfy dev seed creates a project, tenant, application and machine user for you. See the Zero-to-App Local Quickstart and the pfy dev reference. The rest of this page runs the Manager repository on its own.

Prerequisites ​

  • Docker with the Compose plugin
  • Git

For running the backend and frontend outside Docker you also need:

  • Go 1.26 or newer (go.mod says go 1.26.0)
  • Node.js 20 or newer and pnpm; the UI's dev script runs pnpm i && vite, so plain npm is not enough
  • PostgreSQL 14 or newer
  • The Atlas CLI (atlas), for the make migrate-* targets and the migration round-trip tests. Applying migrations does not need it: manager -migrate carries them

1. Clone the repository ​

bash
git clone https://github.com/ProductifyFW/manager.git
cd manager

2. Create a local config file ​

bash
cp config.example.yml config.local.yml

config.local.yml is gitignored. The Manager reads it in preference to config.yml, and any PFY_* environment variable overrides both. The example file already contains a working development setup:

yaml
env: development # anything else turns the production checks on
run_mode: both # API server and trigger executor in one process
port: 8080
health_port: 8081
db:
  host: db # the Compose service name; use localhost outside Compose
  port: 5432
  user: postgres
  password: password
  name: productify # the key is `name`, not `dbname`
  sslmode: disable # the default is `require`; the dev database has no TLS
dev_user_override:
  enabled: true
  id: ca53cb60-e72b-47b5-a7a3-9fa48dda681c
  email: user@productify.dev
  name: Test User
  username: test

env: development and dev_user_override belong together

env defaults to production. In production the Manager refuses to start without a database password, a Pocket ID API key, an encryption key and a proxy secret, and it rejects sslmode: disable.

dev_user_override is an authentication bypass: every request is treated as the configured user. It only works when env is development, and the Manager refuses to start if it is enabled anywhere else. Without it, a Manager that has no proxy in front of it answers every API request with 401 (see Troubleshooting).

3. Start the services ​

bash
docker compose up

Compose starts four services (see docker-compose.yml; a fifth, executor, is behind the production profile and does not start by default):

ServiceWhat it doesHost port
dbPostgreSQL 185432
migrateOne-shot job that runs atlas migrate apply from ent/migrate/migrations. The Manager never migrates on boot, so a fresh database needs this first.none
backendThe Manager, run with air for live reload (run_mode: both)8080 (API), 8081 (health)
frontendThe Vue dev server (pnpm run dev)5173

4. Open the application ​

The first request fails with 500 until the dev user exists

When a request arrives for a user the Manager has never seen, it creates the user row and asks Pocket ID for the username. With dev_user_override and no Pocket ID running, that lookup fails and every UI and GraphQL request returns 500 (Processing error; the log shows pocketid request failed: Get "http://pocketid.localhost/api/users?..."). The username in dev_user_override is read into the config but never used for this.

Create the user row yourself once and the lookup is skipped from then on:

bash
docker compose exec db psql -U postgres -d productify -c \
  "INSERT INTO users (id, external_name, external_username, external_email, role, created_at)
   VALUES ('ca53cb60-e72b-47b5-a7a3-9fa48dda681c', 'Test User', 'test', 'user@productify.dev', 'administrator', now())
   ON CONFLICT DO NOTHING;"

role is the system role. administrator lets the dev user use the system-administrator surfaces (audit export, access review, system roles); use normal if you do not want that.

Developing without Docker ​

Database and migrations ​

Point config.local.yml at your PostgreSQL (db.host: localhost), then apply the migrations once:

bash
make build                 # builds bin/manager
bin/manager -migrate       # reads the same db.* / PFY_DB_* settings as the server

manager -migrate applies the migrations compiled into the binary, through the Atlas Go SDK. It needs no atlas executable and no checkout, and can run from any directory. PFY_MIGRATIONS_DIR points it at an on-disk directory instead, read through the same code path including the atlas.sum check, for an operator holding a newer migration set than the binary.

make migrate-apply DB_URL='postgres://postgres:password@localhost:5432/productify?sslmode=disable' is the equivalent through the Atlas CLI. That one does need atlas on PATH and must run from the repository root, where ent/migrate/migrations lives. Both write the same revision history, so a database can be migrated by either and continued by the other.

Backend with live reload ​

bash
# Install Air (module path github.com/air-verse/air)
go install github.com/air-verse/air@latest

# Run with Air (the repo ships an .air.toml that builds cmd/server)
air

Without Air: make run (which is go run ./cmd/server).

Frontend ​

bash
cd ui
pnpm install
pnpm run dev

The dev server listens on http://localhost:5173 with hot module replacement. The backend's proxy_target setting (default http://localhost:5173) is where the API port forwards non-API requests in development.

Running tests ​

bash
go test ./...                       # all packages
go test -race ./...                 # with the race detector
go test ./pkg/machineuser/...       # one package
go test -cover ./...                # with coverage

The migration round-trip tests are skipped unless a throwaway PostgreSQL and atlas are available; make test-migrations provides both and fails instead of skipping.

Code generation ​

GraphQL resolvers and the Ent client are generated:

bash
go generate ./...   # Ent + gqlgen
make generate       # same thing

Run it after changing:

  • GraphQL schema files in graph/*.graphql
  • Ent schema files in ent/schema/

Environment variables ​

Every setting can be overridden with an environment variable. The name is PFY_ plus the YAML path in upper case, with _ between nested keys:

bash
export PFY_ENV=development
export PFY_PORT=8080
export PFY_DB_HOST=localhost
export PFY_DB_PASSWORD=secret
export PFY_RUN_MODE=both

See Configuration for the full list.

Troubleshooting ​

Port already in use ​

Compose maps the container's fixed ports to the same host ports (8080:8080, 8081:8081, 5173:5173). To use a different host port, change the left-hand side of the mapping in docker-compose.yml, for example "8090:8080".

When you run the binary directly, change port in config.local.yml or set PFY_PORT=8090.

Every request returns 401 ​

If /healthz answers but the API returns 401 for everything, the proxy-secret gate is failing closed. The body says why:

json
{"error":"manager misconfiguration: no proxy secret is configured (PFY_PROXY_SECRET is unset and dev_user_override is not enabled), so the manager cannot recognise the trusted proxy and rejects every request. ..."}

Either set PFY_PROXY_SECRET to the same value as the proxy's PFY_MANAGER_TOKEN, or, when running without a proxy, set env: development and dev_user_override.enabled: true. The Manager also logs a repeated WARNING: PFY_PROXY_SECRET is unset ... at startup in this state.

Every request returns 500 ​

See the note above: the dev user's first request needs Pocket ID or a pre-created user row.

relation "..." does not exist ​

The database has no schema. The Manager never migrates on boot, in any run mode. docker compose up runs the one-shot migrate service for you; if you run the binary directly, run bin/manager -migrate first (see Database and migrations). /readyz reports this condition as 503 with a reason.

The published container image can migrate its own database: docker run --rm -e PFY_DB_HOST=... ghcr.io/productifyfw/manager:<tag> /app/manager -migrate.

Database connection issues ​

bash
docker compose logs db         # check the database
docker compose down -v         # drop the volume; the migrate service reapplies the schema
docker compose up

Frontend build failures ​

bash
cd ui
rm -rf node_modules
pnpm install
pnpm run dev

Next steps ​