Plataforma digital e site público de Jorge Solla
Find a file
Francisco Solla 8dd60cf962 A6 — Dobradinha 2026 automática quando o TSE publicar candidaturas (pós-15/08) (#82)
* docs(A6): freshness audit da #27 no plano de dobradinhas 2026

electionInsights.ts foi deletado no Pass 2 W4a (modulo puro novo),
electionAlliances.ts nao nasce (campoParties + electionPartySpectrum ja
carregam a taxonomia), questoes em aberto resolvidas (tiers, score,
proporcionais, lockdown de lideranca), card na aba Eleicoes, overview da
lista fora de escopo, cache election-tse com bust na conciliacao Fase 5.

Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>

* feat(A6): insight de dobradinhas 2026 na aba Eleicoes do municipio

Lista ranqueada de candidatos proporcionais que concorrem de novo em 2026
(runningAgain2026=sim) por geografia do municipio: score 0,6 alinhamento
(campo 2026 + espectro Bolognesi) + 0,4 forca local normalizada pelo maximo
do conjunto. Estado pendente ate a conciliacao pos-15/08; Solla excluido
(referencia, nao parceiro); leitura derivada sem escrita; loader cacheado
sob a tag election-tse como os irmaos; link para /campanha/dobradinhas
como caminho de registro operacional.

Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>

* test(A6): cobertura unit/int do insight + lease das colecoes eleitorais

Unit: tiers (campo/espectro/falha-para-o-meio), score, ordenacao, empates,
limite, zero votos. Int: pending2026 sem conciliacao (mesmo com votos
locais), so adversarios, misto com exclusao de Solla/nao e geografia
alheia. Lease advisory election-collections serializa os dois specs que
tratam as colecoes eleitorais como test-owned (o import wipe-all apagaria
as fixtures do novo spec no meio do assert, 48-way paralelo).

Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>

* refactor(A6): fixes do /simplify (3 reviewers paralelos)

P1: campo coalition morto removido do input/select/mapping (sem consumidor).
P1: hooks do lease com timeout explicito de 120s nos dois specs eleitorais
(o wait advisory passa dos 10s default do Vitest sob contencao — flake em
ambas as direcoes). P2: sonda de conciliacao via payload.count (idioma da
casa), desempate final por candidateNumber (ordem deterministica), geography
como prop na secao (sem lookup duplicado), casing Dep. Federal/Estadual
alinhado, marcador 1313 via BASELINE_TICKET_2022, entrada no CHANGELOG.

Declinados com justificativa: zones como tupla nao-vazia (churn em tipo
compartilhado por assert provada no catalogo) e early-start da promise
antes do Promise.all (loader-dentro-do-Suspense e o idioma da casa; ganho
so em cache frio).

Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>
2026-07-31 00:14:27 -03:00
.agents/skills Refactor campaign dashboard UX and add product discovery artifacts. 2026-07-19 21:56:01 -03:00
.cursor chore(ops): engineering-audit pronta para rodada autônoma no Cursor Cloud (#79) 2026-07-30 23:13:34 -03:00
.github fix(agent-pool): tick falhava em ERR_MODULE_NOT_FOUND (dotenv) (#72) 2026-07-30 23:41:59 -03:00
.husky feat(ops): auto-promote stage→main e merge em stage sem exigir head (#68) 2026-07-30 21:12:52 -03:00
.impeccable Dim the tour composer proposal when changing identity territory. 2026-07-28 18:41:36 -03:00
.vscode feat: initial commit 2026-02-14 16:11:51 -03:00
.zed Tooling: prettier como autoridade de formatacao (organize-imports deterministico, scripts format/format:check, normalizacao mecanica de 312 arquivos; artefatos gerados e migrations excluidos via .prettierignore) 2026-07-25 17:22:20 -03:00
docker/postgres/init Isolate local/dev and tests from the production database 2026-07-15 13:52:30 -03:00
docs A6 — Dobradinha 2026 automática quando o TSE publicar candidaturas (pós-15/08) (#82) 2026-07-31 00:14:27 -03:00
public Add installable PWA foundation for the /campanha field app. 2026-07-18 17:28:34 -03:00
scripts feat(ops): promote último commit ci-stage green sem exigir head verde 2026-07-30 21:56:50 -03:00
src A6 — Dobradinha 2026 automática quando o TSE publicar candidaturas (pós-15/08) (#82) 2026-07-31 00:14:27 -03:00
tests A6 — Dobradinha 2026 automática quando o TSE publicar candidaturas (pós-15/08) (#82) 2026-07-31 00:14:27 -03:00
.cursorignore docs: agent ops + slice AGENTS.md + kernels + cursorignore + portable hooks + cloud env + PR template 2026-07-30 05:21:35 -03:00
.env.example D2 — Push + sino in-app para /campanha 2026-07-31 01:51:41 +00:00
.env.test Remodel the campaign vertical from Praça to Município 2026-07-23 21:36:20 -03:00
.gitignore Document coordenador geral interview and register A10 plus WhatsApp D3–D5. 2026-07-23 12:24:53 -03:00
.npmrc fix issues to run from cPanel 2026-03-15 14:03:28 -03:00
.prettierignore Engineering Pass 3: consolidate patterns and lock them with guards. 2026-07-29 06:11:29 -03:00
.prettierrc.json Tooling: prettier como autoridade de formatacao (organize-imports deterministico, scripts format/format:check, normalizacao mecanica de 312 arquivos; artefatos gerados e migrations excluidos via .prettierignore) 2026-07-25 17:22:20 -03:00
.yarnrc feat: initial commit 2026-02-14 16:11:51 -03:00
AGENTS.md chore: format AGENTS.md 2026-07-30 05:23:39 -03:00
components.json Including page mandato-no-whatsapp 2026-03-14 18:07:40 -03:00
DESIGN.md simplify(B13): corrige classe agregada, bolhas em pane proprio e registra debitos 2026-07-26 05:12:37 -03:00
docker-compose.yml Isolate local/dev and tests from the production database 2026-07-15 13:52:30 -03:00
Dockerfile feat: initial commit 2026-02-14 16:11:51 -03:00
eslint-legacy-ignores.mjs Guardas programaticas: fronteira lib/ (no-restricted-imports), ban de consent id hardcoded, codebaseConventions.unit.spec (server-only, copy Praca/Nucleo, listas legadas do eslint, wrappers de formActions), ciclo do payload.config quebrado (documents/globals divididos em tags+reads), timeout global do int suite, personName schema-valido, consent drafts Onda 0 p/ Municipio 2026-07-25 18:02:02 -03:00
eslint-local-rules.mjs Add ESLint guard for invalid use server exports and fix plaza staff messages. 2026-07-21 20:07:06 -03:00
eslint.config.mjs Engineering Pass 3: consolidate patterns and lock them with guards. 2026-07-29 06:11:29 -03:00
knip.json Tooling: prettier como autoridade de formatacao (organize-imports deterministico, scripts format/format:check, normalizacao mecanica de 312 arquivos; artefatos gerados e migrations excluidos via .prettierignore) 2026-07-25 17:22:20 -03:00
next.config.mjs Ship /campanha nuclei MVP with RBAC, invites, and vote estimates. 2026-07-18 15:01:56 -03:00
package.json D2 — Push + sino in-app para /campanha 2026-07-31 01:51:41 +00:00
playwright.config.ts fix(campanha): share one Drawer across municipalities mobile cards 2026-07-30 17:37:20 -03:00
pnpm-lock.yaml D2 — Push + sino in-app para /campanha 2026-07-31 01:51:41 +00:00
postcss.config.mjs Migrate from unstable_cache to use cache. And start Petition Form 2026-02-17 22:16:53 -03:00
PRODUCT.md B34: editable município chips on the leaderships list. 2026-07-27 22:35:19 -03:00
README.md docs: AGENT-OPS/README/changelog 2026-07-30 12:22:06 -03:00
skills-lock.json Refactor campaign dashboard UX and add product discovery artifacts. 2026-07-19 21:56:01 -03:00
tailwind.config.ts feat: add Tailwind CSS integration 2026-02-14 16:47:25 -03:00
test.env feat: initial commit 2026-02-14 16:11:51 -03:00
tsconfig.json Tooling: prettier como autoridade de formatacao (organize-imports deterministico, scripts format/format:check, normalizacao mecanica de 312 arquivos; artefatos gerados e migrations excluidos via .prettierignore) 2026-07-25 17:22:20 -03:00
vercel.json chore(ops): gate:ci no pre-push espelha ci-pr com blast radius 2026-07-30 18:48:10 -03:00
vitest.config.mts Guardas programaticas: fronteira lib/ (no-restricted-imports), ban de consent id hardcoded, codebaseConventions.unit.spec (server-only, copy Praca/Nucleo, listas legadas do eslint, wrappers de formActions), ciclo do payload.config quebrado (documents/globals divididos em tags+reads), timeout global do int suite, personName schema-valido, consent drafts Onda 0 p/ Municipio 2026-07-25 18:02:02 -03:00
vitest.setup.ts Ship A10 vote estimate scenarios (pessimistic/central/optimistic) for Praças. 2026-07-23 19:12:22 -03:00
vitest.unit.config.mts Engineering Pass 3: consolidate patterns and lock them with guards. 2026-07-29 06:11:29 -03:00

Teqo

Cheatsheet de operação agentic (humanos) — o fluxo em 5 linhas:

  1. O agente roda pnpm agent:claim e pega a próxima Issue ready por prioridade (prio:P0..P3).
  2. Ele implementa, roda o fast gate (lint + typecheck + unit) e abre PR para stage — sozinho, e para aí.
  3. CI verde → o PR mergeia em stage automaticamente; o merge roda o CI de stage contra o clone Neon de prod.
  4. Você promove quando quiser: pnpm agent:promote -- --i-am-human (PR stage→main, merge só com CI stage + PR green).
  5. Semanalmente: pnpm db:refresh:stage renova o snapshot do stage a partir de prod (humano, requer NEON_API_KEY).

Comandos: pnpm agent:claim | agent:register | agent:prioritize | agent:file-miss | agent:promote e pnpm db:seed:minimal | db:refresh:stage. Labels: estado ready|in-progress|blocked|done|in-prod, prio:P0..P3, kind:*, needs:migration|consent, requirements-changed. Agente faz sozinho: claim → implementar → PR → stage. Só humano: promote stage→main, refresh do stage, envs Vercel/Neon, pnpm build contra banco remoto. Tudo em detalhe: docs/AGENT-OPS.md · CI: .github/workflows/ci-pr.yml + ci-stage.yml + ci.yml.

Teqo starts as the official digital platform for deputado Jorge Solla and evolves into a white-label civic engagement platform for politicians in Brazil.

The goal is to help political teams build direct, durable relationships with their base without depending on Big Tech social platforms as the primary channel.

Mission

  • Strengthen direct communication between representatives and citizens.
  • Reduce platform dependency risk by owning audience and data channels.
  • Provide reusable building blocks so each political team can launch quickly.

Product Direction

Phase 1: Jorge Solla Website

Initial delivery focuses on Jorge Solla's public website, editorial CMS, and the internal /campanha tool:

  • Public-facing content and updates (news/post + tag live)
  • Institutional pages and biography (still pending a Pages collection)
  • Internal campaign operations: electoral nuclei, leaderships, estimates, updates, WhatsApp invites
  • Editorial operations through Payload CMS

Phase 2: White-Label Platform

Teqo then becomes a configurable base product for other politicians in Brazil:

  • Multi-tenant and reusable architecture
  • Brand and content customization per mandate/campaign
  • Shared core modules for communication and engagement
  • Operational autonomy with self-hosted owned channels

Local Development

Production safety: the production database is a live Neon Postgres holding real citizens' data. Local development and tests run against a local Postgres and must never point at production. pnpm dev refuses to start against a non-local database, and the test suite refuses any database whose name doesn't end in _test.

First-time setup

  1. Install dependencies: pnpm install
  2. Create your env file: cp .env.example .env.local
  3. Start Docker, then start the local database: pnpm db:start
    • This runs Postgres 17 (matching production) and auto-creates a teqo_test database for the test suite.
  4. Make sure DATABASE_URL in .env.local points at local:
    DATABASE_URL=postgresql://teqo:teqo@localhost:5432/teqo
    
  5. Load a schema + content into the local database — pick one:
    • Mirror production content (recommended): PROD_DATABASE_URL="<unpooled Neon URL>" pnpm db:pull Copies production's schema and content into local. It only reads production and excludes supporter PII (contact/signature/subscription data).
    • Empty schema from migrations: pnpm migrate
  6. Start the dev server: pnpm dev
  7. Open: http://localhost:3000

Useful scripts: pnpm db:start / pnpm db:stop (local Postgres), pnpm db:pull (refresh local content from prod), pnpm db:seed:posts (import news posts/tags fresh from the live jorgesolla.com.br site into the local db; idempotent by slug, refuses a non-local database), pnpm db:seed:tse (import TSE 2014/2018/2022 Bahia election results into the local db; idempotent per year/office/turn scope, refuses a non-local database), pnpm build:election-aggregates (regenerate the committed TSE aggregate artifact in src/lib/electionAggregates/ from locally seeded data).

Content & cache revalidation

Public news pages (/[type], /[type]/[category], articles, and the home news list) are cached under a shared posts tag. Editing a post or tag in the deployed admin self-revalidates via afterChange hooks. Any write that bypasses the deployed runtime — a direct-DB seed (pnpm db:seed:posts), SQL, Onda 0 migrations, or a restore — does not bust production's cache, so afterwards call the secured endpoint:

# News (default tag: posts)
curl -X POST "https://<prod-domain>/api/revalidate" -H "x-revalidate-secret: $REVALIDATE_SECRET"

# Privacy policy after Onda 0 provision (tag: global_privacy-policy)
curl -X POST "https://<prod-domain>/api/revalidate?tag=global_privacy-policy" -H "x-revalidate-secret: $REVALIDATE_SECRET"

REVALIDATE_SECRET must be set in the Vercel production env (see .env.example). See the "Posts & Tags" section of AGENTS.md for the full model.

Database migrations

Schema is managed by committed Payload migrations (src/migrations/); push is disabled everywhere.

To change the schema:

  1. Edit the collection/global/field config.
  2. Generate a migration: pnpm migrate:create <name>
  3. Review and commit the generated files in src/migrations/ (both .ts and .json, plus index.ts).
  4. Apply it locally: pnpm migrate (check status anytime with pnpm migrate:status).

Deploying to production: pnpm build runs payload migrate before building, so every Vercel deploy automatically applies pending migrations to the production database. Do not run migrations against production by hand.

Running tests

Tests use the isolated teqo_test database (config in .env.test). Prepare its schema once with:

DATABASE_URL=postgresql://teqo:teqo@localhost:5432/teqo_test pnpm migrate

Then run:

  • pnpm test — unit + integration
  • pnpm test:e2e — Playwright (requires the test DB schema and a free port)
  • pnpm test:all — unit + integration + E2E

Quality gates (also enforced by CI on the GitHub mirror): pnpm lint (zero warnings — --max-warnings=0), pnpm typecheck, and pnpm exec knip (dead files/dependencies fail; delete what your change orphaned). Standards: .cursor/rules/engineering-standards.mdc.

Tech Stack

  • Payload CMS
  • Next.js
  • PostgreSQL (via @payloadcms/db-postgres)
  • TypeScript

Campaign (/campanha)

Internal campaign tool for electoral nuclei, local leaderships, vote estimates, field updates, and WhatsApp invites. Authenticated separately from /admin via the campaignUser collection (geral / coordenador / lideranca). Operational status and decisions: .cursor/rules/projects/nucleos-eleitorais.mdc. Conventions and deploy checklist: AGENTS.md (“Campaign auth” / “Campaign nuclei MVP”).

Production blocker: do not load real leadership data or enable invites until counsel-approved Consent.key = 'lideranca-autopreenchimento' exists. Absolute invite URLs require NEXT_PUBLIC_SITE_URL as an exact HTTPS DNS origin in production.

Roadmap

Backlog and future plans live as tracked GitHub Issues (spec + deps + prio + model per issue; flow skills: plan-issue → work-issue → project-status; docs/roadmap.md is a frozen legacy stub).