LGPD — Conformidade
Visão Geral
Implementa os direitos do titular de dados (Lei Geral de Proteção de Dados Pessoais, Lei 13.709/2018):
- Art. 9º — informação sobre tratamento
- Art. 16 — eliminação de dados pessoais
- Art. 17-21 — acesso, correção, portabilidade
- Art. 8º — gestão de consentimento
Tudo via interface admin única e endpoint API estruturado.
Localização
| Camada | Arquivo |
|---|---|
| Módulo | backend/src/lgpd/lgpd.module.ts |
| Service | backend/src/lgpd/lgpd.service.ts |
| Controller | backend/src/lgpd/lgpd.controller.ts |
| Schemas | backend/src/lgpd/schemas/{data-subject-request,consent-record,retention-policy}.schema.ts |
| View | frontend-react/src/views/admin/LgpdView.tsx |
Rota
/t/:slug/admin/lgpd
Data Subject Requests (DSR)
Cada solicitação do titular vira um DataSubjectRequest:
| Campo | Tipo | Descrição |
|---|---|---|
tenant | ObjectId | |
subjectEmail | string | Email do titular |
requestType | enum | access | correction | deletion | portability |
status | enum | pending | in_progress | completed | rejected |
dueDate | Date | createdAt + 15 dias |
handledBy | string? | userId que processou |
notes | string? |
A LGPD exige resposta em 15 dias úteis. O dueDate é calculado automaticamente; o painel ordena por proximidade do vencimento.
Endpoint
POST /admin/lgpd/dsr — cria pedido (também aceita do portal público em POST /public/lgpd/dsr)
PUT /admin/lgpd/dsr/:id — atualiza status / adiciona notes
Hard-Delete
Quando uma DSR de deletion é completada, LgpdService.deleteCustomerData(email, tenantId):
- Anonimiza
User: email →deleted-{uuid}@anon.local, name →Cliente Removido, phone → null - Apaga
ConsentRecorddo usuário - Mantém pedidos/comandas históricos (necessário para fiscal/contábil) mas remove referência ao usuário
Nota: dados fiscais (NF-e, EFD) são imutáveis por requirement legal — mantemos a CPF do consumidor na nota mesmo após o hard-delete, pois a SEFAZ rejeitaria modificação. Documentado no DSR como "campos fiscais retidos por obrigação legal".
Retenção Programada
RetentionPolicy define períodos por tipo de dado:
| Tipo | Default |
|---|---|
| Fiscal (NF-e XMLs) | 5 anos |
| Pagamento (transações) | 10 anos |
| Audit log | 2 anos |
| Suporte / tickets | 1 ano |
| Comportamental (cliques, sessões) | 90 dias |
Defaults em LgpdService.seedDefaultRetention(). Admin pode customizar por tenant.
Job semanal (@Cron('0 4 * * 0')) varre cada coleção e remove documentos cujo createdAt + retentionDays < now. Resultados logados em RetentionRunLog.
Consent Management
ConsentRecord registra cada consentimento dado:
| Campo | Tipo |
|---|---|
userId | ObjectId |
purpose | string (ex: marketing_email, loyalty_program, analytics) |
granted | boolean |
grantedAt | Date |
revokedAt | Date? |
version | string (versão do termo aceito) |
ipAddress | string |
userAgent | string |
upsertConsent(userId, purpose, granted) substitui o registro anterior. revokeConsent(userId, purpose) apenas marca revokedAt (não apaga — auditoria precisa do histórico).
Antes de qualquer envio de campanha, EmailCampaignService.sendCampaign filtra a audiência para incluir só quem tem granted: true no purpose marketing_email.
Subscription Lifecycle ↔ LGPD
Quando uma assinatura entra em scheduled_for_deletion (após 60 dias de restricted), o worker BullMQ subscription-lifecycle.processor.ts chama LgpdService.deleteCustomerData() para todos os usuários do tenant cancelado. Esse é o único caminho automático para hard-delete em massa.
Tenants individualmente cancelados sem essa via continuam com dados intactos — o admin precisa gerar DSRs manualmente se quiser apagar.
Exporting (Art. 18, II)
GET /admin/lgpd/export/:userId retorna um zip com:
user.json— perfil completoorders.json— pedidos do usuárioconsents.json— histórico de consentimentosaddresses.json— endereços salvosloyalty.json— pontos / tier (se aplicável)
Formato JSON simples para portabilidade. PDF estilizado é roadmap.
Direitos do Funcionário (HR)
Além dos direitos dos clientes, o módulo LGPD suporta exercício dos direitos dos funcionários cadastrados no módulo HR, respeitando o prazo de retenção trabalhista de 5 anos (CLT Art. 11).
Schema LgpdAuditLog
Cada ação LGPD (exportação ou anonimização) gera um registro imutável e append-only na coleção lgpd_audit_logs:
| Campo | Tipo | Descrição |
|---|---|---|
tenant | ObjectId | |
actorUserId | string | UserId do admin que executou a ação (ou system para crons) |
actorRole | string | admin, superadmin ou system |
subjectType | customer | employee | Tipo do titular |
subjectId | string | ObjectId do Employee ou User |
action | lgpd_export | lgpd_anonymize | |
lawfulBasis | data-subject-request | retention-expiry | Base legal |
payloadHash | string | SHA-256 hex do payload exportado ou dos parâmetros de anonimização — permite auditoria de integridade |
justification | string? | Justificativa livre capturada do corpo da requisição |
retainTaxRecords | boolean? | Se registros fiscais/trabalhistas foram retidos na anonimização |
Arquivo: backend/src/lgpd/schemas/lgpd-audit-log.schema.ts
Registros são retidos por 5 anos (CLT Art. 11 / LGPD Art. 16).
Endpoint de Exportação de Funcionário
GET /t/:slug/admin/rh/employees/:id/lgpd-export
Authorization: Bearer <admin-token>Retorna o arquivo lgpd-export-{id}-{data}.json com todos os dados PII do funcionário (nome, CPF descriptografado, conta bancária, salário, registros de ponto, solicitações de férias). Grava um LgpdAuditLog com action: lgpd_export e hash SHA-256 do payload antes de responder.
Permissão: Admin ou Superadmin.
Endpoint de Anonimização de Funcionário
POST /t/:slug/admin/rh/employees/:id/lgpd-anonymize
Authorization: Bearer <admin-token>
Content-Type: application/json
{
"justification": "Solicitação do titular — Art. 18 LGPD",
"retainTaxRecords": true
}Realiza a anonimização em cascata:
Employee: nome →Funcionário Removido, CPF → hash mantido (necessário para unicidade),cpfEncrypted→ removido,bankAccountEncrypted→ removido,baseSalaryCipher→ removido,lgpdAnonymized = true.Timesheet: registros de localização GPS (location) → removidos.LeaveRequest: notas livres → removidas.PayrollLine(seretainTaxRecords = false):deductionsCipher→ removido. Setrue: mantido para obrigações fiscais.- Grava
LgpdAuditLogcomaction: lgpd_anonymize.
Idempotência: Retorna 409 Conflict se Employee.lgpdAnonymized === true — a anonimização não é re-executada.
Permissão: Admin ou Superadmin.
Regra de Retenção — CLT Art. 11
Ao demitir um funcionário (PATCH /admin/hr/employees/:id/terminate), o HrService define automaticamente:
Employee.lgpdRetentionExpiresAt = dismissalDate + 5 anosO cron diário de retenção (LgpdRetentionCron) varre Employee com lgpdRetentionExpiresAt <= hoje e lgpdAnonymized = false, e executa a anonimização automaticamente com lawfulBasis: 'retention-expiry'. Isso garante conformidade com o prazo CLT sem ação manual do admin.
Nota: O prazo de 5 anos reflete a prescrição trabalhista do CLT Art. 11. Registros eSocial (
EsocialEvent.xmlPayload) têm prazo de retenção próprio de 5 anos conforme exigência da RFB — configure emRetentionPolicyseparadamente.
Controlador LGPD HR
backend/src/lgpd/lgpd.controller.ts → classe LgpdHrController
Rotas base: /t/:slug/admin/rh/employees