User Management
Author(s)
- Ashik
Last Updated Date
2026-03-04
SRS References
- SRS Document: MarketPulse-SRS-v1.0
- Section: User Management & Authentication
- Document Link: User Management SRS
Version History
| Version | Date | Author | Changes |
|---|---|---|---|
| 1.0 | 2026-02-23 | Ashik | Initial user management document |
| 2.0 | 2026-03-04 | Ashik | Add role and scopes |
Feature Overview
The User Management feature provides comprehensive user administration and authentication capabilities for the MarketPulse platform. This feature manages multiple user types including Admins, Resellers, and Dealers with role-based access control (RBAC) and secure authentication mechanisms.
Key Features
- Multi-Entity Authentication: Separate login flows for Admin, Reseller, and Dealer users
- Role-Based Access Control (RBAC): Dynamic role and scope management with granular permissions
- User Lifecycle Management: Complete user registration, activation, deactivation, and profile management
- JWT-Based Authentication: Secure token-based authentication with configurable expiration
- Session Management: Track active sessions and maintain session history for audit purposes
- Token Refresh: Automatic token renewal using refresh tokens for seamless user experience
- Logout Functionality: Secure logout with session invalidation
- Entity Hierarchy: Support for Admin → Reseller → Dealer organizational structure
- Scope-Based Authorization: Fine-grained permission control through scope and role mapping
- Profile Management: User profile CRUD operations with role-specific data
- Audit Trail: Track user activities, login history, and permission changes
User Types
- Admin: Platform administrators with full system access
- Reseller: Organization-level users managing multiple dealers
- Dealer: Individual dealer users with location-specific access
Requirements
Functional Requirements
| ID | Requirement | Priority |
|---|---|---|
| FR-1 | Admin user authentication with email/password | High |
| FR-2 | Reseller user authentication with email/password | High |
| FR-3 | Dealer user authentication with email/password | High |
| FR-4 | User logout with session invalidation | High |
| FR-5 | Token refresh using refresh tokens | High |
| FR-6 | Role-based access control (RBAC) | High |
| FR-7 | Scope-based authorization system | High |
| FR-8 | User profile management (CRUD operations) | High |
| FR-9 | JWT token generation with configurable expiry | High |
| FR-10 | Password encryption and validation | High |
| FR-11 | Active session tracking and management | High |
| FR-12 | Login history and session audit trail | Medium |
| FR-13 | User status management (Active/Inactive) | Medium |
| FR-14 | Role and scope mapping management | Medium |
| FR-15 | Entity-based user isolation | Medium |
| FR-16 | Primary role assignment | Low |
Non-Functional Requirements
| ID | Requirement | Priority |
|---|---|---|
| NFR-1 | System must handle 10,000+ concurrent users | High |
| NFR-2 | Authentication response time < 500ms | High |
| NFR-3 | Password encryption using industry standards | High |
| NFR-4 | JWT token validation latency < 100ms | High |
| NFR-5 | 99.9% uptime for authentication service | High |
| NFR-6 | Support for timezone-based operations | Medium |
Database Schema
AdminMaster Table
CREATE TABLE IF NOT EXISTS adminmaster (
adminid UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(255) NOT NULL,
primaryemail VARCHAR(255) NOT NULL UNIQUE,
primaryphone VARCHAR(20),
status VARCHAR(20) NOT NULL DEFAULT 'Active',
createdat TIMESTAMPTZ NOT NULL DEFAULT now(),
createdby UUID,
updatedat TIMESTAMPTZ NOT NULL DEFAULT now(),
updatedby UUID,
CONSTRAINT chkadminstatus CHECK (status IN ('Active', 'Disable', 'PendingActivation'))
);
CREATE INDEX IF NOT EXISTS idxadminemail ON adminmaster(primaryemail);
CREATE INDEX IF NOT EXISTS idxadminstatus ON adminmaster(status);
ResellerMaster Table
CREATE TABLE IF NOT EXISTS resellermaster (
resellerid UUID PRIMARY KEY DEFAULT gen_random_uuid(),
resellername VARCHAR(255) NOT NULL,
primaryemail VARCHAR(255) NOT NULL UNIQUE,
primaryphone VARCHAR(20),
status VARCHAR(20) NOT NULL DEFAULT 'Active',
createdat TIMESTAMPTZ NOT NULL DEFAULT now(),
createdby UUID NOT NULL,
updatedat TIMESTAMPTZ NOT NULL DEFAULT now(),
updatedby UUID,
CONSTRAINT fkcreatedbyadmin FOREIGN KEY (createdby) REFERENCES adminmaster(adminid),
CONSTRAINT chkresellerstatus CHECK (status IN ('Active', 'Disable', 'PendingActivation'))
);
CREATE INDEX IF NOT EXISTS idxreselleremail ON resellermaster(primaryemail);
CREATE INDEX IF NOT EXISTS idxresellerstatus ON resellermaster(status);
CREATE INDEX IF NOT EXISTS idxresellercreatedby ON resellermaster(createdby);
DealerMaster Table
CREATE TABLE DealerMaster (
dealerid UUID PRIMARY KEY,
dealername VARCHAR(255) NOT NULL,
timezone VARCHAR(50),
groupheaderid UUID,
createdat TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updatedat TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_groupheader FOREIGN KEY (groupheaderid)
REFERENCES DealerMaster(dealerid)
);
UserDetails Table
CREATE TABLE IF NOT EXISTS userdetails (
userid UUID PRIMARY KEY DEFAULT gen_random_uuid(),
firstname VARCHAR(100) NOT NULL,
lastname VARCHAR(100) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
phone VARCHAR(20),
password VARCHAR(255) NOT NULL,
status VARCHAR(20) DEFAULT 'Active',
usertype VARCHAR(20) NOT NULL,
entityid UUID NOT NULL,
roleid UUID,
profileimageurl VARCHAR(500),
createdat TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
updatedat TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_role FOREIGN KEY (roleid)
REFERENCES role(roleid)
);
Scope Table
CREATE TABLE IF NOT EXISTS scope (
scopeid UUID PRIMARY KEY DEFAULT gen_random_uuid(),
scopename VARCHAR(100) NOT NULL,
accesstype INTEGER NOT NULL,
displayname VARCHAR(100),
groupname VARCHAR(100),
groupsortorder INTEGER,
scopesortorder INTEGER,
description VARCHAR(255),
createdat TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);
Role Table
CREATE TABLE IF NOT EXISTS role (
roleid UUID PRIMARY KEY DEFAULT gen_random_uuid(),
rolename VARCHAR(50) NOT NULL,
description VARCHAR(255),
usertype VARCHAR(20) NOT NULL,
entityid UUID NOT NULL,
logusername VARCHAR(50),
logdts TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
status VARCHAR(20) DEFAULT 'Active',
createdat TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
updatedat TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
isprimary BOOLEAN DEFAULT false
);
RoleScopeMapping Table
CREATE TABLE IF NOT EXISTS rolescopemapping (
mappingid UUID PRIMARY KEY DEFAULT gen_random_uuid(),
roleid UUID NOT NULL,
scopeid UUID NOT NULL,
createdat TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT rolescopemapping_roleid_fkey FOREIGN KEY (roleid)
REFERENCES role(roleid),
CONSTRAINT rolescopemapping_scopeid_fkey FOREIGN KEY (scopeid)
REFERENCES scope(scopeid),
CONSTRAINT unique_role_scope UNIQUE (roleid, scopeid)
);
LoginHistory Table
CREATE TABLE IF NOT EXISTS loginhistory (
loginid UUID PRIMARY KEY DEFAULT gen_random_uuid(),
userid UUID NOT NULL,
attempttime TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
logintime TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
logouttime TIMESTAMPTZ,
issuccess BOOLEAN NOT NULL,
ipaddress VARCHAR(45),
devicetype TEXT,
useragent TEXT,
CONSTRAINT fk_user FOREIGN KEY (userid)
REFERENCES userdetails(userid)
);
ActiveSessions Table
CREATE TABLE IF NOT EXISTS activesessions (
sessionid UUID PRIMARY KEY DEFAULT gen_random_uuid(),
userid UUID NOT NULL,
loginid UUID NOT NULL,
refreshtoken TEXT NOT NULL,
devicetype TEXT,
useragent TEXT,
ipaddress VARCHAR(45),
logintime TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
lastrefreshedat TIMESTAMPTZ,
expiresat TIMESTAMPTZ,
CONSTRAINT activesessions_loginid_fkey FOREIGN KEY (loginid)
REFERENCES loginhistory(loginid),
CONSTRAINT activesessions_userid_fkey FOREIGN KEY (userid)
REFERENCES userdetails(userid)
);
SessionHistory Table
CREATE TABLE IF NOT EXISTS sessionhistory (
sessionid UUID PRIMARY KEY DEFAULT gen_random_uuid(),
userid UUID NOT NULL,
loginid UUID NOT NULL,
refreshtoken TEXT NOT NULL,
devicetype TEXT,
useragent TEXT,
ipaddress VARCHAR(45),
logintime TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
lastrefreshedat TIMESTAMPTZ,
logouttime TIMESTAMPTZ,
expiresat TIMESTAMPTZ,
isactive BOOLEAN DEFAULT true,
CONSTRAINT sessionhistory_loginid_fkey FOREIGN KEY (loginid)
REFERENCES loginhistory(loginid),
CONSTRAINT sessionhistory_userid_fkey FOREIGN KEY (userid)
REFERENCES userdetails(userid)
);
Data Models
AdminMaster
Stores administrator user information.
Fields:
adminid: Unique identifier for admin (auto-generated UUID)name: Full name of administratorprimaryemail: Primary email address (unique, indexed)primaryphone: Primary phone numberstatus: Active/Disable/PendingActivation status (indexed, default: 'Active')createdat: Record creation timestamp (default: now())createdby: User ID who created the recordupdatedat: Last update timestamp (default: now())updatedby: User ID who last updated the record
ResellerMaster
Stores reseller organization information.
Fields:
resellerid: Unique identifier for reseller (auto-generated UUID)resellername: Reseller organization nameprimaryemail: Primary email address (unique, indexed)primaryphone: Primary phone numberstatus: Active/Disable/PendingActivation status (indexed, default: 'Active')createdat: Record creation timestamp (default: now())createdby: Admin ID who created the reseller (required, foreign key to adminmaster)updatedat: Last update timestamp (default: now())updatedby: User ID who last updated the record
DealerMaster
Stores dealer information with timezone and group hierarchy.
Fields:
dealerid: Unique identifier for dealerdealername: Dealer nametimezone: Dealer's timezone (e.g., "America/New_York")groupheaderid: Reference to parent dealer (for hierarchy)
UserDetails
Stores detailed user information for all user types.
Fields:
userid: Unique identifier for userfirstname: User's first namelastname: User's last nameemail: User email address (unique)phone: Phone numberpassword: Hashed passwordstatus: Active/Inactive statususertype: Type of user (Admin/Reseller/Dealer)entityid: Reference to entity (adminid/resellerid/dealerid)roleid: Reference to user's roleprofileimageurl: URL to profile image
Scope
Defines permission scopes for the system.
Fields:
scopeid: Unique identifier for scopescopename: Technical name of scopeaccesstype: Access level (0=None, 1=Read, 2=Write, 3=Full)displayname: User-friendly display namegroupname: Logical grouping of scopesgroupsortorder: Sort order for groupsscopesortorder: Sort order within groupdescription: Scope description
Role
Defines user roles with entity-based isolation.
Fields:
roleid: Unique identifier for rolerolename: Role namedescription: Role descriptionusertype: User type this role applies to (Admin/Reseller/Dealer)entityid: Entity this role belongs tologusername: User who created/modified the rolelogdts: Log timestampstatus: Active/Inactive statusisprimary: Whether this is a primary role
RoleScopeMapping
Maps roles to scopes for permission management.
Fields:
mappingid: Unique identifier for mappingroleid: Reference to rolescopeid: Reference to scopecreatedat: Mapping creation timestamp
LoginHistory
Tracks all login attempts and sessions for audit purposes.
Fields:
loginid: Unique identifier for login attemptuserid: Reference to userattempttime: When the login attempt was madelogintime: When login was successfullogouttime: When user logged out (if applicable)issuccess: Whether login attempt was successfulipaddress: IP address of login attemptdevicetype: Type of device (mobile, desktop, tablet)useragent: Browser/client user agent string
ActiveSessions
Stores currently active user sessions with refresh tokens.
Fields:
sessionid: Unique identifier for sessionuserid: Reference to userloginid: Reference to login history recordrefreshtoken: Refresh token for session renewaldevicetype: Type of deviceuseragent: Browser/client user agent stringipaddress: IP address of sessionlogintime: When session was createdlastrefreshedat: Last time token was refreshedexpiresat: When session expires
SessionHistory
Historical record of all user sessions for audit and compliance.
Fields:
sessionid: Unique identifier for sessionuserid: Reference to userloginid: Reference to login history recordrefreshtoken: Refresh token used in sessiondevicetype: Type of deviceuseragent: Browser/client user agent stringipaddress: IP address of sessionlogintime: When session was createdlastrefreshedat: Last time token was refreshedlogouttime: When user logged outexpiresat: When session expiredisactive: Whether session is currently active
Request and Response Models
LoginRequest
public record LoginRequest
{
[Required(ErrorMessage = "Email is required")]
public required string Email { get; init; }
[Required(ErrorMessage = "Password is required")]
[DataType(DataType.Password)]
public required string Password { get; init; }
}
LoginResponse
public record LoginResponse
{
public string? AccessToken { get; set; }
public double? ExpiresIn { get; set; }
public string? TokenType { get; set; } = "Bearer";
}
CommonResponse
public record CommonResponse
{
public int Status { get; init; }
public string? Message { get; init; }
}
User
public record User
{
public Guid UserId { get; set; }
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
public string? Email { get; set; }
public string? Phone { get; set; }
public string Password { get; set; } = string.Empty;
public Guid RoleId { get; set; } = Guid.Empty;
public Guid EntityId { get; set; }
public UserType UserType { get; set; }
public UserStatus? Status { get; set; }
public string? ProfileImageUrl { get; set; }
public DateTime? CreatedAt { get; set; }
public DateTime? UpdatedAt { get; set; }
public string? Designation { get; init; }
}
UserDetails
public record UserDetails
{
public Guid UserId { get; init; }
public string? FirstName { get; init; }
public string? LastName { get; init; }
public string? Email { get; init; }
public string? Phone { get; init; }
public DateTime CreatedAt { get; init; }
public DateTime UpdatedAt { get; init; }
public UserType UserType { get; init; }
public UserStatus Status { get; init; }
public string? EntityName { get; set; }
public string? RoleName { get; init; }
public Guid RoleId { get; init; }
public string? RoleDescription { get; init; }
public Guid EntityId { get; init; }
public bool IsPrimaryUser { get; init; } = false;
public string? Designation { get; set; }
}
Role
public record Role
{
public Guid RoleId { get; set; }
public string? RoleName { get; init; }
public string? Description { get; init; }
public UserType UserType { get; set; }
public Guid EntityId { get; set; }
public Status? Status { get; set; }
public string? LogUsername { get; set; }
public DateTime? LogDts { get; set; } = DateTime.UtcNow;
public DateTime? CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime? UpdatedAt { get; set; } = DateTime.UtcNow;
public bool IsPrimary { get; set; } = false;
}
Scope
public record Scope
{
public Guid ScopeId { get; init; }
public required string ScopeName { get; init; }
public int AccessType { get; init; }
public required string DisplayName { get; init; }
public required string GroupName { get; init; }
public int GroupSortOrder { get; init; }
public int ScopeSortOrder { get; init; }
public string? Description { get; init; }
}
RoleWithScopeIds
public record RoleWithScopeIds : Role
{
public List<Guid> ScopeIds { get; set; } = new();
}
UserType Enum
public enum UserType
{
Admin = 1,
Reseller = 2,
Dealer = 4
}
UserStatus Enum
public enum UserStatus
{
Active = 1,
Disable = 2,
PendingActivation = 3
}
UserSortBy Enum
public enum UserSortBy
{
FirstName = 1,
LastName = 2,
Email = 3,
Phone = 4,
CreatedAt = 5,
UpdatedAt = 6
}
SortOrder Enum
public enum SortOrder
{
Ascending = 1,
Descending = 2
}
UserFilter
public record UserFilter
{
public string? FirstName { get; init; }
public string? LastName { get; init; }
public string? Email { get; init; }
public string? Phone { get; init; }
public UserStatus? Status { get; init; }
public UserType? UserType { get; set; }
public Guid? EntityId { get; set; }
public Guid? RoleId { get; init; }
public int RowsPerPage { get; set; } = 10;
public int PageNumber { get; set; } = 1;
public string? SearchKeyword { get; set; }
public UserSortBy SortBy { get; set; } = UserSortBy.CreatedAt;
public SortOrder SortOrder { get; set; } = SortOrder.Descending;
}
ServerPaginatedData<T>
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; }
}
UserDetailsWithProfileImage
public record UserDetailsWithProfileImage : UserDetails
{
public string? ProfileImageUrl { get; init; }
}
API Interfaces
| Endpoint | Method | Purpose | Parameters | Request Model | Response Model | Status Codes |
|---|---|---|---|---|---|---|
/auth/admin-login | POST | Authenticate admin users and return JWT access token | - | LoginRequest | LoginResponse | 200, 400, 401, 500 |
/auth/reseller-login | POST | Authenticate reseller users and return JWT access token | - | LoginRequest | LoginResponse | 200, 400, 401, 500 |
/auth/dealer-login | POST | Authenticate dealer users and return JWT access token | - | LoginRequest | LoginResponse | 200, 400, 401, 500 |
/auth/logout | POST | Logout user and invalidate session | JWT in header | - | CommonResponse | 200, 401, 500 |
/auth/refresh-token | GET | Refresh access token using refresh token | JWT in header, Refresh token in cookie/header | - | LoginResponse | 200, 401, 500 |
/auth/users | POST | Create a new user in the system | JWT in header | User | CommonResponse | 200, 400, 401, 500 |
/auth/users/{userId} | PUT | Update an existing user | JWT in header, userId (path) | User | CommonResponse | 200, 400, 401, 404, 500 |
/auth/users | GET | Retrieve paginated list of users with filtering and sorting | JWT in header | UserFilter | ServerPaginatedData<UserDetails> | 200, 400, 401, 500 |
/auth/users/{userId} | GET | Get user details by user ID | JWT in header, userId (path) | - | UserDetailsWithProfileImage | 200, 401, 404, 500 |
/auth/role-suggestion | GET | Get list of role suggestions | JWT in header | - | List<Role> | 200, 401, 500 |
/auth/scope-suggestion | GET | Get list of scope suggestions | JWT in header | - | List<Scope> | 200, 401, 500 |
/auth/role | POST | Create a new role with associated scopes | JWT in header | RoleWithScopeIds | CommonResponse | 200, 400, 401, 500 |
API Examples
Admin Login Example
Request:
POST /auth/admin-login
Host: marketpulse.inworkglobal.com/api
Content-Type: application/json
{
"email": "admin@marketpulse.com",
"password": "SecurePass123!"
}
Success Response (200 OK):
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI1NTBlODQwMC1lMjliLTQxZDQtYTcxNi00NDY2NTU0NDAwMDAiLCJlbWFpbCI6ImFkbWluQG1hcmtldHB1bHNlLmNvbSIsInVzZXJUeXBlIjoiQWRtaW4iLCJlbnRpdHlJZCI6IjExMGU4NDAwLWUyOWItNDFkNC1hNzE2LTQ0NjY1NTQ0MDAwMCIsInJvbGVJZCI6IjIyMGU4NDAwLWUyOWItNDFkNC1hNzE2LTQ0NjY1NTQ0MDAwMCIsImlhdCI6MTcwODcwNDAwMCwiZXhwIjoxNzA4NzA3NjAwfQ.8yJvK5TmQa5L3xN2PX9h4R6tY7uV8wZ9aB1cD3eF4gH",
"expiresIn": 3600,
"tokenType": "Bearer"
}
Error Response (401 Unauthorized):
{
"error": "Unauthorized",
"message": "Invalid email or password"
}
Error Response (400 Bad Request):
{
"error": "ValidationError",
"message": "Email is required",
"details": {
"email": ["Email is required"]
}
}
Reseller Login Example
Request:
POST /auth/reseller-login
Host: marketpulse.inworkglobal.com/api
Content-Type: application/json
{
"email": "reseller@acmecorp.com",
"password": "ResellerPass456!"
}
Success Response (200 OK):
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2NjBmOTUwMC1mM2FjLTUyZTUtYjgyNy01NTc3NjY1NTExMTEiLCJlbWFpbCI6InJlc2VsbGVyQGFjbWVjb3JwLmNvbSIsInVzZXJUeXBlIjoiUmVzZWxsZXIiLCJlbnRpdHlJZCI6IjMzMGY5NTAwLWYzYWMtNTJlNS1iODI3LTU1Nzc2NjU1MTExMSIsInJvbGVJZCI6IjQ0MGY5NTAwLWYzYWMtNTJlNS1iODI3LTU1Nzc2NjU1MTExMSIsImlhdCI6MTcwODcwNDAwMCwiZXhwIjoxNzA4NzA3NjAwfQ.9zKwM6UnRb6M4yO3QY0i5S7uW9xA0a2bC4dE5fG6hJ",
"expiresIn": 3600,
"tokenType": "Bearer"
}
Dealer Login Example
Request:
POST /auth/dealer-login
Host: marketpulse.inworkglobal.com/api
Content-Type: application/json
{
"email": "dealer@downtown.com",
"password": "DealerPass789!"
}
Success Response (200 OK):
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI3NzBnMDYwMC1nNGJkLTYzZjYtYzkzOC02Njg4Nzc2NjIyMjIiLCJlbWFpbCI6ImRlYWxlckBkb3dudG93bi5jb20iLCJ1c2VyVHlwZSI6IkRlYWxlciIsImVudGl0eUlkIjoiNTUwZzA2MDAtZzRiZC02M2Y2LWM5MzgtNjY4ODc3NjYyMjIyIiwicm9sZUlkIjoiNjYwZzA2MDAtZzRiZC02M2Y2LWM5MzgtNjY4ODc3NjYyMjIyIiwidGltZXpvbmUiOiJBbWVyaWNhL05ld19Zb3JrIiwiaWF0IjoxNzA4NzA0MDAwLCJleHAiOjE3MDg3MDc2MDB9.0aLxN7VoSc7N5zP4RZ1j6T8vX0yB1b3cD5eF6gG7iK",
"expiresIn": 3600,
"tokenType": "Bearer"
}
Logout Example
Request:
POST /auth/logout
Host: marketpulse.inworkglobal.com/api
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
Success Response (200 OK):
{
"status": 200,
"message": "Logged out successfully"
}
Error Response (401 Unauthorized):
{
"status": 401,
"message": "Invalid or expired token"
}
Refresh Token Example
Request:
GET /auth/refresh-token
Host: marketpulse.inworkglobal.com/api
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Cookie: refreshToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Success Response (200 OK):
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI1NTBlODQwMC1lMjliLTQxZDQtYTcxNi00NDY2NTU0NDAwMDAiLCJlbWFpbCI6ImFkbWluQG1hcmtldHB1bHNlLmNvbSIsInVzZXJUeXBlIjoiQWRtaW4iLCJpYXQiOjE3MDg3MDc2MDAsImV4cCI6MTcwODcxMTIwMH0.9zKwM6UnRb6M4yO3QY0i5S7uW9xA0a2bC4dE5fG6hJ",
"expiresIn": 3600,
"tokenType": "Bearer"
}
Error Response (401 Unauthorized):
{
"status": 401,
"message": "Invalid or expired refresh token"
}
Create User Example
Request:
POST /auth/users
Host: marketpulse.inworkglobal.com/api
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
{
"userId": "00000000-0000-0000-0000-000000000000",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"phone": "+1234567890",
"password": "SecurePassword123!",
"roleId": "440f9500-f3ac-52e5-b827-557766551111",
"entityId": "330f9500-f3ac-52e5-b827-557766551111",
"userType": "Dealer",
"status": "Active",
"profileImageUrl": "https://example.com/profile/johndoe.jpg",
"designation": "Sales Manager"
}
Success Response (200 OK):
{
"status": 200,
"message": "User created successfully"
}
Error Response (400 Bad Request):
{
"status": 400,
"message": "Validation failed: Email already exists"
}
Error Response (401 Unauthorized):
{
"status": 401,
"message": "Unauthorized: Invalid or expired token"
}
Error Response (500 Internal Server Error):
{
"status": 500,
"message": "An error occurred while creating the user"
}
Update User Example
Request:
PUT /auth/users/770g0600-g4bd-63f6-c938-668877662222
Host: marketpulse.inworkglobal.com/api
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
{
"userId": "770g0600-g4bd-63f6-c938-668877662222",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"phone": "+1234567890",
"password": "SecurePassword123!",
"roleId": "440f9500-f3ac-52e5-b827-557766551111",
"entityId": "330f9500-f3ac-52e5-b827-557766551111",
"userType": 4,
"status": 1,
"profileImageUrl": "https://example.com/profile/johndoe.jpg",
"designation": "Senior Sales Manager"
}
Success Response (200 OK):
{
"status": 200,
"message": "User updated successfully"
}
Error Response (400 Bad Request):
{
"status": 400,
"message": "Validation failed: Invalid email format"
}
Error Response (401 Unauthorized):
{
"status": 401,
"message": "Unauthorized: Invalid or expired token"
}
Error Response (404 Not Found):
{
"status": 404,
"message": "User not found"
}
Error Response (500 Internal Server Error):
{
"status": 500,
"message": "An error occurred while updating the user"
}
Get Paginated Users Example
Request:
GET /auth/users
Host: marketpulse.inworkglobal.com/api
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
{
"firstName": null,
"lastName": null,
"email": null,
"phone": null,
"status": 1,
"userType": 4,
"entityId": "330f9500-f3ac-52e5-b827-557766551111",
"roleId": null,
"rowsPerPage": 10,
"pageNumber": 1,
"searchKeyword": "john",
"sortBy": 5,
"sortOrder": 2
}
Success Response (200 OK):
{
"data": [
{
"userId": "770g0600-g4bd-63f6-c938-668877662222",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"phone": "+1234567890",
"createdAt": "2026-02-20T10:30:00Z",
"updatedAt": "2026-02-23T14:15:00Z",
"userType": 4,
"status": 1,
"entityName": "Downtown Dealership",
"roleName": "Sales Manager",
"roleId": "440f9500-f3ac-52e5-b827-557766551111",
"roleDescription": "Manages sales operations and team",
"entityId": "330f9500-f3ac-52e5-b827-557766551111",
"isPrimaryUser": false,
"designation": "Sales Manager"
},
{
"userId": "880h0700-h5ce-74g7-d049-779988773333",
"firstName": "Johnny",
"lastName": "Smith",
"email": "johnny.smith@example.com",
"phone": "+1987654321",
"createdAt": "2026-02-18T09:15:00Z",
"updatedAt": "2026-02-22T16:30:00Z",
"userType": 4,
"status": 1,
"entityName": "Downtown Dealership",
"roleName": "Sales Associate",
"roleId": "550f9600-f4bd-63f7-c939-668877664444",
"roleDescription": "Handles customer sales and inquiries",
"entityId": "330f9500-f3ac-52e5-b827-557766551111",
"isPrimaryUser": false,
"designation": "Associate"
}
],
"totalNumber": 25,
"hasPreviousPage": false,
"hasNextPage": true,
"totalPages": 3,
"pageNumber": 1,
"rowsPerPage": 10
}
Success Response - No Results (200 OK):
{
"data": [],
"totalNumber": 0,
"hasPreviousPage": false,
"hasNextPage": false,
"totalPages": 0,
"pageNumber": 1,
"rowsPerPage": 10
}
Error Response (400 Bad Request):
{
"status": 400,
"message": "Invalid filter parameters: PageNumber must be greater than 0"
}
Error Response (401 Unauthorized):
{
"status": 401,
"message": "Unauthorized: Invalid or expired token"
}
Error Response (500 Internal Server Error):
{
"status": 500,
"message": "An error occurred while retrieving users"
}
Get User Details By ID Example
Request:
GET /auth/users/770g0600-g4bd-63f6-c938-668877662222
Host: marketpulse.inworkglobal.com/api
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Success Response (200 OK):
{
"userId": "770g0600-g4bd-63f6-c938-668877662222",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"phone": "+1234567890",
"createdAt": "2026-02-20T10:30:00Z",
"updatedAt": "2026-02-23T14:15:00Z",
"userType": 4,
"status": 1,
"entityName": "Downtown Dealership",
"roleName": "Sales Manager",
"roleId": "440f9500-f3ac-52e5-b827-557766551111",
"roleDescription": "Manages sales operations and team",
"entityId": "330f9500-f3ac-52e5-b827-557766551111",
"isPrimaryUser": false,
"designation": "Sales Manager",
"profileImageUrl": "https://example.com/profile/johndoe.jpg"
}
Error Response (404 Not Found):
{
"status": 404,
"message": "User not found"
}
Error Response (401 Unauthorized):
{
"status": 401,
"message": "Unauthorized: Invalid or expired token"
}
Error Response (500 Internal Server Error):
{
"status": 500,
"message": "An error occurred while retrieving user details"
}
Get Role Suggestions
Request:
GET /auth/role-suggestion
Host: marketpulse.inworkglobal.com/api
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Success Response (200 OK):
[
{
"roleId": "440f9500-f3ac-52e5-b827-557766551111",
"roleName": "Sales Manager",
"description": "Manages sales operations and team",
"userType": 4,
"entityId": "330f9500-f3ac-52e5-b827-557766551111",
"status": 1,
"logUsername": "admin@marketpulse.com",
"logDts": "2026-02-23T14:15:00Z",
"createdAt": "2026-02-23T14:15:00Z",
"updatedAt": "2026-02-23T14:15:00Z",
"isPrimary": false
}
]
Get Scope Suggestions
Request:
GET /auth/scope-suggestion
Host: marketpulse.inworkglobal.com/api
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Success Response (200 OK):
[
{
"scopeId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"scopeName": "user.read",
"accessType": 1,
"displayName": "Read Users",
"groupName": "User Management",
"groupSortOrder": 1,
"scopeSortOrder": 1,
"description": "Allows reading user information"
}
]
Create Role
Request:
POST /auth/role
Host: marketpulse.inworkglobal.com/api
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
{
"roleId": "00000000-0000-0000-0000-000000000000",
"roleName": "Sales Manager",
"description": "Manages sales operations and team",
"userType": 4,
"entityId": "330f9500-f3ac-52e5-b827-557766551111",
"status": 1,
"logUsername": "admin@marketpulse.com",
"logDts": "2026-02-23T14:15:00Z",
"createdAt": "2026-02-23T14:15:00Z",
"updatedAt": "2026-02-23T14:15:00Z",
"isPrimary": false,
"scopeIds": [
"a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"b2c3d4e5-f678-90ab-cdef-234567890abc"
]
}
Success Response (200 OK):
{
"status": 200,
"message": "Role created successfully"
}
Error Response (400 Bad Request):
{
"status": 400,
"message": "Validation failed: Role name already exists"
}
Error Response (401 Unauthorized):
{
"status": 401,
"message": "Unauthorized: Invalid or expired token"
}
Error Response (500 Internal Server Error):
{
"status": 500,
"message": "An error occurred while creating the role"
}
Development Tasks & Estimates
| Task ID | Task Description | Estimated Hours | Priority |
|---|---|---|---|
| UM-001 | Create database schema (all 10 tables with relationships) | 5 | High |
| UM-002 | Implement password hashing and JWT utilities | 3 | High |
| UM-003 | Implement user authentication service | 4 | High |
| UM-004 | Create Admin Login API endpoint | 2 | High |
| UM-005 | Create Reseller Login API endpoint | 2 | High |
| UM-006 | Create Dealer Login API endpoint | 2 | High |
| UM-007 | Create Logout API endpoint | 1 | High |
| UM-008 | Create Refresh Token API endpoint | 2 | High |
| UM-009 | Implement session management (active & history) | 3 | High |
| UM-010 | Implement input validation and error handling | 2 | High |
| UM-011 | Write unit and integration tests | 3 | High |
| UM-012 | Code review and security audit | 1 | High |
| UM-013 | Deployment and configuration | 1 | High |
| Total | 31 hours |
Review & Approval
-
Reviewer(s):
- Sanket Mal
- Ayan Ghosh
- Ribhu Gautam
-
Approval Date: [To be completed after reviews]
Additional Notes
Security Considerations
- All passwords must be hashed using bcrypt with a minimum of 12 rounds
- JWT tokens should include user claims: userId, email, userType, entityId, roleId
- Implement token refresh mechanism for long-lived sessions
- Add rate limiting: 5 login attempts per 15 minutes per email/IP
- Implement HTTPS-only communication in production
- Store JWT secret in secure environment variables
- Implement proper CORS policies
Performance Considerations
- Index on email field in UserDetails table
- Index on entityid field for faster entity-based queries
- Cache role and scope mappings to reduce database queries
- Implement connection pooling for database connections
- Use Redis for session management if needed
Future Enhancements
- Multi-factor authentication (MFA)
- Password reset functionality
- Email verification for new users
- OAuth2/OpenID Connect integration
- Single Sign-On (SSO) support
- User activity audit logs
- Session management and concurrent login control
- Password policy enforcement (complexity, expiration)