# Codebase Understanding: workflow-ui & workflow-api

---

## 1. System Overview

This is a **Workflow Management System** that allows institutions to create multi-stage application workflows (e.g., admissions, scholarships, staff requests). Applicants submit forms stage-by-stage, and approvers (staff) act on them.

**Stack:**
- **Frontend:** Vue.js SPA (Vue 2), Vuex, Vue Router, Bootstrap 4, SCSS
- **Backend:** PHP with Slim Framework, MySQL (Phinx migrations), Twig templates for server-side export
- **Architecture:** RESTful API + Single Page Application

---

## 2. workflow-api (PHP/Slim Backend)

### 2.1 Directory Structure

```
workflow-api/
├── bootstrap/
│   ├── app.php              # Slim app initialization
│   ├── routes.php           # Registers all route groups
│   ├── controllers.php      # Controller registration
│   └── middlewares.php      # JWT auth, CORS, etc.
├── db/
│   └── migrations/          # Phinx migration files
├── src/com/linways/
│   ├── api/v1/              # HTTP layer (controllers + routes)
│   │   ├── BaseController.php
│   │   ├── workflow/        # Workflow CRUD API
│   │   ├── stage/           # Stage management API
│   │   ├── application/     # Applicant submission API
│   │   ├── report/          # Custom reports & export API
│   │   └── common/          # Shared lookups (staffs, depts, batches)
│   ├── web/
│   │   └── WorkflowBaseController.php  # User type detection, globals
│   └── core/
│       ├── dto/             # Data Transfer Objects (pure PHP classes)
│       ├── service/         # Business logic layer
│       ├── mapper/          # DB result → DTO mapping
│       ├── constant/        # StatusConstant.php
│       ├── exception/       # WorkFlowException
│       └── exports/         # Twig templates for PDF/Excel export
│           ├── table.twig
│           └── appraisalReportTemplate.twig
```

### 2.2 Database Schema (Key Tables)

```sql
wm_workflow
  id CHAR(17), name VARCHAR(100), rule JSON, type VARCHAR(100), is_active TINYINT
  -- type: STAFF or STUDENT
  -- rule: JSON blob for workflow config (icon, termsAndConditions, maxApplications, etc.)

wm_stages
  id CHAR(17), wm_workflow_id CHAR(17), name VARCHAR(100),
  rule JSON, form_schema JSON, simple_schema JSON, order INT
  -- form_schema: full Form.io-style schema
  -- simple_schema: simplified version for display/print

wm_workflow_requests
  id CHAR(17), wm_workflow_id CHAR(17),
  staff_id INT NULL, student_id INT NULL,
  status VARCHAR(45), application_number VARCHAR(100),
  current_stage_order INT, wm_user_stage_id CHAR(17)
  -- One row per applicant per workflow

wm_user_stages
  id CHAR(17), wm_workflow_request_id CHAR(17), wm_stage_id CHAR(17),
  form_data JSON, status VARCHAR(100), approval_history JSON
  -- One row per stage per application

wm_user_stage_payments
  id CHAR(17), wm_user_stage_id CHAR(17),
  amount INT, linways_txn_id VARCHAR(100), status VARCHAR(100)

wm_custom_reports
  id CHAR(17), name VARCHAR(100),
  fragments JSON, compiled_fragments JSON,
  extra_details JSON,     -- stores: { "templateName": "table" | "appraisalReportTemplate" }
  filters JSON, wm_workflow_id CHAR(17)
  -- Admin-defined SQL reports, rendered via Twig templates

wm_custom_report_staff_permissions
  id INT, wm_custom_report_id CHAR(17), staff_id INT
```

**Entity Relationships:**
```
wm_workflow (1)
  ├── (Many) wm_stages
  ├── (Many) wm_workflow_requests
  │             └── (Many) wm_user_stages
  │                           └── (Many) wm_user_stage_payments
  └── (Many) wm_custom_reports
                └── (Many) wm_custom_report_staff_permissions
```

### 2.3 Key DTOs

| DTO | Key Fields |
|-----|-----------|
| `WorkFlow` | `id, name, rule (JSON→object), description, type, userRule` |
| `WorkFlowStage` | `id, workFlowId, name, rule, formSchema, simpleSchema, order, userStages[], smsMailBody` |
| `WorkFlowRule` | `code, label, fieldName, callFunction, baseTableName, operators, options` |
| `WorkFlowUserStage` | `id, workFlowRequestId, stageId, formData, status, approvalHistory` |
| `WorkFlowUserRequest` | `id, workFlowId, staffId, studentId, status, applicationNumber` |
| `CustomReport` | `id, name, fragments, compiledFragments, extraDetails, templateName, workFlowId` |

### 2.4 Service Layer

| Service | Responsibility |
|---------|---------------|
| `WorkflowService` | Workflow CRUD, rule updates, export/import |
| `WorkflowStageService` | Stage CRUD, ordering, approval rules |
| `WorkflowUserRequestService` | Applicant requests — create, fetch, stage progression |
| `WorkflowRuleEngineService` | Evaluates dynamic business rules on submissions |
| `CustomReportService` | Builds SQL, renders Twig templates, generates PDF/Excel via wkhtmltopdf |

> All services use `MakeSingletonTrait` — accessed as `ServiceName::getInstance()->method()`

### 2.5 API Routes Summary

```
GET/POST/PUT   /wm/api/v1/workflow              Workflow CRUD
PATCH          /wm/api/v1/workflow/{id}/{flag}  Publish/unpublish
GET            /wm/api/v1/workflow/{id}/export  Export workflow definition

GET/POST/PUT   /wm/api/v1/stage/{workFlowId}    Stage CRUD
PUT            /wm/api/v1/stage/order            Reorder stages

GET            /wm/api/v1/application/{workFlowId}                List applicant's requests
POST           /wm/api/v1/application/{workFlowId}/new            Create new application
GET            /wm/api/v1/application/{workFlowId}/{id}/stages    Get all stages for application
POST           /wm/api/v1/application/.../stage/{id}              Submit a stage form
GET            /wm/api/v1/application/{id}/stage/first            Fetch first stage (used for print)

GET/POST/PUT   /wm/api/v1/report                Custom report CRUD
GET            /wm/api/v1/report/{id}           Execute report (PDF/Excel export)
```

### 2.6 Permission System

Controllers declare `public $permissions_methodName = ['PERMISSION_CODE'];`
The base controller validates permissions before calling the method.
User context is stored in PHP globals: `$GLOBALS['userId']`, `$GLOBALS['userType']`, `$GLOBALS['deptID']`.
User types: `STAFF`, `STUDENT`, `ADMISSION_ADMIN`, `ADMISSION_APPLICANT`.

### 2.7 Export / Print (Server-Side)

`CustomReportService::searchReportData()` handles server-side export:
1. Compiles SQL from `compiledFragments` with dynamic filters
2. Executes query, fetches rows
3. Renders HTML via Twig (`table.twig` or `appraisalReportTemplate.twig`)
4. Converts to PDF using `wkhtmltopdf` (binary at `/usr/local/bin/wkhtmltopdf`)
5. Or converts to Excel via `LinwaysExcel::generateExcelFromHtmlString()`
6. Uploads file to S3, returns resource ID

> This is the **admin report export**. The **applicant print** is separate — it is entirely client-side (see workflow-ui below).

---

## 3. workflow-ui (Vue.js Frontend)

### 3.1 Directory Structure

```
workflow-ui/
├── src/
│   ├── App.vue                  # Root: dynamic layout + dynamic page component
│   ├── main.js                  # Vue init, global component registration
│   ├── router/index.js          # Vue Router (routes built from Vuex menuStore)
│   ├── store/
│   │   ├── index.js             # Vuex root store
│   │   ├── authStore.js         # Login state, JWT token, userType
│   │   ├── menuStore.js         # Menu items fetched from API → dynamic routes
│   │   ├── QueryParamsStore.js  # Global query params (batch_id, semester_id…)
│   │   ├── ThemConfigurations.js
│   │   └── uiStore.js
│   ├── layouts/
│   │   ├── DefaultLayout.vue
│   │   ├── PlainLayout.vue
│   │   ├── SimpleLayout.vue
│   │   └── MobileAppWebViewLayout.vue
│   └── assets/scss/
│       ├── modules/print.scss   # @media print — hides nav/sidebar
│       └── themes/              # modern, abstract, retro, corporate, light…
│
└── packages/
    ├── admin/src/               # Admin configuration UI
    │   ├── components/
    │   │   ├── createWorkflow/  # Workflow builder
    │   │   ├── stages/          # Stage management
    │   │   ├── manageApplication/  # Admin reviewing applications
    │   │   ├── assignFaculty/   # Assign approvers
    │   │   ├── permission_management/
    │   │   └── report/          # Custom report builder
    │   ├── pages/               # Full-page views
    │   ├── helpers/AdminWorkflowEndPoints.js   # All admin API URLs
    │   └── store/vueWorkflowConfigureStore.js  # Admin Vuex module
    │
    └── applicant/src/           # Applicant-facing UI
        ├── components/
        │   ├── workflow.vue           # Workflow card list
        │   ├── workFlowRequest.vue    # Application row + Print button trigger
        │   ├── stageReport.vue        # THE PRINT TEMPLATE (current, fixed)
        │   ├── onlinePaymentRequest.vue
        │   └── otherModuleData.vue
        ├── pages/
        │   ├── applications.vue       # Landing page listing all workflows
        │   ├── viewWorkflowRequest.vue  # Lists applicant's requests; hosts print SliderModal
        │   ├── stage.vue              # Form-fill stage view
        │   └── PaymentRequest.vue
        ├── helpers/WorkflowApplicantUrls.js  # All applicant API URLs
        └── store/WorkflowApplicantStore.js   # Applicant Vuex module
```

### 3.2 Dynamic Component System (App.vue)

`App.vue` uses Vue's `:is` binding for both layout and page content:

```vue
<component :is="layout">               <!-- DefaultLayout, PlainLayout, etc. -->
  <template slot="container">
    <component :is="dynamicComponent" v-bind="properties"/>   <!-- Page component -->
  </template>
</component>
```

Page components are lazy-imported (code-splitting) and registered dynamically at runtime based on the menu API response. Routes are added via `this.$router.addRoute()` after login.

### 3.3 Vuex Store Modules

| Module | State | Key Actions |
|--------|-------|-------------|
| `authStore` | `accessToken, userId, userType, userRoles` | `setAccessToken, refreshToken` |
| `menuStore` | `routes[]` | `getMenuList()` → fetches `/common/api/v1/user/get-user-menu-items` |
| `WorkflowConfigureStore` | `stages[], workflows[], staffs[], rules[], reports[]` | Admin CRUD mutations |
| `WorkflowApplicantStore` | `workflows[], workFlowRequests[], stages[], workFlowRequest` | Applicant data mutations |

### 3.4 Print Feature (Client-Side — Applicant)

**Flow:**

```
workFlowRequest.vue (Print button)
  → @click viewFirstStage()
  → this.$emit('print-application', this.workFlowRequest.id)

viewWorkflowRequest.vue (parent)
  → @print-application="showApplication(id)"
  → GET /wm/api/v1/application/{id}/stage/first
  → this.stage = responseBody.data
  → SliderModal opens with <StageReport :stage="stage" :workFlowRequest="workFlowRequest">

User clicks Print in modal footer
  → printStageReport()
  → const html = $("#stage-report").html()   ← reads stageReport.vue root element
  → window.open() → writes CSS links + html → document.close()
  → setTimeout(2000) → WinPrint.print() → WinPrint.close()
```

**`stageReport.vue` — What It Renders:**

| Section | Data Source |
|---------|------------|
| Organization logo | `workFlowRequest.logo` |
| Stage name | `stage.name` |
| Application Number | `workFlowRequest.applicationNumber` |
| Academic term | `workFlowRequest.academicTermName` |
| Form fields | `stage.simpleSchema.components[]` → values from `stage.userStages[0].formData` |
| File fields | Linked by `component.type == 'fw-file'` |
| Submission date | `stage.userStages[0].updatedDate` |
| Other module data | Fetched via `stage.rule.otherStageDetails[].url` |
| Payment info | GET `/wm/api/v1/application/payment/status/all` |
| Application status | `workFlowRequest.status` |
| Footer | "This is a system generated receipt" |

**CSS used for print window:**
- `/wm/static/css/bootstrap_print.css`
- `/wm/static/css/printStyle.css`

### 3.5 API URL Registries

**Applicant:** `WorkflowApplicantUrls.js`
```
GET_WORKFLOWS:           /wm/api/v1/workflow
GET_WORKFLOW_USER_REQUESTS: /wm/api/v1/application/{workFlowId}
GET_APPLICANT_WORKFLOW_STAGE: /wm/api/v1/application/{workFlowId}/{workFlowRequestId}/stages
GET_FIRST_STAGE:         /wm/api/v1/application/{workFlowRequestId}/stage/first
GET_ALL_PAYMENT_STATUS:  /wm/api/v1/application/payment/status/all
```

**Admin:** `AdminWorkflowEndPoints.js`
```
GET_WORKFLOWS:           /wm/api/v1/workflow
GET_WORKFLOW_BY_ID:      /wm/api/v1/workflow/{id}
SAVE_WORKFLOW:           /wm/api/v1/workflow
UPDATE_WORKFLOW:         /wm/api/v1/workflow/{id}
PUBLISH_WORKFLOW:        /wm/api/v1/workflow/{id}/{isActive}
GET_REPORTS:             /wm/api/v1/report
```

### 3.6 Workflow Configuration (Admin)

Admin creates a workflow in `createWorkflowSlider.vue`. The `rule` object constructed at save time:

```js
rule: {
  maxNoOfApplications: ...,
  icon: ...,
  includeSemester: true/false,
  oneApplicationOnly: true/false,
  termsAndConditions: "...",
  redirectTo: { ... },
  copyDataToAcademics: true/false,
  recalculateFee: true/false,
  otherStageDetails: [],
  otherModuleData: []
}
```

This `rule` object is serialized as JSON and stored in `wm_workflow.rule`. It is the primary extension point for workflow-level configuration without DB migrations.

---

## 4. Key Patterns & Conventions

| Pattern | Description |
|---------|------------|
| **Singleton services (PHP)** | All services use `MakeSingletonTrait`, accessed via `Service::getInstance()` |
| **Mapper-DTO pattern** | `WorkFlowServiceMapper` maps DB result rows to typed DTO objects |
| **Dynamic `:is` components (Vue)** | Both App.vue (layouts/pages) and admin UI use `:is` for runtime component selection |
| **JSON rule columns** | `wm_workflow.rule`, `wm_stages.rule`, `wm_custom_reports.extra_details` are all JSON — extension points requiring no DB migrations |
| **Event emitter pattern** | Child components emit events, parents handle them (e.g., `print-application` event) |
| **Lazy imports** | Page-level Vue components use `() => import(...)` for code splitting |
| **API-first routing** | Menu items and routes are fetched from the backend API after login |
| **Permission annotations** | PHP controllers declare `public $permissions_methodName = [...]` arrays |
| **Element ID coupling** | `printStageReport()` uses `#stage-report` ID to extract print HTML — this is intentional and load-bearing |
| **wkhtmltopdf for server-side PDF** | Only used for custom admin reports, not for applicant print |

---

## 5. Applicant vs Admin UI Separation

| Concern | Admin (`packages/admin/`) | Applicant (`packages/applicant/`) |
|---------|--------------------------|----------------------------------|
| Workflow creation | `createWorkflow/` components | — |
| Stage form builder | `stages/`, `editStageForm.vue` | — |
| Reviewing applications | `manageApplication/` | — |
| Submitting applications | — | `stage.vue` |
| Viewing own applications | — | `viewWorkflowRequest.vue` |
| Printing application | — | `stageReport.vue` + `viewWorkflowRequest.vue` |
| Custom reports | `report/`, `createReport.vue` | — |
| Vuex module | `vueWorkflowConfigureStore.js` | `WorkflowApplicantStore.js` |

---

## 6. Existing Extension Points Relevant to Print Templates

1. **`wm_workflow.rule` (JSON)** — Already used for config flags. Adding `printTemplate: "certificate"` requires zero DB changes.
2. **`wm_custom_reports.extra_details.templateName`** — Precedent for template-name-based dispatch in the reporting system.
3. **Twig templates in `/core/exports/`** — Pattern already exists for server-side template switching.
4. **Vue `:is` dynamic component** — Already used in `App.vue`; the same pattern can be applied to the print component.
5. **`stageReport.vue` props** — `stage` and `workFlowRequest` are a clean interface; all future templates can use the same props.
