# Extensible Workflow Architecture Plan
## Supporting Multiple Template Types (Claim Management, Non-Templatized, Future Templates)

## Overview

This document outlines how to design the backend architecture to support:
1. **Unified Request System**: All requests (templatized, non-templatized, claim management) use the same `workflow_requests` table
2. **Template Identification**: Distinguish between different workflow types
3. **Extensibility**: Easy addition of new templates by admins without code changes
4. **Unified Views**: All requests appear in "My Requests", "Open Requests", etc. automatically

---

## Architecture Principles

### 1. **Single Source of Truth: `workflow_requests` Table**

All requests, regardless of type, are stored in the same table:

```sql
workflow_requests {
    request_id UUID PK
    request_number VARCHAR(20) UK
    initiator_id UUID FK
    template_type VARCHAR(20)        -- 'CUSTOM' | 'TEMPLATE' (high-level)
    workflow_type VARCHAR(50)        -- 'NON_TEMPLATIZED' | 'CLAIM_MANAGEMENT' | 'DEALER_ONBOARDING' | etc.
    template_id UUID FK (nullable)    -- Reference to workflow_templates if using admin template
    title VARCHAR(500)
    description TEXT
    status workflow_status
    current_level INTEGER
    total_levels INTEGER
    -- ... common fields
}
```

**Key Fields:**
- `template_type`: High-level classification ('CUSTOM' for user-created, 'TEMPLATE' for admin templates)
- `workflow_type`: Specific workflow identifier (e.g., 'CLAIM_MANAGEMENT', 'NON_TEMPLATIZED')
- `template_id`: Optional reference to `workflow_templates` table if using an admin-created template

### 2. **Template-Specific Data Storage**

Each workflow type can have its own extension table for type-specific data:

```sql
-- For Claim Management
dealer_claim_details {
    claim_id UUID PK
    request_id UUID FK -> workflow_requests(request_id)
    activity_name VARCHAR(500)
    activity_type VARCHAR(100)
    dealer_code VARCHAR(50)
    dealer_name VARCHAR(200)
    dealer_email VARCHAR(255)
    dealer_phone VARCHAR(20)
    dealer_address TEXT
    activity_date DATE
    location VARCHAR(255)
    period_start_date DATE
    period_end_date DATE
    estimated_budget DECIMAL(15,2)
    closed_expenses DECIMAL(15,2)
    io_number VARCHAR(50)
    io_blocked_amount DECIMAL(15,2)
    sap_document_number VARCHAR(100)
    dms_number VARCHAR(100)
    e_invoice_number VARCHAR(100)
    credit_note_number VARCHAR(100)
    -- ... claim-specific fields
}

-- For Non-Templatized (if needed)
non_templatized_details {
    detail_id UUID PK
    request_id UUID FK -> workflow_requests(request_id)
    custom_fields JSONB  -- Flexible storage for any custom data
    -- ... any specific fields
}

-- For Future Templates
-- Each new template can have its own extension table
```

### 3. **Workflow Templates Table (Admin-Created Templates)**

```sql
workflow_templates {
    template_id UUID PK
    template_name VARCHAR(200)        -- Display name: "Claim Management", "Dealer Onboarding"
    template_code VARCHAR(50) UK       -- Unique identifier: "CLAIM_MANAGEMENT", "DEALER_ONBOARDING"
    template_description TEXT
    template_category VARCHAR(100)     -- "Dealer Operations", "HR", "Finance", etc.
    workflow_type VARCHAR(50)          -- Maps to workflow_requests.workflow_type
    approval_levels_config JSONB       -- Step definitions, TAT, roles, etc.
    default_tat_hours DECIMAL(10,2)
    form_fields_config JSONB           -- Form field definitions for wizard
    is_active BOOLEAN
    is_system_template BOOLEAN         -- True for built-in (Claim Management), False for admin-created
    created_by UUID FK
    created_at TIMESTAMP
    updated_at TIMESTAMP
}
```

---

## Database Schema Changes

### Migration: Add Workflow Type Support

```sql
-- Migration: 20251210-add-workflow-type-support.ts

-- 1. Add workflow_type column to workflow_requests
ALTER TABLE workflow_requests 
ADD COLUMN IF NOT EXISTS workflow_type VARCHAR(50) DEFAULT 'NON_TEMPLATIZED';

-- 2. Add template_id column (nullable, for admin templates)
ALTER TABLE workflow_requests 
ADD COLUMN IF NOT EXISTS template_id UUID REFERENCES workflow_templates(template_id);

-- 3. Create index for workflow_type
CREATE INDEX IF NOT EXISTS idx_workflow_requests_workflow_type 
ON workflow_requests(workflow_type);

-- 4. Create index for template_id
CREATE INDEX IF NOT EXISTS idx_workflow_requests_template_id 
ON workflow_requests(template_id);

-- 5. Create dealer_claim_details table
CREATE TABLE IF NOT EXISTS dealer_claim_details (
    claim_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    request_id UUID NOT NULL UNIQUE REFERENCES workflow_requests(request_id) ON DELETE CASCADE,
    activity_name VARCHAR(500) NOT NULL,
    activity_type VARCHAR(100) NOT NULL,
    dealer_code VARCHAR(50) NOT NULL,
    dealer_name VARCHAR(200) NOT NULL,
    dealer_email VARCHAR(255),
    dealer_phone VARCHAR(20),
    dealer_address TEXT,
    activity_date DATE,
    location VARCHAR(255),
    period_start_date DATE,
    period_end_date DATE,
    estimated_budget DECIMAL(15,2),
    closed_expenses DECIMAL(15,2),
    io_number VARCHAR(50),
    io_available_balance DECIMAL(15,2),
    io_blocked_amount DECIMAL(15,2),
    io_remaining_balance DECIMAL(15,2),
    sap_document_number VARCHAR(100),
    dms_number VARCHAR(100),
    e_invoice_number VARCHAR(100),
    e_invoice_date DATE,
    credit_note_number VARCHAR(100),
    credit_note_date DATE,
    credit_note_amount DECIMAL(15,2),
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_dealer_claim_details_request_id ON dealer_claim_details(request_id);
CREATE INDEX idx_dealer_claim_details_dealer_code ON dealer_claim_details(dealer_code);

-- 6. Create proposal_details table (Step 1: Dealer Proposal)
CREATE TABLE IF NOT EXISTS dealer_proposal_details (
    proposal_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    request_id UUID NOT NULL REFERENCES workflow_requests(request_id) ON DELETE CASCADE,
    proposal_document_path VARCHAR(500),
    proposal_document_url VARCHAR(500),
    cost_breakup JSONB,  -- Array of {description, amount}
    total_estimated_budget DECIMAL(15,2),
    timeline_mode VARCHAR(10),  -- 'date' | 'days'
    expected_completion_date DATE,
    expected_completion_days INTEGER,
    dealer_comments TEXT,
    submitted_at TIMESTAMP WITH TIME ZONE,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_dealer_proposal_details_request_id ON dealer_proposal_details(request_id);

-- 7. Create completion_documents table (Step 5: Dealer Completion)
CREATE TABLE IF NOT EXISTS dealer_completion_details (
    completion_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    request_id UUID NOT NULL REFERENCES workflow_requests(request_id) ON DELETE CASCADE,
    activity_completion_date DATE NOT NULL,
    number_of_participants INTEGER,
    closed_expenses JSONB,  -- Array of {description, amount}
    total_closed_expenses DECIMAL(15,2),
    completion_documents JSONB,  -- Array of document references
    activity_photos JSONB,  -- Array of photo references
    submitted_at TIMESTAMP WITH TIME ZONE,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_dealer_completion_details_request_id ON dealer_completion_details(request_id);
```

---

## Model Updates

### 1. Update WorkflowRequest Model

```typescript
// Re_Backend/src/models/WorkflowRequest.ts

interface WorkflowRequestAttributes {
  requestId: string;
  requestNumber: string;
  initiatorId: string;
  templateType: 'CUSTOM' | 'TEMPLATE';
  workflowType: string;  // NEW: 'NON_TEMPLATIZED' | 'CLAIM_MANAGEMENT' | etc.
  templateId?: string;   // NEW: Reference to workflow_templates
  title: string;
  description: string;
  // ... existing fields
}

// Add association
WorkflowRequest.hasOne(DealerClaimDetails, {
  as: 'claimDetails',
  foreignKey: 'requestId',
  sourceKey: 'requestId'
});
```

### 2. Create DealerClaimDetails Model

```typescript
// Re_Backend/src/models/DealerClaimDetails.ts

import { DataTypes, Model } from 'sequelize';
import { sequelize } from '@config/database';
import { WorkflowRequest } from './WorkflowRequest';

interface DealerClaimDetailsAttributes {
  claimId: string;
  requestId: string;
  activityName: string;
  activityType: string;
  dealerCode: string;
  dealerName: string;
  // ... all claim-specific fields
}

class DealerClaimDetails extends Model<DealerClaimDetailsAttributes> {
  public claimId!: string;
  public requestId!: string;
  // ... fields
}

DealerClaimDetails.init({
  claimId: {
    type: DataTypes.UUID,
    defaultValue: DataTypes.UUIDV4,
    primaryKey: true,
    field: 'claim_id'
  },
  requestId: {
    type: DataTypes.UUID,
    allowNull: false,
    unique: true,
    field: 'request_id',
    references: {
      model: 'workflow_requests',
      key: 'request_id'
    }
  },
  // ... all other fields
}, {
  sequelize,
  modelName: 'DealerClaimDetails',
  tableName: 'dealer_claim_details',
  timestamps: true
});

// Association
DealerClaimDetails.belongsTo(WorkflowRequest, {
  as: 'workflowRequest',
  foreignKey: 'requestId',
  targetKey: 'requestId'
});

export { DealerClaimDetails };
```

---

## Service Layer Pattern

### 1. Template-Aware Service Factory

```typescript
// Re_Backend/src/services/templateService.factory.ts

import { WorkflowRequest } from '../models/WorkflowRequest';
import { DealerClaimService } from './dealerClaim.service';
import { NonTemplatizedService } from './nonTemplatized.service';

export class TemplateServiceFactory {
  static getService(workflowType: string) {
    switch (workflowType) {
      case 'CLAIM_MANAGEMENT':
        return new DealerClaimService();
      case 'NON_TEMPLATIZED':
        return new NonTemplatizedService();
      default:
        // For future templates, use a generic service or throw error
        throw new Error(`Unsupported workflow type: ${workflowType}`);
    }
  }

  static async getRequestDetails(requestId: string) {
    const request = await WorkflowRequest.findByPk(requestId);
    if (!request) return null;

    const service = this.getService(request.workflowType);
    return service.getRequestDetails(request);
  }
}
```

### 2. Unified Workflow Service (No Changes Needed)

The existing `WorkflowService.listMyRequests()` and `listOpenForMe()` methods will **automatically** include all request types because they query `workflow_requests` table without filtering by `workflow_type`.

```typescript
// Existing code works as-is - no changes needed!
async listMyRequests(userId: string, page: number, limit: number, filters?: {...}) {
  // This query automatically includes ALL workflow types
  const requests = await WorkflowRequest.findAll({
    where: {
      initiatorId: userId,
      isDraft: false,
      // ... filters
      // NO workflow_type filter - includes everything!
    }
  });
  return requests;
}
```

---

## API Endpoints

### 1. Create Claim Management Request

```typescript
// Re_Backend/src/controllers/dealerClaim.controller.ts

async createClaimRequest(req: AuthenticatedRequest, res: Response) {
  const userId = req.user?.userId;
  const {
    activityName,
    activityType,
    dealerCode,
    // ... claim-specific fields
  } = req.body;

  // 1. Create workflow request (common)
  const workflowRequest = await WorkflowRequest.create({
    initiatorId: userId,
    templateType: 'CUSTOM',
    workflowType: 'CLAIM_MANAGEMENT',  // Identify as claim
    title: `${activityName} - Claim Request`,
    description: req.body.requestDescription,
    totalLevels: 8,  // Fixed 8-step workflow
    // ... other common fields
  });

  // 2. Create claim-specific details
  const claimDetails = await DealerClaimDetails.create({
    requestId: workflowRequest.requestId,
    activityName,
    activityType,
    dealerCode,
    // ... claim-specific fields
  });

  // 3. Create approval levels (8 steps)
  await this.createClaimApprovalLevels(workflowRequest.requestId);

  return ResponseHandler.success(res, {
    request: workflowRequest,
    claimDetails
  });
}
```

### 2. Get Request Details (Template-Aware)

```typescript
async getRequestDetails(req: Request, res: Response) {
  const { requestId } = req.params;
  
  const request = await WorkflowRequest.findByPk(requestId, {
    include: [
      { model: User, as: 'initiator' },
      // Conditionally include template-specific data
      ...(request.workflowType === 'CLAIM_MANAGEMENT' 
        ? [{ model: DealerClaimDetails, as: 'claimDetails' }]
        : [])
    ]
  });

  // Use factory to get template-specific service
  const templateService = TemplateServiceFactory.getService(request.workflowType);
  const enrichedDetails = await templateService.enrichRequestDetails(request);

  return ResponseHandler.success(res, enrichedDetails);
}
```

---

## Frontend Integration

### 1. Request List Views (No Changes Needed)

The existing "My Requests" and "Open Requests" pages will automatically show all request types because the backend doesn't filter by `workflow_type`.

```typescript
// Frontend: MyRequests.tsx - No changes needed!
const fetchMyRequests = async () => {
  const result = await workflowApi.listMyInitiatedWorkflows({
    page,
    limit: itemsPerPage
  });
  // Returns ALL request types automatically
};
```

### 2. Request Detail Page (Template-Aware Rendering)

```typescript
// Frontend: RequestDetail.tsx

const RequestDetail = ({ requestId }) => {
  const request = useRequestDetails(requestId);
  
  // Render based on workflow type
  if (request.workflowType === 'CLAIM_MANAGEMENT') {
    return <ClaimManagementDetail request={request} />;
  } else if (request.workflowType === 'NON_TEMPLATIZED') {
    return <NonTemplatizedDetail request={request} />;
  } else {
    // Future templates - use generic renderer or template config
    return <GenericWorkflowDetail request={request} />;
  }
};
```

---

## Adding New Templates (Future)

### Step 1: Admin Creates Template in UI

1. Admin goes to "Template Management" page
2. Creates new template with:
   - Template name: "Vendor Payment"
   - Template code: "VENDOR_PAYMENT"
   - Approval levels configuration
   - Form fields configuration

### Step 2: Database Entry Created

```sql
INSERT INTO workflow_templates (
  template_name,
  template_code,
  workflow_type,
  approval_levels_config,
  form_fields_config,
  is_active,
  is_system_template
) VALUES (
  'Vendor Payment',
  'VENDOR_PAYMENT',
  'VENDOR_PAYMENT',
  '{"levels": [...], "tat": {...}}'::jsonb,
  '{"fields": [...]}'::jsonb,
  true,
  false  -- Admin-created, not system template
);
```

### Step 3: Create Extension Table (If Needed)

```sql
CREATE TABLE vendor_payment_details (
    payment_id UUID PRIMARY KEY,
    request_id UUID UNIQUE REFERENCES workflow_requests(request_id),
    vendor_code VARCHAR(50),
    invoice_number VARCHAR(100),
    payment_amount DECIMAL(15,2),
    -- ... vendor-specific fields
);
```

### Step 4: Create Service (Optional - Can Use Generic Service)

```typescript
// Re_Backend/src/services/vendorPayment.service.ts

export class VendorPaymentService {
  async getRequestDetails(request: WorkflowRequest) {
    const paymentDetails = await VendorPaymentDetails.findOne({
      where: { requestId: request.requestId }
    });
    
    return {
      ...request.toJSON(),
      paymentDetails
    };
  }
}

// Update factory
TemplateServiceFactory.getService(workflowType: string) {
  switch (workflowType) {
    case 'VENDOR_PAYMENT':
      return new VendorPaymentService();
    // ... existing cases
  }
}
```

### Step 5: Frontend Component (Optional)

```typescript
// Frontend: components/VendorPaymentDetail.tsx

export function VendorPaymentDetail({ request }) {
  // Render vendor payment specific UI
}
```

---

## Benefits of This Architecture

1. **Unified Data Model**: All requests in one table, easy to query
2. **Automatic Inclusion**: My Requests/Open Requests show all types automatically
3. **Extensibility**: Add new templates without modifying existing code
4. **Type Safety**: Template-specific data in separate tables
5. **Flexibility**: Support both system templates and admin-created templates
6. **Backward Compatible**: Existing non-templatized requests continue to work

---

## Migration Strategy

1. **Phase 1**: Add `workflow_type` column, set default to 'NON_TEMPLATIZED' for existing requests
2. **Phase 2**: Create `dealer_claim_details` table and models
3. **Phase 3**: Update claim management creation flow to use new structure
4. **Phase 4**: Update request detail endpoints to be template-aware
5. **Phase 5**: Frontend updates (if needed) for template-specific rendering

---

## Summary

- **All requests** use `workflow_requests` table
- **Template identification** via `workflow_type` field
- **Template-specific data** in extension tables (e.g., `dealer_claim_details`)
- **Unified views** automatically include all types
- **Future templates** can be added by admins without code changes
- **Existing functionality** remains unchanged

This architecture ensures that:
- ✅ Claim Management requests appear in My Requests/Open Requests
- ✅ Non-templatized requests continue to work
- ✅ Future templates can be added easily
- ✅ No code duplication
- ✅ Single source of truth for all requests

