feat(auth): introduce explicit planning read permission
This commit is contained in:
@@ -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');
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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],
|
||||
}));
|
||||
}
|
||||
Reference in New Issue
Block a user