diff --git a/docs/changelog/2026-09-24-c219.md b/docs/changelog/2026-09-24-c219.md
new file mode 100644
index 00000000..51693a0e
--- /dev/null
+++ b/docs/changelog/2026-09-24-c219.md
@@ -0,0 +1 @@
+**C219 — Paridade de busca e filtros entre as fontes do acervo (2026-09-24):** "Gravações enviadas" passa a ter os mesmos gestos de garimpo das "Falas da Câmara" — busca `termo|tema`, filtros de Ano, Tema, Alcance, Município citado e Duração (Pessoa segue exclusiva), chips ativos, contagem, ordenação e vazio honesto — com classificação automática e proveniência auditável sobre a transcrição já existente. Schema: `recording` ganha `year` derivado de `recordedAt` (hook espelho do `Speech`, que agora **limpa** o ano quando a data é limpa), `topics`/`scopes` (mesma taxonomia `lib/speechFacets`), `classifiedBy` (`gazetteer|llm|manual`, **nullable** — nulo = "não classificada", nunca proveniência inventada) e `mentionedMunicipalities` (relationship), com `preserveManualFacets` protegendo curadoria humana de escritas sem `req.user` (job/CLI); migration aditiva `20260924_040210_add_recording_facets` com backfill SQL determinístico do ano. Classificação: `classifyRecordingFacets` (novo, `server-only`) reusa o dono `classifySpeech` (gazetteer offline + refinamento LLM validado na DeepInfra, nunca lança) e resolve os slugs do gazetteer no catálogo de municípios; o seam é o fim do `runRecordingJob` (injetável, fora da transação de save — o LLM não entra no lock) e o acervo existente é coberto pelo CLI idempotente `pnpm recordings:classify` (`--dry-run`, `--limit`, `--all`, guard de DB local + `RECORDING_CLASSIFY_CONFIRM=1` para alvo remoto), com o shape de escrita em dono único (`recordingFacetWriteData`). URL/filtros: `recordingListUrl` ganha `mode|year|topic|scope|municipality|duration|sort` na ordem canônica da Câmara, com `sort=recentes`/`mode=termo` nunca serializados e os deep-links `?source=enviadas&q&person&page` byte-idênticos; `buildRecordingListWhere` ANDa as facetas (duração reusa `durationBucketWhere` exportado do dono da Câmara) e, nos sorts de duração, exige `durationSeconds` existir (senão o NULLS FIRST do Postgres abriria a lista com as gravações sem duração); o loader ganha opções de ano/municípios, injeção da expansão de tema e a degradação honesta (`themeUnavailable`/`themeApplied`); `expandSpeechSearchTheme` ganha o corpus `'recording'` (3º consumidor do mesmo mecanismo, prompt próprio) e o adaptador puro `recordingOmnibox` monta chips/seeds/toggles sobre `lib/campaignListOmnibox`. UI (Impeccable B, porte do design aprovado `docs/plans/acervo-paridade-busca-filtros-ui-design.html`): `RecordingAcervoFilters` novo sobre os shells compartilhados (omnibox com chips dentro do campo, seletor `Termo exato|Por tema`, seis facetas em popovers-chip, absorvendo o antigo `RecordingPersonFilter`), `RecordingSortSelect` ("Mais recentes" default · "Duração (maior)" · "Duração (menor)" com o hint das gravações sem duração), `RecordingThemeFallbackNotice` + `CampaignThemeRetryButton` (movido para `shared/`), chip de tema no card e o vazio honesto do modo tema com "Limpar filtros" + "Trocar para termo exato"; no /simplify o seletor de modo e o rótulo de chip viraram donos compartilhados (`CampaignSearchModeControl`, `selectedFilterTriggerLabel`). Access/Consent intocados (gate `communicationCatalog` fail-closed, sem PII nova, sem rota/collection nova). Verificação: unit (URL canônica/deep-link/ordenação, `where` das facetas+tema+gate de duração, omnibox, corpus novo), int (job grava facetas e degrada sem chave, curadoria `manual` preservada inclusive no escape autenticado, ano derivado/limpo, loader filtra/ordena/degrada o tema), e2e do `campaignSpeechAcervo` estendido (barra de facetas, estreitamento + vazio, ordenação por duração, tema degradando) e `campaignSpeechAcervo` no conjunto curado high-risk do PR (a migration torna a entrega high-risk), `pnpm gate:fast`, `pnpm test:int`, `pnpm build` e os e2e locais. Crítica final do `designer` (trigger c) **certificada em tier primário** (`Design tier: openai/gpt-5.6-sol`); o débito do "X" de limpar do omnibox que quebra linha no mobile com chip longo (pré-existente do shell compartilhado, reproduzido na Câmara) ficou fora e virou a Issue C221, com os demais adiamentos anotados com gatilho no `*-impl.md`.
diff --git a/docs/plans/acervo-paridade-busca-filtros-impl.md b/docs/plans/acervo-paridade-busca-filtros-impl.md
new file mode 100644
index 00000000..ce82d611
--- /dev/null
+++ b/docs/plans/acervo-paridade-busca-filtros-impl.md
@@ -0,0 +1,209 @@
+# Impl: C219 — Paridade de busca e filtros entre as fontes do acervo
+
+Status: aprovado
+Atualizado em: 2026-09-24
+Issue: #1295
+Intenção: docs/plans/acervo-paridade-busca-filtros.md
+Appetite restante: herdado (~2–3 dias eng)
+
+## Leitura da intenção
+
+- **Outcome:** "Gravações enviadas" passa a oferecer os mesmos gestos de garimpo da Câmara — busca `termo|tema`, filtros por Ano, Tema, Alcance, Município citado, Duração (e Pessoa, que segue exclusiva), chips ativos, contagem, ordenação e vazio honesto — com classificação automática e proveniência auditável sobre a transcrição já existente, sem tocar no player/download nem no contrato da Câmara.
+- **O que NÃO negociar:**
+ - "Pessoa" continua **exclusiva** das gravações (rótulo derivado, nunca segundo cadastro de pessoa — C200).
+ - Gate do acervo **fail-closed** (`requireCampaignPageActor({gate:'communicationCatalog'})` + `canReadRecording`/`canReadCommunicationCatalog`); `advisor`/`leader` negados.
+ - Deep-link atual **byte-compatível**: `?source=enviadas&q&person&page` continua canonicalizando para exatamente o mesmo href; `mode=termo` e o sort default nunca serializados.
+ - **Sem lista única** entre fontes; **sem redesenho da barra da Câmara** (ela é a referência).
+ - Classificação **automática e revisável, nunca inventa** — falha degrada para o que existir e é sinalizada; proveniência é rótulo auditável (`gazetteer|llm|manual`), nunca score.
+ - Buckets de duração idênticos à Câmara ("Até 2 min" · "2 a 5 min" · "Mais de 5 min" · "Sem duração"); **Ano derivado de `recordedAt`**, nunca um segundo campo digitado.
+- **O que reavaliar (hipóteses da intenção):**
+ - "Direção no codebase" aponta `speechClassifier` e `expandSpeechSearchTheme` corretamente, mas o seam real do job é `runRecordingJob` (roda via `after()`, sem request) — a classificação entra ali, **fora** da transação de save, e o backfill das linhas existentes é CLI.
+ - `classifySpeech` é reusável como está, mas pede `transcript` **cru** (o `searchText` da gravação é normalizado; o input tem de ser a concatenação dos `text` dos segmentos).
+ - `expandSpeechSearchTheme` já tem o parâmetro `corpus` desde S28 — a extensão é **um prompt novo**, não mecanismo novo.
+ - Gravações **não têm `keywords`**: a perna textual delas é só `searchText` (a Câmara tem `searchText` OR `keywords`).
+ - `Recording` **não tem** os campos de faceta/proveniência de `Speech`: schema novo + migration são inevitáveis (a intenção já previa "facets + proveniência").
+
+## Abordagem recomendada
+
+```mermaid
+flowchart LR
+ UP[upload / retry] --> JOB[runRecordingJob]
+ JOB --> ASR[extrair + transcrever + diarizar]
+ ASR --> CLS{classifyRecordingFacets classify injetável}
+ CLS -- "sem DEEPINFRA_API_KEY / erro" --> GZ[gazetteer: topics/scopes/municípios]
+ CLS -- ok --> LLM[gazetteer ∪ LLM validado]
+ GZ --> TX[(transação: segments + recording)]
+ LLM --> TX
+ TX --> RDY[ready + facets + classifiedBy]
+
+ CLI["scripts/backfill-recording-facets.mjs pnpm recordings:classify"] -. mesma função .-> CLS
+
+ Q["assessoria: ?source=enviadas&q&mode&year&topic&scope&municipality&duration&sort&person&page"] --> URL[recordingListUrl parse + canônico]
+ URL --> MODE{mode=tema?}
+ MODE -- não --> WHERE[buildRecordingListWhere facetas AND + texto OR + pessoa]
+ MODE -- sim --> EXP[expandRecordingSearchTheme corpus 'recording']
+ EXP -- null --> DEG[literal + aviso discreto]
+ EXP -- termos --> WHERE
+ DEG --> WHERE
+ WHERE --> FIND["payload.find user · overrideAccess:false"]
+ FIND --> VM[recordingViewModels excerto + destaque + chips]
+ VM --> UI[RecordingAcervoFilters + lista + contagem + ordenação]
+```
+
+**Opções consideradas | Recomendação | Rejeitadas (decisões caras):**
+
+| # | Decisão | Opções | Recomendação | Rejeitadas |
+| --- | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| i | Onde a classificação roda | A) seam no `runRecordingJob` (injetável) + CLI backfill · B) hook `afterChange` da collection · C) on-demand no loader da busca · D) hook por `recordingSegment` | **A** — o job já tem os segmentos em memória no fim da transcrição; o seam injetável é precedente (`catalogContentPiece`); o CLI cobre as linhas já existentes | B (sem transcrição no momento do hook, roda em caminho quente e re-executa por `step`); C (LLM por request, leitura viraria escrita, faceta inexistente não filtra); D (N chamadas por gravação, unidade errada) |
+| ii | Schema em `Recording` | A) espelhar `Speech` (`year` derivado + `topics`/`scopes`/`classifiedBy`/`mentionedMunicipalities` + `preserveManualFacets`) com migration `add_recording_facets` · B) facetas por segmento · C) sem schema (derivar na busca) · D) ano sem coluna (range sobre `recordedAt`) | **A** — mesma forma de `where`/opções/canônico da Câmara e curadoria manual preservada; a migration é aditiva | B (unidade errada — corte explícito da intenção); C (não filtra/pagina, recalcula a cada busca e morre o "revisável"); D (dois shapes de filtro para o mesmo conceito; a coluna derivada é o que a Câmara tem e o que a intenção chama de "derivado") |
+| iii | Contrato de duração + omnibox | A) reusar donos da Câmara (buckets/labels/tipo de `speechListUrl`, `durationBucketWhere` exportado de `speechListFilters`, parsers de ano/município movidos para `campaignListUrl`) + adaptador novo `recordingOmnibox` · B) extrair módulo compartilhado novo do acervo e migrar a Câmara · C) duplicar no domínio de gravações | **A** — a paridade manda que o bucket tenha UM dono; o adaptador por domínio já é padrão (`municipalityOmnibox`, `municipalityUpdateOmnibox`) | B (churn na Câmara sem volatilidade; extrair quando C216 chegar — 3º consumidor); C (twin: mudança de bucket divergiria as duas fontes) |
+| iv | Busca por tema | A) `ThemeSearchCorpus` ganha `'recording'` + prompt próprio + `expandRecordingSearchTheme` · B) reusar o corpus `'speech'` · C) só busca literal | **A** — o mecanismo é um só (S28); o prompt de discursos da Câmara não descreve plenárias enviadas/debates | B (prompt errado degrada a expansão); C (rejeitada no gate: a ponte foi confirmada) |
+| v | UI | A) `RecordingAcervoFilters` novo sobre os shells compartilhados (absorve o `RecordingPersonFilter`) · B) generalizar `SpeechAcervoFilters` configurável · C) estender `SpeechAcervoFilters` com `source` | **A** — shells compartilhados são os donos das mecânicas; a Câmara não é tocada | B (API genérica rasa e mexe na Câmara — anti-goal); C (acopla os dois contratos num componente) |
+| vi | Ordenação | A) param `sort` com valores pt-BR (`recentes` default omitido, `duracao_maior`, `duracao_menor`); sort de duração só sobre linhas com duração medida · B) par genérico `sort`/`dir` (C117) · C) sort só de UI | **A** — contrato fechado e legível no deep link; default preserva `-createdAt` (zero regressão) | B (o acervo não é tabela; a Câmara não tem esse contrato); C (quebra "paginação preservada no deep link" e back/forward) |
+
+**Recomendação (geral):** uma única passada de classificação no job (com o mesmo `classifySpeech`, injetável e com degradação para gazetteer), um CLI idempotente para o acervo já enviado, e a paridade de filtros construída sobre o contrato de URL, o `where`, o adaptador de omnibox e os shells que a Câmara já usa — mudando **só** a fonte de gravações.
+
+**Rejeitadas (geral):** busca global/lista única (anti-goal); pgvector/embeddings (C192 já rejeitou); facetas por trecho/falante (corte da intenção); qualquer alteração na barra/contrato da Câmara.
+
+### Componentes / mudanças
+
+- **`Recording`** (`src/collections/Recording.ts`): novos campos `year` (number, index, readOnly, derivado), `topics` (select hasMany, index, opções `SPEECH_TOPICS`), `scopes` (select hasMany, index, opções `SPEECH_SCOPES`), `classifiedBy` (select, index, **opcional, sem default**, valores `SPEECH_CLASSIFICATION_SOURCES`), `mentionedMunicipalities` (relationship hasMany → `municipality`, index). Hooks: `deriveRecordingYear` (beforeValidate, espelho de `deriveSpeechYear` — `recordedAt` string `slice(0,4)`, com fallback `originalDoc`) e `preserveManualFacets` (beforeChange, espelho de `Speech.ts:43-57`, `FACET_FIELDS = topics|scopes|classifiedBy|mentionedMunicipalities`; escrita sem `req.user` — job/CLI — nunca sobrescreve `manual`). `admin.defaultColumns` ganha `topics` e `classifiedBy` (superfície de revisão da classificação no admin). `admin.description` registra que a classificação é automática sobre o início da transcrição.
+- **Migration** (`pnpm migrate:create add_recording_facets` → `src/migrations/20260924_120000_add_recording_facets.ts` + `.json` + `index.ts`): tabelas de join `recording_topics`/`recording_scopes` (enums `enum_recording_topics`/`enum_recording_scopes`/`enum_recording_classified_by`), tabela `recording_rels` (`mentionedMunicipalities`), colunas `year`/`classified_by`. **Hand-edit** (precedente `20260913_150000_backfill_speech_search_text_trgm_index`): backfill determinístico de `year` a partir de `recorded_at` (`WHERE recorded_at IS NOT NULL`). Nada destrutivo; `recording_search_text_trgm_idx` já existe (não mexer).
+- **`src/payload-types.ts`**: regenerado (`pnpm generate:types`) — `Recording` ganha os campos.
+- **`classifyRecordingFacets`** (`src/utilities/recordings/recordingClassification.ts`, novo, `import 'server-only'`): `({ payload, transcript, classify = classifySpeech })` → `{ topics, scopes, classifiedBy, mentionedMunicipalities } | null`. Reusa `SpeechFacetInput`/`SpeechClassificationResult`, `classifySpeech` (DeepInfra + validação `lib/speechFacets`) e resolve `municipalities[].slug → municipality.id` numa query (bypass justificado — geografia read-only — precedente `speechImport.ts:176-196`). Nunca lança: transcrição vazia ou throw defensivo devolvem `null` e o job segue sem facets.
+- **`runRecordingJob`** (`src/utilities/recordings/recordingJob.ts`): ganha `classify` injetável (default `classifySpeech`), chamado **depois** de diarizar e **antes** de `markStep('saving')` (o LLM não entra na transação); transcript = `keyedSegments.map(s => s.text).join(' ')`. O update transacional final (`status:'ready'`, `searchText`, `speakerLabels`) passa a incluir `year` (quando houver `recordedAt`), `topics`, `scopes`, `classifiedBy`, `mentionedMunicipalities`.
+- **`scripts/backfill-recording-facets.mjs`** (novo) + `package.json` `"recordings:classify"`: reusa `classifyRecordingFacets`; default = linhas `ready` com `classifiedBy` ausente (`--all` reclassifica não-`manual`), `--dry-run`, `--limit N`; `assertLocalDatabase` + `RECORDING_CLASSIFY_CONFIRM=1` para alvo remoto/produção (precedente `CAMARA_IMPORT_CONFIRM`); relatório (classificadas/puladas-manual/falhas/tokens/custo) e idempotência por `classifiedBy`.
+- **URL** (`src/utilities/recordings/recordingListUrl.ts`): `RecordingListState` ganha `mode?` (reusa `SpeechSearchMode`), `years?`, `topics?`, `scopes?`, `municipalities?`, `durations?` (reusa `SpeechDurationBucket`) e `sort?`; `recordingListParamNames` ganha `mode|year|topic|scope|municipality|duration|sort`. Ordem canônica: `source, q, mode, year[], topic[], scope[], municipality[], duration[], sort, person[], page` — os parâmetros novos não perturbam o href dos deep links atuais. Serialização: `mode=tema` só com `q`; `sort` só quando ≠ `recentes`; `page` só > 1. Novos: `RECORDING_SORT_OPTIONS`/`recordingSortLabels` ("Mais recentes" · "Duração (maior)" · "Duração (menor)"), `recordingSortKeys(state)` (`-createdAt` default / `-durationSeconds` / `durationSeconds`) e `buildRecordingFiltersKey(state)` (espelho de `buildSpeechFiltersKey`, usado como `key` do remount da barra).
+- **`campaignListUrl.ts`**: recebe `parseYearValues`/`parseMunicipalityValues` (movidos de `speechListUrl.ts`, que passa a importá-los) — um dono para a validação estrutural de ano/município nas duas fontes.
+- **`speechListFilters.ts`**: exporta `durationBucketWhere` (sem mudança de comportamento) para o `where` das gravações.
+- **Filtros** (`src/utilities/recordings/recordingListFilters.ts`): `buildRecordingListWhere(state, themeTerms = [])` — facetas AND (`year in`, `topics in`, `scopes in`, `mentionedMunicipalities in`, OR de `durationBucketWhere`, OR de `speakerNames contains`), perna textual OR de `{ searchText: { like: normalizeForSearch(term) } }` para `[q, ...themeTerms]` (sem `keywords`), e `{ durationSeconds: { exists: true } }` quando `sort` é de duração (o Postgres ordena NULLS FIRST em DESC; sem isso "Duração (maior)" abriria com as linhas sem duração).
+- **Loader** (`src/utilities/recordings/recordingPageData.ts`): `RecordingFilterOptions` ganha `years` e `municipalities` (via `loadMunicipalityLabelsByIds`, precedente `loadSpeechFilterOptions`); `loadRecordingsPageData(payload, user, params, expandTheme = expandRecordingSearchTheme)` com o gate de tema (`mode=tema && q && canReadCommunicationCatalog(role)` antes de qualquer chamada externa) e retorno `themeUnavailable`/`themeApplied`; `sort` aplicado; `loadMatchedSegments` passa a receber os termos (`[q, ...themeTerms]`) e casa `or` de `searchText like`; `select` da lista ganha `topics` (chip do card).
+- **View models** (`src/utilities/recordings/recordingViewModels.ts`): `toRecordingListItemViewModel` ganha `themeTerms`; o excerto prefere a evidência de tema (espelho C192: primeiro termo que casa em `searchText`, segmento via `pickMatchingSegment`, `buildHighlightedExcerpt(..., { phrase: true })`) e cai no literal quando não há; `watchHref` mantém `?t=&q=` com o **`q` literal** (byte-compat; espelho de `buildWatchHref`); `RecordingListItemViewModel` ganha `topics: { value, label }[]` (labels de `speechTopicLabels`).
+- **Omnibox** (`src/utilities/recordings/recordingOmnibox.ts`, novo, puro/client-safe): chips (`q`, `year`, `topic`, `scope`, `municipality`, `duration`, `person`), seeds (Tema/Alcance/Duração visíveis com query vazia; Ano/Município citado/Pessoa pesquisáveis por palavra-chave), `applyRecordingOmniboxSuggestion`/`removeRecordingOmniboxChip`/`applyRecordingSearchMode`/`clearRecordingOmnibox` (preservando `source: 'enviadas'` no clear) sobre `lib/campaignListOmnibox.ts`; `person` reusa `toggleRecordingPerson`/`removeRecordingPerson` (dedupe case-insensitive já dono) e o prefixo `person:` lê o valor por `slice` (o rótulo pode conter `:`).
+- **Tema** (`src/utilities/ai/expandSpeechSearchTheme.ts`): `ThemeSearchCorpus` ganha `'recording'`; novo prompt de corpus (plenárias/debates/material próprio enviados pela equipe), `themeExpansionRules('gravação')`; wrapper `expandRecordingSearchTheme` (mesmo timeout/degradação/`normalizeSpeechThemeTerms`).
+- **UI (Impeccable B — port de `docs/plans/acervo-paridade-busca-filtros-ui-design.html`):**
+ - `src/components/campaign/recording/RecordingAcervoFilters.tsx` (novo, client) — **cenas 01/02**: form `campaignListOmniboxFormClassName` com label "Buscar nas gravações enviadas", `CampaignListOmnibox` (chips dentro do campo, como na Câmara — B184/B127), seletor segmentado `role="group"` `grid grid-cols-2 rounded-lg bg-muted p-1` + `aria-pressed` + `min-h-11 md:min-h-9` (com o estado degradado `themeUnavailable`), e as seis facetas como `CampaignHeaderFilterPopover triggerVariant="chip"` (`Ano`, `Tema`, `Alcance`, `Município citado`, `Duração`, `Pessoa`) com `selectedTriggerLabel` dobrando a seleção. A linha "Ativos:" do artefato é realizada pelos chips do próprio omnibox (shell compartilhado), sem segunda fileira.
+ - `src/components/campaign/recording/RecordingSortSelect.tsx` (novo, client) — **cena 01**: label "Ordenar por" + `select` nativo (`rounded-md border border-input`) via `useCampaignListFilterNavigation`; em sort de duração, hint "Gravações sem duração aparecem apenas em Mais recentes." A contagem fica no `CampaignListFooter` (padrão de todas as listas — sem duplicar a linha).
+ - `src/components/campaign/recording/RecordingThemeFallbackNotice.tsx` (novo) — **cena 04/C192**: `Alert variant="pending"` com a copy de gravações + `CampaignThemeRetryButton`; move `SpeechThemeRetryButton` → `src/components/campaign/shared/CampaignThemeRetryButton.tsx` (componente genérico, zero copy própria) e atualiza o import da página da Câmara.
+ - `src/components/campaign/recording/RecordingResultCard.tsx` — **cena 01 (card)**: chip de tema (`bg-muted`) ao lado do chip de pessoa; destaque do termo continua via `SpeechHighlightParts`.
+ - `src/app/(campaign)/campanha/(app)/comunicacao/acervo/page.tsx` — branch `enviadas`: `key={buildRecordingFiltersKey(data.state)}`, barra nova, aviso de tema, `RecordingSortSelect`, `RecordingStatusRefresher` (intocado), lista/vazio/footer; vazio honesto da **cena 03** (título "Nenhuma gravação encontrada para este tema", descrição do artefato, "Limpar filtros" + "Trocar para termo exato") e `hasFilters` por `buildRecordingFiltersKey`. O `RecordingsSearchForm` inline e o `RecordingPersonFilter` somem (absorvidos).
+ - **Cena 04 (sem permissão)** permanece o redirect fail-closed do gate — a cena é ilustrativa, não vira superfície nova. **Cena 05 (carregando)** é o `CampaignListPendingBoundary`/`CampaignListResults` existente (dima o resultado, não o controle).
+ - Remover `src/components/campaign/recording/RecordingPersonFilter.tsx`.
+- **Manifest e2e** (`scripts/lib/e2e-affected-manifest.mjs`): `src/collections/Recording.ts` entra no entry da vertical C154/C199 (`campaignSpeechAcervo`) — hoje um diff só nesse arquivo cairia no smoke da home; e `campaignSpeechAcervo` entra em `E2E_CURATED_SPECS` (precedente C167/S19: a migration torna todo PR da entrega high-risk), com o pin de congelamento atualizado em `tests/unit/e2eAffectedManifest.unit.spec.ts`.
+- **Access / Consent:** **nada muda**. Sem chave `Consent` nova (acervo interno; sem PII nova), sem collection nova, sem rota nova. O classificador fala com a DeepInfra (mesmo provedor/chave que já transcreve a gravação) e o tema com a DeepSeek (só o texto digitado, como na Câmara).
+
+### Dados → forma (se aplicável)
+
+N/A justificado. O item não apresenta métrica, agregado nem score: resultados e facetas são recorte editorial. A proveniência é rótulo auditável (`Gazetteer`/`LLM`/`Manual`) no admin — nunca número na UI; "contagem de resultados" é paginação, não métrica de vaidade.
+
+## Fases verificáveis
+
+1. **Tracer / schema + server** (~1 dia) — `Recording` com os campos/hooks + migration `add_recording_facets` (com backfill de `year`) + `pnpm generate:types` + `recordingClassification` + seam `classify` no `runRecordingJob` + `scripts/backfill-recording-facets.mjs`.
+ - Prova: `tests/int/recording.int.spec.ts` — job end-to-end grava `topics`/`scopes`/`classifiedBy`/`mentionedMunicipalities`/`year` (classificador injetado determinístico + caminho gazetteer sem `DEEPINFRA_API_KEY`); curadoria `manual` não é sobrescrita por escrita sem `user`; retry reclassifica; `pnpm migrate` local verde.
+2. **URL / filtros / loader** (~0,5 dia) — params e estado novos, `buildRecordingFiltersKey`, `recordingSortKeys`, `where` com facetas + tema + gate de sort, loader com opções (`years`/`municipalities`) e injeção do tema, corpus `'recording'`.
+ - Prova: `tests/unit/recordingListUrl.unit.spec.ts` (deep-link byte-compat, canônico, enums exaustivos, `sort` default omitido), `tests/unit/recordingListFilters.unit.spec.ts` (facetas AND, tema OR, duração, `exists` do sort), `tests/unit/recordingOmnibox.unit.spec.ts` (novo), `tests/unit/expandSpeechSearchTheme.unit.spec.ts` (corpus novo), `tests/int/recording.int.spec.ts` (loader filtra/ordena/tema e opções).
+3. **UI port** (~0,5–1 dia) — `RecordingAcervoFilters`, `RecordingSortSelect`, `RecordingThemeFallbackNotice`, `CampaignThemeRetryButton` movido, chip de tema no card, página; remoção do `RecordingPersonFilter`.
+ - Prova: `tests/e2e/campaignSpeechAcervo.e2e.spec.ts` (describe de gravações estendido: barra com chips, filtro que estreita + vazio honesto, modo tema degradando, sort, contagem; o teste de "Pessoa" passa a exercitar a barra nova); `pnpm dev` manual com a cena 01 do artefato.
+4. **Testes/gates** (~0,5 dia) — `pnpm gate:fast`; depois a cascata cheia (`pnpm lint`, `pnpm format:check`, `tsc --noEmit`, `pnpm exec knip`, `pnpm check:cycles`, `pnpm test`, `pnpm build`); `pnpm push`; entrada em `docs/changelog/-c219.md`; PR ready com auto-merge (o check `checks` é o gate; o e2e curado roda `campaignSpeechAcervo`).
+
+## Rabbit holes / Não escopo (engenharia)
+
+- **Generalizar a barra da Câmara** (`SpeechAcervoFilters` configurável / componente `AcervoFilters` genérico) — anti-goal; shells compartilhados já são os donos.
+- **Extrair o adaptador de omnibox/helpers de estado para um genérico** — 2 call sites; extrair quando C216 ("Falas na internet") chegar (3º).
+- **Módulo compartilhado novo do contrato do acervo** (mover buckets/parsers para um terceiro) — churn na Câmara sem volatilidade; deferido para C216.
+- **pgvector/embeddings/índice vetorial** — já rejeitado no C192.
+- **Classificar por segmento/falante** ou reclassificar a taxonomia (18 temas fixos) — cortes de produto.
+- **Segundo cadastro de pessoa / inferir falantes** — "Pessoa" segue rótulo (C200).
+- **Mudar o default de ordenação para `-recordedAt`** — regressão do comportamento atual (`-createdAt`); fora do aceite.
+- **Busca global entre fontes / lista única** — anti-goal.
+- **UI de curadoria de facetas além do form do admin** — o form da collection é a superfície de revisão; qualquer coisa além disso é outro item.
+- **Cache/rerank da expansão de tema** — deferido no C192 (sem cache no v1).
+
+**Adiado com gatilho (triage do /simplify desta entrega):**
+
+- **Extração dos helpers de faceta/estado restantes** (`facetRows`/`clearFacet`/`runAction` e o aviso de fallback por domínio) — gatilho: C216 (3º consumidor do acervo), junto do adaptador de omnibox (S2/S3).
+- **N+1 do backfill** (`scripts/backfill-recording-facets.mjs` consulta os segmentos de cada gravação em queries separadas) — gatilho: acervo na casa das centenas de gravações ou `--all` perceptivelmente lento (S4).
+- **Ternários aninhados do ramo de gravações** em `acervo/page.tsx` — gatilho: extração do 3º consumidor na C216, quando o ramo for compartilhado (S5).
+- **"X" de limpar do omnibox quebra linha no mobile com chip longo** — débito do shell compartilhado, pré-existente e reproduzido na Câmara; registrado como Issue própria (C221, `docs/plans/omnibox-limpar-mobile.md`) — fora deste item (S1).
+
+## Riscos e mitigação
+
+- **Deep-link/redirect:** os nomes novos entram em `recordingListParamNames` (antes seriam "unsupported" e redirecionariam); o serializer precisa reproduzir `?source=enviadas&q=…&person=…&page=…` **byte a byte** (ordem canônica acima; `page` só >1). Mitigação: pins no `recordingListUrl.unit.spec.ts` (incluindo `mode=tema` sem `q` canonicalizando fora e `sort` default omitido).
+- **`select` allowlist:** esquecer `topics` no `recordingListSelect` some com o chip do card silenciosamente. Mitigação: o campo é exigido pelo input do view model (typecheck) + int test do loader.
+- **Manifest e2e:** `src/collections/Recording.ts` está fora do manifest (um diff só nele cairia no smoke da home); `src/payload-types.ts` é `HIGH_RISK_EXACT` → o PR roda o e2e **curado**, que hoje não inclui `campaignSpeechAcervo`. Mitigação: adicionar o arquivo ao entry da vertical e `campaignSpeechAcervo` ao `E2E_CURATED_SPECS` + pin (precedente C167/S19); a suíte full continua no `verify` do deploy.
+- **Ausência de `DEEPINFRA_API_KEY`:** `classifySpeech` degrada para gazetteer (topics/scopes/municípios do léxico) e nunca lança; o CLI reporta `llm: false` e o `mergeFacetClassification` garante que `classifiedBy: 'llm'` só sai com resposta validada.
+- **Gravações já existentes:** `classifiedBy` **nulo = "não classificada"** (honesto; nunca inventar `gazetteer` por default); ficam visíveis e sem faceta até o `pnpm recordings:classify` rodar; o CLI é idempotente e não toca `manual`.
+- **Transcrição longa:** o prompt do LLM trunca em 12k chars (dono: `classifySpeech`) — classificação pelo início da transcrição, registrada no `admin.description`; a busca (trgm) não é afetada. O custo é 1 chamada por gravação `ready` (mesmo provedor/chave do ASR), nunca por request.
+- **Sort × duração nula:** sem o gate `durationSeconds exists`, o Postgres colocaria as linhas sem duração no topo de "Duração (maior)"; o gate + hint no controle mantêm a ordem honesta. Int test cobre.
+- **Matriz de papéis:** intocada — gate da página e `canReadRecording` idênticos; a expansão de tema só roda depois de `canReadCommunicationCatalog(role)`; os bypasses do job/CLI são internos e justificados.
+- **Migration em produção:** aditiva (colunas nulas + joins), aplicada pelo `pnpm build` do deploy; o backfill de `year` é SQL determinístico; `down` gerado cobre rollback.
+- **Ciclos/convenções:** `recordings → speech` não pode criar ciclo (`speech` não importa `recordings`) — `pnpm check:cycles`; `recordingClassification.ts` declara `import 'server-only'` (regra do `codebaseConventions.unit.spec.ts`).
+
+## Aceite de engenharia
+
+- [ ] Aceite de produto da intenção ainda coberto (ano, duração, tema, alcance, município citado, pessoa exclusiva, contagem, chips, ordenação, vazio honesto, tema degradando honestamente).
+- [ ] Invariantes AGENTS/engineering-standards: `user` + `overrideAccess: false` em toda leitura; bypass do job/CLI justificado; sem `Consent`/PII nova; `leader`/`advisor` fail-closed; sem top-level novo em `utilities/`; copy pt-BR / identificadores em inglês; sem `openai/*` (OPS123).
+- [ ] Migrations: só arquivos novos (nunca editar antigas); `pnpm migrate` local; `pnpm generate:types`; prod aplica no build.
+- [ ] Testes de domínio previstos: unit (URL/where/omnibox/corpus), int (job escreve facetas, curadoria manual preservada, loader filtra/ordena/tema), e2e (barra/filtros/ordenação/vazio) — onde os write paths e o contrato de URL mudam.
+- [ ] Manifest/e2e atualizado (`src/collections/Recording.ts` na vertical; `campaignSpeechAcervo` no curado + pin).
+- [ ] Gates: `tsc --noEmit`, `pnpm lint` (0 warnings), `pnpm format:check`, `pnpm exec knip`, `pnpm check:cycles`, `pnpm test`, `pnpm build`; `pnpm push`; entrada em `docs/changelog/`.
+
+## Decisões de engenharia
+
+**(i) Onde a classificação roda**
+
+- **Opções:** A) seam no `runRecordingJob` (injetável) + CLI backfill | B) hook `afterChange` da collection | C) on-demand no loader da busca | D) hook por `recordingSegment`.
+- **Recomendação:** **A** — o job já tem `keyedSegments` em memória ao fim da transcrição, roda fora do request e faz o save transacional; o `classify` injetável (default `classifySpeech`) é o mesmo padrão de `catalogContentPiece` e mantém os testes offline; o CLI cobre as linhas anteriores à entrega com a mesma função.
+- **Rejeitadas:** B porque o hook dispara em cada transição de `status`/`step` (sem transcrição no momento útil), prenderia um LLM de 60s dentro do ciclo de escrita e re-executaria a cada passo; C porque pagaria o LLM em toda página, transformaria leitura em escrita e não filtraria pelo que ainda não foi classificado; D porque faria N chamadas por gravação e classificaria por trecho — unidade rejeitada pela intenção.
+
+**(ii) Schema em `Recording`**
+
+- **Opções:** A) espelhar `Speech` (`year` derivado, `topics`/`scopes`/`classifiedBy`/`mentionedMunicipalities`, `preserveManualFacets`) com a migration `add_recording_facets` | B) facetas por segmento | C) sem schema, derivar na busca | D) ano por range sobre `recordedAt` (sem coluna).
+- **Recomendação:** **A** — mantém `where`, opções de faceta e canônico idênticos aos da Câmara (a paridade é o objetivo), a curadoria manual preservada (hook espelho) e o "revisável" no admin. `year` derivado no `beforeValidate` com backfill SQL na migration; `classifiedBy` opcional (ver vii).
+- **Rejeitadas:** B porque a unidade da Câmara é a fala e o corte da intenção é a gravação; C porque não filtra com `where`/paginação, recalcula a cada busca e perde a revisão; D porque criaria um segundo shape de filtro para o mesmo conceito (e teria de repetir a regra de fuso em cada branch), enquanto a coluna derivada é literalmente o "derivado da data já informada" da intenção.
+
+**(iii) Reuso do contrato de duração e do omnibox**
+
+- **Opções:** A) reusar os donos da Câmara (buckets/labels/tipo em `speechListUrl`, `durationBucketWhere` exportado de `speechListFilters`, parsers de ano/município em `campaignListUrl`) + `recordingOmnibox` novo | B) extrair módulo compartilhado novo do acervo e migrar a Câmara | C) duplicar buckets/where no domínio de gravações.
+- **Recomendação:** **A** — um dono para o bucket (mudança na Câmara reflete nas gravações, que é a paridade pedida) e o adaptador por domínio segue o padrão já existente (`municipalityOmnibox`, `municipalityUpdateOmnibox`); o que é genérico (`lib/campaignListOmnibox`) já é compartilhado.
+- **Rejeitadas:** B porque mover o contrato de referência para um terceiro neutro gera churn na Câmara sem volatilidade real — gatilho de revisitação: a chegada da C216 (3º consumidor); C porque duplicar o bucket/where faz as duas fontes divergirem em silêncio, exatamente o que o item existe para impedir.
+
+**(iv) Corpus da busca por tema**
+
+- **Opções:** A) `ThemeSearchCorpus` ganha `'recording'` + prompt próprio + wrapper | B) reusar o corpus `'speech'` | C) só busca literal.
+- **Recomendação:** **A** — `expandSearchTheme(theme, corpus)` é o mecanismo único desde S28; o que muda é o prompt (plenárias/debates/material próprio enviados pela equipe). Degradação e `normalizeSpeechThemeTerms` são herdados.
+- **Rejeitadas:** B porque o prompt descreve discursos da Câmara e degradaria a expansão para gravações; C porque a pergunta de produto foi confirmada no gate (estender a ponte é a paridade pedida).
+
+**(v) UI: componente novo × generalização**
+
+- **Opções:** A) `RecordingAcervoFilters` novo sobre os shells compartilhados | B) generalizar `SpeechAcervoFilters` configurável | C) estender `SpeechAcervoFilters` com `source`.
+- **Recomendação:** **A** — os donos das mecânicas são os shells (`CampaignListOmnibox`, `CampaignHeaderFilterPopover`, `useCampaignListFilterNavigation`, `CampaignListPending*`, `CampaignListEmptyState/Footer`); o componente de domínio só monta os facets da fonte, como o da Câmara.
+- **Rejeitadas:** B porque uma API genérica configurável é pass-through raso e mexeria na Câmara (anti-goal); C porque acoplaria os dois contratos de URL num único componente e twinaria a Câmara dentro dele.
+
+**(vi) Contrato de ordenação**
+
+- **Opções:** A) `sort` com valores pt-BR (`recentes` default omitido, `duracao_maior`, `duracao_menor`) + exclusão de linhas sem duração nos sorts de duração | B) `sort`/`dir` genérico (C117) | C) sort só de UI.
+- **Recomendação:** **A** — contrato fechado (o canonicalizador redireciona valor desconhecido), default preserva `-createdAt` (zero regressão) e o gate `durationSeconds exists` evita NULLS FIRST no Postgres; o controle avisa que gravações sem duração aparecem só em "Mais recentes".
+- **Rejeitadas:** B porque o acervo não é tabela e a Câmara não tem esse contrato (a paridade pede o gesto, não o par genérico); C porque quebraria "paginação preservada no deep link" e o back/forward.
+
+**(vii) Proveniência nula nas gravações existentes**
+
+- **Opções:** A) `classifiedBy` opcional, sem default — nulo = "não classificada" | B) `required` com `defaultValue: 'gazetteer'` (espelho exato de `Speech`).
+- **Recomendação:** **A** — o default de B afirmaria que o gazetteer classificou linhas que nunca passaram por ele (viola o "nunca inventa"); nulo é o estado honesto até o `pnpm recordings:classify`, e o seletor do CLI fica trivial (`classifiedBy` ausente). Os **valores** persistidos são os mesmos da Câmara (`gazetteer|llm|manual`) — a paridade é do vocabulário, não do `required`.
+- **Rejeitadas:** B porque a migration carimbaria proveniência falsa nas linhas antigas e o backfill não teria como distinguir "classificada" de "nunca classificada".
+
+**Decisões baratas (com gatilho de revisitação):**
+
+- **Excerto no modo tema:** evidência de tema vence o excerto (espelho C192) e o `watchHref` mantém o `q` literal no `?t=&q=` (byte-compat; espelho `buildWatchHref`). Revisitar se a Câmara mudar a regra.
+- **`CampaignThemeRetryButton` movido para `shared/`** (componente genérico, 1 import atualizado na Câmara) — o aviso em si fica por domínio (copy).
+- **Helpers de estado do omnibox (`withPageReset`/`toggleValue`/`removeValue`)** duplicados no adaptador de gravações; extrair na C216 (3º).
+- **Contagem no `CampaignListFooter`** (não na linha do sort, como no artefato) — padrão de todas as listas; sem duplicar a linha.
+- **Chip de tema no card** usa `bg-muted` (mesma linguagem do chip de pessoa) — sem selo "Tema" (o artefato não pede).
+
+**Self-score (0–5, gate ≥4): 5/5.**
+
+1. **Decisões caras com rejeitadas:** 5/5 — as seis decisões caras (seam, schema, reuso de contrato, corpus, UI, sort) e a de proveniência nula têm opções/recomendação/rejeitadas; as baratas ficam com gatilho.
+2. **Appetite:** 5/5 — sem infra/provedor novo, sem collection/rota nova, reusando classificador, ponte de tema, shells e a transação do job; cabe nos ~2–3 dias.
+3. **Rabbit holes nomeados:** 5/5 — barra genérica, módulo compartilhado precoce, embeddings, classificação por trecho, segundo cadastro, mudança de default de sort, lista única.
+4. **Depth check:** 5/5 — reusa `classifySpeech`/`lib/speechFacets`, `expandSearchTheme`, `campaignListOmnibox`, shells de lista, `loadMunicipalityLabelsByIds`, `SpeechHighlightParts`, `withPayloadTransaction`; nada de camada cerimonial.
+5. **Intenção preservada:** 5/5 — Pessoa exclusiva, gate fail-closed, deep-link byte-compatível, sem lista única, sem redesenho da Câmara, classificação auditável e degradando honestamente.
diff --git a/docs/plans/omnibox-limpar-mobile.md b/docs/plans/omnibox-limpar-mobile.md
new file mode 100644
index 00000000..547ce38f
--- /dev/null
+++ b/docs/plans/omnibox-limpar-mobile.md
@@ -0,0 +1,36 @@
+# C221 — "Limpar" do omnibox não pode quebrar linha no mobile
+
+Status: rascunho
+Atualizado em: 2026-09-24
+Issue: (a registrar)
+Priority: P3
+Impeccable: B — ajuste de encaixe do shell de filtros existente (não é fluxo novo)
+Appetite: ~2h eng (fill-in)
+
+## Intenção
+
+Débito capturado na crítica de design da C219 (`docs/plans/acervo-paridade-busca-filtros.md`): no mobile, quando o chip de busca do omnibox compartilhado é longo, o botão global "Limpar" (o "X" circular dentro do campo, `md:hidden`) quebra para uma linha própria e aparece órfão abaixo do chip, criando uma faixa vazia entre o campo e o seletor de modo. Reproduzido igualmente na fonte Câmara e na fonte "Gravações enviadas" — é comportamento pré-existente do `CampaignListOmnibox`, não regressão da C219.
+
+Evidência: `/tmp/opencode/c219-shots/06-mobile-empty.png` (gravações) e `/tmp/opencode/c219-shots/11-mobile-camara-long-chip.png` (Câmara) na sessão da C219; o código é o cluster `flex-wrap` do campo em `src/components/campaign/shared/CampaignListOmnibox.tsx` (chips + input + botão de limpar na mesma linha flexível).
+
+## Objetivo e aceite
+
+- Com um chip de busca longo no mobile, o "X" de limpar permanece visualmente vinculado ao campo/chips (não quebra para uma linha órfã), em todas as listas que usam o shell.
+- Comportamento, acessibilidade (`aria-label="Limpar"`, anel de foco, região `sr-only`) e desktop intocados.
+- Sem mudança de contrato de URL/filtros.
+
+## Direção no codebase (hipótese)
+
+- `src/components/campaign/shared/CampaignListOmnibox.tsx` — cluster do campo (`flex min-h-10 w-full flex-wrap items-center gap-1.5 ...`) com chips, input e o botão de limpar `md:hidden`.
+- Consumidores para regressão visual: `SpeechAcervoFilters`, `RecordingAcervoFilters`, listas de municípios/apoiadores (qualquer `
-)
-
const RecordingsSource = ({
data,
}: {
data: Awaited>
}) => {
- const hasSearch = Boolean(data.state.q)
- const hasPeople = (data.state.people?.length ?? 0) > 0
- const hasFilters = hasSearch || hasPeople
+ const hasFilters = recordingHasActiveFilters(data.state)
+ const themeMode = data.state.mode === 'tema'
+ const themeActive = themeMode && data.themeApplied && !data.themeUnavailable
return (
-
+
-
+ {data.themeUnavailable ? : null}
({ id: row.id, status: row.status }))}
/>
+
+
+
+ {data.themeUnavailable
+ ? 'Resultados por termo exato'
+ : themeActive
+ ? 'Resultados por tema'
+ : 'Gravações encontradas'}
+
+ {themeMode ? (
+
+ {data.themeUnavailable
+ ? 'Comportamento atual do acervo.'
+ : themeActive
+ ? 'Confira o indício em cada gravação antes de abrir.'
+ : 'Nenhum termo relacionado foi acrescentado; mostramos a busca literal.'}
+
+ ) : null}
+
+
+ {data.themeUnavailable ? : null}
+
+
+
+
{data.rows.length > 0 ? (
) : (
- {hasFilters ? (
+ {themeActive ? (
+
+
+ Limpar filtros
+
+
+
+ Trocar para termo exato
+
+
+
+ ) : hasFilters ? (
-
- {hasPeople ? 'Limpar filtros' : 'Limpar busca'}
-
+ Limpar filtros
) : (
@@ -233,7 +249,7 @@ export default async function SpeechAcervoPage({ searchParams }: SpeechAcervoPag
: 'Nenhum termo relacionado foi acrescentado; mostramos a busca literal.'}
- {data.themeUnavailable ? : null}
+ {data.themeUnavailable ? : null}
) : null}
diff --git a/src/collections/Recording.ts b/src/collections/Recording.ts
index ac1620fd..d318cd41 100644
--- a/src/collections/Recording.ts
+++ b/src/collections/Recording.ts
@@ -1,4 +1,5 @@
import type {
+ CollectionBeforeChangeHook,
CollectionBeforeDeleteHook,
CollectionBeforeValidateHook,
CollectionConfig,
@@ -14,6 +15,7 @@ import {
recordingStepLabels,
} from '@/lib/recording'
import { speakerNamesFromLabels } from '@/lib/recordingDiarization'
+import { SPEECH_CLASSIFICATION_SOURCES, SPEECH_SCOPES, SPEECH_TOPICS } from '@/lib/speechFacets'
import {
canDeleteRecording,
canReadRecording,
@@ -67,6 +69,44 @@ const deriveSpeakerNames: CollectionBeforeValidateHook = ({ data, originalDoc })
return data
}
+/**
+ * C219 — the "Ano" facet is derived from the recording date the team already
+ * informed (`recordedAt`), never a second hand-typed field. A recording without
+ * a date honestly has no year (it stays out of the year filter).
+ */
+const deriveRecordingYear: CollectionBeforeValidateHook = ({ data, originalDoc }) => {
+ if (!data) return data
+ const recordedAt =
+ typeof data.recordedAt === 'string' ? data.recordedAt : (originalDoc?.recordedAt ?? null)
+ const year = Number(String(recordedAt ?? '').slice(0, 4))
+ // Clearing the date clears the derived year too — a stale year would keep the
+ // recording in an "Ano" facet the team just removed.
+ data.year = Number.isInteger(year) && year > 1900 ? year : null
+ return data
+}
+const FACET_FIELDS = ['topics', 'scopes', 'classifiedBy', 'mentionedMunicipalities'] as const
+
+/**
+ * C219 — a manual facet correction is curation: unauthenticated writes (the
+ * transcription job and the backfill CLI) never overwrite it. Authenticated
+ * admin edits stay free to change both the facets and the provenance.
+ */
+const preserveManualFacets: CollectionBeforeChangeHook = ({
+ data,
+ operation,
+ originalDoc,
+ req,
+}) => {
+ if (!data || operation !== 'update' || originalDoc?.classifiedBy !== 'manual') return data
+ if (req.user) return data
+
+ const next = data as Record
+ for (const field of FACET_FIELDS) {
+ if (field in next) next[field] = originalDoc[field]
+ }
+ return data
+}
+
export const Recording: CollectionConfig = {
slug: 'recording',
labels: {
@@ -76,9 +116,9 @@ export const Recording: CollectionConfig = {
admin: {
group: 'Comunicação',
useAsTitle: 'title',
- defaultColumns: ['title', 'recordedAt', 'status', 'durationSeconds', 'createdAt'],
+ defaultColumns: ['title', 'recordedAt', 'status', 'topics', 'classifiedBy'],
description:
- 'Gravações próprias da equipe no acervo. O arquivo é privado; a transcrição é somente leitura.',
+ 'Gravações próprias da equipe no acervo. O arquivo é privado; a transcrição é somente leitura. Tema, alcance e municípios citados são classificados automaticamente pelo início da transcrição e podem ser corrigidos aqui (a correção vira proveniência "Manual").',
},
access: {
create: canUploadRecording,
@@ -87,8 +127,8 @@ export const Recording: CollectionConfig = {
delete: canDeleteRecording,
},
hooks: {
- beforeValidate: [deriveSpeakerNames],
- beforeChange: [stampCampaignCreatedBy],
+ beforeValidate: [deriveSpeakerNames, deriveRecordingYear],
+ beforeChange: [preserveManualFacets, stampCampaignCreatedBy],
beforeDelete: [deleteRecordingSegments],
},
fields: [
@@ -108,6 +148,16 @@ export const Recording: CollectionConfig = {
description: 'Data em que a gravação foi feita (opcional).',
},
},
+ {
+ name: 'year',
+ type: 'number',
+ label: 'Ano',
+ index: true,
+ admin: {
+ readOnly: true,
+ description: 'Derivado da data da gravação.',
+ },
+ },
{
name: 'status',
type: 'select',
@@ -155,6 +205,47 @@ export const Recording: CollectionConfig = {
description: 'Concatenação normalizada dos segmentos (sem acentos, minúsculas).',
},
},
+ {
+ name: 'topics',
+ type: 'select',
+ label: 'Temas',
+ hasMany: true,
+ index: true,
+ options: SPEECH_TOPICS.map(({ value, label }) => ({ value, label })),
+ },
+ {
+ name: 'scopes',
+ type: 'select',
+ label: 'Alcance',
+ hasMany: true,
+ index: true,
+ options: SPEECH_SCOPES.map(({ value, label }) => ({ value, label })),
+ },
+ {
+ name: 'classifiedBy',
+ type: 'select',
+ label: 'Proveniência da classificação',
+ // Optional on purpose: a recording from before C219 was never classified,
+ // and stamping it `gazetteer` would claim a pass that never ran. Null is
+ // the honest "não classificada" until the backfill CLI runs.
+ index: true,
+ options: SPEECH_CLASSIFICATION_SOURCES.map((value) => ({
+ value,
+ label: value === 'gazetteer' ? 'Gazetteer' : value === 'llm' ? 'LLM' : 'Manual',
+ })),
+ admin: {
+ description:
+ 'Automática e auditável: Gazetteer (léxico), LLM (refinamento validado) ou Manual (correção humana).',
+ },
+ },
+ {
+ name: 'mentionedMunicipalities',
+ type: 'relationship',
+ relationTo: 'municipality',
+ label: 'Municípios citados',
+ hasMany: true,
+ index: true,
+ },
{
name: 'speakerLabels',
type: 'array',
diff --git a/src/components/campaign/recording/RecordingAcervoFilters.tsx b/src/components/campaign/recording/RecordingAcervoFilters.tsx
new file mode 100644
index 00000000..6cad2353
--- /dev/null
+++ b/src/components/campaign/recording/RecordingAcervoFilters.tsx
@@ -0,0 +1,296 @@
+'use client'
+
+import { useMemo, useOptimistic, useState } from 'react'
+
+import {
+ CampaignHeaderFilterPopover,
+ type CampaignHeaderFilterRow,
+} from '@/components/campaign/shared/CampaignHeaderFilterPopover'
+import {
+ CampaignListOmnibox,
+ campaignListOmniboxFormClassName,
+} from '@/components/campaign/shared/CampaignListOmnibox'
+import { CampaignSearchModeControl } from '@/components/campaign/shared/CampaignSearchModeControl'
+import { useCampaignListFilterNavigation } from '@/components/campaign/shared/useCampaignListFilterNavigation'
+import { selectedFilterTriggerLabel } from '@/lib/campaignListOmnibox'
+import { SPEECH_SCOPES, SPEECH_TOPICS } from '@/lib/speechFacets'
+import {
+ buildRecordingListHref,
+ toggleRecordingPerson,
+ type RecordingFilterOptions,
+ type RecordingListState,
+} from '@/utilities/recordings/recordingListUrl'
+import {
+ applyRecordingOmniboxSuggestion,
+ applyRecordingSearchMode,
+ buildRecordingOmniboxChips,
+ buildRecordingOmniboxSuggestionSeeds,
+ clearRecordingOmnibox,
+ filterRecordingOmniboxSuggestions,
+ removeRecordingOmniboxChip,
+ type RecordingOmniboxAction,
+} from '@/utilities/recordings/recordingOmnibox'
+import {
+ SPEECH_DURATION_BUCKETS,
+ speechDurationLabels,
+ speechScopeLabels,
+ speechTopicLabels,
+ type SpeechSearchMode,
+} from '@/utilities/speech/speechListUrl'
+
+const topicOptions = SPEECH_TOPICS.map(({ value, label }) => ({ value, label }))
+const scopeOptions = SPEECH_SCOPES.map(({ value, label }) => ({ value, label }))
+const durationOptions = SPEECH_DURATION_BUCKETS.map(({ value, label }) => ({ value, label }))
+
+type FacetKey = 'years' | 'topics' | 'scopes' | 'municipalities' | 'durations' | 'people'
+
+type RecordingFacet = {
+ id: string
+ label: string
+ /** Prefix of the omnibox suggestion id (`${prefix}:${value}`). */
+ prefix: string
+ stateKey: FacetKey
+ options: readonly { value: string; label: string }[]
+ selected: readonly string[]
+ labels?: Readonly>
+}
+
+/**
+ * C219 — the filter bar of "Gravações enviadas": same gestures as the Câmara
+ * acervo (search by term or theme, year, topic, scope, cited municipality,
+ * duration) plus the exclusive "Pessoa" facet. The mechanics (omnibox, chips,
+ * facet popovers, pending boundary) are the shared shells; this component only
+ * assembles the recordings facets. Ported from the approved hi-fi design
+ * (`docs/plans/acervo-paridade-busca-filtros-ui-design.html`, scenes 01/02).
+ */
+export const RecordingAcervoFilters = ({
+ state,
+ filterOptions,
+ themeUnavailable = false,
+}: {
+ state: RecordingListState
+ filterOptions: RecordingFilterOptions
+ /** C219 — the theme expansion is down; the selector reflects the fallback. */
+ themeUnavailable?: boolean
+}) => {
+ const { navigate, isPending } = useCampaignListFilterNavigation({
+ state,
+ toHref: (next) => buildRecordingListHref(next, 1),
+ })
+ const [query, setQuery] = useState('')
+ const [viewState, setOptimisticState] = useOptimistic(state)
+
+ const activeMode: SpeechSearchMode =
+ viewState.mode === 'tema' && !themeUnavailable ? 'tema' : 'termo'
+
+ const municipalityLabelsById = useMemo(() => {
+ const map = new Map()
+ for (const option of filterOptions.municipalities) {
+ const id = Number(option.value)
+ if (Number.isSafeInteger(id) && id > 0) map.set(id, option.label)
+ }
+ return map
+ }, [filterOptions.municipalities])
+
+ const chips = useMemo(
+ () => buildRecordingOmniboxChips({ state: viewState, municipalityLabelsById }),
+ [viewState, municipalityLabelsById],
+ )
+
+ const suggestionSeeds = useMemo(
+ () =>
+ buildRecordingOmniboxSuggestionSeeds({
+ years: filterOptions.years,
+ municipalityOptions: filterOptions.municipalities,
+ personOptions: filterOptions.people,
+ }),
+ [filterOptions],
+ )
+
+ const suggestions = useMemo(
+ () => filterRecordingOmniboxSuggestions(suggestionSeeds, query),
+ [suggestionSeeds, query],
+ )
+
+ const runAction = (action: RecordingOmniboxAction) => {
+ if (action.kind === 'clear') {
+ setQuery('')
+ navigate(action.state)
+ return
+ }
+ navigate(action.state)
+ }
+
+ const runMode = (mode: SpeechSearchMode) => {
+ const next = applyRecordingSearchMode({ state: viewState, mode }).state
+ setOptimisticState(next)
+ navigate(next)
+ }
+
+ const facetRows = (
+ prefix: string,
+ options: readonly { value: string; label: string }[],
+ selected: readonly string[],
+ ): CampaignHeaderFilterRow[] =>
+ options.map((option) => {
+ const next = applyRecordingOmniboxSuggestion({
+ state: viewState,
+ suggestionId: `${prefix}:${option.value}`,
+ }).state
+ return {
+ value: option.value,
+ label: option.label,
+ href: buildRecordingListHref(next, 1),
+ selected: selected.includes(option.value),
+ checkbox: true,
+ onChoose: () => setOptimisticState(next),
+ }
+ })
+
+ const personRows = (): CampaignHeaderFilterRow[] =>
+ filterOptions.people.map((person) => {
+ const next = toggleRecordingPerson(viewState, person)
+ return {
+ value: person,
+ label: person,
+ href: buildRecordingListHref(next, 1),
+ selected: (viewState.people ?? []).some(
+ (selected) => selected.toLocaleLowerCase('pt-BR') === person.toLocaleLowerCase('pt-BR'),
+ ),
+ checkbox: true,
+ onChoose: () => setOptimisticState(next),
+ }
+ })
+
+ const clearFacet = (facet: FacetKey) => {
+ const next: RecordingListState = { ...viewState, page: 1, [facet]: undefined }
+ return { href: buildRecordingListHref(next, 1), onChoose: () => setOptimisticState(next) }
+ }
+
+ const years = (viewState.years ?? []).map(String)
+ const topics = viewState.topics ?? []
+ const scopes = viewState.scopes ?? []
+ const municipalities = (viewState.municipalities ?? []).map(String)
+ const durations = viewState.durations ?? []
+ const people = viewState.people ?? []
+
+ const facets: RecordingFacet[] = [
+ {
+ id: 'recording-filter-year',
+ label: 'Ano',
+ prefix: 'year',
+ stateKey: 'years',
+ options: filterOptions.years.map((year) => ({ value: String(year), label: String(year) })),
+ selected: years,
+ },
+ {
+ id: 'recording-filter-topic',
+ label: 'Tema',
+ prefix: 'topic',
+ stateKey: 'topics',
+ options: topicOptions,
+ selected: topics,
+ labels: speechTopicLabels,
+ },
+ {
+ id: 'recording-filter-scope',
+ label: 'Alcance',
+ prefix: 'scope',
+ stateKey: 'scopes',
+ options: scopeOptions,
+ selected: scopes,
+ labels: speechScopeLabels,
+ },
+ {
+ id: 'recording-filter-municipality',
+ label: 'Município citado',
+ prefix: 'municipality',
+ stateKey: 'municipalities',
+ options: filterOptions.municipalities,
+ selected: municipalities,
+ labels: Object.fromEntries(municipalityLabelsById),
+ },
+ {
+ id: 'recording-filter-duration',
+ label: 'Duração',
+ prefix: 'duration',
+ stateKey: 'durations',
+ options: durationOptions,
+ selected: durations,
+ labels: speechDurationLabels,
+ },
+ ]
+
+ return (
+
+ )
+}
diff --git a/src/components/campaign/recording/RecordingPersonFilter.tsx b/src/components/campaign/recording/RecordingPersonFilter.tsx
deleted file mode 100644
index aab8dcbe..00000000
--- a/src/components/campaign/recording/RecordingPersonFilter.tsx
+++ /dev/null
@@ -1,87 +0,0 @@
-'use client'
-
-import { FunnelIcon, XIcon } from 'lucide-react'
-import { useOptimistic } from 'react'
-
-import {
- CampaignHeaderFilterPopover,
- type CampaignHeaderFilterRow,
-} from '@/components/campaign/shared/CampaignHeaderFilterPopover'
-import { useCampaignListFilterNavigation } from '@/components/campaign/shared/useCampaignListFilterNavigation'
-import { foldSpeakerName } from '@/lib/recordingDiarization'
-import {
- buildRecordingListHref,
- removeRecordingPerson,
- toggleRecordingPerson,
- type RecordingListState,
-} from '@/utilities/recordings/recordingListUrl'
-
-const PERSON_FILTER_ID = 'recording-filter-person'
-
-/**
- * C200 — the "Pessoa" facet of the uploaded recordings (design scene 3): one
- * removable chip per selected label plus the multi-select popover backed by the
- * labels actually present. Options come from the server (`speakerNames`), never
- * from a free-form directory — the label is text, not a `Contact`.
- */
-export const RecordingPersonFilter = ({
- state,
- options,
-}: {
- state: RecordingListState
- options: readonly string[]
-}) => {
- const { navigate } = useCampaignListFilterNavigation({
- state,
- toHref: (next) => buildRecordingListHref(next, 1),
- })
- const [viewState, setOptimisticState] = useOptimistic(state)
- const selected = viewState.people ?? []
-
- const optionRows: CampaignHeaderFilterRow[] = options.map((option) => {
- const next = toggleRecordingPerson(viewState, option)
- return {
- value: option,
- label: option,
- href: buildRecordingListHref(next, 1),
- selected: selected.some((person) => foldSpeakerName(person) === foldSpeakerName(option)),
- checkbox: true,
- onChoose: () => setOptimisticState(next),
- }
- })
-
- const clear = {
- href: buildRecordingListHref({ ...viewState, page: 1, people: undefined }, 1),
- onChoose: () => setOptimisticState({ ...viewState, page: 1, people: undefined }),
- }
-
- return (
-
- 1 ? `Pessoa: ${selected.length}` : 'Pessoa'}
- active={selected.length > 0}
- closeOnChoose={false}
- emptyLabel="Nenhuma pessoa identificada nas gravações."
- optionRows={optionRows}
- clear={selected.length ? clear : undefined}
- />
-
- {selected.map((person) => (
- navigate(removeRecordingPerson(viewState, person))}
- aria-label={`Remover filtro de ${person}`}
- >
-
- Pessoa: {person}
-
-
- ))}
-
- )
-}
diff --git a/src/components/campaign/recording/RecordingResultCard.tsx b/src/components/campaign/recording/RecordingResultCard.tsx
index 52889dbb..aedf06e5 100644
--- a/src/components/campaign/recording/RecordingResultCard.tsx
+++ b/src/components/campaign/recording/RecordingResultCard.tsx
@@ -66,8 +66,16 @@ export const RecordingResultCard = ({ recording }: { recording: RecordingListIte
)}
- {recording.matchedPersons.length > 0 ? (
+ {recording.topics.length > 0 || recording.matchedPersons.length > 0 ? (
+ {recording.topics.map((topic) => (
+
+ {topic.label}
+
+ ))}
{recording.matchedPersons.map((person) => (
))}
- aparece nesta gravação
+ {recording.matchedPersons.length > 0 ? (
+ aparece nesta gravação
+ ) : null}
) : null}
diff --git a/src/components/campaign/recording/RecordingSortSelect.tsx b/src/components/campaign/recording/RecordingSortSelect.tsx
new file mode 100644
index 00000000..ff362f6c
--- /dev/null
+++ b/src/components/campaign/recording/RecordingSortSelect.tsx
@@ -0,0 +1,51 @@
+'use client'
+
+import { useCampaignListFilterNavigation } from '@/components/campaign/shared/useCampaignListFilterNavigation'
+import {
+ buildRecordingListHref,
+ RECORDING_SORT_OPTIONS,
+ recordingSortIsDuration,
+ type RecordingListState,
+ type RecordingSortKey,
+} from '@/utilities/recordings/recordingListUrl'
+
+/**
+ * C219 — the list ordering control (design scene 01): "Mais recentes" (the
+ * default, never serialized) plus the two duration orders. A duration order
+ * only lists rows with a measured duration, so the hint says it out loud.
+ */
+export const RecordingSortSelect = ({ state }: { state: RecordingListState }) => {
+ const { navigate, isPending } = useCampaignListFilterNavigation({
+ state,
+ toHref: (next) => buildRecordingListHref(next, 1),
+ })
+ const value: RecordingSortKey = state.sort ?? 'recentes'
+
+ return (
+
+
+ Ordenar por
+ {
+ const next = event.target.value as RecordingSortKey
+ navigate({ ...state, page: 1, sort: next === 'recentes' ? undefined : next })
+ }}
+ >
+ {RECORDING_SORT_OPTIONS.map((option) => (
+
+ {option.label}
+
+ ))}
+
+
+ {recordingSortIsDuration(state) ? (
+
+ Gravações sem duração aparecem apenas em Mais recentes.
+
+ ) : null}
+
+ )
+}
diff --git a/src/components/campaign/recording/RecordingThemeFallbackNotice.tsx b/src/components/campaign/recording/RecordingThemeFallbackNotice.tsx
new file mode 100644
index 00000000..ed9931d6
--- /dev/null
+++ b/src/components/campaign/recording/RecordingThemeFallbackNotice.tsx
@@ -0,0 +1,26 @@
+import { TriangleAlertIcon } from 'lucide-react'
+
+import { Alert, AlertDescription, AlertTitle } from '@/components/ui/Alert'
+
+/**
+ * C219 — the discreet fallback notice when `mode=tema` was asked on the
+ * recordings source but the theme expansion was unavailable. The list below
+ * shows the literal results; the notice keeps the user's request honest
+ * instead of hiding the downgrade (same contract as the Câmara acervo, C192).
+ */
+export const RecordingThemeFallbackNotice = () => (
+
+
+
+ A busca por tema está indisponível agora.
+
+
+ Você pediu “Por tema”. Para não interromper o trabalho, mostramos abaixo os resultados por
+ termo exato.
+
+
+)
diff --git a/src/components/campaign/shared/CampaignSearchModeControl.tsx b/src/components/campaign/shared/CampaignSearchModeControl.tsx
new file mode 100644
index 00000000..f7ebe972
--- /dev/null
+++ b/src/components/campaign/shared/CampaignSearchModeControl.tsx
@@ -0,0 +1,83 @@
+'use client'
+
+import { SparklesIcon, TriangleAlertIcon } from 'lucide-react'
+
+import { cn } from '@/lib/utils'
+import type { SpeechSearchMode } from '@/utilities/speech/speechListUrl'
+
+/** C192/C219 — segmented search-mode button (mobile full width, desktop inline). */
+const modeButtonClass = (active: boolean, tone: 'termo' | 'tema'): string =>
+ cn(
+ 'min-h-11 rounded-md px-3 text-sm md:min-h-9',
+ active
+ ? cn(
+ 'bg-white font-semibold shadow-sm ring-1 ring-border',
+ tone === 'tema' ? 'text-primary' : 'text-foreground',
+ )
+ : 'font-medium text-muted-foreground',
+ )
+
+/**
+ * C219 — the "Termo exato | Por tema" selector shared by the two acervo
+ * sources. The mechanics (mode semantics, degradation) belong to the URL
+ * contract and the loader; this component only renders the choice and the
+ * honest state of the theme bridge.
+ */
+export const CampaignSearchModeControl = ({
+ activeMode,
+ themeUnavailable = false,
+ onSelect,
+ relatedHint,
+}: {
+ activeMode: SpeechSearchMode
+ /** The theme expansion is down; the selector reflects the fallback. */
+ themeUnavailable?: boolean
+ onSelect: (mode: SpeechSearchMode) => void
+ /** Desktop hint of the corpus ("Encontra falas relacionadas pelo sentido."). */
+ relatedHint: string
+}) => (
+
+
+
Buscar por
+
+ onSelect('termo')}
+ >
+ Termo exato
+
+ {
+ if (themeUnavailable) return
+ onSelect('tema')
+ }}
+ >
+
+ {themeUnavailable ? (
+
+ ) : (
+
+ )}
+ Por tema
+
+
+
+
+
+ {themeUnavailable ? 'Indisponível agora; mostramos o termo exato.' : relatedHint}
+
+
+)
diff --git a/src/components/campaign/speech/SpeechThemeRetryButton.tsx b/src/components/campaign/shared/CampaignThemeRetryButton.tsx
similarity index 69%
rename from src/components/campaign/speech/SpeechThemeRetryButton.tsx
rename to src/components/campaign/shared/CampaignThemeRetryButton.tsx
index 4b26fcd3..0b6b1b4b 100644
--- a/src/components/campaign/speech/SpeechThemeRetryButton.tsx
+++ b/src/components/campaign/shared/CampaignThemeRetryButton.tsx
@@ -5,8 +5,11 @@ import { useTransition } from 'react'
import { Button } from '@/components/ui/button'
-/** C192 — re-runs the same `mode=tema` request after a degraded fallback. */
-export const SpeechThemeRetryButton = () => {
+/**
+ * C192/C219 — re-runs the same `mode=tema` request after a degraded fallback.
+ * Shared by both acervo sources; the notice copy stays per domain.
+ */
+export const CampaignThemeRetryButton = () => {
const router = useRouter()
const [isPending, startTransition] = useTransition()
diff --git a/src/components/campaign/speech/SpeechAcervoFilters.tsx b/src/components/campaign/speech/SpeechAcervoFilters.tsx
index a46808f7..3fcf08cc 100644
--- a/src/components/campaign/speech/SpeechAcervoFilters.tsx
+++ b/src/components/campaign/speech/SpeechAcervoFilters.tsx
@@ -1,6 +1,5 @@
'use client'
-import { SparklesIcon, TriangleAlertIcon } from 'lucide-react'
import { useMemo, useOptimistic, useState } from 'react'
import {
@@ -11,9 +10,10 @@ import {
CampaignListOmnibox,
campaignListOmniboxFormClassName,
} from '@/components/campaign/shared/CampaignListOmnibox'
+import { CampaignSearchModeControl } from '@/components/campaign/shared/CampaignSearchModeControl'
import { useCampaignListFilterNavigation } from '@/components/campaign/shared/useCampaignListFilterNavigation'
+import { selectedFilterTriggerLabel } from '@/lib/campaignListOmnibox'
import { SPEECH_SCOPES, SPEECH_TOPICS } from '@/lib/speechFacets'
-import { cn } from '@/lib/utils'
import {
buildSpeechListHref,
SPEECH_DURATION_BUCKETS,
@@ -53,28 +53,6 @@ type SpeechFacet = {
labels?: Readonly>
}
-const selectedTriggerLabel = (
- base: string,
- values: readonly string[],
- labels?: Readonly>,
-): string => {
- if (values.length === 0) return base
- if (values.length === 1) return `${base}: ${labels?.[values[0]!] ?? values[0]}`
- return `${base}: ${values.length}`
-}
-
-/** C192 — segmented search-mode button (mobile full width, desktop inline). */
-const modeButtonClass = (active: boolean, tone: 'termo' | 'tema'): string =>
- cn(
- 'min-h-11 rounded-md px-3 text-sm md:min-h-9',
- active
- ? cn(
- 'bg-white font-semibold shadow-sm ring-1 ring-border',
- tone === 'tema' ? 'text-primary' : 'text-foreground',
- )
- : 'font-medium text-muted-foreground',
- )
-
export const SpeechAcervoFilters = ({
state,
filterOptions,
@@ -257,54 +235,12 @@ export const SpeechAcervoFilters = ({
}}
/>
-
-
-
- Buscar por
-
-
- runMode('termo')}
- >
- Termo exato
-
- {
- if (themeUnavailable) return
- runMode('tema')
- }}
- >
-
- {themeUnavailable ? (
-
- ) : (
-
- )}
- Por tema
-
-
-
-
-
- {themeUnavailable
- ? 'Indisponível agora; mostramos o termo exato.'
- : 'Encontra falas relacionadas pelo sentido.'}
-
-
+
0}
closeOnChoose={false}
optionRows={facetRows(facet.prefix, facet.options, facet.selected)}
diff --git a/src/lib/campaignListOmnibox.ts b/src/lib/campaignListOmnibox.ts
index d0601e8d..2559a85b 100644
--- a/src/lib/campaignListOmnibox.ts
+++ b/src/lib/campaignListOmnibox.ts
@@ -18,6 +18,21 @@ export type CampaignListOmniboxSuggestion = {
keywords?: readonly string[]
}
+/**
+ * The trigger text of a facet chip: the dimension alone when nothing is
+ * selected, "Ano: 2026" for one value and "Tema: 3" for several — one spelling
+ * for every acervo filter bar (C154/C219).
+ */
+export const selectedFilterTriggerLabel = (
+ base: string,
+ values: readonly string[],
+ labels?: Readonly
>,
+): string => {
+ if (values.length === 0) return base
+ if (values.length === 1) return `${base}: ${labels?.[values[0]!] ?? values[0]}`
+ return `${base}: ${values.length}`
+}
+
const omniboxQueryMatches = (
haystack: string,
needle: string,
diff --git a/src/migrations/20260924_040210_add_recording_facets.json b/src/migrations/20260924_040210_add_recording_facets.json
new file mode 100644
index 00000000..84cbd9af
--- /dev/null
+++ b/src/migrations/20260924_040210_add_recording_facets.json
@@ -0,0 +1,18696 @@
+{
+ "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
+ },
+ "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
+ },
+ "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_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_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": {},
+ "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.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
+ },
+ "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_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.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
+ },
+ "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
+ },
+ "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_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_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_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_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_legislature": {
+ "name": "enum_speech_legislature",
+ "schema": "public",
+ "values": [
+ "54",
+ "55",
+ "56",
+ "57"
+ ]
+ },
+ "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_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_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": "a2605c01-03fa-47cc-b4b5-fc826580a632",
+ "prevId": "00000000-0000-0000-0000-000000000000"
+}
\ No newline at end of file
diff --git a/src/migrations/20260924_040210_add_recording_facets.ts b/src/migrations/20260924_040210_add_recording_facets.ts
new file mode 100644
index 00000000..9a007ba0
--- /dev/null
+++ b/src/migrations/20260924_040210_add_recording_facets.ts
@@ -0,0 +1,76 @@
+import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
+
+/**
+ * C219 — facet + provenance columns of the uploaded recordings, mirroring the
+ * speech catalog (C153): `year` derived from the informed recording date,
+ * `topics`/`scopes` enums, `classifiedBy` (nullable: a row from before C219 was
+ * never classified) and the `mentionedMunicipalities` join. Additive only.
+ *
+ * The `year` backfill is deterministic SQL (never an LLM pass in a migration):
+ * it derives exactly what the `deriveRecordingYear` hook derives on the next
+ * write, so old rows join the "Ano" facet before the classification CLI runs.
+ */
+export async function up({ db, payload, req }: MigrateUpArgs): Promise {
+ await db.execute(sql`
+ CREATE TYPE "public"."enum_recording_topics" 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_recording_scopes" AS ENUM('bahia', 'brasil', 'internacional');
+ CREATE TYPE "public"."enum_recording_classified_by" AS ENUM('gazetteer', 'llm', 'manual');
+ CREATE TABLE "recording_topics" (
+ "order" integer NOT NULL,
+ "parent_id" integer NOT NULL,
+ "value" "enum_recording_topics",
+ "id" serial PRIMARY KEY NOT NULL
+ );
+
+ CREATE TABLE "recording_scopes" (
+ "order" integer NOT NULL,
+ "parent_id" integer NOT NULL,
+ "value" "enum_recording_scopes",
+ "id" serial PRIMARY KEY NOT NULL
+ );
+
+ CREATE TABLE "recording_rels" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "order" integer,
+ "parent_id" integer NOT NULL,
+ "path" varchar NOT NULL,
+ "municipality_id" integer
+ );
+
+ ALTER TABLE "recording" ADD COLUMN "year" numeric;
+ ALTER TABLE "recording" ADD COLUMN "classified_by" "enum_recording_classified_by";
+ ALTER TABLE "recording_topics" ADD CONSTRAINT "recording_topics_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."recording"("id") ON DELETE cascade ON UPDATE no action;
+ ALTER TABLE "recording_scopes" ADD CONSTRAINT "recording_scopes_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."recording"("id") ON DELETE cascade ON UPDATE no action;
+ ALTER TABLE "recording_rels" ADD CONSTRAINT "recording_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."recording"("id") ON DELETE cascade ON UPDATE no action;
+ ALTER TABLE "recording_rels" ADD CONSTRAINT "recording_rels_municipality_fk" FOREIGN KEY ("municipality_id") REFERENCES "public"."municipality"("id") ON DELETE cascade ON UPDATE no action;
+ CREATE INDEX "recording_topics_order_idx" ON "recording_topics" USING btree ("order");
+ CREATE INDEX "recording_topics_parent_idx" ON "recording_topics" USING btree ("parent_id");
+ CREATE INDEX "recording_topics_value_idx" ON "recording_topics" USING btree ("value");
+ CREATE INDEX "recording_scopes_order_idx" ON "recording_scopes" USING btree ("order");
+ CREATE INDEX "recording_scopes_parent_idx" ON "recording_scopes" USING btree ("parent_id");
+ CREATE INDEX "recording_scopes_value_idx" ON "recording_scopes" USING btree ("value");
+ CREATE INDEX "recording_rels_order_idx" ON "recording_rels" USING btree ("order");
+ CREATE INDEX "recording_rels_parent_idx" ON "recording_rels" USING btree ("parent_id");
+ CREATE INDEX "recording_rels_path_idx" ON "recording_rels" USING btree ("path");
+ CREATE INDEX "recording_rels_municipality_id_idx" ON "recording_rels" USING btree ("municipality_id");
+ CREATE INDEX "recording_year_idx" ON "recording" USING btree ("year");
+ CREATE INDEX "recording_classified_by_idx" ON "recording" USING btree ("classified_by");
+ UPDATE "recording" SET "year" = EXTRACT(YEAR FROM "recorded_at") WHERE "recorded_at" IS NOT NULL;`)
+}
+
+export async function down({ db, payload, req }: MigrateDownArgs): Promise {
+ await db.execute(sql`
+ ALTER TABLE "recording_topics" DISABLE ROW LEVEL SECURITY;
+ ALTER TABLE "recording_scopes" DISABLE ROW LEVEL SECURITY;
+ ALTER TABLE "recording_rels" DISABLE ROW LEVEL SECURITY;
+ DROP TABLE "recording_topics" CASCADE;
+ DROP TABLE "recording_scopes" CASCADE;
+ DROP TABLE "recording_rels" CASCADE;
+ DROP INDEX "recording_year_idx";
+ DROP INDEX "recording_classified_by_idx";
+ ALTER TABLE "recording" DROP COLUMN "year";
+ ALTER TABLE "recording" DROP COLUMN "classified_by";
+ DROP TYPE "public"."enum_recording_topics";
+ DROP TYPE "public"."enum_recording_scopes";
+ DROP TYPE "public"."enum_recording_classified_by";`)
+}
diff --git a/src/migrations/index.ts b/src/migrations/index.ts
index 24647af2..85922b73 100644
--- a/src/migrations/index.ts
+++ b/src/migrations/index.ts
@@ -82,6 +82,7 @@ import * as migration_20260923_032714_add_content_piece from './20260923_032714_
import * as migration_20260923_054145_add_share_link_announcement from './20260923_054145_add_share_link_announcement';
import * as migration_20260923_172437_add_content_events from './20260923_172437_add_content_events';
import * as migration_20260923_190414_add_content_event_variant from './20260923_190414_add_content_event_variant';
+import * as migration_20260924_040210_add_recording_facets from './20260924_040210_add_recording_facets';
import * as migration_20260924_042028_add_web_speech_origin from './20260924_042028_add_web_speech_origin';
import * as migration_20260924_045625_add_content_piece_link_failure_reason from './20260924_045625_add_content_piece_link_failure_reason';
@@ -506,6 +507,11 @@ export const migrations = [
down: migration_20260923_190414_add_content_event_variant.down,
name: '20260923_190414_add_content_event_variant',
},
+ {
+ up: migration_20260924_040210_add_recording_facets.up,
+ down: migration_20260924_040210_add_recording_facets.down,
+ name: '20260924_040210_add_recording_facets'
+ },
{
up: migration_20260924_042028_add_web_speech_origin.up,
down: migration_20260924_042028_add_web_speech_origin.down,
diff --git a/src/payload-types.ts b/src/payload-types.ts
index bda51902..8fea361f 100644
--- a/src/payload-types.ts
+++ b/src/payload-types.ts
@@ -1362,7 +1362,7 @@ export interface ContentEvent {
createdAt: string;
}
/**
- * Gravações próprias da equipe no acervo. O arquivo é privado; a transcrição é somente leitura.
+ * Gravações próprias da equipe no acervo. O arquivo é privado; a transcrição é somente leitura. Tema, alcance e municípios citados são classificados automaticamente pelo início da transcrição e podem ser corrigidos aqui (a correção vira proveniência "Manual").
*
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "recording".
@@ -1374,6 +1374,10 @@ export interface Recording {
* Data em que a gravação foi feita (opcional).
*/
recordedAt?: string | null;
+ /**
+ * Derivado da data da gravação.
+ */
+ year?: number | null;
status: 'uploading' | 'processing' | 'ready' | 'failed';
/**
* Progresso honesto da transcrição em andamento.
@@ -1391,6 +1395,34 @@ export interface Recording {
* Concatenação normalizada dos segmentos (sem acentos, minúsculas).
*/
searchText?: string | null;
+ topics?:
+ | (
+ | '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;
+ scopes?: ('bahia' | 'brasil' | 'internacional')[] | null;
+ /**
+ * Automática e auditável: Gazetteer (léxico), LLM (refinamento validado) ou Manual (correção humana).
+ */
+ classifiedBy?: ('gazetteer' | 'llm' | 'manual') | null;
+ mentionedMunicipalities?: (number | Municipality)[] | null;
/**
* Rótulos humanos por agrupamento acústico (chave → nome). Identificação sempre humana; o acervo nunca sugere ou infere pessoas.
*/
@@ -2872,11 +2904,16 @@ export interface ContentEventSelect {
export interface RecordingSelect {
title?: T;
recordedAt?: T;
+ year?: T;
status?: T;
step?: T;
media?: T;
durationSeconds?: T;
searchText?: T;
+ topics?: T;
+ scopes?: T;
+ classifiedBy?: T;
+ mentionedMunicipalities?: T;
speakerLabels?:
| T
| {
diff --git a/src/utilities/ai/expandSpeechSearchTheme.ts b/src/utilities/ai/expandSpeechSearchTheme.ts
index fac0bca4..e3555f50 100644
--- a/src/utilities/ai/expandSpeechSearchTheme.ts
+++ b/src/utilities/ai/expandSpeechSearchTheme.ts
@@ -15,17 +15,23 @@ const EXPAND_TIMEOUT_MS = 4000
const MAX_OUTPUT_TOKENS = 200
const MAX_THEME_LENGTH = 200
+const EXPAND_SUBJECT_BY_CORPUS: Record = {
+ speech: 'na transcrição de falas',
+ contentPiece: 'na descrição ou na transcrição de uma peça',
+ recording: 'na transcrição de uma gravação enviada pela equipe',
+}
+
const expandSchemaFor = (corpus: ThemeSearchCorpus) =>
z.object({
terms: z
.array(z.string())
.describe(
- `Termos e expressões curtas (${MIN_SPEECH_THEME_TERMS} a ${MAX_SPEECH_THEME_TERMS}) que podem aparecer ${corpus === 'speech' ? 'na transcrição de falas' : 'na descrição ou na transcrição de uma peça'} sobre o tema. Lista vazia quando não houver termo confiável.`,
+ `Termos e expressões curtas (${MIN_SPEECH_THEME_TERMS} a ${MAX_SPEECH_THEME_TERMS}) que podem aparecer ${EXPAND_SUBJECT_BY_CORPUS[corpus]} sobre o tema. Lista vazia quando não houver termo confiável.`,
),
})
/** The term rules are one contract; only the noun of the corpus changes. */
-const themeExpansionRules = (subject: 'discurso' | 'peça'): string =>
+const themeExpansionRules = (subject: 'discurso' | 'peça' | 'gravação'): string =>
`Devolva de ${MIN_SPEECH_THEME_TERMS} a ${MAX_SPEECH_THEME_TERMS} termos, cada um com no máximo ${MAX_SPEECH_THEME_TERM_LENGTH} caracteres, sem explicações, ` +
`sem pontuação extra e sem termos genéricos que apareceriam em qualquer ${subject} (ex.: "Brasil", ` +
'"povo", "governo"). Se não houver termo confiável, devolva a lista vazia. Nunca invente fatos.'
@@ -48,14 +54,34 @@ const CONTENT_PIECE_CORPUS_PROMPT =
themeExpansionRules('peça')
/**
- * S28 — the corpus a theme expansion serves: the internal speech acervo (C192)
- * and the public Central de Conteúdos (S28). The mechanism is one; only the
- * system prompt describes a different body of material and persona.
+ * C219 — the third corpus: the uploaded recordings of the acervo ("Gravações
+ * enviadas"), whose material is the team's own plenárias/debates rather than
+ * the Câmara's speeches, so the prompt describes that body of material.
*/
-export type ThemeSearchCorpus = 'speech' | 'contentPiece'
+const RECORDING_CORPUS_PROMPT =
+ 'Você ajuda a assessoria de comunicação a achar, no acervo de gravações enviadas pela equipe ' +
+ '(plenárias, debates e materiais próprios do deputado Jorge Solla), trechos sobre um tema mesmo ' +
+ 'quando a gravação não usa as palavras exatas da busca. ' +
+ 'Receberá o tema digitado e deve devolver termos e expressões curtas que provavelmente aparecem ' +
+ 'na transcrição de uma gravação sobre esse tema — sinônimos, nomes de programas, termos técnicos ' +
+ 'e palavras relacionadas. Inclua a própria expressão do tema quando ela for útil. ' +
+ themeExpansionRules('gravação')
-const systemPromptFor = (corpus: ThemeSearchCorpus): string =>
- corpus === 'contentPiece' ? CONTENT_PIECE_CORPUS_PROMPT : SPEECH_CORPUS_PROMPT
+/**
+ * S28/C219 — the corpus a theme expansion serves: the internal speech acervo
+ * (C192), the public Central de Conteúdos (S28) and the uploaded recordings
+ * (C219). The mechanism is one; only the system prompt describes a different
+ * body of material and persona.
+ */
+export type ThemeSearchCorpus = 'speech' | 'contentPiece' | 'recording'
+
+const SYSTEM_PROMPT_BY_CORPUS: Record = {
+ speech: SPEECH_CORPUS_PROMPT,
+ contentPiece: CONTENT_PIECE_CORPUS_PROMPT,
+ recording: RECORDING_CORPUS_PROMPT,
+}
+
+const systemPromptFor = (corpus: ThemeSearchCorpus): string => SYSTEM_PROMPT_BY_CORPUS[corpus]
export type ThemeSearchExpansion = { terms: string[] }
@@ -110,3 +136,7 @@ export const expandSpeechSearchTheme: SpeechThemeExpansionResolver = (theme) =>
/** S28 — the public Central de Conteúdos expansion. */
export const expandContentPieceSearchTheme: ThemeSearchExpansionResolver = (theme) =>
expandSearchTheme(theme, 'contentPiece')
+
+/** C219 — the uploaded recordings expansion ("Gravações enviadas"). */
+export const expandRecordingSearchTheme: ThemeSearchExpansionResolver = (theme) =>
+ expandSearchTheme(theme, 'recording')
diff --git a/src/utilities/campaignListUrl.ts b/src/utilities/campaignListUrl.ts
index fa5f8ce4..5ab3fba4 100644
--- a/src/utilities/campaignListUrl.ts
+++ b/src/utilities/campaignListUrl.ts
@@ -82,6 +82,21 @@ export const strictDecimalInteger = (value: string | undefined): number | undefi
return Number.isSafeInteger(number) ? number : undefined
}
+/**
+ * Structural validation of the data-driven year facet (both acervo sources):
+ * a plausible calendar year, not a closed enum.
+ */
+export const parseYearValues = (raw: string | string[] | undefined): number[] =>
+ allParamValues(raw)
+ .map((token) => strictDecimalInteger(token))
+ .filter((year): year is number => year !== undefined && year >= 1900 && year <= 2100)
+
+/** Structural validation of a municipality-id facet (positive safe integer). */
+export const parseMunicipalityValues = (raw: string | string[] | undefined): number[] =>
+ allParamValues(raw)
+ .map((token) => strictDecimalInteger(token))
+ .filter((id): id is number => id !== undefined && id > 0)
+
export const inspectRawListParams = (
params: RawSearchParams,
paramNameSet: ReadonlySet,
diff --git a/src/utilities/recordings/recordingClassification.ts b/src/utilities/recordings/recordingClassification.ts
new file mode 100644
index 00000000..4d742d5f
--- /dev/null
+++ b/src/utilities/recordings/recordingClassification.ts
@@ -0,0 +1,97 @@
+import 'server-only'
+
+import type { Payload } from 'payload'
+
+import type { MergedSpeechFacets, SpeechScope, SpeechTopic } from '@/lib/speechFacets'
+import type { SpeechFacetInput } from '@/lib/speechGazetteer'
+import type { Recording } from '@/payload-types'
+import {
+ classifySpeech,
+ type SpeechClassificationResult,
+} from '@/utilities/speech/speechClassifier'
+
+/**
+ * C219 — facet classification of one uploaded recording. Reuses the speech
+ * classifier owner (`classifySpeech`: gazetteer + validated LLM refinement)
+ * over the transcript the job already has in memory, so recordings gain the
+ * same topic/scope/município facets with the same provenance vocabulary. The
+ * classifier never throws; this wrapper is also defensive (empty transcript or
+ * a database failure resolve to `null`) because the recording must still
+ * become `ready` with its transcript.
+ */
+
+export type RecordingFacetClassifier = (
+ input: SpeechFacetInput,
+) => Promise
+
+export type RecordingClassification = {
+ topics: SpeechTopic[]
+ scopes: SpeechScope[]
+ classifiedBy: MergedSpeechFacets['classifiedBy']
+ mentionedMunicipalities: number[]
+ /** Provider usage of the refinement pass; the backfill CLI reports it. */
+ llm: SpeechClassificationResult['llm']
+}
+
+/**
+ * The facet write shape, shared by the two writers (the job and the backfill
+ * CLI) so a new facet field lands in one place.
+ */
+export const recordingFacetWriteData = (
+ classification: RecordingClassification,
+): Pick => ({
+ topics: classification.topics,
+ scopes: classification.scopes,
+ classifiedBy: classification.classifiedBy,
+ mentionedMunicipalities: classification.mentionedMunicipalities,
+})
+
+export const classifyRecordingFacets = async ({
+ payload,
+ transcript,
+ classify = classifySpeech,
+}: {
+ payload: Pick
+ transcript: string
+ classify?: RecordingFacetClassifier
+}): Promise => {
+ const text = transcript.trim()
+ if (!text) return null
+
+ try {
+ const { facets, llm } = await classify({ transcript: text })
+
+ const slugs = [...new Set(facets.municipalities.map((entry) => entry.slug))]
+ const municipalities =
+ slugs.length === 0
+ ? []
+ : (
+ await payload.find({
+ collection: 'municipality',
+ where: { slug: { in: slugs } },
+ limit: slugs.length,
+ depth: 0,
+ select: { slug: true },
+ // Intentional admin bypass: resolving gazetteer slugs against the
+ // read-only município catalog (same as the speech import).
+ overrideAccess: true,
+ })
+ ).docs
+
+ return {
+ topics: facets.topics,
+ scopes: facets.scopes,
+ classifiedBy: facets.classifiedBy,
+ mentionedMunicipalities: municipalities.map((doc) => doc.id),
+ llm,
+ }
+ } catch (error) {
+ // Defensive: the classifier contract is "never throws"; a database failure
+ // while resolving the gazetteer slugs lands here. The recording still gets
+ // its transcript — but the failure is logged instead of vanishing.
+ payload.logger.warn(
+ `[recording-classification] falha ao classificar: ${error instanceof Error ? error.message : String(error)}`,
+ )
+ return null
+ }
+}
diff --git a/src/utilities/recordings/recordingJob.ts b/src/utilities/recordings/recordingJob.ts
index 4d2c00ec..bb798eef 100644
--- a/src/utilities/recordings/recordingJob.ts
+++ b/src/utilities/recordings/recordingJob.ts
@@ -39,6 +39,12 @@ import {
type PayloadTransactionRequest,
} from '@/utilities/payloadTransaction'
import { downloadPrivateMediaToFile } from '@/utilities/privateMedia/privateMediaResponse'
+import {
+ classifyRecordingFacets,
+ recordingFacetWriteData,
+ type RecordingFacetClassifier,
+} from '@/utilities/recordings/recordingClassification'
+import { classifySpeech } from '@/utilities/speech/speechClassifier'
/**
* C199 — the transcription job: download the private recording, extract/split
@@ -128,6 +134,7 @@ export const runRecordingJob = async (
recordingId: number,
transcribe: ChunkTranscriber = deepInfraTranscribeSegments,
diarize: SpeakerDiarizer | null = configuredSpeakerDiarizer(),
+ classify: RecordingFacetClassifier = classifySpeech,
): Promise => {
let tempDir: string | null = null
let currentStep: RecordingStep = 'extracting'
@@ -237,6 +244,15 @@ export const runRecordingJob = async (
}
}
+ // C219 — facet classification runs OUTSIDE the save transaction (the LLM
+ // may take a minute) and never fails the recording: a null result keeps the
+ // transcript with no facets and no provenance claim.
+ const classification = await classifyRecordingFacets({
+ payload,
+ transcript: keyedSegments.map((segment) => segment.text).join(' '),
+ classify,
+ })
+
await markStep('saving')
await withPayloadTransaction(payload, async ({ req }) => {
// Fresh reads inside the transaction: the labels a curator wrote while
@@ -310,6 +326,7 @@ export const runRecordingJob = async (
searchText: recordingSearchText(segments),
speakerLabels: labels,
speakerLabelsDropped: dropped,
+ ...(classification ? recordingFacetWriteData(classification) : {}),
},
req,
)
diff --git a/src/utilities/recordings/recordingListFilters.ts b/src/utilities/recordings/recordingListFilters.ts
index 2ec8bef0..386c6771 100644
--- a/src/utilities/recordings/recordingListFilters.ts
+++ b/src/utilities/recordings/recordingListFilters.ts
@@ -1,22 +1,67 @@
/**
- * C199 — Payload `where` of the uploaded-recordings list: one textual branch
- * over the normalized `recording.searchText` (the concatenation of the
- * transcript segments). C200 adds the "Pessoa" facet: any selected label that
- * appears in the recording's derived `speakerNames`. A recording still
- * processing has no `searchText` and is honestly out of the search until the
- * transcript is saved.
+ * C199/C219 — Payload `where` of the uploaded-recordings list. One textual
+ * branch over the normalized `recording.searchText` (the concatenation of the
+ * transcript segments), the "Pessoa" facet (any selected label present in the
+ * derived `speakerNames`) and the C219 parity facets — year, topic, scope,
+ * cited municipality and duration — AND-ed like the Câmara's. A duration sort
+ * also gates `durationSeconds` to exist, otherwise Postgres' NULLS FIRST would
+ * open "Duração (maior)" with the rows that have no duration.
*/
import type { Where } from 'payload'
import { normalizeForSearch } from '@/lib/speechSearch'
import { collapseListWhereOrBranches } from '@/utilities/campaignListUrl'
-import type { RecordingListState } from '@/utilities/recordings/recordingListUrl'
+import {
+ recordingSortIsDuration,
+ type RecordingListState,
+} from '@/utilities/recordings/recordingListUrl'
+import { durationBucketWhere } from '@/utilities/speech/speechListFilters'
-export const buildRecordingListWhere = (state: RecordingListState): Where => {
+const buildRecordingFacetWhere = (state: RecordingListState): Where[] => {
+ const filters: Where[] = []
+
+ if (state.years?.length) filters.push({ year: { in: state.years } })
+ if (state.topics?.length) filters.push({ topics: { in: state.topics } })
+ if (state.scopes?.length) filters.push({ scopes: { in: state.scopes } })
+ if (state.municipalities?.length) {
+ filters.push({ mentionedMunicipalities: { in: state.municipalities } })
+ }
+ if (state.durations?.length) {
+ const branch = collapseListWhereOrBranches(state.durations.map(durationBucketWhere))
+ if (branch) filters.push(branch)
+ }
+ if (recordingSortIsDuration(state)) filters.push({ durationSeconds: { exists: true } })
+
+ return filters
+}
+
+/**
+ * The textual branch: the literal query plus (C219) every expanded theme term,
+ * each matching the normalized recording text. Recordings have no official
+ * keywords, so the speech `keywords` branch has no counterpart here.
+ */
+const buildRecordingTextWhere = (terms: readonly string[]): Where | undefined => {
const branches: Where[] = []
+ const seen = new Set()
- const normalized = normalizeForSearch(state.q ?? '')
- if (normalized) branches.push({ searchText: { like: normalized } })
+ for (const term of terms) {
+ const normalized = normalizeForSearch(term)
+ if (!normalized || seen.has(normalized)) continue
+ seen.add(normalized)
+ branches.push({ searchText: { like: normalized } })
+ }
+
+ return collapseListWhereOrBranches(branches)
+}
+
+export const buildRecordingListWhere = (
+ state: RecordingListState,
+ themeTerms: readonly string[] = [],
+): Where => {
+ const branches = buildRecordingFacetWhere(state)
+
+ const textBranch = buildRecordingTextWhere([...(state.q ? [state.q] : []), ...themeTerms])
+ if (textBranch) branches.push(textBranch)
const peopleBranch = collapseListWhereOrBranches(
(state.people ?? []).map((person) => ({ speakerNames: { contains: person } })),
diff --git a/src/utilities/recordings/recordingListUrl.ts b/src/utilities/recordings/recordingListUrl.ts
index bd1cc2b7..833f7dee 100644
--- a/src/utilities/recordings/recordingListUrl.ts
+++ b/src/utilities/recordings/recordingListUrl.ts
@@ -1,43 +1,108 @@
/**
- * C199 — source switcher + list URL contract of the uploaded recordings. The
- * Câmara acervo keeps its own frozen contract (`speechListUrl`); the recordings
- * branch lives on the same `/campanha/comunicacao/acervo` page behind
- * `?source=enviadas` and owns its parses/serialization over the shared helpers.
+ * C199/C219 — source switcher + list URL contract of the uploaded recordings.
+ * The Câmara acervo keeps its own frozen contract (`speechListUrl`); the
+ * recordings branch lives on the same `/campanha/comunicacao/acervo` page
+ * behind `?source=enviadas` and owns its parses/serialization over the shared
+ * helpers. C219 brings the parity facets — search mode, year, topic, scope,
+ * cited municipality, duration and sort — reusing the Câmara taxonomy, the
+ * duration buckets and the structural year/municipality parsers. The original
+ * `?source=enviadas&q&person&page` deep links stay byte-identical: the new
+ * params are only serialized when selected and `mode=termo`/the default sort
+ * are never serialized.
*/
import { CAMPAIGN_COMMUNICATION_ACERVO } from '@/lib/campaignPaths'
import { isContactSearchQueryReady } from '@/lib/contactSearchQuery'
import { RECORDING_SPEAKER_LABEL_MAX_LENGTH } from '@/lib/recording'
import { foldSpeakerName } from '@/lib/recordingDiarization'
+import {
+ SPEECH_SCOPES,
+ SPEECH_TOPICS,
+ type SpeechScope,
+ type SpeechTopic,
+} from '@/lib/speechFacets'
import {
allParamValues,
buildListHref,
firstValue,
normalizedText,
+ parseExhaustiveEnumParam,
+ parseMunicipalityValues,
+ parseYearValues,
resolveListUrl,
strictDecimalInteger,
type RawSearchParams,
} from '@/utilities/campaignListUrl'
+import {
+ SPEECH_DURATION_BUCKETS,
+ type SpeechDurationBucket,
+ type SpeechSearchMode,
+} from '@/utilities/speech/speechListUrl'
export const recordingPageSize = 25
/** Which acervo source the page is showing. `camara` is the default. */
export type AcervoSource = 'camara' | 'enviadas'
+/**
+ * C219 — list ordering. `recentes` is the default and never serialized (the
+ * stored contract stays `-createdAt`); the duration orders only list rows with
+ * a measured duration, which is why the `where` gates `durationSeconds`.
+ */
+export const RECORDING_SORT_OPTIONS = [
+ { value: 'recentes', label: 'Mais recentes' },
+ { value: 'duracao_maior', label: 'Duração (maior)' },
+ { value: 'duracao_menor', label: 'Duração (menor)' },
+] as const
+
+export type RecordingSortKey = (typeof RECORDING_SORT_OPTIONS)[number]['value']
+
const ACERVO_SOURCE_PARAM = 'source'
const ACERVO_SOURCE_ENVIADAS = 'enviadas'
const ACERVO_PERSON_PARAM = 'person'
-const recordingListParamNames = [ACERVO_SOURCE_PARAM, 'q', 'page', ACERVO_PERSON_PARAM] as const
+const recordingListParamNames = [
+ ACERVO_SOURCE_PARAM,
+ 'q',
+ 'mode',
+ 'year',
+ 'topic',
+ 'scope',
+ 'municipality',
+ 'duration',
+ 'sort',
+ ACERVO_PERSON_PARAM,
+ 'page',
+] as const
const recordingListParamNameSet = new Set(recordingListParamNames)
+const recordingTopicSet = new Set(SPEECH_TOPICS.map(({ value }) => value))
+const recordingScopeSet = new Set(SPEECH_SCOPES.map(({ value }) => value))
+const recordingDurationSet = new Set(SPEECH_DURATION_BUCKETS.map(({ value }) => value))
+const recordingSortSet = new Set(RECORDING_SORT_OPTIONS.map(({ value }) => value))
export type RecordingListState = {
source: 'enviadas'
page: number
q?: string
+ /** C219 — `tema` asks the semantic bridge; `termo` (default) is never stored. */
+ mode?: SpeechSearchMode
+ years?: number[]
+ topics?: SpeechTopic[]
+ scopes?: SpeechScope[]
+ /** Cited municipalities (`mentionedMunicipalities`), not the uploader's. */
+ municipalities?: number[]
+ durations?: SpeechDurationBucket[]
+ sort?: RecordingSortKey
/** Selected "Pessoa" labels; repeated `person` params, literal text. */
people?: string[]
}
+/** Server-loaded filter options (present years, cited municipalities, people). */
+export type RecordingFilterOptions = {
+ people: string[]
+ years: number[]
+ municipalities: { value: string; label: string }[]
+}
+
/** `enviadas` only for the explicit value; anything else is the Câmara default. */
export const parseAcervoSource = (params: RawSearchParams): AcervoSource =>
firstValue(params[ACERVO_SOURCE_PARAM]) === ACERVO_SOURCE_ENVIADAS ? 'enviadas' : 'camara'
@@ -60,33 +125,99 @@ export const parseRecordingPeople = (raw: string | string[] | undefined): string
return people
}
+/** Only `tema` is meaningful; anything else (and `termo`) means the default. */
+const parseRecordingSearchMode = (
+ raw: string | string[] | undefined,
+): SpeechSearchMode | undefined => (firstValue(raw) === 'tema' ? 'tema' : undefined)
+
+/** Only the non-default duration orders are meaningful; anything else is `recentes`. */
+const parseRecordingSort = (raw: string | string[] | undefined): RecordingSortKey | undefined => {
+ const value = firstValue(raw)
+ return value && value !== 'recentes' && recordingSortSet.has(value)
+ ? (value as RecordingSortKey)
+ : undefined
+}
+
export const parseRecordingListParams = (params: RawSearchParams): RecordingListState => {
const rawPage = strictDecimalInteger(firstValue(params.page))
const rawQ = normalizedText(firstValue(params.q))
const q = rawQ && isContactSearchQueryReady(rawQ) ? rawQ : undefined
+ const mode = parseRecordingSearchMode(params.mode)
+ const years = parseYearValues(params.year)
+ const topics = parseExhaustiveEnumParam(params.topic, recordingTopicSet)
+ const scopes = parseExhaustiveEnumParam(params.scope, recordingScopeSet)
+ const municipalities = parseMunicipalityValues(params.municipality)
+ const durations = parseExhaustiveEnumParam(
+ params.duration,
+ recordingDurationSet,
+ )
+ const sort = parseRecordingSort(params.sort)
const people = parseRecordingPeople(params[ACERVO_PERSON_PARAM])
return {
source: 'enviadas',
page: rawPage ?? 1,
...(q ? { q } : {}),
+ ...(mode ? { mode } : {}),
+ ...(years.length ? { years } : {}),
+ ...(topics.length ? { topics } : {}),
+ ...(scopes.length ? { scopes } : {}),
+ ...(municipalities.length ? { municipalities } : {}),
+ ...(durations.length ? { durations } : {}),
+ ...(sort ? { sort } : {}),
...(people.length > 0 ? { people } : {}),
}
}
-const recordingListSearchParams = (
+const recordingListStateToRawParams = (
state: RecordingListState,
page = state.page,
+): RawSearchParams => ({
+ [ACERVO_SOURCE_PARAM]: ACERVO_SOURCE_ENVIADAS,
+ page: String(page),
+ q: state.q,
+ mode: state.mode,
+ year: state.years?.map(String),
+ topic: state.topics,
+ scope: state.scopes,
+ municipality: state.municipalities?.map(String),
+ duration: state.durations,
+ sort: state.sort,
+ [ACERVO_PERSON_PARAM]: state.people,
+})
+
+/** Expects already-canonical state (from parse or a rule-preserving toggle). */
+const serializeCanonicalRecordingListSearchParams = (
+ canonicalState: RecordingListState,
): URLSearchParams => {
const params = new URLSearchParams()
// `source=enviadas` is always serialized — it is what selects the source.
params.set(ACERVO_SOURCE_PARAM, ACERVO_SOURCE_ENVIADAS)
- if (state.q) params.set('q', state.q)
- for (const person of state.people ?? []) params.append(ACERVO_PERSON_PARAM, person)
- if (page > 1) params.set('page', String(page))
+ if (canonicalState.q) params.set('q', canonicalState.q)
+ // `termo` is the default and never serialized; `tema` only makes sense with a
+ // query, so a theme param without `q` canonicalizes away.
+ if (canonicalState.mode === 'tema' && canonicalState.q) params.set('mode', 'tema')
+ for (const year of canonicalState.years ?? []) params.append('year', String(year))
+ for (const topic of canonicalState.topics ?? []) params.append('topic', topic)
+ for (const scope of canonicalState.scopes ?? []) params.append('scope', scope)
+ for (const municipality of canonicalState.municipalities ?? []) {
+ params.append('municipality', String(municipality))
+ }
+ for (const duration of canonicalState.durations ?? []) params.append('duration', duration)
+ // `recentes` is the default and never serialized.
+ if (canonicalState.sort && canonicalState.sort !== 'recentes') {
+ params.set('sort', canonicalState.sort)
+ }
+ for (const person of canonicalState.people ?? []) params.append(ACERVO_PERSON_PARAM, person)
+ if (canonicalState.page > 1) params.set('page', String(canonicalState.page))
return params
}
+const recordingListSearchParams = (state: RecordingListState, page = state.page): URLSearchParams =>
+ serializeCanonicalRecordingListSearchParams(
+ parseRecordingListParams(recordingListStateToRawParams(state, page)),
+ )
+
/** The URL of one "Pessoa" facet option with `person` toggled (page resets). */
export const toggleRecordingPerson = (
state: RecordingListState,
@@ -114,6 +245,47 @@ export const removeRecordingPerson = (
export const buildRecordingListHref = (state: RecordingListState, page: number): string =>
buildListHref(state, recordingListSearchParams, CAMPAIGN_COMMUNICATION_ACERVO, page)
+/**
+ * C219 — the canonical query drives the filter bar remount (`key`), exactly
+ * like `buildSpeechFiltersKey`, so optimistic state resets when the URL
+ * changes.
+ */
+export const buildRecordingFiltersKey = (state: RecordingListState): string =>
+ recordingListSearchParams(state).toString()
+
+/** Payload sort order of the list: the default keeps the stored `-createdAt`. */
+export const recordingSortOrder = (state: RecordingListState): string => {
+ switch (state.sort) {
+ case 'duracao_maior':
+ return '-durationSeconds'
+ case 'duracao_menor':
+ return 'durationSeconds'
+ default:
+ return '-createdAt'
+ }
+}
+
+/** Duration orders only make sense over rows with a measured duration. */
+export const recordingSortIsDuration = (state: RecordingListState): boolean =>
+ state.sort === 'duracao_maior' || state.sort === 'duracao_menor'
+
+/**
+ * C219 — whether the actor narrowed the list (query/mode or any facet). The
+ * empty state uses it to tell "no recording was ever sent" from "the filters
+ * hid everything"; pagination is not a filter.
+ */
+export const recordingHasActiveFilters = (state: RecordingListState): boolean =>
+ Boolean(
+ state.q ||
+ state.mode ||
+ state.years?.length ||
+ state.topics?.length ||
+ state.scopes?.length ||
+ state.municipalities?.length ||
+ state.durations?.length ||
+ state.people?.length,
+ )
+
/** Toggle hrefs of the source switcher (the Câmara side is the bare acervo). */
export const buildAcervoSourceHref = (source: AcervoSource): string =>
source === 'enviadas'
diff --git a/src/utilities/recordings/recordingOmnibox.ts b/src/utilities/recordings/recordingOmnibox.ts
new file mode 100644
index 00000000..363e9922
--- /dev/null
+++ b/src/utilities/recordings/recordingOmnibox.ts
@@ -0,0 +1,286 @@
+/**
+ * C219 — recordings acervo omnibox adapter. Pure / client-safe: builds the
+ * active chips, the suggestion seeds (facet constants plus server-loaded
+ * years/municipalities/people) and the toggle/remove/clear actions over the
+ * URL state, mirroring `speechOmnibox` on the same shared helpers. "Pessoa"
+ * reuses the case-insensitive dedupe owned by the recordings URL contract.
+ */
+import {
+ createOmniboxSuggestionSeed,
+ filterOmniboxSuggestionSeeds,
+ type CampaignListOmniboxChip,
+ type CampaignListOmniboxSuggestion,
+} from '@/lib/campaignListOmnibox'
+import {
+ SPEECH_SCOPES,
+ SPEECH_TOPICS,
+ type SpeechScope,
+ type SpeechTopic,
+} from '@/lib/speechFacets'
+import {
+ removeRecordingPerson,
+ toggleRecordingPerson,
+ type RecordingListState,
+} from '@/utilities/recordings/recordingListUrl'
+import {
+ SPEECH_DURATION_BUCKETS,
+ speechDurationLabels,
+ speechScopeLabels,
+ speechTopicLabels,
+ type SpeechDurationBucket,
+ type SpeechSearchMode,
+} from '@/utilities/speech/speechListUrl'
+
+export type RecordingFilterOption = {
+ value: string
+ label: string
+}
+
+const MUNICIPALITY_CHIP_LABEL = 'Município citado'
+
+export type RecordingOmniboxAction =
+ | { kind: 'url'; state: RecordingListState }
+ | { kind: 'clear'; state: RecordingListState }
+
+const chipLabel = (dimension: string, value: string): string => `${dimension}: ${value}`
+
+const withPageReset = (state: RecordingListState): RecordingListState => ({ ...state, page: 1 })
+
+const toggleValue = (values: T[] | undefined, value: T): T[] | undefined => {
+ const current = values ?? []
+ const next = current.includes(value)
+ ? current.filter((item) => item !== value)
+ : [...current, value]
+ return next.length ? next : undefined
+}
+
+const removeValue = (values: T[] | undefined, value: T): T[] | undefined => {
+ const next = (values ?? []).filter((item) => item !== value)
+ return next.length ? next : undefined
+}
+
+const chipPrefix = (chipId: string): { key: string; value: string } => {
+ const separator = chipId.indexOf(':')
+ if (separator === -1) return { key: chipId, value: '' }
+ return { key: chipId.slice(0, separator), value: chipId.slice(separator + 1) }
+}
+
+type FacetMutation = 'toggle' | 'remove'
+
+/**
+ * ONE facet mutation for both omnibox actions: `toggle` (selecting a
+ * suggestion) and `remove` (dropping a chip) differ only in the values
+ * operation. Returns null when the id carries an invalid numeric value.
+ */
+const mutateFacet = (
+ state: RecordingListState,
+ key: string,
+ value: string,
+ mode: FacetMutation,
+): RecordingListState | null => {
+ const mutate = mode === 'toggle' ? toggleValue : removeValue
+ switch (key) {
+ case 'year': {
+ const year = Number(value)
+ if (!Number.isSafeInteger(year)) return null
+ return { ...state, years: mutate(state.years, year) }
+ }
+ case 'topic':
+ return { ...state, topics: mutate(state.topics, value as SpeechTopic) }
+ case 'scope':
+ return { ...state, scopes: mutate(state.scopes, value as SpeechScope) }
+ case 'municipality': {
+ const municipality = Number(value)
+ if (!Number.isSafeInteger(municipality)) return null
+ return { ...state, municipalities: mutate(state.municipalities, municipality) }
+ }
+ case 'duration':
+ return { ...state, durations: mutate(state.durations, value as SpeechDurationBucket) }
+ default:
+ return null
+ }
+}
+
+export const buildRecordingOmniboxChips = ({
+ state,
+ municipalityLabelsById,
+}: {
+ state: RecordingListState
+ municipalityLabelsById: ReadonlyMap
+}): CampaignListOmniboxChip[] => {
+ const chips: CampaignListOmniboxChip[] = []
+
+ if (state.q) chips.push({ id: 'q', label: chipLabel('Busca', state.q) })
+ for (const year of state.years ?? []) {
+ chips.push({ id: `year:${year}`, label: chipLabel('Ano', String(year)) })
+ }
+ for (const topic of state.topics ?? []) {
+ chips.push({ id: `topic:${topic}`, label: chipLabel('Tema', speechTopicLabels[topic]) })
+ }
+ for (const scope of state.scopes ?? []) {
+ chips.push({ id: `scope:${scope}`, label: chipLabel('Alcance', speechScopeLabels[scope]) })
+ }
+ for (const municipality of state.municipalities ?? []) {
+ chips.push({
+ id: `municipality:${municipality}`,
+ label: chipLabel(
+ MUNICIPALITY_CHIP_LABEL,
+ municipalityLabelsById.get(municipality) ?? `Município #${municipality}`,
+ ),
+ })
+ }
+ for (const duration of state.durations ?? []) {
+ chips.push({
+ id: `duration:${duration}`,
+ label: chipLabel('Duração', speechDurationLabels[duration]),
+ })
+ }
+ for (const person of state.people ?? []) {
+ chips.push({ id: `person:${person}`, label: chipLabel('Pessoa', person) })
+ }
+
+ return chips
+}
+
+export const buildRecordingOmniboxSuggestionSeeds = ({
+ years,
+ municipalityOptions,
+ personOptions,
+}: {
+ years: readonly number[]
+ municipalityOptions: readonly RecordingFilterOption[]
+ personOptions: readonly string[]
+}) => {
+ const seeds = []
+
+ for (const { value, label } of SPEECH_TOPICS) {
+ seeds.push(
+ createOmniboxSuggestionSeed(
+ { id: `topic:${value}`, group: 'Tema', label, keywords: ['tema'] },
+ { emptyQueryVisible: true },
+ ),
+ )
+ }
+
+ for (const { value, label } of SPEECH_SCOPES) {
+ seeds.push(
+ createOmniboxSuggestionSeed(
+ { id: `scope:${value}`, group: 'Alcance', label, keywords: ['alcance'] },
+ { emptyQueryVisible: true },
+ ),
+ )
+ }
+
+ for (const { value, label } of SPEECH_DURATION_BUCKETS) {
+ seeds.push(
+ createOmniboxSuggestionSeed(
+ { id: `duration:${value}`, group: 'Duração', label, keywords: ['duracao', 'tempo'] },
+ { emptyQueryVisible: true },
+ ),
+ )
+ }
+
+ for (const year of years) {
+ seeds.push(
+ createOmniboxSuggestionSeed({
+ id: `year:${year}`,
+ group: 'Ano',
+ label: String(year),
+ keywords: ['ano'],
+ }),
+ )
+ }
+
+ for (const option of municipalityOptions) {
+ seeds.push(
+ createOmniboxSuggestionSeed({
+ id: `municipality:${option.value}`,
+ group: MUNICIPALITY_CHIP_LABEL,
+ label: option.label,
+ keywords: ['municipio', 'cidade', 'citado'],
+ }),
+ )
+ }
+
+ for (const person of personOptions) {
+ seeds.push(
+ createOmniboxSuggestionSeed({
+ id: `person:${person}`,
+ group: 'Pessoa',
+ label: person,
+ keywords: ['pessoa', 'falante'],
+ }),
+ )
+ }
+
+ return seeds
+}
+
+export const filterRecordingOmniboxSuggestions = (
+ seeds: ReturnType,
+ query: string,
+): CampaignListOmniboxSuggestion[] => filterOmniboxSuggestionSeeds(seeds, query)
+
+export const applyRecordingOmniboxSuggestion = ({
+ state,
+ suggestionId,
+}: {
+ state: RecordingListState
+ suggestionId: string
+}): RecordingOmniboxAction => {
+ if (suggestionId.startsWith('q:')) {
+ const q = suggestionId.slice(2).trim()
+ return { kind: 'url', state: withPageReset({ ...state, q: q || undefined }) }
+ }
+
+ const { key, value } = chipPrefix(suggestionId)
+ if (key === 'person') {
+ return { kind: 'url', state: toggleRecordingPerson(withPageReset(state), value) }
+ }
+
+ const next = mutateFacet(withPageReset(state), key, value, 'toggle')
+ return { kind: 'url', state: next ?? state }
+}
+
+export const removeRecordingOmniboxChip = ({
+ state,
+ chipId,
+}: {
+ state: RecordingListState
+ chipId: string
+}): RecordingOmniboxAction => {
+ // Dropping the query also drops the theme mode: a theme without a query has
+ // nothing to expand.
+ if (chipId === 'q') {
+ return { kind: 'url', state: withPageReset({ ...state, q: undefined, mode: undefined }) }
+ }
+
+ const { key, value } = chipPrefix(chipId)
+ if (key === 'person') {
+ return { kind: 'url', state: removeRecordingPerson(withPageReset(state), value) }
+ }
+
+ const next = mutateFacet(withPageReset(state), key, value, 'remove')
+ return { kind: 'url', state: next ?? state }
+}
+
+/**
+ * C219 — the search mode toggle. `tema` only sticks with a query; `termo`
+ * (the default) clears the param so the URL stays canonical and shareable.
+ */
+export const applyRecordingSearchMode = ({
+ state,
+ mode,
+}: {
+ state: RecordingListState
+ mode: SpeechSearchMode
+}): RecordingOmniboxAction => ({
+ kind: 'url',
+ state: withPageReset({ ...state, mode: mode === 'tema' && state.q ? 'tema' : undefined }),
+})
+
+/** Clearing keeps `source=enviadas` — it is what selects this source. */
+export const clearRecordingOmnibox = (_state: RecordingListState): RecordingOmniboxAction => ({
+ kind: 'clear',
+ state: { source: 'enviadas', page: 1 },
+})
diff --git a/src/utilities/recordings/recordingPageData.ts b/src/utilities/recordings/recordingPageData.ts
index e113cbfc..1f4c4803 100644
--- a/src/utilities/recordings/recordingPageData.ts
+++ b/src/utilities/recordings/recordingPageData.ts
@@ -2,15 +2,24 @@ import 'server-only'
import type { Payload } from 'payload'
+import { canReadCommunicationCatalog } from '@/lib/campaignRoles'
import { foldSpeakerName } from '@/lib/recordingDiarization'
import { RECORDING_NOT_FOUND_MESSAGE } from '@/lib/schemas/recording'
import { normalizeForSearch } from '@/lib/speechSearch'
import type { CampaignUser } from '@/payload-types'
+import {
+ expandRecordingSearchTheme,
+ type ThemeSearchExpansionResolver,
+} from '@/utilities/ai/expandSpeechSearchTheme'
+import { collapseListWhereOrBranches } from '@/utilities/campaignListUrl'
import { createEntityNotFoundError } from '@/utilities/entityNotFound'
+import { loadMunicipalityLabelsByIds } from '@/utilities/loadNamesByIds'
import { buildRecordingListWhere } from '@/utilities/recordings/recordingListFilters'
import {
recordingPageSize,
+ recordingSortOrder,
resolveRecordingListUrl,
+ type RecordingFilterOptions,
type RecordingListState,
} from '@/utilities/recordings/recordingListUrl'
import {
@@ -35,6 +44,8 @@ const recordingListSelect = {
recordedAt: true,
durationSeconds: true,
speakerNames: true,
+ // C219 — the card's topic chip; the facet itself is not displayed.
+ topics: true,
} as const
const recordingDetailSelect = {
@@ -63,17 +74,12 @@ const toSegmentRecord = (segment: {
speakerKey: segment.speakerKey ?? null,
})
-/** C200 — the options the "Pessoa" facet offers. */
-export type RecordingFilterOptions = {
- people: string[]
-}
-
/**
- * C200 — distinct labels across the recordings the actor can read: the facet
- * only ever lists what is reachable, and the derived `speakerNames` column is
- * the single source. Small acervo now; if the list grows past a few thousand
- * rows this becomes a `SELECT DISTINCT` (registered as a revisit trigger in the
- * impl plan).
+ * C200/C219 — distinct labels/years/cited municipalities across the
+ * recordings the actor can read: a facet only ever lists what is reachable,
+ * and the derived columns are the single source. Municipality labels resolve
+ * through the justified `loadMunicipalityLabelsByIds` bypass — the ids come
+ * from recordings the actor was already authorized to read.
*/
export const loadRecordingFilterOptions = async (
payload: Payload,
@@ -84,13 +90,15 @@ export const loadRecordingFilterOptions = async (
depth: 0,
limit: 0,
pagination: false,
- select: { speakerNames: true },
+ select: { speakerNames: true, year: true, mentionedMunicipalities: true },
user,
overrideAccess: false,
})
const people: string[] = []
const seen = new Set()
+ const years = new Set()
+ const municipalityIds = new Set()
for (const recording of result.docs) {
for (const name of recording.speakerNames ?? []) {
const trimmed = name.trim()
@@ -99,35 +107,56 @@ export const loadRecordingFilterOptions = async (
seen.add(folded)
people.push(trimmed)
}
+ if (typeof recording.year === 'number') years.add(recording.year)
+ for (const value of recording.mentionedMunicipalities ?? []) {
+ municipalityIds.add(typeof value === 'number' ? value : value.id)
+ }
}
- return { people: people.sort((left, right) => left.localeCompare(right, 'pt-BR')) }
+ const labels = await loadMunicipalityLabelsByIds(payload, [...municipalityIds])
+ const municipalities = [...municipalityIds]
+ .flatMap((id) => {
+ const entry = labels.get(id)
+ return entry ? [{ value: String(id), label: entry.name }] : []
+ })
+ .sort((left, right) => left.label.localeCompare(right.label, 'pt-BR'))
+
+ return {
+ people: people.sort((left, right) => left.localeCompare(right, 'pt-BR')),
+ years: [...years].sort((left, right) => right - left),
+ municipalities,
+ }
}
/**
* The excerpt segment of each listed recording: ONE matching segment per row
* (the search runs `LIKE` on the joined `recording.searchText`, so a page of
- * hour-long recordings never pays for all of its segments). The rows whose
- * query only matches across the junction of two segments fall back together in
- * a single batched query, so a result never renders without an excerpt.
+ * hour-long recordings never pays for all of its segments). C219 passes the
+ * literal query plus every expanded theme term, so a theme result still gets
+ * the passage that surfaced it. The rows whose query only matches across the
+ * junction of two segments fall back together in a single batched query, so a
+ * result never renders without an excerpt.
*/
const loadMatchedSegments = async (
payload: Payload,
user: CampaignUser,
recordingIds: readonly number[],
- q: string,
+ terms: readonly string[],
): Promise> => {
const byRecording = new Map()
- const normalized = normalizeForSearch(q)
- if (!normalized || recordingIds.length === 0) return byRecording
+ const normalizedTerms = [
+ ...new Set(terms.map((term) => normalizeForSearch(term)).filter((term) => term.length > 0)),
+ ]
+ const textBranch = collapseListWhereOrBranches(
+ normalizedTerms.map((term) => ({ searchText: { like: term } })),
+ )
+ if (!textBranch || recordingIds.length === 0) return byRecording
await Promise.all(
recordingIds.map(async (recordingId) => {
const match = await payload.find({
collection: 'recordingSegment',
- where: {
- and: [{ recording: { equals: recordingId } }, { searchText: { like: normalized } }],
- },
+ where: { and: [{ recording: { equals: recordingId } }, textBranch] },
depth: 0,
limit: 1,
pagination: false,
@@ -172,25 +201,44 @@ export type RecordingsPageData = {
redirectHref?: string
totalDocs: number
totalPages: number
+ /**
+ * C219 — true when the actor asked for `mode=tema` but the expansion
+ * mechanism was unavailable; the page shows the discreet fallback notice.
+ */
+ themeUnavailable: boolean
+ /** C219 — true when the expansion actually contributed terms. */
+ themeApplied: boolean
}
export const loadRecordingsPageData = async (
payload: Payload,
user: CampaignUser,
searchParams: Promise | RecordingListSearchParams,
+ expandTheme: ThemeSearchExpansionResolver = expandRecordingSearchTheme,
): Promise => {
const rawSearchParams = await searchParams
const canonicalUrl = resolveRecordingListUrl(rawSearchParams)
const state = canonicalUrl.state
+ // C219 — only expand for an actor who may read the catalog (the `find` below
+ // is still the final, fail-closed barrier) and only with a query.
+ const themeRequested = state.mode === 'tema' && Boolean(state.q)
+ let themeTerms: readonly string[] = []
+ let themeUnavailable = false
+ if (themeRequested && canReadCommunicationCatalog(user.role)) {
+ const expansion = await expandTheme(state.q ?? '')
+ if (expansion) themeTerms = expansion.terms
+ else themeUnavailable = true
+ }
+
const [result, filterOptions] = await Promise.all([
payload.find({
collection: 'recording',
depth: 0,
limit: recordingPageSize,
page: state.page,
- sort: '-createdAt',
- where: buildRecordingListWhere(state),
+ sort: recordingSortOrder(state),
+ where: buildRecordingListWhere(state, themeTerms),
select: recordingListSelect,
user,
overrideAccess: false,
@@ -200,12 +248,13 @@ export const loadRecordingsPageData = async (
const resolvedUrl = resolveRecordingListUrl(rawSearchParams, result.totalPages)
const recordings = result.docs
- const segmentsByRecording = state.q
+ const matchedTerms = [...(state.q ? [state.q] : []), ...themeTerms]
+ const segmentsByRecording = matchedTerms.length
? await loadMatchedSegments(
payload,
user,
recordings.map((recording) => recording.id),
- state.q,
+ matchedTerms,
)
: new Map()
@@ -215,6 +264,7 @@ export const loadRecordingsPageData = async (
recording,
matchedSegments: segmentsByRecording.get(recording.id) ?? [],
query: state.q,
+ themeTerms,
people: state.people,
}),
),
@@ -223,6 +273,8 @@ export const loadRecordingsPageData = async (
redirectHref: resolvedUrl.redirectHref ?? canonicalUrl.redirectHref,
totalDocs: result.totalDocs,
totalPages: result.totalPages,
+ themeUnavailable,
+ themeApplied: themeTerms.length > 0,
}
}
diff --git a/src/utilities/recordings/recordingViewModels.ts b/src/utilities/recordings/recordingViewModels.ts
index 2489c6b2..0053fc91 100644
--- a/src/utilities/recordings/recordingViewModels.ts
+++ b/src/utilities/recordings/recordingViewModels.ts
@@ -11,6 +11,7 @@ import {
} from '@/lib/recording'
import { recordingSpeakerDefaultLabel, speakerNameMatches } from '@/lib/recordingDiarization'
import { formatSpeechClock } from '@/lib/speechClock'
+import type { SpeechTopic } from '@/lib/speechFacets'
import {
buildHighlightedExcerpt,
pickMatchingSegment,
@@ -18,6 +19,7 @@ import {
type SpeechHighlightedExcerpt,
type SpeechHighlightPart,
} from '@/lib/speechHighlight'
+import { speechTopicLabels } from '@/utilities/speech/speechListUrl'
/** The segment shape the recording detail transcript renders. */
export type RecordingSegmentRecord = {
@@ -40,6 +42,8 @@ type RecordingBaseRecord = {
export type RecordingListRecord = RecordingBaseRecord & {
/** C200 — derived distinct labels; drives the card chip under a "Pessoa" filter. */
speakerNames?: string[] | null
+ /** C219 — classified topics; the card shows them as chips. */
+ topics?: SpeechTopic[] | null
}
export type RecordingDetailRecord = RecordingBaseRecord & {
@@ -55,6 +59,8 @@ export type RecordingListItemViewModel = RecordingViewModel & {
excerpt: SpeechHighlightedExcerpt | null
/** Selected "Pessoa" labels that this recording indeed contains. */
matchedPersons: string[]
+ /** C219 — classified topics with their pt-BR labels (card chips). */
+ topics: { value: SpeechTopic; label: string }[]
/**
* Detail link that seeks the player to the matching segment when the search
* found one (`?t=`), carrying the term for transcript highlighting (`?q=`).
@@ -148,6 +154,24 @@ const withSeek = (href: string, segment: RecordingSegmentRecord | undefined, que
return queryString ? `${href}?${queryString}` : href
}
+/**
+ * C219 — the first expanded theme term that actually surfaced this recording:
+ * the passage that carries it, preferred for the excerpt so a theme result
+ * shows why it appeared. Returns undefined when no theme term applies.
+ */
+const pickThemeSegment = (
+ segments: readonly RecordingSegmentRecord[],
+ themeTerms: readonly string[],
+): { term: string; segment: RecordingSegmentRecord } | undefined => {
+ for (const term of themeTerms) {
+ const trimmed = term.trim()
+ if (!trimmed) continue
+ const segment = pickMatchingSegment(segments, trimmed)
+ if (segment) return { term: trimmed, segment }
+ }
+ return undefined
+}
+
/**
* List item of one recording. The excerpt only exists for a `ready` row and a
* search term; the status cards of the other three states carry their own copy
@@ -157,20 +181,31 @@ export const toRecordingListItemViewModel = ({
recording,
matchedSegments,
query,
+ themeTerms = [],
people,
}: {
recording: RecordingListRecord
/** Segments that matched the query (or the row's first one as fallback). */
matchedSegments: readonly RecordingSegmentRecord[]
query?: string
+ /** C219 — expanded theme terms; empty in the literal search. */
+ themeTerms?: readonly string[]
/** C200 — the selected "Pessoa" labels of the list state. */
people?: readonly string[]
}): RecordingListItemViewModel => {
const base = toRecordingViewModel(recording)
const isReady = base.status === 'ready'
const q = query?.trim()
- const segment = isReady && q ? pickMatchingSegment(matchedSegments, q) : undefined
- const excerpt = segment ? buildHighlightedExcerpt(segment.text, q ?? '') : null
+ const themeMatch = isReady ? pickThemeSegment(matchedSegments, themeTerms) : undefined
+ const segment =
+ themeMatch?.segment ?? (isReady && q ? pickMatchingSegment(matchedSegments, q) : undefined)
+ // The theme passage highlights the whole phrase as one band (the per-term
+ // split would break it into pieces), mirroring the speech acervo (C192).
+ const excerpt = themeMatch
+ ? buildHighlightedExcerpt(themeMatch.segment.text, themeMatch.term, { phrase: true })
+ : segment
+ ? buildHighlightedExcerpt(segment.text, q ?? '')
+ : null
const speakerNames = recording.speakerNames ?? []
return {
@@ -179,6 +214,7 @@ export const toRecordingListItemViewModel = ({
matchedPersons: (people ?? []).filter((person) =>
speakerNames.some((name) => speakerNameMatches(name, person)),
),
+ topics: (recording.topics ?? []).map((value) => ({ value, label: speechTopicLabels[value] })),
watchHref: withSeek(base.detailHref, segment, q),
}
}
diff --git a/src/utilities/speech/speechListFilters.ts b/src/utilities/speech/speechListFilters.ts
index 6a5c0ff2..3d21ea84 100644
--- a/src/utilities/speech/speechListFilters.ts
+++ b/src/utilities/speech/speechListFilters.ts
@@ -13,7 +13,11 @@ import type { SpeechDurationBucket, SpeechListState } from '@/utilities/speech/s
const DURATION_MEDIA_MIN_SECONDS = 120
const DURATION_LONGA_MIN_SECONDS = 300
-const durationBucketWhere = (bucket: SpeechDurationBucket): Where => {
+/**
+ * The ONE duration-bucket predicate of the acervo: the recordings list (C219)
+ * reuses it so the buckets can never diverge between the two sources.
+ */
+export const durationBucketWhere = (bucket: SpeechDurationBucket): Where => {
switch (bucket) {
case 'curta':
return { durationSeconds: { less_than: DURATION_MEDIA_MIN_SECONDS } }
diff --git a/src/utilities/speech/speechListUrl.ts b/src/utilities/speech/speechListUrl.ts
index 46defaf8..c7756cd0 100644
--- a/src/utilities/speech/speechListUrl.ts
+++ b/src/utilities/speech/speechListUrl.ts
@@ -19,6 +19,8 @@ import {
firstValue,
normalizedText,
parseExhaustiveEnumParam,
+ parseMunicipalityValues,
+ parseYearValues,
resolveListUrl,
strictDecimalInteger,
type RawSearchParams,
@@ -95,16 +97,6 @@ const speechScopeSet = new Set(SPEECH_SCOPES.map(({ value }) => value))
const speechDurationSet = new Set(SPEECH_DURATION_BUCKETS.map(({ value }) => value))
const MAX_PHASE_LENGTH = 80
-const parseYearValues = (raw: string | string[] | undefined): number[] =>
- allParamValues(raw)
- .map((token) => strictDecimalInteger(token))
- .filter((year): year is number => year !== undefined && year >= 1900 && year <= 2100)
-
-const parseMunicipalityValues = (raw: string | string[] | undefined): number[] =>
- allParamValues(raw)
- .map((token) => strictDecimalInteger(token))
- .filter((id): id is number => id !== undefined && id > 0)
-
/** Only `tema` is meaningful; anything else (and `termo`) means the default. */
const parseSpeechSearchMode = (raw: string | string[] | undefined): SpeechSearchMode | undefined =>
firstValue(raw) === 'tema' ? 'tema' : undefined
diff --git a/tests/e2e/campaignSpeechAcervo.e2e.spec.ts b/tests/e2e/campaignSpeechAcervo.e2e.spec.ts
index 2b92ec14..ccb90685 100644
--- a/tests/e2e/campaignSpeechAcervo.e2e.spec.ts
+++ b/tests/e2e/campaignSpeechAcervo.e2e.spec.ts
@@ -534,6 +534,13 @@ test.describe('communication vertical (C154/C162)', () => {
speakerKey?: string | null
}[]
speakerLabels?: { speakerKey: string; label: string }[]
+ /** C219 — parity facets. */
+ recordedAt?: string
+ durationSeconds?: number
+ topics?: SpeechTopic[]
+ scopes?: SpeechScope[]
+ classifiedBy?: 'gazetteer' | 'llm' | 'manual'
+ mentionedMunicipalities?: number[]
},
) => {
const bytes = Buffer.from(`recording-${input.marker}`)
@@ -552,9 +559,18 @@ test.describe('communication vertical (C154/C162)', () => {
data: {
title: `Gravação ${input.marker}`,
status: input.status ?? 'ready',
- recordedAt: '2026-09-01T00:00:00.000Z',
+ recordedAt: input.recordedAt ?? '2026-09-01T00:00:00.000Z',
media: media.id,
...(input.speakerLabels ? { speakerLabels: input.speakerLabels } : {}),
+ ...(input.durationSeconds !== undefined
+ ? { durationSeconds: input.durationSeconds }
+ : {}),
+ ...(input.topics ? { topics: input.topics } : {}),
+ ...(input.scopes ? { scopes: input.scopes } : {}),
+ ...(input.classifiedBy ? { classifiedBy: input.classifiedBy } : {}),
+ ...(input.mentionedMunicipalities
+ ? { mentionedMunicipalities: input.mentionedMunicipalities }
+ : {}),
},
depth: 0,
})
@@ -806,6 +822,135 @@ test.describe('communication vertical (C154/C162)', () => {
expect(html).not.toContain(`/campanha/comunicacao/acervo/gravacoes/${other.id}`)
})
+ test('the parity facets narrow, order by duration and render the filter bar (C219)', async ({
+ campaign,
+ campaignRequest,
+ }) => {
+ const marker = campaign.fixtures.value('gravacaofacetas')
+ const otherMarker = `${marker}b`
+ const municipality = await campaign.fixtures.claimMunicipality()
+
+ const { recording: health } = await createRecording(campaign, {
+ marker,
+ recordedAt: '2025-04-02T00:00:00.000Z',
+ durationSeconds: 90,
+ topics: ['saude'],
+ scopes: ['bahia'],
+ classifiedBy: 'llm',
+ mentionedMunicipalities: [municipality.id],
+ segments: [
+ { startSeconds: 12, endSeconds: 20, text: `A plenária discutiu a saúde ${marker}.` },
+ ],
+ })
+ const { recording: culture } = await createRecording(campaign, {
+ marker: otherMarker,
+ recordedAt: '2023-08-02T00:00:00.000Z',
+ durationSeconds: 400,
+ topics: ['cultura'],
+ segments: [
+ {
+ startSeconds: 12,
+ endSeconds: 20,
+ text: `A plenária discutiu a cultura ${otherMarker}.`,
+ },
+ ],
+ })
+ const { recording: noDuration } = await createRecording(campaign, {
+ marker: `${marker}c`,
+ segments: [{ startSeconds: 12, endSeconds: 20, text: `Sem duração ${marker}.` }],
+ })
+
+ const user = await campaign.fixtures.createCampaignUser('communicator')
+ const request = await campaignRequest(user, user.password)
+
+ // The bar renders the Câmara-parity facets, the mode selector and the sort.
+ const bar = rendered(
+ await (
+ await request.get(`/campanha/comunicacao/acervo?source=enviadas&q=${marker}`)
+ ).text(),
+ )
+ for (const label of ['Ano', 'Tema', 'Alcance', 'Município citado', 'Duração', 'Pessoa']) {
+ expect(bar).toContain(label)
+ }
+ expect(bar).toContain('Termo exato')
+ expect(bar).toContain('Por tema')
+ expect(bar).toContain('Ordenar por')
+ expect(bar).toContain('Mais recentes')
+
+ // Year + topic + cited municipality + duration narrow to the health row.
+ // The params ride in the canonical order: a hand-built URL out of order
+ // canonicalizes through a redirect the HTTP request helper does not follow.
+ const narrowed = rendered(
+ await (
+ await request.get(
+ `/campanha/comunicacao/acervo?source=enviadas&q=${marker}` +
+ `&year=2025&topic=saude&municipality=${municipality.id}&duration=curta`,
+ )
+ ).text(),
+ )
+ expect(narrowed).toContain(`/gravacoes/${health.id}?`)
+ expect(narrowed).not.toContain(`/gravacoes/${culture.id}?`)
+ expect(narrowed).not.toContain(`/gravacoes/${noDuration.id}?`)
+
+ // A contradictory combination is an honest empty state with the clear CTA.
+ const empty = rendered(
+ await (
+ await request.get(
+ `/campanha/comunicacao/acervo?source=enviadas&q=${marker}&year=2023&topic=saude`,
+ )
+ ).text(),
+ )
+ expect(empty).toContain('Nenhuma gravação encontrada')
+ expect(empty).toContain('Limpar filtros')
+
+ // Duration orders list the measured rows only, longest first.
+ const longestFirst = rendered(
+ await (
+ await request.get(
+ `/campanha/comunicacao/acervo?source=enviadas&q=${marker}&sort=duracao_maior`,
+ )
+ ).text(),
+ )
+ const cultureAt = longestFirst.indexOf(`/gravacoes/${culture.id}?`)
+ const healthAt = longestFirst.indexOf(`/gravacoes/${health.id}?`)
+ expect(cultureAt).toBeGreaterThan(-1)
+ expect(healthAt).toBeGreaterThan(cultureAt)
+ expect(longestFirst).not.toContain(`/gravacoes/${noDuration.id}?`)
+ expect(longestFirst).toContain('Gravações sem duração aparecem apenas em Mais recentes.')
+ })
+
+ test('theme mode degrades honestly on the recordings source too (C219)', async ({
+ campaign,
+ campaignRequest,
+ }) => {
+ const marker = campaign.fixtures.value('gravacaotemadeg')
+ await createRecording(campaign, { marker })
+
+ const user = await campaign.fixtures.createCampaignUser('communicator')
+ const request = await campaignRequest(user, user.password)
+
+ // The e2e environment blanks DEEPSEEK_API_KEY (playwright.config.ts), so
+ // the expansion is unavailable and the page must fall back with the notice.
+ const themed = await request.get(
+ `/campanha/comunicacao/acervo?source=enviadas&q=${marker}&mode=tema`,
+ )
+ expect(themed.status()).toBe(200)
+ const themedHtml = rendered(await themed.text())
+ expect(themedHtml).toContain('data-testid="recording-theme-fallback"')
+ expect(themedHtml).toContain('A busca por tema está indisponível agora.')
+ expect(themedHtml).toContain('Resultados por termo exato')
+ expect(themedHtml).toContain('Tentar por tema novamente')
+ expect(themedHtml).toContain(marker)
+ expect(themedHtml).toContain(' {
const media = withMedia ? await createMedia(`${title}.mp4`) : null
const recording = await payload.create({
@@ -120,6 +134,12 @@ const createRecording = async ({
status,
...(media ? { media: media.id } : {}),
...(speakerLabels ? { speakerLabels } : {}),
+ ...(recordedAt ? { recordedAt } : {}),
+ ...(durationSeconds !== undefined ? { durationSeconds } : {}),
+ ...(topics ? { topics } : {}),
+ ...(scopes ? { scopes } : {}),
+ ...(classifiedBy ? { classifiedBy } : {}),
+ ...(mentionedMunicipalities ? { mentionedMunicipalities } : {}),
},
overrideAccess: true,
})
@@ -431,6 +451,201 @@ describe('uploaded recordings (C199)', () => {
expect(segments.docs[0]?.searchText).toBe('bom dia a todas')
})
+ it('classifies the transcript with the injected classifier and derives the year', async () => {
+ const fixtures = campaignFixtures()
+ const municipality = await fixtures.getMunicipality()
+ const catalogEntry = getMunicipalityCatalogEntry(municipality.slug)
+ expect(catalogEntry).toBeDefined()
+
+ const { recording } = await createRecording({
+ status: 'processing',
+ title: 'Plenária sobre saúde',
+ })
+ await payload.update({
+ collection: 'recording',
+ id: recording.id,
+ data: { recordedAt: '2024-03-10T12:00:00.000Z' },
+ overrideAccess: true,
+ })
+
+ const restore = withEnv('FFMPEG_PATH', FAKE_FFMPEG)
+ try {
+ await runRecordingJob(
+ payload,
+ recording.id,
+ async () => ({
+ ok: true,
+ segments: [{ start: 1, end: 4, text: 'Falamos sobre a saúde no município' }],
+ durationSeconds: 120,
+ }),
+ null,
+ async (input) => {
+ expect(input.transcript).toContain('saúde no município')
+ return {
+ facets: {
+ topics: ['saude'],
+ scopes: ['bahia'],
+ municipalities: [catalogEntry!],
+ people: [],
+ programs: [],
+ projects: [],
+ classifiedBy: 'llm',
+ },
+ llm: { used: true, totalTokens: 42, estimatedCostUsd: 0.001, error: null },
+ }
+ },
+ )
+ } finally {
+ restore()
+ }
+
+ const updated = await payload.findByID({
+ collection: 'recording',
+ id: recording.id,
+ depth: 0,
+ overrideAccess: true,
+ })
+ expect(updated.status).toBe('ready')
+ expect(updated.year).toBe(2024)
+ expect(updated.topics).toEqual(['saude'])
+ expect(updated.scopes).toEqual(['bahia'])
+ expect(updated.classifiedBy).toBe('llm')
+ expect(updated.mentionedMunicipalities).toEqual([municipality.id])
+ })
+
+ it('never overwrites a manual facet curation with the job result', async () => {
+ const { recording } = await createRecording({
+ status: 'processing',
+ title: 'Curadoria manual',
+ })
+ await payload.update({
+ collection: 'recording',
+ id: recording.id,
+ data: { topics: ['cultura'], scopes: ['brasil'], classifiedBy: 'manual' },
+ overrideAccess: true,
+ })
+
+ const restore = withEnv('FFMPEG_PATH', FAKE_FFMPEG)
+ try {
+ await runRecordingJob(
+ payload,
+ recording.id,
+ async () => ({
+ ok: true,
+ segments: [{ start: 1, end: 4, text: 'Falamos sobre saúde' }],
+ durationSeconds: 120,
+ }),
+ null,
+ async () => ({
+ facets: {
+ topics: ['saude'],
+ scopes: ['bahia'],
+ municipalities: [],
+ people: [],
+ programs: [],
+ projects: [],
+ classifiedBy: 'llm',
+ },
+ llm: { used: true, totalTokens: 10, estimatedCostUsd: 0, error: null },
+ }),
+ )
+ } finally {
+ restore()
+ }
+
+ const updated = await payload.findByID({
+ collection: 'recording',
+ id: recording.id,
+ depth: 0,
+ overrideAccess: true,
+ })
+ expect(updated.status).toBe('ready')
+ expect(updated.topics).toEqual(['cultura'])
+ expect(updated.scopes).toEqual(['brasil'])
+ expect(updated.classifiedBy).toBe('manual')
+ })
+
+ it('lets an authenticated actor overwrite a manual curation (the escape hatch)', async () => {
+ const { recording } = await createRecording({
+ status: 'ready',
+ title: 'Curadoria corrigida no admin',
+ topics: ['cultura'],
+ scopes: ['brasil'],
+ classifiedBy: 'manual',
+ })
+
+ const updated = await payload.update({
+ collection: 'recording',
+ id: recording.id,
+ data: { topics: ['saude'], scopes: ['bahia'], classifiedBy: 'llm' },
+ user: communicator,
+ overrideAccess: false,
+ })
+
+ expect(updated.topics).toEqual(['saude'])
+ expect(updated.scopes).toEqual(['bahia'])
+ expect(updated.classifiedBy).toBe('llm')
+ })
+
+ it('keeps the transcript and claims no provenance when the classifier throws', async () => {
+ const { recording } = await createRecording({
+ status: 'processing',
+ title: 'Classificador fora do ar',
+ })
+
+ const restore = withEnv('FFMPEG_PATH', FAKE_FFMPEG)
+ try {
+ await runRecordingJob(
+ payload,
+ recording.id,
+ async () => ({
+ ok: true,
+ segments: [{ start: 1, end: 4, text: 'Bom dia a todas' }],
+ durationSeconds: 120,
+ }),
+ null,
+ async () => {
+ throw new Error('classificador fora do ar')
+ },
+ )
+ } finally {
+ restore()
+ }
+
+ const updated = await payload.findByID({
+ collection: 'recording',
+ id: recording.id,
+ depth: 0,
+ overrideAccess: true,
+ })
+ expect(updated.status).toBe('ready')
+ // The fake ffmpeg emits two chunks and the injected transcriber repeats the
+ // answer for both, exactly like the end-to-end job test above.
+ expect(updated.searchText).toBe('bom dia a todas bom dia a todas')
+ expect(updated.classifiedBy).toBeNull()
+ expect(updated.topics ?? []).toEqual([])
+ })
+
+ it('resolves the gazetteer municipality without the LLM key (degraded provenance)', async () => {
+ const fixtures = campaignFixtures()
+ const municipality = await fixtures.getMunicipality()
+ const catalogEntry = getMunicipalityCatalogEntry(municipality.slug)
+ expect(catalogEntry).toBeDefined()
+
+ const restore = withEnv('DEEPINFRA_API_KEY', undefined)
+ try {
+ const classification = await classifyRecordingFacets({
+ payload,
+ transcript: `Falamos em ${catalogEntry!.city} sobre saúde e educação`,
+ })
+ expect(classification?.classifiedBy).toBe('gazetteer')
+ expect(classification?.topics).toEqual(expect.arrayContaining(['saude', 'educacao']))
+ expect(classification?.mentionedMunicipalities).toContain(municipality.id)
+ } finally {
+ restore()
+ }
+ })
+
it('marks a provider failure as failed, preserves the file and retries', async () => {
const { recording } = await createRecording({ status: 'processing', title: 'Debate' })
@@ -604,6 +819,123 @@ describe('uploaded recordings (C199)', () => {
expect(options.people).toContain(`Dep. ${marker}`)
})
+ it('filters by the C219 facets and lists their options', async () => {
+ const fixtures = campaignFixtures()
+ const municipality = await fixtures.getMunicipality()
+ const marker = `facetas${Date.now().toString(36)}`
+
+ const { recording: health } = await createRecording({
+ title: `Plenária de saúde ${marker}`,
+ recordedAt: '2025-05-04T10:00:00.000Z',
+ durationSeconds: 90,
+ topics: ['saude'],
+ scopes: ['bahia'],
+ classifiedBy: 'llm',
+ mentionedMunicipalities: [municipality.id],
+ segments: [{ startSeconds: 0, endSeconds: 5, text: `Saúde em pauta ${marker}` }],
+ })
+ const { recording: culture } = await createRecording({
+ title: `Debate de cultura ${marker}`,
+ recordedAt: '2023-01-01T10:00:00.000Z',
+ durationSeconds: 400,
+ topics: ['cultura'],
+ segments: [{ startSeconds: 0, endSeconds: 5, text: `Cultura em pauta ${marker}` }],
+ })
+ const { recording: noDuration } = await createRecording({
+ title: `Material sem duração ${marker}`,
+ segments: [{ startSeconds: 0, endSeconds: 5, text: `Ainda processando ${marker}` }],
+ })
+
+ const load = (extra: Record) =>
+ loadRecordingsPageData(payload, communicator, {
+ source: 'enviadas',
+ q: marker,
+ ...extra,
+ })
+
+ expect((await load({ year: '2025' })).rows.map((row) => row.id)).toEqual([health.id])
+ expect((await load({ topic: 'saude' })).rows.map((row) => row.id)).toEqual([health.id])
+ expect((await load({ scope: 'bahia' })).rows.map((row) => row.id)).toEqual([health.id])
+ expect(
+ (await load({ municipality: String(municipality.id) })).rows.map((row) => row.id),
+ ).toEqual([health.id])
+ expect((await load({ duration: 'curta' })).rows.map((row) => row.id)).toEqual([health.id])
+ expect((await load({ duration: 'longa' })).rows.map((row) => row.id)).toEqual([culture.id])
+ expect((await load({ duration: 'sem_duracao' })).rows.map((row) => row.id)).toEqual([
+ noDuration.id,
+ ])
+
+ const options = await loadRecordingFilterOptions(payload, communicator)
+ expect(options.years).toContain(2025)
+ expect(options.municipalities.map((option) => option.value)).toContain(String(municipality.id))
+ })
+
+ it('orders by duration only over rows with a measured duration', async () => {
+ const marker = `ordem${Date.now().toString(36)}`
+ const { recording: short } = await createRecording({
+ title: `Curta ${marker}`,
+ durationSeconds: 60,
+ segments: [{ startSeconds: 0, endSeconds: 5, text: `Trecho ${marker}` }],
+ })
+ const { recording: long } = await createRecording({
+ title: `Longa ${marker}`,
+ durationSeconds: 900,
+ segments: [{ startSeconds: 0, endSeconds: 5, text: `Trecho ${marker}` }],
+ })
+ await createRecording({
+ title: `Sem duração ${marker}`,
+ segments: [{ startSeconds: 0, endSeconds: 5, text: `Trecho ${marker}` }],
+ })
+
+ const load = (sort?: string) =>
+ loadRecordingsPageData(payload, communicator, {
+ source: 'enviadas',
+ q: marker,
+ ...(sort ? { sort } : {}),
+ })
+
+ expect((await load('duracao_maior')).rows.map((row) => row.id)).toEqual([long.id, short.id])
+ expect((await load('duracao_menor')).rows.map((row) => row.id)).toEqual([short.id, long.id])
+ // The default order keeps every row (the gate only applies to duration orders).
+ expect((await load()).rows.length).toBe(3)
+ })
+
+ it('searches by theme with the injected expansion and degrades honestly', async () => {
+ const marker = `tema${Date.now().toString(36)}`
+ const { recording } = await createRecording({
+ title: `Merenda ${marker}`,
+ segments: [
+ { startSeconds: 0, endSeconds: 6, text: `Falamos de alimentação escolar ${marker}.` },
+ ],
+ })
+
+ const expanded = await loadRecordingsPageData(
+ payload,
+ communicator,
+ { source: 'enviadas', q: 'merenda escolar', mode: 'tema' },
+ async (theme) => {
+ expect(theme).toBe('merenda escolar')
+ return { terms: ['alimentacao escolar'] }
+ },
+ )
+ expect(expanded.themeApplied).toBe(true)
+ expect(expanded.themeUnavailable).toBe(false)
+ const row = expanded.rows.find((item) => item.id === recording.id)
+ expect(row).toBeDefined()
+ expect(row?.excerpt?.parts.some((part) => part.highlighted)).toBe(true)
+
+ const degraded = await loadRecordingsPageData(
+ payload,
+ communicator,
+ { source: 'enviadas', q: 'merenda escolar', mode: 'tema' },
+ async () => null,
+ )
+ expect(degraded.themeApplied).toBe(false)
+ expect(degraded.themeUnavailable).toBe(true)
+ // Honest fallback: the literal phrase does not occur, so the row is out.
+ expect(degraded.rows.map((item) => item.id)).not.toContain(recording.id)
+ })
+
it('labels one cluster through the action and rebuilds the facet names', async () => {
const marker = `falante${Date.now().toString(36)}`
const { recording } = await createRecording({
diff --git a/tests/unit/e2eAffectedManifest.unit.spec.ts b/tests/unit/e2eAffectedManifest.unit.spec.ts
index 1de16b35..9c8be258 100644
--- a/tests/unit/e2eAffectedManifest.unit.spec.ts
+++ b/tests/unit/e2eAffectedManifest.unit.spec.ts
@@ -75,6 +75,10 @@ describe('E2E_AFFECTED_MANIFEST (OPS5)', () => {
// route and the vote share sheet are new contracts over the C211
// collection (curated only).
'frontendConteudos',
+ // C219 — deliberate: the recordings acervo gained its own search/facet
+ // contract and the migration makes every PR of this delivery high-risk
+ // (curated only).
+ 'campaignSpeechAcervo',
])
const onDisk = new Set(specNamesOnDisk())
for (const spec of E2E_CURATED_SPECS) {
diff --git a/tests/unit/expandSpeechSearchTheme.unit.spec.ts b/tests/unit/expandSpeechSearchTheme.unit.spec.ts
index 95193d58..f083ec2e 100644
--- a/tests/unit/expandSpeechSearchTheme.unit.spec.ts
+++ b/tests/unit/expandSpeechSearchTheme.unit.spec.ts
@@ -12,6 +12,7 @@ vi.mock('@ai-sdk/deepseek', () => ({ deepSeek: deepSeekMock }))
import {
expandContentPieceSearchTheme,
+ expandRecordingSearchTheme,
expandSearchTheme,
expandSpeechSearchTheme,
} from '@/utilities/ai/expandSpeechSearchTheme'
@@ -98,4 +99,15 @@ describe('expandSearchTheme (S28 — corpus)', () => {
await expect(expandSearchTheme('defesa do SUS', 'contentPiece')).resolves.toBeNull()
expect(generateObjectMock).toHaveBeenCalledTimes(1)
})
+
+ it('uses the recordings prompt for the enviadas corpus (C219)', async () => {
+ generateObjectMock.mockResolvedValue({ object: { terms: ['merenda escolar'] } })
+
+ await expandRecordingSearchTheme('merenda')
+
+ const call = generateObjectMock.mock.calls[0]![0] as { system: string }
+ expect(call.system).toContain('gravações enviadas pela equipe')
+ expect(call.system).not.toContain('acervo de discursos')
+ expect(call.system).not.toContain('Central de Conteúdos')
+ })
})
diff --git a/tests/unit/recordingListFilters.unit.spec.ts b/tests/unit/recordingListFilters.unit.spec.ts
index 7dd2d923..e4653609 100644
--- a/tests/unit/recordingListFilters.unit.spec.ts
+++ b/tests/unit/recordingListFilters.unit.spec.ts
@@ -41,4 +41,80 @@ describe('recording list filters (C199/C200)', () => {
],
})
})
+
+ it('ANDs the C219 facets (year, topic, scope, cited municipality)', () => {
+ expect(
+ buildRecordingListWhere({
+ source: 'enviadas',
+ page: 1,
+ years: [2026],
+ topics: ['saude'],
+ scopes: ['bahia'],
+ municipalities: [42],
+ }),
+ ).toEqual({
+ and: [
+ { year: { in: [2026] } },
+ { topics: { in: ['saude'] } },
+ { scopes: { in: ['bahia'] } },
+ { mentionedMunicipalities: { in: [42] } },
+ ],
+ })
+ })
+
+ it('maps each duration bucket to the shared Câmara predicate', () => {
+ expect(buildRecordingListWhere({ source: 'enviadas', page: 1, durations: ['curta'] })).toEqual({
+ durationSeconds: { less_than: 120 },
+ })
+ expect(buildRecordingListWhere({ source: 'enviadas', page: 1, durations: ['media'] })).toEqual({
+ durationSeconds: { greater_than_equal: 120, less_than: 300 },
+ })
+ expect(buildRecordingListWhere({ source: 'enviadas', page: 1, durations: ['longa'] })).toEqual({
+ durationSeconds: { greater_than_equal: 300 },
+ })
+ expect(
+ buildRecordingListWhere({ source: 'enviadas', page: 1, durations: ['sem_duracao'] }),
+ ).toEqual({ durationSeconds: { exists: false } })
+
+ // Two buckets OR together inside the AND.
+ expect(
+ buildRecordingListWhere({ source: 'enviadas', page: 1, durations: ['curta', 'longa'] }),
+ ).toEqual({
+ or: [
+ { durationSeconds: { less_than: 120 } },
+ { durationSeconds: { greater_than_equal: 300 } },
+ ],
+ })
+ })
+
+ it('ORs the literal query with the expanded theme terms, deduped', () => {
+ expect(
+ buildRecordingListWhere({ source: 'enviadas', page: 1, q: 'saúde' }, [
+ 'acesso universal à saúde',
+ 'saúde',
+ ]),
+ ).toEqual({
+ or: [{ searchText: { like: 'saude' } }, { searchText: { like: 'acesso universal a saude' } }],
+ })
+ })
+
+ it('gates rows without a measured duration out of the duration orders', () => {
+ expect(buildRecordingListWhere({ source: 'enviadas', page: 1, sort: 'duracao_maior' })).toEqual(
+ { durationSeconds: { exists: true } },
+ )
+
+ expect(
+ buildRecordingListWhere({
+ source: 'enviadas',
+ page: 1,
+ sort: 'duracao_menor',
+ q: 'merenda',
+ }),
+ ).toEqual({
+ and: [{ durationSeconds: { exists: true } }, { searchText: { like: 'merenda' } }],
+ })
+
+ // The default order carries no gate.
+ expect(buildRecordingListWhere({ source: 'enviadas', page: 1 })).toEqual({})
+ })
})
diff --git a/tests/unit/recordingListUrl.unit.spec.ts b/tests/unit/recordingListUrl.unit.spec.ts
index 353136bd..224a7036 100644
--- a/tests/unit/recordingListUrl.unit.spec.ts
+++ b/tests/unit/recordingListUrl.unit.spec.ts
@@ -2,16 +2,22 @@
import { describe, expect, it } from 'vitest'
+import { SPEECH_TOPICS } from '@/lib/speechFacets'
import {
buildAcervoSourceHref,
+ buildRecordingFiltersKey,
buildRecordingListHref,
parseAcervoSource,
parseRecordingListParams,
parseRecordingPeople,
+ recordingHasActiveFilters,
+ recordingSortIsDuration,
+ recordingSortOrder,
removeRecordingPerson,
resolveRecordingListUrl,
toggleRecordingPerson,
} from '@/utilities/recordings/recordingListUrl'
+import { SPEECH_DURATION_BUCKETS } from '@/utilities/speech/speechListUrl'
describe('recording list URL (C199)', () => {
it('detects the enviadas source and defaults everything else to the Câmara', () => {
@@ -44,8 +50,8 @@ describe('recording list URL (C199)', () => {
const polluted = resolveRecordingListUrl({
source: 'enviadas',
q: 'merenda',
- year: '2026',
- topic: 'saude',
+ phase: 'Ordem do Dia',
+ foo: 'bar',
})
expect(polluted.redirectHref).toBe('/campanha/comunicacao/acervo?source=enviadas&q=merenda')
@@ -130,4 +136,128 @@ describe('recording list URL (C199)', () => {
people: undefined,
})
})
+
+ it('parses the C219 parity facets and serializes them in canonical order', () => {
+ const canonical = resolveRecordingListUrl({
+ source: 'enviadas',
+ q: 'merenda',
+ mode: 'tema',
+ year: ['2026', '2024'],
+ topic: 'saude',
+ scope: 'bahia',
+ municipality: '42',
+ duration: 'curta',
+ sort: 'duracao_maior',
+ person: 'Solla',
+ page: '2',
+ })
+ expect(canonical.state).toEqual({
+ source: 'enviadas',
+ page: 2,
+ q: 'merenda',
+ mode: 'tema',
+ years: [2026, 2024],
+ topics: ['saude'],
+ scopes: ['bahia'],
+ municipalities: [42],
+ durations: ['curta'],
+ sort: 'duracao_maior',
+ people: ['Solla'],
+ })
+ expect(canonical.href).toBe(
+ '/campanha/comunicacao/acervo?source=enviadas&q=merenda&mode=tema&year=2026&year=2024' +
+ '&topic=saude&scope=bahia&municipality=42&duration=curta&sort=duracao_maior&person=Solla&page=2',
+ )
+ expect(canonical.redirectHref).toBeUndefined()
+ })
+
+ it('keeps the C199 deep link byte-identical (no new param is serialized)', () => {
+ const canonical = resolveRecordingListUrl({
+ source: 'enviadas',
+ q: 'merenda',
+ person: ['Solla', 'Presidente'],
+ page: '2',
+ })
+ expect(canonical.href).toBe(
+ '/campanha/comunicacao/acervo?source=enviadas&q=merenda&person=Solla&person=Presidente&page=2',
+ )
+ expect(canonical.redirectHref).toBeUndefined()
+ })
+
+ it('canonicalizes the default sort and a theme without a query away', () => {
+ const defaultSort = resolveRecordingListUrl({ source: 'enviadas', sort: 'recentes' })
+ expect(defaultSort.state.sort).toBeUndefined()
+ expect(defaultSort.href).toBe('/campanha/comunicacao/acervo?source=enviadas')
+ expect(defaultSort.redirectHref).toBe(defaultSort.href)
+
+ // The parsed state keeps `mode`, but the canonical href drops it and the
+ // redirect lands on the URL without the meaningless param (same as Câmara).
+ const themeWithoutQuery = resolveRecordingListUrl({ source: 'enviadas', mode: 'tema' })
+ expect(themeWithoutQuery.state.mode).toBe('tema')
+ expect(themeWithoutQuery.href).toBe('/campanha/comunicacao/acervo?source=enviadas')
+ expect(themeWithoutQuery.redirectHref).toBe(themeWithoutQuery.href)
+
+ // An unknown sort value can never widen the contract: it canonicalizes away.
+ const unknownSort = resolveRecordingListUrl({ source: 'enviadas', sort: 'aleatorio' })
+ expect(unknownSort.state.sort).toBeUndefined()
+ expect(unknownSort.redirectHref).toBe(unknownSort.href)
+ })
+
+ it('collapses an exhaustive enum selection to no filter (same rule as the Câmara)', () => {
+ const allTopics = resolveRecordingListUrl({
+ source: 'enviadas',
+ topic: SPEECH_TOPICS.map(({ value }) => value),
+ })
+ expect(allTopics.state.topics).toBeUndefined()
+ expect(allTopics.href).toBe('/campanha/comunicacao/acervo?source=enviadas')
+
+ const allDurations = resolveRecordingListUrl({
+ source: 'enviadas',
+ duration: SPEECH_DURATION_BUCKETS.map(({ value }) => value),
+ })
+ expect(allDurations.state.durations).toBeUndefined()
+ expect(allDurations.href).toBe('/campanha/comunicacao/acervo?source=enviadas')
+ })
+
+ it('drops structurally invalid year/municipality values on canonicalization', () => {
+ const canonical = resolveRecordingListUrl({
+ source: 'enviadas',
+ year: ['1800', 'abc', '2026'],
+ municipality: ['-3', '0', '7'],
+ })
+ expect(canonical.state.years).toEqual([2026])
+ expect(canonical.state.municipalities).toEqual([7])
+ expect(canonical.href).toBe(
+ '/campanha/comunicacao/acervo?source=enviadas&year=2026&municipality=7',
+ )
+ })
+
+ it('exposes the canonical filter key and the Payload sort of each order', () => {
+ expect(
+ buildRecordingFiltersKey({ source: 'enviadas', page: 1, q: 'merenda', topics: ['saude'] }),
+ ).toBe('source=enviadas&q=merenda&topic=saude')
+
+ expect(recordingSortOrder({ source: 'enviadas', page: 1 })).toBe('-createdAt')
+ expect(recordingSortOrder({ source: 'enviadas', page: 1, sort: 'duracao_maior' })).toBe(
+ '-durationSeconds',
+ )
+ expect(recordingSortOrder({ source: 'enviadas', page: 1, sort: 'duracao_menor' })).toBe(
+ 'durationSeconds',
+ )
+ expect(recordingSortIsDuration({ source: 'enviadas', page: 1 })).toBe(false)
+ expect(recordingSortIsDuration({ source: 'enviadas', page: 1, sort: 'duracao_maior' })).toBe(
+ true,
+ )
+ })
+
+ it('tells an unfiltered page (including pagination) from a narrowed one', () => {
+ expect(recordingHasActiveFilters({ source: 'enviadas', page: 1 })).toBe(false)
+ expect(recordingHasActiveFilters({ source: 'enviadas', page: 4 })).toBe(false)
+ expect(recordingHasActiveFilters({ source: 'enviadas', page: 1, sort: 'duracao_maior' })).toBe(
+ false,
+ )
+ expect(recordingHasActiveFilters({ source: 'enviadas', page: 1, q: 'merenda' })).toBe(true)
+ expect(recordingHasActiveFilters({ source: 'enviadas', page: 1, years: [2026] })).toBe(true)
+ expect(recordingHasActiveFilters({ source: 'enviadas', page: 1, people: ['Solla'] })).toBe(true)
+ })
})
diff --git a/tests/unit/recordingOmnibox.unit.spec.ts b/tests/unit/recordingOmnibox.unit.spec.ts
new file mode 100644
index 00000000..94f4bf80
--- /dev/null
+++ b/tests/unit/recordingOmnibox.unit.spec.ts
@@ -0,0 +1,197 @@
+// @vitest-environment node
+
+import { describe, expect, it } from 'vitest'
+
+import {
+ applyRecordingOmniboxSuggestion,
+ applyRecordingSearchMode,
+ buildRecordingOmniboxChips,
+ buildRecordingOmniboxSuggestionSeeds,
+ clearRecordingOmnibox,
+ filterRecordingOmniboxSuggestions,
+ removeRecordingOmniboxChip,
+} from '@/utilities/recordings/recordingOmnibox'
+
+const labels = new Map([[42, 'Feira de Santana']])
+
+describe('recordings omnibox (C219)', () => {
+ it('builds one chip per active filter with the facet labels', () => {
+ const chips = buildRecordingOmniboxChips({
+ state: {
+ source: 'enviadas',
+ page: 1,
+ q: 'merenda',
+ years: [2026],
+ topics: ['saude'],
+ scopes: ['bahia'],
+ municipalities: [42],
+ durations: ['curta'],
+ people: ['Dep. Jorge Solla'],
+ },
+ municipalityLabelsById: labels,
+ })
+ expect(chips.map((chip) => chip.label)).toEqual([
+ 'Busca: merenda',
+ 'Ano: 2026',
+ 'Tema: Saúde',
+ 'Alcance: Bahia',
+ 'Município citado: Feira de Santana',
+ 'Duração: Até 2 min',
+ 'Pessoa: Dep. Jorge Solla',
+ ])
+ })
+
+ it('falls back to the id when the municipality label is not loaded', () => {
+ const chips = buildRecordingOmniboxChips({
+ state: { source: 'enviadas', page: 1, municipalities: [99] },
+ municipalityLabelsById: labels,
+ })
+ expect(chips).toEqual([{ id: 'municipality:99', label: 'Município citado: Município #99' }])
+ })
+
+ it('applies the query suggestion resetting the page and keeping the source', () => {
+ const action = applyRecordingOmniboxSuggestion({
+ state: { source: 'enviadas', page: 4 },
+ suggestionId: 'q:merenda escolar',
+ })
+ expect(action).toEqual({
+ kind: 'url',
+ state: { source: 'enviadas', page: 1, q: 'merenda escolar' },
+ })
+ })
+
+ it('toggles facets and people (person dedupes case-insensitively)', () => {
+ const base = { source: 'enviadas' as const, page: 3 }
+
+ expect(applyRecordingOmniboxSuggestion({ state: base, suggestionId: 'topic:saude' })).toEqual({
+ kind: 'url',
+ state: { source: 'enviadas', page: 1, topics: ['saude'] },
+ })
+
+ expect(applyRecordingOmniboxSuggestion({ state: base, suggestionId: 'year:2026' })).toEqual({
+ kind: 'url',
+ state: { source: 'enviadas', page: 1, years: [2026] },
+ })
+
+ expect(
+ applyRecordingOmniboxSuggestion({ state: base, suggestionId: 'municipality:42' }),
+ ).toEqual({ kind: 'url', state: { source: 'enviadas', page: 1, municipalities: [42] } })
+
+ const withPerson = applyRecordingOmniboxSuggestion({
+ state: base,
+ suggestionId: 'person:Dep. Jorge Solla',
+ })
+ expect(withPerson).toEqual({
+ kind: 'url',
+ state: { source: 'enviadas', page: 1, people: ['Dep. Jorge Solla'] },
+ })
+
+ const removedPerson = applyRecordingOmniboxSuggestion({
+ state: { source: 'enviadas', page: 1, people: ['Dep. Jorge Solla'] },
+ suggestionId: 'person:dep. jorge solla',
+ })
+ expect(removedPerson).toEqual({
+ kind: 'url',
+ state: { source: 'enviadas', page: 1, people: undefined },
+ })
+
+ // An invalid numeric id never mutates the state.
+ expect(applyRecordingOmniboxSuggestion({ state: base, suggestionId: 'year:abc' })).toEqual({
+ kind: 'url',
+ state: base,
+ })
+ })
+
+ it('removes chips (dropping the query also drops the theme mode)', () => {
+ expect(
+ removeRecordingOmniboxChip({
+ state: { source: 'enviadas', page: 2, q: 'merenda', mode: 'tema' },
+ chipId: 'q',
+ }),
+ ).toEqual({
+ kind: 'url',
+ state: { source: 'enviadas', page: 1, q: undefined, mode: undefined },
+ })
+
+ expect(
+ removeRecordingOmniboxChip({
+ state: { source: 'enviadas', page: 2, topics: ['saude', 'cultura'] },
+ chipId: 'topic:saude',
+ }),
+ ).toEqual({ kind: 'url', state: { source: 'enviadas', page: 1, topics: ['cultura'] } })
+
+ expect(
+ removeRecordingOmniboxChip({
+ state: { source: 'enviadas', page: 2, people: ['Solla'] },
+ chipId: 'person:Solla',
+ }),
+ ).toEqual({ kind: 'url', state: { source: 'enviadas', page: 1, people: undefined } })
+ })
+
+ it('keeps a person label with a colon intact through the chip round trip', () => {
+ const state = { source: 'enviadas' as const, page: 1, people: ['Ana: assessora'] }
+ expect(buildRecordingOmniboxChips({ state, municipalityLabelsById: labels })).toEqual([
+ { id: 'person:Ana: assessora', label: 'Pessoa: Ana: assessora' },
+ ])
+ expect(removeRecordingOmniboxChip({ state, chipId: 'person:Ana: assessora' })).toEqual({
+ kind: 'url',
+ state: { source: 'enviadas', page: 1, people: undefined },
+ })
+ })
+
+ it('toggles the theme mode only with a query and clears back to the source', () => {
+ expect(
+ applyRecordingSearchMode({
+ state: { source: 'enviadas', page: 2, q: 'merenda' },
+ mode: 'tema',
+ }),
+ ).toEqual({
+ kind: 'url',
+ state: { source: 'enviadas', page: 1, q: 'merenda', mode: 'tema' },
+ })
+
+ expect(
+ applyRecordingSearchMode({ state: { source: 'enviadas', page: 1 }, mode: 'tema' }),
+ ).toEqual({ kind: 'url', state: { source: 'enviadas', page: 1 } })
+
+ expect(
+ applyRecordingSearchMode({
+ state: { source: 'enviadas', page: 1, q: 'merenda', mode: 'tema' },
+ mode: 'termo',
+ }),
+ ).toEqual({ kind: 'url', state: { source: 'enviadas', page: 1, q: 'merenda' } })
+
+ expect(
+ clearRecordingOmnibox({ source: 'enviadas', page: 3, q: 'merenda', topics: ['saude'] }),
+ ).toEqual({ kind: 'clear', state: { source: 'enviadas', page: 1 } })
+ })
+
+ it('seeds the taxonomy up front and the data-driven options by keyword', () => {
+ const seeds = buildRecordingOmniboxSuggestionSeeds({
+ years: [2026],
+ municipalityOptions: [{ value: '42', label: 'Feira de Santana' }],
+ personOptions: ['Dep. Jorge Solla'],
+ })
+
+ const emptyQuery = filterRecordingOmniboxSuggestions(seeds, '')
+ expect(emptyQuery.some((suggestion) => suggestion.id === 'topic:saude')).toBe(true)
+ expect(emptyQuery.some((suggestion) => suggestion.id === 'scope:bahia')).toBe(true)
+ expect(emptyQuery.some((suggestion) => suggestion.id === 'duration:curta')).toBe(true)
+ // Years, municipalities and people are searchable, not shown up front.
+ expect(emptyQuery.some((suggestion) => suggestion.id === 'year:2026')).toBe(false)
+ expect(emptyQuery.some((suggestion) => suggestion.id === 'person:Dep. Jorge Solla')).toBe(false)
+
+ // The typed query itself is always the first suggestion; the facet seed
+ // follows it when it matches.
+ expect(filterRecordingOmniboxSuggestions(seeds, 'feira').map((s) => s.id)).toContain(
+ 'municipality:42',
+ )
+ expect(filterRecordingOmniboxSuggestions(seeds, '2026').map((s) => s.id)).toContain('year:2026')
+ expect(filterRecordingOmniboxSuggestions(seeds, 'falante').map((s) => s.id)).toContain(
+ 'person:Dep. Jorge Solla',
+ )
+ expect(filterRecordingOmniboxSuggestions(seeds, 'municipio').map((s) => s.id)).toContain(
+ 'municipality:42',
+ )
+ })
+})