Files
Core_Be/PROJECT_REFERENCE.md
Dhananjaya99 bffc9b1686 first commit
2026-09-28 11:44:26 +05:30

1269 lines
36 KiB
Markdown

# 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<ChatHub>("/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 <token>` 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<PagedResult<OnboardingRequestSummary>>` |
| `GET` | `/api/admin/onboarding-requests/{id}` | route `id` | `ApiResponse<OnboardingRequestDetail>` |
| `PATCH` | `/api/admin/onboarding-requests/{id}/status` | body: `UpdateOnboardingStatusRequest` | `ApiResponse<OnboardingRequestDetail>` |
| `POST` | `/api/admin/onboarding-requests/{id}/resend-activation-link` | route `id` | `ApiResponse<object>` with `{ sent = true }` |
| `GET` | `/api/admin/payout-kyc` | query: `status` | `ApiResponse<List<ClientPayoutKycDto>>` |
| `GET` | `/api/admin/payout-kyc/{clientId}` | route `clientId` | `ApiResponse<ClientPayoutKycDto>` |
| `PATCH` | `/api/admin/payout-kyc/{clientId}/status` | body: `ReviewPayoutKycRequest` | `ApiResponse<ClientPayoutKycDto>` |
| `GET` | `/api/admin/clients` | query: `ClientDirectoryQuery` | `ApiResponse<PagedResult<ClientSummary>>` |
| `GET` | `/api/admin/clients/{id}` | route `id` | `ApiResponse<object>` |
## C. `ClientController` (`/api/client`)
### C1. Onboarding request access
| Method | Path | Auth | Request | Response |
|---|---|---|---|---|
| `POST` | `/api/client/onboarding/requests/mobile-check` | none | `MobileNumberCheckRequest` | `ApiResponse<MobileNumberCheckResult>` |
| `POST` | `/api/client/onboarding/requests/otp` | none | `SendMobileOtpRequest` | `ApiResponse<SendOtpResult>` |
| `POST` | `/api/client/onboarding/requests/otp/verify` | none | `VerifyMobileOtpRequest` | `ApiResponse<VerifyOtpResult>` |
| `POST` | `/api/client/onboarding/requests` | bearer request-access token | `CreateOnboardingRequest` | `ApiResponse<OnboardingRequestCreated>` |
| `GET` | `/api/client/onboarding/sandbox/{sandboxToken}/status` | none | route `sandboxToken` | `ApiResponse<SandboxStatus>` |
| `PATCH` | `/api/client/onboarding/sandbox/{sandboxToken}/progress` | none | `SandboxProgressUpdate` | `ApiResponse<SandboxStatus>` |
### C2. Activation
| Method | Path | Auth | Request | Response |
|---|---|---|---|---|
| `POST` | `/api/client/activation/{activationToken}/email/otp` | none | `SendEmailOtpRequest` | `ApiResponse<SendOtpResult>` |
| `POST` | `/api/client/activation/{activationToken}/email/otp/verify` | none | `VerifyOtpCodeRequest` | `ApiResponse<object>` with `{ emailVerified = true }` |
| `POST` | `/api/client/activation/{activationToken}/nic` | none | multipart form: `nicNumber`, `frontImage`, `backImage` | `ApiResponse<NicUploadResult>` |
| `PUT` | `/api/client/activation/{activationToken}/gym-profile` | none | `GymProfileRequest` | `ApiResponse<object>` |
| `POST` | `/api/client/activation/{activationToken}/payment-method` | none | `SetPaymentMethodRequest` | `ApiResponse<PaymentMethodResult>` |
| `POST` | `/api/client/activation/{activationToken}/charge` | none | none | `ApiResponse<ActivationCompleteResult>` |
| `GET` | `/api/client/activation/{activationToken}/checklist` | none | route `activationToken` | `ApiResponse<List<SetupChecklistItem>>` |
| `GET` | `/api/client/activation/{activationToken}/status` | none | route `activationToken` | `ApiResponse<ActivationStatusResult>` |
### C3. Own profile and business
| Method | Path | Auth | Request | Response |
|---|---|---|---|---|
| `GET` | `/api/client/me` | `CustomMiddleware` | none | `ApiResponse<object>` |
| `GET` | `/api/client/packages` | `CustomMiddleware` | none | `ApiResponse<object>` |
### C4. Customer management
| Method | Path | Auth | Request | Response |
|---|---|---|---|---|
| `GET` | `/api/client/customers` | `CustomMiddleware` | none | `ApiResponse<object>` |
| `GET` | `/api/client/customers/{customerId}` | `CustomMiddleware` | route `customerId` | `ApiResponse<object>` |
| `POST` | `/api/client/customers` | `CustomMiddleware` | `CreateCustomerWithPlansRequest` | `ApiResponse<object>` |
| `PUT` | `/api/client/customers/{customerId}` | `CustomMiddleware` | `UpdateCustomerByClientRequest` | `ApiResponse<object>` |
| `DELETE` | `/api/client/customers/{customerId}` | `CustomMiddleware` | query `softDelete=true` optional | `ApiResponse<object>` |
### C5. Staff management
| Method | Path | Auth | Request | Response |
|---|---|---|---|---|
| `GET` | `/api/client/staff` | `CustomMiddleware` | none | `ApiResponse<object>` |
| `GET` | `/api/client/staff/{staffId}` | `CustomMiddleware` | route `staffId` | `ApiResponse<object>` |
| `POST` | `/api/client/staff` | `CustomMiddleware` | `CreateStaffRequest` | `ApiResponse<object>` |
| `PUT` | `/api/client/staff/{staffId}` | `CustomMiddleware` | `UpdateStaffRequest` | `ApiResponse<object>` |
| `DELETE` | `/api/client/staff/{staffId}` | `CustomMiddleware` | query `softDelete=true` optional | `ApiResponse<object>` |
### 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<object>` |
| `GET` | `/api/client/customer-invoices/{id}` | `CustomMiddleware` | route `id` | `ApiResponse<object>` |
| `GET` | `/api/client/member-invoices` | `CustomMiddleware` | none | `ApiResponse<object>` |
| `GET` | `/api/client/member-invoices/{id}` | `CustomMiddleware` | route `id` | `ApiResponse<object>` |
### C7. Dashboard stats
| Method | Path | Auth | Request | Response |
|---|---|---|---|---|
| `GET` | `/api/client/stats/summary` | `CustomMiddleware` | none | `ApiResponse<object>` |
| `GET` | `/api/client/stats/monthly-revenue` | `CustomMiddleware` | none | `ApiResponse<object>` |
| `GET` | `/api/client/stats/recent-payments` | `CustomMiddleware` | none | `ApiResponse<object>` |
| `GET` | `/api/client/stats/recent-attendance` | `CustomMiddleware` | none | `ApiResponse<object>` |
### C8. Payments enablement
| Method | Path | Auth | Request | Response |
|---|---|---|---|---|
| `GET` | `/api/client/payments/tracks` | `CustomMiddleware` | none | `ApiResponse<List<PaymentTrackOption>>` |
| `POST` | `/api/client/payments/track-selection` | `CustomMiddleware` | `SelectPaymentTrackRequest` | `ApiResponse<PaymentTrackSelectionResult>` |
| `POST` | `/api/client/payments/kyc` | `CustomMiddleware` | multipart form: `brCertificate`, `bankProof` | `ApiResponse<ClientPayoutKycDto>` |
| `GET` | `/api/client/payments/kyc/status` | `CustomMiddleware` | none | `ApiResponse<object>` with `{ kycStatus }` |
| `GET` | `/api/client/payments/wallet` | `CustomMiddleware` | none | `ApiResponse<WalletDto>` |
| `GET` | `/api/client/payments/payout-schedule` | `CustomMiddleware` | none | `ApiResponse<PayoutScheduleDto>` |
### C9. Attendance
| Method | Path | Auth | Request | Response |
|---|---|---|---|---|
| `GET` | `/api/client/attendance` | `CustomMiddleware` | none | `ApiResponse<object>` |
| `GET` | `/api/client/attendance/today` | `CustomMiddleware` | none | `ApiResponse<object>` |
| `GET` | `/api/client/attendance/counts` | `CustomMiddleware` | query `fromDate`, `toDate` | `ApiResponse<object>` |
### C10. Membership plans
| Method | Path | Auth | Request | Response |
|---|---|---|---|---|
| `GET` | `/api/client/plans` | `CustomMiddleware` | query `includeInactive=false` | `ApiResponse<object>` |
| `GET` | `/api/client/plans/{id}` | `CustomMiddleware` | route `id` | `ApiResponse<object>` |
| `POST` | `/api/client/plans` | `CustomMiddleware` | `CreateCustomerPlanRequest` | `ApiResponse<object>` |
| `PUT` | `/api/client/plans/{id}` | `CustomMiddleware` | `UpdateCustomerPlanRequest` | `ApiResponse<object>` |
| `DELETE` | `/api/client/plans/{id}` | `CustomMiddleware` | route `id` | `ApiResponse<object>` |
### C11. Workout plans
| Method | Path | Auth | Request | Response |
|---|---|---|---|---|
| `GET` | `/api/client/workout-plans` | `CustomMiddleware` | none | `ApiResponse<object>` |
| `GET` | `/api/client/workout-plans/{id}` | `CustomMiddleware` | route `id` | `ApiResponse<object>` |
| `POST` | `/api/client/workout-plans` | `CustomMiddleware` | `WorkoutPlanRequest` | `ApiResponse<object>` |
| `PUT` | `/api/client/workout-plans/{id}` | `CustomMiddleware` | `WorkoutPlanRequest` | `ApiResponse<object>` |
| `DELETE` | `/api/client/workout-plans/{id}` | `CustomMiddleware` | route `id` | `ApiResponse<object>` |
| `GET` | `/api/client/workout-plans/{id}/items` | `CustomMiddleware` | route `id` | `ApiResponse<object>` |
| `POST` | `/api/client/workout-plans/{id}/items` | `CustomMiddleware` | `WorkoutItemRequest` | `ApiResponse<object>` |
| `GET` | `/api/client/workout-plans/categories` | `CustomMiddleware` | none | `ApiResponse<object>` |
| `POST` | `/api/client/workout-plans/categories` | `CustomMiddleware` | `PlanCategoryRequest` | `ApiResponse<object>` |
| `POST` | `/api/client/workout-plans/{id}/assignments` | `CustomMiddleware` | `PlanAssignRequest` | `ApiResponse<object>` |
| `DELETE` | `/api/client/workout-plans/assignments/{customerWorkoutId}` | `CustomMiddleware` | route `customerWorkoutId` | `ApiResponse<object>` |
### C12. Meal plans
| Method | Path | Auth | Request | Response |
|---|---|---|---|---|
| `GET` | `/api/client/meal-plans` | `CustomMiddleware` | none | `ApiResponse<object>` |
| `GET` | `/api/client/meal-plans/{id}` | `CustomMiddleware` | route `id` | `ApiResponse<object>` |
| `POST` | `/api/client/meal-plans` | `CustomMiddleware` | `MealPlanRequest` | `ApiResponse<object>` |
| `PUT` | `/api/client/meal-plans/{id}` | `CustomMiddleware` | `MealPlanRequest` | `ApiResponse<object>` |
| `DELETE` | `/api/client/meal-plans/{id}` | `CustomMiddleware` | route `id` | `ApiResponse<object>` |
| `GET` | `/api/client/meal-plans/{id}/items` | `CustomMiddleware` | route `id` | `ApiResponse<object>` |
| `POST` | `/api/client/meal-plans/{id}/items` | `CustomMiddleware` | `MealItemRequest` | `ApiResponse<object>` |
| `GET` | `/api/client/meal-plans/categories` | `CustomMiddleware` | none | `ApiResponse<object>` |
| `POST` | `/api/client/meal-plans/categories` | `CustomMiddleware` | `PlanCategoryRequest` | `ApiResponse<object>` |
| `POST` | `/api/client/meal-plans/{id}/assignments` | `CustomMiddleware` | `PlanAssignRequest` | `ApiResponse<object>` |
| `DELETE` | `/api/client/meal-plans/assignments/{customerMealId}` | `CustomMiddleware` | route `customerMealId` | `ApiResponse<object>` |
### C13. Feed
| Method | Path | Auth | Request | Response |
|---|---|---|---|---|
| `GET` | `/api/client/feed` | `CustomMiddleware` | none | `ApiResponse<object>` |
| `POST` | `/api/client/feed` | `CustomMiddleware` | `CreateFeedRequest` | `ApiResponse<object>` |
| `DELETE` | `/api/client/feed/{postId}` | `CustomMiddleware` | route `postId` | `ApiResponse<object>` |
| `POST` | `/api/client/feed/{postId}/like` | `CustomMiddleware` | route `postId` | `ApiResponse<object>` |
| `DELETE` | `/api/client/feed/{postId}/like` | `CustomMiddleware` | route `postId` | `ApiResponse<object>` |
| `GET` | `/api/client/feed/{postId}/like` | `CustomMiddleware` | route `postId` | `ApiResponse<object>` |
### C14. Tickets
| Method | Path | Auth | Request | Response |
|---|---|---|---|---|
| `GET` | `/api/client/tickets` | `CustomMiddleware` | none | `ApiResponse<object>` |
| `GET` | `/api/client/tickets/{id}` | `CustomMiddleware` | route `id` | `ApiResponse<object>` |
| `GET` | `/api/client/tickets/categories` | `CustomMiddleware` | none | `ApiResponse<object>` |
| `POST` | `/api/client/tickets` | `CustomMiddleware` | `CreateTicketRequest` | `ApiResponse<object>` |
| `PUT` | `/api/client/tickets/{id}` | `CustomMiddleware` | `UpdateTicketRequest` | `ApiResponse<object>` |
| `POST` | `/api/client/tickets/{id}/messages` | `CustomMiddleware` | `SendTicketMessageRequest` | `ApiResponse<object>` |
| `POST` | `/api/client/tickets/{id}/feedback` | `CustomMiddleware` | `TicketFeedbackRequest` | `ApiResponse<object>` |
| `POST` | `/api/client/tickets/{id}/close` | `CustomMiddleware` | none | `ApiResponse<object>` |
| `DELETE` | `/api/client/tickets/{id}` | `CustomMiddleware` | route `id` | `ApiResponse<object>` |
### C15. Subscriptions and group members
| Method | Path | Auth | Request | Response |
|---|---|---|---|---|
| `GET` | `/api/client/subscriptions/{id}` | `CustomMiddleware` | route `id` | `ApiResponse<object>` |
| `POST` | `/api/client/subscriptions/{id}/members` | `CustomMiddleware` | `AddSubscriptionMemberRequest` | `ApiResponse<object>` |
| `DELETE` | `/api/client/subscriptions/{id}/members/{memberId}` | `CustomMiddleware` | route `id`, route `memberId` | `ApiResponse<object>` |
| `GET` | `/api/client/subscriptions/{id}/payments` | `CustomMiddleware` | route `id` | `ApiResponse<object>` |
| `POST` | `/api/client/subscriptions/{id}/payments` | `CustomMiddleware` | `RecordSubscriptionPaymentRequest` | `ApiResponse<object>` |
## D. `AgentController` (`/api/agent`)
| Method | Path | Auth | Request | Response |
|---|---|---|---|---|
| `POST` | `/api/agent/enroll` | anonymous | `EnrollRequest` | `ApiResponse<object>` |
| `POST` | `/api/agent/devices` | `X-Api-Key` | `RegisterDeviceRequest` | `ApiResponse<object>` |
| `POST` | `/api/agent/attendance` | `X-Api-Key` | `AgentAttendanceRequest` | `ApiResponse<object>` |
| `GET` | `/api/agent/commands` | `X-Api-Key` | none | `ApiResponse<object>` |
| `POST` | `/api/agent/commands/{id}/result` | `X-Api-Key` | `CommandResultRequest` | `ApiResponse<object>` |
| `POST` | `/api/agent/heartbeat` | `X-Api-Key` | none | `ApiResponse<object>` |
## 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<T>`
- `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<T>`
### `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<object>`.
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