Skip to main content

Overview

The Users service is responsible for managing all user entities in the Masar Eagle platform, including drivers, passengers, companies, and administrators. It handles user profiles, vehicle management, zone configuration, file uploads, and verification workflows.
Users service location: src/services/Users/Users.Api/Program.cs

Core Responsibilities

  • Driver Management: Registration, profile updates, document verification, and commission settings
  • Passenger Management: Profile management and wallet preferences
  • Company Management: Company profiles, employees, vehicles, and zones
  • Vehicle Management: Vehicle types, registration, and assignments
  • Zone Management: Geographic zones for service areas
  • File Storage: Profile images, documents, and verification photos
  • Commission Policies: Configure commission rates for drivers and companies
  • Currency Management: Multi-currency support
  • User Verification: Driver document review and approval workflow
  • Background Jobs: Account purge and data cleanup

Technology Stack

  • ASP.NET Core Minimal APIs: Endpoint definitions
  • Entity Framework Core: Database access
  • PostgreSQL: Primary database
  • Wolverine: Message bus with outbox pattern
  • RabbitMQ: Inter-service messaging
  • FluentValidation: Request validation
  • Response Compression: Brotli and Gzip for API responses
  • Local File Storage: File uploads to wwwroot directory

Program.cs Configuration

Program.cs
using Users.Api.Infrastructure.Extensions;
using Users.Api.Infrastructure.Services;
using Users.Api.Infrastructure.BackgroundJobs;
using ServiceDefaults;
using Wolverine.RabbitMQ;

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

// Configure Kestrel for large file uploads
builder.WebHost.ConfigureKestrel(options => 
    options.Limits.MaxRequestBodySize = null);

builder.Services.Configure<FormOptions>(options =>
{
    options.MultipartBodyLengthLimit = long.MaxValue;
    options.ValueLengthLimit = int.MaxValue;
    options.ValueCountLimit = int.MaxValue;
});

// Ensure file storage directories exist
builder.EnsureFileStorageDirectories();

builder.AddServiceDefaults();
builder.Services.AddHealthChecks();

// Enable response compression
builder.Services.AddResponseCompression(options =>
{
    options.EnableForHttps = true;
    options.Providers.Add<BrotliCompressionProvider>();
    options.Providers.Add<GzipCompressionProvider>();
    options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[]
    {
        "application/json",
        "text/json"
    });
});

builder.Services.AddSwaggerDocumentation();
builder.Services.AddAppSettings(builder.Configuration);
builder.Services.AddAppAuthentication(builder.Configuration);
builder.AddDatabase();

builder.Services.AddApplicationServices();
builder.Services.AddValidatorsFromAssemblyContaining(typeof(Program));

// Background job for purging soft-deleted accounts
builder.Services.AddHostedService<AccountPurgeWorker>();

// HTTP client for Trips service
builder.Services.AddHttpClient<TripsUsageClient>("trip", 
    client => client.BaseAddress = new Uri("https+http://trip"))
    .AddServiceDiscovery();

builder.Services.AddScoped<ITripsUsageClient>(provider =>
{
    var factory = provider.GetRequiredService<IHttpClientFactory>();
    var httpClient = factory.CreateClient("trip");
    var logger = provider.GetRequiredService<ILogger<TripsUsageClient>>();
    return new TripsUsageClient(httpClient, logger);
});

// HTTP client for Notifications service
builder.Services.AddHttpClient<NotificationsClient>("notifications", 
    client => client.BaseAddress = new Uri("https+http://notifications"))
    .AddServiceDiscovery();

builder.Services.AddScoped<INotificationsClient>(sp =>
{
    var factory = sp.GetRequiredService<IHttpClientFactory>();
    var http = factory.CreateClient("notifications");
    var logger = sp.GetRequiredService<ILogger<NotificationsClient>>();
    return new NotificationsClient(http, logger);
});

// Configure Wolverine with RabbitMQ and outbox pattern
await builder.UseWolverineWithRabbitMqAsync(
    new WolverineMessagingOptions
    {
        EnablePostgresOutbox = true,
        PostgresConnectionName = Components.Database.User,
        OutboxSchema = "wolverine"
    },
    opts =>
    {
        opts.PublishAllMessages()
            .ToRabbitExchange(Components.RabbitMQConfig.ExchangeName);
        
        opts.ListenToRabbitQueue("users-api-queue",
            cfg => cfg.BindExchange(Components.RabbitMQConfig.ExchangeName));
        
        opts.ApplicationAssembly = typeof(Program).Assembly;
    });

WebApplication app = builder.Build();

app.UseResponseCompression();
app.UseAppMiddleware();
app.ConfigureStaticFiles();
app.UseSwaggerDocumentation();
app.UseAppCors();
app.UseAuthentication();
app.UseAuthorization();

app.MapAllEndpoints();
await app.RunAsync();

API Endpoints Overview

The Users service exposes numerous endpoints organized by domain:

Driver Endpoints

  • GET /api/drivers/{driverId} - Get driver profile
  • PUT /api/drivers/{driverId} - Update driver profile
  • POST /api/drivers/profile/submit-for-review - Submit profile for verification
  • DELETE /api/drivers/{driverId} - Soft delete driver account
  • GET /api/drivers/me/wallet - Get driver’s wallet info
  • PUT /api/drivers/me/default-currency - Set default currency
  • PUT /api/drivers/me/display-currency - Set display currency
  • GET /api/drivers/{driverId}/company - Get driver’s company info
  • Managed through company assignment workflows
  • GET /api/app/captains/settings - Get driver app settings
  • Returns version requirements, features, and configuration

Passenger Endpoints

  • GET /api/passengers/{passengerId} - Get passenger profile
  • PUT /api/passengers/{passengerId} - Update passenger profile
  • DELETE /api/passengers/{passengerId} - Soft delete passenger account
  • GET /api/app/passengers/settings - Get passenger app settings

Company Endpoints

  • GET /api/admin/companies - List all companies (admin)
  • GET /api/admin/companies/{companyId} - Get company details
  • POST /api/admin/companies - Create new company
  • PUT /api/admin/companies/{companyId} - Update company
  • GET /api/companies/{companyId}/public - Public company info
  • GET /api/company/{companyId} - Company profile for authenticated users
  • GET /api/admin/companies/{companyId}/drivers - List company drivers
  • POST /api/admin/companies/{companyId}/drivers - Assign driver to company
  • DELETE /api/admin/companies/{companyId}/drivers/{driverId} - Remove driver

Vehicle Endpoints

  • GET /api/vehicles - List vehicles
  • GET /api/vehicles/{vehicleId} - Get vehicle details
  • POST /api/vehicles - Create vehicle
  • PUT /api/vehicles/{vehicleId} - Update vehicle
  • DELETE /api/vehicles/{vehicleId} - Delete vehicle
  • GET /api/admin/vehicles - Admin vehicle listing
  • GET /api/vehicle-types - List vehicle types
  • POST /api/vehicle-types - Create vehicle type (admin)
  • PUT /api/vehicle-types/{id} - Update vehicle type
  • DELETE /api/vehicle-types/{id} - Delete vehicle type

Zone Endpoints

  • GET /api/zones - List zones
  • GET /api/zones/{zoneId} - Get zone details
  • POST /api/admin/zones - Create zone (admin)
  • PUT /api/admin/zones/{zoneId} - Update zone
  • DELETE /api/admin/zones/{zoneId} - Delete zone
  • POST /api/zones/validate-travel - Check if travel between zones is allowed
  • GET /api/cities - List cities
  • POST /api/cities - Create city (admin)
  • PUT /api/cities/{cityId} - Update city
  • DELETE /api/cities/{cityId} - Delete city

Admin Endpoints

  • GET /api/admin/admins - List administrators
  • POST /api/admin/admins - Create admin user
  • PUT /api/admin/admins/{adminId} - Update admin
  • DELETE /api/admin/admins/{adminId} - Delete admin
  • GET /api/admin/passengers - List all passengers
  • GET /api/admin/driver-verification-reviews - Pending driver verifications
  • POST /api/admin/driver-verification-reviews/{reviewId}/approve - Approve driver
  • POST /api/admin/driver-verification-reviews/{reviewId}/reject - Reject driver
  • GET /api/admin/commission-settings - List commission configurations
  • POST /api/admin/commission-settings - Create commission rule
  • PUT /api/admin/commission-settings/{id} - Update commission rule
  • GET /api/admin/commission-policies - List commission policies
  • POST /api/admin/commission-policies - Create policy
  • GET /api/currencies - Public currency list
  • GET /api/admin/currencies - Admin currency management
  • POST /api/admin/currencies - Add currency
  • PUT /api/admin/currencies/{code} - Update currency
  • DELETE /api/admin/currencies/{code} - Remove currency

File Storage

The Users service handles file uploads for:
  • Driver profile photos
  • Driver license documents
  • Vehicle registration documents
  • National ID/Iqama scans
  • Company logos

Configuration

appsettings.json
"FileStorage": {
  "Provider": "Local",
  "UseAbsolutePath": true,
  "MaxFileSizeMB": 2147483647,
  "AllowedExtensions": [".jpg", ".jpeg", ".png", ".webp"],
  "EnableImageResizing": true,
  "MaxImageWidth": 1920,
  "MaxImageHeight": 1080,
  "ThumbnailWidth": 300,
  "ThumbnailHeight": 200
}

Upload Endpoint

Files are uploaded via:
POST /uploads/upload
Content-Type: multipart/form-data
Authorization: Bearer {token}

--boundary
Content-Disposition: form-data; name="file"; filename="license.jpg"
Content-Type: image/jpeg

[binary data]
--boundary--
Response:
{
  "url": "/uploads/drivers/abc123/license.jpg",
  "thumbnailUrl": "/uploads/drivers/abc123/license_thumb.jpg"
}

Static File Access

Uploaded files are served at:
GET /uploads/{path}
The Gateway routes /uploads/{**catch-all} to the Users service.

App Version Management

The service enforces minimum app versions:
appsettings.json
"AppVersion": {
  "Captain": {
    "Android": { "Current": 26, "Latest": 26 },
    "Ios": { "Current": 26, "Latest": 26 }
  },
  "Passenger": {
    "Android": { "Current": 20, "Latest": 20 },
    "Ios": { "Current": 20, "Latest": 20 }
  }
}
Clients with versions below Current are blocked from API access.

Background Jobs

AccountPurgeWorker

The service includes a background worker that periodically purges soft-deleted accounts:
builder.Services.AddHostedService<AccountPurgeWorker>();
This job runs daily and permanently deletes accounts that have been soft-deleted for more than 30 days.

Inter-Service Communication

The Users service communicates with:

Trips Service

To check if users have active trips before allowing certain operations:
var hasActiveTrips = await tripsUsageClient
    .HasActiveTripsAsync(userId, userType);

Notifications Service

To send notifications for:
  • Driver approval/rejection
  • Company invitations
  • Account status changes
await notificationsClient.SendNotificationAsync(
    userId,
    userType,
    "تم قبول طلبك",
    "مبروك! تم الموافقة على حسابك كسائق"
);

Message Bus Events

The Users service publishes events via Wolverine + RabbitMQ: Published Events:
  • DriverCreated
  • DriverUpdated
  • DriverApproved
  • DriverRejected
  • PassengerCreated
  • CompanyCreated
  • VehicleCreated
Consumed Events:
  • UserAuthenticatedEvent - Provisions user on first login
  • UpdateDriverRatingCommand - Updates driver rating after trip
  • UpdatePassengerRatingCommand - Updates passenger rating after trip
  • UploadFileCommand - Handles async file processing

Outbox Pattern

The service uses Wolverine’s PostgreSQL outbox to ensure reliable message delivery:
await builder.UseWolverineWithRabbitMqAsync(
    new WolverineMessagingOptions
    {
        EnablePostgresOutbox = true,
        PostgresConnectionName = Components.Database.User,
        OutboxSchema = "wolverine"
    },
    opts => { /* ... */ }
);
Messages are first written to the database, then published to RabbitMQ, ensuring no events are lost even if the service crashes.

Email Configuration

The service can send emails to company users:
appsettings.json
"EmailConfiguration": {
  "ApiToken": "re_aafvLsKP_8TkeNCof63WgXyR4RgfyvSux",
  "From": "[email protected]",
  "DisplayName": "مسار إيجل",
  "CompanyPortalUrl": "https://portal.masar-eagle.com",
  "LogoUrl": "https://prod.api.masar-eagle.com/uploads/logos/logo.png"
}

Swagger Documentation

API documentation is available at:
GET /swagger
The Swagger UI includes all endpoints with request/response schemas.

Identity Service

Authenticates users and provisions accounts

Trips Service

Checks user eligibility for operations

Notifications Service

Sends user notifications

Gateway

Routes user-related requests

Build docs developers (and LLMs) love