Agent Types & Permissions
Overview
Section titled “Overview”Agent types are configurable role templates that determine what systems and permissions a given agent has access to. Rather than hardcoding every permission, admins can create named agent types (e.g., “Document Receiver”, “VFS Agent”, “Ticketing Agent”) and assign them to users.
Data model
Section titled “Data model”agent_types id INT name TEXT (unique) description TEXT permissions TEXT ← JSON array of permission strings systems TEXT ← JSON array: ["VFS", "TICKETING"] category TEXT ← legacy field, maps to first system isActive INT (1 = active)Example agent type
Section titled “Example agent type”{ "name": "VFS Agent", "description": "Handles physical document collection and VFS submission", "systems": ["VFS"], "permissions": [ "DOCUMENT_RECEIVER", "DOCUMENT_AT_SHANVI", "VFS_RECEIVED", "REJECT_TASK" ]}Available permissions
Section titled “Available permissions”| Permission | What it unlocks |
|---|---|
MANAGE_TICKETS | Upload and edit FD tickets |
VIEW_ALL_TICKETS | See all agents’ tickets (not just own) |
DOCUMENT_RECEIVER | Move VFS tasks to DOCUMENT_RECEIVER / DISPATCHED_TO_SHANVI |
DOCUMENT_AT_SHANVI | Move VFS tasks to DOCUMENT_AT_SHANVI |
VFS_RECEIVED | Move VFS tasks to VFS_RECEIVED |
VFS_AFTER_SHANVI | Move VFS tasks to VFS_COLLECTED / VFS_AFTER_SHANVI |
CONSULTANCY_RECEIVED | Move VFS tasks to CONSULTANCY_RECEIVED |
TASK_CLOSE | Close VFS tasks |
REJECT_TASK | Reject VFS tasks |
CREATE_TASK | Create new VFS tasks |
VIEW_ALL_DOCUMENTS | See all VFS tasks (not just own) |
Available systems
Section titled “Available systems”| System | What it grants access to |
|---|---|
VFS | VFS tracking pipeline |
TICKETING | FD ticket upload and management |
HEAD_OFFICE: the special built-in type
Section titled “HEAD_OFFICE: the special built-in type”HEAD_OFFICE is a hardcoded agent type that has all permissions and sees all data. It is not stored in agent_types — it is recognized by name at runtime in multiple places:
// From routes/auth.js enrichUserData()const nameUpper = userData.agentType.toUpperCase().trim().replace(/_/g, ' ');if (nameUpper === 'HEAD OFFICE' || nameUpper === 'HEAD_OFFICE') { resolve({ ...userData, permissions: ['MANAGE_TICKETS', 'VIEW_ALL_TICKETS', 'DOCUMENT_RECEIVER', ...all permissions], systems: ['VFS', 'TICKETING'] });}Design smell: Multiple places in the codebase check
agentType.toUpperCase().trim().replace(/_/g, ' ') === 'HEAD OFFICE'individually — this is fragile and prone to drift if the name changes. A better approach is to store HEAD_OFFICE as a seeded row inagent_typeswith all permissions, and rely on the permissions lookup everywhere.
How permissions are checked in the backend
Section titled “How permissions are checked in the backend”When an agent makes a request, the backend fetches their agentType name, looks up the agent_types table, and checks whether the required permission is in the JSON array:
// Simplified from routes/tickets.js checkCanManageTickets()const agentTypeRecord = await get('SELECT * FROM agent_types WHERE name = ?', [agentTypeName]);const systems = JSON.parse(agentTypeRecord.systems || '[]');const permissions = JSON.parse(agentTypeRecord.permissions || '[]');
if (systems.includes('TICKETING') || permissions.includes('MANAGE_TICKETS')) { return true; // can manage tickets}Note that this lookup is only done for the TICKETING system currently. VFS permission checks appear to happen primarily at the frontend level (checking userPermissions from the auth context), which means the backend does not fully enforce VFS permissions. This is a security gap — backend enforcement should be added for VFS status transitions.
Managing agent types
Section titled “Managing agent types”Agent types are managed by ADMIN users in the dashboard Settings tab.
API endpoints (all ADMIN only):
| Method | Path | Description |
|---|---|---|
GET | /api/admin/agent-types | List all agent types |
POST | /api/admin/agent-types | Create agent type |
PUT | /api/admin/agent-types/:id | Update agent type |
DELETE | /api/admin/agent-types/:id | Delete agent type |
Assigning an agent type to a user
Section titled “Assigning an agent type to a user”Done via the role update endpoint:
PUT /api/admin/users/:id/role{ "role": "AGENT", "agentType": "VFS Agent", "kyc_status": "APPROVED" }The agentType field stores the name string of the agent type, not its ID. This means renaming an agent type in agent_types will silently break all users assigned to it — their agentType field will no longer match any row.
Recommendation: Store
agentTypeId(foreign key) instead of the name string. This makes renames safe and queries simpler.