A full-stack, enterprise-grade Approval & Workflow Engine that replaces rigid, hard-coded approval chains with dynamic, admin-configurable multi-step workflows β think mini ServiceNow or Jira Approval Engine, built from scratch.
workflow-system/
βββ backend/ # Spring Boot Application
β βββ src/
β β βββ main/
β β βββ java/com/workflow/
β β β βββ config/ # DataSeeder (seeds default users on startup)
β β β βββ controller/ # AuthController, WorkflowController, WorkflowRequestController
β β β βββ dto/ # Request/Response DTOs
β β β βββ exception/ # GlobalExceptionHandler, ResourceNotFoundException
β β β βββ mapper/ # MapStruct mappers (WorkflowMapper, WorkflowRequestMapper)
β β β βββ model/ # JPA Entities (User, Workflow, WorkflowStep, WorkflowRequest, RequestApproval)
β β β βββ repository/ # Spring Data JPA repositories
β β β βββ security/ # JWT filter, SecurityConfig, UserDetailsServiceImpl
β β β βββ service/ # WorkflowService, WorkflowRequestService
β β βββ resources/
β β βββ application.properties
β βββ pom.xml
β
βββ frontend/ # React + Vite Application
βββ src/
β βββ components/ # Navbar
β βββ context/ # AuthContext (JWT state management)
β βββ pages/ # Login, Signup, Dashboard, WorkflowAdmin,
β β # SubmitRequest, RequestDetails
β βββ services/ # Axios instance (pre-configured with JWT interceptors)
β βββ types/ # TypeScript interfaces
β βββ App.tsx # Router with protected routes
βββ package.json
flowchart TD
User(["π€ User\n(Employee / Manager / Admin)"])
subgraph FRONTEND ["π₯οΈ React Frontend :5173"]
LOGIN["Login / Signup"]
DASH["Dashboard\n(My Requests + Pending Approvals)"]
SUBMIT["Submit Request\n(choose workflow, fill details)"]
DETAIL["Request Detail\n(timeline + approve/reject)"]
ADMIN["Workflow Admin\n(create / edit workflows)"]
end
subgraph BACKEND ["βοΈ Spring Boot API :8080"]
AUTH["AuthController\n/api/auth/signin | /signup"]
WFCTRL["WorkflowController\n/api/workflows (ADMIN only)"]
RQCTRL["WorkflowRequestController\n/api/requests"]
WFS["WorkflowService"]
RQSVC["WorkflowRequestService\n(drives approval sequencing)"]
SEC["JWT Filter + SecurityConfig"]
end
subgraph DB ["ποΈ PostgreSQL :5432"]
USERS["users"]
WFLOW["workflows + workflow_steps"]
REQS["workflow_requests"]
APPROV["request_approvals"]
end
User -->|Browser| LOGIN
LOGIN -->|POST /api/auth/signin| AUTH
AUTH -->|JWT token| FRONTEND
DASH -->|GET /api/requests/my| RQCTRL
SUBMIT -->|POST /api/requests| RQCTRL
DETAIL -->|GET /api/requests/:id| RQCTRL
DETAIL -->|POST /api/requests/:id/approve| RQSVC
ADMIN -->|POST /api/workflows| WFCTRL
RQCTRL --> SEC
WFCTRL --> SEC
SEC --> WFS
SEC --> RQSVC
WFS --> WFLOW
RQSVC --> REQS
RQSVC --> APPROV
AUTH --> USERS
| Step | Component | Action | Result |
|---|---|---|---|
| 1 | AuthController |
User signs in with email + password | JWT issued with role claim (EMPLOYEE, MANAGER, ADMIN) |
| 2 | JWT Filter |
Every subsequent request validates the Bearer token | Unauthorized β 401 |
| 3 | WorkflowController |
Admin creates a workflow with N ordered steps (each assigned to a role or user) | Workflow persisted in PostgreSQL |
| 4 | WorkflowRequestController |
Employee selects a workflow and submits a request with a description | WorkflowRequest created with status PENDING |
| 5 | WorkflowRequestService |
Service identifies the current active step (lowest order step not yet decided) | Surfaces the correct approver |
| 6 | Approver (Manager/Admin) | Approver navigates to Request Detail and clicks Approve or Reject with a comment | RequestApproval record written |
| 7 | WorkflowRequestService |
All steps approved β request moves to APPROVED; any rejection β REJECTED |
Final status persisted |
| 8 | Dashboard |
All users see live status of their requests; Admins/Managers see all pending requests | React polls on mount |
Once both services are running, open http://localhost:5173
| Role | Password | |
|---|---|---|
ADMIN |
admin@workflow.com |
admin123 |
MANAGER |
manager@workflow.com |
manager123 |
- Log in as
admin@workflow.com - Navigate to Workflow Admin β Create New Workflow
- Add a name (e.g. "Leave Approval") and define steps in order:
- Step 1 β
MANAGERrole - Step 2 β
ADMINrole
- Step 1 β
- Save β the workflow is immediately available for submissions.
1. Sign up as a new user (default role: EMPLOYEE)
2. Click "Create Request" on the Dashboard
3. Select "Leave Approval" workflow
4. Fill in the description and submit
What you'll see: Request appears in your Dashboard with status PENDING.
1. Log in as manager@workflow.com β Request appears in "All Organizational Requests"
2. Open the request β Click "Approve" on Step 1
3. Log in as admin@workflow.com β Open the request β Approve Step 2
4. Status changes to APPROVED β visible to all parties instantly
| Component | Tech | Role |
|---|---|---|
| AuthController | Spring Security + JJWT 0.12.5 | Handles sign-in and sign-up; issues signed JWT tokens with role claims |
| WorkflowController | Spring MVC REST | CRUD for Workflows and their ordered steps (Admin-only) |
| WorkflowRequestController | Spring MVC REST | Submit requests, retrieve request lists, trigger approval actions |
| WorkflowRequestService | Spring Service + JPA | Core business logic β drives sequential approval, computes active step, finalises status |
| PostgreSQL | Relational DB | Persists all entities with JPA-managed schema via spring.jpa.hibernate.ddl-auto=update |
| MapStruct | Code-gen mapper | Converts JPA entities β DTOs at compile time with zero runtime reflection overhead |
| React + Vite | Frontend framework | SPA with protected routes, JWT storage, and real-time status reflection |
| AuthContext | React Context API | Global auth state β stores JWT and user role, auto-attaches token to every Axios request |
Workflow: "IT Hardware Request"
βββ Step 1 (order=1) β assigned to MANAGER role
βββ Step 2 (order=2) β assigned to ADMIN role
βββ Step 3 (order=3) β assigned to ADMIN role
Request submitted by Employee:
β Service finds MIN(order) where status == PENDING β Step 1 activated
β Manager approves Step 1 β Step 2 activated
β Admin approves Step 2 β Step 3 activated
β Admin approves Step 3 β Request = APPROVED
β ANY step REJECTED β Request = REJECTED immediately
| Action | EMPLOYEE |
MANAGER |
ADMIN |
|---|---|---|---|
| Submit a request | β | β | β |
| View own requests | β | β | β |
| View all requests | β | β | β |
| Approve / Reject steps | β | β | β |
| Create / Edit Workflows | β | β | β |
An employee requests a new laptop. The request flows through a Manager for budget sign-off, then an IT Admin for provisioning approval β all tracked with timestamped comments.
HR configures a "Leave Request" workflow with the employee's direct manager as Step 1 and HR Admin as Step 2. The entire chain is auditable, with every decision and comment permanently stored.
A company uses AuraFlow to enforce a multi-department review (Finance β Legal β CTO) before a new SaaS tool is approved for use. The workflow is created once in the Admin panel and reused for every new vendor request.
- Java 17+
- Maven 3.8+ (or use the included Maven Wrapper
./mvnw) - Node.js 18+
- PostgreSQL running locally on port 5432
CREATE DATABASE workflow_db;Default connection:
host=localhost,user=postgres,password=postgresChange these inbackend/src/main/resources/application.propertiesif needed.
cd backend
./mvnw clean spring-boot:runOr on Windows:
cd backend
.\mvnw.cmd clean spring-boot:runOn first boot,
DataSeederautomatically creates theadmin@workflow.comandmanager@workflow.comaccounts.
cd frontend
npm install
npm run dev| Service | URL |
|---|---|
| React Frontend | http://localhost:5173 |
| Spring Boot API | http://localhost:8080 |
| Swagger UI | http://localhost:8080/swagger-ui/index.html |
| Skill | Demonstrated By |
|---|---|
| Domain-Driven Design | Clean separation of model, dto, service, repository, and controller layers |
| Type-Safe Mapping | MapStruct generates DTO mappers at compile time β zero boilerplate, zero runtime risk |
| Stateless Auth | JWT-based authentication β no sessions, fully scalable horizontally |
| Dynamic Business Logic | Workflows are runtime-configurable; no code change needed to add or reorder approval steps |
| Reactive UI | React with Context API and Axios interceptors β auth state flows transparently through the entire app |
| RBAC | Spring Security method-level and URL-level role guards enforce least-privilege access |