@tantainnovative/create-ndpr 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,107 +14,109 @@ Or with the short alias (once published to npm):
14
14
  npx create-ndpr
15
15
  ```
16
16
 
17
- Run this from the root of an existing project. The CLI detects your stack and generates the right files with no manual copy-pasting.
17
+ Run the CLI from an existing project root. It detects the framework and ORM, asks which modules you need, and writes stack-specific integration files without overwriting an existing Prisma schema.
18
18
 
19
19
  ## What it does
20
20
 
21
- 1. **Detects your project setup** — checks for `next.config.*`, `express` in `package.json`, an `app/` directory (App Router vs Pages Router), `prisma/schema.prisma`, and `drizzle.config.*`.
21
+ 1. Detects `next.config.*`, Express dependencies, App vs Pages Router directories, `prisma/schema.prisma`, and `drizzle.config.*`.
22
+ 2. Prompts for the organisation, DPO email, framework, ORM, and compliance modules.
23
+ 3. Generates tenant-scoped routes, a fail-closed authentication integration seam, persistence schemas, client wiring, and an `ndpr audit` CI gate.
22
24
 
23
- 2. **Prompts for a few details:**
24
- - Organisation name
25
- - DPO (Data Protection Officer) email address
26
- - Framework (auto-detected, can override)
27
- - ORM: Prisma / Drizzle / None
28
- - Which compliance modules to include
29
-
30
- 3. **Generates files** tailored to your stack.
31
-
32
- ## What it generates
25
+ ## Generated files
33
26
 
34
27
  | File | When |
35
28
  |------|------|
36
29
  | `.env.example` | Always |
37
- | `prisma/schema.prisma` | ORM = Prisma (skips if already exists) |
38
- | `src/drizzle/ndpr-schema.ts` | ORM = Drizzle |
39
- | `app/ndpr-layout.tsx` | Next.js App Router |
40
- | `app/api/consent/route.ts` | Next.js + consent module |
41
- | `app/api/dsr/route.ts` | Next.js + dsr module |
42
- | `app/api/breach/route.ts` | Next.js + breach module |
43
- | `pages/api/consent.ts` | Next.js Pages Router + consent |
44
- | `pages/api/dsr.ts` | Next.js Pages Router + dsr |
45
- | `pages/api/breach.ts` | Next.js Pages Router + breach |
46
- | `src/ndpr/index.ts` | Express (Prisma only) |
47
- | `src/ndpr/routes/consent.ts` | Express + consent module |
48
- | `ndpr.audit.json` | Always — config for the `ndpr audit` compliance gate |
49
- | `.github/workflows/ndpr-audit.yml` | Always CI workflow that fails on a compliance regression |
50
-
51
- All generated files use `{{ORG_NAME}}` and `{{DPO_EMAIL}}` substituted with your answers.
52
-
53
- The generated breach route (`app/api/breach/route.ts`) returns an `ndpcReadiness`
54
- summary on every report — which GAID 2025 Article 33(5) notification fields are
55
- still missing, and how many hours remain on the 72-hour clock so you know what
56
- to collect before filing with the NDPC.
30
+ | `ndpr.audit.json` and `.github/workflows/ndpr-audit.yml` | Always |
31
+ | `prisma/schema.prisma` | Prisma; skipped when a schema already exists so it can be merged manually |
32
+ | `src/drizzle/ndpr-schema.ts` and `src/drizzle/index.ts` | Drizzle |
33
+ | `ndpr/request-context.ts` or `src/ndpr/request-context.ts` | Next.js |
34
+ | `app/ndpr-layout.tsx` or `pages/ndpr-provider.tsx` | Next.js + consent |
35
+ | `app/api/<module>/route.ts` | Next.js App Router backend modules |
36
+ | `pages/api/<module>.ts` | Next.js Pages Router backend modules |
37
+ | `src/ndpr/request-context.ts`, `src/ndpr/index.ts` | Express |
38
+ | `src/ndpr/routes/<module>.ts` | Express backend modules |
39
+
40
+ Maintained persistence routes are generated for consent, DSR, breach, DPIA, lawful-basis, and cross-border modules. Policy and ROPA choices remain represented in the compliance-audit configuration but do not currently generate backend routes.
41
+
42
+ The breach create route returns an `ndpcReadiness` summary showing missing GAID 2025 Article 33(5) notification evidence and the remaining time in the 72-hour window. Reporter identity is taken from the verified staff profile, never from request-body reporter fields.
43
+
44
+ ## Security contract
45
+
46
+ Generated routes intentionally fail closed until you connect `resolveVerifiedNDPRActor` in the request-context file to verified server authentication:
47
+
48
+ - `NDPR_TENANT_ID` is the server-controlled tenant boundary. Request bodies, query parameters, cookies, and arbitrary headers are not tenant authority.
49
+ - A verified actor contains `id`, `displayName`, `email`, optional `department` and account `subjectId`, plus server-mapped roles.
50
+ - Staff routes require exactly `ndpr:staff` or `ndpr:admin`; authentication without one of those roles returns 403.
51
+ - Anonymous consent/DSR access accepts only an `anon_<UUID>` capability in `X-NDPR-Subject-Id`. It never grants staff access.
52
+ - Account actor, profile, subject, and role values must come from a verified session—not client input.
53
+ - Prisma and Drizzle business mutations write their accountability audit row in the same transaction.
54
+ - Consent replacement is serializable, replay-aware, and protected by one-active-record uniqueness. Preserve the generated `timestamp` and `hasInteracted` fields and apply the generated unique index in your migration.
55
+ - The no-ORM stores are development-only and are not durable compliance evidence.
57
56
 
58
57
  ## Modules
59
58
 
60
- | Module | NDPA reference | Description |
61
- |--------|---------------|-------------|
62
- | `consent` | §25–26 | Consent collection, storage, and withdrawal |
63
- | `dsr` | §34–38 | Data subject rights request intake and tracking |
64
- | `breach` | §40 | 72-hour breach notification workflow |
65
- | `policy` | | Privacy policy scaffolding |
66
- | `dpia` | | Data Protection Impact Assessment |
67
- | `lawful-basis` | §25 | Lawful basis register |
68
- | `cross-border` | §43 | Cross-border data transfer management |
69
- | `ropa` | Accountability | Record of Processing Activities |
59
+ | Module | NDPA reference | Generated backend |
60
+ |--------|----------------|:-----------------:|
61
+ | `consent` | §25–26 | Yes |
62
+ | `dsr` | §34–38 | Yes |
63
+ | `breach` | §40 | Yes |
64
+ | `dpia` | §28 | Yes |
65
+ | `lawful-basis` | §25 | Yes |
66
+ | `cross-border` | §41–43 | Yes |
67
+ | `policy` | §27 | Audit config only |
68
+ | `ropa` | §29 | Audit config only |
70
69
 
71
70
  ## After generation
72
71
 
73
- ### With Prisma
72
+ ### Prisma
74
73
 
75
74
  ```bash
76
- # Copy .env.example → .env and set DATABASE_URL
77
75
  cp .env.example .env
78
-
79
- # Install dependencies
80
76
  pnpm add @prisma/client @tantainnovative/ndpr-toolkit
81
77
  pnpm add -D prisma
82
-
83
- # Run migrations
84
78
  pnpm prisma migrate dev --name ndpr-init
85
79
  ```
86
80
 
87
- ### With Drizzle
81
+ If the CLI skipped an existing `prisma/schema.prisma`, merge the generated models and indexes deliberately before migrating.
82
+
83
+ ### Drizzle
88
84
 
89
85
  ```bash
90
86
  cp .env.example .env
91
-
92
87
  pnpm add drizzle-orm @paralleldrive/cuid2 @tantainnovative/ndpr-toolkit
93
88
  pnpm add -D drizzle-kit
89
+ ```
94
90
 
95
- pnpm drizzle-kit push
91
+ Pass your existing Drizzle instance to the generated seam once during server startup, then run the migration command appropriate to your pinned Drizzle setup:
92
+
93
+ ```ts
94
+ import { configureNDPRDatabase } from './src/drizzle';
95
+ import { db } from './src/db';
96
+
97
+ configureNDPRDatabase(db);
96
98
  ```
97
99
 
98
- ### Next.js wire up the layout
100
+ ### Next.js App Router
99
101
 
100
102
  ```tsx
101
103
  // app/layout.tsx
102
- import NDPRLayout from '@/app/ndpr-layout';
104
+ import NDPRClientProvider from './ndpr-layout';
103
105
 
104
- export default async function RootLayout({ children }) {
106
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
105
107
  return (
106
108
  <html lang="en">
107
109
  <body>
108
- <NDPRLayout>
109
- {children}
110
- </NDPRLayout>
110
+ <NDPRClientProvider>{children}</NDPRClientProvider>
111
111
  </body>
112
112
  </html>
113
113
  );
114
114
  }
115
115
  ```
116
116
 
117
- ### Express mount the router
117
+ For Pages Router, wrap your page component with the generated provider from `pages/ndpr-provider.tsx` in `pages/_app.tsx`.
118
+
119
+ ### Express
118
120
 
119
121
  ```ts
120
122
  import express from 'express';
@@ -125,26 +127,20 @@ app.use(express.json());
125
127
  app.use('/api/ndpr', createNDPRRouter());
126
128
  ```
127
129
 
128
- ### Compliance as code (GAID 2025)
130
+ ## Compliance as code
129
131
 
130
- Every scaffold ships an `ndpr.audit.json` config and a GitHub Actions workflow
131
- that runs the toolkit's `ndpr audit` CLI. The audit scores your compliance
132
- posture (consent, DSR, DPIA, breach, policy, lawful basis, cross-border, RoPA)
133
- plus your GAID 2025 DCPMI registration tier, and **exits non-zero when the score
134
- drops below the threshold** — so a regression fails CI like a broken test.
132
+ Every scaffold includes `ndpr.audit.json` and a GitHub Actions workflow that runs `ndpr audit`. Update the configuration to match the real implementation, then use a minimum score as a CI gate:
135
133
 
136
134
  ```bash
137
- # Run it locally any time:
138
135
  npx ndpr audit --min-score 70
139
136
  ```
140
137
 
141
- Edit `ndpr.audit.json` to reflect your real posture, then raise `--min-score` as
142
- you close gaps. See the [audit CLI guide](https://ndprtoolkit.com.ng/docs/guides/audit-cli).
138
+ The audit is implementation support, not legal advice. Verify current NDPC requirements before relying on its output for a filing.
143
139
 
144
140
  ## Requirements
145
141
 
146
142
  - Node.js 18+
147
- - Zero external dependencies works with `npx` out of the box
143
+ - The CLI itself has zero runtime dependencies.
148
144
 
149
145
  ## Links
150
146