All case studies

Web Development case study

Clora AI

Our own product. A multi-company HR, payroll and operations portal with biometric attendance, rule-driven payroll and a scoped AI assistant.

Clora AI interface
The Problem

What was actually broken

Clora is our own product, not a client engagement, and it exists because the HR software a fifty-person company can actually afford tends to be three disconnected things: a spreadsheet for attendance, a second spreadsheet for payroll, and a WhatsApp group for everything else.

The brief we set ourselves was to build one portal that a CEO, an HR manager, a department head and an employee could all open and each see a defensible slice of. That sounds like a permissions problem, and it is, but the harder half is that every module has to agree on the same facts. Payroll has to honour the holiday calendar. The holiday calendar has to block check-in. Attendance has to feed the late penalty. A leave approval has to move the payroll number. Get any of those out of step and the finance team goes back to the spreadsheet, because a payroll figure they cannot reconcile is worse than no payroll figure at all.

The second problem was hardware. Attendance data that people type in is attendance data people negotiate over. We wanted the punch to come from a fingerprint reader and a turnstile, which meant talking to Windows-side devices from a web app.

Our Approach

The decision that shaped everything else

Model the organisation before you model a screen

Companies contain departments, departments contain employees, and every permission in the system is a question about where you sit in that tree. A department manager sees one department. A company manager sees every department of the companies they manage. Only the CEO sees the whole organisation. That rule is enforced server-side on every query rather than by hiding buttons, because a hidden button is not a permission.

One settings record both sides read

Work hours, grace minutes, currency, tax slabs, provident fund rates, leave allowances and payroll policy live in one place the API and the frontend both read. Formatting a salary, deciding whether an 09:12 check-in counts as late, and calculating a month of deductions all trace back to the same record, so there is no second copy to drift out of step.

Payroll as inspectable steps, not one formula

A run moves from draft to processed, and at every stage you can see which allowance, which late penalty, which sandwich-rule day and which perfect-attendance bonus produced the number. Finance teams do not adopt a payroll system they cannot audit, and the fastest way to lose them is a total that appears without a derivation.

An AI assistant confined to the caller’s own scope

The assistant answers through a fixed tool list rather than raw table access, over the same scoped data the person asking could already open. It cannot surface a salary they were not entitled to see. The provider, model and API key are configurable by the CEO, PIN-protected, and the key is encrypted at rest. An assistant that leaks across a permission boundary is not a feature, it is an incident.

The Build

What we shipped, and what fought back

Next.js 16 and React 19 on the front, NestJS and Prisma behind

The portal runs on the App Router with TypeScript in strict mode, styled with Tailwind v4 where the design tokens live in an @theme inline block rather than a config file. The component layer is shadcn in the base-nova style on Base UI, with recharts for dashboards. Behind it sits a NestJS 11 API on Prisma 6 and PostgreSQL.

Protected by default, opted out explicitly

Authentication is JWT with bcrypt hashing, and a global auth guard plus a roles guard means a route is protected unless it explicitly opts out. That default matters. The failure mode of the opposite arrangement is a route somebody forgot to annotate.

One socket for chat, presence and notifications

Chat and notifications share a single Socket.IO gateway, authenticated with the same JWT through the handshake, so presence, unread counts and toasts ride one connection instead of three.

Attendance that comes from hardware, not from typing

A Windows-side bridge handles the devices. Fingerprint enrolment runs in the browser against an HID U.are.U 4500 reader, and an AMF30 gate terminal pushes turnstile punches straight into attendance. Both paths write through the same attendance rules as a manual check-in, which is the only way the late calculation stays honest regardless of how somebody arrived. Self check-in can be locked to approved IP addresses, with a request-and-approve flow for anyone working somewhere new.

The Result

The numbers it holds

Clora runs twenty-five portal modules against one permission model: employees, attendance, leave, payroll, finance, loans, expenses, tasks, assets, documents, recruitment, meetings, announcements, messaging, moderation, analytics and the AI assistant among them.

What we take from it into client work is the shape of the thing rather than the feature list. Model the organisation first. Put policy in one record both sides read. Write money rules as steps somebody can audit. Enforce permissions in the query, not the interface. Give an AI assistant a fixed tool list and the caller's own scope, never the database.

It is also the honest answer to what we can build. This is our own product, so nothing here is a claim about a client we cannot name.

Built with
Next.js 16React 19TypeScriptTailwind CSS v4NestJSPrismaPostgreSQLSocket.IOrecharts

Clora is the longest-running example of how we build web platforms. If you need something with this shape, permissions, money rules and real-world hardware, that work sits under our Next.js web development service, where the scope, timeline and starting price are published before you talk to anyone.

Next case study

Hush

Tell us what’s slowing you down.

Fixed scope, quoted before kickoff, four to eight weeks to production. You talk to the engineer who writes your code.

Start a project