Multi-environment and multi-user construction
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE IF NOT EXISTS "Membership" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"role" "UserRole" NOT NULL DEFAULT 'sales',
|
||||
"orgRoleId" TEXT,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"commissionPercent" DECIMAL(8,2) NOT NULL DEFAULT 0,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "Membership_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "Membership_userId_organizationId_key" ON "Membership"("userId", "organizationId");
|
||||
CREATE INDEX IF NOT EXISTS "Membership_organizationId_role_idx" ON "Membership"("organizationId", "role");
|
||||
CREATE INDEX IF NOT EXISTS "Membership_userId_idx" ON "Membership"("userId");
|
||||
CREATE INDEX IF NOT EXISTS "Membership_orgRoleId_idx" ON "Membership"("orgRoleId");
|
||||
|
||||
ALTER TABLE "Membership" DROP CONSTRAINT IF EXISTS "Membership_userId_fkey";
|
||||
ALTER TABLE "Membership" ADD CONSTRAINT "Membership_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE "Membership" DROP CONSTRAINT IF EXISTS "Membership_organizationId_fkey";
|
||||
ALTER TABLE "Membership" ADD CONSTRAINT "Membership_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE "Membership" DROP CONSTRAINT IF EXISTS "Membership_orgRoleId_fkey";
|
||||
ALTER TABLE "Membership" ADD CONSTRAINT "Membership_orgRoleId_fkey" FOREIGN KEY ("orgRoleId") REFERENCES "OrgRole"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
INSERT INTO "Membership" (
|
||||
"id",
|
||||
"userId",
|
||||
"organizationId",
|
||||
"role",
|
||||
"orgRoleId",
|
||||
"isActive",
|
||||
"commissionPercent",
|
||||
"createdAt",
|
||||
"updatedAt"
|
||||
)
|
||||
SELECT
|
||||
md5(random()::text || clock_timestamp()::text || u."id")::text,
|
||||
u."id",
|
||||
u."organizationId",
|
||||
u."role",
|
||||
u."orgRoleId",
|
||||
COALESCE(u."isActive", true),
|
||||
COALESCE(u."commissionPercent", 0),
|
||||
u."createdAt",
|
||||
CURRENT_TIMESTAMP
|
||||
FROM "User" u
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM "Membership" m
|
||||
WHERE m."userId" = u."id" AND m."organizationId" = u."organizationId"
|
||||
);
|
||||
@@ -150,6 +150,7 @@ model Organization {
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
users User[]
|
||||
memberships Membership[]
|
||||
orgRoles OrgRole[]
|
||||
companies Company[]
|
||||
people Person[]
|
||||
@@ -227,6 +228,7 @@ model User {
|
||||
reportedTickets Ticket[] @relation("TicketReporter")
|
||||
ticketMessages TicketMessage[] @relation("TicketMessageAuthor")
|
||||
confirmedMemories MemoryItem[] @relation("MemoryConfirmedBy")
|
||||
memberships Membership[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@ -248,6 +250,7 @@ model OrgRole {
|
||||
/// owner | admin | sales | support — نقشهای سیستمی قابل حذف نیستند
|
||||
systemKey String?
|
||||
users User[]
|
||||
memberships Membership[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@ -255,6 +258,26 @@ model OrgRole {
|
||||
@@index([organizationId])
|
||||
}
|
||||
|
||||
model Membership {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
role UserRole @default(sales)
|
||||
orgRoleId String?
|
||||
orgRole OrgRole? @relation(fields: [orgRoleId], references: [id], onDelete: SetNull)
|
||||
isActive Boolean @default(true)
|
||||
commissionPercent Decimal @default(0) @db.Decimal(8, 2)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([userId, organizationId])
|
||||
@@index([organizationId, role])
|
||||
@@index([userId])
|
||||
@@index([orgRoleId])
|
||||
}
|
||||
|
||||
model Company {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
|
||||
@@ -139,6 +139,27 @@ async function main() {
|
||||
console.log('Seeded admin user:', adminEmail, '/ demo1234');
|
||||
}
|
||||
|
||||
async function ensureMembership(
|
||||
userId: string,
|
||||
organizationId: string,
|
||||
role: 'owner' | 'admin' | 'sales' | 'support',
|
||||
) {
|
||||
await prisma.membership.upsert({
|
||||
where: { userId_organizationId: { userId, organizationId } },
|
||||
create: { userId, organizationId, role },
|
||||
update: { role },
|
||||
});
|
||||
}
|
||||
|
||||
const ownerRow = await prisma.user.findFirst({
|
||||
where: { email, organizationId: org.id },
|
||||
});
|
||||
if (ownerRow) await ensureMembership(ownerRow.id, org.id, 'owner');
|
||||
const salesRow = await prisma.user.findFirst({ where: { email: salesEmail } });
|
||||
if (salesRow) await ensureMembership(salesRow.id, org.id, 'sales');
|
||||
const adminRow = await prisma.user.findFirst({ where: { email: adminEmail } });
|
||||
if (adminRow) await ensureMembership(adminRow.id, org.id, 'admin');
|
||||
|
||||
let peopleCount = await prisma.person.count({
|
||||
where: { organizationId: org.id },
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user