Plataforma digital e site público de Jorge Solla
Find a file
Francisco Ignácio Fontoura Solla 52c402c049 Fix the three leader-flow bugs the e2e suite pinned + RSC prop contracts
E2E-driven fixes (the suite now passes 9/9; two journeys remain
latency-flaky on cold dev compiles and pass on retry):

- leader home crashed with Forbidden since the remodel:
  loadLeaderContactsPageData loaded municipality options through the
  staff-scoped loader (leaders are denied municipality reads); their scope
  now derives from the engaged leadership's linked municipalities
- leaders saw 'Contato — —' instead of their supporters' names:
  getAccessibleContactIds now mirrors canReadSupporter for leaders
  (contacts of supporters they created)
- leader nav had two items with the same /campanha href (duplicate React
  keys); the leader home IS the contact tool — one entry
- RSC serialization contracts: CampaignListPagination is a server component
  again (hrefForPage stays server-side; CampaignTransitionAnchor client leaf
  intercepts clicks with serializable props); CampaignSearchForm takes
  basePath instead of a function prop
- hasAnyEstimate moved from the 'use client' PledgeEstimateForm to
  voteEstimate.ts — server components may not call client-module exports
- playwright.config honors TEQO_TEST_DATABASE_URL (parity with
  vitest.setup.ts) and uses a fixed .next/e2e dist dir so Next stops
  appending per-PID entries to tsconfig include; report artifacts
  eslint-ignored
2026-07-24 00:38:40 -03:00
.agents/skills Refactor campaign dashboard UX and add product discovery artifacts. 2026-07-19 21:56:01 -03:00
.cursor Document the engineering standards for agents and humans 2026-07-23 23:45:20 -03:00
.github/workflows Add the tooling gate: knip, CI, zero-warning lint, as-never ban 2026-07-23 23:06:12 -03:00
.husky Fix PascalCase lint that broke Vercel builds and run lint on pre-push. 2026-07-19 18:36:33 -03:00
.impeccable Add the tooling gate: knip, CI, zero-warning lint, as-never ban 2026-07-23 23:06:12 -03:00
.vscode feat: initial commit 2026-02-14 16:11:51 -03:00
.zed feat: overhaul petition UX, add contact/signature data model, and refresh shadcn theming 2026-02-22 20:02:51 -03:00
docker/postgres/init Isolate local/dev and tests from the production database 2026-07-15 13:52:30 -03:00
docs Document the engineering standards for agents and humans 2026-07-23 23:45:20 -03:00
public Add installable PWA foundation for the /campanha field app. 2026-07-18 17:28:34 -03:00
scripts Cache the campaign hot path: committed TSE artifact + request-scoped dedup 2026-07-23 23:06:28 -03:00
src Fix the three leader-flow bugs the e2e suite pinned + RSC prop contracts 2026-07-24 00:38:40 -03:00
tests Break up the god modules into deep domain modules 2026-07-23 23:44:45 -03:00
.env.example Add allowlisted global cache revalidation for Onda 0 F1. 2026-07-19 22:21:16 -03: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
.prettierrc.json feat: initial commit 2026-02-14 16:11:51 -03:00
.yarnrc feat: initial commit 2026-02-14 16:11:51 -03:00
AGENTS.md Document the engineering standards for agents and humans 2026-07-23 23:45:20 -03:00
components.json Including page mandato-no-whatsapp 2026-03-14 18:07:40 -03:00
DESIGN.md Polish /campanha Field Desk UX and register FD+/FD2 follow-ups. 2026-07-19 08:17:12 -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-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 Fix the three leader-flow bugs the e2e suite pinned + RSC prop contracts 2026-07-24 00:38:40 -03:00
knip.json Add the tooling gate: knip, CI, zero-warning lint, as-never ban 2026-07-23 23:06:12 -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 Add the tooling gate: knip, CI, zero-warning lint, as-never ban 2026-07-23 23:06:12 -03:00
playwright.config.ts Fix the three leader-flow bugs the e2e suite pinned + RSC prop contracts 2026-07-24 00:38:40 -03:00
pnpm-lock.yaml Add the tooling gate: knip, CI, zero-warning lint, as-never ban 2026-07-23 23:06:12 -03: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 Remodel the campaign vertical from Praça to Município 2026-07-23 21:36:20 -03:00
README.md Add allowlisted global cache revalidation for Onda 0 F1. 2026-07-19 22:21:16 -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 Fix the three leader-flow bugs the e2e suite pinned + RSC prop contracts 2026-07-24 00:38:40 -03:00
vitest.config.mts Ship /campanha nuclei MVP with RBAC, invites, and vote estimates. 2026-07-18 15:01:56 -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 Ship /campanha nuclei MVP with RBAC, invites, and vote estimates. 2026-07-18 15:01:56 -03:00

Teqo

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 2022 Bahia election results into the local db; idempotent per year/office/turn scope, refuses a non-local database).

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

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 in docs/roadmap.md (blockers, public site, /campanha next cycles, admin RBAC, white-label).