Admin DSR Management

DPO/staff-side workflow for handling subject requests: queue, identity verification, response within 30 days, audit trail.

Open in StackBlitzOpen in CodeSandbox

The public DSR portal is half the story. The other half is the DPO / staff workflow: triage the queue, verify identity, generate the response, hit Section 34's 30-day deadline (extendable to 60 if complex, per GAID 2025), and keep an audit trail NDPC can ask for. This recipe wires those pieces.

DPO dashboard

'use client';
import { DSRDashboard } from '@tantainnovative/ndpr-toolkit';
import { useDSR } from '@tantainnovative/ndpr-toolkit/hooks';
import { apiAdapter } from '@tantainnovative/ndpr-toolkit/adapters';
import type { DSRRequest } from '@tantainnovative/ndpr-toolkit/core';

const adapter = apiAdapter<DSRRequest[]>('/api/admin/dsr', {
  credentials: 'include',
  retry: { attempts: 2 },
});

export default function DPODashboard() {
  return (
    <DSRDashboard
      adapter={adapter}
      requestTypes={[
        { id: 'access', name: 'Access', ndpaSection: 'Section 34(1)(a)', estimatedCompletionTime: 30, requiresAdditionalInfo: false },
        { id: 'rectification', name: 'Rectification', ndpaSection: 'Section 34(1)(c)', estimatedCompletionTime: 30, requiresAdditionalInfo: true },
        { id: 'erasure', name: 'Erasure', ndpaSection: 'Section 34(1)(d)', estimatedCompletionTime: 30, requiresAdditionalInfo: false },
        { id: 'portability', name: 'Portability', ndpaSection: 'Section 38', estimatedCompletionTime: 30, requiresAdditionalInfo: false },
        { id: 'objection', name: 'Objection', ndpaSection: 'Section 36', estimatedCompletionTime: 30, requiresAdditionalInfo: true },
        { id: 'withdraw_consent', name: 'Withdraw Consent', ndpaSection: 'Section 35', estimatedCompletionTime: 30, requiresAdditionalInfo: false },
      ]}
    />
  );
}

Identity verification workflow

Before fulfilling an access or erasure request, you must verify the requester actually is the data subject. NDPA doesn't prescribe the method — common patterns:

  • Email magic link: send a verification link to the email on file. Cheap and good enough for low-sensitivity requests.
  • Government ID upload: NIN slip + selfie. Standard for fintech / healthcare. Be careful — you're processing fresh sensitive PII to verify; delete after verification (Section 24(1)(e)).
  • Account login: if the data subject has an active account, requiring them to log in to submit the request is sufficient.

Transition the request status from awaitingVerificationinProgress when verification completes:

// app/api/admin/dsr/[id]/verify/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { verifyDSRSession } from '@/server/dsr-verify'; // your custom auth check

export async function POST(req: NextRequest, { params }: { params: { id: string } }) {
  await verifyDSRSession(req); // ensure caller is the DPO / authorised staff

  // Mark verified — Section 34 30-day clock keeps running from submission
  await db.dsrRequest.update({
    where: { id: params.id },
    data: {
      status: 'inProgress',
      verifiedAt: new Date(),
      // dueDate stays at original (createdAt + 30 days)
    },
  });

  return NextResponse.json({ ok: true });
}

30-day deadline tracking

The useDSR hook exposes getRequestsByStatus — combine with a custom sort to surface requests close to the 30-day deadline:

'use client';
import { useDSR } from '@tantainnovative/ndpr-toolkit/hooks';

export function OverdueAlert({ requestTypes }: { requestTypes: any[] }) {
  const { requests } = useDSR({ requestTypes });
  const now = Date.now();
  const overdue = requests.filter(
    (r) => r.status !== 'completed' && r.dueDate && r.dueDate < now,
  );
  const closeToDeadline = requests.filter(
    (r) =>
      r.status !== 'completed' &&
      r.dueDate &&
      r.dueDate > now &&
      r.dueDate - now < 5 * 24 * 60 * 60 * 1000, // 5 days
  );

  if (overdue.length === 0 && closeToDeadline.length === 0) return null;
  return (
    <aside className="rounded border border-red-200 bg-red-50 p-3 text-sm">
      {overdue.length > 0 && <p><strong>{overdue.length} DSRs are past the 30-day deadline.</strong> Section 34 violation risk.</p>}
      {closeToDeadline.length > 0 && <p>{closeToDeadline.length} DSRs due in the next 5 days.</p>}
    </aside>
  );
}

Audit trail

Every state transition (received → verified → in-progress → completed/rejected) should be recorded with a timestamp, the staff member who acted, and a one-line reason. NDPC asks for this trail during compliance investigations. The toolkit's internalNotes field on DSRRequest covers it.

Related