The foundation work is done. Fraghab’s recommendation engine — the heaviest part of every request — now runs on a dedicated server written in Rust, live in production and proven identical to the original across thousands of real comparisons. Next, that core gets pushed to scale, then Fraghab leaves the browser: native iOS and Android apps on the App Store and Google Play. Everything shipped so far is logged below.
The roadmap reopened, and the work went quieter and deeper: reading every log and bug report from the live app, then rebuilding Fraghab’s backend on a dedicated server written in Rust. That backend is now live in production — engineered so the experience grows faster, not slower, as the community grows.
The heaviest compute — the recommendation engine — has moved off the edge and into a memory-safe, fearlessly concurrent core, swapped in only after it proved identical to the original across thousands of live comparisons. Next comes performance at scale, and then the core powers what follows: native iOS and Android apps on the App Store and Google Play, served by the same API.
Before rebuilding anything, we listened. Every log line and bug report from the live app was read, grouped, and ranked — so the new architecture was shaped by real bottlenecks, not guesses.
Step 1 of 5Request-level traces across Server Actions and the Suggest engine. Every slow path earns a span, so the hot routes surface themselves instead of hiding inside averages.
The in-app bug queue gets a standing review rhythm. Reports are reproduced, grouped by root cause, and ranked by how many wearers each one touches.
p50 / p95 / p99 latency captured per route, plus a slow-query log against Turso. You can't improve what you haven't measured first.
LCP, INP, and CLS sampled from real sessions and split by page and device — so frontend cost and backend cost can finally be told apart.
With the data in hand, we designed the backend that scales — mapped the hot paths, drew clean service boundaries, and landed a versioned API contract between the Next.js app and the new server.
Step 2 of 5Pinpoint the most expensive work — Suggest scoring, Claude tool-use loops, feed and marketplace queries, and on-the-fly image generation.
Decide exactly what moves to a dedicated backend and what stays at the edge, with a clean, versioned API contract between the Next.js app and the new server.
A typed, pooled query layer replacing ad-hoc calls — with read-through caching and tag invalidation so popular reads stop hammering the database.
Project load against exponential user growth and size the system to stay ahead of demand, rather than chase it after the fact.
A dedicated backend server, written in Rust — memory-safe, fearlessly concurrent, and fast enough that compute stops being the ceiling. The recommendation engine, the heaviest hot path in the app, now runs here in production.
Step 3 of 5A live async Rust service on the Tokio runtime with Axum routing — the new home for compute-heavy work, deployed alongside the existing app.
A typed query layer against Turso / libSQL with real connection pooling, tuned for high concurrency.
Done. The recommendation scoring engine — the heaviest per-request work in the app — is fully reimplemented in Rust, matched against the original to the last decimal.
Complete. The two engines ran side by side until the Rust path proved identical across a thousand-plus live comparisons; it now serves production, with instant rollback always one switch away.
The payoff: an application that gets faster under load, not slower. Horizontal scaling, layered caching, and continuous benchmarking turn exponential growth into a non-event.
Step 4 of 5Reproducible benchmarks that model peak community moments — the SOTD world map, tournaments, live feeds — at many multiples of today's traffic.
Stateless backend instances behind a load balancer, scaling out automatically as concurrent wearers climb.
A multi-tier cache — per-region runtime cache plus shared invalidation — so the database serves writes while reads come from memory.
Per-request cost and latency budgets enforced in CI, so a performance regression never reaches production unnoticed.
Once the backend stands on its own, Fraghab leaves the browser. Native apps ship to the Apple App Store and Google Play — built on the very API the Rust rebuild was designed to serve, so the phone in your pocket gets the same speed as the web.
Step 5 of 5The versioned API contract from the Rust backend becomes the shared foundation web and mobile both read from. Native apps are possible precisely because the backend was rebuilt to serve them cleanly.
A native iPhone app with Face ID sign-in and push notifications for wearing prompts, streak milestones, social pings, and marketplace offers — your collection a tap away.
A native Android app at full parity with iOS, tuned for the device in hand rather than wrapped in a browser shell.
Snap a bottle straight from the camera, log a wearing with no signal, and let it sync the moment you're back online. Share to anywhere through the system share sheet.
The build before the rebuild. Sixty days, 74 shipments, zero rollbacks — the numbered roadmap, the engine overhaul, and the platform foundation, laid out in full below. It opens with the day-by-day velocity: one bar per day, the May 25 surge marking the community-launch block where five phases landed together once their dependency gates cleared.
#8 → #12 + #13. Auto-fill populates accord data both downstream features read.
#21 → #22 → #23 → #25. Reviews earn rep; Passport surfaces it; Blind Verdict awards it.
#23 + follows → #38. Passport makes the social graph rich enough to feed scoring.
#35 → #36. The per-wishlist split tracker shipped first; the collector marketplace followed.
#10 → #33 → #34. Each enriches the wishlist data model the next reads from. Soft chain.
Five analytics features derived from existing wearings and remaining_ml data — zero new tables, highest value-to-effort ratio in the backlog.

GitHub-style contribution heatmap of every date this fragrance was worn. Click any day to surface the occasion and notes from that wearing.
Replaces the 5-entry preview with a paginated full timeline. Filters by season, occasion, and date range.
"At your current pace, this bottle runs out in ~4 months." Derived from remaining_ml, bottle_size, and wear frequency.
Total investment, cost per ml, cost-per-wear trend, and estimated bottle value remaining based on remaining_ml / bottle_size.
"You wear this most on Saturday evenings in Fall." Aggregated from day-of-week, occasion, and date → season. Zero extra user input.
Suggest page UX improvements built on the existing scoring engine, plus the catalog lookup that gates two Phase 3 wishlist features.

Pre-suggestion wizard surfacing mood, time of day, event type, and weather override. The engine already handled these signals — this makes them first-class UX.
"Prioritize bottles running low" re-weights toward remaining_ml < 20ml. Opposite toggle excludes almost-empty bottles.
Looks up each wishlist item in catalog_fragrances and auto-populates notes, accords, season, and concentration. Adds a mini scent-profile card to every wishlist item.
"You haven't worn this for Work in 6 weeks, even though you've worn it casually 4 times." Per-occasion rotation awareness surfaced in the fit breakdown.
When an item is promoted to collection, the wishlist record is retained as "purchased" with date bought, price paid vs. estimated, and retailer.
Canvas-based shareable poster of the full bottle collection. 1080px-wide dynamic-height PNG with stats header, accord color bar, adaptive bottle grid, and FRAGHAB footer.
Visual upgrade to the detail page via radar chart, plus two wishlist-intelligence features gated on #8 from Phase 2.


SVG spider/radar chart replacing linear progress bars. 3-axis triangle with grid rings, animated data polygon, diamond vertices, coordinated hover, and stat strip with icons.
When viewing a wishlist item, cross-references its accords against owned fragrances. "You already own Tom Ford Oud Wood, which shares 4 accords with this."
Surfaces matching decants already in the user's collection that share the most accords. "You have a Replica decant that shares 3 accords — try it first."
Surfaces the top 3–5 fragrances from the user's collection that share the most accords/notes with the fragrance on the detail page.
Set a remaining_ml threshold per bottle with an optional purchase URL. A banner appears when the threshold is crossed.
Five standalone features with no upstream dependencies — shareability, detail-page depth, and suggest ergonomics.

Generates a downloadable, Spotify Wrapped-style image card showing name, brand, rating, top notes, wear count, and cost per wear.
Pick any fragrance from your collection to compare — notes overlap in a Venn diagram, performance diff, cost per wear, total wears.
From any recommendation card: "Why not X?" shows the top suggestion vs. runner-up side-by-side with score breakdown diffs.
Pinned "Today's Pick" at the top of Suggest with a narrative: "Cold Tuesday morning, overcast. Reach for something dark and resinous." Refreshes daily.
Read-only shareable link to the wishlist or a curated priority subset. Items can be marked "gifted" and grayed out. No auth required to view.
Search across all users' fragrances from the Add Fragrance wizard to copy metadata into your own collection. Anonymous, deduplicated, sorted by popularity.
The most sequentially dependent block in the roadmap. #21 is the keystone — reputation and passport both require it. Built in strict order.

New "Review" post type with structured fields: overall rating, longevity, projection, value, uniqueness (1–10). When 3+ reviews exist, they aggregate into a Community Verdict card.
Users earn points from reviews, reactions, helpful answers, trades completed. Unlock tiered badges: Nose, House Expert, Holy Grail Guardian.
Every user gets a public profile: collection size, most-worn, top notes, top houses, favorite season, fragrance DNA radar. "Your collection is 78% similar to @fraghead_nyc."
Between community infrastructure and Phase 5b, the recommendation engine was rebuilt from the inside out. Thirteen targeted upgrades to how Fraghab scores, matches, and surfaces your next fragrance — plus a weight rebalance so mood and intent drive results, not just rotation gaps.
Recommendations now use real weather from your saved location — not a hardcoded default. Set your city once, or let the browser detect it.
The engine factors in how loud and long-lasting each fragrance is. Office picks favor quieter projection; evening picks favor fragrances that last all night.
Mood matching weighs base notes and accords more heavily than fleeting top notes. A dark base counts more than a bright opening for "mysterious."
Four new moods join the original five: Romantic, Professional, Cozy, and Mysterious. Each has its own scent vocabulary tuned to the notes that define it.
Untagged fragrances still get scored. The engine reads your notes and accords to infer whether a fragrance fits summer or winter — flagged as "inferred."
No more crude hot/cold/mild buckets. A continuous warmth curve maps every degree to a score, so a heavy oud at 55°F scores differently than at 73°F.
Six new occasions join the original six: Gym, Outdoor, Beach, Night Out, Wedding, Travel. Each has its own projection/longevity preferences and NLQ vocabulary.
The engine builds a scent preference profile from your wear history and ratings. Accords you reach for often get a subtle boost; accords you avoid don't dominate picks.
The daily recommendation checks the last 5 days and avoids repeats. Larger collections get an expanded candidate pool so the engine can surprise you.
A new recommendation mode that prioritizes your most-complimented, highest-rated fragrances with crowd-pleasing projection. Built for guaranteed-hit days.
"Something for Easter brunch" now works. The NLQ parser handles holidays, abstract vibes, fragrance slang, negation, and compound intents.
The AI sees your entire collection — names, accords, wear counts, ratings, feedback. "Something like my Ombré Nomade but fresher" resolves to the actual bottle.
Extended timeout, per-user cache for instant repeats, and a smarter keyword fallback that handles natural phrasings like "not too heavy."
Community engagement features that add entertainment value once the core social infrastructure is active and generating content.
"This Week in Group Therapy": most-reacted post, most-discussed fragrance, fastest-rising poll. Posts hitting thresholds earn "Community Certified" and are pinned for 24 hours.
Post a scent description without revealing the name. Community guesses in comments. Answer revealed after 24 hours. Correct guessers earn rep. Fragrance Detective leaderboard.
Suggest's deeper new-infrastructure features — suggestion logging, travel mode, rotation planning — alongside wishlist price-tracking and sale utilities.





Tracks whether the user actually wore the top suggestion each day. "You wore the top suggestion 14 out of last 30 days." Requires a new suggestion_log table.
Destination city + travel dates. The engine swaps local weather for the destination's forecast and re-scores the collection. Outputs a day-by-day packing list with swap alternatives.
Auto-fills a Mon–Sun grid using the engine, spacing fragrances to avoid repeats within 2 days and respecting tagged occasions. Weather-aware scoring with per-day forecast.
Set a "buy at" target price per wishlist item. Manually log observed prices over time. Mini trend graph: "Low was $70 on Black Friday." Banner fires when target is hit.
Tag known fragrance sale events (Black Friday, Nordstrom Anniversary, FragranceNet). Banner: "Black Friday in 47 days — your high-priority wishlist totals $450."
High-effort Group Therapy features with no upstream dependencies, plus the wishlist's split and bundle mechanics. #35 must ship before #36.
Real-time wall showing what the community is wearing — geographic heatmap with city-level pins, rolling ticker of most-recent SOTDs. "23 people are wearing Sauvage right now."
Community-run bracket tournaments: "Best Summer Fragrance 2026 — Round 2 of 8." Head-to-head polls per matchup. Seasonal championships, note-category battles, house battles.
Groups wishlist items by retailer URL domain. Surfaces: "3 of your high-priority items are on FragranceX — buying together saves shipping."
A dedicated section at the top of Wishlist: "You can afford these 3 items right now." Uses budget goal minus already-spent. Shows only HIGH priority items that fit.
For expensive bottles, track a split with friends — log who's in, amounts owed, ml allocation per person. A "splits" tab per wishlist item.
Buy and sell decants and full bottles, collector to collector. Listings with photos and condition, offers, order tracking, seller reviews, and off-platform payment.
Features that wire together multiple existing systems. #38 is the payoff of the entire social infrastructure built since Phase 5. Outfit vision and couple pairings cap the roadmap.



Post type for IRL events: fragrance pop-ups, brand launches, collector meetups, decant swaps. RSVP with headcount. Calendar view filtered by city.
SOTD fragrances from followed users start influencing Suggest scores. "5 people you follow are reaching for X this week." A "Your Circle's Favorites" card in the sidebar.
"Unworn Streak": challenge to wear every bottle in your collection at least once this month. Progress bar, count of remaining unworn. Engine recommends which unworn fits today best.
Claude-powered semantic parser on Suggest: "Something dark and smoky for a dinner party in the cold." Collection-aware — references your bottles by name, handles holidays, vibes, slang, negation.
Tag fragrances as masculine, feminine, or unisex and build complementary pairing sets for date nights and events. Community-shared pairings surface on Group Therapy with voting.
Upload an outfit photo and Vision AI analyzes color palette, formality, and style to recommend the best-matching fragrance from your collection with a full score breakdown.
Seventeen features built outside the numbered roadmap — collection essentials, growth surfaces, and platform infrastructure the 42-feature plan assumes exists. Most shipped before Phase 1 began; the rest filled gaps the roadmap never enumerated.
Combine two or more fragrances into a named layering combo. Photo, ratings, wear history, dedicated detail page, sharable combo image.
First-class decant inventory parallel to bottles — size, remaining ml, rating, source, photo. Picker for wearings, list view, detail drawer, mobile sheet.
Star any fragrance and organize the collection into named shelves with assignment dialogs. Favorites get a dedicated page and surface across discovery.
Soft-delete archive for wearings with mark-all-as-read and a dedicated archive list. Removes noise from history without losing the audit trail.
Multi-step welcome flow — pick favorite mood, rate a sample set, see your first personalized result. Token-based welcome route for new accounts.
Consecutive-day wearing streak with flame badge, streak milestones, and a milestone modal that triggers on first combo, first wearing, and rotation goals.
Header bell with unread badge, in-app toasts, and a provider feeding the bell, messages, and wearing prompts. Foundation for every social ping.
Generates a shareable monthly summary image — top-worn fragrances, wear count, accord mix, standout days. Distinct from #16 fragrance card.
Per-user theme picker with persisted dashboard themes. Token-driven palette swap — preserves the industrial system while letting users tune contrast.
AI-powered buying assistant for new purchases. Two-step intent + results wizard, scored breakdown for each candidate, "Why this?" rationale modal, post-purchase rate prompt.
Public creator showcases, analytics dashboard, invite flow, and referral-link onboarding. Powers the curator side of the platform — distinct from collector profiles.
Public partner API surface for brands. Application form, signed access, and a landing page for the program. Foundation for verified catalog contributions.
Paste a list of fragrance URLs from supported retailers — Fraghab scrapes name, brand, notes, accords, and image — then review and bulk-confirm. CSV upload pathway too.
Print-ready export of the entire collection — formatted for sharing, archiving, or insurance. Bottle metadata, ratings, and remaining ml in one document.
In-app bug report surface with screenshot + context capture. Feeds an admin queue separate from feedback so issues never get lost in feature requests.
Auto-detect city via browser geolocation with a dismissible banner. Powers real-weather scoring (Engine Upgrade #1) and Travel Mode destination overrides.
Public-facing community feed with six post types, threaded comments, reactions, and search. The social surface that everything in Phase 5+ plugs into.
One row per shipped feature across the numbered roadmap, the engine overhaul, and the platform foundation. Sorted by ship date. No gaps, no rollbacks.
Sign up with Google or create an account with email — start cataloging your collection in seconds.