A ferramenta de abaixo-assinado já existia, mas a petição do PL não tinha caminho reproduzível fora do dump legado: produção só carregava as três petições antigas editadas no admin. O conteúdo agora é versionado em scripts/lib/petitionPl5594Content.mjs e provisionado por pnpm seed:petition-pl-5594 — dry-run por padrão, create-if-missing por id, Consent whatsapp-inscricao resolvido por chave (fail-closed) e guards de escrita (PETITION_SEED_CONFIRM + TEQO_ENV casando o banco exato), sem sobrescrever edição do admin. O corpo traz os fatos do inteiro teor (autorização no registro, 5 exercícios de IR, sigilos bancário/fiscal/telefônico/de conexão, exclusão do conteúdo das comunicações, auditoria, LGPD e divulgação pela Justiça Eleitoral), a motivação de 18-19/10 sem acusar crime e o pedido sem prometer aprovação. A copy hardcoded do bloco do formulário deixa de falar em 'campanha'/'luta dos trabalhadores' e vira genérica. Prova: unit full 475 arquivos/5238 testes verdes, lint/typecheck/format limpos, seed aplicado e reaplicado em DB temporário (criação + no-op) e smoke real no navegador (página 200, consent, assinatura nº 1). Sem migration, collection, Consent novo ou mudança no fluxo de assinatura. |
||
|---|---|---|
| .agents | ||
| .codex | ||
| .cursor | ||
| .forgejo | ||
| .github | ||
| .husky | ||
| .impeccable | ||
| .opencode | ||
| .playwright | ||
| .vscode | ||
| .zed | ||
| docker/postgres/init | ||
| docs | ||
| private | ||
| public | ||
| scripts | ||
| src | ||
| tests | ||
| .cursorignore | ||
| .dockerignore | ||
| .env.example | ||
| .env.test | ||
| .gitignore | ||
| .npmrc | ||
| .nvmrc | ||
| .prettierignore | ||
| .prettierrc.json | ||
| .yarnrc | ||
| AGENTS-campaign.md | ||
| AGENTS-infra.md | ||
| AGENTS-public.md | ||
| AGENTS.md | ||
| components.json | ||
| DESIGN.md | ||
| docker-compose.yml | ||
| Dockerfile | ||
| eslint-legacy-ignores.mjs | ||
| eslint-local-rules.mjs | ||
| eslint.config.mjs | ||
| knip.json | ||
| LICENSE | ||
| next.config.mjs | ||
| opencode.json | ||
| package.json | ||
| playwright.config.ts | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| postcss.config.mjs | ||
| PRODUCT.md | ||
| README.md | ||
| skills-lock.json | ||
| tailwind.config.ts | ||
| test.env | ||
| tsconfig.json | ||
| vitest.config.mts | ||
| vitest.setup.ts | ||
| vitest.unit.config.mts | ||
Teqo
License: proprietary — All Rights Reserved (© Francisco Ignácio Fontoura Solla). Portfolio / demonstration only. Not open source. Use, copy, or redistribution requires prior written permission (
fsolla@pm.me). SeeLICENSE.Sensitive field material belongs in
/private/on local checkouts (gitignored). Cloud agents: use public-clean docs; report sensitive deliverables in chat — do not commit them.
Cheatsheet de operação agentic (humanos) — o fluxo em 5 linhas:
- O agente roda
pnpm agent:claim(oupnpm worktree next --issue N) e pega a próxima Issuereadypor prioridade (prio:P0..P3). O tracker de Issues, o código, os PRs e o CI vivem no GitHub (github.com/fsolla/teqo).- Ele implementa, roda o fast gate (
lint + typecheck + unit) epnpm push -u origin HEAD— abre a PR paramain(Ready,Closes #N).- CI verde (
CI (PR) / checks) → o safety netagent-pr-ready-automerge.ymlarma o auto-merge nativo (rebase) — o servidor só mergea com o required check verde.- Deploy começa automático: o merge em
maindispara odeploy.yml(suíte full noverify) → staging publica sozinho → produção só com o approve do reviewer no environmentproduction(jorgesolla1313.com.br, runner self-hosted) — migrações aplicadas antes do rollout; o staging velho se atualiza via requeue (OPS104); desde a OPS107 o approval pendente não segura o staging nem a aprovação de runs novos — aprove só o run escolhido e rejeite os demais.workflow_dispatchsegue como escape manual.- Secrets humanos (uma vez):
GITHUB_TOKEN(PAT com escoporepo+issues: write) para os scripts de agente/PR (pnpm issue/agent:*,github-pr.mjs); envs de prod em~/stack/teqo-1313.envno homeserver. Branch protection demainjá aplicada (reaplicar:pnpm configure:branch-protection).Comandos:
pnpm agent:claim | agent:register | agent:prioritize | agent:file-miss | worktree nextepnpm db:seed:minimal. Labels: estadoready|in-progress|blocked|done|in-prod,prio:P0..P3,kind:*,needs:migration|consent,requirements-changed. Agente faz sozinho: claim → implementar → PR → main (o merge já inicia o deploy de staging). Só humano: aprovar a produção no environment do run (desde a OPS107, só o run escolhido — rejeite os demais), envs do homeserver, branch protection, runbook de rollback. Tudo em detalhe:docs/AGENT-OPS.md· CI:.github/workflows/ci-pr.yml· Deploy:.github/workflows/deploy.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+taglive) - Institutional pages and biography (still pending a
Pagescollection) - Internal campaign operations: municípios (435, pré-definidos), 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 Postgres on the homeserver (
teqo_1313) holding real citizens' data. Local development and tests run against a local Postgres and must never point at production.pnpm devrefuses to start against a non-local database, and the test suite refuses any database whose name doesn't end in_test.
First-time setup
- Install dependencies:
pnpm install - Create your env file:
cp .env.example .env.local - Start Docker, then start the local database:
pnpm db:start- This runs Postgres 17 (matching production) and auto-creates a
teqo_testdatabase for the test suite.
- This runs Postgres 17 (matching production) and auto-creates a
- Make sure
DATABASE_URLin.env.localpoints at local:DATABASE_URL=postgresql://teqo:teqo@localhost:5432/teqo - Load a schema + content into the local database — pick one:
- Mirror production content (recommended):
PROD_DATABASE_URL="<prod connection string>" pnpm db:pullCopies production's schema and content into local. It only reads production and excludes supporter PII (contact/signature/subscriptiondata). The prod string is theDATABASE_URLof~/stack/teqo-1313.envon the homeserver (Postgresteqo_1313). - Empty schema from migrations:
pnpm migrate
- Mirror production content (recommended):
- Start the dev server:
pnpm dev - Open:
http://localhost:3000
Useful scripts: pnpm db:start / pnpm db:stop (local Postgres — always the same shared container via -p teqo, from any directory), 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).
Parallel worktrees get isolated environments: pnpm worktree next derives a per-branch dev port (3100+slot) and its own databases (teqo_wt<slot> / teqo_wt<slot>_test), so agents never fight over port 3000 or the shared teqo_test. See .agents/skills/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 production env (~/stack/teqo-1313.env on the homeserver — 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:
- Edit the collection/global/field config.
- Generate a migration:
pnpm migrate:create <name> - Review and commit the generated files in
src/migrations/(both.tsand.json, plusindex.ts). - Apply it locally:
pnpm migrate(check status anytime withpnpm migrate:status).
Deploying to production: merges to main trigger deploy.yml automatically (OPS104) — the verify job runs the full suite, deploy-staging publishes on its own, and deploy-production waits for the production environment approval (OPS107: the pending approval no longer holds the shared deploy lane, so later runs still stage and stay approvable — approve only the chosen run and reject the rest). The remote script (scripts/deploy-homeserver.sh) builds on the homeserver and applies pending migrations through the compose maintenance service teqo-1313-migrate before the rollout. Do not run migrations against production by hand. Runbook (rollback, known failures): docs/ops/teqo-1313-deploy.md.
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 + integrationpnpm 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 GitHub Actions — ci-pr.yml): pnpm lint (zero warnings — --max-warnings=0), pnpm typecheck, and pnpm exec knip (dead files/dependencies fail; delete what your change orphaned). Standards: .agents/rules/engineering-standards.mdc.
Tech Stack
- Payload CMS
- Next.js
- PostgreSQL (via
@payloadcms/db-postgres) - TypeScript
Campaign (/campanha)
Internal campaign tool for municípios (435 pré-definidos), local leaderships, vote estimates, field updates, and WhatsApp invites. Authenticated separately from /admin via the campaignUser collection (coordinator / advisor / leader / candidate). Operational status and decisions: .agents/rules/projects/nucleos-eleitorais.mdc. Conventions and deploy checklist: AGENTS.md (“Campaign auth” / “Campaign Municípios model”).
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).