diff --git a/.env.example b/.env.example
index 002cf01f..9f6761a8 100644
--- a/.env.example
+++ b/.env.example
@@ -105,3 +105,14 @@ PORTAL_TRANSPARENCIA_API_KEY=
# read by the CLI at run time and never stored in receipts.
FLICKR_API_KEY=
FLICKR_USER_ID=
+
+# C232 — vision engine of the photo-archive cataloguing (`pnpm archive:catalog`).
+# Any OpenAI-compatible server (Ollama, llama.cpp, vLLM) on the PRIVATE network:
+# the citizens' photos must not leave it (a public host is refused unless
+# ARCHIVE_VISION_ALLOW_REMOTE=1 is declared). Example: an Ollama box on the LAN
+# or tailnet — ARCHIVE_VISION_BASE_URL=http://100.94.122.26:11434/v1.
+# ARCHIVE_VISION_API_KEY is only for servers that require a key; never stored in
+# receipts, and the endpoint is only called by `--apply`.
+ARCHIVE_VISION_BASE_URL=
+ARCHIVE_VISION_MODEL=
+ARCHIVE_VISION_API_KEY=
diff --git a/.gitignore b/.gitignore
index 164f6bf1..16bd3f49 100644
--- a/.gitignore
+++ b/.gitignore
@@ -86,6 +86,8 @@ next-env.d.ts
/data/flickr/
# C229 — speech semantic index reports (pnpm acervo:index)
/data/acervo-index/
+# C232 — photo-archive cataloguing receipts (pnpm archive:catalog)
+/data/archive/
# Solla × Ceuci report HTML cache (scripts/build-solla-ceuci-salvador-report.mjs)
/data/solla-ceuci-salvador/
diff --git a/docs/changelog/2026-09-26-c232.md b/docs/changelog/2026-09-26-c232.md
new file mode 100644
index 00000000..98390e70
--- /dev/null
+++ b/docs/changelog/2026-09-26-c232.md
@@ -0,0 +1 @@
+**C232 — catalogação com IA do acervo de fotos (2026-09-26):** as 6,5k fotos do acervo privado (`archivePhoto`, C231) ganham ficha pré-catalogada revisável no admin: legenda/descrição pt-BR, atividade/cena (vocabulário fechado de 11 valores), texto visível (OCR do próprio VLM), temas do vocabulário existente (`SPEECH_TOPICS`), município pelo gazetteer (regra conservadora: Salvador/zona ambíguo → null, resolver extraído para `src/utilities/municipality/municipalityMentionResolver.ts` com o catálogo de peças delegando) e pessoas públicas **só do catálogo curado, lidas do texto — nunca inferidas de rosto**. O engine de visão é um endpoint OpenAI-compatible local (`ARCHIVE_VISION_BASE_URL`/`MODEL`/`API_KEY` — Ollama/llama.cpp/vLLM; nenhum fornecedor pinado) atrás de guarda falha-fechado de host privado (`isPrivateVisionHost`/`assertLocalVisionEndpoint` em `scripts/lib/cli.mjs`, escape explícito `ARCHIVE_VISION_ALLOW_REMOTE=1` com o escopo registrado no recibo): PII/rostos não saem da rede sem decisão; terceiro/híbrido rejeitados com gatilho de revisita. A curadoria vence a IA pelo mesmo trio do C230 (`ARCHIVE_PHOTO_CURATED_FIELDS` no lib + hook `beforeValidate` que marca campo alterado só quando há `req.user` e não é escrita do sistema + fresh-read dentro da transação em `src/utilities/flickr/archivePhotoCatalog.ts`, que baixa os bytes privados via `downloadPrivateMediaToFile`, prepara JPEG ≤1024px com sharp, injeta o analisador e grava só campo não curado); `catalog.source` = `ai | metadata | none` (nada a propor é estado final honesto) e `catalog.catalogedAt` é a chave de idempotência. O passe é o CLI de manutenção `pnpm archive:catalog` (plan default / `--apply` com `ARCHIVE_CATALOG_CONFIRM=1` + `TEQO_ENV` + 4 `S3_*` / `--verify` read-only que sai 1 com pendentes; `--limit` canário; recibo JSON datado em `data/archive/reports/`), com client HTTP com retry/timeout em `scripts/lib/archiveVisionApi.mjs` e parser zod fail-closed no lib. A busca interna é o admin stock: `searchText` normalizado com índice GIN trgm + `takenOn` (derivado do wall clock do Flickr, meio-dia UTC) + facetas filtráveis (município/cena/temas/pessoas/data/origem); `alt` é refinado a partir da caption só quando nunca curado. Migration aditiva `add_archive_photo_catalog` (grupo `catalog`, `curatedFields`, `takenOn`, `searchText` + índices). Testes: unit do contrato puro/parser/merge, do client (fetch mockado), do parser/recibo e dos guardas por subprocesso; int sobre `teqo_test` (catálogo grava e deriva o índice, curadoria vence, falha não escreve e retenta, skip por `catalogedAt`, fontes ai/metadata/none, marcação só em edição humana); sem e2e novo (superfície admin stock, OPS72). Runbook staging-primeiro com canário em `docs/ops/teqo-1313-deploy.md`. Impl plan: `docs/plans/acervo-fotos-catalogacao-ia-impl.md`.
diff --git a/docs/ops/teqo-1313-deploy.md b/docs/ops/teqo-1313-deploy.md
index d6bc9ce5..e42ebc6f 100644
--- a/docs/ops/teqo-1313-deploy.md
+++ b/docs/ops/teqo-1313-deploy.md
@@ -1375,6 +1375,60 @@ apagar as linhas do `archivePhoto` no admin (o objeto correspondente no bucket
pode ser removido à parte); reexecutar a ingestão recria as mesmas chaves de
objeto.
+## C232 — catalogação com IA do acervo de fotos
+
+O comando `pnpm archive:catalog` pré-cataloga as fotos do acervo (`archivePhoto`)
+com um engine de visão LOCAL: legenda/descrição, atividade/cena, texto visível,
+temas do vocabulário existente, município (gazetteer) e pessoas públicas (só do
+catálogo curado, lidas do TEXTO — nunca de rosto). A curadoria da assessoria
+vence: campo editado no admin entra em "Campos curados" e a catalogação nunca
+sobrescreve; reexecutar converge ("processadas / puladas / falharam com motivo")
+e só as pendentes são processadas. Nada é publicado.
+
+O engine é qualquer servidor OpenAI-compatible na **rede privada** (Ollama,
+llama.cpp, vLLM). Exemplo: servir o modelo na workstation com GPU (o mesmo padrão
+do ML do Immich no tailnet) e apontar o container para lá:
+
+```bash
+# na workstation (GPU), ex. com Ollama:
+ollama serve # porta 11434, alcançável pelo tailnet
+ollama pull qwen2.5vl:7b
+
+# no homeserver:
+ssh homeserver
+cd ~/stack
+# 0) plano (dry-run; lê a fila, não chama o engine nem escreve):
+docker compose --profile maintenance run --rm \
+ -e ARCHIVE_VISION_BASE_URL=http://100.94.122.26:11434/v1 \
+ -e ARCHIVE_VISION_MODEL=qwen2.5vl:7b \
+ teqo-staging-migrate pnpm archive:catalog --limit 5
+# 1) canário no staging (exige TEQO_ENV + confirmação; as 4 S3_* são obrigatórias):
+docker compose --profile maintenance run --rm \
+ -e TEQO_ENV=staging -e ARCHIVE_CATALOG_CONFIRM=1 \
+ -e ARCHIVE_VISION_BASE_URL=http://100.94.122.26:11434/v1 \
+ -e ARCHIVE_VISION_MODEL=qwen2.5vl:7b \
+ teqo-staging-migrate pnpm archive:catalog --apply --limit 5
+# 2) validação no staging e só então produção (TEQO_ENV=production, serviço teqo-1313-migrate)
+# 3) inventário a qualquer momento (read-only, sem engine):
+docker compose --profile maintenance run --rm \
+ teqo-staging-migrate pnpm archive:catalog --verify
+```
+
+Os recibos JSON ficam em `data/archive/reports/` do container — monte um volume
+(`-v /srv/archive-reports:/app/data/archive`) para preservá-los. Guardas: fora de
+teste o `TEQO_ENV=staging|production` é obrigatório com o **nome exato** do banco
+(`teqo_staging`/`teqo_1313`); `ALLOW_REMOTE_DB` é recusado; sem as 4 `S3_*` o
+`--apply` recusa (o acervo não estaria acessível no alvo); `ARCHIVE_CATALOG_CONFIRM=1`
+é exigido em alvo não-local; e o endpoint do engine precisa estar na rede privada
+— host público é recusado e exige `ARCHIVE_VISION_ALLOW_REMOTE=1` explícito
+(registrado no recibo com host/modelo e o escopo). Falha por foto é isolada e
+nomeada (nada é escrito; a próxima execução retenta); o lote de 6,5k é sequencial
+(~4–10 h). A chave do engine (quando houver) nunca entra em recibo/log.
+
+Rollback: a migration `add_archive_photo_catalog` é aditiva; o rollback funcional
+é limpar o grupo `catalog`/`curatedFields` no admin. Reexecutar nunca duplica nem
+sobrescreve curadoria.
+
## Referências
- `scripts/deploy-homeserver.sh` — o script (fonte da verdade do fluxo; parametrizado por `TEQO_ENV`)
diff --git a/docs/plans/acervo-fotos-catalogacao-ia-impl.md b/docs/plans/acervo-fotos-catalogacao-ia-impl.md
new file mode 100644
index 00000000..60aa1ecc
--- /dev/null
+++ b/docs/plans/acervo-fotos-catalogacao-ia-impl.md
@@ -0,0 +1,188 @@
+# Impl: C232 — Catalogação com IA do acervo de fotos
+
+Status: aprovado
+Atualizado em: 2026-09-26
+Issue: #1367
+Intenção: docs/plans/acervo-fotos-catalogacao-ia.md
+Appetite restante: herdado — ~2 dias eng + tempo de processamento do lote (6,5k fotos)
+
+## Leitura da intenção
+
+- **Outcome:** cada foto do acervo C231 ganha ficha pré-catalogada revisável (legenda/descrição pt-BR, atividade/cena, local, pessoas do catálogo curado, texto visível, temas, descrição semântica); a busca interna acha por local/data/atividade/pessoa/termo; a curadoria humana vence a IA; o passe é em lote não interativo com recibo honesto e reexecução idempotente; nada é público e nenhum nome é inferido de rosto.
+- **O que NÃO negociar:** PII/rostos de cidadãos não vão a terceiro sem decisão explícita e contrato; provider reservado aos agentes de design (`openai/*`, OPS123) não entra no app; pessoas só do catálogo curado e com confirmação humana; rosto é presença/tag de cena (biometria é C234); sem segundo engine de catalogação, sem segundo cadastro de pessoa, sem edição de imagem; leitura do acervo pelo mesmo gate da Comunicação (`src/utilities/access/archivePhotos.ts:18-23`).
+- **O que reavaliar:** a hipótese da intenção aponta `src/utilities/content/` e `src/utilities/ai/` como áreas prováveis; a engenharia reavalia e escolhe `src/utilities/flickr/` (dono do archivePhoto server-side, C231) + `src/lib` puro + `scripts/lib` para o client HTTP, **sem** reusar o job de peças (input é imagem, não transcrição). A hipótese "embedding para busca futura" fica adiada com gatilho (só a descrição textual agora).
+
+## Abordagem recomendada
+
+```mermaid
+flowchart LR
+ A[archivePhoto C231
catalog.catalogedAt nulo] --> B[CLI archive:catalog --apply]
+ B --> C[baixa bytes privados
downloadPrivateMediaToFile]
+ C --> D[sharp ≤1024px JPEG
só para o engine]
+ D --> E[analisador injetável
VLM local OpenAI-compatible]
+ E --> F[validação pura pt-BR:
cena · temas · pessoas do catálogo]
+ F --> G[determinístico de texto:
município · temas · pessoas]
+ G --> H[transação: fresh-read curatedFields
escreve só não curado + source/catalogedAt]
+ H --> I[(admin: busca searchText/trgm
filtros local/data/atividade/pessoa)]
+ B -.-> R[recibo JSON: processadas/puladas/falharam com motivo]
+```
+
+**Opções consideradas:** A) pipeline local/self-hosted em CLI de manutenção (recomendada) | B) API de visão de terceiro | C) job in-app com fila.
+**Recomendação:** A — o lote não é interativo e roda em casa; o engine é um endpoint OpenAI-compatible configurado por env (Ollama/llama.cpp/vLLM na workstation com GPU, padrão de serviço via tailnet já usado pelo ML do Immich), então nenhuma foto sai da rede privada e nenhum fornecedor fica pinado no código.
+**Rejeitadas:** B porque manda foto de cidadão para terceiro sem decisão explícita e contrato (guardrail de produto); C porque ainda exterioriza a imagem e cria dois caminhos para o mesmo risco.
+
+### Componentes / mudanças
+
+**Novos — contrato puro (sem I/O, sem `server-only`; mesmo molde de `src/lib/archivePhoto.ts:1-11`)**
+
+- **`ARCHIVE_PHOTO_SCENES` / `isArchivePhotoScene` / `archivePhotoSceneLabel`** (`src/lib/archivePhotoCatalog.ts`): vocabulário fechado de atividade/cena com labels pt-BR — `plenaria` (Plenária), `audiencia` (Audiência), `reuniao` (Reunião), `evento` (Evento), `mobilizacao` (Mobilização), `visita` (Visita), `entrevista` (Entrevista), `discurso` (Discurso), `retrato` (Retrato), `gabinete` (Gabinete), `outro` (Outro).
+- **`ARCHIVE_PHOTO_CURATED_FIELDS` + labels** (`src/lib/archivePhotoCatalog.ts`): `alt`, `caption`, `description`, `scene`, `visibleText`, `hasPeople`, `themes`, `people`, `municipality` — espelha `CONTENT_PIECE_CURATED_FIELDS` (`src/lib/contentPiece.ts:111-137`), um literal por nome de campo persistido.
+- **`ARCHIVE_PHOTO_CATALOG_SOURCES`** (`ai | metadata | none`) + labels pt-BR.
+- **`archivePhotoThemesFrom`** (`src/lib/archivePhotoCatalog.ts`): resolve tokens contra `resolveSpeechTopic` fail-closed (`src/lib/speechFacets.ts:83-88`), deduplica e capa; nunca inventa slug.
+- **`archivePhotoPeopleFromCatalog`** (`src/lib/archivePhotoCatalog.ts`): só nomes que resolvem em `resolvePublicFigureName` (`src/lib/publicFigureCatalog.ts:77-85`); valor não resolvido é descartado, nunca vira nome.
+- **`matchPublicFigureMentions`** (`src/lib/archivePhotoCatalog.ts`): menção exata de nome do catálogo no texto (molde `resolveContentPieceInstitution`, `src/utilities/content/contentPieceCataloging.ts:189-201`) para o caminho determinístico `metadata`.
+- **`archivePhotoSearchText`** (`src/lib/archivePhotoCatalog.ts`): haystack normalizado com `normalizeForSearch` (`src/lib/speechSearch.ts:11-17`; molde `contentPieceSearchText`, `src/lib/contentPiece.ts:337-352`) — alt, título, legenda, descrição (Flickr + catálogo), cena, texto visível, temas, pessoas, município, álbuns e tags.
+- **`archivePhotoTakenOn`** (`src/lib/archivePhotoCatalog.ts`): `YYYY-MM-DD` do wall clock do Flickr (`archivePhotoTakenAt`, `src/lib/archivePhoto.ts:123-127`), fixado ao meio-dia UTC para o admin não exibir o dia anterior.
+- **`changedArchivePhotoCuratedFields`** (`src/lib/archivePhotoCatalog.ts`): diff do hook do admin (arrays normalizados; esvaziar conta como decisão).
+- **`buildArchivePhotoCatalogWrite`** (`src/lib/archivePhotoCatalog.ts`): merge determinístico que só preenche campo fora de `curatedFields`; `alt` refina a partir da caption só quando não curado (C231 delegou "C232 refina", `src/lib/archivePhoto.ts:118-120`); devolve `{ data, source }`.
+- **`parseArchiveVisionOutput` / `buildArchiveVisionPrompt` / `ARCHIVE_VISION_SYSTEM_PROMPT`** (`src/lib/archivePhotoCatalog.ts`): parser zod fail-closed → `ArchivePhotoSuggestion | null`; prompt pt-BR com o vocabulário fechado (cenas, `SPEECH_TOPICS` `src/lib/speechFacets.ts:14-33`, nomes do `publicFigureCatalog` `src/lib/publicFigureCatalog.ts:40-51`) e a regra "nunca inferir nome de rosto; só nomes do catálogo; responder só JSON".
+
+**Novos — server-side Payload**
+
+- **`resolveMentionedMunicipalityId`** (`src/utilities/municipality/municipalityMentionResolver.ts`): extração do lookup de `resolveContentPieceMunicipalityId` (`src/utilities/content/contentPieceCataloging.ts:159-182`) para owner compartilhado na subpasta de domínio já existente; mantém a regra conservadora (só cidade com exatamente 1 entrada; Salvador ambíguo → `null`).
+- **`ArchivePhotoAnalyzer` / `listArchivePhotoCatalogQueue` / `catalogArchivePhoto`** (`src/utilities/flickr/archivePhotoCatalog.ts`, `import 'server-only'`; o laço por foto e o recibo ficam no CLI): pipeline por foto com analisador injetável; baixa os bytes privados com `downloadPrivateMediaToFile` + `resolvePrivateMediaStaticDir` (`src/utilities/privateMedia/privateMediaResponse.ts:219-249,43-51`); prepara o JPEG ≤1024px com `sharp` (`package.json:150`); roda o gazetteer determinístico (`matchMunicipalityMentions` `src/lib/speechGazetteer.ts:396-431`, `classifySpeechByGazetteer` `:449-476`); dentro de `withPayloadTransaction` (`src/utilities/payloadTransaction.ts:86-113`) relê `curatedFields`/`catalog.catalogedAt` e escreve só campo não curado + `catalog.source`/`catalog.catalogedAt` (molde `contentPieceJob.ts:285-323`); `context: { archivePhotoCatalog: true }` e `overrideAccess: true` com comentário de bypass.
+
+**Novos — scripts/CLI**
+
+- **`createArchiveVisionClient` / `analyzeImage` / `ArchiveVisionError`** (`scripts/lib/archiveVisionApi.mjs`): client HTTP OpenAI-compatible (`POST {base}/chat/completions`, imagem em `data:` URL base64), `fetchImpl` injetável, timeout ~90s, retry/backoff só em transitório (429/5xx/rede) e erros nomeados — molde `scripts/lib/flickrApi.mjs:27-46,60-124`; nunca loga a chave; entra em `SCRIPTS_SPEC_PINNED` (`scripts/lib/test-affected-core.mjs:31-110`).
+- **`parseArchiveCatalogCliArgs` / summaries / `formatArchiveCatalogReport`** (`scripts/lib/archiveCatalogPlan.mjs`): parser dos modos e recibo (molde `scripts/lib/flickrPlan.mjs:48-90,337-373`); também pinado.
+- **`scripts/catalog-archive-photos.mjs`** (+ script `pnpm archive:catalog`, molde `package.json:37`): plan default / `--apply` / `--verify`, `--limit` canário, `--out`, `--help`; guardas reusados de `scripts/lib/cli.mjs` (`assertWriteConfirm` com `ARCHIVE_CATALOG_CONFIRM`, `assertEnvironmentDatabaseTarget`, `mirroredMediaRequired` `:312-320,238-301,197-202`) + `assertLocalVisionEndpoint` novo; loop com falha isolada e estágio nomeado (molde `scripts/ingest-flickr-archive.mjs:154-231`); recibo JSON datado em `data/archive/reports/`; `--verify` sai 1 com fotos pendentes.
+
+**Novos — migration/testes/ops**
+
+- **Migration `add_archive_photo_catalog`** (`src/migrations/20260926_HHMMSS_add_archive_photo_catalog.ts` + `.json` + registro em `src/migrations/index.ts`, hoje último em `:89`): grupo `catalog`, `curated_fields`, `taken_on`, `search_text`, índices e GIN trgm (molde `20260923_032714_add_content_piece.ts:5,100`).
+- **Testes:** `tests/unit/archivePhotoCatalog.unit.spec.ts`, `tests/unit/archiveVisionApi.unit.spec.ts`, `tests/unit/archiveCatalogPlan.unit.spec.ts`, `tests/unit/visionEndpoint.unit.spec.ts`, `tests/unit/archiveCatalogCli.unit.spec.ts` (guardas por subprocesso); `tests/int/archivePhotoCatalog.int.spec.ts` sobre a fixture JPEG `tests/helpers/archivePhotoFixture.ts`.
+- **Ops:** seção C232 em `docs/ops/teqo-1313-deploy.md` (após `:1299-1339`), `ARCHIVE_VISION_*` em `.env.example` (`:102-107` é o bloco C231), `/data/archive/` em `.gitignore` (`:86` é o `/data/flickr/`), `docs/changelog/2026-09-26-c232.md`.
+
+**Edits**
+
+- **`markArchivePhotoCuratedFields` / `deriveArchivePhotoCatalogIndex`** (`src/collections/ArchivePhoto.ts`, hooks inline como manda a convenção): marca campo alterado quando `req.user` existe e `req.context.archivePhotoCatalog` está ausente (precedente de contexto: `src/utilities/googleCalendarSync.ts:508`; leitura do contexto de hook: `src/collections/Activity.ts:79`); deriva `takenOn` e `searchText` em `beforeValidate` mesclando `data` com `originalDoc` como `ContentPiece.ts:164-240`. Access intocado (`:32-37`).
+- **Campos novos em `ArchivePhoto.ts`:** grupo `catalog` (`caption` text, `description` textarea, `scene` select index, `visibleText` textarea, `hasPeople` checkbox, `themes` select hasMany index com `SPEECH_TOPICS`, `people` text hasMany, `municipality` relationship, `source` select, `catalogedAt` date index); top-level `curatedFields` (select hasMany readOnly, mesmo trio C230) e `takenOn` (date readOnly index); `searchText` (textarea readOnly).
+- **Admin do `ArchivePhoto.ts`:** `useAsTitle: 'alt'`, `defaultColumns: ['alt', 'takenOn', 'catalog.scene', 'catalog.municipality', 'catalog.source']`, `listSearchableFields: ['searchText']` (opção suportada no Payload 3.82, `node_modules/payload/dist/collections/config/types.d.ts:405`, implementada com `like`).
+- **`resolveContentPieceMunicipalityId`** (`src/utilities/content/contentPieceCataloging.ts:159-182`): passa a delegar ao resolver compartilhado, mesma assinatura e comportamento (spec atual `tests/unit/contentPieceCataloging.unit.spec.ts:56-83` continua verde).
+- **`assertLocalVisionEndpoint`** (`scripts/lib/cli.mjs`): host privado (loopback/RFC1918/CGNAT `100.64/10`/`.local`/`.internal`/host sem ponto) com escape explícito `ARCHIVE_VISION_ALLOW_REMOTE=1` via `isTruthyEnv`; erro nomeado cita o escape.
+
+### Dados → forma (se aplicável)
+
+Não aplicável — a intenção declara que catalogação não é métrica. Não há score/confiança numérico na ficha; o recibo do lote é operacional (processadas/puladas/falharam por motivo e contagem por `source`), nunca um agregado de leitura.
+
+## Decisões de engenharia
+
+### D1 — Engine de visão
+
+- **Opções:** A) VLM local/self-hosted atrás de um endpoint OpenAI-compatible configurado por env | B) API de terceiro (DeepInfra, já contratada para ASR/chat) | C) híbrido local+terceiro | D) modelo ONNX in-process (transformers.js).
+- **Recomendação:** A — `ARCHIVE_VISION_BASE_URL` + `ARCHIVE_VISION_MODEL` obrigatórios no `--apply` e `ARCHIVE_VISION_API_KEY` opcional (servidores locais normalmente não têm chave); exemplo operacional: Ollama/llama.cpp/vLLM na workstation com GPU, alcançável pelo tailnet no mesmo padrão do ML do Immich (`IMMICH_MACHINE_LEARNING_URL=http://100.94.122.26:3003`). Sem vendor pin: o contrato é o protocolo, não o fornecedor.
+- **Rejeitadas:** B porque manda PII/rostos de cidadãos a terceiro sem decisão explícita e contrato (guardrail de produto); C porque ainda exterioriza a foto sensível e paga a complexidade de dois caminhos sem ganho de v1; D porque a qualidade para 6,5k fotos e a dependência pesada não se pagam, e o repo não tem esse runtime.
+- **Gatilho de revisita:** se a qualidade local não fechar o aceite no canário, reabre B/C com decisão explícita de PII — é o que a intenção manda.
+
+### D2 — Guardrail de localidade do engine
+
+- **Opções:** A) `assertLocalVisionEndpoint` em `scripts/lib/cli.mjs` + unit da função pura | B) só documentar a env no runbook | C) checar apenas dentro do parser de argv.
+- **Recomendação:** A — host privado (loopback, RFC1918, CGNAT `100.64/10` — o tailnet da workstation, sufixos `.local`/`.internal`, host sem ponto como `host.docker.internal`) com escape explícito `ARCHIVE_VISION_ALLOW_REMOTE=1`; o `--apply` soma engine configurado + `ARCHIVE_CATALOG_CONFIRM=1` fora de dev local + `TEQO_ENV`/S3 (guardas C231, `scripts/ingest-flickr-archive.mjs:245-259`). `cli.mjs` é o dono dos guardas de CLI (C155/C231).
+- **Rejeitadas:** B porque um typo na base URL mandaria foto de cidadão para um endpoint público em silêncio; C porque a guarda não ficaria unit-pinada nem reutilizável pelo runbook.
+- **Recibo:** o recibo registra `engineScope: local|remote` (host e modelo, nunca a chave) para o escape nunca ser invisível.
+
+### D3 — Fronteira de módulos
+
+- **Opções:** A) contrato puro em `src/lib/archivePhotoCatalog.ts` + pipeline Payload em `src/utilities/flickr/archivePhotoCatalog.ts` + client HTTP em `scripts/lib/archiveVisionApi.mjs` + CLI `scripts/catalog-archive-photos.mjs` | B) tudo no pipeline `src/utilities/flickr/` (client embutido) | C) job in-app disparado por `after()`/fila.
+- **Recomendação:** A — a subpasta `src/utilities/flickr/` já é o dono do archivePhoto server-side (C231, `archivePhotoIngest.ts`), e o client de rede com retry/backoff mora em `scripts/lib/` como o `flickrApi.mjs`; isso mantém o contrato puro testável sem Payload e o pipeline testável com analisador stub. O analisador é **injetado** pela CLI (nada em `src/` importa `scripts/`).
+- **Rejeitadas:** B porque esconde o transporte na camada errada e perde o pin de CI dos módulos de script; C porque não existe fila Payload no repo e 6,5k fotos em lote pertencem ao container de manutenção (precedente C231), não ao `after()` de um upload.
+- **Depth check:** não há módulo profundo de VLM a reusar; o pipeline reusa `downloadPrivateMediaToFile`, `withPayloadTransaction`, o gazetteer/catálogos existentes e o esqueleto de CLI — nenhum pass-through novo é criado.
+
+### D4 — Schema e curadoria que vence a IA
+
+- **Opções:** A) grupo `catalog` dentro do próprio `archivePhoto` + `curatedFields` espelhando C230 (vocabulário no lib + marcação no hook do admin + fresh-read no writer) | B) reusar o pipeline/job do `contentPiece` com campos novos na peça | C) tratar curadoria por trigger de banco / tabela paralela.
+- **Recomendação:** A — a ficha e os campos pertencem à foto (C231 é o dono do shape); o vocabulário fica num literal único no lib (como `CONTENT_PIECE_CURATED_FIELDS`, `src/lib/contentPiece.ts:111-137`), o hook `beforeChange` marca o campo alterado quando `req.user` existe e `!req.context.archivePhotoCatalog`, e o writer re-lê a linha **dentro** da transação e só escreve campo ausente de `curatedFields` (molde `contentPieceJob.ts:285-323`). `alt` entra no vocabulário: o catálogo só o refina quando o humano nunca editou.
+- **Rejeitadas:** B porque peça e foto têm inputs e ciclos de vida distintos — seria um segundo engine de catalogação disfarçado; C porque tira a regra do admin e do padrão C230, onde o humano vê o que está curado.
+- **Escape de sistema:** a escrita do pipeline usa `context: { archivePhotoCatalog: true }` (precedente `src/utilities/googleCalendarSync.ts:508`) e bypass documentado; a ingestão C231 (sem `req.user`) não marca nada.
+
+### D5 — Semântica de estado e idempotência
+
+- **Opções:** A) `catalog.catalogedAt` (date) como chave de idempotência + `catalog.source = ai | metadata | none` | B) persistir estado `failed` no registro | C) marcar `catalogedAt` só quando `source != none`.
+- **Recomendação:** A — `--apply` seleciona só `catalog.catalogedAt` nulo; falha de HTTP/parse **não escreve**, vira falha nomeada no recibo e é retentada na próxima execução; `source=ai` quando o modelo contribuiu com algum campo, `metadata` quando só o determinístico de texto (município/temas/pessoas por menção exata no catálogo) produziu algo, `none` quando nada havia a propor. `none` grava `catalogedAt` porque "nada a propor" é estado final honesto (reprocesso futuro é `--refresh`, adiado). Reexecução reporta "puladas (já catalogadas)" e `--verify` é read-only: total, catalogadas por `source`, pendentes — sai 1 se houver pendente.
+- **Rejeitadas:** B porque falha não é estado de catálogo; poluiria a ficha e esconderia que a próxima execução resolve; C porque faria o engine re-chamar a mesma foto para sempre.
+- **Concorrência:** o fresh-read na transação também confere `catalogedAt` antes de escrever; nada é duplicado.
+
+### D6 — Busca interna (admin stock) e resolver de município
+
+- **Opções:** A) superfície stock do admin — `useAsTitle`, `defaultColumns`, `listSearchableFields: ['searchText']` e filtros nativos sobre `catalog.municipality`, `catalog.scene`, `catalog.themes`, `catalog.people`, `takenOn`, `catalog.source` + índice GIN trgm | B) list view/fila de revisão própria | C) busca externa.
+- **Recomendação:** A — a intenção fixa a superfície existente (Impeccable B, sem tela nova); o índice trgm sobre `searchText` é o mesmo contrato do `ContentPiece` (`20260923_032714_add_content_piece.ts:100`); a leitura continua no gate da Comunicação (`access/archivePhotos.ts` intocado) e nada é exposto ao público.
+- **Rejeitadas:** B porque é escopo que só nasce se o gate pedir (o design nasceria no gate); C porque não há caso de uso externo.
+- **Sub-decisão registrada — resolver de município:** A) extrair o lookup para `src/utilities/municipality/municipalityMentionResolver.ts` com `contentPieceCataloging.resolveContentPieceMunicipalityId` delegando e o pipeline novo importando o genérico (recomendada) | B) importar `resolveContentPieceMunicipalityId` do módulo de peças no pipeline de fotos | C) duplicar a regra conservadora. **Rejeitadas:** B porque acopla a foto ao módulo de conteúdo e puxa as dependências de IA da peça para um caminho que não as quer; C porque a mesma regra em dois lugares diverge (twin). A preserva a assinatura pública e os testes atuais.
+
+### D7 — Testes e invariantes de CI
+
+- **Opções:** A) unit para todo o puro + client mockado + guardas, e int sobre `teqo_wt232_test` com analisador stub; sem e2e novo (OPS72, superfície admin stock) | B) e2e novo para a curadoria no admin | C) confiar em teste manual do lote.
+- **Recomendação:** A — unit de `src/lib/archivePhotoCatalog.ts`, do client (`fetchImpl` mockado: retry em transitório, 4xx terminal, timeout/abort, erro nomeado sem chave), do parser/recibo (`archiveCatalogPlan.mjs`) e da guarda de endpoint; int com fixture JPEG (`tests/helpers/archivePhotoFixture.ts`) e stub: catalogação grava campos, curadoria vence, falha não escreve, `source` ai/metadata/none, `searchText`/`takenOn` derivados, access inalterado (molde `tests/int/archivePhotoIngest.int.spec.ts:69-227`). Os dois novos módulos de `scripts/lib` entram em `SCRIPTS_SPEC_PINNED` (`scripts/lib/test-affected-core.mjs:31-110`) para o invariante `ciSkipInvariants` fechar a closure. Rede de provider real nunca entra na suíte.
+- **Rejeitadas:** B porque a superfície é o admin stock e o repo não mantém e2e de admin como cobertura de domínio (OPS72); C porque os guardas e a idempotência são exatamente o que não pode falhar em silêncio no lote.
+
+### D8 — Migração
+
+- **Opções:** A) uma migration aditiva gerada por `pnpm migrate:create add_archive_photo_catalog` (colunas do grupo, join tables de `themes`/`people`/`curatedFields`, índices e GIN trgm) | B) confiar em `push` | C) escrever o SQL à mão.
+- **Recomendação:** A — `push: false` em todo lugar (`src/payload.config.ts:173`); com o snapshot reparado pelo C231, o diff gerado deve ser limpo; mesmo assim o diff é **revisado à mão** contra o snapshot antes do commit (nenhum objeto existente recriado), aplicado localmente e nunca reescrito depois de mergeado. `down` derruba colunas/tabelas/índices. O `pnpm build` roda `payload migrate` e o deploy aplica no alvo.
+- **Rejeitadas:** B porque é a regra de segurança do repo; C porque o gerador é a fonte do diff e o snapshot agora está confiável.
+
+## Fases verificáveis
+
+1. **Fase 1 — Tracer: contrato puro + schema + curadoria** (quota ~0,5 dia): `src/lib/archivePhotoCatalog.ts`, migration, campos/hooks/admin do `ArchivePhoto.ts`; unit do puro; int de 1 foto com stub (grava, curadoria vence, `source`/`catalogedAt`). Gate: `pnpm gate:fast`.
+2. **Fase 2 — Pipeline Payload** (quota ~0,5 dia): `src/utilities/flickr/archivePhotoCatalog.ts` + resolver extraído com delegação; int completo (falha não escreve, ai/metadata/none, searchText/takenOn, access). Gate: `pnpm gate:fast` + int local.
+3. **Fase 3 — Client + CLI + guardas + recibo** (quota ~0,5 dia): `archiveVisionApi.mjs`, `archiveCatalogPlan.mjs`, `catalog-archive-photos.mjs`, `assertLocalVisionEndpoint`, `pnpm archive:catalog`, pins de CI; unit do client/parser/guarda; plan/`--verify` contra o banco do worktree. Gate: `pnpm gate:fast`.
+4. **Fase 4 — Busca/admin + entrega + lote** (quota ~0,5 dia): colunas/busca do admin, `.env.example`, `.gitignore`, runbook C232, changelog, plano no commit; `pnpm push`; CI high-risk (migration → curated e2e); deploy staging primeiro e canário `--limit` antes do lote completo (processamento ~4–10h de máquina, fora do appetite de código).
+
+## Rabbit holes / Não escopo (engenharia)
+
+- Embedding/vetor para busca semântica: guarda-se a descrição textual agora; a infra de C229 decide depois (gatilho abaixo).
+- Reprocessamento por versão de prompt (`--refresh`) e refresh de metadados EXIF→GPS: adiados com gatilho.
+- Fila/job in-app, retomada por página no CLI (a seleção por `catalogedAt` já é a retomada), paralelismo no engine.
+- OCR dedicado além do VLM, saneamento/recorte de imagem, álbum público (C233) e biometria (C234).
+- Fila/galeria de revisão própria: só se o gate pedir, com design nascido no gate.
+- Segundo engine de catalogação, segundo cadastro de pessoa, provider `openai/*` no app (OPS123), qualquer superfície pública.
+
+## Riscos e mitigação
+
+1. **Qualidade do VLM local abaixo do aceite** — canário `--limit` no staging com amostra revisada por humano antes do lote; curadoria vence e `--refresh` fica adiado; gatilho de revisita reabre B/C de D1 com decisão explícita de PII.
+2. **Engine fora do ar no meio do lote** — falha por foto é isolada e nomeada (HTTP/parse), nada é escrito, o lote não cai e a próxima execução retenta só as pendentes.
+3. **Tamanho/tempo do lote** — 6,5k chamadas sequenciais (~2–5s cada) ≈ 4–10h; roda no container de manutenção com volume de recibos, `--limit` para canário e reexecução idempotente; o recibo fecha o tempo real.
+4. **CI high-risk** — `src/collections/`, `src/migrations/` e `tests/helpers/` disparam unit/int full + e2e curado (`E2E_CURATED_SPECS`, `scripts/lib/e2e-affected-manifest.mjs:24-54`); `src/utilities/flickr` e o lib novo sem entry caem no fallback home smoke (`:396-404`); `src/utilities/municipality` idem; `src/utilities/access` não é tocado. Manter o PR focado para o orçamento de CI.
+5. **Snapshot de migration** — C231 reparou a cadeia; ainda assim o diff gerado é revisado à mão contra o snapshot e aplicado no banco do worktree antes do PR; migrations já entregues nunca são editadas.
+6. **Migração de schema não pré-aprovada** — apesar do `Status: aprovado` e do `--auto`, este plano inclui migração: o fluxo para para confirmação humana antes de executá-la; o deploy aplica migrations antes do build do runner (OPS66) e o alvo segue staging-primeiro.
+7. **PII/rostos** — engine local + guarda de endpoint fail-closed (D2); o recibo não carrega imagem nem chave, só ids/contagens; nenhum caminho publica ou manda bytes para terceiro.
+8. **`alt` sobrescrito** — só quando nunca curado; o alt do C231 é título/placeholder, então o refino é ganho; se a assessoria editar, o campo entra em `curatedFields` e nunca mais é tocado.
+
+## Adiado com gatilho
+
+- **Embedding/vetor** para busca semântica: gatilho = infra de C229 ou busca por termo não bastar.
+- **`--refresh` por versão de prompt/engine**: gatilho = iteração de qualidade ou troca de engine.
+- **EXIF→GPS para município**: gatilho = cobertura de geotag mostrar ganho material além do texto.
+- **OCR dedicado**: gatilho = `visibleText` do VLM insuficiente para faixas/placas.
+- **Fila/job in-app e re-catalogação sob demanda**: gatilho = necessidade real de reprocessar da ficha.
+- **Álbum público (C233) e biometria (C234); superfície de revisão própria (Impeccable B)**: gatilho = gate.
+
+## Aceite de engenharia
+
+- [ ] Aceite de produto da intenção ainda coberto: ficha pré-catalogada revisável, busca interna por local/data/atividade/pessoa/termo, curadoria vence a IA, recibo honesto e idempotente, nenhum nome inventado, nada público.
+- [ ] Invariantes AGENTS/engineering-standards: sem segundo engine/cadastro de pessoa, `openai/*` fora do app, `req` threaded em toda escrita multi-collection, `import 'server-only'` no módulo Payload, bypass com comentário, identificadores em inglês e copy pt-BR.
+- [ ] Testes de domínio previstos (unit/int) onde write paths e curadoria mudam; sem e2e novo (OPS72) documentado; pins de CI atualizados (`SCRIPTS_SPEC_PINNED`, manifest).
+- [ ] Migration aditiva gerada, revisada à mão, aplicada local e registrada; runbook C232, `.env.example`, `.gitignore` e changelog entregues; impl plan no commit.
+- [ ] Guarda de localidade e confirmação de escrita provados por unit; `--apply` exige engine configurado e falha fechado sem `ARCHIVE_CATALOG_CONFIRM` fora de dev local.
+- [ ] Gates: `pnpm gate:fast`, suíte int, e2e curado no CI, deploy staging-primeiro com canário antes do lote.
+
+## Self-score (decision-quality)
+
+1. Decisões caras com rejeitadas? **Sim** — D1–D8 têm opções, recomendação e rejeitadas explícitas.
+2. Abordagem cabe no appetite? **Sim** — ~2 dias eng divididos em 4 fases de ~0,5 dia; o processamento é máquina, não código.
+3. Rabbit holes nomeados? **Sim** — embedding, `--refresh`, GPS, OCR dedicado, fila, C233/C234, superfície própria.
+4. Depth check: reusa shells/helpers? **Sim** — `downloadPrivateMediaToFile`, `withPayloadTransaction`, gazetteer/catálogos, `scripts/lib/cli.mjs`, esqueleto de CLI/recibo C231, padrão `curatedFields` C230.
+5. Intenção permanece satisfeita? **Sim** — a engenharia escolheu módulos e engine sob os guardrails de produto, sem reescrever outcome.
+
+**Score: 5/5.**
diff --git a/package.json b/package.json
index d443a795..bef95c2c 100644
--- a/package.json
+++ b/package.json
@@ -35,6 +35,7 @@
"media:recover": "cross-env NODE_OPTIONS=\"--no-deprecation --import=tsx/esm --import=./scripts/seed-loader.mjs\" node scripts/recover-media.mjs",
"reels:ingest": "cross-env NODE_OPTIONS=\"--no-deprecation --import=tsx/esm --import=./scripts/seed-loader.mjs\" node scripts/reels-ingest.mjs",
"flickr:import": "cross-env NODE_OPTIONS=\"--no-deprecation --import=tsx/esm --import=./scripts/seed-loader.mjs\" node scripts/ingest-flickr-archive.mjs",
+ "archive:catalog": "cross-env NODE_OPTIONS=\"--no-deprecation --import=tsx/esm --import=./scripts/seed-loader.mjs\" node scripts/catalog-archive-photos.mjs",
"db:seed:minimal": "cross-env NODE_OPTIONS=\"--no-deprecation --import=tsx/esm --import=./scripts/seed-loader.mjs\" node scripts/seed-minimal.mjs",
"campaign:staging:test-account": "cross-env NODE_OPTIONS=\"--no-deprecation --import=tsx/esm --import=./scripts/seed-loader.mjs\" node scripts/bootstrap-staging-test-account.mjs",
"db:check:push-chain": "node scripts/check-push-chain.mjs",
diff --git a/scripts/catalog-archive-photos.mjs b/scripts/catalog-archive-photos.mjs
new file mode 100644
index 00000000..e369005e
--- /dev/null
+++ b/scripts/catalog-archive-photos.mjs
@@ -0,0 +1,284 @@
+/**
+ * C232 — catalogues the private photo archive (C231) with the local vision
+ * engine: each pending `archivePhoto` is downloaded from the private storage,
+ * downscaled, analysed by an OpenAI-compatible VLM on the private network and
+ * written back as a revisable ficha — the assessoria's curation always wins and
+ * re-running converges ("processadas / puladas / falharam com motivo"). Nothing
+ * is published and no photo leaves the private network without the explicit
+ * remote escape; the model never names people.
+ *
+ * Modes:
+ * pnpm archive:catalog plan/dry-run (default) — lists the
+ * pending queue; no engine call, no write
+ * pnpm archive:catalog --apply catalogues the pending photos; requires
+ * ARCHIVE_CATALOG_CONFIRM=1 outside local
+ * dev, the complete S3_* envs and the
+ * vision engine envs
+ * pnpm archive:catalog --verify read-only inventory of the catalogue
+ *
+ * Options: --limit (canary), --out (receipts, default `data/archive`),
+ * --help.
+ *
+ * Guards: --apply refuses a non-local/production target without the intent flag
+ * (C155) and demands the declared TEQO_ENV matching the exact database name
+ * (C195/C231); a remote target also demands the complete S3_* set; the vision
+ * endpoint must be on the private network unless ARCHIVE_VISION_ALLOW_REMOTE=1
+ * is declared (PII guardrail). The engine config lives in ARCHIVE_VISION_*
+ * (env only, never the repo).
+ *
+ * Runbook: on the homeserver, inside the compose maintenance service with the
+ * stack env file — see docs/ops/teqo-1313-deploy.md.
+ */
+import { mkdir, writeFile } from 'node:fs/promises'
+import { dirname, join } from 'node:path'
+
+import { getPayload } from 'payload'
+
+import {
+ ARCHIVE_VISION_SYSTEM_PROMPT,
+ buildArchiveVisionPrompt,
+ parseArchiveVisionOutput,
+} from '../src/lib/archivePhotoCatalog.ts'
+
+import {
+ ARCHIVE_CATALOG_DEFAULT_OUT_DIR,
+ archiveCatalogReportStamp,
+ formatArchiveCatalogInventory,
+ formatArchiveCatalogReport,
+ parseArchiveCatalogCliArgs,
+ summarizeArchiveCatalogInventory,
+ summarizeArchiveCatalogResults,
+} from './lib/archiveCatalogPlan.mjs'
+import { analyzeArchivePhotoVision } from './lib/archiveVisionApi.mjs'
+import {
+ TEQO_ENV_DATABASE_BY_ENV,
+ assertEnvironmentDatabaseTarget,
+ assertLocalVisionEndpoint,
+ assertWriteConfirm,
+ databaseTarget,
+ dieWithLabel,
+ isPrivateVisionHost,
+ loadCliEnv,
+ mirroredMediaRequired,
+} from './lib/cli.mjs'
+
+loadCliEnv()
+
+const die = dieWithLabel('archive:catalog')
+
+const WRITE_CONFIRM_FLAG = 'ARCHIVE_CATALOG_CONFIRM'
+
+const envLines = Object.entries(TEQO_ENV_DATABASE_BY_ENV)
+ .map(([environment, database]) => `${environment} (${database})`)
+ .join(' | ')
+
+const HELP = `
+Uso: pnpm archive:catalog [opções]
+
+Pré-cataloga as fotos do acervo privado (C231) com o engine de visão local: por
+foto, legenda/descrição, atividade/cena, texto visível, temas do vocabulário
+existente, município pelo gazetteer e pessoas públicas do catálogo curado.
+A curadoria da assessoria vence: campo curado nunca é sobrescrito. Reexecutar
+converge ("processadas / puladas / falharam com motivo") e nada é publicado.
+
+Modos (mutuamente exclusivos; o default é o plano):
+ (sem flag) plano/dry-run — lista a fila pendente; sem engine nem escrita
+ --apply cataloga as fotos pendentes (engine local + escrita transacional)
+ --verify inventário read-only da catalogação (sem engine)
+
+Opções:
+ --limit --apply: processa no máximo n fotos (canário); no plano, só limita a prévia
+ --out diretório dos recibos (default ${ARCHIVE_CATALOG_DEFAULT_OUT_DIR})
+ --help esta ajuda
+
+Ambiente:
+ ARCHIVE_VISION_BASE_URL endpoint OpenAI-compatible do engine (ex.: http://100.94.122.26:11434/v1)
+ ARCHIVE_VISION_MODEL modelo de visão (ex.: qwen2.5vl:7b)
+ ARCHIVE_VISION_API_KEY opcional, quando o servidor local exige chave
+ DATABASE_URL alvo (obrigatório em todos os modos)
+
+--apply em alvo não-local/produção exige ${WRITE_CONFIRM_FLAG}=1, TEQO_ENV=${envLines}
+casando o banco exato, as quatro envs S3_* e o engine na rede privada (host
+público exige ARCHIVE_VISION_ALLOW_REMOTE=1). O plano e o --verify são read-only.
+`
+
+/** Renders the configured engine without calling it (plan/verify banner). */
+const configuredEngine = () => {
+ const raw = String(process.env.ARCHIVE_VISION_BASE_URL ?? '').trim()
+ if (raw === '') return null
+ try {
+ const host = new URL(raw).hostname
+ return {
+ host,
+ scope: isPrivateVisionHost(host) ? 'local' : 'remote',
+ model: String(process.env.ARCHIVE_VISION_MODEL ?? '').trim() || '(não definido)',
+ }
+ } catch {
+ return null
+ }
+}
+
+const writeReport = async (options, report, suffix = '') => {
+ const stamp = archiveCatalogReportStamp(report.runAt)
+ const reportPath = join(options.out, 'reports', `archive-catalog-${stamp}${suffix}.json`)
+ await mkdir(dirname(reportPath), { recursive: true })
+ await writeFile(reportPath, JSON.stringify(report, null, 2))
+ return reportPath
+}
+
+async function main() {
+ const options = parseArchiveCatalogCliArgs(process.argv.slice(2))
+ if (options.help) {
+ console.log(HELP)
+ process.exit(0)
+ }
+
+ if (!process.env.DATABASE_URL) die('DATABASE_URL não definida; recusando continuar.')
+ const mode = options.apply ? 'apply' : options.verify ? 'verify' : 'plan'
+ const runAt = new Date().toISOString()
+ console.log(`[archive:catalog] alvo: ${databaseTarget()} | modo: ${mode}`)
+
+ let engine = configuredEngine()
+ if (mode === 'apply') {
+ assertWriteConfirm({
+ label: 'archive:catalog',
+ flag: WRITE_CONFIRM_FLAG,
+ command: 'pnpm archive:catalog --apply',
+ })
+ assertEnvironmentDatabaseTarget()
+ const { resolveS3StorageEnv } = await import('../src/utilities/mediaStorage.ts')
+ const storage = resolveS3StorageEnv(process.env)
+ if (mirroredMediaRequired({ s3Enabled: storage.enabled })) {
+ die(
+ 'escrita em produção/remoto exige mídia espelhada: configure S3_BUCKET, S3_ENDPOINT, S3_ACCESS_KEY_ID e S3_SECRET_ACCESS_KEY; sem elas o acervo não está acessível no alvo.',
+ )
+ }
+ const { scope, host } = assertLocalVisionEndpoint()
+ const model = String(process.env.ARCHIVE_VISION_MODEL ?? '').trim()
+ if (model === '') {
+ die('ARCHIVE_VISION_MODEL ausente — informe o modelo de visão (ex.: qwen2.5vl:7b).')
+ }
+ engine = { host, scope, model }
+ }
+
+ const config = (await import('../src/payload.config.ts')).default
+ const { listArchivePhotos } = await import('../src/utilities/flickr/archivePhotoIngest.ts')
+ const { catalogArchivePhoto, listArchivePhotoCatalogQueue } =
+ await import('../src/utilities/flickr/archivePhotoCatalog.ts')
+ const payload = await getPayload({ config })
+ const startedAt = Date.now()
+
+ if (mode === 'verify') {
+ const rows = await listArchivePhotos(payload)
+ const inventory = summarizeArchiveCatalogInventory(rows)
+ const report = {
+ runAt,
+ mode,
+ target: databaseTarget(),
+ engine,
+ ...inventory,
+ durationMs: Date.now() - startedAt,
+ }
+ const reportPath = await writeReport(options, report, '-verify')
+ for (const line of formatArchiveCatalogInventory(inventory)) console.log(line)
+ console.log(`\n[archive:catalog] recibo JSON: ${reportPath}`)
+ if (inventory.missingFilename.length > 0) {
+ die(
+ `${inventory.missingFilename.length} foto(s) sem arquivo armazenado — acervo inconsistente.`,
+ )
+ }
+ if (inventory.pending > 0) {
+ die(`${inventory.pending} foto(s) ainda pendentes de catalogação — rode o --apply.`)
+ }
+ process.exit(0)
+ }
+
+ if (mode === 'plan') {
+ // The plan always reports the TRUE pending count; `--limit` only caps the
+ // preview (the apply mode is where it caps the work).
+ const pending = await listArchivePhotoCatalogQueue({ payload })
+ const report = {
+ runAt,
+ mode,
+ target: databaseTarget(),
+ engine,
+ pending: pending.length,
+ photos: pending.slice(0, options.limit ?? 50).map((item) => ({
+ flickrId: item.flickrId,
+ title: item.title,
+ takenAt: item.takenAt,
+ })),
+ durationMs: Date.now() - startedAt,
+ }
+ const reportPath = await writeReport(options, report)
+ for (const line of formatArchiveCatalogReport(report)) console.log(line)
+ console.log(`\n[archive:catalog] recibo JSON: ${reportPath}`)
+ process.exit(0)
+ }
+
+ const queue = await listArchivePhotoCatalogQueue({ payload, limit: options.limit })
+ console.log(`[archive:catalog] fila: ${queue.length} foto(s) pendente(s)`)
+
+ /**
+ * The engine seam: one HTTP call + the fail-closed parse against the closed
+ * vocabularies. A transport error or an off-contract answer throws and the
+ * pipeline turns it into a named failure — never a write.
+ */
+ const analyze = async ({ imageDataUrl }) => {
+ const content = await analyzeArchivePhotoVision({
+ baseUrl: process.env.ARCHIVE_VISION_BASE_URL,
+ model: process.env.ARCHIVE_VISION_MODEL,
+ apiKey: process.env.ARCHIVE_VISION_API_KEY,
+ imageDataUrl,
+ prompt: buildArchiveVisionPrompt(),
+ systemPrompt: ARCHIVE_VISION_SYSTEM_PROMPT,
+ })
+ const suggestion = parseArchiveVisionOutput(content)
+ if (!suggestion) {
+ throw new Error('resposta do engine fora do contrato JSON da catalogação')
+ }
+ return suggestion
+ }
+
+ const results = []
+ for (const item of queue) {
+ const result = await catalogArchivePhoto({ payload, item, analyze })
+ results.push({ flickrId: item.flickrId, ...result })
+ const detail =
+ result.status === 'cataloged'
+ ? ` (${result.source})`
+ : result.status === 'failed'
+ ? ` [${result.stage}]: ${result.error}`
+ : ''
+ console.log(`[archive:catalog] ${result.status}${detail} ${item.flickrId}`)
+ }
+
+ const summary = summarizeArchiveCatalogResults(results)
+ const report = {
+ runAt,
+ mode,
+ target: databaseTarget(),
+ engine,
+ summary,
+ results: results.map((result) => ({
+ flickrId: result.flickrId,
+ status: result.status,
+ source: result.source ?? null,
+ stage: result.stage ?? null,
+ error: result.error ?? null,
+ })),
+ durationMs: Date.now() - startedAt,
+ }
+ const reportPath = await writeReport(options, report)
+ for (const line of formatArchiveCatalogReport(report)) console.log(line)
+ console.log(`\n[archive:catalog] recibo JSON: ${reportPath}`)
+
+ if (summary.cataloged === 0 && results.length > 0) {
+ die('nenhuma foto foi catalogada — falhas listadas no recibo.')
+ }
+ process.exit(0)
+}
+
+main().catch((error) => {
+ die(error?.message || String(error))
+})
diff --git a/scripts/lib/archiveCatalogPlan.mjs b/scripts/lib/archiveCatalogPlan.mjs
new file mode 100644
index 00000000..d8c528c1
--- /dev/null
+++ b/scripts/lib/archiveCatalogPlan.mjs
@@ -0,0 +1,195 @@
+/**
+ * C232 — pure planning/reporting of the photo-archive cataloguing: the argv
+ * parser, the run summaries (by outcome and by source), the catalogue
+ * `--verify` inventory and the human lines + JSON receipt. No I/O of its own:
+ * the queue, the engine and the Payload writes arrive as parameters, so the
+ * unit spec drives everything with fakes.
+ */
+
+const USAGE = 'uso: `pnpm archive:catalog [--apply|--verify] [--limit ] [--out ]`'
+
+export const ARCHIVE_CATALOG_DEFAULT_OUT_DIR = 'data/archive'
+
+export const archiveCatalogReportStamp = (runAt) => String(runAt).replace(/[:.]/g, '-')
+
+/**
+ * `pnpm archive:catalog` argv parser — pure, so the unit spec pins it (the CLI
+ * owns the exit and the help text). The default mode is the plan/dry-run;
+ * errors carry the usage line.
+ *
+ * @param {string[]} [argv]
+ * @returns {{ apply: boolean, verify: boolean, limit: number | null, out: string, help: boolean }}
+ */
+export const parseArchiveCatalogCliArgs = (argv = process.argv.slice(2)) => {
+ const options = {
+ apply: false,
+ verify: false,
+ limit: null,
+ out: ARCHIVE_CATALOG_DEFAULT_OUT_DIR,
+ help: false,
+ }
+
+ for (let index = 0; index < argv.length; index += 1) {
+ const arg = argv[index]
+ const value = () => {
+ const next = argv[++index]
+ if (next === undefined || next.startsWith('--')) {
+ throw new Error(`faltou valor para ${arg} — ${USAGE}.`)
+ }
+ return next
+ }
+ if (arg === '--help' || arg === '-h') options.help = true
+ else if (arg === '--apply') options.apply = true
+ else if (arg === '--verify') options.verify = true
+ else if (arg === '--limit') options.limit = Number(value())
+ else if (arg === '--out') options.out = value()
+ else throw new Error(`argumento desconhecido: ${arg} — ${USAGE}.`)
+ }
+
+ if (options.help) return options
+ if (options.apply && options.verify) {
+ throw new Error(`--apply e --verify são mutuamente exclusivos — ${USAGE}.`)
+ }
+ if (options.limit !== null && (!Number.isInteger(options.limit) || options.limit < 1)) {
+ throw new Error('--limit deve ser >= 1.')
+ }
+ if (options.out.split(/[\\/]/).includes('..')) {
+ throw new Error('--out não pode escapar do diretório do repo (sem "..").')
+ }
+ return options
+}
+
+const ARCHIVE_CATALOG_SOURCE_KEYS = ['ai', 'metadata', 'none']
+
+const emptyBySource = () => ({ ai: 0, metadata: 0, none: 0 })
+
+/**
+ * Aggregates one run: what was catalogued (and from where), what was skipped
+ * (catalogued before the run) and what failed with stage+reason.
+ *
+ * @param {Array<{ flickrId: string, status: string, source?: string | null, stage?: string | null, error?: string | null }>} results
+ */
+export const summarizeArchiveCatalogResults = (results) => {
+ const bySource = emptyBySource()
+ const failures = []
+ let cataloged = 0
+ let skipped = 0
+ let failed = 0
+
+ for (const result of results) {
+ if (result.status === 'cataloged') {
+ cataloged += 1
+ if (ARCHIVE_CATALOG_SOURCE_KEYS.includes(result.source)) bySource[result.source] += 1
+ } else if (result.status === 'skipped') {
+ skipped += 1
+ } else {
+ failed += 1
+ failures.push({
+ flickrId: result.flickrId,
+ stage: result.stage ?? null,
+ error: result.error ?? null,
+ })
+ }
+ }
+
+ return { cataloged, skipped, failed, bySource, failures }
+}
+
+/**
+ * The `--verify` inventory over the stored rows (read-only): coverage of the
+ * catalogue by source, the pending count (the honest gap this check fails on,
+ * mirroring the `flickr:import --verify` missing-file rule) and the rows
+ * without a stored filename (the one broken state C231 already checks).
+ *
+ * @param {any[]} rows
+ */
+export const summarizeArchiveCatalogInventory = (rows) => {
+ const bySource = emptyBySource()
+ const missingFilename = []
+ let cataloged = 0
+ let pending = 0
+ let withoutScene = 0
+ let withoutMunicipality = 0
+
+ for (const row of rows) {
+ if (!row?.filename) missingFilename.push(String(row?.flickrId ?? ''))
+ const catalog = row?.catalog ?? {}
+ if (!catalog.catalogedAt) {
+ pending += 1
+ continue
+ }
+ cataloged += 1
+ if (ARCHIVE_CATALOG_SOURCE_KEYS.includes(catalog.source)) bySource[catalog.source] += 1
+ if (!catalog.scene) withoutScene += 1
+ if (catalog.municipality === undefined || catalog.municipality === null)
+ withoutMunicipality += 1
+ }
+
+ return {
+ total: rows.length,
+ cataloged,
+ pending,
+ bySource,
+ withoutScene,
+ withoutMunicipality,
+ missingFilename,
+ }
+}
+
+const REPORT_LABEL = '[archive:catalog]'
+
+const engineLine = (engine) =>
+ engine ? `${REPORT_LABEL} engine: ${engine.host} (${engine.model}, ${engine.scope})` : null
+
+/**
+ * Human lines for stdout; the JSON file keeps the full report (the CLI already
+ * announced target/mode before booting Payload). Failures are never hidden —
+ * each one names its stage and reason.
+ *
+ * @param {Record} report
+ * @returns {string[]}
+ */
+export const formatArchiveCatalogReport = (report) => {
+ const label = REPORT_LABEL
+ const lines = []
+
+ const engine = engineLine(report.engine)
+ if (engine) lines.push(engine)
+ if (report.mode === 'plan') {
+ lines.push(`${label} pendentes na fila: ${report.pending}`)
+ }
+ if (report.summary) {
+ const { cataloged, skipped, failed, bySource } = report.summary
+ lines.push(
+ `${label} resultado: processadas: ${cataloged} · puladas (já catalogadas): ${skipped} · falharam: ${failed}`,
+ )
+ lines.push(
+ `${label} origem: IA: ${bySource.ai} · metadados: ${bySource.metadata} · nada a propor: ${bySource.none}`,
+ )
+ }
+ lines.push(`${label} tempo: ${(report.durationMs / 1000).toFixed(1)}s`)
+
+ for (const failure of report.summary?.failures ?? []) {
+ lines.push(
+ ` - ${failure.flickrId} (${failure.stage ?? 'desconhecido'}): ${failure.error ?? 'erro'}`,
+ )
+ }
+ return lines
+}
+
+/** `--verify` human lines (catalogue inventory, read-only). */
+export const formatArchiveCatalogInventory = (inventory) => {
+ const label = REPORT_LABEL
+ const lines = [
+ `${label} inventário: ${inventory.total} foto(s) · catalogadas: ${inventory.cataloged} · pendentes: ${inventory.pending}`,
+ `${label} origem: IA: ${inventory.bySource.ai} · metadados: ${inventory.bySource.metadata} · nada a propor: ${inventory.bySource.none}`,
+ `${label} cobertura: sem cena: ${inventory.withoutScene} · sem município: ${inventory.withoutMunicipality}`,
+ ]
+ if (inventory.missingFilename.length > 0) {
+ lines.push(`${label} sem arquivo armazenado: ${inventory.missingFilename.join(', ')}`)
+ }
+ if (inventory.pending > 0) {
+ lines.push(`${label} ainda pendentes de catalogação: ${inventory.pending}`)
+ }
+ return lines
+}
diff --git a/scripts/lib/archiveVisionApi.mjs b/scripts/lib/archiveVisionApi.mjs
new file mode 100644
index 00000000..7909ef5b
--- /dev/null
+++ b/scripts/lib/archiveVisionApi.mjs
@@ -0,0 +1,145 @@
+/**
+ * C232 — thin OpenAI-compatible vision client for the photo-archive
+ * cataloguing: one POST to `{base}/chat/completions` with the image as a
+ * `data:` URL, plain `fetch` (injectable), timeout and retry with backoff for
+ * transient failures only. There is no SDK dependency and no vendor pinned:
+ * any local server speaking the protocol (Ollama, llama.cpp, vLLM) fits.
+ *
+ * The API key, when the server has one, travels in the `Authorization` header
+ * and never enters logs or receipts. A 4xx answer is terminal (a wrong model
+ * name must not be retried); 429/5xx/network/timeout retry.
+ */
+
+const DEFAULT_TIMEOUT_MS = 90_000
+const DEFAULT_RETRY_ATTEMPTS = 3
+const DEFAULT_RETRY_BASE_DELAY_MS = 2_000
+const DEFAULT_MAX_OUTPUT_TOKENS = 900
+const DEFAULT_TEMPERATURE = 0.2
+
+export class ArchiveVisionError extends Error {
+ /**
+ * @param {string} message
+ * @param {{ status?: number | null }} [options]
+ */
+ constructor(message, { status = null } = {}) {
+ super(message)
+ this.name = 'ArchiveVisionError'
+ this.status = status
+ }
+}
+
+/** HTTP 429/5xx, aborts and network errors retry; a 4xx refusal never does. */
+const isRetryable = (error) => {
+ if (error instanceof ArchiveVisionError) {
+ return error.status === 429 || (error.status !== null && error.status >= 500)
+ }
+ return true
+}
+
+/**
+ * One vision call returning the raw assistant content (the caller parses it
+ * against the closed vocabularies). `imageDataUrl` is the prepared JPEG as a
+ * `data:image/jpeg;base64,…` string; the original never leaves the machine
+ * that prepared it.
+ *
+ * @param {{
+ * baseUrl?: string | null,
+ * model?: string | null,
+ * apiKey?: string | null,
+ * imageDataUrl: string,
+ * prompt: string,
+ * systemPrompt: string,
+ * fetchImpl?: typeof fetch,
+ * timeoutMs?: number,
+ * retryAttempts?: number,
+ * retryBaseDelayMs?: number,
+ * maxOutputTokens?: number,
+ * temperature?: number,
+ * sleep?: (ms: number) => Promise,
+ * }} options
+ * @returns {Promise}
+ */
+export const analyzeArchivePhotoVision = async ({
+ baseUrl,
+ model,
+ apiKey = '',
+ imageDataUrl,
+ prompt,
+ systemPrompt,
+ fetchImpl = fetch,
+ timeoutMs = DEFAULT_TIMEOUT_MS,
+ retryAttempts = DEFAULT_RETRY_ATTEMPTS,
+ retryBaseDelayMs = DEFAULT_RETRY_BASE_DELAY_MS,
+ maxOutputTokens = DEFAULT_MAX_OUTPUT_TOKENS,
+ temperature = DEFAULT_TEMPERATURE,
+ sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
+}) => {
+ const base = String(baseUrl ?? '')
+ .trim()
+ .replace(/\/+$/, '')
+ if (base === '') throw new ArchiveVisionError('ARCHIVE_VISION_BASE_URL ausente.')
+ const chosenModel = String(model ?? '').trim()
+ if (chosenModel === '') throw new ArchiveVisionError('ARCHIVE_VISION_MODEL ausente.')
+ if (typeof imageDataUrl !== 'string' || !imageDataUrl.startsWith('data:image/')) {
+ throw new ArchiveVisionError('imagem preparada inválida (esperado data: URL).')
+ }
+
+ const headers = { 'Content-Type': 'application/json', Accept: 'application/json' }
+ const key = String(apiKey ?? '').trim()
+ if (key !== '') headers.Authorization = `Bearer ${key}`
+
+ const body = JSON.stringify({
+ model: chosenModel,
+ temperature,
+ max_tokens: maxOutputTokens,
+ stream: false,
+ messages: [
+ { role: 'system', content: systemPrompt },
+ {
+ role: 'user',
+ content: [
+ { type: 'text', text: prompt },
+ { type: 'image_url', image_url: { url: imageDataUrl } },
+ ],
+ },
+ ],
+ })
+
+ for (let attempt = 1; ; attempt += 1) {
+ try {
+ const response = await fetchImpl(`${base}/chat/completions`, {
+ method: 'POST',
+ headers,
+ body,
+ signal: AbortSignal.timeout(timeoutMs),
+ })
+ if (!response.ok) {
+ // The provider's error body is operational gold ("model not found") —
+ // clipped into the receipt message; never the request, image or key.
+ let detail = ''
+ try {
+ detail = String(await response.text())
+ .replace(/\s+/g, ' ')
+ .trim()
+ .slice(0, 200)
+ } catch {
+ detail = ''
+ }
+ throw new ArchiveVisionError(`HTTP ${response.status}${detail ? `: ${detail}` : ''}`, {
+ status: response.status,
+ })
+ }
+ const parsed = await response.json().catch(() => {
+ throw new ArchiveVisionError('resposta do engine não é JSON.')
+ })
+ const content = parsed?.choices?.[0]?.message?.content
+ if (typeof content !== 'string' || content.trim() === '') {
+ throw new ArchiveVisionError('resposta do engine sem conteúdo de texto.')
+ }
+ return content
+ } catch (error) {
+ if (attempt >= retryAttempts || !isRetryable(error)) throw error
+ await sleep(retryBaseDelayMs * 2 ** (attempt - 1))
+ }
+ }
+}
diff --git a/scripts/lib/cli.mjs b/scripts/lib/cli.mjs
index 776e1277..e1081d83 100644
--- a/scripts/lib/cli.mjs
+++ b/scripts/lib/cli.mjs
@@ -319,6 +319,89 @@ export const assertWriteConfirm = ({ label, flag, command, hint = '' }) => {
)
}
+/**
+ * True when the host is reachable only from the private network: loopback,
+ * RFC1918, CGNAT/tailnet (`100.64/10`), link-local/ULA IPv6, `.local`/`.internal`
+ * suffixes or a single-label name (docker network). A public IP or domain is
+ * NOT private — it is exactly what the C232 guard refuses by default.
+ *
+ * @param {unknown} hostname
+ * @returns {boolean}
+ */
+export const isPrivateVisionHost = (hostname) => {
+ const host = String(hostname ?? '')
+ .trim()
+ .toLowerCase()
+ .replace(/^\[|\]$/g, '')
+ if (host === '') return false
+ // IPv6 literal (loopback/link-local/ULA). The `includes(':')` gate is what
+ // keeps a NAME starting with "fc"/"fd" (e.g. fdic.gov) from passing here —
+ // it must fall through to the domain checks below.
+ if (
+ host.includes(':') &&
+ (host === '::1' || host.startsWith('fe80:') || host.startsWith('fc') || host.startsWith('fd'))
+ ) {
+ return true
+ }
+ if (!host.includes('.')) return true
+ if (host.endsWith('.local') || host.endsWith('.internal')) return true
+
+ const parts = host.split('.')
+ if (parts.length !== 4 || parts.some((part) => !/^\d{1,3}$/.test(part))) return false
+ const octets = parts.map(Number)
+ if (octets.some((octet) => octet > 255)) return false
+ const [first, second] = octets
+ return (
+ first === 10 ||
+ first === 127 ||
+ (first === 192 && second === 168) ||
+ (first === 172 && second >= 16 && second <= 31) ||
+ (first === 100 && second >= 64 && second <= 127)
+ )
+}
+
+/**
+ * C232 — the vision engine reads the citizens' photos, so it must live on the
+ * private network: a public host is refused unless the run declares the
+ * `ARCHIVE_VISION_ALLOW_REMOTE=1` escape (the product guardrail is "PII/rostos
+ * não vão a terceiro sem decisão explícita e contrato"). Returns the scope so
+ * the receipt records which mode ran — the escape is never invisible.
+ *
+ * @param {{ baseUrl?: string | null, allowRemote?: boolean, label?: string }} [options]
+ * @returns {{ scope: 'local' | 'remote', host: string }}
+ */
+export const assertLocalVisionEndpoint = ({
+ baseUrl = process.env.ARCHIVE_VISION_BASE_URL,
+ allowRemote = isTruthyEnv(process.env.ARCHIVE_VISION_ALLOW_REMOTE),
+ label = 'archive:catalog',
+} = {}) => {
+ const raw = String(baseUrl ?? '').trim()
+ if (raw === '') {
+ dieWithLabel(label)(
+ 'ARCHIVE_VISION_BASE_URL ausente — configure o endpoint do engine de visão (ex.: http://100.94.122.26:11434/v1).',
+ )
+ }
+
+ let url
+ try {
+ url = new URL(raw)
+ } catch {
+ dieWithLabel(label)(`ARCHIVE_VISION_BASE_URL inválida: ${raw}`)
+ }
+ if (url.protocol !== 'http:' && url.protocol !== 'https:') {
+ dieWithLabel(label)(`ARCHIVE_VISION_BASE_URL deve ser http(s), não "${url.protocol}".`)
+ }
+
+ const host = url.hostname
+ if (isPrivateVisionHost(host)) return { scope: 'local', host }
+ if (allowRemote) return { scope: 'remote', host }
+
+ dieWithLabel(label)(
+ `ARCHIVE_VISION_BASE_URL aponta para host público "${host}" — as fotos do acervo (PII/rostos de cidadãos) não vão a terceiro sem decisão explícita e contrato.\n` +
+ ' Rode o engine na rede privada (LAN/tailnet) ou, ciente do risco, declare ARCHIVE_VISION_ALLOW_REMOTE=1.',
+ )
+}
+
/**
* Port for `next dev` (OPS40). Next's CLI resolves its port via commander's
* `.env('PORT')` BEFORE `@next/env` loads `.env.local`, so a `PORT` written by
diff --git a/scripts/lib/test-affected-core.mjs b/scripts/lib/test-affected-core.mjs
index 89351029..64c599f9 100644
--- a/scripts/lib/test-affected-core.mjs
+++ b/scripts/lib/test-affected-core.mjs
@@ -43,6 +43,8 @@ export const SCRIPTS_SPEC_PINNED = [
'scripts/lib/agent-pool-state.mjs',
'scripts/lib/agent-session.mjs',
'scripts/lib/ansi.mjs',
+ 'scripts/lib/archiveCatalogPlan.mjs',
+ 'scripts/lib/archiveVisionApi.mjs',
'scripts/lib/auto-unblock.mjs',
'scripts/lib/briefingContent.mjs',
'scripts/lib/briefingRender.mjs',
diff --git a/src/collections/ArchivePhoto.ts b/src/collections/ArchivePhoto.ts
index d6be5275..35dd1a0f 100644
--- a/src/collections/ArchivePhoto.ts
+++ b/src/collections/ArchivePhoto.ts
@@ -1,6 +1,20 @@
-import type { CollectionConfig } from 'payload'
+import type { CollectionBeforeValidateHook, CollectionConfig, Field } from 'payload'
import { ARCHIVE_PHOTO_SLUG } from '@/lib/archivePhoto'
+import {
+ ARCHIVE_PHOTO_CAPTION_MAX_LENGTH,
+ ARCHIVE_PHOTO_CATALOG_SOURCES,
+ ARCHIVE_PHOTO_CURATED_FIELDS,
+ ARCHIVE_PHOTO_DESCRIPTION_MAX_LENGTH,
+ ARCHIVE_PHOTO_SCENES,
+ ARCHIVE_PHOTO_VISIBLE_TEXT_MAX_LENGTH,
+ archivePhotoCatalogSourceLabels,
+ archivePhotoCuratedFieldLabels,
+ archivePhotoSearchText,
+ archivePhotoTakenOn,
+ changedArchivePhotoCuratedFields,
+} from '@/lib/archivePhotoCatalog'
+import { SPEECH_TOPICS } from '@/lib/speechFacets'
import { canReadArchivePhoto, payloadAdminOnly } from '@/utilities/campaignAccess'
/**
@@ -16,8 +30,186 @@ import { canReadArchivePhoto, payloadAdminOnly } from '@/utilities/campaignAcces
* (`archivePhotoAlt`); the remaining Flickr fields document provenance and feed
* the catalogue. The stored name is deterministic (`flickr-.`), so a
* re-run converges by overwriting the same object key.
+ *
+ * C232 adds the curated pre-cataloguing on these same rows: the `catalog` group
+ * (proposal + honest `source`/`catalogedAt` state), `curatedFields` (what the
+ * assessoria edited — the pipeline never overwrites it), `takenOn` (date facet
+ * derived from the Flickr wall clock) and `searchText` (the normalized haystack
+ * the admin list search matches).
*/
+const catalogGroup: Field = {
+ name: 'catalog',
+ type: 'group',
+ label: 'Pré-catalogação',
+ admin: {
+ description:
+ 'Proposta automática (IA + metadados). A assessoria revisa na ficha: o que ela editar entra em "Campos curados" e nunca é sobrescrito.',
+ },
+ fields: [
+ {
+ name: 'caption',
+ type: 'text',
+ label: 'Legenda',
+ maxLength: ARCHIVE_PHOTO_CAPTION_MAX_LENGTH,
+ },
+ {
+ name: 'description',
+ type: 'textarea',
+ label: 'Descrição',
+ maxLength: ARCHIVE_PHOTO_DESCRIPTION_MAX_LENGTH,
+ admin: {
+ description: 'Descrição semântica do que a foto mostra (não substitui a do Flickr).',
+ },
+ },
+ {
+ name: 'scene',
+ type: 'select',
+ label: 'Atividade/cena',
+ index: true,
+ options: ARCHIVE_PHOTO_SCENES.map((scene) => ({ value: scene.value, label: scene.label })),
+ },
+ {
+ name: 'visibleText',
+ type: 'textarea',
+ label: 'Texto visível',
+ maxLength: ARCHIVE_PHOTO_VISIBLE_TEXT_MAX_LENGTH,
+ admin: {
+ description: 'Texto legível na imagem (faixas, placas, banners).',
+ },
+ },
+ {
+ name: 'hasPeople',
+ type: 'checkbox',
+ label: 'Pessoas na cena',
+ admin: {
+ description: 'Presença de pessoas na foto — sem identificação de rosto (biometria é C234).',
+ },
+ },
+ {
+ name: 'themes',
+ type: 'select',
+ label: 'Temas',
+ hasMany: true,
+ index: true,
+ options: SPEECH_TOPICS.map((topic) => ({ value: topic.value, label: topic.label })),
+ },
+ {
+ name: 'people',
+ type: 'text',
+ hasMany: true,
+ label: 'Pessoas públicas',
+ admin: {
+ description:
+ 'Somente nomes do catálogo curado, mencionados no texto da foto; nunca inferidos de rosto.',
+ },
+ },
+ {
+ name: 'municipality',
+ type: 'relationship',
+ relationTo: 'municipality',
+ label: 'Município',
+ index: true,
+ admin: {
+ description: 'Quando o texto da foto aponta um município sem ambiguidade.',
+ },
+ },
+ {
+ name: 'source',
+ type: 'select',
+ label: 'Origem',
+ options: ARCHIVE_PHOTO_CATALOG_SOURCES.map((source) => ({
+ value: source,
+ label: archivePhotoCatalogSourceLabels[source],
+ })),
+ admin: {
+ readOnly: true,
+ description: 'IA = o modelo contribuiu; Metadados = só o texto derivou; Nada a propor.',
+ },
+ },
+ {
+ name: 'catalogedAt',
+ type: 'date',
+ label: 'Catalogada em',
+ index: true,
+ admin: {
+ readOnly: true,
+ description: 'Chave de idempotência: foto com data preenchida não é reprocessada.',
+ },
+ },
+ ],
+}
+
+/**
+ * C232 — the catalogue index the admin list uses: `takenOn` (date facet derived
+ * from the Flickr wall clock) and `searchText` (normalized haystack). When a
+ * request carries a user (an admin edit), the fields that actually changed are
+ * added to `curatedFields` — the cataloguing/hook never marks on system writes
+ * (`context.archivePhotoCatalog`, or no user at all).
+ */
+const deriveArchivePhotoCatalogIndex: CollectionBeforeValidateHook = async ({
+ data,
+ originalDoc,
+ req,
+}) => {
+ if (!data) return data
+
+ if (req.user && !req.context?.archivePhotoCatalog) {
+ const changed = changedArchivePhotoCuratedFields({ data, originalDoc })
+ if (changed.length > 0) {
+ const curated = new Set(originalDoc?.curatedFields ?? [])
+ for (const field of changed) curated.add(field)
+ data.curatedFields = [...curated]
+ }
+ }
+
+ const takenAt = data.takenAt ?? originalDoc?.takenAt ?? null
+ data.takenOn = archivePhotoTakenOn(takenAt)
+
+ const catalog = { ...(originalDoc?.catalog ?? {}), ...(data.catalog ?? {}) }
+ const rawMunicipality = catalog.municipality
+ const municipalityId =
+ typeof rawMunicipality === 'number'
+ ? rawMunicipality
+ : rawMunicipality && typeof rawMunicipality === 'object'
+ ? rawMunicipality.id
+ : null
+ const municipality =
+ municipalityId != null
+ ? await req.payload
+ .findByID({
+ collection: 'municipality',
+ id: municipalityId,
+ depth: 0,
+ select: { name: true },
+ // Intentional admin bypass: the município catalog is read-only geography.
+ overrideAccess: true,
+ req,
+ })
+ .catch(() => null)
+ : null
+
+ data.searchText = archivePhotoSearchText({
+ alt: data.alt ?? originalDoc?.alt,
+ title: data.title ?? originalDoc?.title,
+ description: data.description ?? originalDoc?.description,
+ catalogDescription: catalog.description,
+ caption: catalog.caption,
+ scene: catalog.scene,
+ visibleText: catalog.visibleText,
+ themes: catalog.themes,
+ people: catalog.people,
+ municipalityName: municipality?.name ?? null,
+ albumTitles: (data.albums ?? originalDoc?.albums ?? []).map(
+ (album: { title?: string | null }) => album?.title,
+ ),
+ tagNames: (data.tags ?? originalDoc?.tags ?? []).map(
+ (tag: { name?: string | null }) => tag?.name,
+ ),
+ })
+ return data
+}
+
export const ArchivePhoto: CollectionConfig = {
slug: ARCHIVE_PHOTO_SLUG,
labels: {
@@ -28,6 +220,9 @@ export const ArchivePhoto: CollectionConfig = {
group: 'Comunicação',
description:
'Originais e metadados do acervo de fotos do Flickr (conta depjorgesolla). Só abrem com login da campanha.',
+ useAsTitle: 'alt',
+ defaultColumns: ['alt', 'takenOn', 'catalog.scene', 'catalog.municipality', 'catalog.source'],
+ listSearchableFields: ['searchText'],
},
access: {
create: payloadAdminOnly,
@@ -35,6 +230,9 @@ export const ArchivePhoto: CollectionConfig = {
update: payloadAdminOnly,
delete: payloadAdminOnly,
},
+ hooks: {
+ beforeValidate: [deriveArchivePhotoCatalogIndex],
+ },
fields: [
{
name: 'flickrId',
@@ -57,6 +255,22 @@ export const ArchivePhoto: CollectionConfig = {
description: 'Descrição do arquivo para acessibilidade.',
},
},
+ catalogGroup,
+ {
+ name: 'curatedFields',
+ type: 'select',
+ label: 'Campos curados pela assessoria',
+ hasMany: true,
+ options: ARCHIVE_PHOTO_CURATED_FIELDS.map((value) => ({
+ value,
+ label: archivePhotoCuratedFieldLabels[value],
+ })),
+ admin: {
+ readOnly: true,
+ description:
+ 'O que a assessoria já editou; a catalogação automática nunca sobrescreve estes campos.',
+ },
+ },
{
name: 'title',
type: 'text',
@@ -89,6 +303,16 @@ export const ArchivePhoto: CollectionConfig = {
description: 'Data informada pelo Flickr, sem fuso (YYYY-MM-DD HH:MM:SS).',
},
},
+ {
+ name: 'takenOn',
+ type: 'date',
+ label: 'Dia da foto',
+ index: true,
+ admin: {
+ readOnly: true,
+ description: 'Derivado da data da foto (meio-dia UTC, sem fuso).',
+ },
+ },
{
name: 'postedAt',
type: 'text',
@@ -157,6 +381,16 @@ export const ArchivePhoto: CollectionConfig = {
type: 'text',
label: 'Licença (Flickr)',
},
+ {
+ name: 'searchText',
+ type: 'textarea',
+ label: 'Texto normalizado (busca)',
+ admin: {
+ readOnly: true,
+ description:
+ 'Tudo o que a busca da lista encontra, normalizado (sem acentos, minúsculas): legenda, texto visível, temas, pessoas, município, álbuns e tags.',
+ },
+ },
],
upload: true,
}
diff --git a/src/lib/archivePhotoCatalog.ts b/src/lib/archivePhotoCatalog.ts
new file mode 100644
index 00000000..5c741425
--- /dev/null
+++ b/src/lib/archivePhotoCatalog.ts
@@ -0,0 +1,506 @@
+/**
+ * C232 — pure contract of the AI pre-cataloguing of the photo archive: the
+ * closed scene vocabulary, the curated-field vocabulary (the same mechanism
+ * C230 persists on a content piece), the source states of a ficha, the vision
+ * output parser and the deterministic merge that decides what gets written.
+ * No I/O and no `server-only`: the collection hooks, the Payload pipeline, the
+ * CLI and the tests share this module.
+ *
+ * The rules encoded here are product rules: the model never names people (only
+ * the curated `publicFigureCatalog` matched against TEXT does, and the
+ * assessoria confirms on the ficha), the scene/themes are closed vocabularies
+ * (unknown tokens are dropped, never invented) and a failed call is not a
+ * state — it stays out of the row so the next run retries it.
+ */
+import { z } from 'zod'
+
+import { publicFigureCatalog } from '@/lib/publicFigureCatalog'
+import { SPEECH_TOPICS, resolveSpeechTopic, type SpeechTopic } from '@/lib/speechFacets'
+import { escapeRegExp, normalizeForSearch } from '@/lib/speechSearch'
+
+/** Closed vocabulary of atividade/cena (the facet C233 consumes). */
+export const ARCHIVE_PHOTO_SCENES = [
+ { value: 'plenaria', label: 'Plenária' },
+ { value: 'audiencia', label: 'Audiência' },
+ { value: 'reuniao', label: 'Reunião' },
+ { value: 'evento', label: 'Evento' },
+ { value: 'mobilizacao', label: 'Mobilização' },
+ { value: 'visita', label: 'Visita' },
+ { value: 'entrevista', label: 'Entrevista' },
+ { value: 'discurso', label: 'Discurso' },
+ { value: 'retrato', label: 'Retrato' },
+ { value: 'gabinete', label: 'Gabinete' },
+ { value: 'outro', label: 'Outro' },
+] as const
+
+export type ArchivePhotoScene = (typeof ARCHIVE_PHOTO_SCENES)[number]['value']
+
+/**
+ * Resolves a scene token (value or pt-BR label, accent/case insensitive) to its
+ * taxonomy entry. Fail-closed: unknown tokens return null.
+ */
+export const resolveArchivePhotoScene = (token: unknown): ArchivePhotoScene | null => {
+ if (typeof token !== 'string') return null
+ const key = normalizeForSearch(token).replace(/-/g, ' ')
+ if (!key) return null
+ const match = ARCHIVE_PHOTO_SCENES.find(
+ (scene) =>
+ normalizeForSearch(scene.value).replace(/-/g, ' ') === key ||
+ normalizeForSearch(scene.label) === key,
+ )
+ return match?.value ?? null
+}
+
+const archivePhotoSceneLabel = (value: ArchivePhotoScene): string =>
+ ARCHIVE_PHOTO_SCENES.find((scene) => scene.value === value)?.label ?? value
+
+/**
+ * The fields a human edit freezes: the cataloguing never writes a field listed
+ * in `curatedFields` (C230's mechanism, one literal per persisted field name).
+ */
+export const ARCHIVE_PHOTO_CURATED_FIELDS = [
+ 'alt',
+ 'caption',
+ 'description',
+ 'scene',
+ 'visibleText',
+ 'hasPeople',
+ 'themes',
+ 'people',
+ 'municipality',
+] as const
+
+export type ArchivePhotoCuratedField = (typeof ARCHIVE_PHOTO_CURATED_FIELDS)[number]
+
+/** pt-BR names of the curated fields for the admin's read-only chip list. */
+export const archivePhotoCuratedFieldLabels: Record = {
+ alt: 'Texto alternativo',
+ caption: 'Legenda',
+ description: 'Descrição',
+ scene: 'Atividade/cena',
+ visibleText: 'Texto visível',
+ hasPeople: 'Pessoas na cena',
+ themes: 'Temas',
+ people: 'Pessoas públicas',
+ municipality: 'Município',
+}
+
+/** Outcome of one photo: the model contributed, only metadata did, or nothing. */
+export const ARCHIVE_PHOTO_CATALOG_SOURCES = ['ai', 'metadata', 'none'] as const
+
+export type ArchivePhotoCatalogSource = (typeof ARCHIVE_PHOTO_CATALOG_SOURCES)[number]
+
+export const archivePhotoCatalogSourceLabels: Record = {
+ ai: 'IA',
+ metadata: 'Metadados',
+ none: 'Nada a propor',
+}
+
+export const ARCHIVE_PHOTO_CAPTION_MAX_LENGTH = 200
+export const ARCHIVE_PHOTO_DESCRIPTION_MAX_LENGTH = 600
+export const ARCHIVE_PHOTO_VISIBLE_TEXT_MAX_LENGTH = 1000
+const ARCHIVE_PHOTO_ALT_MAX_LENGTH = 300
+const ARCHIVE_PHOTO_PEOPLE_MAX = 8
+
+/** What one vision call proposes; every field can be empty (nothing to propose). */
+export type ArchivePhotoSuggestion = {
+ caption: string | null
+ description: string | null
+ scene: ArchivePhotoScene | null
+ visibleText: string | null
+ hasPeople: boolean | null
+ themes: SpeechTopic[]
+}
+
+const clip = (value: string | null, maximum: number): string | null => {
+ if (value === null) return null
+ const text = value.trim().slice(0, maximum).trim()
+ return text === '' ? null : text
+}
+
+/**
+ * Resolves the model's theme tokens against the existing taxonomy (value or
+ * pt-BR label); unknown tokens are dropped and duplicates collapse. Never
+ * invents a slug outside `SPEECH_TOPICS`.
+ */
+export const archivePhotoThemesFrom = (values: readonly unknown[]): SpeechTopic[] => {
+ const themes: SpeechTopic[] = []
+ for (const value of values) {
+ const entry = typeof value === 'string' ? resolveSpeechTopic(value) : null
+ if (entry && !themes.includes(entry.value)) themes.push(entry.value)
+ }
+ return themes
+}
+
+/**
+ * Names of the curated catalog mentioned in the TEXT (title, album, caption,
+ * visible text…). This is a reading of what is written — never of a face — and
+ * an unresolved or ambiguous value never becomes a name. Whole-word,
+ * accent/case insensitive, same normalization family as the catalog resolver.
+ */
+export const matchPublicFigureMentions = (text: string): string[] => {
+ const haystack = normalizeForSearch(text)
+ if (!haystack) return []
+
+ const mentioned: string[] = []
+ for (const entry of publicFigureCatalog) {
+ const needle = normalizeForSearch(entry.name)
+ if (!needle) continue
+ const pattern = new RegExp(`(^|[^a-z0-9])${escapeRegExp(needle)}([^a-z0-9]|$)`)
+ if (!pattern.test(haystack)) continue
+ if (!mentioned.includes(entry.name) && mentioned.length < ARCHIVE_PHOTO_PEOPLE_MAX) {
+ mentioned.push(entry.name)
+ }
+ }
+ return mentioned
+}
+
+const archiveVisionField = {
+ text: z.string().nullish().catch(null),
+ boolean: z.boolean().nullish().catch(null),
+}
+
+const archiveVisionOutputSchema = z
+ .object({
+ caption: archiveVisionField.text,
+ description: archiveVisionField.text,
+ scene: archiveVisionField.text,
+ visibleText: archiveVisionField.text,
+ hasPeople: archiveVisionField.boolean,
+ themes: z.array(z.unknown()).nullish().catch(null),
+ })
+ .passthrough()
+
+const parseJsonObject = (raw: string): unknown => {
+ const text = raw
+ .trim()
+ .replace(/^```(?:json)?/i, '')
+ .replace(/```$/, '')
+ .trim()
+ try {
+ return JSON.parse(text)
+ } catch {
+ return null
+ }
+}
+
+/**
+ * Fail-closed parser of one vision answer: a non-object (or unparsable) answer
+ * is null — the caller reports a named failure and retries next run. Inside a
+ * valid object each field degrades alone: an invalid scene or theme is
+ * dropped, never guessed.
+ */
+export const parseArchiveVisionOutput = (raw: unknown): ArchivePhotoSuggestion | null => {
+ const parsed = typeof raw === 'string' ? parseJsonObject(raw) : raw
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) return null
+ const result = archiveVisionOutputSchema.safeParse(parsed)
+ if (!result.success) return null
+
+ const data = result.data
+ return {
+ caption: clip(data.caption ?? null, ARCHIVE_PHOTO_CAPTION_MAX_LENGTH),
+ description: clip(data.description ?? null, ARCHIVE_PHOTO_DESCRIPTION_MAX_LENGTH),
+ scene: resolveArchivePhotoScene(data.scene),
+ visibleText: clip(data.visibleText ?? null, ARCHIVE_PHOTO_VISIBLE_TEXT_MAX_LENGTH),
+ hasPeople: data.hasPeople ?? null,
+ themes: archivePhotoThemesFrom(data.themes ?? []),
+ }
+}
+
+type ArchivePhotoSearchInput = {
+ alt?: string | null
+ title?: string | null
+ description?: string | null
+ catalogDescription?: string | null
+ caption?: string | null
+ scene?: ArchivePhotoScene | null
+ visibleText?: string | null
+ themes?: readonly SpeechTopic[] | null
+ people?: readonly string[] | null
+ municipalityName?: string | null
+ albumTitles?: readonly string[] | null
+ tagNames?: readonly string[] | null
+}
+
+/**
+ * The normalized haystack the admin list search matches (the same shape C199/
+ * C230 persist): what a person would type to find the photo — names, places,
+ * themes, what is written in it.
+ */
+export const archivePhotoSearchText = (input: ArchivePhotoSearchInput): string =>
+ normalizeForSearch(
+ [
+ input.alt ?? '',
+ input.title ?? '',
+ input.description ?? '',
+ input.catalogDescription ?? '',
+ input.caption ?? '',
+ input.scene ? archivePhotoSceneLabel(input.scene) : '',
+ input.visibleText ?? '',
+ ...(input.themes ?? []).map((theme) => resolveSpeechTopic(theme)?.label ?? theme),
+ ...(input.people ?? []),
+ input.municipalityName ?? '',
+ ...(input.albumTitles ?? []),
+ ...(input.tagNames ?? []),
+ ]
+ .map((value) => value.trim())
+ .filter(Boolean)
+ .join(' '),
+ )
+
+/**
+ * The date facet derived from the Flickr wall clock (`YYYY-MM-DD HH:MM:SS`):
+ * fixed at noon UTC so the admin never shows the previous day. Invalid input
+ * (or an impossible date) is null — never a guessed day.
+ */
+export const archivePhotoTakenOn = (takenAt: unknown): string | null => {
+ if (typeof takenAt !== 'string') return null
+ const match = /^(\d{4})-(\d{2})-(\d{2})(?:[ T]|$)/.exec(takenAt.trim())
+ if (!match) return null
+ const [, year, month, day] = match
+ const utc = Date.UTC(Number(year), Number(month) - 1, Number(day), 12)
+ const date = new Date(utc)
+ if (
+ date.getUTCFullYear() !== Number(year) ||
+ date.getUTCMonth() !== Number(month) - 1 ||
+ date.getUTCDate() !== Number(day)
+ ) {
+ return null
+ }
+ return date.toISOString()
+}
+
+const comparableCuratedValue = (field: ArchivePhotoCuratedField, value: unknown): unknown => {
+ if (field === 'municipality') {
+ if (typeof value === 'number') return value
+ if (value !== null && typeof value === 'object' && 'id' in (value as object)) {
+ return (value as { id: unknown }).id
+ }
+ return null
+ }
+ if (field === 'themes' || field === 'people') {
+ return Array.isArray(value)
+ ? value.filter((entry): entry is string => typeof entry === 'string' && entry.trim() !== '')
+ : []
+ }
+ if (field === 'hasPeople') {
+ return typeof value === 'boolean' ? value : null
+ }
+ return typeof value === 'string' ? value : null
+}
+
+/**
+ * The admin edit path marks which fields the assessoria touched: an incoming
+ * value that differs from the stored one (arrays normalized, clearing counts)
+ * enters `curatedFields`. Only runs for a request with a user — the system
+ * writes (ingest, cataloguing) never mark.
+ */
+export const changedArchivePhotoCuratedFields = ({
+ data,
+ originalDoc,
+}: {
+ data: Record | null | undefined
+ originalDoc: Record | null | undefined
+}): ArchivePhotoCuratedField[] => {
+ if (!data) return []
+ const catalog = data.catalog
+ const incomingCatalog =
+ catalog !== null && typeof catalog === 'object' ? (catalog as Record) : null
+ const originalCatalog = originalDoc?.catalog
+ const storedCatalog =
+ originalCatalog !== null && typeof originalCatalog === 'object'
+ ? (originalCatalog as Record)
+ : null
+
+ const changed: ArchivePhotoCuratedField[] = []
+ for (const field of ARCHIVE_PHOTO_CURATED_FIELDS) {
+ const incoming = field === 'alt' ? data.alt : incomingCatalog?.[field]
+ if (incoming === undefined) continue
+ const stored = field === 'alt' ? originalDoc?.alt : storedCatalog?.[field]
+ const before = comparableCuratedValue(field, stored)
+ const after = comparableCuratedValue(field, incoming)
+ if (JSON.stringify(before) !== JSON.stringify(after)) changed.push(field)
+ }
+ return changed
+}
+
+type ArchivePhotoCatalogValues = {
+ caption?: string
+ description?: string
+ scene?: ArchivePhotoScene
+ visibleText?: string
+ hasPeople?: boolean
+ themes?: SpeechTopic[]
+ people?: string[]
+ municipality?: number
+ source: ArchivePhotoCatalogSource
+ catalogedAt: string
+}
+
+export type ArchivePhotoCatalogWrite = {
+ data: {
+ alt?: string
+ catalog: ArchivePhotoCatalogValues
+ }
+ source: ArchivePhotoCatalogSource
+}
+
+/**
+ * The deterministic merge of one photo: proposed values (model + text
+ * metadata) fill only fields the assessoria never curated, and the source
+ * states what actually landed — `ai` when a model field was written,
+ * `metadata` when only the text-derived ones were, `none` when there was
+ * nothing to propose. `catalogedAt` is set on every outcome, so "nada a
+ * propor" is a final honest state instead of a silent retry loop.
+ */
+export const buildArchivePhotoCatalogWrite = ({
+ suggestion,
+ municipalityId,
+ mentionedPeople,
+ gazetteerThemes,
+ curatedFields,
+ currentCatalog,
+ currentAlt,
+ catalogedAt,
+}: {
+ suggestion: ArchivePhotoSuggestion | null
+ municipalityId: number | null
+ mentionedPeople: readonly string[]
+ gazetteerThemes: readonly SpeechTopic[]
+ curatedFields: readonly string[]
+ currentCatalog?: {
+ caption?: string | null
+ description?: string | null
+ scene?: ArchivePhotoScene | null
+ visibleText?: string | null
+ hasPeople?: boolean | null
+ themes?: SpeechTopic[] | null
+ people?: string[] | null
+ municipality?: number | null
+ } | null
+ currentAlt?: string | null
+ catalogedAt: string
+}): ArchivePhotoCatalogWrite => {
+ const curated = new Set(curatedFields)
+ const current: NonNullable = currentCatalog ?? {}
+
+ /** A proposed value that will be written: not curated, not blank/empty. */
+ const writes = (field: ArchivePhotoCuratedField, value: unknown): boolean =>
+ !curated.has(field) &&
+ value !== null &&
+ value !== undefined &&
+ !(typeof value === 'string' && value.trim() === '') &&
+ !(Array.isArray(value) && value.length === 0)
+
+ /**
+ * Kept curated value when the field is frozen (verbatim), otherwise the
+ * proposal normalized: blank strings and empty arrays are "nothing to
+ * propose", never a written value.
+ */
+ const pick = (
+ field: Key,
+ proposed: NonNullable<(typeof current)[Key]> | null | undefined,
+ ): NonNullable<(typeof current)[Key]> | undefined => {
+ if (curated.has(field)) {
+ const kept = current[field]
+ return kept === null || kept === undefined
+ ? undefined
+ : (kept as NonNullable<(typeof current)[Key]>)
+ }
+ if (proposed === null || proposed === undefined) return undefined
+ if (Array.isArray(proposed)) {
+ return proposed.length === 0 ? undefined : (proposed as NonNullable<(typeof current)[Key]>)
+ }
+ if (typeof proposed === 'string') {
+ const text = proposed.trim()
+ return text === '' ? undefined : (text as NonNullable<(typeof current)[Key]>)
+ }
+ return proposed as NonNullable<(typeof current)[Key]>
+ }
+
+ const aiThemes = suggestion?.themes ?? []
+ const themes = [...new Set([...aiThemes, ...gazetteerThemes])]
+ const people = [...new Set(mentionedPeople)]
+
+ const caption = suggestion?.caption ?? null
+ const written = {
+ caption: pick('caption', caption),
+ description: pick('description', suggestion?.description ?? null),
+ scene: pick('scene', suggestion?.scene ?? null),
+ visibleText: pick('visibleText', suggestion?.visibleText ?? null),
+ hasPeople: pick('hasPeople', suggestion?.hasPeople ?? null),
+ themes: pick('themes', themes.length > 0 ? themes : null),
+ people: pick('people', people.length > 0 ? people : null),
+ municipality: pick('municipality', municipalityId),
+ }
+
+ const modelWrote =
+ writes('caption', caption) ||
+ writes('description', suggestion?.description) ||
+ writes('scene', suggestion?.scene) ||
+ writes('visibleText', suggestion?.visibleText) ||
+ writes('hasPeople', suggestion?.hasPeople) ||
+ writes('themes', aiThemes)
+ const metadataWrote =
+ !modelWrote &&
+ (writes('municipality', municipalityId) ||
+ writes('people', people) ||
+ writes('themes', gazetteerThemes))
+ const source: ArchivePhotoCatalogSource = modelWrote ? 'ai' : metadataWrote ? 'metadata' : 'none'
+
+ // The AI refines the alt only from its OWN caption (never from human text):
+ // a curated caption leaves the alt exactly where it was.
+ const alt = curated.has('alt')
+ ? (currentAlt ?? undefined)
+ : curated.has('caption')
+ ? undefined
+ : (clip(caption, ARCHIVE_PHOTO_ALT_MAX_LENGTH) ?? undefined)
+
+ return {
+ data: {
+ ...(alt !== undefined ? { alt } : {}),
+ catalog: {
+ ...written,
+ source,
+ catalogedAt,
+ },
+ },
+ source,
+ }
+}
+
+const ARCHIVE_VISION_SCENE_LINES = ARCHIVE_PHOTO_SCENES.filter((scene) => scene.value !== 'outro')
+ .map((scene) => `${scene.value}=${scene.label}`)
+ .join('; ')
+
+/** The theme vocabulary is offered from its owner — no copied literal to drift. */
+const ARCHIVE_VISION_THEME_LINES = SPEECH_TOPICS.map(
+ ({ value, label }) => `${value}=${label}`,
+).join('; ')
+
+export const ARCHIVE_VISION_SYSTEM_PROMPT =
+ 'Você pré-cataloga fotos do acervo do deputado federal Jorge Solla (PT-BA) para uma base interna da campanha. ' +
+ 'Descreva apenas o que está visível na imagem: nunca invente lugar, data, evento, número ou fala. ' +
+ 'NUNCA identifique pessoas por rosto nem escreva nomes de pessoas (nem do deputado). ' +
+ 'Não escreva nomes de cidades: o local é resolvido por outra via. ' +
+ 'Responda SOMENTE com um objeto JSON válido, sem markdown e sem comentários.'
+
+/**
+ * The user prompt of one photo: the closed vocabularies the answer must use.
+ * The model is free to answer null/empty for anything it cannot see — the
+ * parser drops whatever leaves the vocabulary.
+ */
+export const buildArchiveVisionPrompt = (): string =>
+ [
+ 'Analise a foto e devolva um JSON com exatamente estas chaves:',
+ '{"caption": "legenda curta em português (máx. 200 caracteres)",',
+ ' "description": "uma ou duas frases factuais em português (máx. 600 caracteres)",',
+ ' "scene": "um dos valores de cena ou null",',
+ ' "visibleText": "texto legível de faixas, placas e banners ou null",',
+ ' "hasPeople": true, false ou null,',
+ ' "themes": ["zero ou mais valores de tema"]}',
+ '',
+ `Cenas: ${ARCHIVE_VISION_SCENE_LINES}; outro=Outro (use outro só se nenhuma se aplicar).`,
+ `Temas: ${ARCHIVE_VISION_THEME_LINES}.`,
+ 'Use null ou lista vazia quando não houver certeza; é melhor não propor do que inventar.',
+ ].join('\n')
diff --git a/src/lib/speechGazetteer.ts b/src/lib/speechGazetteer.ts
index 12a6372b..7db69e51 100644
--- a/src/lib/speechGazetteer.ts
+++ b/src/lib/speechGazetteer.ts
@@ -6,7 +6,7 @@ import {
type SpeechScope,
type SpeechTopic,
} from '@/lib/speechFacets'
-import { normalizeForSearch } from '@/lib/speechSearch'
+import { escapeRegExp, normalizeForSearch } from '@/lib/speechSearch'
/**
* Offline gazetteer pass of the speech facet classifier (C153): topic/scope
@@ -287,8 +287,6 @@ const SPEECH_SCOPE_TERMS: Record = {
],
}
-const escapeRegExp = (value: string): string => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
-
const containsTerm = (normalizedText: string, term: string): boolean =>
new RegExp(`(^|[^a-z0-9])${escapeRegExp(term)}($|[^a-z0-9])`).test(normalizedText)
diff --git a/src/lib/speechSearch.ts b/src/lib/speechSearch.ts
index 753aa488..5e861d52 100644
--- a/src/lib/speechSearch.ts
+++ b/src/lib/speechSearch.ts
@@ -16,6 +16,9 @@ export const normalizeForSearch = (value: string): string =>
.replace(/\s+/g, ' ')
.trim()
+/** Escapes a literal for a RegExp source; the whole-word matchers share it. */
+export const escapeRegExp = (value: string): string => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
+
type SpeechSearchableRecord = {
/** Normalized segment text persisted by the segment hook (C153). */
searchText?: string | null
diff --git a/src/migrations/20260926_132106_add_archive_photo_catalog.json b/src/migrations/20260926_132106_add_archive_photo_catalog.json
new file mode 100644
index 00000000..ebac31c8
--- /dev/null
+++ b/src/migrations/20260926_132106_add_archive_photo_catalog.json
@@ -0,0 +1,20337 @@
+{
+ "version": "7",
+ "dialect": "postgresql",
+ "tables": {
+ "public.users_roles": {
+ "name": "users_roles",
+ "schema": "",
+ "columns": {
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "enum_users_roles",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "users_roles_order_idx": {
+ "name": "users_roles_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "users_roles_parent_idx": {
+ "name": "users_roles_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "users_roles_parent_fk": {
+ "name": "users_roles_parent_fk",
+ "tableFrom": "users_roles",
+ "tableTo": "users",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.users_sessions": {
+ "name": "users_sessions",
+ "schema": "",
+ "columns": {
+ "_order": {
+ "name": "_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "_parent_id": {
+ "name": "_parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "id": {
+ "name": "id",
+ "type": "varchar",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "users_sessions_order_idx": {
+ "name": "users_sessions_order_idx",
+ "columns": [
+ {
+ "expression": "_order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "users_sessions_parent_id_idx": {
+ "name": "users_sessions_parent_id_idx",
+ "columns": [
+ {
+ "expression": "_parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "users_sessions_parent_id_fk": {
+ "name": "users_sessions_parent_id_fk",
+ "tableFrom": "users_sessions",
+ "tableTo": "users",
+ "columnsFrom": [
+ "_parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.users": {
+ "name": "users",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "email": {
+ "name": "email",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "reset_password_token": {
+ "name": "reset_password_token",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "reset_password_expiration": {
+ "name": "reset_password_expiration",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "salt": {
+ "name": "salt",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "hash": {
+ "name": "hash",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "login_attempts": {
+ "name": "login_attempts",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 0
+ },
+ "lock_until": {
+ "name": "lock_until",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "users_updated_at_idx": {
+ "name": "users_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "users_created_at_idx": {
+ "name": "users_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "users_email_idx": {
+ "name": "users_email_idx",
+ "columns": [
+ {
+ "expression": "email",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.campaign_user_sessions": {
+ "name": "campaign_user_sessions",
+ "schema": "",
+ "columns": {
+ "_order": {
+ "name": "_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "_parent_id": {
+ "name": "_parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "id": {
+ "name": "id",
+ "type": "varchar",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "campaign_user_sessions_order_idx": {
+ "name": "campaign_user_sessions_order_idx",
+ "columns": [
+ {
+ "expression": "_order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_user_sessions_parent_id_idx": {
+ "name": "campaign_user_sessions_parent_id_idx",
+ "columns": [
+ {
+ "expression": "_parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "campaign_user_sessions_parent_id_fk": {
+ "name": "campaign_user_sessions_parent_id_fk",
+ "tableFrom": "campaign_user_sessions",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "_parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.campaign_user": {
+ "name": "campaign_user",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "contact_id": {
+ "name": "contact_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "avatar_id": {
+ "name": "avatar_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "role": {
+ "name": "role",
+ "type": "enum_campaign_user_role",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'leader'"
+ },
+ "visibility": {
+ "name": "visibility",
+ "type": "enum_campaign_user_visibility",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'carteira'"
+ },
+ "editing": {
+ "name": "editing",
+ "type": "enum_campaign_user_editing",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'carteira'"
+ },
+ "phone": {
+ "name": "phone",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "email": {
+ "name": "email",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "username": {
+ "name": "username",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "reset_password_token": {
+ "name": "reset_password_token",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "reset_password_expiration": {
+ "name": "reset_password_expiration",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "salt": {
+ "name": "salt",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "hash": {
+ "name": "hash",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "login_attempts": {
+ "name": "login_attempts",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 0
+ },
+ "lock_until": {
+ "name": "lock_until",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "campaign_user_contact_idx": {
+ "name": "campaign_user_contact_idx",
+ "columns": [
+ {
+ "expression": "contact_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_user_avatar_idx": {
+ "name": "campaign_user_avatar_idx",
+ "columns": [
+ {
+ "expression": "avatar_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_user_phone_idx": {
+ "name": "campaign_user_phone_idx",
+ "columns": [
+ {
+ "expression": "phone",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_user_updated_at_idx": {
+ "name": "campaign_user_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_user_created_at_idx": {
+ "name": "campaign_user_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_user_email_idx": {
+ "name": "campaign_user_email_idx",
+ "columns": [
+ {
+ "expression": "email",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_user_username_idx": {
+ "name": "campaign_user_username_idx",
+ "columns": [
+ {
+ "expression": "username",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "campaign_user_contact_id_contact_id_fk": {
+ "name": "campaign_user_contact_id_contact_id_fk",
+ "tableFrom": "campaign_user",
+ "tableTo": "contact",
+ "columnsFrom": [
+ "contact_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "campaign_user_avatar_id_media_id_fk": {
+ "name": "campaign_user_avatar_id_media_id_fk",
+ "tableFrom": "campaign_user",
+ "tableTo": "media",
+ "columnsFrom": [
+ "avatar_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.campaign_web_authn_credential": {
+ "name": "campaign_web_authn_credential",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "credential_id": {
+ "name": "credential_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "public_key": {
+ "name": "public_key",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "counter": {
+ "name": "counter",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "transports": {
+ "name": "transports",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "device_label": {
+ "name": "device_label",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "last_used_at": {
+ "name": "last_used_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "campaign_web_authn_credential_user_idx": {
+ "name": "campaign_web_authn_credential_user_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_web_authn_credential_credential_id_idx": {
+ "name": "campaign_web_authn_credential_credential_id_idx",
+ "columns": [
+ {
+ "expression": "credential_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_web_authn_credential_updated_at_idx": {
+ "name": "campaign_web_authn_credential_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_web_authn_credential_created_at_idx": {
+ "name": "campaign_web_authn_credential_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "campaign_web_authn_credential_user_id_campaign_user_id_fk": {
+ "name": "campaign_web_authn_credential_user_id_campaign_user_id_fk",
+ "tableFrom": "campaign_web_authn_credential",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.notification": {
+ "name": "notification",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "recipient_id": {
+ "name": "recipient_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "type": {
+ "name": "type",
+ "type": "enum_notification_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "payload": {
+ "name": "payload",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "municipality_id": {
+ "name": "municipality_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "read_at": {
+ "name": "read_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "notification_recipient_idx": {
+ "name": "notification_recipient_idx",
+ "columns": [
+ {
+ "expression": "recipient_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "notification_type_idx": {
+ "name": "notification_type_idx",
+ "columns": [
+ {
+ "expression": "type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "notification_municipality_idx": {
+ "name": "notification_municipality_idx",
+ "columns": [
+ {
+ "expression": "municipality_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "notification_read_at_idx": {
+ "name": "notification_read_at_idx",
+ "columns": [
+ {
+ "expression": "read_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "notification_updated_at_idx": {
+ "name": "notification_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "notification_created_at_idx": {
+ "name": "notification_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "notification_recipient_id_campaign_user_id_fk": {
+ "name": "notification_recipient_id_campaign_user_id_fk",
+ "tableFrom": "notification",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "recipient_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "notification_municipality_id_municipality_id_fk": {
+ "name": "notification_municipality_id_municipality_id_fk",
+ "tableFrom": "notification",
+ "tableTo": "municipality",
+ "columnsFrom": [
+ "municipality_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.push_subscription": {
+ "name": "push_subscription",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "endpoint": {
+ "name": "endpoint",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "p256dh": {
+ "name": "p256dh",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "auth": {
+ "name": "auth",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "expiration_time": {
+ "name": "expiration_time",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "consent_id": {
+ "name": "consent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "consent_content_hash": {
+ "name": "consent_content_hash",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "consented_at": {
+ "name": "consented_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_agent": {
+ "name": "user_agent",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "push_subscription_user_idx": {
+ "name": "push_subscription_user_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "push_subscription_endpoint_idx": {
+ "name": "push_subscription_endpoint_idx",
+ "columns": [
+ {
+ "expression": "endpoint",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "push_subscription_consent_idx": {
+ "name": "push_subscription_consent_idx",
+ "columns": [
+ {
+ "expression": "consent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "push_subscription_updated_at_idx": {
+ "name": "push_subscription_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "push_subscription_created_at_idx": {
+ "name": "push_subscription_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "push_subscription_user_id_campaign_user_id_fk": {
+ "name": "push_subscription_user_id_campaign_user_id_fk",
+ "tableFrom": "push_subscription",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "push_subscription_consent_id_consent_id_fk": {
+ "name": "push_subscription_consent_id_consent_id_fk",
+ "tableFrom": "push_subscription",
+ "tableTo": "consent",
+ "columnsFrom": [
+ "consent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.campaign_invite": {
+ "name": "campaign_invite",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "token_hash": {
+ "name": "token_hash",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "leadership_id": {
+ "name": "leadership_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "kind": {
+ "name": "kind",
+ "type": "enum_campaign_invite_kind",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "used_at": {
+ "name": "used_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "revoked_at": {
+ "name": "revoked_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_by_id": {
+ "name": "created_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "campaign_invite_token_hash_idx": {
+ "name": "campaign_invite_token_hash_idx",
+ "columns": [
+ {
+ "expression": "token_hash",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_invite_leadership_idx": {
+ "name": "campaign_invite_leadership_idx",
+ "columns": [
+ {
+ "expression": "leadership_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_invite_kind_idx": {
+ "name": "campaign_invite_kind_idx",
+ "columns": [
+ {
+ "expression": "kind",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_invite_expires_at_idx": {
+ "name": "campaign_invite_expires_at_idx",
+ "columns": [
+ {
+ "expression": "expires_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_invite_used_at_idx": {
+ "name": "campaign_invite_used_at_idx",
+ "columns": [
+ {
+ "expression": "used_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_invite_revoked_at_idx": {
+ "name": "campaign_invite_revoked_at_idx",
+ "columns": [
+ {
+ "expression": "revoked_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_invite_created_by_idx": {
+ "name": "campaign_invite_created_by_idx",
+ "columns": [
+ {
+ "expression": "created_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_invite_updated_at_idx": {
+ "name": "campaign_invite_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_invite_created_at_idx": {
+ "name": "campaign_invite_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "leadership_kind_idx": {
+ "name": "leadership_kind_idx",
+ "columns": [
+ {
+ "expression": "leadership_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "kind",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "campaign_invite_leadership_id_leadership_id_fk": {
+ "name": "campaign_invite_leadership_id_leadership_id_fk",
+ "tableFrom": "campaign_invite",
+ "tableTo": "leadership",
+ "columnsFrom": [
+ "leadership_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "campaign_invite_created_by_id_campaign_user_id_fk": {
+ "name": "campaign_invite_created_by_id_campaign_user_id_fk",
+ "tableFrom": "campaign_invite",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "created_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.campaign_vote_summary_snapshot": {
+ "name": "campaign_vote_summary_snapshot",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "day": {
+ "name": "day",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "scope_key": {
+ "name": "scope_key",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'statewide'"
+ },
+ "staff_vote_total_central": {
+ "name": "staff_vote_total_central",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "campaign_vote_summary_snapshot_day_idx": {
+ "name": "campaign_vote_summary_snapshot_day_idx",
+ "columns": [
+ {
+ "expression": "day",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_vote_summary_snapshot_scope_key_idx": {
+ "name": "campaign_vote_summary_snapshot_scope_key_idx",
+ "columns": [
+ {
+ "expression": "scope_key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_vote_summary_snapshot_updated_at_idx": {
+ "name": "campaign_vote_summary_snapshot_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_vote_summary_snapshot_created_at_idx": {
+ "name": "campaign_vote_summary_snapshot_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "day_scopeKey_idx": {
+ "name": "day_scopeKey_idx",
+ "columns": [
+ {
+ "expression": "day",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "scope_key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.municipality_strengths": {
+ "name": "municipality_strengths",
+ "schema": "",
+ "columns": {
+ "_order": {
+ "name": "_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "_parent_id": {
+ "name": "_parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "id": {
+ "name": "id",
+ "type": "varchar",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "text": {
+ "name": "text",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "municipality_strengths_order_idx": {
+ "name": "municipality_strengths_order_idx",
+ "columns": [
+ {
+ "expression": "_order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_strengths_parent_id_idx": {
+ "name": "municipality_strengths_parent_id_idx",
+ "columns": [
+ {
+ "expression": "_parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "municipality_strengths_parent_id_fk": {
+ "name": "municipality_strengths_parent_id_fk",
+ "tableFrom": "municipality_strengths",
+ "tableTo": "municipality",
+ "columnsFrom": [
+ "_parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.municipality_risks": {
+ "name": "municipality_risks",
+ "schema": "",
+ "columns": {
+ "_order": {
+ "name": "_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "_parent_id": {
+ "name": "_parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "id": {
+ "name": "id",
+ "type": "varchar",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "text": {
+ "name": "text",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "municipality_risks_order_idx": {
+ "name": "municipality_risks_order_idx",
+ "columns": [
+ {
+ "expression": "_order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_risks_parent_id_idx": {
+ "name": "municipality_risks_parent_id_idx",
+ "columns": [
+ {
+ "expression": "_parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "municipality_risks_parent_id_fk": {
+ "name": "municipality_risks_parent_id_fk",
+ "tableFrom": "municipality_risks",
+ "tableTo": "municipality",
+ "columnsFrom": [
+ "_parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.municipality": {
+ "name": "municipality",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "slug": {
+ "name": "slug",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "kind": {
+ "name": "kind",
+ "type": "enum_municipality_kind",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "city": {
+ "name": "city",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "region": {
+ "name": "region",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "ibge_code": {
+ "name": "ibge_code",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "tse_city_code": {
+ "name": "tse_city_code",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "zone_number": {
+ "name": "zone_number",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "priority": {
+ "name": "priority",
+ "type": "enum_municipality_priority",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'normal'"
+ },
+ "engagement_level": {
+ "name": "engagement_level",
+ "type": "enum_municipality_engagement_level",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "level_note": {
+ "name": "level_note",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "level_changed_at": {
+ "name": "level_changed_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "expected_votes_pessimistic": {
+ "name": "expected_votes_pessimistic",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "expected_votes_central": {
+ "name": "expected_votes_central",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "expected_votes_optimistic": {
+ "name": "expected_votes_optimistic",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "political_trend_status": {
+ "name": "political_trend_status",
+ "type": "enum_municipality_political_trend_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "political_trend_note": {
+ "name": "political_trend_note",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "political_trend_recorded_by_id": {
+ "name": "political_trend_recorded_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "political_trend_recorded_at": {
+ "name": "political_trend_recorded_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "dobradinha_notes": {
+ "name": "dobradinha_notes",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "next_steps": {
+ "name": "next_steps",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "budget_notes": {
+ "name": "budget_notes",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_update_at": {
+ "name": "last_update_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "municipality_name_idx": {
+ "name": "municipality_name_idx",
+ "columns": [
+ {
+ "expression": "name",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_slug_idx": {
+ "name": "municipality_slug_idx",
+ "columns": [
+ {
+ "expression": "slug",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_kind_idx": {
+ "name": "municipality_kind_idx",
+ "columns": [
+ {
+ "expression": "kind",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_city_idx": {
+ "name": "municipality_city_idx",
+ "columns": [
+ {
+ "expression": "city",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_region_idx": {
+ "name": "municipality_region_idx",
+ "columns": [
+ {
+ "expression": "region",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_ibge_code_idx": {
+ "name": "municipality_ibge_code_idx",
+ "columns": [
+ {
+ "expression": "ibge_code",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_tse_city_code_idx": {
+ "name": "municipality_tse_city_code_idx",
+ "columns": [
+ {
+ "expression": "tse_city_code",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_zone_number_idx": {
+ "name": "municipality_zone_number_idx",
+ "columns": [
+ {
+ "expression": "zone_number",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_priority_idx": {
+ "name": "municipality_priority_idx",
+ "columns": [
+ {
+ "expression": "priority",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_engagement_level_idx": {
+ "name": "municipality_engagement_level_idx",
+ "columns": [
+ {
+ "expression": "engagement_level",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_level_changed_at_idx": {
+ "name": "municipality_level_changed_at_idx",
+ "columns": [
+ {
+ "expression": "level_changed_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_political_trend_political_trend_recorded_by_idx": {
+ "name": "municipality_political_trend_political_trend_recorded_by_idx",
+ "columns": [
+ {
+ "expression": "political_trend_recorded_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_last_update_at_idx": {
+ "name": "municipality_last_update_at_idx",
+ "columns": [
+ {
+ "expression": "last_update_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_updated_at_idx": {
+ "name": "municipality_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_created_at_idx": {
+ "name": "municipality_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "municipality_political_trend_recorded_by_id_campaign_user_id_fk": {
+ "name": "municipality_political_trend_recorded_by_id_campaign_user_id_fk",
+ "tableFrom": "municipality",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "political_trend_recorded_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.municipality_rels": {
+ "name": "municipality_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "campaign_user_id": {
+ "name": "campaign_user_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "state_deputy_id": {
+ "name": "state_deputy_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "municipality_rels_order_idx": {
+ "name": "municipality_rels_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_rels_parent_idx": {
+ "name": "municipality_rels_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_rels_path_idx": {
+ "name": "municipality_rels_path_idx",
+ "columns": [
+ {
+ "expression": "path",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_rels_campaign_user_id_idx": {
+ "name": "municipality_rels_campaign_user_id_idx",
+ "columns": [
+ {
+ "expression": "campaign_user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_rels_state_deputy_id_idx": {
+ "name": "municipality_rels_state_deputy_id_idx",
+ "columns": [
+ {
+ "expression": "state_deputy_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "municipality_rels_parent_fk": {
+ "name": "municipality_rels_parent_fk",
+ "tableFrom": "municipality_rels",
+ "tableTo": "municipality",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "municipality_rels_campaign_user_fk": {
+ "name": "municipality_rels_campaign_user_fk",
+ "tableFrom": "municipality_rels",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "campaign_user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "municipality_rels_state_deputy_fk": {
+ "name": "municipality_rels_state_deputy_fk",
+ "tableFrom": "municipality_rels",
+ "tableTo": "state_deputy",
+ "columnsFrom": [
+ "state_deputy_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.leadership": {
+ "name": "leadership",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "contact_id": {
+ "name": "contact_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "exclusive": {
+ "name": "exclusive",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": true
+ },
+ "support_status": {
+ "name": "support_status",
+ "type": "enum_leadership_support_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'a_abordar'"
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "consent_id": {
+ "name": "consent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "consent_content_hash": {
+ "name": "consent_content_hash",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "consented_at": {
+ "name": "consented_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "notes": {
+ "name": "notes",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_by_id": {
+ "name": "created_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "leadership_contact_idx": {
+ "name": "leadership_contact_idx",
+ "columns": [
+ {
+ "expression": "contact_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "leadership_exclusive_idx": {
+ "name": "leadership_exclusive_idx",
+ "columns": [
+ {
+ "expression": "exclusive",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "leadership_support_status_idx": {
+ "name": "leadership_support_status_idx",
+ "columns": [
+ {
+ "expression": "support_status",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "leadership_user_idx": {
+ "name": "leadership_user_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "leadership_consent_idx": {
+ "name": "leadership_consent_idx",
+ "columns": [
+ {
+ "expression": "consent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "leadership_created_by_idx": {
+ "name": "leadership_created_by_idx",
+ "columns": [
+ {
+ "expression": "created_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "leadership_updated_at_idx": {
+ "name": "leadership_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "leadership_created_at_idx": {
+ "name": "leadership_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "leadership_contact_id_contact_id_fk": {
+ "name": "leadership_contact_id_contact_id_fk",
+ "tableFrom": "leadership",
+ "tableTo": "contact",
+ "columnsFrom": [
+ "contact_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "leadership_user_id_campaign_user_id_fk": {
+ "name": "leadership_user_id_campaign_user_id_fk",
+ "tableFrom": "leadership",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "leadership_consent_id_consent_id_fk": {
+ "name": "leadership_consent_id_consent_id_fk",
+ "tableFrom": "leadership",
+ "tableTo": "consent",
+ "columnsFrom": [
+ "consent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "leadership_created_by_id_campaign_user_id_fk": {
+ "name": "leadership_created_by_id_campaign_user_id_fk",
+ "tableFrom": "leadership",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "created_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.leadership_rels": {
+ "name": "leadership_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "municipality_id": {
+ "name": "municipality_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "organization_id": {
+ "name": "organization_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "state_deputy_id": {
+ "name": "state_deputy_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "campaign_user_id": {
+ "name": "campaign_user_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "leadership_rels_order_idx": {
+ "name": "leadership_rels_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "leadership_rels_parent_idx": {
+ "name": "leadership_rels_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "leadership_rels_path_idx": {
+ "name": "leadership_rels_path_idx",
+ "columns": [
+ {
+ "expression": "path",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "leadership_rels_municipality_id_idx": {
+ "name": "leadership_rels_municipality_id_idx",
+ "columns": [
+ {
+ "expression": "municipality_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "leadership_rels_organization_id_idx": {
+ "name": "leadership_rels_organization_id_idx",
+ "columns": [
+ {
+ "expression": "organization_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "leadership_rels_state_deputy_id_idx": {
+ "name": "leadership_rels_state_deputy_id_idx",
+ "columns": [
+ {
+ "expression": "state_deputy_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "leadership_rels_campaign_user_id_idx": {
+ "name": "leadership_rels_campaign_user_id_idx",
+ "columns": [
+ {
+ "expression": "campaign_user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "leadership_rels_parent_fk": {
+ "name": "leadership_rels_parent_fk",
+ "tableFrom": "leadership_rels",
+ "tableTo": "leadership",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "leadership_rels_municipality_fk": {
+ "name": "leadership_rels_municipality_fk",
+ "tableFrom": "leadership_rels",
+ "tableTo": "municipality",
+ "columnsFrom": [
+ "municipality_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "leadership_rels_organization_fk": {
+ "name": "leadership_rels_organization_fk",
+ "tableFrom": "leadership_rels",
+ "tableTo": "organization",
+ "columnsFrom": [
+ "organization_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "leadership_rels_state_deputy_fk": {
+ "name": "leadership_rels_state_deputy_fk",
+ "tableFrom": "leadership_rels",
+ "tableTo": "state_deputy",
+ "columnsFrom": [
+ "state_deputy_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "leadership_rels_campaign_user_fk": {
+ "name": "leadership_rels_campaign_user_fk",
+ "tableFrom": "leadership_rels",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "campaign_user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.organization": {
+ "name": "organization",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "slug": {
+ "name": "slug",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "kind": {
+ "name": "kind",
+ "type": "enum_organization_kind",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "notes": {
+ "name": "notes",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_by_id": {
+ "name": "created_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "organization_name_idx": {
+ "name": "organization_name_idx",
+ "columns": [
+ {
+ "expression": "name",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "organization_slug_idx": {
+ "name": "organization_slug_idx",
+ "columns": [
+ {
+ "expression": "slug",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "organization_kind_idx": {
+ "name": "organization_kind_idx",
+ "columns": [
+ {
+ "expression": "kind",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "organization_created_by_idx": {
+ "name": "organization_created_by_idx",
+ "columns": [
+ {
+ "expression": "created_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "organization_updated_at_idx": {
+ "name": "organization_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "organization_created_at_idx": {
+ "name": "organization_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "organization_created_by_id_campaign_user_id_fk": {
+ "name": "organization_created_by_id_campaign_user_id_fk",
+ "tableFrom": "organization",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "created_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.organization_rels": {
+ "name": "organization_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "municipality_id": {
+ "name": "municipality_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "organization_rels_order_idx": {
+ "name": "organization_rels_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "organization_rels_parent_idx": {
+ "name": "organization_rels_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "organization_rels_path_idx": {
+ "name": "organization_rels_path_idx",
+ "columns": [
+ {
+ "expression": "path",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "organization_rels_municipality_id_idx": {
+ "name": "organization_rels_municipality_id_idx",
+ "columns": [
+ {
+ "expression": "municipality_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "organization_rels_parent_fk": {
+ "name": "organization_rels_parent_fk",
+ "tableFrom": "organization_rels",
+ "tableTo": "organization",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "organization_rels_municipality_fk": {
+ "name": "organization_rels_municipality_fk",
+ "tableFrom": "organization_rels",
+ "tableTo": "municipality",
+ "columnsFrom": [
+ "municipality_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.state_deputy": {
+ "name": "state_deputy",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "contact_id": {
+ "name": "contact_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "slug": {
+ "name": "slug",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "party": {
+ "name": "party",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "ballot_name": {
+ "name": "ballot_name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "notes": {
+ "name": "notes",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_by_id": {
+ "name": "created_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "state_deputy_contact_idx": {
+ "name": "state_deputy_contact_idx",
+ "columns": [
+ {
+ "expression": "contact_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "state_deputy_slug_idx": {
+ "name": "state_deputy_slug_idx",
+ "columns": [
+ {
+ "expression": "slug",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "state_deputy_party_idx": {
+ "name": "state_deputy_party_idx",
+ "columns": [
+ {
+ "expression": "party",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "state_deputy_created_by_idx": {
+ "name": "state_deputy_created_by_idx",
+ "columns": [
+ {
+ "expression": "created_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "state_deputy_updated_at_idx": {
+ "name": "state_deputy_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "state_deputy_created_at_idx": {
+ "name": "state_deputy_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "state_deputy_contact_id_contact_id_fk": {
+ "name": "state_deputy_contact_id_contact_id_fk",
+ "tableFrom": "state_deputy",
+ "tableTo": "contact",
+ "columnsFrom": [
+ "contact_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "state_deputy_created_by_id_campaign_user_id_fk": {
+ "name": "state_deputy_created_by_id_campaign_user_id_fk",
+ "tableFrom": "state_deputy",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "created_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.state_deputy_rels": {
+ "name": "state_deputy_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "campaign_user_id": {
+ "name": "campaign_user_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "state_deputy_rels_order_idx": {
+ "name": "state_deputy_rels_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "state_deputy_rels_parent_idx": {
+ "name": "state_deputy_rels_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "state_deputy_rels_path_idx": {
+ "name": "state_deputy_rels_path_idx",
+ "columns": [
+ {
+ "expression": "path",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "state_deputy_rels_campaign_user_id_idx": {
+ "name": "state_deputy_rels_campaign_user_id_idx",
+ "columns": [
+ {
+ "expression": "campaign_user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "state_deputy_rels_parent_fk": {
+ "name": "state_deputy_rels_parent_fk",
+ "tableFrom": "state_deputy_rels",
+ "tableTo": "state_deputy",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "state_deputy_rels_campaign_user_fk": {
+ "name": "state_deputy_rels_campaign_user_fk",
+ "tableFrom": "state_deputy_rels",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "campaign_user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.vote_pledge": {
+ "name": "vote_pledge",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "leadership_id": {
+ "name": "leadership_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "municipality_id": {
+ "name": "municipality_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "declared_votes": {
+ "name": "declared_votes",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "declared_at": {
+ "name": "declared_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "declared_by_id": {
+ "name": "declared_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "estimated_votes_pessimistic": {
+ "name": "estimated_votes_pessimistic",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "estimated_votes_central": {
+ "name": "estimated_votes_central",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "estimated_votes_optimistic": {
+ "name": "estimated_votes_optimistic",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "estimate_note": {
+ "name": "estimate_note",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "estimated_by_id": {
+ "name": "estimated_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "estimated_at": {
+ "name": "estimated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "vote_pledge_leadership_idx": {
+ "name": "vote_pledge_leadership_idx",
+ "columns": [
+ {
+ "expression": "leadership_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "vote_pledge_municipality_idx": {
+ "name": "vote_pledge_municipality_idx",
+ "columns": [
+ {
+ "expression": "municipality_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "vote_pledge_declared_votes_idx": {
+ "name": "vote_pledge_declared_votes_idx",
+ "columns": [
+ {
+ "expression": "declared_votes",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "vote_pledge_declared_by_idx": {
+ "name": "vote_pledge_declared_by_idx",
+ "columns": [
+ {
+ "expression": "declared_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "vote_pledge_estimated_by_idx": {
+ "name": "vote_pledge_estimated_by_idx",
+ "columns": [
+ {
+ "expression": "estimated_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "vote_pledge_updated_at_idx": {
+ "name": "vote_pledge_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "vote_pledge_created_at_idx": {
+ "name": "vote_pledge_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "leadership_municipality_idx": {
+ "name": "leadership_municipality_idx",
+ "columns": [
+ {
+ "expression": "leadership_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "municipality_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "vote_pledge_leadership_id_leadership_id_fk": {
+ "name": "vote_pledge_leadership_id_leadership_id_fk",
+ "tableFrom": "vote_pledge",
+ "tableTo": "leadership",
+ "columnsFrom": [
+ "leadership_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "vote_pledge_municipality_id_municipality_id_fk": {
+ "name": "vote_pledge_municipality_id_municipality_id_fk",
+ "tableFrom": "vote_pledge",
+ "tableTo": "municipality",
+ "columnsFrom": [
+ "municipality_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "vote_pledge_declared_by_id_campaign_user_id_fk": {
+ "name": "vote_pledge_declared_by_id_campaign_user_id_fk",
+ "tableFrom": "vote_pledge",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "declared_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "vote_pledge_estimated_by_id_campaign_user_id_fk": {
+ "name": "vote_pledge_estimated_by_id_campaign_user_id_fk",
+ "tableFrom": "vote_pledge",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "estimated_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public._vote_pledge_v": {
+ "name": "_vote_pledge_v",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_leadership_id": {
+ "name": "version_leadership_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "version_municipality_id": {
+ "name": "version_municipality_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "version_declared_votes": {
+ "name": "version_declared_votes",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "version_declared_at": {
+ "name": "version_declared_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_declared_by_id": {
+ "name": "version_declared_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_estimated_votes_pessimistic": {
+ "name": "version_estimated_votes_pessimistic",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_estimated_votes_central": {
+ "name": "version_estimated_votes_central",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_estimated_votes_optimistic": {
+ "name": "version_estimated_votes_optimistic",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_estimate_note": {
+ "name": "version_estimate_note",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_estimated_by_id": {
+ "name": "version_estimated_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_estimated_at": {
+ "name": "version_estimated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_updated_at": {
+ "name": "version_updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_created_at": {
+ "name": "version_created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "_vote_pledge_v_parent_idx": {
+ "name": "_vote_pledge_v_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_vote_pledge_v_version_version_leadership_idx": {
+ "name": "_vote_pledge_v_version_version_leadership_idx",
+ "columns": [
+ {
+ "expression": "version_leadership_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_vote_pledge_v_version_version_municipality_idx": {
+ "name": "_vote_pledge_v_version_version_municipality_idx",
+ "columns": [
+ {
+ "expression": "version_municipality_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_vote_pledge_v_version_version_declared_votes_idx": {
+ "name": "_vote_pledge_v_version_version_declared_votes_idx",
+ "columns": [
+ {
+ "expression": "version_declared_votes",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_vote_pledge_v_version_version_declared_by_idx": {
+ "name": "_vote_pledge_v_version_version_declared_by_idx",
+ "columns": [
+ {
+ "expression": "version_declared_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_vote_pledge_v_version_version_estimated_by_idx": {
+ "name": "_vote_pledge_v_version_version_estimated_by_idx",
+ "columns": [
+ {
+ "expression": "version_estimated_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_vote_pledge_v_version_version_updated_at_idx": {
+ "name": "_vote_pledge_v_version_version_updated_at_idx",
+ "columns": [
+ {
+ "expression": "version_updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_vote_pledge_v_version_version_created_at_idx": {
+ "name": "_vote_pledge_v_version_version_created_at_idx",
+ "columns": [
+ {
+ "expression": "version_created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_vote_pledge_v_created_at_idx": {
+ "name": "_vote_pledge_v_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_vote_pledge_v_updated_at_idx": {
+ "name": "_vote_pledge_v_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "version_leadership_version_municipality_idx": {
+ "name": "version_leadership_version_municipality_idx",
+ "columns": [
+ {
+ "expression": "version_leadership_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "version_municipality_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "_vote_pledge_v_parent_id_vote_pledge_id_fk": {
+ "name": "_vote_pledge_v_parent_id_vote_pledge_id_fk",
+ "tableFrom": "_vote_pledge_v",
+ "tableTo": "vote_pledge",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "_vote_pledge_v_version_leadership_id_leadership_id_fk": {
+ "name": "_vote_pledge_v_version_leadership_id_leadership_id_fk",
+ "tableFrom": "_vote_pledge_v",
+ "tableTo": "leadership",
+ "columnsFrom": [
+ "version_leadership_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "_vote_pledge_v_version_municipality_id_municipality_id_fk": {
+ "name": "_vote_pledge_v_version_municipality_id_municipality_id_fk",
+ "tableFrom": "_vote_pledge_v",
+ "tableTo": "municipality",
+ "columnsFrom": [
+ "version_municipality_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "_vote_pledge_v_version_declared_by_id_campaign_user_id_fk": {
+ "name": "_vote_pledge_v_version_declared_by_id_campaign_user_id_fk",
+ "tableFrom": "_vote_pledge_v",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "version_declared_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "_vote_pledge_v_version_estimated_by_id_campaign_user_id_fk": {
+ "name": "_vote_pledge_v_version_estimated_by_id_campaign_user_id_fk",
+ "tableFrom": "_vote_pledge_v",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "version_estimated_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.allocation_decision": {
+ "name": "allocation_decision",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "municipality_id": {
+ "name": "municipality_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "pattern_id": {
+ "name": "pattern_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "outcome": {
+ "name": "outcome",
+ "type": "enum_allocation_decision_outcome",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "rationale": {
+ "name": "rationale",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "alternative_reading": {
+ "name": "alternative_reading",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "snapshot": {
+ "name": "snapshot",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "decided_by_id": {
+ "name": "decided_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "allocation_decision_municipality_idx": {
+ "name": "allocation_decision_municipality_idx",
+ "columns": [
+ {
+ "expression": "municipality_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "allocation_decision_pattern_id_idx": {
+ "name": "allocation_decision_pattern_id_idx",
+ "columns": [
+ {
+ "expression": "pattern_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "allocation_decision_decided_by_idx": {
+ "name": "allocation_decision_decided_by_idx",
+ "columns": [
+ {
+ "expression": "decided_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "allocation_decision_updated_at_idx": {
+ "name": "allocation_decision_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "allocation_decision_created_at_idx": {
+ "name": "allocation_decision_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "allocation_decision_municipality_id_municipality_id_fk": {
+ "name": "allocation_decision_municipality_id_municipality_id_fk",
+ "tableFrom": "allocation_decision",
+ "tableTo": "municipality",
+ "columnsFrom": [
+ "municipality_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "allocation_decision_decided_by_id_campaign_user_id_fk": {
+ "name": "allocation_decision_decided_by_id_campaign_user_id_fk",
+ "tableFrom": "allocation_decision",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "decided_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.campaign_demand_status_history": {
+ "name": "campaign_demand_status_history",
+ "schema": "",
+ "columns": {
+ "_order": {
+ "name": "_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "_parent_id": {
+ "name": "_parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "id": {
+ "name": "id",
+ "type": "varchar",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "status": {
+ "name": "status",
+ "type": "enum_campaign_demand_status_history_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "note": {
+ "name": "note",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "author_id": {
+ "name": "author_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "campaign_demand_status_history_order_idx": {
+ "name": "campaign_demand_status_history_order_idx",
+ "columns": [
+ {
+ "expression": "_order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_demand_status_history_parent_id_idx": {
+ "name": "campaign_demand_status_history_parent_id_idx",
+ "columns": [
+ {
+ "expression": "_parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_demand_status_history_author_idx": {
+ "name": "campaign_demand_status_history_author_idx",
+ "columns": [
+ {
+ "expression": "author_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "campaign_demand_status_history_author_id_campaign_user_id_fk": {
+ "name": "campaign_demand_status_history_author_id_campaign_user_id_fk",
+ "tableFrom": "campaign_demand_status_history",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "author_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "campaign_demand_status_history_parent_id_fk": {
+ "name": "campaign_demand_status_history_parent_id_fk",
+ "tableFrom": "campaign_demand_status_history",
+ "tableTo": "campaign_demand",
+ "columnsFrom": [
+ "_parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.campaign_demand": {
+ "name": "campaign_demand",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "title": {
+ "name": "title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "slug": {
+ "name": "slug",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "kind": {
+ "name": "kind",
+ "type": "enum_campaign_demand_kind",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "municipality_id": {
+ "name": "municipality_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "activity_id": {
+ "name": "activity_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "leadership_id": {
+ "name": "leadership_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "status": {
+ "name": "status",
+ "type": "enum_campaign_demand_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'aberta'"
+ },
+ "decision_note": {
+ "name": "decision_note",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "decided_by_id": {
+ "name": "decided_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "decided_at": {
+ "name": "decided_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cost": {
+ "name": "cost",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_by_id": {
+ "name": "created_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "campaign_demand_title_idx": {
+ "name": "campaign_demand_title_idx",
+ "columns": [
+ {
+ "expression": "title",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_demand_slug_idx": {
+ "name": "campaign_demand_slug_idx",
+ "columns": [
+ {
+ "expression": "slug",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_demand_kind_idx": {
+ "name": "campaign_demand_kind_idx",
+ "columns": [
+ {
+ "expression": "kind",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_demand_municipality_idx": {
+ "name": "campaign_demand_municipality_idx",
+ "columns": [
+ {
+ "expression": "municipality_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_demand_activity_idx": {
+ "name": "campaign_demand_activity_idx",
+ "columns": [
+ {
+ "expression": "activity_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_demand_leadership_idx": {
+ "name": "campaign_demand_leadership_idx",
+ "columns": [
+ {
+ "expression": "leadership_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_demand_status_idx": {
+ "name": "campaign_demand_status_idx",
+ "columns": [
+ {
+ "expression": "status",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_demand_decided_by_idx": {
+ "name": "campaign_demand_decided_by_idx",
+ "columns": [
+ {
+ "expression": "decided_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_demand_created_by_idx": {
+ "name": "campaign_demand_created_by_idx",
+ "columns": [
+ {
+ "expression": "created_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_demand_updated_at_idx": {
+ "name": "campaign_demand_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_demand_created_at_idx": {
+ "name": "campaign_demand_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "campaign_demand_municipality_id_municipality_id_fk": {
+ "name": "campaign_demand_municipality_id_municipality_id_fk",
+ "tableFrom": "campaign_demand",
+ "tableTo": "municipality",
+ "columnsFrom": [
+ "municipality_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "campaign_demand_activity_id_activity_id_fk": {
+ "name": "campaign_demand_activity_id_activity_id_fk",
+ "tableFrom": "campaign_demand",
+ "tableTo": "activity",
+ "columnsFrom": [
+ "activity_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "campaign_demand_leadership_id_leadership_id_fk": {
+ "name": "campaign_demand_leadership_id_leadership_id_fk",
+ "tableFrom": "campaign_demand",
+ "tableTo": "leadership",
+ "columnsFrom": [
+ "leadership_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "campaign_demand_decided_by_id_campaign_user_id_fk": {
+ "name": "campaign_demand_decided_by_id_campaign_user_id_fk",
+ "tableFrom": "campaign_demand",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "decided_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "campaign_demand_created_by_id_campaign_user_id_fk": {
+ "name": "campaign_demand_created_by_id_campaign_user_id_fk",
+ "tableFrom": "campaign_demand",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "created_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.campaign_demand_rels": {
+ "name": "campaign_demand_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "campaign_user_id": {
+ "name": "campaign_user_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "media_id": {
+ "name": "media_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "campaign_demand_rels_order_idx": {
+ "name": "campaign_demand_rels_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_demand_rels_parent_idx": {
+ "name": "campaign_demand_rels_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_demand_rels_path_idx": {
+ "name": "campaign_demand_rels_path_idx",
+ "columns": [
+ {
+ "expression": "path",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_demand_rels_campaign_user_id_idx": {
+ "name": "campaign_demand_rels_campaign_user_id_idx",
+ "columns": [
+ {
+ "expression": "campaign_user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "campaign_demand_rels_media_id_idx": {
+ "name": "campaign_demand_rels_media_id_idx",
+ "columns": [
+ {
+ "expression": "media_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "campaign_demand_rels_parent_fk": {
+ "name": "campaign_demand_rels_parent_fk",
+ "tableFrom": "campaign_demand_rels",
+ "tableTo": "campaign_demand",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "campaign_demand_rels_campaign_user_fk": {
+ "name": "campaign_demand_rels_campaign_user_fk",
+ "tableFrom": "campaign_demand_rels",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "campaign_user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "campaign_demand_rels_media_fk": {
+ "name": "campaign_demand_rels_media_fk",
+ "tableFrom": "campaign_demand_rels",
+ "tableTo": "media",
+ "columnsFrom": [
+ "media_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.supporter": {
+ "name": "supporter",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "contact_id": {
+ "name": "contact_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "municipality_id": {
+ "name": "municipality_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "vote_intention": {
+ "name": "vote_intention",
+ "type": "enum_supporter_vote_intention",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "consent_id": {
+ "name": "consent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "consent_content_hash": {
+ "name": "consent_content_hash",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "consented_at": {
+ "name": "consented_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "vote_intention_consent_id": {
+ "name": "vote_intention_consent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "vote_intention_consent_content_hash": {
+ "name": "vote_intention_consent_content_hash",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "vote_intention_consented_at": {
+ "name": "vote_intention_consented_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "source": {
+ "name": "source",
+ "type": "enum_supporter_source",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'manual'"
+ },
+ "consent_note": {
+ "name": "consent_note",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "notes": {
+ "name": "notes",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_by_id": {
+ "name": "created_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "supporter_contact_idx": {
+ "name": "supporter_contact_idx",
+ "columns": [
+ {
+ "expression": "contact_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "supporter_municipality_idx": {
+ "name": "supporter_municipality_idx",
+ "columns": [
+ {
+ "expression": "municipality_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "supporter_vote_intention_idx": {
+ "name": "supporter_vote_intention_idx",
+ "columns": [
+ {
+ "expression": "vote_intention",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "supporter_consent_idx": {
+ "name": "supporter_consent_idx",
+ "columns": [
+ {
+ "expression": "consent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "supporter_vote_intention_consent_idx": {
+ "name": "supporter_vote_intention_consent_idx",
+ "columns": [
+ {
+ "expression": "vote_intention_consent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "supporter_source_idx": {
+ "name": "supporter_source_idx",
+ "columns": [
+ {
+ "expression": "source",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "supporter_created_by_idx": {
+ "name": "supporter_created_by_idx",
+ "columns": [
+ {
+ "expression": "created_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "supporter_updated_at_idx": {
+ "name": "supporter_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "supporter_created_at_idx": {
+ "name": "supporter_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "supporter_contact_id_contact_id_fk": {
+ "name": "supporter_contact_id_contact_id_fk",
+ "tableFrom": "supporter",
+ "tableTo": "contact",
+ "columnsFrom": [
+ "contact_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "supporter_municipality_id_municipality_id_fk": {
+ "name": "supporter_municipality_id_municipality_id_fk",
+ "tableFrom": "supporter",
+ "tableTo": "municipality",
+ "columnsFrom": [
+ "municipality_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "supporter_consent_id_consent_id_fk": {
+ "name": "supporter_consent_id_consent_id_fk",
+ "tableFrom": "supporter",
+ "tableTo": "consent",
+ "columnsFrom": [
+ "consent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "supporter_vote_intention_consent_id_consent_id_fk": {
+ "name": "supporter_vote_intention_consent_id_consent_id_fk",
+ "tableFrom": "supporter",
+ "tableTo": "consent",
+ "columnsFrom": [
+ "vote_intention_consent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "supporter_created_by_id_campaign_user_id_fk": {
+ "name": "supporter_created_by_id_campaign_user_id_fk",
+ "tableFrom": "supporter",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "created_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.supporter_import_batch": {
+ "name": "supporter_import_batch",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "batch_id": {
+ "name": "batch_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "actor_id": {
+ "name": "actor_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "rows": {
+ "name": "rows",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "supporter_import_batch_batch_id_idx": {
+ "name": "supporter_import_batch_batch_id_idx",
+ "columns": [
+ {
+ "expression": "batch_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "supporter_import_batch_actor_idx": {
+ "name": "supporter_import_batch_actor_idx",
+ "columns": [
+ {
+ "expression": "actor_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "supporter_import_batch_expires_at_idx": {
+ "name": "supporter_import_batch_expires_at_idx",
+ "columns": [
+ {
+ "expression": "expires_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "supporter_import_batch_updated_at_idx": {
+ "name": "supporter_import_batch_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "supporter_import_batch_created_at_idx": {
+ "name": "supporter_import_batch_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "supporter_import_batch_actor_id_campaign_user_id_fk": {
+ "name": "supporter_import_batch_actor_id_campaign_user_id_fk",
+ "tableFrom": "supporter_import_batch",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "actor_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.municipality_update_comments": {
+ "name": "municipality_update_comments",
+ "schema": "",
+ "columns": {
+ "_order": {
+ "name": "_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "_parent_id": {
+ "name": "_parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "id": {
+ "name": "id",
+ "type": "varchar",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "body": {
+ "name": "body",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "author_id": {
+ "name": "author_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "municipality_update_comments_order_idx": {
+ "name": "municipality_update_comments_order_idx",
+ "columns": [
+ {
+ "expression": "_order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_update_comments_parent_id_idx": {
+ "name": "municipality_update_comments_parent_id_idx",
+ "columns": [
+ {
+ "expression": "_parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_update_comments_author_idx": {
+ "name": "municipality_update_comments_author_idx",
+ "columns": [
+ {
+ "expression": "author_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "municipality_update_comments_author_id_campaign_user_id_fk": {
+ "name": "municipality_update_comments_author_id_campaign_user_id_fk",
+ "tableFrom": "municipality_update_comments",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "author_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "municipality_update_comments_parent_id_fk": {
+ "name": "municipality_update_comments_parent_id_fk",
+ "tableFrom": "municipality_update_comments",
+ "tableTo": "municipality_update",
+ "columnsFrom": [
+ "_parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.municipality_update": {
+ "name": "municipality_update",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "municipality_id": {
+ "name": "municipality_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "author_id": {
+ "name": "author_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "polarity": {
+ "name": "polarity",
+ "type": "enum_municipality_update_polarity",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'neutra'"
+ },
+ "urgent": {
+ "name": "urgent",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "adversary_signal": {
+ "name": "adversary_signal",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "body": {
+ "name": "body",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "active_volunteers": {
+ "name": "active_volunteers",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "new_supports": {
+ "name": "new_supports",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "responsible_id": {
+ "name": "responsible_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "resolved_by_id": {
+ "name": "resolved_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "municipality_update_municipality_idx": {
+ "name": "municipality_update_municipality_idx",
+ "columns": [
+ {
+ "expression": "municipality_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_update_author_idx": {
+ "name": "municipality_update_author_idx",
+ "columns": [
+ {
+ "expression": "author_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_update_polarity_idx": {
+ "name": "municipality_update_polarity_idx",
+ "columns": [
+ {
+ "expression": "polarity",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_update_urgent_idx": {
+ "name": "municipality_update_urgent_idx",
+ "columns": [
+ {
+ "expression": "urgent",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_update_adversary_signal_idx": {
+ "name": "municipality_update_adversary_signal_idx",
+ "columns": [
+ {
+ "expression": "adversary_signal",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_update_responsible_idx": {
+ "name": "municipality_update_responsible_idx",
+ "columns": [
+ {
+ "expression": "responsible_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_update_resolved_by_idx": {
+ "name": "municipality_update_resolved_by_idx",
+ "columns": [
+ {
+ "expression": "resolved_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_update_resolved_at_idx": {
+ "name": "municipality_update_resolved_at_idx",
+ "columns": [
+ {
+ "expression": "resolved_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_update_updated_at_idx": {
+ "name": "municipality_update_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "municipality_update_created_at_idx": {
+ "name": "municipality_update_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "municipality_update_municipality_id_municipality_id_fk": {
+ "name": "municipality_update_municipality_id_municipality_id_fk",
+ "tableFrom": "municipality_update",
+ "tableTo": "municipality",
+ "columnsFrom": [
+ "municipality_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "municipality_update_author_id_campaign_user_id_fk": {
+ "name": "municipality_update_author_id_campaign_user_id_fk",
+ "tableFrom": "municipality_update",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "author_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "municipality_update_responsible_id_campaign_user_id_fk": {
+ "name": "municipality_update_responsible_id_campaign_user_id_fk",
+ "tableFrom": "municipality_update",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "responsible_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "municipality_update_resolved_by_id_campaign_user_id_fk": {
+ "name": "municipality_update_resolved_by_id_campaign_user_id_fk",
+ "tableFrom": "municipality_update",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "resolved_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.activity_tasks": {
+ "name": "activity_tasks",
+ "schema": "",
+ "columns": {
+ "_order": {
+ "name": "_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "_parent_id": {
+ "name": "_parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "id": {
+ "name": "id",
+ "type": "varchar",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "title": {
+ "name": "title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "responsible_id": {
+ "name": "responsible_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "done": {
+ "name": "done",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "done_at": {
+ "name": "done_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "activity_tasks_order_idx": {
+ "name": "activity_tasks_order_idx",
+ "columns": [
+ {
+ "expression": "_order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_tasks_parent_id_idx": {
+ "name": "activity_tasks_parent_id_idx",
+ "columns": [
+ {
+ "expression": "_parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_tasks_responsible_idx": {
+ "name": "activity_tasks_responsible_idx",
+ "columns": [
+ {
+ "expression": "responsible_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "activity_tasks_responsible_id_contact_id_fk": {
+ "name": "activity_tasks_responsible_id_contact_id_fk",
+ "tableFrom": "activity_tasks",
+ "tableTo": "contact",
+ "columnsFrom": [
+ "responsible_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "activity_tasks_parent_id_fk": {
+ "name": "activity_tasks_parent_id_fk",
+ "tableFrom": "activity_tasks",
+ "tableTo": "activity",
+ "columnsFrom": [
+ "_parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.activity_updates": {
+ "name": "activity_updates",
+ "schema": "",
+ "columns": {
+ "_order": {
+ "name": "_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "_parent_id": {
+ "name": "_parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "id": {
+ "name": "id",
+ "type": "varchar",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "body": {
+ "name": "body",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "author_id": {
+ "name": "author_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "activity_updates_order_idx": {
+ "name": "activity_updates_order_idx",
+ "columns": [
+ {
+ "expression": "_order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_updates_parent_id_idx": {
+ "name": "activity_updates_parent_id_idx",
+ "columns": [
+ {
+ "expression": "_parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_updates_author_idx": {
+ "name": "activity_updates_author_idx",
+ "columns": [
+ {
+ "expression": "author_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "activity_updates_author_id_campaign_user_id_fk": {
+ "name": "activity_updates_author_id_campaign_user_id_fk",
+ "tableFrom": "activity_updates",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "author_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "activity_updates_parent_id_fk": {
+ "name": "activity_updates_parent_id_fk",
+ "tableFrom": "activity_updates",
+ "tableTo": "activity",
+ "columnsFrom": [
+ "_parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.activity": {
+ "name": "activity",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "title": {
+ "name": "title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "slug": {
+ "name": "slug",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "status": {
+ "name": "status",
+ "type": "enum_activity_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'confirmado'"
+ },
+ "description": {
+ "name": "description",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "deputy_present": {
+ "name": "deputy_present",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "all_day": {
+ "name": "all_day",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "public_event": {
+ "name": "public_event",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "start_at": {
+ "name": "start_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "end_at": {
+ "name": "end_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "municipality_id": {
+ "name": "municipality_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "locality": {
+ "name": "locality",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "task_total": {
+ "name": "task_total",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 0
+ },
+ "task_done_count": {
+ "name": "task_done_count",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 0
+ },
+ "result_summary": {
+ "name": "result_summary",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "result_recorded_by_id": {
+ "name": "result_recorded_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "result_recorded_at": {
+ "name": "result_recorded_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_mirrored_change_at": {
+ "name": "last_mirrored_change_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "google_event_id": {
+ "name": "google_event_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "google_calendar_id": {
+ "name": "google_calendar_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_by_id": {
+ "name": "created_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "activity_title_idx": {
+ "name": "activity_title_idx",
+ "columns": [
+ {
+ "expression": "title",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_slug_idx": {
+ "name": "activity_slug_idx",
+ "columns": [
+ {
+ "expression": "slug",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_status_idx": {
+ "name": "activity_status_idx",
+ "columns": [
+ {
+ "expression": "status",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_deputy_present_idx": {
+ "name": "activity_deputy_present_idx",
+ "columns": [
+ {
+ "expression": "deputy_present",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_all_day_idx": {
+ "name": "activity_all_day_idx",
+ "columns": [
+ {
+ "expression": "all_day",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_public_event_idx": {
+ "name": "activity_public_event_idx",
+ "columns": [
+ {
+ "expression": "public_event",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_start_at_idx": {
+ "name": "activity_start_at_idx",
+ "columns": [
+ {
+ "expression": "start_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_municipality_idx": {
+ "name": "activity_municipality_idx",
+ "columns": [
+ {
+ "expression": "municipality_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_result_recorded_by_idx": {
+ "name": "activity_result_recorded_by_idx",
+ "columns": [
+ {
+ "expression": "result_recorded_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_google_event_id_idx": {
+ "name": "activity_google_event_id_idx",
+ "columns": [
+ {
+ "expression": "google_event_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_created_by_idx": {
+ "name": "activity_created_by_idx",
+ "columns": [
+ {
+ "expression": "created_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_updated_at_idx": {
+ "name": "activity_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_created_at_idx": {
+ "name": "activity_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "activity_municipality_id_municipality_id_fk": {
+ "name": "activity_municipality_id_municipality_id_fk",
+ "tableFrom": "activity",
+ "tableTo": "municipality",
+ "columnsFrom": [
+ "municipality_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "activity_result_recorded_by_id_campaign_user_id_fk": {
+ "name": "activity_result_recorded_by_id_campaign_user_id_fk",
+ "tableFrom": "activity",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "result_recorded_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "activity_created_by_id_campaign_user_id_fk": {
+ "name": "activity_created_by_id_campaign_user_id_fk",
+ "tableFrom": "activity",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "created_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.activity_texts": {
+ "name": "activity_texts",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "text": {
+ "name": "text",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "activity_texts_order_parent": {
+ "name": "activity_texts_order_parent",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_texts_text_idx": {
+ "name": "activity_texts_text_idx",
+ "columns": [
+ {
+ "expression": "text",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "activity_texts_parent_fk": {
+ "name": "activity_texts_parent_fk",
+ "tableFrom": "activity_texts",
+ "tableTo": "activity",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.activity_rels": {
+ "name": "activity_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "organization_id": {
+ "name": "organization_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "campaign_user_id": {
+ "name": "campaign_user_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "leadership_id": {
+ "name": "leadership_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "state_deputy_id": {
+ "name": "state_deputy_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "media_id": {
+ "name": "media_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "activity_rels_order_idx": {
+ "name": "activity_rels_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_rels_parent_idx": {
+ "name": "activity_rels_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_rels_path_idx": {
+ "name": "activity_rels_path_idx",
+ "columns": [
+ {
+ "expression": "path",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_rels_organization_id_idx": {
+ "name": "activity_rels_organization_id_idx",
+ "columns": [
+ {
+ "expression": "organization_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_rels_campaign_user_id_idx": {
+ "name": "activity_rels_campaign_user_id_idx",
+ "columns": [
+ {
+ "expression": "campaign_user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_rels_leadership_id_idx": {
+ "name": "activity_rels_leadership_id_idx",
+ "columns": [
+ {
+ "expression": "leadership_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_rels_state_deputy_id_idx": {
+ "name": "activity_rels_state_deputy_id_idx",
+ "columns": [
+ {
+ "expression": "state_deputy_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "activity_rels_media_id_idx": {
+ "name": "activity_rels_media_id_idx",
+ "columns": [
+ {
+ "expression": "media_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "activity_rels_parent_fk": {
+ "name": "activity_rels_parent_fk",
+ "tableFrom": "activity_rels",
+ "tableTo": "activity",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "activity_rels_organization_fk": {
+ "name": "activity_rels_organization_fk",
+ "tableFrom": "activity_rels",
+ "tableTo": "organization",
+ "columnsFrom": [
+ "organization_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "activity_rels_campaign_user_fk": {
+ "name": "activity_rels_campaign_user_fk",
+ "tableFrom": "activity_rels",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "campaign_user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "activity_rels_leadership_fk": {
+ "name": "activity_rels_leadership_fk",
+ "tableFrom": "activity_rels",
+ "tableTo": "leadership",
+ "columnsFrom": [
+ "leadership_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "activity_rels_state_deputy_fk": {
+ "name": "activity_rels_state_deputy_fk",
+ "tableFrom": "activity_rels",
+ "tableTo": "state_deputy",
+ "columnsFrom": [
+ "state_deputy_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "activity_rels_media_fk": {
+ "name": "activity_rels_media_fk",
+ "tableFrom": "activity_rels",
+ "tableTo": "media",
+ "columnsFrom": [
+ "media_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.speech_topics": {
+ "name": "speech_topics",
+ "schema": "",
+ "columns": {
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "enum_speech_topics",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "speech_topics_order_idx": {
+ "name": "speech_topics_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_topics_parent_idx": {
+ "name": "speech_topics_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_topics_value_idx": {
+ "name": "speech_topics_value_idx",
+ "columns": [
+ {
+ "expression": "value",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "speech_topics_parent_fk": {
+ "name": "speech_topics_parent_fk",
+ "tableFrom": "speech_topics",
+ "tableTo": "speech",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.speech_scopes": {
+ "name": "speech_scopes",
+ "schema": "",
+ "columns": {
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "enum_speech_scopes",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "speech_scopes_order_idx": {
+ "name": "speech_scopes_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_scopes_parent_idx": {
+ "name": "speech_scopes_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_scopes_value_idx": {
+ "name": "speech_scopes_value_idx",
+ "columns": [
+ {
+ "expression": "value",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "speech_scopes_parent_fk": {
+ "name": "speech_scopes_parent_fk",
+ "tableFrom": "speech_scopes",
+ "tableTo": "speech",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.speech": {
+ "name": "speech",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "source_key": {
+ "name": "source_key",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "origin": {
+ "name": "origin",
+ "type": "enum_speech_origin",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'camara'"
+ },
+ "speech_at": {
+ "name": "speech_at",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "year": {
+ "name": "year",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "legislature": {
+ "name": "legislature",
+ "type": "enum_speech_legislature",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "type": {
+ "name": "type",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "phase": {
+ "name": "phase",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "duration_seconds": {
+ "name": "duration_seconds",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "summary": {
+ "name": "summary",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "official_transcript": {
+ "name": "official_transcript",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "official_text_url": {
+ "name": "official_text_url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "search_text": {
+ "name": "search_text",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "''"
+ },
+ "event_id": {
+ "name": "event_id",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "event_start_at": {
+ "name": "event_start_at",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "event_end_at": {
+ "name": "event_end_at",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "youtube_url": {
+ "name": "youtube_url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "presiding_officer": {
+ "name": "presiding_officer",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "audio_id": {
+ "name": "audio_id",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "excerpt_t_ms": {
+ "name": "excerpt_t_ms",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "vod_playback_url": {
+ "name": "vod_playback_url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "vod_download_url": {
+ "name": "vod_download_url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "platform": {
+ "name": "platform",
+ "type": "enum_speech_platform",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "external_id": {
+ "name": "external_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "source_url": {
+ "name": "source_url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "title": {
+ "name": "title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "channel": {
+ "name": "channel",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "mirrored_media_id": {
+ "name": "mirrored_media_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "thumbnail_id": {
+ "name": "thumbnail_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "classified_by": {
+ "name": "classified_by",
+ "type": "enum_speech_classified_by",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'gazetteer'"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "speech_source_key_idx": {
+ "name": "speech_source_key_idx",
+ "columns": [
+ {
+ "expression": "source_key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_origin_idx": {
+ "name": "speech_origin_idx",
+ "columns": [
+ {
+ "expression": "origin",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_speech_at_idx": {
+ "name": "speech_speech_at_idx",
+ "columns": [
+ {
+ "expression": "speech_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_year_idx": {
+ "name": "speech_year_idx",
+ "columns": [
+ {
+ "expression": "year",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_legislature_idx": {
+ "name": "speech_legislature_idx",
+ "columns": [
+ {
+ "expression": "legislature",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_phase_idx": {
+ "name": "speech_phase_idx",
+ "columns": [
+ {
+ "expression": "phase",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_event_id_idx": {
+ "name": "speech_event_id_idx",
+ "columns": [
+ {
+ "expression": "event_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_audio_id_idx": {
+ "name": "speech_audio_id_idx",
+ "columns": [
+ {
+ "expression": "audio_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_excerpt_t_ms_idx": {
+ "name": "speech_excerpt_t_ms_idx",
+ "columns": [
+ {
+ "expression": "excerpt_t_ms",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_platform_idx": {
+ "name": "speech_platform_idx",
+ "columns": [
+ {
+ "expression": "platform",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_mirrored_media_idx": {
+ "name": "speech_mirrored_media_idx",
+ "columns": [
+ {
+ "expression": "mirrored_media_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_thumbnail_idx": {
+ "name": "speech_thumbnail_idx",
+ "columns": [
+ {
+ "expression": "thumbnail_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_classified_by_idx": {
+ "name": "speech_classified_by_idx",
+ "columns": [
+ {
+ "expression": "classified_by",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_updated_at_idx": {
+ "name": "speech_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_created_at_idx": {
+ "name": "speech_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "speech_mirrored_media_id_internet_speech_media_id_fk": {
+ "name": "speech_mirrored_media_id_internet_speech_media_id_fk",
+ "tableFrom": "speech",
+ "tableTo": "internet_speech_media",
+ "columnsFrom": [
+ "mirrored_media_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "speech_thumbnail_id_internet_speech_media_id_fk": {
+ "name": "speech_thumbnail_id_internet_speech_media_id_fk",
+ "tableFrom": "speech",
+ "tableTo": "internet_speech_media",
+ "columnsFrom": [
+ "thumbnail_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.speech_texts": {
+ "name": "speech_texts",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "text": {
+ "name": "text",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "speech_texts_order_parent": {
+ "name": "speech_texts_order_parent",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "speech_texts_parent_fk": {
+ "name": "speech_texts_parent_fk",
+ "tableFrom": "speech_texts",
+ "tableTo": "speech",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.speech_rels": {
+ "name": "speech_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "municipality_id": {
+ "name": "municipality_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "speech_rels_order_idx": {
+ "name": "speech_rels_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_rels_parent_idx": {
+ "name": "speech_rels_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_rels_path_idx": {
+ "name": "speech_rels_path_idx",
+ "columns": [
+ {
+ "expression": "path",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_rels_municipality_id_idx": {
+ "name": "speech_rels_municipality_id_idx",
+ "columns": [
+ {
+ "expression": "municipality_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "speech_rels_parent_fk": {
+ "name": "speech_rels_parent_fk",
+ "tableFrom": "speech_rels",
+ "tableTo": "speech",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "speech_rels_municipality_fk": {
+ "name": "speech_rels_municipality_fk",
+ "tableFrom": "speech_rels",
+ "tableTo": "municipality",
+ "columnsFrom": [
+ "municipality_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.speech_segment": {
+ "name": "speech_segment",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "speech_id": {
+ "name": "speech_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "start_seconds": {
+ "name": "start_seconds",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "end_seconds": {
+ "name": "end_seconds",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "text": {
+ "name": "text",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "search_text": {
+ "name": "search_text",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "speech_segment_speech_idx": {
+ "name": "speech_segment_speech_idx",
+ "columns": [
+ {
+ "expression": "speech_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_segment_updated_at_idx": {
+ "name": "speech_segment_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_segment_created_at_idx": {
+ "name": "speech_segment_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "speech_segment_speech_id_speech_id_fk": {
+ "name": "speech_segment_speech_id_speech_id_fk",
+ "tableFrom": "speech_segment",
+ "tableTo": "speech",
+ "columnsFrom": [
+ "speech_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.speech_cut": {
+ "name": "speech_cut",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "speech_id": {
+ "name": "speech_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "start_seconds": {
+ "name": "start_seconds",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "end_seconds": {
+ "name": "end_seconds",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "duration_seconds": {
+ "name": "duration_seconds",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "title": {
+ "name": "title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "status": {
+ "name": "status",
+ "type": "enum_speech_cut_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'processing'"
+ },
+ "step": {
+ "name": "step",
+ "type": "enum_speech_cut_step",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "media_id": {
+ "name": "media_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "error": {
+ "name": "error",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "published_at": {
+ "name": "published_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_by_id": {
+ "name": "created_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "speech_cut_speech_idx": {
+ "name": "speech_cut_speech_idx",
+ "columns": [
+ {
+ "expression": "speech_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_cut_status_idx": {
+ "name": "speech_cut_status_idx",
+ "columns": [
+ {
+ "expression": "status",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_cut_media_idx": {
+ "name": "speech_cut_media_idx",
+ "columns": [
+ {
+ "expression": "media_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_cut_created_by_idx": {
+ "name": "speech_cut_created_by_idx",
+ "columns": [
+ {
+ "expression": "created_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_cut_updated_at_idx": {
+ "name": "speech_cut_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_cut_created_at_idx": {
+ "name": "speech_cut_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "speech_cut_speech_id_speech_id_fk": {
+ "name": "speech_cut_speech_id_speech_id_fk",
+ "tableFrom": "speech_cut",
+ "tableTo": "speech",
+ "columnsFrom": [
+ "speech_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "speech_cut_media_id_media_id_fk": {
+ "name": "speech_cut_media_id_media_id_fk",
+ "tableFrom": "speech_cut",
+ "tableTo": "media",
+ "columnsFrom": [
+ "media_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "speech_cut_created_by_id_campaign_user_id_fk": {
+ "name": "speech_cut_created_by_id_campaign_user_id_fk",
+ "tableFrom": "speech_cut",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "created_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.speech_embedding": {
+ "name": "speech_embedding",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "speech_id": {
+ "name": "speech_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "kind": {
+ "name": "kind",
+ "type": "enum_speech_embedding_kind",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "start_seconds": {
+ "name": "start_seconds",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "model": {
+ "name": "model",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "dimensions": {
+ "name": "dimensions",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "content_hash": {
+ "name": "content_hash",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "vector": {
+ "name": "vector",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "speech_embedding_speech_idx": {
+ "name": "speech_embedding_speech_idx",
+ "columns": [
+ {
+ "expression": "speech_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_embedding_kind_idx": {
+ "name": "speech_embedding_kind_idx",
+ "columns": [
+ {
+ "expression": "kind",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_embedding_updated_at_idx": {
+ "name": "speech_embedding_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "speech_embedding_created_at_idx": {
+ "name": "speech_embedding_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "speech_embedding_speech_id_speech_id_fk": {
+ "name": "speech_embedding_speech_id_speech_id_fk",
+ "tableFrom": "speech_embedding",
+ "tableTo": "speech",
+ "columnsFrom": [
+ "speech_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.internet_speech_media": {
+ "name": "internet_speech_media",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "alt": {
+ "name": "alt",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "url": {
+ "name": "url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "thumbnail_u_r_l": {
+ "name": "thumbnail_u_r_l",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filename": {
+ "name": "filename",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "mime_type": {
+ "name": "mime_type",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filesize": {
+ "name": "filesize",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "width": {
+ "name": "width",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "height": {
+ "name": "height",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "focal_x": {
+ "name": "focal_x",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "focal_y": {
+ "name": "focal_y",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "internet_speech_media_updated_at_idx": {
+ "name": "internet_speech_media_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "internet_speech_media_created_at_idx": {
+ "name": "internet_speech_media_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "internet_speech_media_filename_idx": {
+ "name": "internet_speech_media_filename_idx",
+ "columns": [
+ {
+ "expression": "filename",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.reel": {
+ "name": "reel",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "title": {
+ "name": "title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "feature": {
+ "name": "feature",
+ "type": "enum_reel_feature",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "source_hash": {
+ "name": "source_hash",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "status": {
+ "name": "status",
+ "type": "enum_reel_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'draft'"
+ },
+ "video_id": {
+ "name": "video_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "video_with_audio_id": {
+ "name": "video_with_audio_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "narration_audio_id": {
+ "name": "narration_audio_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "captions_id": {
+ "name": "captions_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cover_id": {
+ "name": "cover_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "transcript": {
+ "name": "transcript",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "published_at": {
+ "name": "published_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_by_id": {
+ "name": "created_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "reel_source_hash_idx": {
+ "name": "reel_source_hash_idx",
+ "columns": [
+ {
+ "expression": "source_hash",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "reel_status_idx": {
+ "name": "reel_status_idx",
+ "columns": [
+ {
+ "expression": "status",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "reel_video_idx": {
+ "name": "reel_video_idx",
+ "columns": [
+ {
+ "expression": "video_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "reel_video_with_audio_idx": {
+ "name": "reel_video_with_audio_idx",
+ "columns": [
+ {
+ "expression": "video_with_audio_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "reel_narration_audio_idx": {
+ "name": "reel_narration_audio_idx",
+ "columns": [
+ {
+ "expression": "narration_audio_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "reel_captions_idx": {
+ "name": "reel_captions_idx",
+ "columns": [
+ {
+ "expression": "captions_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "reel_cover_idx": {
+ "name": "reel_cover_idx",
+ "columns": [
+ {
+ "expression": "cover_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "reel_created_by_idx": {
+ "name": "reel_created_by_idx",
+ "columns": [
+ {
+ "expression": "created_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "reel_updated_at_idx": {
+ "name": "reel_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "reel_created_at_idx": {
+ "name": "reel_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "reel_video_id_reel_media_id_fk": {
+ "name": "reel_video_id_reel_media_id_fk",
+ "tableFrom": "reel",
+ "tableTo": "reel_media",
+ "columnsFrom": [
+ "video_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "reel_video_with_audio_id_reel_media_id_fk": {
+ "name": "reel_video_with_audio_id_reel_media_id_fk",
+ "tableFrom": "reel",
+ "tableTo": "reel_media",
+ "columnsFrom": [
+ "video_with_audio_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "reel_narration_audio_id_reel_media_id_fk": {
+ "name": "reel_narration_audio_id_reel_media_id_fk",
+ "tableFrom": "reel",
+ "tableTo": "reel_media",
+ "columnsFrom": [
+ "narration_audio_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "reel_captions_id_reel_media_id_fk": {
+ "name": "reel_captions_id_reel_media_id_fk",
+ "tableFrom": "reel",
+ "tableTo": "reel_media",
+ "columnsFrom": [
+ "captions_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "reel_cover_id_reel_media_id_fk": {
+ "name": "reel_cover_id_reel_media_id_fk",
+ "tableFrom": "reel",
+ "tableTo": "reel_media",
+ "columnsFrom": [
+ "cover_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "reel_created_by_id_campaign_user_id_fk": {
+ "name": "reel_created_by_id_campaign_user_id_fk",
+ "tableFrom": "reel",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "created_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.reel_media": {
+ "name": "reel_media",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "alt": {
+ "name": "alt",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "url": {
+ "name": "url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "thumbnail_u_r_l": {
+ "name": "thumbnail_u_r_l",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filename": {
+ "name": "filename",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "mime_type": {
+ "name": "mime_type",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filesize": {
+ "name": "filesize",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "width": {
+ "name": "width",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "height": {
+ "name": "height",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "focal_x": {
+ "name": "focal_x",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "focal_y": {
+ "name": "focal_y",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "reel_media_updated_at_idx": {
+ "name": "reel_media_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "reel_media_created_at_idx": {
+ "name": "reel_media_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "reel_media_filename_idx": {
+ "name": "reel_media_filename_idx",
+ "columns": [
+ {
+ "expression": "filename",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.content_piece_topics": {
+ "name": "content_piece_topics",
+ "schema": "",
+ "columns": {
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "enum_content_piece_topics",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "content_piece_topics_order_idx": {
+ "name": "content_piece_topics_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "content_piece_topics_parent_idx": {
+ "name": "content_piece_topics_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "content_piece_topics_value_idx": {
+ "name": "content_piece_topics_value_idx",
+ "columns": [
+ {
+ "expression": "value",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "content_piece_topics_parent_fk": {
+ "name": "content_piece_topics_parent_fk",
+ "tableFrom": "content_piece_topics",
+ "tableTo": "content_piece",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.content_piece_curated_fields": {
+ "name": "content_piece_curated_fields",
+ "schema": "",
+ "columns": {
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "enum_content_piece_curated_fields",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "content_piece_curated_fields_order_idx": {
+ "name": "content_piece_curated_fields_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "content_piece_curated_fields_parent_idx": {
+ "name": "content_piece_curated_fields_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "content_piece_curated_fields_parent_fk": {
+ "name": "content_piece_curated_fields_parent_fk",
+ "tableFrom": "content_piece_curated_fields",
+ "tableTo": "content_piece",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.content_piece": {
+ "name": "content_piece",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "title": {
+ "name": "title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "slug": {
+ "name": "slug",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "type": {
+ "name": "type",
+ "type": "enum_content_piece_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "municipality_id": {
+ "name": "municipality_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "city_label": {
+ "name": "city_label",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "region": {
+ "name": "region",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "institution": {
+ "name": "institution",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "piece_date": {
+ "name": "piece_date",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "duration_seconds": {
+ "name": "duration_seconds",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "transcript": {
+ "name": "transcript",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "media_id": {
+ "name": "media_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "source_url": {
+ "name": "source_url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "origin": {
+ "name": "origin",
+ "type": "enum_content_piece_origin",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'arquivo'"
+ },
+ "status": {
+ "name": "status",
+ "type": "enum_content_piece_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'rascunho'"
+ },
+ "published_at": {
+ "name": "published_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "processing_status": {
+ "name": "processing_status",
+ "type": "enum_content_piece_processing_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'pronto'"
+ },
+ "step": {
+ "name": "step",
+ "type": "enum_content_piece_step",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "error": {
+ "name": "error",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "link_failure_reason": {
+ "name": "link_failure_reason",
+ "type": "enum_content_piece_link_failure_reason",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "search_text": {
+ "name": "search_text",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_by_id": {
+ "name": "created_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "content_piece_slug_idx": {
+ "name": "content_piece_slug_idx",
+ "columns": [
+ {
+ "expression": "slug",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "content_piece_type_idx": {
+ "name": "content_piece_type_idx",
+ "columns": [
+ {
+ "expression": "type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "content_piece_municipality_idx": {
+ "name": "content_piece_municipality_idx",
+ "columns": [
+ {
+ "expression": "municipality_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "content_piece_piece_date_idx": {
+ "name": "content_piece_piece_date_idx",
+ "columns": [
+ {
+ "expression": "piece_date",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "content_piece_media_idx": {
+ "name": "content_piece_media_idx",
+ "columns": [
+ {
+ "expression": "media_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "content_piece_source_url_idx": {
+ "name": "content_piece_source_url_idx",
+ "columns": [
+ {
+ "expression": "source_url",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "content_piece_status_idx": {
+ "name": "content_piece_status_idx",
+ "columns": [
+ {
+ "expression": "status",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "content_piece_processing_status_idx": {
+ "name": "content_piece_processing_status_idx",
+ "columns": [
+ {
+ "expression": "processing_status",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "content_piece_created_by_idx": {
+ "name": "content_piece_created_by_idx",
+ "columns": [
+ {
+ "expression": "created_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "content_piece_updated_at_idx": {
+ "name": "content_piece_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "content_piece_created_at_idx": {
+ "name": "content_piece_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "content_piece_municipality_id_municipality_id_fk": {
+ "name": "content_piece_municipality_id_municipality_id_fk",
+ "tableFrom": "content_piece",
+ "tableTo": "municipality",
+ "columnsFrom": [
+ "municipality_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "content_piece_media_id_content_media_id_fk": {
+ "name": "content_piece_media_id_content_media_id_fk",
+ "tableFrom": "content_piece",
+ "tableTo": "content_media",
+ "columnsFrom": [
+ "media_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "content_piece_created_by_id_campaign_user_id_fk": {
+ "name": "content_piece_created_by_id_campaign_user_id_fk",
+ "tableFrom": "content_piece",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "created_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.content_piece_texts": {
+ "name": "content_piece_texts",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "text": {
+ "name": "text",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "content_piece_texts_order_parent": {
+ "name": "content_piece_texts_order_parent",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "content_piece_texts_parent_fk": {
+ "name": "content_piece_texts_parent_fk",
+ "tableFrom": "content_piece_texts",
+ "tableTo": "content_piece",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.content_piece_rels": {
+ "name": "content_piece_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "leadership_id": {
+ "name": "leadership_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "content_piece_rels_order_idx": {
+ "name": "content_piece_rels_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "content_piece_rels_parent_idx": {
+ "name": "content_piece_rels_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "content_piece_rels_path_idx": {
+ "name": "content_piece_rels_path_idx",
+ "columns": [
+ {
+ "expression": "path",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "content_piece_rels_leadership_id_idx": {
+ "name": "content_piece_rels_leadership_id_idx",
+ "columns": [
+ {
+ "expression": "leadership_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "content_piece_rels_parent_fk": {
+ "name": "content_piece_rels_parent_fk",
+ "tableFrom": "content_piece_rels",
+ "tableTo": "content_piece",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "content_piece_rels_leadership_fk": {
+ "name": "content_piece_rels_leadership_fk",
+ "tableFrom": "content_piece_rels",
+ "tableTo": "leadership",
+ "columnsFrom": [
+ "leadership_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.content_media": {
+ "name": "content_media",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "alt": {
+ "name": "alt",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "url": {
+ "name": "url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "thumbnail_u_r_l": {
+ "name": "thumbnail_u_r_l",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filename": {
+ "name": "filename",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "mime_type": {
+ "name": "mime_type",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filesize": {
+ "name": "filesize",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "width": {
+ "name": "width",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "height": {
+ "name": "height",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "focal_x": {
+ "name": "focal_x",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "focal_y": {
+ "name": "focal_y",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "content_media_updated_at_idx": {
+ "name": "content_media_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "content_media_created_at_idx": {
+ "name": "content_media_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "content_media_filename_idx": {
+ "name": "content_media_filename_idx",
+ "columns": [
+ {
+ "expression": "filename",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.archive_photo_catalog_themes": {
+ "name": "archive_photo_catalog_themes",
+ "schema": "",
+ "columns": {
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "enum_archive_photo_catalog_themes",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "archive_photo_catalog_themes_order_idx": {
+ "name": "archive_photo_catalog_themes_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "archive_photo_catalog_themes_parent_idx": {
+ "name": "archive_photo_catalog_themes_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "archive_photo_catalog_themes_value_idx": {
+ "name": "archive_photo_catalog_themes_value_idx",
+ "columns": [
+ {
+ "expression": "value",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "archive_photo_catalog_themes_parent_fk": {
+ "name": "archive_photo_catalog_themes_parent_fk",
+ "tableFrom": "archive_photo_catalog_themes",
+ "tableTo": "archive_photo",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.archive_photo_curated_fields": {
+ "name": "archive_photo_curated_fields",
+ "schema": "",
+ "columns": {
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "enum_archive_photo_curated_fields",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "archive_photo_curated_fields_order_idx": {
+ "name": "archive_photo_curated_fields_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "archive_photo_curated_fields_parent_idx": {
+ "name": "archive_photo_curated_fields_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "archive_photo_curated_fields_parent_fk": {
+ "name": "archive_photo_curated_fields_parent_fk",
+ "tableFrom": "archive_photo_curated_fields",
+ "tableTo": "archive_photo",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.archive_photo_tags": {
+ "name": "archive_photo_tags",
+ "schema": "",
+ "columns": {
+ "_order": {
+ "name": "_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "_parent_id": {
+ "name": "_parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "id": {
+ "name": "id",
+ "type": "varchar",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "archive_photo_tags_order_idx": {
+ "name": "archive_photo_tags_order_idx",
+ "columns": [
+ {
+ "expression": "_order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "archive_photo_tags_parent_id_idx": {
+ "name": "archive_photo_tags_parent_id_idx",
+ "columns": [
+ {
+ "expression": "_parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "archive_photo_tags_parent_id_fk": {
+ "name": "archive_photo_tags_parent_id_fk",
+ "tableFrom": "archive_photo_tags",
+ "tableTo": "archive_photo",
+ "columnsFrom": [
+ "_parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.archive_photo_albums": {
+ "name": "archive_photo_albums",
+ "schema": "",
+ "columns": {
+ "_order": {
+ "name": "_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "_parent_id": {
+ "name": "_parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "id": {
+ "name": "id",
+ "type": "varchar",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "album_id": {
+ "name": "album_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "title": {
+ "name": "title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "archive_photo_albums_order_idx": {
+ "name": "archive_photo_albums_order_idx",
+ "columns": [
+ {
+ "expression": "_order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "archive_photo_albums_parent_id_idx": {
+ "name": "archive_photo_albums_parent_id_idx",
+ "columns": [
+ {
+ "expression": "_parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "archive_photo_albums_parent_id_fk": {
+ "name": "archive_photo_albums_parent_id_fk",
+ "tableFrom": "archive_photo_albums",
+ "tableTo": "archive_photo",
+ "columnsFrom": [
+ "_parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.archive_photo": {
+ "name": "archive_photo",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "flickr_id": {
+ "name": "flickr_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "alt": {
+ "name": "alt",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "catalog_caption": {
+ "name": "catalog_caption",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "catalog_description": {
+ "name": "catalog_description",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "catalog_scene": {
+ "name": "catalog_scene",
+ "type": "enum_archive_photo_catalog_scene",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "catalog_visible_text": {
+ "name": "catalog_visible_text",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "catalog_has_people": {
+ "name": "catalog_has_people",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "catalog_municipality_id": {
+ "name": "catalog_municipality_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "catalog_source": {
+ "name": "catalog_source",
+ "type": "enum_archive_photo_catalog_source",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "catalog_cataloged_at": {
+ "name": "catalog_cataloged_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "title": {
+ "name": "title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "description": {
+ "name": "description",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "taken_at": {
+ "name": "taken_at",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "taken_on": {
+ "name": "taken_on",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "posted_at": {
+ "name": "posted_at",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "geo_latitude": {
+ "name": "geo_latitude",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "geo_longitude": {
+ "name": "geo_longitude",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "exif": {
+ "name": "exif",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "source_url": {
+ "name": "source_url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "owner": {
+ "name": "owner",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "license": {
+ "name": "license",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "search_text": {
+ "name": "search_text",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "url": {
+ "name": "url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "thumbnail_u_r_l": {
+ "name": "thumbnail_u_r_l",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filename": {
+ "name": "filename",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "mime_type": {
+ "name": "mime_type",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filesize": {
+ "name": "filesize",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "width": {
+ "name": "width",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "height": {
+ "name": "height",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "focal_x": {
+ "name": "focal_x",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "focal_y": {
+ "name": "focal_y",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "archive_photo_flickr_id_idx": {
+ "name": "archive_photo_flickr_id_idx",
+ "columns": [
+ {
+ "expression": "flickr_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "archive_photo_catalog_catalog_scene_idx": {
+ "name": "archive_photo_catalog_catalog_scene_idx",
+ "columns": [
+ {
+ "expression": "catalog_scene",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "archive_photo_catalog_catalog_municipality_idx": {
+ "name": "archive_photo_catalog_catalog_municipality_idx",
+ "columns": [
+ {
+ "expression": "catalog_municipality_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "archive_photo_catalog_catalog_cataloged_at_idx": {
+ "name": "archive_photo_catalog_catalog_cataloged_at_idx",
+ "columns": [
+ {
+ "expression": "catalog_cataloged_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "archive_photo_taken_on_idx": {
+ "name": "archive_photo_taken_on_idx",
+ "columns": [
+ {
+ "expression": "taken_on",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "archive_photo_updated_at_idx": {
+ "name": "archive_photo_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "archive_photo_created_at_idx": {
+ "name": "archive_photo_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "archive_photo_filename_idx": {
+ "name": "archive_photo_filename_idx",
+ "columns": [
+ {
+ "expression": "filename",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "archive_photo_catalog_municipality_id_municipality_id_fk": {
+ "name": "archive_photo_catalog_municipality_id_municipality_id_fk",
+ "tableFrom": "archive_photo",
+ "tableTo": "municipality",
+ "columnsFrom": [
+ "catalog_municipality_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.archive_photo_texts": {
+ "name": "archive_photo_texts",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "text": {
+ "name": "text",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "archive_photo_texts_order_parent": {
+ "name": "archive_photo_texts_order_parent",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "archive_photo_texts_parent_fk": {
+ "name": "archive_photo_texts_parent_fk",
+ "tableFrom": "archive_photo_texts",
+ "tableTo": "archive_photo",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.content_event": {
+ "name": "content_event",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "type": {
+ "name": "type",
+ "type": "enum_content_event_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "subject_type": {
+ "name": "subject_type",
+ "type": "enum_content_event_subject_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "subject_id": {
+ "name": "subject_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "variant": {
+ "name": "variant",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "content_event_updated_at_idx": {
+ "name": "content_event_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "content_event_created_at_idx": {
+ "name": "content_event_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "subjectType_subjectId_type_idx": {
+ "name": "subjectType_subjectId_type_idx",
+ "columns": [
+ {
+ "expression": "subject_type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "subject_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.recording_topics": {
+ "name": "recording_topics",
+ "schema": "",
+ "columns": {
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "enum_recording_topics",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "recording_topics_order_idx": {
+ "name": "recording_topics_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "recording_topics_parent_idx": {
+ "name": "recording_topics_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "recording_topics_value_idx": {
+ "name": "recording_topics_value_idx",
+ "columns": [
+ {
+ "expression": "value",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "recording_topics_parent_fk": {
+ "name": "recording_topics_parent_fk",
+ "tableFrom": "recording_topics",
+ "tableTo": "recording",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.recording_scopes": {
+ "name": "recording_scopes",
+ "schema": "",
+ "columns": {
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "enum_recording_scopes",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "recording_scopes_order_idx": {
+ "name": "recording_scopes_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "recording_scopes_parent_idx": {
+ "name": "recording_scopes_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "recording_scopes_value_idx": {
+ "name": "recording_scopes_value_idx",
+ "columns": [
+ {
+ "expression": "value",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "recording_scopes_parent_fk": {
+ "name": "recording_scopes_parent_fk",
+ "tableFrom": "recording_scopes",
+ "tableTo": "recording",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.recording_speaker_labels": {
+ "name": "recording_speaker_labels",
+ "schema": "",
+ "columns": {
+ "_order": {
+ "name": "_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "_parent_id": {
+ "name": "_parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "id": {
+ "name": "id",
+ "type": "varchar",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "speaker_key": {
+ "name": "speaker_key",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "label": {
+ "name": "label",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "recording_speaker_labels_order_idx": {
+ "name": "recording_speaker_labels_order_idx",
+ "columns": [
+ {
+ "expression": "_order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "recording_speaker_labels_parent_id_idx": {
+ "name": "recording_speaker_labels_parent_id_idx",
+ "columns": [
+ {
+ "expression": "_parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "recording_speaker_labels_parent_id_fk": {
+ "name": "recording_speaker_labels_parent_id_fk",
+ "tableFrom": "recording_speaker_labels",
+ "tableTo": "recording",
+ "columnsFrom": [
+ "_parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.recording": {
+ "name": "recording",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "title": {
+ "name": "title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "recorded_at": {
+ "name": "recorded_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "year": {
+ "name": "year",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "status": {
+ "name": "status",
+ "type": "enum_recording_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'uploading'"
+ },
+ "step": {
+ "name": "step",
+ "type": "enum_recording_step",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "media_id": {
+ "name": "media_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "duration_seconds": {
+ "name": "duration_seconds",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "search_text": {
+ "name": "search_text",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "classified_by": {
+ "name": "classified_by",
+ "type": "enum_recording_classified_by",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "speaker_labels_dropped": {
+ "name": "speaker_labels_dropped",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "error": {
+ "name": "error",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_by_id": {
+ "name": "created_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "recording_recorded_at_idx": {
+ "name": "recording_recorded_at_idx",
+ "columns": [
+ {
+ "expression": "recorded_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "recording_year_idx": {
+ "name": "recording_year_idx",
+ "columns": [
+ {
+ "expression": "year",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "recording_status_idx": {
+ "name": "recording_status_idx",
+ "columns": [
+ {
+ "expression": "status",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "recording_media_idx": {
+ "name": "recording_media_idx",
+ "columns": [
+ {
+ "expression": "media_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "recording_classified_by_idx": {
+ "name": "recording_classified_by_idx",
+ "columns": [
+ {
+ "expression": "classified_by",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "recording_created_by_idx": {
+ "name": "recording_created_by_idx",
+ "columns": [
+ {
+ "expression": "created_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "recording_updated_at_idx": {
+ "name": "recording_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "recording_created_at_idx": {
+ "name": "recording_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "recording_media_id_recording_media_id_fk": {
+ "name": "recording_media_id_recording_media_id_fk",
+ "tableFrom": "recording",
+ "tableTo": "recording_media",
+ "columnsFrom": [
+ "media_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "recording_created_by_id_campaign_user_id_fk": {
+ "name": "recording_created_by_id_campaign_user_id_fk",
+ "tableFrom": "recording",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "created_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.recording_texts": {
+ "name": "recording_texts",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "text": {
+ "name": "text",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "recording_texts_order_parent": {
+ "name": "recording_texts_order_parent",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "recording_texts_parent_fk": {
+ "name": "recording_texts_parent_fk",
+ "tableFrom": "recording_texts",
+ "tableTo": "recording",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.recording_rels": {
+ "name": "recording_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "municipality_id": {
+ "name": "municipality_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "recording_rels_order_idx": {
+ "name": "recording_rels_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "recording_rels_parent_idx": {
+ "name": "recording_rels_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "recording_rels_path_idx": {
+ "name": "recording_rels_path_idx",
+ "columns": [
+ {
+ "expression": "path",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "recording_rels_municipality_id_idx": {
+ "name": "recording_rels_municipality_id_idx",
+ "columns": [
+ {
+ "expression": "municipality_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "recording_rels_parent_fk": {
+ "name": "recording_rels_parent_fk",
+ "tableFrom": "recording_rels",
+ "tableTo": "recording",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "recording_rels_municipality_fk": {
+ "name": "recording_rels_municipality_fk",
+ "tableFrom": "recording_rels",
+ "tableTo": "municipality",
+ "columnsFrom": [
+ "municipality_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.recording_media": {
+ "name": "recording_media",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "alt": {
+ "name": "alt",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "url": {
+ "name": "url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "thumbnail_u_r_l": {
+ "name": "thumbnail_u_r_l",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filename": {
+ "name": "filename",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "mime_type": {
+ "name": "mime_type",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filesize": {
+ "name": "filesize",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "width": {
+ "name": "width",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "height": {
+ "name": "height",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "focal_x": {
+ "name": "focal_x",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "focal_y": {
+ "name": "focal_y",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "recording_media_updated_at_idx": {
+ "name": "recording_media_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "recording_media_created_at_idx": {
+ "name": "recording_media_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "recording_media_filename_idx": {
+ "name": "recording_media_filename_idx",
+ "columns": [
+ {
+ "expression": "filename",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.recording_segment": {
+ "name": "recording_segment",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "recording_id": {
+ "name": "recording_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "speaker_key": {
+ "name": "speaker_key",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "start_seconds": {
+ "name": "start_seconds",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "end_seconds": {
+ "name": "end_seconds",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "text": {
+ "name": "text",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "search_text": {
+ "name": "search_text",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "recording_segment_recording_idx": {
+ "name": "recording_segment_recording_idx",
+ "columns": [
+ {
+ "expression": "recording_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "recording_segment_updated_at_idx": {
+ "name": "recording_segment_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "recording_segment_created_at_idx": {
+ "name": "recording_segment_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "recording_segment_recording_id_recording_id_fk": {
+ "name": "recording_segment_recording_id_recording_id_fk",
+ "tableFrom": "recording_segment",
+ "tableTo": "recording",
+ "columnsFrom": [
+ "recording_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.calendar_feed": {
+ "name": "calendar_feed",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "secret_slug": {
+ "name": "secret_slug",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "label": {
+ "name": "label",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "filter_municipality_id": {
+ "name": "filter_municipality_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filter_deputy_present": {
+ "name": "filter_deputy_present",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "filter_tag": {
+ "name": "filter_tag",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "revoked_at": {
+ "name": "revoked_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_by_id": {
+ "name": "created_by_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "calendar_feed_secret_slug_idx": {
+ "name": "calendar_feed_secret_slug_idx",
+ "columns": [
+ {
+ "expression": "secret_slug",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "calendar_feed_filter_municipality_idx": {
+ "name": "calendar_feed_filter_municipality_idx",
+ "columns": [
+ {
+ "expression": "filter_municipality_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "calendar_feed_revoked_at_idx": {
+ "name": "calendar_feed_revoked_at_idx",
+ "columns": [
+ {
+ "expression": "revoked_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "calendar_feed_created_by_idx": {
+ "name": "calendar_feed_created_by_idx",
+ "columns": [
+ {
+ "expression": "created_by_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "calendar_feed_updated_at_idx": {
+ "name": "calendar_feed_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "calendar_feed_created_at_idx": {
+ "name": "calendar_feed_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "calendar_feed_filter_municipality_id_municipality_id_fk": {
+ "name": "calendar_feed_filter_municipality_id_municipality_id_fk",
+ "tableFrom": "calendar_feed",
+ "tableTo": "municipality",
+ "columnsFrom": [
+ "filter_municipality_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "calendar_feed_created_by_id_campaign_user_id_fk": {
+ "name": "calendar_feed_created_by_id_campaign_user_id_fk",
+ "tableFrom": "calendar_feed",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "created_by_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.google_calendar_sync": {
+ "name": "google_calendar_sync",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "calendar_id": {
+ "name": "calendar_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "oauth_refresh_token": {
+ "name": "oauth_refresh_token",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "oauth_scope": {
+ "name": "oauth_scope",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "oauth_connected_at": {
+ "name": "oauth_connected_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "oauth_error_at": {
+ "name": "oauth_error_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "oauth_error": {
+ "name": "oauth_error",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "disabled_at": {
+ "name": "disabled_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_synced_at": {
+ "name": "last_synced_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_success_at": {
+ "name": "last_success_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_error_at": {
+ "name": "last_error_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_error": {
+ "name": "last_error",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "push_channel_id": {
+ "name": "push_channel_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "push_channel_resource_id": {
+ "name": "push_channel_resource_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "push_channel_expires_at": {
+ "name": "push_channel_expires_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "push_channel_secret": {
+ "name": "push_channel_secret",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "push_channel_error": {
+ "name": "push_channel_error",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_seen_event_ids": {
+ "name": "last_seen_event_ids",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "google_calendar_sync_calendar_id_idx": {
+ "name": "google_calendar_sync_calendar_id_idx",
+ "columns": [
+ {
+ "expression": "calendar_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "google_calendar_sync_disabled_at_idx": {
+ "name": "google_calendar_sync_disabled_at_idx",
+ "columns": [
+ {
+ "expression": "disabled_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "google_calendar_sync_updated_at_idx": {
+ "name": "google_calendar_sync_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "google_calendar_sync_created_at_idx": {
+ "name": "google_calendar_sync_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.election_tally": {
+ "name": "election_tally",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "year": {
+ "name": "year",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "office": {
+ "name": "office",
+ "type": "enum_election_tally_office",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "turn": {
+ "name": "turn",
+ "type": "enum_election_tally_turn",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "state": {
+ "name": "state",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'BA'"
+ },
+ "city_code": {
+ "name": "city_code",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "city_name": {
+ "name": "city_name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "zone_number": {
+ "name": "zone_number",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "aptos": {
+ "name": "aptos",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "comparecimento": {
+ "name": "comparecimento",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "abstencoes": {
+ "name": "abstencoes",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "votos_validos": {
+ "name": "votos_validos",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "votos_nominais_validos": {
+ "name": "votos_nominais_validos",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "votos_legenda": {
+ "name": "votos_legenda",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "votos_branco": {
+ "name": "votos_branco",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "votos_nulo": {
+ "name": "votos_nulo",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "votos_anulados": {
+ "name": "votos_anulados",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "winner_candidate_number": {
+ "name": "winner_candidate_number",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "winner_candidate_name": {
+ "name": "winner_candidate_name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "winner_votes": {
+ "name": "winner_votes",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "winner_coalition": {
+ "name": "winner_coalition",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "winner_party": {
+ "name": "winner_party",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "election_tally_year_idx": {
+ "name": "election_tally_year_idx",
+ "columns": [
+ {
+ "expression": "year",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_tally_office_idx": {
+ "name": "election_tally_office_idx",
+ "columns": [
+ {
+ "expression": "office",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_tally_turn_idx": {
+ "name": "election_tally_turn_idx",
+ "columns": [
+ {
+ "expression": "turn",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_tally_state_idx": {
+ "name": "election_tally_state_idx",
+ "columns": [
+ {
+ "expression": "state",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_tally_city_code_idx": {
+ "name": "election_tally_city_code_idx",
+ "columns": [
+ {
+ "expression": "city_code",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_tally_city_name_idx": {
+ "name": "election_tally_city_name_idx",
+ "columns": [
+ {
+ "expression": "city_name",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_tally_zone_number_idx": {
+ "name": "election_tally_zone_number_idx",
+ "columns": [
+ {
+ "expression": "zone_number",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_tally_updated_at_idx": {
+ "name": "election_tally_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_tally_created_at_idx": {
+ "name": "election_tally_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "year_office_turn_state_cityCode_zoneNumber_idx": {
+ "name": "year_office_turn_state_cityCode_zoneNumber_idx",
+ "columns": [
+ {
+ "expression": "year",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "office",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "turn",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "state",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "city_code",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "zone_number",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.election_candidate_vote": {
+ "name": "election_candidate_vote",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "year": {
+ "name": "year",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "office": {
+ "name": "office",
+ "type": "enum_election_candidate_vote_office",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "turn": {
+ "name": "turn",
+ "type": "enum_election_candidate_vote_turn",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "state": {
+ "name": "state",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'BA'"
+ },
+ "city_code": {
+ "name": "city_code",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "city_name": {
+ "name": "city_name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "zone_number": {
+ "name": "zone_number",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "candidate_number": {
+ "name": "candidate_number",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "candidate_name": {
+ "name": "candidate_name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "coalition": {
+ "name": "coalition",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "party": {
+ "name": "party",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "vote_type": {
+ "name": "vote_type",
+ "type": "enum_election_candidate_vote_vote_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'nominal'"
+ },
+ "votes": {
+ "name": "votes",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "election_candidate_vote_year_idx": {
+ "name": "election_candidate_vote_year_idx",
+ "columns": [
+ {
+ "expression": "year",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_candidate_vote_office_idx": {
+ "name": "election_candidate_vote_office_idx",
+ "columns": [
+ {
+ "expression": "office",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_candidate_vote_turn_idx": {
+ "name": "election_candidate_vote_turn_idx",
+ "columns": [
+ {
+ "expression": "turn",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_candidate_vote_state_idx": {
+ "name": "election_candidate_vote_state_idx",
+ "columns": [
+ {
+ "expression": "state",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_candidate_vote_city_code_idx": {
+ "name": "election_candidate_vote_city_code_idx",
+ "columns": [
+ {
+ "expression": "city_code",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_candidate_vote_city_name_idx": {
+ "name": "election_candidate_vote_city_name_idx",
+ "columns": [
+ {
+ "expression": "city_name",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_candidate_vote_zone_number_idx": {
+ "name": "election_candidate_vote_zone_number_idx",
+ "columns": [
+ {
+ "expression": "zone_number",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_candidate_vote_candidate_number_idx": {
+ "name": "election_candidate_vote_candidate_number_idx",
+ "columns": [
+ {
+ "expression": "candidate_number",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_candidate_vote_vote_type_idx": {
+ "name": "election_candidate_vote_vote_type_idx",
+ "columns": [
+ {
+ "expression": "vote_type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_candidate_vote_updated_at_idx": {
+ "name": "election_candidate_vote_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_candidate_vote_created_at_idx": {
+ "name": "election_candidate_vote_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "compound_index_idx": {
+ "name": "compound_index_idx",
+ "columns": [
+ {
+ "expression": "year",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "office",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "turn",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "state",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "city_code",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "zone_number",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "candidate_number",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "vote_type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.election_candidate": {
+ "name": "election_candidate",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "year": {
+ "name": "year",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "office": {
+ "name": "office",
+ "type": "enum_election_candidate_office",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "turn": {
+ "name": "turn",
+ "type": "enum_election_candidate_turn",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "state": {
+ "name": "state",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'BA'"
+ },
+ "candidate_number": {
+ "name": "candidate_number",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "urna_name": {
+ "name": "urna_name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "complete_name": {
+ "name": "complete_name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "party": {
+ "name": "party",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "coalition": {
+ "name": "coalition",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "candidate_status": {
+ "name": "candidate_status",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "elected": {
+ "name": "elected",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "elected_by": {
+ "name": "elected_by",
+ "type": "enum_election_candidate_elected_by",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "total_votes_state": {
+ "name": "total_votes_state",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "identity_key": {
+ "name": "identity_key",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "running_again2026": {
+ "name": "running_again2026",
+ "type": "enum_election_candidate_running_again2026",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'desconhecido'"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "election_candidate_year_idx": {
+ "name": "election_candidate_year_idx",
+ "columns": [
+ {
+ "expression": "year",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_candidate_office_idx": {
+ "name": "election_candidate_office_idx",
+ "columns": [
+ {
+ "expression": "office",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_candidate_turn_idx": {
+ "name": "election_candidate_turn_idx",
+ "columns": [
+ {
+ "expression": "turn",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_candidate_state_idx": {
+ "name": "election_candidate_state_idx",
+ "columns": [
+ {
+ "expression": "state",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_candidate_candidate_number_idx": {
+ "name": "election_candidate_candidate_number_idx",
+ "columns": [
+ {
+ "expression": "candidate_number",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_candidate_elected_idx": {
+ "name": "election_candidate_elected_idx",
+ "columns": [
+ {
+ "expression": "elected",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_candidate_identity_key_idx": {
+ "name": "election_candidate_identity_key_idx",
+ "columns": [
+ {
+ "expression": "identity_key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_candidate_updated_at_idx": {
+ "name": "election_candidate_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "election_candidate_created_at_idx": {
+ "name": "election_candidate_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "year_office_turn_state_candidateNumber_idx": {
+ "name": "year_office_turn_state_candidateNumber_idx",
+ "columns": [
+ {
+ "expression": "year",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "office",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "turn",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "state",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "candidate_number",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.media": {
+ "name": "media",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "alt": {
+ "name": "alt",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "url": {
+ "name": "url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "thumbnail_u_r_l": {
+ "name": "thumbnail_u_r_l",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filename": {
+ "name": "filename",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "mime_type": {
+ "name": "mime_type",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filesize": {
+ "name": "filesize",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "width": {
+ "name": "width",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "height": {
+ "name": "height",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "focal_x": {
+ "name": "focal_x",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "focal_y": {
+ "name": "focal_y",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "media_updated_at_idx": {
+ "name": "media_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "media_created_at_idx": {
+ "name": "media_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "media_filename_idx": {
+ "name": "media_filename_idx",
+ "columns": [
+ {
+ "expression": "filename",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.petition": {
+ "name": "petition",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "varchar",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "title": {
+ "name": "title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "subtitle": {
+ "name": "subtitle",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "enabled": {
+ "name": "enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "body": {
+ "name": "body",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "form_title": {
+ "name": "form_title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "form_subtitle": {
+ "name": "form_subtitle",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "form_consent_id": {
+ "name": "form_consent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "tracking_facebook_pixel_id": {
+ "name": "tracking_facebook_pixel_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "_status": {
+ "name": "_status",
+ "type": "enum_petition_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'draft'"
+ }
+ },
+ "indexes": {
+ "petition_form_form_consent_idx": {
+ "name": "petition_form_form_consent_idx",
+ "columns": [
+ {
+ "expression": "form_consent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "petition_updated_at_idx": {
+ "name": "petition_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "petition_created_at_idx": {
+ "name": "petition_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "petition__status_idx": {
+ "name": "petition__status_idx",
+ "columns": [
+ {
+ "expression": "_status",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "petition_form_consent_id_consent_id_fk": {
+ "name": "petition_form_consent_id_consent_id_fk",
+ "tableFrom": "petition",
+ "tableTo": "consent",
+ "columnsFrom": [
+ "form_consent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public._petition_v": {
+ "name": "_petition_v",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_title": {
+ "name": "version_title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_subtitle": {
+ "name": "version_subtitle",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_enabled": {
+ "name": "version_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "version_body": {
+ "name": "version_body",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_form_title": {
+ "name": "version_form_title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_form_subtitle": {
+ "name": "version_form_subtitle",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_form_consent_id": {
+ "name": "version_form_consent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_tracking_facebook_pixel_id": {
+ "name": "version_tracking_facebook_pixel_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_updated_at": {
+ "name": "version_updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_created_at": {
+ "name": "version_created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version__status": {
+ "name": "version__status",
+ "type": "enum__petition_v_version_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'draft'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "latest": {
+ "name": "latest",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "_petition_v_parent_idx": {
+ "name": "_petition_v_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_petition_v_version_form_version_form_consent_idx": {
+ "name": "_petition_v_version_form_version_form_consent_idx",
+ "columns": [
+ {
+ "expression": "version_form_consent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_petition_v_version_version_updated_at_idx": {
+ "name": "_petition_v_version_version_updated_at_idx",
+ "columns": [
+ {
+ "expression": "version_updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_petition_v_version_version_created_at_idx": {
+ "name": "_petition_v_version_version_created_at_idx",
+ "columns": [
+ {
+ "expression": "version_created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_petition_v_version_version__status_idx": {
+ "name": "_petition_v_version_version__status_idx",
+ "columns": [
+ {
+ "expression": "version__status",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_petition_v_created_at_idx": {
+ "name": "_petition_v_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_petition_v_updated_at_idx": {
+ "name": "_petition_v_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_petition_v_latest_idx": {
+ "name": "_petition_v_latest_idx",
+ "columns": [
+ {
+ "expression": "latest",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "_petition_v_parent_id_petition_id_fk": {
+ "name": "_petition_v_parent_id_petition_id_fk",
+ "tableFrom": "_petition_v",
+ "tableTo": "petition",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "_petition_v_version_form_consent_id_consent_id_fk": {
+ "name": "_petition_v_version_form_consent_id_consent_id_fk",
+ "tableFrom": "_petition_v",
+ "tableTo": "consent",
+ "columnsFrom": [
+ "version_form_consent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.contact_phones": {
+ "name": "contact_phones",
+ "schema": "",
+ "columns": {
+ "_order": {
+ "name": "_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "_parent_id": {
+ "name": "_parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "id": {
+ "name": "id",
+ "type": "varchar",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "contact_phones_order_idx": {
+ "name": "contact_phones_order_idx",
+ "columns": [
+ {
+ "expression": "_order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "contact_phones_parent_id_idx": {
+ "name": "contact_phones_parent_id_idx",
+ "columns": [
+ {
+ "expression": "_parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "contact_phones_value_idx": {
+ "name": "contact_phones_value_idx",
+ "columns": [
+ {
+ "expression": "value",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "contact_phones_parent_id_fk": {
+ "name": "contact_phones_parent_id_fk",
+ "tableFrom": "contact_phones",
+ "tableTo": "contact",
+ "columnsFrom": [
+ "_parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.contact": {
+ "name": "contact",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "email": {
+ "name": "email",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "gender": {
+ "name": "gender",
+ "type": "enum_contact_gender",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "state": {
+ "name": "state",
+ "type": "enum_contact_state",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "city": {
+ "name": "city",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "postal_code": {
+ "name": "postal_code",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "contact_updated_at_idx": {
+ "name": "contact_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "contact_created_at_idx": {
+ "name": "contact_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.consent": {
+ "name": "consent",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "key": {
+ "name": "key",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "text": {
+ "name": "text",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "consent_key_idx": {
+ "name": "consent_key_idx",
+ "columns": [
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "consent_updated_at_idx": {
+ "name": "consent_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "consent_created_at_idx": {
+ "name": "consent_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.signature": {
+ "name": "signature",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "contact_id": {
+ "name": "contact_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "petition_id": {
+ "name": "petition_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "consent_id": {
+ "name": "consent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "comment": {
+ "name": "comment",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "signature_contact_idx": {
+ "name": "signature_contact_idx",
+ "columns": [
+ {
+ "expression": "contact_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "signature_petition_idx": {
+ "name": "signature_petition_idx",
+ "columns": [
+ {
+ "expression": "petition_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "signature_consent_idx": {
+ "name": "signature_consent_idx",
+ "columns": [
+ {
+ "expression": "consent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "signature_updated_at_idx": {
+ "name": "signature_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "signature_created_at_idx": {
+ "name": "signature_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "signature_contact_id_contact_id_fk": {
+ "name": "signature_contact_id_contact_id_fk",
+ "tableFrom": "signature",
+ "tableTo": "contact",
+ "columnsFrom": [
+ "contact_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "signature_petition_id_petition_id_fk": {
+ "name": "signature_petition_id_petition_id_fk",
+ "tableFrom": "signature",
+ "tableTo": "petition",
+ "columnsFrom": [
+ "petition_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "signature_consent_id_consent_id_fk": {
+ "name": "signature_consent_id_consent_id_fk",
+ "tableFrom": "signature",
+ "tableTo": "consent",
+ "columnsFrom": [
+ "consent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.subscription": {
+ "name": "subscription",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "contact_id": {
+ "name": "contact_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "consent_id": {
+ "name": "consent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "comment": {
+ "name": "comment",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "campaign_level": {
+ "name": "campaign_level",
+ "type": "enum_subscription_campaign_level",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "subscription_contact_idx": {
+ "name": "subscription_contact_idx",
+ "columns": [
+ {
+ "expression": "contact_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "subscription_consent_idx": {
+ "name": "subscription_consent_idx",
+ "columns": [
+ {
+ "expression": "consent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "subscription_updated_at_idx": {
+ "name": "subscription_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "subscription_created_at_idx": {
+ "name": "subscription_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "subscription_contact_id_contact_id_fk": {
+ "name": "subscription_contact_id_contact_id_fk",
+ "tableFrom": "subscription",
+ "tableTo": "contact",
+ "columnsFrom": [
+ "contact_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "subscription_consent_id_consent_id_fk": {
+ "name": "subscription_consent_id_consent_id_fk",
+ "tableFrom": "subscription",
+ "tableTo": "consent",
+ "columnsFrom": [
+ "consent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.post": {
+ "name": "post",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "title": {
+ "name": "title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "slug": {
+ "name": "slug",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "type": {
+ "name": "type",
+ "type": "enum_post_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "category_id": {
+ "name": "category_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "subtitle": {
+ "name": "subtitle",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cover_image_id": {
+ "name": "cover_image_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "published_date": {
+ "name": "published_date",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "body": {
+ "name": "body",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "_status": {
+ "name": "_status",
+ "type": "enum_post_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'draft'"
+ }
+ },
+ "indexes": {
+ "post_slug_idx": {
+ "name": "post_slug_idx",
+ "columns": [
+ {
+ "expression": "slug",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "post_category_idx": {
+ "name": "post_category_idx",
+ "columns": [
+ {
+ "expression": "category_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "post_cover_image_idx": {
+ "name": "post_cover_image_idx",
+ "columns": [
+ {
+ "expression": "cover_image_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "post_updated_at_idx": {
+ "name": "post_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "post_created_at_idx": {
+ "name": "post_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "post__status_idx": {
+ "name": "post__status_idx",
+ "columns": [
+ {
+ "expression": "_status",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "post_category_id_tag_id_fk": {
+ "name": "post_category_id_tag_id_fk",
+ "tableFrom": "post",
+ "tableTo": "tag",
+ "columnsFrom": [
+ "category_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "post_cover_image_id_media_id_fk": {
+ "name": "post_cover_image_id_media_id_fk",
+ "tableFrom": "post",
+ "tableTo": "media",
+ "columnsFrom": [
+ "cover_image_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.post_rels": {
+ "name": "post_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "tag_id": {
+ "name": "tag_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "post_rels_order_idx": {
+ "name": "post_rels_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "post_rels_parent_idx": {
+ "name": "post_rels_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "post_rels_path_idx": {
+ "name": "post_rels_path_idx",
+ "columns": [
+ {
+ "expression": "path",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "post_rels_tag_id_idx": {
+ "name": "post_rels_tag_id_idx",
+ "columns": [
+ {
+ "expression": "tag_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "post_rels_parent_fk": {
+ "name": "post_rels_parent_fk",
+ "tableFrom": "post_rels",
+ "tableTo": "post",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "post_rels_tag_fk": {
+ "name": "post_rels_tag_fk",
+ "tableFrom": "post_rels",
+ "tableTo": "tag",
+ "columnsFrom": [
+ "tag_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public._post_v": {
+ "name": "_post_v",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_title": {
+ "name": "version_title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_slug": {
+ "name": "version_slug",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_type": {
+ "name": "version_type",
+ "type": "enum__post_v_version_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_category_id": {
+ "name": "version_category_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_subtitle": {
+ "name": "version_subtitle",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_cover_image_id": {
+ "name": "version_cover_image_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_published_date": {
+ "name": "version_published_date",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_body": {
+ "name": "version_body",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_updated_at": {
+ "name": "version_updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_created_at": {
+ "name": "version_created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version__status": {
+ "name": "version__status",
+ "type": "enum__post_v_version_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'draft'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "latest": {
+ "name": "latest",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "_post_v_parent_idx": {
+ "name": "_post_v_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_post_v_version_version_slug_idx": {
+ "name": "_post_v_version_version_slug_idx",
+ "columns": [
+ {
+ "expression": "version_slug",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_post_v_version_version_category_idx": {
+ "name": "_post_v_version_version_category_idx",
+ "columns": [
+ {
+ "expression": "version_category_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_post_v_version_version_cover_image_idx": {
+ "name": "_post_v_version_version_cover_image_idx",
+ "columns": [
+ {
+ "expression": "version_cover_image_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_post_v_version_version_updated_at_idx": {
+ "name": "_post_v_version_version_updated_at_idx",
+ "columns": [
+ {
+ "expression": "version_updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_post_v_version_version_created_at_idx": {
+ "name": "_post_v_version_version_created_at_idx",
+ "columns": [
+ {
+ "expression": "version_created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_post_v_version_version__status_idx": {
+ "name": "_post_v_version_version__status_idx",
+ "columns": [
+ {
+ "expression": "version__status",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_post_v_created_at_idx": {
+ "name": "_post_v_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_post_v_updated_at_idx": {
+ "name": "_post_v_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_post_v_latest_idx": {
+ "name": "_post_v_latest_idx",
+ "columns": [
+ {
+ "expression": "latest",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "_post_v_parent_id_post_id_fk": {
+ "name": "_post_v_parent_id_post_id_fk",
+ "tableFrom": "_post_v",
+ "tableTo": "post",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "_post_v_version_category_id_tag_id_fk": {
+ "name": "_post_v_version_category_id_tag_id_fk",
+ "tableFrom": "_post_v",
+ "tableTo": "tag",
+ "columnsFrom": [
+ "version_category_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "_post_v_version_cover_image_id_media_id_fk": {
+ "name": "_post_v_version_cover_image_id_media_id_fk",
+ "tableFrom": "_post_v",
+ "tableTo": "media",
+ "columnsFrom": [
+ "version_cover_image_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public._post_v_rels": {
+ "name": "_post_v_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "tag_id": {
+ "name": "tag_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "_post_v_rels_order_idx": {
+ "name": "_post_v_rels_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_post_v_rels_parent_idx": {
+ "name": "_post_v_rels_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_post_v_rels_path_idx": {
+ "name": "_post_v_rels_path_idx",
+ "columns": [
+ {
+ "expression": "path",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_post_v_rels_tag_id_idx": {
+ "name": "_post_v_rels_tag_id_idx",
+ "columns": [
+ {
+ "expression": "tag_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "_post_v_rels_parent_fk": {
+ "name": "_post_v_rels_parent_fk",
+ "tableFrom": "_post_v_rels",
+ "tableTo": "_post_v",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "_post_v_rels_tag_fk": {
+ "name": "_post_v_rels_tag_fk",
+ "tableFrom": "_post_v_rels",
+ "tableTo": "tag",
+ "columnsFrom": [
+ "tag_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.tag": {
+ "name": "tag",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "slug": {
+ "name": "slug",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "hidden": {
+ "name": "hidden",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "tag_slug_idx": {
+ "name": "tag_slug_idx",
+ "columns": [
+ {
+ "expression": "slug",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "tag_updated_at_idx": {
+ "name": "tag_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "tag_created_at_idx": {
+ "name": "tag_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.share_link_destinations": {
+ "name": "share_link_destinations",
+ "schema": "",
+ "columns": {
+ "_order": {
+ "name": "_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "_parent_id": {
+ "name": "_parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "id": {
+ "name": "id",
+ "type": "varchar",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "label": {
+ "name": "label",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "url": {
+ "name": "url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "live": {
+ "name": "live",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ }
+ },
+ "indexes": {
+ "share_link_destinations_order_idx": {
+ "name": "share_link_destinations_order_idx",
+ "columns": [
+ {
+ "expression": "_order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "share_link_destinations_parent_id_idx": {
+ "name": "share_link_destinations_parent_id_idx",
+ "columns": [
+ {
+ "expression": "_parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "share_link_destinations_parent_id_fk": {
+ "name": "share_link_destinations_parent_id_fk",
+ "tableFrom": "share_link_destinations",
+ "tableTo": "share_link",
+ "columnsFrom": [
+ "_parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.share_link": {
+ "name": "share_link",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "title": {
+ "name": "title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "slug": {
+ "name": "slug",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "mode": {
+ "name": "mode",
+ "type": "enum_share_link_mode",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'direct'"
+ },
+ "description": {
+ "name": "description",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "image_id": {
+ "name": "image_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "starts_at": {
+ "name": "starts_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "ends_at": {
+ "name": "ends_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "location": {
+ "name": "location",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "published": {
+ "name": "published",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "share_link_slug_idx": {
+ "name": "share_link_slug_idx",
+ "columns": [
+ {
+ "expression": "slug",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "share_link_image_idx": {
+ "name": "share_link_image_idx",
+ "columns": [
+ {
+ "expression": "image_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "share_link_updated_at_idx": {
+ "name": "share_link_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "share_link_created_at_idx": {
+ "name": "share_link_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "share_link_image_id_media_id_fk": {
+ "name": "share_link_image_id_media_id_fk",
+ "tableFrom": "share_link",
+ "tableTo": "media",
+ "columnsFrom": [
+ "image_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.jingle": {
+ "name": "jingle",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "title": {
+ "name": "title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "slug": {
+ "name": "slug",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cover_image_id": {
+ "name": "cover_image_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "audio_id": {
+ "name": "audio_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "published": {
+ "name": "published",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "jingle_slug_idx": {
+ "name": "jingle_slug_idx",
+ "columns": [
+ {
+ "expression": "slug",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "jingle_cover_image_idx": {
+ "name": "jingle_cover_image_idx",
+ "columns": [
+ {
+ "expression": "cover_image_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "jingle_audio_idx": {
+ "name": "jingle_audio_idx",
+ "columns": [
+ {
+ "expression": "audio_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "jingle_updated_at_idx": {
+ "name": "jingle_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "jingle_created_at_idx": {
+ "name": "jingle_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "jingle_cover_image_id_media_id_fk": {
+ "name": "jingle_cover_image_id_media_id_fk",
+ "tableFrom": "jingle",
+ "tableTo": "media",
+ "columnsFrom": [
+ "cover_image_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "jingle_audio_id_media_id_fk": {
+ "name": "jingle_audio_id_media_id_fk",
+ "tableFrom": "jingle",
+ "tableTo": "media",
+ "columnsFrom": [
+ "audio_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.exports": {
+ "name": "exports",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "format": {
+ "name": "format",
+ "type": "enum_exports_format",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'csv'"
+ },
+ "limit": {
+ "name": "limit",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "page": {
+ "name": "page",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 1
+ },
+ "sort": {
+ "name": "sort",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "sort_order": {
+ "name": "sort_order",
+ "type": "enum_exports_sort_order",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "drafts": {
+ "name": "drafts",
+ "type": "enum_exports_drafts",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'yes'"
+ },
+ "collection_slug": {
+ "name": "collection_slug",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'signature'"
+ },
+ "where": {
+ "name": "where",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'{}'::jsonb"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "url": {
+ "name": "url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "thumbnail_u_r_l": {
+ "name": "thumbnail_u_r_l",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filename": {
+ "name": "filename",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "mime_type": {
+ "name": "mime_type",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filesize": {
+ "name": "filesize",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "width": {
+ "name": "width",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "height": {
+ "name": "height",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "focal_x": {
+ "name": "focal_x",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "focal_y": {
+ "name": "focal_y",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "exports_updated_at_idx": {
+ "name": "exports_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "exports_created_at_idx": {
+ "name": "exports_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "exports_filename_idx": {
+ "name": "exports_filename_idx",
+ "columns": [
+ {
+ "expression": "filename",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.exports_texts": {
+ "name": "exports_texts",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "text": {
+ "name": "text",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "exports_texts_order_parent": {
+ "name": "exports_texts_order_parent",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "exports_texts_parent_fk": {
+ "name": "exports_texts_parent_fk",
+ "tableFrom": "exports_texts",
+ "tableTo": "exports",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.imports": {
+ "name": "imports",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "collection_slug": {
+ "name": "collection_slug",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "import_mode": {
+ "name": "import_mode",
+ "type": "enum_imports_import_mode",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "match_field": {
+ "name": "match_field",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'id'"
+ },
+ "status": {
+ "name": "status",
+ "type": "enum_imports_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'pending'"
+ },
+ "summary_imported": {
+ "name": "summary_imported",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "summary_updated": {
+ "name": "summary_updated",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "summary_total": {
+ "name": "summary_total",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "summary_issues": {
+ "name": "summary_issues",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "summary_issue_details": {
+ "name": "summary_issue_details",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "url": {
+ "name": "url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "thumbnail_u_r_l": {
+ "name": "thumbnail_u_r_l",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filename": {
+ "name": "filename",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "mime_type": {
+ "name": "mime_type",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filesize": {
+ "name": "filesize",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "width": {
+ "name": "width",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "height": {
+ "name": "height",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "focal_x": {
+ "name": "focal_x",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "focal_y": {
+ "name": "focal_y",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "imports_updated_at_idx": {
+ "name": "imports_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "imports_created_at_idx": {
+ "name": "imports_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "imports_filename_idx": {
+ "name": "imports_filename_idx",
+ "columns": [
+ {
+ "expression": "filename",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.payload_kv": {
+ "name": "payload_kv",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "key": {
+ "name": "key",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "data": {
+ "name": "data",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "payload_kv_key_idx": {
+ "name": "payload_kv_key_idx",
+ "columns": [
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.payload_jobs_log": {
+ "name": "payload_jobs_log",
+ "schema": "",
+ "columns": {
+ "_order": {
+ "name": "_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "_parent_id": {
+ "name": "_parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "id": {
+ "name": "id",
+ "type": "varchar",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "executed_at": {
+ "name": "executed_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "completed_at": {
+ "name": "completed_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "task_slug": {
+ "name": "task_slug",
+ "type": "enum_payload_jobs_log_task_slug",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "task_i_d": {
+ "name": "task_i_d",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "input": {
+ "name": "input",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "output": {
+ "name": "output",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "state": {
+ "name": "state",
+ "type": "enum_payload_jobs_log_state",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "error": {
+ "name": "error",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "payload_jobs_log_order_idx": {
+ "name": "payload_jobs_log_order_idx",
+ "columns": [
+ {
+ "expression": "_order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_jobs_log_parent_id_idx": {
+ "name": "payload_jobs_log_parent_id_idx",
+ "columns": [
+ {
+ "expression": "_parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "payload_jobs_log_parent_id_fk": {
+ "name": "payload_jobs_log_parent_id_fk",
+ "tableFrom": "payload_jobs_log",
+ "tableTo": "payload_jobs",
+ "columnsFrom": [
+ "_parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.payload_jobs": {
+ "name": "payload_jobs",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "input": {
+ "name": "input",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "completed_at": {
+ "name": "completed_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "total_tried": {
+ "name": "total_tried",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 0
+ },
+ "has_error": {
+ "name": "has_error",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "error": {
+ "name": "error",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "task_slug": {
+ "name": "task_slug",
+ "type": "enum_payload_jobs_task_slug",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "queue": {
+ "name": "queue",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'default'"
+ },
+ "wait_until": {
+ "name": "wait_until",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "processing": {
+ "name": "processing",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "payload_jobs_completed_at_idx": {
+ "name": "payload_jobs_completed_at_idx",
+ "columns": [
+ {
+ "expression": "completed_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_jobs_total_tried_idx": {
+ "name": "payload_jobs_total_tried_idx",
+ "columns": [
+ {
+ "expression": "total_tried",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_jobs_has_error_idx": {
+ "name": "payload_jobs_has_error_idx",
+ "columns": [
+ {
+ "expression": "has_error",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_jobs_task_slug_idx": {
+ "name": "payload_jobs_task_slug_idx",
+ "columns": [
+ {
+ "expression": "task_slug",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_jobs_queue_idx": {
+ "name": "payload_jobs_queue_idx",
+ "columns": [
+ {
+ "expression": "queue",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_jobs_wait_until_idx": {
+ "name": "payload_jobs_wait_until_idx",
+ "columns": [
+ {
+ "expression": "wait_until",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_jobs_processing_idx": {
+ "name": "payload_jobs_processing_idx",
+ "columns": [
+ {
+ "expression": "processing",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_jobs_updated_at_idx": {
+ "name": "payload_jobs_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_jobs_created_at_idx": {
+ "name": "payload_jobs_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.payload_locked_documents": {
+ "name": "payload_locked_documents",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "global_slug": {
+ "name": "global_slug",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "payload_locked_documents_global_slug_idx": {
+ "name": "payload_locked_documents_global_slug_idx",
+ "columns": [
+ {
+ "expression": "global_slug",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_updated_at_idx": {
+ "name": "payload_locked_documents_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_created_at_idx": {
+ "name": "payload_locked_documents_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.payload_locked_documents_rels": {
+ "name": "payload_locked_documents_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "users_id": {
+ "name": "users_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "campaign_user_id": {
+ "name": "campaign_user_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "campaign_web_authn_credential_id": {
+ "name": "campaign_web_authn_credential_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "notification_id": {
+ "name": "notification_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "push_subscription_id": {
+ "name": "push_subscription_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "campaign_invite_id": {
+ "name": "campaign_invite_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "campaign_vote_summary_snapshot_id": {
+ "name": "campaign_vote_summary_snapshot_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "municipality_id": {
+ "name": "municipality_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "leadership_id": {
+ "name": "leadership_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "organization_id": {
+ "name": "organization_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "state_deputy_id": {
+ "name": "state_deputy_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "vote_pledge_id": {
+ "name": "vote_pledge_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "allocation_decision_id": {
+ "name": "allocation_decision_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "campaign_demand_id": {
+ "name": "campaign_demand_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "supporter_id": {
+ "name": "supporter_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "supporter_import_batch_id": {
+ "name": "supporter_import_batch_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "municipality_update_id": {
+ "name": "municipality_update_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "activity_id": {
+ "name": "activity_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "speech_id": {
+ "name": "speech_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "speech_segment_id": {
+ "name": "speech_segment_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "speech_cut_id": {
+ "name": "speech_cut_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "speech_embedding_id": {
+ "name": "speech_embedding_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "internet_speech_media_id": {
+ "name": "internet_speech_media_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "reel_id": {
+ "name": "reel_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "reel_media_id": {
+ "name": "reel_media_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "content_piece_id": {
+ "name": "content_piece_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "content_media_id": {
+ "name": "content_media_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "archive_photo_id": {
+ "name": "archive_photo_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "content_event_id": {
+ "name": "content_event_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "recording_id": {
+ "name": "recording_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "recording_media_id": {
+ "name": "recording_media_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "recording_segment_id": {
+ "name": "recording_segment_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "calendar_feed_id": {
+ "name": "calendar_feed_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "google_calendar_sync_id": {
+ "name": "google_calendar_sync_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "election_tally_id": {
+ "name": "election_tally_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "election_candidate_vote_id": {
+ "name": "election_candidate_vote_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "election_candidate_id": {
+ "name": "election_candidate_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "media_id": {
+ "name": "media_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "petition_id": {
+ "name": "petition_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "contact_id": {
+ "name": "contact_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "consent_id": {
+ "name": "consent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "signature_id": {
+ "name": "signature_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "subscription_id": {
+ "name": "subscription_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "post_id": {
+ "name": "post_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "tag_id": {
+ "name": "tag_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "share_link_id": {
+ "name": "share_link_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "jingle_id": {
+ "name": "jingle_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "payload_locked_documents_rels_order_idx": {
+ "name": "payload_locked_documents_rels_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_parent_idx": {
+ "name": "payload_locked_documents_rels_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_path_idx": {
+ "name": "payload_locked_documents_rels_path_idx",
+ "columns": [
+ {
+ "expression": "path",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_users_id_idx": {
+ "name": "payload_locked_documents_rels_users_id_idx",
+ "columns": [
+ {
+ "expression": "users_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_campaign_user_id_idx": {
+ "name": "payload_locked_documents_rels_campaign_user_id_idx",
+ "columns": [
+ {
+ "expression": "campaign_user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_campaign_web_authn_credent_idx": {
+ "name": "payload_locked_documents_rels_campaign_web_authn_credent_idx",
+ "columns": [
+ {
+ "expression": "campaign_web_authn_credential_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_notification_id_idx": {
+ "name": "payload_locked_documents_rels_notification_id_idx",
+ "columns": [
+ {
+ "expression": "notification_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_push_subscription_id_idx": {
+ "name": "payload_locked_documents_rels_push_subscription_id_idx",
+ "columns": [
+ {
+ "expression": "push_subscription_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_campaign_invite_id_idx": {
+ "name": "payload_locked_documents_rels_campaign_invite_id_idx",
+ "columns": [
+ {
+ "expression": "campaign_invite_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_campaign_vote_summary_snap_idx": {
+ "name": "payload_locked_documents_rels_campaign_vote_summary_snap_idx",
+ "columns": [
+ {
+ "expression": "campaign_vote_summary_snapshot_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_municipality_id_idx": {
+ "name": "payload_locked_documents_rels_municipality_id_idx",
+ "columns": [
+ {
+ "expression": "municipality_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_leadership_id_idx": {
+ "name": "payload_locked_documents_rels_leadership_id_idx",
+ "columns": [
+ {
+ "expression": "leadership_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_organization_id_idx": {
+ "name": "payload_locked_documents_rels_organization_id_idx",
+ "columns": [
+ {
+ "expression": "organization_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_state_deputy_id_idx": {
+ "name": "payload_locked_documents_rels_state_deputy_id_idx",
+ "columns": [
+ {
+ "expression": "state_deputy_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_vote_pledge_id_idx": {
+ "name": "payload_locked_documents_rels_vote_pledge_id_idx",
+ "columns": [
+ {
+ "expression": "vote_pledge_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_allocation_decision_id_idx": {
+ "name": "payload_locked_documents_rels_allocation_decision_id_idx",
+ "columns": [
+ {
+ "expression": "allocation_decision_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_campaign_demand_id_idx": {
+ "name": "payload_locked_documents_rels_campaign_demand_id_idx",
+ "columns": [
+ {
+ "expression": "campaign_demand_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_supporter_id_idx": {
+ "name": "payload_locked_documents_rels_supporter_id_idx",
+ "columns": [
+ {
+ "expression": "supporter_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_supporter_import_batch_id_idx": {
+ "name": "payload_locked_documents_rels_supporter_import_batch_id_idx",
+ "columns": [
+ {
+ "expression": "supporter_import_batch_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_municipality_update_id_idx": {
+ "name": "payload_locked_documents_rels_municipality_update_id_idx",
+ "columns": [
+ {
+ "expression": "municipality_update_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_activity_id_idx": {
+ "name": "payload_locked_documents_rels_activity_id_idx",
+ "columns": [
+ {
+ "expression": "activity_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_speech_id_idx": {
+ "name": "payload_locked_documents_rels_speech_id_idx",
+ "columns": [
+ {
+ "expression": "speech_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_speech_segment_id_idx": {
+ "name": "payload_locked_documents_rels_speech_segment_id_idx",
+ "columns": [
+ {
+ "expression": "speech_segment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_speech_cut_id_idx": {
+ "name": "payload_locked_documents_rels_speech_cut_id_idx",
+ "columns": [
+ {
+ "expression": "speech_cut_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_speech_embedding_id_idx": {
+ "name": "payload_locked_documents_rels_speech_embedding_id_idx",
+ "columns": [
+ {
+ "expression": "speech_embedding_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_internet_speech_media_id_idx": {
+ "name": "payload_locked_documents_rels_internet_speech_media_id_idx",
+ "columns": [
+ {
+ "expression": "internet_speech_media_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_reel_id_idx": {
+ "name": "payload_locked_documents_rels_reel_id_idx",
+ "columns": [
+ {
+ "expression": "reel_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_reel_media_id_idx": {
+ "name": "payload_locked_documents_rels_reel_media_id_idx",
+ "columns": [
+ {
+ "expression": "reel_media_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_content_piece_id_idx": {
+ "name": "payload_locked_documents_rels_content_piece_id_idx",
+ "columns": [
+ {
+ "expression": "content_piece_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_content_media_id_idx": {
+ "name": "payload_locked_documents_rels_content_media_id_idx",
+ "columns": [
+ {
+ "expression": "content_media_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_archive_photo_id_idx": {
+ "name": "payload_locked_documents_rels_archive_photo_id_idx",
+ "columns": [
+ {
+ "expression": "archive_photo_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_content_event_id_idx": {
+ "name": "payload_locked_documents_rels_content_event_id_idx",
+ "columns": [
+ {
+ "expression": "content_event_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_recording_id_idx": {
+ "name": "payload_locked_documents_rels_recording_id_idx",
+ "columns": [
+ {
+ "expression": "recording_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_recording_media_id_idx": {
+ "name": "payload_locked_documents_rels_recording_media_id_idx",
+ "columns": [
+ {
+ "expression": "recording_media_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_recording_segment_id_idx": {
+ "name": "payload_locked_documents_rels_recording_segment_id_idx",
+ "columns": [
+ {
+ "expression": "recording_segment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_calendar_feed_id_idx": {
+ "name": "payload_locked_documents_rels_calendar_feed_id_idx",
+ "columns": [
+ {
+ "expression": "calendar_feed_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_google_calendar_sync_id_idx": {
+ "name": "payload_locked_documents_rels_google_calendar_sync_id_idx",
+ "columns": [
+ {
+ "expression": "google_calendar_sync_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_election_tally_id_idx": {
+ "name": "payload_locked_documents_rels_election_tally_id_idx",
+ "columns": [
+ {
+ "expression": "election_tally_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_election_candidate_vote_id_idx": {
+ "name": "payload_locked_documents_rels_election_candidate_vote_id_idx",
+ "columns": [
+ {
+ "expression": "election_candidate_vote_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_election_candidate_id_idx": {
+ "name": "payload_locked_documents_rels_election_candidate_id_idx",
+ "columns": [
+ {
+ "expression": "election_candidate_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_media_id_idx": {
+ "name": "payload_locked_documents_rels_media_id_idx",
+ "columns": [
+ {
+ "expression": "media_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_petition_id_idx": {
+ "name": "payload_locked_documents_rels_petition_id_idx",
+ "columns": [
+ {
+ "expression": "petition_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_contact_id_idx": {
+ "name": "payload_locked_documents_rels_contact_id_idx",
+ "columns": [
+ {
+ "expression": "contact_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_consent_id_idx": {
+ "name": "payload_locked_documents_rels_consent_id_idx",
+ "columns": [
+ {
+ "expression": "consent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_signature_id_idx": {
+ "name": "payload_locked_documents_rels_signature_id_idx",
+ "columns": [
+ {
+ "expression": "signature_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_subscription_id_idx": {
+ "name": "payload_locked_documents_rels_subscription_id_idx",
+ "columns": [
+ {
+ "expression": "subscription_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_post_id_idx": {
+ "name": "payload_locked_documents_rels_post_id_idx",
+ "columns": [
+ {
+ "expression": "post_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_tag_id_idx": {
+ "name": "payload_locked_documents_rels_tag_id_idx",
+ "columns": [
+ {
+ "expression": "tag_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_share_link_id_idx": {
+ "name": "payload_locked_documents_rels_share_link_id_idx",
+ "columns": [
+ {
+ "expression": "share_link_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_locked_documents_rels_jingle_id_idx": {
+ "name": "payload_locked_documents_rels_jingle_id_idx",
+ "columns": [
+ {
+ "expression": "jingle_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "payload_locked_documents_rels_parent_fk": {
+ "name": "payload_locked_documents_rels_parent_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "payload_locked_documents",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_users_fk": {
+ "name": "payload_locked_documents_rels_users_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "users",
+ "columnsFrom": [
+ "users_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_campaign_user_fk": {
+ "name": "payload_locked_documents_rels_campaign_user_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "campaign_user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_campaign_web_authn_credenti_fk": {
+ "name": "payload_locked_documents_rels_campaign_web_authn_credenti_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "campaign_web_authn_credential",
+ "columnsFrom": [
+ "campaign_web_authn_credential_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_notification_fk": {
+ "name": "payload_locked_documents_rels_notification_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "notification",
+ "columnsFrom": [
+ "notification_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_push_subscription_fk": {
+ "name": "payload_locked_documents_rels_push_subscription_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "push_subscription",
+ "columnsFrom": [
+ "push_subscription_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_campaign_invite_fk": {
+ "name": "payload_locked_documents_rels_campaign_invite_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "campaign_invite",
+ "columnsFrom": [
+ "campaign_invite_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_campaign_vote_summary_snaps_fk": {
+ "name": "payload_locked_documents_rels_campaign_vote_summary_snaps_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "campaign_vote_summary_snapshot",
+ "columnsFrom": [
+ "campaign_vote_summary_snapshot_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_municipality_fk": {
+ "name": "payload_locked_documents_rels_municipality_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "municipality",
+ "columnsFrom": [
+ "municipality_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_leadership_fk": {
+ "name": "payload_locked_documents_rels_leadership_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "leadership",
+ "columnsFrom": [
+ "leadership_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_organization_fk": {
+ "name": "payload_locked_documents_rels_organization_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "organization",
+ "columnsFrom": [
+ "organization_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_state_deputy_fk": {
+ "name": "payload_locked_documents_rels_state_deputy_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "state_deputy",
+ "columnsFrom": [
+ "state_deputy_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_vote_pledge_fk": {
+ "name": "payload_locked_documents_rels_vote_pledge_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "vote_pledge",
+ "columnsFrom": [
+ "vote_pledge_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_allocation_decision_fk": {
+ "name": "payload_locked_documents_rels_allocation_decision_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "allocation_decision",
+ "columnsFrom": [
+ "allocation_decision_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_campaign_demand_fk": {
+ "name": "payload_locked_documents_rels_campaign_demand_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "campaign_demand",
+ "columnsFrom": [
+ "campaign_demand_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_supporter_fk": {
+ "name": "payload_locked_documents_rels_supporter_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "supporter",
+ "columnsFrom": [
+ "supporter_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_supporter_import_batch_fk": {
+ "name": "payload_locked_documents_rels_supporter_import_batch_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "supporter_import_batch",
+ "columnsFrom": [
+ "supporter_import_batch_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_municipality_update_fk": {
+ "name": "payload_locked_documents_rels_municipality_update_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "municipality_update",
+ "columnsFrom": [
+ "municipality_update_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_activity_fk": {
+ "name": "payload_locked_documents_rels_activity_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "activity",
+ "columnsFrom": [
+ "activity_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_speech_fk": {
+ "name": "payload_locked_documents_rels_speech_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "speech",
+ "columnsFrom": [
+ "speech_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_speech_segment_fk": {
+ "name": "payload_locked_documents_rels_speech_segment_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "speech_segment",
+ "columnsFrom": [
+ "speech_segment_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_speech_cut_fk": {
+ "name": "payload_locked_documents_rels_speech_cut_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "speech_cut",
+ "columnsFrom": [
+ "speech_cut_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_speech_embedding_fk": {
+ "name": "payload_locked_documents_rels_speech_embedding_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "speech_embedding",
+ "columnsFrom": [
+ "speech_embedding_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_internet_speech_media_fk": {
+ "name": "payload_locked_documents_rels_internet_speech_media_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "internet_speech_media",
+ "columnsFrom": [
+ "internet_speech_media_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_reel_fk": {
+ "name": "payload_locked_documents_rels_reel_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "reel",
+ "columnsFrom": [
+ "reel_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_reel_media_fk": {
+ "name": "payload_locked_documents_rels_reel_media_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "reel_media",
+ "columnsFrom": [
+ "reel_media_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_content_piece_fk": {
+ "name": "payload_locked_documents_rels_content_piece_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "content_piece",
+ "columnsFrom": [
+ "content_piece_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_content_media_fk": {
+ "name": "payload_locked_documents_rels_content_media_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "content_media",
+ "columnsFrom": [
+ "content_media_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_archive_photo_fk": {
+ "name": "payload_locked_documents_rels_archive_photo_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "archive_photo",
+ "columnsFrom": [
+ "archive_photo_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_content_event_fk": {
+ "name": "payload_locked_documents_rels_content_event_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "content_event",
+ "columnsFrom": [
+ "content_event_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_recording_fk": {
+ "name": "payload_locked_documents_rels_recording_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "recording",
+ "columnsFrom": [
+ "recording_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_recording_media_fk": {
+ "name": "payload_locked_documents_rels_recording_media_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "recording_media",
+ "columnsFrom": [
+ "recording_media_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_recording_segment_fk": {
+ "name": "payload_locked_documents_rels_recording_segment_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "recording_segment",
+ "columnsFrom": [
+ "recording_segment_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_calendar_feed_fk": {
+ "name": "payload_locked_documents_rels_calendar_feed_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "calendar_feed",
+ "columnsFrom": [
+ "calendar_feed_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_google_calendar_sync_fk": {
+ "name": "payload_locked_documents_rels_google_calendar_sync_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "google_calendar_sync",
+ "columnsFrom": [
+ "google_calendar_sync_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_election_tally_fk": {
+ "name": "payload_locked_documents_rels_election_tally_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "election_tally",
+ "columnsFrom": [
+ "election_tally_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_election_candidate_vote_fk": {
+ "name": "payload_locked_documents_rels_election_candidate_vote_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "election_candidate_vote",
+ "columnsFrom": [
+ "election_candidate_vote_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_election_candidate_fk": {
+ "name": "payload_locked_documents_rels_election_candidate_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "election_candidate",
+ "columnsFrom": [
+ "election_candidate_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_media_fk": {
+ "name": "payload_locked_documents_rels_media_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "media",
+ "columnsFrom": [
+ "media_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_petition_fk": {
+ "name": "payload_locked_documents_rels_petition_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "petition",
+ "columnsFrom": [
+ "petition_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_contact_fk": {
+ "name": "payload_locked_documents_rels_contact_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "contact",
+ "columnsFrom": [
+ "contact_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_consent_fk": {
+ "name": "payload_locked_documents_rels_consent_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "consent",
+ "columnsFrom": [
+ "consent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_signature_fk": {
+ "name": "payload_locked_documents_rels_signature_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "signature",
+ "columnsFrom": [
+ "signature_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_subscription_fk": {
+ "name": "payload_locked_documents_rels_subscription_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "subscription",
+ "columnsFrom": [
+ "subscription_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_post_fk": {
+ "name": "payload_locked_documents_rels_post_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "post",
+ "columnsFrom": [
+ "post_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_tag_fk": {
+ "name": "payload_locked_documents_rels_tag_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "tag",
+ "columnsFrom": [
+ "tag_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_share_link_fk": {
+ "name": "payload_locked_documents_rels_share_link_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "share_link",
+ "columnsFrom": [
+ "share_link_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_locked_documents_rels_jingle_fk": {
+ "name": "payload_locked_documents_rels_jingle_fk",
+ "tableFrom": "payload_locked_documents_rels",
+ "tableTo": "jingle",
+ "columnsFrom": [
+ "jingle_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.payload_preferences": {
+ "name": "payload_preferences",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "key": {
+ "name": "key",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "value": {
+ "name": "value",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "payload_preferences_key_idx": {
+ "name": "payload_preferences_key_idx",
+ "columns": [
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_preferences_updated_at_idx": {
+ "name": "payload_preferences_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_preferences_created_at_idx": {
+ "name": "payload_preferences_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.payload_preferences_rels": {
+ "name": "payload_preferences_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "users_id": {
+ "name": "users_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "campaign_user_id": {
+ "name": "campaign_user_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "payload_preferences_rels_order_idx": {
+ "name": "payload_preferences_rels_order_idx",
+ "columns": [
+ {
+ "expression": "order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_preferences_rels_parent_idx": {
+ "name": "payload_preferences_rels_parent_idx",
+ "columns": [
+ {
+ "expression": "parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_preferences_rels_path_idx": {
+ "name": "payload_preferences_rels_path_idx",
+ "columns": [
+ {
+ "expression": "path",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_preferences_rels_users_id_idx": {
+ "name": "payload_preferences_rels_users_id_idx",
+ "columns": [
+ {
+ "expression": "users_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_preferences_rels_campaign_user_id_idx": {
+ "name": "payload_preferences_rels_campaign_user_id_idx",
+ "columns": [
+ {
+ "expression": "campaign_user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "payload_preferences_rels_parent_fk": {
+ "name": "payload_preferences_rels_parent_fk",
+ "tableFrom": "payload_preferences_rels",
+ "tableTo": "payload_preferences",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_preferences_rels_users_fk": {
+ "name": "payload_preferences_rels_users_fk",
+ "tableFrom": "payload_preferences_rels",
+ "tableTo": "users",
+ "columnsFrom": [
+ "users_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_preferences_rels_campaign_user_fk": {
+ "name": "payload_preferences_rels_campaign_user_fk",
+ "tableFrom": "payload_preferences_rels",
+ "tableTo": "campaign_user",
+ "columnsFrom": [
+ "campaign_user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.payload_migrations": {
+ "name": "payload_migrations",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "batch": {
+ "name": "batch",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "payload_migrations_updated_at_idx": {
+ "name": "payload_migrations_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "payload_migrations_created_at_idx": {
+ "name": "payload_migrations_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.site_settings_social_links": {
+ "name": "site_settings_social_links",
+ "schema": "",
+ "columns": {
+ "_order": {
+ "name": "_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "_parent_id": {
+ "name": "_parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "id": {
+ "name": "id",
+ "type": "varchar",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "platform": {
+ "name": "platform",
+ "type": "enum_site_settings_social_links_platform",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "url": {
+ "name": "url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "label": {
+ "name": "label",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "enabled": {
+ "name": "enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "site_settings_social_links_order_idx": {
+ "name": "site_settings_social_links_order_idx",
+ "columns": [
+ {
+ "expression": "_order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "site_settings_social_links_parent_id_idx": {
+ "name": "site_settings_social_links_parent_id_idx",
+ "columns": [
+ {
+ "expression": "_parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "site_settings_social_links_parent_id_fk": {
+ "name": "site_settings_social_links_parent_id_fk",
+ "tableFrom": "site_settings_social_links",
+ "tableTo": "site_settings",
+ "columnsFrom": [
+ "_parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.site_settings": {
+ "name": "site_settings",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "header_title": {
+ "name": "header_title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "tracking_facebook_pixel_id": {
+ "name": "tracking_facebook_pixel_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "_status": {
+ "name": "_status",
+ "type": "enum_site_settings_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'draft'"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "site_settings__status_idx": {
+ "name": "site_settings__status_idx",
+ "columns": [
+ {
+ "expression": "_status",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public._site_settings_v_version_social_links": {
+ "name": "_site_settings_v_version_social_links",
+ "schema": "",
+ "columns": {
+ "_order": {
+ "name": "_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "_parent_id": {
+ "name": "_parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "platform": {
+ "name": "platform",
+ "type": "enum__site_settings_v_version_social_links_platform",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "url": {
+ "name": "url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "label": {
+ "name": "label",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "enabled": {
+ "name": "enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "_uuid": {
+ "name": "_uuid",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "_site_settings_v_version_social_links_order_idx": {
+ "name": "_site_settings_v_version_social_links_order_idx",
+ "columns": [
+ {
+ "expression": "_order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_site_settings_v_version_social_links_parent_id_idx": {
+ "name": "_site_settings_v_version_social_links_parent_id_idx",
+ "columns": [
+ {
+ "expression": "_parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "_site_settings_v_version_social_links_parent_id_fk": {
+ "name": "_site_settings_v_version_social_links_parent_id_fk",
+ "tableFrom": "_site_settings_v_version_social_links",
+ "tableTo": "_site_settings_v",
+ "columnsFrom": [
+ "_parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public._site_settings_v": {
+ "name": "_site_settings_v",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "version_header_title": {
+ "name": "version_header_title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_tracking_facebook_pixel_id": {
+ "name": "version_tracking_facebook_pixel_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version__status": {
+ "name": "version__status",
+ "type": "enum__site_settings_v_version_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'draft'"
+ },
+ "version_updated_at": {
+ "name": "version_updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "version_created_at": {
+ "name": "version_created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "latest": {
+ "name": "latest",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "autosave": {
+ "name": "autosave",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "_site_settings_v_version_version__status_idx": {
+ "name": "_site_settings_v_version_version__status_idx",
+ "columns": [
+ {
+ "expression": "version__status",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_site_settings_v_created_at_idx": {
+ "name": "_site_settings_v_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_site_settings_v_updated_at_idx": {
+ "name": "_site_settings_v_updated_at_idx",
+ "columns": [
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_site_settings_v_latest_idx": {
+ "name": "_site_settings_v_latest_idx",
+ "columns": [
+ {
+ "expression": "latest",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "_site_settings_v_autosave_idx": {
+ "name": "_site_settings_v_autosave_idx",
+ "columns": [
+ {
+ "expression": "autosave",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.home": {
+ "name": "home",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "image_id": {
+ "name": "image_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "home_image_idx": {
+ "name": "home_image_idx",
+ "columns": [
+ {
+ "expression": "image_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "home_image_id_media_id_fk": {
+ "name": "home_image_id_media_id_fk",
+ "tableFrom": "home",
+ "tableTo": "media",
+ "columnsFrom": [
+ "image_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.metadata_keywords": {
+ "name": "metadata_keywords",
+ "schema": "",
+ "columns": {
+ "_order": {
+ "name": "_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "_parent_id": {
+ "name": "_parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "id": {
+ "name": "id",
+ "type": "varchar",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "keyword": {
+ "name": "keyword",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "metadata_keywords_order_idx": {
+ "name": "metadata_keywords_order_idx",
+ "columns": [
+ {
+ "expression": "_order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "metadata_keywords_parent_id_idx": {
+ "name": "metadata_keywords_parent_id_idx",
+ "columns": [
+ {
+ "expression": "_parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "metadata_keywords_parent_id_fk": {
+ "name": "metadata_keywords_parent_id_fk",
+ "tableFrom": "metadata_keywords",
+ "tableTo": "metadata",
+ "columnsFrom": [
+ "_parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.metadata": {
+ "name": "metadata",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "url": {
+ "name": "url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "title": {
+ "name": "title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "open_graph_site_name": {
+ "name": "open_graph_site_name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "open_graph_description": {
+ "name": "open_graph_description",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "twitter_creator": {
+ "name": "twitter_creator",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "twitter_description": {
+ "name": "twitter_description",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "image_id": {
+ "name": "image_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "metadata_image_idx": {
+ "name": "metadata_image_idx",
+ "columns": [
+ {
+ "expression": "image_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "metadata_image_id_media_id_fk": {
+ "name": "metadata_image_id_media_id_fk",
+ "tableFrom": "metadata",
+ "tableTo": "media",
+ "columnsFrom": [
+ "image_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.privacy_policy": {
+ "name": "privacy_policy",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "published": {
+ "name": "published",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "body": {
+ "name": "body",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.campaign_goals": {
+ "name": "campaign_goals",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "state_goal": {
+ "name": "state_goal",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 150000
+ },
+ "margin": {
+ "name": "margin",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "base_year": {
+ "name": "base_year",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "note": {
+ "name": "note",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.social_feed_settings_excluded_items": {
+ "name": "social_feed_settings_excluded_items",
+ "schema": "",
+ "columns": {
+ "_order": {
+ "name": "_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "_parent_id": {
+ "name": "_parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "id": {
+ "name": "id",
+ "type": "varchar",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "platform": {
+ "name": "platform",
+ "type": "enum_social_feed_settings_excluded_items_platform",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "item_id": {
+ "name": "item_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "reason": {
+ "name": "reason",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "social_feed_settings_excluded_items_order_idx": {
+ "name": "social_feed_settings_excluded_items_order_idx",
+ "columns": [
+ {
+ "expression": "_order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "social_feed_settings_excluded_items_parent_id_idx": {
+ "name": "social_feed_settings_excluded_items_parent_id_idx",
+ "columns": [
+ {
+ "expression": "_parent_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "social_feed_settings_excluded_items_parent_id_fk": {
+ "name": "social_feed_settings_excluded_items_parent_id_fk",
+ "tableFrom": "social_feed_settings_excluded_items",
+ "tableTo": "social_feed_settings",
+ "columnsFrom": [
+ "_parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.social_feed_settings": {
+ "name": "social_feed_settings",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "enabled": {
+ "name": "enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": true
+ },
+ "youtube_enabled": {
+ "name": "youtube_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": true
+ },
+ "youtube_api_key": {
+ "name": "youtube_api_key",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "youtube_channel_id": {
+ "name": "youtube_channel_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "youtube_max_items": {
+ "name": "youtube_max_items",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 3
+ },
+ "instagram_enabled": {
+ "name": "instagram_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": true
+ },
+ "instagram_access_token": {
+ "name": "instagram_access_token",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "instagram_user_id": {
+ "name": "instagram_user_id",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "instagram_max_items": {
+ "name": "instagram_max_items",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 3
+ },
+ "youtube_feed_snapshot": {
+ "name": "youtube_feed_snapshot",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "instagram_feed_snapshot": {
+ "name": "instagram_feed_snapshot",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "instagram_sync_status": {
+ "name": "instagram_sync_status",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ }
+ },
+ "enums": {
+ "public.enum_users_roles": {
+ "name": "enum_users_roles",
+ "schema": "public",
+ "values": [
+ "admin",
+ "editor"
+ ]
+ },
+ "public.enum_campaign_user_role": {
+ "name": "enum_campaign_user_role",
+ "schema": "public",
+ "values": [
+ "coordinator",
+ "advisor",
+ "candidate",
+ "communicator",
+ "leader"
+ ]
+ },
+ "public.enum_campaign_user_visibility": {
+ "name": "enum_campaign_user_visibility",
+ "schema": "public",
+ "values": [
+ "carteira",
+ "tudo"
+ ]
+ },
+ "public.enum_campaign_user_editing": {
+ "name": "enum_campaign_user_editing",
+ "schema": "public",
+ "values": [
+ "carteira",
+ "tudo",
+ "somente_leitura"
+ ]
+ },
+ "public.enum_notification_type": {
+ "name": "enum_notification_type",
+ "schema": "public",
+ "values": [
+ "municipality_update",
+ "new_supporter",
+ "activity_attention",
+ "invite_accepted"
+ ]
+ },
+ "public.enum_campaign_invite_kind": {
+ "name": "enum_campaign_invite_kind",
+ "schema": "public",
+ "values": [
+ "login",
+ "autopreenchimento"
+ ]
+ },
+ "public.enum_municipality_kind": {
+ "name": "enum_municipality_kind",
+ "schema": "public",
+ "values": [
+ "municipio",
+ "zona"
+ ]
+ },
+ "public.enum_municipality_priority": {
+ "name": "enum_municipality_priority",
+ "schema": "public",
+ "values": [
+ "alta",
+ "normal"
+ ]
+ },
+ "public.enum_municipality_engagement_level": {
+ "name": "enum_municipality_engagement_level",
+ "schema": "public",
+ "values": [
+ "n0",
+ "n1",
+ "n2",
+ "n3",
+ "n4"
+ ]
+ },
+ "public.enum_municipality_political_trend_status": {
+ "name": "enum_municipality_political_trend_status",
+ "schema": "public",
+ "values": [
+ "favoravel",
+ "neutra",
+ "desfavoravel"
+ ]
+ },
+ "public.enum_leadership_support_status": {
+ "name": "enum_leadership_support_status",
+ "schema": "public",
+ "values": [
+ "engajado",
+ "a_abordar",
+ "em_disputa",
+ "lembranca",
+ "negativo"
+ ]
+ },
+ "public.enum_organization_kind": {
+ "name": "enum_organization_kind",
+ "schema": "public",
+ "values": [
+ "sindicato",
+ "associacao",
+ "religioso",
+ "movimento",
+ "categoria_profissional",
+ "outro"
+ ]
+ },
+ "public.enum_allocation_decision_outcome": {
+ "name": "enum_allocation_decision_outcome",
+ "schema": "public",
+ "values": [
+ "aceita",
+ "descarta",
+ "movimento",
+ "adiada"
+ ]
+ },
+ "public.enum_campaign_demand_status_history_status": {
+ "name": "enum_campaign_demand_status_history_status",
+ "schema": "public",
+ "values": [
+ "aberta",
+ "em_analise",
+ "escalada",
+ "aprovada",
+ "rejeitada"
+ ]
+ },
+ "public.enum_campaign_demand_kind": {
+ "name": "enum_campaign_demand_kind",
+ "schema": "public",
+ "values": [
+ "material",
+ "servico",
+ "transporte",
+ "alimentacao",
+ "infraestrutura",
+ "espaco",
+ "equipamento",
+ "pessoal_apoio",
+ "outro"
+ ]
+ },
+ "public.enum_campaign_demand_status": {
+ "name": "enum_campaign_demand_status",
+ "schema": "public",
+ "values": [
+ "aberta",
+ "em_analise",
+ "escalada",
+ "aprovada",
+ "rejeitada"
+ ]
+ },
+ "public.enum_supporter_vote_intention": {
+ "name": "enum_supporter_vote_intention",
+ "schema": "public",
+ "values": [
+ "certo",
+ "tende_a_certo",
+ "indeciso",
+ "outro"
+ ]
+ },
+ "public.enum_supporter_source": {
+ "name": "enum_supporter_source",
+ "schema": "public",
+ "values": [
+ "import_csv",
+ "manual",
+ "lideranca",
+ "convite",
+ "evento"
+ ]
+ },
+ "public.enum_municipality_update_polarity": {
+ "name": "enum_municipality_update_polarity",
+ "schema": "public",
+ "values": [
+ "boa",
+ "neutra",
+ "ruim"
+ ]
+ },
+ "public.enum_activity_status": {
+ "name": "enum_activity_status",
+ "schema": "public",
+ "values": [
+ "confirmado",
+ "realizado",
+ "cancelado"
+ ]
+ },
+ "public.enum_speech_topics": {
+ "name": "enum_speech_topics",
+ "schema": "public",
+ "values": [
+ "saude",
+ "educacao",
+ "cultura",
+ "esporte",
+ "seguranca-publica",
+ "meio-ambiente",
+ "economia-trabalho",
+ "direitos-humanos",
+ "infraestrutura",
+ "ciencia-tecnologia",
+ "politica-instituicoes",
+ "agricultura",
+ "habitacao-cidades",
+ "comunicacao-midia",
+ "igualdade-racial",
+ "mulheres-genero",
+ "juventude",
+ "pessoa-deficiencia"
+ ]
+ },
+ "public.enum_speech_scopes": {
+ "name": "enum_speech_scopes",
+ "schema": "public",
+ "values": [
+ "bahia",
+ "brasil",
+ "internacional"
+ ]
+ },
+ "public.enum_speech_origin": {
+ "name": "enum_speech_origin",
+ "schema": "public",
+ "values": [
+ "camara",
+ "web"
+ ]
+ },
+ "public.enum_speech_legislature": {
+ "name": "enum_speech_legislature",
+ "schema": "public",
+ "values": [
+ "54",
+ "55",
+ "56",
+ "57"
+ ]
+ },
+ "public.enum_speech_platform": {
+ "name": "enum_speech_platform",
+ "schema": "public",
+ "values": [
+ "youtube",
+ "instagram",
+ "radio",
+ "audio"
+ ]
+ },
+ "public.enum_speech_classified_by": {
+ "name": "enum_speech_classified_by",
+ "schema": "public",
+ "values": [
+ "gazetteer",
+ "llm",
+ "manual"
+ ]
+ },
+ "public.enum_speech_cut_status": {
+ "name": "enum_speech_cut_status",
+ "schema": "public",
+ "values": [
+ "processing",
+ "published",
+ "unpublished",
+ "failed"
+ ]
+ },
+ "public.enum_speech_cut_step": {
+ "name": "enum_speech_cut_step",
+ "schema": "public",
+ "values": [
+ "resolving",
+ "cutting",
+ "metadata",
+ "publishing"
+ ]
+ },
+ "public.enum_speech_embedding_kind": {
+ "name": "enum_speech_embedding_kind",
+ "schema": "public",
+ "values": [
+ "speech",
+ "segment",
+ "window"
+ ]
+ },
+ "public.enum_reel_feature": {
+ "name": "enum_reel_feature",
+ "schema": "public",
+ "values": [
+ "cards"
+ ]
+ },
+ "public.enum_reel_status": {
+ "name": "enum_reel_status",
+ "schema": "public",
+ "values": [
+ "draft",
+ "published",
+ "unpublished"
+ ]
+ },
+ "public.enum_content_piece_topics": {
+ "name": "enum_content_piece_topics",
+ "schema": "public",
+ "values": [
+ "saude",
+ "educacao",
+ "cultura",
+ "esporte",
+ "seguranca-publica",
+ "meio-ambiente",
+ "economia-trabalho",
+ "direitos-humanos",
+ "infraestrutura",
+ "ciencia-tecnologia",
+ "politica-instituicoes",
+ "agricultura",
+ "habitacao-cidades",
+ "comunicacao-midia",
+ "igualdade-racial",
+ "mulheres-genero",
+ "juventude",
+ "pessoa-deficiencia"
+ ]
+ },
+ "public.enum_content_piece_curated_fields": {
+ "name": "enum_content_piece_curated_fields",
+ "schema": "public",
+ "values": [
+ "title",
+ "description",
+ "topics",
+ "municipality",
+ "institution",
+ "pieceDate",
+ "transcript",
+ "type"
+ ]
+ },
+ "public.enum_content_piece_type": {
+ "name": "enum_content_piece_type",
+ "schema": "public",
+ "values": [
+ "video",
+ "foto",
+ "texto",
+ "audio",
+ "card"
+ ]
+ },
+ "public.enum_content_piece_origin": {
+ "name": "enum_content_piece_origin",
+ "schema": "public",
+ "values": [
+ "arquivo",
+ "instagram",
+ "youtube"
+ ]
+ },
+ "public.enum_content_piece_status": {
+ "name": "enum_content_piece_status",
+ "schema": "public",
+ "values": [
+ "rascunho",
+ "publicado"
+ ]
+ },
+ "public.enum_content_piece_processing_status": {
+ "name": "enum_content_piece_processing_status",
+ "schema": "public",
+ "values": [
+ "processando",
+ "pronto",
+ "falhou"
+ ]
+ },
+ "public.enum_content_piece_step": {
+ "name": "enum_content_piece_step",
+ "schema": "public",
+ "values": [
+ "extraindo",
+ "transcrevendo",
+ "catalogando",
+ "salvando"
+ ]
+ },
+ "public.enum_content_piece_link_failure_reason": {
+ "name": "enum_content_piece_link_failure_reason",
+ "schema": "public",
+ "values": [
+ "nao-encontrado",
+ "carrossel",
+ "indisponivel",
+ "sem-credencial"
+ ]
+ },
+ "public.enum_archive_photo_catalog_themes": {
+ "name": "enum_archive_photo_catalog_themes",
+ "schema": "public",
+ "values": [
+ "saude",
+ "educacao",
+ "cultura",
+ "esporte",
+ "seguranca-publica",
+ "meio-ambiente",
+ "economia-trabalho",
+ "direitos-humanos",
+ "infraestrutura",
+ "ciencia-tecnologia",
+ "politica-instituicoes",
+ "agricultura",
+ "habitacao-cidades",
+ "comunicacao-midia",
+ "igualdade-racial",
+ "mulheres-genero",
+ "juventude",
+ "pessoa-deficiencia"
+ ]
+ },
+ "public.enum_archive_photo_curated_fields": {
+ "name": "enum_archive_photo_curated_fields",
+ "schema": "public",
+ "values": [
+ "alt",
+ "caption",
+ "description",
+ "scene",
+ "visibleText",
+ "hasPeople",
+ "themes",
+ "people",
+ "municipality"
+ ]
+ },
+ "public.enum_archive_photo_catalog_scene": {
+ "name": "enum_archive_photo_catalog_scene",
+ "schema": "public",
+ "values": [
+ "plenaria",
+ "audiencia",
+ "reuniao",
+ "evento",
+ "mobilizacao",
+ "visita",
+ "entrevista",
+ "discurso",
+ "retrato",
+ "gabinete",
+ "outro"
+ ]
+ },
+ "public.enum_archive_photo_catalog_source": {
+ "name": "enum_archive_photo_catalog_source",
+ "schema": "public",
+ "values": [
+ "ai",
+ "metadata",
+ "none"
+ ]
+ },
+ "public.enum_content_event_type": {
+ "name": "enum_content_event_type",
+ "schema": "public",
+ "values": [
+ "abertura",
+ "download",
+ "compartilhar_whatsapp",
+ "compartilhar_link"
+ ]
+ },
+ "public.enum_content_event_subject_type": {
+ "name": "enum_content_event_subject_type",
+ "schema": "public",
+ "values": [
+ "peca",
+ "card"
+ ]
+ },
+ "public.enum_recording_topics": {
+ "name": "enum_recording_topics",
+ "schema": "public",
+ "values": [
+ "saude",
+ "educacao",
+ "cultura",
+ "esporte",
+ "seguranca-publica",
+ "meio-ambiente",
+ "economia-trabalho",
+ "direitos-humanos",
+ "infraestrutura",
+ "ciencia-tecnologia",
+ "politica-instituicoes",
+ "agricultura",
+ "habitacao-cidades",
+ "comunicacao-midia",
+ "igualdade-racial",
+ "mulheres-genero",
+ "juventude",
+ "pessoa-deficiencia"
+ ]
+ },
+ "public.enum_recording_scopes": {
+ "name": "enum_recording_scopes",
+ "schema": "public",
+ "values": [
+ "bahia",
+ "brasil",
+ "internacional"
+ ]
+ },
+ "public.enum_recording_status": {
+ "name": "enum_recording_status",
+ "schema": "public",
+ "values": [
+ "uploading",
+ "processing",
+ "ready",
+ "failed"
+ ]
+ },
+ "public.enum_recording_step": {
+ "name": "enum_recording_step",
+ "schema": "public",
+ "values": [
+ "extracting",
+ "transcribing",
+ "saving"
+ ]
+ },
+ "public.enum_recording_classified_by": {
+ "name": "enum_recording_classified_by",
+ "schema": "public",
+ "values": [
+ "gazetteer",
+ "llm",
+ "manual"
+ ]
+ },
+ "public.enum_election_tally_office": {
+ "name": "enum_election_tally_office",
+ "schema": "public",
+ "values": [
+ "presidente",
+ "governador",
+ "deputado_federal",
+ "deputado_estadual"
+ ]
+ },
+ "public.enum_election_tally_turn": {
+ "name": "enum_election_tally_turn",
+ "schema": "public",
+ "values": [
+ "1",
+ "2"
+ ]
+ },
+ "public.enum_election_candidate_vote_office": {
+ "name": "enum_election_candidate_vote_office",
+ "schema": "public",
+ "values": [
+ "presidente",
+ "governador",
+ "deputado_federal",
+ "deputado_estadual"
+ ]
+ },
+ "public.enum_election_candidate_vote_turn": {
+ "name": "enum_election_candidate_vote_turn",
+ "schema": "public",
+ "values": [
+ "1",
+ "2"
+ ]
+ },
+ "public.enum_election_candidate_vote_vote_type": {
+ "name": "enum_election_candidate_vote_vote_type",
+ "schema": "public",
+ "values": [
+ "nominal",
+ "legenda"
+ ]
+ },
+ "public.enum_election_candidate_office": {
+ "name": "enum_election_candidate_office",
+ "schema": "public",
+ "values": [
+ "presidente",
+ "governador",
+ "deputado_federal",
+ "deputado_estadual"
+ ]
+ },
+ "public.enum_election_candidate_turn": {
+ "name": "enum_election_candidate_turn",
+ "schema": "public",
+ "values": [
+ "1",
+ "2"
+ ]
+ },
+ "public.enum_election_candidate_elected_by": {
+ "name": "enum_election_candidate_elected_by",
+ "schema": "public",
+ "values": [
+ "QP",
+ "média",
+ "2º turno"
+ ]
+ },
+ "public.enum_election_candidate_running_again2026": {
+ "name": "enum_election_candidate_running_again2026",
+ "schema": "public",
+ "values": [
+ "sim",
+ "nao",
+ "desconhecido"
+ ]
+ },
+ "public.enum_petition_status": {
+ "name": "enum_petition_status",
+ "schema": "public",
+ "values": [
+ "draft",
+ "published"
+ ]
+ },
+ "public.enum__petition_v_version_status": {
+ "name": "enum__petition_v_version_status",
+ "schema": "public",
+ "values": [
+ "draft",
+ "published"
+ ]
+ },
+ "public.enum_contact_gender": {
+ "name": "enum_contact_gender",
+ "schema": "public",
+ "values": [
+ "feminino",
+ "masculino",
+ "outro",
+ "nao_informado"
+ ]
+ },
+ "public.enum_contact_state": {
+ "name": "enum_contact_state",
+ "schema": "public",
+ "values": [
+ "AC",
+ "AL",
+ "AM",
+ "AP",
+ "BA",
+ "CE",
+ "DF",
+ "ES",
+ "GO",
+ "MA",
+ "MG",
+ "MS",
+ "MT",
+ "PA",
+ "PB",
+ "PE",
+ "PI",
+ "PR",
+ "RJ",
+ "RN",
+ "RO",
+ "RR",
+ "RS",
+ "SC",
+ "SE",
+ "SP",
+ "TO"
+ ]
+ },
+ "public.enum_subscription_campaign_level": {
+ "name": "enum_subscription_campaign_level",
+ "schema": "public",
+ "values": [
+ "time",
+ "esporadico"
+ ]
+ },
+ "public.enum_post_type": {
+ "name": "enum_post_type",
+ "schema": "public",
+ "values": [
+ "noticia",
+ "campanha",
+ "artigo",
+ "evento"
+ ]
+ },
+ "public.enum_post_status": {
+ "name": "enum_post_status",
+ "schema": "public",
+ "values": [
+ "draft",
+ "published"
+ ]
+ },
+ "public.enum__post_v_version_type": {
+ "name": "enum__post_v_version_type",
+ "schema": "public",
+ "values": [
+ "noticia",
+ "campanha",
+ "artigo",
+ "evento"
+ ]
+ },
+ "public.enum__post_v_version_status": {
+ "name": "enum__post_v_version_status",
+ "schema": "public",
+ "values": [
+ "draft",
+ "published"
+ ]
+ },
+ "public.enum_share_link_mode": {
+ "name": "enum_share_link_mode",
+ "schema": "public",
+ "values": [
+ "direct",
+ "announcement"
+ ]
+ },
+ "public.enum_exports_format": {
+ "name": "enum_exports_format",
+ "schema": "public",
+ "values": [
+ "csv",
+ "json"
+ ]
+ },
+ "public.enum_exports_sort_order": {
+ "name": "enum_exports_sort_order",
+ "schema": "public",
+ "values": [
+ "asc",
+ "desc"
+ ]
+ },
+ "public.enum_exports_drafts": {
+ "name": "enum_exports_drafts",
+ "schema": "public",
+ "values": [
+ "yes",
+ "no"
+ ]
+ },
+ "public.enum_imports_import_mode": {
+ "name": "enum_imports_import_mode",
+ "schema": "public",
+ "values": [
+ "create",
+ "update",
+ "upsert"
+ ]
+ },
+ "public.enum_imports_status": {
+ "name": "enum_imports_status",
+ "schema": "public",
+ "values": [
+ "pending",
+ "completed",
+ "partial",
+ "failed"
+ ]
+ },
+ "public.enum_payload_jobs_log_task_slug": {
+ "name": "enum_payload_jobs_log_task_slug",
+ "schema": "public",
+ "values": [
+ "inline",
+ "createCollectionExport",
+ "createCollectionImport",
+ "schedulePublish"
+ ]
+ },
+ "public.enum_payload_jobs_log_state": {
+ "name": "enum_payload_jobs_log_state",
+ "schema": "public",
+ "values": [
+ "failed",
+ "succeeded"
+ ]
+ },
+ "public.enum_payload_jobs_task_slug": {
+ "name": "enum_payload_jobs_task_slug",
+ "schema": "public",
+ "values": [
+ "inline",
+ "createCollectionExport",
+ "createCollectionImport",
+ "schedulePublish"
+ ]
+ },
+ "public.enum_site_settings_social_links_platform": {
+ "name": "enum_site_settings_social_links_platform",
+ "schema": "public",
+ "values": [
+ "instagram",
+ "facebook",
+ "youtube",
+ "whatsapp"
+ ]
+ },
+ "public.enum_site_settings_status": {
+ "name": "enum_site_settings_status",
+ "schema": "public",
+ "values": [
+ "draft",
+ "published"
+ ]
+ },
+ "public.enum__site_settings_v_version_social_links_platform": {
+ "name": "enum__site_settings_v_version_social_links_platform",
+ "schema": "public",
+ "values": [
+ "instagram",
+ "facebook",
+ "youtube",
+ "whatsapp"
+ ]
+ },
+ "public.enum__site_settings_v_version_status": {
+ "name": "enum__site_settings_v_version_status",
+ "schema": "public",
+ "values": [
+ "draft",
+ "published"
+ ]
+ },
+ "public.enum_social_feed_settings_excluded_items_platform": {
+ "name": "enum_social_feed_settings_excluded_items_platform",
+ "schema": "public",
+ "values": [
+ "youtube",
+ "instagram"
+ ]
+ }
+ },
+ "schemas": {},
+ "sequences": {},
+ "roles": {},
+ "policies": {},
+ "views": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "id": "4b9166ce-5e65-45a5-8f34-4d1df27a6258",
+ "prevId": "00000000-0000-0000-0000-000000000000"
+}
\ No newline at end of file
diff --git a/src/migrations/20260926_132106_add_archive_photo_catalog.ts b/src/migrations/20260926_132106_add_archive_photo_catalog.ts
new file mode 100644
index 00000000..a5639bda
--- /dev/null
+++ b/src/migrations/20260926_132106_add_archive_photo_catalog.ts
@@ -0,0 +1,88 @@
+import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
+
+export async function up({ db, payload, req }: MigrateUpArgs): Promise {
+ await db.execute(sql`
+ CREATE EXTENSION IF NOT EXISTS pg_trgm;
+ CREATE TYPE "public"."enum_archive_photo_catalog_themes" AS ENUM('saude', 'educacao', 'cultura', 'esporte', 'seguranca-publica', 'meio-ambiente', 'economia-trabalho', 'direitos-humanos', 'infraestrutura', 'ciencia-tecnologia', 'politica-instituicoes', 'agricultura', 'habitacao-cidades', 'comunicacao-midia', 'igualdade-racial', 'mulheres-genero', 'juventude', 'pessoa-deficiencia');
+ CREATE TYPE "public"."enum_archive_photo_curated_fields" AS ENUM('alt', 'caption', 'description', 'scene', 'visibleText', 'hasPeople', 'themes', 'people', 'municipality');
+ CREATE TYPE "public"."enum_archive_photo_catalog_scene" AS ENUM('plenaria', 'audiencia', 'reuniao', 'evento', 'mobilizacao', 'visita', 'entrevista', 'discurso', 'retrato', 'gabinete', 'outro');
+ CREATE TYPE "public"."enum_archive_photo_catalog_source" AS ENUM('ai', 'metadata', 'none');
+ CREATE TABLE "archive_photo_catalog_themes" (
+ "order" integer NOT NULL,
+ "parent_id" integer NOT NULL,
+ "value" "enum_archive_photo_catalog_themes",
+ "id" serial PRIMARY KEY NOT NULL
+ );
+
+ CREATE TABLE "archive_photo_curated_fields" (
+ "order" integer NOT NULL,
+ "parent_id" integer NOT NULL,
+ "value" "enum_archive_photo_curated_fields",
+ "id" serial PRIMARY KEY NOT NULL
+ );
+
+ CREATE TABLE "archive_photo_texts" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "order" integer NOT NULL,
+ "parent_id" integer NOT NULL,
+ "path" varchar NOT NULL,
+ "text" varchar
+ );
+
+ ALTER TABLE "archive_photo" ADD COLUMN "catalog_caption" varchar;
+ ALTER TABLE "archive_photo" ADD COLUMN "catalog_description" varchar;
+ ALTER TABLE "archive_photo" ADD COLUMN "catalog_scene" "enum_archive_photo_catalog_scene";
+ ALTER TABLE "archive_photo" ADD COLUMN "catalog_visible_text" varchar;
+ ALTER TABLE "archive_photo" ADD COLUMN "catalog_has_people" boolean;
+ ALTER TABLE "archive_photo" ADD COLUMN "catalog_municipality_id" integer;
+ ALTER TABLE "archive_photo" ADD COLUMN "catalog_source" "enum_archive_photo_catalog_source";
+ ALTER TABLE "archive_photo" ADD COLUMN "catalog_cataloged_at" timestamp(3) with time zone;
+ ALTER TABLE "archive_photo" ADD COLUMN "taken_on" timestamp(3) with time zone;
+ ALTER TABLE "archive_photo" ADD COLUMN "search_text" varchar;
+ ALTER TABLE "archive_photo_catalog_themes" ADD CONSTRAINT "archive_photo_catalog_themes_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."archive_photo"("id") ON DELETE cascade ON UPDATE no action;
+ ALTER TABLE "archive_photo_curated_fields" ADD CONSTRAINT "archive_photo_curated_fields_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."archive_photo"("id") ON DELETE cascade ON UPDATE no action;
+ ALTER TABLE "archive_photo_texts" ADD CONSTRAINT "archive_photo_texts_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."archive_photo"("id") ON DELETE cascade ON UPDATE no action;
+ CREATE INDEX "archive_photo_catalog_themes_order_idx" ON "archive_photo_catalog_themes" USING btree ("order");
+ CREATE INDEX "archive_photo_catalog_themes_parent_idx" ON "archive_photo_catalog_themes" USING btree ("parent_id");
+ CREATE INDEX "archive_photo_catalog_themes_value_idx" ON "archive_photo_catalog_themes" USING btree ("value");
+ CREATE INDEX "archive_photo_curated_fields_order_idx" ON "archive_photo_curated_fields" USING btree ("order");
+ CREATE INDEX "archive_photo_curated_fields_parent_idx" ON "archive_photo_curated_fields" USING btree ("parent_id");
+ CREATE INDEX "archive_photo_texts_order_parent" ON "archive_photo_texts" USING btree ("order","parent_id");
+ ALTER TABLE "archive_photo" ADD CONSTRAINT "archive_photo_catalog_municipality_id_municipality_id_fk" FOREIGN KEY ("catalog_municipality_id") REFERENCES "public"."municipality"("id") ON DELETE set null ON UPDATE no action;
+ CREATE INDEX "archive_photo_catalog_catalog_scene_idx" ON "archive_photo" USING btree ("catalog_scene");
+ CREATE INDEX "archive_photo_catalog_catalog_municipality_idx" ON "archive_photo" USING btree ("catalog_municipality_id");
+ CREATE INDEX "archive_photo_catalog_catalog_cataloged_at_idx" ON "archive_photo" USING btree ("catalog_cataloged_at");
+ CREATE INDEX "archive_photo_taken_on_idx" ON "archive_photo" USING btree ("taken_on");
+ CREATE INDEX IF NOT EXISTS "archive_photo_search_text_trgm_idx" ON "archive_photo" USING gin ("search_text" gin_trgm_ops);`)
+}
+
+export async function down({ db, payload, req }: MigrateDownArgs): Promise {
+ await db.execute(sql`
+ DROP INDEX IF EXISTS "archive_photo_search_text_trgm_idx";
+ ALTER TABLE "archive_photo_catalog_themes" DISABLE ROW LEVEL SECURITY;
+ ALTER TABLE "archive_photo_curated_fields" DISABLE ROW LEVEL SECURITY;
+ ALTER TABLE "archive_photo_texts" DISABLE ROW LEVEL SECURITY;
+ DROP TABLE "archive_photo_catalog_themes" CASCADE;
+ DROP TABLE "archive_photo_curated_fields" CASCADE;
+ DROP TABLE "archive_photo_texts" CASCADE;
+ ALTER TABLE "archive_photo" DROP CONSTRAINT "archive_photo_catalog_municipality_id_municipality_id_fk";
+
+ DROP INDEX "archive_photo_catalog_catalog_scene_idx";
+ DROP INDEX "archive_photo_catalog_catalog_municipality_idx";
+ DROP INDEX "archive_photo_catalog_catalog_cataloged_at_idx";
+ DROP INDEX "archive_photo_taken_on_idx";
+ ALTER TABLE "archive_photo" DROP COLUMN "catalog_caption";
+ ALTER TABLE "archive_photo" DROP COLUMN "catalog_description";
+ ALTER TABLE "archive_photo" DROP COLUMN "catalog_scene";
+ ALTER TABLE "archive_photo" DROP COLUMN "catalog_visible_text";
+ ALTER TABLE "archive_photo" DROP COLUMN "catalog_has_people";
+ ALTER TABLE "archive_photo" DROP COLUMN "catalog_municipality_id";
+ ALTER TABLE "archive_photo" DROP COLUMN "catalog_source";
+ ALTER TABLE "archive_photo" DROP COLUMN "catalog_cataloged_at";
+ ALTER TABLE "archive_photo" DROP COLUMN "taken_on";
+ ALTER TABLE "archive_photo" DROP COLUMN "search_text";
+ DROP TYPE "public"."enum_archive_photo_catalog_themes";
+ DROP TYPE "public"."enum_archive_photo_curated_fields";
+ DROP TYPE "public"."enum_archive_photo_catalog_scene";
+ DROP TYPE "public"."enum_archive_photo_catalog_source";`)
+}
diff --git a/src/migrations/index.ts b/src/migrations/index.ts
index 340e3854..7d07e7b1 100644
--- a/src/migrations/index.ts
+++ b/src/migrations/index.ts
@@ -88,6 +88,7 @@ import * as migration_20260924_045625_add_content_piece_link_failure_reason from
import * as migration_20260924_123940_add_content_piece_people from './20260924_123940_add_content_piece_people';
import * as migration_20260926_034118_add_speech_embedding from './20260926_034118_add_speech_embedding';
import * as migration_20260926_062039_add_archive_photo from './20260926_062039_add_archive_photo';
+import * as migration_20260926_132106_add_archive_photo_catalog from './20260926_132106_add_archive_photo_catalog';
export const migrations = [
{
@@ -533,11 +534,16 @@ export const migrations = [
{
up: migration_20260926_034118_add_speech_embedding.up,
down: migration_20260926_034118_add_speech_embedding.down,
- name: '20260926_034118_add_speech_embedding'
+ name: '20260926_034118_add_speech_embedding',
},
{
up: migration_20260926_062039_add_archive_photo.up,
down: migration_20260926_062039_add_archive_photo.down,
- name: '20260926_062039_add_archive_photo'
+ name: '20260926_062039_add_archive_photo',
+ },
+ {
+ up: migration_20260926_132106_add_archive_photo_catalog.up,
+ down: migration_20260926_132106_add_archive_photo_catalog.down,
+ name: '20260926_132106_add_archive_photo_catalog',
},
];
diff --git a/src/payload-types.ts b/src/payload-types.ts
index 4fb4d210..6d2a7e62 100644
--- a/src/payload-types.ts
+++ b/src/payload-types.ts
@@ -1412,6 +1412,93 @@ export interface ArchivePhoto {
* Descrição do arquivo para acessibilidade.
*/
alt: string;
+ /**
+ * Proposta automática (IA + metadados). A assessoria revisa na ficha: o que ela editar entra em "Campos curados" e nunca é sobrescrito.
+ */
+ catalog?: {
+ caption?: string | null;
+ /**
+ * Descrição semântica do que a foto mostra (não substitui a do Flickr).
+ */
+ description?: string | null;
+ scene?:
+ | (
+ | 'plenaria'
+ | 'audiencia'
+ | 'reuniao'
+ | 'evento'
+ | 'mobilizacao'
+ | 'visita'
+ | 'entrevista'
+ | 'discurso'
+ | 'retrato'
+ | 'gabinete'
+ | 'outro'
+ )
+ | null;
+ /**
+ * Texto legível na imagem (faixas, placas, banners).
+ */
+ visibleText?: string | null;
+ /**
+ * Presença de pessoas na foto — sem identificação de rosto (biometria é C234).
+ */
+ hasPeople?: boolean | null;
+ themes?:
+ | (
+ | 'saude'
+ | 'educacao'
+ | 'cultura'
+ | 'esporte'
+ | 'seguranca-publica'
+ | 'meio-ambiente'
+ | 'economia-trabalho'
+ | 'direitos-humanos'
+ | 'infraestrutura'
+ | 'ciencia-tecnologia'
+ | 'politica-instituicoes'
+ | 'agricultura'
+ | 'habitacao-cidades'
+ | 'comunicacao-midia'
+ | 'igualdade-racial'
+ | 'mulheres-genero'
+ | 'juventude'
+ | 'pessoa-deficiencia'
+ )[]
+ | null;
+ /**
+ * Somente nomes do catálogo curado, mencionados no texto da foto; nunca inferidos de rosto.
+ */
+ people?: string[] | null;
+ /**
+ * Quando o texto da foto aponta um município sem ambiguidade.
+ */
+ municipality?: (number | null) | Municipality;
+ /**
+ * IA = o modelo contribuiu; Metadados = só o texto derivou; Nada a propor.
+ */
+ source?: ('ai' | 'metadata' | 'none') | null;
+ /**
+ * Chave de idempotência: foto com data preenchida não é reprocessada.
+ */
+ catalogedAt?: string | null;
+ };
+ /**
+ * O que a assessoria já editou; a catalogação automática nunca sobrescreve estes campos.
+ */
+ curatedFields?:
+ | (
+ | 'alt'
+ | 'caption'
+ | 'description'
+ | 'scene'
+ | 'visibleText'
+ | 'hasPeople'
+ | 'themes'
+ | 'people'
+ | 'municipality'
+ )[]
+ | null;
title?: string | null;
description?: string | null;
tags?:
@@ -1424,6 +1511,10 @@ export interface ArchivePhoto {
* Data informada pelo Flickr, sem fuso (YYYY-MM-DD HH:MM:SS).
*/
takenAt?: string | null;
+ /**
+ * Derivado da data da foto (meio-dia UTC, sem fuso).
+ */
+ takenOn?: string | null;
/**
* Data de publicação no Flickr (ISO 8601, UTC).
*/
@@ -1454,6 +1545,10 @@ export interface ArchivePhoto {
sourceUrl?: string | null;
owner?: string | null;
license?: string | null;
+ /**
+ * Tudo o que a busca da lista encontra, normalizado (sem acentos, minúsculas): legenda, texto visível, temas, pessoas, município, álbuns e tags.
+ */
+ searchText?: string | null;
updatedAt: string;
createdAt: string;
url?: string | null;
@@ -3045,6 +3140,21 @@ export interface ContentMediaSelect {
export interface ArchivePhotoSelect {
flickrId?: T;
alt?: T;
+ catalog?:
+ | T
+ | {
+ caption?: T;
+ description?: T;
+ scene?: T;
+ visibleText?: T;
+ hasPeople?: T;
+ themes?: T;
+ people?: T;
+ municipality?: T;
+ source?: T;
+ catalogedAt?: T;
+ };
+ curatedFields?: T;
title?: T;
description?: T;
tags?:
@@ -3054,6 +3164,7 @@ export interface ArchivePhotoSelect {
id?: T;
};
takenAt?: T;
+ takenOn?: T;
postedAt?: T;
albums?:
| T
@@ -3072,6 +3183,7 @@ export interface ArchivePhotoSelect {
sourceUrl?: T;
owner?: T;
license?: T;
+ searchText?: T;
updatedAt?: T;
createdAt?: T;
url?: T;
diff --git a/src/utilities/content/contentPieceCataloging.ts b/src/utilities/content/contentPieceCataloging.ts
index d4d53a30..cff718a8 100644
--- a/src/utilities/content/contentPieceCataloging.ts
+++ b/src/utilities/content/contentPieceCataloging.ts
@@ -15,12 +15,13 @@ import {
} from '@/lib/contentPiece'
import { institutionCatalog, institutionSpellings } from '@/lib/institutionCatalog'
import { type SpeechTopic } from '@/lib/speechFacets'
-import { matchMunicipalityMentions, type SpeechFacetInput } from '@/lib/speechGazetteer'
-import { normalizeForSearch } from '@/lib/speechSearch'
+import { type SpeechFacetInput } from '@/lib/speechGazetteer'
+import { escapeRegExp, normalizeForSearch } from '@/lib/speechSearch'
import {
DEEPSEEK_FLASH_STRUCTURED_MAX_OUTPUT_TOKENS,
DEEPSEEK_FLASH_STRUCTURED_PROVIDER_OPTIONS,
} from '@/utilities/ai/deepseekFlashDefaults'
+import { resolveMentionedMunicipalityId } from '@/utilities/municipality/municipalityMentionResolver'
import { classifySpeech } from '@/utilities/speech/speechClassifier'
/**
@@ -76,8 +77,6 @@ const SYSTEM_PROMPT =
const clip = (value: string, maximum: number): string => value.trim().slice(0, maximum).trim()
-const escapeRegExp = (value: string): string => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
-
/** Deterministic fallback: never empty, never invents a fact. */
export const buildContentPieceFallbackMetadata = ({
type,
@@ -151,10 +150,10 @@ const suggestContentPieceMetadata: ContentPieceSuggester = async ({
}
/**
- * The city rule is deliberately conservative: the gazetteer mention list is
- * converted to distinct cities, and only a city with exactly ONE catalog entry
- * resolves. Salvador has one entry per TSE zone, so a bare "Salvador" mention
- * is ambiguous and stays empty — the assessoria picks the zone on the ficha.
+ * The content-piece entry point to the shared conservative city rule
+ * (`resolveMentionedMunicipalityId`): only a city with exactly ONE catalog
+ * entry resolves, and a bare "Salvador" stays empty — the assessoria picks the
+ * zone on the ficha.
*/
export const resolveContentPieceMunicipalityId = async ({
payload,
@@ -162,24 +161,7 @@ export const resolveContentPieceMunicipalityId = async ({
}: {
payload: Payload
transcript: string
-}): Promise => {
- const mentions = matchMunicipalityMentions(transcript)
- const cities = new Set(mentions.map((entry) => entry.city))
- if (cities.size !== 1) return null
- const entries = mentions.filter((entry) => entry.city === [...cities][0])
- if (entries.length !== 1) return null
-
- const found = await payload.find({
- collection: 'municipality',
- where: { slug: { equals: entries[0]!.slug } },
- depth: 0,
- limit: 1,
- pagination: false,
- // Intentional admin bypass: the município catalog is read-only geography.
- overrideAccess: true,
- })
- return found.docs[0]?.id ?? null
-}
+}): Promise => resolveMentionedMunicipalityId({ payload, text: transcript })
/**
* Matches the institution catalog against the text: a spelling counts only as a
diff --git a/src/utilities/flickr/archivePhotoCatalog.ts b/src/utilities/flickr/archivePhotoCatalog.ts
new file mode 100644
index 00000000..77540a59
--- /dev/null
+++ b/src/utilities/flickr/archivePhotoCatalog.ts
@@ -0,0 +1,277 @@
+import 'server-only'
+
+import { mkdtemp, rm } from 'node:fs/promises'
+import { tmpdir } from 'node:os'
+import { join } from 'node:path'
+import type { Payload } from 'payload'
+import sharp from 'sharp'
+
+import { ARCHIVE_PHOTO_SLUG } from '@/lib/archivePhoto'
+import {
+ buildArchivePhotoCatalogWrite,
+ matchPublicFigureMentions,
+ type ArchivePhotoCatalogSource,
+ type ArchivePhotoSuggestion,
+} from '@/lib/archivePhotoCatalog'
+import { classifySpeechByGazetteer } from '@/lib/speechGazetteer'
+import { messageOf } from '@/utilities/media/ffmpeg'
+import { resolveMentionedMunicipalityId } from '@/utilities/municipality/municipalityMentionResolver'
+import { withPayloadTransaction } from '@/utilities/payloadTransaction'
+import {
+ downloadPrivateMediaToFile,
+ resolvePrivateMediaStaticDir,
+} from '@/utilities/privateMedia/privateMediaResponse'
+
+/**
+ * C232 — Payload-side cataloguing of one archive photo: the private bytes are
+ * downloaded to a temp file, downscaled for the engine, answered by the
+ * injected analyzer and merged with the deterministic text rules (gazetteer
+ * municipality/themes, curated-catalog people) inside ONE transaction that
+ * re-reads `curatedFields` and never overwrites a human decision. The engine
+ * is a seam: `src/` never imports `scripts/`; the CLI injects the HTTP client.
+ *
+ * Failure of one photo is returned, never thrown — the caller owns the receipt,
+ * nothing is written and the next run retries it (a failure is NOT a state).
+ * The model never names people and there is no biometrics here.
+ */
+
+/** Long edge sent to the engine; the original never leaves the archive. */
+const IMAGE_MAX_EDGE = 1024
+const IMAGE_JPEG_QUALITY = 80
+
+export type ArchivePhotoCatalogItem = {
+ id: number
+ flickrId: string
+ filename: string | null
+ mimeType: string | null
+ title: string | null
+ description: string | null
+ takenAt: string | null
+ alt: string
+ albums: { title: string }[]
+ tags: string[]
+}
+
+export type ArchivePhotoAnalyzer = (input: {
+ imageDataUrl: string
+}) => Promise
+
+export type ArchivePhotoCatalogResult =
+ | { status: 'cataloged'; source: ArchivePhotoCatalogSource }
+ | { status: 'skipped' }
+ | {
+ status: 'failed'
+ stage: 'download' | 'image' | 'analyze' | 'resolve' | 'write'
+ error: string
+ }
+
+const toItem = (doc: {
+ id: number
+ flickrId: string
+ filename?: string | null
+ mimeType?: string | null
+ title?: string | null
+ description?: string | null
+ takenAt?: string | null
+ alt: string
+ albums?: ({ title?: string | null } | null)[] | null
+ tags?: ({ name?: string | null } | null)[] | null
+}): ArchivePhotoCatalogItem => ({
+ id: doc.id,
+ flickrId: doc.flickrId,
+ filename: doc.filename ?? null,
+ mimeType: doc.mimeType ?? null,
+ title: doc.title ?? null,
+ description: doc.description ?? null,
+ takenAt: doc.takenAt ?? null,
+ alt: doc.alt,
+ albums: (doc.albums ?? [])
+ .map((album) => album?.title ?? '')
+ .filter((title) => title !== '')
+ .map((title) => ({ title })),
+ tags: (doc.tags ?? []).map((tag) => tag?.name ?? '').filter((name) => name !== ''),
+})
+
+const catalogSelect = {
+ flickrId: true,
+ filename: true,
+ mimeType: true,
+ title: true,
+ description: true,
+ takenAt: true,
+ alt: true,
+ albums: true,
+ tags: true,
+} as const
+
+/**
+ * The photos still waiting for a catalogue, oldest first. `catalogedAt` is the
+ * idempotency key: a catalogued photo (any source, including "nada a propor")
+ * never enters the queue again. `limit` is the canary cap — when absent, the
+ * whole queue is paged read-only.
+ */
+export const listArchivePhotoCatalogQueue = async ({
+ payload,
+ limit,
+}: {
+ payload: Payload
+ limit?: number | null
+}): Promise => {
+ const items: ArchivePhotoCatalogItem[] = []
+ let page = 1
+ let totalPages = 1
+ do {
+ const found = await payload.find({
+ collection: ARCHIVE_PHOTO_SLUG,
+ where: { 'catalog.catalogedAt': { exists: false } },
+ page,
+ limit: 100,
+ depth: 0,
+ sort: 'id',
+ select: catalogSelect,
+ // Intentional bypass: the catalogue CLI is a trusted actor with no session.
+ overrideAccess: true,
+ })
+ for (const doc of found.docs) {
+ items.push(toItem(doc))
+ if (limit != null && items.length >= limit) return items
+ }
+ totalPages = found.totalPages
+ page += 1
+ } while (page <= totalPages)
+ return items
+}
+
+/**
+ * One photo through the whole pipeline. Phases fail with a NAMED stage so the
+ * receipt says why: download/image never reach the engine, analyze is the
+ * provider, write is the transaction. `skipped` means the photo was catalogued
+ * after the queue was read (fresh read inside the transaction).
+ */
+export const catalogArchivePhoto = async ({
+ payload,
+ item,
+ analyze,
+}: {
+ payload: Payload
+ item: ArchivePhotoCatalogItem
+ analyze: ArchivePhotoAnalyzer
+}): Promise => {
+ let tempDir: string | null = null
+ try {
+ tempDir = await mkdtemp(join(tmpdir(), 'archive-photo-'))
+ const originalPath = join(tempDir, 'original')
+
+ try {
+ await downloadPrivateMediaToFile({
+ media: { filename: item.filename, mimeType: item.mimeType },
+ staticDir: resolvePrivateMediaStaticDir(payload, ARCHIVE_PHOTO_SLUG),
+ destinationPath: originalPath,
+ })
+ } catch (error) {
+ return { status: 'failed', stage: 'download', error: messageOf(error, 'erro desconhecido') }
+ }
+
+ let imageDataUrl: string
+ try {
+ const resized = await sharp(originalPath)
+ .rotate()
+ .resize({
+ width: IMAGE_MAX_EDGE,
+ height: IMAGE_MAX_EDGE,
+ fit: 'inside',
+ withoutEnlargement: true,
+ })
+ .jpeg({ quality: IMAGE_JPEG_QUALITY })
+ .toBuffer()
+ imageDataUrl = `data:image/jpeg;base64,${resized.toString('base64')}`
+ } catch (error) {
+ return { status: 'failed', stage: 'image', error: messageOf(error, 'erro desconhecido') }
+ }
+
+ let suggestion: ArchivePhotoSuggestion
+ try {
+ suggestion = await analyze({ imageDataUrl })
+ } catch (error) {
+ return { status: 'failed', stage: 'analyze', error: messageOf(error, 'erro desconhecido') }
+ }
+
+ const text = [
+ item.alt,
+ item.title,
+ item.description,
+ ...item.albums.map((album) => album.title),
+ ...item.tags,
+ suggestion.caption,
+ suggestion.visibleText,
+ ]
+ .filter((value): value is string => typeof value === 'string' && value.trim() !== '')
+ .join(' ')
+
+ let municipalityId: number | null
+ try {
+ municipalityId = await resolveMentionedMunicipalityId({ payload, text })
+ } catch (error) {
+ return { status: 'failed', stage: 'resolve', error: messageOf(error, 'erro desconhecido') }
+ }
+ const mentionedPeople = matchPublicFigureMentions(text)
+ const gazetteerThemes = classifySpeechByGazetteer({ transcript: text }).topics
+
+ try {
+ return await withPayloadTransaction(payload, async ({ req }) => {
+ // Fresh read inside the transaction: whatever the assessoria curated
+ // (or another run catalogued) while this photo was in flight wins.
+ const fresh = await payload.find({
+ collection: ARCHIVE_PHOTO_SLUG,
+ where: { id: { equals: item.id } },
+ depth: 0,
+ limit: 1,
+ pagination: false,
+ select: { alt: true, curatedFields: true, catalog: true },
+ req,
+ // Intentional bypass: the catalogue CLI is a trusted actor with no session.
+ overrideAccess: true,
+ })
+ const doc = fresh.docs[0]
+ if (!doc) return { status: 'failed', stage: 'write', error: 'Foto não encontrada.' }
+ if (doc.catalog?.catalogedAt) return { status: 'skipped' }
+
+ const write = buildArchivePhotoCatalogWrite({
+ suggestion,
+ municipalityId,
+ mentionedPeople,
+ gazetteerThemes,
+ curatedFields: doc.curatedFields ?? [],
+ // Depth 0: the relationship is the id even when the generated type
+ // still allows the populated shape.
+ currentCatalog: doc.catalog
+ ? {
+ ...doc.catalog,
+ municipality:
+ typeof doc.catalog.municipality === 'number' ? doc.catalog.municipality : null,
+ }
+ : null,
+ currentAlt: doc.alt,
+ catalogedAt: new Date().toISOString(),
+ })
+
+ await payload.update({
+ collection: ARCHIVE_PHOTO_SLUG,
+ id: item.id,
+ data: write.data,
+ depth: 0,
+ req,
+ context: { archivePhotoCatalog: true },
+ // Intentional bypass: the catalogue CLI is a trusted actor with no session.
+ overrideAccess: true,
+ })
+
+ return { status: 'cataloged', source: write.source }
+ })
+ } catch (error) {
+ return { status: 'failed', stage: 'write', error: messageOf(error, 'erro desconhecido') }
+ }
+ } finally {
+ if (tempDir) await rm(tempDir, { recursive: true, force: true }).catch(() => undefined)
+ }
+}
diff --git a/src/utilities/municipality/municipalityMentionResolver.ts b/src/utilities/municipality/municipalityMentionResolver.ts
new file mode 100644
index 00000000..a532d4d8
--- /dev/null
+++ b/src/utilities/municipality/municipalityMentionResolver.ts
@@ -0,0 +1,38 @@
+import 'server-only'
+
+import type { Payload } from 'payload'
+
+import { matchMunicipalityMentions } from '@/lib/speechGazetteer'
+
+/**
+ * C232 — the shared, conservative município resolution from free text: the
+ * gazetteer mentions are reduced to distinct cities and only a city with
+ * exactly ONE catalogue entry resolves. Salvador has one entry per TSE zone,
+ * so a bare "Salvador" mention is ambiguous and stays empty — the ficha picks
+ * the zone. Extracted from the content-piece cataloguing (C211) so the photo
+ * cataloguing (C232) uses the same rule instead of a twin.
+ */
+export const resolveMentionedMunicipalityId = async ({
+ payload,
+ text,
+}: {
+ payload: Payload
+ text: string
+}): Promise => {
+ const mentions = matchMunicipalityMentions(text)
+ const cities = new Set(mentions.map((entry) => entry.city))
+ if (cities.size !== 1) return null
+ const entries = mentions.filter((entry) => entry.city === [...cities][0])
+ if (entries.length !== 1) return null
+
+ const found = await payload.find({
+ collection: 'municipality',
+ where: { slug: { equals: entries[0]!.slug } },
+ depth: 0,
+ limit: 1,
+ pagination: false,
+ // Intentional admin bypass: the município catalog is read-only geography.
+ overrideAccess: true,
+ })
+ return found.docs[0]?.id ?? null
+}
diff --git a/tests/int/archivePhotoCatalog.int.spec.ts b/tests/int/archivePhotoCatalog.int.spec.ts
new file mode 100644
index 00000000..66aeb357
--- /dev/null
+++ b/tests/int/archivePhotoCatalog.int.spec.ts
@@ -0,0 +1,337 @@
+// @vitest-environment node
+
+import { mkdtemp, rm, writeFile } from 'node:fs/promises'
+import { tmpdir } from 'node:os'
+import { join } from 'node:path'
+import type { Payload } from 'payload'
+import { getPayload } from 'payload'
+import { afterAll, beforeAll, describe, expect, it } from 'vitest'
+
+import { ARCHIVE_PHOTO_SLUG, type ArchivePhotoImport } from '@/lib/archivePhoto'
+import type { ArchivePhotoSuggestion } from '@/lib/archivePhotoCatalog'
+import { publicFigureCatalog } from '@/lib/publicFigureCatalog'
+import config from '@/payload.config'
+import {
+ catalogArchivePhoto,
+ listArchivePhotoCatalogQueue,
+ type ArchivePhotoAnalyzer,
+ type ArchivePhotoCatalogItem,
+} from '@/utilities/flickr/archivePhotoCatalog'
+import { ingestArchivePhoto } from '@/utilities/flickr/archivePhotoIngest'
+
+import { ARCHIVE_PHOTO_JPEG_BYTES } from '../helpers/archivePhotoFixture'
+import { installCampaignFixtures } from '../helpers/campaignFixtures'
+
+// C232 — the cataloguing boundary over the real Payload `teqo_test`: the
+// transactional write, the curated-wins rule, the honest failure (nothing
+// written, retried) and the derived index (searchText/takenOn). The vision
+// engine is a stub — the real provider never enters the suite.
+
+let payload: Payload
+const createdFlickrIds = new Set()
+const tempDirs: string[] = []
+
+const campaignFixtures = installCampaignFixtures({
+ getPayload: () => payload,
+ setPayload: (nextPayload) => {
+ payload = nextPayload
+ },
+})
+
+const figureName = publicFigureCatalog[0]!.name
+
+const record = (
+ flickrId: string,
+ overrides: Partial = {},
+): ArchivePhotoImport => {
+ createdFlickrIds.add(flickrId)
+ return {
+ flickrId,
+ sourceUrl: `https://www.flickr.com/photos/depjorgesolla/${flickrId}/`,
+ owner: '12345678@N00',
+ license: '0',
+ title: `Foto ${flickrId}`,
+ description: null,
+ tags: [],
+ takenAt: '2025-03-14 10:20:30',
+ postedAt: '2025-03-15T10:00:00.000Z',
+ albums: [],
+ geo: null,
+ exif: [],
+ originalUrl: `https://live.staticflickr.com/65535/${flickrId}_abcdef_o.jpg`,
+ originalKind: 'original',
+ ...overrides,
+ }
+}
+
+const createPhoto = async (
+ flickrId: string,
+ overrides: Partial = {},
+): Promise<{ id: number; item: ArchivePhotoCatalogItem }> => {
+ const dir = await mkdtemp(join(tmpdir(), 'archive-photo-'))
+ tempDirs.push(dir)
+ const filePath = join(dir, `flickr-${flickrId}.jpg`)
+ await writeFile(filePath, ARCHIVE_PHOTO_JPEG_BYTES)
+ const created = await ingestArchivePhoto(payload, record(flickrId, overrides), { filePath })
+ if (created.status !== 'created') throw new Error(`fixture not created: ${created.status}`)
+
+ const queue = await listArchivePhotoCatalogQueue({ payload })
+ const item = queue.find((entry) => entry.flickrId === flickrId)
+ if (!item) throw new Error(`fixture not in the catalog queue: ${flickrId}`)
+ return { id: created.id, item }
+}
+
+const suggestion = (overrides: Partial = {}): ArchivePhotoSuggestion => ({
+ caption: null,
+ description: null,
+ scene: null,
+ visibleText: null,
+ hasPeople: null,
+ themes: [],
+ ...overrides,
+})
+
+const analyzeWith =
+ (answer: ArchivePhotoSuggestion): ArchivePhotoAnalyzer =>
+ async () =>
+ answer
+
+const findByFlickrId = async (flickrId: string) => {
+ const found = await payload.find({
+ collection: ARCHIVE_PHOTO_SLUG,
+ where: { flickrId: { equals: flickrId } },
+ depth: 0,
+ limit: 1,
+ overrideAccess: true,
+ })
+ return found.docs[0] ?? null
+}
+
+const municipalityId = async (slug: string): Promise => {
+ const found = await payload.find({
+ collection: 'municipality',
+ where: { slug: { equals: slug } },
+ depth: 0,
+ limit: 1,
+ overrideAccess: true,
+ })
+ const id = found.docs[0]?.id
+ if (id == null) throw new Error(`município fixture ausente: ${slug}`)
+ return id
+}
+
+describe('catalogArchivePhoto (C232)', () => {
+ beforeAll(async () => {
+ payload = await getPayload({ config: await config })
+ })
+
+ afterAll(async () => {
+ for (const flickrId of createdFlickrIds) {
+ await payload.delete({
+ collection: ARCHIVE_PHOTO_SLUG,
+ where: { flickrId: { equals: flickrId } },
+ overrideAccess: true,
+ })
+ }
+ await Promise.all(tempDirs.map((dir) => rm(dir, { recursive: true, force: true })))
+ })
+
+ it('catalogues one photo and derives the searchable index', async () => {
+ const feira = await municipalityId('feira-de-santana')
+ const { item } = await createPhoto('53900000001', {
+ title: 'Plenária em Feira de Santana',
+ albums: [{ albumId: '1', title: 'Plenária em Feira de Santana' }],
+ tags: ['saude'],
+ })
+
+ const result = await catalogArchivePhoto({
+ payload,
+ item,
+ analyze: analyzeWith(
+ suggestion({
+ caption: 'Plenária lotada no interior',
+ description: 'Solla discursa para uma plateia cheia.',
+ scene: 'plenaria',
+ visibleText: 'SAÚDE É DIREITO',
+ hasPeople: true,
+ themes: ['saude'],
+ }),
+ ),
+ })
+
+ expect(result).toEqual({ status: 'cataloged', source: 'ai' })
+ const doc = await findByFlickrId('53900000001')
+ expect(doc?.catalog).toMatchObject({
+ caption: 'Plenária lotada no interior',
+ description: 'Solla discursa para uma plateia cheia.',
+ scene: 'plenaria',
+ visibleText: 'SAÚDE É DIREITO',
+ hasPeople: true,
+ themes: ['saude'],
+ municipality: feira,
+ source: 'ai',
+ })
+ expect(doc?.catalog?.catalogedAt).toBeTruthy()
+ expect(doc?.takenOn).toBe('2025-03-14T12:00:00.000Z')
+ expect(doc?.searchText).toContain('plenaria')
+ expect(doc?.searchText).toContain('feira de santana')
+ expect(doc?.searchText).toContain('saude')
+ expect(doc?.searchText).toContain('plenaria lotada no interior')
+ })
+
+ it('matches the curated public-figure catalog against the text, never the model', async () => {
+ const { item } = await createPhoto('53900000002', {
+ title: `Encontro com ${figureName}`,
+ })
+
+ expect(item.title).toContain(figureName)
+ const result = await catalogArchivePhoto({
+ payload,
+ item,
+ analyze: analyzeWith(suggestion({ caption: 'Encontro político' })),
+ })
+
+ expect(result).toEqual({ status: 'cataloged', source: 'ai' })
+ const doc = await findByFlickrId('53900000002')
+ expect(doc?.catalog?.people).toEqual([figureName])
+ })
+
+ it('states metadata when the model has nothing to propose', async () => {
+ const feira = await municipalityId('feira-de-santana')
+ const { item } = await createPhoto('53900000003', {
+ title: 'Visita a Feira de Santana',
+ })
+
+ const result = await catalogArchivePhoto({
+ payload,
+ item,
+ analyze: analyzeWith(suggestion()),
+ })
+
+ expect(result).toEqual({ status: 'cataloged', source: 'metadata' })
+ const doc = await findByFlickrId('53900000003')
+ expect(doc?.catalog?.municipality).toBe(feira)
+ expect(doc?.catalog?.source).toBe('metadata')
+ expect(doc?.catalog?.catalogedAt).toBeTruthy()
+ })
+
+ it('states none, honestly, when there is nothing at all', async () => {
+ const { item } = await createPhoto('53900000004')
+
+ const result = await catalogArchivePhoto({
+ payload,
+ item,
+ analyze: analyzeWith(suggestion()),
+ })
+
+ expect(result).toEqual({ status: 'cataloged', source: 'none' })
+ const doc = await findByFlickrId('53900000004')
+ expect(doc?.catalog?.source).toBe('none')
+ expect(doc?.catalog?.catalogedAt).toBeTruthy()
+ })
+
+ it('never overwrites a curated field', async () => {
+ const feira = await municipalityId('feira-de-santana')
+ const { id, item } = await createPhoto('53900000005', {
+ title: 'Plenária em Feira de Santana',
+ })
+ const admin = await campaignFixtures().createAdminUser()
+ await payload.update({
+ collection: ARCHIVE_PHOTO_SLUG,
+ id,
+ data: { catalog: { caption: 'Legenda humana', municipality: feira } },
+ user: admin,
+ overrideAccess: false,
+ })
+
+ const result = await catalogArchivePhoto({
+ payload,
+ item,
+ analyze: analyzeWith(suggestion({ caption: 'Legenda da IA' })),
+ })
+
+ expect(result).toEqual({ status: 'cataloged', source: 'none' })
+ const doc = await findByFlickrId('53900000005')
+ expect(doc?.catalog?.caption).toBe('Legenda humana')
+ expect(doc?.catalog?.municipality).toBe(feira)
+ expect(doc?.curatedFields).toEqual(expect.arrayContaining(['caption', 'municipality']))
+ })
+
+ it('reports a failed analysis, writes nothing and lets the next run retry', async () => {
+ const { item } = await createPhoto('53900000006', { title: 'Plenária em Feira de Santana' })
+
+ const failing: ArchivePhotoAnalyzer = async () => {
+ throw new Error('engine fora do ar')
+ }
+ const failed = await catalogArchivePhoto({ payload, item, analyze: failing })
+
+ expect(failed).toEqual({ status: 'failed', stage: 'analyze', error: 'engine fora do ar' })
+ expect((await findByFlickrId('53900000006'))?.catalog?.catalogedAt ?? null).toBeNull()
+
+ const retried = await catalogArchivePhoto({
+ payload,
+ item,
+ analyze: analyzeWith(suggestion({ caption: 'Segunda tentativa' })),
+ })
+ expect(retried).toEqual({ status: 'cataloged', source: 'ai' })
+ expect((await findByFlickrId('53900000006'))?.catalog?.caption).toBe('Segunda tentativa')
+ })
+
+ it('skips a photo catalogued after the queue was read', async () => {
+ const { item } = await createPhoto('53900000007')
+ await catalogArchivePhoto({
+ payload,
+ item,
+ analyze: analyzeWith(suggestion({ caption: 'Primeira passada' })),
+ })
+
+ const second = await catalogArchivePhoto({
+ payload,
+ item,
+ analyze: analyzeWith(suggestion({ caption: 'Segunda passada' })),
+ })
+
+ expect(second).toEqual({ status: 'skipped' })
+ expect((await findByFlickrId('53900000007'))?.catalog?.caption).toBe('Primeira passada')
+ expect(
+ (await listArchivePhotoCatalogQueue({ payload })).map((entry) => entry.flickrId),
+ ).not.toContain('53900000007')
+ })
+
+ it('caps the queue with the canary limit and marks curation only on user edits', async () => {
+ const { id } = await createPhoto('53900000008')
+ await createPhoto('53900000009')
+ const queued = await listArchivePhotoCatalogQueue({ payload, limit: 1 })
+ expect(queued).toHaveLength(1)
+
+ const admin = await campaignFixtures().createAdminUser()
+ await payload.update({
+ collection: ARCHIVE_PHOTO_SLUG,
+ id,
+ data: { catalog: { scene: 'evento' } },
+ user: admin,
+ overrideAccess: false,
+ })
+ expect((await findByFlickrId('53900000008'))?.curatedFields).toEqual(['scene'])
+
+ // A no-op admin save marks nothing new.
+ await payload.update({
+ collection: ARCHIVE_PHOTO_SLUG,
+ id,
+ data: { catalog: { scene: 'evento' } },
+ user: admin,
+ overrideAccess: false,
+ })
+ expect((await findByFlickrId('53900000008'))?.curatedFields).toEqual(['scene'])
+
+ // The system write (the cataloguing itself) never marks.
+ await payload.update({
+ collection: ARCHIVE_PHOTO_SLUG,
+ id,
+ data: { catalog: { caption: 'escrita do sistema' } },
+ context: { archivePhotoCatalog: true },
+ overrideAccess: true,
+ })
+ expect((await findByFlickrId('53900000008'))?.curatedFields).toEqual(['scene'])
+ })
+})
diff --git a/tests/unit/archiveCatalogCli.unit.spec.ts b/tests/unit/archiveCatalogCli.unit.spec.ts
new file mode 100644
index 00000000..c3a16241
--- /dev/null
+++ b/tests/unit/archiveCatalogCli.unit.spec.ts
@@ -0,0 +1,125 @@
+import { spawnSync } from 'node:child_process'
+import { join } from 'node:path'
+
+import { describe, expect, it } from 'vitest'
+
+// C232 — the cataloguing CLI's fail-closed write guards, exercised as a
+// subprocess: each refusal must happen before any engine call or DB connection.
+
+const repoRoot = process.cwd()
+const scriptPath = join(repoRoot, 'scripts', 'catalog-archive-photos.mjs')
+
+const run = (args: string[], env: Record = {}) =>
+ spawnSync(process.execPath, [scriptPath, ...args], {
+ cwd: repoRoot,
+ encoding: 'utf8',
+ timeout: 30_000,
+ env: {
+ ...process.env,
+ NODE_OPTIONS: '--no-deprecation --import=tsx/esm --import=./scripts/seed-loader.mjs',
+ NODE_ENV: 'production',
+ VITEST: '',
+ DATABASE_URL: 'postgresql://teqo:teqo@127.0.0.1:5432/teqo_1313',
+ PAYLOAD_SECRET: 'test-secret',
+ ARCHIVE_CATALOG_CONFIRM: '',
+ ARCHIVE_VISION_BASE_URL: '',
+ ARCHIVE_VISION_MODEL: '',
+ ARCHIVE_VISION_ALLOW_REMOTE: '',
+ TEQO_ENV: '',
+ ALLOW_REMOTE_DB: '',
+ S3_BUCKET: '',
+ S3_ENDPOINT: '',
+ S3_ACCESS_KEY_ID: '',
+ S3_SECRET_ACCESS_KEY: '',
+ ...env,
+ },
+ })
+
+const output = (result: ReturnType) => `${result.stdout}${result.stderr}`
+const withS3 = {
+ S3_BUCKET: 'bucket',
+ S3_ENDPOINT: 'http://127.0.0.1:3900',
+ S3_ACCESS_KEY_ID: 'key',
+ S3_SECRET_ACCESS_KEY: 'secret',
+}
+
+describe('archive:catalog write guards (C232)', () => {
+ it('prints the help even without a database', () => {
+ const result = run(['--help'], { DATABASE_URL: '' })
+
+ expect(result.status).toBe(0)
+ expect(result.stdout).toContain('ARCHIVE_CATALOG_CONFIRM')
+ expect(result.stdout).toContain('ARCHIVE_VISION_BASE_URL')
+ })
+
+ it('refuses --apply on a production target without the intent flag', () => {
+ const result = run(['--apply'])
+
+ expect(result.status).toBe(1)
+ expect(output(result)).toContain('ARCHIVE_CATALOG_CONFIRM=1')
+ })
+
+ it('requires the declared TEQO_ENV once the intent flag is set', () => {
+ const result = run(['--apply'], { ARCHIVE_CATALOG_CONFIRM: '1' })
+
+ expect(result.status).toBe(1)
+ expect(output(result)).toContain('TEQO_ENV')
+ })
+
+ it('refuses a target database that does not match the declared environment', () => {
+ const result = run(['--apply'], { ARCHIVE_CATALOG_CONFIRM: '1', TEQO_ENV: 'staging' })
+
+ expect(result.status).toBe(1)
+ expect(output(result)).toContain('≠ "teqo_staging"')
+ })
+
+ it('refuses --apply without the complete S3_* set on a declared production target', () => {
+ const result = run(['--apply'], { ARCHIVE_CATALOG_CONFIRM: '1', TEQO_ENV: 'production' })
+
+ expect(result.status).toBe(1)
+ expect(output(result)).toContain('S3_BUCKET')
+ })
+
+ it('refuses --apply without the vision endpoint', () => {
+ const result = run(['--apply'], {
+ ARCHIVE_CATALOG_CONFIRM: '1',
+ TEQO_ENV: 'production',
+ ...withS3,
+ })
+
+ expect(result.status).toBe(1)
+ expect(output(result)).toContain('ARCHIVE_VISION_BASE_URL')
+ })
+
+ it('refuses a public vision host without the explicit remote escape', () => {
+ const result = run(['--apply'], {
+ ARCHIVE_CATALOG_CONFIRM: '1',
+ TEQO_ENV: 'production',
+ ARCHIVE_VISION_BASE_URL: 'https://api.example.com/v1',
+ ...withS3,
+ })
+
+ expect(result.status).toBe(1)
+ expect(output(result)).toContain('host público')
+ expect(output(result)).toContain('ARCHIVE_VISION_ALLOW_REMOTE')
+ })
+
+ it('requires the model once the private endpoint is accepted', () => {
+ const result = run(['--apply'], {
+ ARCHIVE_CATALOG_CONFIRM: '1',
+ TEQO_ENV: 'production',
+ ARCHIVE_VISION_BASE_URL: 'http://100.94.122.26:11434/v1',
+ ...withS3,
+ })
+
+ expect(result.status).toBe(1)
+ expect(output(result)).toContain('ARCHIVE_VISION_MODEL')
+ })
+
+ it('refuses an unknown argument before touching anything', () => {
+ const result = run(['--force'])
+
+ expect(result.status).toBe(1)
+ expect(output(result)).toContain('argumento desconhecido')
+ })
+})
diff --git a/tests/unit/archiveCatalogPlan.unit.spec.ts b/tests/unit/archiveCatalogPlan.unit.spec.ts
new file mode 100644
index 00000000..fbd4c36e
--- /dev/null
+++ b/tests/unit/archiveCatalogPlan.unit.spec.ts
@@ -0,0 +1,141 @@
+import { describe, expect, it } from 'vitest'
+
+import {
+ ARCHIVE_CATALOG_DEFAULT_OUT_DIR,
+ formatArchiveCatalogInventory,
+ formatArchiveCatalogReport,
+ parseArchiveCatalogCliArgs,
+ summarizeArchiveCatalogInventory,
+ summarizeArchiveCatalogResults,
+} from '../../scripts/lib/archiveCatalogPlan.mjs'
+
+// C232 — the pure CLI planning/reporting of the archive cataloguing: the argv
+// contract, the run summaries and the `--verify` inventory the receipt and the
+// stdout lines are built from.
+
+describe('parseArchiveCatalogCliArgs (C232)', () => {
+ it('defaults to the plan mode and the canonical receipt dir', () => {
+ expect(parseArchiveCatalogCliArgs([])).toEqual({
+ apply: false,
+ verify: false,
+ limit: null,
+ out: ARCHIVE_CATALOG_DEFAULT_OUT_DIR,
+ help: false,
+ })
+ })
+
+ it('parses the modes and options', () => {
+ expect(
+ parseArchiveCatalogCliArgs(['--apply', '--limit', '5', '--out', 'data/x']),
+ ).toMatchObject({
+ apply: true,
+ limit: 5,
+ out: 'data/x',
+ })
+ expect(parseArchiveCatalogCliArgs(['--verify'])).toMatchObject({ verify: true })
+ expect(parseArchiveCatalogCliArgs(['--help'])).toMatchObject({ help: true })
+ })
+
+ it('refuses conflicting, unknown and unsafe input', () => {
+ expect(() => parseArchiveCatalogCliArgs(['--apply', '--verify'])).toThrow(/mutuamente/)
+ expect(() => parseArchiveCatalogCliArgs(['--limit', '0'])).toThrow(/--limit/)
+ expect(() => parseArchiveCatalogCliArgs(['--limit'])).toThrow(/faltou valor/)
+ expect(() => parseArchiveCatalogCliArgs(['--force'])).toThrow(/desconhecido/)
+ expect(() => parseArchiveCatalogCliArgs(['--out', '../fora'])).toThrow(/\.\./)
+ })
+})
+
+describe('summarizeArchiveCatalogResults (C232)', () => {
+ it('counts the outcomes, the sources and names every failure', () => {
+ const summary = summarizeArchiveCatalogResults([
+ { flickrId: '1', status: 'cataloged', source: 'ai' },
+ { flickrId: '2', status: 'cataloged', source: 'none' },
+ { flickrId: '3', status: 'skipped' },
+ { flickrId: '4', status: 'failed', stage: 'analyze', error: 'engine fora do ar' },
+ ])
+
+ expect(summary).toEqual({
+ cataloged: 2,
+ skipped: 1,
+ failed: 1,
+ bySource: { ai: 1, metadata: 0, none: 1 },
+ failures: [{ flickrId: '4', stage: 'analyze', error: 'engine fora do ar' }],
+ })
+ })
+})
+
+describe('summarizeArchiveCatalogInventory (C232)', () => {
+ it('separates catalogued from pending and flags the missing file', () => {
+ const inventory = summarizeArchiveCatalogInventory([
+ {
+ flickrId: '1',
+ filename: 'a.jpg',
+ catalog: { catalogedAt: 'x', source: 'ai', scene: 'evento', municipality: 1 },
+ },
+ { flickrId: '2', filename: 'b.jpg', catalog: { catalogedAt: 'x', source: 'metadata' } },
+ { flickrId: '3', filename: 'c.jpg', catalog: {} },
+ { flickrId: '4', filename: null, catalog: { catalogedAt: 'x', source: 'none' } },
+ ])
+
+ expect(inventory).toMatchObject({
+ total: 4,
+ cataloged: 3,
+ pending: 1,
+ bySource: { ai: 1, metadata: 1, none: 1 },
+ withoutScene: 2,
+ withoutMunicipality: 2,
+ missingFilename: ['4'],
+ })
+ })
+})
+
+describe('report lines (C232)', () => {
+ it('renders the plan line with the pending count', () => {
+ const lines = formatArchiveCatalogReport({
+ mode: 'plan',
+ target: '127.0.0.1/teqo_staging',
+ engine: { host: '100.94.122.26', model: 'qwen2.5vl:7b', scope: 'local' },
+ pending: 12,
+ durationMs: 1500,
+ })
+
+ expect(lines[0]).toContain('100.94.122.26 (qwen2.5vl:7b, local)')
+ expect(lines.join('\n')).toContain('pendentes na fila: 12')
+ })
+
+ it('renders the apply summary and every failure', () => {
+ const lines = formatArchiveCatalogReport({
+ mode: 'apply',
+ target: '127.0.0.1/teqo_staging',
+ durationMs: 2000,
+ summary: summarizeArchiveCatalogResults([
+ { flickrId: '1', status: 'cataloged', source: 'ai' },
+ { flickrId: '2', status: 'failed', stage: 'analyze', error: 'timeout' },
+ ]),
+ })
+
+ const text = lines.join('\n')
+ expect(text).toContain('processadas: 1')
+ expect(text).toContain('falharam: 1')
+ expect(text).toContain('IA: 1')
+ expect(text).toContain('2 (analyze): timeout')
+ })
+
+ it('renders the verify inventory with the pending gap', () => {
+ const lines = formatArchiveCatalogInventory({
+ total: 3,
+ cataloged: 2,
+ pending: 1,
+ bySource: { ai: 1, metadata: 1, none: 0 },
+ withoutScene: 1,
+ withoutMunicipality: 1,
+ missingFilename: [],
+ })
+
+ const text = lines.join('\n')
+ expect(text).toContain('catalogadas: 2')
+ expect(text).toContain('pendentes: 1')
+ expect(text).toContain('IA: 1')
+ expect(text).toContain('ainda pendentes de catalogação: 1')
+ })
+})
diff --git a/tests/unit/archivePhotoCatalog.unit.spec.ts b/tests/unit/archivePhotoCatalog.unit.spec.ts
new file mode 100644
index 00000000..42b10ce2
--- /dev/null
+++ b/tests/unit/archivePhotoCatalog.unit.spec.ts
@@ -0,0 +1,357 @@
+import { describe, expect, it } from 'vitest'
+
+import {
+ ARCHIVE_PHOTO_CAPTION_MAX_LENGTH,
+ archivePhotoSearchText,
+ archivePhotoTakenOn,
+ archivePhotoThemesFrom,
+ buildArchivePhotoCatalogWrite,
+ changedArchivePhotoCuratedFields,
+ matchPublicFigureMentions,
+ parseArchiveVisionOutput,
+ resolveArchivePhotoScene,
+} from '@/lib/archivePhotoCatalog'
+import { publicFigureCatalog } from '@/lib/publicFigureCatalog'
+
+// C232 — the pure rules of the archive pre-cataloguing: closed vocabularies
+// (scene/themes/curated fields), the fail-closed vision parser, the
+// deterministic text matches and the merge that never overwrites curation.
+// No provider, network or Payload here.
+
+const suggestion = (
+ overrides: Partial[0]['suggestion']> = {},
+) => ({
+ caption: null as string | null,
+ description: null as string | null,
+ scene: null as ReturnType,
+ visibleText: null as string | null,
+ hasPeople: null as boolean | null,
+ themes: [] as ReturnType,
+ ...overrides,
+})
+
+const writeInput = (
+ overrides: Partial[0]> = {},
+): Parameters[0] => ({
+ suggestion: suggestion(),
+ municipalityId: null,
+ mentionedPeople: [],
+ gazetteerThemes: [],
+ curatedFields: [],
+ currentCatalog: null,
+ currentAlt: null,
+ catalogedAt: '2026-09-26T12:00:00.000Z',
+ ...overrides,
+})
+
+describe('resolveArchivePhotoScene (C232)', () => {
+ it('resolves value and pt-BR label, accent/case insensitive', () => {
+ expect(resolveArchivePhotoScene('plenaria')).toBe('plenaria')
+ expect(resolveArchivePhotoScene('Plenária')).toBe('plenaria')
+ expect(resolveArchivePhotoScene('SEGURANCA')).toBeNull()
+ expect(resolveArchivePhotoScene('Audiência')).toBe('audiencia')
+ expect(resolveArchivePhotoScene('outro')).toBe('outro')
+ })
+
+ it('is fail-closed for unknown or non-string tokens', () => {
+ expect(resolveArchivePhotoScene('comício')).toBeNull()
+ expect(resolveArchivePhotoScene(null)).toBeNull()
+ expect(resolveArchivePhotoScene(7)).toBeNull()
+ expect(resolveArchivePhotoScene('')).toBeNull()
+ })
+})
+
+describe('archivePhotoThemesFrom (C232)', () => {
+ it('resolves the existing taxonomy and drops the unknown', () => {
+ expect(archivePhotoThemesFrom(['saude', 'Saúde', 'educacao', 'inventado', 7])).toEqual([
+ 'saude',
+ 'educacao',
+ ])
+ expect(archivePhotoThemesFrom([])).toEqual([])
+ })
+})
+
+describe('matchPublicFigureMentions (C232)', () => {
+ const name = publicFigureCatalog[0]!.name
+
+ it('matches the curated catalog by whole word, accent/case insensitive', () => {
+ expect(matchPublicFigureMentions(`Plenária com ${name} no palco`)).toEqual([name])
+ expect(matchPublicFigureMentions(name.toLowerCase())).toEqual([name])
+ })
+
+ it('never invents a name and ignores unrelated text', () => {
+ expect(matchPublicFigureMentions('Plenária em Vitória da Conquista')).toEqual([])
+ expect(matchPublicFigureMentions('')).toEqual([])
+ })
+})
+
+describe('parseArchiveVisionOutput (C232)', () => {
+ it('parses a fenced JSON answer and normalizes the closed fields', () => {
+ const answer = [
+ '```json',
+ JSON.stringify({
+ caption: ' Plenária lotada no interior ',
+ description: 'Solla discursa para uma plateia cheia.',
+ scene: 'Plenária',
+ visibleText: 'SAÚDE É DIREITO',
+ hasPeople: true,
+ themes: ['Saúde', 'inventado'],
+ }),
+ '```',
+ ].join('\n')
+
+ expect(parseArchiveVisionOutput(answer)).toEqual({
+ caption: 'Plenária lotada no interior',
+ description: 'Solla discursa para uma plateia cheia.',
+ scene: 'plenaria',
+ visibleText: 'SAÚDE É DIREITO',
+ hasPeople: true,
+ themes: ['saude'],
+ })
+ })
+
+ it('is null for a non-object answer (named failure upstream)', () => {
+ expect(parseArchiveVisionOutput('resposta em prosa')).toBeNull()
+ expect(parseArchiveVisionOutput('["a"]')).toBeNull()
+ expect(parseArchiveVisionOutput('{quebrado')).toBeNull()
+ expect(parseArchiveVisionOutput(null)).toBeNull()
+ })
+
+ it('degrades field by field instead of guessing', () => {
+ expect(
+ parseArchiveVisionOutput({
+ caption: 42,
+ scene: 'comício',
+ themes: ['saude', 5],
+ hasPeople: 'sim',
+ }),
+ ).toEqual({
+ caption: null,
+ description: null,
+ scene: null,
+ visibleText: null,
+ hasPeople: null,
+ themes: ['saude'],
+ })
+ })
+
+ it('clips the caption to the field contract', () => {
+ const parsed = parseArchiveVisionOutput({ caption: 'a'.repeat(500) })
+ expect(parsed?.caption).toHaveLength(ARCHIVE_PHOTO_CAPTION_MAX_LENGTH)
+ })
+})
+
+describe('archivePhotoTakenOn (C232)', () => {
+ it('keeps the wall-clock day at noon UTC', () => {
+ expect(archivePhotoTakenOn('2025-03-14 10:20:30')).toBe('2025-03-14T12:00:00.000Z')
+ expect(archivePhotoTakenOn('2025-03-14')).toBe('2025-03-14T12:00:00.000Z')
+ })
+
+ it('is null for a missing or impossible date', () => {
+ expect(archivePhotoTakenOn(null)).toBeNull()
+ expect(archivePhotoTakenOn('14/03/2025')).toBeNull()
+ expect(archivePhotoTakenOn('2025-02-31 10:00:00')).toBeNull()
+ })
+})
+
+describe('changedArchivePhotoCuratedFields (C232)', () => {
+ it('marks only what actually changed for a request with data', () => {
+ expect(
+ changedArchivePhotoCuratedFields({
+ data: { alt: 'novo', catalog: { caption: 'x', scene: 'plenaria' } },
+ originalDoc: { alt: 'velho', catalog: { caption: 'x', scene: null } },
+ }),
+ ).toEqual(['alt', 'scene'])
+ })
+
+ it('treats clearing and array edits as curation', () => {
+ expect(
+ changedArchivePhotoCuratedFields({
+ data: { catalog: { themes: [], people: ['Fulano'] } },
+ originalDoc: { catalog: { themes: ['saude'], people: ['Fulano'] } },
+ }),
+ ).toEqual(['themes'])
+ })
+
+ it('normalizes the relationship shape and ignores absent fields', () => {
+ expect(
+ changedArchivePhotoCuratedFields({
+ data: { catalog: { municipality: { id: 5 } } },
+ originalDoc: { catalog: { municipality: 5 } },
+ }),
+ ).toEqual([])
+ expect(
+ changedArchivePhotoCuratedFields({ data: {}, originalDoc: { catalog: { caption: 'x' } } }),
+ ).toEqual([])
+ expect(changedArchivePhotoCuratedFields({ data: null, originalDoc: {} })).toEqual([])
+ })
+})
+
+describe('buildArchivePhotoCatalogWrite (C232)', () => {
+ it('writes the model fields and derives the alt from the caption', () => {
+ const { data, source } = buildArchivePhotoCatalogWrite(
+ writeInput({
+ suggestion: suggestion({
+ caption: 'Comício em Feira de Santana',
+ description: 'Solla cumprimenta apoiadores.',
+ scene: 'evento',
+ visibleText: 'JUNTOS PELA BAHIA',
+ hasPeople: true,
+ themes: ['politica-instituicoes'],
+ }),
+ }),
+ )
+
+ expect(source).toBe('ai')
+ expect(data.alt).toBe('Comício em Feira de Santana')
+ expect(data.catalog).toEqual({
+ caption: 'Comício em Feira de Santana',
+ description: 'Solla cumprimenta apoiadores.',
+ scene: 'evento',
+ visibleText: 'JUNTOS PELA BAHIA',
+ hasPeople: true,
+ themes: ['politica-instituicoes'],
+ source: 'ai',
+ catalogedAt: '2026-09-26T12:00:00.000Z',
+ })
+ })
+
+ it('states metadata when only the text-derived fields landed', () => {
+ const { data, source } = buildArchivePhotoCatalogWrite(
+ writeInput({
+ municipalityId: 7,
+ mentionedPeople: ['Fulano de Tal'],
+ gazetteerThemes: ['saude'],
+ }),
+ )
+
+ expect(source).toBe('metadata')
+ expect(data.alt).toBeUndefined()
+ expect(data.catalog).toEqual({
+ themes: ['saude'],
+ people: ['Fulano de Tal'],
+ municipality: 7,
+ source: 'metadata',
+ catalogedAt: '2026-09-26T12:00:00.000Z',
+ })
+ })
+
+ it('states none when there was nothing to propose', () => {
+ const { data, source } = buildArchivePhotoCatalogWrite(writeInput())
+
+ expect(source).toBe('none')
+ expect(data.catalog).toEqual({
+ source: 'none',
+ catalogedAt: '2026-09-26T12:00:00.000Z',
+ })
+ })
+
+ it('never overwrites a curated field, and the source reflects only what landed', () => {
+ const { data, source } = buildArchivePhotoCatalogWrite(
+ writeInput({
+ suggestion: suggestion({ caption: 'IA', themes: ['saude'] }),
+ municipalityId: 9,
+ curatedFields: ['caption', 'themes', 'municipality'],
+ currentCatalog: { caption: 'Humano', themes: ['esporte'], municipality: 3 },
+ }),
+ )
+
+ expect(source).toBe('none')
+ expect(data.catalog).toEqual({
+ caption: 'Humano',
+ themes: ['esporte'],
+ municipality: 3,
+ source: 'none',
+ catalogedAt: '2026-09-26T12:00:00.000Z',
+ })
+ expect(data.alt).toBeUndefined()
+ })
+
+ it('keeps writing when the curation freezes only one field', () => {
+ const { data, source } = buildArchivePhotoCatalogWrite(
+ writeInput({
+ suggestion: suggestion({ caption: 'IA', description: 'Descrição da IA' }),
+ curatedFields: ['caption'],
+ currentCatalog: { caption: 'Humano' },
+ currentAlt: 'Alt humano',
+ }),
+ )
+
+ expect(source).toBe('ai')
+ expect(data.catalog.caption).toBe('Humano')
+ expect(data.catalog.description).toBe('Descrição da IA')
+ // The curated caption freezes the alt refinement too (never mirrors human text).
+ expect(data.alt).toBeUndefined()
+ })
+
+ it('keeps a curated alt and never mirrors the curated caption into it', () => {
+ const { data } = buildArchivePhotoCatalogWrite(
+ writeInput({
+ suggestion: suggestion({ caption: 'IA' }),
+ curatedFields: ['alt', 'caption'],
+ currentCatalog: { caption: 'Humano' },
+ currentAlt: 'Alt humano',
+ }),
+ )
+
+ expect(data.alt).toBe('Alt humano')
+ expect(data.catalog.caption).toBe('Humano')
+ })
+
+ it('writes a negative hasPeople as a real proposal, never a blank string', () => {
+ const negative = buildArchivePhotoCatalogWrite(
+ writeInput({ suggestion: suggestion({ hasPeople: false }) }),
+ )
+ expect(negative.source).toBe('ai')
+ expect(negative.data.catalog.hasPeople).toBe(false)
+
+ const blank = buildArchivePhotoCatalogWrite(
+ writeInput({ suggestion: suggestion({ caption: ' ' }) }),
+ )
+ expect(blank.source).toBe('none')
+ expect(blank.data.catalog.caption).toBeUndefined()
+ })
+
+ it('unions the model themes with the gazetteer without duplicating', () => {
+ const { data, source } = buildArchivePhotoCatalogWrite(
+ writeInput({
+ suggestion: suggestion({ themes: ['saude'] }),
+ gazetteerThemes: ['saude', 'educacao'],
+ }),
+ )
+
+ expect(source).toBe('ai')
+ expect(data.catalog.themes).toEqual(['saude', 'educacao'])
+ })
+})
+
+describe('archivePhotoSearchText (C232)', () => {
+ it('normalizes every facet into one haystack', () => {
+ const text = archivePhotoSearchText({
+ alt: 'Comício',
+ title: 'Plenária',
+ description: 'Evento',
+ catalogDescription: 'Descrição IA',
+ caption: 'Legenda',
+ scene: 'plenaria',
+ visibleText: 'SAÚDE',
+ themes: ['saude'],
+ people: ['Fulano de Tal'],
+ municipalityName: 'Feira de Santana',
+ albumTitles: ['Vitória da Conquista'],
+ tagNames: ['Solla'],
+ })
+
+ expect(text).toContain('comicio')
+ expect(text).toContain('plenaria')
+ expect(text).toContain('saude')
+ expect(text).toContain('fulano de tal')
+ expect(text).toContain('feira de santana')
+ expect(text).toContain('vitoria da conquista')
+ expect(text).toContain('solla')
+ })
+
+ it('is empty for an empty input', () => {
+ expect(archivePhotoSearchText({})).toBe('')
+ })
+})
diff --git a/tests/unit/archiveVisionApi.unit.spec.ts b/tests/unit/archiveVisionApi.unit.spec.ts
new file mode 100644
index 00000000..129b782b
--- /dev/null
+++ b/tests/unit/archiveVisionApi.unit.spec.ts
@@ -0,0 +1,149 @@
+// @vitest-environment node
+
+import { describe, expect, it, vi } from 'vitest'
+
+import {
+ ArchiveVisionError,
+ analyzeArchivePhotoVision,
+} from '../../scripts/lib/archiveVisionApi.mjs'
+
+// C232 — the vision client contract: request shape, auth header, transient
+// retry, terminal 4xx, timeout/abort and the named refusals. `fetch` is always
+// a fake — the real engine never enters the suite.
+
+const jsonResponse = (body: unknown, status = 200) =>
+ ({
+ ok: status >= 200 && status < 300,
+ status,
+ json: async () => body,
+ text: async () => JSON.stringify(body),
+ }) as Response
+
+const fakeFetch = (impl: (url: string, init?: RequestInit) => Promise) =>
+ vi.fn(impl) as unknown as typeof fetch
+
+const call = (fetchImpl: typeof fetch, overrides: Record = {}) =>
+ analyzeArchivePhotoVision({
+ baseUrl: 'http://100.94.122.26:11434/v1',
+ model: 'qwen2.5vl:7b',
+ imageDataUrl: 'data:image/jpeg;base64,AAAA',
+ prompt: 'descreva a foto',
+ systemPrompt: 'responda em JSON',
+ fetchImpl,
+ retryAttempts: 1,
+ sleep: async () => undefined,
+ ...overrides,
+ })
+
+describe('analyzeArchivePhotoVision (C232)', () => {
+ it('refuses to call without the engine config or a prepared image', async () => {
+ await expect(
+ call(
+ fakeFetch(async () => jsonResponse({})),
+ { baseUrl: ' ' },
+ ),
+ ).rejects.toThrow(/ARCHIVE_VISION_BASE_URL/)
+ await expect(
+ call(
+ fakeFetch(async () => jsonResponse({})),
+ { model: '' },
+ ),
+ ).rejects.toThrow(/ARCHIVE_VISION_MODEL/)
+ await expect(
+ call(
+ fakeFetch(async () => jsonResponse({})),
+ { imageDataUrl: 'http://x/foto.jpg' },
+ ),
+ ).rejects.toThrow(/data: URL/)
+ })
+
+ it('posts the OpenAI-compatible shape with the image and the key header', async () => {
+ const fetchImpl = fakeFetch(async () =>
+ jsonResponse({ choices: [{ message: { content: '{"caption":"ok"}' } }] }),
+ )
+
+ const content = await call(fetchImpl, { apiKey: 'segredo' })
+
+ expect(content).toBe('{"caption":"ok"}')
+ const [url, init] = (fetchImpl as unknown as { mock: { calls: [string, RequestInit][] } }).mock
+ .calls[0]
+ expect(url).toBe('http://100.94.122.26:11434/v1/chat/completions')
+ expect(init.method).toBe('POST')
+ const headers = init.headers as Record
+ expect(headers.Authorization).toBe('Bearer segredo')
+ const body = JSON.parse(String(init.body))
+ expect(body.model).toBe('qwen2.5vl:7b')
+ expect(body.stream).toBe(false)
+ expect(body.messages[0]).toMatchObject({ role: 'system', content: 'responda em JSON' })
+ expect(body.messages[1].content[0]).toMatchObject({ type: 'text', text: 'descreva a foto' })
+ expect(body.messages[1].content[1]).toMatchObject({
+ type: 'image_url',
+ image_url: { url: 'data:image/jpeg;base64,AAAA' },
+ })
+ })
+
+ it('retries a transient 5xx with backoff and succeeds', async () => {
+ const sleeps: number[] = []
+ let attempts = 0
+ const fetchImpl = fakeFetch(async () => {
+ attempts += 1
+ if (attempts === 1) return jsonResponse({ error: 'sobrecarregado' }, 503)
+ return jsonResponse({ choices: [{ message: { content: 'ok' } }] })
+ })
+
+ const content = await call(fetchImpl, {
+ retryAttempts: 3,
+ retryBaseDelayMs: 100,
+ sleep: async (ms: number) => {
+ sleeps.push(ms)
+ },
+ })
+
+ expect(content).toBe('ok')
+ expect(attempts).toBe(2)
+ expect(sleeps).toEqual([100])
+ })
+
+ it('does not retry a terminal 4xx refusal and keeps the provider detail', async () => {
+ const fetchImpl = fakeFetch(async () => jsonResponse({ error: 'modelo desconhecido' }, 404))
+
+ await expect(call(fetchImpl, { retryAttempts: 3 })).rejects.toMatchObject({
+ name: 'ArchiveVisionError',
+ status: 404,
+ message: expect.stringContaining('modelo desconhecido'),
+ })
+ expect((fetchImpl as unknown as { mock: { calls: unknown[] } }).mock.calls).toHaveLength(1)
+ })
+
+ it('retries a network failure as transient', async () => {
+ let attempts = 0
+ const fetchImpl = fakeFetch(async () => {
+ attempts += 1
+ if (attempts === 1) throw new TypeError('fetch failed')
+ return jsonResponse({ choices: [{ message: { content: 'ok' } }] })
+ })
+
+ await expect(call(fetchImpl, { retryAttempts: 2 })).resolves.toBe('ok')
+ expect(attempts).toBe(2)
+ })
+
+ it('names an off-contract answer instead of guessing', async () => {
+ await expect(call(fakeFetch(async () => jsonResponse({ choices: [] })))).rejects.toBeInstanceOf(
+ ArchiveVisionError,
+ )
+ await expect(
+ call(
+ fakeFetch(
+ async () =>
+ ({
+ ok: true,
+ status: 200,
+ json: async () => {
+ throw new Error('html')
+ },
+ }) as unknown as Response,
+ ),
+ ),
+ ).rejects.toThrow(/não é JSON/)
+ })
+})
diff --git a/tests/unit/visionEndpoint.unit.spec.ts b/tests/unit/visionEndpoint.unit.spec.ts
new file mode 100644
index 00000000..dfa1ed77
--- /dev/null
+++ b/tests/unit/visionEndpoint.unit.spec.ts
@@ -0,0 +1,55 @@
+import { describe, expect, it } from 'vitest'
+
+import { isPrivateVisionHost } from '../../scripts/lib/cli.mjs'
+
+// C232 — the vision-endpoint locality predicate behind the PII guardrail: only
+// the private network (loopback, RFC1918, CGNAT/tailnet, link-local/ULA, local
+// names) passes without the explicit remote escape.
+
+describe('isPrivateVisionHost (C232)', () => {
+ it('accepts loopback, private ranges and the tailnet CGNAT block', () => {
+ for (const host of [
+ 'localhost',
+ '127.0.0.1',
+ '10.0.0.7',
+ '172.16.0.1',
+ '172.31.255.254',
+ '192.168.15.142',
+ '100.94.122.26',
+ '100.64.0.1',
+ '::1',
+ '[::1]',
+ 'fe80::1',
+ 'fd00::1',
+ 'gpu-box',
+ 'ollama',
+ 'host.docker.internal',
+ 'workstation.local',
+ 'engine.internal',
+ ]) {
+ expect(isPrivateVisionHost(host), host).toBe(true)
+ }
+ })
+
+ it('rejects public hosts and out-of-range addresses', () => {
+ for (const host of [
+ '8.8.8.8',
+ '1.1.1.1',
+ '172.32.0.1',
+ '172.15.0.1',
+ '100.63.0.1',
+ '100.128.0.1',
+ '203.0.113.10',
+ 'api.openai.com',
+ 'example.com',
+ '256.1.1.1',
+ // Names that merely START with the IPv6 ULA/link-local prefixes.
+ 'fdic.gov',
+ 'fcc.gov',
+ 'fd-openai.com',
+ '',
+ ]) {
+ expect(isPrivateVisionHost(host), host).toBe(false)
+ }
+ })
+})