{"openapi":"3.0.0","info":{"title":"Comedi API","description":"API documentation for Comedi application","license":{"name":"MIT"},"version":"1.0.0"},"servers":[{"url":"\/api","description":"API base path"}],"paths":{"\/company-branches\/{id}":{"get":{"tags":["App company branches"],"summary":"Get company branch detail (app)","description":"Branch profile for workers. Response includes `is_favorite` for the authenticated user.","operationId":"62193f0297ca6411fc2fb87421cdff41","parameters":[{"name":"id","in":"path","description":"Company branch id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Success"},"401":{"description":"Unauthorized"},"404":{"description":"Not found"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/app\/auth\/send-code":{"post":{"tags":["App"],"summary":"Send verify code to phone number","description":"Swagger endpoint: `sendVerifyCode` (POST `\/app\/auth\/send-code`).","operationId":"6f8437e44719fc3ed5c010e7af01811f","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["phone_number"],"properties":{"phone_number":{"type":"string","example":"09012345678"}},"type":"object"}}}},"responses":{"200":{"description":"Verify code sent successfully","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Verify code sent successfully."},"data":{"properties":{"otp":{"type":"string","example":"1234"}},"type":"object"}},"type":"object"}}}},"422":{"description":"Validation Error","content":{"application\/json":{"schema":[]}}}}}},"\/app\/auth\/confirm-code":{"post":{"tags":["App"],"summary":"Confirm the verification code sent to the phone number","description":"Swagger endpoint: `confirmVerifyCode` (POST `\/app\/auth\/confirm-code`).","operationId":"2a62c02b3c97aa0216083babf8dd5f0d","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["phone_number","code"],"properties":{"phone_number":{"type":"string","example":"09012345678"},"code":{"type":"string","example":"1234"}},"type":"object"}}}},"responses":{"200":{"description":"Verification successful","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Verification successful."},"data":{"properties":{"access_token":{"type":"string","example":"..."},"refresh_token":{"type":"string","example":"..."},"token_type":{"type":"string","example":"bearer"},"expires_in":{"type":"integer","example":3600},"user":{"type":"object"}},"type":"object"}},"type":"object"}}}},"422":{"description":"Validation Error","content":{"application\/json":{"schema":[]}}},"400":{"description":"Invalid code","content":{"application\/json":{"schema":[]}}}}}},"\/app\/auth\/refresh-token":{"post":{"tags":["App"],"summary":"Refresh the JWT token for the user","description":"Swagger endpoint: `refreshToken` (POST `\/app\/auth\/refresh-token`).","operationId":"53336a66d03fb81abf47a0f680d9835f","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["refresh_token"],"properties":{"refresh_token":{"type":"string","example":"refresh_token"}},"type":"object"}}}},"responses":{"200":{"description":"Token refreshed successfully","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Token refreshed successfully."},"data":{"properties":{"access_token":{"type":"string"},"refresh_token":{"type":"string"},"token_type":{"type":"string","example":"bearer"},"expires_in":{"type":"integer"},"user":{"$ref":"#\/components\/schemas\/user"}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthorized","content":{"application\/json":{"schema":[]}}},"422":{"description":"Validation Error","content":{"application\/json":{"schema":[]}}}}}},"\/app\/auth\/logout":{"post":{"tags":["App"],"summary":"Logout","description":"Swagger endpoint: `logout` (POST `\/app\/auth\/logout`).","operationId":"e29416956439a8018af81aefcdefdbb0","responses":{"200":{"description":"Successful Operation","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Logout successfully."},"data":{"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthorized","content":{"application\/json":{"schema":[]}}}},"security":[{"bearerAuth":[]}]}},"\/bank\/account":{"post":{"tags":["App Bank Account"],"summary":"Upsert bank account","description":"Create bank account if missing; otherwise update the existing bank account for the authenticated app user.","operationId":"003383ced616ced43b40a5884ef89c82","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["bank_id","bank_branch_id","bank_account_type","bank_account_name","bank_account_number"],"properties":{"bank_id":{"description":"Bank ID (m_banks.id)","type":"integer","example":1},"bank_branch_id":{"description":"Bank branch ID (m_bank_branches.id)","type":"integer","example":10},"bank_account_type":{"description":"Account type ID (m_bank_account_types.id)","type":"integer","example":1},"bank_account_name":{"description":"Account holder name","type":"string","example":"\u5c71\u7530 \u592a\u90ce"},"bank_account_number":{"description":"Account number","type":"string","example":"1234567"}},"type":"object"}}}},"responses":{"200":{"description":"Bank account saved successfully","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"\u9280\u884c\u53e3\u5ea7\u3092\u66f4\u65b0\u3057\u307e\u3057\u305f\u3002"},"data":{"properties":{"id":{"type":"integer"},"user_id":{"type":"integer"},"bank_id":{"type":"integer"},"bank_branch_id":{"type":"integer"},"bank_account_type":{"type":"integer"},"bank_account_name":{"type":"string"},"bank_account_number":{"type":"string"},"bank":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"},"bank_branch":{"properties":{"id":{"type":"integer"},"bank_id":{"type":"integer"},"name":{"type":"string"}},"type":"object"},"account_type":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/company-branch-favorites":{"get":{"tags":["App favorites"],"summary":"List company branch favorites (app)","operationId":"bdb334f66641a78368bf4932954c9fc1","parameters":[{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"limit","in":"query","schema":{"type":"integer"}},{"name":"order_by","in":"query","description":"Sort field (optional; requires `order_direction` if provided).","required":false,"schema":{"type":"string","enum":["id"]}},{"name":"order_direction","in":"query","description":"Sort direction (optional; requires `order_by` if provided).","required":false,"schema":{"type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Paginated favorites"},"401":{"description":"Unauthorized"}},"security":[{"bearerAuth":[]}]},"post":{"tags":["App favorites"],"summary":"Add company branch to favorites","operationId":"7d8d114141b100dcb1b4396d45bf27dc","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["company_branch_id"],"properties":{"company_branch_id":{"description":"Company branch id","type":"integer","example":1}},"type":"object"}}}},"responses":{"200":{"description":"Created"},"400":{"description":"Business rule error"},"401":{"description":"Unauthorized"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/company-branch-favorites\/{id}":{"delete":{"tags":["App favorites"],"summary":"Remove company branch favorite","operationId":"ebf630033c0a2f333c59c0233aec7912","parameters":[{"name":"id","in":"path","description":"Company branch id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Deleted"},"400":{"description":"Not found"},"401":{"description":"Unauthorized"}},"security":[{"bearerAuth":[]}]}},"\/reviews\/company-branches\/{id}\/summary":{"get":{"tags":["App Review company branches"],"summary":"Get company branch review summary","description":"Get aggregated review summary for a specific company branch.","operationId":"1d0b5f77b431a775d73f37ceb0618157","parameters":[{"name":"id","in":"path","description":"Company Branch ID","required":true,"schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"Review summary","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Company branch review summary fetched successfully."},"data":{"properties":{"company_branch_id":{"type":"integer","example":3},"work_environment_avg":{"type":"string","example":"4.00"},"guidance_avg":{"type":"string","example":"3.75"},"equipment_avg":{"type":"string","example":"4.25"},"total_avg":{"type":"string","example":"4.00"},"total_reviews":{"type":"integer","example":8},"can_review":{"type":"boolean","example":true}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/reviews\/company-branches\/{id}\/me":{"get":{"tags":["App Review company branches"],"summary":"Get my company branch review","description":"Get the authenticated user's review for the specified company branch.","operationId":"a69fe5c52ecfe9c5f903221c83d47658","parameters":[{"name":"id","in":"path","description":"Company Branch ID","required":true,"schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"Review detail","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Company branch review fetched successfully."},"data":{"properties":{"id":{"type":"integer","example":1},"company_branch_id":{"type":"integer","example":3},"user_id":{"type":"integer","example":10},"work_environment":{"type":"integer","example":4},"guidance":{"type":"integer","example":3},"equipment":{"type":"integer","example":5},"average_score":{"type":"string","example":"4.00"},"comment":{"type":"string","example":"Nice place.","nullable":true},"created_at":{"type":"string","format":"date-time","nullable":true},"updated_at":{"type":"string","format":"date-time","nullable":true}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"404":{"description":"Not found"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/reviews\/company-branches\/{id}":{"get":{"tags":["App Review company branches"],"summary":"List company branch reviews","description":"Get paginated reviews for a specific company branch. Default sort: `order_by=id` and `order_direction=desc` (newest first). Examples: oldest first \u2192 `id` + `asc`; highest rating \u2192 `average_score` + `desc`; lowest rating \u2192 `average_score` + `asc`.","operationId":"aaf72645dad3c4a86eb6bc2b868936ff","parameters":[{"name":"id","in":"path","description":"Company Branch ID","required":true,"schema":{"type":"integer","minimum":1}},{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","minimum":1,"example":1}},{"name":"limit","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"example":15}},{"name":"order_by","in":"query","description":"Sort field: `id` (time \/ insert order) or `average_score` (rating)","required":false,"schema":{"type":"string","enum":["id","average_score"]}},{"name":"order_direction","in":"query","description":"Sort direction: `desc` or `asc`","required":false,"schema":{"type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Review list","content":{"application\/json":{"schema":{"properties":{"data":{"type":"array","items":{"properties":{"id":{"type":"integer","example":1},"company_branch_id":{"type":"integer","example":3},"user_id":{"type":"integer","example":10},"work_environment":{"type":"integer","example":4},"guidance":{"type":"integer","example":3},"equipment":{"type":"integer","example":5},"average_score":{"type":"string","example":"4.00"},"comment":{"type":"string","example":"\u30b9\u30bf\u30c3\u30d5\u306e\u6848\u5185\u304c\u89aa\u5207\u3067\u3057\u305f\u3002","nullable":true},"created_at":{"type":"string","format":"date-time","nullable":true},"updated_at":{"type":"string","format":"date-time","nullable":true}},"type":"object"}},"total":{"type":"integer","example":3},"last_page":{"type":"integer","example":1},"current_page":{"type":"integer","example":1}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]},"post":{"tags":["App Review company branches"],"summary":"Submit company branch review","description":"Create or update the authenticated user's review for the specified company branch. Each user can submit one review per branch; re-submitting will overwrite the previous review.","operationId":"7b54c36507afa27aea9df158626e7502","parameters":[{"name":"id","in":"path","description":"Company Branch ID","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["work_environment","guidance","equipment"],"properties":{"work_environment":{"description":"Work environment rating (1-5)","type":"integer","maximum":5,"minimum":1,"example":4},"guidance":{"description":"Guidance and instruction rating (1-5)","type":"integer","maximum":5,"minimum":1,"example":3},"equipment":{"description":"Equipment and facilities rating (1-5)","type":"integer","maximum":5,"minimum":1,"example":5},"comment":{"type":"string","maxLength":1000,"example":"The staff guidance was very helpful.","nullable":true}},"type":"object"}}}},"responses":{"200":{"description":"Review submitted successfully","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"\u4e8b\u696d\u6240\u306e\u30ec\u30d3\u30e5\u30fc\u3092\u9001\u4fe1\u3057\u307e\u3057\u305f\u3002"},"data":{"type":"boolean","example":true}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"404":{"description":"Company branch not found"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/documents\/privacy-policy":{"get":{"tags":["App\/Documents"],"summary":"Get privacy-policy PDF URL","description":"Get privacy-policy PDF presigned URL.","operationId":"46f1f2c0099932ff2df11224f396ede7","responses":{"200":{"description":"Presigned URL","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Succeed"},"data":{"properties":{"url":{"type":"string","example":"https:\/\/example.com\/presigned-url"}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearerAuth":[]}]}},"\/fcm\/devices":{"post":{"tags":["App - FCM"],"summary":"Register an FCM device token","operationId":"92873512364d106a0785dde0f364b5e3","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["fcm_token"],"properties":{"fcm_token":{"type":"string","example":"abcyxz123456789"},"device_model":{"type":"string","example":"09012345678"},"os":{"type":"string","example":"ios,android,web"},"os_version":{"type":"string","example":"1.1.1"}},"type":"object"}}}},"responses":{"200":{"description":"Token registered"}},"security":[{"bearerAuth":[]}]}},"\/fcm\/devices\/{id}":{"delete":{"tags":["App - FCM"],"summary":"Remove an FCM device token","operationId":"d0e759bffadb7158480505e62c877ba0","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Token removed"}},"security":[{"bearerAuth":[]}]}},"\/job-apply":{"get":{"tags":["App jobs"],"summary":"List applied jobs","description":"Get paginated applied jobs for the authenticated user.","operationId":"32abfdff2b15c36b24a2a4582b56998b","parameters":[{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","minimum":1}},{"name":"limit","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"example":15}},{"name":"status","in":"query","description":"Filter by list tab: pending, approved, closed (rejected + cancel-related apply statuses), or completed (job working is payment or done \u2014 salary confirmed\/settled). Checkout and request_change stay on approved. Each job appears in at most one tab. Legacy granular apply statuses are normalized to closed.","required":false,"schema":{"type":"string","enum":["pending","approved","closed","completed"]}},{"name":"search_key","in":"query","description":"Search by keyword","required":false,"schema":{"type":"string","maxLength":255}},{"name":"start_working_date","in":"query","description":"Filter from date (Y-m-d)","required":false,"schema":{"type":"string","format":"date"}},{"name":"end_working_date","in":"query","description":"Filter to date (Y-m-d)","required":false,"schema":{"type":"string","format":"date"}},{"name":"order_by","in":"query","description":"Sort field (optional; omit to use default ordering)","required":false,"schema":{"type":"string","enum":["id","created_at","status"]}},{"name":"order_direction","in":"query","description":"Sort direction (optional; omit to use default ordering)","required":false,"schema":{"type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Paginated applied jobs","content":{"application\/json":{"schema":{"properties":{"data":{"type":"array","items":{"properties":{"job_working_status":{"description":"Latest t_job_workings.status for this user on the latest apply (e.g. approved, checkin, checkout, request_change, payment, done). Tab completed only includes payment and done.","type":"string","nullable":true},"job_working_id":{"description":"Latest t_job_workings.id paired with job_working_status","type":"integer","nullable":true}},"type":"object"}},"total":{"type":"integer","example":10},"last_page":{"type":"integer","example":1},"current_page":{"type":"integer","example":1}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/job-apply\/to-do-list":{"get":{"tags":["App jobs"],"summary":"List jobs pending confirmed note","description":"Paginated jobs where the authenticated user's latest apply is approved and confirmed_note is false. Same job shape as GET \/job-apply (includes job_working_status). Excludes applies whose job working is payment or done.","operationId":"e1bece2065feb4bcbd940d473ebac053","parameters":[{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","minimum":1}},{"name":"limit","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"example":20}},{"name":"search_key","in":"query","description":"Search by keyword","required":false,"schema":{"type":"string","maxLength":255}},{"name":"start_working_date","in":"query","description":"Filter from date (Y-m-d)","required":false,"schema":{"type":"string","format":"date"}},{"name":"end_working_date","in":"query","description":"Filter to date (Y-m-d)","required":false,"schema":{"type":"string","format":"date"}},{"name":"order_by","in":"query","description":"Sort field (optional; omit to use default ordering)","required":false,"schema":{"type":"string","enum":["id","status"]}},{"name":"order_direction","in":"query","description":"Sort direction (optional; omit to use default ordering)","required":false,"schema":{"type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Paginated jobs pending confirmed note","content":{"application\/json":{"schema":{"properties":{"data":{"type":"array","items":{"type":"object"}},"total":{"type":"integer","example":1},"last_page":{"type":"integer","example":1},"current_page":{"type":"integer","example":1}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/job-apply\/applied-jobs":{"get":{"tags":["App jobs"],"summary":"List applied jobs with latest apply","description":"Returns paginated jobs the authenticated user has applied to. Each job includes `latest_apply` (the most recent t_job_applies row for that job). Optional `company_branch_id` narrows to one branch.","operationId":"1339bd56508d9c4d07793b9cb0ec62be","parameters":[{"name":"company_branch_id","in":"query","required":false,"schema":{"type":"integer","minimum":1}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1}}],"responses":{"200":{"description":"Paginated jobs with latest apply per job","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"},"data":{"properties":{"jobs":{"type":"array","items":{"properties":{"latest_apply":{"description":"Latest apply row for this job","type":"object","nullable":true}},"type":"object"}},"total":{"type":"integer"},"last_page":{"type":"integer"},"current_page":{"type":"integer"},"company_branch_id":{"type":"integer","nullable":true}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/job-apply\/history":{"get":{"tags":["App jobs"],"summary":"List all applied job history","description":"Returns apply timeline for the authenticated user, grouped by date (newest first). Omit both `page` and `limit` to return the full timeline (`success`, `message`, `data`). Pass either query param to paginate date groups (`data`, `total`, `last_page`, `current_page`; default page=1, limit=15). Each row in `t_job_apply_status_histories` becomes one item in `jobs` (grouped by that row's `created_at` date). When an apply has no status history yet, a single snapshot from `t_job_applies` is returned. Pending or approved applies also include a scheduled snapshot on `t_jobs.start_working_date` when it differs from other events on that date. When a linked `t_job_workings` row exists, an additional snapshot is included on `working_date` with `job_working_status` and `job_working_id` set.","operationId":"a56ed05098eb86a4076d54be39616a34","parameters":[{"name":"page","in":"query","description":"Page number (1-based). Omit with `limit` to return all rows.","required":false,"schema":{"type":"integer","minimum":1,"example":1}},{"name":"limit","in":"query","description":"Date groups per page (max 100). Omit with `page` to return all rows.","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"example":15}}],"responses":{"200":{"description":"Apply history date groups. Without `page`\/`limit`: `success`, `message`, and `data`. With either param: `data`, `total`, `last_page`, `current_page` only.","content":{"application\/json":{"schema":{"properties":{"success":{"description":"Present only when pagination params are omitted.","type":"boolean","example":true,"nullable":true},"message":{"description":"Present only when pagination params are omitted.","type":"string","example":"","nullable":true},"data":{"type":"array","items":{"properties":{"date":{"type":"string","format":"date","example":"2026-05-15","nullable":true},"jobs":{"type":"array","items":{"properties":{"id":{"type":"integer","example":123},"name":{"type":"string","example":"Seeded Job #01"},"job_apply_id":{"type":"integer","example":456},"job_apply_status":{"type":"string","example":"user_cancelled"},"event_type":{"type":"string","enum":["apply","status_change","scheduled","working"],"example":"scheduled"},"job_apply_confirmed_note":{"type":"boolean","example":false},"job_apply_status_history_id":{"type":"integer","example":99,"nullable":true},"job_apply_status_note":{"type":"string","example":"Company note","nullable":true},"status_changed_at":{"type":"string","format":"date-time","example":"2026-05-20 14:30:00"},"job_working_status":{"type":"string","example":"payment","nullable":true},"job_working_id":{"type":"integer","example":42,"nullable":true}},"type":"object"}}},"type":"object"}},"total":{"description":"Present only when `page` or `limit` is sent.","type":"integer","example":42,"nullable":true},"last_page":{"description":"Present only when `page` or `limit` is sent.","type":"integer","example":3,"nullable":true},"current_page":{"description":"Present only when `page` or `limit` is sent.","type":"integer","example":1,"nullable":true}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/jobs\/{id}\/apply":{"post":{"tags":["App jobs"],"summary":"Apply to a job (app)","description":"Submit an application for a job.","operationId":"db83de3594510357864421136f737a99","parameters":[{"name":"id","in":"path","description":"Job ID","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Application submitted","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Application submitted successfully."},"data":{"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Job not found"},"400":{"description":"Business rule error. Notable `error.key` values include `job_apply.time_overlap` (another pending\/approved shift overlaps this time range), `job_apply.shift_insufficient_gap` (same day, non-overlapping but less than 60 minutes apart), `job_apply.cancelled_slot_blocked` (user cancelled this job or an overlapping shift window and cannot re-apply), `job_apply.already_applied`, `job_apply.job_full` (approved count reached recruitment limit), `job_apply.monthly_working_hours_exceeded`.","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":false},"message":{"type":"string"},"error":{"properties":{"key":{"type":"string","example":"job_apply.shift_insufficient_gap"},"content":{"type":"string"}},"type":"object"}},"type":"object"}}}}},"security":[{"bearerAuth":[]}]}},"\/jobs\/{id}\/cancel":{"post":{"tags":["App jobs"],"summary":"Cancel job application (app)","description":"Cancel or request cancellation of a job application.\n\nBehaviour depends on the current application status:\n- `pending`  \u2192 user_cancelled immediately.\n- `approved` \u2192 transitions to `cancel_requested`; company must approve\/reject.\nAllowed only before shift start; blocked after start or once check-in\/out exists.\n- `checkin` \/ `checkout` \/ `request_change` \u2192 400 error (cannot cancel while shift is in progress).\n- Any other status \u2192 400 error (cannot cancel).","operationId":"e51f62731b5d740a38842d091cf48c99","parameters":[{"name":"id","in":"path","description":"t_jobs.id of the job to cancel the application for","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["cancel_note"],"properties":{"cancel_note":{"description":"Mandatory note recorded in status history.","type":"string","maxLength":2000}},"type":"object"}}}},"responses":{"200":{"description":"Cancelled (pending\u2192user_cancelled) or cancel request submitted (approved\u2192cancel_requested).","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"description":"'Application cancelled successfully.' when pending was user_cancelled; 'Cancellation request submitted successfully.' when an approved application moves to cancel_requested.","type":"string","example":"Application cancelled successfully."},"data":{"properties":{"id":{"type":"integer"},"job_id":{"type":"integer"},"user_id":{"type":"integer"},"status":{"description":"'user_cancelled' when the pending apply was cancelled directly; 'cancel_requested' when the approved apply is awaiting company decision.","type":"string","enum":["user_cancelled","cancel_requested"]}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthenticated","content":{"application\/json":{"schema":[]}}},"400":{"description":"Business rule error. Possible `error.key` values:\n     *       - `job_apply.not_found` \u2014 no active application found for this job\n     *       - `job_apply.cannot_cancel` \u2014 application is in a non-cancellable status (rejected, cancelled, cancel_requested)\n     *       - `job_apply.currently_working` \u2014 shift is currently in progress (checkin \/ checkout \/ request_change)","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":false},"message":{"type":"string","example":"This application cannot be cancelled."},"error":{"properties":{"key":{"type":"string","example":"job_apply.cannot_cancel"},"content":{"type":"string","example":"This application cannot be cancelled."}},"type":"object"}},"type":"object"}}}}},"security":[{"bearerAuth":[]}]}},"\/jobs\/{id}\/confirmed-note":{"post":{"tags":["App jobs"],"summary":"confirmed-note to an approved job (app)","description":"User agrees to an approved job application.","operationId":"aa2b4bc4bfee80bd19aad19b87289e7b","parameters":[{"name":"id","in":"path","description":"Job ID","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Agreement confirmed","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Application note updated successfully."},"data":{"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Application not found"},"400":{"description":"Status not APPROVED"}},"security":[{"bearerAuth":[]}]}},"\/jobs\/{id}\/verify-certificates":{"get":{"tags":["App jobs"],"summary":"Get license verification context (app)","description":"Returns user licenses matching the job category and certificate, plus acknowledgment state and whether confirmation is allowed at the current time.","operationId":"48fb19f519d21da286a63956b73299db","parameters":[{"name":"id","in":"path","description":"Job ID","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"License verification context","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"License verification context fetched successfully."},"data":{"properties":{"matching_licenses":{"type":"array","items":{"properties":{"id":{"type":"integer","example":1},"type":{"type":"string","example":"nurse"},"category_id":{"type":"integer","example":5},"license_number":{"type":"string","example":"123456","nullable":true},"registration_subtype_id":{"description":"Master id (m_registration_subtypes.id).","type":"integer","nullable":true},"registration_subtype":{"properties":{"id":{"type":"integer","example":1},"key":{"type":"string","example":"medical"},"name":{"type":"string","example":"\u533b\u79d1"}},"type":"object","nullable":true},"acquired_at":{"type":"string","format":"date","example":"2020-01-01","nullable":true},"clinical_training_end_at":{"type":"string","format":"date","nullable":true}},"type":"object"}},"confirmed_license":{"type":"boolean","example":false},"can_confirm_now":{"description":"True when current time is within [T-1h, end_working_date_time).","type":"boolean","example":true}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthorized"},"400":{"description":"Not approved, no matching license, or certificate not required"}},"security":[{"bearerAuth":[]}]},"post":{"tags":["App jobs"],"summary":"Acknowledge license before shift (app)","description":"Records `confirmed_license` on the approved apply. Available from one hour before shift start until shift end. Idempotent when already acknowledged.","operationId":"48b7b9535aca881f422dbb02e7c3e5b4","parameters":[{"name":"id","in":"path","description":"Job ID","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"License acknowledgment recorded","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"License acknowledgment recorded."},"data":{"type":"boolean","example":true}},"type":"object"}}}},"401":{"description":"Unauthorized"},"400":{"description":"Not approved, outside time window, or certificate not required"}},"security":[{"bearerAuth":[]}]}},"\/jobs":{"get":{"tags":["App jobs"],"summary":"List jobs (app)","description":"List open job postings.","operationId":"57a9be4c4972adfa99693561b4f9384d","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer"}},{"name":"order_by","in":"query","description":"Sort field (optional; omit to use default ordering). Use distance only with lat\/lon.","required":false,"schema":{"type":"string","enum":["id","start_working_date","end_apply_date_time","hourly_salary","distance"]}},{"name":"order_direction","in":"query","description":"Sort direction (optional; omit to use default ordering)","required":false,"schema":{"type":"string","enum":["asc","desc"]}},{"name":"search_key","in":"query","required":false,"schema":{"type":"string"}},{"name":"company_id","in":"query","required":false,"schema":{"type":"integer"}},{"name":"prefecture_ids","in":"query","description":"Comma-separated prefecture ids","required":false,"schema":{"type":"string"}},{"name":"district_ids","in":"query","description":"Comma-separated district ids","required":false,"schema":{"type":"string"}},{"name":"start_working_date","in":"query","description":"Working date filter. With end_working_date: range start. Without end_working_date: exact day.","required":false,"schema":{"type":"string","format":"date"}},{"name":"end_working_date","in":"query","description":"Working date filter. With start_working_date: range end. Without start_working_date: exact day.","required":false,"schema":{"type":"string","format":"date"}},{"name":"start_working_time","in":"query","required":false,"schema":{"type":"string"}},{"name":"end_working_time","in":"query","required":false,"schema":{"type":"string"}},{"name":"hourly_salary","in":"query","description":"Minimum hourly salary","required":false,"schema":{"type":"number"}},{"name":"category_ids","in":"query","description":"Comma-separated m_category ids","required":false,"schema":{"type":"string"}},{"name":"skill_ids","in":"query","description":"Comma-separated m_skills ids","required":false,"schema":{"type":"string"}},{"name":"workplace_ids","in":"query","description":"Comma-separated m_workplaces ids","required":false,"schema":{"type":"string"}},{"name":"condition_ids","in":"query","description":"Comma-separated m_job_conditions ids (\u3053\u3060\u308f\u308a\u6761\u4ef6 checkbox filter)","required":false,"schema":{"type":"string"}},{"name":"appearance_option_ids","in":"query","description":"Comma-separated m_appearance_items leaf ids (\u670d\u88c5\/\u9aea\u578b\/\u30cd\u30a4\u30eb options from t_job_appearance_selections)","required":false,"schema":{"type":"string"}},{"name":"travel_method_ids","in":"query","description":"Comma-separated m_travel_methods ids (commute \/ transport options from t_job_travels)","required":false,"schema":{"type":"string"}},{"name":"transport_expenses","in":"query","description":"Minimum transport expense filter (yen). Returns jobs with transport_expenses >= value. Range 0\u20133000.","required":false,"schema":{"type":"number"}},{"name":"favorites","in":"query","description":"When true, return only jobs favorited by the authenticated app user (includes closed\/expired favorites; requires Bearer token).","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Paginated job rows: data, total, last_page, current_page. Each row always includes distance (kilometers, null when unavailable). Distance is computed from the authenticated user's saved coordinates when available."},"401":{"description":"Unauthenticated"},"422":{"description":"Validation error"}}}},"\/jobs\/repeats":{"get":{"tags":["App jobs"],"summary":"List repeat jobs by repeat_id (app)","description":"List open job postings by repeat group.","operationId":"95c4ba682e92b5c5c1e3a458514eb13b","parameters":[{"name":"repeat_id","in":"query","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer"}},{"name":"order_by","in":"query","description":"Sort field (optional; omit to use default ordering). Use distance only with lat\/lon.","required":false,"schema":{"type":"string","enum":["id","start_working_date","end_apply_date_time","hourly_salary","distance"]}},{"name":"order_direction","in":"query","description":"Sort direction (optional; omit to use default ordering)","required":false,"schema":{"type":"string","enum":["asc","desc"]}},{"name":"search_key","in":"query","required":false,"schema":{"type":"string"}},{"name":"company_id","in":"query","required":false,"schema":{"type":"integer"}},{"name":"prefecture_ids","in":"query","description":"Comma-separated prefecture ids","required":false,"schema":{"type":"string"}},{"name":"district_ids","in":"query","description":"Comma-separated district ids","required":false,"schema":{"type":"string"}},{"name":"start_working_date","in":"query","description":"Working date filter. With end_working_date: range start. Without end_working_date: exact day.","required":false,"schema":{"type":"string","format":"date"}},{"name":"end_working_date","in":"query","description":"Working date filter. With start_working_date: range end. Without start_working_date: exact day.","required":false,"schema":{"type":"string","format":"date"}},{"name":"start_working_time","in":"query","required":false,"schema":{"type":"string"}},{"name":"end_working_time","in":"query","required":false,"schema":{"type":"string"}},{"name":"hourly_salary","in":"query","description":"Minimum hourly salary","required":false,"schema":{"type":"number"}},{"name":"category_ids","in":"query","description":"Comma-separated m_category ids","required":false,"schema":{"type":"string"}},{"name":"skill_ids","in":"query","description":"Comma-separated m_skills ids","required":false,"schema":{"type":"string"}},{"name":"workplace_ids","in":"query","description":"Comma-separated m_workplaces ids","required":false,"schema":{"type":"string"}},{"name":"condition_ids","in":"query","description":"Comma-separated m_job_conditions ids (\u3053\u3060\u308f\u308a\u6761\u4ef6 checkbox filter)","required":false,"schema":{"type":"string"}},{"name":"appearance_option_ids","in":"query","description":"Comma-separated m_appearance_items leaf ids (\u670d\u88c5\/\u9aea\u578b\/\u30cd\u30a4\u30eb options from t_job_appearance_selections)","required":false,"schema":{"type":"string"}},{"name":"travel_method_ids","in":"query","description":"Comma-separated m_travel_methods ids (commute \/ transport options from t_job_travels)","required":false,"schema":{"type":"string"}},{"name":"transport_expenses","in":"query","description":"Minimum transport expense filter (yen). Returns jobs with transport_expenses >= value. Range 0\u20133000.","required":false,"schema":{"type":"number"}},{"name":"favorites","in":"query","description":"When true, return only jobs favorited by the authenticated app user (includes closed\/expired favorites; requires Bearer token).","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Paginated job rows filtered by repeat_id. Same distance behavior as GET \/jobs."},"422":{"description":"Validation error"}}}},"\/jobs\/{id}":{"get":{"tags":["App jobs"],"summary":"Get job detail (app)","description":"Job detail for the app (open job only: published + deadline not passed).","operationId":"6a0571f1d8e8ad496d2ecaf70fd03d77","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Success","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Job detail fetched successfully."},"data":{"properties":{"job":{"description":"Job detail object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"thumbnail":{"description":"FK to t_file_uploads.id","type":"integer","nullable":true},"thumbnail_file":{"properties":{"id":{"type":"integer"},"url":{"description":"Presigned S3 URL (expires ~1h)","type":"string","nullable":true}},"type":"object","nullable":true},"total_user":{"type":"integer"},"approved_count":{"description":"Number of approved applications for this job.","type":"integer","example":2},"distance":{"description":"Distance in kilometers from the authenticated user's saved coordinates to the job. Always present; null when guest, user has no saved coordinates, or job has no coordinates.","type":"number","format":"float","example":2.5,"nullable":true},"conditions":{"description":"\u3053\u3060\u308f\u308a\u6761\u4ef6 attached to this job","type":"array","items":{"properties":{"id":{"type":"integer"},"name":{"type":"string"},"key":{"type":"string"},"display_order":{"type":"integer"}},"type":"object"}},"company":{"type":"object"},"category":{"type":"object"},"prefecture":{"type":"object","nullable":true},"district":{"type":"object","nullable":true},"company_branch":{"properties":{"id":{"type":"integer"},"name":{"type":"string"},"review_summary":{"description":"Review summary for the job's branch","properties":{"total_avg":{"type":"number","format":"float","example":4.12},"total_reviews":{"type":"integer","example":18}},"type":"object","nullable":true}},"type":"object"},"categories":{"type":"array","items":{"type":"object"}},"skills":{"type":"array","items":{"type":"object"}},"workplaces":{"type":"array","items":{"type":"object"}},"job_certificates":{"type":"array","items":{"type":"object"}},"job_travels":{"type":"array","items":{"type":"object"}},"job_shifts":{"type":"array","items":{"type":"object"}},"job_workings":{"description":"Job working row for this job, including check-in time.","type":"array","items":{"properties":{"id":{"type":"integer"},"user_id":{"type":"integer"},"job_id":{"type":"integer"},"status":{"type":"string","example":"user_checkin"},"working_date":{"type":"string","format":"date","nullable":true},"start_working_time":{"type":"string","format":"date-time","example":"2026-05-12 09:05:00","nullable":true},"end_working_time":{"type":"string","format":"date-time","nullable":true}},"type":"object"}}},"type":"object"},"is_applied":{"description":"Whether the authenticated user has already applied to this job.","type":"boolean","example":false},"job_apply_status":{"description":"Latest apply status for the authenticated user (pending\/approved\/rejected\/cancelled\/cancel_requested\/approve_cancelled\/user_cancelled).","type":"string","example":"approved","nullable":true},"job_apply_confirmed_note":{"description":"Whether the authenticated user confirmed the pre-work note on their latest apply. Null when not logged in or not applied.","type":"boolean","example":true,"nullable":true},"job_apply_confirmed_license":{"description":"Whether the authenticated user acknowledged their license on their latest apply. Null when not logged in or not applied.","type":"boolean","example":false,"nullable":true},"job_apply_qr":{"description":"QR code URL returned only when the latest apply status is approved.","type":"string","example":"https:\/\/example.com\/qrcode.svg","nullable":true},"user_review":{"description":"Company review of the authenticated worker for this job (`t_user_reviews`). Null when not logged in or no review row exists yet.","properties":{"id":{"type":"integer","example":1},"job_working_id":{"type":"integer","example":10},"job_id":{"type":"integer","example":3},"user_id":{"type":"integer","example":10},"status":{"type":"string","enum":["not_reviewed","reviewed"],"example":"reviewed"},"punctuality":{"type":"integer","example":5,"nullable":true},"appearance":{"type":"integer","example":4,"nullable":true},"communication":{"type":"integer","example":5,"nullable":true},"work_attitude":{"type":"integer","example":4,"nullable":true},"skill":{"type":"integer","example":5,"nullable":true},"average_score":{"type":"string","example":"4.60","nullable":true},"comment":{"type":"string","example":"Great worker.","nullable":true}},"type":"object","nullable":true},"job_repeats":{"description":"Other open jobs in the same repeat group (published, apply deadline not passed), excluding the current job.","type":"array","items":{"properties":{"id":{"type":"integer"},"repeat_id":{"type":"string"},"start_working_date":{"type":"string","format":"date"},"start_working_time":{"type":"string"},"end_working_time":{"type":"string"},"income_after_tax":{"type":"number"},"total_user":{"type":"integer"},"applier_count":{"type":"integer"}},"type":"object"}}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"404":{"description":"Not found or not open for application"}}}},"\/job-favorites":{"get":{"tags":["App favorites"],"summary":"List job favorites (app)","operationId":"13dc646c51317ea022293caded196372","parameters":[{"name":"type","in":"query","description":"Filter type. Use `published` to return only favorites whose job is still open for application.","required":false,"schema":{"type":"string","enum":["published"]}},{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"limit","in":"query","schema":{"type":"integer"}},{"name":"order_by","in":"query","description":"Sort field (optional; requires `order_direction` if provided).","required":false,"schema":{"type":"string","enum":["start_working_date","end_apply_date_time","hourly_salary"]}},{"name":"order_direction","in":"query","description":"Sort direction (optional; requires `order_by` if provided).","required":false,"schema":{"type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Paginated favorites"},"401":{"description":"Unauthorized"}},"security":[{"bearerAuth":[]}]},"post":{"tags":["App favorites"],"summary":"Add job to favorites","operationId":"eb84438118e7462a1bf730a3d2199d0e","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["job_id"],"properties":{"job_id":{"description":"Job id","type":"integer","example":1}},"type":"object"}}}},"responses":{"200":{"description":"Created"},"400":{"description":"Business rule error"},"401":{"description":"Unauthorized"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/job-favorites\/{id}":{"delete":{"tags":["App favorites"],"summary":"Remove job favorite","operationId":"50ba8908deb068e7a32a2c252f0240a6","parameters":[{"name":"id","in":"path","description":"Job id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Deleted"},"400":{"description":"Not found"},"401":{"description":"Unauthorized"}},"security":[{"bearerAuth":[]}]}},"\/kyc\/applicant":{"get":{"tags":["KYC"],"summary":"Get Sumsub applicant ID","description":"Returns the authenticated user's Sumsub applicant ID (t_users.kyc_applicant_id). Creates a Sumsub applicant from the user profile when missing.","operationId":"getKycApplicantId","responses":{"200":{"description":"Applicant ID returned successfully","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Get applicant successfully."},"data":{"properties":{"applicant_id":{"description":"Sumsub applicant ID (t_users.kyc_applicant_id)","type":"string","example":"6a14063d8f5f99497c6ae143"}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthorized"},"400":{"description":"User not found or Sumsub error"}},"security":[{"bearerAuth":[]}]},"post":{"tags":["KYC"],"summary":"Create KYC applicant (Sumsub)","description":"Creates a Sumsub applicant from request body. Bearer token required. Optional user_id loads phone from t_users; otherwise phone_number and phone_number_with_country_code are required. Sumsub: externalUserId=phone_number (domestic), info.phone=phone_number_with_country_code. Email is not sent.","operationId":"createKycApplicant","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["first_name","last_name","dob","nationality","country","id_number"],"properties":{"user_id":{"description":"Optional. When set, phones may be omitted (loaded from t_users).","type":"integer","example":1,"nullable":true},"first_name":{"type":"string","maxLength":100,"example":"John"},"last_name":{"type":"string","maxLength":100,"example":"Doe"},"dob":{"type":"string","format":"date","example":"1990-01-01"},"nationality":{"description":"ISO 3166-1 alpha-3","type":"string","maxLength":3,"minLength":3,"example":"JPN"},"country":{"description":"ISO 3166-1 alpha-3 (alpha-2 converted server-side)","type":"string","maxLength":3,"minLength":3,"example":"JPN"},"id_number":{"description":"Required. Sent to Sumsub as idNumber (not stored on t_users).","type":"string","maxLength":50,"example":"A1234567"},"phone_number":{"description":"Domestic JP phone. Required when user_id omitted. Sumsub externalUserId.","type":"string","maxLength":20,"example":"09012345002","nullable":true},"phone_number_with_country_code":{"description":"E.164 phone. Required when user_id omitted. Sumsub info.phone.","type":"string","maxLength":32,"example":"+819012345002","nullable":true},"gender":{"type":"string","example":"male","nullable":true},"address":{"properties":{"street":{"type":"string","maxLength":255,"example":"123 Main St"},"city":{"type":"string","maxLength":100,"example":"New York"},"state":{"type":"string","maxLength":100,"example":"NY"},"postal_code":{"type":"string","maxLength":20,"example":"10001"},"country":{"description":"ISO alpha-2 or alpha-3 (converted to alpha-3 for Sumsub, e.g. US \u2192 USA)","type":"string","maxLength":3,"minLength":2,"example":"US"}},"type":"object","nullable":true}},"type":"object"}}}},"responses":{"200":{"description":"Applicant created successfully","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Create applicant successfully."},"data":{"properties":{"id":{"description":"Sumsub applicant id","type":"string","example":"6a14063d8f5f99497c6ae143"}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthorized"},"422":{"description":"Validation error"},"400":{"description":"Sumsub or business error (error.key e.g. sumsub.create_applicant_failed)"}},"security":[{"bearerAuth":[]}]}},"\/kyc\/generate-sdk-token":{"post":{"tags":["KYC"],"summary":"Generate Sumsub SDK token","description":"Returns SDK access token for the authenticated user's phone number (Sumsub externalUserId).","operationId":"generateKycSdkToken","responses":{"200":{"description":"SDK token generated successfully","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Generate sdk access token successfully."},"data":{"properties":{"token":{"type":"string","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."},"userId":{"type":"string","example":"09012345678","nullable":true}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearerAuth":[]}]}},"\/kyc\/init":{"post":{"tags":["KYC"],"summary":"Init KYC (create applicant if needed + SDK token)","description":"Uses authenticated user profile from t_users (no request body). Creates Sumsub applicant when kyc_applicant_id is empty, then returns SDK token.","operationId":"initKycApplicant","responses":{"200":{"description":"SDK token returned (applicant created when missing)","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Init applicant successfully."},"data":{"properties":{"token":{"type":"string","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."},"userId":{"type":"string","example":"09012345678","nullable":true}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthorized"},"400":{"description":"User not found or Sumsub error"}},"security":[{"bearerAuth":[]}]}},"\/locations\/reverse-geocode":{"get":{"tags":["App locations"],"summary":"Reverse geocode coordinates","description":"Reverse geocode latitude\/longitude to an address.","operationId":"df70ca375c10a58b96e8199834ce34af","parameters":[{"name":"lat","in":"query","description":"Latitude","required":true,"schema":{"type":"number","format":"float","maximum":90,"minimum":-90,"example":35.65858}},{"name":"lon","in":"query","description":"Longitude","required":true,"schema":{"type":"number","format":"float","maximum":180,"minimum":-180,"example":139.745433}}],"responses":{"200":{"description":"Normalized address data","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Succeed"},"data":{"properties":{"formatted_address":{"type":"string","example":"Tokyo Tower, 4-2-8, Shibakoen, Shibakoen, Minato","nullable":true},"prefecture":{"type":"string","example":"Tokyo","nullable":true},"city":{"type":"string","example":"Minato","nullable":true},"ward":{"type":"string","example":"Shibakoen","nullable":true},"postal_code":{"type":"string","example":"105-0011","nullable":true},"country":{"type":"string","example":"jp","nullable":true},"raw":{"type":"object","nullable":true}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/locations\/geocode":{"get":{"tags":["App locations"],"summary":"Geocode address to coordinates","description":"Geocode a free-text address to latitude\/longitude.","operationId":"1c22bd4d10e031d4ee534bf740796442","parameters":[{"name":"address","in":"query","description":"Free-text address (Japanese recommended)","required":true,"schema":{"type":"string","maxLength":500,"example":"\u6771\u4eac\u90fd\u5343\u4ee3\u7530\u533a\u4e38\u306e\u51851-1-1"}}],"responses":{"200":{"description":"Resolved coordinates","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Succeed"},"data":{"properties":{"latitude":{"type":"number","format":"float","example":35.681236},"longitude":{"type":"number","format":"float","example":139.767125},"formatted_address":{"type":"string","example":"1-1 Marunouchi, Chiyoda City, Tokyo 100-0005, Japan","nullable":true},"raw":{"type":"object","nullable":true}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/masters\/categories":{"get":{"tags":["App"],"summary":"Get medical profile category master data","operationId":"38da5ba0333ec41097f3538d3de365dc","responses":{"200":{"description":"Per-category medical profile master payload","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"data":{"properties":{"categories":{"description":"Per-category medical profile master payload. Unused sections are empty arrays.","type":"array","items":{"properties":{"id":{"type":"integer","example":3},"key":{"type":"string","example":"nurse"},"name":{"type":"string","example":"\u770b\u8b77\u5e2b"},"display_order":{"type":"integer","example":3},"experience_years":{"type":"array","items":{"type":"object"}},"sub_categories":{"type":"array","items":{"type":"object"}},"skills":{"type":"array","items":{"type":"object"}},"workplaces":{"type":"array","items":{"type":"object"}},"workplace_types":{"type":"array","items":{"type":"object"}},"certificates":{"description":"Category certificates including board specialists (scope=board_specialist) with nested children","type":"array","items":{"properties":{"id":{"type":"integer"},"key":{"type":"string"},"name":{"type":"string"},"display_order":{"type":"integer"},"scope":{"type":"string","example":"board_specialist"},"children":{"type":"array","items":{"type":"object"}}},"type":"object"}},"registration_subtypes":{"description":"Insurance physician registration subtype options (doctor category only; empty for other categories)","type":"array","items":{"properties":{"id":{"type":"integer","example":1},"key":{"type":"string","example":"medical"},"name":{"type":"string","example":"\u533b\u79d1"}},"type":"object"}}},"type":"object"}},"current_work_types":{"type":"array","items":{"type":"object"}},"work_preferences":{"type":"array","items":{"type":"object"}},"job_change_interests":{"type":"array","items":{"type":"object"}}},"type":"object"}},"type":"object"}}}},"500":{"description":"Internal Server Error"}}}},"\/masters":{"get":{"tags":["App"],"summary":"Get master data","description":"Get master data for registration and job filters.","operationId":"143715bd61650f0d0a686c697702cc8d","responses":{"200":{"description":"Master data payload","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"data":{"properties":{"countries":{"type":"array","items":{"type":"object"}},"prefectures":{"type":"array","items":{"properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"Tokyo"},"short":{"type":"string","example":"TK","nullable":true},"kana":{"type":"string","example":"\u3068\u3046\u304d\u3087\u3046","nullable":true},"en":{"type":"string","example":"Tokyo","nullable":true},"salary":{"description":"Minimum hourly wage (JPY) for this prefecture","type":"number","format":"float","example":1072},"districts":{"type":"array","items":{"properties":{"id":{"type":"integer","example":1},"prefecture_id":{"type":"integer","example":1},"name":{"type":"string","example":"Chiyoda"}},"type":"object"}}},"type":"object"}},"districts":{"type":"array","items":{"type":"object"}},"job_categories":{"type":"array","items":{"type":"object"}},"job_sub_categories":{"type":"array","items":{"type":"object"}},"experience_years":{"type":"array","items":{"type":"object"}},"registration_subtypes":{"type":"array","items":{"type":"object"}},"current_work_types":{"type":"array","items":{"type":"object"}},"work_preferences":{"type":"array","items":{"type":"object"}},"job_change_interests":{"type":"array","items":{"type":"object"}},"certificates":{"type":"array","items":{"type":"object"}},"travel_methods":{"type":"array","items":{"type":"object"}},"job_conditions":{"type":"array","items":{"type":"object"}},"banks":{"description":"List of banks (m_banks) with their branches","type":"array","items":{"properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"\u4e09\u83f1UFJ\u9280\u884c"},"name_half_size":{"type":"string","example":"\uff90\uff82\uff8b\uff9e\uff7cUFJ\uff77\uff9e\uff9d\uff7a\uff73"},"branches":{"description":"Bank branches (m_bank_branches)","type":"array","items":{"properties":{"id":{"type":"integer","example":1},"bank_id":{"type":"integer","example":1},"code":{"type":"string","example":"001"},"name":{"type":"string","example":"\u6771\u4eac\u55b6\u696d\u90e8"},"kana":{"type":"string","example":"\u30c8\u30a6\u30ad\u30e7\u30a6\u30a8\u30a4\u30ae\u30e7\u30a6\u30d6"},"hira":{"type":"string","example":"\u3068\u3046\u304d\u3087\u3046\u3048\u3044\u304e\u3087\u3046\u3076"},"roma":{"type":"string","example":"tokyoeigyobu"}},"type":"object"}}},"type":"object"}},"bank_account_types":{"description":"Bank account types (m_bank_account_types)","type":"array","items":{"properties":{"id":{"type":"integer","example":1},"code":{"type":"string","example":"01"},"name":{"type":"string","example":"\u666e\u901a"}},"type":"object"}}},"type":"object"}},"type":"object"}}}},"500":{"description":"Internal Server Error"}}}},"\/notifications":{"get":{"tags":["App - Notifications"],"summary":"List push notifications for the authenticated user","operationId":"1747035a2ef2e3707698574f55215b2e","parameters":[{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"limit","in":"query","schema":{"type":"integer"}},{"name":"type","in":"query","description":"Filter by notification type","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated notifications"},"401":{"description":"Unauthorized"}},"security":[{"bearerAuth":[]}]}},"\/notifications\/{id}\/read":{"put":{"tags":["App - Notifications"],"summary":"Mark a notification as read","operationId":"9c0da90a875858aea03a9f239fbfdc9c","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Notification marked as read"},"404":{"description":"Notification not found"}},"security":[{"bearerAuth":[]}]}},"\/notifications\/read-all":{"put":{"tags":["App - Notifications"],"summary":"Mark notifications as read (all for user when ids omitted, or specific ids)","operationId":"a160e03d170155a48ecd5c7911c576f9","requestBody":{"required":false,"content":{"application\/json":{"schema":{"properties":{"ids":{"description":"Optional. When omitted or empty, marks all notifications for the authenticated user.","type":"array","items":{"type":"integer","example":1}}},"type":"object"}}}},"responses":{"200":{"description":"Notifications marked as read"}},"security":[{"bearerAuth":[]}]}},"\/salary\/list-year-working":{"get":{"tags":["App\/SalaryExport"],"summary":"List working years and companies for withholding tax certificate","description":"List calendar years and companies where the authenticated user has completed job work.","operationId":"8558bf3026896fa043cfc1fe000f563f","responses":{"200":{"description":"Success","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Succeed"},"data":{"type":"array","items":{"properties":{"year":{"type":"string","example":"2026"},"companies":{"type":"array","items":{"properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"Sample Corp KK"}},"type":"object"}}},"type":"object"}}},"type":"object"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearerAuth":[]}]}},"\/salary\/withholding-tax-certificate":{"get":{"tags":["App\/SalaryExport"],"summary":"Get withholding tax certificate preview","description":"SCR-001 detail: payment amount, withholding tax, social insurance (0 when not tracked), payer name and address.","operationId":"83611227edc1e038a631424961d5e1f5","parameters":[{"name":"year","in":"query","description":"Target year (YYYY)","required":true,"schema":{"type":"integer","example":2026}},{"name":"company_id","in":"query","description":"Company ID. Defaults to 1 if omitted. Use 0 for all companies (aggregated totals, payer name All).","required":false,"schema":{"type":"integer","default":1,"minimum":0,"example":1}}],"responses":{"200":{"description":"Success","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"data":{"properties":{"year":{"type":"integer","example":2026},"company_id":{"type":"integer","example":1},"payment_amount":{"description":"\u652f\u6255\u91d1\u984d","type":"number","format":"float","example":1080000},"withholding_tax_amount":{"description":"\u6e90\u6cc9\u5fb4\u53ce\u7a0e\u984d","type":"number","format":"float","example":108000},"social_insurance_amount":{"description":"\u793e\u4f1a\u4fdd\u967a\u6599\u7b49\u306e\u91d1\u984d","type":"number","format":"float","example":0},"payer_name":{"description":"\u652f\u6255\u8005\u306e\u540d\u79f0","type":"string","example":"\u682a\u5f0f\u4f1a\u793e\u30b5\u30f3\u30d7\u30eb"},"payer_address":{"description":"\u652f\u6255\u8005\u306e\u6240\u5728\u5730","type":"string","example":"\u6771\u4eac\u90fd\u65b0\u5bbf\u533a\u3007\u3007"}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthorized"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/salary\/withholding-tax-certificate\/download":{"get":{"tags":["App\/SalaryExport"],"summary":"Download withholding tax certificate file","description":"SCR-001: file download \u6e90\u6cc9\u5fb4\u53ce\u7968. Name: \u6e90\u6cc9\u5fb4\u53ce\u7968_{staff}_{company}_{year}\u5e74.pdf when LibreOffice conversion succeeds; otherwise filled XLSX with the same stem and .xlsx.","operationId":"257a6387f199005fe1845acfe2a3c522","parameters":[{"name":"year","in":"query","description":"Target year (YYYY)","required":true,"schema":{"type":"integer","example":2026}},{"name":"company_id","in":"query","description":"Company ID. Defaults to 1 if omitted. Use 0 for all companies.","required":false,"schema":{"type":"integer","default":1,"minimum":0,"example":1}}],"responses":{"200":{"description":"File download","content":{"application\/pdf":{"schema":{"type":"string","format":"binary"}},"application\/vnd.openxmlformats-officedocument.spreadsheetml.sheet":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"Unauthorized"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/timekeeping\/{id}":{"get":{"tags":["App\/Timekeeping"],"summary":"Get job working detail","description":"Returns one `t_job_workings` row owned by the authenticated user, including nested `job`, `company`, `company_branch`, `job_apply`, withdraw `transaction_logs`, and the latest `job_working_request` for that shift.","operationId":"e4fa6b76cc3ca9e479d35eea6db92e3a","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","example":1}}],"responses":{"200":{"description":"Shift detail","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Timekeeping record fetched successfully."},"data":{"description":"`JobWorking` with nested relations","type":"object"}},"type":"object"}}}},"401":{"description":"Unauthorized"},"400":{"description":"Record not found or not owned by the user"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/timekeeping":{"post":{"tags":["App\/Timekeeping"],"summary":"Timekeeping: check-in \/ check-out","description":"Check-in or check-out (same endpoint, server branches by state).","operationId":"1b97488b02c2c429146913b82c730c03","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["job_id","branch_id"],"properties":{"job_id":{"description":"Job ID (`t_jobs.id`)","type":"integer","example":1},"branch_id":{"description":"Branch ID decoded from the branch QR. Must match `t_jobs.company_branch_id`.","type":"integer","example":10}},"type":"object"}}}},"responses":{"200":{"description":"Check-in or check-out success","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Check-in \/ Check-out successful."},"data":{"description":"Updated `JobWorking`. After check-out, credits user\/company wallets and creates deposit + pending withdraw transaction logs (status stays `checkout`). Includes nested `job` with `name`, `service_type` (`id`, `name`), and `thumbnail_file` (`id`, `path`, `name`, `extension`) for the same `t_jobs` row.","type":"object"}},"type":"object"}}}},"401":{"description":"Unauthorized"},"422":{"description":"Validation or business rule error"}},"security":[{"bearerAuth":[]}]}},"\/timekeeping\/calculate":{"post":{"tags":["App\/Timekeeping"],"summary":"Preview timekeeping salary","description":"Dry-run calculation for the authenticated user's shift. Uses hourly rates from `t_job_workings`. Optional `start_break_time` \/ `end_break_time` apply a single break window; when omitted, the existing break on `t_job_workings` is used. Does not update `t_job_workings` or create requests.","operationId":"c29c677788fc4f287f61e4e13390ff14","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["job_working_id","start_working_time","end_working_time"],"properties":{"job_working_id":{"type":"integer","example":10},"start_working_time":{"type":"string","format":"date-time","example":"2026-06-08 09:00:00"},"end_working_time":{"type":"string","format":"date-time","example":"2026-06-08 18:00:00"},"start_break_time":{"description":"Break start (H:i), same as company job create","type":"string","example":"12:00","nullable":true},"end_break_time":{"description":"Break end (H:i); required when start_break_time is set","type":"string","example":"13:00","nullable":true}},"type":"object"}}}},"responses":{"200":{"description":"Preview calculated","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Salary preview calculated successfully."},"data":{"description":"Working minutes and salary buckets (same shape as post-calculation shift fields)","type":"object"}},"type":"object"}}}},"401":{"description":"Unauthorized"},"400":{"description":"Shift not found or not owned by the user"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/timekeeping\/request":{"post":{"tags":["App\/Timekeeping"],"summary":"Submit timekeeping change request","description":"Only when `t_job_workings.status` is `checkout` or `company_confirmed` (post QR check-out) and `user_salary_confirmed_at` is null. Creates `t_job_working_requests` (status pending) and sets `t_job_workings.status` to `request_change`. Optional single break window via `start_break_time` \/ `end_break_time`; when omitted, the existing break on `t_job_workings` is used if it lies within the requested check-in\/out window. At most 5 requests per shift row; the 6th returns `timekeeping.max_request_working_time`.","operationId":"e91de07144467ba3bc44fbdeb6b6463b","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["job_id","job_working_id","start_working_time","end_working_time","request_reason"],"properties":{"job_id":{"type":"integer","example":1},"job_working_id":{"type":"integer","example":10},"start_working_time":{"type":"string","format":"date-time","example":"2026-06-03 09:00:00"},"end_working_time":{"type":"string","format":"date-time","example":"2026-06-03 18:00:00"},"start_break_time":{"description":"Break start (H:i), same as company job create","type":"string","example":"12:00","nullable":true},"end_break_time":{"description":"Break end (H:i); required when start_break_time is set","type":"string","example":"13:00","nullable":true},"request_reason":{"type":"string","example":"Forgot to check out on time"}},"type":"object"}}}},"responses":{"200":{"description":"Change request created","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Timekeeping change request created successfully."},"data":{"description":"Created `JobWorkingRequest` row","type":"object"}},"type":"object"}}}},"401":{"description":"Unauthorized"},"400":{"description":"Business rule error. `error.key`: `timekeeping.change_request_after_salary_confirmed` when `user_salary_confirmed_at` is set; `timekeeping.change_request_pending_review` when shift status is `request_change`; `timekeeping.change_request_shift_already_paid` when shift status is `payment`; `timekeeping.change_request_company_already_approved` when shift status is `company_confirmed` and a prior request is `approved`; `timekeeping.change_request_requires_checkout` for other non-requestable statuses (e.g. `checkin`); `timekeeping.max_request_working_time` when 5 requests already exist for the shift."},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/timekeeping\/confirm":{"post":{"tags":["App\/Timekeeping"],"summary":"Confirm salary after check-out","description":"Only when `t_job_workings.status` is `checkout` or `company_confirmed`. Sets `user_salary_confirmed_at` and blocks further `POST \/timekeeping\/request` for the shift. Wallet credit happens at QR check-out; this endpoint does not change shift status to `payment`.","operationId":"9f7e7bc64b36f2c3089fa35115fbac66","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["job_id"],"properties":{"job_id":{"type":"integer","example":1},"branch_id":{"description":"Optional; when sent must match the job branch.","type":"integer","example":10}},"type":"object"}}}},"responses":{"200":{"description":"Salary confirmed","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Salary confirmed successfully."},"data":{"description":"Updated `JobWorking` with nested `job`","type":"object"}},"type":"object"}}}},"401":{"description":"Unauthorized"},"422":{"description":"Validation or business rule error"}},"security":[{"bearerAuth":[]}]}},"\/user\/profile":{"get":{"tags":["App"],"summary":"Get authenticated user profile","operationId":"94403608ae232233447fd9989443f1dc","responses":{"200":{"description":"Successful Operation","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"},"data":{"properties":{"total_withdrawable_amount":{"type":"string","example":"12000.00"},"total_received_amount":{"description":"Cumulative salary credited to the user wallet (`t_user_wallets.total_amount`).","type":"string","example":"15000.00"},"has_unread_notifications":{"description":"True when at least one notification for this user has is_read = 0.","type":"boolean","example":true},"categories":{"description":"Selected medical profile categories (full m_category rows).","type":"array","items":{"type":"object"}},"skills":{"description":"Selected skills (full m_skills rows).","type":"array","items":{"type":"object"}},"workplaces":{"description":"Selected workplaces (full m_workplaces rows).","type":"array","items":{"type":"object"}},"workplace_experiences":{"description":"Workplace type experience rows with nested master objects.","type":"array","items":{"type":"object"}},"sub_categories":{"type":"array","items":{"type":"object"}},"sub_category_details":{"type":"array","items":{"type":"object"}},"certificates":{"description":"Selected certificates (full m_certificates rows).","type":"array","items":{"type":"object"}},"experience_year":{"description":"Primary experience year from t_user_categories.experience_year_id.","type":"object","nullable":true}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearerAuth":[]}]},"put":{"tags":["App"],"summary":"Update user profile","description":"Partial update \u2014 send only fields to change. Phone number is excluded (use \/user\/phone\/send-code flow). When any address field is sent, the server geocodes the merged address and updates latitude\/longitude (clients must not send coordinates). Medical profile uses categories[] (same shape as register\/update-info): only blocks sent are upserted; other user categories are preserved. Use DELETE \/user\/profile to remove professions.","operationId":"c1fe4ddeca043281e5eeb7d99788d527","requestBody":{"description":"Use `application\/json` for Swagger testing (no avatar). Use `multipart\/form-data` to upload `avatar`; send `categories` as a JSON string in that case.","required":true,"content":{"multipart\/form-data":{"schema":{"properties":{"first_name":{"type":"string","example":"Taro"},"last_name":{"type":"string","example":"Yamada"},"first_katakana_name":{"type":"string","example":"\u30bf\u30ed\u30a6"},"last_katakana_name":{"type":"string","example":"\u30e4\u30de\u30c0"},"dob":{"type":"string","format":"date","example":"1995-08-20"},"gender":{"type":"string","example":"male","nullable":true},"country_id":{"type":"integer","example":1,"nullable":true},"postal_code":{"type":"string","example":"1000001"},"prefecture_id":{"type":"integer","example":1},"district_id":{"type":"integer","example":1,"nullable":true},"administrative_address":{"type":"string","example":"Chiyoda-ku"},"street_address":{"type":"string","example":"1-1-1 Marunouchi"},"building_address":{"type":"string","example":"ABC Building 101","nullable":true},"self_pr":{"type":"string","nullable":true},"current_work_type_id":{"type":"integer","example":1,"nullable":true},"work_preference_id":{"type":"integer","example":2,"nullable":true},"job_change_interest_id":{"type":"integer","example":1,"nullable":true},"emergency_name":{"type":"string","example":"\u7dca\u6025\u9023\u7d61\u5148 \u592a\u90ce","nullable":true},"emergency_phone":{"type":"string","example":"09012345678","nullable":true},"categories":{"description":"JSON-encoded categories[] blocks (same shape as application\/json request). Example: array of objects with category_id and optional pivot ids.","type":"string"},"avatar":{"description":"Profile image (jpeg, jpg, png, gif, webp, heic, heif; max 5 MB).","type":"string","format":"binary","nullable":true}},"type":"object"}},"application\/json":{"schema":{"properties":{"first_name":{"type":"string","example":"Taro"},"last_name":{"type":"string","example":"Yamada"},"first_katakana_name":{"type":"string","example":"\u30bf\u30ed\u30a6"},"last_katakana_name":{"type":"string","example":"\u30e4\u30de\u30c0"},"dob":{"type":"string","format":"date","example":"1995-08-20"},"gender":{"type":"string","example":"male","nullable":true},"country_id":{"description":"Nationality \/ country master id (m_countries.id)","type":"integer","example":1,"nullable":true},"postal_code":{"type":"string","example":"1000001"},"prefecture_id":{"type":"integer","example":1},"district_id":{"type":"integer","example":1,"nullable":true},"administrative_address":{"type":"string","example":"Chiyoda-ku"},"street_address":{"type":"string","example":"1-1-1 Marunouchi"},"building_address":{"type":"string","example":"ABC Building 101","nullable":true},"self_pr":{"type":"string","nullable":true},"current_work_type_id":{"description":"m_current_work_types.id","type":"integer","example":1,"nullable":true},"work_preference_id":{"description":"m_work_preferences.id","type":"integer","example":2,"nullable":true},"job_change_interest_id":{"description":"m_job_change_interests.id","type":"integer","example":1,"nullable":true},"emergency_name":{"type":"string","example":"\u7dca\u6025\u9023\u7d61\u5148 \u592a\u90ce","nullable":true},"emergency_phone":{"type":"string","example":"09012345678","nullable":true},"categories":{"description":"Medical profile blocks (per profession). When sent, upserts only listed categories and their pivots; other categories are unchanged.","type":"array","items":{"$ref":"#\/components\/schemas\/UserMedicalCategoryProfileBlock"}},"avatar":{"description":"Profile image (jpeg, jpg, png, gif, webp, heic, heif; max 5 MB). Multipart only.","type":"string","format":"binary","nullable":true}},"type":"object"}}}},"responses":{"200":{"description":"Profile updated successfully","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"},"data":{"description":"Updated user with all relations","type":"object"}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]},"delete":{"tags":["App"],"summary":"Remove medical profile categories","description":"Deletes the given category_ids and all user pivots scoped to those professions (skills, workplaces, licenses, certificates, \u2026). Other categories are preserved. Idempotent for category_ids the user does not have.","operationId":"d47c3bf63dcfc6262565486993d78b0b","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["category_ids"],"properties":{"category_ids":{"type":"array","items":{"type":"integer","example":3},"minItems":1}},"type":"object"}}}},"responses":{"200":{"description":"Categories removed successfully","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"},"data":{"type":"boolean","example":true}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/user\/license-histories":{"get":{"tags":["App"],"summary":"List user licenses and license history","description":"User licenses and their history (raw lists).","operationId":"3514fed61a36d3eff82bfe72b9cd2b9d","parameters":[{"name":"category_id","in":"query","description":"Filter history by medical category (m_category.id).","required":false,"schema":{"type":"integer","example":1}}],"responses":{"200":{"description":"Successful Operation","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"},"data":{"properties":{"user_licenses":{"type":"array","items":{"type":"object"}}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearerAuth":[]}]}},"\/user\/quit-app":{"put":{"tags":["App"],"summary":"Quit \/ deactivate account","description":"Deactivates the user's account after verifying no active job shifts remain. No request parameters are required. Sets status to inactive and invalidates all JWT tokens. Re-registration is allowed after 30 days.","operationId":"8922fc4d8a1e25e0981cd24fdc45273b","responses":{"200":{"description":"Account deactivated successfully","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Your account has been deactivated successfully."},"data":{"type":"array","items":[]}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"422":{"description":"Validation error or active jobs exist"}},"security":[{"bearerAuth":[]}]}},"\/user\/job\/completed":{"get":{"tags":["App jobs"],"summary":"List completed job workings","description":"Paginated JobWorking rows in payment or done only (excludes checkout and request_change). Optional status query filters to one. Date filters: `start_working_date` and `end_working_date` must be sent together; when both are present they take precedence over `year_month` (month filter is ignored). Each row includes selected JobWorking columns, nested job (id, name, status, company with name, company_branch with name), and transaction_logs: single withdraw log object or null \u2014 id, type, user_status, company_status, status, transaction_id, amount.","operationId":"dbb6ddadba3e16165d81b638a24183b9","parameters":[{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","minimum":1}},{"name":"limit","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"example":15}},{"name":"status","in":"query","description":"Filter by job working status (default: payment, done)","required":false,"schema":{"type":"string","enum":["payment","done"]}},{"name":"year_month","in":"query","description":"Filter by shift month (`t_job_workings.working_date`, format YYYY-MM). Ignored when both `start_working_date` and `end_working_date` are present.","required":false,"schema":{"type":"string","format":"date","example":"2026-06"}},{"name":"start_working_date","in":"query","description":"Working date range start (Y-m-d). Required together with `end_working_date`.","required":false,"schema":{"type":"string","format":"date"}},{"name":"end_working_date","in":"query","description":"Working date range end (Y-m-d). Required together with `start_working_date`.","required":false,"schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Paginated completed shifts","content":{"application\/json":{"schema":{"properties":{"data":{"type":"array","items":{"type":"object"}},"total":{"type":"integer","example":10},"last_page":{"type":"integer","example":1},"current_page":{"type":"integer","example":1}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/user\/job\/completed\/export":{"get":{"tags":["App jobs"],"summary":"Export completed shifts as wage ledger","description":"Downloads an XLSX wage ledger for the authenticated user. Requires `year_month` or both `start_working_date` and `end_working_date`. Uses the same status and date filters as GET `\/user\/job\/completed`. Footer row shows \u5408\u8a08\u91d1\u984d with SUM formulas for columns I\u2013L.","operationId":"4171fc191042b56f29f8a320ab27431a","parameters":[{"name":"status","in":"query","description":"Filter by job working status (default: all done statuses)","required":false,"schema":{"type":"string","enum":["checkout","company_confirmed","payment"]}},{"name":"year_month","in":"query","description":"Filter by shift month (`t_job_workings.working_date`, format YYYY-MM). Required when date range is not provided.","required":false,"schema":{"type":"string","format":"date","example":"2026-06"}},{"name":"start_working_date","in":"query","description":"Working date range start (Y-m-d). Required together with `end_working_date` when `year_month` is absent.","required":false,"schema":{"type":"string","format":"date"}},{"name":"end_working_date","in":"query","description":"Working date range end (Y-m-d). Required together with `start_working_date` when `year_month` is absent.","required":false,"schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Wage ledger XLSX file","content":{"application\/vnd.openxmlformats-officedocument.spreadsheetml.sheet":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"Unauthenticated"},"422":{"description":"Validation error or no data for selected filters"}},"security":[{"bearerAuth":[]}]}},"\/register\/update-info":{"post":{"tags":["App"],"summary":"Complete user registration","description":"Requires Bearer token from phone OTP verification (`auth:phone`). Phone numbers are taken from that session, not from the request body. Address is stored on registration; latitude and longitude are filled asynchronously via a queued job (do not send coordinates).","operationId":"40cc7e6f523ba78485faa87682079589","requestBody":{"description":"Use `application\/json` for Swagger testing (no avatar). Use `multipart\/form-data` to upload `avatar`; send `categories` as a JSON string in that case.","required":true,"content":{"multipart\/form-data":{"schema":{"required":["first_name","last_name","first_katakana_name","last_katakana_name","dob","country_id","postal_code","prefecture_id","administrative_address","street_address","categories"],"properties":{"first_name":{"type":"string","example":"Taro"},"last_name":{"type":"string","example":"Yamada"},"first_katakana_name":{"type":"string","example":"\u30bf\u30ed\u30a6"},"last_katakana_name":{"type":"string","example":"\u30e4\u30de\u30c0"},"dob":{"type":"string","format":"date","example":"1995-08-20"},"gender":{"type":"string","example":"male","nullable":true},"country_id":{"type":"integer","example":1},"postal_code":{"type":"string","example":"1000001"},"prefecture_id":{"type":"integer","example":1},"district_id":{"type":"integer","example":1,"nullable":true},"administrative_address":{"type":"string","example":"Chiyoda-ku"},"street_address":{"type":"string","example":"1-1-1 Marunouchi"},"building_address":{"type":"string","example":"ABC Building 101","nullable":true},"self_pr":{"type":"string","example":"Backend engineer","nullable":true},"categories":{"description":"Required. JSON-encoded categories[] blocks (same shape as application\/json request). Example: array of objects with category_id and optional pivot ids.","type":"string"},"current_work_type_id":{"type":"integer","example":1,"nullable":true},"work_preference_id":{"type":"integer","example":2,"nullable":true},"job_change_interest_id":{"type":"integer","example":1,"nullable":true},"avatar":{"description":"Profile image (jpeg, jpg, png, gif, webp, heic, heif; max 5 MB).","type":"string","format":"binary"}},"type":"object"}},"application\/json":{"schema":{"required":["first_name","last_name","first_katakana_name","last_katakana_name","dob","country_id","postal_code","prefecture_id","administrative_address","street_address","categories"],"properties":{"first_name":{"type":"string","example":"Taro"},"last_name":{"type":"string","example":"Yamada"},"first_katakana_name":{"type":"string","example":"\u30bf\u30ed\u30a6"},"last_katakana_name":{"type":"string","example":"\u30e4\u30de\u30c0"},"dob":{"type":"string","format":"date","example":"1995-08-20"},"gender":{"type":"string","example":"male","nullable":true},"country_id":{"description":"Nationality \/ country master id (m_countries.id)","type":"integer","example":1},"postal_code":{"type":"string","example":"1000001"},"prefecture_id":{"type":"integer","example":1},"district_id":{"type":"integer","example":1,"nullable":true},"administrative_address":{"type":"string","example":"Chiyoda-ku"},"street_address":{"type":"string","example":"1-1-1 Marunouchi"},"building_address":{"type":"string","example":"ABC Building 101","nullable":true},"self_pr":{"type":"string","example":"Backend engineer","nullable":true},"categories":{"description":"Required. One block per medical profession (m_category.id).","type":"array","items":{"$ref":"#\/components\/schemas\/UserMedicalCategoryProfileBlock"},"minItems":1},"current_work_type_id":{"description":"m_current_work_types.id","type":"integer","example":1,"nullable":true},"work_preference_id":{"description":"m_work_preferences.id","type":"integer","example":2,"nullable":true},"job_change_interest_id":{"description":"m_job_change_interests.id","type":"integer","example":1,"nullable":true}},"type":"object"}}}},"responses":{"200":{"description":"Successful Operation"},"401":{"description":"Unauthenticated (missing or invalid phone OTP token)"},"422":{"description":"Validation Error"},"500":{"description":"Internal Server Error"}},"security":[{"bearerAuth":[]}]}},"\/user\/phone\/send-code":{"post":{"tags":["App"],"summary":"Send OTP to new phone number","description":"Send OTP to new phone number for phone change verification.","operationId":"8b575a9e556e6008decfc589d9333be0","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["phone_number"],"properties":{"phone_number":{"description":"New phone number (8-15 digits, optional leading +)","type":"string","example":"0901234567"}},"type":"object"}}}},"responses":{"200":{"description":"OTP sent successfully (mock OTP: 1234)","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"},"data":{"type":"array","items":[]}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"422":{"description":"Validation error or phone already taken"}},"security":[{"bearerAuth":[]}]}},"\/user\/phone\/verify-code":{"post":{"tags":["App"],"summary":"Verify OTP and update phone number","description":"Verify OTP and update phone number. Returns new JWT token.","operationId":"464b959a88b8f8b20fb6fa47a5e914da","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["phone_number","code"],"properties":{"phone_number":{"type":"string","example":"0901234567"},"code":{"description":"4-digit OTP code","type":"string","example":"1234"}},"type":"object"}}}},"responses":{"200":{"description":"Phone updated. Old token is invalidated \u2014 use the returned token.","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"},"data":{"properties":{"access_token":{"type":"string"},"refresh_token":{"type":"string"},"expires_in":{"type":"integer","example":3600},"token_type":{"type":"string","example":"bearer"},"user":{"description":"Updated user","type":"object"}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"422":{"description":"Invalid or expired OTP"}},"security":[{"bearerAuth":[]}]}},"\/reviews\/users\/summary":{"get":{"tags":["App Review users"],"summary":"Get worker review summary","description":"Returns aggregated review scores and total review count for the authenticated worker (`t_user_review_summaries`). Only submitted company reviews (`status = reviewed`) are included.","operationId":"c30f02e3200a54e715804abdce8d610d","responses":{"200":{"description":"Review summary","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Worker review summary fetched successfully."},"data":{"properties":{"user_id":{"type":"integer","example":10},"punctuality_avg":{"type":"string","example":"4.25"},"appearance_avg":{"type":"string","example":"4.00"},"communication_avg":{"type":"string","example":"4.50"},"work_attitude_avg":{"type":"string","example":"4.00"},"skill_avg":{"type":"string","example":"4.25"},"total_avg":{"type":"string","example":"4.19"},"total_reviews":{"type":"integer","example":8},"user":{"properties":{"id":{"type":"integer","example":10},"name":{"type":"string","example":"Demo User"},"image":{"type":"string","example":"https:\/\/example.com\/avatar.png","nullable":true}},"type":"object"}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthenticated"}},"security":[{"bearerAuth":[]}]}},"\/reviews\/users":{"get":{"tags":["App Review users"],"summary":"List worker reviews","description":"Returns paginated company reviews for the authenticated worker. Only submitted reviews (`status = reviewed`) are returned. Sorted by `id` descending (newest first).","operationId":"d3e8ecf6e4c33367d4801b2513e5cf92","parameters":[{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","minimum":1,"example":1}},{"name":"limit","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"example":15}}],"responses":{"200":{"description":"Review list","content":{"application\/json":{"schema":{"properties":{"data":{"type":"array","items":{"properties":{"id":{"type":"integer","example":1},"job_working_id":{"type":"integer","example":42},"job_id":{"type":"integer","example":7},"company_branch_id":{"type":"integer","example":3},"punctuality":{"type":"integer","example":5},"appearance":{"type":"integer","example":4},"communication":{"type":"integer","example":5},"work_attitude":{"type":"integer","example":4},"skill":{"type":"integer","example":5},"average_score":{"type":"string","example":"4.60"},"comment":{"type":"string","example":"Great worker.","nullable":true},"created_at":{"type":"string","format":"date-time","example":"2026-06-01 14:30:00"},"company_branch":{"properties":{"id":{"type":"integer","example":3},"name":{"type":"string","example":"Shinjuku Medical Clinic"}},"type":"object"}},"type":"object"}},"total":{"type":"integer","example":8},"last_page":{"type":"integer","example":1},"current_page":{"type":"integer","example":1}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/user\/withdraw":{"post":{"tags":["App Wallet"],"summary":"Withdraw from wallet","description":"Sets `t_transaction_logs.user_status` from `pending` to `approved`. When `company_status` is already `approved` on the same withdraw row, the shift moves to `done`. Optional `job_id` scopes to the latest shift for that job.","operationId":"50ae986648fb489eadf05f2b5f7610eb","requestBody":{"required":false,"content":{"application\/json":{"schema":{"properties":{"job_id":{"description":"Optional. Job ID (`t_jobs.id`); when present, only that job's latest shift is withdrawn. Omit or null to withdraw all in-wallet rows.","type":"integer","example":42,"nullable":true}},"type":"object"}}}},"responses":{"200":{"description":"Withdrawal recorded","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"},"data":{"properties":{"transaction_id":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000"},"amount":{"type":"string","example":"5000.00"},"job_working_ids":{"type":"array","items":{"type":"integer"}}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"422":{"description":"Validation or business rule error"}},"security":[{"bearerAuth":[]}]}},"\/test\/log":{"get":{"tags":["Test"],"summary":"Test structured logging (INFO)","description":"Triggers a manual Log::info() with structured context to verify CloudWatch JSON formatting.","operationId":"f2f61a574fb0876990036021b9ea8d50","responses":{"200":{"description":"Log sent successfully","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Log sent successfully"}},"type":"object"}}}}}}},"\/test\/log-error":{"get":{"tags":["Test"],"summary":"Test structured logging (ERROR)","description":"Triggers a manual Log::error() with structured context to verify CloudWatch JSON formatting.","operationId":"0fb6168ad6d18e75c94fef5ddcc5b50e","responses":{"200":{"description":"Log sent successfully","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Log sent successfully"}},"type":"object"}}}}}}},"\/test\/exception\/base":{"get":{"tags":["Test"],"summary":"Test BaseException handling","description":"Throws a BaseException to verify JSON rendering and logging behavior (should NOT show stack trace in production).","operationId":"a07986fd9fcf77891e0f6f1650ac0678","responses":{"400":{"description":"BaseException triggered","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":false},"message":{"type":"string","example":"Test BaseException message"},"error":{"properties":{"key":{"type":"string","example":"auth.failed"},"content":{"type":"string","example":"Test BaseException message"}},"type":"object"}},"type":"object"}}}}}}},"\/test\/exception\/generic":{"get":{"tags":["Test"],"summary":"Test generic Exception handling","description":"Throws a generic Exception to verify 500 JSON rendering and logging behavior (should show full stack trace).","operationId":"2d51e5f727e95c4675b6b656381f4392","responses":{"500":{"description":"Internal Server Error","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":false},"message":{"type":"string","example":"Internal server error."}},"type":"object"}}}}}}}},"components":{"schemas":{"user":{"description":"User model","properties":{"id":{"description":"OpenAPI definition: root + components (schemas, security).","type":"integer","example":1},"name":{"type":"string","example":"John Doe"},"email":{"type":"string","format":"email","example":"john@example.com"},"email_verified_at":{"type":"string","format":"date-time","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"type":"object"},"api_response":{"description":"Standard API response wrapper","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Succeed"},"data":{"description":"Response payload (object, array or null)"}},"type":"object"},"UnprocessableEntity":{"description":"Laravel validation error (HTTP 422)","properties":{"message":{"type":"string","example":"The given data was invalid."},"errors":{"description":"Field name to list of validation messages","type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"type":"object"},"paginated_response":{"description":"Paginator object (value of response.data for list endpoints)","properties":{"current_page":{"type":"integer","example":1},"data":{"type":"array","items":{"$ref":"#\/components\/schemas\/user"}},"first_page_url":{"type":"string"},"from":{"type":"integer"},"last_page":{"type":"integer"},"last_page_url":{"type":"string"},"links":{"type":"array","items":{"type":"object"}},"next_page_url":{"type":"string","nullable":true},"path":{"type":"string"},"per_page":{"type":"integer","example":15},"prev_page_url":{"type":"string","nullable":true},"to":{"type":"integer"},"total":{"type":"integer"}},"type":"object"},"company":{"description":"Company model","properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"Comedi Inc."},"status":{"description":"1=active 2=inactive","type":"integer","example":1},"furigana":{"type":"string","example":"\u30b3\u30e1\u30c7\u30a3"},"email":{"type":"string","format":"email","example":"contact@example.com"},"tax_code":{"description":"Business \/ corporate registration number (\u6cd5\u4eba\u756a\u53f7).","type":"string","example":"1234567890123","nullable":true},"address":{"type":"string","example":"1-2-3 Shibuya"},"latitude":{"type":"number","format":"float","example":35.681236,"nullable":true},"longitude":{"type":"number","format":"float","example":139.767125,"nullable":true},"company_file_id":{"type":"integer","example":10,"nullable":true},"company_file":{"oneOf":[{"$ref":"#\/components\/schemas\/FileUpload"}],"nullable":true},"company_avatar_id":{"type":"integer","example":11,"nullable":true},"company_avatar":{"oneOf":[{"$ref":"#\/components\/schemas\/FileUpload"}],"nullable":true},"branch_count":{"description":"Current non-deleted company branch count, included in admin company list and detail.","type":"integer","example":3},"prefecture_id":{"type":"integer","example":13},"district_id":{"type":"integer","example":101,"nullable":true},"representative_name":{"type":"string","example":"Tanaka Taro"},"business_content":{"type":"string","example":"Software development"},"area":{"description":"Company area \/ region label.","type":"string","example":"Kanto","nullable":true},"categories":{"description":"Company-level job categories (m_category via t_company_category)","type":"array","items":{"properties":{"id":{"type":"integer","example":1},"key":{"type":"string","example":"nurse"},"name":{"type":"string","example":"\u770b\u8b77\u5e2b"},"display_order":{"type":"integer","example":1}},"type":"object"}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"type":"object"},"CompanyUser":{"description":"Company user (login account linked to a company)","properties":{"id":{"type":"integer","example":1},"company_id":{"type":"integer","example":1},"type":{"description":"1=admin 2=branch","type":"integer","example":1},"status":{"description":"1=active 2=inactive","type":"integer","example":1},"name":{"type":"string","example":"ABC Clinic"},"email":{"type":"string","format":"email","example":"clinic@example.com"},"token_version":{"type":"integer","example":0},"phone_number":{"type":"string","example":"08012345678","nullable":true},"branch_user_roles":{"description":"Assigned branch roles (empty for company admin accounts)","type":"array","items":{"$ref":"#\/components\/schemas\/BranchUserRole"}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"type":"object"},"FileUpload":{"description":"t_file_uploads: `path` is the S3 object key (persisted). `url` is a temporary presigned URL for S3 (fallback: public base + path if signing is unavailable).","properties":{"id":{"type":"integer","example":1},"path":{"description":"Object key on S3 (always stored)","type":"string","example":"uploads\/avatars\/abc.png"},"url":{"description":"Temporary presigned URL (TTL controlled by FILE_UPLOAD_PRESIGNED_TTL_MINUTES). Falls back to public base URL if signing is unavailable; null only when path\/base is missing.","type":"string","format":"uri","nullable":true},"name":{"type":"string","example":"photo.jpg"},"extension":{"type":"string","example":"jpg"}},"type":"object"},"CompanyBranch":{"description":"Company branch (t_company_branches)","properties":{"id":{"type":"integer","example":1},"company_id":{"type":"integer","example":1},"name":{"type":"string","example":"Shibuya Branch"},"prefecture_id":{"type":"integer","example":13,"nullable":true},"district_id":{"type":"integer","example":101,"nullable":true},"postal_code":{"type":"string","example":"1500002","nullable":true},"address_line":{"type":"string","nullable":true},"latitude":{"type":"number","format":"float","example":35.658034,"nullable":true},"longitude":{"type":"number","format":"float","example":139.701636,"nullable":true},"access_note":{"type":"string","nullable":true},"has_on_site_parking":{"type":"boolean","example":true},"commuting_note":{"type":"string","nullable":true},"responsible_person_name":{"type":"string","nullable":true},"face_photo_file_id":{"type":"integer","nullable":true},"face_photo_file":{"oneOf":[{"$ref":"#\/components\/schemas\/FileUpload"}],"nullable":true},"responsible_person_photo_file_id":{"type":"integer","nullable":true},"responsible_person_photo_file":{"oneOf":[{"$ref":"#\/components\/schemas\/FileUpload"}],"nullable":true},"greeting_message":{"type":"string","nullable":true},"worker_contact_name":{"type":"string","nullable":true},"worker_contact_photo_file_id":{"type":"integer","nullable":true},"worker_contact_photo_file":{"oneOf":[{"$ref":"#\/components\/schemas\/FileUpload"}],"nullable":true},"worker_contact_phone":{"type":"string","nullable":true},"emergency_contact":{"type":"string","nullable":true},"responsible_person_email":{"type":"string","format":"email","nullable":true},"first_confirmation_auto_message":{"type":"string","nullable":true},"facility_open_date":{"type":"string","format":"date","nullable":true},"unemployment_insurance_office_number":{"type":"string","nullable":true},"company_regions":{"description":"Company regions this branch belongs to (t_company_regions via pivot)","type":"array","items":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}},"categories":{"description":"Branch job categories (m_category via t_company_branch_category)","type":"array","items":{"properties":{"id":{"type":"integer","example":1},"key":{"type":"string","example":"nurse"},"name":{"type":"string","example":"\u770b\u8b77\u5e2b"},"display_order":{"type":"integer","example":1}},"type":"object"}},"travel_methods":{"description":"Commute options (m_travel_methods via pivot)","type":"array","items":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"type":"object"},"BranchRole":{"description":"Branch role master (m_branch_roles)","properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"Manager"},"description":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time","nullable":true},"updated_at":{"type":"string","format":"date-time","nullable":true}},"type":"object"},"BranchUserRole":{"description":"Pivot row (t_branch_user_roles) with nested role","properties":{"id":{"type":"integer","example":1},"branch_user_profile_id":{"type":"integer","example":1},"branch_role_id":{"type":"integer","example":1},"branch_role":{"$ref":"#\/components\/schemas\/BranchRole"}},"type":"object"},"CompanyRegion":{"description":"Company region (t_company_regions)","properties":{"id":{"type":"integer","example":1},"company_id":{"type":"integer","example":1},"name":{"type":"string","example":"Kanto"}},"type":"object"},"BranchUser":{"description":"Branch user profile (t_branch_user_profiles) with relations","properties":{"id":{"type":"integer","example":1},"company_id":{"type":"integer","example":1},"name":{"type":"string","example":"Yamada Taro"},"furigana":{"type":"string","nullable":true},"phone_number":{"type":"string","nullable":true},"company_user":{"description":"Login credentials (t_company_user)","properties":{"id":{"type":"integer"},"email":{"type":"string","format":"email"}},"type":"object","nullable":true},"branches":{"description":"Assigned branches (t_branch_user_branches pivot)","type":"array","items":{"$ref":"#\/components\/schemas\/CompanyBranch"}},"regions":{"description":"Assigned regions (t_branch_user_regions pivot)","type":"array","items":{"$ref":"#\/components\/schemas\/CompanyRegion"}},"branch_user_roles":{"type":"array","items":{"$ref":"#\/components\/schemas\/BranchUserRole"}},"created_at":{"type":"string","format":"date-time","nullable":true},"updated_at":{"type":"string","format":"date-time","nullable":true}},"type":"object"},"Region":{"description":"Region master (m_regions)","properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"Kanto"},"key":{"type":"string","example":"kanto"},"description":{"type":"string","example":"Kanto region of Japan","nullable":true}},"type":"object"},"UserMedicalWorkplaceExperience":{"required":["workplace_type_id","experience_year_id"],"properties":{"workplace_type_id":{"description":"m_workplace_types.id","type":"integer","example":1},"experience_year_id":{"description":"m_experience_years.id","type":"integer","example":2}},"type":"object"},"UserMedicalLicenseInput":{"required":["type"],"properties":{"id":{"description":"Existing t_user_licenses.id when updating","type":"integer","example":1,"nullable":true},"type":{"type":"string","example":"doctor"},"category_id":{"type":"integer","example":1,"nullable":true},"license_number":{"type":"string","example":"123456","nullable":true},"registration_subtype_id":{"type":"integer","example":1,"nullable":true},"acquired_at":{"type":"string","format":"date","example":"2020-04-01","nullable":true},"clinical_training_end_at":{"type":"string","format":"date","example":"2025-03-31","nullable":true}},"type":"object"},"UserMedicalCategoryProfileBlock":{"description":"Medical profile data for one profession (m_category.id). Certificates and licenses must be nested here \u2014 root-level certificate_ids \/ licenses are rejected.","required":["category_id"],"properties":{"category_id":{"type":"integer","example":1},"experience_year_id":{"description":"m_experience_years.id","type":"integer","example":2,"nullable":true},"skill_ids":{"type":"array","items":{"type":"integer","example":1},"nullable":true},"workplace_ids":{"type":"array","items":{"type":"integer","example":1},"nullable":true},"workplace_experiences":{"type":"array","items":{"$ref":"#\/components\/schemas\/UserMedicalWorkplaceExperience"},"nullable":true},"sub_category_ids":{"type":"array","items":{"type":"integer","example":1},"nullable":true},"sub_category_detail_ids":{"type":"array","items":{"type":"integer","example":1},"nullable":true},"certificate_ids":{"type":"array","items":{"type":"integer","example":1},"nullable":true},"licenses":{"type":"array","items":{"$ref":"#\/components\/schemas\/UserMedicalLicenseInput"},"nullable":true}},"type":"object"}},"securitySchemes":{"bearerAuth":{"type":"http","description":"JWT access token (tymon\/jwt-auth); send as Authorization: Bearer <token>","bearerFormat":"JWT","scheme":"bearer"}}},"tags":[{"name":"App company branches","description":"Company branch resources for the mobile app"},{"name":"App","description":"App API"},{"name":"App Bank Account","description":"Bank account management for app users"},{"name":"App\/Documents","description":"Policy documents (presigned URLs)"},{"name":"App jobs","description":"Job listings for the mobile app"},{"name":"App locations","description":"Location utilities for the mobile app"},{"name":"App\/SalaryExport","description":"Withholding tax certificate (\u6e90\u6cc9\u5fb4\u53ce\u7968) exports"},{"name":"App\/Timekeeping","description":"App user check-in, check-out (credits wallet on check-out), salary confirm, and time-change requests"},{"name":"App Wallet","description":"Wallet and withdrawals (app users)"},{"name":"Test","description":"Test endpoints for logging and exception handling"},{"name":"App favorites","description":"App favorites"},{"name":"App Review company branches","description":"App Review company branches"},{"name":"App - FCM","description":"App - FCM"},{"name":"KYC","description":"KYC"},{"name":"App - Notifications","description":"App - Notifications"},{"name":"App Review users","description":"App Review users"}]}