ProcessInstance, ProcessWorkItem, auto field updates, and the day I learned why escalation rules save careers.
π’ Once upon a time in a mid-sized companyβ¦
We had a purchase request system.
It looked fine on the surface β users could submit requests, data was stored, reports existed.
But there was one massive problem:
There was no approval system.
And that created chaos.
- Finance didnβt trust the numbers
- Department heads didnβt know what they were approving
- Requests were being edited after submission
- The CFO saw critical approvals 2 weeks late
Thatβs when I got the task:
βBuild a structured L1 β L2 β L3 approval process.
With record locking, automated emails, escalation rules, and audit-ready tracking.β
This wasnβt just a feature.
It was a system that would define how decisions move inside the company.
Hereβs exactly how I built it β step by step.
π 1. Record Locking & Unlocking (Data Integrity First)
β Problem
Users were editing records even after submitting them for approval.
That meant:
- Approvers were reviewing moving targets
- Decisions became invalid
- Audit trails were unreliable
β Solution
I implemented state-based record locking.
- When a record is submitted β it becomes read-only
- If rejected β it becomes editable again
- If fully approved β it is permanently locked
π§ Logic
if(status == "Submitted" OR "L1 Approved" OR "L2 Approved")
isLocked = true
else
isLocked = false
π‘ Insight
Locking isnβt just a feature β itβs what makes approvals trustworthy.
π₯ 2. Designing L1, L2, L3 Approval Levels
I mapped the approval hierarchy to real business roles:
| Level | Role | Responsibility |
|---|---|---|
| L1 | Department Head | Validate request legitimacy |
| L2 | COO | Operational approval |
| L3 | CFO | Financial approval |
Rules I enforced:
-
Each approver can:
- β Approve
- β Reject
- π¬ Add comments
β No one can modify previous decisions
π Rejection at any level sends the request back to the requester
π‘ Insight
Approval systems are not technical flows β they are organizational trust layers.
π§ 3. Automated Email Notifications (Communication Layer)
Approvals fail without visibility.
So I built a trigger-based email system tied to each stage.
π Email Triggers
- On submission β notify L1
- On L1 approval β notify L2 + requester
- On L2 approval β notify L3
- On final approval β notify requester + finance
- On rejection β notify requester with reason + unlock info
π¨ Example Email (L1 β L2)
Subject: L1 Approved β Pending COO Review
Hi [COO Name],
Request #[Record ID] has been approved by the Department Head.
Please review and take action before [Due Date].
Thanks,
System Automation
π‘ Insight
Emails are not notifications.
They are decision triggers.
π 4. Automated Field Updates (State Management)
To keep everything trackable, I designed a clear status lifecycle.
π Status Flow
Draft β Submitted β L1 Approved β L2 Approved β Final Approved
β β β
Rejected Rejected Rejected
β β β
Unlock Unlock Unlock
π§© Fields I maintained
StatusLast_Approved_ByLast_Approved_DateNext_Approver_NameIs_Locked
Each approval step automatically updated these fields using Flows / Apex logic.
π‘ Insight
If your status field is messy, your entire system becomes untraceable.
β° 5. Escalation Rules (The Real Game-Changer)
This is where the system went from βgoodβ to βproduction-readyβ.
π¨ Problem
Approvers delay.
Always.
β Solution: Time-based escalation
Rule 1:
- If L1 pending > 48 hours β Reassign to L2 β Send escalation email
Rule 2:
- If L2 pending > 24 hours β Notify CFO (view-only) β Send daily reminder to COO
π₯ Why this matters
- Prevents bottlenecks
- Removes dependency on manual follow-ups
- Keeps process moving without friction
π‘ Insight
Escalation rules donβt just improve systems β
they protect deadlines, teams, and accountability.
π§ 6. The Core Engine: ProcessInstance & ProcessWorkItem
This is the part that separates beginners from real Salesforce developers.
π¦ ProcessInstance
Represents the entire approval process for one record.
Stores:
- Overall status β
IN_PROGRESS,APPROVED,REJECTED - Start time / end time
- Current stage
π§© ProcessWorkItem
Represents each approval step.
Stores:
- Assigned approver
- Step status (Pending / Approved / Rejected)
- Due date
- Escalation status
- Comments
π Real-world query example
Find all L2 approvals that are pending and escalated
This is critical for:
- Dashboards
- Reporting
- Audits
π‘ Insight
Without these objects, your system has no memory.
And without memory, there is no audit.
π 7. Final Architecture Snapshot
User submits request
β Lock record
β Create ProcessInstance
β Create ProcessWorkItem (L1)
β Send email to L1
L1 approves
β Update status
β Create ProcessWorkItem (L2)
β Notify L2
L2 approves
β Update status
β Create ProcessWorkItem (L3)
β Notify L3
L3 approves
β Final approval
β Permanently lock record
β Close ProcessInstance
β Send final email
π§ͺ 8. What Iβd Improve Next Time
No system is perfect. Hereβs what Iβd upgrade:
- π Parallel approvals (e.g., L2 + Legal together)
- π 24-hour reminders (not just escalation)
- β‘ Store approval history as JSON for faster UI rendering
- π Build dashboards for real-time approval tracking
β Key Lessons from This Build
- π Locking is non-negotiable for data integrity
- π§ Emails without escalation = ignored notifications
- π§ ProcessInstance + ProcessWorkItem = audit backbone
- π§ͺ Always test escalations using mock overdue scenarios
π Final Thought
If youβve ever built approval systems, you already know:
L1 is fast. L2 is busy. L3 is critical.
Each level behaves differently.
Your system must respect that.
π Closing
This project wasnβt just about approvals.
It was about:
- Building trust in data
- Creating accountability
- Designing systems that work *without constant human follow-up
If you're building something similar or want to discuss architecture decisions, feel free to connect. Always happy to exchange ideas π












