Inspiration

Woke up one morning, looked in the mirror, and just — didn't recognise myself anymore.

Acne that wouldn't quit. Patches of dryness sitting right next to oily zones. Redness that flared up for no reason I could ever figure out. Spent years trying random things off shelves, copying routines from influencers who clearly didn't have my skin, spending money I didn't have on products that made things worse.

The worst part wasn't the breakouts. It was walking into a pharmacy, staring at a wall of a hundred products, and having absolutely no idea where to start. No one to ask. No framework. Just guilt that I wasn't doing "the right thing" — whatever that was.

Skincare advice online is either too generic to be useful or so overwhelming it sends you spiraling into a 3am Reddit rabbit hole. Dermatologist visits are expensive, often gatekept, and over in 10 minutes. The gap between "I have a problem" and "I know what to do about it" felt impossibly wide.

That gap is where Le Rituel was born.

Not from a business idea. Not from a hackathon prompt. From genuine frustration — from looking at a shelf of failed purchases, from cancelling another derm appointment because of the cost, from feeling like your own skin is a stranger.

If even one person avoids that spiral because of this, it was worth every late night building it.

What it does

Meets you exactly where you are. No assumptions.

You answer a short quiz — skin type, top concerns, what you're allergic to, your budget, your age range, how experienced you are with routines. Or, if words feel hard, you just take a selfie. Claude Sonnet 4.5 looks at your skin — the texture, the oiliness, the redness, the pores — and fills in the quiz for you, gently, like a friend who actually knows what they're looking at.

Then it builds your routine. A real one. AM and PM, step by step, with products ranked to your budget and matched to your skin. No one-size-fits-all. If you're 30+ with fine lines, retinol quietly appears in your PM steps. If your skin is sensitive, it doesn't. If you listed a fragrance allergy, those products are gone before you ever see them.

And it doesn't stop there.

Ask the chat assistant anything — "can I layer niacinamide with vitamin C?", "why is my moisturizer pilling?", "what order do I apply these?" — and you get answers grounded in your routine, your skin, not a generic blog post.

Not sure if two actives clash? The ingredient conflict checker tells you instantly — avoid, safe, or synergy — with a plain-language reason.

Log your progress. Track your streak. See your skin change week by week in your own photo journal. That's the part that hits different. Actually watching it work.

How we built it

Async Python at the core. FastAPI for the API layer — fast to iterate, strict on validation. Pydantic v2 models on every single request body, because garbage input is the enemy of a product people trust with their skin data.

MongoDB for storage — flexible enough for evolving schemas as we figured out the right data shapes mid-build. Motor for async access so nothing blocks.

For AI: Emergent Integrations as the LLM bridge into Claude Sonnet 4.5. Two separate contexts — one for vision (skin photo analysis, structured JSON output with strict sanitization), one for chat (scoped system prompt enriched with the user's profile and current routine steps).

The recommendation engine is deliberately rule-based and deterministic — score products by skin-type match, concern overlap, budget proximity, filter allergies, rank, pick the top two per step. Fast, explainable, testable. AI for perception, rules for decisions.

React 19 on the frontend. shadcn/ui for components, Framer Motion for animations that feel considered rather than gratuitous. SWR for data fetching, React Hook Form + Zod for forms that don't let bad data through.

The whole thing ships as three Docker containers — nginx, FastAPI, MongoDB — behind a single origin proxy so auth cookies just work. Deployed live at nodeflowai.in with TLS at the edge.

Security was non-negotiable: bcrypt, 15-min JWT access tokens, 7-day refresh tokens, JTI blocklist for revocation, Fernet encryption for allergy data at rest, brute-force lockout after 5 failed logins.

Challenges we ran into

Getting Claude to return only structured JSON — no prose, no preamble, no apologies — took more prompt engineering than expected. Added a fallback regex JSON extractor for when the model drifted. Lesson learned: always sanitize LLM output server-side, never trust the shape.

The recommendation engine's product-to-step mapping went through three complete rewrites. First schema used nested am_steps/pm_steps objects. Second was a flat list. Third (current) is ordered steps with time_of_day tags. Still had to ship a legacy migration function to keep older stored routines rendering correctly without forcing re-generation.

Cookie auth across origins was painful. SameSite=None; Secure requires HTTPS everywhere — including during local dev once you touch Safari. Setting up a local HTTPS proxy just to test cookie behavior is not how you expect to spend a Saturday.

Streak logic sounds trivial until you actually implement it. Timezone edge cases. What counts as "today" when a user is in UTC+5:30 and the server is UTC. Whether today counts if only AM is done. Walking backward through a sparse dataset of completion records without assuming continuity. Wrote the algorithm three times before it felt right.

Progress photo storage in MongoDB documents grows fast. Base64 images inside document fields is not a long-term solution — learned this the hard way when export payloads became unexpectedly large. Object storage migration is already on the roadmap.

Accomplishments that we're proud of

And the streak tracker. Watching a number go up day after day because you remembered to cleanse and moisturise — small, but it rewires behavior. Consistency is the one thing every skincare expert agrees on, and gamifying it slightly actually works.

What we learned

LLMs are powerful. LLMs with no guardrails are a liability. The chat assistant's system prompt is opinionated by design — it will not discuss anything outside skincare, it will not diagnose, it will redirect off-topic messages with a single polite sentence. Scoping an LLM tightly is an engineering decision as much as a product one.

Encryption at rest is not difficult. Not encrypting sensitive user data is not an acceptable default. The Fernet key rotation path should have been designed from day one — it wasn't, and retrofitting it is on the backlog.

Async all the way down matters more than it seems. A single blocking database call inside an async FastAPI handler will tank concurrency under load. Motor's async driver wasn't just a nice-to-have — it was the right foundation.

Building for yourself makes the decisions easier. Every ambiguous product call — what concerns to allow, how to handle unknown ingredients, whether to show retinol to 20-year-olds — had a personal answer. "Would I want this as someone who's struggled with this?" usually resolved the debate.

And perhaps most importantly: consistency beats perfection. The streak tracker isn't in the codebase because it's technically impressive. It's there because the hardest part of skincare isn't knowing what to do — it's actually doing it, every day, especially on the days when you really don't want to.

What's next for Le Rituel

Skin problems don't resolve overnight. Neither will this product. But it's alive, it's deployed, and it's already trying to help. That's the beginning.

Built With

Share this project:

Updates

Submission history