2026-04-18 02:00:09 +00:00
/**
* Generated by orval v8.5.3 🍺
* Do not edit manually.
* Api
2026-04-22 10:26:53 +00:00
* Tx OS API specification
2026-04-18 02:00:09 +00:00
* OpenAPI spec version: 0.1.0
*/
export interface HealthStatus {
status : string ;
}
2026-04-20 09:20:50 +00:00
export interface ErrorResponse {
error : string ;
}
export interface SuccessResponse {
success : boolean ;
}
export interface RegisterBody {
username : string ;
email : string ;
password : string ;
/** @nullable */
displayNameAr? : string | null ;
/** @nullable */
displayNameEn? : string | null ;
preferredLanguage? : string ;
}
2026-04-22 08:47:35 +00:00
export interface CreateUserBody {
username : string ;
email : string ;
password : string ;
/** @nullable */
displayNameAr? : string | null ;
/** @nullable */
displayNameEn? : string | null ;
preferredLanguage? : string ;
/** Initial group memberships in addition to the auto-assigned Everyone group. */
groupIds? : number [ ] ;
}
2026-04-20 09:20:50 +00:00
export interface LoginBody {
username : string ;
password : string ;
}
2026-04-20 16:28:50 +00:00
export interface ForgotPasswordBody {
/** Username or email */
identifier : string ;
}
export interface ForgotPasswordResponse {
success : boolean ;
}
export interface ResetPasswordBody {
token : string ;
/** @minLength 6 */
newPassword : string ;
}
export interface VerifyResetTokenBody {
token : string ;
}
export interface AdminResetLinkResponse {
resetUrl : string ;
expiresAt : string ;
}
export interface VerifyResetTokenResponse {
valid : boolean ;
}
2026-04-20 09:20:50 +00:00
export interface UpdateLanguageBody {
language : string ;
}
2026-04-20 16:40:49 +00:00
/**
* Per-user home-screen clock style preference
*/
export type ClockStyle = ( typeof ClockStyle ) [ keyof typeof ClockStyle ] ;
export const ClockStyle = {
full : "full" ,
digital : "digital" ,
"digital-no-seconds" : "digital-no-seconds" ,
analog : "analog" ,
minimal : "minimal" ,
} as const ;
export interface UpdateClockStyleBody {
/** Clock style; pass null to clear and use the default */
clockStyle : ClockStyle | null ;
}
2026-05-05 08:13:38 +00:00
export type NotificationSoundId =
( typeof NotificationSoundId ) [ keyof typeof NotificationSoundId ] ;
export const NotificationSoundId = {
ding : "ding" ,
chime : "chime" ,
bell : "bell" ,
knock : "knock" ,
pop : "pop" ,
alert : "alert" ,
beep : "beep" ,
soft : "soft" ,
} as const ;
export interface UpdateNotificationPreferencesBody {
notificationSoundOrder? : NotificationSoundId ;
notificationSoundMeeting? : NotificationSoundId ;
notifyOrdersEnabled? : boolean ;
notifyMeetingsEnabled? : boolean ;
2026-05-05 08:20:54 +00:00
vibrationEnabledOrder? : boolean ;
vibrationEnabledMeeting? : boolean ;
2026-05-05 08:13:38 +00:00
notificationsMuted? : boolean ;
}
2026-04-21 07:16:50 +00:00
export interface UpdateClockHour12Body {
/**
* Whether to use 12-hour (AM/PM) clock format; null clears and uses the default (24-hour)
* @nullable
*/
clockHour12 : boolean | null ;
}
2026-04-22 08:28:31 +00:00
export interface GroupSummary {
id : number ;
name : string ;
/** @nullable */
descriptionAr? : string | null ;
/** @nullable */
descriptionEn? : string | null ;
}
2026-04-20 09:20:50 +00:00
export interface AuthUser {
id : number ;
username : string ;
email : string ;
/** @nullable */
displayNameAr? : string | null ;
/** @nullable */
displayNameEn? : string | null ;
preferredLanguage : string ;
2026-04-20 16:40:49 +00:00
clockStyle? : ClockStyle | null ;
2026-04-20 09:20:50 +00:00
/** @nullable */
2026-04-21 07:16:50 +00:00
clockHour12? : boolean | null ;
/** @nullable */
2026-04-20 09:20:50 +00:00
avatarUrl? : string | null ;
isActive : boolean ;
2026-05-05 08:13:38 +00:00
notificationSoundOrder : NotificationSoundId ;
notificationSoundMeeting : NotificationSoundId ;
notifyOrdersEnabled : boolean ;
notifyMeetingsEnabled : boolean ;
2026-05-05 08:20:54 +00:00
vibrationEnabledOrder : boolean ;
vibrationEnabledMeeting : boolean ;
2026-05-05 08:13:38 +00:00
notificationsMuted : boolean ;
2026-04-20 09:20:50 +00:00
roles : string [ ] ;
2026-04-22 08:28:31 +00:00
groups : GroupSummary [ ] ;
2026-04-20 09:20:50 +00:00
createdAt : string ;
}
export interface UserProfile {
id : number ;
username : string ;
email : string ;
/** @nullable */
displayNameAr? : string | null ;
/** @nullable */
displayNameEn? : string | null ;
preferredLanguage : string ;
2026-04-20 16:40:49 +00:00
clockStyle? : ClockStyle | null ;
2026-04-20 09:20:50 +00:00
/** @nullable */
2026-04-21 07:16:50 +00:00
clockHour12? : boolean | null ;
/** @nullable */
2026-04-20 09:20:50 +00:00
avatarUrl? : string | null ;
isActive : boolean ;
roles : string [ ] ;
2026-04-22 08:28:31 +00:00
groups : GroupSummary [ ] ;
2026-04-20 09:20:50 +00:00
createdAt : string ;
2026-04-29 08:48:29 +00:00
/** Dependent record counts. Populated only by the admin list endpoint
(GET /users) so the delete dialog can warn before the first click.
Omitted from single-user responses (GET /users/:id, PATCH, etc).
*/
noteCount? : number ;
/** Number of service orders owned by this user. Populated only by the
admin list endpoint (GET /users).
*/
orderCount? : number ;
/** Number of conversations created by this user. Populated only by the
admin list endpoint (GET /users).
*/
conversationCount? : number ;
/** Number of messages authored by this user. Populated only by the
admin list endpoint (GET /users).
*/
messageCount? : number ;
2026-04-20 09:20:50 +00:00
}
export interface UpdateUserBody {
/** @nullable */
displayNameAr? : string | null ;
/** @nullable */
displayNameEn? : string | null ;
isActive? : boolean ;
preferredLanguage? : string ;
2026-04-22 08:28:31 +00:00
/** If provided, replaces the user's group memberships */
groupIds? : number [ ] ;
2026-04-20 09:20:50 +00:00
}
2026-04-21 18:58:19 +00:00
export interface AddUserRoleBody {
/** @minLength 1 */
roleName : string ;
}
2026-04-22 10:13:17 +00:00
export interface Role {
id : number ;
name : string ;
/** @nullable */
descriptionAr? : string | null ;
/** @nullable */
descriptionEn? : string | null ;
2026-04-27 10:26:24 +00:00
isSystem : boolean ;
2026-04-22 10:13:17 +00:00
createdAt : string ;
2026-05-01 06:58:52 +00:00
/** Number of users assigned this role. Populated only by the admin
list endpoint (GET /admin/roles) so the admin list can show the
same dependency counts inline as the Apps/Services/Users/Groups
panels. Omitted from create/update responses.
*/
userCount? : number ;
/** Number of groups granting this role. Populated only by the admin
list endpoint (GET /admin/roles).
*/
groupCount? : number ;
2026-04-22 10:13:17 +00:00
}
2026-04-27 10:26:24 +00:00
export interface CreateRoleBody {
/** @minLength 1 */
name : string ;
/** @nullable */
descriptionAr? : string | null ;
/** @nullable */
descriptionEn? : string | null ;
}
export interface UpdateRoleBody {
2026-04-27 12:31:09 +00:00
/** @minLength 1 */
name? : string ;
2026-04-27 10:26:24 +00:00
/** @nullable */
descriptionAr? : string | null ;
/** @nullable */
descriptionEn? : string | null ;
}
2026-04-29 10:57:44 +00:00
export interface RoleUsage {
userCount : number ;
groupCount : number ;
}
2026-04-27 10:26:24 +00:00
export interface RoleDeletionConflict {
error : string ;
userCount : number ;
groupCount : number ;
}
2026-04-27 12:58:16 +00:00
export interface Permission {
id : number ;
name : string ;
/** @nullable */
descriptionAr? : string | null ;
/** @nullable */
descriptionEn? : string | null ;
}
2026-04-29 15:31:42 +00:00
export interface AddAppPermissionBody {
/** ID of the permission to require for this app. */
permissionId : number ;
}
export interface AppPermissionLink {
appId : number ;
permissionId : number ;
}
2026-04-30 18:03:08 +00:00
export interface AppPermissionsImpactBody {
/** Candidate set of permission IDs that would gate this app. Pass an empty array to model "remove every requirement" (i.e. make the app unrestricted). */
permissionIds : number [ ] ;
}
export interface AppPermissionImpactGroup {
id : number ;
name : string ;
}
export interface AppPermissionsImpact {
/** Distinct non-admin users who currently see the app and would lose visibility under the candidate permission set. Already accounts for users who keep access via `group_apps` group-grants. */
affectedUserCount : number ;
/** Distinct non-admin users who currently see the app under the existing permission set. Useful for showing the warning as a fraction (e.g. "12 of 80 will lose access"). */
currentlyVisibleUserCount : number ;
/** Groups that currently grant this app via `group_apps`. Members of any of these groups keep access regardless of permission changes. */
groups : AppPermissionImpactGroup [ ] ;
/** True when the candidate set is identical to the current permission set so no change would actually be saved. */
noChange : boolean ;
}
2026-04-27 12:58:16 +00:00
export interface ReplaceRolePermissionsBody {
/** Full set of permission IDs the role should grant. Existing assignments not present here are removed. */
permissionIds : number [ ] ;
}
2026-04-29 12:45:19 +00:00
export interface RolePermissionsImpactBody {
/** Candidate set of permission IDs to evaluate against the role's current assignments. */
permissionIds : number [ ] ;
}
export interface RolePermissionImpactGroup {
id : number ;
name : string ;
}
export interface RolePermissionImpactItem {
permissionId : number ;
permissionName : string ;
/** Distinct users who currently have this permission via this role and would lose it (no other role they hold grants the permission). */
userCount : number ;
/** Number of groups that currently grant this role. */
groupCount : number ;
/** Groups that currently grant this role and therefore propagate the removal to their members. */
groups : RolePermissionImpactGroup [ ] ;
}
export interface RolePermissionsImpact {
/** One entry per permission that is currently assigned to the role but not in the candidate set. */
removed : RolePermissionImpactItem [ ] ;
/** Distinct users that would lose at least one permission across all removals. */
totalAffectedUsers : number ;
}
2026-04-22 08:28:31 +00:00
export interface Group {
id : number ;
name : string ;
/** @nullable */
descriptionAr? : string | null ;
/** @nullable */
descriptionEn? : string | null ;
isSystem : boolean ;
memberCount : number ;
appCount : number ;
roleCount : number ;
createdAt : string ;
}
2026-04-22 11:05:34 +00:00
export interface GroupDeletionConflict {
error : string ;
memberCount : number ;
appCount : number ;
roleCount : number ;
}
2026-04-27 12:07:07 +00:00
export interface UserDeletionConflict {
error : string ;
noteCount : number ;
orderCount : number ;
conversationCount : number ;
messageCount : number ;
}
export interface AppDeletionConflict {
error : string ;
groupCount : number ;
restrictionCount : number ;
openCount : number ;
}
export interface ServiceDeletionConflict {
error : string ;
orderCount : number ;
}
2026-04-22 08:28:31 +00:00
export interface GroupDetail {
id : number ;
name : string ;
/** @nullable */
descriptionAr? : string | null ;
/** @nullable */
descriptionEn? : string | null ;
isSystem : boolean ;
appIds : number [ ] ;
roleIds : number [ ] ;
userIds : number [ ] ;
createdAt : string ;
}
export interface CreateGroupBody {
/** @minLength 1 */
name : string ;
/** @nullable */
descriptionAr? : string | null ;
/** @nullable */
descriptionEn? : string | null ;
appIds? : number [ ] ;
roleIds? : number [ ] ;
userIds? : number [ ] ;
}
export interface UpdateGroupBody {
/** @minLength 1 */
name? : string ;
/** @nullable */
descriptionAr? : string | null ;
/** @nullable */
descriptionEn? : string | null ;
appIds? : number [ ] ;
roleIds? : number [ ] ;
userIds? : number [ ] ;
}
2026-04-20 09:20:50 +00:00
export interface App {
id : number ;
slug : string ;
nameAr : string ;
nameEn : string ;
/** @nullable */
descriptionAr? : string | null ;
/** @nullable */
descriptionEn? : string | null ;
iconName : string ;
route : string ;
color : string ;
isActive : boolean ;
isSystem : boolean ;
sortOrder : number ;
createdAt : string ;
updatedAt : string ;
2026-04-29 08:48:29 +00:00
/** Number of groups granting access to this app. Populated only by the
admin list endpoint (GET /admin/apps) so the delete dialog can warn
before the first click. Omitted from non-admin and single-app
responses.
*/
groupCount? : number ;
/** Number of legacy permission restrictions for this app. Populated
only by the admin list endpoint (GET /admin/apps).
*/
restrictionCount? : number ;
/** Number of recorded app-open events for this app. Populated only by
the admin list endpoint (GET /admin/apps).
*/
openCount? : number ;
2026-04-20 09:20:50 +00:00
}
export interface CreateAppBody {
slug : string ;
nameAr : string ;
nameEn : string ;
/** @nullable */
descriptionAr? : string | null ;
/** @nullable */
descriptionEn? : string | null ;
iconName : string ;
route : string ;
color : string ;
isActive? : boolean ;
isSystem? : boolean ;
sortOrder? : number ;
2026-04-30 18:21:21 +00:00
/** Optional set of permission IDs to gate the new app on. Inserted with onConflictDoNothing so duplicates are tolerated. */
permissionIds? : number [ ] ;
2026-04-20 09:20:50 +00:00
}
export interface UpdateAppBody {
nameAr? : string ;
nameEn? : string ;
/** @nullable */
descriptionAr? : string | null ;
/** @nullable */
descriptionEn? : string | null ;
iconName? : string ;
route? : string ;
color? : string ;
isActive? : boolean ;
sortOrder? : number ;
}
export interface Service {
id : number ;
/** @nullable */
categoryId? : number | null ;
nameAr : string ;
nameEn : string ;
/** @nullable */
descriptionAr? : string | null ;
/** @nullable */
descriptionEn? : string | null ;
/** @nullable */
imageUrl? : string | null ;
/** @nullable */
price? : string | null ;
isAvailable : boolean ;
sortOrder : number ;
createdAt : string ;
updatedAt : string ;
2026-04-29 08:48:29 +00:00
/** Number of service_orders rows referencing this service. Populated
only by the list endpoint (GET /services) so the admin delete
dialog can warn before the first click. Omitted from single-service
responses.
*/
orderCount? : number ;
2026-04-20 09:20:50 +00:00
}
export interface CreateServiceBody {
/** @nullable */
categoryId? : number | null ;
nameAr : string ;
nameEn : string ;
/** @nullable */
descriptionAr? : string | null ;
/** @nullable */
descriptionEn? : string | null ;
/** @nullable */
imageUrl? : string | null ;
/** @nullable */
price? : string | null ;
isAvailable? : boolean ;
sortOrder? : number ;
}
export interface UpdateServiceBody {
/** @nullable */
categoryId? : number | null ;
nameAr? : string ;
nameEn? : string ;
/** @nullable */
descriptionAr? : string | null ;
/** @nullable */
descriptionEn? : string | null ;
/** @nullable */
imageUrl? : string | null ;
/** @nullable */
price? : string | null ;
isAvailable? : boolean ;
sortOrder? : number ;
}
export interface ServiceCategory {
id : number ;
nameAr : string ;
nameEn : string ;
sortOrder : number ;
createdAt : string ;
}
2026-04-21 18:24:20 +00:00
export interface ServiceOrderUser {
id : number ;
username : string ;
/** @nullable */
displayNameAr? : string | null ;
/** @nullable */
displayNameEn? : string | null ;
/** @nullable */
avatarUrl? : string | null ;
}
export interface ServiceOrderService {
id : number ;
nameAr : string ;
nameEn : string ;
/** @nullable */
imageUrl? : string | null ;
}
export type ServiceOrderStatus =
( typeof ServiceOrderStatus ) [ keyof typeof ServiceOrderStatus ] ;
export const ServiceOrderStatus = {
pending : "pending" ,
received : "received" ,
2026-04-21 18:34:14 +00:00
preparing : "preparing" ,
completed : "completed" ,
2026-04-21 18:24:20 +00:00
cancelled : "cancelled" ,
} as const ;
export interface ServiceOrder {
id : number ;
serviceId : number ;
2026-04-21 18:34:14 +00:00
userId : number ;
2026-04-21 18:24:20 +00:00
/** @nullable */
assignedTo? : number | null ;
/** @nullable */
notes? : string | null ;
status : ServiceOrderStatus ;
createdAt : string ;
2026-04-21 18:34:14 +00:00
updatedAt : string ;
2026-04-21 18:24:20 +00:00
service : ServiceOrderService ;
requester? : ServiceOrderUser | null ;
assignee? : ServiceOrderUser | null ;
}
export interface CreateServiceOrderBody {
serviceId : number ;
/**
* @maxLength 500
* @nullable
*/
notes? : string | null ;
}
export type UpdateServiceOrderStatusBodyStatus =
( typeof UpdateServiceOrderStatusBodyStatus ) [ keyof typeof UpdateServiceOrderStatusBodyStatus ] ;
export const UpdateServiceOrderStatusBodyStatus = {
2026-04-22 09:04:28 +00:00
pending : "pending" ,
received : "received" ,
2026-04-21 18:34:14 +00:00
preparing : "preparing" ,
completed : "completed" ,
2026-04-21 18:24:20 +00:00
cancelled : "cancelled" ,
} as const ;
export interface UpdateServiceOrderStatusBody {
status : UpdateServiceOrderStatusBodyStatus ;
}
2026-05-05 13:35:21 +00:00
export interface BulkDeleteServiceOrdersBody {
/**
* @minItems 1
* @maxItems 200
*/
ids : number [ ] ;
}
export interface BulkDeleteServiceOrdersResponse {
/** Ids that were successfully deleted. */
deletedIds : number [ ] ;
/** Ids that were skipped (not found, or caller is not authorized). */
failedIds : number [ ] ;
}
2026-04-20 09:20:50 +00:00
export interface ParticipantInfo {
id : number ;
username : string ;
/** @nullable */
displayNameAr? : string | null ;
/** @nullable */
displayNameEn? : string | null ;
/** @nullable */
avatarUrl? : string | null ;
isAdmin : boolean ;
}
2026-04-21 09:35:32 +00:00
export type MessageWithSenderKind =
( typeof MessageWithSenderKind ) [ keyof typeof MessageWithSenderKind ] ;
export const MessageWithSenderKind = {
user : "user" ,
group_renamed : "group_renamed" ,
members_added : "members_added" ,
member_removed : "member_removed" ,
2026-04-21 10:20:22 +00:00
member_left : "member_left" ,
admin_promoted : "admin_promoted" ,
2026-04-21 09:35:32 +00:00
} as const ;
export type MessageWithSenderMeta = { [ key : string ] : unknown } | null ;
2026-04-20 09:20:50 +00:00
export interface MessageWithSender {
id : number ;
conversationId : number ;
senderId : number ;
content : string ;
2026-04-21 09:35:32 +00:00
kind : MessageWithSenderKind ;
meta? : MessageWithSenderMeta ;
2026-04-20 09:20:50 +00:00
sender : ParticipantInfo ;
createdAt : string ;
updatedAt : string ;
}
export interface ConversationWithDetails {
id : number ;
/** @nullable */
nameAr? : string | null ;
/** @nullable */
nameEn? : string | null ;
2026-04-21 07:46:16 +00:00
/** @nullable */
avatarUrl? : string | null ;
2026-04-20 09:20:50 +00:00
isGroup : boolean ;
createdBy : number ;
participants : ParticipantInfo [ ] ;
lastMessage? : MessageWithSender | null ;
unreadCount : number ;
2026-04-21 08:29:01 +00:00
isMuted : boolean ;
isArchived : boolean ;
2026-04-20 09:20:50 +00:00
createdAt : string ;
updatedAt : string ;
}
export interface CreateConversationBody {
participantIds : number [ ] ;
/** @nullable */
nameAr? : string | null ;
/** @nullable */
nameEn? : string | null ;
2026-04-21 07:46:16 +00:00
/** @nullable */
avatarUrl? : string | null ;
2026-04-20 09:20:50 +00:00
isGroup? : boolean ;
}
2026-04-21 07:46:16 +00:00
export interface UpdateConversationBody {
/** @nullable */
avatarUrl? : string | null ;
2026-04-21 08:07:15 +00:00
/** @nullable */
nameAr? : string | null ;
/** @nullable */
nameEn? : string | null ;
}
2026-04-21 08:29:01 +00:00
export interface UpdateConversationStateBody {
isMuted? : boolean ;
isArchived? : boolean ;
}
2026-04-21 08:07:15 +00:00
export interface AddParticipantsBody {
userIds : number [ ] ;
2026-04-21 07:46:16 +00:00
}
2026-04-20 09:20:50 +00:00
export interface SendMessageBody {
content : string ;
}
export interface Notification {
id : number ;
userId : number ;
titleAr : string ;
titleEn : string ;
/** @nullable */
bodyAr? : string | null ;
/** @nullable */
bodyEn? : string | null ;
type : string ;
isRead : boolean ;
/** @nullable */
relatedId? : number | null ;
/** @nullable */
relatedType? : string | null ;
createdAt : string ;
}
2026-04-20 11:06:15 +00:00
export interface AppSettings {
siteNameAr : string ;
siteNameEn : string ;
2026-04-20 11:33:06 +00:00
registrationOpen : boolean ;
2026-04-20 12:28:25 +00:00
footerTextAr : string ;
footerTextEn : string ;
2026-04-20 11:06:15 +00:00
updatedAt? : string ;
}
2026-04-20 12:09:14 +00:00
export interface UpdateMyAppOrderBody {
/** App IDs in the desired display order */
order : number [ ] ;
}
2026-04-20 11:06:15 +00:00
export interface UpdateAppSettingsBody {
/**
* @minLength 1
* @maxLength 200
*/
siteNameAr? : string ;
/**
* @minLength 1
* @maxLength 200
*/
siteNameEn? : string ;
2026-04-20 11:33:06 +00:00
registrationOpen? : boolean ;
2026-04-20 12:28:25 +00:00
/**
* @minLength 1
* @maxLength 300
*/
footerTextAr? : string ;
/**
* @minLength 1
* @maxLength 300
*/
footerTextEn? : string ;
2026-04-20 11:06:15 +00:00
}
2026-04-20 10:55:11 +00:00
export interface RequestUploadUrlBody {
/** @minLength 1 */
name : string ;
/** @minimum 1 */
size : number ;
/** @minLength 1 */
contentType : string ;
}
export interface RequestUploadUrlResponse {
uploadURL : string ;
objectPath : string ;
metadata? : RequestUploadUrlBody ;
}
2026-04-20 09:20:50 +00:00
export interface HomeStats {
totalApps : number ;
totalServices : number ;
unreadNotifications : number ;
unreadMessages : number ;
totalUsers : number ;
}
2026-04-20 12:16:55 +00:00
2026-04-20 15:38:28 +00:00
export type AdminStatsRange =
( typeof AdminStatsRange ) [ keyof typeof AdminStatsRange ] ;
export const AdminStatsRange = {
"7d" : "7d" ,
"30d" : "30d" ,
"90d" : "90d" ,
2026-04-21 07:01:43 +00:00
custom : "custom" ,
2026-04-20 15:38:28 +00:00
} as const ;
2026-04-20 12:16:55 +00:00
export type AdminStatsSignupsByDayItem = {
date : string ;
count : number ;
} ;
2026-04-20 15:16:19 +00:00
export type AdminStatsAppOpensByDayItem = {
date : string ;
count : number ;
} ;
export type AdminStatsServicesCreatedByDayItem = {
date : string ;
count : number ;
} ;
2026-04-21 06:11:28 +00:00
export interface TopAppItem {
appId : number ;
slug : string ;
nameAr : string ;
nameEn : string ;
iconName : string ;
color : string ;
count : number ;
}
export interface TopUserItem {
userId : number ;
username : string ;
/** @nullable */
displayNameAr? : string | null ;
/** @nullable */
displayNameEn? : string | null ;
/** @nullable */
avatarUrl? : string | null ;
count : number ;
}
2026-04-20 12:16:55 +00:00
export interface AdminStats {
2026-04-20 15:38:28 +00:00
range : AdminStatsRange ;
rangeDays : number ;
2026-04-21 07:01:43 +00:00
/** Start date (YYYY-MM-DD UTC) of the selected window */
rangeFrom? : string ;
/** End date (YYYY-MM-DD UTC) of the selected window */
rangeTo? : string ;
2026-04-20 15:38:28 +00:00
newUsersInRange : number ;
newUsersPrevRange : number ;
2026-04-20 12:16:55 +00:00
activeServices : number ;
inactiveServices : number ;
signupsByDay : AdminStatsSignupsByDayItem [ ] ;
2026-04-20 15:16:19 +00:00
appOpensByDay : AdminStatsAppOpensByDayItem [ ] ;
2026-04-20 15:38:28 +00:00
appOpensInRange : number ;
appOpensPrevRange : number ;
2026-04-20 15:16:19 +00:00
servicesCreatedByDay : AdminStatsServicesCreatedByDayItem [ ] ;
2026-04-20 15:38:28 +00:00
servicesCreatedInRange : number ;
2026-04-21 06:11:28 +00:00
topApps : TopAppItem [ ] ;
mostActiveUsers : TopUserItem [ ] ;
2026-04-20 12:16:55 +00:00
}
2026-04-20 15:38:28 +00:00
2026-04-21 10:17:41 +00:00
export interface AppOpenByAppEntry {
id : number ;
createdAt : string ;
userId : number ;
username : string ;
/** @nullable */
displayNameAr? : string | null ;
/** @nullable */
displayNameEn? : string | null ;
/** @nullable */
avatarUrl? : string | null ;
}
export type AdminAppOpensByAppRange =
( typeof AdminAppOpensByAppRange ) [ keyof typeof AdminAppOpensByAppRange ] ;
export const AdminAppOpensByAppRange = {
"7d" : "7d" ,
"30d" : "30d" ,
"90d" : "90d" ,
custom : "custom" ,
} as const ;
export interface AdminAppOpensByApp {
appId : number ;
slug : string ;
nameAr : string ;
nameEn : string ;
iconName : string ;
color : string ;
range : AdminAppOpensByAppRange ;
rangeDays : number ;
rangeFrom : string ;
rangeTo : string ;
totalCount : number ;
2026-04-21 11:48:40 +00:00
limit : number ;
offset : number ;
/** @nullable */
nextOffset : number | null ;
2026-04-21 10:17:41 +00:00
opens : AppOpenByAppEntry [ ] ;
}
export interface AppOpenByUserEntry {
id : number ;
createdAt : string ;
appId : number ;
slug : string ;
nameAr : string ;
nameEn : string ;
iconName : string ;
color : string ;
}
export type AdminAppOpensByUserRange =
( typeof AdminAppOpensByUserRange ) [ keyof typeof AdminAppOpensByUserRange ] ;
export const AdminAppOpensByUserRange = {
"7d" : "7d" ,
"30d" : "30d" ,
"90d" : "90d" ,
custom : "custom" ,
} as const ;
export interface AdminAppOpensByUser {
userId : number ;
username : string ;
/** @nullable */
displayNameAr? : string | null ;
/** @nullable */
displayNameEn? : string | null ;
/** @nullable */
avatarUrl? : string | null ;
range : AdminAppOpensByUserRange ;
rangeDays : number ;
rangeFrom : string ;
rangeTo : string ;
totalCount : number ;
2026-04-21 11:48:40 +00:00
limit : number ;
offset : number ;
/** @nullable */
nextOffset : number | null ;
2026-04-21 10:17:41 +00:00
opens : AppOpenByUserEntry [ ] ;
}
2026-05-01 07:32:11 +00:00
export interface AppDependentGroupItem {
id : number ;
name : string ;
/** @nullable */
descriptionAr : string | null ;
/** @nullable */
descriptionEn : string | null ;
}
export interface AppDependentGroupsPage {
items : AppDependentGroupItem [ ] ;
totalCount : number ;
limit : number ;
offset : number ;
/** @nullable */
nextOffset : number | null ;
}
export interface AppDependentRestrictionItem {
id : number ;
name : string ;
/** @nullable */
descriptionAr : string | null ;
/** @nullable */
descriptionEn : string | null ;
/** Names of roles currently holding this permission. */
roles : string [ ] ;
}
export interface AppDependentRestrictionsPage {
items : AppDependentRestrictionItem [ ] ;
totalCount : number ;
limit : number ;
offset : number ;
/** @nullable */
nextOffset : number | null ;
}
export interface AppDependentOpenItem {
id : number ;
createdAt : string ;
userId : number ;
username : string ;
/** @nullable */
displayNameAr : string | null ;
/** @nullable */
displayNameEn : string | null ;
/** @nullable */
avatarUrl : string | null ;
}
export interface AppDependentOpensPage {
items : AppDependentOpenItem [ ] ;
totalCount : number ;
limit : number ;
offset : number ;
/** @nullable */
nextOffset : number | null ;
}
export interface ServiceDependentOrderItem {
id : number ;
status : string ;
/** @nullable */
notes : string | null ;
createdAt : string ;
userId : number ;
username : string ;
/** @nullable */
displayNameAr : string | null ;
/** @nullable */
displayNameEn : string | null ;
}
export interface ServiceDependentOrdersPage {
items : ServiceDependentOrderItem [ ] ;
totalCount : number ;
limit : number ;
offset : number ;
/** @nullable */
nextOffset : number | null ;
}
export interface UserDependentNoteItem {
id : number ;
title : string ;
isPinned : boolean ;
isArchived : boolean ;
updatedAt : string ;
}
2026-05-05 15:26:23 +00:00
export type NoteRecipientStatus =
( typeof NoteRecipientStatus ) [ keyof typeof NoteRecipientStatus ] ;
export const NoteRecipientStatus = {
unread : "unread" ,
read : "read" ,
replied : "replied" ,
archived : "archived" ,
} as const ;
export interface NoteUserSummary {
id : number ;
username : string ;
/** @nullable */
displayNameAr : string | null ;
/** @nullable */
displayNameEn : string | null ;
/** @nullable */
avatarUrl? : string | null ;
isActive? : boolean ;
}
export interface NoteRecipientSummary {
id : number ;
noteId? : number ;
recipientUserId : number ;
senderUserId : number ;
status : NoteRecipientStatus ;
sentAt : string ;
/** @nullable */
readAt : string | null ;
/** @nullable */
archivedAt : string | null ;
recipient? : NoteUserSummary | null ;
}
export interface SentNote {
id : number ;
userId : number ;
title : string ;
content : string ;
color : string ;
isPinned? : boolean ;
isArchived? : boolean ;
createdAt : string ;
updatedAt : string ;
recipients : NoteRecipientSummary [ ] ;
replyCount : number ;
}
export interface ReceivedNote {
id : number ;
title : string ;
content : string ;
color : string ;
createdAt : string ;
updatedAt : string ;
sender? : NoteUserSummary | null ;
recipientRowId : number ;
status : NoteRecipientStatus ;
sentAt : string ;
/** @nullable */
readAt : string | null ;
/** @nullable */
archivedAt : string | null ;
}
export interface NoteReply {
id : number ;
noteId : number ;
senderUserId : number ;
recipientUserId : number ;
content : string ;
createdAt : string ;
sender? : NoteUserSummary | null ;
}
export interface NoteThread {
id : number ;
title : string ;
content : string ;
color : string ;
/** @nullable */
createdAt? : string | null ;
/** @nullable */
updatedAt? : string | null ;
senderUserId : number ;
sender? : NoteUserSummary | null ;
isOwner : boolean ;
isAdmin : boolean ;
myStatus : NoteRecipientStatus | null ;
recipients : NoteRecipientSummary [ ] ;
replies : NoteReply [ ] ;
}
export interface SendNoteResult {
success : boolean ;
sent : number ;
}
2026-05-01 07:32:11 +00:00
export interface UserDependentNotesPage {
items : UserDependentNoteItem [ ] ;
totalCount : number ;
limit : number ;
offset : number ;
/** @nullable */
nextOffset : number | null ;
}
export interface UserDependentOrderItem {
id : number ;
status : string ;
/** @nullable */
notes : string | null ;
createdAt : string ;
serviceId : number ;
serviceNameAr : string ;
serviceNameEn : string ;
}
export interface UserDependentOrdersPage {
items : UserDependentOrderItem [ ] ;
totalCount : number ;
limit : number ;
offset : number ;
/** @nullable */
nextOffset : number | null ;
}
export interface UserDependentConversationItem {
id : number ;
/** @nullable */
nameAr : string | null ;
/** @nullable */
nameEn : string | null ;
isGroup : boolean ;
createdAt : string ;
}
export interface UserDependentConversationsPage {
items : UserDependentConversationItem [ ] ;
totalCount : number ;
limit : number ;
offset : number ;
/** @nullable */
nextOffset : number | null ;
}
export interface UserDependentMessageItem {
id : number ;
content : string ;
kind : string ;
createdAt : string ;
conversationId : number ;
/** @nullable */
conversationNameAr : string | null ;
/** @nullable */
conversationNameEn : string | null ;
conversationIsGroup : boolean ;
}
export interface UserDependentMessagesPage {
items : UserDependentMessageItem [ ] ;
totalCount : number ;
limit : number ;
offset : number ;
/** @nullable */
nextOffset : number | null ;
}
2026-04-27 11:28:20 +00:00
export interface AuditLogActor {
id : number ;
username : string ;
/** @nullable */
displayNameAr? : string | null ;
/** @nullable */
displayNameEn? : string | null ;
/** @nullable */
avatarUrl? : string | null ;
}
2026-04-29 13:16:02 +00:00
export interface RolePermissionAuditEntry {
id : number ;
roleId : number ;
previousPermissionIds : number [ ] ;
newPermissionIds : number [ ] ;
addedPermissionIds : number [ ] ;
removedPermissionIds : number [ ] ;
createdAt : string ;
actor : AuditLogActor | null ;
}
2026-04-30 10:45:07 +00:00
export interface RolePermissionAuditList {
entries : RolePermissionAuditEntry [ ] ;
totalCount : number ;
limit : number ;
offset : number ;
/** @nullable */
nextOffset : number | null ;
}
2026-04-30 11:58:18 +00:00
export type PermissionAuditEntryTargetKind =
( typeof PermissionAuditEntryTargetKind ) [ keyof typeof PermissionAuditEntryTargetKind ] ;
export const PermissionAuditEntryTargetKind = {
user : "user" ,
group : "group" ,
app : "app" ,
} as const ;
export type PermissionAuditEntryChangeKind =
( typeof PermissionAuditEntryChangeKind ) [ keyof typeof PermissionAuditEntryChangeKind ] ;
export const PermissionAuditEntryChangeKind = {
userroles : "user.roles" ,
usergroups : "user.groups" ,
groupusers : "group.users" ,
grouproles : "group.roles" ,
groupapps : "group.apps" ,
apppermissions : "app.permissions" ,
} as const ;
export interface PermissionAuditEntry {
id : number ;
targetKind : PermissionAuditEntryTargetKind ;
targetId : number ;
changeKind : PermissionAuditEntryChangeKind ;
previousIds : number [ ] ;
newIds : number [ ] ;
addedIds : number [ ] ;
removedIds : number [ ] ;
createdAt : string ;
actor : AuditLogActor | null ;
}
export interface PermissionAuditList {
entries : PermissionAuditEntry [ ] ;
totalCount : number ;
limit : number ;
offset : number ;
/** @nullable */
nextOffset : number | null ;
}
2026-04-27 11:28:20 +00:00
/**
* @nullable
*/
export type AuditLogEntryMetadata = { [ key : string ] : unknown } | null ;
export interface AuditLogEntry {
id : number ;
action : string ;
targetType : string ;
/** @nullable */
targetId : number | null ;
/** @nullable */
metadata : AuditLogEntryMetadata ;
createdAt : string ;
actor : AuditLogActor | null ;
}
export interface AuditLogList {
entries : AuditLogEntry [ ] ;
totalCount : number ;
limit : number ;
offset : number ;
/** @nullable */
nextOffset : number | null ;
/** All distinct action names present in the audit log (for building filter UI). */
actions : string [ ] ;
}
2026-04-27 12:07:07 +00:00
export type DeleteAppParams = {
/**
* Force deletion of an app that has dependent records (records an audit log entry).
*/
force? : boolean ;
} ;
export type DeleteServiceParams = {
/**
* Force deletion of a service that has existing orders (records an audit log entry).
*/
force? : boolean ;
} ;
2026-04-21 11:29:39 +00:00
export type LeaveConversationBody = {
/** When the leaver is the only admin, optionally name a specific
remaining member to promote. Omit (or send null) to keep the
automatic behavior of promoting the longest-tenured member.
*/
successorId? : number | null ;
} ;
2026-04-22 08:28:31 +00:00
export type ListUsersParams = {
/**
* Free-text search across username, email, and display names
*/
q? : string ;
/**
* Filter to users that belong to the given group
*/
groupId? : number ;
/**
* Filter by active/disabled state
*/
status? : ListUsersStatus ;
} ;
export type ListUsersStatus =
( typeof ListUsersStatus ) [ keyof typeof ListUsersStatus ] ;
export const ListUsersStatus = {
active : "active" ,
disabled : "disabled" ,
} as const ;
2026-04-27 12:07:07 +00:00
export type DeleteUserParams = {
/**
* Force deletion of a user that owns dependent records (records an audit log entry).
*/
force? : boolean ;
} ;
2026-04-29 13:16:02 +00:00
export type GetRolePermissionAuditParams = {
/**
* @minimum 1
2026-04-30 10:45:07 +00:00
* @maximum 200
2026-04-29 13:16:02 +00:00
*/
limit? : number ;
2026-04-30 10:45:07 +00:00
/**
* @minimum 0
*/
offset? : number ;
/**
* Restrict results to entries authored by the given user. Use
`0` or omit to return entries from any actor.
2026-05-01 16:11:43 +00:00
* @minimum 0
*/
actorUserId? : number ;
/**
* Start date (inclusive, YYYY-MM-DD UTC).
*/
from ? : string ;
/**
* End date (inclusive, YYYY-MM-DD UTC).
*/
to? : string ;
} ;
export type ExportRolePermissionAuditCsvParams = {
/**
* Restrict results to entries authored by the given user. Use
`0` or omit to return entries from any actor.
2026-04-30 10:45:07 +00:00
* @minimum 0
*/
actorUserId? : number ;
/**
* Start date (inclusive, YYYY-MM-DD UTC).
*/
from ? : string ;
/**
* End date (inclusive, YYYY-MM-DD UTC).
*/
to? : string ;
2026-04-29 13:16:02 +00:00
} ;
2026-04-22 08:28:31 +00:00
export type ListGroupsParams = {
q? : string ;
} ;
2026-04-22 11:05:34 +00:00
export type DeleteGroupParams = {
/**
* Force deletion of a non-empty group (records an audit log entry).
*/
force? : boolean ;
} ;
2026-04-30 11:58:18 +00:00
export type GetUserPermissionAuditParams = {
/**
* @minimum 1
* @maximum 200
*/
limit? : number ;
/**
* @minimum 0
*/
offset? : number ;
/**
* @minimum 0
*/
actorUserId? : number ;
from ? : string ;
to? : string ;
} ;
export type GetGroupPermissionAuditParams = {
/**
* @minimum 1
* @maximum 200
*/
limit? : number ;
/**
* @minimum 0
*/
offset? : number ;
/**
* @minimum 0
*/
actorUserId? : number ;
from ? : string ;
to? : string ;
} ;
export type GetAppPermissionAuditParams = {
/**
* @minimum 1
* @maximum 200
*/
limit? : number ;
/**
* @minimum 0
*/
offset? : number ;
/**
* @minimum 0
*/
actorUserId? : number ;
from ? : string ;
to? : string ;
} ;
2026-04-20 15:38:28 +00:00
export type GetAdminStatsParams = {
/**
2026-04-21 07:01:43 +00:00
* Time range for trend stats. Use "custom" with from/to.
2026-04-20 15:38:28 +00:00
*/
range? : GetAdminStatsRange ;
2026-04-21 07:01:43 +00:00
/**
* Start date (inclusive, YYYY-MM-DD UTC) when range=custom
*/
from ? : string ;
/**
* End date (inclusive, YYYY-MM-DD UTC) when range=custom
*/
to? : string ;
2026-04-20 15:38:28 +00:00
} ;
export type GetAdminStatsRange =
( typeof GetAdminStatsRange ) [ keyof typeof GetAdminStatsRange ] ;
export const GetAdminStatsRange = {
"7d" : "7d" ,
"30d" : "30d" ,
"90d" : "90d" ,
2026-04-21 07:01:43 +00:00
custom : "custom" ,
2026-04-20 15:38:28 +00:00
} as const ;
2026-04-21 10:17:41 +00:00
export type GetAdminAppOpensByAppParams = {
range? : GetAdminAppOpensByAppRange ;
from ? : string ;
to? : string ;
2026-04-21 11:48:40 +00:00
/**
* @minimum 1
* @maximum 200
*/
limit? : number ;
/**
* @minimum 0
*/
offset? : number ;
2026-04-21 10:17:41 +00:00
} ;
export type GetAdminAppOpensByAppRange =
( typeof GetAdminAppOpensByAppRange ) [ keyof typeof GetAdminAppOpensByAppRange ] ;
export const GetAdminAppOpensByAppRange = {
"7d" : "7d" ,
"30d" : "30d" ,
"90d" : "90d" ,
custom : "custom" ,
} as const ;
export type GetAdminAppOpensByUserParams = {
range? : GetAdminAppOpensByUserRange ;
from ? : string ;
to? : string ;
2026-04-21 11:48:40 +00:00
/**
* @minimum 1
* @maximum 200
*/
limit? : number ;
/**
* @minimum 0
*/
offset? : number ;
2026-04-21 10:17:41 +00:00
} ;
export type GetAdminAppOpensByUserRange =
( typeof GetAdminAppOpensByUserRange ) [ keyof typeof GetAdminAppOpensByUserRange ] ;
export const GetAdminAppOpensByUserRange = {
"7d" : "7d" ,
"30d" : "30d" ,
"90d" : "90d" ,
custom : "custom" ,
} as const ;
2026-04-27 11:28:20 +00:00
export type ListAuditLogsParams = {
/**
* Exact action name to filter by (e.g. "group.force_delete").
*/
action? : string ;
2026-04-29 10:32:54 +00:00
/**
* When true, restrict results to forced deletions only — i.e. rows
with action `group.force_delete`, `user.force_delete`,
`app.force_delete`, `service.force_delete`, or any
`group.delete`/`user.delete`/`app.delete` row whose metadata
contains `force: true`. Overrides the `action` filter when set.
*/
forcedOnly? : boolean ;
2026-04-27 11:28:20 +00:00
/**
* Start date (inclusive, YYYY-MM-DD UTC).
*/
from ? : string ;
/**
* End date (inclusive, YYYY-MM-DD UTC).
*/
to? : string ;
2026-04-30 07:25:16 +00:00
/**
* Restrict results to entries whose `target_type` exactly matches
(e.g. "group", "app", "role", "user", "service", "settings").
Combines with `targetId` and the other filters.
*/
targetType? : string ;
/**
* Restrict results to entries whose `target_id` exactly matches.
Typically used together with `targetType` to focus on the history
of a single entity.
* @minimum 1
*/
targetId? : number ;
2026-05-01 06:54:26 +00:00
/**
* Restrict results to entries written by a specific acting user
(matches `actor_user_id`). Combines with the other filters.
* @minimum 1
*/
actorUserId? : number ;
2026-04-27 11:28:20 +00:00
/**
* @minimum 1
* @maximum 200
*/
limit? : number ;
/**
* @minimum 0
*/
offset? : number ;
} ;
2026-04-29 06:56:09 +00:00
export type ExportAuditLogsCsvParams = {
/**
* Exact action name to filter by (e.g. "group.force_delete").
*/
action? : string ;
2026-04-29 10:32:54 +00:00
/**
* When true, restrict the export to forced deletions only.
See the list endpoint for the exact set of matching rows.
Overrides the `action` filter when set.
*/
forcedOnly? : boolean ;
2026-04-29 06:56:09 +00:00
/**
* Start date (inclusive, YYYY-MM-DD UTC).
*/
from ? : string ;
/**
* End date (inclusive, YYYY-MM-DD UTC).
*/
to? : string ;
2026-04-30 07:25:16 +00:00
/**
* Restrict the export to entries whose `target_type` exactly matches.
Combines with `targetId` and the other filters.
*/
targetType? : string ;
/**
* Restrict the export to entries whose `target_id` exactly matches.
* @minimum 1
*/
targetId? : number ;
2026-05-01 06:54:26 +00:00
/**
* Restrict the export to entries written by a specific acting user.
* @minimum 1
*/
actorUserId? : number ;
2026-04-29 06:56:09 +00:00
} ;
2026-05-01 07:32:11 +00:00
export type GetAdminAppDependentGroupsParams = {
/**
* @minimum 1
* @maximum 200
*/
limit? : number ;
/**
* @minimum 0
*/
offset? : number ;
} ;
export type GetAdminAppDependentRestrictionsParams = {
/**
* @minimum 1
* @maximum 200
*/
limit? : number ;
/**
* @minimum 0
*/
offset? : number ;
} ;
export type GetAdminAppDependentOpensParams = {
/**
* @minimum 1
* @maximum 200
*/
limit? : number ;
/**
* @minimum 0
*/
offset? : number ;
} ;
export type GetAdminServiceDependentOrdersParams = {
/**
* @minimum 1
* @maximum 200
*/
limit? : number ;
/**
* @minimum 0
*/
offset? : number ;
} ;
2026-05-05 15:01:18 +00:00
export type ListReceivedNotesParams = {
archived? : boolean ;
} ;
export type SendNoteBody = {
recipientUserIds : number [ ] ;
} ;
export type ArchiveReceivedNoteBody = {
archived : boolean ;
} ;
export type ReplyToNoteBody = {
content : string ;
/** Required when the note owner replies and there is more than one recipient. */
recipientUserId? : number ;
} ;
2026-05-01 07:32:11 +00:00
export type GetAdminUserDependentNotesParams = {
/**
* @minimum 1
* @maximum 200
*/
limit? : number ;
/**
* @minimum 0
*/
offset? : number ;
} ;
export type GetAdminUserDependentOrdersParams = {
/**
* @minimum 1
* @maximum 200
*/
limit? : number ;
/**
* @minimum 0
*/
offset? : number ;
} ;
export type GetAdminUserDependentConversationsParams = {
/**
* @minimum 1
* @maximum 200
*/
limit? : number ;
/**
* @minimum 0
*/
offset? : number ;
} ;
export type GetAdminUserDependentMessagesParams = {
/**
* @minimum 1
* @maximum 200
*/
limit? : number ;
/**
* @minimum 0
*/
offset? : number ;
} ;