Skip to main content
Version: RK Auto

Targeted Notifications

Author(s)

  • Amarnath Garai

Last Updated Date

2026-03-23


Version History

VersionDateChangesAuthor
1.02026-03-18Initial documentation for targeted notificationsAmarnath Garai
1.12026-03-23Notification History Response Model Modify (Sender Details Added)Amarnath Garai
1.22026-03-26Scheduled Notification Support added Modified Request and Response ModelsAmarnath Garai

Feature Overview

Objective:
Send notifications to selected users (technicians/customers) based on search suggestions and chosen user IDs, and keep an audit trail of all targeted notifications sent by admins.

Scope:

  • Search and list target users
  • Send notifications to selected users

Dependencies:

  • Notification delivery (Push/Email)
  • User directory (Technicians/Customers)

Design Specifications

PostgreSQL Script:

CREATE TABLE targetednotifications (
notificationid UUID PRIMARY KEY,
senderid UUID NOT NULL,
title TEXT NOT NULL,
body TEXT NOT NULL,
imageurl TEXT NULL,
categoey VARCHAR(50),
ispush BOOLEAN NOT NULL,
isemail BOOLEAN NOT NULL,
isscheduled BOOLEAN NOT NULL DEFAULT FALSE,
scheduledat TIMESTAMPTZ NULL,
status TEXT NOT NULL,
createdat TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE targetednotificationrecipients (
id UUID PRIMARY KEY,
notificationid UUID NOT NULL REFERENCES targetednotifications(notificationid) ON DELETE CASCADE,
recipientid UUID NOT NULL,
status TEXT NOT NULL,
sentat TIMESTAMPTZ NULL,
error TEXT NULL
);




Data Models


public enum NotificationScheduledStatus{
Pending = 1,
Sent
}

public enum NotificationStatus{
Pending = 1,
Sent,
Failed
}

public enum UserType
{
Admin = 1,
Technician,
Customer
}

public record UserSuggestionsFilter
{
public string? SearchKeyword { get; init; }
public UserType? User { get; init; } // User can be only Customer or Technician , if User is not given then it will be consider as both
}

public record UserSuggestionsResponse
{
public List<TechnicianBasicInfo>? Technicians { get; init; }
public List<CustomerBasicInfo>? Customers { get; init; }
}

public record SendTargetedNotificationRequest
{
public required string Title { get; init; }
public required string Body { get; init; }
public string? ImageUrl { get; init; }
public bool SendPush { get; init; } = true; // default true
public bool SendEmail { get; init; } = true; // default true
public NotificationCategory Category { get; init; }
public bool IsScheduled { get; init; } = false;
public DateTime? ScheduledAt { get; init; } // ScheduledAt is required when isScheduled is true
public required IEnumerable<Guid> UserIds { get; init; }
}


public record TargetedNotificationHistoryFilter
{
public Guid? SenderId { get; init; }
public Guid? UserId { get; init; }
public DateTime? DateFrom { get; init; }
public DateTime? DateTo { get; init; }
public bool? IsPush { get; init; }
public bool? IsEmail { get; init; }
public bool? IsScheduled { get; init; }
public NotificationScheduledStatus? Status { get; init; }
public int PageNumber { get; init; } = 1;
public int RowsPerPage { get; init; } = 10;
}

public record TargetedNotificationHistoryItem
{
public Guid NotificationId { get; init; }
public Guid SenderId { get; init; }
public required UserBasicInfo SenderDetails { get; init; }
public string Title { get; init; } = string.Empty;
public string Body { get; init; } = string.Empty;
public string? ImageUrl { get; init; }
public bool IsPush { get; init; }
public bool IsEmail { get; init; }
public NotificationScheduledStatus Status { get; init; }
public bool IsScheduled { get; init; }
public DateTime? ScheduledAt { get; init; }
public DateTime CreatedAt { get; init; }
public required List<NotificationRecipientDetails> Users { get; init; }
}

public record NotificationRecipientDetails : UserBasicInfo
{
public DateTime? SentAt { get; init; }
public NotificationStatus NotificationStatus { get; init; }
}

public class 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; }
}

public record TechnicianBasicInfo
{
public Guid? UserId { get; set; }
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 string? ProfileImageUrl { get; set; }
}

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 string? ProfileImageUrl { get; set; }
public Gender? Gender { get; init; }
}

public record UserBasicInfo
{
public Guid UserId { get; init; }
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 UserType UserType { get; init; }
public Guid EntityId { get; init; }
public string? ProfileImageUrl { get; init; }
}

API Endpoints

Summary of all endpoints:

MethodEndpointPurposeRequestResponse
GET/user-suggestionsGet Users Suggestions for sending targeted notificationsUserSuggestionsFilterUserSuggestionsResponse
POST/notification/sendSend Notifications To Targeted UsersSendTargetedNotificationRequestCommonResponse
GET/targeted-notificationsGet Targeted Notifications HistoryTargetedNotificationHistoryFilterServerPaginatedData<TargetedNotificationHistoryItem>

1. Get Users Suggestions for Targeted Notifications

Endpoint: GET /user-suggestions
Auth: Required (Bearer Token)

Request (Query Parameters):

{
"searchKeyword": "john",
"user": 2
}

Note: user is a UserType enum (Admin = 1, Technician = 2, Customer = 3). For this endpoint, use only Technician or Customer. If user is omitted, both are considered.

Success Response (UserSuggestionsResponse):

{
"technicians": [
{
"userId": "9a0d3f9a-1b7f-4d5c-9a1c-8b7b3a6f1f11",
"technicianId": "0b7a2d6b-3a19-4d2c-9c3a-0b2b9c2f4a10",
"technicianCode": "TECH-1023",
"availabilityStatus": 1,
"firstName": "John",
"lastName": "Carter",
"email": "john.carter@example.com",
"phoneNumber": "+1-555-0100",
"profileImageUrl": "https://cdn.example.com/profiles/tech-1023.png"
}
],
"customers": [
{
"userId": "e3c9a5ab-2f3a-4f91-9d4d-3c8f8b2a7b21",
"customerId": "7c2a1d4b-8e61-4c3f-9d13-2a7b9d9c1f55",
"customerCode": "CUST-4501",
"email": "john.wilson@example.com",
"firstName": "John",
"lastName": "Wilson",
"phoneNumber": "+1-555-0199",
"profileImageUrl": "https://cdn.example.com/profiles/cust-4501.png",
"gender": 1
}
]
}

Error Responses:

  • -20009: Invalid input parameters
  • -20012: Unauthorized

2. Send Notifications To Targeted Users

Endpoint: POST /notification/send
Auth: Required (Bearer Token)

Request (SendTargetedNotificationRequest):

{
"title": "Service Request Update",
"body": "Your service request #SR-1023 has been assigned.",
"imageUrl": "https://cdn.example.com/notifications/sr-1023.png",
"sendPush": true,
"sendEmail": true,
"isScheduled": true,
"scheduledAt": "2026-03-20T09:30:00Z",
"userIds": [
"9a0d3f9a-1b7f-4d5c-9a1c-8b7b3a6f1f11",
"e3c9a5ab-2f3a-4f91-9d4d-3c8f8b2a7b21"
]
}

Success Response (CommonResponse):

{
"status": 0,
"message": "Notification sent successfully"
}

Error Responses:

  • -20009: Invalid input parameters
  • -20012: Unauthorized

3. Get Targeted Notifications History

Endpoint: GET /targeted-notifications
Auth: Required (Bearer Token)

Request (Query Parameters):

{
"senderId": "a1111111-2222-3333-4444-555555555555",
"userId": "e3c9a5ab-2f3a-4f91-9d4d-3c8f8b2a7b21",
"dateFrom": "2026-03-01T00:00:00Z",
"dateTo": "2026-03-18T23:59:59Z",
"isPush": true,
"isEmail": false,
"isScheduled": true,
"pageNumber": 1,
"rowsPerPage": 10
}

Success Response (ServerPaginatedData<TargetedNotificationHistoryItem>):

{
"data": [
{
"notificationId": "2a6b5c9d-7f2d-4d2a-9c1f-0f1b2a3c4d5e",
"senderId": "a1111111-2222-3333-4444-555555555555",
"senderDetails": {
"userId": "a1111111-2222-3333-4444-555555555555",
"email": "admin@example.com",
"firstName": "System",
"lastName": "Admin",
"phoneNumber": "+1-555-0001",
"userType": 1,
"entityId": "1a2b3c4d-5e6f-7g8h-9i0j-0k1l2m3n4o5p",
"profileImageUrl": "https://cdn.example.com/profiles/admin-001.png"
},
"title": "Service Request Update",
"body": "Your service request #SR-1023 has been assigned.",
"imageUrl": "https://cdn.example.com/notifications/sr-1023.png",
"isPush": true,
"isEmail": false,
"status": 1,
"isScheduled": true,
"scheduledAt": "2026-03-20T09:30:00Z",
"createdAt": "2026-03-12T10:15:30Z",
"users": [
{
"userId": "e3c9a5ab-2f3a-4f91-9d4d-3c8f8b2a7b21",
"email": "john.wilson@example.com",
"firstName": "John",
"lastName": "Wilson",
"phoneNumber": "+1-555-0199",
"userType": 3,
"entityId": "7c2a1d4b-8e61-4c3f-9d13-2a7b9d9c1f55",
"profileImageUrl": "https://cdn.example.com/profiles/cust-4501.png",
"sentAt": null,
"notificationStatus": 1
},
{
"userId": "9a0d3f9a-1b7f-4d5c-9a1c-8b7b3a6f1f11",
"email": "john.carter@example.com",
"firstName": "John",
"lastName": "Carter",
"phoneNumber": "+1-555-0100",
"userType": 2,
"entityId": "0b7a2d6b-3a19-4d2c-9c3a-0b2b9c2f4a10",
"profileImageUrl": "https://cdn.example.com/profiles/tech-1023.png",
"sentAt": null,
"notificationStatus": 1
}
]
},
{
"notificationId": "8f7e6d5c-4b3a-2c1d-0e9f-8a7b6c5d4e3f",
"senderId": "a1111111-2222-3333-4444-555555555555",
"senderDetails": {
"userId": "a1111111-2222-3333-4444-555555555555",
"email": "admin@example.com",
"firstName": "System",
"lastName": "Admin",
"phoneNumber": "+1-555-0001",
"userType": 1,
"entityId": "1a2b3c4d-5e6f-7g8h-9i0j-0k1l2m3n4o5p",
"profileImageUrl": "https://cdn.example.com/profiles/admin-001.png"
},
"title": "Work Completed",
"body": "Technician has completed the work for request #SR-1019.",
"imageUrl": null,
"isPush": true,
"isEmail": true,
"status": 2,
"isScheduled": false,
"scheduledAt": null,
"createdAt": "2026-03-05T08:40:00Z",
"users": [
{
"userId": "e3c9a5ab-2f3a-4f91-9d4d-3c8f8b2a7b21",
"email": "john.wilson@example.com",
"firstName": "John",
"lastName": "Wilson",
"phoneNumber": "+1-555-0199",
"userType": 3,
"entityId": "7c2a1d4b-8e61-4c3f-9d13-2a7b9d9c1f55",
"profileImageUrl": "https://cdn.example.com/profiles/cust-4501.png",
"sentAt": "2026-03-05T08:40:10Z",
"notificationStatus": 2
}
]
}
],
"totalNumber": 42,
"hasPreviousPage": false,
"hasNextPage": true,
"totalPages": 5,
"pageNumber": 1,
"rowsPerPage": 10
}

Error Responses:

  • -20009: Invalid input parameters
  • -20012: Unauthorized