Enterprise HR Platform
DOPA Faculty Management System
Payroll, scheduling, and role-based access for a coaching institute's entire faculty operation.
Overview
Problem
Faculty payroll, class scheduling, and staff record-keeping were spread across spreadsheets and manual approvals. There was no single source of truth for who was scheduled where, what they were owed, or who could see what — and every payroll cycle meant reconciling data by hand.
Solution
A single internal platform where payroll, scheduling, and staff records live in one system, gated by role-based access so faculty, coordinators, and admins each see exactly what their role requires — nothing more.
Architecture
Client
Next.js App Router UI, server components for data-heavy views, role-aware navigation.
API
Next.js route handlers enforcing auth + RBAC checks before touching data.
Auth
JWT-based sessions with role claims; middleware guards protected routes.
Data
MongoDB with schemas for staff, schedules, payroll runs, and audit history.
- Role-based access control is enforced at the API boundary, not just hidden in the UI — every route handler checks the caller's role before executing a query.
- Payroll calculations run server-side and are logged per run, so every figure is traceable back to the schedule data that produced it.
- Scheduling and payroll share the same underlying staff/attendance records, so there's one source of truth instead of two systems drifting apart.
Feature Breakdown
- Role-scoped dashboards for admin, coordinator, and faculty accounts
- Payroll runs generated from logged schedules and attendance, with an auditable history
- Faculty scheduling with conflict detection across time slots
- Permission-scoped staff records — each role sees only what it's authorized to
Implementation Detail
export async function withRole(role: Role, handler: Handler) {
return async (req: Request) => {
const session = await getSession(req);
if (!session || !session.roles.includes(role)) {
return Response.json({ error: "Forbidden" }, { status: 403 });
}
return handler(req, session);
};
}Challenges & Solutions
Payroll figures needed to be trustworthy — a wrong number erodes confidence in the whole system immediately.
Payroll runs are computed from immutable schedule/attendance snapshots and stored as an auditable record, so any figure can be traced back to its source data.
Different roles needed meaningfully different views of the same data without maintaining separate codebases per role.
Centralized RBAC middleware that scopes queries and UI rendering from a single role definition, checked at the API layer.
Results
- Payroll and scheduling run out of one system instead of three separate spreadsheets that had to be manually cross-checked.
- Coordinators and admins each get a dashboard scoped to their role, instead of one shared spreadsheet everyone could edit.
- Every payroll figure now has an audit trail back to its source data — previously, a disputed number meant digging through email history.
Lessons Learned
- The distinction between roles and permissions mattered more than expected — modeling them separately from the start avoided a rewrite when a coordinator later needed one admin-level capability.
- Logging *why* a payroll figure came out a certain way, not just the figure itself, turned out to be what actually built staff trust in the system.
Gallery
Screenshots to be added.