{"openapi":"3.0.0","info":{"title":"Backend API","version":"0.1.0","description":"API documentation for this service. Use GET /api-docs.json for the full spec as copy-pasteable JSON. All schemas include example values."},"servers":[{"url":"/api"}],"tags":[{"name":"Auth","description":"Authentication — register, login, logout, password reset, and current user"},{"name":"Users","description":"User management — CRUD, search, and role assignment"},{"name":"Roles","description":"RBAC roles and permissions"},{"name":"Health","description":"Service liveness and version"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"ApiSuccessResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"statusCode":{"type":"integer","example":200},"data":{"type":"object","description":"Response payload"},"message":{"type":"string","example":"Data has been successfully retrieved."}},"example":{"success":true,"statusCode":200,"data":{},"message":"Data has been successfully retrieved."}},"ApiSuccessResponseWithPagination":{"type":"object","properties":{"success":{"type":"boolean","example":true},"statusCode":{"type":"integer","example":200},"data":{"type":"array","items":{"type":"object"}},"message":{"type":"string"},"pagination":{"description":"Present only when the client passes `page` or `page_size` query params; omitted when no pagination is requested (all results returned).","type":"object","properties":{"total":{"type":"integer","example":100},"pageIndex":{"type":"integer","example":1},"pageSize":{"type":"integer","example":20}}}},"example":{"success":true,"statusCode":200,"data":[],"message":"Data has been successfully retrieved.","pagination":{"total":100,"pageIndex":1,"pageSize":20}}},"ApiErrorResponse":{"type":"object","properties":{"success":{"type":"boolean","example":false},"statusCode":{"type":"integer","example":401},"data":{"type":"object","nullable":true},"message":{"type":"string"}},"example":{"success":false,"statusCode":401,"data":null,"message":"Invalid or expired authentication token. Please log in again."}},"SearchHit":{"type":"object","required":["id","entity_type","display_name","sub_text"],"properties":{"id":{"type":"string"},"entity_type":{"type":"string","enum":["student","parent","staff","enquiry","invoice"]},"display_name":{"type":"string"},"sub_text":{"type":"string"}}}}},"paths":{"/v1/users":{"get":{"tags":["Users"],"summary":"List users (paginated + searchable)","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","minimum":1},"description":"1-based page index. Omit to return all records."},{"in":"query","name":"page_size","schema":{"type":"integer","minimum":1,"maximum":200},"description":"Page size. Defaults to 20 when pagination is requested."},{"in":"query","name":"search","schema":{"type":"string"},"description":"Case-insensitive search over email and full_name."},{"in":"query","name":"is_active","schema":{"type":"boolean"}},{"in":"query","name":"role_code","schema":{"type":"string"}}],"responses":{"200":{"description":"List of users","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}},"401":{"description":"Unauthenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/users/{id}":{"get":{"tags":["Users"],"summary":"Get a single user by id","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"User","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"put":{"tags":["Users"],"summary":"Update a user","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"full_name":{"type":"string"},"is_active":{"type":"boolean"},"password":{"type":"string","minLength":8},"role_codes":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"User updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"delete":{"tags":["Users"],"summary":"Soft-delete a user","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"User deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/timetables":{"get":{"tags":["Timetable"],"summary":"List timetables","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"academic_year_id","schema":{"type":"string"}},{"in":"query","name":"class_id","schema":{"type":"string"}},{"in":"query","name":"section_id","schema":{"type":"string"}},{"in":"query","name":"status","schema":{"type":"string","enum":["draft","finalized"]}}],"responses":{"200":{"description":"Timetable list"}}},"post":{"tags":["Timetable"],"summary":"Create a new timetable (draft)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["academic_year_id","class_id","section_id","branch_id"]}}}},"responses":{"200":{"description":"Created timetable"}}}},"/v1/timetables/{id}":{"get":{"tags":["Timetable"],"summary":"Get timetable by ID (with all slots)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Timetable detail with slots"}}}},"/v1/timetables/{id}/slots":{"post":{"tags":["Timetable"],"summary":"Bulk upsert timetable slots (day x period x subject x teacher)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slots"],"properties":{"slots":{"type":"array","items":{"type":"object","required":["day_of_week","period_number","subject_id","teacher_id"]}}}}}}},"responses":{"200":{"description":"Slots upserted"}}}},"/v1/timetables/{id}/finalize":{"post":{"tags":["Timetable"],"summary":"Finalize timetable (validates no teacher conflicts first)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Timetable finalized"},"400":{"description":"Conflict detected"}}}},"/v1/teacher-assignments":{"get":{"tags":["Teacher Assignments"],"summary":"List teacher assignments (filterable by teacher, class, subject)","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer"}},{"in":"query","name":"page_size","schema":{"type":"integer"}},{"in":"query","name":"academic_year_id","schema":{"type":"string"}},{"in":"query","name":"staff_id","schema":{"type":"string"}},{"in":"query","name":"class_id","schema":{"type":"string"}},{"in":"query","name":"section_id","schema":{"type":"string"},"description":"When provided, returns assignments for this section plus any class-level (sectionless) assignments."},{"in":"query","name":"subject_id","schema":{"type":"string"}}],"responses":{"200":{"description":"Assignment list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}},"post":{"tags":["Teacher Assignments"],"summary":"Assign teacher to class + subject + section","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["academic_year_id","staff_id","class_id","subject_id"],"properties":{"academic_year_id":{"type":"string"},"staff_id":{"type":"string"},"class_id":{"type":"string"},"section_id":{"type":"string"},"subject_id":{"type":"string"},"periods_per_week":{"type":"integer"}}}}}},"responses":{"200":{"description":"Assignment created"}}}},"/v1/teacher-assignments/{id}":{"put":{"tags":["Teacher Assignments"],"summary":"Update a teacher assignment","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"staff_id":{"type":"string"},"section_id":{"type":"string","nullable":true},"periods_per_week":{"type":"integer","nullable":true}}}}}},"responses":{"200":{"description":"Assignment updated"}}},"delete":{"tags":["Teacher Assignments"],"summary":"Remove a teacher assignment (soft-delete)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Assignment deleted"},"404":{"description":"Not found"}}}},"/v1/staff/{id}/workload":{"get":{"tags":["Staff","Teacher Assignments"],"summary":"Get teacher workload summary (periods/week, classes, subjects)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Workload summary"}}}},"/v1/substitutions":{"get":{"tags":["Substitution"],"summary":"List substitutions (filterable by date)","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"date","schema":{"type":"string","format":"date"}},{"in":"query","name":"original_teacher_id","schema":{"type":"string"}},{"in":"query","name":"substitute_teacher_id","schema":{"type":"string"}}],"responses":{"200":{"description":"Substitution list"}}},"post":{"tags":["Substitution"],"summary":"Create a substitution (absent teacher -> substitute teacher x date)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["original_slot_id","date"],"properties":{"original_slot_id":{"type":"string"},"substitute_teacher_id":{"type":"string"},"date":{"type":"string","format":"date"},"reason":{"type":"string"}}}}}},"responses":{"200":{"description":"Substitution created"}}}},"/v1/substitutions/suggest/{date}":{"get":{"tags":["Substitution"],"summary":"Suggest free teachers for a given date","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"date","required":true,"schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Free teacher suggestions sorted by fewest periods"}}}},"/v1/students/summary":{"get":{"tags":["Students"],"summary":"Get student counts by status","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"branch_id","schema":{"type":"string"}}],"responses":{"200":{"description":"Student summary counts"}}}},"/v1/students":{"get":{"tags":["Students"],"summary":"List students (paginated, searchable, scope-filtered)","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer"}},{"in":"query","name":"page_size","schema":{"type":"integer"}},{"in":"query","name":"search","schema":{"type":"string"},"description":"Search by name, admission number, or phone"},{"in":"query","name":"class_id","schema":{"type":"string"}},{"in":"query","name":"section_id","schema":{"type":"string"}},{"in":"query","name":"status","schema":{"type":"string","enum":["active","transferred","alumni","suspended"]}},{"in":"query","name":"academic_year_id","schema":{"type":"string"}}],"responses":{"200":{"description":"Student list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}},"post":{"tags":["Students"],"summary":"Create a new student with family info","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["first_name","last_name","dob","gender","branch_id","academic_year_id","class_id","section_id","family"]}}}},"responses":{"200":{"description":"Created student","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/students/{id}":{"get":{"tags":["Students"],"summary":"Get student full profile (with family, academic, documents, custom fields)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Student detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found"}}},"put":{"tags":["Students"],"summary":"Update a student (field sensitivity enforced)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"first_name":{"type":"string"},"last_name":{"type":"string"},"reason":{"type":"string","description":"Required for edit_with_reason fields"}}}}}},"responses":{"200":{"description":"Updated student","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}},"delete":{"tags":["Students"],"summary":"Soft-delete a student","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Student deleted"},"404":{"description":"Not found"}}}},"/v1/students/{id}/toggle-status":{"put":{"tags":["Students"],"summary":"Activate or deactivate a student","description":"Sets isActive on the student. Deactivating also sets status to 'inactive'; activating sets status back to 'active'. Blocked for transferred/alumni students.\n","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["is_active"],"properties":{"is_active":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Student activated or deactivated"},"400":{"description":"Already in requested state or status does not allow toggle"},"404":{"description":"Student not found"}}}},"/v1/students/{id}/siblings":{"get":{"tags":["Students"],"summary":"List siblings of a student","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sibling list"}}}},"/v1/students/link-siblings":{"post":{"tags":["Students"],"summary":"Manually link students as siblings","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["student_ids"],"properties":{"student_ids":{"type":"array","items":{"type":"string"},"minItems":2}}}}}},"responses":{"200":{"description":"Siblings linked"}}}},"/v1/students/{id}/documents":{"post":{"tags":["Students"],"summary":"Upload a document for a student (multipart/form-data)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["document_type","file"],"properties":{"document_type":{"type":"string"},"file":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"Document uploaded"}}},"get":{"tags":["Students"],"summary":"List documents for a student","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Document list"}}}},"/v1/students/{id}/documents/{docId}/verify":{"put":{"tags":["Students"],"summary":"Verify or reject a student document","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"path","name":"docId","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["verified","rejected"]},"remarks":{"type":"string"}}}}}},"responses":{"200":{"description":"Document verification updated"},"404":{"description":"Document not found"}}}},"/v1/students/{id}/documents/{docId}":{"delete":{"tags":["Students"],"summary":"Soft-delete a student document","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"path","name":"docId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Document deleted"},"404":{"description":"Not found"}}}},"/v1/students/{id}/erasure-request":{"post":{"tags":["Students"],"summary":"Initiate DPDP erasure for a student","description":"Soft-deletes student and anonymizes all PII fields. Retains transactional records.","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Erasure initiated"},"404":{"description":"Student not found"}}}},"/v1/students/{id}/custom-fields":{"put":{"tags":["Students"],"summary":"Bulk upsert custom field values for a student","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"type":"object","required":["definition_id"],"properties":{"definition_id":{"type":"string"},"value_text":{"type":"string","nullable":true},"value_number":{"type":"number","nullable":true},"value_date":{"type":"string","nullable":true},"value_json":{}}}}}}}}},"responses":{"200":{"description":"Custom fields updated"}}}},"/v1/staff/{id}/exit":{"post":{"tags":["Staff"],"summary":"Initiate staff exit process","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["notice_date","last_working_date","exit_reason"],"properties":{"notice_date":{"type":"string","format":"date"},"last_working_date":{"type":"string","format":"date"},"exit_reason":{"type":"string"}}}}}},"responses":{"200":{"description":"Exit initiated"}}},"get":{"tags":["Staff"],"summary":"Get exit status with final settlement preview","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Exit status and settlement preview"},"404":{"description":"Exit not initiated"}}}},"/v1/staff/{id}/exit/complete":{"put":{"tags":["Staff"],"summary":"Complete exit process (deactivate login, generate certificates)","description":"Calculates final settlement, deactivates user login, soft-deletes teacher assignments, and optionally attaches experience certificate and relieving letter URLs.","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"experience_cert_url":{"type":"string","format":"uri"},"relieving_letter_url":{"type":"string","format":"uri"}}}}}},"responses":{"200":{"description":"Exit completed"}}}},"/v1/staff":{"get":{"tags":["Staff"],"summary":"List staff (paginated, searchable, scope-filtered)","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer"}},{"in":"query","name":"page_size","schema":{"type":"integer"}},{"in":"query","name":"search","schema":{"type":"string"},"description":"Search by name, employee ID, phone, or email"},{"in":"query","name":"status","schema":{"type":"string","enum":["active","on_leave","suspended","exited"]}},{"in":"query","name":"employment_type","schema":{"type":"string","enum":["permanent","contract","visiting","substitute"]}},{"in":"query","name":"department","schema":{"type":"string"}}],"responses":{"200":{"description":"Staff list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}},"post":{"tags":["Staff"],"summary":"Create a new staff member with optional bank details","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["first_name","last_name","dob","gender","phone","designation","employment_type","joining_date","branch_id"]}}}},"responses":{"200":{"description":"Created staff","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/staff/summary":{"get":{"tags":["Staff"],"summary":"Staff KPI summary — total/active/inactive/on-leave + teacher vs non-teaching counts (scope-filtered)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Staff summary counts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/staff/{id}":{"get":{"tags":["Staff"],"summary":"Get staff full profile (with bank details, qualifications, documents)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Staff detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found"}}},"put":{"tags":["Staff"],"summary":"Update a staff member","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Updated staff","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}},"delete":{"tags":["Staff"],"summary":"Soft-delete a staff member","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Staff deleted"},"404":{"description":"Not found"}}}},"/v1/staff/{id}/documents":{"post":{"tags":["Staff"],"summary":"Upload a document for a staff member","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["document_type","file_url"],"properties":{"document_type":{"type":"string","enum":["aadhaar","pan","degree","experience","police_verification","photo","other"]},"file_url":{"type":"string","format":"uri"},"expiry_date":{"type":"string","format":"date"}}}}}},"responses":{"200":{"description":"Document uploaded"}}},"get":{"tags":["Staff"],"summary":"List documents for a staff member","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Document list"}}}},"/v1/staff/{id}/documents/{docId}/verify":{"put":{"tags":["Staff"],"summary":"Verify a staff document","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"path","name":"docId","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["verified","rejected"]}}}}}},"responses":{"200":{"description":"Document verified"}}}},"/v1/staff/{id}/documents/{docId}":{"delete":{"tags":["Staff"],"summary":"Soft-delete a staff document","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"path","name":"docId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Document deleted"}}}},"/v1/staff/{id}/onboard":{"post":{"tags":["Staff"],"summary":"Trigger onboarding checklist for a staff member","description":"Auto-generates employee ID step, login credentials placeholder, welcome SMS placeholder, and initializes payroll record.","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Onboarding checklist created"}}}},"/v1/staff/{id}/onboarding":{"get":{"tags":["Staff"],"summary":"Get onboarding checklist status for a staff member","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Onboarding checklist"}}}},"/v1/staff/{id}/employment-type":{"put":{"tags":["Staff"],"summary":"Change staff employment type (logged)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["employment_type"],"properties":{"employment_type":{"type":"string","enum":["permanent","contract","visiting","substitute"]}}}}}},"responses":{"200":{"description":"Employment type updated"}}}},"/v1/staff/{id}/toggle-status":{"put":{"tags":["Staff"],"summary":"Toggle staff active / inactive status","description":"Flips a staff member between `active` and `inactive`. Returns 400 if the staff member has already exited.","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Staff ID"}],"responses":{"200":{"description":"Status toggled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"400":{"description":"Staff has exited and cannot be toggled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"Staff not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/staff/{id}/account":{"post":{"tags":["Staff"],"summary":"Provision a login account for a staff member","description":"Creates a User account linked to the staff record, assigns the given role, generates a temporary password, and sends credentials via email. Returns 409 if the staff member already has an account.","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Staff ID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["role_id"],"properties":{"role_id":{"type":"string","description":"ID of the existing role to assign","example":"3"}}}}}},"responses":{"201":{"description":"Account provisioned successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"400":{"description":"Staff has no email address on record","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"Staff or role not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"409":{"description":"Staff already has a login account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/search":{"get":{"tags":["Search"],"summary":"Global search across students, parents, staff, enquiries and invoices","description":"Powers the admin top-bar global search. Runs 5 parallel queries\n(one per entity type) and returns up to 5 hits per group.\n\nScope rules:\n- Query is case-insensitive substring (`ILIKE`).\n- Results are scoped to the caller's branch when the JWT carries a\n  `branch_id`. School/platform admins (no branch on token) search\n  across all branches.\n- Each result group is gated by the corresponding view permission:\n  students/parents → `m3.student.view`, staff → `m5.staff.view`,\n  enquiries → `m4.enquiry.view`, invoices → `m9.fee_slip.view`.\n  Groups for which the caller lacks permission are returned as `[]`.\n- Queries shorter than 2 characters (after trim) return all groups\n  empty (HTTP 200).\n\nNote: `Enquiry.parent_phone` and `Staff.phone` are encrypted at rest\nand are not searchable from this endpoint.\n","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"q","required":true,"schema":{"type":"string","minLength":1,"maxLength":100},"description":"Search term. Min 2 effective characters after trim; shorter inputs return empty groups."}],"responses":{"200":{"description":"Search results grouped by entity type.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiSuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"students":{"type":"array","items":{"$ref":"#/components/schemas/SearchHit"}},"parents":{"type":"array","items":{"$ref":"#/components/schemas/SearchHit"}},"staff":{"type":"array","items":{"$ref":"#/components/schemas/SearchHit"}},"enquiries":{"type":"array","items":{"$ref":"#/components/schemas/SearchHit"}},"invoices":{"type":"array","items":{"$ref":"#/components/schemas/SearchHit"}}}}}}]}}}},"401":{"description":"Unauthenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/school-configs":{"get":{"tags":["SchoolConfig"],"summary":"Get school configuration values for a given group","description":"Returns the key/value map stored under the requested `group` in the\nschool_configs table. Used by settings UIs (e.g. timetable\nconfiguration) to pre-fill defaults captured during onboarding.\n","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"group","required":true,"schema":{"type":"string","example":"schedule"},"description":"configGroup to filter by. Known groups: `schedule`, `fees`.\n"}],"responses":{"200":{"description":"Map of configKey to configValue (JSON values returned verbatim)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"422":{"description":"Missing or invalid `group` query parameter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/role-templates":{"get":{"tags":["Role Templates"],"summary":"List all role templates (paginated, filterable)","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","minimum":1}},{"in":"query","name":"page_size","schema":{"type":"integer","minimum":1,"maximum":200}},{"in":"query","name":"scope_level","schema":{"type":"string"},"description":"Filter by scope_level (tenant, branch, class, section, own)"},{"in":"query","name":"is_platform_role","schema":{"type":"boolean"}},{"in":"query","name":"search","schema":{"type":"string"}}],"responses":{"200":{"description":"List of role templates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}},"401":{"description":"Unauthenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/role-templates/{id}":{"get":{"tags":["Role Templates"],"summary":"Get a single role template with permissions","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Role template with permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/roles/clone":{"post":{"tags":["Roles"],"summary":"Clone a role template into a custom role","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["template_id","name"],"properties":{"template_id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"}}}}}},"responses":{"201":{"description":"Cloned role"},"404":{"description":"Template not found"}}}},"/v1/roles":{"get":{"tags":["Roles"],"summary":"List roles (filterable by is_custom, scope_level)","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","minimum":1}},{"in":"query","name":"page_size","schema":{"type":"integer","minimum":1,"maximum":200}},{"in":"query","name":"is_custom","schema":{"type":"boolean"}},{"in":"query","name":"scope_level","schema":{"type":"string"}},{"in":"query","name":"search","schema":{"type":"string"}}],"responses":{"200":{"description":"List of roles","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}}},"/v1/roles/{id}":{"get":{"tags":["Roles"],"summary":"Get a single role with permissions","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Role with permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"put":{"tags":["Roles"],"summary":"Update a custom role's name/description","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"}}}}}},"responses":{"200":{"description":"Updated role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"403":{"description":"Not a custom role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"delete":{"tags":["Roles"],"summary":"Soft-delete a custom role (only is_custom=true)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"403":{"description":"Not a custom role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/roles/{id}/permissions":{"post":{"tags":["Roles"],"summary":"Add permissions to a custom role","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["permission_ids"],"properties":{"permission_ids":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Role with updated permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"403":{"description":"Not a custom role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"delete":{"tags":["Roles"],"summary":"Remove permissions from a custom role","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["permission_ids"],"properties":{"permission_ids":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Role with updated permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"403":{"description":"Not a custom role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/user-roles":{"post":{"tags":["User Roles"],"summary":"Assign a role to a user","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["user_id","role_id"],"properties":{"user_id":{"type":"string"},"role_id":{"type":"string"},"branch_id":{"type":"string"}}}}}},"responses":{"201":{"description":"Role assigned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"User or role not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"delete":{"tags":["User Roles"],"summary":"Revoke a role from a user","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["user_id","role_id"],"properties":{"user_id":{"type":"string"},"role_id":{"type":"string"}}}}}},"responses":{"200":{"description":"Role revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"User-role assignment not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/users/{id}/effective-permissions":{"get":{"tags":["User Roles"],"summary":"Get the union of all role permissions for a user (cached 30min)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Effective permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/roles/{id}/reset":{"post":{"tags":["Roles"],"summary":"Reset a role's permissions back to the original template defaults","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Role with restored default permissions"},"404":{"description":"Role or template not found"},"422":{"description":"Role has no source template"}}}},"/v1/promotions":{"get":{"tags":["Promotions"],"summary":"List promotion batches","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Promotion batch list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}},"post":{"tags":["Promotions"],"summary":"Create a promotion batch","description":"Collects all students in from_class for the academic year, creates draft promotion records","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["academic_year_id","from_class_id","to_class_id"],"properties":{"academic_year_id":{"type":"string"},"from_class_id":{"type":"string"},"to_class_id":{"type":"string"}}}}}},"responses":{"200":{"description":"Batch created"}}}},"/v1/promotions/{id}":{"get":{"tags":["Promotions"],"summary":"Get promotion batch detail with all records","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Promotion batch detail"},"404":{"description":"Not found"}}},"put":{"tags":["Promotions"],"summary":"Mark exceptions (detained, leaving, transferred) on a promotion batch","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["exceptions"],"properties":{"exceptions":{"type":"array","items":{"type":"object","required":["student_id","result"],"properties":{"student_id":{"type":"string"},"result":{"type":"string","enum":["promoted","detained","transferred","leaving"]},"to_section_id":{"type":"string"},"notes":{"type":"string"}}}}}}}}},"responses":{"200":{"description":"Exceptions updated"},"400":{"description":"Batch not in draft status"},"404":{"description":"Batch or record not found"}}}},"/v1/promotions/{id}/execute":{"post":{"tags":["Promotions"],"summary":"Execute a promotion batch","description":"Creates new StudentAcademic records for promoted students, handles detained/transferred/leaving","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Promotion executed"},"400":{"description":"Batch not in draft status or next academic year not found"},"404":{"description":"Batch not found"}}}},"/api/platform/v1/schools/by-subdomain/{slug}":{"get":{"tags":["Platform - Schools"],"summary":"Public — fetch a school's name, status, and branding by URL subdomain.","description":"No authentication required. Used by the tenant frontend at page-load to\nconfirm the subdomain belongs to a real school, get the display name to\nrender on the login page, and detect suspended/churned schools.\n","parameters":[{"in":"path","name":"slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"School branding","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"400":{"description":"Invalid subdomain","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"School suspended or churned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"School not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/pincode-masters":{"get":{"tags":["Pincode Masters"],"summary":"List pincodes (paginated, filterable)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}},"post":{"tags":["Pincode Masters"],"summary":"Create a new pincode record","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created"}}}},"/v1/pincode-masters/lookup/{pincode}":{"get":{"tags":["Pincode Masters"],"summary":"Lookup a pincode (auto-fill city/state on form)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"pincode","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Pincode info or null","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/pincode-masters/{id}":{"get":{"tags":["Pincode Masters"],"summary":"Get a pincode record by ID","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Pincode","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}},"put":{"tags":["Pincode Masters"],"summary":"Update a pincode record (pincode value itself cannot change)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Updated"}}},"delete":{"tags":["Pincode Masters"],"summary":"Soft-delete a pincode record","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"}}}},"/v1/permissions":{"get":{"tags":["Permissions"],"summary":"List permissions (paginated + filterable)","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","minimum":1},"description":"1-based page index. Omit to return all records."},{"in":"query","name":"page_size","schema":{"type":"integer","minimum":1,"maximum":200},"description":"Page size. Defaults to 20 when pagination is requested."},{"in":"query","name":"module","schema":{"type":"string"},"description":"Filter by module name (exact match)."},{"in":"query","name":"resource","schema":{"type":"string"},"description":"Filter by resource name (exact match)."},{"in":"query","name":"action","schema":{"type":"string"},"description":"Filter by action type (exact match)."},{"in":"query","name":"is_deprecated","schema":{"type":"boolean"},"description":"Filter by deprecated status."},{"in":"query","name":"search","schema":{"type":"string"},"description":"Case-insensitive search across key, module, resource, action, description."}],"responses":{"200":{"description":"List of permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}},"401":{"description":"Unauthenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/permissions/{id}":{"get":{"tags":["Permissions"],"summary":"Get a single permission by ID","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/permissions/grouped":{"get":{"tags":["Permissions"],"summary":"Get all permissions grouped by module (for role builder UI)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Permissions grouped by module","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"401":{"description":"Unauthenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/module-activations":{"get":{"tags":["Module Activations"],"summary":"List all modules with their activation status","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of module activations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"401":{"description":"Unauthenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/module-activations/{moduleKey}":{"put":{"tags":["Module Activations"],"summary":"Toggle a module on or off","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"moduleKey","required":true,"schema":{"type":"string"},"description":"The module key (e.g. \"attendance\", \"transport\")"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["is_enabled"],"properties":{"is_enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated module activation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Module key not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/lookup-masters":{"get":{"tags":["Lookup Masters"],"summary":"List lookup master entries (paginated + filtered)","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"type","schema":{"type":"string"},"description":"Filter by lookup type (caste, religion, blood_group, etc.)"},{"in":"query","name":"search","schema":{"type":"string"}},{"in":"query","name":"is_active","schema":{"type":"boolean"}},{"in":"query","name":"parent_id","schema":{"type":"string"}},{"in":"query","name":"page","schema":{"type":"integer","minimum":1}},{"in":"query","name":"page_size","schema":{"type":"integer","minimum":1,"maximum":500}}],"responses":{"200":{"description":"List of lookups","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}},"401":{"description":"Unauthenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"post":{"tags":["Lookup Masters"],"summary":"Create a new lookup entry","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","code","name"],"properties":{"type":{"type":"string","example":"caste"},"code":{"type":"string","example":"GEN"},"name":{"type":"string","example":"General"},"parent_id":{"type":"string"},"display_order":{"type":"integer"},"is_active":{"type":"boolean"},"extra_data":{"type":"object"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/lookup-masters/types":{"get":{"tags":["Lookup Masters"],"summary":"List distinct lookup types in use","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Lookup type list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/lookup-masters/{id}":{"get":{"tags":["Lookup Masters"],"summary":"Get a single lookup entry by ID","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Lookup entry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"put":{"tags":["Lookup Masters"],"summary":"Update a lookup entry (cannot change type/code/system flag)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"parent_id":{"type":"string","nullable":true},"display_order":{"type":"integer"},"is_active":{"type":"boolean"},"extra_data":{"type":"object"}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"delete":{"tags":["Lookup Masters"],"summary":"Soft-delete a lookup entry (blocks system rows)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"422":{"description":"System row protected","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/institution-masters":{"get":{"tags":["Institution Masters"],"summary":"List institutions (paginated, filterable by state_id, type)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}},"post":{"tags":["Institution Masters"],"summary":"Create a new institution","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created"}}}},"/v1/institution-masters/{id}":{"get":{"tags":["Institution Masters"],"summary":"Get an institution by ID","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Institution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}},"put":{"tags":["Institution Masters"],"summary":"Update an institution","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Updated"}}},"delete":{"tags":["Institution Masters"],"summary":"Soft-delete an institution","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"}}}},"/v1/imports/upload":{"post":{"tags":["Imports"],"summary":"Upload an Excel file and create an import job","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["entity_type","file_url"],"properties":{"entity_type":{"type":"string"},"file_url":{"type":"string","format":"uri"}}}}}},"responses":{"201":{"description":"Import job created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/imports/{id}/map-columns":{"post":{"tags":["Imports"],"summary":"Save column mapping for an import job","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["mapping"],"properties":{"mapping":{"type":"object","additionalProperties":{"type":"string"}}}}}}},"responses":{"200":{"description":"Mapping saved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Import job not found"}}}},"/v1/imports/{id}/validate":{"post":{"tags":["Imports"],"summary":"Run validation on an import job","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Validation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Import job not found"}}}},"/v1/imports/{id}/execute":{"post":{"tags":["Imports"],"summary":"Execute the import (create records)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Import executed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Import job not found"}}}},"/v1/imports":{"get":{"tags":["Imports"],"summary":"List import jobs","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"entity_type","schema":{"type":"string"}},{"in":"query","name":"status","schema":{"type":"string","enum":["uploaded","mapping","validating","validated","importing","completed","failed"]}},{"in":"query","name":"page","schema":{"type":"integer"}},{"in":"query","name":"page_size","schema":{"type":"integer"}}],"responses":{"200":{"description":"List of import jobs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}}},"/v1/imports/{id}":{"get":{"tags":["Imports"],"summary":"Get a single import job with status and error details","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Import job detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found"}}}},"/v1/homework":{"get":{"tags":["Homework"],"summary":"List homework","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"class_id","schema":{"type":"string"}},{"in":"query","name":"section_id","schema":{"type":"string"}},{"in":"query","name":"subject_id","schema":{"type":"string"}},{"in":"query","name":"status","schema":{"type":"string","enum":["active","cancelled"]}}],"responses":{"200":{"description":"Homework list"}}},"post":{"tags":["Homework"],"summary":"Create homework","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["class_id","section_id","subject_id","title","description","due_date","academic_year_id"]}}}},"responses":{"200":{"description":"Created homework"}}}},"/v1/homework/{id}":{"get":{"tags":["Homework"],"summary":"Get homework by ID","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Homework detail"}}},"put":{"tags":["Homework"],"summary":"Update homework","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Updated homework"}}}},"/v1/homework/{id}/upload-attachment":{"post":{"tags":["Homework"],"summary":"Upload a file attachment for a homework record","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"Returns updated homework with attachment_url"}}}},"/v1/syllabus-progress":{"get":{"tags":["Homework"],"summary":"List syllabus progress","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"academic_year_id","schema":{"type":"string"}},{"in":"query","name":"class_id","schema":{"type":"string"}}],"responses":{"200":{"description":"Syllabus progress list"}}}},"/v1/syllabus-progress/alerts":{"get":{"tags":["Homework"],"summary":"Get syllabus progress alerts (< 70% completion at 80% of term)","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"academic_year_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Syllabus alerts"}}}},"/v1/academic-calendars":{"get":{"tags":["Events & Calendar"],"summary":"List academic calendars","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Calendar list"}}}},"/v1/holidays":{"get":{"tags":["Events & Calendar"],"summary":"List holidays","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"calendar_id","schema":{"type":"string"}},{"in":"query","name":"holiday_type","schema":{"type":"string","enum":["public","school","optional"]}}],"responses":{"200":{"description":"Holiday list"}}}},"/v1/events":{"get":{"tags":["Events & Calendar"],"summary":"List events","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"status","schema":{"type":"string","enum":["draft","approved","cancelled"]}},{"in":"query","name":"branch_id","schema":{"type":"string"}}],"responses":{"200":{"description":"Event list"}}}},"/v1/ptm-sessions":{"get":{"tags":["Events & Calendar"],"summary":"List PTM sessions","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"PTM session list"}}}},"/v1/document-type-masters":{"get":{"tags":["Document Type Masters"],"summary":"List document types","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"applies_to","schema":{"type":"string","enum":["student","staff","both"]}},{"in":"query","name":"is_required","schema":{"type":"boolean"}},{"in":"query","name":"search","schema":{"type":"string"}}],"responses":{"200":{"description":"List","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}},"post":{"tags":["Document Type Masters"],"summary":"Create a new document type","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","name","applies_to","allowed_mime_types"],"properties":{"code":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"applies_to":{"type":"string","enum":["student","staff","both"]},"is_required":{"type":"boolean"},"max_size_mb":{"type":"integer"},"allowed_mime_types":{"type":"array","items":{"type":"string"}},"expiry_required":{"type":"boolean"},"display_order":{"type":"integer"},"is_active":{"type":"boolean"}}}}}},"responses":{"201":{"description":"Created"}}}},"/v1/document-type-masters/{id}":{"get":{"tags":["Document Type Masters"],"summary":"Get a document type by ID","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Document type","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}},"put":{"tags":["Document Type Masters"],"summary":"Update a document type","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Updated"}}},"delete":{"tags":["Document Type Masters"],"summary":"Soft-delete a document type","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"},"422":{"description":"In use / system row"}}}},"/v1/designation-masters":{"get":{"tags":["Designation Masters"],"summary":"List designations (paginated, filterable by department_id + is_teaching)","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"department_id","schema":{"type":"string"}},{"in":"query","name":"is_teaching","schema":{"type":"boolean"}},{"in":"query","name":"search","schema":{"type":"string"}},{"in":"query","name":"is_active","schema":{"type":"boolean"}},{"in":"query","name":"page","schema":{"type":"integer","minimum":1}},{"in":"query","name":"page_size","schema":{"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"List of designations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}},"post":{"tags":["Designation Masters"],"summary":"Create a new designation","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","name"],"properties":{"code":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"department_id":{"type":"string"},"is_teaching":{"type":"boolean"},"salary_grade":{"type":"string"},"display_order":{"type":"integer"},"is_active":{"type":"boolean"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/designation-masters/{id}":{"get":{"tags":["Designation Masters"],"summary":"Get a designation by ID","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Designation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}},"put":{"tags":["Designation Masters"],"summary":"Update a designation","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}},"delete":{"tags":["Designation Masters"],"summary":"Soft-delete a designation","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"},"422":{"description":"In use / system row"}}}},"/v1/department-masters":{"get":{"tags":["Department Masters"],"summary":"List departments (paginated + searchable)","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","minimum":1}},{"in":"query","name":"page_size","schema":{"type":"integer","minimum":1,"maximum":200}},{"in":"query","name":"search","schema":{"type":"string"}},{"in":"query","name":"is_active","schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of departments","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}},"post":{"tags":["Department Masters"],"summary":"Create a new department","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","name"],"properties":{"code":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"cost_center":{"type":"string"},"head_staff_id":{"type":"string"},"display_order":{"type":"integer"},"is_active":{"type":"boolean"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/department-masters/{id}":{"get":{"tags":["Department Masters"],"summary":"Get a department by ID","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Department","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"put":{"tags":["Department Masters"],"summary":"Update a department","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string","nullable":true},"cost_center":{"type":"string","nullable":true},"head_staff_id":{"type":"string","nullable":true},"display_order":{"type":"integer"},"is_active":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}},"delete":{"tags":["Department Masters"],"summary":"Soft-delete a department (blocks if referenced)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"},"422":{"description":"In use / system row"}}}},"/v1/custom-fields":{"get":{"tags":["Custom Fields"],"summary":"List custom field definitions","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"entity_type","schema":{"type":"string","enum":["student","staff","admission","fee","transport"]},"required":false}],"responses":{"200":{"description":"List of definitions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"401":{"description":"Unauthenticated"},"403":{"description":"Missing permission"}}},"post":{"tags":["Custom Fields"],"summary":"Create a custom field definition","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["entity_type","field_name","field_type","is_required","display_order"],"properties":{"entity_type":{"type":"string","enum":["student","staff","admission","fee","transport"]},"field_name":{"type":"string"},"field_type":{"type":"string","enum":["text","number","date","dropdown","file"]},"dropdown_options":{"type":"object"},"is_required":{"type":"boolean"},"display_order":{"type":"integer"}}}}}},"responses":{"201":{"description":"Created definition","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/custom-fields/{id}":{"put":{"tags":["Custom Fields"],"summary":"Update a custom field definition","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"field_name":{"type":"string"},"field_type":{"type":"string","enum":["text","number","date","dropdown","file"]},"dropdown_options":{"type":"object"},"is_required":{"type":"boolean"},"display_order":{"type":"integer"},"is_active":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated definition","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found"}}},"delete":{"tags":["Custom Fields"],"summary":"Soft-delete a custom field definition","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found"}}}},"/v1/custom-fields/reorder":{"put":{"tags":["Custom Fields"],"summary":"Reorder custom field definitions (bulk display_order update)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["fields"],"properties":{"fields":{"type":"array","items":{"type":"object","required":["id","display_order"],"properties":{"id":{"type":"string"},"display_order":{"type":"integer"}}}}}}}}},"responses":{"200":{"description":"Reordered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/custom-fields/{entityType}/{entityId}/values":{"get":{"tags":["Custom Fields"],"summary":"Get custom field values for an entity","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"entityType","required":true,"schema":{"type":"string","enum":["student","staff","admission","fee","transport"]}},{"in":"path","name":"entityId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Field values","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}},"put":{"tags":["Custom Fields"],"summary":"Bulk upsert custom field values for an entity","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"entityType","required":true,"schema":{"type":"string","enum":["student","staff","admission","fee","transport"]}},{"in":"path","name":"entityId","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["values"],"properties":{"values":{"type":"array","items":{"type":"object","required":["definition_id"],"properties":{"definition_id":{"type":"string"},"value_text":{"type":"string","nullable":true},"value_number":{"type":"number","nullable":true},"value_date":{"type":"string","nullable":true},"value_json":{"type":"object"}}}}}}}}},"responses":{"200":{"description":"Upserted values","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/certificate-templates":{"get":{"tags":["Certificate Templates"],"summary":"List certificate templates","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"template_type","schema":{"type":"string","enum":["tc","bonafide","character","study","custom"]},"required":false}],"responses":{"200":{"description":"List of templates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}},"post":{"tags":["Certificate Templates"],"summary":"Create a certificate template","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["template_type","name","placeholders"],"properties":{"template_type":{"type":"string","enum":["tc","bonafide","character","study","custom"]},"name":{"type":"string"},"file_url":{"type":"string","format":"uri","nullable":true},"placeholders":{"type":"object"},"is_default":{"type":"boolean"}}}}}},"responses":{"201":{"description":"Created template","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/certificate-templates/{id}":{"get":{"tags":["Certificate Templates"],"summary":"Get a single certificate template","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Template detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found"}}},"put":{"tags":["Certificate Templates"],"summary":"Update a certificate template","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"file_url":{"type":"string","format":"uri","nullable":true},"placeholders":{"type":"object"},"is_default":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated template","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found"}}},"delete":{"tags":["Certificate Templates"],"summary":"Soft-delete a certificate template","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found"}}}},"/v1/certificate-templates/placeholders":{"get":{"tags":["Certificate Templates"],"summary":"List available placeholders by template type","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"template_type","schema":{"type":"string","enum":["tc","bonafide","character","study","custom"]},"required":false}],"responses":{"200":{"description":"Placeholder map","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/certificate-configs":{"get":{"tags":["Certificate Configs"],"summary":"List all certificate configs for the authenticated user's branch","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of certificate configs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"401":{"description":"Unauthorized"}}}},"/v1/certificate-configs/{type}":{"get":{"tags":["Certificate Configs"],"summary":"Get the certificate config for a specific cert type","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"type","required":true,"schema":{"type":"string","enum":["tc","bonafide","character","study"]}}],"responses":{"200":{"description":"Certificate config detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"400":{"description":"Invalid cert type"},"401":{"description":"Unauthorized"},"404":{"description":"Config not found"}}},"put":{"tags":["Certificate Configs"],"summary":"Save builder HTML content for a cert type","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"type","required":true,"schema":{"type":"string","enum":["tc","bonafide","character","study"]}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["html_content"],"properties":{"html_content":{"type":"string"},"is_enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated certificate config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"404":{"description":"Config not found"}}}},"/v1/certificate-configs/{type}/upload":{"post":{"tags":["Certificate Configs"],"summary":"Upload a .docx file for a cert type","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"type","required":true,"schema":{"type":"string","enum":["tc","bonafide","character","study"]}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"Updated certificate config with uploaded file URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"400":{"description":"Invalid file or missing placeholder"},"401":{"description":"Unauthorized"},"404":{"description":"Config not found"}}}},"/v1/certificate-configs/{type}/file":{"delete":{"tags":["Certificate Configs"],"summary":"Remove the uploaded .docx file for a cert type (reverts to builder mode)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"type","required":true,"schema":{"type":"string","enum":["tc","bonafide","character","study"]}}],"responses":{"200":{"description":"File removed, config reverted to builder mode","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"400":{"description":"Invalid cert type"},"401":{"description":"Unauthorized"},"404":{"description":"Config not found"}}}},"/v1/students/{id}/certificates/tc":{"post":{"tags":["Certificates"],"summary":"Generate a Transfer Certificate for a student","description":"Checks fee clearance, generates TC, and sets student status to transferred","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reason","board_format"],"properties":{"reason":{"type":"string"},"board_format":{"type":"string"},"tc_data":{"type":"object"}}}}}},"responses":{"200":{"description":"TC generated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"400":{"description":"Fee clearance required"},"404":{"description":"Student not found"}}}},"/v1/students/{id}/certificates/{type}":{"post":{"tags":["Certificates"],"summary":"Generate a certificate (bonafide, character, study, custom)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"path","name":"type","required":true,"schema":{"type":"string","enum":["bonafide","character","study","custom"]}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["template_id"],"properties":{"template_id":{"type":"string"}}}}}},"responses":{"200":{"description":"Certificate generated"},"404":{"description":"Student or template not found"}}}},"/v1/students/{id}/certificates":{"get":{"tags":["Certificates"],"summary":"List all certificates (TCs and other) for a student","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Certificate list"},"404":{"description":"Student not found"}}}},"/v1/students/{id}/certificates/{certId}/download":{"get":{"tags":["Certificates"],"summary":"Get PDF download URL for a certificate","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"path","name":"certId","required":true,"schema":{"type":"string"}},{"in":"query","name":"tc","schema":{"type":"string","enum":["true","false"]},"description":"Pass tc=true for transfer certificates"}],"responses":{"200":{"description":"PDF URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"400":{"description":"PDF not ready yet"},"404":{"description":"Certificate not found"}}}},"/v1/branding":{"get":{"tags":["Branding"],"summary":"Get current branding settings","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"branch_id","schema":{"type":"string"},"description":"Optional branch ID for branch-specific branding. Omit for school-wide."}],"responses":{"200":{"description":"Branding settings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"put":{"tags":["Branding"],"summary":"Update branding settings","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"branch_id","schema":{"type":"string"},"description":"Optional branch ID. Omit for school-wide."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"school_name":{"type":"string"},"primary_color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"secondary_color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"portal_title":{"type":"string"},"app_title":{"type":"string"}}}}}},"responses":{"200":{"description":"Updated branding","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/branding/logo":{"post":{"tags":["Branding"],"summary":"Upload school logo","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"branch_id","schema":{"type":"string"},"description":"Optional branch ID. Omit for school-wide."}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"logo":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"Updated branding with logo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/branch-transfers":{"post":{"tags":["Branch Transfers"],"summary":"Initiate a cross-branch transfer","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["entity_type","entity_id","to_branch_id"],"properties":{"entity_type":{"type":"string","enum":["student","staff"]},"entity_id":{"type":"string"},"to_branch_id":{"type":"string"},"reason":{"type":"string"}}}}}},"responses":{"200":{"description":"Transfer initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Entity or branch not found"},"409":{"description":"Transfer already pending"}}},"get":{"tags":["Branch Transfers"],"summary":"List transfers (filterable by status, entity_type)","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"status","schema":{"type":"string","enum":["requested","approved_source","approved_target","completed","rejected"]}},{"in":"query","name":"entity_type","schema":{"type":"string","enum":["student","staff"]}}],"responses":{"200":{"description":"List of transfers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/branch-transfers/{id}/approve":{"put":{"tags":["Branch Transfers"],"summary":"Approve a transfer (advances state machine)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Transfer approved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"400":{"description":"Invalid state transition"},"404":{"description":"Not found"}}}},"/v1/branch-transfers/{id}/reject":{"put":{"tags":["Branch Transfers"],"summary":"Reject a transfer","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Transfer rejected","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"400":{"description":"Already completed or rejected"},"404":{"description":"Not found"}}}},"/v1/branch-policies":{"get":{"tags":["Branch Policies"],"summary":"List all branch policies","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"branch_id","schema":{"type":"string"}},{"in":"query","name":"policy_type","schema":{"type":"string"}}],"responses":{"200":{"description":"List of branch policies","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}},"post":{"tags":["Branch Policies"],"summary":"Create a branch policy (Owner pushes to all branches when set_by_owner=true)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["branch_id","policy_type","policy_data"],"properties":{"branch_id":{"type":"string"},"policy_type":{"type":"string"},"policy_data":{"type":"object"},"set_by_owner":{"type":"boolean"},"override_allowed":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Created policy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/branch-policies/{id}":{"put":{"tags":["Branch Policies"],"summary":"Update a branch policy","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"policy_data":{"type":"object"},"override_allowed":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated policy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found"}}}},"/v1/branch-policies/{id}/override":{"post":{"tags":["Branch Policies"],"summary":"Request an override for a branch policy","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["branch_id","override_data"],"properties":{"branch_id":{"type":"string"},"override_data":{"type":"object"}}}}}},"responses":{"200":{"description":"Override requested","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"400":{"description":"Override not allowed"},"404":{"description":"Policy not found"}}}},"/v1/branch-overrides/{id}/approve":{"put":{"tags":["Branch Policies"],"summary":"Approve or reject a branch override","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["approved","rejected"]}}}}}},"responses":{"200":{"description":"Override updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"400":{"description":"Already processed"},"404":{"description":"Not found"}}}},"/v1/branches":{"get":{"tags":["Branches"],"summary":"List all branches","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"401":{"description":"Unauthenticated"},"403":{"description":"Missing permission"}}},"post":{"tags":["Branches"],"summary":"Create a new branch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","code"],"properties":{"name":{"type":"string"},"code":{"type":"string"},"address":{"type":"string"},"phone":{"type":"string"},"is_main":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Created branch","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"409":{"description":"Branch code already exists"}}}},"/v1/branches/{id}":{"get":{"tags":["Branches"],"summary":"Get a single branch","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Branch detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found"}}},"put":{"tags":["Branches"],"summary":"Update a branch","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"phone":{"type":"string"},"is_active":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated branch","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found"}}},"delete":{"tags":["Branches"],"summary":"Soft-delete a branch","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Branch deleted"},"400":{"description":"Cannot delete main branch"},"404":{"description":"Not found"}}}},"/v1/branches/dashboard":{"get":{"tags":["Branches"],"summary":"Aggregated metrics across all branches","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Dashboard metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/branches/{id}/dashboard":{"get":{"tags":["Branches"],"summary":"Per-branch metrics drill-down","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Branch dashboard","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Branch not found"}}}},"/v1/branches/compare":{"get":{"tags":["Branches"],"summary":"Side-by-side comparison of selected branches","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"branch_ids","required":true,"schema":{"type":"array","items":{"type":"string"}},"style":"form","explode":true}],"responses":{"200":{"description":"Comparison result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/board-configs":{"get":{"tags":["Board Configs"],"summary":"List all board configurations","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of board configs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"401":{"description":"Unauthenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/board-configs/{id}":{"get":{"tags":["Board Configs"],"summary":"Get a single board configuration","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Board config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"put":{"tags":["Board Configs"],"summary":"Update a board configuration","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"board_name":{"type":"string"},"subjects_template":{"type":"object"},"report_card_format":{"type":"object"},"tc_format":{"type":"object"}}}}}},"responses":{"200":{"description":"Updated board config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/board-configs/{id}/activate":{"post":{"tags":["Board Configs"],"summary":"Activate a board configuration (multi-board supported)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Activated board config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/board-configs/{id}/deactivate":{"post":{"tags":["Board Configs"],"summary":"Deactivate a board configuration","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deactivated board config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/board-configs/provision":{"post":{"tags":["Board Configs"],"summary":"Provision board configs during tenant setup (auto-load)","description":"Called during tenant provisioning (M0) to activate board configurations based on the selected board(s). Accepts an array of board codes.\n","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["board_codes"],"properties":{"board_codes":{"type":"array","items":{"type":"string"},"example":["CBSE","ICSE"]}}}}}},"responses":{"200":{"description":"Provisioned board configs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Board code not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/board-configs/{id}/sections":{"post":{"tags":["Board Configs"],"summary":"Assign a board config to a section","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["section_id"],"properties":{"section_id":{"type":"string"}}}}}},"responses":{"200":{"description":"Section-board assignment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Board config or section not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/board-configs/{id}/sections/{sectionId}":{"delete":{"tags":["Board Configs"],"summary":"Remove a board config assignment from a section","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"path","name":"sectionId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Assignment removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Assignment not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/board-configs/sections/{sectionId}":{"get":{"tags":["Board Configs"],"summary":"List board configs assigned to a section","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"sectionId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Board configs for section","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/bank-masters":{"get":{"tags":["Bank Masters"],"summary":"List banks (search by IFSC/name/branch)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}},"post":{"tags":["Bank Masters"],"summary":"Create a new bank","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created"}}}},"/v1/bank-masters/ifsc/{ifsc}":{"get":{"tags":["Bank Masters"],"summary":"Lookup a bank by IFSC code (returns null if not found)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"ifsc","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Bank or null","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/bank-masters/{id}":{"get":{"tags":["Bank Masters"],"summary":"Get a bank by ID","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Bank","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}},"put":{"tags":["Bank Masters"],"summary":"Update a bank (IFSC cannot be changed)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Updated"}}},"delete":{"tags":["Bank Masters"],"summary":"Soft-delete a bank","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"}}}},"/v1/auth/otp/request":{"post":{"tags":["Auth"],"summary":"Request an OTP for phone-based authentication","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["phone"],"properties":{"phone":{"type":"string"}}}}}},"responses":{"200":{"description":"OTP sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/auth/otp/verify":{"post":{"tags":["Auth"],"summary":"Verify OTP and receive JWT + refresh token","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["phone","otp"],"properties":{"phone":{"type":"string"},"otp":{"type":"string","minLength":6,"maxLength":6}}}}}},"responses":{"200":{"description":"Login successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"401":{"description":"Invalid OTP","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/auth/login":{"post":{"tags":["Auth"],"summary":"Login with password (+ OTP if new device)","description":"Step 1: send phone + password. If device is known, returns tokens. If new device, returns `requires_otp: true` and sends OTP. Step 2: resend with phone + password + otp to complete login.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["phone","password"],"properties":{"phone":{"type":"string"},"password":{"type":"string"},"otp":{"type":"string","minLength":6,"maxLength":6}}}}}},"responses":{"200":{"description":"Login successful or OTP challenge","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"401":{"description":"Invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/auth/devices":{"get":{"tags":["Auth"],"summary":"List trusted devices for the authenticated user","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Device list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/auth/devices/{id}":{"delete":{"tags":["Auth"],"summary":"Revoke trust for a device","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Device revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Device not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/auth/refresh":{"post":{"tags":["Auth"],"summary":"Rotate refresh token and issue new JWT","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["refresh_token"],"properties":{"refresh_token":{"type":"string"}}}}}},"responses":{"200":{"description":"New token pair","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"401":{"description":"Invalid refresh token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/auth/logout":{"post":{"tags":["Auth"],"summary":"Logout current session (blacklist JWT + revoke refresh token)","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"refresh_token":{"type":"string"}}}}}},"responses":{"200":{"description":"Logged out","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/auth/logout-all":{"post":{"tags":["Auth"],"summary":"Logout all sessions (revoke all refresh tokens)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"All sessions revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/auth/impersonate":{"post":{"tags":["Auth"],"summary":"Start an impersonation session","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["target_user_id","reason"],"properties":{"target_user_id":{"type":"string"},"reason":{"type":"string"}}}}}},"responses":{"200":{"description":"Impersonation started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"403":{"description":"Not authorized to impersonate","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/auth/impersonate/end":{"post":{"tags":["Auth"],"summary":"End an impersonation session","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["session_id"],"properties":{"session_id":{"type":"string"}}}}}},"responses":{"200":{"description":"Impersonation ended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/auth/me":{"get":{"tags":["Auth"],"summary":"Get the currently authenticated user","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Current user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"401":{"description":"Unauthenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/auth/sign-out":{"post":{"tags":["Auth"],"summary":"Invalidate the current JWT (legacy — prefer /logout)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Logged out","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/auth/forgot-password":{"post":{"tags":["Auth"],"summary":"Request a password-reset OTP (sent to registered email)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["school_code","email"],"properties":{"school_code":{"type":"string"},"email":{"type":"string","format":"email"}}}}}},"responses":{"200":{"description":"OTP sent (or silently succeeded)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/v1/auth/verify-reset-otp":{"post":{"tags":["Auth"],"summary":"Verify password-reset OTP and receive a short-lived resetToken","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["school_code","email","otp"],"properties":{"school_code":{"type":"string"},"email":{"type":"string","format":"email"},"otp":{"type":"string","minLength":6,"maxLength":6}}}}}},"responses":{"200":{"description":"OTP verified — resetToken returned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"400":{"description":"Invalid or expired OTP","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/auth/reset-password":{"post":{"tags":["Auth"],"summary":"Set a new password using the resetToken from verify-reset-otp","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["school_code","email","reset_token","new_password"],"properties":{"school_code":{"type":"string"},"email":{"type":"string","format":"email"},"reset_token":{"type":"string"},"new_password":{"type":"string","minLength":6}}}}}},"responses":{"200":{"description":"Password reset successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"400":{"description":"Invalid or expired reset token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/auth/change-password":{"post":{"tags":["Auth"],"security":[{"bearerAuth":[]}],"summary":"Change own password (authenticated). current_password optional if mustResetPassword=true.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["new_password"],"properties":{"current_password":{"type":"string"},"new_password":{"type":"string","minLength":6}}}}}},"responses":{"200":{"description":"Password changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"401":{"description":"Current password incorrect","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/approval-chains":{"get":{"tags":["Approval Chains"],"summary":"List approval chain steps (filterable by entity_type, action, branch_id)","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","minimum":1}},{"in":"query","name":"page_size","schema":{"type":"integer","minimum":1,"maximum":200}},{"in":"query","name":"entity_type","schema":{"type":"string"},"description":"Filter by entity type (e.g., fee_structure, leave, scholarship)"},{"in":"query","name":"action","schema":{"type":"string"},"description":"Filter by action (e.g., approve, review)"},{"in":"query","name":"branch_id","schema":{"type":"string"}}],"responses":{"200":{"description":"List of approval chain steps","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}},"401":{"description":"Unauthenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"post":{"tags":["Approval Chains"],"summary":"Create a new approval chain step","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["entity_type","action","step_order","approver_role_id"],"properties":{"entity_type":{"type":"string","description":"e.g., fee_structure, leave, scholarship, circular"},"action":{"type":"string","description":"e.g., approve, review, verify"},"step_order":{"type":"integer","minimum":1},"approver_role_id":{"type":"string"},"threshold_amount":{"type":"number","minimum":0},"branch_id":{"type":"string"}}}}}},"responses":{"201":{"description":"Created approval chain step","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Approver role or branch not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/approval-chains/{id}":{"get":{"tags":["Approval Chains"],"summary":"Get a single approval chain step","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Approval chain step","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"put":{"tags":["Approval Chains"],"summary":"Update an approval chain step","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"entity_type":{"type":"string"},"action":{"type":"string"},"step_order":{"type":"integer","minimum":1},"approver_role_id":{"type":"string"},"threshold_amount":{"type":"number","nullable":true},"branch_id":{"type":"string","nullable":true}}}}}},"responses":{"200":{"description":"Updated approval chain step","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"delete":{"tags":["Approval Chains"],"summary":"Soft-delete an approval chain step","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/approval-chains/next-approver":{"get":{"tags":["Approval Chains"],"summary":"Get the next approver role for a given entity type, action, and current step","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"entity_type","required":true,"schema":{"type":"string"}},{"in":"query","name":"action","required":true,"schema":{"type":"string"}},{"in":"query","name":"current_step","required":true,"schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"Next approver info (null if no more steps)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"401":{"description":"Unauthenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/academic-years":{"get":{"tags":["Academics"],"summary":"List academic years","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer"}},{"in":"query","name":"page_size","schema":{"type":"integer"}},{"in":"query","name":"search","schema":{"type":"string"}},{"in":"query","name":"is_active","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Academic year list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}},"post":{"tags":["Academics"],"summary":"Create academic year","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","start_date","end_date"]}}}},"responses":{"200":{"description":"Created academic year"}}}},"/v1/academic-years/{id}":{"get":{"tags":["Academics"],"summary":"Get academic year by ID","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Academic year detail"}}},"put":{"tags":["Academics"],"summary":"Update academic year","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Updated academic year"}}}},"/v1/classes":{"get":{"tags":["Academics"],"summary":"List academic classes","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"academic_year_id","schema":{"type":"string"}},{"in":"query","name":"branch_id","schema":{"type":"string"}}],"responses":{"200":{"description":"Class list"}}}},"/v1/sections":{"get":{"tags":["Academics"],"summary":"List sections","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"class_id","schema":{"type":"string"}}],"responses":{"200":{"description":"Section list"}}}},"/v1/subjects":{"get":{"tags":["Academics"],"summary":"List subjects","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Subject list"}}}},"/platform/v1/schools/{school_id}/setup-snapshot":{"get":{"tags":["Platform - Master Data"],"summary":"List tenant master snapshots for a school","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"school_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of snapshots","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"422":{"description":"Invalid school_id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/platform/v1/master-data/role-templates":{"get":{"tags":["Platform - Master Data"],"summary":"List role templates (paginated + searchable, optional scope filter)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}},"post":{"tags":["Platform - Master Data"],"summary":"Create a role template","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"409":{"description":"Code already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/platform/v1/master-data/role-templates/{id}":{"get":{"tags":["Platform - Master Data"],"summary":"Get one role template","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Role template","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"put":{"tags":["Platform - Master Data"],"summary":"Update a role template","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}},"delete":{"tags":["Platform - Master Data"],"summary":"Soft-delete a role template (system templates cannot be deleted)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"403":{"description":"System template not deletable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/platform/v1/master-data/pincodes":{"get":{"tags":["Platform - Master Data"],"summary":"List pincodes","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}},"post":{"tags":["Platform - Master Data"],"summary":"Create a pincode","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/platform/v1/master-data/pincodes/{id}":{"get":{"tags":["Platform - Master Data"],"summary":"Get one pincode","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Pincode","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"put":{"tags":["Platform - Master Data"],"summary":"Update a pincode","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}},"delete":{"tags":["Platform - Master Data"],"summary":"Soft-delete a pincode","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/platform/v1/master-data/lookups":{"get":{"tags":["Platform - Master Data"],"summary":"List tenant-default lookups (scoped, filterable by type)","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"type","schema":{"type":"string"}}],"responses":{"200":{"description":"List","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}},"post":{"tags":["Platform - Master Data"],"summary":"Create a tenant-default lookup","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/platform/v1/master-data/lookups/{id}":{"get":{"tags":["Platform - Master Data"],"summary":"Get one lookup","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Lookup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"put":{"tags":["Platform - Master Data"],"summary":"Update a tenant-default lookup","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}},"delete":{"tags":["Platform - Master Data"],"summary":"Soft-delete a tenant-default lookup","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/platform/v1/master-data/leave-types":{"get":{"tags":["Platform - Master Data"],"summary":"List leave types (paginated + searchable)","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","minimum":1}},{"in":"query","name":"page_size","schema":{"type":"integer","minimum":1,"maximum":200}},{"in":"query","name":"search","schema":{"type":"string"}},{"in":"query","name":"active_only","schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of leave types","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}},"post":{"tags":["Platform - Master Data"],"summary":"Create a leave type","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/platform/v1/master-data/leave-types/{id}":{"get":{"tags":["Platform - Master Data"],"summary":"Get a single leave type by id","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Leave type","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"put":{"tags":["Platform - Master Data"],"summary":"Update a leave type","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"delete":{"tags":["Platform - Master Data"],"summary":"Soft-delete a leave type","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/platform/v1/master-data/holidays":{"get":{"tags":["Platform - Master Data"],"summary":"List holidays (filterable by academic_year_label)","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"academic_year_label","schema":{"type":"string"}}],"responses":{"200":{"description":"List","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}},"post":{"tags":["Platform - Master Data"],"summary":"Create a holiday","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/platform/v1/master-data/holidays/{id}":{"get":{"tags":["Platform - Master Data"],"summary":"Get one holiday","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Holiday","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"put":{"tags":["Platform - Master Data"],"summary":"Update a holiday","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}},"delete":{"tags":["Platform - Master Data"],"summary":"Soft-delete a holiday","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/platform/v1/master/fee-heads":{"get":{"tags":["Platform - Master Data"],"summary":"List fee heads (paginated + searchable)","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","minimum":1}},{"in":"query","name":"page_size","schema":{"type":"integer","minimum":1,"maximum":200}},{"in":"query","name":"search","schema":{"type":"string"}},{"in":"query","name":"active_only","schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of fee heads","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}},"post":{"tags":["Platform - Master Data"],"summary":"Create a fee head","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","fee_type"],"properties":{"name":{"type":"string"},"fee_type":{"type":"string","enum":["recurring","one_time"]},"description":{"type":"string","nullable":true},"is_system":{"type":"boolean"},"is_new_student_only":{"type":"boolean"},"default_on":{"type":"boolean"},"is_active":{"type":"boolean"}}}}}},"responses":{"201":{"description":"Fee head created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/platform/v1/master/fee-heads/{id}":{"get":{"tags":["Platform - Master Data"],"summary":"Get a single fee head by id","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Fee head","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"put":{"tags":["Platform - Master Data"],"summary":"Update a fee head","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"fee_type":{"type":"string","enum":["recurring","one_time"]},"description":{"type":"string","nullable":true},"is_system":{"type":"boolean"},"is_new_student_only":{"type":"boolean"},"default_on":{"type":"boolean"},"is_active":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Fee head updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"delete":{"tags":["Platform - Master Data"],"summary":"Soft-delete a fee head","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Fee head deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/platform/v1/master-data/document-types":{"get":{"tags":["Platform - Master Data"],"summary":"List document types","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}},"post":{"tags":["Platform - Master Data"],"summary":"Create a document type","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/platform/v1/master-data/document-types/{id}":{"get":{"tags":["Platform - Master Data"],"summary":"Get one document type","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Document type","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"put":{"tags":["Platform - Master Data"],"summary":"Update a document type","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}},"delete":{"tags":["Platform - Master Data"],"summary":"Soft-delete a document type","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/platform/v1/master-data/designations":{"get":{"tags":["Platform - Master Data"],"summary":"List designations","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}},"post":{"tags":["Platform - Master Data"],"summary":"Create a designation","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/platform/v1/master-data/designations/{id}":{"get":{"tags":["Platform - Master Data"],"summary":"Get one designation","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Designation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"put":{"tags":["Platform - Master Data"],"summary":"Update a designation","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}},"delete":{"tags":["Platform - Master Data"],"summary":"Soft-delete a designation","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/platform/v1/master-data/departments":{"get":{"tags":["Platform - Master Data"],"summary":"List departments (paginated + searchable)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponseWithPagination"}}}}}},"post":{"tags":["Platform - Master Data"],"summary":"Create a department","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}},"/platform/v1/master-data/departments/{id}":{"get":{"tags":["Platform - Master Data"],"summary":"Get one department","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Department","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"put":{"tags":["Platform - Master Data"],"summary":"Update a department","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}},"delete":{"tags":["Platform - Master Data"],"summary":"Soft-delete a department","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSuccessResponse"}}}}}}}}}