All work
THMulti-Tenant SaaS · HospitalityEnterprise SaaSCase study

Technaut HMS — Hotel Management System

Runs a hotel front desk — bookings, the tape chart, folios and check-out — with the bill blocked while money is still owed.

Multi-tenant hotel management: availability and bookings, a month tape chart, check-in/out, per-stay folios with snapshotted tax, food and beverage, housekeeping, expenses and a full reporting suite — Fastify API and Next.js web, one deployment serving many hotels.

Source private
Technaut HMS — Hotel Management System interface
Industry
Hospitality
Role
Architect & Full-Stack Engineer
Type
SaaS Platform
Year
2026
Status
Delivered
5, per-route
Roles
Snapshotted
Tax
Append-only
Audit Log

Overview

Technaut HMS is provisioned per hotel: an account is issued, and the hotel configures its own world inside it — property details, room types and rooms, tax rates, food menu and staff. One deployment, many hotels, hard isolation between them.

The front desk covers availability search, bookings and walk-ins, a month tape chart, check-in/out, room moves, no-shows, cancellation with a reason, and a per-stay timeline read straight from the audit log. Billing is a folio per stay: charges carry snapshotted tax so a later tax-rate change cannot rewrite history, and discounts, voids, split and partial payments, refunds as negative payments and invoices frozen at issue time all hang off it. Check-out is blocked while money is owed — overridable by a manager, and the override is audited.

The three operational areas interlock rather than sitting side by side. Room service posts a single line to the guest's bill in the same transaction as the order, so a drink cannot be served without reaching the folio. Check-out queues the room clean automatically, and finishing it marks the room clean. A high-priority room issue takes the room out of order, which removes it from what can be sold — so housekeeping state feeds availability directly.

Five roles are enforced from one permissions module that is the single source of truth: the UI hides what a role cannot do, and every route checks it independently.

The problem

Small and mid-size hotels run the front desk on a booking sheet and the billing on a calculator. Room service reaches the guest's bill only if someone remembers, housekeeping state lives on a whiteboard that availability does not read, and a changed tax rate quietly rewrites what old invoices say.

Discovery

Traced a single stay from enquiry to invoice and found the failures were all at the seams — order to folio, check-out to cleaning, cleaning to sellable inventory — not inside any one module.

The solution

Built the seams into transactions and state rather than into staff habits. Room service posts to the folio in the same transaction as the order; check-out queues the clean and finishing it frees the room; a high-priority issue takes the room out of sale. Charges snapshot their tax so history stays fixed, and check-out is blocked while a balance is owed.

Technical stack

Frontend

  • TypeScript
  • Next.js 16
  • React 19
  • Tailwind CSS 4
  • TanStack Query
  • Vitest

Backend

  • Fastify 5

Data

  • MySQL

Also used

  • Prisma 6
  • shadcn/ui
  • Playwright

System architecture

  1. 1

    Fastify 5 (TypeScript, ESM) + Prisma 6 over MySQL — owns the database, exposes only REST

  2. 2

    Next.js 16 frontend with no database access, proxying /api/* so auth cookies stay first-party

  3. 3

    One module per domain under backend/src/modules, with shared rules in lib: permissions, folio, occupancy, availability, reservation-state, reports, audit

  4. 4

    Server/client page split — page.tsx (server) beside <name>-client.tsx (client) per route

  5. 5

    JWT access token plus hashed rotating refresh token, CSRF double-submit on mutations, sameSite strict cookies, per-route login rate limiting and account lockout

  6. 6

    Append-only audit log written inside the same transaction as the change it records

Engineering challenges

Challenge

A tax-rate change rewrote the tax on charges that had already been billed, so reprinting an old invoice produced a different number than the guest had paid.

How I solved it

Snapshotted tax onto each charge at the moment it is posted and froze invoices at issue time, so rate changes apply forward only and history is reproducible.

Challenge

Housekeeping state and sellable inventory were separate, so a dirty or out-of-order room could still be sold and the guest arrived to a room that was not ready.

How I solved it

Made availability read room condition directly — check-out queues the clean, finishing it marks the room clean, and a high-priority issue takes the room out of order and out of what can be sold.

Challenge

A folio could be closed with money still outstanding, and the loss only surfaced at the month-end reconciliation.

How I solved it

Blocked check-out while a balance is owed, with an explicit manager override that is written to the append-only audit log in the same transaction.

Core features

  • Multi-tenant — hotels provisioned per account with hard isolation
  • Availability search, bookings, walk-ins and a month tape chart
  • Check-in/out, room moves, no-shows and cancellation with reason
  • Per-stay folio with snapshotted tax, discounts, voids and split payments
  • Refunds as negative payments; invoices frozen at issue time
  • Check-out blocked while a balance is owed, with an audited manager override
  • Food & beverage — room service posts to the folio in the same transaction
  • Housekeeping by floor, room issues, and out-of-order rooms removed from sale
  • Reports — occupancy, ADR, RevPAR, revenue by charge type, source mix, P&L
  • Five fixed roles from one permissions module, enforced per route
  • JWT plus rotating refresh tokens, CSRF double-submit, lockout and audit log

Results & impact

One system runs the desk, the bill, the kitchen and the floor, with occupancy, ADR, RevPAR and revenue-versus-expenses coming out of the same records the staff already touch. Because the frontend has no database access, the REST API is the single contract a Flutter client can later sit beside.

Screenshots

Technaut HMS — Hotel Management System screenshot 1
Technaut HMS — Hotel Management System screenshot 2
Technaut HMS — Hotel Management System screenshot 3
Technaut HMS — Hotel Management System screenshot 4
Technaut HMS — Hotel Management System screenshot 5
Technaut HMS — Hotel Management System screenshot 6
Technaut HMS — Hotel Management System screenshot 7
Technaut HMS — Hotel Management System screenshot 8

What I learned

  • Most hotel-software failures live at the seams between modules, so the seams are where the transactions belong.
  • Snapshotting tax and freezing invoices is the difference between a report and a reconstruction.
  • A permissions module that both the UI and every route read independently is what keeps RBAC honest.

Related work

All projects
Next step

Have a system like this to build?

I take projects from the first conversation through to production, and stay on for the support that follows.