Built for Northland Ski & Bike Shop in Canazei, Italy.

Cinnamon

Cinnamon is the point-of-sale, inventory and analytics system for Northland Ski & Bike Shop in Canazei, Italy. Staff use it at the counter every day. I designed and built it, I have run it remotely from California since January 2022, and I have been the shop's sole IT administrator since 2023. Its sister system, Haven, handles the shop's bike-rental reservations.

It tracks 40,000+ SKUs and about €240k of inventory and rings up hundreds of transactions a day. It is a solo project, about 1,850 commits.

01

Fiscal register integration

In Italy, retail sales are recorded on certified telematic fiscal registers (RT), which speak a proprietary positional protocol. I wrote a Node.js bridge that talks to them over raw TCP and exposes them to the POS over Socket.IO. It handles receipts, the cash drawer and payment signalling. It ships as a single Windows or Linux executable, or runs in Docker.

before staff re-typed every fiscal amount into the register by hand. now nothing is entered by hand.

POSSvelteKit bridgeNode.js · single binary or Docker RT registerpositional protocol

Illustrative screens, not real data.

02

Stock-takes from a phone

Physical stock-takes run from the mobile app, which is built for scanning and inventory on the shop floor. Staff scan barcodes with the phone.

A missing-labels workflow covers items without a label, and a scan-to-identify screen covers unfamiliar ones.

Every receipt carries a sale-ID barcode, and an exchange starts by scanning it to pull up the original sale.

03

Access control

Cinnamon supports multiple shops. Users sign in through federated SSO, and a blocking function reads their organization and groups and sets a custom claim tying them to one shop; admin rights come from group membership. Every screen and every Firestore security rule checks that claim, and an account that doesn't belong to a shop is refused at sign-in.

04

Keeping the numbers right

Supplier orders flow into stock through atomic counters for ordered, delivered, in stock and defective on arrival, keyed on supplier, brand, season, model, size, colour and price. Prices and discounts use decimal arithmetic, so there are no floating-point rounding errors.

Each shop gets a nightly snapshot of stock value and sales by brand and category, with days computed in Rome local time so they stay correct across daylight-saving changes. A nightly job raises an alert on negative stock (overselling) or a missing snapshot, so problems are caught the same day instead of at year-end.

05

Stack

Two SvelteKit apps in TypeScript, built as static single-page apps with Vite: the desktop back office and POS, and the mobile app. The backend is Firebase (Auth, Firestore, Storage, Hosting) with about 15 Cloud Functions in TypeScript: callable functions, Firestore triggers, scheduled jobs and a blocking auth trigger. Algolia indexes items, sales, orders, coupons and inventories. It is a pnpm monorepo, with models and services shared by both apps and the functions.