Database Setup & Schema Guide
Step-by-step tutorial for setting up the unified database, adding new schemas, and migrating plugins.
Prerequisites#
- Docker Desktop running
- Node.js 20+, pnpm installed
- NaaP repository cloned
Quick Start (30 seconds)#
Start the unified database and push all schemas:
Or use the helper script:
That's it. One database container, all schemas created, ready to go.
Verify Setup#
Check that all schemas exist:
Expected output:
| 1 | List of schemas |
| 2 | Name | Owner |
| 3 | -----------------------+---------- |
| 4 | plugin_capacity | postgres |
| 5 | plugin_community | postgres |
| 6 | plugin_dashboard | postgres |
| 7 | plugin_daydream | postgres |
| 8 | plugin_developer_api | postgres |
| 9 | plugin_gateway | postgres |
| 10 | plugin_wallet | postgres |
| 11 | public | postgres |
Tutorial: Adding a New Plugin Schema#
This walks through adding a brand-new plugin (e.g., plugin_analytics) to the unified database.
Step 1: Register the Schema#
Add the new schema name to three places:
A. docker/init-schemas.sql — so it's created on first boot:
CREATE SCHEMA IF NOT EXISTS plugin_analytics;B. packages/database/prisma/schema.prisma — datasource schemas list:
| 1 | datasource db { |
| 2 | provider = "postgresql" |
| 3 | url = env("DATABASE_URL") |
| 4 | schemas = [ |
| 5 | "public", |
| 6 | "plugin_community", |
| 7 | "plugin_wallet", |
| 8 | "plugin_dashboard", |
| 9 | "plugin_daydream", |
| 10 | "plugin_gateway", |
| 11 | "plugin_capacity", |
| 12 | "plugin_developer_api", |
| 13 | "plugin_analytics" // ← Add here |
| 14 | ] |
| 15 | } |
C. bin/start.sh — PLUGIN_SCHEMAS array:
Step 2: Define Models#
Add your models to packages/database/prisma/schema.prisma. Follow the naming convention: prefix every model with a short name to avoid collisions.
| 1 | // ============================================= |
| 2 | // Analytics Plugin — plugin_analytics schema |
| 3 | // ============================================= |
| 4 | |
| 5 | model AnalyticsEvent { |
| 6 | id String @id @default(uuid()) |
| 7 | eventType String |
| 8 | payload Json |
| 9 | userId String? |
| 10 | sessionId String |
| 11 | createdAt DateTime @default(now()) |
| 12 | |
| 13 | @@index([eventType, createdAt]) |
| 14 | @@schema("plugin_analytics") |
| 15 | } |
| 16 | |
| 17 | model AnalyticsDashboard { |
| 18 | id String @id @default(uuid()) |
| 19 | name String |
| 20 | config Json |
| 21 | ownerId String |
| 22 | isPublic Boolean @default(false) |
| 23 | createdAt DateTime @default(now()) |
| 24 | updatedAt DateTime @updatedAt |
| 25 | |
| 26 | widgets AnalyticsWidget[] |
| 27 | |
| 28 | @@schema("plugin_analytics") |
| 29 | } |
| 30 | |
| 31 | model AnalyticsWidget { |
| 32 | id String @id @default(uuid()) |
| 33 | type String |
| 34 | query String |
| 35 | position Json |
| 36 | dashboardId String |
| 37 | dashboard AnalyticsDashboard @relation(fields: [dashboardId], references: [id]) |
| 38 | createdAt DateTime @default(now()) |
| 39 | updatedAt DateTime @updatedAt |
| 40 | |
| 41 | @@schema("plugin_analytics") |
| 42 | } |
Step 3: Generate and Push#
Step 4: Use in Your Plugin Backend#
Create the database client file:
// plugins/analytics/backend/src/db/client.ts
import { prisma } from '@naap/database';
export const db = prisma;Use it in your routes:
| 1 | // plugins/analytics/backend/src/routes/events.ts |
| 2 | import { Router } from 'express'; |
| 3 | import { db } from '../db/client.js'; |
| 4 | |
| 5 | const router = Router(); |
| 6 | |
| 7 | router.post('/', async (req, res) => { |
| 8 | const event = await db.analyticsEvent.create({ |
| 9 | data: { |
| 10 | eventType: req.body.type, |
| 11 | payload: req.body.payload, |
| 12 | userId: req.user?.id, |
| 13 | sessionId: req.body.sessionId, |
| 14 | }, |
| 15 | }); |
| 16 | res.status(201).json({ success: true, data: event }); |
| 17 | }); |
| 18 | |
| 19 | router.get('/dashboard/:id', async (req, res) => { |
| 20 | const dashboard = await db.analyticsDashboard.findUnique({ |
| 21 | where: { id: req.params.id }, |
| 22 | include: { widgets: true }, |
| 23 | }); |
| 24 | res.json({ success: true, data: dashboard }); |
| 25 | }); |
| 26 | |
| 27 | export default router; |
Step 5: Wire Up package.json#
Your plugin's package.json should depend on @naap/database, not @prisma/client:
| 1 | { |
| 2 | "dependencies": { |
| 3 | "@naap/database": "workspace:*", |
| 4 | "express": "^4.18.0" |
| 5 | } |
| 6 | } |
No db:generate, db:push, or db:migrate scripts needed — the central packages/database handles all schema management.
Common Operations#
View Tables in a Schema#
Open Prisma Studio (all schemas)#
Reset the Database (development only)#
Seed Data#
| 1 | // packages/database/prisma/seed.ts |
| 2 | import { prisma } from '../src/index'; |
| 3 | |
| 4 | async function seed() { |
| 5 | // Seed analytics data |
| 6 | await prisma.analyticsEvent.createMany({ |
| 7 | data: [ |
| 8 | { eventType: 'page_view', sessionId: 'demo-1', payload: { path: '/' } }, |
| 9 | { eventType: 'click', sessionId: 'demo-1', payload: { target: 'signup' } }, |
| 10 | ], |
| 11 | }); |
| 12 | } |
| 13 | |
| 14 | seed().then(() => prisma.$disconnect()); |
Troubleshooting#
"Schema does not exist"#
The schema isn't created yet. Either:
- Re-run
docker-compose down -v && docker-compose up -d database(this executesinit-schemas.sql), or - Manually create it:
docker exec naap-db psql -U postgres -d naap -c "CREATE SCHEMA plugin_analytics;"
"Model not found on prisma client"#
You forgot to run npx prisma generate after editing schema.prisma. Run:
"Cannot resolve @naap/database"#
Run pnpm install from the monorepo root to link the workspace package.
Prisma client type errors after adding models#
Restart your TypeScript server (VS Code: Cmd+Shift+P → "TypeScript: Restart TS Server").
Model Naming Convention#
To prevent collisions across plugins, prefix every model:
| Plugin | Prefix | Example |
|---|---|---|
| community | Community | CommunityPost, CommunityComment |
| my-wallet | Wallet | WalletConnection, WalletTransactionLog |
| daydream-video | Daydream | DaydreamSession, DaydreamSettings |
| gateway-manager | Gateway | Gateway, GatewayOrchestratorConnection |
| capacity-planner | Capacity | CapacityRequest, CapacitySoftCommit |
| developer-api | DevApi | DevApiKey, DevApiAIModel |
| dashboard | Dashboard | Dashboard, DashboardUserPreference |
| your-plugin | YourPlugin | YourPluginWidget, YourPluginConfig |
Next Steps#
- Database Architecture Rules — Why and how
- Full Example — Complete worked example
- AI Prompt — Generate compliant code