feat(auth): introduce explicit planning read permission

This commit is contained in:
2026-03-30 09:15:07 +02:00
parent a50ca09333
commit 93c4374973
11 changed files with 293 additions and 11 deletions
@@ -0,0 +1,63 @@
INSERT INTO "system_role_configs" (
"role",
"label",
"description",
"defaultPermissions",
"color",
"sortOrder"
)
VALUES
(
'ADMIN',
'Admin',
'Full platform administration and security management.',
'["viewPlanning","viewCosts","useAssistantAdvancedTools","exportData","importData","approveVacations","manageBlueprints","viewAllResources","manageResources","manageProjects","manageAllocations","manageRoles","manageUsers","viewScores"]'::jsonb,
'purple',
1
),
(
'MANAGER',
'Manager',
'Operational delivery management across resources, projects, and staffing.',
'["viewPlanning","viewCosts","exportData","importData","approveVacations","viewAllResources","manageResources","manageProjects","manageAllocations","manageRoles","viewScores"]'::jsonb,
'blue',
2
),
(
'CONTROLLER',
'Controller',
'Read-heavy planning, resource, and financial oversight.',
'["viewPlanning","viewCosts","exportData","viewAllResources"]'::jsonb,
'amber',
3
),
(
'USER',
'User',
'Standard authenticated access with self-service capabilities only.',
'[]'::jsonb,
'gray',
4
),
(
'VIEWER',
'Viewer',
'Restricted read-only access for limited observation scenarios.',
'[]'::jsonb,
'gray',
5
)
ON CONFLICT ("role") DO NOTHING;
UPDATE "system_role_configs"
SET
"defaultPermissions" = CASE
WHEN jsonb_typeof("defaultPermissions") = 'array'
AND NOT ("defaultPermissions" @> '["viewPlanning"]'::jsonb)
THEN "defaultPermissions" || '["viewPlanning"]'::jsonb
WHEN "defaultPermissions" IS NULL
THEN '["viewPlanning"]'::jsonb
ELSE "defaultPermissions"
END,
"updatedAt" = CURRENT_TIMESTAMP
WHERE "role" IN ('ADMIN', 'MANAGER', 'CONTROLLER');
+15
View File
@@ -6,6 +6,7 @@ import { SystemRole } from "@capakraken/shared";
import { PrismaClient } from "@prisma/client";
import { assertDestructiveDbAllowed } from "./destructive-db-guard.js";
import { loadWorkspaceEnv, resolveWorkspacePath } from "./load-workspace-env.js";
import { buildSystemRoleConfigSeedData } from "./system-role-config-defaults.js";
loadWorkspaceEnv();
@@ -139,6 +140,20 @@ async function bootstrapPlatform(adminEmail: string, adminPassword: string, admi
},
});
for (const config of buildSystemRoleConfigSeedData()) {
await prisma.systemRoleConfig.upsert({
where: { role: config.role },
update: {
label: config.label,
description: config.description,
defaultPermissions: config.defaultPermissions,
color: config.color,
sortOrder: config.sortOrder,
},
create: config,
});
}
return admin;
}
+18
View File
@@ -15,11 +15,28 @@ import { hash } from "@node-rs/argon2";
import { getHolidayDemoProfileForIndex } from "./holiday-demo-profiles.js";
import { loadWorkspaceEnv } from "./load-workspace-env.js";
import { assertSafeSeedTarget } from "./safe-destructive-env.js";
import { buildSystemRoleConfigSeedData } from "./system-role-config-defaults.js";
loadWorkspaceEnv();
const prisma = new PrismaClient();
async function seedSystemRoleConfigs() {
for (const config of buildSystemRoleConfigSeedData()) {
await prisma.systemRoleConfig.upsert({
where: { role: config.role },
update: {
label: config.label,
description: config.description,
defaultPermissions: config.defaultPermissions,
color: config.color,
sortOrder: config.sortOrder,
},
create: config,
});
}
}
// ─── Skill helpers ─────────────────────────────────────────────────────────────
interface SkillEntry {
@@ -338,6 +355,7 @@ async function main() {
});
console.warn(`Users: admin=${admin.id}, manager=${manager.id}, viewer=${viewer.id}`);
await seedSystemRoleConfigs();
// ── 2b. Create Dispo v2 entities ──────────────────────────────────────────
@@ -0,0 +1,46 @@
import { ROLE_DEFAULT_PERMISSIONS, SystemRole } from "@capakraken/shared";
export const SYSTEM_ROLE_CONFIG_DEFAULTS = [
{
role: SystemRole.ADMIN,
label: "Admin",
description: "Full platform administration and security management.",
color: "purple",
sortOrder: 1,
},
{
role: SystemRole.MANAGER,
label: "Manager",
description: "Operational delivery management across resources, projects, and staffing.",
color: "blue",
sortOrder: 2,
},
{
role: SystemRole.CONTROLLER,
label: "Controller",
description: "Read-heavy planning, resource, and financial oversight.",
color: "amber",
sortOrder: 3,
},
{
role: SystemRole.USER,
label: "User",
description: "Standard authenticated access with self-service capabilities only.",
color: "gray",
sortOrder: 4,
},
{
role: SystemRole.VIEWER,
label: "Viewer",
description: "Restricted read-only access for limited observation scenarios.",
color: "gray",
sortOrder: 5,
},
] as const;
export function buildSystemRoleConfigSeedData() {
return SYSTEM_ROLE_CONFIG_DEFAULTS.map((config) => ({
...config,
defaultPermissions: ROLE_DEFAULT_PERMISSIONS[config.role],
}));
}