T.ME/BIBIL_0DAY
CasperSecurity


Server : Apache/2
System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64
User : gositeme ( 1004)
PHP Version : 8.2.29
Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
Directory :  /home/gositeme/domains/lavocat.ca/public_html/src/lib/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/lavocat.ca/public_html/src/lib/workflow-automation.ts
import { prisma } from './prisma';
import { AIAssignmentEngine } from './ai-assignment-engine';
import { logger } from './logger';

interface WorkflowRule {
  id: string;
  name: string;
  trigger: 'case_created' | 'status_changed' | 'document_uploaded' | 'deadline_approaching';
  conditions: WorkflowCondition[];
  actions: WorkflowAction[];
  isActive: boolean;
  priority: number;
}

interface WorkflowCondition {
  field: string;
  operator: 'equals' | 'contains' | 'greater_than' | 'less_than' | 'in_list';
  value: any;
}

interface WorkflowAction {
  type: 'assign_case' | 'send_notification' | 'update_status' | 'create_task' | 'escalate';
  parameters: any;
}

export class WorkflowAutomation {
  
  private static workflows: WorkflowRule[] = [
    {
      id: 'urgent_case_auto_assign',
      name: 'Auto-assign urgent cases',
      trigger: 'case_created',
      conditions: [
        { field: 'urgentNeeds', operator: 'contains', value: ['urgent', 'court date', 'hearing'] }
      ],
      actions: [
        { type: 'assign_case', parameters: { priority: 'high', autoAssign: true } },
        { type: 'send_notification', parameters: { recipients: 'admins', template: 'urgent_case' } }
      ],
      isActive: true,
      priority: 1
    },
    {
      id: 'complex_case_team_assignment',
      name: 'Complex cases need full team',
      trigger: 'case_created',
      conditions: [
        { field: 'documentCount', operator: 'greater_than', value: 5 },
        { field: 'message', operator: 'contains', value: ['appeal', 'wrongful conviction', 'class action'] }
      ],
      actions: [
        { type: 'assign_case', parameters: { teamSize: 'full', includeSecretary: true } },
        { type: 'create_task', parameters: { type: 'document_review', assignTo: 'secretary' } }
      ],
      isActive: true,
      priority: 2
    },
    {
      id: 'deadline_reminder_system',
      name: 'Deadline reminder automation',
      trigger: 'deadline_approaching',
      conditions: [
        { field: 'daysUntilDeadline', operator: 'less_than', value: 7 }
      ],
      actions: [
        { type: 'send_notification', parameters: { recipients: 'assigned_team', template: 'deadline_reminder' } },
        { type: 'escalate', parameters: { to: 'primary_lawyer', urgency: 'high' } }
      ],
      isActive: true,
      priority: 3
    },
    {
      id: 'status_update_notifications',
      name: 'Status change notifications',
      trigger: 'status_changed',
      conditions: [
        { field: 'newStatus', operator: 'in_list', value: ['APPROVED', 'REJECTED', 'UNDER_REVIEW'] }
      ],
      actions: [
        { type: 'send_notification', parameters: { recipients: 'client_family', template: 'status_update' } }
      ],
      isActive: true,
      priority: 4
    },
    {
      id: 'workload_balancing',
      name: 'Auto-balance team workload',
      trigger: 'case_created',
      conditions: [
        { field: 'assignedLawyerUtilization', operator: 'greater_than', value: 85 }
      ],
      actions: [
        { type: 'assign_case', parameters: { strategy: 'load_balance', skipOverloaded: true } }
      ],
      isActive: true,
      priority: 5
    }
  ];

  /**
   * Process workflow triggers for new cases
   */
  static async processNewCase(registrationId: string): Promise<void> {
    try {
      const registration = await prisma.registration.findUnique({
        where: { id: registrationId },
        include: { documents: true, detaineeInfo: true }
      });

      if (!registration) return;

      const triggerWorkflows = this.workflows.filter(
        w => w.trigger === 'case_created' && w.isActive
      ).sort((a, b) => a.priority - b.priority);

      for (const workflow of triggerWorkflows) {
        if (await this.evaluateConditions(workflow.conditions, registration)) {
          await this.executeActions(workflow.actions, registration);
          
          logger.info('Workflow executed', {
            workflowId: workflow.id,
            registrationId,
            trigger: 'case_created'
          });
        }
      }
    } catch (error) {
      logger.error('Error processing workflow for new case', { error, registrationId });
    }
  }

  /**
   * Process status change workflows
   */
  static async processStatusChange(
    registrationId: string, 
    oldStatus: string, 
    newStatus: string
  ): Promise<void> {
    try {
      const registration = await prisma.registration.findUnique({
        where: { id: registrationId },
        include: { documents: true, detaineeInfo: true }
      });

      if (!registration) return;

      const triggerWorkflows = this.workflows.filter(
        w => w.trigger === 'status_changed' && w.isActive
      ).sort((a, b) => a.priority - b.priority);

      for (const workflow of triggerWorkflows) {
        const contextData = { ...registration, oldStatus, newStatus };
        if (await this.evaluateConditions(workflow.conditions, contextData)) {
          await this.executeActions(workflow.actions, contextData);
          
          logger.info('Status change workflow executed', {
            workflowId: workflow.id,
            registrationId,
            oldStatus,
            newStatus
          });
        }
      }
    } catch (error) {
      logger.error('Error processing status change workflow', { error, registrationId });
    }
  }

  /**
   * Evaluate workflow conditions
   */
  private static async evaluateConditions(
    conditions: WorkflowCondition[], 
    data: any
  ): Promise<boolean> {
    for (const condition of conditions) {
      const fieldValue = this.getFieldValue(data, condition.field);
      
      if (!this.evaluateCondition(fieldValue, condition.operator, condition.value)) {
        return false;
      }
    }
    return true;
  }

  /**
   * Get field value from data object
   */
  private static getFieldValue(data: any, fieldPath: string): any {
    const keys = fieldPath.split('.');
    let value = data;
    
    for (const key of keys) {
      if (value && typeof value === 'object') {
        value = value[key];
      } else {
        return undefined;
      }
    }
    
    // Special computed fields
    if (fieldPath === 'documentCount') {
      return data.documents?.length || 0;
    }
    
    return value;
  }

  /**
   * Evaluate single condition
   */
  private static evaluateCondition(fieldValue: any, operator: string, expectedValue: any): boolean {
    switch (operator) {
      case 'equals':
        return fieldValue === expectedValue;
      
      case 'contains':
        if (typeof fieldValue === 'string') {
          if (Array.isArray(expectedValue)) {
            return expectedValue.some(val => fieldValue.toLowerCase().includes(val.toLowerCase()));
          }
          return fieldValue.toLowerCase().includes(expectedValue.toLowerCase());
        }
        return false;
      
      case 'greater_than':
        return Number(fieldValue) > Number(expectedValue);
      
      case 'less_than':
        return Number(fieldValue) < Number(expectedValue);
      
      case 'in_list':
        return Array.isArray(expectedValue) && expectedValue.includes(fieldValue);
      
      default:
        return false;
    }
  }

  /**
   * Execute workflow actions
   */
  private static async executeActions(actions: WorkflowAction[], data: any): Promise<void> {
    for (const action of actions) {
      try {
        await this.executeAction(action, data);
      } catch (error) {
        logger.error('Error executing workflow action', { error, action, registrationId: data.id });
      }
    }
  }

  /**
   * Execute single workflow action
   */
  private static async executeAction(action: WorkflowAction, data: any): Promise<void> {
    switch (action.type) {
      case 'assign_case':
        await this.handleCaseAssignment(action.parameters, data);
        break;
      
      case 'send_notification':
        await this.handleNotification(action.parameters, data);
        break;
      
      case 'update_status':
        await this.handleStatusUpdate(action.parameters, data);
        break;
      
      case 'create_task':
        await this.handleTaskCreation(action.parameters, data);
        break;
      
      case 'escalate':
        await this.handleEscalation(action.parameters, data);
        break;
    }
  }

  /**
   * Handle automatic case assignment
   */
  private static async handleCaseAssignment(parameters: any, data: any): Promise<void> {
    if (parameters.autoAssign) {
      // Use AI engine for optimal assignment
      const adminUser = await prisma.user.findFirst({
        where: { role: { in: ['SUPERADMIN', 'SUPERADMIN'] } }
      });
      
      if (adminUser) {
        await AIAssignmentEngine.autoAssignOptimalTeam(data.id, adminUser.id);
      }
    } else if (parameters.strategy === 'load_balance') {
      // Implement load balancing logic
      const availableLawyers = await prisma.user.findMany({
        where: { 
          role: { in: ['LAWYER', 'ADMIN'] },
        },
        include: {
          caseAssignments: {
            where: { isActive: true }
          }
        }
      });
      
      // Find lawyer with lowest caseload
      const optimalLawyer = availableLawyers.reduce((prev, current) => 
        (prev.caseAssignments.length < current.caseAssignments.length) ? prev : current
      );
      
      if (optimalLawyer) {
        await prisma.caseAssignment.create({
          data: {
            registrationId: data.id,
            userId: optimalLawyer.id,
            role: 'primary_lawyer',
            assignedBy: 'SYSTEM_AUTO'
          }
        });
      }
    }
  }

  /**
   * Handle notification sending
   */
  private static async handleNotification(parameters: any, data: any): Promise<void> {
    // This would integrate with your notification system
    logger.info('Sending automated notification', {
      recipients: parameters.recipients,
      template: parameters.template,
      registrationId: data.id
    });
    
    // Example: Send to assigned team
    if (parameters.recipients === 'assigned_team') {
      const assignments = await prisma.caseAssignment.findMany({
        where: { registrationId: data.id, isActive: true },
        include: { user: true }
      });
      
      // Send notifications to each team member
      for (const assignment of assignments) {
        // Integrate with your notification service here
        console.log(`Notification sent to ${assignment.user.email}: ${parameters.template}`);
      }
    }
  }

  /**
   * Handle status updates
   */
  private static async handleStatusUpdate(parameters: any, data: any): Promise<void> {
    if (parameters.newStatus) {
      await prisma.registration.update({
        where: { id: data.id },
        data: { status: parameters.newStatus }
      });
    }
  }

  /**
   * Handle task creation
   */
  private static async handleTaskCreation(parameters: any, data: any): Promise<void> {
    // This would create tasks in your task management system
    logger.info('Creating automated task', {
      type: parameters.type,
      assignTo: parameters.assignTo,
      registrationId: data.id
    });
  }

  /**
   * Handle escalation
   */
  private static async handleEscalation(parameters: any, data: any): Promise<void> {
    // Find the person to escalate to
    let escalationTarget;
    
    if (parameters.to === 'primary_lawyer') {
      const primaryAssignment = await prisma.caseAssignment.findFirst({
        where: { 
          registrationId: data.id, 
          role: 'primary_lawyer',
          isActive: true 
        },
        include: { user: true }
      });
      escalationTarget = primaryAssignment?.user;
    } else {
      escalationTarget = await prisma.user.findFirst({
        where: { role: { in: ['SUPERADMIN', 'SUPERADMIN'] } }
      });
    }
    
    if (escalationTarget) {
      logger.info('Case escalated', {
        escalatedTo: escalationTarget.email,
        urgency: parameters.urgency,
        registrationId: data.id
      });
    }
  }

  /**
   * Run daily automation checks
   */
  static async runDailyAutomation(): Promise<void> {
    try {
      // Check for approaching deadlines
      const approachingDeadlines = await prisma.registration.findMany({
        where: {
          status: { in: ['PENDING', 'DOCUMENTS_UNDER_REVIEW', 'UNDER_REVIEW'] },
          // Add deadline field to your schema if needed
        },
        include: { documents: true }
      });

      for (const registration of approachingDeadlines) {
        // Process deadline workflows
        const triggerWorkflows = this.workflows.filter(
          w => w.trigger === 'deadline_approaching' && w.isActive
        );

        for (const workflow of triggerWorkflows) {
          if (await this.evaluateConditions(workflow.conditions, registration)) {
            await this.executeActions(workflow.actions, registration);
          }
        }
      }

      // Check for overloaded team members
      await this.checkWorkloadBalance();

      logger.info('Daily automation completed successfully');
    } catch (error) {
      logger.error('Error in daily automation', { error });
    }
  }

  /**
   * Check and rebalance workloads
   */
  private static async checkWorkloadBalance(): Promise<void> {
    const teamMembers = await prisma.user.findMany({
      where: { role: { in: ['LAWYER', 'ADMIN'] } },
      include: {
        caseAssignments: {
          where: { isActive: true },
          include: { registration: true }
        }
      }
    });

    for (const member of teamMembers) {
      const utilization = (member.caseAssignments.length / 5) * 100; // Assuming 5 cases = 100%
      
      if (utilization > 90) {
        logger.warn('Team member overloaded', {
          userId: member.id,
          name: member.name,
          utilization,
          activeCases: member.caseAssignments.length
        });
        
        // Could trigger reassignment or hiring recommendations
      }
    }
  }

  /**
   * Get workflow statistics
   */
  static async getWorkflowStats(): Promise<any> {
    return {
      totalWorkflows: this.workflows.length,
      activeWorkflows: this.workflows.filter(w => w.isActive).length,
      executionsToday: 0, // Would track in database
      averageExecutionTime: 0 // Would track performance
    };
  }
} 

CasperSecurity Mini