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

79 lines
4.3 KiB
SQL

CREATE TABLE "Organization" (
"id" TEXT NOT NULL,
"code" TEXT NOT NULL,
"name" TEXT NOT NULL,
"status" TEXT NOT NULL DEFAULT 'ACTIVE',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Organization_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "Membership" (
"id" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"organizationId" TEXT NOT NULL,
"role" TEXT NOT NULL DEFAULT 'MEMBER',
"status" TEXT NOT NULL DEFAULT 'PENDING',
"rejectionReason" TEXT,
"driveFolderId" TEXT,
"reviewedAt" TIMESTAMP(3),
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Membership_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "GoogleDriveConnection" (
"id" TEXT NOT NULL,
"organizationId" TEXT NOT NULL,
"tokenCiphertext" TEXT NOT NULL,
"storageType" TEXT NOT NULL DEFAULT 'MY_DRIVE',
"sharedDriveId" TEXT,
"rootFolderId" TEXT,
"status" TEXT NOT NULL DEFAULT 'CONNECTED',
"scope" TEXT,
"connectedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "GoogleDriveConnection_pkey" PRIMARY KEY ("id")
);
ALTER TABLE "Folder" ADD COLUMN "organizationId" TEXT;
ALTER TABLE "FileAsset" ADD COLUMN "organizationId" TEXT;
INSERT INTO "Organization" ("id", "code", "name", "status", "updatedAt")
VALUES ('00000000-0000-0000-0000-000000000001', 'METATRON', 'Metatron Drive Legacy', 'ACTIVE', CURRENT_TIMESTAMP);
INSERT INTO "Membership" ("id", "userId", "organizationId", "role", "status", "driveFolderId", "reviewedAt", "updatedAt")
SELECT "id", "id", '00000000-0000-0000-0000-000000000001',
CASE WHEN "id" = (SELECT "id" FROM "User" ORDER BY "createdAt" ASC LIMIT 1) THEN 'OWNER' ELSE 'MEMBER' END,
CASE WHEN "isSuspended" THEN 'SUSPENDED' ELSE 'APPROVED' END,
"driveFolderId", CURRENT_TIMESTAMP, CURRENT_TIMESTAMP
FROM "User";
UPDATE "Folder" SET "organizationId" = '00000000-0000-0000-0000-000000000001';
UPDATE "FileAsset" SET "organizationId" = '00000000-0000-0000-0000-000000000001';
ALTER TABLE "Folder" ALTER COLUMN "organizationId" SET NOT NULL;
ALTER TABLE "FileAsset" ALTER COLUMN "organizationId" SET NOT NULL;
ALTER TABLE "User" DROP COLUMN "driveFolderId";
DROP INDEX IF EXISTS "Folder_userId_parentId_name_key";
DROP INDEX IF EXISTS "Folder_userId_parentId_idx";
DROP INDEX IF EXISTS "FileAsset_userId_folderId_createdAt_idx";
CREATE UNIQUE INDEX "Organization_code_key" ON "Organization"("code");
CREATE INDEX "Organization_status_createdAt_idx" ON "Organization"("status", "createdAt");
CREATE UNIQUE INDEX "Membership_driveFolderId_key" ON "Membership"("driveFolderId");
CREATE UNIQUE INDEX "Membership_userId_organizationId_key" ON "Membership"("userId", "organizationId");
CREATE INDEX "Membership_organizationId_status_createdAt_idx" ON "Membership"("organizationId", "status", "createdAt");
CREATE INDEX "Membership_userId_status_idx" ON "Membership"("userId", "status");
CREATE UNIQUE INDEX "GoogleDriveConnection_organizationId_key" ON "GoogleDriveConnection"("organizationId");
CREATE UNIQUE INDEX "Folder_organizationId_userId_parentId_name_key" ON "Folder"("organizationId", "userId", "parentId", "name");
CREATE INDEX "Folder_organizationId_userId_parentId_idx" ON "Folder"("organizationId", "userId", "parentId");
CREATE INDEX "FileAsset_organizationId_userId_folderId_createdAt_idx" ON "FileAsset"("organizationId", "userId", "folderId", "createdAt");
ALTER TABLE "Membership" ADD CONSTRAINT "Membership_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "Membership" ADD CONSTRAINT "Membership_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "GoogleDriveConnection" ADD CONSTRAINT "GoogleDriveConnection_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "Folder" ADD CONSTRAINT "Folder_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "FileAsset" ADD CONSTRAINT "FileAsset_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;