Oluwafemi Obajuluwa

Oluwafemi Obajuluwa › Picashot

How it's built

Several apps sharing one account and one library

How it's built

Picashot is several apps sharing one account and one library, which is most of the reason it took as long as it did.

  • Mobile app: iOS and Android, one Expo codebase
  • picashot.co: the main site
  • Studio: creator tools, separate app
  • Portfolios: rendered on creators' own domains
  • Origin: reverse image search for credit
  • Blog: editorial and release notes
  • API: one backend behind all of it
  • Workers: thumbnails, hashes, embeddings

It started as an Android app in Kotlin, because that's what I knew. A year later I rewrote it in Expo so it could run on iOS too. That meant one codebase for both platforms and over-the-air updates, so a fix can reach people the same day instead of waiting on a store review.

The website has been rewritten twice. Next.js, then Next.js again, and it now runs on TanStack Start. The site is mostly image loading and data fetching, and Start handles both without getting in the way.

The backend is a Node API split by feature with Postgres behind it. Images are the expensive part. An original goes to S3, a Lambda picks it up and generates five sizes with Sharp, and a webhook writes the URLs back when it's finished. Uploads don't wait for any of that. Perceptual hashes and CLIP embeddings are generated on the same path.

  • Expo, React Native: the app, updated over the air
  • TanStack Start: the website
  • Node, TypeScript: the API, split by feature
  • Postgres: photos, games, people, points
  • pgvector: image embeddings for Origin
  • S3, Lambda, Sharp: originals in, five sizes out
  • SES: login codes, digests, Wrapped