User Leave Allowances
Relevant source files
The following files were used as context for generating this wiki page:
- packages/api/Modules/UserLeaveAllowances/UserLeaveAllowance.cs
- packages/api/Modules/UserLeaveAllowances/UserLeaveAllowanceConfiguration.cs
- packages/api/Modules/Users/UserService.cs
- packages/api/Modules/LeaveTypes/LeaveType.cs
- packages/web/src/routes/_authed/admin/users/-components/form.tsx
- packages/web/src/features/users/users.schemas.ts
- packages/api/Migrations/AppDb/20260518070459_AddUserLeaveAllowances.cs
User Leave Allowances represent the specific leave entitlements assigned to a user for a given calendar year. This system bridges the gap between global Leave Types and individual employee contracts, allowing administrators to define how many days of a specific leave type (e.g., Holiday, Sickness) a user is entitled to.
The system supports both "Limited" modes, where a fixed number of days is allocated, and "Unlimited" modes, typically used for categories like sick leave where no hard ceiling is applied. Allowances are versioned by year, ensuring that changes in employment terms or annual resets are preserved historically.
Sources: packages/api/Modules/UserLeaveAllowances/UserLeaveAllowance.cs:11-19, packages/api/Modules/Users/UserService.cs:72-87, packages/web/src/routes/_authed/admin/users/-components/form.tsx:145-155
Data Model and Schema
The UserLeaveAllowance entity links a User to a LeaveType for a specific Year.
Entity Definition
| Field | Type | Description |
|---|---|---|
Id | Guid | Unique identifier for the allowance record. |
UserId | Guid | Reference to the user the allowance belongs to. |
LeaveTypeId | Guid | Reference to the category of leave (e.g., Holiday). |
Year | int | The calendar year this allowance is valid for. |
Mode | AllowanceMode | Enum: Limited or Unlimited. |
TotalDays | decimal(5,1) | Total days granted (only applicable if Mode is Limited). |
Sources: packages/api/Modules/UserLeaveAllowances/UserLeaveAllowance.cs:11-19, packages/api/Modules/UserLeaveAllowances/UserLeaveAllowanceConfiguration.cs:15-32
Entity Relationships
The following diagram illustrates the relationship between users, their annual allowances, and the underlying leave type definitions.
The database enforces a unique constraint on the combination of UserId, LeaveTypeId, and Year to prevent duplicate entitlements for the same period.
Sources: packages/api/Modules/UserLeaveAllowances/UserLeaveAllowanceConfiguration.cs:34-45, packages/api/Migrations/AppDb/20260518070459_AddUserLeaveAllowances.cs:51-54
Core Logic and Lifecycle
Automatic Provisioning (Seeding)
When a new user is created or provisioned via CreateAsync or GetOrProvisionAsync, the system automatically generates leave allowances for the current calendar year. It iterates through all active (non-archived) LeaveTypes and copies their DefaultMode and DefaultDays into new UserLeaveAllowance records.
Synchronization and Updates
The UserService.UpdateAsync method handles the synchronization of leave allowances when a user profile is edited. The logic follows a "reconcile" pattern:
- Updates: If an incoming allowance has an ID, existing records are updated with new
ModeandTotalDays. - Additions: If an allowance has no ID, a new record is inserted for the current year.
- Deletions: Any existing allowances for the current year not present in the update request are hard-deleted.
- Validation: The system prevents duplicate
LeaveTypeIdentries for the same year, throwing aDuplicateUserLeaveAllowanceExceptionif found.
Sources: packages/api/Modules/Users/UserService.cs:115-155, packages/api.tests/Users/UserLeaveAllowanceServiceTests.cs:141-171
User Interface Implementation
In the administrative web interface, leave allowances are managed within the User Form.
Component Logic
The UserForm component uses a dynamic table to list current allowances. It calculates the "Balance" in real-time for Limited modes by subtracting "Taken" days from "Total Days".
- Mode Toggle: Switching to
Unlimitedmode automatically setsTotalDaysto 0 and disables the input field. - Decimals: The
TotalDaysinput usesstep="any"and is validated to allow a maximum of one decimal place (e.g., 0.5 days). - Add Leave: A picker allows administrators to add leave types that are not yet configured for the user.
Sources: packages/web/src/routes/_authed/admin/users/-components/form.tsx:135-185, packages/api/Modules/LeaveTypes/LeaveTypeContracts.cs:33-40
Validation Schema
Client-side validation is handled by Zod, ensuring UUID formats and valid allowance modes before submission.
export const userLeaveAllowanceSchema = z.object({
id: z.string().uuid().nullish(),
leaveTypeId: z.string().uuid(),
mode: allowanceModeSchema,
totalDays: daysWithOneDecimal,
});
Sources: packages/web/src/features/users/users.schemas.ts:16-21
API Integration
Response Structure
When fetching a user via GetByIdAsync, the API performs a join between UserLeaveAllowances and LeaveTypes to provide the human-readable name of the leave category alongside the allowance data.
| Property | Type | Source |
|---|---|---|
Name | string | Joined from LeaveType |
Taken | decimal | Currently hardcoded to 0m in service (logic pending) |
Balance | decimal? | Calculated as TotalDays - Taken (null if Unlimited) |
Sources: packages/api/Modules/Users/UserService.cs:75-87, packages/web/src/api/schema.ts:983-994
Request Structure
Updates are sent as a collection within the UserRequest DTO.
public class UserLeaveAllowanceRequest
{
public Guid? Id { get; set; }
public Guid LeaveTypeId { get; set; }
public AllowanceMode Mode { get; set; }
public decimal TotalDays { get; set; }
}
Sources: packages/web/src/api/schema.ts:975-981, packages/api.tests.integration/Users/UserLeaveAllowanceEndpointsTests.cs:100-112
Summary
The User Leave Allowance system provides a flexible, per-user configuration for annual leave entitlements. It automates the initial setup using global defaults while allowing fine-grained administrative overrides. By anchoring records to specific years and enforcing unique constraints, the system ensures data integrity and historical accuracy for employee benefits.