- Drop model-selection skill (dead, pool is dormant) - Drop PNG rendering from UI planning (HTML-only, no pnpm ui-draft:render) - Trim code-simplification: 331→~150 lines, Python/React examples moved to reference/ - Compress engineering-brief.md: remove redundant 'Pinhos do repo' (alwaysApply rules) - Deduplicate capture-review-debts: reference decision-quality.md instead of re-explaining - Create concise-output skill (35 lines) to enforce terse agent output - Trim all 99 skill descriptions to ≤1 sentence - Split AGENTS.md into layers: core (73 lines, always) + campaign/public/infra (on-demand) - Decompose plan-issue: exploration sub-agent + parallel plan-writers + register sub-agent - Decompose work-issue: exploration sub-agent + plan-writer + 2 parallel reviewers + debt sub-agent - Update agent-work-issue to match sub-agent pattern
8.5 KiB
| name | description |
|---|---|
| local-database | Set up and safely use the Teqo local Postgres 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 [--stay] provisions each worktree with a deterministic isolated env (next/plan/new print cd <dir> by default — apply it, or pass --stay to suppress; --go is still accepted as a no-op):
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 and the minimal seed applied (one-time, ~30 s each; OPS28 parity with CI, which runsmigrate → seed:minimalbefore e2e — a worktree'spnpm test:e2emirrors CI). - 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, NEXT_PUBLIC_SITE_URL, PLAYWRIGHT_BASE_URL — both URL vars derived from the same slot port so a parallel e2e run never falls back to :3000; seeworktreeEnvFileContentsinscripts/lib/worktree-env.mjs). Both carry the marker# teqo worktree env (generated by pnpm worktree next); manual env files are never overwritten — remove them and re-runpnpm worktree next(orpnpm worktree planfor the /plan-issue worktree,pnpm worktree newfor a neutral one) to regenerate. --no-migrateskips the migration runs and the minimal seed (the seed depends on the migrated catalog);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 — migrate + seed still run on the shared databases (same parity). - 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 ~43 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 through the configured media storage (Garage S3 when theS3_*envs are set — the adapter overwrites the deterministic<slug>.<ext>key natively; local disk otherwise). -
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.
-
Bucket-write guard (OPS60): with the
S3_*envs set (e.g. a worktree with the main repo's prod-credentials copy), the sync requires explicit write intent —SEED_MEDIA_CONFIRM=1— and refuses with exit 1 before any write without it;--dry-runstays flag-free (it never writes). -
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.