Skip to main content
Version: RK Auto

First Available Service Request Assignment (Ring System)

Author(s)

  • Sanket Mal
  • Ayan Ghosh
  • Ribhu Gautam

Last Updated Date

2026-02-05


SRS References


Version History

VersionDateChangesAuthor
1.02026-02-05Initial MVP specification with SignalR-based ring systemDevelopment Team
1.1TBDFCM integration for background notificationsTBD

Feature Overview

Objective:
Implement an intelligent technician assignment system for "First Available" service requests using a progressive ring-based notification approach. When a customer requests immediate service, the system will notify nearby technicians in expanding geographic radiuses, calculate accurate ETAs based on queue positions, and manage pending requests when no technician accepts within the defined timeframe.

Scope:
This feature covers:

  • Initiating ring notifications to technicians based on distance radiuses
  • Managing technician responses (accept/reject) via SignalR
  • Queue management with maximum limits per technician
  • ETA calculation based on pending queue and service durations
  • Fallback to pending request queue when no assignment succeeds
  • Ring event tracking and audit logging
  • Real-time customer notifications about assignment status

Out of scope for MVP:

  • FCM background notifications (scheduled for post-MVP)
  • Admin override capabilities (assign/unassign/reorder queue) - deferred to post-MVP
  • Predictive/AI-based technician matching
  • Geographic optimization of queue ordering

Dependencies:

  • Existing SignalR hub infrastructure RealTimeHub.cs (VanTrackerService/Hubs/RealTimeHub.cs)
  • Existing REST APIs ServiceManagementController.cs (VanTrackerService/Controllers/ServiceManagementController.cs)
  • MapBox API for distance and ETA calculations
  • Redis/Valkey for caching technician availability status
  • PostgreSQL database (migrations for new tables)
  • Existing service request and technician management systems

Requirements

Functional Requirements

  1. Ring Notification System

    • Ring technicians in expanding geographic radiuses: 0-20 miles (15 sec) → 20-40 miles (15 sec) → 40-60 miles (15 sec) → 60-80 miles (15 sec)
    • Only ring technicians with status: Available, EnRoute, or Servicing
    • Only ring technicians whose queue count is < maximum queue limit (5 services)
    • Only ring technicians with active SignalR connections (online)
    • Each technician receives ring notification via SignalR with request details
  2. Technician Response Handling

    • Technician can accept, reject, or ignore ring notification within 15-second timeout (first ring)
    • Acceptance triggers atomic assignment (prevent double-assignment with optimistic locking)
    • Timeout (no response) after ring period ends automatically.
  3. Queue Management

    • Each technician can have maximum 5 pending service requests in queue
    • Block ring notifications to technicians at queue limit
    • FIFO ordering within each technician's queue
    • Track queue position and display to customers
    • Allow customers to view queue status and estimated arrival time
  4. ETA Calculation

    • Calculate ETA as sum of: service durations for queued requests + travel times between locations + 15-minute buffer per service
    • Provide precise ETA window: "Arriving 3:15-4:15 PM" (max 60-minute window)
    • Update ETA in real-time as technician progresses through queue
    • Use estimatedduration from service master for service time estimates
    • Use MapBox API for travel time calculations between locations
  5. Pending Request Fallback

    • If no technician accepts across all 4 ring phases (80 miles), mark request as Pending
    • Notify customer: "Your request is confirmed. We're finding the best available technician. You'll receive an update within 15 minutes."
    • Display request to all technicians on "Available Requests" section with distance filter (default 60 miles)
    • Technician can manually accept pending request at any time
  6. Ring Event Tracking

    • Log all ring events: which technician received ring, response time, response type (accept/reject/timeout)
    • Maintain audit trail for debugging and analytics
    • Track notification delivery status
  7. Customer Notifications

    • Notify customer immediately when request created: "Your request received. Finding technician..."
    • Notify when technician accepted: "Great news! Technician [Name] accepted your request. ETA: 3:15-4:15 PM. You're #2 in queue."
    • Notify of queue position changes when customer's position improves
    • Show real-time progress on technician's queue status
    • Allow customer to cancel request anytime until technician starts traveling

Non-Functional Requirements

  1. Performance

    • Ring notification delivery within 2 seconds of request creation
    • Accept/reject response handling within 100ms
    • Queue update notifications within 1 second
  2. Reliability

    • Handle concurrent ring notifications without race conditions (optimistic locking)
    • Graceful handling of technician disconnections during ring period
    • Auto-reconnection and missed notification recovery
    • No data loss on queue updates or admin overrides
  3. Scalability

    • Support up to 100+ concurrent requests in ring process
    • Support 50+ technicians receiving ring notifications simultaneously
    • Efficient database queries using proper indexing
  4. Availability

    • 99.5% uptime for ring assignment system
    • Graceful degradation if SignalR connection fails (fallback to polling)
    • Automatic retry logic for failed operations
  5. Security

    • Only authenticated technicians and customers can access their respective requests
    • Admin override actions require admin authentication and authorization
    • Audit trail cannot be modified or deleted
    • Sensitive customer location data encrypted in transit and at rest

Design Specifications

UI/UX Design

Customer App - Service Status View:

┌──────────────────────────────────────┐
│ Your Service Request │
│ Status: Assigned ✅ │
│ │
│ 🚗 Technician Assigned │
│ Name: John Smith (⭐⭐⭐⭐⭐) │
│ Van: RK-Auto Van #12 │
│ [Call] [Message] [Live Tracking] │
│ │
│ 📊 Queue Status │
│ You're #2 in queue │
│ ETA: 3:15-3:45 PM │
│ [Live Progress] │
└──────────────────────────────────────┘

Data Models

Database Schema Updates:

-- 1. Modify servicerequests table
ALTER TABLE servicerequests
ADD COLUMN ringstarttime TIMESTAMP,
ADD COLUMN ringendtime TIMESTAMP,
ADD COLUMN maxringradius INT DEFAULT 80;

-- 2. Ring event log table
CREATE TABLE technicianringlog (
ringlogid UUID PRIMARY KEY DEFAULT gen_random_uuid(),
requestid UUID NOT NULL REFERENCES servicerequests(requestid),
technicianid UUID NOT NULL REFERENCES technicianmaster(technicianid),
ringminradius INT NOT NULL, -- Minimum radius of ring phase
ringmaxradius INT NOT NULL, -- Maximum radius of ring phase
ringstartedat TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
ringendedat TIMESTAMP,
createdat TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updatedat TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE(requestid, technicianid)
);

CREATE INDEX idx_ringlog_request ON technicianringlog(requestid, ringstartedat DESC);
CREATE INDEX idx_ringlog_technician ON technicianringlog(technicianid, ringstartedat DESC);
CREATE INDEX idx_ringlog_status ON technicianringlog(requestid, response);

C# Models

Enums

// Existing enum (already in codebase)
public enum RequestStatus
{
Pending = 1,
Accepted,
InProgress,
Completed,
Canceled,
Ringing
}

Existing Models (Reuse - No Changes Needed)

// Location data component (used in broadcasts)
public record CustomerLocation
{
public decimal Latitude { get; set; }
public decimal Longitude { get; set; }
}
public record TechnicianLocation : CustomerLocation
{
public double Heading { get; set; }
public double Speed { get; set; }
public double Accuracy { get; set; }
public DateTime Time { get; set; }
}
// Technician sends location update (always, whether serving request or available)
public class LocationDataWithRequestId:TechnicianLocation
{
public Guid? RequestId { get; set; } // Nullable - null when available/no active request
}
public record TechnicianBasicInfo
{
public Guid TechnicianId { get; init; }
public string TechnicianCode { get; init; } = string.Empty;
public TechnicianAvailabilityStatus? AvailabilityStatus { get; init; }
public string FirstName { get; init; } = string.Empty;
public string LastName { get; init; } = string.Empty;
public string? Email { get; init; }
public string? PhoneNumber { get; init; }
}
public record CustomerBasicInfo
{
public Guid UserId { get; init; }

// Customer identification
public Guid CustomerId { get; init; }
public string CustomerCode { get; init; } = string.Empty;

// User information
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 Gender? Gender { get; init; }
}
public record VanBasicInfo
{
public Guid VanId { get; init; }
public string VanNumber { get; init; } = string.Empty;
public string RegistrationNumber { get; init; } = string.Empty;
public string VIN { get; init; } = string.Empty;

}

public record ServiceRequestBasicInfo
{
public Guid RequestId { get; init; }
public required string RequestNumber { get; set;}
public Guid CustomerId { get; init; }
public Guid? TechnicianId { get; init; }
public ServiceStatus ServiceStatus { get; init; }
public decimal Latitude { get; init;}
public decimal Longitude {get; init;}
public DateTime RequestedAt {get; init;}
}

public record RingNotificationModel
{
public ServiceRequestBasicInfo ServiceRequestInfo { get; init; }
public CustomerBasicInfo CustomerInfo { get; init; }
public CustomerLocation CustomerLocation { get; init; }
public int MaxDistanceInMiles { get; init; }
public int RingTimeoutSeconds { get; init; } // Always 15 for MVP
public DateTime RingStartedAt { get; init; }
}

API Interfaces

Existing REST APIs (Reuse/Enhance)

EndpointMethodStatusEnhancement Needed
/service-management/service-requestPOST✅ ExistsAdd ring initiation logic for OnDemand (First Available) requests
/service-management/service-request/{requestId}GET✅ ExistsEnhance to include ETA and queue position in response

New SignalR Events (RealTimeHub.cs)

EventDirectionPayloadDescription
ring_notification_receivedServer→TechRingNotificationModelRing sent to technician with countdown timer
request_acceptedServer→specific Tech + specific customerRequestAssignedResponseBroadcast: Request taken by another technician
request_status_changedServer→(Customer + technician who received ring call previously + all admins)ServiceRequestBasicInfoCustomer notification of assignment

Workflow

Complete Ring Assignment Flow:

[CUSTOMER CREATES REQUEST via POST /service-request]

System: status = 'Ringing', ringstarttime = NOW()

[RING PHASE 1: 0-20 MILES, 15 SECONDS]
Query: Technicians within 20mi, queue < 5, online (SignalR connected)
Send: ReceiveRingNotification via SignalR (RealTimeHub)

IF Accept (via PUT /service-request/{id}/1):
- Assign technician + update status
- Send RequestAccepted to the specific customer and the specific technician who accepted the request
- Send RequestStatusChanged to other ringed techs (If ringing then only those technicians who received ring call and if ringing completed then to all the technician)
- EXIT ring process
IF Timeout: Continue to next phase

[RING PHASE 2-4: 20-40, 40-60, 60-80 MILES - 15 sec each]
(Same as Phase 1)

IF Still No Accept after all phases:
status = 'Pending'
ringendtime = NOW()
Request visible to ALL technicians via GET /service-requests
Send RequestStatusChanged to customer (fallback message)

[TECHNICIAN MANUAL ACCEPT FROM PENDING]
Technician uses PUT /service-request/{id}/1 to accept
Same flow as ring accept

[ETA CALCULATION]
= Σ(service durations) + Σ(travel times) + 30min buffer
Result: "3:15-4:15 PM" (60-min window)
Send QueueUpdated to technician
Send QueuePositionChanged to customer

State Transitions:

Ringing → Accepted (technician accepts during ring)
Ringing → Pending (no acceptance after all ring phases)
Pending → Accepted (technician accepts from pending list)
Accepted → InProgress (technician starts work)
InProgress → Completed (technician completes work)
Any → Canceled (customer cancels)

Development Tasks & Estimates

Development Timeline: 7 Days (2 Backend Developers)

Backend Tasks

NoTask NameEst. (Hrs)DependenciesDeliverable
1DB Migration: Add columns to servicerequests table0.5-ringstarttime, ringendtime, maxringradius columns
2DB Migration: Create technicianringlog table with indexes1.5Task 1Table + indexes for request/technician lookup
3Create RingNotificationModel and related DTOs2-Models in Models/Ring/ folder
4Implement GetEligibleTechnicians for ringing5Query techs with Available/EnRoute/Servicing status, queue < 5
5Implement StartRingProcess method4Task 4Initiate ring for a service request, return ring ID
6Implement ring phase progression logic (4 phases, 15 sec each)4Task 5 & Task 6Timer-based transitions: 0-20, 20-40, 40-60, 60-80 miles
7Implement ring timeout and phase transition handling1.5Mark timeout, move to next phase or set Pending
8Implement ring event logging to technicianringlog1.5Insert/update ring log entries with timestamps
9Implement queue limit validation2Task 10Count accepted requests, enforce max 5 limit
10Implement GetCustomerQueuePosition (FIFO ordering)4Calculate position in technician's queue
11Implement CalculateETA (service duration + travel + buffer)7Task 13, 14Sum service durations + MapBox travel times + 30-min buffer
12Cache technician locations in Redis for ETA calc2Store/retrieve last known location
13Add SignalR event: ring_notification_received3Task 8Hub method to send ring to technician group
14Add SignalR event: request_accepted3Hub method to notify tech + customer of acceptance
15Add SignalR event: request_status_changed2Hub method to notify status transitions (Ringing→Pending, etc.)
16Enhance POST /service-request for ring initiation3Trigger ring process when requestType = OnDemand
17Enhance PUT /service-request/{id}/accept with optimistic lock5Prevent double-assignment, validate queue, assign technician
18Enhance PUT /service-request/{id}/reject with ring logging1Log rejection reason in technicianringlog
19Enhance GET /service-request/{id} with ETA and queue position2Include ETAWindow and QueuePosition in response
TOTAL54 hrs

Deferred to Post-MVP:

  • Admin override (assign/unassign/reorder)
  • Admin action audit logging
  • FCM background notifications

Testing & Quality Assurance

Unit Tests

RingAssignmentService Tests:

  • Test_GetEligibleTechnicians_FiltersCorrectly() - Distance, queue, status filters
  • Test_CalculateDistance_ReturnsAccurateResults() - MapBox distance accuracy
  • Test_RingTimeout_TransitionsToNextPhase() - Phase progression
  • Test_RingTimeout_MarksPendingAfterAllPhases() - Fallback to pending

TechnicianQueueService Tests:

  • Test_AcceptRequest_OptimisticLocking() - Prevent double-assignment
  • Test_AcceptRequest_QueueLimitEnforced() - Reject if queue ≥ 5
  • Test_CalculateQueuePosition_FIFO() - Correct ordering
  • Test_RejectRequest_LogsReason() - Rejection tracking

ETACalculationService Tests:

  • Test_CalculateETA_SumServiceDurations() - Service time summation
  • Test_CalculateETA_IncludeTravelTime() - MapBox travel time
  • Test_CalculateETA_AddBuffer() - 15-minute buffer
  • Test_CalculateETA_Window45Minutes() - ETA precision
  • Test_UpdateETAInRealtime() - Dynamic updates

AdminRequestActionService Tests:

  • Test_ManualAssignment_UpdatesQueueCorrectly()
  • Test_UnassignRequest_ReturnsToPending()
  • Test_ReorderQueue_ValidatesOrder()
  • Test_AdminAction_LogsAuditTrail()

Integration Tests

  1. Complete Ring Flow

    • Setup: Customer request, 5+ technicians at various distances
    • Verify: Ring phases execute, correct techs notified, proper state transition
  2. Technician Acceptance During Ring

    • Setup: Request in ring phase 2, tech queue < 5
    • Verify: Assignment succeeds, others notified, ETA calculated, race condition prevented
  3. No-Acceptance Fallback

    • Setup: All technicians >75 miles away
    • Verify: Request → PendingAssignment, visible to all, customer notified, admin alerted
  4. Admin Manual Assignment

    • Setup: Pending request, technician available
    • Verify: Assignment succeeds, action logged, both parties notified, audit trail complete
  5. ETA Real-time Updates

    • Setup: Tech with 3 requests in queue
    • Verify: ETA updates when service completes, customers notified
  6. Queue Limit Enforcement

    • Setup: Technician with 5 requests, new request created
    • Verify: Technician not eligible for ring, cannot manually accept
  7. SignalR Disconnection Recovery

    • Setup: Technician receives ring, disconnects
    • Verify: Timeout detected, auto-marked, tech can reconnect and recover missed notifications

Acceptance Criteria

Ring Assignment:

  • ✅ Ring notifications sent within 2 seconds
  • ✅ Ring timeouts enforced (30/20/15/15 seconds)
  • ✅ No double-assignment (race condition prevented)
  • ✅ Rejection tracked with reason
  • ✅ All 4 phases execute properly

Queue Management:

  • ✅ Queue limit enforced (≤ 5)
  • ✅ Queue position visible to customers
  • ✅ FIFO ordering maintained
  • ✅ Real-time queue updates

ETA:

  • ✅ Calculated within 1 second
  • ✅ Includes service duration + travel + buffer
  • ✅ Window ≤ 45 minutes
  • ✅ Updates dynamically as queue progresses
  • ✅ Shown to customer within 5 seconds

Admin Override:

  • ✅ Can manually assign pending requests
  • ✅ Can unassign requests
  • ✅ Can reorder queue
  • ✅ All actions audited with oldstate/newstate
  • ✅ Both parties notified

Notifications:

  • ✅ Customer notified when created/assigned/position changes
  • ✅ Technician notified of rings/queue changes
  • ✅ Admin notified when pending queue grows

Performance:

  • ✅ Ring delivery: < 2 sec
  • ✅ Accept/reject: < 100ms
  • ✅ ETA calculation: < 1 sec
  • ✅ Queue updates: < 1 sec
  • ✅ Database queries: < 200ms

Testing Tools

  • xUnit.NET - Unit testing
  • Moq - Mocking dependencies
  • testcontainers-dotnet - Docker PostgreSQL for integration tests
  • Postman - API endpoint testing
  • Fiddler - SignalR message inspection
  • JetBrains Rider Debugger - Debugging

Deployment Considerations

Configuration Changes

Environment Variables (Secrets):

  • MAPBOX_API_KEY - Already configured
  • REDIS_CONNECTION_STRING - Ensure Redis running
  • SIGNALR_HUB_URL - Configure for your environment

Rollout Plan

Phase 1: Development & Testing (Days 1-7)

  • Full integration testing with test data
  • Load testing with concurrent requests
  • Client review and approval

Phase 2: Staging (Day 8)

  • Deploy to staging environment
  • End-to-end tests with staging techs
  • Verify SignalR connectivity
  • Performance baseline measurement

Phase 3: Production (Day 9-10)

  • Create database backup before migration
  • Run migration during low-traffic window (2 AM)
  • Deploy backend services (rolling deployment)
  • Verify APIs operational
  • Keep feature flag RingAssignment.Enabled = false initially

Phase 4: Gradual Rollout (Days 11-14)

  • Day 1: Enable for 10% of technicians (test group)
  • Day 2: Enable for 25%
  • Day 3: Enable for 50%
  • Day 4: Enable for 100%

Rollback Plan:

  • Set RingAssignment.Enabled = false in config
  • All new requests revert to manual assignment
  • No data loss (all ring logs preserved)
  • Rollback time: < 5 minutes

Health Checks:

  • /health/ring-assignment endpoint returns all system statuses
  • Monitor: SignalR, Redis, MapBox, Database connectivity

Monitoring & Alerts:

  • Ring failure rate > 5% → Alert
  • Pending queue size > 10 → Alert
  • SignalR failures > 2% → Alert
  • MapBox latency > 5 sec → Fallback to cache

Risks & Mitigations

RiskImpactLikelihoodMitigation
Race Condition: Multiple Simultaneous AcceptsHighHighOptimistic locking with version check; clear error to slower technician
SignalR Disconnect During RingHighMediumAuto-reconnection; mark as timeout; missed notification recovery
MapBox API Unavailable/SlowMediumLowFallback estimation (25 mph avg); cache results; 10-sec timeout
Technician Queue All at LimitHighLowEmergency service priority; admin override; alert client
ETA Calculation InaccuracyMediumMediumUse historical completion data; customer feedback loop
Database Performance DegradationHighMediumAdd indexes; implement connection pooling; monitor queries
Pending Queue Grows IndefinitelyHighLowAuto-retry when tech available; customer cancellation after 4 hours; admin daily review
Notification Delivery DelayMediumLowBackground worker pool; optimize queries; caching
Technician Offline Status Not UpdatedMediumMediumHeartbeat every 60 sec; manual reconnection trigger
Redis Cache InconsistencyMediumLowAtomic Redis operations; validation checks; regenerate from DB
Memory Leak in Ring ProcessHighLowProper async/await; resource disposal; memory monitoring
Admin Invalid Queue ReorderMediumLowValidation for all operations; transaction-based consistency
SignalR Hub Resource ExhaustionHighLowConnection limits (1 max per tech); cleanup abandoned connections

Review & Approval

  • Reviewer:

    • Product Manager / Client
    • Tech Lead / Architecture Review
    • QA Lead / Testing Strategy Review
  • Approval Date:

    • Pending client/product manager approval
    • Pending tech lead architecture review
    • Pending QA test strategy approval

Implementation Notes

Key Design Decisions

  1. SignalR-Only for MVP (FCM to follow in Phase 2)

    • Faster initial delivery (7-day timeline)
    • Requires technicians to keep app open during shifts
    • Clear path to FCM addition without major refactoring
  2. Progressive Ring with Expanding Radiuses

    • Prioritizes nearby technicians (faster service)
    • Automatic fallback when no local technicians available
    • Guarantees completion within 65 seconds
  3. FIFO Queue Ordering

    • Simple, fair, predictable for MVP
    • Customer satisfaction (no one jumps ahead)
    • Future: Can evolve to load-based or geographic optimization
  4. Optimistic Locking for Acceptance

    • Prevents double-assignment without distributed locks
    • Fast response time
    • Clear error message to slower technician
  5. Real-time ETA Updates

    • Calculated at assignment time
    • Updated as queue progresses
    • 45-minute max window for realistic expectations

Future Enhancements (Post-MVP)

  • FCM Background Notifications - Remove app-open requirement
  • Predictive Queue Matching - Assign based on remaining queue time
  • Geographic Optimization - Minimize total travel time
  • Service Type Specialization - Ring only certified technicians
  • Machine Learning - Predict acceptance rates
  • SMS/Email Fallback - Notify when push fails

Success Metrics

  • Ring acceptance rate: 80%+ on ring 1, 95%+ by ring 3
  • Ring-to-assignment time: < 60 seconds (goal: 30 sec)
  • Customer ETA satisfaction: > 85% within 30-min window
  • Average pending queue size: < 2 requests, max < 5
  • System uptime: 99.5% availability
  • Technician queue overload complaints: < 5%

Support & Maintenance

  • Daily monitoring of ring assignment metrics
  • Weekly client review meeting
  • Rapid hotfix deployment (< 4 hours SLA for critical bugs)
  • Monthly performance optimization
  • Quarterly feature planning