{"openapi":"3.0.0","paths":{"/service-inquiries":{"post":{"description":"Accepts a lead from the Wakeel Online website contact form and persists it as a row in `service_inquiries`. Returns the new row id.","operationId":"ServiceInquiriesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServiceInquiryDto"}}}},"responses":{"201":{"description":"Inquiry created.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"}}}}}},"429":{"description":"Submission rate limit exceeded."},"500":{"description":"Unable to submit service inquiry at this time."}},"summary":"Submit a service inquiry","tags":["service-inquiries"]},"get":{"operationId":"ServiceInquiriesController_list","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["new","contacted","in_progress","closed"]}},{"name":"urgency","required":false,"in":"query","schema":{"type":"string","enum":["urgent","this_week","exploring"]}},{"name":"based_in","required":false,"in":"query","schema":{"type":"string","enum":["pakistan","overseas"]}},{"name":"assigned_to","required":false,"in":"query","description":"Filter by assignee.","schema":{"format":"uuid","type":"string"}},{"name":"search","required":false,"in":"query","description":"Case-insensitive search across name, phone, email, service_title.","schema":{"type":"string"}},{"name":"sort","required":false,"in":"query","description":"Sort column and direction, e.g. \"created_at:desc\" or \"name:asc\".","schema":{"default":"created_at:desc","type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"List service inquiries (paginated, filterable)","tags":["service-inquiries"]}},"/service-inquiries/{id}":{"get":{"operationId":"ServiceInquiriesController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get a single service inquiry by ID","tags":["service-inquiries"]},"patch":{"operationId":"ServiceInquiriesController_updateNotes","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateInquiryDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Update inquiry internal notes","tags":["service-inquiries"]},"delete":{"operationId":"ServiceInquiriesController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Delete a service inquiry","tags":["service-inquiries"]}},"/service-inquiries/{id}/status":{"patch":{"operationId":"ServiceInquiriesController_updateStatus","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateInquiryStatusDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Update inquiry status","tags":["service-inquiries"]}},"/service-inquiries/{id}/assign":{"patch":{"operationId":"ServiceInquiriesController_assign","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignInquiryDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Assign or unassign an inquiry","tags":["service-inquiries"]}},"/authentication/sign-up":{"post":{"description":"Accepts exactly one of `email` or `phone`. When confirmation is on in the Supabase project, the response is 200 with `session: null` and `confirmationRequired: true`; Supabase has sent the confirmation link or SMS. When confirmation is off, the response includes a session.","operationId":"AuthenticationController_signUp","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignUpDto"}}}},"responses":{"200":{"description":"Sign-up accepted."},"400":{"description":"Validation or Supabase error."}},"summary":"Create a new account with email or phone + password.","tags":["authentication"]}},"/authentication/sign-in":{"post":{"operationId":"AuthenticationController_signIn","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignInPasswordDto"}}}},"responses":{"200":{"description":"Returns the user + session."},"401":{"description":"Bad credentials. Generic message."},"403":{"description":"Account exists but email is not confirmed (`code: \"email_not_confirmed\"`)."},"429":{"description":"Sign-in rate limit exceeded."}},"summary":"Sign in with email or phone + password.","tags":["authentication"]}},"/authentication/magic-link":{"post":{"operationId":"AuthenticationController_sendMagicLink","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignInMagicLinkDto"}}}},"responses":{"202":{"description":"Email dispatch accepted."}},"summary":"Send a passwordless sign-in link to an email address.","tags":["authentication"]}},"/authentication/sms-otp":{"post":{"description":"Requires Twilio (or another Supabase-configured SMS provider) to be set up on the project. Without it, this endpoint will return a 400.","operationId":"AuthenticationController_sendSmsOtp","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignInSmsOtpDto"}}}},"responses":{"202":{"description":"OTP dispatch accepted."}},"summary":"Send a 6-digit one-time code over SMS or WhatsApp.","tags":["authentication"]}},"/authentication/verify-otp":{"post":{"description":"Works for both email types (`email`, `signup`, `recovery`, `magiclink`, `invite`, `email_change`) and phone types (`sms`, `phone_change`). The `type` field controls whether `email` or `phone` is required.","operationId":"AuthenticationController_verifyOtp","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyOtpDto"}}}},"responses":{"200":{"description":"Returns the user + session."},"401":{"description":"Code is wrong or expired."}},"summary":"Exchange an OTP for a session.","tags":["authentication"]}},"/authentication/oauth":{"post":{"description":"Returns `{ url, provider }`. The client should redirect the user to `url`. After the round-trip, Supabase lands the user on `redirectTo` with a session in the URL fragment that the frontend SDK parses.","operationId":"AuthenticationController_oauth","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthSignInDto"}}}},"responses":{"200":{"description":"Provider URL to redirect to."},"400":{"description":"`redirectTo` is not an allowed origin."}},"summary":"Start a third-party OAuth flow.","tags":["authentication"]}},"/authentication/me":{"get":{"operationId":"AuthenticationController_me","parameters":[],"responses":{"200":{"description":"Current user."},"401":{"description":"Token missing or invalid."}},"security":[{"bearer":[]}],"summary":"Return the user behind the supplied bearer access token.","tags":["authentication"]},"patch":{"description":"At least one field is required. Changing `email` triggers an email-change confirmation flow on the new address.","operationId":"AuthenticationController_updateMe","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserDto"}}}},"responses":{"200":{"description":"Updated user."},"400":{"description":"No fields supplied, or Supabase rejected the update."},"401":{"description":"Token missing or invalid."}},"security":[{"bearer":[]}],"summary":"Update the current user (email, phone, password, metadata).","tags":["authentication"]}},"/authentication/password/reset":{"post":{"description":"The user clicks the link, lands on `redirectTo` with a recovery session, and the frontend completes the change by calling `PATCH /authentication/me` with the new password.","operationId":"AuthenticationController_resetPassword","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordDto"}}}},"responses":{"202":{"description":"Email dispatch accepted."}},"summary":"Send a password-reset email.","tags":["authentication"]}},"/authentication/sign-out":{"post":{"operationId":"AuthenticationController_signOut","parameters":[],"responses":{"200":{"description":"Signed out."},"401":{"description":"Token missing or invalid."}},"security":[{"bearer":[]}],"summary":"Revoke the bearer token's session globally.","tags":["authentication"]}},"/authentication/invite":{"post":{"description":"Uses the Supabase service role key on the server. Gated by AdminGuard: the caller must present a valid bearer token whose user carries an admin role in `app_metadata` (`{ role: 'admin' }`).","operationId":"AuthenticationController_invite","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteUserDto"}}}},"responses":{"200":{"description":"Invite dispatched."},"401":{"description":"Token missing or invalid."},"403":{"description":"Caller is not an admin."}},"security":[{"bearer":[]}],"summary":"Send a sign-up invite via email (admin only).","tags":["authentication"]}},"/modules":{"get":{"operationId":"ModulesController_findAll","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["modules"]},"post":{"operationId":"ModulesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateModuleDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["modules"]}},"/modules/{id}":{"get":{"operationId":"ModulesController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["modules"]},"patch":{"operationId":"ModulesController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateModuleDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["modules"]},"delete":{"operationId":"ModulesController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["modules"]}},"/permissions":{"get":{"operationId":"PermissionsController_findAll","parameters":[{"name":"moduleId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["permissions"]},"post":{"operationId":"PermissionsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePermissionDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["permissions"]}},"/permissions/{id}":{"get":{"operationId":"PermissionsController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["permissions"]},"patch":{"operationId":"PermissionsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePermissionDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["permissions"]},"delete":{"operationId":"PermissionsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["permissions"]}},"/roles":{"get":{"operationId":"RolesController_findAll","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["roles"]},"post":{"operationId":"RolesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRoleDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["roles"]}},"/roles/{id}":{"get":{"operationId":"RolesController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["roles"]},"patch":{"operationId":"RolesController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRoleDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["roles"]},"delete":{"operationId":"RolesController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["roles"]}},"/roles/{roleId}/permissions":{"get":{"operationId":"RolePermissionsController_list","parameters":[{"name":"roleId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["role-permissions"]},"put":{"operationId":"RolePermissionsController_set","parameters":[{"name":"roleId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetRolePermissionsDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["role-permissions"]}},"/users":{"get":{"operationId":"UserRolesController_listUsers","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["user-roles"]},"post":{"operationId":"UserRolesController_createUser","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["user-roles"]}},"/users/{userId}":{"patch":{"operationId":"UserRolesController_updateProfile","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserProfileDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["user-roles"]}},"/users/{userId}/roles":{"get":{"operationId":"UserRolesController_getRoles","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["user-roles"]},"put":{"operationId":"UserRolesController_setRoles","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetUserRolesDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["user-roles"]}},"/me/permissions":{"get":{"operationId":"UserRolesController_myPermissions","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["user-roles"]}},"/services":{"get":{"operationId":"ServicesController_findPublic","parameters":[],"responses":{"200":{"description":""}},"tags":["services"]},"post":{"operationId":"ServicesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServiceDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["services"]}},"/services/admin":{"get":{"operationId":"ServicesController_findAll","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["services"]}},"/services/by-slug/{slug}":{"get":{"operationId":"ServicesController_findBySlug","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["services"]}},"/services/{id}":{"patch":{"operationId":"ServicesController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateServiceDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["services"]},"delete":{"operationId":"ServicesController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["services"]}},"/service-categories":{"get":{"operationId":"ServiceCategoriesController_findPublic","parameters":[],"responses":{"200":{"description":""}},"tags":["service-categories"]},"post":{"operationId":"ServiceCategoriesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServiceCategoryDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["service-categories"]}},"/service-categories/admin":{"get":{"operationId":"ServiceCategoriesController_findAll","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["service-categories"]}},"/service-categories/{id}":{"patch":{"operationId":"ServiceCategoriesController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateServiceCategoryDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["service-categories"]},"delete":{"operationId":"ServiceCategoriesController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["service-categories"]}},"/service-requests":{"post":{"operationId":"ServiceRequestsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServiceRequestDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Submit a new service request (client)","tags":["service-requests"]},"get":{"operationId":"ServiceRequestsController_listAll","parameters":[{"name":"page","required":false,"in":"query","schema":{"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["submitted","under_review","in_progress","completed","cancelled"]}},{"name":"search","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"List all service requests (office)","tags":["service-requests"]}},"/service-requests/my":{"get":{"operationId":"ServiceRequestsController_listMy","parameters":[{"name":"page","required":false,"in":"query","schema":{"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["submitted","under_review","in_progress","completed","cancelled"]}},{"name":"search","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"List the authenticated client's own requests","tags":["service-requests"]}},"/service-requests/my/{id}":{"get":{"operationId":"ServiceRequestsController_findMy","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get a single request (client view — own only)","tags":["service-requests"]},"patch":{"operationId":"ServiceRequestsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateServiceRequestDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Edit urgency/description while status is submitted (client)","tags":["service-requests"]}},"/service-requests/my/{id}/cancel":{"patch":{"operationId":"ServiceRequestsController_cancelByClient","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Cancel own request (client)","tags":["service-requests"]}},"/service-requests/{id}":{"get":{"operationId":"ServiceRequestsController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get a single service request (office)","tags":["service-requests"]},"delete":{"operationId":"ServiceRequestsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Soft-delete a service request (office)","tags":["service-requests"]}},"/service-requests/{id}/status":{"patch":{"operationId":"ServiceRequestsController_updateStatus","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateServiceRequestStatusDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Advance request status (office)","tags":["service-requests"]}},"/service-requests/{id}/assign":{"patch":{"operationId":"ServiceRequestsController_assign","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignServiceRequestDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Assign or unassign a lawyer (office)","tags":["service-requests"]}},"/service-requests/{id}/cancel":{"patch":{"operationId":"ServiceRequestsController_cancelByOffice","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Cancel a request (office)","tags":["service-requests"]}},"/service-requests/{serviceRequestId}/messages":{"post":{"operationId":"ServiceRequestMessagesController_create","parameters":[{"name":"serviceRequestId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServiceRequestMessageDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Send a message on a service request (client or office)","tags":["service-request-messages"]},"get":{"operationId":"ServiceRequestMessagesController_list","parameters":[{"name":"serviceRequestId","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":50,"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"List messages for a service request","tags":["service-request-messages"]}},"/service-requests/{serviceRequestId}/documents":{"post":{"operationId":"ServiceRequestDocumentsController_create","parameters":[{"name":"serviceRequestId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServiceRequestDocumentDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Create a document request (office/lawyer)","tags":["service-request-documents"]},"get":{"operationId":"ServiceRequestDocumentsController_list","parameters":[{"name":"serviceRequestId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"List all document requests for a service request (client or office)","tags":["service-request-documents"]}},"/service-requests/{serviceRequestId}/documents/{docId}/upload":{"patch":{"operationId":"ServiceRequestDocumentsController_upload","parameters":[{"name":"serviceRequestId","required":true,"in":"path","schema":{"type":"string"}},{"name":"docId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Client uploads a file against a document request (multipart, field name \"file\")","tags":["service-request-documents"]}},"/service-requests/{serviceRequestId}/documents/{docId}/download":{"get":{"operationId":"ServiceRequestDocumentsController_download","parameters":[{"name":"serviceRequestId","required":true,"in":"path","schema":{"type":"string"}},{"name":"docId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get a short-lived signed download URL for an uploaded document","tags":["service-request-documents"]}},"/service-requests/{serviceRequestId}/documents/{docId}/accept":{"patch":{"operationId":"ServiceRequestDocumentsController_accept","parameters":[{"name":"serviceRequestId","required":true,"in":"path","schema":{"type":"string"}},{"name":"docId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Accept an uploaded document (office)","tags":["service-request-documents"]}},"/service-requests/{serviceRequestId}/documents/{docId}/reject":{"patch":{"operationId":"ServiceRequestDocumentsController_reject","parameters":[{"name":"serviceRequestId","required":true,"in":"path","schema":{"type":"string"}},{"name":"docId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RejectServiceRequestDocumentDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Reject an uploaded document with a reason (office)","tags":["service-request-documents"]}},"/service-requests/{serviceRequestId}/timeline":{"get":{"operationId":"ServiceRequestTimelineController_list","parameters":[{"name":"serviceRequestId","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":50,"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"List timeline events for a service request","tags":["service-request-timeline"]}},"/service-requests/{serviceRequestId}/notes":{"post":{"operationId":"ServiceRequestNotesController_create","parameters":[{"name":"serviceRequestId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServiceRequestNoteDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Add an internal note to a service request (office only)","tags":["service-request-notes"]},"get":{"operationId":"ServiceRequestNotesController_list","parameters":[{"name":"serviceRequestId","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":50,"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"List internal notes for a service request (office only)","tags":["service-request-notes"]}}},"info":{"title":"Wakeel Online API","description":"API documentation for the Wakeel Online platform","version":"1.0.0","contact":{}},"tags":[],"servers":[],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"JWT","type":"http"}},"schemas":{"CreateServiceInquiryDto":{"type":"object","properties":{"service_slug":{"type":"string","example":"family-law"},"service_title":{"type":"string","example":"Family Law Consultation"},"name":{"type":"string","example":"Aisha Khan"},"phone":{"type":"string","example":"+92 300 1234567"},"email":{"type":"string","format":"email"},"based_in":{"type":"string","enum":["pakistan","overseas"]},"city":{"type":"string","example":"Karachi"},"country":{"type":"string","example":"United Kingdom"},"best_time_to_call":{"type":"string","enum":["now_today","morning","afternoon","evening"]},"urgency":{"type":"string","enum":["urgent","this_week","exploring"]},"message":{"type":"string"},"service_details":{"type":"object","additionalProperties":true,"description":"Free-form JSONB payload for service-specific fields."}},"required":["service_slug","service_title","name","phone","based_in","best_time_to_call","urgency","message","service_details"]},"UpdateInquiryStatusDto":{"type":"object","properties":{"status":{"type":"string","enum":["new","contacted","in_progress","closed"]}},"required":["status"]},"AssignInquiryDto":{"type":"object","properties":{"assigned_to":{"type":"object","format":"uuid","nullable":true,"description":"User ID to assign, or null to unassign."}},"required":["assigned_to"]},"UpdateInquiryDto":{"type":"object","properties":{"internal_notes":{"type":"string","description":"Free-text internal notes."}}},"SignUpDto":{"type":"object","properties":{"email":{"type":"string","example":"user@example.com","description":"Required if `phone` is not provided."},"phone":{"type":"string","example":"+12025550123","description":"E.164 phone number. Required if `email` is not provided."},"password":{"type":"string","example":"a-strong-password","description":"Plaintext password. Minimum 6 characters (Supabase default).","minLength":6},"data":{"type":"object","description":"Arbitrary metadata stored on auth.users.user_metadata. Returned later as `user.metadata`."},"emailRedirectTo":{"type":"string","description":"URL Supabase will append to the confirmation email link. Must be in the project's allow-list (Supabase Auth → URL Configuration)."},"channel":{"type":"string","enum":["sms","whatsapp"],"description":"Delivery channel for the phone confirmation code."}},"required":["password"]},"SignInPasswordDto":{"type":"object","properties":{"email":{"type":"string","example":"user@example.com","description":"Required if `phone` is not provided."},"phone":{"type":"string","example":"+12025550123","description":"E.164 phone number. Required if `email` is not provided."},"password":{"type":"string","example":"a-strong-password"}},"required":["password"]},"SignInMagicLinkDto":{"type":"object","properties":{"email":{"type":"string","example":"user@example.com"},"emailRedirectTo":{"type":"string","description":"Where to send the user after they click the link. Must be allow-listed in the Supabase project."},"shouldCreateUser":{"type":"boolean","description":"When false, Supabase will refuse to issue a magic link for an unknown email instead of silently creating a new account. Defaults to true."}},"required":["email"]},"SignInSmsOtpDto":{"type":"object","properties":{"phone":{"type":"string","example":"+12025550123","description":"E.164 phone number."},"channel":{"type":"string","enum":["sms","whatsapp"]},"shouldCreateUser":{"type":"boolean","description":"When false, Supabase will refuse to OTP an unknown phone instead of silently creating a new account. Defaults to true."}},"required":["phone"]},"VerifyOtpDto":{"type":"object","properties":{"email":{"type":"string","example":"user@example.com","description":"Required for email-style types."},"phone":{"type":"string","example":"+12025550123","description":"Required for SMS / phone_change types."},"token":{"type":"string","example":"123456"},"type":{"type":"string","enum":["email","signup","recovery","magiclink","invite","email_change","sms","phone_change"]}},"required":["token","type"]},"OAuthSignInDto":{"type":"object","properties":{"provider":{"type":"string","description":"OAuth provider key. Common values: `google`, `github`, `facebook`, `apple`, `azure`, `gitlab`, `bitbucket`, `linkedin_oidc`.","example":"google"},"redirectTo":{"type":"string","description":"Where to send the user after the OAuth round-trip completes. Must be in the project's Auth → URL Configuration allow-list."},"scopes":{"type":"string","description":"Space-separated provider scopes (e.g. `read:user user:email`)."}},"required":["provider"]},"ResetPasswordDto":{"type":"object","properties":{"email":{"type":"string","example":"user@example.com"},"redirectTo":{"type":"string","description":"Where the reset link should land. Must be in the project's Auth → URL Configuration allow-list."}},"required":["email"]},"UpdateUserDto":{"type":"object","properties":{"email":{"type":"string","example":"new@example.com"},"phone":{"type":"string","example":"+12025550123"},"password":{"type":"string","minLength":6},"data":{"type":"object","description":"Merged into the existing user_metadata blob. Pass `null` for a key to remove it."}}},"InviteUserDto":{"type":"object","properties":{"email":{"type":"string","example":"newcomer@example.com"},"data":{"type":"object","description":"Stored on user_metadata so the new account starts with context."},"redirectTo":{"type":"string","description":"Where the invite link lands. Must be in the project's Auth → URL Configuration allow-list."}},"required":["email"]},"CreateModuleDto":{"type":"object","properties":{"name":{"type":"string","example":"Service Inquiries"},"description":{"type":"string"},"sort_order":{"type":"number","default":0}},"required":["name"]},"UpdateModuleDto":{"type":"object","properties":{"name":{"type":"string","example":"Service Inquiries"},"description":{"type":"string"},"sort_order":{"type":"number","default":0}}},"CreatePermissionDto":{"type":"object","properties":{"module_id":{"type":"string","description":"Owning module id"},"action":{"type":"string","example":"assign"},"description":{"type":"string"}},"required":["module_id","action"]},"UpdatePermissionDto":{"type":"object","properties":{"action":{"type":"string","example":"assign"},"description":{"type":"string"}}},"CreateRoleDto":{"type":"object","properties":{"name":{"type":"string","example":"Inquiry Agent"},"description":{"type":"string"},"parent_id":{"type":"object","description":"Parent role id for hierarchy. Omit or null for a top-level role.","format":"uuid","nullable":true}},"required":["name"]},"UpdateRoleDto":{"type":"object","properties":{"name":{"type":"string","example":"Inquiry Agent"},"description":{"type":"string"},"parent_id":{"type":"object","description":"Parent role id for hierarchy. Omit or null for a top-level role.","format":"uuid","nullable":true}}},"SetRolePermissionsDto":{"type":"object","properties":{"permission_ids":{"description":"Full set of permission ids for this role","type":"array","items":{"type":"string"}}},"required":["permission_ids"]},"CreateUserDto":{"type":"object","properties":{"email":{"type":"string","example":"jane@example.com"},"first_name":{"type":"string"},"last_name":{"type":"string"},"phone":{"type":"string"},"designation":{"type":"string","example":"Senior Advocate"},"avatar_url":{"type":"string"},"is_active":{"type":"boolean","default":true},"role_ids":{"description":"Role ids to assign","type":"array","items":{"type":"string"}}},"required":["email"]},"UpdateUserProfileDto":{"type":"object","properties":{"first_name":{"type":"string"},"last_name":{"type":"string"},"phone":{"type":"string"},"designation":{"type":"string"},"avatar_url":{"type":"string"},"is_active":{"type":"boolean"}}},"SetUserRolesDto":{"type":"object","properties":{"role_ids":{"description":"Full set of role ids for this user","type":"array","items":{"type":"string"}}},"required":["role_ids"]},"CreateServiceDto":{"type":"object","properties":{"slug":{"type":"string","example":"case-files"},"title":{"type":"string","example":"Case Files"},"icon":{"type":"string","example":"doc","description":"Icon key matching the website's Icon atom."},"description":{"type":"string","description":"Short one-line description."},"short_intro":{"type":"string","description":"Longer intro paragraph."},"highlights":{"type":"array","items":{"type":"string"}},"cta_label":{"type":"string","example":"Request Case Files"},"whatsapp_text":{"type":"string","example":"Hello, I need help with case files."},"featured":{"type":"boolean","default":false},"is_active":{"type":"boolean","default":true},"sort_order":{"type":"number","default":0},"category_id":{"type":"object","format":"uuid","nullable":true}},"required":["slug","title","icon","description","short_intro","highlights","cta_label","whatsapp_text"]},"UpdateServiceDto":{"type":"object","properties":{"slug":{"type":"string","example":"case-files"},"title":{"type":"string","example":"Case Files"},"icon":{"type":"string","example":"doc","description":"Icon key matching the website's Icon atom."},"description":{"type":"string","description":"Short one-line description."},"short_intro":{"type":"string","description":"Longer intro paragraph."},"highlights":{"type":"array","items":{"type":"string"}},"cta_label":{"type":"string","example":"Request Case Files"},"whatsapp_text":{"type":"string","example":"Hello, I need help with case files."},"featured":{"type":"boolean","default":false},"is_active":{"type":"boolean","default":true},"sort_order":{"type":"number","default":0},"category_id":{"type":"object","format":"uuid","nullable":true}}},"CreateServiceCategoryDto":{"type":"object","properties":{"slug":{"type":"string","example":"court-litigation"},"name":{"type":"string","example":"Court & Litigation"},"icon":{"type":"string","example":"shield","description":"Icon key matching the website's Icon atom."},"description":{"type":"object","nullable":true},"is_active":{"type":"boolean","default":true},"sort_order":{"type":"number","default":0}},"required":["slug","name","icon"]},"UpdateServiceCategoryDto":{"type":"object","properties":{"slug":{"type":"string","example":"court-litigation"},"name":{"type":"string","example":"Court & Litigation"},"icon":{"type":"string","example":"shield","description":"Icon key matching the website's Icon atom."},"description":{"type":"object","nullable":true},"is_active":{"type":"boolean","default":true},"sort_order":{"type":"number","default":0}}},"CreateServiceRequestDto":{"type":"object","properties":{"service_id":{"type":"string","example":"uuid-of-service"},"urgency":{"type":"string","enum":["asap","within_a_week","no_rush"]},"description":{"type":"string"}},"required":["service_id","urgency","description"]},"UpdateServiceRequestDto":{"type":"object","properties":{"urgency":{"type":"string","enum":["asap","within_a_week","no_rush"]},"description":{"type":"string"}}},"UpdateServiceRequestStatusDto":{"type":"object","properties":{"status":{"type":"string","enum":["under_review","in_progress","completed"]}},"required":["status"]},"AssignServiceRequestDto":{"type":"object","properties":{"assigned_to":{"type":"object","description":"Lawyer user UUID. Null to unassign."}}},"CreateServiceRequestMessageDto":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]},"CreateServiceRequestDocumentDto":{"type":"object","properties":{"document_name":{"type":"string","example":"CNIC copy"},"description":{"type":"string","example":"Please provide both front and back side."}},"required":["document_name"]},"RejectServiceRequestDocumentDto":{"type":"object","properties":{"rejection_reason":{"type":"string"}},"required":["rejection_reason"]},"CreateServiceRequestNoteDto":{"type":"object","properties":{"note":{"type":"string"}},"required":["note"]}}}}