Ticket Management System
Author(s)
- Aishika Majumdar
- Arabinda Bhowmick
Last Updated Date
[2026-04-24]
SRS References
N/A
Version History
| Version | Date | Changes | Author |
|---|---|---|---|
| 1.0 | 2026-04-23 | Initial draft | Aishika Majumdar, Arabinda Bhowmick |
Feature Overview
Objective:
The Ticket Management System provides a centralized platform for users to report issues and for administrators to manage and resolve them efficiently. It ensures a simple, structured workflow from ticket creation to closure while maintaining data consistency. The API provides functionality for creating, listing, and managing support tickets in the Van Tracker service. Tickets can be created by customers and technicians to report issues, and they can be tracked through a lifecycle of status transitions. Admin users can update ticket statuses to track resolution progress.
Scope:
This feature includes:
- Ticket creation by Customers and Technicians
- Viewing tickets (role-based access)
- Status updates managed by Admin
- Image attachment support (up to 5 images per ticket)
Dependencies:
- Authentication system (JWT-based)
- User service (for user details)
- File storage service (for image URLs)
Requirements
- Users (Customer/Technician) must be able to create tickets
- Admin must be able to view all tickets
- Users can only view their own tickets
- Admin can update ticket status
- Ticket must follow a strict lifecycle: OPEN → IN_PROGRESS → RESOLVED → CLOSED
- Maximum 5 images allowed per ticket
- All APIs must be secured using JWT authentication
- System must support pagination for ticket listing
- Ticket data must be immutable except status updates
Design Specifications
-
UI/UX Design:
-
Ticket creation form with:
- Title
- Description
- Image upload (max 5)
-
Admin panel:
- Paginated ticket list
- Status update actions (with confirmation dialog)
-
Data Models:
public enum TicketStatus
{
OPEN = 1,
IN_PROGRESS,
RESOLVED,
CLOSED
}
public record Ticket
{
public Guid TicketId { get; init; }
public string TicketNo { get; init; } = string.Empty;
public string Title { get; init; } = string.Empty;
public string Description { get; init; } = string.Empty;
public List<string> ImageUrls { get; init; } = new();
public UserBasicInfo CreatedBy { get; init; } = default!;
public UserBasicInfo? UpdatedBy { get; init; };
public TicketStatus Status { get; init; }
public DateTime CreatedAt { get; init; }
public DateTime UpdatedAt { get; init; }
}
API Interfaces
1. Create Ticket
| Endpoint | Method | Parameters | Response | Response Status Codes |
|---|---|---|---|---|
/ticket | POST | title (required, string)description (required, string)imageUrls (optional, array of string, max 5) | TicketId + ticketNo | 200, 400, 401, 500 |
Authorization Scope(s):
customer.usertechnician.user
Sample Request:
{
"title": "Van Air Conditioning Issue",
"description": "The air conditioning system is not cooling the cabin properly. The compressor seems to be working but no cold air is coming out of the vents.",
"imageUrls": [
"https://example.com/images/van-ac-issue-1.jpg",
"https://example.com/images/van-ac-issue-2.jpg"
]
}
Sample Response:
{
"status": 1,
"message": "Ticket created successfully",
"data": {
"ticketId": "550e8400-e29b-41d4-a716-446655440000",
"ticketNo": "TKT-20240115ABC12345"
}
}
2. Get Ticket List
| Endpoint | Method | Parameters | Response | Response Status Codes |
|---|---|---|---|---|
/ticket/list | GET | searchKeyword (optional)ticketNo (optional)status (optional)rowsPerPage (optional, max 100)pageNumber (optional) | Paginated Ticket List | 200, 400, 401, 500 |
Authorization Scope(s):
customer.usertechnician.useradmin.user
Sample Request:
GET /ticket/list?searchKeyword=AC&status=1&pageNumber=1&rowsPerPage=10
Sample Response:
{
"data": [
{
"ticketId": "550e8400-e29b-41d4-a716-446655440000",
"ticketNo": "TKT-20240115ABC12345",
"title": "Van Air Conditioning Issue",
"description": "The air conditioning system is not cooling properly",
"imageUrls": ["https://example.com/images/van-ac-issue-1.jpg"],
"createdBy": {
"userId": "660e8400-e29b-41d4-a716-446655440001",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"phoneNumber": "+1-555-0101",
"profileImageUrl": "https://example.com/profiles/john-doe.jpg"
},
"updatedBy": null,
"status": 1,
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
},
{
"ticketId": "770e8400-e29b-41d4-a716-446655440002",
"ticketNo": "TKT-20240114XYZ67890",
"title": "Engine Oil Leak",
"description": "Noticed oil leaking from the engine area",
"imageUrls": [],
"createdBy": {
"userId": "880e8400-e29b-41d4-a716-446655440003",
"firstName": "Jane",
"lastName": "Smith",
"email": "jane.smith@example.com",
"phoneNumber": "+1-555-0102",
"profileImageUrl": "https://example.com/profiles/jane-smith.jpg"
},
"updatedBy": {
"userId": "990e8400-e29b-41d4-a716-446655440004",
"firstName": "Admin",
"lastName": "User",
"email": "admin@example.com"
},
"status": 2,
"createdAt": "2024-01-14T15:45:00Z",
"updatedAt": "2024-01-15T09:00:00Z"
}
],
"totalNumber": 25,
"hasNextPage": true,
"hasPreviousPage": false,
"totalPages": 3,
"pageNumber": 1,
"rowsPerPage": 10
}
3. Update Ticket Status
| Endpoint | Method | Parameters | Response | Response Status Codes |
|---|---|---|---|---|
/ticket/update | PUT | ticketId (required, guid)status (required, int) | Success Message | 200, 400, 401, 403, 404, 500 |
Authorization Scope(s):
admin.user
Sample Request:
{
"ticketId": "550e8400-e29b-41d4-a716-446655440000",
"status": 2
}
Sample Response:
{
"status": 1,
"message": "Ticket status updated successfully"
}
- Third-Party Integrations:
- File storage (for image hosting) - Amazon S3
- Workflow:
-
User (Customer/Technician) creates a ticket
-
Ticket is automatically assigned status OPEN
-
Admin views tickets from dashboard
-
Admin updates status as work progresses:
- IN_PROGRESS → when work starts
- RESOLVED → issue fixed
- CLOSED → workflow completed
-
User can track status updates
Ticket Status Codes:
| Code | Status | Allowed Transitions |
|---|---|---|
| 1 | Open | Can transition to InProgress (2) |
| 2 | InProgress | Can transition to Resolved (3) |
| 3 | Resolved | Can transition to Closed (4) |
| 4 | Closed | No further transitions allowed |
Error Handling
Common Error Scenarios
Missing Required Fields:
{
"status": -1,
"message": "Title and Description are required"
}
Unauthorized Access:
{
"status": -2,
"message": "User ID not found in token"
}
Invalid Status Transition:
{
"status": -1,
"message": "Invalid status transition. Current status does not allow transition to the requested status."
}
Ticket Not Found:
{
"status": -3,
"message": "Ticket not found"
}
Admin-Only Operation:
{
"status": -2,
"message": "Only admin users can update ticket status"
}
Development Tasks & Estimates
| No | Task Name | Estimate (Hours) | Dependencies | Notes |
|---|---|---|---|---|
| 1 | API Design & Contract | 6 hours | SRS Finalization | Define endpoints & schemas |
| 2 | Ticket Creation API | 8 hours | Auth Service | Validation + DB integration |
| 3 | Ticket Listing API | 10 hours | DB + Pagination Logic | Filtering + role-based access |
| 4 | Status Update API | 6 hours | Admin Role Setup | Lifecycle enforcement |
| 5 | Image Upload Integration | 8 hours | File Storage (S3) | Max 5 images validation |
| 6 | Testing (Unit + Integration) | 10 hours | All APIs | Full lifecycle validation |
| 7 | Total | 48 hours | - | - |
Usage Examples
Example 1: Customer Creates a Ticket
curl -X POST http://localhost:5000/ticket \
-H "Authorization: Bearer <jwt_token>" \
-H "Content-Type: application/json" \
-d '{
"title": "Brake Pad Replacement",
"description": "Front brake pads are worn and need replacement",
"imageUrls": ["https://example.com/brake-image.jpg"]
}'
Response:
{
"status": 1,
"message": "Ticket created successfully",
"data": {
"ticketId": "550e8400-e29b-41d4-a716-446655440000",
"ticketNo": "TKT-20240115ABC12345"
}
}
Example 2: Customer Views Their Tickets
curl -X GET "http://localhost:5000/ticket/list?pageNumber=1&rowsPerPage=10" \
-H "Authorization: Bearer <jwt_token>"
Example 3: Admin Updates Ticket Status
curl -X PUT http://localhost:5000/ticket/update \
-H "Authorization: Bearer <jwt_token>" \
-H "Content-Type: application/json" \
-d '{
"ticketId": "550e8400-e29b-41d4-a716-446655440000",
"status": 2
}'
Response:
{
"status": 1,
"message": "Ticket status updated successfully"
}
Example 4: Admin Views All Tickets with Filtering
curl -X GET "http://localhost:5000/ticket/list?searchKeyword=brake&status=1&pageNumber=1&rowsPerPage=20" \
-H "Authorization: Bearer <jwt_token>"
Testing & Quality Assurance
Unit Tests:
- Create ticket validation
- Status transition validation
- Image limit validation
Integration Tests:
- End-to-end ticket lifecycle
- Role-based access checks
Acceptance Criteria:
- Ticket can be created successfully
- Only Admin can update status
- Status follows defined lifecycle
- Pagination works correctly
- Users cannot access others' tickets
Testing Tools:
- Swagger
Deployment Considerations
Configuration Changes:
- JWT authentication setup
- File storage configuration (Amazon S3)
Rollout Plan:
- Deploy backend APIs
- Enable feature in Admin panel first
- Gradual rollout to Customer/Technician apps
Risks & Mitigations
| Risk | Impact | Likelihood | Mitigation Strategy |
|---|---|---|---|
| Unauthorized access | High | Medium | Strict JWT validation & RBAC |
| Invalid status transitions | Medium | Medium | Backend validation rules |
| Excess image uploads | Low | Medium | Enforce max 5 images |
| Data inconsistency | Medium | Low | Centralized API design |
Review & Approval
-
Reviewer: (Name and role of the person reviewing the document.)
-
Approval Date: (Date when the feature is approved for development.)
Notes
- All timestamps are in UTC (ISO 8601 format)
- Ticket numbers follow format:
TKT-<YYYYMMDD><Random_String> - Images must be uploaded separately and passed as URLs
- Pagination supports max 100 rows per page
- Role-based access strictly enforced via JWT scopes
- System tracks audit fields (CreatedAt, UpdatedAt)
- This system is intentionally simplified for performance and scalability
- No assignment or chat features are included
- Focus is on structured, status-driven workflow