# Fitness Core Backend Reference ## Purpose This file is a code-first reference for the current backend implementation in `Fitness_Core_BE`. It covers: - project structure - runtime configuration - authentication - response envelopes - REST endpoints - legacy RPC-style endpoints - request and response DTOs - helpers - services, repositories, and models - existing support files such as Postman collections and Markdown files This document reflects the codebase as currently implemented on July 6, 2026. ## Project Overview The backend is an ASP.NET Core Web API project with: - Entity Framework Core + MySQL - controller-based HTTP APIs - a mixed API style: - newer resource-oriented REST endpoints in `Controllers/ClientController.cs`, `Controllers/AdminController.cs`, and `Controllers/AgentController.cs` - older function-dispatch endpoints in `Controllers/APIController.cs` - SignalR chat hub at `/hubs/chat` - helper-based JWT validation for normal user flows - custom API-key authentication for on-prem agent flows - AI orchestration services for meal/workout planning ## Top-Level Structure - `Controllers/` - HTTP API entrypoints - `Services/` - business logic - `Services/FunctionHandler/` - legacy function router layer for `ApiRequest` - `Repos/` - repository implementations - `Interfaces/` - repository and service contracts - `Models/` - EF entities, enums, IO contracts - `DTOs/` - request/response DTOs - `Helpers/` - auth, payload, response, crypto, parsing, and utility helpers - `AI/` - AI client and meal/workout plan orchestration - `Infra/UoW/` - unit-of-work abstraction - `Hubs/` - SignalR hub(s) - `Migrations/` - EF Core migrations - `postman/` and `.postman/` - API collections - `README.md` - current content is only a short placeholder ## Runtime and DI Setup `Program.cs` configures: - controllers with `ReferenceHandler.IgnoreCycles` - Swagger in development - MySQL `AppDBContext` - permissive CORS policy named `AllowAll` - SignalR - dependency injection for repositories, services, helpers, function handlers, agent auth, and AI services - `app.MapControllers()` - `app.MapHub("/hubs/chat")` ## Authentication and Authorization ### 1. Standard user/client/admin flows The custom action filter `JwtMiddleware.CustomMiddlewareAttribute` is used on protected endpoints. It accepts the token from: - `MobileAuthToken: Bearer ` request header, or - `access_token` cookie It validates against: - `Jwt:PublicKey` - `Jwt:Issuer` - `Jwt:Audience` It populates: - `HttpContext.Items["UserId"]` - `HttpContext.Items["Email"]` - `HttpContext.Items["UserType"]` - `HttpContext.Items["RoleId"]` ### 2. Request-access token for onboarding `RequestAccessTokenHelper` creates a short-lived JWT used between OTP verification and onboarding request creation. Claims: - `MobileNumber` - `Purpose = RequestAccess` Configuration: - `RequestAccessToken:SigningKey` - `RequestAccessToken:ExpiresInMinutes` ### 3. On-prem agent authentication The agent flow uses `X-Api-Key`. Implementation: - `Auth/AgentApiKeyAuthenticationHandler.cs` - policy name: `AgentApiKey` Resolved server-side claims: - `AgentId` - `FKClientId` Important behavior: - the backend never trusts `clientId` or `agentId` from the request body for authenticated agent endpoints - the API key is stored hashed with SHA-256 via `ApiKeyHelper` ## Standard Response Envelopes ### Generic API envelope Most endpoints return: ```json { "statusCode": 200, "message": "success", "data": {} } ``` Code types: - `Models/IOs/ApiResponse.cs` - `Helpers/ApiResponseHelper.cs` ### Legacy RPC request envelope Used by the old `POST /api/...` dispatcher endpoints: ```json { "functionName": "SomeFunction", "payload": {}, "reference": "optional caller reference" } ``` Type: - `Models/IOs/ApiRequest.cs` ## HTTP Surface ## A. `APIController` legacy dispatcher (`/api`) This controller mixes one health endpoint, one document download endpoint, and many RPC-style POST endpoints. ### A1. Direct endpoints | Method | Path | Auth | Request | Response | |---|---|---|---|---| | `GET` | `/api/status` | `CustomMiddleware` | none | `200 OK` with `{ status, timestamp }` | | `GET` | `/api/docService/{docId}` | anonymous | route param `docId` | file download or error string | ### A2. RPC dispatch endpoints All of these accept `ApiRequest` unless otherwise noted. | Method | Path | Auth | |---|---|---| | `POST` | `/api/ticket` | `CustomMiddleware` | | `POST` | `/api/activitylog` | none | | `POST` | `/api/client` | `CustomMiddleware` | | `POST` | `/api/auth` | none | | `POST` | `/api/VerifyOTP` | `CustomMiddleware` | | `POST` | `/api/refreshToken` | anonymous | | `POST` | `/api/logout` | anonymous | | `POST` | `/api/staff` | `CustomMiddleware` | | `POST` | `/api/clientinvoice` | `CustomMiddleware` | | `POST` | `/api/customer` | `CustomMiddleware` | | `POST` | `/api/customerinvoice` | `CustomMiddleware` | | `POST` | `/api/customerplan` | `CustomMiddleware` | | `POST` | `/api/customersubscription` | `CustomMiddleware` | | `POST` | `/api/meal` | `CustomMiddleware` | | `POST` | `/api/workout` | `CustomMiddleware` | | `POST` | `/api/document` | `CustomMiddleware` | | `POST` | `/api/feed` | `CustomMiddleware` | | `POST` | `/api/accessdevice` | none | | `POST` | `/api/attendance` | `CustomMiddleware` | | `POST` | `/api/chat` | `CustomMiddleware` | | `POST` | `/api/initChat` | `CustomMiddleware` | | `POST` | `/api/payment` | `CustomMiddleware` | | `POST` | `/api/clientstat` | `CustomMiddleware` | | `POST` | `/api/register` | none | ### A3. Function names supported by each legacy dispatcher #### `/api/activitylog` - `LogActivity` - `GetActivityLogs` #### `/api/auth` - `SendOtp` - `VerifyOTP` - `IsAvailable` - `RegisterUser` - `UpdateUser` - `GetUserDetails` - `LoginUser` - `RefreshToken` - `VerifyOtpForLogin` - `LogOut` `POST /api/VerifyOTP` forces `FunctionName = "VerifyOTP"`. `POST /api/refreshToken` forces `FunctionName = "RefreshToken"`. `POST /api/logout` forces `FunctionName = "LogOut"`. #### `/api/client` - `GetClientList` - `GetClientById` - `GetCustomerDetailsById` - `CreateCustomerWithPlans` - `UpdateCustomerByClient` - `GetCustomersByClientId` - `GetCustomerPlansByClientId` - `RegisterClient` - `GetPackageList` - `GetAllCustomers` - `DeleteCustomerByClient` - `ClientLogOut` - `GetAllCustomerPlans` - `GetMealPlansByClientId` - `GetWorkoutPlansByClientId` - `GetMealPlanById` - `GetWorkoutPlanById` - `GetCustomerPlanById` - `GetOwnCards` #### `/api/staff` - `GetAllStaff` - `GetStaffById` - `GetStaffByClientId` - `CreateStaff` - `UpdateStaff` - `DeleteStaff` #### `/api/clientinvoice` - `CreateClientInvoiceFromSubscription` - `GetClientInvoiceById` - `GetClientInvoicesByClientId` - `GetClientInvoicesByUserId` - `UpdateClientInvoiceStatus` - `CalculateClientInvoiceTotal` #### `/api/customer` - `CreateCustomer` - `DeleteCustomer` - `UpdateCustomer` - `GetCustomerMealPlan` - `GetCustomerMealPlanById` - `GetCustomerWorkOutPlan` - `GetCustomerWorkoutPlanById` - `FollowMealPlan` - `GetFollowedMealPlans` - `GetFollowedWorkoutPlans` - `FollowWorkOutPlan` - `GetClientDataById` - `CreateCusHealthRec` - `CreateCusProgressRec` - `UpdateCusHealthRec` - `UpdateCusProgressRec` - `UpdateCustomerTargetNutritions` - `GetClientGyms` - `GetCustomerProgress` - `UpdateWeeklyProgress` - `GetWeeklyProgressForCustomer` - `GetCusBasicDetails` - `GetCusHealthDetails` - `GetCusProgressDetails` - `CreateFeed` - `GetOwnCards` #### `/api/customerinvoice` - `CreateCustomerInvoiceFromSubscription` - `GetCustomerInvoiceById` - `GetCustomerInvoicesByCustomerId` - `GetCustomerInvoicesByClientId` - `UpdateCustomerInvoiceStatus` - `CalculateCustomerInvoiceTotal` #### `/api/customerplan` - `GetAllCustomerPlans` - `GetCustomerPlanById` - `CreateCustomerPlan` - `UpdateCustomerPlan` - `DeleteCustomerPlan` #### `/api/customersubscription` - `CreateCustomerSubscription` - `GetCustomerSubscriptionById` - `GetCustomerSubscriptionsByCustomerId` - `GetActiveSubscriptionByCustomerId` #### `/api/meal` - `GetMealCategoryList` - `CreateMealCategory` - `GetMealPlanList` - `GetMealPlanById` - `GetMealPlanByCustomerId` - `CreateMealPlan` - `CreateCustomerMealPlan` - `UpdateMealPlan` - `GetMealItemsByMealPlanId` - `CreateMealItem` - `DeleteMealPlan` #### `/api/workout` - `GetWorkoutCategoryList` - `CreateWorkoutCategory` - `GetWorkoutPlanList` - `GetWorkoutPlanById` - `GetWorkoutPlanByCustomerId` - `CreateWorkoutPlan` - `CreateCustomerWorkout` - `UpdateWorkoutPlan` - `DeleteWorkoutPlan` - `GetWorkoutItemsByWorkoutPlanId` - `CreateWorkoutItem` #### `/api/document` - `UploadDocument` - `GetDocumentsByUserId` - `GetDocumentById` - `RemoveDocument` #### `/api/feed` - `GetFeedPostById` - `GetFeedList` - `Like` - `Unlike` - `IsLiked` - `CreateFeed` - `ShowFeedByClientId` - `DeleteFeedByPostId` #### `/api/accessdevice` - `AddDevice` - `RemoveDevice` - `GeneratePairingCode` - `AddUser` - `WhiteListMember` - `BlackListMember` #### `/api/attendance` - `GetAllAttendanceRecords` - `GetAttendanceCounts` - `GetTodayAttendance` #### `/api/chat` Current function map in code: - `GetOrCreateChatAsync` - `GetClientById` -> calls `SendMessageAsync` - `RegisterClient` -> calls `GetMessagesAsync` These function names look legacy/inconsistent, but this is the current implementation. #### `/api/payment` - `CreateCustomerPayment` - `CreateClientPayment` - `GetPaymentById` - `GetPaymentsByCustomerInvoice` - `GetPaymentsByClientInvoice` - `ApprovePayment` #### `/api/clientstat` - `GetTotalCustomerCount` - `GetMonthlyCustomerCount` - `GetTotalWorkoutPlanCount` - `GetTotalMealPlanCount` - `GetLastMonthCustomerCount` - `GetLastFiveAttendances` - `GetLastFivePayments` - `GetLastMonthRevenue` - `GetMonthlyRevenueVariation` - `GetTotalRevenue` - `GetClientStatSummary` #### `/api/register` - `CreateCustomer` - `RegisterClient` ## B. `AdminController` (`/api/admin`) All endpoints are protected by `CustomMiddleware`. | Method | Path | Request | Response | |---|---|---|---| | `GET` | `/api/admin/onboarding-requests` | query: `OnboardingRequestQuery` | `ApiResponse>` | | `GET` | `/api/admin/onboarding-requests/{id}` | route `id` | `ApiResponse` | | `PATCH` | `/api/admin/onboarding-requests/{id}/status` | body: `UpdateOnboardingStatusRequest` | `ApiResponse` | | `POST` | `/api/admin/onboarding-requests/{id}/resend-activation-link` | route `id` | `ApiResponse` with `{ sent = true }` | | `GET` | `/api/admin/payout-kyc` | query: `status` | `ApiResponse>` | | `GET` | `/api/admin/payout-kyc/{clientId}` | route `clientId` | `ApiResponse` | | `PATCH` | `/api/admin/payout-kyc/{clientId}/status` | body: `ReviewPayoutKycRequest` | `ApiResponse` | | `GET` | `/api/admin/clients` | query: `ClientDirectoryQuery` | `ApiResponse>` | | `GET` | `/api/admin/clients/{id}` | route `id` | `ApiResponse` | ## C. `ClientController` (`/api/client`) ### C1. Onboarding request access | Method | Path | Auth | Request | Response | |---|---|---|---|---| | `POST` | `/api/client/onboarding/requests/mobile-check` | none | `MobileNumberCheckRequest` | `ApiResponse` | | `POST` | `/api/client/onboarding/requests/otp` | none | `SendMobileOtpRequest` | `ApiResponse` | | `POST` | `/api/client/onboarding/requests/otp/verify` | none | `VerifyMobileOtpRequest` | `ApiResponse` | | `POST` | `/api/client/onboarding/requests` | bearer request-access token | `CreateOnboardingRequest` | `ApiResponse` | | `GET` | `/api/client/onboarding/sandbox/{sandboxToken}/status` | none | route `sandboxToken` | `ApiResponse` | | `PATCH` | `/api/client/onboarding/sandbox/{sandboxToken}/progress` | none | `SandboxProgressUpdate` | `ApiResponse` | ### C2. Activation | Method | Path | Auth | Request | Response | |---|---|---|---|---| | `POST` | `/api/client/activation/{activationToken}/email/otp` | none | `SendEmailOtpRequest` | `ApiResponse` | | `POST` | `/api/client/activation/{activationToken}/email/otp/verify` | none | `VerifyOtpCodeRequest` | `ApiResponse` with `{ emailVerified = true }` | | `POST` | `/api/client/activation/{activationToken}/nic` | none | multipart form: `nicNumber`, `frontImage`, `backImage` | `ApiResponse` | | `PUT` | `/api/client/activation/{activationToken}/gym-profile` | none | `GymProfileRequest` | `ApiResponse` | | `POST` | `/api/client/activation/{activationToken}/payment-method` | none | `SetPaymentMethodRequest` | `ApiResponse` | | `POST` | `/api/client/activation/{activationToken}/charge` | none | none | `ApiResponse` | | `GET` | `/api/client/activation/{activationToken}/checklist` | none | route `activationToken` | `ApiResponse>` | | `GET` | `/api/client/activation/{activationToken}/status` | none | route `activationToken` | `ApiResponse` | ### C3. Own profile and business | Method | Path | Auth | Request | Response | |---|---|---|---|---| | `GET` | `/api/client/me` | `CustomMiddleware` | none | `ApiResponse` | | `GET` | `/api/client/packages` | `CustomMiddleware` | none | `ApiResponse` | ### C4. Customer management | Method | Path | Auth | Request | Response | |---|---|---|---|---| | `GET` | `/api/client/customers` | `CustomMiddleware` | none | `ApiResponse` | | `GET` | `/api/client/customers/{customerId}` | `CustomMiddleware` | route `customerId` | `ApiResponse` | | `POST` | `/api/client/customers` | `CustomMiddleware` | `CreateCustomerWithPlansRequest` | `ApiResponse` | | `PUT` | `/api/client/customers/{customerId}` | `CustomMiddleware` | `UpdateCustomerByClientRequest` | `ApiResponse` | | `DELETE` | `/api/client/customers/{customerId}` | `CustomMiddleware` | query `softDelete=true` optional | `ApiResponse` | ### C5. Staff management | Method | Path | Auth | Request | Response | |---|---|---|---|---| | `GET` | `/api/client/staff` | `CustomMiddleware` | none | `ApiResponse` | | `GET` | `/api/client/staff/{staffId}` | `CustomMiddleware` | route `staffId` | `ApiResponse` | | `POST` | `/api/client/staff` | `CustomMiddleware` | `CreateStaffRequest` | `ApiResponse` | | `PUT` | `/api/client/staff/{staffId}` | `CustomMiddleware` | `UpdateStaffRequest` | `ApiResponse` | | `DELETE` | `/api/client/staff/{staffId}` | `CustomMiddleware` | query `softDelete=true` optional | `ApiResponse` | ### C6. Invoices `customer-invoices` here means platform invoices billed to the gym. `member-invoices` means invoices billed to gym members. | Method | Path | Auth | Request | Response | |---|---|---|---|---| | `GET` | `/api/client/customer-invoices` | `CustomMiddleware` | none | `ApiResponse` | | `GET` | `/api/client/customer-invoices/{id}` | `CustomMiddleware` | route `id` | `ApiResponse` | | `GET` | `/api/client/member-invoices` | `CustomMiddleware` | none | `ApiResponse` | | `GET` | `/api/client/member-invoices/{id}` | `CustomMiddleware` | route `id` | `ApiResponse` | ### C7. Dashboard stats | Method | Path | Auth | Request | Response | |---|---|---|---|---| | `GET` | `/api/client/stats/summary` | `CustomMiddleware` | none | `ApiResponse` | | `GET` | `/api/client/stats/monthly-revenue` | `CustomMiddleware` | none | `ApiResponse` | | `GET` | `/api/client/stats/recent-payments` | `CustomMiddleware` | none | `ApiResponse` | | `GET` | `/api/client/stats/recent-attendance` | `CustomMiddleware` | none | `ApiResponse` | ### C8. Payments enablement | Method | Path | Auth | Request | Response | |---|---|---|---|---| | `GET` | `/api/client/payments/tracks` | `CustomMiddleware` | none | `ApiResponse>` | | `POST` | `/api/client/payments/track-selection` | `CustomMiddleware` | `SelectPaymentTrackRequest` | `ApiResponse` | | `POST` | `/api/client/payments/kyc` | `CustomMiddleware` | multipart form: `brCertificate`, `bankProof` | `ApiResponse` | | `GET` | `/api/client/payments/kyc/status` | `CustomMiddleware` | none | `ApiResponse` with `{ kycStatus }` | | `GET` | `/api/client/payments/wallet` | `CustomMiddleware` | none | `ApiResponse` | | `GET` | `/api/client/payments/payout-schedule` | `CustomMiddleware` | none | `ApiResponse` | ### C9. Attendance | Method | Path | Auth | Request | Response | |---|---|---|---|---| | `GET` | `/api/client/attendance` | `CustomMiddleware` | none | `ApiResponse` | | `GET` | `/api/client/attendance/today` | `CustomMiddleware` | none | `ApiResponse` | | `GET` | `/api/client/attendance/counts` | `CustomMiddleware` | query `fromDate`, `toDate` | `ApiResponse` | ### C10. Membership plans | Method | Path | Auth | Request | Response | |---|---|---|---|---| | `GET` | `/api/client/plans` | `CustomMiddleware` | query `includeInactive=false` | `ApiResponse` | | `GET` | `/api/client/plans/{id}` | `CustomMiddleware` | route `id` | `ApiResponse` | | `POST` | `/api/client/plans` | `CustomMiddleware` | `CreateCustomerPlanRequest` | `ApiResponse` | | `PUT` | `/api/client/plans/{id}` | `CustomMiddleware` | `UpdateCustomerPlanRequest` | `ApiResponse` | | `DELETE` | `/api/client/plans/{id}` | `CustomMiddleware` | route `id` | `ApiResponse` | ### C11. Workout plans | Method | Path | Auth | Request | Response | |---|---|---|---|---| | `GET` | `/api/client/workout-plans` | `CustomMiddleware` | none | `ApiResponse` | | `GET` | `/api/client/workout-plans/{id}` | `CustomMiddleware` | route `id` | `ApiResponse` | | `POST` | `/api/client/workout-plans` | `CustomMiddleware` | `WorkoutPlanRequest` | `ApiResponse` | | `PUT` | `/api/client/workout-plans/{id}` | `CustomMiddleware` | `WorkoutPlanRequest` | `ApiResponse` | | `DELETE` | `/api/client/workout-plans/{id}` | `CustomMiddleware` | route `id` | `ApiResponse` | | `GET` | `/api/client/workout-plans/{id}/items` | `CustomMiddleware` | route `id` | `ApiResponse` | | `POST` | `/api/client/workout-plans/{id}/items` | `CustomMiddleware` | `WorkoutItemRequest` | `ApiResponse` | | `GET` | `/api/client/workout-plans/categories` | `CustomMiddleware` | none | `ApiResponse` | | `POST` | `/api/client/workout-plans/categories` | `CustomMiddleware` | `PlanCategoryRequest` | `ApiResponse` | | `POST` | `/api/client/workout-plans/{id}/assignments` | `CustomMiddleware` | `PlanAssignRequest` | `ApiResponse` | | `DELETE` | `/api/client/workout-plans/assignments/{customerWorkoutId}` | `CustomMiddleware` | route `customerWorkoutId` | `ApiResponse` | ### C12. Meal plans | Method | Path | Auth | Request | Response | |---|---|---|---|---| | `GET` | `/api/client/meal-plans` | `CustomMiddleware` | none | `ApiResponse` | | `GET` | `/api/client/meal-plans/{id}` | `CustomMiddleware` | route `id` | `ApiResponse` | | `POST` | `/api/client/meal-plans` | `CustomMiddleware` | `MealPlanRequest` | `ApiResponse` | | `PUT` | `/api/client/meal-plans/{id}` | `CustomMiddleware` | `MealPlanRequest` | `ApiResponse` | | `DELETE` | `/api/client/meal-plans/{id}` | `CustomMiddleware` | route `id` | `ApiResponse` | | `GET` | `/api/client/meal-plans/{id}/items` | `CustomMiddleware` | route `id` | `ApiResponse` | | `POST` | `/api/client/meal-plans/{id}/items` | `CustomMiddleware` | `MealItemRequest` | `ApiResponse` | | `GET` | `/api/client/meal-plans/categories` | `CustomMiddleware` | none | `ApiResponse` | | `POST` | `/api/client/meal-plans/categories` | `CustomMiddleware` | `PlanCategoryRequest` | `ApiResponse` | | `POST` | `/api/client/meal-plans/{id}/assignments` | `CustomMiddleware` | `PlanAssignRequest` | `ApiResponse` | | `DELETE` | `/api/client/meal-plans/assignments/{customerMealId}` | `CustomMiddleware` | route `customerMealId` | `ApiResponse` | ### C13. Feed | Method | Path | Auth | Request | Response | |---|---|---|---|---| | `GET` | `/api/client/feed` | `CustomMiddleware` | none | `ApiResponse` | | `POST` | `/api/client/feed` | `CustomMiddleware` | `CreateFeedRequest` | `ApiResponse` | | `DELETE` | `/api/client/feed/{postId}` | `CustomMiddleware` | route `postId` | `ApiResponse` | | `POST` | `/api/client/feed/{postId}/like` | `CustomMiddleware` | route `postId` | `ApiResponse` | | `DELETE` | `/api/client/feed/{postId}/like` | `CustomMiddleware` | route `postId` | `ApiResponse` | | `GET` | `/api/client/feed/{postId}/like` | `CustomMiddleware` | route `postId` | `ApiResponse` | ### C14. Tickets | Method | Path | Auth | Request | Response | |---|---|---|---|---| | `GET` | `/api/client/tickets` | `CustomMiddleware` | none | `ApiResponse` | | `GET` | `/api/client/tickets/{id}` | `CustomMiddleware` | route `id` | `ApiResponse` | | `GET` | `/api/client/tickets/categories` | `CustomMiddleware` | none | `ApiResponse` | | `POST` | `/api/client/tickets` | `CustomMiddleware` | `CreateTicketRequest` | `ApiResponse` | | `PUT` | `/api/client/tickets/{id}` | `CustomMiddleware` | `UpdateTicketRequest` | `ApiResponse` | | `POST` | `/api/client/tickets/{id}/messages` | `CustomMiddleware` | `SendTicketMessageRequest` | `ApiResponse` | | `POST` | `/api/client/tickets/{id}/feedback` | `CustomMiddleware` | `TicketFeedbackRequest` | `ApiResponse` | | `POST` | `/api/client/tickets/{id}/close` | `CustomMiddleware` | none | `ApiResponse` | | `DELETE` | `/api/client/tickets/{id}` | `CustomMiddleware` | route `id` | `ApiResponse` | ### C15. Subscriptions and group members | Method | Path | Auth | Request | Response | |---|---|---|---|---| | `GET` | `/api/client/subscriptions/{id}` | `CustomMiddleware` | route `id` | `ApiResponse` | | `POST` | `/api/client/subscriptions/{id}/members` | `CustomMiddleware` | `AddSubscriptionMemberRequest` | `ApiResponse` | | `DELETE` | `/api/client/subscriptions/{id}/members/{memberId}` | `CustomMiddleware` | route `id`, route `memberId` | `ApiResponse` | | `GET` | `/api/client/subscriptions/{id}/payments` | `CustomMiddleware` | route `id` | `ApiResponse` | | `POST` | `/api/client/subscriptions/{id}/payments` | `CustomMiddleware` | `RecordSubscriptionPaymentRequest` | `ApiResponse` | ## D. `AgentController` (`/api/agent`) | Method | Path | Auth | Request | Response | |---|---|---|---|---| | `POST` | `/api/agent/enroll` | anonymous | `EnrollRequest` | `ApiResponse` | | `POST` | `/api/agent/devices` | `X-Api-Key` | `RegisterDeviceRequest` | `ApiResponse` | | `POST` | `/api/agent/attendance` | `X-Api-Key` | `AgentAttendanceRequest` | `ApiResponse` | | `GET` | `/api/agent/commands` | `X-Api-Key` | none | `ApiResponse` | | `POST` | `/api/agent/commands/{id}/result` | `X-Api-Key` | `CommandResultRequest` | `ApiResponse` | | `POST` | `/api/agent/heartbeat` | `X-Api-Key` | none | `ApiResponse` | ## Request and Response DTOs ## Onboarding and activation DTOs Defined in `Models/IOs/OnboardingDtos.cs`. ### Request contracts - `SendMobileOtpRequest` - `mobileNumber` - `VerifyMobileOtpRequest` - `mobileNumber` - `referenceNumber` - `otpCode` - `VerifyOtpCodeRequest` - `referenceNumber` - `otpCode` - `CreateOnboardingRequest` - `ownerName` - `gymName` - `city` - `MobileNumberCheckRequest` - `mobileNumber` - `SandboxProgressUpdate` - `tourStepCompleted` - `minutesElapsedDelta` - `SendEmailOtpRequest` - `email` - `GymProfileRequest` - `gymName` - `address` - `city` - `SetPaymentMethodRequest` - `payHereToken` - `UpdateOnboardingStatusRequest` - `status` - `reason` - `ReviewPayoutKycRequest` - `status` - `reason` - `SelectPaymentTrackRequest` - `track` - `OnboardingRequestQuery` - `status` - `search` - `page` - `pageSize` - `ClientDirectoryQuery` - `search` - `page` - `pageSize` ### Response contracts - `SendOtpResult` - `referenceNumber` - `expiresInSeconds` - `resendAllowedInSeconds` - `VerifyOtpResult` - `requestAccessToken` - `expiresIn` - `OnboardingRequestCreated` - `onboardingRequestId` - `sandboxToken` - `status` - `SandboxStatus` - `id` - `status` - `bannerMessage` - `tourProgress` - `minutesInSandbox` - `ActivationStatusResult` - `status` - `canActivate` - `rejectionReason` - `MobileNumberCheckResult` - `exists` - `message` - `status` - `sandboxToken` - `OnboardingRequestSummary` - `OnboardingRequestDetail` - `PagedResult` - `NicUploadResult` - `nicFrontDocId` - `nicBackDocId` - `OwnerActivationSummary` - `PaymentMethodResult` - `cardLast4` - `cardType` - `ActivationCompleteResult` - `accessToken` - `refreshToken` - `clientId` - `checklist` - `SetupChecklistItem` - `key` - `label` - `isComplete` - `PaymentTrackOption` - `track` - `feeSummary` - `PaymentTrackSelectionResult` - `track` - `kycRequired` - `ClientPayoutKycDto` - `id` - `clientId` - `kycStatus` - `submittedAt` - `WalletDto` - `WalletLedgerEntryDto` - `PayoutScheduleDto` - `ClientSummary` ## ClientController inline request DTOs These are declared at the bottom of `Controllers/ClientController.cs`. - `WorkoutPlanRequest` - `name` - `description` - `isTemplate` - `workoutCategoryId` - `customerIds` - `workoutItems` - `WorkoutItemRequest` - `exerciseDay` - `description` - `exercises` - `howToDo` - `doURL` - `MealPlanRequest` - `name` - `description` - `isTemplate` - `mealCategoryId` - `customerIds` - `mealItems` - `MealItemRequest` - `name` - `description` - `calories` - `servingSize` - `preparationNotes` - `PlanCategoryRequest` - `name` - `description` - `PlanAssignRequest` - `customerId` - `notes` - `CreateFeedRequest` - `caption` - `description` - `document` - `CreateTicketRequest` - `mainReason` - `ticketCategoryId` - `UpdateTicketRequest` - `mainReason` - `ticketCategoryId` - `SendTicketMessageRequest` - `message` - `attachmentURL` - `TicketFeedbackRequest` - `rating` - `feedback` - `AddSubscriptionMemberRequest` - `customerId` - `RecordSubscriptionPaymentRequest` - `amount` - `note` ## DTO inventory under `DTOs/` ### Auth - `DTOs/Auth/AuthResponse.cs` - `AuthResponse` ### Agent - `DTOs/Agent/AgentRequests.cs` - `EnrollRequest` - `RegisterDeviceRequest` - `AgentAttendanceRequest` - `AgentAttendanceEvent` - `CommandResultRequest` ### Attendance - `AttendanceCountDTO` - `AttendanceDTO` - `TodayAttendanceDTO` ### Client invoice - `ClientInvoiceDto` - `ClientInvoiceItemDto` - `CreateClientInvoiceRequest` - `UpdateClientInvoiceStatusRequest` ### Customer - `CreateCustomerRequest` - `CustomerDto` - `MemberListRowDto` - `UpdateCustomerRequest` ### Customer invoice - `CreateCustomerInvoiceRequest` - `CustomerInvoiceDto` - `CustomerInvoiceItemDto` - `UpdateCustomerInvoiceStatusRequest` ### Customer plan - `CreateCustomerPlanRequest` - `CustomerPlanDto` - `UpdateCustomerPlanRequest` ### Customer subscription - `CreateCustomerSubscriptionRequest` - `CustomerSubscriptionDto` - `CustomerSubItemDto` - `SubscriptionSummaryDto` - `SubscriptionMemberDto` - `SubscriptionInstallmentDto` ### Meal - `CustomerMealDto` - `MealCategoryDto` - `MealDto` - `MealPlanDetailDto` - `MealPlanDto` ### Staff - `CreateStaffRequest` - `StaffDto` - `UpdateStaffRequest` ### Stats - `ClientStatSummaryDto` - `MonthlyRevenueStat` ### Ticket - `TicketDto` - `TicketDetailDto` - `TicketMessageDto` ### Workout - `CustomerWorkoutDto` - `WorkoutCategoryDto` - `WorkoutItemDto` - `WorkoutPlanDetailDto` - `WorkoutPlanDto` ### Miscellaneous - `DocumentDownloadModel` - `UpdateTuteItemRequest` ## Notable request DTO field detail ### `CreateCustomerPlanRequest` Fields: - `planName` required - `planDescription` optional - `planPrice` required decimal - `durationInDays` optional, validated by service - `planScope` optional, `"Individual"` or `"Group"` - `memberLimit` optional, used for group plans - `durationMode` optional, `"Rolling"` or `"FixedRange"` - `validFrom` optional - `validTo` optional - `allowSplitPayments` optional - `installmentCount` optional ### `AuthResponse` Fields: - `statusCode` - `success` - `message` - `data` ## Helpers ### `Helpers/ApiKeyHelper.cs` - generates 256-bit agent API keys - hashes API keys using SHA-256 for storage and lookup ### `Helpers/ApiResponseHelper.cs` - wraps data into `ApiResponse` ### `Helpers/AuthOtpResponseParser.cs` - parses OTP-related auth responses ### `Helpers/CustomerProgressHelper.cs` - customer fitness/progress calculations and predictions - related to progress formulas in `CustomerProgressFormulas.txt` ### `Helpers/DataExtractor.cs` - extracts typed values from JSON payload dictionaries - helpers for string, int, decimal, bool, guid, datetime, date, and auth response parsing - provides `GetUserIdFromContext` ### `Helpers/DeserializePayload.cs` - payload deserialization helper ### `Helpers/EncryptionHelper.cs` - encryption-related utility methods ### `Helpers/JwtMiddleware.cs` - custom auth filter named `CustomMiddlewareAttribute` - validates standard JWT access tokens ### `Helpers/RequestAccessTokenHelper.cs` - issues and validates onboarding request-access tokens ### `Helpers/UserRoleHelper.cs` - resolves role/client relationships from users ## Services ### Core services - `AccessDeviceService` - `ActivationService` - `ActivityLogService` - `AdminClientDirectoryService` - `AgentService` - `AttendanceService` - `AuthService` - `ChatService` - `ClientInvoiceService` - `ClientService` - `ClientStatService` - `CustomerInvoiceService` - `CustomerPlanService` - `CustomerService` - `CustomerSubscriptionService` - `DocumentService` - `FeedService` - `MealService` - `OnboardingAdminService` - `OnboardingService` - `PaymentService` - `PaymentsEnablementService` - `PayoutKycReviewService` - `SmsService` - `StaffService` - `TicketService` - `WorkoutService` ### Function handler services - `AccessDeviceFunctionHandler` - `ActivityLogFuncHandler` - `AttendanceFunctionHandler` - `AuthFuncHandler` - `ChatFunctionHandler` - `ClientFuncHandler` - `ClientInvoiceFunctionHandler` - `ClientStatFuncHandler` - `CustomerFunctionHandler` - `CustomerInvoiceFunctionHandler` - `CustomerPlanFunctionHandler` - `CustomerSubscriptionFunctionHandler` - `DocumentFunctionHandler` - `FeedFuncHandler` - `MealFunctionHandler` - `PaymentFunctionHandler` - `StaffFunctionHandler` - `TicketFunctionhandler` - `UserRegisterHandler` - `WorkoutFunctionHandler` ### AI services - `GeminiClient` - `IAiClient` - `MealPlanOrchestrator` - `WorkoutPlanOrchestrator` - `ModificationGuard` ## Repositories - `AccessDeviceRepo` - `ActivityLogRepository` - `AdminClientDirectoryRepository` - `AgentRepo` - `AttendanceRepository` - `ChatRepository` - `ClientInvoiceRepository` - `ClientRepository` - `ClientStatRepository` - `CustomerInvoiceRepository` - `CustomerPlanRepository` - `CustomerRepository` - `CustomerSubscriptionRepository` - `DeviceCommandRepo` - `DocumentRepository` - `FeedRepository` - `MealRepository` - `OnboardingRepository` - `PairingCodeRepo` - `PaymentRepository` - `PaymentsEnablementRepository` - `StaffRepository` - `TicketRepository` - `WorkoutRepository` ## Data Model Inventory ### Main entities - `User` - `Admin` - `Client` - `ClientBusiness` - `ClientCard` - `ClientPackage` - `ClientSubscription` - `ClientSubItems` - `ClientInvoice` - `ClientInvoiceItem` - `ClientPayoutKyc` - `ClientWallet` - `WalletLedgerEntry` - `PayoutBatch` - `Customer` - `CustomerAccess` - `CustomerCards` - `CustomerHealth` - `CustomerTarget` - `CusWeightLossProgress` - `CustomerPlan` - `CustomerSubscription` - `CustomerSubItem` - `SubscriptionMember` - `SubscriptionInstallment` - `CustomerInvoice` - `CustomerInvoiceItem` - `CustomerWorkout` - `CustomerMeal` - `WorkoutCategory` - `WorkoutPlan` - `WorkoutItem` - `MealCategory` - `MealPlan` - `Meal` - `FeedPost` - `FeedLike` - `Ticket` - `TicketCategory` - `TicketMessage` - `TicketStatus` - `Attendance` - `ActivityLog` - `Chat` - `ChatMessages` - `UserDocument` - `DocumentTypes` - `AccessDevice` - `Agent` - `PairingCode` - `DeviceCommand` - `OnboardingRequest` - `OwnerActivation` ### Enum inventory - `BeneficiaryType` - `BusinessType` - `FirstChargeStatus` - `KycStatus` - `OnboardingStatus` - `PaymentTrack` - `PayoutBatchStatus` - `PriorityLevel` - `ProgressGoalType` - `Sex` - `TicketStatusEnum` - `WalletEntryType` ### EF Core DbSets in `AppDBContext` The context currently exposes DbSets for all major entities above, including: - users, clients, customers, staff - plans and subscriptions - invoices and payments - meals and workouts - feed, chat, tickets, attendance - access devices and agents - onboarding and payout flows ## Interfaces ### Repository interfaces - `IActivityLogRepository` - `IAccessDeviceRepo` - `IAdminClientDirectoryRepository` - `IAgentRepo` - `IAttendanceRepository` - `IChatRepo` - `IClientInvoiceRepository` - `IClientRepository` - `IClientStatRepository` - `ICustomerInvoiceRepository` - `ICustomerPlanRepository` - `ICustomerRepository` - `ICustomerSubscriptionRepository` - `IDeviceCommandRepo` - `IDocumentRepository` - `IFeedRepository` - `IMealRepository` - `IOnboardingRepository` - `IPairingCodeRepo` - `IPaymentRepository` - `IPaymentsEnablementRepository` - `IStaffRepository` - `ITicketRepository` - `IWorkoutRepository` ### Service interfaces - `IAccessDeviceService` - `IActivationService` - `IActivityLogService` - `IAdminClientDirectoryService` - `IAgentService` - `IAttendanceService` - `IAuthService` - `IChatService` - `IClientInvoiceService` - `IClientService` - `IClientStatService` - `ICustomerInvoiceService` - `ICustomerPlanService` - `ICustomerService` - `ICustomerSubscriptionService` - `IDocumentService` - `IFeedService` - `IMealService` - `IOnboardingAdminService` - `IOnboardingService` - `IPaymentService` - `IPaymentsEnablementService` - `IPayoutKycReviewService` - `ISmsService` - `IStaffService` - `ITicketService` - `IWorkoutService` ## Other Important Files ### Markdown - `README.md` - current placeholder text only - `PROJECT_REFERENCE.md` - this generated project reference ### Postman - `Fitness_Core_API.postman_collection.json` - `postman/Client-Admin-API.postman_collection.json` ### Miscellaneous - `CustomerProgressFormulas.txt` - formulas used by customer progress logic - `tools/Update-Md5Reference.ps1` - PowerShell utility script ## Practical Notes and Caveats 1. Many newer endpoints in `ClientController` and `AdminController` still return `ApiResponse`. The actual data shape comes from service-layer return objects and may not always have a dedicated DTO class. 2. Some REST endpoints intentionally omit null properties before passing payloads to services. This matters because several services use direct `GetString()`, `GetDecimal()`, or similar access patterns. 3. The legacy RPC layer is still a major part of the system. If you are building a frontend or integration, do not assume every domain has a clean REST endpoint yet. 4. Chat function names in `ChatFunctionHandler` appear mismatched with the actual service methods. This document lists them exactly as implemented. 5. Protected endpoints mostly rely on the custom middleware rather than standard `[Authorize]` attributes. ## Suggested Reading Order If you need to understand the project quickly, read in this order: 1. `Program.cs` 2. `Controllers/ClientController.cs` 3. `Controllers/AdminController.cs` 4. `Controllers/AgentController.cs` 5. `Controllers/APIController.cs` 6. `Models/IOs/OnboardingDtos.cs` 7. `Helpers/JwtMiddleware.cs` 8. `Services/FunctionHandler/*` 9. target service file for the domain you are changing