**Prepared by:** Oditha

**Date:** 23 January 2026

**Version:** 1.0

**Reference:** [FRD - HoReCa Field Operations & Workflow Management](https://www.notion.so/FRD-HoReCa-Field-Operations-Workflow-Management-2f7cd2773bc548c9a2595d856f15ac15?pvs=21)

---

## Overview

This document defines all business rules, logic, calculations, and decision-making criteria for the Lion HoReCa Excellence system.

---

## 1. User Management & Hierarchy

### BR-UM-001: User Role Hierarchy

**Rule:** Users follow a strict hierarchical reporting structure

**Hierarchy Chain:**

```
LSR → TM → SM → Regional Manager → Admin
```

**Logic:**

-   Each user (except Admin) must have a `reports_to_id` pointing to their immediate supervisor
-   LSR reports to TM
-   TM reports to SM
-   SM reports to Regional Manager
-   Regional Manager can report to Admin or another Regional Manager

**Validation:**

-   System validates hierarchy chain on user creation/update
-   Circular references are not allowed
-   A user cannot report to someone with a lower role level

---

### BR-UM-002: Data Visibility by Role

**Rule:** Users can only view data within their hierarchy

**Visibility Matrix:**

| Role             | Can View                                             |
| ---------------- | ---------------------------------------------------- |
| LSR              | Own data only                                        |
| TM               | Own data + all assigned LSRs' data                   |
| SM               | Own data + all assigned TMs' data + their LSRs' data |
| Regional Manager | All data in assigned region                          |
| Admin            | All data in system                                   |

**Logic:**

-   Database queries automatically filter by hierarchy
-   Apply WHERE clause: `user_id IN (hierarchy_chain)`
-   Outlet visibility: User can see outlet if they are assigned as LSR, TM, or SM

---

### BR-UM-003: User Assignment to Outlets

**Rule:** Outlet assignments must follow hierarchy

**Logic:**

-   When LSR is assigned to outlet:
    -   Auto-populate `assigned_tm_id` from LSR's `reports_to_id`
    -   Auto-populate `assigned_sm_id` from TM's `reports_to_id`
-   When assignment changes:
    -   Update all dependent assignments
    -   Reassign pending tasks to new user

**Validation:**

-   LSR assignment is mandatory
-   TM and SM assignments can be manually overridden by Admin
-   All assigned users must be active

---

## 2. Workflow Management

### BR-WF-001: Workflow Step Ordering

**Rule:** Workflow steps must be executed in sequential order

**Logic:**

-   Steps have `step_order` field (integer, starting from 1)
-   User cannot skip to step N+2 without completing step N+1
-   Exception: Steps with conditional logic that evaluates to false are auto-skipped

**Validation:**

-   On step response submission, check if previous step (step_order - 1) is completed
-   If not completed and not skipped by condition: Return error "INVALID_STEP_ORDER"

---

### BR-WF-002: Mandatory Step Enforcement

**Rule:** Mandatory steps cannot be completed without valid response

**Logic:**

-   If `is_mandatory = true` and `allow_skip = false`:
    -   Response value or response text is required
    -   If `require_photo = true`, at least 1 photo is required
-   If `is_mandatory = true` and `allow_skip = true`:
    -   Either response OR skip reason is required

**Validation:**

-   On workflow completion, check all mandatory steps:
    -   Status = completed OR status = skipped with reason
-   If any mandatory step incomplete: Block workflow completion

---

### BR-WF-003: Conditional Step Visibility

**Rule:** Steps with conditions are only visible when conditions are met

**Logic:**

-   Evaluate conditions on previous step response
-   If condition_operator = "equals":
    -   Show step if `previous_response = condition_value`
-   If condition_operator = "not_equals":
    -   Show step if `previous_response ≠ condition_value`
-   If condition_operator = "contains":
    -   Show step if `previous_response LIKE '%condition_value%'`
-   If multiple conditions with logic_operator = "AND":
    -   All conditions must be true
-   If multiple conditions with logic_operator = "OR":
    -   At least one condition must be true

**Calculation:**

-   On each step response submission:
    -   Re-evaluate all conditions for remaining steps
    -   Update `is_visible` flag for each step
    -   Recalculate progress percentage based on visible steps only

---

### BR-WF-004: Service Request Auto-Trigger

**Rule:** Service requests are automatically created when trigger conditions are met

**Logic:**

-   When workflow step response is submitted:
    -   Check if response matches any `workflow_step_options` with `triggers_service_request = true`
    -   If match found:
        -   Get `service_request_category_id` and `service_request_template_id`
        -   Apply template placeholders:
            -   {outlet_name} → [outlet.name](http://outlet.name)
            -   {workflow_name} → [workflow.name](http://workflow.name)
            -   {step_name} → [step.name](http://step.name)
            -   {response} → response_value
            -   {user_name} → [user.name](http://user.name)
            -   {date_time} → current timestamp
        -   Create service request with:
            -   title = template name
            -   description = processed template text
            -   category_id = from option
            -   outlet_id = current outlet
            -   workflow_id = current workflow
            -   step_id = current step
            -   created_by = current user
            -   assigned_to = determined by category assignment rules
            -   priority = from category
            -   sla_due_date = current timestamp + category.sla_hours
            -   status = "open"
        -   Send notification to assigned user

**Validation:**

-   Template must exist and be active
-   Category must exist and be active
-   Assignment user must exist and be active

---

### BR-WF-005: Workflow Template Assignment

**Rule:** Each outlet must have exactly one workflow group template assigned

**Logic:**

-   On outlet creation: `workflow_group_template_id` is required
-   Template provides default workflow list
-   Individual workflows can be enabled/disabled per outlet via `outlet_workflow_customizations`

**Calculation:**

-   Effective workflows for outlet:
    ```
    enabled_workflows = template.workflows WHERE outlet_customizations.is_enabled = true OR no customization exists
    ```

**Validation:**

-   Template must be active
-   Cannot remove template if outlet has workflow execution history
-   Can change template (migrates to new template's workflows)

---

## 3. Outlet Management

### BR-OM-001: Geofence Validation

**Rule:** Check-in location must be validated against outlet coordinates

**Calculation:**

-   Calculate distance using Haversine formula:
    ```
    a = sin²(Δlat/2) + cos(lat1) × cos(lat2) × sin²(Δlon/2)
    c = 2 × atan2(√a, √(1−a))
    distance = R × c (where R = Earth radius = 6371 km)
    ```

**Logic:**

-   If distance ≤ 100m (configurable threshold):
    -   `within_geofence = true`
    -   Allow check-in without additional validation
-   If distance > 100m:
    -   `within_geofence = false`
    -   Require `remote_checkin_reason` (mandatory field)
    -   Log geofence compliance issue for Red Flags dashboard

**Validation:**

-   Latitude must be between -90 and 90
-   Longitude must be between -180 and 180
-   Outlet coordinates must be valid

---

### BR-OM-002: Visit Time Calculation

**Rule:** Visit duration is calculated from check-in to check-out

**Calculation:**

```
time_spent_minutes = TIMESTAMPDIFF(MINUTE, check_in_time, check_out_time)
```

**Logic:**

-   Auto-calculate on check-out
-   If user forgets to check out:
    -   System prompts on next app launch
    -   Admin can manually close visit with estimated check-out time

**Validation:**

-   Check-out time must be after check-in time
-   Maximum visit duration: 12 hours (warning if exceeded)
-   Cannot check in to multiple outlets simultaneously

---

### BR-OM-003: Brand Availability Tracking

**Rule:** Track brand presence at outlets during workflow execution

**Logic:**

-   Brands are configured per outlet:
    -   `is_must_have = true`: Required brands (triggers alert if unavailable)
    -   `is_must_have = false`: Optional brands (tracked for reporting only)
-   During workflow execution:
    -   User responds yes/no for each brand
    -   "No" response for must-have brand can trigger service request (if configured in workflow)

**Calculation:**

-   Brand Availability Rate:
    ```
    availability_rate = (outlets_with_brand_available / total_outlets_with_brand_configured) × 100
    ```

**Reporting:**

-   Red Flag if must-have brand unavailable at outlet
-   Track availability trends over time

---

## 4. POSM Audit Scheduling

### BR-PA-001: Automated Audit Generation

**Rule:** Generate new audit task 20 days after previous audit completion

**Logic:**

-   Daily cron job runs at 02:00 Asia/Colombo time
-   Query outlets with completed audits:
    ```sql
    SELECT outlet_id, MAX(completed_date) as last_audit_date
    FROM posm_audits
    WHERE status = 'completed'
    GROUP BY outlet_id
    HAVING DATE_ADD(last_audit_date, INTERVAL 20 DAY) = CURDATE()
    ```
-   For each outlet:
    -   Create new audit:
        -   scheduled_date = CURDATE()
        -   due_date = CURDATE() + 5 days
        -   assigned_tm_id = outlet.assigned_tm_id
        -   status = "scheduled"
    -   Send notification to TM

**First Audit:**

-   For new outlets or outlets without audit history:
    -   Admin manually creates first audit
    -   Or auto-create on outlet activation

**Exception Handling:**

-   If TM is inactive: Assign to SM
-   If outlet is inactive: Skip audit generation

---

### BR-PA-002: Overdue Audit Flagging

**Rule:** Flag audits not completed by due date

**Logic:**

-   Daily cron job runs at 03:00 Asia/Colombo time
-   Query overdue audits:
    ```sql
    UPDATE posm_audits
    SET is_overdue = true
    WHERE due_date < CURDATE()
    AND status != 'completed'
    AND is_overdue = false
    ```
-   For each newly overdue audit:
    -   Send escalation notification to TM's SM
    -   Add to Red Flags dashboard
    -   Track in overdue audit report

**Escalation:**

-   1 day overdue: Notify SM
-   3 days overdue: Notify Regional Manager
-   7 days overdue: Escalate to Admin

**Clear Flag:**

-   When audit completed: `is_overdue = false`

---

### BR-PA-003: Audit Variance Calculation

**Rule:** Calculate variance between actual and norm quantities

**Calculation:**

```
variance = actual_quantity - norm_quantity
variance_percentage = (variance / norm_quantity) × 100
```

**Logic:**

-   For each material in audit:
    -   If variance = 0: No action required
    -   If variance < 0: Under-stocked (negative variance)
    -   If variance > 0: Over-stocked (positive variance)
    -   If |variance_percentage| > 20%: Require mandatory remarks

**Alerting:**

-   Under-stocked by >50%: High priority alert
-   Consistent negative variance: Trigger restocking workflow

---

### BR-PA-004: Audit Completion Buffer

**Rule:** TM has 5-day buffer to complete restocking and finalize audit

**Logic:**

-   Audit due_date = scheduled_date + 5 days
-   During buffer period:
    -   TM can execute audit (capture variances)
    -   TM can update audit with restocking notes
    -   Status remains "in_progress" or "scheduled"
-   On audit completion:
    -   Status = "completed"
    -   completed_date = CURDATE()
    -   Trigger next audit generation (20 days from completed_date)

**Validation:**

-   All materials must have actual_quantity entered
-   Remarks required for significant variances

---

## 5. Service Request Management

### BR-SR-001: SLA Calculation

**Rule:** SLA due date is calculated from creation timestamp + category SLA hours

**Calculation:**

```
sla_due_date = created_at + INTERVAL category.sla_hours HOUR
```

**Logic:**

-   SLA tracking starts immediately on creation
-   SLA countdown displayed in hours or days
-   SLA status:
    -   "within_sla": current_time < sla_due_date
    -   "sla_breached": current_time ≥ sla_due_date AND status ≠ closed

**Alerting:**

-   80% of SLA elapsed: Warning notification
-   100% of SLA elapsed: Breach notification
-   SLA breached: Add to Red Flags dashboard

---

### BR-SR-002: Status Transition Rules

**Rule:** Service requests follow defined status lifecycle

**Valid Transitions:**

-   Open → In Progress (by assigned user)
-   Open → Cancelled (by creator or admin)
-   In Progress → Resolved (by assigned user)
-   In Progress → Cancelled (by admin)
-   Resolved → Closed (by TM/SM/Admin after verification)
-   Resolved → In Progress (if verification fails)
-   Any status → Cancelled (by admin with reason)

**Invalid Transitions:**

-   Open → Resolved (must go through In Progress)
-   Closed → Any other status (closed is final)
-   Cancelled → Any other status (cancelled is final)

**Validation:**

-   On status change request:
    -   Check if transition is valid
    -   Check if user has permission for transition
    -   If invalid: Return error "INVALID_STATUS_TRANSITION"

---

### BR-SR-003: Auto-Assignment Logic

**Rule:** Service requests are auto-assigned based on category configuration

**Logic:**

-   Each category has `assignment_hierarchy` (JSON):
    ```json
    {
        "default_role": "tm",
        "escalation": ["sm", "regional_manager"]
    }
    ```
-   On SR creation:
    -   Get outlet's assigned user for `default_role`
    -   If user is active: Assign to that user
    -   If user is inactive: Escalate to next role in hierarchy

**Example:**

-   Category: "Equipment Repair"
-   Default role: "tm"
-   Outlet's TM: Jane (active)
-   Result: Assigned to Jane

**Manual Reassignment:**

-   Admin/SM can manually reassign SR to any user
-   Log reassignment in activity log
-   Send notification to new assignee

---

### BR-SR-004: Resolution Time Calculation

**Rule:** Track time taken to resolve service request

**Calculation:**

```
resolution_time_hours = TIMESTAMPDIFF(HOUR, created_at, resolved_date)
```

**Metrics:**

-   Average resolution time per category
-   Average resolution time per user
-   SLA compliance rate:
    ```
    compliance_rate = (requests_resolved_within_sla / total_requests_closed) × 100
    ```

**Reporting:**

-   Track resolution time trends
-   Identify bottlenecks (categories/users with long resolution times)

---

## 6. Dashboard & Reporting

### BR-DR-001: Visit Coverage Calculation

**Rule:** Calculate outlet visit coverage for users and territories

**Calculation:**

```
coverage_percentage = (outlets_visited / outlets_assigned) × 100
```

**Logic:**

-   For period (today, last 7 days, last 30 days):
    -   Count distinct outlets visited by user
    -   Count total outlets assigned to user
    -   Calculate coverage %

**Targets:**

-   LSR: 90% coverage per month
-   TM: 50% coverage per month (TM focuses on audits)

**Color Coding:**

-   Green: ≥ 90%
-   Yellow: 70-89%
-   Red: < 70%

---

### BR-DR-002: Workflow Completion Rate

**Rule:** Track percentage of workflows completed vs started

**Calculation:**

```
completion_rate = (workflows_completed / workflows_started) × 100
```

**Logic:**

-   Workflow statuses:
    -   in_progress: Started but not completed
    -   completed: All steps done
    -   abandoned: Not completed within 24 hours
-   Only "completed" counts toward completion rate

**Targets:**

-   Completion rate: ≥ 95%

**Alerting:**

-   If user's completion rate < 80%: Flag for manager review

---

### BR-DR-003: Red Flags Priority

**Rule:** Red flags are prioritized by severity and age

**Priority Calculation:**

```
priority_score = (base_score × days_overdue_multiplier) + urgency_factor
```

**Base Scores:**

-   SLA Breached SR (Critical priority): 100
-   SLA Breached SR (High priority): 75
-   Overdue Audit (7+ days): 90
-   Overdue Audit (3-6 days): 60
-   Overdue Audit (1-2 days): 40
-   Must-Have Brand Stockout: 80
-   Unvisited Outlet (30+ days): 70
-   Geolocation Compliance Issue: 30

**Multipliers:**

-   Days overdue 0-1: 1.0×
-   Days overdue 2-3: 1.5×
-   Days overdue 4-7: 2.0×
-   Days overdue 8+: 3.0×

**Display Order:**

-   Sort red flags by priority_score (descending)

---

### BR-DR-004: Dashboard Auto-Refresh Logic

**Rule:** Dashboard widgets refresh at different intervals based on data volatility

**Refresh Intervals:**

-   KPI Cards (visit count, workflow count): 5 minutes
-   Charts (trends, coverage): 15 minutes
-   Red Flags: 15 minutes
-   Reports: On-demand (manual refresh)

**Logic:**

-   Use Redis cache with TTL
-   On widget load:
    -   Check cache
    -   If cache exists and not expired: Return cached data
    -   If cache expired: Query database, update cache

**Performance:**

-   Prevents excessive database queries
-   Ensures near-real-time data visibility

---

## 7. Offline Data Sync

### BR-OS-001: Offline Data Storage

**Rule:** Mobile app stores data locally when offline

**Logic:**

-   On network loss:
    -   Switch to offline mode
    -   Save all write operations to local database (SQLite)
    -   Assign temporary IDs (UUID format: "local*[entity]*[timestamp]")
    -   Mark records with `pending_sync = true`
-   Continue normal operations:
    -   Check-in/check-out
    -   Workflow execution
    -   Photo capture (store locally)
    -   Service request updates

**Validation:**

-   Essential data must be available offline:
    -   Assigned outlets
    -   Workflow configurations
    -   Current visit data
    -   POSM norms (for TM)

---

### BR-OS-002: Data Sync Priority

**Rule:** Sync data in order of business importance

**Sync Order:**

1. **Critical (sync immediately on connection):**
    - Check-ins/check-outs (visit logs)
    - Service requests (high/critical priority)
2. **High (sync within 5 minutes):**
    - Workflow executions
    - POSM audit data
    - Service request updates
3. **Medium (sync within 30 minutes):**
    - Photos
    - Comments
4. **Low (sync within 24 hours):**
    - Activity logs
    - Read receipts

**Logic:**

-   Sync in batches (max 50 records per API call)
-   Retry failed syncs with exponential backoff
-   Show sync progress to user

---

### BR-OS-003: Conflict Resolution

**Rule:** Handle data conflicts when syncing offline changes

**Conflict Scenarios:**

1. **Same record updated by multiple users:**
    - Server timestamp wins (last-write-wins strategy)
    - Show conflict notification to user
2. **Outlet deleted while offline:**
    - Reject offline data for that outlet
    - Notify user of data loss
3. **Workflow changed while offline:**
    - Accept offline responses if step still exists
    - Skip responses for deleted steps

**Validation:**

-   Check entity existence on server
-   Check user permissions (may have changed)
-   Validate data integrity

---

## 8. Security & Permissions

### BR-SP-001: Role-Based Access Control

**Rule:** Actions are restricted by user role

**Permission Matrix:**

| Action                  | LSR           | TM            | SM               | Admin |
| ----------------------- | ------------- | ------------- | ---------------- | ----- |
| Execute workflows       | ✓             | ✓             | ✓                | ✓     |
| Execute POSM audits     | ✗             | ✓             | ✓                | ✓     |
| Create service requests | ✓             | ✓             | ✓                | ✓     |
| Update SR status        | Assigned only | Assigned only | All in hierarchy | All   |
| Reassign SRs            | ✗             | ✗             | ✓                | ✓     |
| Configure workflows     | ✗             | ✗             | ✗                | ✓     |
| Configure outlets       | ✗             | ✗             | ✗                | ✓     |
| View reports            | Own data      | Territory     | Region           | All   |
| Manage users            | ✗             | ✗             | ✗                | ✓     |

**Validation:**

-   Check user role on every API request
-   If permission denied: Return 403 Forbidden

---

### BR-SP-002: Token Expiration

**Rule:** Authentication tokens expire after inactivity

**Logic:**

-   Token lifetime: 30 days from creation
-   Inactivity timeout: 30 minutes
-   On each API request:
    -   Check token expiration
    -   If expired: Return 401 Unauthorized
    -   If valid: Update last_activity timestamp

**Refresh:**

-   User can manually refresh token
-   Auto-refresh on app launch (if token expires within 24 hours)

---

### BR-SP-003: Data Encryption

**Rule:** Sensitive data must be encrypted

**Encrypted Fields:**

-   passwords (bcrypt hash)
-   remember_token (encrypted)
-   API tokens (encrypted)

**Encryption in Transit:**

-   All API communication via HTTPS (TLS 1.3)
-   Certificate pinning in mobile app

**Encryption at Rest:**

-   Database: AES-256 encryption
-   File storage: Server-side encryption (SSE)
-   Mobile local storage: iOS Keychain / Android Keystore

---

## 9. Validation Rules

### BR-VR-001: Input Validation Standards

**Rule:** All user inputs must be validated

**String Fields:**

-   Max length enforced (specified in database schema)
-   Trim whitespace
-   No SQL injection patterns
-   No XSS patterns (sanitize HTML)

**Numeric Fields:**

-   Must be valid number
-   Range validation (e.g., quantity ≥ 0)
-   Decimal precision enforced

**Date/Time Fields:**

-   ISO 8601 format required
-   Valid date/time
-   Timezone aware (convert to UTC for storage)

**File Uploads:**

-   Allowed types: jpg, jpeg, png, pdf
-   Max size: 10MB per file
-   Max files per upload: 10
-   Virus scan (if applicable)

**Geolocation:**

-   Latitude: -90 to 90
-   Longitude: -180 to 180
-   Precision: 8 decimal places

---

### BR-VR-002: Business Logic Validation

**Rule:** Validate business rules before data persistence

**Examples:**

-   Cannot check in if already checked in elsewhere
-   Cannot check out if not checked in
-   Cannot complete workflow if mandatory steps incomplete
-   Cannot change SR status if user not authorized
-   Cannot assign outlet without LSR
-   Cannot delete workflow if used in active executions

**Error Handling:**

-   Return 422 Unprocessable Entity
-   Include specific validation errors in response
-   Display user-friendly error messages

---

## 10. Performance & Optimization

### BR-PO-001: Query Optimization Rules

**Rule:** Optimize database queries for performance

**Guidelines:**

-   Use indexes on frequently queried columns
-   Avoid SELECT \*, specify required columns
-   Use pagination for list queries (default: 25, max: 100)
-   Use LIMIT for large result sets
-   Cache frequently accessed data (Redis)
-   Use eager loading to prevent N+1 queries

**Cache Strategy:**

-   Cache static data (workflows, templates): TTL 1 hour
-   Cache dashboard metrics: TTL 5 minutes
-   Cache outlet lists: TTL 15 minutes
-   Invalidate cache on data updates

---

### BR-PO-002: Background Job Processing

**Rule:** Long-running tasks must be processed asynchronously

**Background Jobs:**

-   Audit task generation (cron: daily 02:00)
-   Overdue audit flagging (cron: daily 03:00)
-   SLA breach checking (cron: hourly)
-   Photo processing/compression (queue)
-   Report generation (queue)
-   Notification sending (queue)
-   Data archival (cron: monthly)

**Queue Priority:**

-   High: Notifications, SLA checks
-   Medium: Photo processing, report generation
-   Low: Data archival, cleanup tasks

---

## 11. Notification Rules

### BR-NR-001: Notification Triggers

**Rule:** Send notifications for critical events

**Notification Events:**

| Event                          | Recipient               | Channel                |
| ------------------------------ | ----------------------- | ---------------------- |
| Service request created        | Assigned user           | Push + Email           |
| Service request assigned to me | Assigned user           | Push                   |
| Service request status changed | Creator + Assignee      | Push                   |
| SLA breach imminent (80%)      | Assigned user           | Push                   |
| SLA breached                   | Assigned user + Manager | Push + Email           |
| POSM audit assigned            | TM                      | Push                   |
| POSM audit overdue             | TM + SM                 | Push + Email           |
| Audit overdue 7+ days          | Regional Manager        | Email                  |
| Must-have brand unavailable    | SM                      | Push                   |
| User forgot to check out       | User                    | Push (next app launch) |

**Delivery:**

-   Push notifications: Firebase Cloud Messaging
-   Email: Via configured SMTP
-   Retry on failure: 3 attempts with exponential backoff

---

### BR-NR-002: Notification Batching

**Rule:** Batch similar notifications to avoid spam

**Logic:**

-   If multiple events of same type within 5 minutes:
    -   Combine into single notification
    -   Example: "3 service requests assigned to you" instead of 3 separate notifications
-   Respect user's notification preferences
-   Do Not Disturb: 22:00 - 06:00 (configurable)

---

**Document Status:** Final

**Next Steps:** Share with development team for implementation reference
