Skip to content

Golden seed — fresh local database

The repo ships a reproducible golden seed: a baseline schema plus a small, secret-free data seed (complete lookup/reference tables, the login identities, and a little per-tenant sample content). One command stands it up in a pinned, containerized Postgres — no per-developer backup files, no interactive prompts, no drift between your DB and the next dev's.

If your local build has gone janky — empty-state crashes, stale lookups, a DB that drifted off head after months of ad-hoc migrations — the fastest fix is a clean reseed. This is the canonical local database.

Want the why behind it (subsetting, scrubbing, the crawl → walk → run rollout)? That's the Golden Seed RFC. This page is the how-to.

Prerequisites

  1. Docker — Colima or Docker Desktop. The seed runs Postgres in a pinned container (devtools/db/docker-compose.yml, postgres:17).

  2. Dependencies installed — from the repo root:

    bash
    bun run deps.dev   # backend + agents: Python deps via uv (creates .venv)
    bun install        # frontend
  3. A .envcp .env.example .env. The defaults already match the seeded DB (localhost:5432, postgres / onramp_local), so no edits are needed for a stock setup.

  4. Hosts entries (for running the app afterward):

    bash
    echo "127.0.0.1 local.onramp.us"          | sudo tee -a /etc/hosts
    echo "127.0.0.1 portal.local.onramp.us"   | sudo tee -a /etc/hosts
    echo "127.0.0.1 customer.local.onramp.us" | sudo tee -a /etc/hosts

Seed it — one command

bash
bun run db.seed

That, idempotently:

  1. Starts the compose Postgres and waits on its healthcheck.
  2. Restores schema-baseline.sql (the schema, pinned to a baseline migration).
  3. Runs uv run flask db upgrade — replays every migration since the baseline, so your DB lands at head no matter how old the dump is.
  4. Loads seed_data.sql (system baseline: lookups + login identities) and seed_sample_data.sql (demo accounts, playbooks, projects, data fields).

Then run the stack:

bash
bun run dev      # http://local.onramp.us:3000/

Log in

IdentityPasswordTenantRole
admin@example.comOnRampLocal!23vendor 0 (OnRamp self-tenant)OnRamp admin
customer@example.comOnRampLocal!23vendor 1customer-tenant owner

vendor 0 is the OnRamp self-tenant — a legitimate tenant in stage/prod, not a null. Use admin@example.com for org-admin work, customer@example.com to see the customer portal side.

The @example.com domain is RFC-2606-reserved and never routes real mail — safe to commit as public dev credentials. @onramp.us is reserved as the Google-SSO trigger domain in PR previews (see PR-preview Google SSO).

Common operations

CommandWhat it does
bun run db.seedStart Postgres + restore + migrate + seed. Idempotent — safe to re-run.
bun run db.resetDrop onramp_local and reseed from scratch (the "my build is janky" button).
bun run db.up / bun run db.downStart / stop the Postgres container without reseeding.

The DB listens on localhost:5432 (postgres / onramp_local). Override the host port with ONRAMP_DB_PORT if 5432 is taken.

Seeding your own Postgres instead

Prefer your own Postgres server (host or a different container) over the compose one? Point ONRAMP_DATABASE_* at it (env or .env) and seed a named database:

bash
./devtools/db/seed.sh --db onramp_scratch          # creates + seeds it
./devtools/db/seed.sh --db onramp_scratch --reset   # drop + reseed only that DB
ONRAMP_DATABASE_NAME=onramp_scratch bun run dev      # run the stack against it

It refuses to overwrite an existing database without --reset, and never touches the system databases. Needs a host psql from a 2025-08+ release (for the dump's \restrict directive).

What the golden seed does not cover

The seed is the database only — a clean, migrated, populated Postgres. Two things devs often conflate with it are separate concerns:

  • Aero / local agents. The AgentCore runtimes (Aero copilot, portal, intel) run as their own processes — bun run dev.agent, dev.agent.portal, dev.agent.intel. Setup + config live in onramp-agents/README.md and onramp-agents/CONFIGURATION.md, not here.
  • Email. Outbound email is config-driven (see the ENVIRONMENT_NAME config map, not env vars). A fresh seed won't change whether mail sends — that's a config/credential question, not a DB one.

A clean reseed will fix a janky build whose root cause is a drifted or corrupt local DB. If Aero or email are still broken after reseeding, the cause is in those subsystems, not the seed.

Known limitations (at time of writing — 2026-06)

The golden seed is live at its crawl stage only (see the RFC rollout). That sets real expectations:

  • It's dev data, not a prod-realistic dataset. The seed is a deliberate floor: complete lookup/reference tables, the login identities, and a small set of per-tenant sample fixtures (seed_sample_data.sql). It is not a scrubbed prod subset — the walk stage (Greenmask-scrubbed prod subset) and run stage (copy-on-write per-PR branches) haven't shipped yet. Don't expect prod-volume content or every feature area to be populated.
  • Sample content is demo/mock, illustrative only. Some screens will look sparse or empty. That's the seed, not a bug — create what you need through the UI.
  • No PII scrub (and none needed yet) — because the source is dev data, not prod. Scrubbing lands with the walk stage.
  • CRM integrations: cached schema, no live OAuth. A cached HubSpot or_integration schema is seeded (vendor 0) so integration UIs render, but there's no live Salesforce/HubSpot connection. CRM-connected flows still need a real connection.
  • Forward-only. The model is restore-baseline → migrate-to-head; it never downgrades. A bad migration is fixed forward, not rolled back.
  • Seed currency is a manual discipline between stages. New fixtures are routed in by hand via the /golden-seed-update skill until the walk-stage automation replaces it.

None of these block local dev — they're about what data you get, not whether the stack runs.

Regenerating the seed (rare)

You almost never need this. Expand migrations replay onto the existing baseline automatically, so most schema changes need no regeneration. Only a contract migration (a drop/rename/type-change) forces a fresh baseline:

bash
SOURCE_DB_URL=postgresql://…@…/onramp_demo bun run db.regen

Adding data the seed should reflect (a new lookup row, an E2E fixture) is a different task — and usually belongs in a migration, not the seed. The /golden-seed-update skill routes each case. Generator details live in devtools/db/.

Internal documentation — gated behind Cloudflare Access.