Why Rewriting a Hotel Management System Was Faster Than Patching It
#Backend

Why Rewriting a Hotel Management System Was Faster Than Patching It

Backend Reporter
2 min read

When faced with three incompatible data layers and no frontend, extracting the valuable backend logic and rebuilding with FastAPI and SQLite proved more efficient than incremental fixes.

The Task "Connect LINE Bot to our existing hotel management system." That was the brief. When I opened the codebase, I found something unexpected.

Code Audit: Three Data Layers, Zero Compatibility

Here's what was inside:

  • api.py — in-memory dict for data management
  • models.py — SQLite ORM demo
  • demo.py — another separate in-memory dict

Three incompatible data layers in the same project. None of them talking to each other. No frontend either. Not a single screen that hotel staff could actually use.

But the backend logic had value. tasks.py (workflow), scheduler.py (shift management), inventory.py (33 types of supplies) — too good to throw away.

Decision: Extract the backend logic, redesign everything else with FastAPI + unified SQLite layer.

Redesign Principles

Unify the Data Layer

Eliminated all in-memory implementations. SQLite became the single source of truth. Dev, test, and production all go through the same code path.

Flask → FastAPI

Migrated the Flask endpoints to FastAPI for async support and automatic OpenAPI docs generation. Hotel projects keep growing — having an OpenAPI spec means the next developer (human or AI) can get up to speed quickly.

Guest / Staff Bot Separation

Separate LINE Bot channels for guests and staff. Independent webhook endpoints for each, with Rich Menus and Quick Replies controlling the UX flow.

LIFF Pages

LINE Front-end Framework (LIFF) lets you embed web apps inside LINE. I used it for form-heavy flows that Quick Reply can't handle. Two LIFF pages deployed:

LIFF Purpose
checkin Check-in process
reservation Reservation form

Hosted at linebot.techsfree.com/hotel/liff/. Nginx + HTTPS, PM2 for process management.

The Bug That Bit Me: Field Name Mismatch

The LIFF form was sending guestName, but the FastAPI Pydantic model expected guest_name. Classic camelCase vs snake_case collision. Fixed by adding alias to the reservation endpoint. Simple once you know where to look, maddening before you do.

P0 Progress (≈40% complete)

Working:

  • ✅ G01 Reservation (via LIFF)
  • ✅ G07 WiFi password information

Still pending:

  • ⚠️ G03 Check-in LIFF (API path fix needed)
  • ⚠️ G08 Front desk call (Guest → Staff Push notification not implemented)
  • ⚠️ G20 Check-out (Flex Message incomplete)
  • ⚠️ Staff time clock and task list

What I Learned

"Preserve the existing code" is a trap. Patching three incompatible data layers incrementally would have taken longer and stayed fragile. Extracting the good parts and redesigning the rest was faster.

The final diff looks like a full rewrite — because it basically was — but decisions were cleaner and the result is maintainable.

LIFF + webhook is a great fit for hospitality, F&B, and retail. If you can assume all staff have LINE (a safe assumption in many Asian markets), you skip the native app entirely. Onboarding cost drops dramatically.

The fastest path to a working product isn't always the one that tries to save existing code.

Vibe coding until the vibes turn into vulnerabilities?

Comments

Loading comments...