teqo/src/migrations/20260715_163500_consent_text_to_jsonb.ts
Francisco Ignácio Fontoura Solla 4f0f997c32 Isolate local/dev and tests from the production database
Local dev and the test suite previously defaulted to the live production
Neon database, and running the tests mutated prod data. Add guardrails plus
a proper local Postgres + migrations workflow so production can't be hit by
mistake:

- docker-compose: local Postgres 17 (matches prod) + auto-created teqo_test
- dev guard refuses a non-local DATABASE_URL; tests refuse non-_test databases
- .env.test isolates the suite; vitest/playwright load it and fail closed
- Payload migrations set up (push disabled); build runs `payload migrate`,
  so deploys apply pending migrations to prod automatically
- baseline `initial` migration + idempotent consent.text varchar->jsonb fix
- `pnpm db:pull` copies prod content locally, excluding supporter PII
- docs (README, AGENTS.md) + agent skills for the local-db/migration workflow
2026-07-15 13:52:30 -03:00

43 lines
1.4 KiB
TypeScript

import { MigrateDownArgs, MigrateUpArgs, sql } from '@payloadcms/db-postgres'
/**
* Reconciles production schema drift: `consent.text` is a `richText` field in the
* Payload config (which maps to `jsonb`), but the production database still has it
* as `varchar`. Its single row already contains valid Lexical JSON, so the cast is
* lossless. This migration is idempotent — it only runs the conversion when the
* column is still `varchar`, so it is a no-op on any database already at `jsonb`
* (e.g. a fresh local DB built from the initial migration).
*/
export async function up({ db }: MigrateUpArgs): Promise<void> {
await db.execute(sql`
DO $$
BEGIN
IF EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'consent'
AND column_name = 'text'
AND data_type = 'character varying'
) THEN
ALTER TABLE "consent" ALTER COLUMN "text" TYPE jsonb USING "text"::jsonb;
END IF;
END $$;
`)
}
export async function down({ db }: MigrateDownArgs): Promise<void> {
await db.execute(sql`
DO $$
BEGIN
IF EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'consent'
AND column_name = 'text'
AND data_type = 'jsonb'
) THEN
ALTER TABLE "consent" ALTER COLUMN "text" TYPE varchar USING "text"::text;
END IF;
END $$;
`)
}