The tension nobody mentions
Nigeria's Data Protection Act (NDPA 2023) gives every data subject the right to:
- Access: know what data you hold about them
- Rectification: correct inaccurate data
- Erasure: have their data deleted
CBN's AML/CFT regulations require financial institutions to retain:
- Transaction records and screening evidence for 5 years after the relationship ends
- KYC/CDD records for the same period
- Suspicious transaction reports indefinitely
- An immutable audit trail
These obligations directly conflict when a customer says "delete everything you have on me" and the law says "you must keep their transaction history for five years."
Most platforms either ignore NDPA (leaving the bank exposed) or implement a naive "delete" that destroys AML evidence (leaving the bank exposed differently). Neither is acceptable.
Our solution: a documented carve-out
When a compliance officer fulfills an erasure request, the system automatically:
Erases (platform processing, no statutory retention)
- Behavioral auth events (login/logout telemetry)
- Behavioral profile (EWMA baseline, device/geo memory, trust score)
- Behavioral engine blacklist flags for the account
Retains (AML statutory records, CBN 5-year rule)
- Transactions and verdicts (screening evidence)
- Cases, SAR/CTR/FTR reports, interdiction records
- KYC application and documents
- The hash-chained audit trail
Every erasure produces a determination document stored on the request:
{
"erased": [
{ "record": "behavioral_events", "basis": "platform processing" },
{ "record": "behavioral_profile", "basis": "platform processing" },
{ "record": "engine_blacklist_flags", "basis": "platform processing" }
],
"retained": [
{ "record": "transactions + verdicts", "basis": "CBN AML/CFT statutory retention (5 years)" },
{ "record": "cases, reports, audit trail", "basis": "regulatory evidence, NFIU/CBN obligations" },
{ "record": "KYC application + documents", "basis": "CDD record retention" }
]
}
The audit answer: this is the evidence an NDPA auditor asks for. "You received an erasure request. Show us what you erased, what you retained, and why."
The access export
When a customer asks "what data do you have on me?", the officer clicks Generate export and gets a structured JSON bundle containing:
- Transactions (as sender AND receiver)
- Every screening verdict with triggered rules
- Linked cases
- Sanctions screening results
- KYC applications with risk levels
- Customer risk history (reclassifications with drivers)
- Behavioral profile and auth events
- A retention notice explaining what's kept and why
Every export generation is audited and recorded on the request. The officer can see how many times the data was exported and by whom.
The statutory clock
NDPA requires response within 30 days. Every request gets:
- A due date (30 days from receipt)
- Overdue flags in the dashboard
- A stat strip showing open/past-due counts
Identity protection
Subject identifiers are masked in list views (******6789). Full account numbers are only visible inside an open request. This isn't just UX polish; it prevents shoulder-surfing in a compliance office where multiple officers work side by side.
Rejection requires justification
A DSAR can be rejected (e.g., the requester isn't the data subject), but only with documented justification. The API returns 400 without notes, and the rejection reason is stored in the request's timeline.
The engineering
The DSAR module is a clean NestJS module with:
- Pure utility functions for date calculations, status transitions, and identifier masking (9 unit tests)
- A service that aggregates the subject's data from 8 different tables using blind-index hashes
- An audited workflow: every state change lands in the hash-chained audit trail
- A role-guarded controller (BANK_ADMIN / COMPLIANCE_OFFICER only)
The erasure execution reuses the existing behavioral feedback service (which already knows how to clear engine flags), so there's no code duplication between "officer removes someone from the blacklist" and "data subject exercises their erasure right."
See a live trace on your own data
We'll run the tracer against a scenario from your institution in a 30-minute demo: blocked transaction, full fund trace, frozen destination, packaged case.