teqo-backup/src/lib/campaignConsentKeys.ts
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

53 lines
2.5 KiB
TypeScript

/**
* Stable LGPD consent keys the app resolves at runtime (fail-closed: the flows
* refuse to run while the admin has not created the Consent row with the exact
* key). Client-safe constants — the resolution logic lives in
* `src/utilities/campaignConsent.ts` (server-only).
*/
export const CAMPAIGN_INVITE_CONSENT_KEY = 'lideranca-autopreenchimento'
export const SUPPORTER_REGISTRATION_CONSENT_KEY = 'apoiador-cadastro'
export const SUPPORTER_VOTE_INTENTION_CONSENT_KEY = 'apoiador-intencao-voto'
/**
* Fail-closed refusals shown while the keyed Consent row is missing — matched
* verbatim by the routes' `safeMessages`, so they live next to their keys.
*/
export const SUPPORTER_REGISTRATION_CONSENT_MISSING_MESSAGE =
'Consentimento de cadastro de apoiador ainda não configurado.'
export const SUPPORTER_VOTE_INTENTION_CONSENT_MISSING_MESSAGE =
'Consentimento de intenção de voto ainda não configurado.'
/**
* Public-site WhatsApp subscription consent. Historically the flow hardcoded
* `consent: 2`; migration `20260725_170000_whatsapp_subscription_consent_key`
* tags that live document with this stable key (Pass 2 D3).
*/
export const WHATSAPP_SUBSCRIPTION_CONSENT_KEY = 'whatsapp-inscricao'
export const CAMPAIGN_PUSH_CONSENT_KEY = 'campanha-notificacoes-push'
export const CAMPAIGN_PUSH_CONSENT_MISSING_MESSAGE =
'Consentimento de notificações push ainda não configurado.'
/**
* C234 — the public selfie search on the photo album. Two keys because the
* two biometric uses are distinct: `FACE_SEARCH_CONSENT_KEY` is the temporary
* use of the querying person's face to find themselves in the album (the
* vector is discarded with the request), while `FACE_INDEX_CONSENT_KEY` is
* the enrollment in the search index (the vector is stored until removal).
* Both fail closed: without the Consent row with the exact key the flow is
* closed, and editing the text invalidates every enrolled subject until
* re-consent.
*/
export const FACE_SEARCH_CONSENT_KEY = 'busca-selfie-fotos'
export const FACE_INDEX_CONSENT_KEY = 'busca-selfie-indice'
/**
* S9 — campaign home "novidades" capture (name + WhatsApp, engagement level
* toggle). Fail-closed like every public flow: while the admin has not created
* the Consent row with this key (jurídico-approved text pending), the form
* refuses to record anything.
*/
export const CAMPAIGN_NEWSLETTER_CONSENT_KEY = 'campanha-novidades'
export const CAMPAIGN_NEWSLETTER_CONSENT_MISSING_MESSAGE =
'Consentimento de novidades da campanha ainda não configurado.'