MOHAN 6b105c07c4 feat: Implement multi-tenant architecture with organization support
- Added organization model and membership management to support multi-tenancy.
- Updated file and folder routes to include organization context for ownership checks.
- Integrated Google Drive connection management per organization, ensuring proper authorization and folder structure.
- Enhanced user account deletion to prevent removal if the user owns organizations.
- Introduced middleware for organization validation and admin role checks.
- Created organization admin routes for managing memberships and retrieving statistics.
- Implemented token encryption/decryption for secure Google Drive token storage.
- Updated serializers to include organization data in user memberships.
- Added database migration for new organization and membership tables.
2026-07-06 15:37:26 +05:30

112 lines
3.7 KiB
Plaintext

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
}
model User {
id String @id @default(uuid())
username String @unique
passwordHash String
name String
phone String @unique
email String @unique
gender String
age Int
isSuspended Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
memberships Membership[]
folders Folder[]
files FileAsset[]
@@index([isSuspended, createdAt])
}
model Organization {
id String @id @default(uuid())
code String @unique
name String
status String @default("ACTIVE")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
memberships Membership[]
driveConnection GoogleDriveConnection?
folders Folder[]
files FileAsset[]
@@index([status, createdAt])
}
model Membership {
id String @id @default(uuid())
userId String
organizationId String
role String @default("MEMBER")
status String @default("PENDING")
rejectionReason String?
driveFolderId String? @unique
reviewedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
@@unique([userId, organizationId])
@@index([organizationId, status, createdAt])
@@index([userId, status])
}
model GoogleDriveConnection {
id String @id @default(uuid())
organizationId String @unique
tokenCiphertext String
storageType String @default("MY_DRIVE")
sharedDriveId String?
rootFolderId String?
status String @default("CONNECTED")
scope String?
connectedAt DateTime @default(now())
updatedAt DateTime @updatedAt
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
}
model Folder {
id String @id @default(uuid())
name String
driveFolderId String @unique
scopeKey String? @unique
userId String
organizationId String
parentId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
parent Folder? @relation("FolderTree", fields: [parentId], references: [id], onDelete: Cascade)
children Folder[] @relation("FolderTree")
files FileAsset[]
@@unique([organizationId, userId, parentId, name])
@@index([organizationId, userId, parentId])
}
model FileAsset {
id String @id @default(uuid())
originalName String
driveFileId String @unique
mimeType String
sizeBytes BigInt
userId String
organizationId String
folderId String?
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
folder Folder? @relation(fields: [folderId], references: [id], onDelete: SetNull)
@@index([organizationId, userId, folderId, createdAt])
}