Skip to content

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

CamadaArquivo
Módulobackend/src/lgpd/lgpd.module.ts
Servicebackend/src/lgpd/lgpd.service.ts
Controllerbackend/src/lgpd/lgpd.controller.ts
Schemasbackend/src/lgpd/schemas/{data-subject-request,consent-record,retention-policy}.schema.ts
Viewfrontend-react/src/views/admin/LgpdView.tsx

Rota

/t/:slug/admin/lgpd


Data Subject Requests (DSR)

Cada solicitação do titular vira um DataSubjectRequest:

CampoTipoDescrição
tenantObjectId
subjectEmailstringEmail do titular
requestTypeenumaccess | correction | deletion | portability
statusenumpending | in_progress | completed | rejected
dueDateDatecreatedAt + 15 dias
handledBystring?userId que processou
notesstring?

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):

  1. Anonimiza User: email → deleted-{uuid}@anon.local, name → Cliente Removido, phone → null
  2. Apaga ConsentRecord do usuário
  3. 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:

TipoDefault
Fiscal (NF-e XMLs)5 anos
Pagamento (transações)10 anos
Audit log2 anos
Suporte / tickets1 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.


ConsentRecord registra cada consentimento dado:

CampoTipo
userIdObjectId
purposestring (ex: marketing_email, loyalty_program, analytics)
grantedboolean
grantedAtDate
revokedAtDate?
versionstring (versão do termo aceito)
ipAddressstring
userAgentstring

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 completo
  • orders.json — pedidos do usuário
  • consents.json — histórico de consentimentos
  • addresses.json — endereços salvos
  • loyalty.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:

CampoTipoDescrição
tenantObjectId
actorUserIdstringUserId do admin que executou a ação (ou system para crons)
actorRolestringadmin, superadmin ou system
subjectTypecustomer | employeeTipo do titular
subjectIdstringObjectId do Employee ou User
actionlgpd_export | lgpd_anonymize
lawfulBasisdata-subject-request | retention-expiryBase legal
payloadHashstringSHA-256 hex do payload exportado ou dos parâmetros de anonimização — permite auditoria de integridade
justificationstring?Justificativa livre capturada do corpo da requisição
retainTaxRecordsboolean?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:

  1. Employee: nome → Funcionário Removido, CPF → hash mantido (necessário para unicidade), cpfEncrypted → removido, bankAccountEncrypted → removido, baseSalaryCipher → removido, lgpdAnonymized = true.
  2. Timesheet: registros de localização GPS (location) → removidos.
  3. LeaveRequest: notas livres → removidas.
  4. PayrollLine (se retainTaxRecords = false): deductionsCipher → removido. Se true: mantido para obrigações fiscais.
  5. Grava LgpdAuditLog com action: 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 anos

O 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 em RetentionPolicy separadamente.

Controlador LGPD HR

backend/src/lgpd/lgpd.controller.ts → classe LgpdHrController

Rotas base: /t/:slug/admin/rh/employees

Lançado sob a licença MIT.