Skip to main content

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

  1. Clone and enter the repo.

    git clone <your-fork-or-mirror-url> placeholder-cloud
    cd placeholder-cloud
  2. Copy the env template and fill in the critical values.

    cp .env.example .env

    At minimum you must set:

    • SECRET_KEY — generate with openssl rand -hex 32.
    • ENCRYPTION_KEY — generate with python -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_URL and REDIS_URL are fine at their defaults if you're using the bundled infra/docker-compose-dev.yml.

    See reference/configuration.md for every supported env var.

  3. Start Postgres and Redis.

    docker compose -f infra/docker-compose-dev.yml up -d

    You should see postgres-dev and redis-dev running.

  4. Create a virtualenv and install the workspace.

    python -m venv .venv
    source .venv/bin/activate
    pip install -e '.[api,worker,test]'
  5. Run the migrations.

    alembic upgrade head

    This creates the public schema (orgs, users, tokens, LLM configs). Tenant schemas are created later, per-org, by dqc provision-tenant (see reference/cli.md).

  6. Seed a development workspace.

    python -m scripts.seed_dev

    This creates one org, one workspace, one owner account, and a sample datasource so you can log in immediately.

  7. Start the API.

    uvicorn dq_cloud_api.main:app --reload --port 8000
  8. Start the worker. In a second terminal:

    arq dq_cloud_worker.main.WorkerSettings
  9. Start the UI. In a third terminal:

    cd ui
    npm install
    npm run dev

    The UI listens on http://localhost:3000 and proxies API requests to the Python process on :8000.

Verify

  • http://localhost:8000/health returns {"status":"ok"}.
  • http://localhost:3000 renders the login page.
  • Log in with the credentials printed by seed_dev and 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 /metrics for your scraper to pull; OpenTelemetry is off until you set OTEL_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/deployment endpoint 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.