Project · active

AM HRIS

A full-stack employee time tracking, leave management, and payroll system with role-based access control and audit logging.

Sun, February 22, 2026
6 min read
View on GitHub
Tech Stack:
Next.js 16 TypeScript Tailwind CSS v4 Prisma ORM PostgreSQL Better Auth TanStack Query TanStack Table React Hook Form Zod Vitest shadcn/ui
LOC 5,435
Languages TypeScript, TSX, CSS
Files 89

Overview

AM HRIS is a full-stack Human Resource Information System built for small to medium-sized teams. It handles employee time tracking, leave management, payroll calculation, and staff directory management under a single dashboard with role-based access control.

The system was built in a weekend to explore how modern Next.js patterns — Server Actions, React Query hydration, and middleware-based auth — could replace traditional HR tools that charge per-seat pricing. The result is a self-hosted, zero-cost alternative that an organization can deploy on Vercel with a PostgreSQL backend.

Live Demo: Not deployed publicly (self-hosted architecture) Source Code: github.com/brian-dizon/nextjs-am_hris


Problem It Solves

Small teams and startups often rely on spreadsheets or expensive SaaS tools for basic HR operations. The gap between “free but manual” and “automated but costly” leaves many organizations with broken workflows: employees forget to log hours, leave requests get lost in email threads, and payroll calculations become error-prone guesswork.

AM HRIS closes that gap with an integrated system where time tracking feeds directly into payroll, leave balances are enforced automatically, and every administrative action is logged for compliance.


Architecture

The application follows a modular Next.js App Router structure with clear separation between public auth pages and protected dashboard routes.

Route Groups

  • (auth) — Login, password change, and initial setup flows
  • (dashboard) — All authenticated functionality: dashboard, directory, timesheet, leave, payroll, approvals, activity log
  • api/auth/[...better-auth] — Better Auth API endpoints for session management

Data Flow

  1. Authentication — Better Auth handles email/password login with session cookies, role assignment, and password change enforcement via middleware (proxy.ts)
  2. Dashboard Hydration — Server components prefetch critical data (active timer, time stats) via React Query dehydration; secondary data (weekly logs, admin feeds) streams in via Suspense
  3. Mutations — Server Actions handle all writes (clock in/out, leave requests, staff CRUD) with automatic cache revalidation
  4. Audit Trail — Every administrative action creates an immutable audit log capturing actor identity, IP address, before/after state

Database Schema

PostgreSQL with Prisma ORM. Key models:

  • User — Employee profiles with role (ADMIN/LEADER/EMPLOYEE), manager relationship, org membership
  • Organization — Multi-tenancy boundary; all data scoped by org
  • TimeLog — Clock in/out sessions with duration, status (pending/approved/rejected), type (work/break/leave)
  • TimeCorrection — Requests to modify existing time logs with approval workflow
  • LeaveRequest — Vacation, sick, earned, and emergency leave with balance enforcement
  • LeaveBalance — Per-user, per-type balance tracking
  • AuditLog — Immutable compliance log with JSON snapshots of changed data
  • OrganizationInvitation — Token-based email invitations for onboarding

Key Technical Decisions

Better Auth over NextAuth.js

Better Auth was chosen for its built-in admin plugin, role-based access control, and organization-aware session management. The admin plugin provides user creation, banning, and impersonation APIs out of the box — features that would require custom code in NextAuth.js.

Server Actions with TanStack Query

All data mutations use Next.js Server Actions for direct database access without API routes. TanStack Query provides optimistic updates, deduplication, and background refetching on the client. The combination eliminates the need for a separate REST or tRPC layer while keeping the UI responsive.

Middleware-Based Route Protection

The proxy.ts middleware checks session validity on every dashboard request. Unauthenticated users redirect to login; authenticated users on auth pages redirect to dashboard. Password change enforcement happens at the middleware level — users with requirePasswordChange: true cannot access any route except /change-password.

Audit Logging as a Side Effect

Every administrative action (staff creation, leave approval, timesheet correction) triggers an audit log via a utility function. The design captures before/after state as JSON, ensuring compliance trails survive even if the original record is modified or deleted.


What Was Built

Time Tracking

A real-time clock in/out system with live timer display. Employees see their active session duration updating every second. Admins and leaders view an organization-wide live feed of who is currently clocked in. Time logs support manual entry, correction requests, and approval workflows.

Leave Management

Employees submit leave requests with date range selection and reason. The system calculates net working days, validates against available balance, and checks for overlapping requests. Managers approve or reject with a single action; approved requests automatically deduct from balance.

Payroll Calculation

Admins generate payroll reports for arbitrary date ranges. The system aggregates approved time logs per employee, calculates total hours, and presents a sortable, exportable table. CSV export is built-in for accounting handoff.

Staff Directory

Role-gated directory with add, edit, and reset-password capabilities. Admins can invite new staff via email, assign managers, and set leave balances. Leaders have read-only access to their subordinates. The directory uses TanStack Table for sorting, filtering, and pagination.

Approvals Dashboard

A unified inbox for managers showing pending time corrections, manual time entries, and leave requests. Approval actions trigger audit logs and notify affected employees via cache invalidation.

Activity Log

Admin-only view of all audit logs across the organization. Filterable by action type, user, and date range. Each entry shows the actor, target entity, before/after state, and metadata (IP, user agent).


Metrics

MetricValue
Total LOC5,435
Files89
LanguagesTypeScript, TSX
Test CoverageStaff actions, timer logic
Database Models14

Lessons Learned

Server Actions simplify CRUD but require careful cache invalidation. Every mutation needs explicit revalidatePath and revalidateTag calls. Missing one creates stale UI that confuses users.

Role-based UI gating belongs in two places. The middleware blocks route access, but components must also conditionally render admin features. Keeping role checks consistent between server and client prevents security gaps.

Audit logging should be fire-and-forget. Wrapping audit creation in try/catch ensures a logging failure does not crash the primary transaction. The tradeoff is potential silent audit gaps — acceptable for a weekend build, but production systems should queue audit writes.

Better Auth’s admin plugin saves days of work. User creation, password resets, and role management are non-trivial to build securely. The plugin handles hashing, session rotation, and cross-subdomain cookies automatically.


Next Steps

  • Email notifications — Send approval/rejection emails via Resend or SendGrid
  • Shift scheduling — Allow admins to define recurring shifts and auto-clock expectations
  • Overtime rules — Configurable thresholds for overtime calculation per jurisdiction
  • Payslip generation — PDF export with tax and deduction support
  • Biometric integration — Clock in via fingerprint or face recognition APIs