Files
2026-03-05 12:29:37 -05:00

172 KiB
Executable File
Raw Permalink Blame History

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()).
  • 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 return 401/422.
  • GET /api/v1/administrator/search (search)
    • Query param q is 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.
  • GET /api/v1/administrator/enrollment-withdrawal (enrollmentWithdrawal)
    • Paginated list of enrollment rows filtered by school_year (defaults to configured year).
  • 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 of admission under review, payment pending, enrolled, withdraw under review, refund pending, withdrawn, denied, or waitlist.
    • Wraps updates in a transaction, adjusts admission flags, and when a status moves into refund pending runs FeeCalculationService + RefundModel bookkeeping. Responds with summary + any per-student errors.
  • 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 parent role, and augments each record with their latest invoice paid_amount/balance.
  • 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) Optional class_id, teacher_id, student_id, page, and per_page filters; returns paginated assignments.
  • GET /api/v1/assignments/{id} (show) Returns a single assignment or 404.
  • POST /api/v1/assignments (store) Requires title, due_date (Y-m-d), class_id, and teacher_id; creates an assignment row.
  • PATCH /api/v1/assignments/{id} (update) Partial update for the same fields as store.
  • 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 optional school_year filter, 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 a student_class record 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 or 404.
  • store() Body requires student_id, date (Y-m-d), status (present|absent|late), optional notes. Prevents duplicates per (student,date) and returns 201 with inserted payload.
  • update($id) Allows patching status and/or notes, 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 optional date query 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}/record body: {"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; accepts class_section_id, date, semester, and school_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 include student_id and date; 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 given student_id, code, and optional variant/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 admins 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) Validates email and password, looks up the user case-insensitively, uses ci_password_verify, and returns {access_token, token_type, expires_in} or 401.
  • GET /api/v1/auth/me (me) Requires a valid bearer token, returns the decoded User JSON via JWTAuth::parseToken()->authenticate().
  • POST /api/v1/auth/logout (logout) Invalidates the callers 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; accepts email, 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 delegates authorized_user_id for the password setup UI.
  • GET /api/v1/authorized-users/{id}/set-password (setPassword) Public; returns the delegates basic info so the frontend can render the password form.
  • POST /api/v1/authorized-users/{id}/password (savePassword) Public; accepts password/password_confirm, hashes it with PBKDF2, and updates the delegates 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 the respond* 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, and normalizeRules accept CodeIgniter rule strings (e.g., max_length[255], permit_empty) and translate them to Laravel validator syntax before running Validator::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 the user_id from the session, and getCurrentUser() fetches the hydrated UserModel record, falling back to querying user_roles if roles are missing from the session cache.
  • Constructor: captures the Laravel Request and exposes it as $this->request via CiRequestAdapter so 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 (using UserModel::getParents) and the sender dropdown derived from MAIL_SENDERS so 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 via EmailService, reports {attempted, sent, failed}.
  • POST /api/v1/broadcast-email/upload-image (uploadImage) Validates and stores rich-text editor image uploads (JPEG/PNG/GIF/WebP ≤ 5MB) under public/uploads/email and 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) Supports page, per_page, month, and year query params. Filters by start_date, orders ascending, and returns paginated events.
  • GET /api/v1/calendar/{id} (show) Returns the event by ID or 404.
  • POST /api/v1/calendar (store) Body must include title, start_date (Y-m-d) and optional description, end_date, location. Responds with 201 and 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 CodeIgniters $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 optional grade and teacher_id filters; returns ordered list of class records.
  • GET /api/v1/classes/{id} (show) Retrieves a single class or 404.
  • GET /api/v1/classes/{id}/students (students) Joins student_class and students to 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 optional school_year and semester query 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 status
    • totals Required totals for each prep category
    • shortages Items where available inventory is less than required
    • available Current inventory map
  • POST /api/v1/class-prep/adjustments (saveAdjustment) Body requires class_section_id, school_year, and adjustments object. Persists manual adjustments for large/small tables and returns {updated: count}.
  • POST /api/v1/class-prep/mark-printed (markPrinted) Body requires school_year and class_section_ids array. Stores printed snapshots for the supplied section IDs to reset needs_print flag. 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 optional sender_id and/or receiver_id, ordered newest-first.
  • POST /api/v1/communications (send) Body must include sender_id, receiver_id, subject, message. Returns 201 with stored record.
  • GET /api/v1/communications/conversation (conversation) Requires both sender_id and receiver_id query 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 the is_primary_home flag so the front-end can preselect the right household.
  • GET /api/v1/communications/families/{family_id}/guardians (guardians) Joins family_guardians with users to return each guardians name, email, relation, and preferred delivery flags.
  • POST /api/v1/communications/preview (preview) Body requires template_key, student_id, and family_id; optional vars. Renders the Twig-like placeholders in the chosen template and returns a sanitized subject/body preview.
  • POST /api/v1/communications/send-email (sendEmail) Body requires student_id, family_id, template_key, subject, body, and recipients (JSON array or string). Accepts optional cc/bcc, sends the HTML email through Mail::send, and logs the result in communication_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 fuzzy key search.
  • 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 unique config_key and config_value; wraps persistence in try/catch and returns 201.
  • PATCH /api/v1/configuration/{id} (update) Allows updating config_key and/or config_value, ensuring the payload isnt 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 requires name, email, subject, and message. Validates lengths + email format, then composes HTML and sends it to SUPPORT_EMAIL (default support@alrahmaisgl.org). Returns a friendly success message or 500 if 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=true filters 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). Responds 404 if inactive/expired and 400 if the max usage has already been hit.
  • POST /api/v1/discounts/apply (apply) Requires authentication plus a JSON body with code and invoice_id. Validates the voucher, ensures it hasnt been applied to that invoice, records the usage (discount_usage), increments times_used, and returns the refreshed voucher payload. Errors return 400/401/500 with 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 requires recipient, subject, and html_message. Optional parameters include:

    • profile Email profile name (e.g., 'communication', 'payment', 'default'). Uses MAIL_PROFILE_DEFAULT or 'default' if not specified.
    • reply_to_email Override reply-to email address
    • reply_to_name Override reply-to name
    • attachments Array of attachment objects: [{'path': '...', 'name': '...'}, ...]

    Supports multiple SMTP profiles via environment variables (MAIL_{PROFILE}_* or MAIL_DEFAULT_*). Features include:

    • DKIM signing (if configured)
    • Socket preflight checks
    • Debug mode (via MAIL_DEBUG env)
    • 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 from users.email and parents.secondparent_email as {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 csvEmails array

    Compares CSV emails against database emails and returns:

    • existed Emails present in both CSV and database
    • needToAdd Emails in database but not in CSV
    • counts Object with csv, db, users, and parents counts

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) Optional parent_id filter; 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 ID
      • parent_name Full name of the parent
      • students Array of students associated with this parent (id, firstname, lastname, school_id)
      • contacts Array of emergency contacts for this parent
      • parent_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 or 404.
  • 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) Requires parent_id, emergency_contact_name, cellphone, relation; optional email. Attaches the current year/semester before inserting.
  • PATCH /api/v1/emergency-contacts/{id} (update) Allows updating emergency_contact_name, cellphone, email, and relation.
  • 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 optional school_year query param. When ?upcoming=true, filters by expiration_date >= today. Returns {events: array, active_event_count: number}.
  • GET /api/v1/events/{id} (show) Fetch an event by ID or 404.
  • POST /api/v1/events (create) Creates a new event. Body requires event_name, amount, expiration_date. Optional: description, semester, school_year, flyer (file upload). Automatically sets created_by from session.
  • PATCH /api/v1/events/{id} (update) Updates an event. Allows updating event_name, description, amount, expiration_date, semester, school_year, and flyer (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: generateInvoice method 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 requires parent_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: generateInvoice may 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 by status and/or category, always constrained to the active year/semester.
  • GET /api/v1/expenses/{id} (show) Retrieve a single expense.
  • POST /api/v1/expenses (create) Body needs category, amount, description, date_of_purchase; fills metadata like school_year, semester, purchased_by, and status.
  • PATCH /api/v1/expenses/{id} (update) Allows selective updates (category/amount/description/retailor/date/status/status_reason) and stamps updated_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 by school_year, semester, status, and optional search query q. Returns charges with parent names and invoice numbers. Defaults to configured year/semester.

  • GET /api/v1/extra-charges/{id} (show) Retrieve a single charge or 404.

  • POST /api/v1/extra-charges (store) Creates a new charge. Body requires:

    • parent_id (integer, required) The user ID of the parent
    • title (string, required, min 2 chars)
    • amount (numeric, required)
    • charge_type (required, add or deduct)
    • due_date (nullable, date format)
    • invoice_id (nullable, integer) If provided, charge is immediately applied to invoice
    • description (optional string)
    • school_year (optional, defaults to configured year)
    • semester (optional, defaults to configured semester)

    When invoice_id is provided, the charge is automatically applied to the invoice (adjusting total_amount and balance). Dispatches extraCharge event 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 the invoice_id. Only works on charges with status applied.

  • 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 param q filters 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 memberships
    • guardian_id (optional) If provided without student_id, resolves to one of the guardian's students

    Returns:

    • students Simple list of all students (id, name) for dropdowns
    • search_students Student search dataset (id, firstname, lastname)
    • search_guardians Guardian search dataset (id, firstname, lastname, email, cellphone)
    • student Selected student info (if student_id provided)
    • 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 preferences
      • students Array of students in the family with grade information
      • invoices All invoices for guardians in this family
      • payments Recent payments (limit 10) for guardians
      • finance_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 param q (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/guardian
    • label Full name
    • sub 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 ID
    • student_id (optional) Resolves to primary family for that student
    • guardian_id (optional) Resolves to a family via guardian link or student parent_id

    Returns a single family object with:

    • Family details (all fields from families table)
    • guardians All guardians with full contact info
    • students All students with grade information
    • invoices All invoices for guardians
    • payments Recent payments (limit 10)
    • finance_summary Aggregated financial totals
    • invoice_map Invoice ID to number mapping
    • emergency_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-loaded students and guardians.
  • 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 with is_primary_home flag, 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 with parent_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 requires student_id, user_id, and optional relation (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 requires student_id, email, and optional firstname, lastname, relation (defaults to 'secondary').

Maintenance Actions:

  • POST /api/v1/families/set-primary-home (setPrimaryHome) Sets the is_primary_home flag for a student-family relationship. Body requires family_id, student_id, and is_primary_home (0/1).
  • POST /api/v1/families/set-guardian-flags (setGuardianFlags) Updates guardian flags. Body requires family_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 requires family_id and user_id.
  • POST /api/v1/families/unlink-student (unlinkStudent) Removes a student from a family. Body requires family_id and student_id.
  • POST /api/v1/families/import-second-parents (importSecondParentsFromLegacy) Imports second parents from legacy parents table. 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. Returns 400 for invalid filenames, 404 for missing files or disallowed extensions.
  • GET /api/v1/files/reimb/{name} (reimb) Streams a reimbursement file with the same security and caching features as receipt().
  • GET /api/v1/files/reimbursement/{name} (reimbursement) Alias for reimb() for backward compatibility.
  • GET /api/v1/files (index) Requires auth. Query param type must be one of receipts|reimbursements|checks (defaults to receipts). 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 to mime_content_type())
  • X-Content-Type-Options: nosniff header

Caching:

  • ETag generation based on filename, modification time, and file size
  • Last-Modified header support
  • 304 Not Modified responses when If-None-Match or If-Modified-Since conditions are met
  • Cache-Control: public, max-age=86400 header 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. Accepts class_section_id as 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 with student_id, school_id, firstname, lastname, and score, along with semester, schoolYear, and class_section_id metadata. 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 returns 201.
  • PATCH /api/v1/finals/{id} (update) Allows changing score and comment.

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 via SemesterScoreService::updateScoresForStudents().
  • GET /api/v1/midterm/management (showManagement) Returns midterm exam data for management view. Same as index but 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:api middleware).
  • 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. Supports date_from, date_to, and school_year query 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. Supports date_from, date_to, and school_year query 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. Supports school_year query 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. Supports date_from, date_to, and school_year query 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) Paginates current_flags with optional student_id, flag_type (or flag), state (or flag_state) filters. Also returns class sections (grades) array for UI dropdowns.
  • GET /api/v1/flags/{id} (show) Returns a single flag from current_flag table.
  • 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 for addFlag(). 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. Requires student_id (or student), flag (or flag_type), description (or open_description). Optional: flag_state, state_description, grade. Automatically sets semester and school_year from configuration. New flags default to Open state.
  • PATCH /api/v1/flags/{id}/state (updateState) Updates flag_state and/or state_description. Updates appropriate description field (open_description, close_description, or cancel_description) based on the new state.
  • POST /api/v1/flags/{id}/close (close) Alias for closeFlag(). Closes a flag and moves it to history.
  • POST /api/v1/flags/{id}/close-flag (closeFlag) Closes a flag and moves it to history. Requires state_description (or close_description) in request body. Updates flag state to Closed, sets updated_by_closed, then moves the flag from current_flag to flag table and deletes from current_flag.
  • POST /api/v1/flags/{id}/cancel (cancel) Alias for cancelFlag(). Cancels a flag and moves it to history.
  • POST /api/v1/flags/{id}/cancel-flag (cancelFlag) Cancels a flag and moves it to history. Requires state_description (or cancel_description) in request body. Updates flag state to Canceled, sets updated_by_canceled, then moves the flag from current_flag to flag table and deletes from current_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 fallback
    • user_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 Unauthorized if user is not logged in. Returns 200 OK with 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 metadata
    • teacher Returns teacher metadata including class_section_id
    • student Returns student metadata
    • parent / 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, semester
    • enrollment_deadline, refund_deadline
    • class_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 parents
  • students Array of students associated with the parent, including class section/grade information
  • attendance Attendance records for students filtered by current school year/semester
  • grades Final scores for students filtered by current school year/semester
  • enrollments Enrollment records for students filtered by current school year/semester
  • paymentBalance Latest invoice total amount for the parent
  • lastDayOfRegistration Enrollment deadline from configuration
  • withdrawalDeadline Refund deadline from configuration
  • school_year, semester Current term information

User Type Handling:

  • Supports primary, secondary, and tertiary user types
  • Automatically resolves parent ID for secondary/tertiary users from parents and authorized_users tables

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 or 404 if not found.

Log Fields:

  • id, school_year, semester
  • student_name, slip_date, time_in
  • grade, reason, admin_name
  • printed_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 params type=sent|inbox and read=true|false.
  • GET /api/v1/messages/{id} Ensures the caller is sender/recipient, marks as read.
  • POST /api/v1/messages Validates to, subject, body, auto-increments message_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, or
    • recipient_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 subject
    • message (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_number in 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 parameter type must be 'teacher' or 'parent':
    • teacher Returns all teachers from teacher_class assignments with their names
    • parent 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_id
  • subject, message
  • sent_datetime, read_status, read_datetime
  • message_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 Validates recipient_id and 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 assignment
    • parentOptions 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 new
    • label (string, required) Display label for the menu item
    • url (string, optional) URL path for the menu item
    • icon_class (string, optional) CSS class for icon
    • target (string, optional) Link target (e.g., '_blank')
    • menu_parent_id or parent_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:api middleware)
  • 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_items table)
    • Returns 403 Forbidden if 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_items table 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 optional read=true|false.
  • GET /api/v1/notifications/{id} Ensures the caller owns the record.
  • POST /api/v1/notifications/{id}/read Sets is_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, and isExpired flag
  • GET /api/v1/notifications/deleted (deletedNotificationsData) Returns soft-deleted notifications. Returns array of deleted notifications with id, title, message, priority, scheduled_at, expires_at, and deleted_at fields.
  • POST /api/v1/notifications/send (send) Creates and sends notifications to a target group. Body requires:
    • title (string, required) Notification title
    • message (string, required) Notification message content
    • target_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, and sms_sent counts.
  • 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:api middleware)
  • The send endpoint uses UserModel::getUsersByRole() to find users in the target group
  • Email sending uses EmailService for 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 from public/html/privacy_policy.html. Returns JSON response with content (HTML string) and type fields. Returns error if file is not readable or cannot be loaded.
  • GET /api/v1/pages/terms (termsOfService) Returns terms of service HTML content from public/html/terms_of_service.html. Returns JSON response with content (HTML string) and type fields. Returns error if file is not readable or cannot be loaded.
  • GET /api/v1/pages/help (helpCenter) Returns help center HTML content from public/html/help_center.html. Returns JSON response with content (HTML string) and type fields. 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 address
    • message (string, required, min 10 characters) Contact message content
    • Saves message to contactus table (uses ContactUsModel if supported, otherwise falls back to direct DB insert)
    • Sends email notification to alrahma.isgl@gmail.com using EmailService
    • Returns success response with email and email_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 ContactUsModel but 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 includes student_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 in ParentFlowsTest.
    • 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 via SemesterScoreService::updateScoresForStudents().
  • GET /api/v1/participation/management (showManagement) Returns participation data for management view. Same as index but 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:api middleware).
  • 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 or 404 if 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_amount to 0, balance_amount to total_amount, and status to '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 requires paid_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 param search_term (required). Returns:
    • parent Parent user data (excluding password)
    • students Students associated with the parent
    • payments Paginated payment history
    • invoices Invoices with calculated balances (total - paid - discounts - refunds)
    • today_ymd Current date
    • installment_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 is check), 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 paymentReceived event 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 is check), 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 by school_year and semester query 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) OR student_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 with mode=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 paymentReceived and studentEnrolled events
  • 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:api middleware) 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 pagination
    • per_page (integer, optional, default: 20, max: 100) Number of records per page
    • from (string, optional) Filter logs sent on or after this date
    • to (string, optional) Filter logs sent on or before this date
    • type (string, optional) Filter by notification type: no_payment or installment
    • 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 balance
    • type (string, optional) Notification type: no_payment or installment. If not provided, automatically detected based on payment history
    • school_year (string, optional) School year to process (defaults to configured school year)
    • force (integer, optional, default: 0) Set to 1 to bypass idempotency check and send even if already sent this month
    • Returns summary with sent, skipped, failed counts and detailed results array

Notification Behavior:

  • Single Parent Mode: When parent_id is 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)
  • Bulk Mode: When parent_id is 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_logs table
  • One notification per parent per month per type (unless force=1)
  • Checks period_year, period_month, type, and parent_id

Notification Types:

  • no_payment Parent has no payment history for the school year
  • installment Parent has made at least one payment for the school year

Notes:

  • All endpoints require authentication (auth:api middleware)
  • Email sending uses EmailService with 'finance' profile
  • Notifications are logged in payment_notification_logs table 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 pagination
    • per_page (integer, optional, default: 20, max: 100) Number of records per page
    • payment_id (integer, optional) Filter transactions by payment ID
    • status (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. Returns 404 if not found.
  • GET /api/v1/payment-transactions/payment/{paymentId} (getByPayment) Returns all transactions for a specific payment, ordered by transaction date (newest first). Returns 404 if 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 identifier
    • payment_id (integer, required) Reference to the payment record
    • amount (numeric, required, min: 0) Transaction amount
    • payment_method (string, required, max: 50) Payment method (e.g., 'cash', 'check', 'card')
    • transaction_date (string, optional) Transaction date in Y-m-d H:i:s format (defaults to current date/time)
    • transaction_fee (numeric, optional, min: 0) Transaction fee (defaults to 0)
    • payment_reference (string, optional, max: 255) Payment reference number
    • is_full_payment (integer, optional) Flag indicating full payment: 0 for installment, 1 for full payment (defaults to 0)
    • Automatically sets payment_status to 'Pending' and includes current school_year and semester from configuration
    • Returns 201 with 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 transactionId can be either the numeric id or the string transaction_id
    • Returns updated transaction data on success, 404 if 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_payment flag
  • Default status is 'Pending' when created
  • Automatically includes school_year and semester from system configuration
  • Supports transaction fees and payment references

Notes:

  • All endpoints require authentication (auth:api middleware)
  • 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_date descending when retrieved by payment ID
  • The controller uses PaymentTransactionModel which provides helper methods like getTransactionsByPaymentId() and updateTransactionStatus()

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 pagination
    • per_page (integer, optional, default: 20, max: 100) Number of records per page
    • q (string, optional) Search keyword that searches across multiple fields:
      • transaction_id PayPal transaction identifier
      • payer_email Payer's email address
      • event_type PayPal webhook event type
      • order_id Order identifier
      • parent_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. Returns 404 if not found.
  • GET /api/v1/paypal-transactions/transaction/{transactionId} (getByTransactionId) Returns a transaction by PayPal transaction ID (string). Returns 404 if 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 as index endpoint)
    • 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 (q parameter) 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:api middleware)
  • Transactions are ordered by created_at descending (newest first)
  • CSV export returns all matching records without pagination
  • The controller uses PayPalPaymentModel which 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.php view with that data
    • If the partial returns HTML string, uses it directly
    • Returns JSON response with html field containing the rendered policy content
    • Returns 404 if the partial file is not found
  • 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.php Blade view with the metadata
    • Returns JSON response with both meta (data array) and html (rendered content) fields
    • Returns 404 if the partial file is not found
    • Falls back to JSON-encoded meta if the Blade view doesn't exist

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 current style_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 years
      • selectedYear Currently selected school year
      • semesters Array of available semesters for selected year
      • selectedSemester Currently selected semester
      • students 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 IDs
    • roles (array, optional) Map of user_id => role label
    • classes (array, optional) Map of user_id => class name
    • school_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 with primary_count and secondary_count sticker requirements
      • totals 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:api middleware)
  • 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 classSection and semester_scores tables

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 ID
    • class_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 by project_index for the current semester and school year.
  • POST /api/v1/projects (store) Create a new project entry. Body parameters:
    • student_id (integer, required) Student ID
    • class_section_id (integer, required) Class section ID
    • project_index (integer, required) Project index/column number
    • score (float, optional) Project score
    • comment (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 score
    • comment (string) Project comment
    • project_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's teacher_class record. Returns:
    • students Array of students with their project scores organized by project index
    • project_headers Array of project index values (column headers)
    • semester Current semester
    • school_year Current school year
    • class_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 SemesterScoreService after 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 created
      • students_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 ID
      • students Array of students in the class section
      • project_headers Array of project index values
      • semester Current semester
      • school_year Current school year
      • class_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 IDs
    • semester (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 SemesterScoreService after saving
    • Returns success message

Notes:

  • All endpoints require authentication (auth:api middleware)
  • 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-project endpoint automatically determines the teacher's class section from the teacher_class table
  • Session is used to persist class_section_id for 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 number
    • supplier_id (integer, required) Supplier ID
    • order_date (date, required) Order date (Y-m-d format)
    • expected_date (date, optional) Expected delivery date
    • status (string, optional) Status: 'draft' or 'ordered' (default: 'ordered')
    • notes (string, optional) Notes
    • tax (float, optional) Tax amount (default: 0.00)
    • Modern JSON format:
      • items (array, required) Array of item objects:
        • supply_id (integer, required) Supply/inventory item ID
        • description (string, optional) Item description
        • quantity (integer, required) Quantity ordered
        • unit_cost (float, required) Unit cost
    • CodeIgniter-style form arrays:
      • item_supply_id[] (array, required) Array of supply IDs
      • item_description[] (array, optional) Array of descriptions
      • item_quantity[] (array, required) Array of quantities
      • item_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 status
    • expected_date (date) Expected delivery date
    • notes (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_qty on purchase order items
    • Updates inventory item quantities (if supply_id maps to inventory_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:api middleware)
  • Purchase orders support statuses: 'draft', 'ordered', 'received', 'canceled'
  • When receiving items, the system automatically updates inventory quantities and creates movement records
  • The store method 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 ID
    • class_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 by quiz_index for the current semester and school year.
  • POST /api/v1/quizzes (store) Create a new quiz entry. Body parameters:
    • student_id (integer, required) Student ID
    • class_section_id (integer, required) Class section ID
    • quiz_index (integer, required) Quiz index/column number
    • score (float, optional) Quiz score
    • comment (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 score
    • comment (string) Quiz comment
    • quiz_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 index
      • quiz_headers Array of quiz index values (column headers)
      • semester Current semester
      • school_year Current school year
      • class_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 SemesterScoreService after 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 created
      • new_quiz_id ID of the first inserted quiz record
      • students_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 ID
      • students Array of students in the class section
      • quiz_headers Array of quiz index values
      • semester Current semester
      • school_year Current school year
      • class_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 IDs
    • semester (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 SemesterScoreService after saving
    • Returns success message

Notes:

  • All endpoints require authentication (auth:api middleware)
  • 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-scores endpoint normalizes single score inputs to quiz_index 1 for backward compatibility
  • Session is used to persist class_section_id for 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 by parent_id or status when reviewing requests.
  • POST /api/v1/refunds Auth-required; body must include parent_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 match email
      • cellphone (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/checked
      • captcha (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 guest
      • no_second_parent_info (boolean/string, optional) If '1' or true, skips second parent information
    • Second parent fields (required if is_parent is true and no_second_parent_info is false):
      • second_firstname (string, required) Second parent first name
      • second_lastname (string, required) Second parent last name
      • second_gender (string, required) Second parent gender: 'Male' or 'Female'
      • second_email (string, required) Second parent email address
      • second_cellphone (string, required) Second parent phone number
    • Process:
      1. Validates all input fields
      2. Checks CAPTCHA answer against session
      3. Verifies email is not already registered (checks for pending activation)
      4. Determines role ('parent' or 'guest') based on is_parent flag
      5. Generates unique token for email confirmation
      6. Creates user record with formatted data
      7. Assigns role to user
      8. Optionally creates second parent record if applicable
      9. Sends confirmation email with activation link
      10. 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

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 = 0 and status = '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 EmailService with 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 by status or reimbursed_to.
  • POST /api/v1/reimbursements Requires amount, reimbursed_to, description, and expense_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 incoming rfid, finds the matching user or student, logs to scan_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 ID
      • name Role name
      • description Role description
      • user_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 name
      • slug (string) Role slug
      • description (string) Role description
      • dashboard_route (string) Dashboard route
      • priority (integer) Priority value
      • is_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 ID
      • name Permission name
      • description Permission description
      • created_at Creation timestamp
      • updated_at Update timestamp
    • POST /api/v1/rolepermission/permissions (storePermission) Create a new permission. Body parameters:
      • name (string, required) Permission name
      • description (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 name
      • description (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 details
      • permissions All available permissions
      • role_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 ID
        • firstname First name
        • lastname Last name
        • email Email address
        • account_id Account ID
        • roles 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:api middleware)
  • 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 staff table 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 user
    • auto_redirect Boolean flag indicating if user has only one role (true) or multiple roles (false)
    • route Dashboard route for the role (only present when auto_redirect is true)
    • role Role name (only present when auto_redirect is true)
    • current_role Currently active role from session (only present when auto_redirect is false)
    • If user has only one role, returns auto_redirect: true with the route to automatically redirect
    • If user has multiple roles, returns auto_redirect: false with 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_role in session
    • Returns:
      • role The role name that was switched to
      • route Dashboard route for the role (from RoleModel::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 as switchRole but accepts role as URL parameter instead of request body.

Notes:

  • All endpoints require authentication (auth:api middleware)
  • Role matching is case-insensitive and works with both role names and slugs
  • Dashboard routes are retrieved from the roles table using RoleModel::getRouteByNameOrSlug()
  • Default route is /landing_page/guest_dashboard if no route is found for the role
  • Session stores the active role as active_role for 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_year and semester metadata
  • 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 format
    • description (string, optional) Event description
    • notify_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 format
    • description (string) Event description
    • notify_parent (boolean) Whether to notify parents
    • notify_teacher (boolean) Whether to notify teachers
    • notify_admin (boolean) Whether to notify admins
    • no_school (boolean) Whether this is a no-school day
    • school_year (string) School year
    • semester (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:api middleware)
  • 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_school are always visible to all audiences
  • FullCalendar view endpoints format events with:
    • id Event ID
    • title Event title (with "no school" phrase title-cased if applicable)
    • start Event date (FullCalendar expects 'start' field)
    • description Event description
    • extendedProps Object containing semester, school_year, notification flags, no_school flag, and backgroundColor
  • The controller uses the date field in the database (not start_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 ID
    • semester (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 saved and errors arrays
  • 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 text
    • reviews (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_reviewer config) 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 semester
      • school_year Current school year
      • class_section_id Class section ID
    • Only loads comments for score types: ptap, midterm, final
    • Stores class_section_id in 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 ID
    • score_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:api middleware)
  • 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 configuration table with key comment_reviewer
    • Value should be a comma-separated list of role names (e.g., "administrator,head_of_department")
    • Only reviewers can update comment_review and reviewed_by fields
    • Reviewer check is case-insensitive
  • 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 teacher
    • class_section_id Class section ID
    • class_section_name Name of the class section
    • mains_text Main teachers assigned to the section
    • tas_text Teaching assistants assigned to the section
    • active_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 ID
      • school_years Available school years from semester_scores
      • selected_year Selected school year
      • selected_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 as updateScores with table='final_exam'.
  • POST /api/v1/scores/update-midterm (updateMidtermScores) Update midterm exam scores. Same as updateScores with 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_id
    • semester (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:api middleware)
  • 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_scores table and override calculated values if present
  • Total semester days are retrieved from configuration: total_semester1_days (Fall) or total_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 ID
        • school_id School ID
        • firstname First name
        • lastname Last name
        • class_section_id Class section ID
        • fall_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 year
      • class_sections All available class sections
      • selected_class_section_id Selected class section ID (if filtered)
      • semester Current semester
      • stats Statistical data:
        • mean Mean of spring semester scores
        • std Standard deviation of spring semester scores
        • target_trophy Trophy threshold from configuration
        • target_pass Pass threshold from configuration
    • Students are sorted by final average (descending)
    • Trophy winners are determined per class section using:
      1. All students at/above trophy threshold (minimum 94.0 or configured value)
      2. Minimum trophies: max(ceil(class_size / 4), 3), capped at class size
      3. Tolerance tie-break: students within 0.2 points of last included winner

Notes:

  • All endpoints require authentication (auth:api middleware)
  • Trophy threshold: minimum 94.0, or higher if configured in trophy_score
  • Pass threshold: from pass_score configuration (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 Validates message and 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 includes success, timeout, warning_time, check_interval, logout_url, keep_alive_url, and check_url.
  • GET /api/v1/session/checkTimeout (checkTimeout) Requires auth. Checks the current session's last activity timestamp against the configured timeout duration. Returns status (active, warning, or expired) and time_remaining in seconds. If session has expired, returns status: 'expired' with redirect URL and message.
  • POST /api/v1/session/pingActivity (pingActivity) Requires auth. Updates the session's last_activity timestamp to keep the session alive. Only updates if the session is still valid (not already expired). Returns status: 'active' and time_remaining set to the full timeout duration. If session has already expired, returns the same expired response as checkTimeout.

Session Management:

  • Tracks user activity via last_activity session 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_mm for PDF customization.
  • GET /api/v1/slips/preview (preview) Requires auth. Returns a list of recent late slip logs with optional filtering by school_year and semester query 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. Returns ok, text (formatted slip text), and width (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 includes issues_count (total count of teachers/TAs without class assignments), semester, and school_year metadata.
  • GET /api/v1/staff/{id} (show) Requires auth. Returns a single staff member by ID with school_id attached.
  • POST /api/v1/staff (store) Requires auth. Creates a new staff member. Accepts fields: firstname, lastname, email, phone, role_name (automatically sets active_role to lowercase version), school_year (optional, defaults to configured year), status (optional, defaults to 'Active'). Automatically sets created_at and updated_at timestamps.
  • PATCH /api/v1/staff/{id} (update) Requires auth. Updates a staff member. Accepts any of: firstname, lastname, email, phone, role_name (updates active_role if provided), school_year, status. Only updates fields that are provided and non-empty. Automatically updates updated_at timestamp.
  • 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|financial query 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. Accepts student_id and class_section_id. Updates student_class table, 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. Accepts class_id (or class_section_id to derive class_id), students_per_section, and optional school_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: schoolYear or school_year to 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 assign
    • class_section_id (required) ID of the class section
    • teacher_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 reason
    • reason_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 servers 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 palettes
    • menu (optional) Menu color palette name from available palettes, or custom for custom colors
    • menu_bg (optional) Custom menu background color in hex format (e.g., #0f172a or 0f172a)
    • menu_text (optional) Custom menu text color in hex format (e.g., #ffffff or ffffff)
    • menu_mode (optional) Menu mode: light, dark, or auto (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 name
    • menu (optional) Menu color palette name or custom
    • menu_bg (optional) Custom menu background color in hex format
    • menu_text (optional) Custom menu text color in hex format
    • menu_mode (optional) Menu mode: light, dark, or auto
    • 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_mode is auto
  • 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 optional sort=id|firstname|lastname|email|role and order query 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 provided role_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 associated user_roles rows.
  • 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 (requires current_password), password (requires current_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 (requires parent_ids array)
    • class: Send invites to all parents in a specific class (requires class_section_id)
    • all: Send invites to all parents across all classes

    Triggers whatsapp_invites.send event 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') and subject_id to 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. type must be one of homework|quiz|project|midterm|final|test|comments. Optional class_section_id and student_id parameters. 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, comments
    • student_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 with class_section_id and class_section_name
    • students_by_section Array keyed by section_id, containing students with their PTAP scores and semester scores
    • semester Current semester
    • school_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:
      • uploads base directory
      • uploads/reimbursements
      • uploads/receipts
      • uploads/checks
    • Database schema: Verifies existence of critical tables and required columns:
      • user_preferences table and timezone column
      • settings table and timezone column
      • migrations table

    Returns JSON payload with:

    • ok (boolean) Overall health status
    • paths (array) Status of each filesystem path with label, path, exists, writable
    • database (object) Database schema checks with table/column existence flags
    • write_path (string) Base storage path
    • timestamp (string) ISO 8601 timestamp of the check

    HTTP Status Codes:

    • 200 OK All checks passed
    • 503 Service Unavailable One or more checks failed

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 optional class_section_id query 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 param class_section_id (required). Returns:

    • homework_scores Scores grouped by student ID
    • students List of students in the class section
    • homework_headers Array of unique homework_index values
    • semester, school_year, class_section_id
    • has_homework_cols Boolean indicating if any homework columns exist
  • GET /api/v1/homework/students-with-scores (getStudentsWithScores) Returns students with their homework scores. Query param class_section_id (required). Returns students array with student_id, firstname, lastname, and scores object 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 number
    • new_homework_id ID of the first inserted record
    • students_processed Number of students for whom the column was added
  • PATCH /api/v1/homework/{id} (update) Updates a single homework entry. Allows updating score and/or comment fields.

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 period
    • end_date (optional, default: '2026-01-18') End date for the tracking period
    • page (optional, default: 1) Page number for paginated teacher/section results (8 per page)

    Returns:

    • semester Current semester
    • school_year Current school year
    • sundays Array of all Sunday dates (Y-m-d format) within the date range, starting from the first Sunday on/after start_date
    • event_days Object mapping dates (Y-m-d) to boolean true for no-school days from calendar events
    • date_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 ID
      • class_id Class ID (for sorting: KG=13, Grades 1-11, Youth=12)
      • class_section_name Name of the class section
      • teachers Array of main teacher names
      • tas Array of TA names
    • has_homework Nested object: {class_section_id: {homework_index: true}} indicating which sections have homework for which indices
    • hw_entered_at Nested object: {class_section_id: {homework_index: 'Y-m-d'}} with first creation date per homework index
    • has_homework_by_date Nested object: {class_section_id: {sunday_date: true}} mapping homework to the nearest prior non-no-school Sunday
    • hw_entered_at_by_date Nested object: {class_section_id: {sunday_date: 'Y-m-d'}} with earliest entry date per Sunday
    • pagination Pagination metadata:
      • page Current page number
      • total_pages Total number of pages
      • per_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 by type (classroom/book/office/kitchen), school_year, and semester. 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 requires name, type, optional category_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. Updates updated_by automatically.
  • DELETE /api/v1/inventory/{id} (delete) Remove an inventory item.

Category Management:

  • POST /api/v1/inventory/categories (saveCategory) Create or update a category. Body requires type, name, optional description. 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 requires needs_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 optional school_year query 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 requires mode (in/out/adjust), quantity (> 0), optional reason, 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 requires item_id, class_section_id, student_ids (array), optional note. 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, semester for 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 requires item_id, qty_change, movement_type (initial/in/out/adjust/distribution), optional reason, note, semester, school_year, teacher_id, student_id, class_section_id. Automatically sets performed_by from session.
  • PATCH /api/v1/inventory/movements/{id} (movementsUpdate) Update a movement. Allows updating all fields except item_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 requires ids (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 or 404 if not found.
  • GET /api/v1/invoices/management-data (managementData) Composite data for invoice management view. Returns:
    • schoolYears Available school years from invoices
    • invoices Array of parent invoice summaries with:
      • parent_name, parent_id
      • enrolledKids Array of enrolled students with name, grade, tuition_fee
      • withdrawnKids Array of withdrawn students
      • invoice_amount, refund_amount, invoice_date, last_updated, invoice_id
    • Query params: schoolYear or year (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 requires parent_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 requires parent_id and status. 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 sets school_year and semester from 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 requires status field.
  • 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_charges table (add/deduct types)
  • Balance calculation: total_amount - discounts - refunds_paid - payments_received

Helper Methods:

  • calculateTuitionFee() Calculates tuition based on enrolled/withdrawn students and refund window
  • calculateTotalTuitionFee() Computes total tuition with regular/youth fee logic
  • recalculateAndUpdateDiscount() Recalculates and updates discount amounts for invoices
  • prepareInvoiceData() Prepares comprehensive invoice data for display/PDF
  • getGradeLevel() 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 by status=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 or 404 if not found.
  • POST /api/v1/ip-bans/unban (unban) Unban IP(s). Body accepts:
    • id (integer) Unban by record ID
    • ip (string) Unban by IP address
    • all (integer, 1) Unban all active bans (sets blocked_until to null and attempts to 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 ban
    • blocked_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, or
    • ip (string) Ban by IP address
    • hours (integer, default 24) Number of hours to ban (minimum 1, defaults to 24)
    • Calculates blocked_until automatically from current time + hours
    • Sets attempts to max(current attempts, 10) for clarity
    • Returns IP address, blocked_until date, and hours