Consentimento
A atestação do responsável, o link de consentimento, a página pública, a evidência por selfie e áudio, a recusa e a parada pela própria pessoa.
A proteção só liga com o sim da própria pessoa (AD-009). São duas camadas:
- Atestação do responsável: a base legal, gravada na ativação (
guardianAttestation: true). - Consentimento da pessoa: ela abre um link, lê o que será acessado e confirma com uma selfie e um áudio lendo a frase do termo.
Ao lado corre a checagem de vínculo, que confere a relação declarada pelo documento. Só refuted bloqueia. Hoje não há provedor ligado, e toda checagem sai inconclusive (vai pra revisão manual).
Lado do responsável
| Ação | Rota |
|---|---|
| Pedir o sim (vaga pendente, antes do cartão) | POST /seats/{uid}/consent-request com { send: "now" | "later" }. Veja Onboarding |
| Ver o estado | GET /seats/{uid}/consent: o consentimento, a evidência recebida (só metadados, nunca os arquivos), a checagem de vínculo, pairingAllowed e blockedBy |
| Mandar um link novo | POST /seats/{uid}/consent-request/resend. O anterior para de funcionar |
| Retirar o pedido pendente | DELETE /seats/{uid}/consent-request. Não desfaz um sim já dado |
O link vai por WhatsApp quando o telefone começa com +55, e por SMS nos outros casos. Vale CONSENT_TTL_HOURS (padrão 72 h). O objeto consent da vaga traz a linha do tempo da entrega: sentAt, deliveredAt (recibo da Meta), openedAt, declinedAt, resendAvailableAt, revokedAt e revokedBy. link aparece só enquanto o pedido está pending.
Status do pedido: pending, given, declined, expired ou revoked.
Lado da pessoa (rotas públicas pelo token)
-
Abrir o link.
GET /consent-requests/{token}devolve quem pede, o nome da família, o que será acessado (scope), a frase exata pra ler (congelada nesse pedido, comphraseVersionetermsVersion), o blocoprivacyeprotection(not_started,active,pausedoustopped). A primeira abertura geraconsent.openedpros responsáveis. -
Dar o sim.
POST /consent-requests/{token}/evidence, emmultipart/form-data:Campo Regra selfieimage/jpeg,pngouwebp, até 8 MB. Exatamente um rostoaudioaudio/webm,mp4,ogg,mpegouwav(aceitavideo/webm), até 20 MB. Precisa bater com a fraseaccepted"true"audioDurationMsOpcional A verificação roda antes de guardar qualquer coisa. Só depois de aprovada os arquivos são gravados e o pedido vira
given(201). A resposta trazprotectionLink, o link de "Minha proteção" da própria pessoa. Ele aparece uma vez, só na tela dela, e nunca em resposta pro responsável. -
Ou recusar.
POST /consent-requests/{token}/declinecom{ choice: "not_now" | "talk_first" }. A escolha fica no servidor: o responsável recebe só o fato e a hora (consent.declined), nunca o motivo. Repetir a recusa devolve a primeira. Depois de uma recusa, o resend fica travado porCONSENT_RESEND_COOLDOWN_HOURS(padrão 24 h,RESEND_LOCKED).
Erros da evidência: AUDIO_PHRASE_MISMATCH (com expected, heard, missing, score), AUDIO_UNINTELLIGIBLE, SELFIE_NO_FACE, CONSENT_EXPIRED (422), 409 se o sim já foi dado, 503 EVIDENCE_VERIFICATION_UNAVAILABLE se o verificador estiver fora. Todas as rotas públicas têm limite de taxa.
Minha proteção e a parada
GET /consent-requests/{token}/protection: o estado (not_started,active,pausedoustopped), desde quando, quem recebe os avisos (nome e vínculo, nunca e-mail), o que essas pessoas recebem, o que ninguém vê e o que acontece com a selfie e a voz.POST /consent-requests/{token}/stopcom{ confirm: true }: a pessoa para a proteção sozinha (D7). Os efeitos estão em Pausar e parar.
As duas rotas aceitam o link de consentimento ou o link de proteção. Quando um consentimento mais novo é dado, os links antigos param (422 PROTECTION_LINK_REPLACED). Um link cujo pedido nunca recebeu o sim responde 422 CONSENT_NOT_GIVEN.
Biometria e retenção (D6)
- Toda chamada ao verificador (OpenRouter) pede
data_collection: "deny"ezdr: true. O provedor não guarda nem treina com a selfie e o áudio. - Os arquivos ficam no storage (S3/MinIO) enquanto o consentimento vale, porque são a prova.
- Eles são apagados
EVIDENCE_RETENTION_DAYS(padrão 180) depois que o consentimento termina: parada pela pessoa, troca por um consentimento mais novo ou vaga arquivada. O workerevidence-purgerroda de hora em hora. A linha emconsent_evidencefica com tipo, tamanho, sha256 epurged_at.
const form = new FormData();
form.append("selfie", selfieBlob, "selfie.jpg");
form.append("audio", audioBlob, "voz.webm");
form.append("accepted", "true");
const res = await fetch(`${API}/consent-requests/${token}/evidence`, {
method: "POST",
body: form,
});
const body = await res.json();
if (body.success)
showDone(body.data.protectionLink); // mostrar só pra pessoa
else if (body.error.code === "AUDIO_PHRASE_MISMATCH")
highlight(body.error.details.missing);Em aberto
- Ainda não existe provedor de checagem de vínculo: todo resultado é
inconclusive, e a revisão manual não tem tela. - Nenhum template de WhatsApp leva o
protectionLink(G-37). Se a pessoa perder o link, não há como reenviá-lo hoje. - A renovação do consentimento com diff do termo (G-18) e a frase v2 sem CPF (G-12, regra P6) ainda não estão na
main. A página pública ainda devolvedependent.documentMasked.
Fontes
backend/src/http/routes/consents/page.route.ts,evidence.route.ts,decline.route.ts,protection.route.ts,schemas.tsbackend/src/http/routes/seats/consent-request.route.ts,consent-status.route.ts,activate.route.tsbackend/src/domains/consents/use-cases/request-consent.ts,submit-evidence.ts,decline-consent.ts,protection.ts,purge-evidence.tsbackend/src/domains/consents/checks/registry.ts,verification/errors.tsbackend/apps/workers/evidence-purger.ts,backend/src/config/env.ts- Notas da frente k-consent (
k-consent-api.md) .specs/features/redesign/api-gaps.md(G-12, G-16, G-17, G-18, G-37),api-map.md(§0.2)- AD-009, AD-011 (verificação de evidência), AD-019 (D6, D7)
Onboarding
Da conta de família à vaga ativa, com o consentimento antes do cartão (D2) e o teste grátis contado a partir da primeira conexão (D1).
Pareamento
Como o app do responsável conecta o WhatsApp da pessoa protegida - pré-requisitos, código no celular da pessoa ou QR na tela, estados, eventos e erros.
