Back to Projects

EmPay

A connected HRMS built for the Odoo Hackathon, where attendance quietly flows into leave and payroll instead of living in three disconnected spreadsheets.

Hackathon build — Odoo Hackathon
  • Next.js
  • Prisma
  • NextAuth
  • PostgreSQL
Cover coming soon

Most HR software is three products in a trench coat: one thing tracks attendance, another handles leave, a third runs payroll, and a human copies numbers between them at the end of the month. EmPay was my answer to that at the Odoo Hackathon — a single workspace where attendance feeds leave and attendance-plus-leave feeds payroll, so the month-end number falls out of the data instead of being reassembled by hand.

The idea

The pitch was integration as the feature. Anyone can build an attendance calendar. The interesting part is what happens when those three systems share one source of truth: a day marked present is a day that counts toward payroll; an approved leave is a day that doesn't; and payroll is just the arithmetic on top. Get the data model and the boundaries right and the "integration showcase" — the run-payroll step — becomes almost boring, which is exactly what you want from something that pays people.

What I built

Given a hackathon clock, I made a decision I'd defend again: build one role all the way down before building every role halfway. So the employee experience is complete and real, and the HR/Payroll/Admin surfaces ship behind honest "coming soon" placeholders rather than fake screens.

Underneath is Next.js with Prisma on Postgres and NextAuth v5 for sessions. An employee gets a dashboard with today's attendance, their leave balance, and latest payslips; a full month attendance calendar they can mark; a leave flow with balance cards, an apply dialog, and cancellable requests; and a read-only profile with a change-password form. Behind it all is role-based route protection in middleware and a permissions module, so an employee simply cannot reach a screen that isn't theirs.

The detail I'm quietly proud of

Employees never self-register — HR issues their identity — so every person gets a generated login ID in a fixed format: OI + two letters of the first name + two of the last + the joining year + a zero-padded serial. OIJODO20220001 is John Doe, joined 2022, first hire of the year.

The trap in that scheme is the serial. Two people onboarded at the same instant must not collide on 0001. So the allocator runs inside a Prisma transaction backed by a dedicated counter table — the serial is claimed atomically, not read-then-written. It's a small thing that would only ever break under concurrency, which is precisely why it was worth getting right before demo day rather than after. You can sign in with either the login ID or an email; both go through the same credentials provider.

Making it look like one product

A hackathon app usually looks like a hackathon app. I gave EmPay a real design language instead: the structural calm of Notion — warm off-white canvas, tight 3–8px radii, that layered soft shadow — reskinned with Odoo's own palette (mauve for actions, teal for links and focus rings). Every value lives as a CSS variable with light and dark themes, mapped through to Tailwind utilities, so the whole surface stays coherent and themable rather than a pile of one-off colors.

Where it stands

What landed is the employee shell plus the full design system — a genuinely usable slice, not a mock. The next pass is the part the whole thing was designed to show off: the run-payroll action that reads attendance and leave and produces payslips, the payroll officer's leave-approval flow, salary-structure forms, and the HR directory built on that same atomic login-ID allocator. The foundation was deliberately laid so those slot in without reworking what's underneath.