- {{ settingsCategories.find(c => c.id === activeCategory)?.icon }}
+
+
+
+
🔄 Workflow & Automation
+
+
+
+
Approval Workflows
+
+
+
+
+
+
+
+
+
+
+
+
Notification Settings
+
-
- {{ settingsCategories.find(c => c.id === activeCategory)?.name }}
-
-
- Settings for this category are being developed and will be available in the next update.
-
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 4d234d3..1af48bc 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -12,52 +12,94 @@ model audit {
auditIP String? @db.VarChar(255)
auditURL String? @db.VarChar(255)
auditURLMethod String? @db.VarChar(255)
- auditURLPayload String? @db.VarChar(255)
- auditCreatedDate DateTime? @db.DateTime(0)
+ auditURLPayload String? @db.Text
+ auditCreatedDate DateTime? @default(now()) @db.DateTime(0)
+ auditAction String? @db.VarChar(255)
+ auditDetails String? @db.Text
+ auditUserID Int?
+ auditUsername String? @db.VarChar(255)
+ user user? @relation(fields: [auditUserID], references: [userID])
+
+ @@index([auditUserID], map: "FK_audit_user")
}
-model lookup {
- lookupID Int @id @default(autoincrement())
- lookupOrder Int?
- lookupTitle String? @db.VarChar(255)
- lookupRefCode String? @db.VarChar(255)
- lookupValue String? @db.VarChar(255)
- lookupType String? @db.VarChar(255)
- lookupStatus String? @db.VarChar(255)
- lookupCreatedDate DateTime? @db.DateTime(0)
- lookupModifiedDate DateTime? @db.DateTime(0)
+model organization {
+ org_id Int @id @default(autoincrement())
+ org_name String @unique(map: "organization_unique") @db.VarChar(255)
+ org_address1 String? @db.VarChar(255)
+ org_address2 String? @db.VarChar(255)
+ org_postcode Int?
+ org_state String? @db.VarChar(100)
+ org_country String? @db.VarChar(100)
+ org_active Int?
+ departments department[]
+}
+
+model department {
+ dp_id Int @id @default(autoincrement())
+ dp_name String @db.VarChar(255)
+ org_id Int
+ cabinets cabinets[]
+ organization organization @relation(fields: [org_id], references: [org_id], onDelete: Cascade, onUpdate: NoAction, map: "department_organization_FK")
+ users sys_user[]
+
+ @@index([org_id], map: "department_organization_FK")
+}
+
+model cabinets {
+ cb_id Int @id @default(autoincrement())
+ cb_name String @unique(map: "cabinet_master_unique") @db.VarChar(255)
+ cb_parent_id Int?
+ cb_private Int? @default(0)
+ cb_owner Int?
+ dp_id Int?
+ created_at DateTime? @db.DateTime(0)
+ modified_at DateTime? @db.DateTime(0)
+ department department? @relation(fields: [dp_id], references: [dp_id], onDelete: NoAction, onUpdate: NoAction, map: "cabinets_department_FK")
+
+ @@index([dp_id], map: "cabinets_department_FK")
+}
+
+model sys_user {
+ su_id Int @id @default(autoincrement())
+ su_username String @unique(map: "sys_user_unique") @db.VarChar(100)
+ su_name String @db.VarChar(255)
+ su_nric Int @unique(map: "sys_user_unique_1")
+ su_dob DateTime @db.Date
+ su_email String? @db.VarChar(255)
+ su_password String @db.VarChar(255)
+ dp_id Int
+ su_active Int? @default(1)
+ su_lock Int? @default(0)
+ su_org_id Int
+ department department @relation(fields: [dp_id], references: [dp_id], onDelete: NoAction, onUpdate: NoAction, map: "sys_user_department_FK")
+
+ @@index([dp_id], map: "sys_user_department_FK")
}
model role {
- roleID Int @id @default(autoincrement())
- roleName String? @db.VarChar(255)
- roleDescription String? @db.VarChar(255)
- roleStatus String? @db.VarChar(255)
- roleCreatedDate DateTime? @db.DateTime(0)
- roleModifiedDate DateTime? @db.DateTime(0)
+ roleID Int @id @default(autoincrement())
+ roleName String? @db.VarChar(255)
+ roleDescription String? @db.VarChar(255)
+ roleStatus String? @db.VarChar(255)
+ roleCreatedDate DateTime? @db.DateTime(0)
+ roleModifiedDate DateTime? @db.DateTime(0)
userrole userrole[]
- permissions AccessPermission[]
}
model user {
- userID Int @id @default(autoincrement())
- userSecretKey String? @db.VarChar(255)
- userUsername String? @db.VarChar(255)
- userPassword String? @db.VarChar(255)
- userFullName String? @db.VarChar(255)
- userEmail String? @db.VarChar(255)
- userPhone String? @db.VarChar(255)
- userStatus String? @db.VarChar(255)
- userCreatedDate DateTime? @db.DateTime(0)
- userModifiedDate DateTime? @db.DateTime(0)
+ userID Int @id @default(autoincrement())
+ userSecretKey String? @db.VarChar(255)
+ userUsername String? @db.VarChar(255)
+ userPassword String? @db.VarChar(255)
+ userFullName String? @db.VarChar(255)
+ userEmail String? @db.VarChar(255)
+ userPhone String? @db.VarChar(255)
+ userStatus String? @db.VarChar(255)
+ userCreatedDate DateTime? @db.DateTime(0)
+ userModifiedDate DateTime? @db.DateTime(0)
+ audit audit[]
userrole userrole[]
- accessRequests AccessRequest[]
- permissions AccessPermission[]
- documents Document[] @relation("DocumentCreator")
- cabinets Cabinet[] @relation("CabinetCreator")
- drawers Drawer[] @relation("DrawerCreator")
- folders Folder[] @relation("FolderCreator")
- subfolders Subfolder[] @relation("SubfolderCreator")
}
model userrole {
@@ -73,198 +115,105 @@ model userrole {
}
model site_settings {
- settingID Int @id @default(autoincrement())
- siteName String? @db.VarChar(255)
- siteNameFontSize Int? @default(18)
- siteDescription String? @db.Text
- siteLogo String? @db.VarChar(500)
- siteLoadingLogo String? @db.VarChar(500)
- siteFavicon String? @db.VarChar(500)
- showSiteNameInHeader Boolean? @default(true)
- primaryColor String? @db.VarChar(50)
- secondaryColor String? @db.VarChar(50)
- successColor String? @db.VarChar(50)
- infoColor String? @db.VarChar(50)
- warningColor String? @db.VarChar(50)
- dangerColor String? @db.VarChar(50)
- customCSS String? @db.Text
- themeMode String? @db.VarChar(50)
- customThemeFile String? @db.VarChar(500)
- currentFont String? @db.VarChar(255)
- fontSource String? @db.VarChar(500)
- seoTitle String? @db.VarChar(255)
- seoDescription String? @db.Text
- seoKeywords String? @db.Text
- seoAuthor String? @db.VarChar(255)
- seoOgImage String? @db.VarChar(500)
- seoTwitterCard String? @default("summary_large_image") @db.VarChar(50)
- seoCanonicalUrl String? @db.VarChar(500)
- seoRobots String? @default("index, follow") @db.VarChar(100)
- seoGoogleAnalytics String? @db.VarChar(255)
- seoGoogleTagManager String? @db.VarChar(255)
- seoFacebookPixel String? @db.VarChar(255)
- settingCreatedDate DateTime? @db.DateTime(0)
- settingModifiedDate DateTime? @db.DateTime(0)
- siteLoginLogo String? @db.VarChar(500)
+ settingID Int @id @default(autoincrement())
+ siteName String? @default("corradAF") @db.VarChar(255)
+ siteNameFontSize Int? @default(18)
+ siteDescription String? @db.Text
+ siteLogo String? @db.VarChar(500)
+ siteLoadingLogo String? @db.VarChar(500)
+ siteFavicon String? @db.VarChar(500)
+ siteLoginLogo String? @db.VarChar(500)
+ showSiteNameInHeader Boolean? @default(true)
+ customCSS String? @db.LongText
+ themeMode String? @default("biasa") @db.VarChar(100)
+ customThemeFile String? @db.VarChar(500)
+ currentFont String? @db.VarChar(100)
+ fontSource String? @db.VarChar(100)
+ seoTitle String? @db.VarChar(255)
+ seoDescription String? @db.Text
+ seoKeywords String? @db.Text
+ seoAuthor String? @db.VarChar(255)
+ seoOgImage String? @db.VarChar(500)
+ seoTwitterCard String? @default("summary_large_image") @db.VarChar(100)
+ seoCanonicalUrl String? @db.VarChar(500)
+ seoRobots String? @default("index, follow") @db.VarChar(100)
+ seoGoogleAnalytics String? @db.VarChar(255)
+ seoGoogleTagManager String? @db.VarChar(255)
+ seoFacebookPixel String? @db.VarChar(255)
+ settingCreatedDate DateTime? @default(now()) @db.DateTime(0)
+ settingModifiedDate DateTime? @default(now()) @db.DateTime(0)
}
-// DMS Models
-
-model Cabinet {
- id Int @id @default(autoincrement())
- name String @db.VarChar(255)
- description String? @db.Text
- createdAt DateTime @default(now()) @db.DateTime(0)
- updatedAt DateTime @updatedAt @db.DateTime(0)
- createdBy Int
- status String @default("active") @db.VarChar(50)
- user user @relation("CabinetCreator", fields: [createdBy], references: [userID])
- drawers Drawer[]
- permissions AccessPermission[]
-
- @@index([createdBy])
-}
-
-model Drawer {
- id Int @id @default(autoincrement())
- name String @db.VarChar(255)
- description String? @db.Text
- cabinetId Int
- createdAt DateTime @default(now()) @db.DateTime(0)
- updatedAt DateTime @updatedAt @db.DateTime(0)
- createdBy Int
- status String @default("active") @db.VarChar(50)
- cabinet Cabinet @relation(fields: [cabinetId], references: [id], onDelete: Cascade)
- user user @relation("DrawerCreator", fields: [createdBy], references: [userID])
- folders Folder[]
- permissions AccessPermission[]
-
- @@index([cabinetId])
- @@index([createdBy])
-}
-
-model Folder {
- id Int @id @default(autoincrement())
- name String @db.VarChar(255)
- description String? @db.Text
- drawerId Int
- createdAt DateTime @default(now()) @db.DateTime(0)
- updatedAt DateTime @updatedAt @db.DateTime(0)
- createdBy Int
- status String @default("active") @db.VarChar(50)
- drawer Drawer @relation(fields: [drawerId], references: [id], onDelete: Cascade)
- user user @relation("FolderCreator", fields: [createdBy], references: [userID])
- subfolders Subfolder[]
- documents Document[] @relation("FolderDocuments")
- permissions AccessPermission[]
-
- @@index([drawerId])
- @@index([createdBy])
-}
-
-model Subfolder {
- id Int @id @default(autoincrement())
- name String @db.VarChar(255)
- description String? @db.Text
- folderId Int
- createdAt DateTime @default(now()) @db.DateTime(0)
- updatedAt DateTime @updatedAt @db.DateTime(0)
- createdBy Int
- status String @default("active") @db.VarChar(50)
- folder Folder @relation(fields: [folderId], references: [id], onDelete: Cascade)
- user user @relation("SubfolderCreator", fields: [createdBy], references: [userID])
- documents Document[] @relation("SubfolderDocuments")
- permissions AccessPermission[]
-
- @@index([folderId])
- @@index([createdBy])
-}
-
-model Document {
- id Int @id @default(autoincrement())
- name String @db.VarChar(255)
- description String? @db.Text
- fileSize Int @default(0)
- fileType String @db.VarChar(100)
- fileExtension String @db.VarChar(20)
- filePath String @db.VarChar(500)
- version Int @default(1)
- isTemplate Boolean @default(false)
- isPublic Boolean @default(false)
- folderId Int?
- subfolderId Int?
- createdAt DateTime @default(now()) @db.DateTime(0)
- updatedAt DateTime @updatedAt @db.DateTime(0)
- createdBy Int
- status String @default("active") @db.VarChar(50)
- folder Folder? @relation("FolderDocuments", fields: [folderId], references: [id], onDelete: SetNull)
- subfolder Subfolder? @relation("SubfolderDocuments", fields: [subfolderId], references: [id], onDelete: SetNull)
- user user @relation("DocumentCreator", fields: [createdBy], references: [userID])
- accessRequests AccessRequest[]
- permissions AccessPermission[]
- versions DocumentVersion[]
-
- @@index([folderId])
- @@index([subfolderId])
- @@index([createdBy])
-}
-
-model DocumentVersion {
- id Int @id @default(autoincrement())
- documentId Int
- version Int
- filePath String @db.VarChar(500)
- fileSize Int @default(0)
- createdAt DateTime @default(now()) @db.DateTime(0)
- createdBy Int
- document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
-
- @@index([documentId])
-}
-
-model AccessRequest {
- id Int @id @default(autoincrement())
- documentId Int
- userId Int
- requestedLevel String @db.VarChar(50) // view, download, print, edit, full
- justification String? @db.Text
- status String @default("pending") @db.VarChar(50) // pending, approved, rejected
- responseNote String? @db.Text
- requestedAt DateTime @default(now()) @db.DateTime(0)
- respondedAt DateTime? @db.DateTime(0)
- document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
- user user @relation(fields: [userId], references: [userID])
-
- @@index([documentId])
- @@index([userId])
-}
-
-model AccessPermission {
- id Int @id @default(autoincrement())
- userId Int?
- roleId Int?
- documentId Int?
- cabinetId Int?
- drawerId Int?
- folderId Int?
- subfolderId Int?
- permissionLevel String @db.VarChar(50) // view, download, print, edit, full
- createdAt DateTime @default(now()) @db.DateTime(0)
- updatedAt DateTime @updatedAt @db.DateTime(0)
- expiresAt DateTime? @db.DateTime(0)
- user user? @relation(fields: [userId], references: [userID], onDelete: SetNull)
- role role? @relation(fields: [roleId], references: [roleID], onDelete: SetNull)
- document Document? @relation(fields: [documentId], references: [id], onDelete: Cascade)
- cabinet Cabinet? @relation(fields: [cabinetId], references: [id], onDelete: Cascade)
- drawer Drawer? @relation(fields: [drawerId], references: [id], onDelete: Cascade)
- folder Folder? @relation(fields: [folderId], references: [id], onDelete: Cascade)
- subfolder Subfolder? @relation(fields: [subfolderId], references: [id], onDelete: Cascade)
-
- @@index([userId])
- @@index([roleId])
- @@index([documentId])
- @@index([cabinetId])
- @@index([drawerId])
- @@index([folderId])
- @@index([subfolderId])
+model dms_settings {
+ settingID Int @id @default(autoincrement())
+ // User & Access Management
+ userRoles String? @db.Text
+ rbacEnabled Boolean? @default(true)
+ userGroups String? @db.Text
+ permissionView Boolean? @default(true)
+ permissionEdit Boolean? @default(true)
+ permissionDelete Boolean? @default(false)
+ permissionDownload Boolean? @default(true)
+ permissionShare Boolean? @default(true)
+ ssoEnabled Boolean? @default(false)
+ mfaRequired Boolean? @default(false)
+ ldapIntegration Boolean? @default(false)
+ sessionTimeout Int? @default(8)
+
+ // Document & Folder Settings
+ folderMaxDepth Int? @default(5)
+ folderDefaultStructure String? @db.Text
+ folderTemplates String? @db.Text
+ namingAutoGenerate Boolean? @default(true)
+ namingMandatoryFields String? @db.Text
+ namingPattern String? @default("{department}_{title}_{date}") @db.VarChar(255)
+ retentionEnabled Boolean? @default(true)
+ retentionDefaultDays Int? @default(2555)
+ retentionArchiveBeforeDelete Boolean? @default(true)
+ versionControlEnabled Boolean? @default(true)
+ versionControlMaxVersions Int? @default(10)
+ versionControlAutoVersioning Boolean? @default(true)
+
+ // Metadata & Tagging
+ metadataCustomFields String? @db.LongText
+ taggingPredefinedTags String? @db.Text
+ taggingUserGeneratedTags Boolean? @default(true)
+ taggingTagSuggestions Boolean? @default(true)
+ classificationAutoEnabled Boolean? @default(true)
+ classificationRules String? @db.Text
+
+ // Workflow & Automation
+ workflowApprovalEnabled Boolean? @default(true)
+ workflowDefaultFlow String? @default("department-head-approval") @db.VarChar(255)
+ workflowCustomFlows String? @db.Text
+ notificationEmail Boolean? @default(true)
+ notificationInApp Boolean? @default(true)
+ notificationUploadAlerts Boolean? @default(true)
+ notificationDeadlineReminders Boolean? @default(true)
+ automationTriggers String? @db.Text
+ automationActions String? @db.Text
+
+ // Upload & Storage Settings
+ uploadAllowedFileTypes String? @db.Text
+ uploadBlockedFileTypes String? @db.Text
+ uploadFileSizeLimit Int? @default(100)
+ uploadQuotaPerUser Int? @default(5000)
+ uploadQuotaPerGroup Int? @default(50000)
+ uploadQuotaPerProject Int? @default(100000)
+ storageType String? @default("local") @db.VarChar(100)
+ storagePath String? @default("/var/uploads/edms") @db.VarChar(500)
+ storageBackupEnabled Boolean? @default(true)
+ storageCompressionEnabled Boolean? @default(false)
+
+ // System Settings
+ systemTimezone String? @default("Asia/Kuala_Lumpur") @db.VarChar(100)
+ systemBackupSchedule String? @default("daily") @db.VarChar(100)
+ systemLogLevel String? @default("info") @db.VarChar(100)
+ systemMaintenanceMode Boolean? @default(false)
+ systemAutoUpdates Boolean? @default(false)
+ systemMonitoring Boolean? @default(true)
+ systemPerformanceMetrics Boolean? @default(true)
+
+ settingCreatedDate DateTime? @default(now()) @db.DateTime(0)
+ settingModifiedDate DateTime? @default(now()) @db.DateTime(0)
}
diff --git a/server/api/dms/settings.js b/server/api/dms/settings.js
new file mode 100644
index 0000000..3261bdf
--- /dev/null
+++ b/server/api/dms/settings.js
@@ -0,0 +1,350 @@
+import { PrismaClient } from "@prisma/client";
+
+const prisma = new PrismaClient();
+
+export default defineEventHandler(async (event) => {
+ const method = getMethod(event);
+
+ try {
+ if (method === "GET") {
+ // Get DMS settings
+ let settings = await prisma.dms_settings.findFirst({
+ orderBy: { settingID: "desc" },
+ });
+
+ // If no settings exist, create default ones
+ if (!settings) {
+ settings = await prisma.dms_settings.create({
+ data: {
+ settingCreatedDate: new Date(),
+ settingModifiedDate: new Date(),
+ },
+ });
+ }
+
+ // Transform database fields to frontend structure
+ const transformedSettings = {
+ // User & Access Management
+ access: {
+ userRoles: settings.userRoles ? settings.userRoles.split(',') : ['Admin', 'Editor', 'Viewer', 'Uploader'],
+ rbacEnabled: settings.rbacEnabled ?? true,
+ userGroups: settings.userGroups ? settings.userGroups.split(',') : ['HR Department', 'Finance', 'IT', 'Legal'],
+ permissions: {
+ view: settings.permissionView ?? true,
+ edit: settings.permissionEdit ?? true,
+ delete: settings.permissionDelete ?? false,
+ download: settings.permissionDownload ?? true,
+ share: settings.permissionShare ?? true
+ },
+ authentication: {
+ ssoEnabled: settings.ssoEnabled ?? false,
+ mfaRequired: settings.mfaRequired ?? false,
+ ldapIntegration: settings.ldapIntegration ?? false,
+ sessionTimeout: settings.sessionTimeout ?? 8
+ }
+ },
+
+ // Document & Folder Settings
+ documents: {
+ folderHierarchy: {
+ maxDepth: settings.folderMaxDepth ?? 5,
+ defaultStructure: settings.folderDefaultStructure ? settings.folderDefaultStructure.split(',') : ['Department', 'Project', 'Category', 'Year'],
+ folderTemplates: settings.folderTemplates ? settings.folderTemplates.split(',') : ['Standard', 'Project-based', 'Department-based']
+ },
+ namingConventions: {
+ autoGenerate: settings.namingAutoGenerate ?? true,
+ mandatoryFields: settings.namingMandatoryFields ? settings.namingMandatoryFields.split(',') : ['title', 'department', 'date'],
+ pattern: settings.namingPattern ?? '{department}_{title}_{date}'
+ },
+ retention: {
+ enabled: settings.retentionEnabled ?? true,
+ defaultDays: settings.retentionDefaultDays ?? 2555,
+ archiveBeforeDelete: settings.retentionArchiveBeforeDelete ?? true
+ },
+ versionControl: {
+ enabled: settings.versionControlEnabled ?? true,
+ maxVersions: settings.versionControlMaxVersions ?? 10,
+ autoVersioning: settings.versionControlAutoVersioning ?? true
+ }
+ },
+
+ // Metadata & Tagging
+ metadata: {
+ customFields: settings.metadataCustomFields ? JSON.parse(settings.metadataCustomFields) : [
+ { name: 'Department', type: 'dropdown', required: true },
+ { name: 'Priority', type: 'select', required: false },
+ { name: 'Project Code', type: 'text', required: true },
+ { name: 'Review Date', type: 'date', required: false }
+ ],
+ tagging: {
+ predefinedTags: settings.taggingPredefinedTags ? settings.taggingPredefinedTags.split(',') : ['urgent', 'confidential', 'public', 'draft', 'final'],
+ userGeneratedTags: settings.taggingUserGeneratedTags ?? true,
+ tagSuggestions: settings.taggingTagSuggestions ?? true
+ },
+ classification: {
+ autoClassification: settings.classificationAutoEnabled ?? true,
+ rules: settings.classificationRules ? settings.classificationRules.split(',') : ['confidential-keywords', 'department-based', 'file-type']
+ }
+ },
+
+ // Workflow & Automation
+ workflow: {
+ approvalFlows: {
+ enabled: settings.workflowApprovalEnabled ?? true,
+ defaultFlow: settings.workflowDefaultFlow ?? 'department-head-approval',
+ customFlows: settings.workflowCustomFlows ? settings.workflowCustomFlows.split(',') : ['legal-review', 'finance-approval', 'director-sign-off']
+ },
+ notifications: {
+ emailNotifications: settings.notificationEmail ?? true,
+ inAppNotifications: settings.notificationInApp ?? true,
+ uploadAlerts: settings.notificationUploadAlerts ?? true,
+ deadlineReminders: settings.notificationDeadlineReminders ?? true
+ },
+ automation: {
+ triggers: settings.automationTriggers ? settings.automationTriggers.split(',') : ['document-uploaded', 'approval-completed', 'deadline-reached'],
+ actions: settings.automationActions ? settings.automationActions.split(',') : ['move-to-folder', 'send-notification', 'create-task']
+ }
+ },
+
+ // Upload & Storage Settings
+ upload: {
+ fileTypes: {
+ allowed: settings.uploadAllowedFileTypes ? settings.uploadAllowedFileTypes.split(',') : ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'jpg', 'png'],
+ blocked: settings.uploadBlockedFileTypes ? settings.uploadBlockedFileTypes.split(',') : ['exe', 'bat', 'cmd']
+ },
+ fileSizeLimit: settings.uploadFileSizeLimit ?? 100,
+ quotas: {
+ perUser: settings.uploadQuotaPerUser ?? 5000,
+ perGroup: settings.uploadQuotaPerGroup ?? 50000,
+ perProject: settings.uploadQuotaPerProject ?? 100000
+ },
+ storage: {
+ type: settings.storageType ?? 'local',
+ path: settings.storagePath ?? '/var/uploads/edms',
+ backupEnabled: settings.storageBackupEnabled ?? true,
+ compressionEnabled: settings.storageCompressionEnabled ?? false
+ }
+ },
+
+ // System Settings
+ system: {
+ timezone: settings.systemTimezone ?? 'Asia/Kuala_Lumpur',
+ backupSchedule: settings.systemBackupSchedule ?? 'daily',
+ logLevel: settings.systemLogLevel ?? 'info',
+ maintenanceMode: settings.systemMaintenanceMode ?? false,
+ autoUpdates: settings.systemAutoUpdates ?? false,
+ systemMonitoring: settings.systemMonitoring ?? true,
+ performanceMetrics: settings.systemPerformanceMetrics ?? true
+ }
+ };
+
+ return {
+ statusCode: 200,
+ message: "Success",
+ data: transformedSettings,
+ };
+ }
+
+ if (method === "POST") {
+ let body;
+ try {
+ body = await readBody(event);
+ } catch (bodyError) {
+ console.error("Error reading request body:", bodyError);
+ return {
+ statusCode: 400,
+ message: "Invalid request body",
+ error: bodyError.message,
+ };
+ }
+
+ // Validate required fields
+ if (!body || typeof body !== 'object') {
+ return {
+ statusCode: 400,
+ message: "Request body must be a valid JSON object",
+ };
+ }
+
+ // Check if settings exist
+ const existingSettings = await prisma.dms_settings.findFirst();
+
+ // Transform frontend structure to database fields
+ const dbData = {
+ settingModifiedDate: new Date()
+ };
+
+ // User & Access Management
+ if (body.access) {
+ if (body.access.userRoles) dbData.userRoles = body.access.userRoles.join(',');
+ if (body.access.rbacEnabled !== undefined) dbData.rbacEnabled = body.access.rbacEnabled;
+ if (body.access.userGroups) dbData.userGroups = body.access.userGroups.join(',');
+ if (body.access.permissions) {
+ if (body.access.permissions.view !== undefined) dbData.permissionView = body.access.permissions.view;
+ if (body.access.permissions.edit !== undefined) dbData.permissionEdit = body.access.permissions.edit;
+ if (body.access.permissions.delete !== undefined) dbData.permissionDelete = body.access.permissions.delete;
+ if (body.access.permissions.download !== undefined) dbData.permissionDownload = body.access.permissions.download;
+ if (body.access.permissions.share !== undefined) dbData.permissionShare = body.access.permissions.share;
+ }
+ if (body.access.authentication) {
+ if (body.access.authentication.ssoEnabled !== undefined) dbData.ssoEnabled = body.access.authentication.ssoEnabled;
+ if (body.access.authentication.mfaRequired !== undefined) dbData.mfaRequired = body.access.authentication.mfaRequired;
+ if (body.access.authentication.ldapIntegration !== undefined) dbData.ldapIntegration = body.access.authentication.ldapIntegration;
+ if (body.access.authentication.sessionTimeout !== undefined) dbData.sessionTimeout = body.access.authentication.sessionTimeout;
+ }
+ }
+
+ // Document & Folder Settings
+ if (body.documents) {
+ if (body.documents.folderHierarchy) {
+ if (body.documents.folderHierarchy.maxDepth !== undefined) dbData.folderMaxDepth = body.documents.folderHierarchy.maxDepth;
+ if (body.documents.folderHierarchy.defaultStructure) dbData.folderDefaultStructure = body.documents.folderHierarchy.defaultStructure.join(',');
+ if (body.documents.folderHierarchy.folderTemplates) dbData.folderTemplates = body.documents.folderHierarchy.folderTemplates.join(',');
+ }
+ if (body.documents.namingConventions) {
+ if (body.documents.namingConventions.autoGenerate !== undefined) dbData.namingAutoGenerate = body.documents.namingConventions.autoGenerate;
+ if (body.documents.namingConventions.mandatoryFields) dbData.namingMandatoryFields = body.documents.namingConventions.mandatoryFields.join(',');
+ if (body.documents.namingConventions.pattern !== undefined) dbData.namingPattern = body.documents.namingConventions.pattern;
+ }
+ if (body.documents.retention) {
+ if (body.documents.retention.enabled !== undefined) dbData.retentionEnabled = body.documents.retention.enabled;
+ if (body.documents.retention.defaultDays !== undefined) dbData.retentionDefaultDays = body.documents.retention.defaultDays;
+ if (body.documents.retention.archiveBeforeDelete !== undefined) dbData.retentionArchiveBeforeDelete = body.documents.retention.archiveBeforeDelete;
+ }
+ if (body.documents.versionControl) {
+ if (body.documents.versionControl.enabled !== undefined) dbData.versionControlEnabled = body.documents.versionControl.enabled;
+ if (body.documents.versionControl.maxVersions !== undefined) dbData.versionControlMaxVersions = body.documents.versionControl.maxVersions;
+ if (body.documents.versionControl.autoVersioning !== undefined) dbData.versionControlAutoVersioning = body.documents.versionControl.autoVersioning;
+ }
+ }
+
+ // Metadata & Tagging
+ if (body.metadata) {
+ if (body.metadata.customFields) dbData.metadataCustomFields = JSON.stringify(body.metadata.customFields);
+ if (body.metadata.tagging) {
+ if (body.metadata.tagging.predefinedTags) dbData.taggingPredefinedTags = body.metadata.tagging.predefinedTags.join(',');
+ if (body.metadata.tagging.userGeneratedTags !== undefined) dbData.taggingUserGeneratedTags = body.metadata.tagging.userGeneratedTags;
+ if (body.metadata.tagging.tagSuggestions !== undefined) dbData.taggingTagSuggestions = body.metadata.tagging.tagSuggestions;
+ }
+ if (body.metadata.classification) {
+ if (body.metadata.classification.autoClassification !== undefined) dbData.classificationAutoEnabled = body.metadata.classification.autoClassification;
+ if (body.metadata.classification.rules) dbData.classificationRules = body.metadata.classification.rules.join(',');
+ }
+ }
+
+ // Workflow & Automation
+ if (body.workflow) {
+ if (body.workflow.approvalFlows) {
+ if (body.workflow.approvalFlows.enabled !== undefined) dbData.workflowApprovalEnabled = body.workflow.approvalFlows.enabled;
+ if (body.workflow.approvalFlows.defaultFlow !== undefined) dbData.workflowDefaultFlow = body.workflow.approvalFlows.defaultFlow;
+ if (body.workflow.approvalFlows.customFlows) dbData.workflowCustomFlows = body.workflow.approvalFlows.customFlows.join(',');
+ }
+ if (body.workflow.notifications) {
+ if (body.workflow.notifications.emailNotifications !== undefined) dbData.notificationEmail = body.workflow.notifications.emailNotifications;
+ if (body.workflow.notifications.inAppNotifications !== undefined) dbData.notificationInApp = body.workflow.notifications.inAppNotifications;
+ if (body.workflow.notifications.uploadAlerts !== undefined) dbData.notificationUploadAlerts = body.workflow.notifications.uploadAlerts;
+ if (body.workflow.notifications.deadlineReminders !== undefined) dbData.notificationDeadlineReminders = body.workflow.notifications.deadlineReminders;
+ }
+ if (body.workflow.automation) {
+ if (body.workflow.automation.triggers) dbData.automationTriggers = body.workflow.automation.triggers.join(',');
+ if (body.workflow.automation.actions) dbData.automationActions = body.workflow.automation.actions.join(',');
+ }
+ }
+
+ // Upload & Storage Settings
+ if (body.upload) {
+ if (body.upload.fileTypes) {
+ if (body.upload.fileTypes.allowed) dbData.uploadAllowedFileTypes = body.upload.fileTypes.allowed.join(',');
+ if (body.upload.fileTypes.blocked) dbData.uploadBlockedFileTypes = body.upload.fileTypes.blocked.join(',');
+ }
+ if (body.upload.fileSizeLimit !== undefined) dbData.uploadFileSizeLimit = body.upload.fileSizeLimit;
+ if (body.upload.quotas) {
+ if (body.upload.quotas.perUser !== undefined) dbData.uploadQuotaPerUser = body.upload.quotas.perUser;
+ if (body.upload.quotas.perGroup !== undefined) dbData.uploadQuotaPerGroup = body.upload.quotas.perGroup;
+ if (body.upload.quotas.perProject !== undefined) dbData.uploadQuotaPerProject = body.upload.quotas.perProject;
+ }
+ if (body.upload.storage) {
+ if (body.upload.storage.type !== undefined) dbData.storageType = body.upload.storage.type;
+ if (body.upload.storage.path !== undefined) dbData.storagePath = body.upload.storage.path;
+ if (body.upload.storage.backupEnabled !== undefined) dbData.storageBackupEnabled = body.upload.storage.backupEnabled;
+ if (body.upload.storage.compressionEnabled !== undefined) dbData.storageCompressionEnabled = body.upload.storage.compressionEnabled;
+ }
+ }
+
+ // System Settings
+ if (body.system) {
+ if (body.system.timezone !== undefined) dbData.systemTimezone = body.system.timezone;
+ if (body.system.backupSchedule !== undefined) dbData.systemBackupSchedule = body.system.backupSchedule;
+ if (body.system.logLevel !== undefined) dbData.systemLogLevel = body.system.logLevel;
+ if (body.system.maintenanceMode !== undefined) dbData.systemMaintenanceMode = body.system.maintenanceMode;
+ if (body.system.autoUpdates !== undefined) dbData.systemAutoUpdates = body.system.autoUpdates;
+ if (body.system.systemMonitoring !== undefined) dbData.systemMonitoring = body.system.systemMonitoring;
+ if (body.system.performanceMetrics !== undefined) dbData.systemPerformanceMetrics = body.system.performanceMetrics;
+ }
+
+ let settings;
+ if (existingSettings) {
+ // Update existing settings
+ settings = await prisma.dms_settings.update({
+ where: { settingID: existingSettings.settingID },
+ data: dbData,
+ });
+ } else {
+ // Create new settings
+ settings = await prisma.dms_settings.create({
+ data: {
+ ...dbData,
+ settingCreatedDate: new Date(),
+ },
+ });
+ }
+
+ return {
+ statusCode: 200,
+ message: "DMS settings updated successfully",
+ data: { settingID: settings.settingID },
+ };
+ }
+
+ return {
+ statusCode: 405,
+ message: "Method not allowed",
+ };
+ } catch (error) {
+ console.error("DMS settings API error:", error);
+
+ // Provide more specific error messages
+ if (error.code === 'P2002') {
+ return {
+ statusCode: 400,
+ message: "Duplicate entry error",
+ error: error.message,
+ };
+ }
+
+ if (error.code === 'P2025') {
+ return {
+ statusCode: 404,
+ message: "Record not found",
+ error: error.message,
+ };
+ }
+
+ if (error.code && error.code.startsWith('P')) {
+ return {
+ statusCode: 400,
+ message: "Database error",
+ error: error.message,
+ code: error.code,
+ };
+ }
+
+ return {
+ statusCode: 500,
+ message: "Internal server error",
+ error: error.message,
+ };
+ } finally {
+ await prisma.$disconnect();
+ }
+});
\ No newline at end of file