172 KiB
Executable File
API Controllers
This document lists every API controller alphabetically with any inline route comments we can gather.
AdministratorController
File: app/Http/Controllers/Api/AdministratorController.php
Purpose: Surface administrator-portal analytics, student and parent search tools, and the enrollment workflow.
Endpoints
GET /api/v1/administrator/dashboard(dashboard)- Returns counts for students, staff roles, and parents plus the four most recent login activities. Always reflects the configured school year/semester.
GET /api/v1/administrator/absence(absenceInfo)- Requires auth. Responds with semester/year metadata, existing absence submissions for the current admin, and the list of valid Sunday dates (computed via
allowedAbsenceDates()).
- Requires auth. Responds with semester/year metadata, existing absence submissions for the current admin, and the list of valid Sunday dates (computed via
POST /api/v1/administrator/absence(submitAbsence)- Body:
{"dates":["YYYY-MM-DD",...], "reason_type":"optional", "reason":"required"}. - Validates each date against the allowed list, creates/upserts staff attendance rows, and emails the principal. Response lists
saved,invalid, and the saved date values; validation errors return401/422.
- Body:
GET /api/v1/administrator/search(search)- Query param
qis required. Tokenizes the search string and looks across users, students, parents, staff, and emergency contacts (including phone-number heuristics). Returns bucketed arrays and a total hit count.
- Query param
GET /api/v1/administrator/enrollment-withdrawal(enrollmentWithdrawal)- Paginated list of enrollment rows filtered by
school_year(defaults to configured year).
- Paginated list of enrollment rows filtered by
GET /api/v1/administrator/enrollment-withdrawal/data(enrollmentWithdrawalData)- Supplies UI metadata: available school years, each student with parent context, and class-section options for the chosen year.
POST /api/v1/administrator/enrollment-withdrawal/update(updateEnrollmentStatuses)- Body:
{"enrollment_status":{"student_id":"status", ...}}where status must be one ofadmission under review,payment pending,enrolled,withdraw under review,refund pending,withdrawn,denied, orwaitlist. - Wraps updates in a transaction, adjusts admission flags, and when a status moves into
refund pendingrunsFeeCalculationService+RefundModelbookkeeping. Responds with summary + any per-student errors.
- Body:
GET /api/v1/administrator/students(studentProfiles)- Returns every student ordered alphabetically, enriched with parent contact info, emergency contacts, allergy/medical summaries, and current class section name.
GET /api/v1/administrator/parents(parentProfiles)- Iterates all users, filters by
parentrole, and augments each record with their latest invoicepaid_amount/balance.
- Iterates all users, filters by
GET /api/v1/administrator/enrollment/new-students(newStudents)- Lists all students marked as new for the active school year, including parent/emergency contacts, enrollment status, class assignment, and formatted registration dates.
AssignmentController
File: app/Http/Controllers/Api/AssignmentController.php
Purpose: CRUD interface around the assignments table plus APIs for the class-assignment management screen.
GET /api/v1/assignments(index) – Optionalclass_id,teacher_id,student_id,page, andper_pagefilters; returns paginated assignments.GET /api/v1/assignments/{id}(show) – Returns a single assignment or404.POST /api/v1/assignments(store) – Requirestitle,due_date (Y-m-d),class_id, andteacher_id; creates an assignment row.PATCH /api/v1/assignments/{id}(update) – Partial update for the same fields asstore.DELETE /api/v1/assignments/{id}(delete) – Removes the assignment.GET /api/v1/assignments/student/{id}(student) – Lists assignments attached to a specific student.GET /api/v1/assignments/class-sections(classAssignments) – Mirrors the legacy admin Class Assignment screen; groups teacher + student rosters by class section, with optionalschool_yearfilter, and returns the list of available school years.GET /api/v1/assignments/class-sections/data(classAssignmentData) – Lightweight JSON payload of all class sections/teachers/students used by the SPA.POST /api/v1/assignments/class-sections(saveClassAssignment) – Creates astudent_classrecord for a student/section pairing, capturing term metadata and editor.
AttendanceController
File: app/Http/Controllers/Api/AttendanceController.php
Purpose: Manage per-student attendance plus provide roster tools for class-wide check-in.
index()– Query params:page,per_page,student_id,date. Responds with paginated attendance rows and pager metadata.show($id)– Returns a single attendance record or404.store()– Body requiresstudent_id,date (Y-m-d),status (present|absent|late), optionalnotes. Prevents duplicates per (student,date) and returns201with inserted payload.update($id)– Allows patchingstatusand/ornotes, re-validates, and echoes the updated entity.delete($id)– Removes the record if it exists.student($id)– Returns all attendance rows for the given student sorted newest-first.classRoster($class_section_id)–GET /api/v1/attendance/class/{class_section_id}accepts optionaldatequery param (default today) and returns each student in the section with their attendance status/reason for that date.recordClass($class_section_id)–POST /api/v1/attendance/class/{class_section_id}/recordbody:{"date":"YYYY-MM-DD","records":[{"student_id":1,"status":"present|absent|late","reason":"optional"},...]}. Validates rows, ensures roster membership, and records each entry atomically, returning per-student success/error arrays.GET /api/v1/attendance/teacher/grid(teacherSectionGrid) – Returns the section dropdown, current staff grid, and lock state for the teacher attendance landing page; acceptsclass_section_id,date,semester, andschool_year.GET /api/v1/attendance/teacher/update-data(teacherUpdateData) – Supplies the detailed payload used by the teacher update form: teacher metadata, the most recent dates (today plus the last three sessions), student attendance history, staff statuses, and any no-school days for the selected section/term.
AttendanceTrackingController
File: app/Http/Controllers/Api/AttendanceTrackingController.php
Purpose: Surface pending attendance violations, automate/track parent notifications, and expose helpers for the manual email workflow.
GET /api/v1/attendance-tracking/pending(pendingViolations) – Filters unreported/unnotified absences & lates in the last five active weeks and returns the computed violation list, including parent contact info and recommended actions.GET /api/v1/attendance-tracking/notified(notifiedViolations) – Lists previously notified violations enriched with student, class, and parent metadata.POST /api/v1/attendance-tracking/notify(recordNotification) – Manually mark a violation as notified (and dispatch the corresponding Laravel event). Body must includestudent_idanddate; optional term overrides and parent contact info may be supplied.POST /api/v1/attendance-tracking/send-auto-emails(sendAutoEmails) – Scans for auto-email violations and sends templated emails (with CC to secondary parents when available); responds with{sent, skipped, errors, details}.GET /api/v1/attendance-tracking/compose(composeEmail) – Returns the rendered subject/body preview plus parent addresses for a givenstudent_id,code, and optionalvariant/incident_date.POST /api/v1/attendance-tracking/send-email(sendEmailManual) – Sends a manual attendance email using the body/subject from the compose UI, logs the notification, and flips the tracking/attendance rows to notified.GET /api/v1/attendance-tracking/parents-info(parentsInfo) – Convenience endpoint that returns the primary and secondary parent contacts for a student.POST /api/v1/attendance-tracking/notes(saveNotificationNote) – Persists the admin’s follow-up note against the relevant tracking row (or creates one if missing) after a notification is sent.
AuthController
File: app/Http/Controllers/Api/Auth/AuthController.php
Purpose: JWT-backed authentication endpoints.
POST /api/v1/auth/login(login) – Validatesemailandpassword, looks up the user case-insensitively, usesci_password_verify, and returns{access_token, token_type, expires_in}or401.GET /api/v1/auth/me(me) – Requires a valid bearer token, returns the decodedUserJSON viaJWTAuth::parseToken()->authenticate().POST /api/v1/auth/logout(logout) – Invalidates the caller’s JWT token (best-effort) and returns{message: "Logged out"}even if the token was already invalid.
AuthorizedUsersController
File: app/Http/Controllers/Api/AuthorizedUsersController.php
Purpose: Allow primary users to manage their authorized delegates and guide those delegates through the confirmation/password flow.
GET /api/v1/authorized-users(index) – Auth required; returns every authorized user tied to the signed-in primary account.GET /api/v1/authorized-users/{id}(show) – Auth required; fetches a single authorized user (scoped to the current owner).POST /api/v1/authorized-users(store) – Auth required; acceptsemail, verifies that user exists, creates a pending authorized-user row, and sends a confirmation email with a tokenized link.PATCH /api/v1/authorized-users/{id}(update) – Auth required; currently allows updating the email address for the authorized user.DELETE /api/v1/authorized-users/{id}(destroy) – Auth required; removes the authorized user entry for the current owner.POST /api/v1/authorized-users/confirm(confirm) – Public endpoint hit from email links; validates the token, activates the record, and returns the delegate’sauthorized_user_idfor the password setup UI.GET /api/v1/authorized-users/{id}/set-password(setPassword) – Public; returns the delegate’s basic info so the frontend can render the password form.POST /api/v1/authorized-users/{id}/password(savePassword) – Public; acceptspassword/password_confirm, hashes it with PBKDF2, and updates the delegate’s user record.
BaseApiController
File: app/Http/Controllers/Api/BaseApiController.php
Purpose: Shared foundation for every API controller. Wraps the Laravel request in a CiRequestAdapter, standardizes JSON responses, bridges CodeIgniter-style validation rules, and exposes helper utilities.
- Response helpers:
success,error, and therespond*variants keep payloads consistent ({status, message, data}) and map to the right HTTP codes (200,201,204,400,422, etc.). - Validation bridge:
validateRequest,validate,payloadData, andnormalizeRulesaccept CodeIgniter rule strings (e.g.,max_length[255],permit_empty) and translate them to Laravel validator syntax before runningValidator::make. - Pagination:
paginate($source, $page, $perPage)works with Eloquent builders, query builders, or arrays, returning{data, pagination:{current_page, per_page, total, total_pages}}. - Session context:
getCurrentUserId()reads theuser_idfrom the session, andgetCurrentUser()fetches the hydratedUserModelrecord, falling back to queryinguser_rolesif roles are missing from the session cache. - Constructor: captures the Laravel
Requestand exposes it as$this->requestviaCiRequestAdapterso consuming controllers can continue to use familiar CI-style helpers (getGet,getJSON, etc.).
BroadcastEmailController
File: app/Http/Controllers/Api/BroadcastEmailController.php
Purpose: Simple bulk-email helper for administrators plus a convenience list of eligible parent recipients.
GET /api/v1/broadcast-email(metadata) – Provides the parent roster (usingUserModel::getParents) and the sender dropdown derived fromMAIL_SENDERSso the UI can render the compose screen.POST /api/v1/broadcast-email/send(send) – Supports both test mode (send_test_only,test_email) and broadcast mode. Accepts layout options (wrap_layout,preheader, CTA text/URL) plus personalization toggle. Sends viaEmailService, reports{attempted, sent, failed}.POST /api/v1/broadcast-email/upload-image(uploadImage) – Validates and stores rich-text editor image uploads (JPEG/PNG/GIF/WebP ≤ 5 MB) underpublic/uploads/emailand returns the public URL.
CalendarController
File: app/Http/Controllers/Api/CalendarController.php
Purpose: CRUD for the school calendar, including month/year filters and validation for event creation.
GET /api/v1/calendar(index) – Supportspage,per_page,month, andyearquery params. Filters bystart_date, orders ascending, and returns paginated events.GET /api/v1/calendar/{id}(show) – Returns the event by ID or404.POST /api/v1/calendar(store) – Body must includetitle,start_date (Y-m-d)and optionaldescription,end_date,location. Responds with201and the created record.PATCH /api/v1/calendar/{id}(update) – Allows partial updates to the same fields; returns the refreshed record.DELETE /api/v1/calendar/{id}(delete) – Removes the event and returns the standard success envelope.
CiRequestAdapter
File: app/Http/Controllers/Api/CiRequestAdapter.php
Purpose: Lightweight shim that lets the Laravel request behave like CodeIgniter’s $this->request.
getGet()/getPost()– Mirror CI helpers by returning either all query/form params or a single key with a default.getJSON($assoc = false)– Parses the raw body once and returns decoded JSON (array/object).getVar()– Unified accessor that checks body/query for a key.getHeader()/getHeaderLine()– Pull HTTP headers using familiar CI naming.getFile()– Returns the uploaded file object (if any) for the key.getRawInput()– Gives the unparsed request body string.all()– Aggregates query, form, and JSON payloads into a single array—handy when migrating legacy controllers.
ClassController
File: app/Http/Controllers/Api/ClassController.php
Purpose: Provide read endpoints for classes and their rosters.
GET /api/v1/classes(index) – Supports pagination plus optionalgradeandteacher_idfilters; returns ordered list of class records.GET /api/v1/classes/{id}(show) – Retrieves a single class or404.GET /api/v1/classes/{id}/students(students) – Joinsstudent_classandstudentsto return each enrolled student (id,firstname,lastname,school_id) sorted alphabetically.
ClassPreparationController
File: app/Http/Controllers/Api/ClassPreparationController.php
Purpose: Track supplies needed for each class and provide a lightweight "requirements" calculator.
GET /api/v1/class-prep/list(index) – Returns class preparation data filtered by optionalschool_yearandsemesterquery params. Calculates per-section prep items, available inventory, shortages, and change flags. Returns:results– Array of class sections with prep items, student counts, adjustments, and print statustotals– Required totals for each prep categoryshortages– Items where available inventory is less than requiredavailable– Current inventory map
POST /api/v1/class-prep/adjustments(saveAdjustment) – Body requiresclass_section_id,school_year, andadjustmentsobject. Persists manual adjustments for large/small tables and returns{updated: count}.POST /api/v1/class-prep/mark-printed(markPrinted) – Body requiresschool_yearandclass_section_idsarray. Stores printed snapshots for the supplied section IDs to resetneeds_printflag. Returns{updated: count}.
CommunicationController
File: app/Http/Controllers/Api/CommunicationController.php
Purpose: Internal messaging between users (parents ↔ staff, etc.).
GET /api/v1/communications(index) – Paginated feed filtered by optionalsender_idand/orreceiver_id, ordered newest-first.POST /api/v1/communications(send) – Body must includesender_id,receiver_id,subject,message. Returns201with stored record.GET /api/v1/communications/conversation(conversation) – Requires bothsender_idandreceiver_idquery params. Returns the chronological conversation (both directions) between the two users.DELETE /api/v1/communications/{id}(delete) – Removes a message by ID.GET /api/v1/communications/metadata(metadata) – Returns the active students list (id, firstname, lastname, grade) plus all active email templates for building a mailing UI.GET /api/v1/communications/students/{student_id}/families(families) – Returns the active families for the supplied student along with theis_primary_homeflag so the front-end can preselect the right household.GET /api/v1/communications/families/{family_id}/guardians(guardians) – Joinsfamily_guardianswithusersto return each guardian’s name, email, relation, and preferred delivery flags.POST /api/v1/communications/preview(preview) – Body requirestemplate_key,student_id, andfamily_id; optionalvars. Renders the Twig-like placeholders in the chosen template and returns a sanitized subject/body preview.POST /api/v1/communications/send-email(sendEmail) – Body requiresstudent_id,family_id,template_key,subject,body, andrecipients(JSON array or string). Accepts optionalcc/bcc, sends the HTML email throughMail::send, and logs the result incommunication_logs.
ConfigurationController
File: app/Http/Controllers/Api/ConfigurationController.php
Purpose: Manage key/value pairs stored in the configuration table.
GET /api/v1/configuration(index) – Paginated list ordered by ID with optional fuzzykeysearch.GET /api/v1/configuration/{id}(show) – Fetch a config row by numeric ID.GET /api/v1/configuration/key/{config_key}(getByKey) – Convenience lookup using the string key.POST /api/v1/configuration(create) – Requires uniqueconfig_keyandconfig_value; wraps persistence in try/catch and returns201.PATCH /api/v1/configuration/{id}(update) – Allows updatingconfig_keyand/orconfig_value, ensuring the payload isn’t empty.DELETE /api/v1/configuration/{id}(delete) – Removes the row after existence check.GET /api/v1/configuration/list(listData) – Returns all configs as{id, config_key, config_value}for settings UIs.
ContactController
File: app/Http/Controllers/Api/ContactController.php
Purpose: Public “Contact Us” submission endpoint that relays a message via the shared EmailService.
POST /api/v1/contact(submit) – Body requiresname,email,subject, andmessage. Validates lengths + email format, then composes HTML and sends it toSUPPORT_EMAIL(defaultsupport@alrahmaisgl.org). Returns a friendly success message or500if delivery fails.
DiscountController
File: app/Http/Controllers/Api/DiscountController.php
Purpose: Validate and apply voucher codes against invoices, enforcing date windows and usage limits.
GET /api/v1/discounts(index) – Returns all vouchers ordered newest-first. Optional?active=truefilters down to vouchers that are enabled, within the valid-from/until window.GET /api/v1/discounts/{code}(getByCode) – Looks up the code (case-sensitive in the DB). Responds404if inactive/expired and400if the max usage has already been hit.POST /api/v1/discounts/apply(apply) – Requires authentication plus a JSON body withcodeandinvoice_id. Validates the voucher, ensures it hasn’t been applied to that invoice, records the usage (discount_usage), incrementstimes_used, and returns the refreshed voucher payload. Errors return400/401/500with descriptive messages.
EmailController
File: app/Http/Controllers/Api/EmailController.php
Purpose: Send HTML emails using PHPMailer with support for multiple email profiles, DKIM signing, and attachments.
-
POST /api/v1/email/send(send) – Body requiresrecipient,subject, andhtml_message. Optional parameters include:profile– Email profile name (e.g., 'communication', 'payment', 'default'). UsesMAIL_PROFILE_DEFAULTor 'default' if not specified.reply_to_email– Override reply-to email addressreply_to_name– Override reply-to nameattachments– Array of attachment objects:[{'path': '...', 'name': '...'}, ...]
Supports multiple SMTP profiles via environment variables (
MAIL_{PROFILE}_*orMAIL_DEFAULT_*). Features include:- DKIM signing (if configured)
- Socket preflight checks
- Debug mode (via
MAIL_DEBUGenv) - TLS/SSL encryption with auto-correction
- Returns
{recipient, subject, sent: true}or error response on failure.
EmailExtractorController
File: app/Http/Controllers/Api/EmailExtractorController.php
Purpose: Admin utility to export user/parent emails and compare them against a CSV list or uploaded file.
-
GET /api/v1/email-extractor/emails(getEmails) – Returns all normalized emails fromusers.emailandparents.secondparent_emailas{users: string[], parents: string[]}. Emails are validated, lowercased, and de-duplicated. -
POST /api/v1/email-extractor/compare(compare) – Accepts either:- Multipart/form-data with a CSV file named
file(emails extracted via regex) - JSON body with
csvEmailsarray
Compares CSV emails against database emails and returns:
existed– Emails present in both CSV and databaseneedToAdd– Emails in database but not in CSVcounts– Object withcsv,db,users, andparentscounts
- Multipart/form-data with a CSV file named
EmergencyContactController
File: app/Http/Controllers/Api/EmergencyContactController.php
Purpose: Maintain emergency contacts scoped to the configured school year/semester.
GET /api/v1/emergency-contacts(index) – Optionalparent_idfilter; automatically filters by current year/semester. Returns paginated list of emergency contacts.GET /api/v1/emergency-contacts/data(data) – Returns emergency contacts grouped by parent with enriched data:groups– Array of parent groups, each containing:parent_id– Parent user IDparent_name– Full name of the parentstudents– Array of students associated with this parent (id, firstname, lastname, school_id)contacts– Array of emergency contacts for this parentparent_phones– Array of phone numbers (primary and secondary parent phones, filtered to non-empty values)
GET /api/v1/emergency-contacts/{id}(show) – Fetch a single emergency contact or404.GET /api/v1/emergency-contacts/parent/{parent_id}(getByParent) – Returns all emergency contacts for a specific parent, filtered by current year/semester.POST /api/v1/emergency-contacts(create) – Requiresparent_id,emergency_contact_name,cellphone,relation; optionalemail. Attaches the current year/semester before inserting.PATCH /api/v1/emergency-contacts/{id}(update) – Allows updatingemergency_contact_name,cellphone,email, andrelation.DELETE /api/v1/emergency-contacts/{id}(delete) – Removes the contact.
EventController
File: app/Http/Controllers/Api/EventController.php
Purpose: CRUD operations for events and event charges management.
GET /api/v1/events(index) – Returns all events filtered by optionalschool_yearquery param. When?upcoming=true, filters byexpiration_date >= today. Returns{events: array, active_event_count: number}.GET /api/v1/events/{id}(show) – Fetch an event by ID or404.POST /api/v1/events(create) – Creates a new event. Body requiresevent_name,amount,expiration_date. Optional:description,semester,school_year,flyer(file upload). Automatically setscreated_byfrom session.PATCH /api/v1/events/{id}(update) – Updates an event. Allows updatingevent_name,description,amount,expiration_date,semester,school_year, andflyer(file upload). Old flyer is deleted when a new one is uploaded.DELETE /api/v1/events/{id}(delete) – Deletes an event and all associated event charges. Collects affected parent IDs for invoice regeneration (note:generateInvoicemethod may need implementation).GET /api/v1/events/charges(charges) – Returns event charges with parent and student information. Optional query params:school_year,semester. Returns{charges: array, parents: array, events: array, school_year: string, semester: string}.POST /api/v1/events/charges/update(updateCharges) – Updates event charges for a parent and students. Body requiresparent_id,event_id,participation(object mapping student_id to 'yes'/'no'). Optional:school_year,semester. Creates or updates charges, deletes when participation is 'no'. Regenerates invoice for parent (note:generateInvoicemay need implementation).GET /api/v1/events/students-with-charges(getStudentsWithCharges) – Returns students for a parent with their charge status. Query params:parent_id(required),semester,school_year. Returns array of{id, name, charged: boolean}.
ExpenseController
File: app/Http/Controllers/Api/ExpenseController.php
Purpose: CRUD for expense reimbursement records with school year/semester scoping.
GET /api/v1/expenses(index) – Paginated list filtered bystatusand/orcategory, always constrained to the active year/semester.GET /api/v1/expenses/{id}(show) – Retrieve a single expense.POST /api/v1/expenses(create) – Body needscategory,amount,description,date_of_purchase; fills metadata likeschool_year,semester,purchased_by, andstatus.PATCH /api/v1/expenses/{id}(update) – Allows selective updates (category/amount/description/retailor/date/status/status_reason) and stampsupdated_by.DELETE /api/v1/expenses/{id}(delete) – Deletes the record.
ExtraChargesController
File: app/Http/Controllers/Api/ExtraChargesController.php
Purpose: Manage "additional charges" tacked onto parent invoices with full transaction support and invoice adjustment.
-
GET /api/v1/extra-charges(index) – Paginated list filtered byschool_year,semester,status, and optional search queryq. Returns charges with parent names and invoice numbers. Defaults to configured year/semester. -
GET /api/v1/extra-charges/{id}(show) – Retrieve a single charge or404. -
POST /api/v1/extra-charges(store) – Creates a new charge. Body requires:parent_id(integer, required) – The user ID of the parenttitle(string, required, min 2 chars)amount(numeric, required)charge_type(required,addordeduct)due_date(nullable, date format)invoice_id(nullable, integer) – If provided, charge is immediately applied to invoicedescription(optional string)school_year(optional, defaults to configured year)semester(optional, defaults to configured semester)
When
invoice_idis provided, the charge is automatically applied to the invoice (adjustingtotal_amountandbalance). DispatchesextraChargeevent with full context including pre/post balance snapshots. -
PATCH /api/v1/extra-charges/{id}(update) – Updates charge fields (title,description,amount,due_date,charge_type). If the charge is already applied to an invoice and the amount changes, the invoice is automatically adjusted to reflect the delta. -
POST /api/v1/extra-charges/{id}/void(void) – Marks a charge as void. If the charge was applied to an invoice, the invoice impact is rolled back (reversed for additions, re-added for deductions). Uses database transactions. -
POST /api/v1/extra-charges/{id}/reverse(reverse) – Reverses an applied charge back to pending status. Undoes the invoice impact and clears theinvoice_id. Only works on charges with statusapplied. -
DELETE /api/v1/extra-charges/{id}(delete) – Permanently deletes the charge record. -
GET /api/v1/extra-charges/parent-options(parentOptions) – Returns Select2-compatible{results: [{id, text}]}array for parent users. Optional query paramqfilters by firstname, lastname, or email. Format: "Lastname, Firstname — email (ID: x)". -
GET /api/v1/extra-charges/invoices-for-parent(invoicesForParent) – Returns Select2-compatible invoice list for a parent. Query params:parent_id(required),school_year(optional). Format: "INV-123 — status (Bal: $X.XX)".
FamilyAdminController
File: app/Http/Controllers/Api/FamilyAdminController.php
Purpose: Admin-only aggregate view of students, families, guardians, and financial data.
-
GET /api/v1/family-admin(index) – Returns comprehensive family administration data. Query params:student_id(optional) – Filters to that student's family membershipsguardian_id(optional) – If provided withoutstudent_id, resolves to one of the guardian's students
Returns:
students– Simple list of all students (id, name) for dropdownssearch_students– Student search dataset (id, firstname, lastname)search_guardians– Guardian search dataset (id, firstname, lastname, email, cellphone)student– Selected student info (ifstudent_idprovided)families– Array of families for the student, each containing:- Family details (family_code, household_name, address, etc.)
guardians– Array of guardians with contact info and preferencesstudents– Array of students in the family with grade informationinvoices– All invoices for guardians in this familypayments– Recent payments (limit 10) for guardiansfinance_summary– Aggregated totals (invoices_count, total_amount, paid_amount, balance)invoice_map– Mapping of invoice IDs to invoice numbers
guardians– Guardians of the first family (back-compat)
-
GET /api/v1/family-admin/search(search) – Search for students and guardians. Query paramq(required) searches by:- Students: firstname, lastname
- Guardians: firstname, lastname, email, cellphone
Returns
{items: []}array where each item has:type– "student" or "guardian"id– ID of the student/guardianlabel– Full namesub– Additional info (email/phone for guardians, "Student" for students)
Limited to 8 results per type.
-
GET /api/v1/family-admin/card(card) – Returns detailed family card data. Query params:family_id(optional) – Direct family IDstudent_id(optional) – Resolves to primary family for that studentguardian_id(optional) – Resolves to a family via guardian link or student parent_id
Returns a single
familyobject with:- Family details (all fields from families table)
guardians– All guardians with full contact infostudents– All students with grade informationinvoices– All invoices for guardianspayments– Recent payments (limit 10)finance_summary– Aggregated financial totalsinvoice_map– Invoice ID to number mappingemergency_contacts– Emergency contacts for all guardians, enriched with parent labels
FamilyController
File: app/Http/Controllers/Api/FamilyController.php
Purpose: CRUD and management endpoints for families, linking families to guardians (users) and students, including bootstrap from existing schema.
Read Endpoints:
GET /api/v1/families(index) – Paginated families with eager-loadedstudentsandguardians.GET /api/v1/families/{id}(show) – Fetch a family with its relations.GET /api/v1/families/by-student/{student_id}(getByStudent) – Returns every family associated with the student, including nested members.GET /api/v1/families/{id}/guardians(getGuardians) – Convenience list of guardians for a family.GET /api/v1/families/students/{student_id}/families(familiesByStudent) – Returns all active families for a student withis_primary_homeflag, ordered by primary home first.GET /api/v1/families/{family_id}/guardians-list(guardiansByFamily) – Returns guardians for a family with user details (firstname, lastname, email) and guardian flags (relation, is_primary, receive_emails, receive_sms).
Bootstrap & Linking:
POST /api/v1/families/bootstrap(bootstrap) – Creates/ensures families for every student withparent_id, links students to families, and links primary parents as guardians. Returns counts of families created, students linked, and guardians linked. Uses database transactions.POST /api/v1/families/attach-second-by-user(attachSecondByUser) – Attaches a second parent/guardian to a student's primary family. Body requiresstudent_id,user_id, and optionalrelation(defaults to 'secondary').POST /api/v1/families/attach-second-by-email(attachSecondByEmail) – Attaches a second parent by email, creating a stub user if the email doesn't exist. Body requiresstudent_id,email, and optionalfirstname,lastname,relation(defaults to 'secondary').
Maintenance Actions:
POST /api/v1/families/set-primary-home(setPrimaryHome) – Sets theis_primary_homeflag for a student-family relationship. Body requiresfamily_id,student_id, andis_primary_home(0/1).POST /api/v1/families/set-guardian-flags(setGuardianFlags) – Updates guardian flags. Body requiresfamily_id,user_id, and any of:receive_emails(0/1),is_primary(0/1),receive_sms(0/1),relation(string).POST /api/v1/families/unlink-guardian(unlinkGuardian) – Removes a guardian from a family. Body requiresfamily_idanduser_id.POST /api/v1/families/unlink-student(unlinkStudent) – Removes a student from a family. Body requiresfamily_idandstudent_id.POST /api/v1/families/import-second-parents(importSecondParentsFromLegacy) – Imports second parents from legacyparentstable. Creates users for email-only entries, links them as guardians, and ensures all students are linked to families. Returns counts of users created, guardians linked, skipped, and total source rows.
FilesController
File: app/Http/Controllers/Api/FilesController.php
Purpose: Serve uploaded receipts and reimbursements from storage with security validation, MIME detection, and HTTP caching support.
Endpoints:
GET /api/v1/files/receipt/{name}(receipt) – Streams a receipt file with path traversal protection, extension allow-list validation, MIME type detection, ETag/Last-Modified headers, and 304 Not Modified support. Returns400for invalid filenames,404for missing files or disallowed extensions.GET /api/v1/files/reimb/{name}(reimb) – Streams a reimbursement file with the same security and caching features asreceipt().GET /api/v1/files/reimbursement/{name}(reimbursement) – Alias forreimb()for backward compatibility.GET /api/v1/files(index) – Requires auth. Query paramtypemust be one ofreceipts|reimbursements|checks(defaults toreceipts). Returns paginated list of files with name, size, and modified timestamp.
Security Features:
- Path traversal protection via
basename()validation - Extension allow-list:
jpg,jpeg,png,webp,gif,pdf - MIME type detection using
finfo_open()(with fallback tomime_content_type()) X-Content-Type-Options: nosniffheader
Caching:
- ETag generation based on filename, modification time, and file size
- Last-Modified header support
- 304 Not Modified responses when
If-None-MatchorIf-Modified-Sinceconditions are met Cache-Control: public, max-age=86400header for browser caching
FinalController
File: app/Http/Controllers/Api/FinalController.php
Purpose: Manage final exam scores per student/class-section for the active term.
Endpoints:
GET /api/v1/finals/student/{student_id}(getByStudent) – Returns the final exam entry for the student scoped by school year/semester.GET /api/v1/finals/class-section/{class_section_id}(getByClassSection) – Returns all students in a class section with their final exam scores. Acceptsclass_section_idas route parameter, query param, or POST body. Uses a subquery to select the latest final exam per student (by MAX(id)) and joins it with the student roster. Returns an array of students withstudent_id,school_id,firstname,lastname, andscore, along withsemester,schoolYear, andclass_section_idmetadata. Students are ordered by lastname, then firstname.POST /api/v1/finals(create) – Upserts by (student_id,class_section_id) after validating input; fills metadata and returns201.PATCH /api/v1/finals/{id}(update) – Allows changingscoreandcomment.
MidtermController
File: app/Http/Controllers/Api/MidtermController.php
Purpose: Manage midterm exam scores for students in class sections.
Endpoints:
GET /api/v1/midterm(index) – Returns midterm exam data for a class section. Query parameters:class_section_id(integer, optional) – Class section ID (can also be provided via POST or session). If not provided, falls back to session value.- Returns array of students with their midterm scores, semester, school year, and class section ID. Uses a subquery to select the latest midterm exam per student (by MAX(id)) and joins it with the student roster. Students are ordered by lastname, then firstname.
POST /api/v1/midterm(update) – Updates midterm exam scores (teacher endpoint). Body requires:final_score(object, required) – Object mapping student IDs to score objects:{"student_id": {"score": float}}class_section_id(integer, optional) – Class section ID (can also be provided via session)- Automatically uses current authenticated user as
updated_by. Updates or creates midterm exam records and triggers semester score recalculation viaSemesterScoreService::updateScoresForStudents().
GET /api/v1/midterm/management(showManagement) – Returns midterm exam data for management view. Same asindexbut intended for administrative use. Query parameters:class_section_id(integer, optional) – Class section ID (can also be provided via POST or session)
POST /api/v1/midterm/management(updateManagement) – Updates midterm exam scores (management endpoint). Body requires:final_score(object, required) – Object mapping student IDs to score objects:{"student_id": {"score": float}}teacher_id(integer, optional) – Teacher ID to record as updater (defaults to current user)class_section_id(integer, optional) – Class section ID (can also be provided via session)- Returns updated student roster with scores after successful update. Triggers semester score recalculation.
Notes:
- All endpoints require authentication (
auth:apimiddleware). - Class section ID can be provided via query parameter, POST body, or session (checked in that order).
- Scores are automatically scoped to the configured semester and school year.
- Updates trigger
SemesterScoreService::updateScoresForStudents()to recalculate semester scores. - The system ensures one score record per student per class section per term (updates existing or creates new).
FinancialController
File: app/Http/Controllers/Api/FinancialController.php
Purpose: Generate comprehensive financial reports, summaries, and identify parents with outstanding balances.
Endpoints:
GET /api/v1/financial/report(report) – Detailed financial report with invoices, payments, payment breakdown by method (cash/credit/check), refunds, expenses, reimbursements, and discounts. Supportsdate_from,date_to, andschool_yearquery parameters. Returns invoices with parent names, payment breakdown per invoice, overall payment totals by method, grouped refunds/discounts, expenses by category, and reimbursements by status. Also includes available school years list.GET /api/v1/financial/report-summary(reportSummary) – Aggregated financial summary. Supportsdate_from,date_to, andschool_yearquery parameters. Returns totals for charges (including extra charges), discounts, refunds, expenses, reimbursements (excluding donations), donations to school, paid amounts, unpaid amounts, and net amount calculations. Includes available school years list.GET /api/v1/financial/unpaid-parents(unpaidParents) – Lists parents with outstanding balances (> 0) for a school year. Supportsschool_yearquery parameter (defaults to configured year). Computes balances dynamically by subtracting payments, discounts, and refunds from invoice totals. Returns parent details, total invoiced, total balance, remaining installments, suggested installment amount, payment type (installment vs no_payment), total paid, and next installment date. Results ordered by balance descending.GET /api/v1/financial/download-csv(downloadCsv) – Downloads financial report as CSV file. Supportsdate_from,date_to, andschool_yearquery parameters. CSV includes invoices section (with parent names, totals, paid, balance, refund), expenses summary by category, and reimbursements summary by status. Filename format:financial_report_YYYYMMDD_HHMMSS.csv.
FlagController
File: app/Http/Controllers/Api/FlagController.php
Purpose: Track behavioral/academic flags assigned to students and manage their lifecycle.
Endpoints:
GET /api/v1/flags(index) – Paginatescurrent_flagswith optionalstudent_id,flag_type(orflag),state(orflag_state) filters. Also returns class sections (grades) array for UI dropdowns.GET /api/v1/flags/{id}(show) – Returns a single flag fromcurrent_flagtable.GET /api/v1/flags/students/{grade_id}(getStudentsByGrade) – Returns students in the class section (grade), helpful for flag assignment UIs. Returns array of{id, name}objects.POST /api/v1/flags(create) – Alias foraddFlag(). Creates or updates a flag for a student.POST /api/v1/flags/add(addFlag) – Add or update a flag for a student. If a flag of the same type already exists for the student, it updates it (appends description based on state); otherwise creates a new one. Requiresstudent_id(orstudent),flag(orflag_type),description(oropen_description). Optional:flag_state,state_description,grade. Automatically sets semester and school_year from configuration. New flags default toOpenstate.PATCH /api/v1/flags/{id}/state(updateState) – Updatesflag_stateand/orstate_description. Updates appropriate description field (open_description,close_description, orcancel_description) based on the new state.POST /api/v1/flags/{id}/close(close) – Alias forcloseFlag(). Closes a flag and moves it to history.POST /api/v1/flags/{id}/close-flag(closeFlag) – Closes a flag and moves it to history. Requiresstate_description(orclose_description) in request body. Updates flag state toClosed, setsupdated_by_closed, then moves the flag fromcurrent_flagtoflagtable and deletes fromcurrent_flag.POST /api/v1/flags/{id}/cancel(cancel) – Alias forcancelFlag(). Cancels a flag and moves it to history.POST /api/v1/flags/{id}/cancel-flag(cancelFlag) – Cancels a flag and moves it to history. Requiresstate_description(orcancel_description) in request body. Updates flag state toCanceled, setsupdated_by_canceled, then moves the flag fromcurrent_flagtoflagtable and deletes fromcurrent_flag.
Flag States: Open, Closed, Canceled (capitalized)
Flag Lifecycle: Flags start in current_flag table. When closed or canceled, they are moved to flag (history) table via moveToHistory() method.
FrontendController
File: app/Http/Controllers/Api/FrontendController.php
Purpose: Provide lightweight data to the public frontend SPA.
GET /api/v1/frontend/user(getUser) – Requires auth; returns first/last name, full name, and initials for the current session.GET /api/v1/frontend/pages(getPages) – Returns the static mapping of page keys to URLs that the frontend expects.
InfoIconController
File: app/Http/Controllers/Api/InfoIconController.php
Purpose: Provide user profile icon information (name and initials) for UI display.
-
GET /api/v1/info-icon/profile(profileIcon) – Requires auth; returns user name and initials for the current logged-in user. Returns:user_name(string) – Full name of the user (firstname + lastname), or email if name is empty, or "User #ID" as fallbackuser_initials(string) – Uppercase initials derived from firstname and lastname (first letter of each), or first 2 characters of firstname/lastname/email as fallback, or "??" if no data available
Returns
401 Unauthorizedif user is not logged in. Returns200 OKwith fallback values if user is not found.
LandingPageController
File: app/Http/Controllers/Api/LandingPageController.php
Purpose: Deliver role-based dashboard data including school year, deadlines, notifications, students, attendance, grades, and enrollments.
Endpoints:
GET /api/v1/landing(index) – Requires auth; returns role-specific dashboard data based on user's role. Routes to:administrator– Returns basic admin metadata (school year, semester, deadlines)admin– Returns basic admin metadatateacher– Returns teacher metadata includingclass_section_idstudent– Returns student metadataparent/authorized_user– Returns comprehensive parent dashboard data (see below)guest– Returns basic guest metadata
GET /api/v1/landing/data(getData) – Requires auth; returns basic landing page bootstrap data:school_year,semesterenrollment_deadline,refund_deadlineclass_section_id(for teachers)user_role
Parent Dashboard Data (returned when role is parent or authorized_user):
notifications– Array of active, non-expired notifications (personal and broadcast) for parentsstudents– Array of students associated with the parent, including class section/grade informationattendance– Attendance records for students filtered by current school year/semestergrades– Final scores for students filtered by current school year/semesterenrollments– Enrollment records for students filtered by current school year/semesterpaymentBalance– Latest invoice total amount for the parentlastDayOfRegistration– Enrollment deadline from configurationwithdrawalDeadline– Refund deadline from configurationschool_year,semester– Current term information
User Type Handling:
- Supports
primary,secondary, andtertiaryuser types - Automatically resolves parent ID for secondary/tertiary users from
parentsandauthorized_userstables
LateSlipLogsController
File: app/Http/Controllers/Api/LateSlipLogsController.php
Purpose: Paginated search and retrieval of late slip submission logs.
Endpoints:
GET /api/v1/late-slip-logs(index) – Paginated list of late slip logs with optional filters. Query parameters:school_year(string, optional) – Filter by school year (defaults to configured year)semester(string, optional) – Filter by semester (defaults to configured semester)q(string, optional) – Search term to filter by student name (LIKE search)date_from(date, optional) – Filter logs from this date (inclusive, format: Y-m-d or any parseable date)date_to(date, optional) – Filter logs until this date (inclusive, format: Y-m-d or any parseable date)page(integer, optional) – Page number for pagination (default: 1)per_page(integer, optional) – Items per page (default: 20, max: 200)- Returns paginated results with logs array, pagination metadata, and applied filters
GET /api/v1/late-slip-logs/{id}(show) – Fetch a single late slip log by ID or404if not found.
Log Fields:
id,school_year,semesterstudent_name,slip_date,time_ingrade,reason,admin_nameprinted_by,printed_at
MessageController
File: app/Http/Controllers/Api/MessageController.php
Purpose: Inbox/sent endpoints with read receipts for the legacy messaging UI.
GET /api/v1/messages– Query paramstype=sent|inboxandread=true|false.GET /api/v1/messages/{id}– Ensures the caller is sender/recipient, marks as read.POST /api/v1/messages– Validatesto,subject,body, auto-incrementsmessage_number.
MessagesController
File: app/Http/Controllers/Api/MessagesController.php
Purpose: Full-featured messaging module with folder management, attachments, and recipient lookup.
Endpoints:
GET /api/v1/messages(index) – Returns role and received messages overview. Includes user role and all received messages with sender information.GET /api/v1/messages/inbox(inbox) – Returns all inbox messages (status='received') for the authenticated user, ordered by sent_datetime DESC.GET /api/v1/messages/sent(sent) – Returns all sent messages (status='sent') for the authenticated user, ordered by sent_datetime DESC.GET /api/v1/messages/drafts(drafts) – Returns all draft messages (status='draft') for the authenticated user, ordered by sent_datetime DESC.GET /api/v1/messages/trash(trash) – Returns all trashed messages (status='trashed') for the authenticated user (both sent and received), ordered by sent_datetime DESC.POST /api/v1/messages(send) – Sends a new message. Body requires:recipient_id(integer) – Recipient user ID, orrecipient_role(string) – Role name to resolve recipient (uses hardcoded mapping: teacher=1, parent=2, admin=3, student=4, guest=5, administrator=6)subject(string, required) – Message subjectmessage(string, required) – Message body- Optional:
priority(string, default: 'normal'),status(string, default: 'sent'),semester,school_year - Optional:
attachment(file upload) – Attachment file - Automatically generates
message_numberin format 'MSG-YYYYMMDDHHMMSS' - Returns created message
POST /api/v1/messages/receive(receive) – Fetches all received messages for the authenticated user and automatically marks them as read. Returns messages with sender information.GET /api/v1/messages/recipients/{type}(getRecipients) – Lists recipients for message composition. Path parametertypemust be 'teacher' or 'parent':teacher– Returns all teachers from teacher_class assignments with their namesparent– Returns all parents (first and second parents) from students in teacher classes, with their names- Returns array of
{id, name}objects, deduplicated by ID
Message Fields:
id,sender_id,recipient_idsubject,messagesent_datetime,read_status,read_datetimemessage_number,priority(normal/high/low)attachment(file path),status(sent/received/draft/trashed)semester,school_year
MessagingController
File: app/Http/Controllers/Api/MessagingController.php
Purpose: Chat-style messaging (“subjectless” chats) with unread counts.
GET /api/v1/messaging/conversations– Lists conversation previews.GET /api/v1/messaging/conversations/{user}– Paginated thread with another user; marks inbound as read.POST /api/v1/messaging/messages– Validatesrecipient_idand body, enforces no self-messaging, records term metadata.- Additional helpers (mark read, unread count, search users, delete) support the chat client.
NavBuilderController
File: app/Http/Controllers/Api/NavBuilderController.php
Purpose: Manage navigation menu items and their role-based access assignments.
Endpoints:
GET /api/v1/nav-builder/data(data) – Returns navigation builder data including:items– Flattened array of all navigation items with hierarchical structure, role assignments, parent relationships, and metadata (label, url, icon_class, target, order, enabled status, depth)roles– Array of all available roles (id, name) for assignmentparentOptions– Alphabetically sorted list of navigation items that can be used as parents (id, label)- Items are sorted alphabetically (case-insensitive, ignoring leading articles and punctuation)
- Requires authentication and admin access (user must have a role that has access to the 'nav-builder' navigation item)
POST /api/v1/nav-builder(save) – Creates or updates a navigation item. Body requires:id(integer, optional) – If provided, updates existing item; otherwise creates newlabel(string, required) – Display label for the menu itemurl(string, optional) – URL path for the menu itemicon_class(string, optional) – CSS class for icontarget(string, optional) – Link target (e.g., '_blank')menu_parent_idorparent_id(integer, optional) – Parent navigation item ID (null for top-level)sort_order(integer, optional) – Sort order (default: 0)is_enabled(boolean, optional) – Whether the item is enabled (default: false)roles(array, optional) – Array of role IDs to assign to this navigation item- Prevents items from being their own parent. Validates parent exists if provided. Clears navigation cache after save.
DELETE /api/v1/nav-builder/{id}(delete) – Deletes a navigation item by ID. Children are handled by foreign key constraints (SET NULL on parent). Clears navigation cache after deletion.POST /api/v1/nav-builder/reorder(reorder) – Reorders navigation items. Body requires:orders(object, required) – Object mapping item IDs to sort orders:{"item_id": sort_order, ...}- Clears navigation cache after reordering.
Access Control:
- All endpoints require authentication (
auth:apimiddleware) - All endpoints require admin access via
ensureAdmin()method which:- Checks that user has at least one role
- Verifies that at least one of the user's roles has access to the 'nav-builder' navigation item (checked via
role_nav_itemstable) - Returns
403 Forbiddenif access is denied
Notes:
- Navigation items are organized hierarchically using
menu_parent_id - Items are sorted alphabetically using natural case-insensitive sorting, ignoring leading articles ("a", "an", "the") and punctuation
- Role assignments are stored in the
role_nav_itemstable linking roles to navigation items - The
clearCache()method is called after save/delete/reorder operations (currently a no-op, placeholder for future caching)
NotificationController
File: app/Http/Controllers/Api/NotificationController.php
Purpose: Retrieve and mark notifications read for the signed-in user.
GET /api/v1/notifications– Paginated feed with optionalread=true|false.GET /api/v1/notifications/{id}– Ensures the caller owns the record.POST /api/v1/notifications/{id}/read– Setsis_read+read_at.
NotificationsController
File: app/Http/Controllers/Api/NotificationsController.php
Purpose: Placeholder for legacy notifications (no public API methods today).
NotificationManagementController
File: app/Http/Controllers/Api/NotificationManagementController.php
Purpose: Admin/management endpoints for creating, sending, and managing notifications to user groups.
Endpoints:
GET /api/v1/notifications/active(activeNotificationsData) – Returns active (non-deleted, non-expired) notifications. Query parameters:target_group(string, optional) – Filter by target group (e.g., 'parent', 'teacher', 'admin')- Returns array of notifications with metadata including
id,title,message,priority,scheduled_at,expires_at,created_at,target_group, andisExpiredflag
GET /api/v1/notifications/deleted(deletedNotificationsData) – Returns soft-deleted notifications. Returns array of deleted notifications withid,title,message,priority,scheduled_at,expires_at, anddeleted_atfields.POST /api/v1/notifications/send(send) – Creates and sends notifications to a target group. Body requires:title(string, required) – Notification titlemessage(string, required) – Notification message contenttarget_group(string, required) – Target role/group (e.g., 'parent', 'teacher', 'admin')channels(array, required) – Array of delivery channels:['in_app', 'email', 'sms']- Creates notification record, creates user notification records for all users in the target group, and sends via specified channels (email/SMS). Returns summary with
notification_id,users_notified,emails_sent, andsms_sentcounts.
POST /api/v1/notifications/{id}/restore(restore) – Restores a soft-deleted notification by ID. Returns success message with notification ID.
Notes:
- All endpoints require authentication (
auth:apimiddleware) - The
sendendpoint usesUserModel::getUsersByRole()to find users in the target group - Email sending uses
EmailServicefor delivery - SMS sending is currently logged only (placeholder for future SMS service integration)
- Active notifications are filtered by
scheduled_at <= NOW()and(expires_at IS NULL OR expires_at > NOW()) - Notifications support soft deletes and can be restored
PageController
File: app/Http/Controllers/Api/PageController.php
Purpose: Handle marketing-site contact submissions and serve static policy/help content.
Endpoints:
GET /api/v1/pages/privacy(privacyPolicy) – Returns privacy policy HTML content frompublic/html/privacy_policy.html. Returns JSON response withcontent(HTML string) andtypefields. Returns error if file is not readable or cannot be loaded.GET /api/v1/pages/terms(termsOfService) – Returns terms of service HTML content frompublic/html/terms_of_service.html. Returns JSON response withcontent(HTML string) andtypefields. Returns error if file is not readable or cannot be loaded.GET /api/v1/pages/help(helpCenter) – Returns help center HTML content frompublic/html/help_center.html. Returns JSON response withcontent(HTML string) andtypefields. Returns error if file is not readable or cannot be loaded.POST /api/v1/pages/contact(submitContact) – Submits contact form. Body requires:email(string, required, valid email) – Contact email addressmessage(string, required, min 10 characters) – Contact message content- Saves message to
contactustable (usesContactUsModelif supported, otherwise falls back to direct DB insert) - Sends email notification to
alrahma.isgl@gmail.comusingEmailService - Returns success response with
emailandemail_sent(boolean) fields - Does not fail the request if email sending fails (logs error instead)
Notes:
- All endpoints are public (no authentication required)
- Static HTML files are read from
public/html/directory - Contact form attempts to use
ContactUsModelbut falls back to direct DB insert if model structure differs - Email sending failures are logged but don't cause the request to fail
ParentAttendanceReportController
File: app/Http/Controllers/Api/ParentAttendanceReportController.php
Purpose: Allow parents to report lateness/absences for their children.
POST /api/v1/parent-attendance-reports– Body includesstudent_ids,date,type, optional arrival/dismiss times/reason.GET /api/v1/parent-attendance-reports– Paginated list filtered by school year.PATCH /api/v1/parent-attendance-reports/{id}– Parents can edit their own submission fields.
ParentController
File: app/Http/Controllers/Api/ParentController.php
Purpose: Backbone for the parent portal (enrollment, emergency contacts, authorized pickups, student CRUD, dashboard metrics, payments view, etc.).
- Examples:
GET /api/v1/parent– Dashboard snapshot (students, balances, notifications).GET /api/v1/parent/enrollment-classes+POST /api/v1/parent/enrollments– Manage enrollment/withdrawal requests.- Emergency contact + authorized user endpoints for CRUD operations.
POST /api/v1/parent/students/PATCH /api/v1/parent/students/{id}– Mirror the flows covered inParentFlowsTest.- Additional helpers (
attendance,payments,events,profile) expose data to the SPA; authorization checks ensure parents only touch their own records.
ParticipationController
File: app/Http/Controllers/Api/ParticipationController.php
Purpose: Manage participation scores for students in class sections.
Endpoints:
GET /api/v1/participation(index) – Returns participation exam data for a class section. Query parameters:class_section_id(integer, optional) – Class section ID (can also be provided via POST or session). If not provided, falls back to session value.- Returns array of students with their participation scores, semester, school year, and class section ID. Uses a join with the student roster and participation table. Students are ordered by lastname, then firstname.
POST /api/v1/participation(update) – Updates participation scores (teacher endpoint). Body requires:final_score(object, required) – Object mapping student IDs to score objects:{"student_id": {"score": float}}class_section_id(integer, optional) – Class section ID (can also be provided via session)- Automatically uses current authenticated user as
updated_by. Updates or creates participation records and triggers semester score recalculation viaSemesterScoreService::updateScoresForStudents().
GET /api/v1/participation/management(showManagement) – Returns participation data for management view. Same asindexbut intended for administrative use. Query parameters:class_section_id(integer, optional) – Class section ID (can also be provided via POST or session)
POST /api/v1/participation/management(updateManagement) – Updates participation scores (management endpoint). Body requires:final_score(object, required) – Object mapping student IDs to score objects:{"student_id": {"score": float}}teacher_id(integer, optional) – Teacher ID to record as updater (defaults to current user)class_section_id(integer, optional) – Class section ID (can also be provided via session)- Returns updated student roster with scores after successful update. Triggers semester score recalculation.
GET /api/v1/participation/student/{id}(getByStudent) – Returns the student's participation entry for the current term.
Notes:
- All endpoints require authentication (
auth:apimiddleware). - Class section ID can be provided via query parameter, POST body, or session (checked in that order).
- Scores are automatically scoped to the configured semester and school year.
- Updates trigger
SemesterScoreService::updateScoresForStudents()to recalculate semester scores. - The system ensures one score record per student per class section per term (updates existing or creates new).
PaymentController
File: app/Http/Controllers/Api/PaymentController.php
Purpose: Comprehensive payment management including CRUD operations, manual payment processing, event charges, and invoice balance management.
Endpoints:
GET /api/v1/payments(index) – Paginated list of payments with optional filters:parent_id,status,page,per_page.GET /api/v1/payments/{id}(show) – Returns a single payment by ID or404if not found.GET /api/v1/payments/parent/{id}(getByParent) – Returns all payments for a specific parent with invoice numbers. Includes parent name in response.POST /api/v1/payments(store) – Creates a new payment plan. Body requires:parent_id(integer, required)total_amount(numeric, required)payment_date(date, required)- Optional:
number_of_installments,payment_type,semester,school_year - Automatically sets
paid_amountto 0,balance_amounttototal_amount, andstatusto 'Pending'.
PATCH /api/v1/payments/{id}(update) – Updates payment fields. Allowed fields:paid_amount,balance,status,payment_method,payment_date,check_number. Requires authentication.DELETE /api/v1/payments/{id}(destroy) – Removes a payment record.POST /api/v1/payments/{id}/update-balance(updateBalance) – Updates balance after payment. Body requirespaid_amount(numeric, required).GET /api/v1/payments/enrolled-students/{parentId}(getEnrolledStudents) – Returns enrolled students for a parent with their grades.GET /api/v1/payments/manual-pay-search(manualPaySearch) – Search for parent by email or phone and retrieve payment data. Query paramsearch_term(required). Returns:parent– Parent user data (excluding password)students– Students associated with the parentpayments– Paginated payment historyinvoices– Invoices with calculated balances (total - paid - discounts - refunds)today_ymd– Current dateinstallment_end_ymd– Installment deadline from configuration
POST /api/v1/payments/manual-pay-update(manualPayUpdate) – Records a manual payment. Body requires:invoice_id(integer, required)amount(numeric, required, must be > 0)payment_method(string, required, one of:cash,check,card)- Optional:
check_number(required if method ischeck),payment_date,payment_file(file upload for receipt) - Card payments must equal the full remaining balance
- Automatically calculates installment sequence, generates transaction ID, updates invoice balance, and triggers enrollment status update if payment is made
- Dispatches
paymentReceivedevent with payment and student data
POST /api/v1/payments/manual-pay-edit(manualPayEdit) – Edits an existing manual payment. Body requires:payment_id(integer, required)paid_amount(numeric, required, must be > 0)payment_method(string, required)- Optional:
check_number(required if method ischeck),payment_file(file upload) - Validates amount doesn't exceed remaining balance (excluding current payment)
- Recalculates invoice after update
GET /api/v1/payments/event-charges(eventChargesShow) – Returns event charges filtered byschool_yearandsemesterquery params. Includes parent and student names. Also returns list of all parents.POST /api/v1/payments/event-charges(eventChargesUpdate) – Creates event charges for students. Body requires:parent_id(integer, required)event_name(string, required)amount(numeric, required)student_ids(array, required) ORstudent_id(integer, required)- Optional:
description,semester,school_year
GET /api/v1/payments/redirect-page(redirectPage) – Returns payment redirect page data for authenticated parent. Includes parent name, total amount from latest invoice, school ID, and PayPal mode.GET /api/v1/payments/check-file/{filename}(serveCheckFile) – Serves payment receipt files (checks, cards, misc). Searches in multiple upload directories. Returns file download or inline view.GET /api/v1/payments/check-file/{filename}/inline– Serves payment file inline (same as above withmode=inline).
Payment Processing Features:
- Automatic invoice balance recalculation after payments
- Installment sequence tracking
- Transaction ID generation
- Enrollment status auto-update when payment is received
- Event dispatching for
paymentReceivedandstudentEnrolledevents - Support for cash, check, and card payment methods
- File upload support for payment receipts (JPG, PNG, PDF, max 5MB)
- Discount and refund calculation in balance computation
- Grade-based tuition calculation (regular vs youth students)
Invoice Balance Calculation:
- Balance =
total_amount-paid_amount-discounts-refund_paid_amount - Automatically recalculates when payments are added/edited
- Considers voided/failed payments
- Handles partial payments and full payments
Notes:
- All endpoints require authentication (
auth:apimiddleware) except file serving endpoints. - Payments are automatically scoped to configured school year and semester.
- Manual payment updates trigger invoice recalculation and enrollment status updates.
- Event charges can be created for multiple students at once.
- Payment files are stored in
storage/app/public/uploads/payments/{checks|cards|misc}/.
PaymentNotificationController
File: app/Http/Controllers/Api/PaymentNotificationController.php
Purpose: Manage payment reminder notifications - view logs and send monthly tuition reminders to parents.
Endpoints:
GET /api/v1/payments/notifications(index) – Returns paginated payment notification logs with optional filters. Query parameters:page(integer, optional, default: 1) – Page number for paginationper_page(integer, optional, default: 20, max: 100) – Number of records per pagefrom(string, optional) – Filter logs sent on or after this dateto(string, optional) – Filter logs sent on or before this datetype(string, optional) – Filter by notification type:no_paymentorinstallment- Returns paginated list of notification logs with parent names included
POST /api/v1/payments/notifications/send(send) – Sends payment reminder notifications. Body parameters:parent_id(integer, optional) – If provided, sends notification to this parent only. If omitted, sends to all parents with positive balancetype(string, optional) – Notification type:no_paymentorinstallment. If not provided, automatically detected based on payment historyschool_year(string, optional) – School year to process (defaults to configured school year)force(integer, optional, default: 0) – Set to1to bypass idempotency check and send even if already sent this month- Returns summary with
sent,skipped,failedcounts and detailed results array
Notification Behavior:
- Single Parent Mode: When
parent_idis provided:- Sends notification only to that parent (if balance > 0 or
force=1) - Skips if already sent this month/type (unless
force=1) - Skips if balance is 0 (unless
force=1)
- Sends notification only to that parent (if balance > 0 or
- Bulk Mode: When
parent_idis omitted:- Processes all parents with invoices in the selected school year
- Sends to parents with positive balance (or all if
force=1) - Respects idempotency (1 email per month/type per parent) unless
force=1 - Optionally notifies head of finance users in-app
Email Content:
- Subject: "Monthly Tuition Reminder — {school_year}"
- Includes:
- Personalized greeting with parent name
- Current outstanding balance
- Remaining installments count
- Suggested installment amount for current month
- Maximum installments available
- Reminder period (month and year)
- Email is sent to primary parent email and CC'd to secondary guardian (if configured and
receive_emails=1)
Balance Calculation:
- Computes total balance across all invoices for parent/school year
- Formula:
total_amount - discounts - paid_amount - refunds - Excludes voided, failed, or cancelled payments
- Rounds to 2 decimal places
Idempotency:
- Prevents duplicate notifications by checking
payment_notification_logstable - One notification per parent per month per type (unless
force=1) - Checks
period_year,period_month,type, andparent_id
Notification Types:
no_payment– Parent has no payment history for the school yearinstallment– Parent has made at least one payment for the school year
Notes:
- All endpoints require authentication (
auth:apimiddleware) - Email sending uses
EmailServicewith 'finance' profile - Notifications are logged in
payment_notification_logstable with full details - Secondary guardian emails are automatically included if they have
receive_emails=1 - Head of finance users are optionally notified in bulk mode (logged for now, can be extended to in-app notifications)
PaymentTransactionController
File: app/Http/Controllers/Api/PaymentTransactionController.php
Purpose: Manage payment-processor transactions linked to payments. Handles creation, retrieval, and status updates for payment transactions (installments).
Endpoints:
GET /api/v1/payment-transactions(index) – Returns paginated list of payment transactions with optional filters. Query parameters:page(integer, optional, default: 1) – Page number for paginationper_page(integer, optional, default: 20, max: 100) – Number of records per pagepayment_id(integer, optional) – Filter transactions by payment IDstatus(string, optional) – Filter transactions by payment status- Returns paginated list of transactions
GET /api/v1/payment-transactions/{id}(show) – Returns a single payment transaction by ID. Returns404if not found.GET /api/v1/payment-transactions/payment/{paymentId}(getByPayment) – Returns all transactions for a specific payment, ordered by transaction date (newest first). Returns404if no transactions found for the payment.POST /api/v1/payment-transactions(store) – Creates a new payment transaction (installment). Body parameters:transaction_id(string, required, unique) – Unique transaction identifierpayment_id(integer, required) – Reference to the payment recordamount(numeric, required, min: 0) – Transaction amountpayment_method(string, required, max: 50) – Payment method (e.g., 'cash', 'check', 'card')transaction_date(string, optional) – Transaction date inY-m-d H:i:sformat (defaults to current date/time)transaction_fee(numeric, optional, min: 0) – Transaction fee (defaults to 0)payment_reference(string, optional, max: 255) – Payment reference numberis_full_payment(integer, optional) – Flag indicating full payment:0for installment,1for full payment (defaults to 0)- Automatically sets
payment_statusto 'Pending' and includes currentschool_yearandsemesterfrom configuration - Returns
201with created transaction data
PATCH /api/v1/payment-transactions/{transactionId}/status(updateStatus) – Updates the payment status of a transaction. Body parameters:status(string, required, max: 50) – New payment status (e.g., 'Pending', 'Completed', 'Failed', 'Refunded')- The
transactionIdcan be either the numericidor the stringtransaction_id - Returns updated transaction data on success,
404if transaction not found
Transaction Data:
- Each transaction is linked to a payment record via
payment_id - Transactions track installment payments and full payments via
is_full_paymentflag - Default status is 'Pending' when created
- Automatically includes
school_yearandsemesterfrom system configuration - Supports transaction fees and payment references
Notes:
- All endpoints require authentication (
auth:apimiddleware) - Transaction IDs must be unique across all transactions
- Status updates can be performed using either the numeric ID or the transaction_id string
- Transactions are ordered by
transaction_datedescending when retrieved by payment ID - The controller uses
PaymentTransactionModelwhich provides helper methods likegetTransactionsByPaymentId()andupdateTransactionStatus()
PaypalTransactionsController
File: app/Http/Controllers/Api/PaypalTransactionsController.php
Purpose: Inspect and export PayPal webhook transaction data stored locally. Provides search, retrieval, and CSV export functionality for PayPal payment transactions.
Endpoints:
GET /api/v1/paypal-transactions(index) – Returns paginated list of PayPal transactions with optional search. Query parameters:page(integer, optional, default: 1) – Page number for paginationper_page(integer, optional, default: 20, max: 100) – Number of records per pageq(string, optional) – Search keyword that searches across multiple fields:transaction_id– PayPal transaction identifierpayer_email– Payer's email addressevent_type– PayPal webhook event typeorder_id– Order identifierparent_school_id– Parent school ID
- Returns paginated list of transactions ordered by creation date (newest first)
GET /api/v1/paypal-transactions/{id}(show) – Returns a single PayPal transaction by numeric ID. Returns404if not found.GET /api/v1/paypal-transactions/transaction/{transactionId}(getByTransactionId) – Returns a transaction by PayPal transaction ID (string). Returns404if not found.GET /api/v1/paypal-transactions/export-csv(exportCsv) – Exports PayPal transactions to CSV file. Query parameters:q(string, optional) – Search keyword (same search logic asindexendpoint)- Returns a downloadable CSV file with filename format:
paypal_transactions_YYYYMMDD_HHMMSS.csv - CSV columns: ID, Transaction ID, Order ID, Parent School ID, Email, Amount, Net Amount, Currency, Status, Event Type, Created At
- Includes all matching transactions (no pagination limit for export)
Search Functionality:
- The search keyword (
qparameter) performs a case-insensitive LIKE search across multiple fields - Uses OR logic - matches if any field contains the keyword
- Searches in:
transaction_id,payer_email,event_type,order_id,parent_school_id
CSV Export:
- Generates CSV file with all matching transactions
- File is streamed directly to the browser for download
- Filename includes timestamp for uniqueness
- Includes all transaction fields relevant for reporting/analysis
- Respects the same search filters as the index endpoint
Transaction Data:
- Transactions are stored from PayPal webhook events
- Includes payment details: amount, currency, fees, net amount
- Tracks payer information: email address
- Contains event metadata: event type, status, order ID
- Linked to parent/school via
parent_school_id - Includes raw webhook payload for reference
Notes:
- All endpoints require authentication (
auth:apimiddleware) - Transactions are ordered by
created_atdescending (newest first) - CSV export returns all matching records without pagination
- The controller uses
PayPalPaymentModelwhich stores webhook data from PayPal - Search is case-insensitive and uses SQL LIKE pattern matching
PaypalWebhook
File: app/Http/Controllers/Api/PaypalWebhook.php
Purpose: Validate and process PayPal webhook notifications.
POST /api/v1/paypal/webhook– Verifies headers + signature, requests an OAuth token, and persists the webhook payload when verification succeeds.
PolicyController
File: app/Http/Controllers/Api/PolicyController.php
Purpose: Serve school and picture policy documents as JSON API responses. Loads policy content from PHP partial files and renders them using Blade views.
Endpoints:
GET /api/v1/policy(index) – Placeholder endpoint that returns a success response. Can be used to check if the policy API is available.GET /api/v1/policy/picture(schoolPicturePolicy) – Returns the school picture policy content.- Loads content from
resources/views/policy/picture_policy_partial.php(PHP file that may return data array or output HTML) - If the partial returns an array, attempts to render
resources/views/policy/picture_policy.blade.phpview with that data - If the partial returns HTML string, uses it directly
- Returns JSON response with
htmlfield containing the rendered policy content - Returns
404if the partial file is not found
- Loads content from
GET /api/v1/policy/school(schoolPolicy) – Returns the main school policy content.- Loads metadata from
resources/views/policy/school_policy_partial.php(PHP file that returns data array) - Renders
resources/views/policy/school_policy.blade.phpBlade view with the metadata - Returns JSON response with both
meta(data array) andhtml(rendered content) fields - Returns
404if the partial file is not found - Falls back to JSON-encoded meta if the Blade view doesn't exist
- Loads metadata from
Policy File Structure:
- Partial files (
.php) are included and expected to return data arrays or HTML strings - Blade views (
.blade.php) are rendered with the data from partial files - Partial files are located in
resources/views/policy/directory
Response Format:
- All endpoints return JSON with standard API response format:
{status: true, message: "...", data: {...}} - Picture policy returns:
{html: "<rendered HTML>"} - School policy returns:
{meta: {...}, html: "<rendered HTML>"}
Notes:
- All endpoints are public (no authentication required)
- Policy files are read from the filesystem at runtime
- Errors are logged and return appropriate HTTP status codes (404 for not found, 500 for server errors)
- The controller handles both array and string returns from PHP partial files for flexibility
PreferencesController
File: app/Http/Controllers/Api/PreferencesController.php
Purpose: Let users adjust notification + UI preferences.
GET /api/v1/preferences– Retrieves or falls back to defaults; includes currentstyle_color/menu_color.PATCH /api/v1/preferences– Validates toggles and theme selections, persists them, updates session colors.
PrintablesReportsController
File: app/Http/Controllers/Api/PrintablesReportsController.php
Purpose: Provide report-card metadata, badge printing, sticker generation, and student data for printable reports. Handles metadata retrieval, badge print logging, and sticker count calculations.
Endpoints:
GET /api/v1/printables/report-card-meta(reportCardMeta) – Returns available school years, students, and class sections for report generation. Query parameters:school_year(string, optional) – Filter by school year (defaults to configured school year)semester(string, optional) – Filter by semester (defaults to configured semester)- Returns:
schoolYears– Array of available school yearsselectedYear– Currently selected school yearsemesters– Array of available semesters for selected yearselectedSemester– Currently selected semesterstudents– Array of students with scores in selected year/semester (or all students if none found)classSections– Array of class sections for selected year
GET /api/v1/printables/badge-status(badgePrintStatus) – Returns badge print status for given users. Query parameters:user_ids(array|string, required) – User IDs (can be comma-separated string or array)school_year(string, optional) – Filter by school year- Returns object mapping user IDs to print status:
{count, last_printed_at, last_printed_by}
POST /api/v1/printables/badge-status(logBadgePrint) – Logs badge prints for users. Body parameters:user_ids(array, required) – Array of user IDsroles(array, optional) – Map of user_id => role labelclasses(array, optional) – Map of user_id => class nameschool_year(string, optional) – School year for the prints- Returns count of inserted log records
GET /api/v1/printables/students-by-class/{classSectionId}(getByClass) – Returns students in a class section. Returns array of students with id, firstname, lastname, registration_grade, and gender.GET /api/v1/printables/students-by-class/{classSectionId}/alt(studentsByClass) – Alternative endpoint for students by class with additional class section name in response.GET /api/v1/printables/preview-sticker-counts(previewStickerCounts) – Returns sticker counts per student. Query parameters:class_id(integer, optional) – If provided, returns counts for that class only; otherwise returns for entire school year- Returns:
students– Array of students withprimary_countandsecondary_countsticker requirementstotals– Summary totals for primary, secondary, and student counts
POST /api/v1/printables/badge(badge) – Generates staff badge PDF. Note: Requires FPDF library integration (not yet implemented).POST /api/v1/printables/generate-stickers(generateStickers) – Generates student name sticker PDF. Note: Requires FPDF library integration (not yet implemented).GET /api/v1/printables/report-card/{studentId}(generateSingleReport) – Generates single student report card PDF. Note: Requires FPDF library integration (not yet implemented).GET /api/v1/printables/report-card/class/{classSectionId}(generateClassReport) – Generates report cards for all students in a class. Note: Requires FPDF library integration (not yet implemented).
Sticker Count Rules:
- Special grades: KG (1), 1-A (3), 1-B (4), 2-A (5), 2-B (5), 9 (2)
- Upper block (3-8): New students (4), Grade 5 returning (3), Other returning (2)
- Other grades: Default (4)
- Youth and KG classes are excluded from sticker calculations
Badge Print Logging:
- Tracks which users had badges printed, when, and by whom
- Supports role and class metadata for each print
- Can filter by school year
- Used for audit and tracking purposes
Notes:
- All endpoints require authentication (
auth:apimiddleware) - PDF generation endpoints (
badge,generateStickers,generateSingleReport,generateClassReport) require FPDF library integration and are currently placeholders - Sticker counts follow specific rules based on grade level and student status (new vs returning)
- Report card metadata automatically falls back to all students if none found for selected year/semester
- School years are collected from both
classSectionandsemester_scorestables
ProjectController
File: app/Http/Controllers/Api/ProjectController.php
Purpose: Manage project scores for students, similar to homework and participation. Provides endpoints for teachers to add project columns, update scores, and view project data for their class sections.
Endpoints:
GET /api/v1/projects(index) – List projects with optional filters. Query parameters:page(integer, optional) – Page number for pagination (default: 1)per_page(integer, optional) – Items per page (default: 20, max: 100)student_id(integer, optional) – Filter by student IDclass_section_id(integer, optional) – Filter by class section ID- Returns paginated list of projects for the current semester and school year
GET /api/v1/projects/{id}(show) – Get a single project by ID. Returns project details or 404 if not found.GET /api/v1/projects/student/{id}(getByStudent) – Get all projects for a specific student. Returns array of projects ordered byproject_indexfor the current semester and school year.POST /api/v1/projects(store) – Create a new project entry. Body parameters:student_id(integer, required) – Student IDclass_section_id(integer, required) – Class section IDproject_index(integer, required) – Project index/column numberscore(float, optional) – Project scorecomment(string, optional) – Project comment- Returns created project with 201 status
PATCH /api/v1/projects/{id}(update) – Update an existing project. Body parameters (all optional):score(float) – Project scorecomment(string) – Project commentproject_index(integer) – Project index/column number- Returns updated project
GET /api/v1/projects/add-project(addProject) – Get project data for teacher's class section. Automatically determines class section from teacher'steacher_classrecord. Returns:students– Array of students with their project scores organized by project indexproject_headers– Array of project index values (column headers)semester– Current semesterschool_year– Current school yearclass_section_id– Class section ID
POST /api/v1/projects/update-scores(updateProjectScores) – Update project scores for multiple students. Body parameters:scores(array, required) – Nested array:{student_id: {project_index: score}}class_section_id(integer, optional) – Class section ID (falls back to session)- Automatically updates semester scores via
SemesterScoreServiceafter saving - Returns success message
POST /api/v1/projects/add-column(addNextProjectColumn) – Add a new project column for all students in a class section. Body parameters:class_section_id(integer, optional) – Class section ID (falls back to session)- Creates a new project index (highest existing + 1) and inserts empty project records for all students
- Returns:
status– "success"project_index– The new project index that was createdstudents_processed– Number of students for whom records were created
GET /api/v1/projects/management(showProjectMngt) – Get project management data for a class section. Query/body parameters:class_section_id(integer, optional) – Can be provided via POST body, GET query, or session- Returns:
project_scores– Project scores organized by student IDstudents– Array of students in the class sectionproject_headers– Array of project index valuessemester– Current semesterschool_year– Current school yearclass_section_id– Class section ID
POST /api/v1/projects/update(updateProject) – Update project scores (management endpoint). Body parameters:scores(array, required) – Nested array:{student_id: {project_index: score}}student_ids(array, required) – Array of student IDssemester(string, optional) – Semester (defaults to current)school_year(string, optional) – School year (defaults to current)teacher_id(integer, optional) – Teacher ID (defaults to current user)class_section_id(integer, optional) – Class section ID (falls back to session)- Automatically updates semester scores via
SemesterScoreServiceafter saving - Returns success message
Notes:
- All endpoints require authentication (
auth:apimiddleware) - Project scores are automatically scoped to the current semester and school year from configuration
- When updating scores, the system automatically recalculates semester scores using
SemesterScoreService - Project indices are numeric and represent column numbers in the grading interface
- The
add-projectendpoint automatically determines the teacher's class section from theteacher_classtable - Session is used to persist
class_section_idfor subsequent requests
PurchaseOrderController
File: app/Http/Controllers/Api/PurchaseOrderController.php
Purpose: Create and track purchase orders plus their line items. Handles PO creation, receiving items, and cancellation.
Endpoints:
GET /api/v1/purchase-orders(index) – Paginated list of purchase orders with keyword search. Query parameters:page(integer, optional) – Page number for pagination (default: 1)per_page(integer, optional) – Items per page (default: 20, max: 100)q(string, optional) – Keyword search for PO number or supplier name- Returns paginated list with supplier names joined
GET /api/v1/purchase-orders/{id}(show) – Get a single purchase order with all line items. Returns:- Purchase order header with supplier name
- Array of line items with supply names and units (if supply_id maps to inventory_items)
- Returns 404 if not found
POST /api/v1/purchase-orders(store) – Create a new purchase order with line items. Supports both CodeIgniter-style form arrays and modern JSON format. Body parameters:po_number(string, required) – Purchase order numbersupplier_id(integer, required) – Supplier IDorder_date(date, required) – Order date (Y-m-d format)expected_date(date, optional) – Expected delivery datestatus(string, optional) – Status: 'draft' or 'ordered' (default: 'ordered')notes(string, optional) – Notestax(float, optional) – Tax amount (default: 0.00)- Modern JSON format:
items(array, required) – Array of item objects:supply_id(integer, required) – Supply/inventory item IDdescription(string, optional) – Item descriptionquantity(integer, required) – Quantity orderedunit_cost(float, required) – Unit cost
- CodeIgniter-style form arrays:
item_supply_id[](array, required) – Array of supply IDsitem_description[](array, optional) – Array of descriptionsitem_quantity[](array, required) – Array of quantitiesitem_unit_cost[](array, required) – Array of unit costs
- Automatically calculates subtotal, total, and creates all line items in a transaction
- Returns created purchase order with 201 status
PATCH /api/v1/purchase-orders/{id}(update) – Update purchase order fields. Body parameters (all optional):status(string) – New statusexpected_date(date) – Expected delivery datenotes(string) – Notes- Returns updated purchase order
POST /api/v1/purchase-orders/{id}/receive(receive) – Receive items (partial or full) from a purchase order. Body parameters:received(array, required) – Object mapping item IDs to quantities:{item_id: quantity}- Updates
received_qtyon purchase order items - Updates inventory item quantities (if
supply_idmaps toinventory_items) - Creates inventory movement records for tracking
- Automatically sets PO status to 'received' if all items are fully received, otherwise keeps 'ordered'
- Cannot receive items if PO status is 'canceled' or 'received'
- Returns success message indicating full or partial receipt
POST /api/v1/purchase-orders/{id}/cancel(cancel) – Cancel a purchase order. Body parameters: none- Sets PO status to 'canceled'
- Cannot cancel a PO with status 'received'
- Returns updated purchase order
Notes:
- All endpoints require authentication (
auth:apimiddleware) - Purchase orders support statuses: 'draft', 'ordered', 'received', 'canceled'
- When receiving items, the system automatically updates inventory quantities and creates movement records
- The
storemethod supports both legacy CodeIgniter form array format and modern JSON format for backward compatibility - Line items are validated to ensure at least one valid item with quantity > 0
- All financial calculations (subtotal, tax, total) are performed automatically
- Database transactions ensure data consistency when creating POs or receiving items
QuizController
File: app/Http/Controllers/Api/QuizController.php
Purpose: Manage quiz scores for students, similar to homework and projects. Provides endpoints for teachers to add quiz columns, update scores, and view quiz data for their class sections.
Endpoints:
GET /api/v1/quizzes(index) – List quizzes with optional filters. Query parameters:page(integer, optional) – Page number for pagination (default: 1)per_page(integer, optional) – Items per page (default: 20, max: 100)student_id(integer, optional) – Filter by student IDclass_section_id(integer, optional) – Filter by class section ID- Returns paginated list of quizzes for the current semester and school year
GET /api/v1/quizzes/{id}(show) – Get a single quiz by ID. Returns quiz details or 404 if not found.GET /api/v1/quizzes/student/{id}(getByStudent) – Get all quizzes for a specific student. Returns array of quizzes ordered byquiz_indexfor the current semester and school year.POST /api/v1/quizzes(store) – Create a new quiz entry. Body parameters:student_id(integer, required) – Student IDclass_section_id(integer, required) – Class section IDquiz_index(integer, required) – Quiz index/column numberscore(float, optional) – Quiz scorecomment(string, optional) – Quiz comment- Returns created quiz with 201 status
PATCH /api/v1/quizzes/{id}(update) – Update an existing quiz. Body parameters (all optional):score(float) – Quiz scorecomment(string) – Quiz commentquiz_index(integer) – Quiz index/column number- Returns updated quiz
GET /api/v1/quizzes/add-quiz(addQuiz) – Get quiz data for teacher's class section. Query/body parameters:class_section_id(integer, optional) – Can be provided via POST body, GET query, or session- Returns:
students– Array of students with their quiz scores organized by quiz indexquiz_headers– Array of quiz index values (column headers)semester– Current semesterschool_year– Current school yearclass_section_id– Class section ID
POST /api/v1/quizzes/update-scores(updateQuizScores) – Update quiz scores for multiple students. Body parameters:scores(array, required) – Nested array:{student_id: {quiz_index: score}}or{student_id: score}(normalized to quiz_index 1)class_section_id(integer, optional) – Class section ID (falls back to session)- Automatically updates semester scores via
SemesterScoreServiceafter saving - Returns success message
POST /api/v1/quizzes/add-column(addNextQuizColumn) – Add a new quiz column for all students in a class section. Body parameters:class_section_id(integer, optional) – Class section ID (falls back to session)- Creates a new quiz index (highest existing + 1) and inserts empty quiz records for all students
- Returns:
status– "success"quiz_index– The new quiz index that was creatednew_quiz_id– ID of the first inserted quiz recordstudents_processed– Number of students for whom records were created
GET /api/v1/quizzes/management(showQuizMngt) – Get quiz management data for a class section. Query/body parameters:class_section_id(integer, optional) – Can be provided via POST body, GET query, or session- Returns:
quiz_scores– Quiz scores organized by student IDstudents– Array of students in the class sectionquiz_headers– Array of quiz index valuessemester– Current semesterschool_year– Current school yearclass_section_id– Class section ID
POST /api/v1/quizzes/update(updateQuiz) – Update quiz scores (management endpoint). Body parameters:scores(array, required) – Nested array:{student_id: {quiz_index: score}}student_ids(array, required) – Array of student IDssemester(string, optional) – Semester (defaults to current)school_year(string, optional) – School year (defaults to current)teacher_id(integer, optional) – Teacher ID (defaults to current user)class_section_id(integer, optional) – Class section ID (falls back to session)- Automatically updates semester scores via
SemesterScoreServiceafter saving - Returns success message
Notes:
- All endpoints require authentication (
auth:apimiddleware) - Quiz scores are automatically scoped to the current semester and school year from configuration
- When updating scores, the system automatically recalculates semester scores using
SemesterScoreService - Quiz indices are numeric and represent column numbers in the grading interface
- The
update-scoresendpoint normalizes single score inputs to quiz_index 1 for backward compatibility - Session is used to persist
class_section_idfor subsequent requests - Quiz data is organized by student with scores mapped to quiz indices for easy grid display
RefundController
File: app/Http/Controllers/Api/RefundController.php
Purpose: Collect and manage refund requests tied to invoices.
GET /api/v1/refunds/GET /api/v1/refunds/{id}– Filter byparent_idorstatuswhen reviewing requests.POST /api/v1/refunds– Auth-required; body must includeparent_id,invoice_id,refund_amount,reason.PATCH /api/v1/refunds/{id}– Update status, payout amounts/methods, or notes; stamps approval/refunded timestamps when applicable.
RegisterController
File: app/Http/Controllers/Api/RegisterController.php
Purpose: Public registration portal for parents/guests, including CAPTCHA and confirmation email handling. Handles user registration with validation, role assignment, optional second parent information, and email confirmation.
Endpoints:
GET /api/v1/register(index) – Generate or retrieve CAPTCHA challenge for registration form. Returns:captcha_question– Random CAPTCHA string (4-8 characters) stored in session- If CAPTCHA already exists in session, returns existing value
- Used to prevent automated registrations
GET /api/v1/register/success(registrationSuccess) – Get registration success data. Returns:email– Email address from registration session- Returns 400 error if no registration session exists
- Used to display confirmation screen after successful registration
POST /api/v1/register(register) – Submit registration form. Body parameters:- Required fields:
firstname(string, required) – First name (2-30 chars, letters/spaces/hyphens only)lastname(string, required) – Last name (2-30 chars, letters/spaces/hyphens only)gender(string, required) – Gender: 'Male' or 'Female'email(string, required) – Email address (max 50 chars, valid email format)confirm_email(string, required) – Must matchemailcellphone(string, required) – Phone number (10-20 chars, digits/spaces/hyphens/parentheses/dots)city(string, required) – City name (2-30 chars, letters/spaces only)state(string, required) – State code: 'CT', 'ME', 'MA', 'NH', 'NY', 'RI', or 'VT'zip(string, required) – ZIP code (exactly 5 digits)accept_school_policy(boolean/string, required) – Must be accepted/checkedcaptcha(string, required) – CAPTCHA answer (4-10 alphanumeric chars, must match session)
- Optional fields:
address_street(string, optional) – Street address (max 150 chars)apt(string, optional) – Apartment/unit number (max 10 chars)is_parent(boolean/string, optional) – If '1' or true, registers as parent; otherwise registers as guestno_second_parent_info(boolean/string, optional) – If '1' or true, skips second parent information
- Second parent fields (required if
is_parentis true andno_second_parent_infois false):second_firstname(string, required) – Second parent first namesecond_lastname(string, required) – Second parent last namesecond_gender(string, required) – Second parent gender: 'Male' or 'Female'second_email(string, required) – Second parent email addresssecond_cellphone(string, required) – Second parent phone number
- Process:
- Validates all input fields
- Checks CAPTCHA answer against session
- Verifies email is not already registered (checks for pending activation)
- Determines role ('parent' or 'guest') based on
is_parentflag - Generates unique token for email confirmation
- Creates user record with formatted data
- Assigns role to user
- Optionally creates second parent record if applicable
- Sends confirmation email with activation link
- Stores email in session and clears CAPTCHA
- Returns:
- Success:
{email: "user@example.com"}with 200 status - Validation errors: 422 with error details
- Duplicate email: 409 with appropriate message
- Server errors: 500 with error message
- Success:
- Required fields:
Notes:
- All endpoints are public (no authentication required)
- CAPTCHA is stored in session and must be answered correctly
- Email addresses are normalized to lowercase
- Phone numbers are formatted using
PhoneFormatterService - Names and addresses are formatted (proper case)
- School ID is auto-generated using
SchoolIdService - Users are created with
is_verified = 0andstatus = 'Inactive'until email confirmation - Activation link format:
/user/confirm/{token} - Second parent information is optional for parent registrations
- All database operations are wrapped in transactions for data integrity
- Email confirmation is sent using
EmailServicewith different templates for parents vs. guests
ReimbursementController
File: app/Http/Controllers/Api/ReimbursementController.php
Purpose: Track reimbursements for staff expenses.
GET /api/v1/reimbursements/{id}– Scoped to the active school year/semester; filter bystatusorreimbursed_to.POST /api/v1/reimbursements– Requiresamount,reimbursed_to,description, andexpense_id.PATCH /api/v1/reimbursements/{id}– Update status/method/check information, stamping approver metadata.
RFIDController
File: app/Http/Controllers/Api/RFIDController.php
Purpose: Process RFID scans and expose scan history.
POST /api/v1/rfid/process– Validates the incomingrfid, finds the matching user or student, logs toscan_log, and returns the resolved entity.GET /api/v1/rfid/logs– Paginated log with associated user/student names and timestamps.
RolePermissionController
File: app/Http/Controllers/Api/RolePermissionController.php
Purpose: Admin tooling for roles, permissions, and assignments. Provides CRUD operations for roles and permissions, role-permission mapping, and user role assignment.
Endpoints:
- Roles:
GET /api/v1/rolepermission/roles(roles) – List all roles with user counts. Returns array of roles with:id– Role IDname– Role namedescription– Role descriptionuser_count– Number of users with this role
GET /api/v1/rolepermission/roles/{id}(showRole) – Get a single role by ID. Returns role details or 404 if not found.POST /api/v1/rolepermission/roles(storeRole) – Create a new role. Body parameters:name(string, required) – Role name (3-255 chars, lowercase stored)slug(string, optional) – URL-friendly slug (max 64 chars, auto-generated from name if not provided)description(string, optional) – Role description (max 500 chars, lowercase stored)dashboard_route(string, required) – Dashboard route path (lowercase, alphanumeric/underscores/slashes/hyphens only)priority(integer, required) – Priority value (0-100000)is_active(integer, required) – Active status: 0 or 1- Returns created role with 201 status
PATCH /api/v1/rolepermission/roles/{id}(updateRole) – Update an existing role. Body parameters (all optional):name(string) – Role nameslug(string) – Role slugdescription(string) – Role descriptiondashboard_route(string) – Dashboard routepriority(integer) – Priority valueis_active(integer) – Active status- Returns updated role
DELETE /api/v1/rolepermission/roles/{id}(deleteRole) – Delete a role. Returns success message or 404 if not found.
- Permissions:
GET /api/v1/rolepermission/permissions(permissions) – List all permissions. Returns array of permissions with:id– Permission IDname– Permission namedescription– Permission descriptioncreated_at– Creation timestampupdated_at– Update timestamp
POST /api/v1/rolepermission/permissions(storePermission) – Create a new permission. Body parameters:name(string, required) – Permission namedescription(string, optional) – Permission description- Returns created permission with 201 status, or existing permission if name already exists
PATCH /api/v1/rolepermission/permissions/{id}(updatePermission) – Update a permission. Body parameters (all optional):name(string) – Permission namedescription(string) – Permission description- Returns updated permission
DELETE /api/v1/rolepermission/permissions/{id}(deletePermission) – Delete a permission. Returns success message or 404 if not found.
- Role Permissions:
GET /api/v1/rolepermission/roles/{roleId}/permissions(rolePermissions) – Get permissions for a specific role. Returns:role– Role detailspermissions– All available permissionsrole_permissions– Object mapping permission IDs to CRUD flags:{permission_id: {can_create, can_read, can_update, can_delete}}
POST /api/v1/rolepermission/roles/{roleId}/permissions(saveRolePermissions) – Save role permissions. Body parameters:permissions(object, required) – Object mapping permission IDs to CRUD flags:{permission_id: {create: boolean, read: boolean, update: boolean, delete: boolean}}- Updates existing permissions, creates new ones, and removes permissions not in the payload
- Returns success message
- User Role Assignment:
GET /api/v1/rolepermission/users(users) – Get all users with their assigned roles. Returns:users– Array of users, each with:id– User IDfirstname– First namelastname– Last nameemail– Email addressaccount_id– Account IDroles– Array of role names assigned to the user
POST /api/v1/rolepermission/users/{userId}/roles(assignRole) – Assign roles to a user. Body parameters:role_ids(array, required) – Array of role IDs to assign- Replaces all existing roles for the user with the provided roles
- Automatically updates staff record if user has staff roles
- Generates unique staff email if needed
- Returns success message
GET /api/v1/rolepermission/admins(admins) – Get all admin users. Returns array of users with admin role.
Notes:
- All endpoints require authentication (
auth:apimiddleware) - Role names and descriptions are stored in lowercase for consistency
- Slugs are auto-generated from role names if not provided, normalized to lowercase with underscores
- Slug uniqueness is enforced (appends
_2,_3, etc. if duplicates exist) - When assigning roles to users, the system automatically updates the
stafftable if the user has staff roles (excluding parent/student/guest) - Staff email addresses are auto-generated using firstname + lastname pattern with uniqueness checks
- Role permissions use CRUD flags (can_create, can_read, can_update, can_delete) for fine-grained access control
- All role/permission assignments are wrapped in database transactions for data integrity
- User role assignments completely replace existing roles (not additive)
RoleSwitcherController
File: app/Http/Controllers/Api/RoleSwitcherController.php
Purpose: Allow users with multiple roles to view available roles and switch between them. Provides endpoints to retrieve user roles and switch the active role in the session.
Endpoints:
GET /api/v1/role-switcher(index) – Get available roles for the current authenticated user. Returns:roles– Array of role names assigned to the userauto_redirect– Boolean flag indicating if user has only one role (true) or multiple roles (false)route– Dashboard route for the role (only present whenauto_redirectis true)role– Role name (only present whenauto_redirectis true)current_role– Currently active role from session (only present whenauto_redirectis false)- If user has only one role, returns
auto_redirect: truewith the route to automatically redirect - If user has multiple roles, returns
auto_redirect: falsewith all available roles - Returns 404 if no roles are assigned to the user
POST /api/v1/role-switcher/switch(switchRole) – Switch to a specific role using role name/slug in request body. Body parameters:role(string, required) – Role name or slug to switch to- Validates that the user has the requested role
- Sets
active_rolein session - Returns:
role– The role name that was switched toroute– Dashboard route for the role (fromRoleModel::getRouteByNameOrSlug)message– Success message
- Returns 403 if user does not have the requested role
POST /api/v1/role-switcher/switch/{role}(switchTo) – Switch to a specific role using role name/slug in URL parameter. Same behavior asswitchRolebut accepts role as URL parameter instead of request body.
Notes:
- All endpoints require authentication (
auth:apimiddleware) - Role matching is case-insensitive and works with both role names and slugs
- Dashboard routes are retrieved from the
rolestable usingRoleModel::getRouteByNameOrSlug() - Default route is
/landing_page/guest_dashboardif no route is found for the role - Session stores the active role as
active_rolefor use by other parts of the application - The controller loads semester and school year from configuration but doesn't use them in the current implementation (available for future use)
SchoolCalendarController
File: app/Http/Controllers/Api/SchoolCalendarController.php
Purpose: Manage school calendar events with CRUD operations and audience-specific views. Supports filtering by school year and semester, and provides formatted calendar views for parents, teachers, and administrators.
Endpoints:
GET /api/v1/school-calendar(index) – Get calendar events filtered by school year and optional semester. Query parameters:school_year(optional) – Filter by school year (defaults to configured school year)semester(optional) – Filter by semester- Returns array of events with
school_yearandsemestermetadata
GET /api/v1/school-calendar/{id}(show) – Get a single calendar event by ID. Returns 404 if not found.POST /api/v1/school-calendar(store) – Create a new calendar event. Body parameters:title(string, required) – Event title (minimum 3 characters)start(string, required) – Event date in Y-m-d formatdescription(string, optional) – Event descriptionnotify_parent(boolean, optional) – Whether to notify parents (default: false)notify_teacher(boolean, optional) – Whether to notify teachers (default: false)notify_admin(boolean, optional) – Whether to notify admins (default: false)no_school(boolean, optional) – Whether this is a no-school day (default: false)school_year(string, optional) – School year (defaults to configured school year)semester(string, optional) – Semester (defaults to configured semester)- Returns created event with 201 status
PATCH /api/v1/school-calendar/{id}(update) – Update an existing calendar event. Body parameters (all optional):title(string) – Event title (minimum 3 characters if provided)start(string) – Event date in Y-m-d formatdescription(string) – Event descriptionnotify_parent(boolean) – Whether to notify parentsnotify_teacher(boolean) – Whether to notify teachersnotify_admin(boolean) – Whether to notify adminsno_school(boolean) – Whether this is a no-school dayschool_year(string) – School yearsemester(string) – Semester- Returns updated event
DELETE /api/v1/school-calendar/{id}(delete) – Delete a calendar event. Returns success message or 404 if not found.GET /api/v1/school-calendar/view/parent(calendarParentView) – Get calendar events formatted for parent view. Returns FullCalendar-compatible format with:- Events filtered by audience visibility rules
- No-school events highlighted in yellow (#ffc107)
- Extended properties including notification flags and metadata
GET /api/v1/school-calendar/view/teacher(calendarTeacherView) – Get calendar events formatted for teacher view. Returns FullCalendar-compatible format with:- Events filtered by audience visibility rules
- No-school events highlighted in yellow (#ffc107)
- Staff-only events (visible to teachers/admins but not parents) highlighted in green (#28a745)
- Extended properties including notification flags and metadata
GET /api/v1/school-calendar/view/admin(calendarAdminView) – Get calendar events formatted for admin view. Returns FullCalendar-compatible format with:- Events filtered by audience visibility rules
- Staff-only events highlighted in green (#28a745)
- Extended properties including notification flags and metadata
Notes:
- All endpoints require authentication (
auth:apimiddleware) - Events are filtered by the configured school year by default
- Audience visibility rules:
- If no notification checkboxes are selected (all
notify_*= 0), events are visible to everyone - If notification checkboxes are selected, events are only visible to the selected audience
- Events marked as
no_schoolare always visible to all audiences
- If no notification checkboxes are selected (all
- FullCalendar view endpoints format events with:
id– Event IDtitle– Event title (with "no school" phrase title-cased if applicable)start– Event date (FullCalendar expects 'start' field)description– Event descriptionextendedProps– Object containing semester, school_year, notification flags, no_school flag, and backgroundColor
- The controller uses the
datefield in the database (notstart_date) - School year and semester are loaded from configuration on controller construction
ScoreCommentController
File: app/Http/Controllers/Api/ScoreCommentController.php
Purpose: Manage score comments for students across different score types (PTAP, midterm, final). Supports saving comments, updating comments and reviews, and retrieving comments for students or class sections.
Endpoints:
POST /api/v1/score-comments(save) – Save comments for multiple students. Body parameters:comments(object, required) – Object mapping student IDs to score types to comments:{student_id: {score_type: "comment text"}}subject_id(integer, required) – Subject IDsemester(string, optional) – Semester (defaults to session semester or configured semester)- Score types are normalized to lowercase (ptap, midterm, final)
- Uses upsert logic: updates existing comments or creates new ones
- Returns array of saved comments
- Returns 207 (Partial Content) if some comments failed to save, with
savedanderrorsarrays
POST /api/v1/score-comments/update(updateComments) – Update comments and reviews for multiple students. Body parameters:comments(object, required) – Object mapping student IDs to score types to comment textreviews(object, optional) – Object mapping student IDs to score types to review text (only processed if user is a reviewer)semester(string, optional) – Semester (defaults to configured semester)school_year(string, optional) – School year (defaults to configured school year)teacher_id(integer, optional) – Teacher ID (defaults to current user ID)- Only users with reviewer roles (from
comment_reviewerconfig) can update reviews - Returns array of updated comments
- Returns 207 (Partial Content) if some comments failed to update
GET /api/v1/score-comments/management(viewCommentsMngt) – Get comments management view data for a class section. Query/body parameters:class_section_id(integer, required) – Class section ID (can be in query string, request body, or session)- Returns:
students– Array of students in the class section (id, firstname, lastname, school_id)comments– Object mapping student IDs to score types to comment data:{student_id: {score_type: {comment, comment_review, commented_by, reviewed_by}}}semester– Current semesterschool_year– Current school yearclass_section_id– Class section ID
- Only loads comments for score types: ptap, midterm, final
- Stores
class_section_idin session for future requests
GET /api/v1/score-comments/student/{studentId}(getByStudent) – Get comments for a specific student. Query parameters:subject_id(integer, optional) – Filter by subject IDscore_type(string, optional) – Filter by score type- Returns comments filtered by current school year and semester
PATCH /api/v1/score-comments/{id}(update) – Update a single comment by ID. Body parameters:comment(string, required) – Updated comment text- Returns updated comment
Notes:
- All endpoints require authentication (
auth:apimiddleware) - Comments are scoped to school year and semester
- Score types are normalized to lowercase: 'ptap', 'midterm', 'final'
- Reviewer functionality:
- Reviewer roles are configured in the
configurationtable with keycomment_reviewer - Value should be a comma-separated list of role names (e.g., "administrator,head_of_department")
- Only reviewers can update
comment_reviewandreviewed_byfields - Reviewer check is case-insensitive
- Reviewer roles are configured in the
- The
save()method uses semester from session if available, otherwise falls back to configured semester - Comments use upsert logic: if a comment exists for the same student/subject/score_type/semester/school_year combination, it's updated; otherwise, a new record is created
- Empty comment strings are skipped during save operations
- The management endpoint returns students ordered by lastname, then firstname
ScoreController
File: app/Http/Controllers/Api/ScoreController.php
Purpose: Manage student scores for teachers and parents. Provides comprehensive score calculation, retrieval, and update functionality for homework, quizzes, projects, midterm exams, final exams, attendance, and semester scores.
Endpoints:
GET /api/v1/scores(index) – Get student scores for teacher's class section. Returns:students– Array of students with all their scores (homework, quiz, project, midterm, final_exam, attendance, ptap, semester_score)teacher_name– Name of the teacherclass_section_id– Class section IDclass_section_name– Name of the class sectionmains_text– Main teachers assigned to the sectiontas_text– Teaching assistants assigned to the sectionactive_semester– Active semester (fall/spring)- Automatically refreshes semester scores via SemesterScoreService
- Students are sorted by lastname, then firstname
- Returns 404 if teacher has no assigned class
GET /api/v1/scores/student/{studentId}(getByStudent) – Get scores for a specific student. Returns semester scores filtered by current school year and semester.GET /api/v1/scores/parent-view(viewStudentScore) – Get student scores for parent view. Query parameters:school_year(optional) – Filter by school year (defaults to configured school year)- Returns:
organized_scores– Scores organized by school year, semester, and student IDschool_years– Available school years from semester_scoresselected_year– Selected school yearselected_semester– Selected semester
- Handles primary, secondary, and tertiary parent user types
- Returns scores for all students linked to the parent
POST /api/v1/scores/update(updateScores) – Generic method to update scores for various types. Body parameters:table(string, required) – Table type: 'final_exam', 'midterm_exam', 'quiz', etc.final_score(object, required) – Object mapping student IDs to score data:{student_id: {score: float, quiz_index?: int}}class_section_id(integer, optional) – Class section ID (defaults to session value)- Uses upsert logic: updates existing records or creates new ones
- Automatically triggers semester score recalculation for Spring final exams
- Returns count of updated students
POST /api/v1/scores/update-final-exam(updateFinalExamScores) – Update final exam scores. Same asupdateScoreswith table='final_exam'.POST /api/v1/scores/update-midterm(updateMidtermScores) – Update midterm exam scores. Same asupdateScoreswith table='midterm_exam'.POST /api/v1/scores/recalculate(recalculate) – Recalculate scores for students. Body parameters:class_section_id(integer, optional) – Class section ID (if provided, fetches all students in that section)students(array, optional) – Array of student data with student_id, school_id, class_section_idsemester(string, optional) – Semester (defaults to configured semester)school_year(string, optional) – School year (defaults to configured school year)- Uses SemesterScoreService to recalculate scores
- Returns count of processed students
Notes:
- All endpoints require authentication (
auth:apimiddleware) - Score calculation formula:
- PTAP = (homework_avg + quiz_avg + project_avg) / 3
- Attendance = min((total_days - absences + 1) / total_days * 100, 100)
- Fall semester: semester_score = 0.2 * PTAP + 0.2 * attendance + 0.6 * midterm
- Spring semester: semester_score = 0.2 * PTAP + 0.2 * attendance + 0.6 * final_exam
- The controller automatically refreshes semester scores when loading teacher view
- Class section resolution:
- First tries to find class section for active semester/school year
- Falls back to any class section assigned to the teacher if not found
- Parent view handles three user types:
- Primary: uses user_id directly
- Secondary: looks up parent_id from parents table
- Tertiary: looks up parent_id from authorized_users table
- Score types supported: homework, quiz, project, midterm, final_exam
- Comments are loaded separately for ptap, midterm, and final score types
- Semester scores are loaded from
semester_scorestable and override calculated values if present - Total semester days are retrieved from configuration:
total_semester1_days(Fall) ortotal_semester2_days(Spring)
ScorePredictorController
File: app/Http/Controllers/Api/ScorePredictorController.php
Purpose: Generate combined score prediction reports with statistical analysis, trophy winner determination, and risk assessment for students based on fall and spring semester scores.
Endpoints:
GET /api/v1/score-predictor/combined-report(combinedReport) – Generate combined score prediction report. Query parameters:school_year(optional) – Filter by school year (defaults to configured school year)class_section_id(optional) – Filter by class section ID- Returns:
students– Array of students with predictions, each containing:student_id– Student IDschool_id– School IDfirstname– First namelastname– Last nameclass_section_id– Class section IDfall_score– Fall semester score or 'N/A'spring_score– Spring semester score or 'N/A'final_average– Final average (fall + spring) / 2, rounded to 1 decimal, or 'N/A'required_spring_score– Required spring score to achieve trophy threshold, or 'N/A'winning_risk– Trophy winning risk: 'Achieved Trophy', 'Unreachable', 'New student', 'Low', 'Medium', 'High'required_spring_to_pass– Required spring score to pass, or 'N/A'failure_risk– Failure risk: 'Unlikely to pass', 'New student', 'High', 'Medium', 'Low'status– Overall status: 'Passed', 'Failed', 'Undetermined'
school_year– Selected school yearclass_sections– All available class sectionsselected_class_section_id– Selected class section ID (if filtered)semester– Current semesterstats– Statistical data:mean– Mean of spring semester scoresstd– Standard deviation of spring semester scorestarget_trophy– Trophy threshold from configurationtarget_pass– Pass threshold from configuration
- Students are sorted by final average (descending)
- Trophy winners are determined per class section using:
- All students at/above trophy threshold (minimum 94.0 or configured value)
- Minimum trophies: max(ceil(class_size / 4), 3), capped at class size
- Tolerance tie-break: students within 0.2 points of last included winner
Notes:
- All endpoints require authentication (
auth:apimiddleware) - Trophy threshold: minimum 94.0, or higher if configured in
trophy_score - Pass threshold: from
pass_scoreconfiguration (default 60.0) - Statistical calculations:
- Uses normal cumulative distribution function (normalCDF) for probability calculations
- Calculates z-scores based on mean and standard deviation of spring scores
- Probability thresholds for risk assessment:
- High risk: probability < 0.33
- Medium risk: 0.33 <= probability < 0.66
- Low risk: probability >= 0.66
- Trophy winner determination:
- Per-class section basis
- Minimum 3 trophies per class (or 25% of class size, whichever is higher)
- Tolerance of 0.2 points for tie-breaking
- Students with final average >= trophy threshold are automatically included
- New students (no fall score) have 'N/A' for calculated values and 'New student' risk labels
- Final average calculation: (fall_score + spring_score) / 2, rounded to 1 decimal
- Required spring scores: calculated to achieve trophy threshold or pass threshold
- The report uses spring semester statistics for probability calculations
SendSMSController
File: app/Http/Controllers/Api/SendSMSController.php
Purpose: Trigger SMS blasts.
POST /api/v1/sms/send– Validatesmessageand recipients (phone numbers or parent IDs), queues the SMS, and returns the send summary.
SessionTimeoutController
File: app/Http/Controllers/Api/SessionTimeoutController.php
Purpose: Manage session timeout tracking and provide keep-alive functionality for the SPA to prevent unexpected logouts due to inactivity.
Endpoints:
GET /api/v1/session/timeout-config(getTimeoutConfig) – Public endpoint that returns session timeout configuration including timeout duration, warning threshold, check interval, and related URLs (logout, keep-alive, check). Response includessuccess,timeout,warning_time,check_interval,logout_url,keep_alive_url, andcheck_url.GET /api/v1/session/checkTimeout(checkTimeout) – Requires auth. Checks the current session's last activity timestamp against the configured timeout duration. Returnsstatus(active,warning, orexpired) andtime_remainingin seconds. If session has expired, returnsstatus: 'expired'withredirectURL andmessage.POST /api/v1/session/pingActivity(pingActivity) – Requires auth. Updates the session'slast_activitytimestamp to keep the session alive. Only updates if the session is still valid (not already expired). Returnsstatus: 'active'andtime_remainingset to the full timeout duration. If session has already expired, returns the same expired response ascheckTimeout.
Session Management:
- Tracks user activity via
last_activitysession key - Automatically expires sessions that exceed
SessionTimeout::TIMEOUT_DURATION(default: 1200 seconds / 20 minutes) - Warns users when activity exceeds
SessionTimeout::WARNING_THRESHOLD(default: 900 seconds / 15 minutes) - Frontend should check session status at intervals defined by
SessionTimeout::CHECK_INTERVAL(default: 60 seconds / 1 minute)
SettingsController
File: app/Http/Controllers/Api/SettingsController.php
Purpose: Read/update global settings.
GET /api/v1/settings– Returns grouped configuration values.PATCH /api/v1/settings– Accepts a key/value object and persists changes after validation.
SlipPrinterController
File: app/Http/Controllers/Api/SlipPrinterController.php
Purpose: Generate printable late slips as PDFs, manage slip previews, and handle reprinting of previously logged slips.
Endpoints:
POST /api/v1/slips/print(print) – Requires auth. Generates and returns a PDF late slip. Accepts POST data with fields:school_year(optional, defaults to configured year),student_name(required),date(optional, defaults to current date in m/d/Y format),time_in(optional, defaults to current time in h:i A format),grade,reason,admin_name(optional, auto-filled from logged-in user). Automatically logs the slip print to the database before generating the PDF. Returns PDF binary with appropriate headers for inline display or download. Supports optional query parameters:paper(card, card-portrait, receipt80, receipt58),font_pt,line_h,rows,height_mmfor PDF customization.GET /api/v1/slips/preview(preview) – Requires auth. Returns a list of recent late slip logs with optional filtering byschool_yearandsemesterquery parameters. Returns paginated list (up to 50 records) with formatted date/time fields. Each record includes:id,school_year,semester,student_name,date,time_in,grade,reason,admin_name.POST /api/v1/slips/preview(preview) – Requires auth. Returns a JSON preview of slip text formatted for printer output. Accepts the same fields as the print endpoint. Returnsok,text(formatted slip text), andwidth(characters per line) for preview purposes.POST /api/v1/slips/reprint/{id}(reprint) – Requires auth. Reprints a previously logged late slip by its log ID. Retrieves the slip data from the database, updates the admin name to the current logged-in user, generates a new PDF, and logs the reprint for audit purposes. Returns PDF binary response.
Features:
- PDF generation using DomPDF with customizable paper sizes (card, receipt formats)
- Automatic logging of all slip prints and reprints for audit trail
- ESC/POS printer support (network, USB, Windows) via Mike42\Escpos library (configured via environment variables)
- Automatic admin name resolution from logged-in user's database record
- Flexible date/time parsing and formatting
- Configurable printer settings via environment:
PRINTER_MODE,PRINTER_HOST,PRINTER_PORT,PRINTER_USB_VID,PRINTER_USB_PID,PRINTER_WINDOWS_NAME,PRINTER_CHARS_PER_LINE,PRINTER_FEED_LINES
StaffController
File: app/Http/Controllers/Api/StaffController.php
Purpose: CRUD for staff/teacher records with class assignment verification and issue tracking.
Endpoints:
GET /api/v1/staff(index) – Requires auth. Returns paginated list of staff members excluding roles: student, parent, guest, inactive. Optional query parameters:page,per_page,role(filter by role). Each staff member includes:school_id,class_section(for teachers/TAs),verification_issue(boolean flag for teachers/TAs without class assignments). Response includesissues_count(total count of teachers/TAs without class assignments),semester, andschool_yearmetadata.GET /api/v1/staff/{id}(show) – Requires auth. Returns a single staff member by ID withschool_idattached.POST /api/v1/staff(store) – Requires auth. Creates a new staff member. Accepts fields:firstname,lastname,email,phone,role_name(automatically setsactive_roleto lowercase version),school_year(optional, defaults to configured year),status(optional, defaults to 'Active'). Automatically setscreated_atandupdated_attimestamps.PATCH /api/v1/staff/{id}(update) – Requires auth. Updates a staff member. Accepts any of:firstname,lastname,email,phone,role_name(updatesactive_roleif provided),school_year,status. Only updates fields that are provided and non-empty. Automatically updatesupdated_attimestamp.DELETE /api/v1/staff/{id}(destroy) – Requires auth. Deletes a staff member by ID.
Features:
- Automatic class assignment verification for teachers and teacher assistants
- Issue tracking for teachers/TAs without class assignments
- School ID resolution from user records
- Role-based filtering and exclusion
StatsController
File: app/Http/Controllers/Api/StatsController.php
Purpose: Aggregate metrics for dashboards (attendance, enrollment, finances).
- Endpoints like
GET /api/v1/stats/attendance|students|financialquery reporting tables and return summary numbers + breakdowns for the admin UI.
StudentController
File: app/Http/Controllers/Api/StudentController.php
Purpose: Full REST API for managing students, class assignments, health information, and automated distribution.
Endpoints:
GET /api/v1/students(index) – Requires auth. Supports pagination and filters (parent_id,class_id). Augments each record with the student's current class info. Returns paginated list of students.GET /api/v1/students/{id}(show) – Requires auth. Returns detailed student profile plus current class section information.POST /api/v1/students(store) – Requires auth. Creates a new student. Validates demographic fields (firstname, lastname, dob, gender, parent_id) and automatically stamps school year, semester, and registration date.PATCH /api/v1/students/{id}(update) – Requires auth. Updates student information. Accepts fields:school_id,firstname,lastname,dob(automatically calculates age),gender,registration_grade,photo_consent,parent_id,registration_date,tuition_paid,year_of_registration,school_year,rfid_tag,semester,is_new. Also supports health information:medical_conditions(comma/semicolon/newline separated list),allergies(comma/semicolon/newline separated list),medical_touched,allergies_touched(flags to indicate user interaction). Health lists are normalized, deduplicated, and synced with related tables. Only updates fields that are provided and non-empty.DELETE /api/v1/students/{id}(destroy) – Requires auth. Removes the student record.POST /api/v1/students/assign-class(assignClassStudent) – Requires auth. Assigns a student to a class section. Acceptsstudent_idandclass_section_id. Updatesstudent_classtable, enrollment records, attendance data/records, and all score-related tables (homework, quiz, project, participation, midterm_exam, final_exam, final_score, semester_scores) for the current semester/year. Returns assignment details including attendance and score update statistics.POST /api/v1/students/auto-distribute(autoDistributeSections) – Requires auth. Automatically distributes students from promotion queue into lettered sections for a class. Acceptsclass_id(orclass_section_idto derive class_id),students_per_section, and optionalschool_year. Balances male/female distribution across sections. Only considers students with enrollment status 'payment pending' or 'enrolled'. Updates promotion queue and student_class records. Returns summary with distribution details per section (total, male, female counts).GET /api/v1/students/promotion-totals(promotionTotalsApi) – Requires auth. Returns promotion totals per base class (KG, 1-9, Youth) for the selected school year. Optional query parameter:school_year(defaults to configured year). Only counts students with enrollment status 'payment pending' or 'enrolled'. Returns array with class_id, class_section_id, class_section_name, and total count per class.
Features:
- Comprehensive student data management with health information (allergies, medical conditions)
- Automatic class assignment with cascading updates to attendance and score tables
- Gender-balanced automated section distribution
- Promotion queue integration
- Health list normalization (removes duplicates, filters placeholders like "none", "n/a")
- Transaction-safe operations with rollback on errors
SupplierController
File: app/Http/Controllers/Api/SupplierController.php
Purpose: CRUD for supplier/vendor records used by purchase orders and inventory management.
Endpoints:
GET /api/v1/suppliers(index) – Requires auth. Returns paginated list of suppliers. Optional query parameters:page,per_page,q(search keyword). Search filters by name, email, or phone. Results ordered by name ascending.GET /api/v1/suppliers/{id}(show) – Requires auth. Returns a single supplier by ID.POST /api/v1/suppliers(store) – Requires auth. Creates a new supplier. Accepts fields:name(required),email(optional, validated as email),phone(optional),address(optional),notes(optional). Returns created supplier record.PATCH /api/v1/suppliers/{id}(update) – Requires auth. Updates a supplier. Accepts any of:name,email,phone,address,notes. Only updates fields that are provided. Returns updated supplier record.DELETE /api/v1/suppliers/{id}(destroy) – Requires auth. Deletes a supplier by ID.
Features:
- Search functionality across name, email, and phone fields
- Standard RESTful CRUD operations
- Validation for required fields and email format
SupportController
File: app/Http/Controllers/Api/SupportController.php
Purpose: Ticket management for internal support.
GET /api/v1/support/tickets/{id}– List or fetch support tickets.POST /api/v1/support/tickets/PATCH /api/v1/support/tickets/{id}– Create/update ticket records with status notes.
TeacherController
File: app/Http/Controllers/Api/TeacherController.php
Purpose: Manage teacher records, class assignments, class view data, and absence/vacation requests.
Endpoints:
GET /api/v1/teachers(index) – Requires auth. Returns paginated list of teachers and teacher assistants. Optional query parameters:page,per_page. Results include class assignments for the current school year and semester.GET /api/v1/teachers/{id}(show) – Requires auth. Returns detailed information about a specific teacher including their class assignments for the current term.GET /api/v1/teachers/{id}/classes(getClasses) – Requires auth. Returns the class sections currently assigned to the teacher for the current school year and semester.GET /api/v1/teachers/class-view(getClassView) – Requires auth. Returns comprehensive class view data for the logged-in teacher including:- Teacher name and role
- All assigned classes (as main teacher or TA)
- Students grouped by class section with medical conditions and allergies
- Assigned staff names (main teachers and TAs) per class section
GET /api/v1/teachers/class-assignments(getTeacherClassAssignments) – Requires auth. Returns teacher class assignment data for administration. Optional query parameter:schoolYearorschool_yearto filter by specific year. Returns:- List of all teachers and TAs
- Their main and TA assignments
- Available class sections
POST /api/v1/teachers/class-assignments/assign(assignClassTeacher) – Requires auth. Assigns a teacher to a class. Body requires:teacher_id(required) – ID of the teacher to assignclass_section_id(required) – ID of the class sectionteacher_role(optional) – Role of the teacher (if not provided, will be determined from user roles)- Optional:
semester,school_year(defaults to configured values) - Returns success/error status with message
DELETE /api/v1/teachers/class-assignments(deleteAssignment) – Requires auth. Removes a teacher class assignment. Body requires:teacher_id(required)class_section_id(required)position(required) – Either "main" or "ta"- Optional:
semester,school_year(defaults to configured values)
GET /api/v1/teachers/absence-form(getAbsenceForm) – Requires auth. Returns absence form data for the logged-in teacher including:- Teacher name
- Current semester and school year
- Existing absence records for the current term
- Available dates (future Sundays within the school year range)
POST /api/v1/teachers/absence(submitAbsence) – Requires auth. Submits an absence/vacation request. Body requires:dates(required) – Array of date strings in Y-m-d format (must be valid Sundays)reason(required) – Text description of the absence reasonreason_type(optional) – Category of the reason- Validates dates against allowed Sundays list, creates/updates staff attendance records, and sends notification email to principal. Returns count of saved dates.
TestDBController
File: app/Http/Controllers/Api/TestDBController.php
Purpose: Simple health endpoint for confirming DB connectivity/migrations.
GET /api/v1/test-db– Returns the status of DB checks used in diagnostics.
TimeController
File: app/Http/Controllers/Api/TimeController.php
Purpose: Share the server’s current timestamp/timezone for client sync logic.
GET /api/v1/time– Responds with ISO timestamp and timezone metadata.
UiController
File: app/Http/Controllers/Api/UiController.php
Purpose: Store and return UI palette preferences that drive the SPA theme.
Endpoints:
GET /api/v1/ui/style(style) – Requires auth. Returns the user's current accent/menu colors plus the available palettes defined in config. Can also accept query parameters to update style preferences:accent(optional) – Accent color palette name from available palettesmenu(optional) – Menu color palette name from available palettes, orcustomfor custom colorsmenu_bg(optional) – Custom menu background color in hex format (e.g.,#0f172aor0f172a)menu_text(optional) – Custom menu text color in hex format (e.g.,#fffffforffffff)menu_mode(optional) – Menu mode:light,dark, orauto(defaults to auto-detect based on background luminance)- When query parameters are provided, updates the style preferences and returns the updated values. When no parameters are provided, returns current preferences.
POST /api/v1/ui/style(updateStyle) – Requires auth. Accepts JSON body with style preferences:accent(optional) – Accent color palette namemenu(optional) – Menu color palette name orcustommenu_bg(optional) – Custom menu background color in hex formatmenu_text(optional) – Custom menu text color in hex formatmenu_mode(optional) – Menu mode:light,dark, orauto- Persists the preferences in the session and returns the updated values.
Features:
- Supports both predefined palettes and custom hex colors
- Automatically detects light/dark mode based on background color luminance when
menu_modeisauto - Normalizes hex color formats (supports both 3-digit and 6-digit hex codes)
- All preferences are stored in session and persist across requests
UserController
File: app/Http/Controllers/Api/UserController.php
Purpose: Manage user accounts, profile data, login activity, password reset/activation flows, and role management.
Endpoints:
GET /api/v1/users(index) – Auth required. Returns users with optionalsort=id|firstname|lastname|email|roleandorderquery params plus the role catalog for dropdowns.GET /api/v1/users/with-roles(listWithRoles) – Auth required. Expands every user with their roles, guardian type, and whether they exist as a secondary parent in legacy tables.POST /api/v1/users(store) – Auth required. Creates a user with PBKDF2 password hashing and immediately assigns the providedrole_id. Body requires:firstname,lastname,email,password,cellphone,address_street,city,state,zip,accept_school_policy,role_id.PATCH /api/v1/users/{id}(updateUser) – Auth required. Updates the account/profile metadata fields used by the admin UI (status flags, address, contact info, tokens, etc.). Accepts partial updates for any user field.DELETE /api/v1/users/{id}(destroy) – Auth required. Removes the user and associateduser_rolesrows.GET /api/v1/users/login-activity(loginActivity) – Auth required. Paginated login history with metadata and pager info. Query params:per_page(default 25),page(default 1).POST /api/v1/users/select-role(selectRole) – Auth required. Selects and updates the logged-in user's role in the database. Body requires:role(role name or slug). Returns the role and dashboard route.DELETE /api/v1/users/roles/{roleId}(deleteRole) – Auth required. Deletes a role and reassigns all users with that role to the "Guest" role. Users are set to Inactive status.POST /api/v1/users/password/forgot(requestPasswordReset) – Public. Throttles by IP (max 3 attempts per 24 hours), verifies account status, creates a one-hour reset token, and emails the link. Body requires:email.GET /api/v1/users/password/reset/{token}(validateResetToken) – Public. Validates whether the token is still usable and returns the associated email.POST /api/v1/users/password/reset(completePasswordReset) – Public. Consumes the token, hashes the new password, clears lockouts, and deletes the reset entry. Body requires:token,password,password_confirmation. Password must meet complexity requirements.GET /api/v1/user/confirm/{token}(confirm) – Public. Validates the registration token so the UI can prompt for an initial password. Returns user_id and email if valid.POST /api/v1/user/set-password(setPassword) – Public. Finalizes onboarding by setting the password, activating the user, and clearing the token. Body requires:user_id,token,password,password_confirm. Generates account_id if not present.GET /api/v1/user/profile(profile) – Auth required. Returns the signed-in user's details with any attached roles.POST /api/v1/user/profile-auth(profileAuth) – Public. PBKDF2 credential check for legacy clients that need a session+JWT payload. Body requires:email,password.PATCH /api/v1/user/profile(updateProfile) – Auth required. Updates contact info and optionally email/password after verifying the current password. Body can include:firstname,lastname,cellphone,address_street,apt,city,state,zip,gender,email(requirescurrent_password),password(requirescurrent_password).
WhatsappController
File: app/Http/Controllers/Api/WhatsappController.php
Purpose: Manage WhatsApp invite links per class section, send invites to parents, and track parent participation.
Endpoints:
-
GET /api/v1/whatsapp/(index) – Get initial data for WhatsApp management page. Returns sections, parents, links by section, school year, and semester. -
GET /api/v1/whatsapp/links(links) – Lists links for the active school year/semester sorted by class section. -
POST /api/v1/whatsapp/links(saveLink) – Upserts the invite link for a class section. Body requires:class_section_id(integer, required)invite_link(string, required)active(integer, optional: 0 or 1)class_section_name(string, optional)
-
POST /api/v1/whatsapp/send-invites(sendInvites) – Send WhatsApp invites in three modes. Body requires:mode(string, required: 'parents' | 'class' | 'all')parent_ids(array of integers, required if mode='parents')class_section_id(integer, required if mode='class')
Modes:
parents: Send invites to selected parents (requiresparent_idsarray)class: Send invites to all parents in a specific class (requiresclass_section_id)all: Send invites to all parents across all classes
Triggers
whatsapp_invites.sendevent for each recipient group with parent info, sections, links, teachers, and email addresses (TO and CC). -
GET /api/v1/whatsapp/parent-contacts(parentContacts) – Get a flat list of all parent contacts (primary and secondary parents) for the current term. Optional query parameters:school_year(string)semester(string)
Returns contacts sorted by last name, first name, and type (Primary before Second).
-
GET /api/v1/whatsapp/parent-contacts-by-class(parentContactsByClass) – Get parent contacts grouped by class section. Optional query parameters:school_year(string)semester(string)
Returns class sections with associated parents (primary and secondary), teachers (main and assistants), and membership flags indicating if parents have joined the WhatsApp groups.
-
POST /api/v1/whatsapp/memberships(updateMembership) – Update WhatsApp group membership flags for a class/parent(s). Body requires:class_section_id(integer, required)primary_id(integer, optional)second_id(integer, optional)primary_member(string/integer, optional: '1' or 'on' if checked)second_member(string/integer, optional: '1' or 'on' if checked)school_year(string, optional)semester(string, optional)
Updates membership status for primary and/or secondary parents in a class section. Uses
subject_type('primary' or 'second') andsubject_idto track membership.
GradingController
File: app/Http/Controllers/Api/GradingController.php
Purpose: Unified interface for CRUD operations across scores (homework, quizzes, projects, midterms, finals, semester tests, comments) and comprehensive grading management.
Endpoints:
-
GET /api/v1/grading/{type}/{class_section_id?}/{student_id?}(show) – Retrieves scores for a specific type.typemust be one ofhomework|quiz|project|midterm|final|test|comments. Optionalclass_section_idandstudent_idparameters. Filters by student, semester, and school year. Returns student information, scores array, type, class section ID, semester, and school year. -
POST /api/v1/grading(update) – Updates scores for various types. Body requires:type(required) – One of:homework,quiz,project,midterm,final,test,commentsstudent_id(required for midterm/final/test/comments)class_section_id(required for midterm/final/test)- For
homework|quiz|project:score_ids(array),scores(array),comments(optional array) - For
midterm|final|test:score(numeric) - For
comments:comment(string)
After updating scores, automatically triggers semester score recalculation for all students in the class section via
SemesterScoreService. -
GET /api/v1/grading(grading) – Returns comprehensive grading data for all students grouped by class sections. Returns:grades– Array grouped by class_id, containing class sections withclass_section_idandclass_section_namestudents_by_section– Array keyed by section_id, containing students with their PTAP scores and semester scoressemester– Current semesterschool_year– Current school year
Uses dual-join strategy to match semester_scores by both business ID (class_section_id) and primary key (id) for compatibility.
-
GET /api/v1/grading/scores-comments(getScoreComment) – Retrieves all scores and comments for all students in the current semester and school year. Returns a comprehensive dataset including:- Student basic information (school_id, firstname, lastname, class_name)
- Attendance data (score, absences, total_days)
- All score types:
final_exam,homework,midterm,project,quiz,semester_score - Comments array for each student
- Semester scores with all averages (homework_avg, quiz_avg, project_avg, midterm_exam_score, final_exam_score, attendance_score, participation_score, ptap_score, test_avg, semester_score)
HealthController
File: app/Http/Controllers/Api/HealthController.php
Purpose: Operational health check combining filesystem permissions and database schema sanity.
-
GET /api/v1/health(index) – Public endpoint (no auth required) that performs health checks on:- Filesystem paths: Checks if upload directories exist and are writable:
uploadsbase directoryuploads/reimbursementsuploads/receiptsuploads/checks
- Database schema: Verifies existence of critical tables and required columns:
user_preferencestable andtimezonecolumnsettingstable andtimezonecolumnmigrationstable
Returns JSON payload with:
ok(boolean) – Overall health statuspaths(array) – Status of each filesystem path withlabel,path,exists,writabledatabase(object) – Database schema checks with table/column existence flagswrite_path(string) – Base storage pathtimestamp(string) – ISO 8601 timestamp of the check
HTTP Status Codes:
200 OK– All checks passed503 Service Unavailable– One or more checks failed
- Filesystem paths: Checks if upload directories exist and are writable:
HomeworkController
File: app/Http/Controllers/Api/HomeworkController.php
Purpose: CRUD for per-student homework scores scoped by class section, with bulk update and column management capabilities.
Endpoints:
-
GET /api/v1/homework(index) – Paginated list with optionalclass_section_idquery parameter. Filters by current semester and school year. -
GET /api/v1/homework/student/{id}(getByStudent) – Returns all homework entries for a specific student, filtered by current semester and school year. -
GET /api/v1/homework/class-section(getByClassSection) – Retrieves comprehensive homework data for a class section. Query paramclass_section_id(required). Returns:homework_scores– Scores grouped by student IDstudents– List of students in the class sectionhomework_headers– Array of unique homework_index valuessemester,school_year,class_section_idhas_homework_cols– Boolean indicating if any homework columns exist
-
GET /api/v1/homework/students-with-scores(getStudentsWithScores) – Returns students with their homework scores. Query paramclass_section_id(required). Returns students array withstudent_id,firstname,lastname, andscoresobject keyed by homework_index. -
POST /api/v1/homework(create) – Creates a single homework entry. Body requires:student_id(integer, required)class_section_id(integer, required)homework_index(integer, required)score(numeric, optional)comment(string, optional)
-
POST /api/v1/homework/update-scores(updateScores) – Bulk update homework scores for multiple students. Body requires:scores(object, required) – Nested object:{student_id: {homework_index: score}}class_section_id(integer, required)
Behavior:
- Updates existing scores if record exists
- Creates new records if they don't exist
- Deletes records if score is blank/null
- Automatically triggers semester score recalculation for all students in the class section
-
POST /api/v1/homework/add-column(addNextColumn) – Adds a new homework column (index) for all students in a class section. Body requires:class_section_id(integer, required)
Returns:
homework_index– The new homework index numbernew_homework_id– ID of the first inserted recordstudents_processed– Number of students for whom the column was added
-
PATCH /api/v1/homework/{id}(update) – Updates a single homework entry. Allows updatingscoreand/orcommentfields.
HomeworkTrackingController
File: app/Http/Controllers/Api/HomeworkTrackingController.php
Purpose: Build a Sunday-based schedule of homework indices for dashboards with comprehensive tracking data.
-
GET /api/v1/homework/tracking(index) – Returns comprehensive homework tracking data. Query parameters:start_date(optional, default: '2025-09-21') – Start date for the tracking periodend_date(optional, default: '2026-01-18') – End date for the tracking periodpage(optional, default: 1) – Page number for paginated teacher/section results (8 per page)
Returns:
semester– Current semesterschool_year– Current school yearsundays– Array of all Sunday dates (Y-m-d format) within the date range, starting from the first Sunday on/after start_dateevent_days– Object mapping dates (Y-m-d) to boolean true for no-school days from calendar eventsdate_to_index– Object mapping Sunday dates to homework_index numbers (null for no-school Sundays)teachers– Paginated array of class sections with:class_section_id– Class section IDclass_id– Class ID (for sorting: KG=13, Grades 1-11, Youth=12)class_section_name– Name of the class sectionteachers– Array of main teacher namestas– Array of TA names
has_homework– Nested object:{class_section_id: {homework_index: true}}indicating which sections have homework for which indiceshw_entered_at– Nested object:{class_section_id: {homework_index: 'Y-m-d'}}with first creation date per homework indexhas_homework_by_date– Nested object:{class_section_id: {sunday_date: true}}mapping homework to the nearest prior non-no-school Sundayhw_entered_at_by_date– Nested object:{class_section_id: {sunday_date: 'Y-m-d'}}with earliest entry date per Sundaypagination– Pagination metadata:page– Current page numbertotal_pages– Total number of pagesper_page– Items per page (8)total_rows– Total number of class sections
The endpoint calculates Sunday-based homework indices, skips no-school days, aggregates homework data by both index and date, and provides teacher/TA information for each class section. Results are sorted by grade order (KG first, then Grades 1-11, then Youth).
InventoryController
File: app/Http/Controllers/Api/InventoryController.php
Purpose: Comprehensive inventory management system for tracking items, categories, stock movements, classroom audits, book distribution, and inventory summaries.
Item Management:
GET /api/v1/inventory(index) – List inventory items filtered bytype(classroom/book/office/kitchen),school_year, andsemester. Returns items with categories, condition options, school years, and user names for updated_by fields.GET /api/v1/inventory/create(create) – Get form data for creating a new item, including categories and condition options for the specified type.GET /api/v1/inventory/{id}(show) – Retrieve a single inventory item with its categories and condition options.POST /api/v1/inventory(store) – Create a new inventory item. Automatically records initial stock movement if quantity > 0. Body requiresname,type, optionalcategory_id,quantity,description,unit,sku,notes. For books:isbn,edition. For classroom:condition.PATCH /api/v1/inventory/{id}(update) – Update an inventory item. Type is locked to the original item type. Updatesupdated_byautomatically.DELETE /api/v1/inventory/{id}(delete) – Remove an inventory item.
Category Management:
POST /api/v1/inventory/categories(saveCategory) – Create or update a category. Body requirestype,name, optionaldescription. For book categories:grade_min,grade_max(validated: min ≤ max, both ≤ 13). Prevents duplicate (type, name) combinations. Returns conflict error if duplicate exists.
Classroom Audit:
GET /api/v1/inventory/classroom/{id}/audit(auditClassroomForm) – Get audit form data for a classroom item, including current good/needs_repair/need_replace/cannot_find quantities.POST /api/v1/inventory/classroom/{id}/audit(auditClassroomStore) – Save audit data. Calculates deltas for loss/missing quantities and records stock movements (out for increases, in for decreases). Updates good_qty as on-hand minus needs_repair. Body requiresneeds_repair_qty,need_replace_qty,cannot_find_qty.
Summary & Reports:
GET /api/v1/inventory/summary/{type?}(summary) – Get inventory summary for a type (default: classroom). Returns items with aggregated received/issued quantities from movements, filtered by optionalschool_yearquery param.GET /api/v1/inventory/summary-all(summaryAll) – Comprehensive summary across all types or a selected type. Query params:school_year(default: current),type(all/book/classroom/office/kitchen). Returns rows with opening, received, distributed, other_out, adjust_net, ending, onhand, variance calculations. Includes totals row.
Stock Adjustments:
GET /api/v1/inventory/{id}/adjust(adjustForm) – Get form data for adjusting stock.POST /api/v1/inventory/{id}/adjust(adjustStore) – Adjust inventory quantity. Body requiresmode(in/out/adjust),quantity(> 0), optionalreason,note. Records movement and prevents negative stock for out/adjust modes.
Book Distribution (Teacher):
GET /api/v1/inventory/books/distribute(teacherDistributeForm) – Get book distribution form for teachers. Requires authentication and teacher/TA role. Filters books by category grade range matching the selected class section's grade level. Groups books by category with grade range labels. Returns students in the class, prior distribution history for selected book, and on-hand quantity. Query params:class_section_id(optional if teacher has only one class),item_id(optional, for showing history).POST /api/v1/inventory/books/distribute(teacherDistributeStore) – Distribute books to students. Body requiresitem_id,class_section_id,student_ids(array), optionalnote. Validates students belong to teacher's class, checks stock availability, prevents duplicate distributions (only assigns to students who don't already have the book this school year). Records one movement per student with type 'distribution'. Returns count of successfully distributed books.
Movement Management:
GET /api/v1/inventory/movements(movementsIndex) – List all inventory movements with enriched data (item name, performed_by name, teacher name, student name, class section name). Query params:school_year,semesterfor filtering. Ordered by ID descending.GET /api/v1/inventory/movements/create(movementsCreate) – Get form data for creating a movement, including movement types, semesters, items, class sections, teachers, and students.GET /api/v1/inventory/movements/{id}(movementsEdit) – Get a single movement with hydrated display names.POST /api/v1/inventory/movements(movementsStore) – Create a movement. Body requiresitem_id,qty_change,movement_type(initial/in/out/adjust/distribution), optionalreason,note,semester,school_year,teacher_id,student_id,class_section_id. Automatically setsperformed_byfrom session.PATCH /api/v1/inventory/movements/{id}(movementsUpdate) – Update a movement. Allows updating all fields exceptitem_id(immutable after creation).DELETE /api/v1/inventory/movements/{id}(movementsDelete) – Delete a movement.POST /api/v1/inventory/movements/bulk-delete(movementsBulkDelete) – Bulk delete movements. Body requiresids(array of movement IDs).
Movement Types: initial, in, out, adjust, distribution
Inventory Types: classroom, book, office, kitchen
Key Features:
- Automatic quantity recalculation from movement history
- Legacy item support: ensures initial movements exist for items without movement history
- School year opening balance tracking: ensures initial movement exists for each school year
- Classroom-specific: good_qty automatically calculated as on-hand minus needs_repair_qty
- Book distribution: grade range filtering, prevents duplicate distributions, stock validation
- Comprehensive audit trail with user tracking (updated_by, performed_by)
InvoiceController
File: app/Http/Controllers/Api/InvoiceController.php
Purpose: Comprehensive invoice management including generation, calculation, PDF export, and parent invoice tracking.
Endpoints:
GET /api/v1/invoices(index) – Paginated list of invoices with optional filters:parent_id,status,school_year,page,per_page. Returns invoices with pagination metadata.GET /api/v1/invoices/{id}(show) – Returns a single invoice by ID or404if not found.GET /api/v1/invoices/management-data(managementData) – Composite data for invoice management view. Returns:schoolYears– Available school years from invoicesinvoices– Array of parent invoice summaries with:parent_name,parent_idenrolledKids– Array of enrolled students with name, grade, tuition_feewithdrawnKids– Array of withdrawn studentsinvoice_amount,refund_amount,invoice_date,last_updated,invoice_id
- Query params:
schoolYearoryear(defaults to configured year)
GET /api/v1/invoices/unpaid(unpaidInvoices) – Returns all unpaid invoices ordered by due date ascending.GET /api/v1/invoices/parent/{parentId}(getByParent) – Returns all invoices for a specific parent. Optional query param:school_year(defaults to configured year).POST /api/v1/invoices/generate(generateInvoice) – Generates or updates invoice for a parent. Body requiresparent_id. Calculates tuition fees based on enrolled/withdrawn students, applies discounts, includes event charges, and handles refunds. Creates new invoice if none exists, or updates existing invoices with recalculated totals. Returns{ok, updated, updated_ids, insert_id}.POST /api/v1/invoices/check-and-generate(checkAndGenerateInvoice) – Checks enrollment status and generates invoice if needed. Body requiresparent_idandstatus. Only generates for statuses:payment pending,withdrawn,enrolled.GET /api/v1/invoices/{id}/pdf(generatePdfInvoice) – Prepares invoice data for PDF generation. Returns comprehensive invoice data including parent info, students (enrolled/withdrawn), charges, payments, discounts, refunds, and additional charges. Note: Actual PDF rendering would need separate implementation.POST /api/v1/invoices(store) – Creates a new invoice. Body should include invoice fields (see InvoiceModel fillable). Automatically setsschool_yearandsemesterfrom configuration if not provided.PATCH /api/v1/invoices/{id}(update) – Updates invoice fields. Allowed fields:status,paid_amount,balance,description.PATCH /api/v1/invoices/{id}/status(updateStatus) – Updates invoice status only. Body requiresstatusfield.DELETE /api/v1/invoices/{id}(delete) – Deletes an invoice.
Invoice Calculation Logic:
- Tuition fees calculated based on student grade levels (regular vs youth)
- Regular students (grade <= configured
grade_fee): First student full price, additional students discounted - Youth students (grade >
grade_fee): Flat youth fee per student - Refund window: Withdrawn students excluded from billing if within refund deadline, otherwise billed
- Event charges: Summed from event charges table
- Discounts: Recalculated based on voucher type (percent or fixed)
- Additional charges: Applied from
additional_chargestable (add/deduct types) - Balance calculation:
total_amount - discounts - refunds_paid - payments_received
Helper Methods:
calculateTuitionFee()– Calculates tuition based on enrolled/withdrawn students and refund windowcalculateTotalTuitionFee()– Computes total tuition with regular/youth fee logicrecalculateAndUpdateDiscount()– Recalculates and updates discount amounts for invoicesprepareInvoiceData()– Prepares comprehensive invoice data for display/PDFgetGradeLevel()– Parses grade names to numeric levels (handles KG, Pre-K, Youth, numeric grades)compareGrades()– Compares grade levels for sorting
IpBanController
File: app/Http/Controllers/Api/IpBanController.php
Purpose: Manage IP lockouts resulting from failed login attempts.
Endpoints:
GET /api/v1/ip-bans(index) – Paginated list of IP ban records filtered bystatus=all|active|expired. Query params:page,per_page,status. Returns paginated results with IP addresses, attempt counts, blocked_until dates, and timestamps.GET /api/v1/ip-bans/{id}(show) – Fetch a specific ban record by ID or404if not found.POST /api/v1/ip-bans/unban(unban) – Unban IP(s). Body accepts:id(integer) – Unban by record IDip(string) – Unban by IP addressall(integer, 1) – Unban all active bans (setsblocked_untilto null andattemptsto 0 for all active bans)- Returns count of unbanned IPs and success message
POST /api/v1/ip-bans(ban) – Ban an IP with explicit date. Body requires:ip(string, required) – IP address to banblocked_until(date, required) – Ban expiration date/time- Optional:
attempts(integer, default 5),reason(string) - Creates new record if IP doesn't exist, or updates existing record
- Returns the ban record
POST /api/v1/ip-bans/ban-now(banNow) – Ban an IP immediately for specified hours. Body accepts:id(integer) – Ban by record ID, orip(string) – Ban by IP addresshours(integer, default 24) – Number of hours to ban (minimum 1, defaults to 24)- Calculates
blocked_untilautomatically from current time + hours - Sets attempts to max(current attempts, 10) for clarity
- Returns IP address, blocked_until date, and hours