>

06/2026 ~ Present

Scentlog・Fragrance Journal

Full-Stack Development
PWA
Offline Sync
Cloudflare
Active
Featured

A fragrance collection PWA built on Hono + Cloudflare Workers that records tasting notes, your collection, and daily wear, then recommends today's fragrance based on weather and personal preference

Scentlog・Fragrance Journal

Tech Stack

Hono

Worker routing, public page SSG, and member APIs

React 19

Interactive components mounted as islands

Cloudflare Workers

Edge runtime handling sign-in, APIs, and page output

Cloudflare D1

Serverless SQLite and the single source of truth for member data and versions

Cloudflare R2 / KV

R2 stores fragrance images; KV caches disposable read results

Durable Objects

Notifies a member's other devices over WebSocket to resync

WorkOS AuthKit

Member sign-in and session management

Tailwind CSS v4

Utility-first CSS framework

Framer Motion

Motion for drawers, tab switching, and other interactions

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.