Project Overview
Scentlog is a fragrance collection and tasting journal. You try several fragrances at a counter and forget which ones you liked a week later; your collection grows and you still don’t know what to wear each morning. Scentlog keeps tasting notes, fragrance profiles, and daily wear records in one place, then uses those records to help you pick today’s fragrance.
The service runs on Cloudflare Workers with D1, R2, KV, and Durable Objects. It installs as a PWA, so you can take notes at a counter with no signal and let it sync once you’re back online.
Core Features
Technical Architecture
Frontend
Hono JSX renders the page shell, while interactive sections mount as React 19 islands. Tailwind CSS v4, Base UI, and Framer Motion deliver native-feeling drawers, tabs, and gestures on mobile.
Backend
Runs on Cloudflare Workers. D1 is the source of truth for data and versions, R2 stores fragrance images, and KV only caches disposable reads with keys that include the member and D1 version, so entries expire naturally after updates.
Authentication
Sign-in uses WorkOS AuthKit, with the Worker handling PKCE, callbacks, and session refresh. The sealed session lives in an HttpOnly cookie with the __Host- prefix over HTTPS, and the browser only receives basic member info.
Offline Sync
IndexedDB stores a data snapshot and an offline outbox that replays in order once the connection returns. Durable Objects notify a member’s other devices over WebSocket to reread D1, and the foreground also checks the version every five minutes.
Data Isolation and the Shared Catalog
Per-Member Isolation
Ratings, notes, wear, and purchase records are personal. Every private query goes through a single data access layer that scopes it to the verified member, database triggers check ownership across related tables, and private APIs, pages, and images never enter shared caches.
Reviewed Shared Catalog
If a fragrance isn’t listed, you only need the brand and name to start your own record and submit an inclusion request. An admin verifies every field’s source and usage rights before publishing; once approved, it links to the shared entry automatically while keeping your ratings, records, and private images.
No Bulk Crawling
Source import is off for every site by default. A domain’s reading basis must be recorded first, and product pages are read one at a time for structured data. Only field suggestions awaiting verification are stored; images, descriptions, and reviews are never copied.
Recommendation Logic
Recommendations don’t call generative AI. They’re rule-based, using your preference tags, ratings, suitable occasions and weather, recent wear, and optional live weather (feels-like temperature, humidity, chance of rain). Each pick comes with a reason, such as “heat-friendly: fresh, your weather: cloudy”, so you know why it was chosen.






