Back to Projects
WIPFull Stack2026

Pokoje Borowa

A bespoke hotel management system for a cozy mountain guesthouse. React Vite frontend with an Electron desktop app for staff, NestJS backend with MikroORM. Covers online reservations, live room availability, automated booking confirmations, and a clean admin panel — streamlining operations from reservation to checkout.

ReactViteTypeScriptElectronNest.jsMikroORMPostgreSQLNodemailer

A bespoke hotel management system for a small mountain guesthouse in Poland — online reservations, live room availability, automated booking confirmations, and a desktop app for staff. Built because the owner was running the entire operation from a paper notebook and a spreadsheet.

The Real-World Brief

Pokoje Borowa is a small family-run guesthouse. Before this project, reservations came in by phone or email, availability was tracked manually in a spreadsheet, and booking confirmation emails were written by hand. The owner wanted a website where guests could check availability and book directly, and a tool for staff to manage everything from a desktop app.

This is the kind of project that teaches you more than any tutorial — real requirements, a real client with real expectations, and real data that cannot be lost.

Architecture: Three Surfaces

The system is split across three surfaces that share a single NestJS backend:

NestJS API (backend)
  └── Reservation CRUD
  └── Room availability engine
  └── Email queue (Nodemailer + BullMQ)
  └── MikroORM → PostgreSQL

React + Vite (guest-facing web)
  └── Room browser with availability calendar
  └── Booking form + confirmation page
  └── Deployed on Vercel

Electron + React (staff desktop app)
  └── Reservation dashboard
  └── Room management
  └── Check-in / check-out flow
  └── Guest history

The Availability Engine

Calculating room availability across a date range sounds simple. It becomes complicated when you consider partial overlaps, same-day check-in/check-out, and reservations that are "pending" (not yet confirmed but blocking availability to avoid double bookings).

// A room is unavailable for a requested range if any 
// existing reservation overlaps it

function isRoomAvailable(
  room: Room,
  checkIn: Date,
  checkOut: Date,
  reservations: Reservation[]
): boolean {
  return !reservations.some(
    (r) =>
      r.roomId === room.id &&
      r.status !== 'cancelled' &&
      r.checkIn < checkOut &&
      r.checkOut > checkIn
  );
}

The availability query runs against an indexed PostgreSQL query rather than fetching all reservations into memory — important when the date range spans multiple months and the property grows its room count.

Automated Email Flow

Booking confirmation, check-in reminder (sent 48 hours before arrival), and post-stay thank-you emails are queued in BullMQ and sent via Nodemailer. Email templates are HTML with inline styles — deliberately simple to ensure they render correctly in Gmail, Outlook, and Apple Mail without a dedicated email framework.

Each email job includes idempotency protection: if the queue is retried due to a worker crash, duplicate emails are not sent. A Redis set tracks sent job IDs; before sending, the worker checks membership.

The Electron Desktop App

Staff interact with the system through an Electron app rather than a web browser — partly for offline resilience (the guesthouse occasionally has connectivity issues), partly because the owner wanted something that "felt like proper software."

The Electron shell is thin: it loads a React Vite app in a BrowserWindow and exposes a small IPC bridge for native features (file downloads, printer access for reservation receipts). All data fetching goes through the same NestJS API as the guest-facing web app.

Offline mode uses a local SQLite cache via better-sqlite3. Read operations fall back to cache when the API is unreachable. Writes are queued and synced when connectivity returns.

What I Learned

Electron packaging for a non-technical user is harder than building the app. The owner needed to receive an installer, run it, and have the app work — with no command line, no "allow this app from unidentified developer," no configuration. Electron Forge with a NSIS installer got close, but code signing was necessary to avoid Windows security warnings. Working through that process taught me more about Windows application distribution than I ever expected to need to know.

MikroORM is excellent. The entity-first approach with explicit change tracking feels right for a domain like reservations where you need precise control over what gets written and when.

Status

The backend and guest-facing web app are complete and in use. The Electron desktop app is in active development — the reservation dashboard and check-in flow are done; room management and guest history are in progress.

Interested in working together?

I am available for new projects — whether you have a clear brief or just an idea worth exploring.