348 lines
11 KiB
Markdown
348 lines
11 KiB
Markdown
|
|
# Approval Workflow Architecture & Module Relationships
|
||
|
|
|
||
|
|
## 📋 **Overview**
|
||
|
|
|
||
|
|
Sistem approval workflow di MEDOLS menggunakan arsitektur multi-module yang saling terintegrasi untuk mengelola proses persetujuan artikel secara dinamis. Setiap module memiliki peran spesifik dalam alur approval yang kompleks.
|
||
|
|
|
||
|
|
## 🏗️ **Module Architecture**
|
||
|
|
|
||
|
|
### **1. Core Workflow Modules**
|
||
|
|
|
||
|
|
#### **`approval_workflows`** - Master Workflow Definition
|
||
|
|
- **Purpose**: Mendefinisikan template workflow approval
|
||
|
|
- **Key Fields**:
|
||
|
|
- `id`: Primary key
|
||
|
|
- `name`: Nama workflow (e.g., "Standard Approval", "Fast Track")
|
||
|
|
- `description`: Deskripsi workflow
|
||
|
|
- `is_default`: Apakah workflow default untuk client
|
||
|
|
- `is_active`: Status aktif workflow
|
||
|
|
- `client_id`: Client yang memiliki workflow
|
||
|
|
|
||
|
|
#### **`approval_workflow_steps`** - Workflow Steps Definition
|
||
|
|
- **Purpose**: Mendefinisikan step-step dalam workflow
|
||
|
|
- **Key Fields**:
|
||
|
|
- `id`: Primary key
|
||
|
|
- `workflow_id`: Foreign key ke `approval_workflows`
|
||
|
|
- `step_order`: Urutan step (1, 2, 3, dst.)
|
||
|
|
- `step_name`: Nama step (e.g., "Level 2 Review", "Level 1 Final Approval")
|
||
|
|
- `required_user_level_id`: User level yang harus approve step ini
|
||
|
|
- `is_required`: Apakah step wajib atau optional
|
||
|
|
|
||
|
|
### **2. Execution Modules**
|
||
|
|
|
||
|
|
#### **`article_approval_flows`** - Active Approval Instances
|
||
|
|
- **Purpose**: Instance aktif dari workflow yang sedang berjalan
|
||
|
|
- **Key Fields**:
|
||
|
|
- `id`: Primary key
|
||
|
|
- `article_id`: Foreign key ke `articles`
|
||
|
|
- `workflow_id`: Foreign key ke `approval_workflows`
|
||
|
|
- `current_step`: Step saat ini yang sedang menunggu approval
|
||
|
|
- `status_id`: Status (1=pending, 2=approved, 3=rejected, 4=revision_requested)
|
||
|
|
- `submitted_by_id`: User yang submit artikel
|
||
|
|
- `submitted_at`: Waktu submit
|
||
|
|
- `completed_at`: Waktu selesai (jika approved/rejected)
|
||
|
|
|
||
|
|
#### **`article_approval_step_logs`** - Step Execution History
|
||
|
|
- **Purpose**: Log setiap step yang telah dieksekusi
|
||
|
|
- **Key Fields**:
|
||
|
|
- `id`: Primary key
|
||
|
|
- `approval_flow_id`: Foreign key ke `article_approval_flows`
|
||
|
|
- `step_order`: Urutan step yang dieksekusi
|
||
|
|
- `step_name`: Nama step
|
||
|
|
- `approved_by_id`: User yang approve step ini
|
||
|
|
- `action`: Aksi yang dilakukan (approve, reject, auto_skip)
|
||
|
|
- `message`: Pesan dari approver
|
||
|
|
- `processed_at`: Waktu eksekusi
|
||
|
|
|
||
|
|
### **3. Legacy & Configuration Modules**
|
||
|
|
|
||
|
|
#### **`article_approvals`** - Legacy Approval System
|
||
|
|
- **Purpose**: Sistem approval legacy untuk backward compatibility
|
||
|
|
- **Key Fields**:
|
||
|
|
- `id`: Primary key
|
||
|
|
- `article_id`: Foreign key ke `articles`
|
||
|
|
- `approval_by`: User yang approve
|
||
|
|
- `status_id`: Status approval
|
||
|
|
- `approval_at_level`: Level yang approve
|
||
|
|
- `message`: Pesan approval
|
||
|
|
|
||
|
|
#### **`client_approval_settings`** - Client Configuration
|
||
|
|
- **Purpose**: Konfigurasi approval untuk setiap client
|
||
|
|
- **Key Fields**:
|
||
|
|
- `id`: Primary key
|
||
|
|
- `client_id`: Foreign key ke `clients`
|
||
|
|
- `workflow_id`: Workflow default untuk client
|
||
|
|
- `auto_approve_levels`: Level yang auto-approve
|
||
|
|
- `notification_settings`: Konfigurasi notifikasi
|
||
|
|
|
||
|
|
## 🔄 **Approval Workflow Process Flow**
|
||
|
|
|
||
|
|
### **Phase 1: Setup & Configuration**
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
graph TD
|
||
|
|
A[Client Setup] --> B[Create Approval Workflow]
|
||
|
|
B --> C[Define Workflow Steps]
|
||
|
|
C --> D[Set Required User Levels]
|
||
|
|
D --> E[Configure Client Settings]
|
||
|
|
E --> F[Activate Workflow]
|
||
|
|
```
|
||
|
|
|
||
|
|
**Steps:**
|
||
|
|
1. **Client Registration**: Client baru dibuat di sistem
|
||
|
|
2. **Workflow Creation**: Admin membuat workflow approval
|
||
|
|
3. **Step Definition**: Mendefinisikan step-step dengan user level requirement
|
||
|
|
4. **Client Configuration**: Set workflow default untuk client
|
||
|
|
|
||
|
|
### **Phase 2: Article Submission**
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
graph TD
|
||
|
|
A[User Creates Article] --> B{User Level Requires Approval?}
|
||
|
|
B -->|Yes| C[Create Article Approval Flow]
|
||
|
|
B -->|No| D[Auto Publish]
|
||
|
|
C --> E[Set Current Step = 1]
|
||
|
|
E --> F[Status = Pending]
|
||
|
|
F --> G[Create Legacy Approval Record]
|
||
|
|
G --> H[Notify Approvers]
|
||
|
|
```
|
||
|
|
|
||
|
|
**Database Changes:**
|
||
|
|
- `articles`: `workflow_id`, `current_approval_step = 1`, `status_id = 1`
|
||
|
|
- `article_approval_flows`: New record dengan `current_step = 1`
|
||
|
|
- `article_approvals`: Legacy record untuk backward compatibility
|
||
|
|
|
||
|
|
### **Phase 3: Step-by-Step Approval**
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
graph TD
|
||
|
|
A[Approver Reviews Article] --> B{Approve or Reject?}
|
||
|
|
B -->|Approve| C[Create Step Log]
|
||
|
|
B -->|Reject| D[Update Status to Rejected]
|
||
|
|
C --> E{More Steps?}
|
||
|
|
E -->|Yes| F[Move to Next Step]
|
||
|
|
E -->|No| G[Complete Approval]
|
||
|
|
F --> H[Update Current Step]
|
||
|
|
H --> I[Notify Next Approver]
|
||
|
|
G --> J[Update Article Status to Approved]
|
||
|
|
D --> K[Notify Submitter]
|
||
|
|
```
|
||
|
|
|
||
|
|
**Database Changes per Step:**
|
||
|
|
- `article_approval_step_logs`: New log record
|
||
|
|
- `article_approval_flows`: Update `current_step` dan `status_id`
|
||
|
|
- `articles`: Update `current_approval_step`
|
||
|
|
|
||
|
|
### **Phase 4: Completion**
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
graph TD
|
||
|
|
A[All Steps Approved] --> B[Update Final Status]
|
||
|
|
B --> C[Set Completed At]
|
||
|
|
C --> D[Publish Article]
|
||
|
|
D --> E[Send Notifications]
|
||
|
|
E --> F[Update Analytics]
|
||
|
|
```
|
||
|
|
|
||
|
|
## 📊 **Module Relationships Diagram**
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
erDiagram
|
||
|
|
CLIENTS ||--o{ APPROVAL_WORKFLOWS : "has"
|
||
|
|
CLIENTS ||--o{ CLIENT_APPROVAL_SETTINGS : "configures"
|
||
|
|
|
||
|
|
APPROVAL_WORKFLOWS ||--o{ APPROVAL_WORKFLOW_STEPS : "contains"
|
||
|
|
APPROVAL_WORKFLOWS ||--o{ ARTICLE_APPROVAL_FLOWS : "instantiates"
|
||
|
|
|
||
|
|
ARTICLES ||--o{ ARTICLE_APPROVAL_FLOWS : "has"
|
||
|
|
ARTICLES ||--o{ ARTICLE_APPROVALS : "has_legacy"
|
||
|
|
|
||
|
|
ARTICLE_APPROVAL_FLOWS ||--o{ ARTICLE_APPROVAL_STEP_LOGS : "logs"
|
||
|
|
ARTICLE_APPROVAL_FLOWS }o--|| APPROVAL_WORKFLOWS : "uses"
|
||
|
|
|
||
|
|
USERS ||--o{ ARTICLE_APPROVAL_FLOWS : "submits"
|
||
|
|
USERS ||--o{ ARTICLE_APPROVAL_STEP_LOGS : "approves"
|
||
|
|
|
||
|
|
USER_LEVELS ||--o{ APPROVAL_WORKFLOW_STEPS : "requires"
|
||
|
|
USER_LEVELS ||--o{ USERS : "defines"
|
||
|
|
```
|
||
|
|
|
||
|
|
## 🔧 **Technical Implementation Details**
|
||
|
|
|
||
|
|
### **1. Dynamic Workflow Assignment**
|
||
|
|
|
||
|
|
```go
|
||
|
|
// Ketika artikel dibuat
|
||
|
|
if userLevel.RequiresApproval {
|
||
|
|
// 1. Cari workflow default untuk client
|
||
|
|
workflow := getDefaultWorkflow(clientId)
|
||
|
|
|
||
|
|
// 2. Buat approval flow instance
|
||
|
|
approvalFlow := ArticleApprovalFlows{
|
||
|
|
ArticleId: articleId,
|
||
|
|
WorkflowId: workflow.ID,
|
||
|
|
CurrentStep: 1,
|
||
|
|
StatusId: 1, // pending
|
||
|
|
}
|
||
|
|
|
||
|
|
// 3. Buat legacy record
|
||
|
|
legacyApproval := ArticleApprovals{
|
||
|
|
ArticleId: articleId,
|
||
|
|
ApprovalAtLevel: nextApprovalLevel,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### **2. Step Progression Logic**
|
||
|
|
|
||
|
|
```go
|
||
|
|
// Ketika step di-approve
|
||
|
|
func ApproveStep(flowId, approvedById, message) {
|
||
|
|
// 1. Log step yang di-approve
|
||
|
|
stepLog := ArticleApprovalStepLogs{
|
||
|
|
ApprovalFlowId: flowId,
|
||
|
|
StepOrder: currentStep,
|
||
|
|
ApprovedById: approvedById,
|
||
|
|
Action: "approve",
|
||
|
|
}
|
||
|
|
|
||
|
|
// 2. Cek apakah ada next step
|
||
|
|
nextStep := getNextStep(workflowId, currentStep)
|
||
|
|
|
||
|
|
if nextStep != nil {
|
||
|
|
// 3. Pindah ke step berikutnya
|
||
|
|
updateCurrentStep(flowId, nextStep.StepOrder)
|
||
|
|
} else {
|
||
|
|
// 4. Complete approval
|
||
|
|
completeApproval(flowId)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### **3. User Level Hierarchy**
|
||
|
|
|
||
|
|
```go
|
||
|
|
// Level hierarchy (level_number field)
|
||
|
|
Level 1: Highest Authority (POLDAS)
|
||
|
|
Level 2: Mid Authority (POLDAS)
|
||
|
|
Level 3: Lower Authority (POLRES)
|
||
|
|
|
||
|
|
// Approval flow
|
||
|
|
Level 3 → Level 2 → Level 1 → Approved
|
||
|
|
```
|
||
|
|
|
||
|
|
## 📈 **Data Flow Examples**
|
||
|
|
|
||
|
|
### **Example 1: Standard 3-Step Approval**
|
||
|
|
|
||
|
|
```
|
||
|
|
1. User Level 3 creates article
|
||
|
|
├── article_approval_flows: {current_step: 1, status: pending}
|
||
|
|
├── article_approvals: {approval_at_level: 2}
|
||
|
|
└── articles: {current_approval_step: 1, status: pending}
|
||
|
|
|
||
|
|
2. User Level 2 approves
|
||
|
|
├── article_approval_step_logs: {step_order: 1, action: approve}
|
||
|
|
├── article_approval_flows: {current_step: 2, status: pending}
|
||
|
|
└── articles: {current_approval_step: 2}
|
||
|
|
|
||
|
|
3. User Level 1 approves
|
||
|
|
├── article_approval_step_logs: {step_order: 2, action: approve}
|
||
|
|
├── article_approval_flows: {status: approved, completed_at: now}
|
||
|
|
└── articles: {status: approved, published: true}
|
||
|
|
```
|
||
|
|
|
||
|
|
### **Example 2: Auto-Skip Logic**
|
||
|
|
|
||
|
|
```
|
||
|
|
1. User Level 1 creates article (highest authority)
|
||
|
|
├── Check: Can skip all steps?
|
||
|
|
├── article_approval_flows: {status: approved, completed_at: now}
|
||
|
|
└── articles: {status: approved, published: true}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 🚀 **API Endpoints Flow**
|
||
|
|
|
||
|
|
### **Article Creation**
|
||
|
|
```
|
||
|
|
POST /api/articles
|
||
|
|
├── Check user level
|
||
|
|
├── Create article
|
||
|
|
├── Assign workflow (if needed)
|
||
|
|
├── Create approval flow
|
||
|
|
└── Return article data
|
||
|
|
```
|
||
|
|
|
||
|
|
### **Approval Process**
|
||
|
|
```
|
||
|
|
PUT /api/article-approval-flows/{id}/approve
|
||
|
|
├── Validate approver permissions
|
||
|
|
├── Create step log
|
||
|
|
├── Check for next step
|
||
|
|
├── Update flow status
|
||
|
|
└── Send notifications
|
||
|
|
```
|
||
|
|
|
||
|
|
### **Status Checking**
|
||
|
|
```
|
||
|
|
GET /api/articles/{id}/approval-status
|
||
|
|
├── Get current flow
|
||
|
|
├── Get step logs
|
||
|
|
├── Get next step info
|
||
|
|
└── Return status data
|
||
|
|
```
|
||
|
|
|
||
|
|
## 🔍 **Debugging & Monitoring**
|
||
|
|
|
||
|
|
### **Key Queries for Monitoring**
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- Active approval flows
|
||
|
|
SELECT aaf.*, a.title, ul.name as current_approver_level
|
||
|
|
FROM article_approval_flows aaf
|
||
|
|
JOIN articles a ON aaf.article_id = a.id
|
||
|
|
JOIN approval_workflow_steps aws ON aaf.workflow_id = aws.workflow_id
|
||
|
|
AND aaf.current_step = aws.step_order
|
||
|
|
JOIN user_levels ul ON aws.required_user_level_id = ul.id
|
||
|
|
WHERE aaf.status_id = 1;
|
||
|
|
|
||
|
|
-- Approval history
|
||
|
|
SELECT aasl.*, u.name as approver_name, ul.name as level_name
|
||
|
|
FROM article_approval_step_logs aasl
|
||
|
|
JOIN users u ON aasl.approved_by_id = u.id
|
||
|
|
JOIN user_levels ul ON aasl.user_level_id = ul.id
|
||
|
|
WHERE aasl.approval_flow_id = ?;
|
||
|
|
```
|
||
|
|
|
||
|
|
## ⚠️ **Common Issues & Solutions**
|
||
|
|
|
||
|
|
### **Issue 1: Step Not Progressing**
|
||
|
|
- **Cause**: `getUserLevelId` returning wrong level
|
||
|
|
- **Solution**: Fix user level mapping logic
|
||
|
|
|
||
|
|
### **Issue 2: Wrong Approval Level**
|
||
|
|
- **Cause**: `findNextApprovalLevel` logic incorrect
|
||
|
|
- **Solution**: Fix level hierarchy comparison
|
||
|
|
|
||
|
|
### **Issue 3: Missing Step Logs**
|
||
|
|
- **Cause**: Step log not created during approval
|
||
|
|
- **Solution**: Ensure step log creation in `ApproveStep`
|
||
|
|
|
||
|
|
## 📝 **Best Practices**
|
||
|
|
|
||
|
|
1. **Always create step logs** for audit trail
|
||
|
|
2. **Validate user permissions** before approval
|
||
|
|
3. **Use transactions** for multi-table updates
|
||
|
|
4. **Implement proper error handling** for edge cases
|
||
|
|
5. **Log all approval actions** for debugging
|
||
|
|
6. **Test with different user level combinations**
|
||
|
|
|
||
|
|
## 🎯 **Summary**
|
||
|
|
|
||
|
|
Sistem approval workflow MEDOLS menggunakan arsitektur modular yang memisahkan:
|
||
|
|
- **Configuration** (workflows, steps, settings)
|
||
|
|
- **Execution** (flows, logs)
|
||
|
|
- **Legacy Support** (article_approvals)
|
||
|
|
|
||
|
|
Setiap module memiliki tanggung jawab spesifik, dan mereka bekerja sama untuk menciptakan sistem approval yang fleksibel dan dapat di-audit.
|