All Projects
API
Kwara State Polytechnic Staff API
A comprehensive backend API for managing staff profiles, institutional hierarchy, appointments, and internal communications for Kwara State Polytechnic.
Role: Backend Lead
Problem Statement
The institution needed a centralized, secure, and structured system to manage a complex hierarchy of academic and non-academic staff, institutes, and departments, while securely handling administrative appointments, portal news, and internal events.
Target users: Polytechnic administrators, institute directors, heads of departments, and general staff members.
Project Walkthrough
When building the Kwara State Polytechnic Staff API, the primary challenge was digitizing a highly complex institutional hierarchy. The polytechnic needed a robust, centralized backend to manage thousands of staff members across various institutes, departments, and administrative roles. I designed a layered Node.js/Express architecture, focusing heavily on strict data modeling with Mongoose to accurately represent the intricate web of academic designations—from Chief Lecturers to Institute Directors and HODs.
One of the most critical engineering decisions I made was how to handle role-specific data. Rather than polluting the core Staff model with fields only relevant to specific leadership roles, I created dedicated models (like Director and Hod) that are dynamically referenced based on a staff member's current appointment. This kept the database normalized and the business logic incredibly clean. I also implemented a robust JWT-based authentication system with refresh token rotation, alongside custom Express middlewares that strictly enforce role-based access control down to specific appointment types.
Beyond core CRUD functionality, the system needed to be resilient and efficient at scale. I integrated Agenda for MongoDB-backed cron jobs to handle automated state changes, built a custom response utility middleware to ensure API responses were 100% consistent, and engineered a batch-processing bulk onboarding script capable of safely migrating large JSON datasets into the database.
Tech Stack
Languages
Frameworks
Databases
Cloud & Infrastructure
Dev Tools
Authentication
JWT (JSON Web Tokens) with refresh token rotation, bcrypt for password hashing, and role/appointment-based access control.
Third-Party APIs & Integrations
Cloudinary (image/avatar storage)
Paystack (payment initialization and account resolution)
Google APIs (SMTP/Email services)
System Architecture
Architecture Pattern
MVC-inspired layered architecture (Routes -> Middlewares -> Controllers -> Services -> Models).
Request Data Flow
Client Request → Helmet/CORS Security → Route Definitions → Joi Payload Validation → Auth/RBAC Middleware → Controller Logic → Mongoose Models → Unified Custom Response Utility.
Key Engineering Decisions
1. Extracted all response formatting into a custom `responseUtilities` middleware for strict API shape consistency. 2. Used `express-async-errors` to completely eliminate repetitive try/catch blocks in controllers. 3. Abstracted all errors into custom Error classes mapped to a centralized HTTP Error Codes dictionary. 4. Utilized `agenda` and `agendash` for robust, database-backed background job scheduling.
Database Design
Highly relational schema design over MongoDB. The core `Staff` collection utilizes strict enums for designations (e.g., 'Chief Lecturer', 'Technologist II') and departments. Role-specific metadata is normalized into separate collections (`Director`, `Hod`) that are referenced by the `Staff` document to prevent schema pollution. Other key collections include `Admin`, `NewsEvents`, `Gallery`, and `Job`.
Module Structure
Key Features & Implementation
Hierarchical Authentication & Authorization
Role-based access control that distinguishes between general Staff and Admins, with deeper checks for specific institutional appointments.
How it was built
Implemented via custom middlewares and JWT. Beyond standard token validation, controllers actively check `req.loggedInAccount.appointment` to restrict actions. For example, only a staff member with the 'Head of Department' enum can update HOD-specific data.
Bulk Staff Onboarding
Allows administrators to quickly import large batches of staff members from JSON data exports.
How it was built
Engineered a memory-efficient batch processing script in the auth controller. It reads data, slices it into chunks of 50, strictly validates/formats inputs, skips existing emails/IDs, and uses `Staff.insertMany` to write to the DB. It returns a detailed report of created vs. skipped users.
Institutional Role Management
Manages complex relationships between Staff, Directors, and HODs based on their current academic or administrative appointment.
How it was built
Used Mongoose references. When a staff member is assigned a Director or HOD role, dedicated records are created in those respective collections and their ObjectIDs are attached to the core `Staff` document. This keeps role-specific data (like 'welcomeAddress' or 'vision') separate from standard staff data.
Automated Background Jobs
Automatically expires old jobs or appointments without manual administrative intervention.
How it was built
Integrated `agenda` to run MongoDB-backed cron tasks. The `activate-cron.js` script queries for active jobs with a `completedDate` in the past, updates their status to 'expired', and saves them.
Challenges & Engineering Decisions
Designing the `Staff` schema was a significant challenge due to the complex institutional hierarchy. Kwara State Polytechnic has dozens of designations (from Chief Lecturer to Assistant Lecturer), diverse departments, institutes, and specific administrative appointments (Rector, Registrar, HOD, Director). I solved this by using strict Mongoose enums and referencing separate `Director` and `Hod` models for appointment-specific metadata rather than polluting the core `Staff` schema.
Handling bulk staff onboarding was another technical hurdle. Reading and writing thousands of records at once risked memory bloat and database timeouts. I implemented a `formStaffRegisterBulk` function that processes large JSON arrays in batches (e.g., 50 at a time) using `Staff.insertMany`, gracefully skipping existing records or invalid entries.
To maintain code cleanliness across a large controller footprint, I integrated `express-async-errors` and a centralized error handling middleware. This allowed me to throw custom error classes directly from business logic without writing a single try-catch block in the controllers.
API Documentation
API Route Namespaces