Skip To Content

HRIS

A human resource information system for employee records, attendance, overtime, leave, and documents, with a seat-based subscription billed through Midtrans. Next.js on the front, Go and PostgreSQL behind it, deployed to Azure from GitHub Actions.

links

stack

Next.js

nextjs

TypeScript

typescript

Go

go

Gin

gin

PostgreSQL

postgresql

Supabase

supabase

Tailwind CSS

tailwindcss

Docker

docker

HRIS is a team project on the SukaMajuu org. The brief was an HR tool that a real HR team could run its day on. That meant employee records, legal documents, attendance and clock-in, overtime and leave approval, and a paid tier for teams past a seat count.

Five of us built it. I was the largest contributor by commit count and I carried most of the frontend plus the subscription path on the backend.

What the product does

Employees clock in and out, file leave requests, and keep their profile current. HR sees the same data from the other side. They manage employee records, review and approve leave, track overtime, and export what finance or legal asks for.

Document handling sits alongside the records, so a contract or a permit lives next to the person it belongs to instead of in someone’s drive.

Billing with seats

The subscription is the part I owned end to end.

  • A seat tier sets how many employees an account may hold.
  • Checkout runs through Midtrans. The backend owns the charge and the webhook, so a seat count only moves after the payment provider confirms it.
  • The Go side keeps this in a usecase layer with its own test file, because billing logic that drifts is expensive.

Architecture

The frontend is Next.js with Radix primitives, TanStack Query for server state, and TanStack Table for the record grids. Charts come from Chart.js and the map views from Leaflet.

The backend is Go with Gin and GORM over PostgreSQL. Supabase holds auth and file storage. Handlers stay thin, repositories talk to the database, and usecases hold the business rules.

Every push runs lint and the Go test suite with coverage in GitHub Actions. Two separate workflows build the frontend and backend images, push them to Azure Container Registry, and deploy to Azure Web Apps.

What I would do differently

The frontend grew a service layer and a hook layer that sometimes disagreed about where a network call belonged. On a rewrite I would pick one boundary and hold it, rather than letting both halves of the app decide.