feat(identity): redesign identity module and introduce RBAC foundation
- Redesign the Identity module with a richer domain model. - Extend the User entity to support username, Authentik integration, activity tracking, and storage information. - Add Role and Permission domain models with many-to-many relationships. - Implement RBAC foundation using UserRole, RolePermission, and UserPermission mappings. - Add user storage quota and usage fields with default values. - Introduce Authentik identifiers and synchronization metadata. - Refactor user domain logic for role and permission management. - Update Prisma schema to support the new identity architecture. - Improve JWT authentication and permission guard integration. - Update repositories, handlers, controllers, mappers, DTOs, and Swagger configuration. - Refresh environment configuration and project dependencies.
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "User" (
|
||||
"id" TEXT NOT NULL,
|
||||
"username" TEXT NOT NULL,
|
||||
"email" TEXT NOT NULL,
|
||||
"password" TEXT NOT NULL,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Role" (
|
||||
"id" TEXT NOT NULL,
|
||||
"code" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Role_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Permission" (
|
||||
"id" TEXT NOT NULL,
|
||||
"code" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Permission_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "UserRole" (
|
||||
"userId" TEXT NOT NULL,
|
||||
"roleId" TEXT NOT NULL,
|
||||
"assignedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "UserRole_pkey" PRIMARY KEY ("userId","roleId")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "RolePermission" (
|
||||
"roleId" TEXT NOT NULL,
|
||||
"permissionId" TEXT NOT NULL,
|
||||
"assignedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "RolePermission_pkey" PRIMARY KEY ("roleId","permissionId")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "UserPermission" (
|
||||
"userId" TEXT NOT NULL,
|
||||
"permissionId" TEXT NOT NULL,
|
||||
"assignedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "UserPermission_pkey" PRIMARY KEY ("userId","permissionId")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_username_key" ON "User"("username");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Role_code_key" ON "Role"("code");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Permission_code_key" ON "Permission"("code");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "UserRole" ADD CONSTRAINT "UserRole_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "UserRole" ADD CONSTRAINT "UserRole_roleId_fkey" FOREIGN KEY ("roleId") REFERENCES "Role"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "RolePermission" ADD CONSTRAINT "RolePermission_roleId_fkey" FOREIGN KEY ("roleId") REFERENCES "Role"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "RolePermission" ADD CONSTRAINT "RolePermission_permissionId_fkey" FOREIGN KEY ("permissionId") REFERENCES "Permission"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "UserPermission" ADD CONSTRAINT "UserPermission_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "UserPermission" ADD CONSTRAINT "UserPermission_permissionId_fkey" FOREIGN KEY ("permissionId") REFERENCES "Permission"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- Added the required column `assignedBy` to the `RolePermission` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `assignedBy` to the `UserPermission` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `assignedBy` to the `UserRole` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "RolePermission" ADD COLUMN "assignedBy" TEXT NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "UserPermission" ADD COLUMN "assignedBy" TEXT NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "UserRole" ADD COLUMN "assignedBy" TEXT NOT NULL;
|
||||
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Role" ADD COLUMN "isDefault" BOOLEAN NOT NULL DEFAULT false;
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- A unique constraint covering the columns `[authentikId]` on the table `User` will be added. If there are existing duplicate values, this will fail.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "User" ADD COLUMN "authentikId" TEXT;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_authentikId_key" ON "User"("authentikId");
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `password` on the `User` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "User" DROP COLUMN "password",
|
||||
ADD COLUMN "deletedAt" TIMESTAMP(3),
|
||||
ADD COLUMN "lastSeenAt" TIMESTAMP(3);
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- A unique constraint covering the columns `[authentikUserId]` on the table `User` will be added. If there are existing duplicate values, this will fail.
|
||||
- A unique constraint covering the columns `[authentikSubject]` on the table `User` will be added. If there are existing duplicate values, this will fail.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "User" ALTER COLUMN "lastSyncedAt" SET DATA TYPE TIMESTAMP(3);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_authentikUserId_key" ON "User"("authentikUserId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_authentikSubject_key" ON "User"("authentikSubject");
|
||||
@@ -0,0 +1,17 @@
|
||||
-- Migration: add_authentik_fields
|
||||
|
||||
ALTER TABLE "User"
|
||||
ADD COLUMN IF NOT EXISTS "authentikUserId" TEXT;
|
||||
|
||||
ALTER TABLE "User"
|
||||
ADD COLUMN IF NOT EXISTS "authentikSubject" TEXT;
|
||||
|
||||
ALTER TABLE "User"
|
||||
ADD COLUMN IF NOT EXISTS "lastSyncedAt" TIMESTAMP;
|
||||
|
||||
ALTER TABLE "User"
|
||||
ADD COLUMN IF NOT EXISTS "syncStatus" TEXT;
|
||||
|
||||
-- Optional: add unique constraints if desired
|
||||
-- DO NOT add unique constraints without verifying existing data
|
||||
-- ALTER TABLE "User" ADD CONSTRAINT "User_authentikUserId_key" UNIQUE ("authentikUserId");
|
||||
@@ -0,0 +1,7 @@
|
||||
-- Migration: add_storage
|
||||
|
||||
ALTER TABLE "User"
|
||||
ADD COLUMN IF NOT EXISTS "storageQuota" bigint NOT NULL DEFAULT 10737418240;
|
||||
|
||||
ALTER TABLE "User"
|
||||
ADD COLUMN IF NOT EXISTS "storageUsed" bigint NOT NULL DEFAULT 0;
|
||||
@@ -0,0 +1,3 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (i.e. Git)
|
||||
provider = "postgresql"
|
||||
+95
-9
@@ -11,13 +11,99 @@ datasource db {
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(uuid())
|
||||
name String
|
||||
email String @unique
|
||||
password String
|
||||
status String @default("ACTIVE")
|
||||
metadata Json?
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
deleted_at DateTime?
|
||||
id String @id @default(uuid())
|
||||
|
||||
authentikId String? @unique
|
||||
authentikUserId String? @unique
|
||||
authentikSubject String? @unique
|
||||
|
||||
username String @unique
|
||||
email String @unique
|
||||
|
||||
|
||||
isActive Boolean @default(true)
|
||||
|
||||
// storage (in bytes)
|
||||
storageQuota BigInt @default(10737418240)
|
||||
storageUsed BigInt @default(0)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime?
|
||||
lastSeenAt DateTime?
|
||||
lastSyncedAt DateTime?
|
||||
syncStatus String?
|
||||
|
||||
roles UserRole[]
|
||||
permissions UserPermission[]
|
||||
|
||||
}
|
||||
|
||||
model Role {
|
||||
id String @id @default(uuid())
|
||||
|
||||
code String @unique
|
||||
name String
|
||||
description String?
|
||||
|
||||
isDefault Boolean @default(false)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
users UserRole[]
|
||||
permissions RolePermission[]
|
||||
}
|
||||
|
||||
model Permission {
|
||||
id String @id @default(uuid())
|
||||
|
||||
code String @unique
|
||||
name String
|
||||
description String?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
roles RolePermission[]
|
||||
users UserPermission[]
|
||||
}
|
||||
|
||||
model UserRole {
|
||||
userId String
|
||||
roleId String
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
||||
|
||||
assignedAt DateTime @default(now())
|
||||
assignedBy String
|
||||
|
||||
@@id([userId, roleId])
|
||||
}
|
||||
|
||||
model RolePermission {
|
||||
roleId String
|
||||
permissionId String
|
||||
|
||||
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
||||
permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)
|
||||
|
||||
assignedAt DateTime @default(now())
|
||||
assignedBy String
|
||||
|
||||
@@id([roleId, permissionId])
|
||||
}
|
||||
|
||||
model UserPermission {
|
||||
userId String
|
||||
permissionId String
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)
|
||||
|
||||
assignedAt DateTime @default(now())
|
||||
assignedBy String
|
||||
|
||||
@@id([userId, permissionId])
|
||||
}
|
||||
Reference in New Issue
Block a user