Kord
LIVECo-founder & CTO2026
A multi-tenant SaaS platform for Croatian security companies: rostered guards, NFC patrol scans, incidents, and every hour priced for the client. Every company shares one platform, so security and data isolation came first: each tenant's data is scoped at the data layer, and another company's record is a 404, never a row. I co-founded it in 2026 with Jelena Njeguš, who designs it, and I built the web app, the API, the infrastructure and every integration it runs on. It's also where my AI setup proves itself: over a thousand pull requests merged, most of them opened by kormanjonac and every one reviewed by me.
THE DECISION
A shift's price is frozen when it's written
CONTEXT
Every shift is priced for the client, by the hour or per shift, plus uplifts for night, Sunday and holiday hours. Rates change. Managers roster weeks ahead and send last month's site report after the month has closed.
DECISION
Store the rate on the shift when it's saved, using the rate in force when the shift starts, and freeze every uplift it falls under right beside it. Repricing the shifts that haven't started yet is an explicit flag on the save that changed the rate.
CONSEQUENCES
A closed month never moves, and a rate edit changes nothing on its own. One function turns a frozen rate into money and floors once per line, so every total is exactly the sum of its lines, pinned by a property test. The cost is an edit form that keeps a hand-typed price apart from one taken off the rate.
REJECTED
Computing money on read from today's rates. One source of truth and nothing to keep in sync, until the first rate change rewrites a month somebody already invoiced.
FOUR SMALLER CALLS
Every write is scoped like a read
Every query goes through the model's scope, writes included, so an id from another company throws a 404 instead of touching a row. Nothing fetches a row just to check who may change it.
The API is the contract
Every request and response shape is declared once, on its route. The API validates its own responses, and the web and mobile apps generate their typed clients from the same declarations, so a renamed field fails the build instead of a screen in production.
Missing money isn't zero
A manager never sees an employee's fixed costs and HR never sees revenue. The API leaves the field out instead of sending a zero, so no screen can mistake "not yours to see" for "free".
Nothing broken reaches production
Every release runs the full gate first: formatting, lint, type checks and the whole test suite, with the model and API tests against a real PostgreSQL. A red run ships nothing. A green one takes a fresh database backup before the migrations run, so every schema change starts from a copy I can restore.
WHAT I BUILT
One Bun monorepo with 1,800+ tests across the API, the shared code and the apps. The API owns every business rule, the database, mail through Brevo, push through Firebase and the scheduled work: missed patrol scans, the monthly bill, a daily error recap and hourly backups. The web app is the dashboard for admins, managers and HR. The guards' Expo app, for shifts, NFC patrol scans and incidents, runs on the same API. It all runs on a server I keep, behind Cloudflare, live at kord.hr.
THE STACK
WEB
- React
- TanStack Query
- Tailwind CSS
BACKEND
- Bun
- PostgreSQL
- Knex
- Zod
- Firebase
- FCM
- Brevo
INFRASTRUCTURE
- Docker
- nginx
- Cloudflare
- GitHub Actions
Building something with this many moving parts? I'd love to hear about it.
CH 04 CONTACT