/home/techb158/cosmic-risk.abdallabala.com/prisma
Edit: /home/techb158/cosmic-risk.abdallabala.com/prisma/seed.js (17790B)
const fs = require("fs");
const path = require("path");
const bcrypt = require("bcryptjs");
const { PrismaClient } = require("@prisma/client");
const prisma = new PrismaClient();
const CREATE_DEMO = process.env.COSMIC_CREATE_DEMO === "true";
const ROLE_TEMPLATES = [
{ code: "owner", name: "Owner", permissions: ["*"] },
{ code: "admin", name: "Admin", permissions: ["organization:view", "organization:manage", "workspace:manage", "project:read", "project:write", "risk:read", "risk:write", "risk:delete", "mitigation:write", "gate:evaluate", "gate:review", "report:export", "integration:manage", "billing:manage", "audit:read"] },
{ code: "project_manager", name: "Project Manager", permissions: ["organization:view", "project:read", "project:write", "risk:read", "risk:write", "mitigation:write", "gate:evaluate", "report:export", "integration:read", "audit:read"] },
{ code: "risk_owner", name: "Risk Owner", permissions: ["project:read", "risk:read", "risk:write", "mitigation:write", "gate:read"] },
{ code: "governance_reviewer", name: "Governance Reviewer", permissions: ["project:read", "risk:read", "gate:evaluate", "gate:review", "report:export", "audit:read"] },
{ code: "legal_ethics_reviewer", name: "Legal / Ethics Reviewer", permissions: ["project:read", "risk:read", "mitigation:write", "gate:review", "report:export", "audit:read"] },
{ code: "integration_admin", name: "Integration Admin", permissions: ["project:read", "integration:read", "integration:manage", "integration:sync", "oauth:manage", "audit:read"] },
{ code: "viewer", name: "Viewer", permissions: ["organization:view", "project:read", "risk:read", "gate:read", "integration:read", "report:export"] },
{ code: "consultant", name: "Consultant", permissions: ["workspace:manage", "project:read", "project:write", "risk:read", "risk:write", "mitigation:write", "gate:evaluate", "gate:review", "report:export", "audit:read"] }
];
function slug(value) {
return String(value || "item")
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/(^-|-$)/g, "");
}
const defaultPassword = process.env.COSMIC_BOOTSTRAP_PASSWORD || "cosmic123";
async function upsertChild(model, projectId, item) {
try {
await prisma[model].upsert({
where: { projectId_name: { projectId, name: item.name } },
update: item,
create: { projectId, ...item }
});
} catch {
// Fallback if the unique constraint isn't applied yet
const existing = await prisma[model].findFirst({ where: { projectId, name: item.name } });
if (existing) await prisma[model].update({ where: { id: existing.id }, data: item });
else await prisma[model].create({ data: { projectId, ...item } });
}
}
async function upsertUser(email, displayName, password, platformRole, roleCode, organizationId) {
const h = await bcrypt.hash(password || defaultPassword, 12);
// Never downgrade a platform-level user (SUPER_OWNER/SUPER_ADMIN) to NONE
const existing = await prisma.user.findUnique({ where: { email } });
const finalPlatformRole = (existing && existing.platformRole !== "NONE") ? existing.platformRole : (platformRole || "NONE");
const user = await prisma.user.upsert({
where: { email },
update: { displayName, passwordHash: h, platformRole: finalPlatformRole },
create: { email, displayName, passwordHash: h, platformRole: platformRole || "NONE", emailVerifiedAt: new Date() },
});
if (organizationId && roleCode) {
const role = await prisma.role.findUnique({ where: { code: roleCode } });
if (role) {
await prisma.membership.upsert({
where: { organizationId_userId: { organizationId, userId: user.id } },
update: { roleId: role.id, status: "ACTIVE" },
create: { organizationId, userId: user.id, roleId: role.id, status: "ACTIVE" },
}).catch(() => {});
}
}
return user;
}
async function main() {
for (const role of ROLE_TEMPLATES) {
await prisma.role.upsert({
where: { code: role.code },
update: { name: role.name, permissions: role.permissions },
create: role
});
}
// Bootstrap user from env var (e.g., COSMIC_BOOTSTRAP_EMAIL)
const bootstrapEmail = process.env.COSMIC_BOOTSTRAP_EMAIL;
if (bootstrapEmail) {
await upsertUser(
bootstrapEmail,
process.env.COSMIC_BOOTSTRAP_NAME || "COSMIC Platform Owner",
defaultPassword,
"SUPER_OWNER",
null,
null
);
}
// Always create the standard demo platform users
const superOwner = await upsertUser("super-owner@cosmic.local", "COSMIC Platform Owner", defaultPassword, "SUPER_OWNER", null, null);
const superAdmin = await upsertUser("super-admin@cosmic.local", "Super Admin", "super123", "SUPER_ADMIN", null, null);
// Cleanup: remove orphaned orgs from any previous seed runs
await prisma.$executeRawUnsafe(`DELETE FROM "Organization" WHERE id NOT IN (SELECT "organizationId" FROM "Membership")`).catch(() => {});
if (CREATE_DEMO) {
// Demo organization with org-level users
const organization = await prisma.organization.upsert({
where: { slug: "cosmic-demo" },
update: {},
create: {
name: "COSMIC Demo Organization",
slug: "cosmic-demo",
status: "TRIAL",
planCode: "pilot",
manualBilling: true
}
});
// Grant Super Admin access to this organization
await prisma.organizationAccess.upsert({
where: { userId_organizationId: { userId: superAdmin.id, organizationId: organization.id } },
update: {},
create: { userId: superAdmin.id, organizationId: organization.id }
}).catch(() => {});
await prisma.subscription.create({
data: {
organizationId: organization.id,
source: "MANUAL",
status: "TRIALING",
planCode: "pilot",
userLimit: 10,
projectLimit: 5,
reportLimitMonthly: 100,
integrationLimit: 4,
adminOverride: true
}
}).catch(() => null);
const workspace = await prisma.workspace.upsert({
where: { organizationId_slug: { organizationId: organization.id, slug: "ai-risk-governance" } },
update: {},
create: {
organizationId: organization.id,
name: "AI Risk Governance",
slug: "ai-risk-governance",
type: "B2B_TEAM",
status: "TRIAL"
}
});
// Org-level users (members of the demo org)
const orgOwner = await upsertUser("org-owner@cosmic.local", "Organization Owner", "orgowner123", "NONE", "owner", organization.id);
// Only create org-level owner@ if it wasn't already created as SUPER_OWNER by bootstrap env var
const ownerExisting = await prisma.user.findUnique({ where: { email: "owner@cosmic.local" } });
if (!ownerExisting || ownerExisting.platformRole === "NONE") {
await upsertUser("owner@cosmic.local", "Owner", "owner123", "NONE", "owner", organization.id);
}
await upsertUser("admin@cosmic.local", "COSMIC Admin", "admin123", "NONE", "admin", organization.id);
await upsertUser("pm@cosmic.local", "Project Manager", "pm123", "NONE", "project_manager", organization.id);
await upsertUser("risk-owner@cosmic.local", "Risk Owner", "risk123", "NONE", "risk_owner", organization.id);
await upsertUser("viewer@cosmic.local", "Read-Only Viewer", "view123", "NONE", "viewer", organization.id);
// Seed project data
const sourcePath = path.join(__dirname, "..", "..", "data", "database.json");
let sourceData = null;
try {
if (fs.existsSync(sourcePath)) {
sourceData = JSON.parse(fs.readFileSync(sourcePath, "utf8"));
}
} catch (e) {
console.warn(`Could not read seed data file: ${e.message}`);
}
let project = await prisma.project.findFirst({ where: { workspaceId: workspace.id } });
if (!project) {
project = await prisma.project.create({
data: {
workspaceId: workspace.id,
name: "Demo Project",
projectType: "GENERATIVE_AI",
currentLifecyclePhase: "DEPLOYMENT",
riskAppetite: 50,
status: "ACTIVE",
ownerDisplayName: "Organization Owner",
description: "Demo project seeded on first startup",
thresholds: {},
reviews: {}
}
});
console.log(`Created project: ${project.id}`);
} else {
console.log(`Project already exists: ${project.id}`);
}
const riskIdMap = new Map();
const mitigationIdMap = new Map();
await prisma.$executeRawUnsafe(`DELETE FROM "LifecyclePhase" lp USING "LifecyclePhase" lp2 WHERE lp.id > lp2.id AND lp."projectId" = lp2."projectId" AND lp.name = lp2.name`).catch(() => {});
for (const ph of [
{ name: "Design", status: "Completed", readinessScore: 95, sequence: 1 },
{ name: "Development", status: "Completed", readinessScore: 80, sequence: 2 },
{ name: "Testing", status: "In Progress", readinessScore: 55, sequence: 3 },
{ name: "Deployment", status: "Pending", readinessScore: 15, sequence: 4 },
]) await upsertChild("lifecyclePhase", project.id, ph);
const demoRisks = [
{ title: "LLM hallucination in production outputs", dimension: "Technical", domain: "Reliability", lifecyclePhase: "Deployment", probability: 70, impact: 85, detectability: 30, status: "OPEN", approvalStatus: "PENDING" },
{ title: "Insufficient human oversight on AI decisions", dimension: "Organizational", domain: "Accountability", lifecyclePhase: "Deployment", probability: 55, impact: 75, detectability: 45, status: "IN_MITIGATION", approvalStatus: "APPROVED" },
{ title: "Training data copyright infringement", dimension: "Organizational", domain: "IP", lifecyclePhase: "Development", probability: 45, impact: 90, detectability: 50, status: "OPEN", approvalStatus: "PENDING" },
{ title: "Bias amplification in user-facing outputs", dimension: "Human", domain: "Fairness", lifecyclePhase: "Testing", probability: 60, impact: 80, detectability: 35, status: "OPEN", approvalStatus: "PENDING" },
{ title: "Model drift after deployment", dimension: "Technical", domain: "Monitoring", lifecyclePhase: "Deployment", probability: 65, impact: 70, detectability: 40, status: "OPEN", approvalStatus: "PENDING" },
];
for (const r of demoRisks) {
const risk = await prisma.risk.create({
data: {
projectId: project.id,
ownerDisplayName: "Organization Owner",
description: `Sample risk: ${r.title}`,
...r,
}
}).catch(() => null);
if (!risk) continue;
riskIdMap.set(r.title, risk.id);
const mits = [
{ title: `Implement guardrails for "${r.title}"`, status: r.status === "IN_MITIGATION" ? "IN_PROGRESS" : "NOT_STARTED", progressPercent: r.status === "IN_MITIGATION" ? 50 : 0, effectivenessPercent: r.status === "IN_MITIGATION" ? 30 : 0 },
{ title: `Document mitigation plan for "${r.title}"`, status: "NOT_STARTED", progressPercent: 0, effectivenessPercent: 0 },
];
for (const m of mits) {
const mit = await prisma.mitigation.create({
data: { riskId: risk.id, ownerDisplayName: "Organization Owner", ...m }
}).catch(() => null);
if (mit) mitigationIdMap.set(m.title, mit.id);
}
}
const demoGate = await prisma.gateEvaluation.create({
data: {
projectId: project.id,
status: "WARNING",
reviewStatus: "Pending review",
summary: "Deployment gate review for AI Risk Governance demo project. Most criteria met, bias testing needs improvement.",
evaluatedByUserId: orgOwner.id,
evaluatedAt: new Date(),
}
}).catch(() => null);
if (demoGate) {
const criteria = [
{ name: "Risk Assessment", actualValue: "90%", expectedRule: ">=80%", status: "Pass", blocking: false },
{ name: "Bias & Fairness Testing", actualValue: "55%", expectedRule: ">=70%", status: "Fail", blocking: true, evidenceTitle: "Bias audit report v2" },
{ name: "Documentation", actualValue: "85%", expectedRule: ">=80%", status: "Pass", blocking: false },
{ name: "Human Oversight Plan", actualValue: "70%", expectedRule: ">=75%", status: "Fail", blocking: false, evidenceTitle: "Oversight plan draft" },
];
for (const c of criteria) {
await prisma.gateCriterion.create({ data: { gateId: demoGate.id, ...c } }).catch(() => {});
}
}
await prisma.$executeRawUnsafe(`DELETE FROM "Indicator" lp USING "Indicator" lp2 WHERE lp.id > lp2.id AND lp."projectId" = lp2."projectId" AND lp.name = lp2.name`).catch(() => {});
await prisma.$executeRawUnsafe(`DELETE FROM "Experiment" lp USING "Experiment" lp2 WHERE lp.id > lp2.id AND lp."projectId" = lp2."projectId" AND lp.name = lp2.name`).catch(() => {});
for (const ind of [
{ name: "Fairness Score", dimension: "Technical", measurand: "Demographic parity ratio", unit: "ratio", target: ">=0.8", interpretationRule: "Higher is better" },
{ name: "Model Accuracy", dimension: "Technical", measurand: "Accuracy rate", unit: "%", target: ">=90", interpretationRule: "Higher is better" },
{ name: "Response Latency", dimension: "Operational", measurand: "P95 response time", unit: "ms", target: "<2000", interpretationRule: "Lower is better" },
]) await upsertChild("indicator", project.id, ind);
const demoExperiments = [
{ name: "GPT-4 Baseline", modelName: "gpt-4", selected: true, metrics: [
{ metricName: "Accuracy", metricValue: 92, thresholdValue: 85, status: "pass" },
{ metricName: "Latency (ms)", metricValue: 480, thresholdValue: 500, status: "warn" },
{ metricName: "Fairness Score", metricValue: 0.78, thresholdValue: 0.8, status: "warn" },
]},
{ name: "Claude 3 Comparison", modelName: "claude-3-opus", selected: false, metrics: [
{ metricName: "Accuracy", metricValue: 94, thresholdValue: 85, status: "pass" },
{ metricName: "Latency (ms)", metricValue: 620, thresholdValue: 500, status: "fail" },
{ metricName: "Fairness Score", metricValue: 0.85, thresholdValue: 0.8, status: "pass" },
]},
{ name: "Fine-tuned LLaMA", modelName: "llama-3-70b", selected: false, metrics: [
{ metricName: "Accuracy", metricValue: 88, thresholdValue: 85, status: "pass" },
{ metricName: "Latency (ms)", metricValue: 350, thresholdValue: 500, status: "pass" },
]},
];
for (const exp of demoExperiments) {
const existing = await prisma.experiment.findFirst({ where: { projectId: project.id, name: exp.name } });
const experiment = existing
? await prisma.experiment.update({ where: { id: existing.id }, data: { name: exp.name, modelName: exp.modelName, selected: exp.selected } })
: await prisma.experiment.create({ data: { projectId: project.id, name: exp.name, modelName: exp.modelName, selected: exp.selected } });
for (const m of exp.metrics) {
const em = await prisma.modelMetric.findFirst({ where: { experimentId: experiment.id, metricName: m.metricName } });
if (em) await prisma.modelMetric.update({ where: { id: em.id }, data: { metricValue: m.metricValue, thresholdValue: m.thresholdValue, status: m.status } });
else await prisma.modelMetric.create({ data: { experimentId: experiment.id, ...m, measuredAt: new Date() } });
}
}
const existingReport = await prisma.reportExport.findFirst({ where: { projectId: project.id } });
if (!existingReport) {
await prisma.reportExport.create({
data: { workspaceId: workspace.id, projectId: project.id, reportType: "executive.html", format: "html", status: "Generated", metadata: { note: "Seeded demo report" }, createdById: orgOwner.id }
}).catch(() => {});
}
await prisma.integration.create({
data: {
workspaceId: workspace.id,
provider: "TRELLO",
workspaceName: "AI Risk Board",
baseUrl: "https://trello.com",
authMode: "API_KEY",
connectionStatus: "NEEDS_CONFIGURATION",
syncDirection: "COSMIC to PM",
liveEnabled: false,
}
}).catch(() => {});
await prisma.auditEvent.create({
data: {
organizationId: organization.id,
workspaceId: workspace.id,
projectId: project.id,
actorUserId: orgOwner.id,
entityType: "Seed",
entityId: project.id,
action: "seed-demo-workspace",
afterJson: { risks: riskIdMap.size }
}
});
console.log(`Seeded ${organization.name} with workspace ${workspace.name} and ${riskIdMap.size} risks.`);
console.log("");
console.log("=== Organization-level users (members of COSMIC Demo Org) ===");
console.log(" owner@cosmic.local / owner123 → Organization Owner");
console.log(" org-owner@cosmic.local / orgowner123 → Organization Owner");
console.log(" admin@cosmic.local / admin123 → Organization Admin");
console.log(" pm@cosmic.local / pm123 → Project Manager");
console.log(" risk-owner@cosmic.local / risk123 → Risk Owner");
console.log(" viewer@cosmic.local / view123 → Viewer");
}
console.log("=== Platform-level users (no org membership) ===");
console.log(" super-owner@cosmic.local / cosmic123 → Super Owner");
console.log(" super-admin@cosmic.local / super123 → Super Admin");
if (!CREATE_DEMO) {
console.log("");
console.log("=== No demo organization created ===");
console.log(" Set COSMIC_CREATE_DEMO=true to seed demo data.");
console.log(" Log in as Super Owner to create your own organizations and projects.");
}
}
main()
.catch(error => {
console.error(error);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});