A property management system for a portfolio of short and long-term rentals: bookings, clients, billing, and the sales channels the stays arrive through.
StatusIn production
StartedMay 2026
StackNode · Vue 3 · SQLite
What it is
Overview
A booking calendar with the operational parts attached: clients and their documents, billing per stay, and a fixed catalogue of sales channels — each one switched on or off, with its own commission rate. Channels are not names somebody typed; each is a driver the application knows, which is what let it later speak those portals' own calendar protocol.
Multi-user from the start, so the interesting problems were never the CRUD ones: who may change what, how you prove afterwards what was changed, and how a release reaches the running instance without a half-applied moment where the shell is new and the API is old.
How it evolved
Arc
May — make it work. The calendar, expandable booking rows edited in place, reusable field components, and a design system pulled out of the scattered SCSS once the shape settled. Two languages by the end of the month.
June — make it trustworthy. Authorization enforced rather than assumed, and an immutable audit log: every accepted change leaves a record nobody can quietly edit.
August — make it hold. Persistence moved from JSON files to embedded SQLite with a one-off conversion, and the server now refuses to boot against a schema it does not recognise. Roles became four, with the permission decided at the route. Deployment stopped being a manual step. Then two-way calendar sync and a public request inbox, which turned a private admin tool into something the outside world talks to — and that, in turn, is why a password stopped being the whole answer.
The arc, in one line: a CRUD app in May, a system with an audit trail, a migration path, a release pipeline and two-factor authentication by September.
Screens
Interface
Calendar — screenshot pending
The booking calendar: stays coloured by channel, today drawn as a box over the whole column.
Metrics — screenshot pending
Occupancy and billing metrics, redesigned in June.
Changelog
Newest first
August 2026
2026-08
Two-step verification Security
A password is no longer the whole answer. Any account can ask for a six-digit code mailed to its own address, opt-in per user from the profile screen. An admin can clear somebody else's when they lose access to the mailbox it goes to.
2026-08
Channels became drivers Feature
A channel stopped being a name somebody typed and became a driver the application knows, carrying its own mark and commission. Direct stays are a channel too — no intermediary, no commission, never deletable.
2026-08
Two-way calendar sync Feature
Reads the channels' calendars and publishes its own, so a stay booked anywhere blocks the dates everywhere. Plus an inbox for requests coming from the public site, and a read-only availability endpoint it may ask about.
2026-08
Four roles, decided at the route Security
Permission checks moved to where the request is handled instead of being spread through the UI. A role is changed, an account is deleted, an address is saved — three different operations that used to be one blurry one.
2026-08
Automated release pipeline Infra
Tests run, the image is built and published, the instance is redeployed, and the pipeline waits for the health check and confirms the deployed version before calling it done. A separate development instance is seeded from real data. The SPA shell is served no-store, so a deploy can never be half-applied in someone's browser.
2026-08
SQLite replaces the JSON files Infra
Embedded SQLite instead of files on disk, with a one-off conversion for existing data and a schema collapsed into a single migration before launch. The server refuses to boot against a schema it does not recognise, rather than corrupting one it half-understands.
2026-08
Hardening pass Security
The login rate limit is keyed on a client IP that cannot be forged. A malformed body answers 400, not 500. Errors reaching the top are logged instead of silently becoming a 500. Two bugs the test suite could not see were found by running against the real container.
June 2026
2026-06
Audit log and enforced authorization Security
Every accepted change writes an immutable record. Authorization stopped being an assumption about who reaches a screen and became a rule the server enforces.
2026-06
Metrics page redesign Feature
Rebuilt so the numbers are read at a glance, and fixed the row clipping and the shrinking date ranges that showed up on narrow displays.
May 2026
2026-05
Two languages and a design system Refactor
English and Spanish through vue-i18n, scattered SCSS centralized into a styles layer, inline SVGs replaced by real assets, and reusable input field subcomponents so editing behaves the same everywhere.
2026-05
The calendar, editable in place Feature
Expandable booking rows edited without leaving the calendar, a client administration screen, per-user self-administration, and the navigation hierarchy the rest of the app still uses.
2026-05
First commit Start
A monorepo, a Node server, a Vue client, and a booking that could be written down.