CLI Scaffolder
Scaffold a full NDPA-compliant backend in seconds with create-ndpr — detects your stack and generates API routes, database schema, and layout wrappers automatically
Overview
create-ndpr is a zero-dependency interactive CLI that wires the NDPA compliance toolkit into an existing project. Run it once from your project root and it:
- Inspects your project and detects the framework and ORM automatically
- Asks a few questions about your organisation
- Generates ready-to-use API routes, database schema, and layout files
- Embeds your organisation name and DPO email in every generated file
No extra packages are required to run the CLI itself — it ships as a single .mjs file with no external dependencies, so npx can execute it straight from the npm registry on Node.js 18+.
Usage
Run the CLI from the root of an existing project — the same directory where your package.json and next.config.* live.
# Recommended — always uses the latest published version
npx @tantainnovative/create-ndpr
# Short alias (once the package is registered on npm)
npx create-ndprRun from the project root
The CLI reads package.json, next.config.*, prisma/schema.prisma, and drizzle.config.* from the current working directory. Always cd into your project root before running it.
What It Detects
Before prompting for anything, the CLI performs a silent stack-detection pass. The detected values are shown upfront and can be overridden at the framework and ORM prompts.
| Signal | Detected as |
|---|---|
| next.config.js / .ts / .mjs | Next.js project |
| app/ or src/app/ directory | Next.js App Router |
| No app/ directory + next.config.* | Next.js Pages Router |
| express in package.json deps | Express |
| @prisma/client or prisma in deps, or prisma/schema.prisma | Prisma ORM |
| drizzle-orm / drizzle-kit in deps, or drizzle.config.* | Drizzle ORM |
What It Prompts For
The CLI walks through four short sections. Detected values are pre-selected as defaults so you can press Enter to confirm them.
1. Organisation details
- Organisation name — embedded in every generated file (e.g. Acme Corp Nigeria Ltd)
- DPO email address — the Data Protection Officer contact used in notices and policy headers
2. Framework
- Next.js — App Router
- Next.js — Pages Router
- Express
- None (generate shared files only)
Auto-detected from your project; you can override the choice.
3. Compliance modules
Multi-select. Defaults: consent, dsr, breach.
consent— NDPA §25-26 consent managementdsr— Data Subject Rights requests (§34-38)breach— 72-hour breach notification workflow (§40)policy— Privacy policy scaffoldingdpia— Data Protection Impact Assessmentlawful-basis— Lawful basis register (§25)cross-border— Cross-border transfer management (§43)ropa— Record of Processing Activities
4. ORM
- Prisma — generates
prisma/schema.prismawith NDPA models - Drizzle — generates
src/drizzle/ndpr-schema.ts - None — skips database schema generation
A summary is shown before any files are written. You can abort at the confirmation prompt with no changes made to your project.
What Files It Generates
Every file is rendered from a template with your organisation name and DPO email substituted in. Files that already exist on disk are skipped rather than overwritten.
| File | Generated when | Purpose |
|---|---|---|
| .env.example | Always | Environment variable template with DATABASE_URL and NDPA_DPO_EMAIL pre-filled |
| prisma/schema.prisma | ORM = Prisma (if not already present) | Prisma schema with ConsentRecord, DSRRequest, BreachReport, and AuditLog models |
| src/drizzle/ndpr-schema.ts | ORM = Drizzle | Drizzle table definitions mirroring the Prisma schema above |
| app/ndpr-layout.tsx | Next.js App Router | NDPRProvider wrapper component — import and render around your children |
| app/api/consent/route.ts | App Router + consent module | POST handler: saves consent records; GET handler: returns current consent |
| app/api/dsr/route.ts | App Router + dsr module | POST handler: saves DSR submissions; GET handler: lists requests by email |
| app/api/breach/route.ts | App Router + breach module | POST handler: records breach reports and triggers 72-hour timer logic |
| pages/api/consent.ts | Pages Router + consent module | Same logic as the App Router variant, in Pages Router format |
| pages/api/dsr.ts | Pages Router + dsr module | Pages Router DSR handler |
| pages/api/breach.ts | Pages Router + breach module | Pages Router breach handler |
| src/ndpr/index.ts | Express | Express router factory — exports createNDPRRouter() |
| src/ndpr/routes/consent.ts | Express + consent module | Express consent route handler |
If prisma/schema.prisma already exists the CLI skips it and prints the template path so you can merge the NDPA models manually.
Example: Next.js + Prisma
Below is an example session for a Next.js App Router project with Prisma, including consent, DSR, and breach modules.
$ npx @tantainnovative/create-ndpr
███╗ ██╗██████╗ ██████╗ ██████╗
████╗ ██║██╔══██╗██╔══██╗██╔══██╗
██╔██╗ ██║██║ ██║██████╔╝██████╔╝
██║╚██╗██║██║ ██║██╔═══╝ ██╔══██╗
██║ ╚████║██████╔╝██║ ██║ ██║
╚═╝ ╚═══╝╚═════╝ ╚═╝ ╚═╝ ╚═╝
create-ndpr — NDPA compliance scaffolder
Powered by @tantainnovative/ndpr-toolkit
Detected project setup:
Framework: Next.js (App Router)
ORM: Prisma
Organisation details
Organisation name (e.g. Acme Corp Nigeria Ltd): Acme Corp Nigeria Ltd
DPO email address (e.g. dpo@acmecorp.ng): dpo@acme.ng
Framework
Which framework are you using?
1) Next.js — App Router
2) Next.js — Pages Router
3) Express
4) None (generate shared files only)
Choice [1]:
Compliance modules [default: 1,2,3]
1) consent — NDPA §25-26 consent management
2) dsr — Data Subject Rights requests (§34-38)
3) breach — Breach notification workflow (§40)
4) policy — Privacy policy generation
5) dpia — Data Protection Impact Assessment
6) lawful-basis — Lawful basis register
7) cross-border — Cross-border transfer management
8) ropa — Record of Processing Activities
Enter numbers separated by commas (or press Enter for default):
Database / ORM
Which ORM are you using?
1) Prisma
2) Drizzle
3) None (skip database schema)
Choice [1]:
Summary
Organisation: Acme Corp Nigeria Ltd
DPO email: dpo@acme.ng
Framework: Next.js — App Router
ORM: Prisma
Modules: consent, dsr, breach
Generate files? [Y/n]:
Generating files...
+ .env.example
+ prisma/schema.prisma
+ src/app/ndpr-layout.tsx
+ src/app/api/consent/route.ts
+ src/app/api/dsr/route.ts
+ src/app/api/breach/route.ts
Done! Files generated:
✓ .env.example
✓ prisma/schema.prisma
✓ src/app/ndpr-layout.tsx
✓ src/app/api/consent/route.ts
✓ src/app/api/dsr/route.ts
✓ src/app/api/breach/route.ts
Next steps:
1. Set your database URL in .env:
DATABASE_URL="postgresql://user:password@localhost:5432/mydb_dev"
2. Install the Prisma client and run migrations:
pnpm add @prisma/client
pnpm add -D prisma
pnpm prisma migrate dev --name ndpr-init
3. Install the ndpr-toolkit:
pnpm add @tantainnovative/ndpr-toolkit
4. Wrap your root layout with NDPRLayout:
// src/app/layout.tsx
import NDPRLayout from './ndpr-layout';
// Render <NDPRLayout>{children}</NDPRLayout> inside your <body>Next Steps After Scaffolding
With Prisma
# 1. Copy .env.example and set your database URL
cp .env.example .env
# 2. Install Prisma dependencies
pnpm add @prisma/client @tantainnovative/ndpr-toolkit
pnpm add -D prisma
# 3. Run the initial migration
pnpm prisma migrate dev --name ndpr-initWith Drizzle
cp .env.example .env
pnpm add drizzle-orm @paralleldrive/cuid2 @tantainnovative/ndpr-toolkit
pnpm add -D drizzle-kit
pnpm drizzle-kit pushWire up Next.js layout
// src/app/layout.tsx
import NDPRLayout from '@/app/ndpr-layout';
export default async function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<NDPRLayout>{children}</NDPRLayout>
</body>
</html>
);
}Mount in Express
import express from 'express';
import { createNDPRRouter } from './src/ndpr';
const app = express();
app.use(express.json());
app.use('/api/ndpr', createNDPRRouter());After wiring the layout
- Add DSR and breach pages using the toolkit's preset components
- Customise the consent banner position, styling, and categories
- Optionally pass a
localeprop to translate all UI strings - Replace the generated API handlers with your own persistence logic as needed