# 02 · Roles & Permissions

Individual accounts only. Each person signs in with their own company email. No shared accounts.

## Users at launch

| Name | Email | Role | Access |
|---|---|---|---|
| Syafiqah | fatin.syafiqah@asgb.com.my | `full_access` | FULL ACCESS |
| Asyraff | asyraaf@asgb.com.my | `full_access` | FULL ACCESS |
| Siti | siti@asgb.com.my | `management` | MANAGEMENT – FULL ACCESS |
| Ng Zhiyan | ngzhiyan@asgb.com.my | `management` | MANAGEMENT – FULL ACCESS |
| Other Operation Team | own company email each | `operations` | Operational Execution |
| Finance Team | own company email each | `finance` | Finance & Reporting |

## Permission matrix

✓ = allowed · — = not allowed · *own* = only records assigned to them

| Permission | Full Access | Management | Operations | Finance |
|---|:-:|:-:|:-:|:-:|
| View all modules & merchants | ✓ | ✓ | *assigned only* | Finance modules |
| Create / edit operational records | ✓ | ✓ | *own* | — |
| Upload documents | ✓ | ✓ | ✓ | — |
| Upload Excel / CSV | ✓ | ✓ | ✓ | settlement & bank only |
| Assign / reassign tasks and PIC | ✓ | ✓ | create tasks only | — |
| Update assigned tasks, submit for verification | ✓ | ✓ | *own* | — |
| **Verify / reject documents** | ✓ | — ¹ | — | — |
| **Verify tasks** | ✓ | — ¹ | — | — |
| Record ZUS location decision | ✓ | ✓ | — | — |
| Activate merchant | ✓ | ✓ | — | — |
| Create issues, update status, add remarks | ✓ | ✓ | ✓ | — |
| **Verify / close issues** | ✓ | — ¹ | — | — |
| Record bank receipts, match bank transactions | ✓ | ✓ | ✓ | ✓ |
| Edit Finance-specific fields | ✓ | ✓ | — | ✓ |
| Change allocation rule | ✓ | ✓ | — | — |
| Create restock orders | ✓ | ✓ | ✓ | — |
| Complete restock (verify delivery, deduct balance) | ✓ | ✓ | — | — |
| Prepare daily Finance report (draft) | ✓ | ✓ | ✓ | — |
| **Verify Finance report / send to Finance** | ✓ | — ¹ | — | — |
| **Lock month** | ✓ | — ¹ | — | — |
| Request adjustment on locked record | ✓ | ✓ | ✓ | ✓ |
| Approve adjustment (never own request) | ✓ | ✓ | — | — |
| Download reports / export | ✓ | ✓ | ✓ (own scope) | ✓ |
| Manage users & roles | ✓ | ✓ | — | — |
| Review audit log | ✓ | ✓ | — | — |
| Delete audit history | — | — | — | — |
| Permanently delete operational records | — | — | — | — |

¹ The requirement names Syafiqah and Asyraff as the verifiers and lockers. Management has full visibility and every other right. If Management should also verify, change one line in `is_full_access()` / the permission map — see `05-open-questions.md`.

## Approval rules

1. **Executor ≠ verifier.** The person who uploaded a document, completed a task or prepared a report cannot verify it, unless they are Full Access (Syafiqah, Asyraff).
2. **No self-approval of adjustments**, for anyone (database check: `approved_by <> requested_by`).
3. **Mandatory reason** on every rejection (documents, tasks, ZUS location rejection, adjustments).
4. **Finance** does not get operational approval rights unless explicitly granted through `user_permission_overrides`.

## Data visibility

| Role | Merchants visible | Modules in navigation |
|---|---|---|
| Full Access, Management | All | All 17 (incl. Users & Roles, Audit Log) |
| Operations | `assigned_pic_id = me` OR has a task assigned to me | All except Users & Roles and Audit Log |
| Finance | All (read) | Dashboard, Merchants, Sales, Settlement, Fund Allocation, Repayment, Reports |

## Implementation notes

- Keep the permission map in one server-side module (e.g. `can(user, action, record?)`) and call it in every server action and every list query.
- Store role on `users.role`; per-person exceptions in `user_permission_overrides` (granted/denied, by whom, when).
- Deactivation (`users.status = 'inactive'`) blocks login immediately; records keep the user as PIC for history, and the UI flags inactive PICs so work can be reassigned.
