- Implemented `stage-resolver.ts` to unify old and new pipeline stage definitions. - Created `org-scope.ts` for organization access verification and scoping queries. - Added role-based permissions management in `permissions.ts` and `rbac-service.ts`. - Introduced invitation management in `invitation-service.ts` with validation schemas. - Developed custom field and notification rule services with respective validators. - Established pipeline template CRUD operations in `pipeline-template-service.ts`. - Added Zustand store for managing pipeline builder state in `pipeline-builder-store.ts`.
99 lines
2.9 KiB
TypeScript
99 lines
2.9 KiB
TypeScript
/**
|
|
* Backfill Organization IDs Script
|
|
*
|
|
* Populates the new organizationId columns on Deliverable and DeliverableStage
|
|
* by copying from their parent Project's organizationId.
|
|
*
|
|
* Run with: npx tsx scripts/backfill-org-ids.ts
|
|
*/
|
|
|
|
import "dotenv/config";
|
|
import { PrismaPg } from "@prisma/adapter-pg";
|
|
import { PrismaClient } from "../src/generated/prisma/client";
|
|
|
|
const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL! });
|
|
const prisma = new PrismaClient({ adapter });
|
|
|
|
async function main() {
|
|
console.log("Backfilling organizationId on deliverables...");
|
|
|
|
// Get all deliverables missing organizationId
|
|
const deliverables = await prisma.deliverable.findMany({
|
|
where: { organizationId: null },
|
|
select: { id: true, projectId: true },
|
|
});
|
|
|
|
if (deliverables.length === 0) {
|
|
console.log("No deliverables need backfill.");
|
|
} else {
|
|
// Group by projectId for efficiency
|
|
const projectIds = [...new Set(deliverables.map((d) => d.projectId))];
|
|
const projects = await prisma.project.findMany({
|
|
where: { id: { in: projectIds } },
|
|
select: { id: true, organizationId: true },
|
|
});
|
|
const projectOrgMap = new Map(projects.map((p) => [p.id, p.organizationId]));
|
|
|
|
let updated = 0;
|
|
for (const deliverable of deliverables) {
|
|
const orgId = projectOrgMap.get(deliverable.projectId);
|
|
if (!orgId) {
|
|
console.warn(` Skipping deliverable ${deliverable.id} — project ${deliverable.projectId} has no org`);
|
|
continue;
|
|
}
|
|
await prisma.deliverable.update({
|
|
where: { id: deliverable.id },
|
|
data: { organizationId: orgId },
|
|
});
|
|
updated++;
|
|
}
|
|
console.log(` Updated ${updated}/${deliverables.length} deliverables.`);
|
|
}
|
|
|
|
console.log("Backfilling organizationId on deliverable stages...");
|
|
|
|
const stages = await prisma.deliverableStage.findMany({
|
|
where: { organizationId: null },
|
|
select: {
|
|
id: true,
|
|
deliverable: {
|
|
select: { project: { select: { organizationId: true } } },
|
|
},
|
|
},
|
|
});
|
|
|
|
if (stages.length === 0) {
|
|
console.log("No stages need backfill.");
|
|
} else {
|
|
let updated = 0;
|
|
// Batch update for efficiency
|
|
const batchSize = 100;
|
|
for (let i = 0; i < stages.length; i += batchSize) {
|
|
const batch = stages.slice(i, i + batchSize);
|
|
await prisma.$transaction(
|
|
batch.map((stage) =>
|
|
prisma.deliverableStage.update({
|
|
where: { id: stage.id },
|
|
data: { organizationId: stage.deliverable.project.organizationId },
|
|
})
|
|
)
|
|
);
|
|
updated += batch.length;
|
|
if (updated % 500 === 0) {
|
|
console.log(` Progress: ${updated}/${stages.length}`);
|
|
}
|
|
}
|
|
console.log(` Updated ${updated}/${stages.length} stages.`);
|
|
}
|
|
|
|
console.log("Backfill complete!");
|
|
}
|
|
|
|
main()
|
|
.catch((e) => {
|
|
console.error(e);
|
|
process.exit(1);
|
|
})
|
|
.finally(async () => {
|
|
await prisma.$disconnect();
|
|
});
|