{"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}\/reviews\/{review_id}\/reply":{"post":{"tags":["App Review company branches"],"summary":"Reply to a company branch review","description":"Create or update a single-level reply for a specific review. Only the author of the review can reply via this endpoint.","operationId":"61d8af0534a271d9c7af3dac86a1a133","parameters":[{"name":"id","in":"path","description":"Company Branch ID","required":true,"schema":{"type":"integer","minimum":1}},{"name":"review_id","in":"path","description":"Review ID","required":true,"schema":{"type":"integer","minimum":1}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["reply"],"properties":{"reply":{"type":"string","maxLength":1000,"example":"Thanks for the update."}},"type":"object"}}}},"responses":{"200":{"description":"Reply upserted","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Company branch review replied successfully."},"data":{"type":"boolean","example":true}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"404":{"description":"Not found"},"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.","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":20}},{"name":"order_by","in":"query","description":"Sort field","required":false,"schema":{"type":"string","enum":["id","created_at"]}},{"name":"order_direction","in":"query","description":"Sort direction","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},"reply":{"properties":{"user_id":{"type":"integer","example":5},"reply":{"type":"string","example":"Thanks for your feedback."},"created_at":{"type":"string","format":"date-time","nullable":true},"updated_at":{"type":"string","format":"date-time","nullable":true},"user":{"properties":{"id":{"type":"integer","example":5},"name":{"type":"string","example":"Demo User"},"katakana_name":{"type":"string","example":"\u30c7\u30e2\u30e6\u30fc\u30b6\u30fc"}},"type":"object","nullable":true}},"type":"object","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":20}},{"name":"status","in":"query","description":"Filter by status: pending, approved, rejected, cancelled","required":false,"schema":{"type":"string","enum":["pending","approved","rejected","cancelled"]}},{"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":{"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":[]}]}},"\/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"},"422":{"description":"Validation \/ business rule error"}},"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 cancelled immediately. `is_early_cancel` is not set.\n- `approved` \u2192 transitions to `cancel_requested`; company must approve\/reject.\n`is_early_cancel` is set to `true` when the request arrives\nmore than 1 hour before the shift start time, `false` otherwise.\n- `working` \/ `user_checkout` \/ `company_checkout` \u2192 400 error (cannot cancel while working).\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":{"properties":{"cancel_note":{"description":"Mandatory note recorded in status history.","type":"string","maxLength":2000,"nullable":true}},"type":"object"}}}},"responses":{"200":{"description":"Cancelled (pending\u2192cancelled) 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 cancelled directly; '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":"'cancelled' when the pending apply was cancelled directly; 'cancel_requested' when the approved apply is awaiting company decision.","type":"string","enum":["cancelled","cancel_requested"]},"is_early_cancel":{"description":"null when cancelled from pending. true when the cancel request was submitted more than 1 hour before shift start; false otherwise.","type":"boolean","nullable":true}},"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 (working \/ user_checkout \/ company_checkout)","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":{"get":{"tags":["App jobs"],"summary":"List jobs (app)","description":"List open job postings (requires logged-in app user).","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)","required":false,"schema":{"type":"string","enum":["id","start_working_date","end_apply_date_time"]}},{"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","required":false,"schema":{"type":"string","format":"date"}},{"name":"end_working_date","in":"query","required":false,"schema":{"type":"string","format":"date"}},{"name":"start_working_time","in":"query","required":false,"schema":{"type":"string","example":"09:00"}},{"name":"end_working_time","in":"query","required":false,"schema":{"type":"string","example":"18:00"}},{"name":"hourly_salary","in":"query","description":"Minimum hourly salary","required":false,"schema":{"type":"number"}},{"name":"service_type_ids","in":"query","description":"Comma-separated m_service_types ids \u2014 filters by job.service_type_id directly","required":false,"schema":{"type":"string"}},{"name":"strength_service_ids","in":"query","description":"Comma-separated m_strength_services 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":"experience_domain_ids","in":"query","description":"Comma-separated m_experience_domains ids","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated job rows: data, total, last_page, current_page"},"401":{"description":"Unauthenticated"},"422":{"description":"Validation error"}},"security":[{"bearerAuth":[]}]}},"\/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"},"service_type_id":{"type":"integer","nullable":true},"service_type":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object","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"},"experience_domains":{"type":"array","items":{"type":"object"}},"strength_services":{"type":"array","items":{"type":"object"}},"job_levels":{"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":"working"},"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).","type":"string","example":"approved","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}},"type":"object"}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"404":{"description":"Not found or not open for application"}},"security":[{"bearerAuth":[]}]}},"\/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":{"post":{"tags":["KYC"],"summary":"Create KYC applicant","description":"Swagger endpoint: `createApplicant` (POST `\/kyc\/applicant`).","operationId":"createKycApplicant","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["user_id","first_name","last_name","dob","nationality","country"],"properties":{"user_id":{"description":"User ID must exist in t_users table","type":"integer","example":1001},"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":"USA"},"country":{"description":"ISO 3166-1 alpha-3","type":"string","maxLength":3,"minLength":3,"example":"USA"},"id_number":{"type":"string","maxLength":50,"example":"A1234567","nullable":true},"phone":{"type":"string","maxLength":20,"example":"+84901234567","nullable":true},"email":{"type":"string","format":"email","maxLength":255,"example":"user@email.com","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 3166-1 alpha-2","type":"string","maxLength":2,"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},"applicant_id":{"type":"string","example":"65f123abc"}},"type":"object"}}}},"422":{"description":"Validation error"}}}},"\/kyc\/generate-sdk-token":{"post":{"tags":["KYC"],"summary":"Generate Sumsub SDK token","description":"Generate SDK access token for Sumsub Web\/Mobile SDK using applicant_id","operationId":"generateKycSdkToken","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["applicant_id"],"properties":{"applicant_id":{"description":"Sumsub applicant ID","type":"string","maxLength":255,"example":"65f123abc987654321"}},"type":"object"}}}},"responses":{"200":{"description":"SDK token generated successfully","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"token":{"type":"string","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"},"expired_at":{"type":"integer","example":1710000000}},"type":"object"}}}},"422":{"description":"Validation error","content":{"application\/json":{"schema":{"properties":{"message":{"type":"string","example":"The given data was invalid."}},"type":"object"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearerAuth":[]}]}},"\/kyc\/init":{"post":{"tags":["KYC"],"summary":"Init KYC applicant","description":"Swagger endpoint: `initKycApplicant` (POST `\/kyc\/init`).","operationId":"initKycApplicant","responses":{"200":{"description":"Applicant created successfully","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"applicant_id":{"type":"string","example":"65f123abc"}},"type":"object"}}}},"422":{"description":"Validation error"}}}},"\/masters":{"get":{"tags":["App"],"summary":"Get master data","description":"Get master data for registration and job filters (includes service_types \/ facility types for \u65bd\u8a2d\u5f62\u614b).","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":{"type":"object"}},"districts":{"type":"array","items":{"type":"object"}},"job_categories":{"type":"array","items":{"type":"object"}},"job_sub_categories":{"type":"array","items":{"type":"object"}},"experience_domains":{"type":"array","items":{"type":"object"}},"experience_years":{"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"}},"service_types":{"type":"array","items":{"type":"object"}},"strength_services":{"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"}}}},"\/salary\/list-year-working":{"get":{"tags":["App\/SalaryExport"],"summary":"List working years for withholding tax certificate","description":"List years (YYYY) 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":{"type":"string","example":"2026"}}},"type":"object"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearerAuth":[]}]}},"\/salary\/source-income-slip-pdf":{"get":{"tags":["App\/SalaryExport"],"summary":"Download withholding tax certificate (PDF)","description":"SCR-001: file download \u6e90\u6cc9\u5fb4\u53ce\u7968. Name: \u6e90\u6cc9\u5fb4\u53ce\u7968_{staff}_{company}_{year}\u5e74.pdf. May return filled XLSX if PDF conversion (e.g. PSPDFKit) is unavailable.","operationId":"7f43bf4d64f492aaec91edd354eb505f","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":{"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` payload","type":"object"}},"type":"object"}}}},"401":{"description":"Unauthorized"},"422":{"description":"Validation or business rule error"}},"security":[{"bearerAuth":[]}]}},"\/timekeeping\/confirm":{"post":{"tags":["App\/Timekeeping"],"summary":"Confirm salary (finalize shift as done)","description":"Requires check-in and checkout (`start_working_time` and `end_working_time`). Writes consumption tax on net pay, sets `t_job_workings.status=done` and `t_job_applies.status=done` with actual minutes\/income snapshot.","operationId":"19cfcd1070ffa9a98535ab4d23c1a4f5","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` and working snapshot when set","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` including `consumption_tax`, `user_salary_tax_value`, `user_salary_after_tax`, `done_at`","type":"object"}},"type":"object"}}}},"401":{"description":"Unauthorized"},"422":{"description":"Validation or business rule error (wrong status, branch mismatch, early checkout, etc.)"}},"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"}},"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). Pivot arrays replace all existing records when sent.","operationId":"c1fe4ddeca043281e5eeb7d99788d527","requestBody":{"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":{"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},"experience_years":{"type":"integer","example":3,"nullable":true},"current_work_type":{"type":"integer","example":1,"nullable":true},"work_preference":{"type":"integer","example":2,"nullable":true},"job_change_interest":{"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},"experience_domain_ids[]":{"type":"array","items":{"type":"integer"},"nullable":true},"strength_service_ids[]":{"type":"array","items":{"type":"integer"},"nullable":true},"business_category_ids[]":{"description":"User category ids (m_user_categories.id)","type":"array","items":{"type":"integer"},"nullable":true},"certificate_ids[]":{"type":"array","items":{"type":"integer"},"nullable":true},"certificate_type_other":{"type":"string","nullable":true},"avatar":{"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":[]}]}},"\/user\/quit-app":{"put":{"tags":["App"],"summary":"Quit \/ deactivate account","description":"Deactivates the user's account after verifying no active job shifts remain. Records survey answers, sets status to inactive, and invalidates all JWT tokens. Re-registration is allowed after 30 days.","operationId":"8922fc4d8a1e25e0981cd24fdc45273b","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["few_number_of_jobs","heavy_penalty_mechanism","using_another_app"],"properties":{"few_number_of_jobs":{"description":"Survey answer key","type":"string","enum":["high","medium","low","unlike"],"example":"high"},"heavy_penalty_mechanism":{"description":"Survey answer key","type":"string","enum":["high","medium","low","unlike"],"example":"medium"},"using_another_app":{"description":"Survey answer key","type":"string","enum":["high","medium","low","unlike"],"example":"low"},"reason":{"description":"Optional free-text reason","type":"string","maxLength":200,"nullable":true}},"type":"object"}}}},"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 statuses company_checkout, done, or payment (optional status query filters to one). Each row includes selected JobWorking columns, nested job (id, name, status, company with name, company_branch with name), and transaction_logs: array of objects containing only the status field per wallet movement linked to the shift.","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":20}},{"name":"status","in":"query","description":"Filter by job working status: company_checkout, done, payment","required":false,"schema":{"type":"string","enum":["company_checkout","done","payment"]}}],"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\/company":{"get":{"tags":["App"],"summary":"List companies for withholding slip year","description":"Returns distinct `t_companies` where the user has `t_job_workings` in the given calendar year with completed statuses (same set as list-year-working \/ slip download).","operationId":"f5806ac5eeebaa61730a0ca3af83c272","parameters":[{"name":"year","in":"query","required":true,"schema":{"type":"integer","example":2026}}],"responses":{"200":{"description":"Array of objects with id and name properties, sorted by name","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"Sample Corp"}},"type":"object"}}},"type":"object"}}}},"401":{"description":"Unauthenticated"},"422":{"description":"Validation error (e.g. missing year)"}},"security":[{"bearerAuth":[]}]}},"\/register\/update-info":{"post":{"tags":["App"],"summary":"Register user","description":"Requires Bearer token from phone OTP verification (`auth:phone`). Phone numbers are taken from that session, not from the request body.","operationId":"40cc7e6f523ba78485faa87682079589","requestBody":{"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"],"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"},"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},"administrative_address":{"type":"string","example":"Chiyoda-ku"},"street_address":{"type":"string","example":"1-1-1 Marunouchi"},"building_address":{"type":"string","example":"ABC Building 101"},"experience_years":{"type":"integer","example":3},"self_pr":{"type":"string","example":"Backend engineer"},"current_work_type":{"type":"integer","example":1},"work_preference":{"type":"integer","example":2},"job_change_interest":{"type":"integer","example":1},"experience_domain_ids[]":{"type":"array","items":{"type":"integer","example":1}},"strength_service_ids[]":{"type":"array","items":{"type":"integer","example":1}},"business_category_ids[]":{"description":"User category ids (m_user_categories.id)","type":"array","items":{"type":"integer","example":1}},"certificate_ids[]":{"type":"array","items":{"type":"integer","example":1}},"certificate_type_other":{"type":"string","example":"Other cert"},"avatar":{"type":"string","format":"binary"}},"type":"object"}}}},"responses":{"200":{"description":"Successful Operation"},"422":{"description":"Validation Error"},"500":{"description":"Internal Server Error"}}}},"\/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":[]}]}},"\/user\/withdraw":{"post":{"tags":["App Wallet"],"summary":"Withdraw from wallet","description":"Without `job_id`: withdraws every `in-wallet` company payment for the user (all jobs). With `job_id`: withdraws only lines linked to the user's latest job working for that job. Each distinct employer among the touched payments must have a row in `t_company_bank_accounts`. Until a bank payout API is integrated, success rows are persisted locally so wallet and transaction tables stay consistent.","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"},"company_payment_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."},"furigana":{"type":"string","example":"\u30b3\u30e1\u30c7\u30a3"},"email":{"type":"string","format":"email","example":"contact@example.com"},"phone_number":{"type":"string","example":"08012345678"},"work_place":{"type":"string","example":"Tokyo"},"address":{"type":"string","example":"1-2-3 Shibuya"},"prefecture_id":{"type":"integer","example":13},"representative_name":{"type":"string","example":"Tanaka Taro"},"total_staff":{"type":"integer","example":20},"business_content":{"type":"string","example":"Software development"},"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},"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},"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"}},"service_types":{"description":"Facility service categories (m_service_types via pivot)","type":"array","items":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"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"}},"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\/SalaryExport","description":"Withholding tax certificate (\u6e90\u6cc9\u5fb4\u53ce\u7968) exports"},{"name":"App\/Timekeeping","description":"App user check-in, check-out, and salary confirmation"},{"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"}]}