Skip to content
SerdarDilshad

Published · 2026-05-06 · 12 min read

A technical breakdown of motelsystem — the multi-tenant hotel platform I built and ship weekly: how I solved local-government reporting, ran on Cloudflare Workers' 10ms CPU budget, and made it work in EN/AR/KU.

TL;DR: I built a multi-tenant hotel management platform for the Kurdistan Region called motelsystem. It runs on Cloudflare Workers' 10 ms CPU budget, ships in English, Arabic, and Kurdish, prints government-compliant reports for the local registry by one click, and has been live in production through 33 weekly waves. This post is the technical breakdown.

Why a custom hotel platform was even needed

In 2024 a friend in Duhok asked me to look at his motel's "system." It was a 47-tab Excel file, a printer connected by USB, three handwritten notebooks, and a paper folder of regulatory forms half-filled in marker. Check-in took 30 to 45 minutes per guest. Regulatory reports were rejected about once every two weeks for missing fields, and nobody knew which nights were full until a guest showed up.

He'd tried two off-the-shelf hotel SaaS products. Both failed for the same three reasons:

  • Neither spoke Kurdish in any meaningful way.
  • Neither could output the local-government .docx in the format the office actually accepts.
  • Neither handled IQD + USD reliably (or at all).

That third point is interesting because most Kurdistan SMBs operate in two currencies all day. International software doesn't model this; you either pick one currency and lie to yourself, or you keep a parallel paper ledger. Both are bad.

The architecture decisions that mattered

Multi-tenant from day one

I designed the schema for multiple hotels from the first commit. Each property is a tenant; every row in every table carries a tenant_id; Supabase Row-Level Security enforces strict isolation. This was non-negotiable — even if there was only one customer at first, retrofitting tenancy later is a nightmare.

Cloudflare Workers as the runtime

Workers Free has a 10 ms CPU limit per request. That sounds painful for a Next.js App Router app — and it is, until you redesign for it. The rules I now live by:

  • Skip middleware auth on anonymous paths. Customer-facing pages don't need to wake up the auth client. Saves ~3 ms per request.
  • Use the admin Supabase client for anonymous reads, bypassing RLS for already-public data.
  • Pre-fetch in page.tsx instead of layering on parallel Suspense boundaries that each spin up a new connection.
  • Auto-retry from error.tsx. On a CPU timeout, Workers throws a synchronous error. A simple useEffect retry catches the rare miss without the user noticing.
  • Navigate, don't router.refresh() after heavy mutations. refresh rebuilds the entire route tree and easily blows the 10 ms budget. A targeted router.push(currentPath) after a mutation gets you fresh data without the cost.

EN/AR/KU at the database level

Most "multilingual" apps store English in the primary table and bolt translations on later. I went the other way: every translatable field is a JSON triplet { en, ar, ku } at the column level, with a localizeContent() helper that flattens to whichever locale the request is in. RTL layout is enforced at the layout level — not text-direction CSS — so Arabic and Kurdish UIs are mirror images, not LTR pages with right-aligned text.

The government-reporting problem and how I solved it

The local-government form is a specific .docx file: A4 landscape, 10 RTL columns, yellow header, color-coded data rows (yellow for arrivals, green for current guests, red for incomplete data). The office rejects anything that doesn't match this template.

I reverse-engineered it by inspecting the .docx XML directly, then wrote a generator that takes any night's guest set and outputs a file the regulator accepts on first try. The system tracks every required field per guest (national ID, name, nationality, arrival, departure, room, accompaniment), flags incomplete data with a banner in the dashboard before the export is run, and supports multi-night stays so a guest who arrived three days ago still appears on tonight's report.

The result: zero rejected submissions in 12+ months, and the front-desk operator's reporting time went from "30 minutes plus another 30 if something's wrong" to "press export, fix any flags, done."

Walk-in flow under 90 seconds

Walk-ins are the cash flow of a Kurdistan boutique hotel. They're also where the old system burned the most time. I built a single-page flow: operator selects a room from a real-time availability grid, scans or types the guest ID, the deposit posts immediately to the day's accounting, and a dual receipt prints — guest copy and accounting copy — in under 30 seconds end-to-end. The ID details flow into the night's reporting queue automatically.

Sub-90-second total walk-in handling, including conversation, ID scan, room walk, and key handoff. Operators stop dreading 11 PM walk-ins.

A customer-facing CMS the manager actually uses

Most B2B software fails at the customer-facing layer because the manager can't update content without calling the developer. I built a boutique CMS so the hotel manager can edit hero images, descriptions, amenities, FAQ, contact info, and seasonal offers — in EN/AR/KU — from the same admin he uses for bookings. No "developer required" surfaces. That's the difference between a system that ships and a system that rots.

What 33 weekly production waves taught me

Shipping every week was the single highest-leverage decision. Each wave was small enough to be safe (one or two features, fully tested), but cadence forced compound improvement. Some highlights:

  • Wave 12: walk-in flow re-architecture cut handling time by 60%.
  • Wave 21: customer-facing CMS launch eliminated 90% of "can you change…" requests to me.
  • Wave 27: multi-night reporting tracking caught the missing-data class of bug at the source.
  • Wave 33: Workers Free CPU optimization wave — every customer-facing page now hits sub-1.5s LCP across Kurdistan.

Lessons for anyone building software for Kurdistan

  1. Stop adapting Western SaaS. The cost of building custom is lower than the cost of perpetually fighting a tool that doesn't understand your reality.
  2. Multi-tenant from day one if there's any chance of a second customer.
  3. Translation at the column level, not as an after-thought.
  4. The government format is solvable — it's deterministic, and once you've reverse-engineered it, the second hotel is free.
  5. Weekly waves beat quarterly releases by a wide margin in this market.

If you have a similar problem

If you run a hotel, motel, clinic, school, or any business in Kurdistan that's been failed by off-the-shelf software, I'm interested. Multi-tenant means I can onboard you on the platform we already have — you don't have to fund building it from scratch. Send a brief on the contact page or message me on WhatsApp.

More on the same theme — Kurdistan SMBs, AI, and the messy practical bits.

SB

Serdar Dilshad

AI Automation Specialist & Software Engineer · Duhok, Kurdistan

About Serdar →

Available — Q3 2026

Free 15-minute scoping call. No obligation. We'll figure out together whether AI or automation actually helps your business — and where it doesn't.