Skip to content
Selected Work

AI Wellness Platform

SOLACE

You’re not imagining it. There’s more to how you feel — and maybe a pattern in it.

An emotionally intelligent AI wellness companion that helps you notice the quiet, hard-to-name things — low energy, brain fog, mood swings — and surfaces honest, non-clinical patterns in your own data, without ever diagnosing or prescribing.

Automated tests
149
Deployed services
3
Role
Design and development, end to end
Team
Solo
Timeline
May 2026 — Present
Status
In active development

Walkthrough

Video coming soon

DemoA 30–40 second walkthrough: sign in, the daily check-in, the dashboard, an insight card and the pattern prediction.

Overview

SOLACE is an emotionally intelligent AI wellness companion. It’s not a medical app and it’s not a chatbot — it’s built to feel like a personal health detective with a warm, human soul: something that helps you notice the quiet, hard-to-name things (low energy, brain fog, mood swings, “just off”) and surfaces honest, non-clinical patterns in your own data, without ever diagnosing or prescribing.

It’s a solo portfolio project, built in public phases, and it’s in active development: Phases 0–4 are complete and Phase 5 is in progress.

Why I built it

I wanted to explore how AI could be used for wellness without turning into another generic chatbot. The idea came from noticing how difficult it can be to connect things like sleep, stress, energy, mood, and lifestyle into a bigger picture, so I built SOLACE around finding those patterns while keeping the experience non-clinical and human.

Who it’s for

People who feel that something is “off” but cannot easily explain why, especially students and young professionals dealing with stress, inconsistent routines, and generic wellness advice.

My role

I designed and built SOLACE end-to-end, including the product flow, architecture, backend/ML separation, data model, AI pipeline, and frontend experience. The hand-drawn visual language was also intentionally designed as part of the product identity, with customized UI components rather than using a generic template.

What it does

SOLACE dashboard in its dark theme: a hand-drawn greeting card reading Good evening, demo, buttons for today’s check-in and the journal, and a hand-drawn line chart of mood and energy over the past month.
Fig. 01The dashboard: a greeting, today’s check-in, and recent days of mood and energy.
The SOLACE check-in page: six hand-drawn mood faces, body and mind note chips such as brain fog and low energy, and sliders for energy and sleep.
Fig. 02

Daily check-ins

Mood, energy, sleep, water, sunlight, stress, symptoms, food — in under two minutes.

The SOLACE insights page titled Your patterns, so far, with a not-medical-advice note and insight cards such as A pattern around sunlight.
Fig. 03

Rule engine + Gemini insight cards

A rule engine maps symptom patterns to possible nutrient and lifestyle flags (iron, vitamin D, magnesium, B12, vitamin C, sleep debt, dehydration, sedentary behavior, sustained stress), sourced from peer-reviewed nutrition research.

Gemini turns those flags into warm, specific, hedged language — never “you have a deficiency,” always “there might be a pattern here.”

The Your patterns card: next-day mood and energy predictions as plain-language chips, and a list of hedged patterns such as more sleep seems to come with higher energy the next day.
Fig. 04

A personal pattern model

scikit-learn, trained per-user and stateless. It learns your data after 14+ check-ins and surfaces an honest next-day mood/energy prediction — banded into plain language (“steadier,” “brighter”) rather than raw numbers, and hidden entirely when the model isn’t confident.

What it deliberately doesn’t do

No diagnoses. No medical claims. No supplement or affiliate pushing. No dark patterns.

The journal will never feed any AI/ML layer — that boundary is architectural, not a setting.

Architecture

Three independently deployed services:

System architecture
  1. Client

    Next.js

    Vercel

  2. API

    Express + TypeScript API

    Railway

  3. Data

    Supabase Postgres

    Postgres + Auth, via Prisma

  4. External

    Google Gemini Flash

  5. Service

    FastAPI ML service

    Railway, stateless

  • Express + TypeScript API → Supabase Postgres — Prisma
  • Express + TypeScript API → Google Gemini Flash — insight cards
  • Express + TypeScript API → FastAPI ML service — GET /api/patterns, decoupled
  • Sync
  • Async
  • Auth
  • The frontend never talks to the database, Gemini, or the ML service directly — everything routes through the backend.
  • GET /api/patterns is decoupled from the main dashboard load and has a 4-second timeout: if the ML service is slow, asleep, or fails, the prediction card is silently hidden rather than blocking the dashboard.
  • The journal (Phase 5) is encrypted in the browser using Web Crypto: the key never leaves the client, and the backend stores only ciphertext.

Stack

Frontend
Next.js 16 (App Router), TypeScript, Tailwind CSS 4, Framer Motion, custom hand-drawn UI kit
Backend
Express 5, TypeScript, Prisma, Zod
ML service
Python 3.12, FastAPI, scikit-learn, pandas, numpy, scipy
Auth & DB
Supabase (Postgres + Auth)
AI
Google Gemini Flash
Deploy
Vercel (frontend), Railway (backend + ML), Supabase Cloud

Key decisions

  • A separate Python ML service

    Why
    Python has a much stronger ML ecosystem through libraries like scikit-learn, while TypeScript is better suited to the application’s API and business logic. Keeping it separate also gives the ML layer its own deployment and scaling boundary, while preventing the frontend from ever accessing the ML service directly.
    Trade-off
    It adds another service to develop, deploy, monitor, and communicate with, but the separation gives me cleaner responsibilities and makes the architecture easier to evolve.
  • A stateless model, retrained per request

    Why
    The backend sends the user’s complete check-in history to the ML service, which trains the Gradient Boosting models in memory for that request and immediately returns the prediction. This avoids storing model files on Railway’s ephemeral filesystem and keeps the service horizontally scalable.
    Trade-off
    The model has to retrain for every prediction request, so there is some additional CPU/time cost compared with loading a persisted model. With the current small per-user datasets, the training is lightweight enough that the simplicity and reliability are worth it.
  • Rule engine decides, Gemini writes

    Why
    The rule engine is responsible for the deterministic wellness signals/flags, while Gemini turns those signals into warm, human-readable insight copy. This keeps the important decision logic deterministic and testable instead of asking an LLM to independently decide whether a user has a particular signal.
    Trade-off
    It requires maintaining two layers instead of letting one AI model do everything, but it gives much better control, testability, and consistency.
  • Gemini Flash

    Why
    SOLACE needs fast, lightweight text generation rather than a large reasoning model. It is used mainly for synthesizing already-structured signals into concise, warm insight cards, so a faster model with low inference cost was a better fit. The implementation also includes rate limiting, caching/storage of generated insights, and fallback copy when Gemini is unavailable.
  • Supabase with Prisma

    Why
    Supabase gives me managed PostgreSQL plus authentication, while Prisma gives the backend a type-safe ORM and migration workflow. Supabase handles infrastructure/auth while the Express backend retains ownership of database access, instead of allowing the frontend to directly query application data.
  • A 14-check-in gate and confidence checks

    Why
    The model is learning an individual’s patterns rather than using a large population dataset, so below fourteen check-ins there simply isn’t enough personal history to justify a prediction. After training, confidence combines sample count, cross-validation stability, correlation agreement, and model variance; the prediction is also hidden on negative R², degenerate output variance, or unstable correlation patterns across bootstrap resamples.

Challenges

  1. Training a model on very little data per user

    The biggest ML challenge was making a personalized model useful without pretending that a small dataset is highly reliable. I used conservative Gradient Boosting hyperparameters, a minimum 14-check-in gate, recency weighting, correlation analysis, permutation-importance cross-checking, bootstrap stability checks, and confidence/sanity gates. If those checks do not produce a sufficiently reliable signal, SOLACE simply hides the prediction instead of forcing an answer.

  2. Keeping Gemini from sounding like it was diagnosing someone

    Because SOLACE is a wellness product rather than a medical application, I treated the AI output as a constrained generation problem rather than trusting the model’s wording by default. Gemini is given structured signals from the rule engine, prompts are designed around non-clinical language, and generated text passes through a tone validator with 19 banned phrases. There is also fallback copy and a “not medical advice” disclaimer on insight cards.

  3. Deferring emotion classification to Phase 7

    The Hugging Face emotion model was deferred because the free inference infrastructure was unreliable and the model’s PyTorch memory requirements were too high for Railway’s 512 MB free tier. Rather than compromising the core product around an unreliable dependency, I kept Phase 4 focused on structured check-in data and moved free-text emotion classification to Phase 7.

Quality and safety

Automated tests
149
Rule-engine rules
9
Banned phrases
19

Testing

  • 89 backend tests (Vitest) cover the rule engine, the Gemini tone validator and the ML client.
  • 60 ML-service tests (pytest) cover feature preparation and the model’s training, sanity, stability and confidence gates.

Rule engine

Nine rules: five deficiency-related rules (iron, vitamin D, magnesium, B12, vitamin C), three lifestyle rules (sleep debt, dehydration, sedentary behaviour) and one sustained-stress rule. The rules are based on peer-reviewed nutritional science, with their sources documented in the project.

Security and safety

  • Supabase authentication with session verification on API routes.
  • Zod validation at API boundaries, and Prisma parameterized queries.
  • Rate limiting, sanitized markdown, and environment-variable separation.
  • Gemini is kept behind the backend rather than being exposed directly to the frontend.

Progress

  1. Phase 0 — Monorepo, deploy pipeline, Supabase (complete)

  2. Phase 1 — Auth + animated onboarding (complete)

  3. Phase 2 — Daily check-in + dashboard (complete)

  4. Phase 3 — Rule engine + Gemini insights (complete)

  5. Phase 4 — Personal ML pattern model (complete)

  6. Phase 5 — Encrypted journalIn progress

  7. Phase 6 — Women’s wellness section (not started)

  8. Phase 7 — Polish, accessibility, docs, deploy hardening (not started)

Phase 5 is the private encrypted journal: its encrypted backend is done, and the journal interface is next. The deferred emotion-classification work is planned for Phase 7.

What I learned

  1. Adding AI to a product is less about calling an LLM and more about designing the system around it — deterministic logic, validation, safety constraints, fallbacks, and clear boundaries matter just as much as the model itself.

  2. How to design a distributed application where different services have deliberately different responsibilities instead of putting everything into one backend.

  3. Personalization with small datasets requires being comfortable saying “there isn’t enough evidence yet” instead of forcing the system to produce an answer.