Seeding the Database
The DBS seed script (prisma/seed.ts) is the single source of truth for bootstrapping your application’s initial data: roles, permissions, sidebar menus, and the default super admin user.
Running the Seed
npm run db:seed
# or directly
npx prisma db seedThe seed script uses upsert operations, so it is safe to run multiple times without creating duplicate records. However, always review your data in Prisma Studio after seeding in production.
What Gets Seeded
1. Permissions
All permission constants from src/lib/rbac/permission.ts are inserted into the Permission table:
// prisma/seed.ts (excerpt)
const permissions = [
{ key: 'dashboard.access', label: 'Access Dashboard' },
{ key: 'user.read', label: 'View Users' },
{ key: 'user.write', label: 'Create Users' },
{ key: 'user.update', label: 'Edit Users' },
{ key: 'user.delete', label: 'Delete Users' },
{ key: 'roles.manage', label: 'Manage Roles & Permissions' },
{ key: 'log.read', label: 'View Audit Logs' },
{ key: 'settings.manage', label: 'Manage System Settings' },
{ key: 'team.read', label: 'View Teams' },
{ key: 'team.write', label: 'Manage Teams' },
];
for (const perm of permissions) {
await prisma.permission.upsert({
where: { key: perm.key },
update: {},
create: perm,
});
}2. Roles
Default roles are created with their associated permissions:
const roles = [
{
name: 'super_admin',
label: 'Super Admin',
permissions: ['*'], // all permissions (bypasses checks)
},
{
name: 'admin',
label: 'Administrator',
permissions: [
'dashboard.access', 'user.read', 'user.write', 'user.update',
'user.delete', 'roles.manage', 'log.read', 'settings.manage',
'team.read', 'team.write',
],
},
{
name: 'manager',
label: 'Manager',
permissions: ['dashboard.access', 'user.read', 'team.read', 'team.write'],
},
{
name: 'user',
label: 'User',
permissions: ['dashboard.access'],
},
{
name: 'guest',
label: 'Guest',
permissions: [],
},
];3. Menu Items (Sidebar)
The sidebar is fully database-driven. Menu items are seeded with title, url, icon, and requiredPermission:
const menus = [
{
title: 'Dashboard',
url: '/dashboard',
icon: 'LayoutDashboard',
order: 1,
requiredPermission: 'dashboard.access',
},
{
title: 'Users',
url: '/dashboard/users',
icon: 'Users',
order: 2,
requiredPermission: 'user.read',
},
{
title: 'Teams',
url: '/dashboard/teams',
icon: 'UsersRound',
order: 3,
requiredPermission: 'team.read',
},
{
title: 'Access Control',
url: '/dashboard/access',
icon: 'ShieldCheck',
order: 4,
requiredPermission: 'roles.manage',
},
{
title: 'Audit Logs',
url: '/dashboard/logs',
icon: 'FileText',
order: 5,
requiredPermission: 'log.read',
},
{
title: 'Settings',
url: '/dashboard/settings',
icon: 'Settings',
order: 6,
requiredPermission: 'dashboard.access',
},
{
title: 'Broadcast',
url: '/dashboard/broadcast',
icon: 'Megaphone',
order: 7,
requiredPermission: 'settings.manage',
},
];The icon field maps to a Lucide React icon name. The sidebar component resolves this string to the corresponding icon component at render time.
4. Super Admin User
A default super admin account is created:
await prisma.user.upsert({
where: { email: process.env.SUPER_ADMIN_EMAIL ?? 'admin@example.com' },
update: {},
create: {
name: 'Super Admin',
email: process.env.SUPER_ADMIN_EMAIL ?? 'admin@example.com',
emailVerified: true,
userRoles: {
create: {
role: { connect: { name: 'super_admin' } },
},
},
},
});Set SUPER_ADMIN_EMAIL and SUPER_ADMIN_PASSWORD in your .env before seeding in production. The default value admin@example.com is for local development only.
Adding a New Menu Item
Add the entry to prisma/seed.ts
{
title: 'Reports',
url: '/dashboard/reports',
icon: 'BarChart2',
order: 8,
requiredPermission: 'reports.read',
}Add the corresponding permission
Ensure reports.read exists in src/lib/rbac/permission.ts and the seed data.
Re-seed (dev) or use the sync endpoint (production)
npm run db:seed
# or call the sync API
POST /api/access/syncSyncing Permissions Without Reseed
If you’ve added new permissions to permission.ts in a production environment, you can sync them to the database without running the full seed:
# Via API (requires super_admin session)
curl -X POST https://your-app.com/api/access/sync \
-H "Cookie: your-session-cookie"This inserts any missing permission records without touching existing roles or users.