Self-host PLACEHOLDER Cloud
Shortcut: if you just want PLACEHOLDER Cloud running, the all-in-one Docker compose is faster —
git clone … && make compose-up. See the Quickstart (path A) and Deploy with Docker. The walkthrough below is the longer "running services on the host" path used by contributors.
Goal
You'll stand up a local PLACEHOLDER Cloud — Postgres, Redis, the API, the worker, and the UI — on a single machine, with seed data so you can immediately log in.
Prereqs
- Python 3.12+
- Node.js 22 LTS
- Docker Desktop (or compatible — you need a working
docker compose) - 4 GB RAM free for Postgres + Redis + the API + the worker
This walkthrough was written against a Mac. It works the same on Linux. On Windows, use WSL2.
Steps
-
Clone and enter the repo.
git clone <your-fork-or-mirror-url> placeholder-cloudcd placeholder-cloud -
Copy the env template and fill in the critical values.
cp .env.example .envAt minimum you must set:
SECRET_KEY— generate withopenssl rand -hex 32.ENCRYPTION_KEY— generate withpython -c "import base64,os; print(base64.urlsafe_b64encode(os.urandom(32)).decode())". PLACEHOLDER Cloud refuses to start if this isn't a URL-safe base64 string that decodes to exactly 32 bytes.DB_URLandREDIS_URLare fine at their defaults if you're using the bundledinfra/docker-compose-dev.yml.
See
reference/configuration.mdfor every supported env var. -
Start Postgres and Redis.
docker compose -f infra/docker-compose-dev.yml up -dYou should see
postgres-devandredis-devrunning. -
Create a virtualenv and install the workspace.
python -m venv .venvsource .venv/bin/activatepip install -e '.[api,worker,test]' -
Run the migrations.
alembic upgrade headThis creates the
publicschema (orgs, users, tokens, LLM configs). Tenant schemas are created later, per-org, bydqc provision-tenant(seereference/cli.md). -
Seed a development workspace.
python -m scripts.seed_devThis creates one org, one workspace, one owner account, and a sample datasource so you can log in immediately.
-
Start the API.
uvicorn dq_cloud_api.main:app --reload --port 8000 -
Start the worker. In a second terminal:
arq dq_cloud_worker.main.WorkerSettings -
Start the UI. In a third terminal:
cd uinpm installnpm run devThe UI listens on
http://localhost:3000and proxies API requests to the Python process on:8000.
Verify
http://localhost:8000/healthreturns{"status":"ok"}.http://localhost:3000renders the login page.- Log in with the credentials printed by
seed_devand you land on an empty dashboard.
What data lives where, and how to declare your region
PLACEHOLDER Cloud is self-host-first — the answer to "where is my data hosted?" is wherever you just deployed it. Concretely:
- Customer datasource data (the rows you validate) is read by the worker process only. It is never persisted by PLACEHOLDER Cloud — the worker runs each checkpoint in a sandboxed subprocess and keeps only summary metrics + per-expectation pass/fail counts.
- Metadata + result snapshots (orgs, users, datasources, assets, suites, validation results, anomalies, AI suggestions) live in your Postgres, in the schema-per-tenant layout described in Multi-tenancy. Datasource credentials and LLM API keys are AES-256-GCM-encrypted at rest.
- AI calls (suggestions, explanations, autoresolve, NL→SQL) go outbound to whichever LLM provider you configured — Anthropic, OpenAI, an Ollama instance you supply, or a custom OpenAI-compatible endpoint. The provider, model, and API key are per-org (
llm_configs). Per-org cost / token budgeting is tracked in HARDEN-25. - Alerts go to the destination configured on each alert rule (Slack webhook, Microsoft Teams URL, PagerDuty Events API, generic webhook, SMTP).
- Telemetry is opt-in: Prometheus exposes
/metricsfor your scraper to pull; OpenTelemetry is off until you setOTEL_EXPORTER_OTLP_ENDPOINT.
So that customers and auditors can see at a glance where a given deployment is running, set DEPLOYMENT_REGION in your .env to a label that matches reality:
DEPLOYMENT_REGION=eu-west-1 # us-east-1 | eu-west-1 | apac-northeast-1 | self-hosted | …
That value shows up in two places:
- The UI footer renders
Region: <value>next to the version on every page. - The public, unauthenticated
GET /api/v1/deploymentendpoint returns{region, version, sso_enabled, llm_provider}— enterprise procurement teams can hit it before signing without an account.
Multi-region replication is out of scope (FEATURE-34). Pin a single region in your hosting platform and the answer to "where is my data?" is that region.
Next: Run your first checkpoint.