Skip to content

feat(replica): --db neon gives the app a throwaway copy of the database - #16

Open
pyjeebz wants to merge 4 commits into
mainfrom
feat/neon-db-branch
Open

pyjeebz wants to merge 4 commits into
mainfrom
feat/neon-db-branch

Conversation

@pyjeebz

@pyjeebz pyjeebz commented Nov 13, 2026

Copy link
Copy Markdown
Owner

The first piece of the "simulated world" (PRD §0): the app under test gets its own throwaway copy of the database, not a shared staging database.

prescale run http://localhost:3000 --app "npm run build && npm start" --db neon --db-parent staging

With --db neon on run, investigate or ci, PreScale:

  1. copies the named Neon branch. Branches are copy-on-write, so this takes seconds whatever the size.
  2. gives the copy its own read_write compute and waits for Neon's operations to finish
  3. starts the app (--app) with DATABASE_URL, or --db-env VAR, set to the copy's connection URL
  4. runs the test
  5. stops the app, then deletes the copy, however the run ended: verdict, error or Ctrl-C. If Neon refuses the delete, PreScale names the prescale-… branch to remove by hand.

Why: journeys that write (sign-ups, carts, orders) change the copy, never staging. The load runs on the copy's own compute, never the parent's. Neon's own guide describes this exact use ("load tested it with k6 on the branch's own compute").

Safety rules, in code:

  • --db-parent is required. The default branch is often production, so PreScale never picks it.
  • --db requires --app. Only an app PreScale starts can be pointed at the copy.
  • The connection URL is a secret. It goes into the app's environment and nowhere else: not the terminal, the Result, an upload or a log, and the Branch dataclass hides it from repr. Saved runs record only config.database: {provider, parent, database}, plus a warning that the copy's compute may be sized differently from production's.
  • Missing NEON_API_KEY / NEON_PROJECT_ID stops the run before the app starts.

Neon API used (console.neon.tech/api/v2, Bearer auth):

  • GET /projects/{id}/branches to find the parent by name or ID
  • POST /projects/{id}/branches with {branch: {parent_id, name}, endpoints: [{type: read_write}]}
  • poll GET /projects/{id}/operations/{op} until finished; failed/error/cancelled raise, and the half-made branch is still deleted
  • GET …/branches/{b}/databases to pick the database: the only one, or --db-name
  • GET /projects/{id}/connection_uri for the URL, with pooled from --db-pooled
  • DELETE /projects/{id}/branches/{b}

Not in this slice:

  • GitHub Action inputs (slice 2)
  • 10–100× data (slice 3)
  • Neon's anonymized branches of production, which are in beta (slice 4)
  • Supabase (slice 5)
  • automatic expiry (expires_at), which is early-access only. Cleanup relies on the delete in finally.

How it was verified

  • Unit tests against a fake Neon API (cli/tests/test_dbbranch.py, 10 new):
    • the right parent and body are sent
    • operations are polled until finished
    • deletion happens on success, on Ctrl-C, and after a failed creation
    • a missing parent lists the branches and makes nothing
    • several databases need --db-name; --db-pooled is passed
    • a 401 is named
    • missing settings stop the run before the app starts
    • --db without --app or --db-parent is a usage error
  • End to end: prescale run --app <real python server> --db neon --db-parent staging --json, with the fake Neon.
    • The app process read the copy's URL from DATABASE_URL.
    • The copy was deleted.
    • The Result has config.database and the note.
    • The URL's password and host appear nowhere in the output or the saved run.
  • ruff check cli/src cli/tests: clean · pytest cli/tests -q: 378 passed.
  • Not verified yet: a live run against real Neon. That needs a throwaway Neon project and an API key, and will be done before this ships in a release.

Risk

Tier: risky. It calls an external API with a secret, creates and deletes cloud resources, and adds new public flags.

Public surface:

  • flags --db, --db-parent, --db-name, --db-env, --db-pooled
  • environment variables NEON_API_KEY, NEON_PROJECT_ID
  • Result config.database (additive)

Nothing changes without --db.

Rollback: revert. Without --db, behaviour is identical.

Worst case: a prescale-… branch is left behind if both the run and the delete fail. PreScale names it.


Generated by Claude Code

@mintlify

mintlify Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
prescale 🟢 Ready View Preview Nov 13, 2026, 6:32 PM

💡 Tip: Enable Automations to automatically generate PRs for you.

This branch was successfully deployed

1 active (outdated) deployment
staging - docs — 842e9bdd Deployed Nov 13, 2026 by mintlify[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants