pnpm worktree next [--go] [--no-migrate] agora provisiona um ambiente determinístico por worktree: slot = parte numérica do código da Issue (C15→15; hash sem dígitos; bump em colisão entre worktrees vivos), dev server em 3100+slot, bancos teqo_wt<slot> / teqo_wt<slot>_test no container compartilhado (-p teqo) com a cadeia de migrations aplicada; escreve .env.local + .env.test.local (gitignored, marcador gerado; envs manuais nunca sobrescritos) e copia PAYLOAD_SECRET/Blob/VAPID do main. kill remove o worktree e dropa os bancos gerados (WITH FORCE, best-effort). Suites leem .env.test.local depois de .env.test (vitest.setup / playwright / db-doctor / gate-ci espelham o layering) e assertTestDatabase aceita teqo_test ou teqo_<worktree>_test em localhost só (fail-closed preservado). db:start/db:stop fixam -p teqo (um container de qualquer diretório); max_connections 200→400. Sem Docker (Cursor Cloud): degrada ao compartilhado com aviso. Derivação pura em scripts/lib/worktree-env.mjs (unit-tested); fluxo validado end-to-end: provision → migrate → 598/598 int no banco do worktree → kill sem resíduo.
7.9 KiB
| name | description |
|---|---|
| local-database | Set up, refresh, and safely use the Teqo local Postgres database, and copy production content locally with `pnpm db:pull`. Use when starting local development, when the local database is empty or stale, when preparing the test database, or when the user mentions the local DB, docker-compose, db:pull, or seeding local data. Enforces that local development and tests never touch the production Neon database. |
Teqo Local Database
Production is a live Neon Postgres with real citizens' PII. Local development and tests run against a local Docker Postgres and must never connect to production.
Guardrails already in place (do not weaken them)
pnpm devrunsscripts/guard-dev-db.mjsand refuses to start ifDATABASE_URLis a non-local host. Escape hatch:ALLOW_REMOTE_DB=true(use only with a very good reason).- Tests load
.env.test(databaseteqo_test) and callassertTestDatabase()(tests/helpers/assertTestDatabase.ts), which throws unless the database name ends in_test. - Never repoint
DATABASE_URLin.env,.env.local, or.env.testat Neon..env.testis committed and local-only on purpose.
Cursor Cloud (sem Docker)
VMs Cloud não rodam docker compose / pnpm db:start. Postgres nativo: .cursor/environment.json (.cursor/cloud-setup.sh + .cursor/ensure-postgres.sh). Mesmos URLs localhost:5432/teqo e teqo_test. Agentes em work-issue / agent-work-issue: não tente Docker; gate:fast/gate:push não precisam de banco.
Local connection values
- Dev database:
postgresql://teqo:teqo@localhost:5432/teqo - Test database:
postgresql://teqo:teqo@localhost:5432/teqo_test - Local Postgres major version is pinned to 17 in
docker-compose.ymlto match production Neon. - In a worktree provisioned by
pnpm worktree next, read.env.local/.env.test.localinstead: dev databaseteqo_wt<slot>, test databaseteqo_wt<slot>_test, dev server on port3100+slot(see "Per-worktree environments" below).
Per-worktree environments (pnpm worktree next)
Parallel agents must not fight over port 3000, the shared teqo_test, or a second Postgres container. pnpm worktree next [--go] provisions each worktree with a deterministic isolated env:
slot= numeric part of the issue code (C15→ 15,B164→ 164; hash fallback without digits; bumped on collision among live worktrees).- Dev server port
3100+slot; databasesteqo_wt<slot>(dev) andteqo_wt<slot>_test(tests), created on the one shared container with the full migration chain applied (one-time, ~30 s each). - Writes
.env.local(DATABASE_URL, PORT, NEXT_PUBLIC_SITE_URL, PLAYWRIGHT_BASE_URL, PAYLOAD_SECRET + Blob/VAPID copied from the main repo) and.env.test.local(test DATABASE_URL). Both carry the marker# teqo worktree env (generated by pnpm worktree next); manual env files are never overwritten — remove them and re-runpnpm worktree nextto regenerate. --no-migrateskips the migration runs;pnpm worktree killdrops the worktree's generated databases (best-effort,DROP DATABASE … WITH (FORCE)).- Without Docker (Cursor Cloud) it degrades to the shared
teqo/teqo_testwith a warning and no port override. - Pure derivation:
scripts/lib/worktree-env.mjs(unit-tested intests/unit/worktree.unit.spec.ts).
First-time setup
- Ensure Docker is running (
open -a Dockeron macOS if the daemon is down). pnpm db:start— boots local Postgres and auto-createsteqo_test.- Set
DATABASE_URL=postgresql://teqo:teqo@localhost:5432/teqoin.env.local. - Load schema + data (pick one):
- Mirror prod content (recommended): see "Refresh local content from prod" below.
- Empty schema from migrations:
pnpm migrate.
pnpm dev.
Stop the database with pnpm db:stop.
Troubleshooting connectivity (pnpm db:doctor)
When pnpm dev, pnpm build, or the int suite cannot reach Postgres, run pnpm db:doctor before anything else. It checks the dev (.env.local/.env) and test (.env.test) targets with a real connection and prints the concrete remedy: which container to docker start, which foreign container is holding the port, or that a container is crash-looping (docker logs). pnpm dev runs the same preflight through guard-dev-db.
It also flags Postgres containers sharing one data volume. Never run a second Postgres container against teqo_pgdata: the postmaster lock cannot interlock across container PID namespaces, so both instances write the same WAL and corrupt it (this destroyed the local cluster's checkpoint on 2026-07-25 — recovered via pg_resetwal + rebuilding teqo_test). The canonical setup is ONE compose container (teqo-postgres-1, host port 5432) hosting both teqo and teqo_test.
Refresh local content from prod (pnpm db:pull)
PROD_DATABASE_URL="<unpooled Neon URL>" pnpm db:pull
- The unpooled URL is
DATABASE_URL_UNPOOLEDin.env.local. scripts/db-pull.mjsonly reads prod (viapg_dump) and only writes local; it refuses any non-local target.- It excludes PII: row data of
contact,signature,subscription(and their_rels) is not copied; the table structure is kept. - It resets and rebuilds the local
publicschema, so it overwrites local data.
Seed news content (pnpm db:seed:posts)
pnpm db:seed:posts
-
scripts/seed-posts.mjsfetches ~39 articles live from jorgesolla.com.br (WordPress REST API, HTML-crawl fallback) and imports them intopost/tag/mediaas publishednoticiaposts, converting the WP HTML body to Payload Lexical and uploading covers to Vercel Blob. -
Same safety guard as
pnpm dev: it refuses a non-localDATABASE_URLunlessALLOW_REMOTE_DB=true. -
Idempotent by slug — re-running skips existing posts and reuses tags/media, so it never duplicates. Because the Vercel Blob store is shared across environments, it deletes any orphan blob under the deterministic
<slug>.<ext>key before uploading, so it stays re-runnable. -
Post-seed revalidation (required for prod): the seed writes from a CLI process outside the deployed runtime, so it does not bust production's frozen
postscache. After seeding prod content — or after ANY direct-DB write — bust it:curl -X POST "https://<prod-domain>/api/revalidate" -H "x-revalidate-secret: $REVALIDATE_SECRET"REVALIDATE_SECRETmust be set in the Vercel production env. See the "Posts & Tags" section inAGENTS.mdfor the full rationale (returns401on a bad secret,500if the secret is unset).
Seed TSE 2022 election results (pnpm db:seed:tse)
pnpm db:seed:tse
TSE_CACHE_DIR=./data/tse pnpm db:seed:tse # reuse downloaded zips
scripts/seed-tse-results.mjsdownloads the TSE open-data zips for the 2022 general election (provenance URLs + SHA-256 in the script header), parses the Bahia scope, and imports intoelectionTally/electionCandidateVote/electionCandidatevia a drizzle transaction.- Same safety guard as
pnpm dev: it refuses a non-localDATABASE_URLunlessALLOW_REMOTE_DB=true. - Idempotent by scope — each
(year, office, turn)scope is replaced wholesale (delete + bulk insert), so re-running never duplicates. - No revalidation step: campaign pages are dynamic with auth (no ISR tags). Downloads are cached under
data/tse/(gitignored).
Prepare / reset the test database
The test DB needs the schema applied via migrations:
DATABASE_URL=postgresql://teqo:teqo@localhost:5432/teqo_test pnpm migrate
Then run pnpm test (or pnpm test:int / pnpm test:e2e). Playwright injects the test DB into its own dev server and never reuses a running one.
Never do
- Point any
DATABASE_URLat Neon for dev or tests. - Run the test suite against a database not ending in
_test. - Try to use
db:pullto push local → prod (it cannot; it is read-only on the source).
Related
- Schema changes and migrations: use the
payload-migrationsskill.