← work

stackd

a structured rating and discovery platform for health products.

react · typescript · supabase · postgresql — 2026

visit sitegithub

01 / why

Ratings for supplements and health products are mostly attached to listings, which means they are attached to whatever a seller decided constitutes a product. Two sizes of the same formula accumulate separate reviews; a reformulation inherits the old ones.

Stackd was an attempt to model the thing being rated properly first, and to see what a rating system looks like when it sits on top of a real product graph.

02 / system

A React and TypeScript front end on Vite, with Supabase providing Postgres, auth, row-level security, and edge functions. The catalog holds 432 product variants across 24 brands, with search, filtering, ratings and reviews, and ranked lists a user can share.

brandproductvariantratinglist
data model

03 / engineering

The core modeling decision is the brand → product → variant chain. Ratings attach to the product, not the variant, so size and packaging differences don't fragment the signal, while ingredient data lives at the variant level where it actually differs.

Access control is enforced in the database with row-level security rather than in application code: a user may write only their own ratings and lists, and reads of public lists are a policy rather than a query convention. Ingredient analysis runs in a Supabase edge function that calls an OpenAI model and caches the parsed result against the variant, so the same label is never analyzed twice.

04 / decisions

Why Postgres with RLS? The interesting queries here are relational — variants by ingredient, products ranked within a category — and the authorization rules are simple enough to express as policies. Putting them in the database meant the client could talk to it directly without an intermediate API layer to keep honest.

Why analyze ingredients with a model at all? Ingredient lists are unstructured, inconsistently ordered, and full of synonyms. A model is good at normalizing them; it is not good at adjudicating safety, so the output is presented as description rather than verdict.

05 / results

432 variants and 24 brands ingested, with auth, ratings, lists, search, and ingredient analysis working end to end. This is an experiment, not a product: there is no user base and no traction to report.

Minimal data model diagram: brand, product, variant, rating, and shareable list
product data model

06 / reflections

Most of the difficulty was not engineering. It was deciding what a rating means when the thing rated is a chemical formulation — and realizing that a trustworthy rating system needs a position on who is rating and why, which a schema alone can't supply.

If I returned to it, I'd start with the trust model rather than the catalog.