Technician-Van Management Features
Author(s)
- Sanket Mal
- Ashik Ikbal
Last Updated Date
2025-01-01
Feature Overview
The Technician-Van Management system provides comprehensive fleet management and technician-vehicle assignment capabilities for the RKAuto Van Tracker platform. This feature enables administrators to manage service vans, assign them to technicians, track assignment history, and monitor vehicle availability in real-time.
Key Features
- Van Fleet Management: Complete CRUD operations for service vehicle inventory
- VIN Decoding Integration: Auto-populate vehicle details using NHTSA API
- Technician-Van Assignment: Dynamic assignment and reassignment of vans to technicians
- Assignment History Tracking: Complete audit trail of all van assignments
- Real-Time Availability: Track current van status and technician assignments
- Automatic Unassignment: Cascade updates when technician status changes to disabled
- Role-Based Access: Admin-only write operations, read access for technicians
User Types & Workflows
- Admin: Add van → Decode VIN → Assign technician → Manage assignments → View history
- Technician: View assigned van → View own assignment history → Track current assignment
Requirements
Functional Requirements
| ID | Requirement | Priority |
|---|---|---|
| FR-1 | Admin can add new van with VIN decoding | High |
| FR-2 | Admin can optionally assign technician during van creation | Medium |
| FR-3 | Admin can update van details and reassign technicians | High |
| FR-4 | Admin can view all vans with pagination and filters | High |
| FR-5 | Admin and technician can view technician assignment history | Medium |
| FR-6 | Admin can view complete van assignment history | Medium |
| FR-7 | System auto-unassigns van when technician is disabled | High |
| FR-8 | Prevent assigning van to technician already assigned a van | High |
| FR-9 | Track assignment and unassignment timestamps | Medium |
| FR-10 | Update technician list API to include current van info | High |
Non-Functional Requirements
| ID | Requirement | Target |
|---|---|---|
| NFR-1 | API response time | < 500ms (95th percentile) |
| NFR-2 | VIN validation | Real-time validation on input |
| NFR-3 | Pagination performance | Support 1000+ vans efficiently |
| NFR-4 | Assignment history retention | Maintain complete audit trail |
| NFR-5 | Database transaction | ACID compliance for assignments |
Security Requirements
- Only Admin role can create, update, and delete vans
- Only Admin role can assign/unassign technicians to vans
- Technicians can only view their own assignment history
- Admin can only view all technician assignment history
- VIN must be unique across the system
- Registration numbers must be unique
Component Responsibilities
- VanController: HTTP endpoint handling, request validation, authorization
- VanService: Business logic, VIN decoding, assignment management, history tracking
- VanDal: Database operations, transaction management, complex queries
- NHTSA VIN API: External service for vehicle information decoding
- PostgreSQL: Van data persistence, assignment tracking, relationship management
Database Schema (PostgreSQL)
Core Tables
vanmaster - Service van inventory and current assignments
Note: This table was already created in migration script
000001-AddUserManagementRelatedTables.
Table Structure:
-- Table already exists from 000001-AddUserManagementRelatedTables migration
-- Shown here for reference
vanmaster (
vanid UUID PRIMARY KEY DEFAULT gen_random_uuid(),
registrationnumber VARCHAR(50) NOT NULL UNIQUE,
vin VARCHAR(17) NOT NULL UNIQUE,
make VARCHAR(50),
model VARCHAR(50),
year INT,
trim VARCHAR(50),
bodytype VARCHAR(50),
status VARCHAR(20) DEFAULT 'Active',
currentlatitude VARCHAR(50),
currentlongitude VARCHAR(50),
createdat TIMESTAMP NOT NULL DEFAULT NOW(),
updatedat TIMESTAMP NOT NULL DEFAULT NOW(),
createdby VARCHAR(100),
updatedby VARCHAR(100)
);
-- Existing indexes
CREATE INDEX idx_vanmaster_status ON vanmaster(status);
CREATE INDEX idx_vanmaster_vin ON vanmaster(vin);
vanassignmenthistory - Complete audit trail of van assignments
CREATE TABLE IF NOT EXISTS vanassignmenthistory (
assignmentid UUID PRIMARY KEY DEFAULT gen_random_uuid(),
vanid UUID NOT NULL,
technicianid UUID NOT NULL,
actionat TIMESTAMPTZ NOT NULL DEFAULT NOW(),
actionby UUID,
action VARCHAR(10),
CONSTRAINT fk_assignment_van
FOREIGN KEY (vanid)
REFERENCES vanmaster(vanid)
ON DELETE CASCADE,
CONSTRAINT fk_assignment_technician
FOREIGN KEY (technicianid)
REFERENCES technicianmaster(technicianid)
ON DELETE CASCADE
);
CREATE INDEX idx_vanassignmenthistory_vanid ON vanassignmenthistory(vanid);
CREATE INDEX idx_vanassignmenthistory_technicianid ON vanassignmenthistory(technicianid);
CREATE INDEX idx_vanassignmenthistory_actionat ON vanassignmenthistory(actionat);
CREATE INDEX idx_vanassignmenthistory_action ON vanassignmenthistory(action);
technicianmaster - Updated to include availability status
-- Migration to add new column for availability status
ALTER TABLE technicianmaster
ADD COLUMN IF NOT EXISTS availabilitystatus VARCHAR(20) DEFAULT 'Available';
CREATE INDEX idx_technicianmaster_availabilitystatus ON technicianmaster(availabilitystatus);
Enumerations
VanStatus - Vehicle operational status
public enum VanStatus
{
Active = 1, // Vehicle is operational and can be used
Maintenance = 2, // Vehicle is in shop for repairs
OutOfService = 3, // Vehicle is broken/damaged
Retired = 4 // Vehicle decommissioned
}
TechnicianAvailabilityStatus - Technician current work status
public enum TechnicianAvailabilityStatus
{
Available = 1, // Roaming around city, available for requests
EnRoute = 2, // Driving to customer location
Servicing = 3, // Actively working on a car
Offline = 4, // Technician off-duty / logged out
OnBreak = 5 // Technician on lunch/break
}
SortDirection - Sorting direction for list queries
public enum SortDirection
{
ASC = 1, // Ascending order
DESC // Descending order
}
VanSortBy - Sorting options for van list
public enum VanSortBy
{
RegistrationNumber = 1,
VIN,
Make,
Model,
Year,
Status,
CreatedAt,
UpdatedAt
}
VanAssignmentHistorySortBy - Sorting options for van assignment history
public enum VanAssignmentHistorySortBy
{
ActionAt = 1,
TechnicianCode = 2,
TechnicianName = 3,
Action = 4
}
TechnicianAssignmentHistorySortBy - Sorting options for technician assignment history
public enum TechnicianAssignmentHistorySortBy
{
ActionAt = 1,
VanRegNumber,
Make,
Model,
Year,
Action
}
VanAssignmentAction - Assignment action type
public enum VanAssignmentAction
{
Assign = 1,
UnAssign
}
C# Request/Response Models
1. Add Van
public record VanRequest
{
[JsonIgnore]
public Guid? VanId { get; init; }
[Required(ErrorMessage = "Registration number is required")]
[MaxLength(50, ErrorMessage = "Registration number cannot exceed 50 characters")]
public required string RegistrationNumber { get; init; }
[Required(ErrorMessage = "VIN is required")]
[StringLength(17, MinimumLength = 17, ErrorMessage = "VIN must be exactly 17 characters")]
[RegularExpression(@"^[A-HJ-NPR-Z0-9]{17}$", ErrorMessage = "Invalid VIN format")]
public required string VIN { get; init; }
[Required(ErrorMessage = "Make is required")]
[MaxLength(50, ErrorMessage = "Make cannot exceed 50 characters")]
public required string Make { get; init; }
[Required(ErrorMessage = "Model is required")]
[MaxLength(50, ErrorMessage = "Model cannot exceed 50 characters")]
public required string Model { get; init; }
[Required(ErrorMessage = "Year is required")]
[Range(1900, 2100, ErrorMessage = "Year must be between 1900 and 2100")]
public required int Year { get; init; }
[MaxLength(50, ErrorMessage = "Trim cannot exceed 50 characters")]
public string? Trim { get; init; }
[MaxLength(50, ErrorMessage = "Body type cannot exceed 50 characters")]
public string? BodyType { get; init; }
public VanStatus Status { get; init; } = VanStatus.Active;
// Optional: Assign technician during van creation/update
public Guid? TechnicianId { get; init; }
}
2. Update Van
// Uses same VanRequest model as Add Van
// VanId is passed in route parameter
3. Van Assign/Unassign Request
public record VanAssignUnassignRequest
{
[Required(ErrorMessage = "Technician ID is required")]
public required Guid TechnicianId { get; init; }
[Required(ErrorMessage = "Action is required")]
public required VanAssignmentAction Action { get; init; }
}
4. Van Details Response
public record VanDetails
{
public Guid VanId { get; init; }
public string RegistrationNumber { get; init; } = string.Empty;
public string VIN { get; init; } = string.Empty;
public string Make { get; init; } = string.Empty;
public string Model { get; init; } = string.Empty;
public int Year { get; init; }
public string? Trim { get; init; }
public string? BodyType { get; init; }
public VanStatus Status { get; init; }
public string StatusDisplayName { get; init; } = string.Empty;
public TechnicianBasicInfo? AssignedTechnician { get; init; }
public DateTime CreatedAt { get; init; }
public DateTime UpdatedAt { get; init; }
}
public record TechnicianBasicInfo
{
public Guid TechnicianId { get; init; }
public string TechnicianCode { get; init; } = string.Empty;
public string FirstName { get; init; } = string.Empty;
public string LastName { get; init; } = string.Empty;
public string Email { get; init; } = string.Empty;
public string PhoneNumber { get; init; } = string.Empty;
public TechnicianAvailabilityStatus AvailabilityStatus { get; init; }
}
5. Technician with Van Response (Updated Technician List)
public record TechnicianDetails
{
public Guid TechnicianId { get; init; }
public Guid UserId { get; init; }
public string TechnicianCode { get; init; } = string.Empty;
public string Email { get; init; } = string.Empty;
public string FirstName { get; init; } = string.Empty;
public string LastName { get; init; } = string.Empty;
public string PhoneNumber { get; init; } = string.Empty;
public UserStatus Status { get; init; }
public string Specialization { get; init; } = string.Empty;
public List<string> Skills { get; init; } = new();
public string EmployeeType { get; init; } = string.Empty;
public TechnicianAvailabilityStatus AvailabilityStatus { get; init; }
public DateOnly JoiningDate { get; init; }
public string? EmergencyContactName { get; init; }
public string? EmergencyContactPhone { get; init; }
public string? ProfileImageUrl { get; init; }
public List<TechnicianAddress> Addresses { get; init; } = new();
public VanInfo? CurrentVan { get; init; }
public DateTime CreatedAt { get; init; }
}
6. Van List Filter
public record VanFilter
{
public string? SearchKeyword { get; set; } // Global search across VIN, registration number, make, model
public VanStatus? Status { get; set; } // Filter by van status
public string? Make { get; set; } // Filter by manufacturer
public string? Model { get; set; } // Filter by model
public int? YearFrom { get; set; }
public int? YearTo { get; set; }
public bool? HasAssignedTechnician { get; set; } // Filter vans with/without technician
public Guid? TechnicianId { get; set; } // Filter by specific technician
public VanSortBy SortBy { get; set; } = VanSortBy.CreatedAt;
public SortDirection SortDirection { get; set; } = SortDirection.DESC;
public int RowsPerPage { get; set; } = 10;
public int PageNumber { get; set; } = 1;
}
7. Van Assignment History Response
public record VanAssignmentHistoryResponse
{
public Guid AssignmentId { get; init; }
public VanInfo Van { get; init; } = new();
public TechnicianInfo Technician { get; init; } = new();
public DateTime ActionAt { get; init; }
public string? ActionBy { get; init; }
public VanAssignmentAction Action { get; init; }
}
public record VanInfo
{
public Guid VanId { get; init; }
public string VanNumber { get; init; } = string.Empty;
public string? RegistrationNumber { get; init; }
public string? Make { get; init; }
public string? Model { get; init; }
public int? Year { get; init; }
}
public record TechnicianInfo
{
public Guid TechnicianId { get; init; }
public string TechnicianCode { get; init; } = string.Empty;
public string TechnicianName { get; init; } = string.Empty;
public string? Email { get; init; }
public string? PhoneNumber { get; init; }
}
8. Van Assignment History Filter
public record VanAssignmentHistoryFilter
{
public DateTime? FromDate { get; set; }
public DateTime? ToDate { get; set; }
public VanAssignmentAction? Action { get; set; } // Filter by action type
public VanAssignmentHistorySortBy SortBy { get; set; } = VanAssignmentHistorySortBy.ActionAt;
public SortDirection SortDirection { get; set; } = SortDirection.DESC;
public int RowsPerPage { get; set; } = 10;
public int PageNumber { get; set; } = 1;
}
9. Technician Assignment History Filter
public record TechnicianAssignmentHistoryFilter
{
public DateTime? FromDate { get; set; }
public DateTime? ToDate { get; set; }
public VanAssignmentAction? Action { get; set; } // Filter by action type
public TechnicianAssignmentHistorySortBy SortBy { get; set; } = TechnicianAssignmentHistorySortBy.ActionAt;
public SortDirection SortDirection { get; set; } = SortDirection.DESC;
public int RowsPerPage { get; set; } = 10;
public int PageNumber { get; set; } = 1;
}
Common Response Models
public record CommonResponse
{
public int Status { get; init; }
public string? Message { get; init; }
}
public record ServerPaginatedData<T>
{
public List<T> Data { get; set; } = [];
public int TotalNumber { get; set; }
public bool HasPreviousPage { get; set; }
public bool HasNextPage { get; set; }
public int TotalPages { get; set; }
public int PageNumber { get; set; }
public int RowsPerPage { get; set; }
}
API Endpoints Overview
Van Management Endpoints
| No | Endpoint | Method | Auth Required | Description | Request Model | Response Model |
|---|---|---|---|---|---|---|
| 1 | /van | POST | Yes (Admin) | Add new van with optional technician | VanRequest | CommonResponse |
| 2 | /van/{vanId} | PUT | Yes (Admin) | Update van details and assignment | VanRequest | CommonResponse |
| 3 | /van/{vanId}/technician-assign-unassign | POST | Yes (Admin) | Assign or unassign technician to van | VanAssignUnassignRequest | CommonResponse |
| 4 | /vans | GET | Yes (Admin) | Get all vans with pagination | VanFilter (Query) | ServerPaginatedData<VanDetails> |
| 5 | /van/{vanId} | GET | Yes (Admin) | Get single van details | None | VanDetails |
| 6 | /van/{vanId}/assignment-history | GET | Yes (Admin) | Get complete history of a van | VanAssignmentHistoryFilter | ServerPaginatedData<VanAssignmentHistoryResponse> |
Technician Endpoints (Updated)
| No | Endpoint | Method | Auth Required | Description | Request Model | Response Model |
|---|---|---|---|---|---|---|
| 7 | /technicians | GET | Yes (Admin) | Get all technicians with van info | TechnicianFilter | ServerPaginatedData<TechnicianDetails> |
| 8 | /technician/{technicianId}/assignment-history | GET | Yes (Admin/Technician) | Get technician's van assignment history | TechnicianAssignmentHistoryFilter | ServerPaginatedData<VanAssignmentHistoryResponse> |
HTTP Status Codes
| Status Code | Description | When Used |
|---|---|---|
| 200 | OK | Successful request |
| 201 | Created | Van created successfully |
| 400 | Bad Request | Invalid input, validation failure |
| 401 | Unauthorized | Invalid credentials, missing auth |
| 403 | Forbidden | Insufficient permissions |
| 404 | Not Found | Van/Technician not found |
| 409 | Conflict | VIN/Registration already exists, Technician already assigned |
| 500 | Internal Server Error | Server-side error |
API Request & Response Examples
1. Add Van API
Endpoint: POST /van
Request Body:
{
"registrationNumber": "DL-1AB-1234",
"vin": "1HGBH41JXMN109186",
"make": "Honda",
"model": "Accord",
"year": 2021,
"trim": "EX-L",
"bodyType": "Sedan",
"status": 1,
"technicianId": "a1b2c3d4-e5f6-7890-abcd-1234567890ab"
}
Success Response (201 Created):
{
"status": 201,
"message": "Van added successfully"
}
Error Response - VIN Already Exists (409 Conflict):
{
"status": 409,
"message": "Van with VIN '1HGBH41JXMN109186' already exists"
}
Error Response - Technician Already Assigned (409 Conflict):
{
"status": 409,
"message": "Technician is already assigned to another van"
}
2. Update Van API
Endpoint: PUT /van/{vanId}
Request Body:
{
"registrationNumber": "DL-1AB-1234",
"vin": "1HGBH41JXMN109186",
"make": "Honda",
"model": "Accord",
"year": 2021,
"trim": "EX-L",
"bodyType": "Sedan",
"status": 2,
"technicianId": "b2c3d4e5-f6a7-8901-bcde-2345678901bc"
}
Success Response (200 OK):
{
"status": 200,
"message": "Van updated successfully"
}
Error Response - Van Not Found (404 Not Found):
{
"status": 404,
"message": "Van not found"
}
3. Van Technician Assign/Unassign API
Endpoint: POST /van/{vanId}/technician-assign-unassign
Request Body (Assign Technician):
{
"technicianId": "a1b2c3d4-e5f6-7890-abcd-1234567890ab",
"action": 1
}
Request Body (Unassign Technician):
{
"technicianId": "a1b2c3d4-e5f6-7890-abcd-1234567890ab",
"action": 2
}
Success Response (200 OK):
{
"status": 200,
"message": "Technician assigned to van successfully"
}
Success Response - Unassign (200 OK):
{
"status": 200,
"message": "Technician unassigned from van successfully"
}
Error Response - Van Not Found (404 Not Found):
{
"status": 404,
"message": "Van not found"
}
Error Response - Technician Not Found (404 Not Found):
{
"status": 404,
"message": "Technician not found"
}
Error Response - Technician Already Assigned (409 Conflict):
{
"status": 409,
"message": "Technician is already assigned to another van"
}
Error Response - Van Already Assigned to Different Technician (409 Conflict):
{
"status": 409,
"message": "Van is already assigned to a different technician"
}
4. Get Van List API
Endpoint: GET /vans
Query Parameters:
?searchKeyword=honda&status=1&hasAssignedTechnician=true&rowsPerPage=10&pageNumber=1
Success Response (200 OK):
{
"data": [
{
"vanId": "f1e2d3c4-b5a6-7890-cdef-3456789012cd",
"registrationNumber": "DL-1AB-1234",
"vin": "1HGBH41JXMN109186",
"make": "Honda",
"model": "Accord",
"year": 2021,
"trim": "EX-L",
"bodyType": "Sedan",
"status": 1,
"statusDisplayName": "Active",
"assignedTechnician": {
"technicianId": "a1b2c3d4-e5f6-7890-abcd-1234567890ab",
"technicianCode": "TECH-001",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@rkauto.com",
"phoneNumber": "+1-555-0100",
"availabilityStatus": 1
},
"createdAt": "2025-01-01T10:00:00Z",
"updatedAt": "2025-01-01T15:30:00Z"
},
{
"vanId": "a2b3c4d5-e6f7-8901-defg-4567890123de",
"registrationNumber": "DL-2BC-5678",
"vin": "2HGBH41JXMN109187",
"make": "Honda",
"model": "CR-V",
"year": 2022,
"trim": "Touring",
"bodyType": "SUV",
"status": 1,
"statusDisplayName": "Active",
"assignedTechnician": {
"technicianId": "b2c3d4e5-f6a7-8901-bcde-2345678901bc",
"technicianCode": "TECH-002",
"firstName": "Jane",
"lastName": "Smith",
"email": "jane.smith@rkauto.com",
"phoneNumber": "+1-555-0101",
"availabilityStatus": 2
},
"createdAt": "2025-01-02T09:00:00Z",
"updatedAt": "2025-01-02T11:00:00Z"
}
],
"totalNumber": 25,
"hasPreviousPage": false,
"hasNextPage": true,
"totalPages": 3,
"pageNumber": 1,
"rowsPerPage": 10
}
5. Get Single Van Details API
Endpoint: GET /van/{vanId}
Success Response (200 OK):
{
"status": 200,
"message": "Van retrieved successfully",
"data": {
"vanId": "f1e2d3c4-b5a6-7890-cdef-3456789012cd",
"registrationNumber": "DL-1AB-1234",
"vin": "1HGBH41JXMN109186",
"make": "Honda",
"model": "Accord",
"year": 2021,
"trim": "EX-L",
"bodyType": "Sedan",
"status": 1,
"statusDisplayName": "Active",
"assignedTechnician": {
"technicianId": "a1b2c3d4-e5f6-7890-abcd-1234567890ab",
"technicianCode": "TECH-001",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@rkauto.com",
"phoneNumber": "+1-555-0100",
"availabilityStatus": 1
},
"createdAt": "2025-01-01T10:00:00Z",
"updatedAt": "2025-01-01T15:30:00Z"
}
}
Error Response - Van Not Found (404 Not Found):
{
"status": 404,
"message": "Van not found"
}
6. Get Van Assignment History API
Endpoint: GET /van/{vanId}/assignment-history
Query Parameters:
?fromDate=2024-01-01&toDate=2025-12-31&action=1&rowsPerPage=10&pageNumber=1
Success Response (200 OK):
{
"data": [
{
"assignmentId": "c1d2e3f4-a5b6-7890-efgh-5678901234ef",
"van": {
"vanId": "f1e2d3c4-b5a6-7890-cdef-3456789012cd",
"registrationNumber": "DL-1AB-1234",
"make": "Honda",
"model": "Accord",
"year": 2021
},
"technician": {
"technicianId": "a1b2c3d4-e5f6-7890-abcd-1234567890ab",
"technicianCode": "TECH-001",
"technicianName": "John Doe",
"email": "john.doe@rkauto.com",
"phoneNumber": "+1-555-0100"
},
"actionAt": "2025-01-01T10:00:00Z",
"actionBy": "admin@rkauto.com",
"action": 1
},
{
"assignmentId": "d2e3f4a5-b6c7-8901-fghi-6789012345fg",
"van": {
"vanId": "f1e2d3c4-b5a6-7890-cdef-3456789012cd",
"registrationNumber": "DL-1AB-1234",
"make": "Honda",
"model": "Accord",
"year": 2021
},
"technician": {
"technicianId": "a1b2c3d4-e5f6-7890-abcd-1234567890ab",
"technicianCode": "TECH-001",
"technicianName": "John Doe",
"email": "john.doe@rkauto.com",
"phoneNumber": "+1-555-0100"
},
"actionAt": "2025-01-08T09:00:00Z",
"actionBy": "admin@rkauto.com",
"action": 2
},
{
"assignmentId": "e3f4a5b6-c7d8-9012-ghij-7890123456gh",
"van": {
"vanId": "f1e2d3c4-b5a6-7890-cdef-3456789012cd",
"registrationNumber": "DL-1AB-1234",
"make": "Honda",
"model": "Accord",
"year": 2021
},
"technician": {
"technicianId": "b2c3d4e5-f6a7-8901-bcde-2345678901bc",
"technicianCode": "TECH-002",
"technicianName": "Jane Smith",
"email": "jane.smith@rkauto.com",
"phoneNumber": "+1-555-0101"
},
"actionAt": "2025-01-08T09:00:00Z",
"actionBy": "admin@rkauto.com",
"action": 1
},
{
"assignmentId": "f4a5b6c7-d8e9-0123-hijk-8901234567hi",
"van": {
"vanId": "f1e2d3c4-b5a6-7890-cdef-3456789012cd",
"registrationNumber": "DL-1AB-1234",
"make": "Honda",
"model": "Accord",
"year": 2021
},
"technician": {
"technicianId": "b2c3d4e5-f6a7-8901-bcde-2345678901bc",
"technicianCode": "TECH-002",
"technicianName": "Jane Smith",
"email": "jane.smith@rkauto.com",
"phoneNumber": "+1-555-0101"
},
"actionAt": "2025-01-20T17:00:00Z",
"actionBy": "admin@rkauto.com",
"action": 2
}
],
"totalNumber": 8,
"hasPreviousPage": false,
"hasNextPage": false,
"totalPages": 1,
"pageNumber": 1,
"rowsPerPage": 10
}
7. Get Technician List with Van Info API
Endpoint: GET /technicians
Query Parameters:
?searchKeyword=john&hasVanAssigned=true&rowsPerPage=10&pageNumber=1
Success Response (200 OK):
{
"data": [
{
"technicianId": "a1b2c3d4-e5f6-7890-abcd-1234567890ab",
"technicianCode": "TECH-001",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@rkauto.com",
"phoneNumber": "+1-555-0100",
"joiningDate": "2024-01-15T00:00:00Z",
"employeeType": "Full-Time",
"specialization": "Engine Specialist",
"skills": ["Engine Repair", "Diagnostics", "Oil Change"],
"availabilityStatus": 1,
"currentVan": {
"vanId": "f1e2d3c4-b5a6-7890-cdef-3456789012cd",
"registrationNumber": "DL-1AB-1234",
"make": "Honda",
"model": "Accord",
"year": 2021,
"status": 1
},
"createdAt": "2024-01-15T08:00:00Z",
"updatedAt": "2025-01-01T10:00:00Z"
},
{
"technicianId": "b2c3d4e5-f6a7-8901-bcde-2345678901bc",
"technicianCode": "TECH-002",
"firstName": "Jane",
"lastName": "Smith",
"email": "jane.smith@rkauto.com",
"phoneNumber": "+1-555-0101",
"joiningDate": "2024-02-01T00:00:00Z",
"employeeType": "Full-Time",
"specialization": "Transmission Expert",
"skills": ["Transmission Repair", "Brake Service", "Suspension"],
"availabilityStatus": 2,
"currentVan": {
"vanId": "a2b3c4d5-e6f7-8901-defg-4567890123de",
"registrationNumber": "DL-2BC-5678",
"make": "Honda",
"model": "CR-V",
"year": 2022,
"status": 1
},
"createdAt": "2024-02-01T08:00:00Z",
"updatedAt": "2025-01-02T09:00:00Z"
}
],
"totalNumber": 15,
"hasPreviousPage": false,
"hasNextPage": true,
"totalPages": 2,
"pageNumber": 1,
"rowsPerPage": 10
}
8. Get Technician Assignment History API
Endpoint: GET /technician/{technicianId}/assignment-history
Query Parameters:
?fromDate=2024-01-01&action=1&rowsPerPage=10&pageNumber=1
Success Response (200 OK):
{
"data": [
{
"assignmentId": "c1d2e3f4-a5b6-7890-efgh-5678901234ef",
"van": {
"vanId": "f1e2d3c4-b5a6-7890-cdef-3456789012cd",
"registrationNumber": "DL-1AB-1234",
"make": "Honda",
"model": "Accord",
"year": 2021
},
"technician": {
"technicianId": "a1b2c3d4-e5f6-7890-abcd-1234567890ab",
"technicianCode": "TECH-001",
"technicianName": "John Doe",
"email": "john.doe@rkauto.com",
"phoneNumber": "+1-555-0100"
},
"actionAt": "2025-01-01T10:00:00Z",
"actionBy": "admin@rkauto.com",
"action": 1
},
{
"assignmentId": "d2e3f4a5-b6c7-8901-fghi-6789012345fg",
"van": {
"vanId": "f1e2d3c4-b5a6-7890-cdef-3456789012cd",
"registrationNumber": "DL-1AB-1234",
"make": "Honda",
"model": "Accord",
"year": 2021
},
"technician": {
"technicianId": "a1b2c3d4-e5f6-7890-abcd-1234567890ab",
"technicianCode": "TECH-001",
"technicianName": "John Doe",
"email": "john.doe@rkauto.com",
"phoneNumber": "+1-555-0100"
},
"actionAt": "2025-01-08T09:00:00Z",
"actionBy": "admin@rkauto.com",
"action": 2
},
{
"assignmentId": "e3f4a5b6-c7d8-9012-ghij-7890123456gh",
"van": {
"vanId": "a2b3c4d5-e6f7-8901-defg-4567890123de",
"registrationNumber": "DL-2BC-5678",
"make": "Honda",
"model": "CR-V",
"year": 2022
},
"technician": {
"technicianId": "a1b2c3d4-e5f6-7890-abcd-1234567890ab",
"technicianCode": "TECH-001",
"technicianName": "John Doe",
"email": "john.doe@rkauto.com",
"phoneNumber": "+1-555-0100"
},
"actionAt": "2025-01-08T09:00:00Z",
"actionBy": "admin@rkauto.com",
"action": 1
}
],
"totalNumber": 3,
"hasPreviousPage": false,
"hasNextPage": false,
"totalPages": 1,
"pageNumber": 1,
"rowsPerPage": 10
}
Business Logic & Workflows
1. Add Van Workflow
1. Admin enters VIN (17 characters)
2. System validates VIN format
3. System calls NHTSA VIN Decoder API
4. Auto-populate: Make, Model, Year, Body Type, Trim
5. Admin reviews and edits if needed
6. Admin enters Registration Number
7. Admin optionally selects available technician
8. System validates:
- VIN uniqueness
- Registration number uniqueness
- Technician availability (not already assigned to another van)
9. Create van record in vanmaster table
10. If technician assigned:
- Update technicianmaster.currentvanid
- Create entry in vanassignmenthistory
11. Return van details with assignment info
2. Update Van Workflow
1. Admin updates van details (make, model, status, etc.)
2. Admin changes technician assignment:
Case A: Assign new technician to unassigned van
Case B: Reassign van from one technician to another
Case C: Unassign van from current technician
3. System validates:
- New technician (if any) is not already assigned to another van
- Van exists and is editable
4. For Case B or Case C:
- Update previous assignment: set unassignedat = NOW()
- Update previous technician: set currentvanid = NULL
5. For Case A or Case B:
- Update vanmaster.currenttechnicianid
- Update new technician: set currentvanid
- Create new entry in van_assignment_history
6. Return updated van details
3. Disable Technician Cascade Logic
When technician status changes to Disabled:
1. Check if technician has assigned van (currentvanid IS NOT NULL)
2. If yes:
- Get vanid from technician record
- Update vanassignmenthistory: set unassignedat = NOW()
- Update technicianmaster: set currentvanid = NULL
3. Update technician status to Disabled
4. Commit transaction
Development Tasks & Estimates
Phase 1: Core Van Management (3 days)
| Task | Estimated Hours | Priority | Optimization Strategy |
|---|---|---|---|
| Database migration script | 3h | High | Use existing migration templates |
| Add Van API | 6h | High | Leverage existing CRUD patterns |
| Update Van API | 4h | High | Reuse Add Van validation logic |
| Get Van List API | 5h | High | Apply existing pagination patterns |
| Get Single Van Details API | 2h | Medium | Simple query, minimal logic |
| VIN Decoder Integration | 4h | High | Basic HTTP client wrapper |
Subtotal: 24 hours
Phase 2: Assignment History (2 days)
| Task | Estimated Hours | Priority | Optimization Strategy |
|---|---|---|---|
| Van Assignment History API | 4h | Medium | Reuse list API patterns |
| Technician Assignment History API | 4h | Medium | Clone van history logic |
| Assignment/Unassignment Logic | 6h | High | Core business logic - minimal viable |
| Cascade Unassignment on Disable | 3h | High | Database trigger or event handler |
Subtotal: 17 hours
Phase 3: Technician Updates (1 day)
| Task | Estimated Hours | Priority | Optimization Strategy |
|---|---|---|---|
| Update Technician List API (add van) | 3h | High | Add join query to existing API |
| Add availability status field | 2h | Medium | Single column migration + model |
| Update technician models | 1h | Medium | Straightforward model updates |
Subtotal: 6 hours
Phase 4: Testing & Documentation (2.5 days)
| Task | Estimated Hours | Priority | Optimization Strategy |
|---|---|---|---|
| Unit Tests | 8h | High | Focus on critical paths only |
| Integration Tests | 6h | High | Test key workflows (add/assign/history) |
| API Documentation (Swagger) | 2h | Medium | Auto-generate from attributes |
| Performance Testing | 4h | Medium | Basic load testing on list endpoints |
Subtotal: 20 hours
Total Estimated Time: 2 weeks (67 hours)
Time Savings: 32 hours
Optimization Approach
- Reuse Existing Patterns: Leverage established CRUD, pagination, and filtering patterns
- Parallel Development: Database migrations and API endpoints can be developed concurrently
- Auto-Generation: Use Swagger attributes for automatic API documentation
- Focused Testing: Prioritize critical business logic over exhaustive coverage
- Template Utilization: Apply proven migration and boilerplate templates
Notes
Key Implementation Considerations
-
Assignment Tracking Design:
- Assignment relationship is maintained via
technicianmaster.currentvanidonly - To get assigned technician for a van:
SELECT * FROM technicianmaster WHERE currentvanid = @vanid - To get assigned van for a technician: Use
currentvaniddirectly from technician record - This unidirectional approach prevents data inconsistency issues
- Assignment relationship is maintained via
-
VIN Decoding Integration:
- Use NHTSA VIN Decoder API:
https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVin/{VIN}?format=json - Cache decoded results to reduce external API calls
- Handle API failures gracefully with manual entry fallback
- Validate VIN format before making external calls
- Use NHTSA VIN Decoder API:
-
Assignment Transaction Logic:
BEGIN TRANSACTION;
-- Unassign previous technician (if any)
UPDATE vanassignmenthistory
SET unassignedat = NOW(), unassignedby = @admin_user
WHERE vanid = @vanid AND unassignedat IS NULL;
UPDATE technicianmaster
SET currentvanid = NULL
WHERE currentvanid = @vanid;
-- Assign new technician
UPDATE technicianmaster
SET currentvanid = @vanid
WHERE technicianid = @new_technician_id;
UPDATE vanmaster
SET updatedat = NOW()
WHERE vanid = @vanid;
INSERT INTO vanassignmenthistory (vanid, technicianid, assignedby)
VALUES (@vanid, @new_technician_id, @admin_user);
COMMIT; -
Validation Rules:
- VIN must be exactly 17 alphanumeric characters (no I, O, Q)
- Registration number format varies by state/country (configurable regex)
- Technician can only be assigned to one van at a time
- Van can only be assigned to one technician at a time
- Cannot delete van with active assignments (must unassign first)
-
Performance Optimization:
- Index on frequently queried columns (status, currentvanid in technicianmaster)
- Use pagination for all list endpoints
- Implement caching for van list queries
- Consider materialized views for complex history queries
-
Security Considerations:
- Only Admin role can modify van data
- Technicians can only view their own assignment history
- Log all assignment/unassignment operations
- Validate user permissions before any write operation
-
Future Enhancements:
- GPS tracking integration for real-time van location
- Maintenance schedule tracking
- Fuel consumption and mileage tracking
- Van availability calendar
- Automated assignment based on technician location
- Mobile app notifications for assignment changes
- Van inspection checklist integration
- Insurance and registration expiry alerts