Commit graph

110 commits

Author SHA1 Message Date
Francisco Solla
dcf8e85a9d feat(archive): varredura e reparo de integridade do acervo no Garage (C246)
Adiciona a CLI pnpm archive:integrity: varredura read-only de todas as archivePhoto (download + decode pelo mesmo caminho da rota pública e do índice facial; sai 1 enquanto houver mídia quebrada approved) e --apply que re-ingere do Flickr pelo flickrId, substitui o objeto na mesma chave via payload.update filePath (sem tocar curadoria/status) e rebaixa a draft as irrecuperáveis (removed intocado).

Dono da leitura ganha inspectPrivateMediaObject e isPrivateMediaMissingError (S3 NoSuchKey/404 + ENOENT local; checksum nunca é missing); archivePhotoIngest ganha repairArchivePhotoObject e withdrawArchivePhotoFromPublic; decisão do reparo em scripts/lib/archiveIntegrityRepair.mjs com deps injetadas e puro de CLI/recibo em scripts/lib/archiveIntegrityPlan.mjs. Sem migration, sem UI. Guardas: ARCHIVE_INTEGRITY_CONFIRM + TEQO_ENV exato + 4 S3_* (em qualquer modo no alvo não-local) + FLICKR_API_KEY. Runbook C246, changelog e unit/int/e2e afetado.
2026-10-02 10:53:39 -03:00
Francisco Solla
269b3d9e3b feat(ops): CLI ops:global para flags de globais públicos (C247)
Grava um único campo do global via Local API e busta a tag no processo Next vivo pelo POST /api/revalidate (allowlist ampliada com REVALIDATE_PHOTO_ALBUM_CACHE_TAG), com guardas de escrita, plan/apply/verify, recibo com rollback e int pin do update parcial.
2026-10-02 10:10:16 -03:00
Francisco Solla
ee3dda757b feat(C244): aviso do índice curado, seed de figuras e enrollment 2026-10-02 09:35:43 -03:00
Francisco Solla
cd4942d9e2 feat(C242/C243): abre a busca por selfie a qualquer visitante (escopo B) + seção na homepage
O escopo A/C do gate (PR #1370) é superado por decisão do dono (2026-10-01, aval jurídico declarado): o índice vira anônimo (archivePhotoFace, foto + descritor 128-d, sem nome/vínculo), o enrollment por pessoa morre (faceSubject/faces:enroll removidos) e qualquer visitante encontra as próprias fotos aprovadas.

- faces:index persiste os descritores por foto (transação substitui as linhas + marker = modelo); desaprovar/remover/deletar foto apaga os descritores (hooks + FK cascade)
- POST /api/fotos/selfie casa o vetor da consulta contra o índice em memória (TTL 60 s) e devolve só a interseção com o read aprovado do C233, sem score/nome de terceiro; leave-index apaga os descritores que casarem
- Consentimentos seguem fail-closed: busca-selfie-fotos (consulta) e busca-selfie-indice (aviso público do índice), textos versionados em scripts/lib/faceConsentTexts.mjs e provisionados por pnpm seed:face-consents
- pnpm archive:publish aprova o acervo em lote (draft -> approved; removed nunca) com guardas e recibo
- C243: seção condicional SelfieSearchHomeSection (port do design hi-fi, cenas 390/1280) entre a Central e a newsletter; sem engine/captura na home e sem CTA morto quando fechada
- docs: planos C242/C243, AGENTS-public, runbook §C242, changelog

Provas: gate:fast 457 arquivos/5.055 testes; int full 109/1.075; e2e frontendFotosSelfie 9/9; knip verde.
2026-10-01 12:54:47 -03:00
Francisco Solla
3d269725f8 feat(C230): expurgo de peças fora do período eleitoral na Central
O rascunho pré-campanha que o --publish-existing ressuscita precisa sair
do catálogo de vez: o novo CLI content:instagram:prune faz hard delete da
peça e da mídia privada (linha, arquivo e still do C226), então uma
importação futura não a recria. Compartilha o mesmo núcleo de corte da
retirada (data civil na Bahia, peça sem data no feed nunca é tocada) e
espelha as guardas dos irmãos: --before obrigatório, TEQO_ENV casando o
nome exato do banco, CONTENT_INSTAGRAM_PRUNE_CONFIRM=1 e recibos JSON.

Testes: planejador/parser/recibo em unit e guardas do CLI em subprocesso.
Runbook e changelog atualizados.
2026-10-01 02:29:19 -03:00
Francisco Solla
5eb8fd75ef feat(C230): lote da Central — publicar rascunhos da janela e retirar pré-campanha
--publish-existing no content:instagram:import (publica rascunhos prontos da
janela, mais antigo primeiro) e CLI novo content:instagram:withdraw (despublica
por corte civil na Bahia, com as datas vindas do feed oficial). Plumbing
compartilhado dos dois em scripts/lib/instagramContentCli.mjs; teto do feed
passa ao da edge (10K) com early-stop por data; guardas C155/C195/C231, testes
unit das guardas e do planejador, runbook e changelog.
2026-09-29 22:51:25 -03:00
Francisco Solla
35eb2ed432 feat(C230): importação em lote do Instagram para a Central (CLI)
CLI operacional `content:instagram:import`: lê o feed oficial do perfil,
filtra a janela por dias (default 60), deduplica pela identidade do post e
processa cada novidade inline pelo pipeline C220 (download, transcrição,
catalogação); --publish publica ao final o que terminou pronto, mais antigo
primeiro, e revalida a Central pública. Guardas C155/C195/C231 (TEQO_ENV +
nome exato do banco, confirmação explícita, S3_* obrigatórias, dry-run padrão).
2026-09-29 09:51:46 -03:00
Francisco Solla
9e9864f420 feat(C234): busca por selfie no álbum público — índice A/C consentido, selfie on-device
- /fotos/encontre + POST /api/fotos/selfie: só o vetor 128-d, sem imagem, sem score e
  sem nomes de terceiros; fail-closed pela flag photoAlbum.selfieSearchEnabled (default
  false) e pelos Consents por chave estável (busca-selfie-fotos/busca-selfie-indice, não
  seedados — a superfície nasce fechada até o aval jurídico/DPIA).
- Índice A/C do gate (PR #1370): só quem aderiu é indexado; descriptors do acervo são
  transitórios. Collection faceSubject (admin-only, sem vínculo com Contact), vínculos
  matchedPhotos e marker faces.checkedKey no archivePhoto (modelo + enrolledAt).
- Engine @vladmandic/face-api nos dois lados: browser lazy com modelos same-origin
  (copy-face-vision-assets no prebuild/predev/Docker) e CLI node-wasm sem tfjs-node.
  CLIs ops-only faces:enroll / faces:index --apply|--verify com guardas C231/C232.
- Opt-out self-service por reconhecimento (leave-index) + canal de remoção do C233;
  rate limit próprio (namespace selfie:<hash>) e bounded body extraído do beacon.
- UI portada classe-a-classe do design estendido (paridade certificada, tier primário);
  e2e frontendFotosSelfie (manifest+curado+projeto, engine stubada) e canário do engine
  real; runbook §C234, contrato em AGENTS-public.md e changelog.
- Migration aditiva add_face_subject (SQL revisado); hard-stops aprovados na sessão.
2026-09-27 20:04:41 -03:00
Francisco Solla
671af1e21f feat(C232): pré-catalogar o acervo de fotos com IA local e curadoria que vence
Some checks are pending
Deploy / preflight (push) Waiting to run
Deploy / verify (push) Blocked by required conditions
Deploy / deploy staging (teqo-staging) (push) Blocked by required conditions
Deploy / requeue when main advanced (push) Blocked by required conditions
Deploy / deploy production (teqo-1313) (push) Blocked by required conditions
Collection archivePhoto ganha o grupo catalog (legenda/descrição/cena/texto
visível/temas/pessoas/município/origem/catalogedAt), curatedFields (o que a
assessoria edita nunca é sobrescrito), takenOn e searchText com índice GIN trgm
(migration aditiva add_archive_photo_catalog); hook beforeValidate deriva o
índice e marca curadoria só em edição humana; pipeline transacional baixa os
bytes privados, prepara JPEG <=1024px com sharp e mescla o VLM local com o
gazetteer/catálogo curado (pessoas só do TEXTO, nunca de rosto); CLI
pnpm archive:catalog (plan/--apply/--verify, recibo honesto, idempotente por
catalogedAt) com engine OpenAI-compatible na rede privada atrás de guarda de
host (ARCHIVE_VISION_ALLOW_REMOTE é o escape); client HTTP com retry/timeout e
parser zod fail-closed; resolver de município extraído para owner compartilhado
com o catálogo de peças delegando; unit/int novos e runbook staging-primeiro.
2026-09-26 12:30:34 -03:00
Francisco Solla
3e8429daae feat(C229): busca por sentido no acervo de falas
Troca o motor do modo tema (Câmara + internet) de expansão lexical para
embeddings (Deep Infra, BAAI/bge-m3), com índice próprio (speechEmbedding),
ranking por proximidade em memória, evidência real do trecho mais próximo,
vazio honesto por limiar e degradação para a busca literal. Inclui a
collection oculta + migration, o CLI pnpm acervo:index (--dry-run/--limit/
--source/--force/--probe), o port do design aprovado e a suíte de testes.

Pós-rebase: o snapshot da migration seguinte (20260926_062039_add_archive_photo,
do C231 já na main) foi regenerado para incluir speech_embedding — sem ele o
próximo migrate:create recriaria a tabela.

Closes #1360
2026-09-26 11:59:21 -03:00
Francisco Solla
aba3aa4816 feat(C231): ingerir o acervo de fotos do Flickr no storage privado
Collection privada archivePhoto (flickrId unique+index, metadados do Flickr +
EXIF, leitura pela comunicação, mutação admin, entrada no mapa S3) com migration
aditiva add_archive_photo; ingestão idempotente (transação + upload) e CLI
pnpm flickr:import (plano dry-run por padrão, --apply com intenção/TEQO_ENV/S3,
--verify inventário read-only, recibos JSON em data/flickr/reports). Guard de
alvo extraído de reel-ingest para scripts/lib/cli.mjs; downloadUrlToFile ganha
headers (User-Agent do Flickr).
2026-09-26 05:40:22 -03:00
Francisco Solla
a9f377f985 fix(C225-large): espelha mídia web acima de 2 GiB 2026-09-26 03:57:27 -03:00
Francisco Solla
38e6742673 feat(C219): paridade de busca e filtros nas gravações do acervo (Closes #1295)
Some checks are pending
Deploy / preflight (push) Waiting to run
Deploy / verify (push) Blocked by required conditions
Deploy / deploy staging (teqo-staging) (push) Blocked by required conditions
Deploy / requeue when main advanced (push) Blocked by required conditions
Deploy / deploy production (teqo-1313) (push) Blocked by required conditions
Classificação automática com proveniência (job + CLI recordings:classify), facetas ano/tema/alcance/município/duração na URL canônica, busca por tema no corpus próprio, ordenação e a barra de filtros portada do design aprovado sobre os shells compartilhados. Deep-links existentes byte-idênticos; Câmara intocada.
2026-09-24 04:00:06 -03:00
Francisco Solla
8318fb5fce feat(C215): ingestão de falas da internet no acervo — origem web, espelho privado e catálogo (Closes #1291) 2026-09-24 03:26:10 -03:00
Francisco Solla
6480768926 feat(S30): card Time do estadual — 5º modelo com as 53 dobradinhas (Closes #1271) 2026-09-23 10:06:17 -03:00
Francisco Solla
31ebb932af feat(C197): narração rascunho (TTS pt-BR) + transcrição sempre no pacote do reel (Closes #1156) 2026-09-19 00:33:37 -03:00
Francisco Solla
83092adabf chore(C196): merge origin/main (resolve SCRIPTS_SPEC_PINNED com reel-ingest do C195) 2026-09-18 22:55:52 -03:00
Francisco Solla
a8a5ed324f
C195 — Ingestão do pacote do reel na biblioteca privada (#1182)
C195 — Ingestão do pacote do reel na biblioteca privada
2026-09-18 22:30:57 -03:00
Francisco Solla
8041f64b0b chore(C196): merge origin/main (resolve lista de commands) 2026-09-18 22:24:21 -03:00
Francisco Solla
560f2e494a feat(S15): card "Time de você" — quarto modelo auto-serviço no funil público (Closes #1161) 2026-09-18 22:17:52 -03:00
Francisco Solla
8504b3b13a feat(C196): skill /reels-tutoriais — captura mobile + composição de vídeo
- skill + command finos: shot list é a fonte única; ajuste regenera, nada publica
- scripts/build-reel.mjs + scripts/lib/reel*.mjs: captura CDP com timestamps de
  parede (sem drift), cursor/halo DOM-injected, zoompan do log de cliques,
  legendas queimadas, capa 1080x1350-safe, concat H.264 1080x1920/30fps
- ffmpeg: FFMPEG_PATH -> PATH -> @ffmpeg-installer (registry-only) com probe fail-closed
- kit oficial da campanha: public/campaign-kit (marcas positiva/negativa, numero,
  estrela) + manual em docs/campaign-kit + README de regras; skill e agente de
  design referenciam o material
- 26 testes unit novos + pin do command; changelog 2026-09-18-c196

Closes #1155
2026-09-18 21:50:28 -03:00
Francisco Solla
5afa16c33b feat(C195): ingestão do pacote do reel na biblioteca privada (Closes #1154) 2026-09-18 21:47:48 -03:00
Francisco Solla
10b58afe4c chore(OPS125): conta de teste dos agentes no staging (Closes #1126)
Some checks are pending
Deploy / preflight (push) Waiting to run
Deploy / verify (push) Blocked by required conditions
Deploy / deploy staging (teqo-staging) (push) Blocked by required conditions
Deploy / requeue when main advanced (push) Blocked by required conditions
Deploy / deploy production (teqo-1313) (push) Blocked by required conditions
2026-09-17 02:08:57 -03:00
Francisco Solla
c2ee60dd6a feat(OPS109): painel de issues e planos no terminal (via SSH) 2026-09-15 16:24:15 -03:00
Francisco Solla
ab9c164615 feat(OPS110): sessões persistentes de agente com attach/detach (Closes #1019) 2026-09-15 09:31:45 -03:00
Francisco Solla
fbe67f0358 feat(C162): player do acervo resolve o trecho sob demanda e YouTube vira default (Closes #999) 2026-09-14 07:09:58 -03:00
Francisco Solla
37b338a700 feat(OPS106): falha do verify dispara agente autônomo de desbloqueio (single-flight)
Workflow separado auto-unblock.yml (workflow_run no Deploy, push/main + job verify vermelho pela jobs API), launcher com flock próprio + Issue token auto-unblock como single-flight, e wrapper destacado que provisiona worktree fix/* via worktree.mjs fix --headless, aplica guard de banco local teqo_wt* fail-closed e roda opencode run --command bug-fix (cap 4h). deploy.yml/verify intocados; sem auto-retry e produção segue com approval humano.
2026-09-14 05:51:39 -03:00
Francisco Solla
aca3ea6188 feat(C153): catálogo de falas do Solla — schema, access, import idempotente e busca
Collections speech/speechSegment no grupo Comunicação, papel communicator
(leitura restrita) e índice trigram normalizado para a busca por segmento.
Import idempotente da Câmara (discurso→evento→trecho→VOD→ASR) com facetas
gazetteer+LLM, proveniência e preservação de curadoria manual; parser de
quem presidia; reusa a lógica pura do piloto C152 via scripts/lib.

Related #955
2026-09-13 02:08:55 -03:00
Francisco Solla
fa6933c1cd feat(C152): piloto da fonte de vídeos e transcrição minutada da Câmara
Spike de viabilidade da fonte (sem DB/Payload): script + lib pura + unit tests; 3 discursos (55ª/56ª/57ª) processados ponta a ponta com segmentos ASR; relatório em docs/research/.
2026-09-12 20:43:36 -03:00
Francisco Solla
493f4ba997 feat(OPS99): generate importMap at build time with dummy S3_* envs
Generate the Payload importMap at build time (Dockerfile) and dev time
(predev hook) with dummy S3_* envs, eliminating the class of bugs where
the admin goes blank because the S3ClientUploadHandler entry is missing
(OPS69/OPS72/OPS73).

Changes:
- Dockerfile: add pnpm generate:importmap with dummy S3_* envs before next build
- scripts/predev-importmap.mjs: predev hook that generates importMap if missing or stale
- Delete scripts/check-importmap-s3.mjs (guard no longer needed)
- Delete tests/unit/importMapS3UploadHandler.unit.spec.ts (unit pin no longer needed)
- Remove check-importmap-s3.mjs step from CI workflows
- Add importMap.js to .gitignore (build artifact, not committed)
- Update AGENTS.md with new contract

Closes #928
2026-08-27 16:05:36 -03:00
Francisco Solla
81513d5b14 fix(deploy): reverte package.json para desbloquear o deploy — cache deps do BuildKit
O deploy de fea6c645 falhou 2x: a mudança do script generate:importmap
em package.json invalidou a cache da camada deps do Dockerfile no
homeserver, e o pnpm install re-rodou do zero — o postinstall do
sharp@0.32.6 (transitivo) estourou o timeout baixando o libvips de
objects.githubusercontent.com ('sharp: Installation error: Request
timed out'; o git fetch de github.com funciona — o release vai por
outro hostname da CDN). Produção intocada (falha pré compose swap).

Reverte package.json ao byte do estado cacheado (a9f0c61e) — o install
nem roda. Remove o wrapper generate-importmap.mjs (desligado vira dead
code); proteção do importMap fica com o guard CI+deploy + pin unit +
contrato. Hardening do deps documentado no post-mortem (retry do
install / libvips via apk / proxy), changelog do follow-up incluído.
2026-08-27 09:04:47 -03:00
Francisco Solla
fea6c64514 fix(admin): restaura S3ClientUploadHandler no importMap — admin em branco em prod (4ª recorrência da classe OPS69)
O importMap commitado perdeu a entrada do handler S3 no 1c865bd8
(regenerado sem as envs S3_*): com S3_* em prod, getFromImportMap
retorna undefined e a raiz do Payload não monta — tela branca, zero
erros de console, invisível no loop local (storage local em dev/test).

Fix da causa: regeneração com S3_* dummy (+2 linhas). Prevenção no
mesmo PR — o guard planejado no OPS69 (depends #77/#87) que nunca
existiu: pin unit, guard CI+deploy que regenera com envs dummy e falha
em divergência, wrapper do generate:importmap que injeta as envs, e
contrato compartilhado da chave. Post-mortem + changelog incluídos.
2026-08-26 20:27:22 -03:00
Francisco Solla
c13174b8aa feat(ops96): motor de métricas baratas + @vitest/coverage-v8 atrás de flag 2026-08-25 02:42:40 -03:00
Francisco Solla
7d7fee1619 feat(OPS88): verify do CI/deploy com um Postgres e reset determinístico, um build por run (Closes #834) 2026-08-24 16:12:44 -03:00
Francisco Solla
2aa445dd1d impl(OPS84): verificar valores (não só entidades) da migração — 13 tabelas, 0 diffs (Closes #828) 2026-08-24 15:03:31 -03:00
Francisco Solla
60a71eea4b feat(OPS85): matar o agregado commitado do changelog — registro por-arquivo + HISTORY congelado + leitura sob demanda (Closes #830) 2026-08-24 14:44:25 -03:00
Francisco Solla
bddbd5c085 ops(OPS79): última migração de dados em produção — reconciliação da vertical campanha (Neon→teqo_1313) + migração do residual público (Closes #797)
- scripts/reconcile-campaign-vertical.mjs: verificação read-only repetível (contagens + junta de IDs das 13 coleções da vertical + conteúdo semântico das rels); absorve os 3 links de edição de portfolio pós-OPS51; nunca imprime PII
- scripts/migrate-signature-orphan.mjs: migração one-off com guard OPS79_MIGRATE_CONFIRM=1, dry-run/apply, transação única, PII mascarada
- Execução 100% no homeserver: aplicado contact 2225 + signature 1486 preservada + subscription 1492; sequences ajustadas; pós-verificação signature 1485=1485 e reconcile 19/19
- Runbook (docs/ops/teqo-1313-deploy.md §OPS79): execução + rollback (DELETE 3 linhas + setval)
- docs: plano de intenção restaurado (deletado acidentalmente em C140) + impl plan + changelog
2026-08-23 22:45:43 -03:00
Francisco Solla
0822cca82c chore: reduce token overhead in agent workflow
- Drop model-selection skill (dead, pool is dormant)
- Drop PNG rendering from UI planning (HTML-only, no pnpm ui-draft:render)
- Trim code-simplification: 331→~150 lines, Python/React examples moved to reference/
- Compress engineering-brief.md: remove redundant 'Pinhos do repo' (alwaysApply rules)
- Deduplicate capture-review-debts: reference decision-quality.md instead of re-explaining
- Create concise-output skill (35 lines) to enforce terse agent output
- Trim all 99 skill descriptions to ≤1 sentence
- Split AGENTS.md into layers: core (73 lines, always) + campaign/public/infra (on-demand)
- Decompose plan-issue: exploration sub-agent + parallel plan-writers + register sub-agent
- Decompose work-issue: exploration sub-agent + plan-writer + 2 parallel reviewers + debt sub-agent
- Update agent-work-issue to match sub-agent pattern
2026-08-21 20:38:56 -03:00
Francisco Solla
64ea0dbab9 ops(OPS54): allowlist onlyBuiltDependencies migra para pnpm-workspace.yaml — fim do warning do pnpm 10 sobre o campo pnpm ignorado 2026-08-18 09:06:37 -03:00
Francisco Solla
45e29a7785 feat(OPS52-media): recupera os objetos de media de produção do WordPress para o bucket (pnpm media:recover)
- scripts/recover-media.mjs: CLI de reconciliação (reconcile/--dry-run/--verify)
  — lê rows de media + posts.coverImage, resolve a capa com a mesma lógica do
  seed (featured media, senão 1ª imagem inline), PutObject com key = filename;
  DB nunca escrito; fail-closed (S3_* completas, ALLOW_REMOTE_DB, echo do alvo,
  timeouts curtos, covers só do origin WP e image/*)
- scripts/lib/wpArticles.mjs: fetch ao vivo do WordPress extraído do seed
  (sem twin), helpers puros de resolução + row→cover mapping (unit-testados)
- seed-posts.mjs: importa o fetch da lib (comportamento idêntico) e usa
  resolveCoverSource em processContent
- runbook de execução no homeserver (impl plan), nota no AGENTS.md, changelog
Closes #10
2026-08-18 08:20:45 -03:00
Francisco Solla
dabc00f46c ops(OPS52): migra a media de produção do Vercel Blob para o Garage S3
- payload.config.ts: vercelBlobStorage -> s3Storage (@payloadcms/storage-s3)
  com endpoint Garage (forcePathStyle, region garage); bucket privado — o
  staticHandler do plugin streama os objetos em /api/media/file/<filename>,
  mantendo o contrato de URL relativa das 40 rows pré-existentes
- src/utilities/mediaStorage.ts: resolveS3StorageEnv fail-closed (S3_* parcial
  -> throw no boot com a lista exata; nenhuma -> storage local dev/test)
- seed-posts: remove pre-delete do @vercel/blob (S3 sobrescreve nativamente)
- worktree-env.mjs: s3EnvCopiedLines all-or-nothing (unit-testada)
- envs S3_BUCKET/S3_ENDPOINT/S3_REGION/S3_ACCESS_KEY_ID/S3_SECRET_ACCESS_KEY
  no .env.example/.env.test; cloud-setup.sh sem o sed morto do blob
- deps: -storage-vercel-blob -@vercel/blob +storage-s3; importMap regenerado
- docs: impl plan (revisão A->B: Garage v2 sem acesso anônimo na API S3),
  AGENTS.md, changelog 2026-08-18-ops52
2026-08-17 22:36:34 -03:00
Francisco Solla
7ddc281f22 feat(site): publica home da campanha Jorge Solla 1313 2026-08-16 00:49:24 -03:00
Francisco Solla
9471c8f0aa OPS44: changelog por entrega + guards de docs + merge por rebase 2026-08-13 17:55:22 +00:00
Francisco Solla
5940c4c61e fix(OPS40): pnpm dev honra o PORT do .env.local — next dev -p via scripts/dev.mjs (Closes #682)
next dev resolve a porta antes de @next/env carregar env-files (commander
.env('PORT') no bin/next), então o PORT=3100+slot do provisionador de
worktree era ignorado e todo dev server subia em 3000. pnpm dev/devsafe
passam por scripts/dev.mjs: preflight do guard-dev-db inline, env com a
mesma precedência (real > .env.local > .env, override:false) e porta como
flag CLI -p (resolveDevPort/nextDevArgs em scripts/lib/cli.mjs,
unit-testados). Sem PORT → nenhum -p → default 3000 + allowRetry intactos.
2026-08-11 20:04:07 -03:00
Francisco Solla
631635ee89 chore(plan-issue): rascunho UI/UX do gate vira HTML+Tailwind commitado no repo (ad-hoc) 2026-08-11 19:14:21 -03:00
Francisco Solla
70070db8dc feat(C114): agenda da campanha espelhada no Google Calendar com notificação (push Teqo → Google)
Espelho oficial da agenda em calendário Google compartilhado via API
(service account, jose + fetch): reconciliação por passada com id
determinístico teqo+base32hex (upsert idempotente, sem estado por evento),
hooks afterChange/afterDelete na activity (só campos espelhados, nunca
lança), auto-resync quando calendarId muda, retry na view da agenda,
pill de estado no header + FAB + diálogo (4 estados). Cancelado no Teqo
deleta o evento no Google. Sem participantes no v1 (decisão de produto).
Sem migration nova de tabela (hand-written). Closes #635
2026-08-11 13:53:51 -03:00
Francisco Solla
7c17d43723 fix(OPS37): db:start idempotente — não recria o container Postgres compartilhado (no-op quando saudável; --force-recreate explícito) 2026-08-10 20:40:36 -03:00
Francisco Solla
f4873b8b3f fix(D6): push no device ponta a ponta — SW dinâmico, subscribe idempotente, check-push-chain
- /campanha/sw.js force-dynamic: buildId VERCEL_DEPLOYMENT_ID em runtime
  (deploys CLI --prebuilt não têm envs de build; prod servia campanha-dev)
- subscribeCampaignPush find-before-create (endpoint UNIQUE — 2º toque
  estourava com erro falso)
- scripts/check-push-chain.mjs + pnpm db:check:push-chain (read-only,
  veredito por elo: SW/envs/consent/inscrições/eventos)
- VAPID envs adicionadas no Vercel production (ops)
- impl plan + CHANGELOG-AGENTS
2026-08-09 23:41:00 -03:00
Francisco Solla
fdedfa9ad4 feat(C97): seletor shadcn de dia+horário 24h no popover de criação rápida da agenda
Troca o datetime-local nativo (AM/PM no idioma do browser, horário pouco
confiável) por ActivityDateTimeField: trigger com rótulo civil
dd/mm/aaaa às hh:mm + popover com Calendar (react-day-picker 9.7,
timeZone America/Bahia, locale pt-BR) e selects Hora 00-23 / Minuto
em passos de 15. Contrato de valor e submit inalterados; prefill do
slot mantido. Novo ui/Calendar.tsx (variante radix-nova), helpers
puros em campaignTime.ts. Sem migration. Closes #482 (PR).
2026-08-09 15:13:15 -03:00
Francisco Solla
5be317318d
chore(ai-chat): Sollinha volta para a DeepSeek direta (api.deepseek.com) (#476)
O cache-hit do DeepSeek-V4-Flash custa $0.0028/M contra $0.018/M na
Deep Infra (~6,4x mais barato), e a Sollinha tem prefixo estável
(system prompt + tools + historico), entao o custo efetivo cai. Mesmo
modelo (deepseek-v4-flash), mesmas tools. @ai-sdk/deepseek pinado em
3.0.19 para ficar na ferroviaria provider 4.0.4 / provider-utils
5.0.18 do ai@7.0.47 (o ^ flutuaria a 3.0.26 e duplicaria 4.0.7).

STT (B173) permanece na Deep Infra: whisper-large-v3 a $0.00045/min
de audio e o mais barato verificado (Groq $0.0019, OpenAI $0.006).
.env.example documenta as duas chaves: DEEPSEEK_API_KEY (LLM) e
DEEPINFRA_API_KEY (STT).
2026-08-09 06:11:00 +00:00