< back to work > case_study

> · project

Przepisnik

A recipe book for home bakers — same code, three places

Cross-platform recipe and cake-planning app. Turborepo + Bun monorepo sharing business logic between an Expo mobile app and a Vite web app, with self-hosted PocketBase as the backend.

Stack

  • Turborepo
  • Bun
  • React Native
  • Expo
  • Unistyles
  • React 19
  • Vite
  • TailwindCSS
  • shadcn/ui
  • TanStack Query
  • PocketBase

Engagement

  • statusside project
  • modelside project
  • since2024
  • > solo, evenings and weekends

Przepisnik (“recipe book” in Polish) is a recipe-management app for home bakers. Save recipes, plan multi-tier cakes, scale ingredients, walk through bakes step by step. iOS, Android, and web — all driven by the same TypeScript code.

The monorepo

Turborepo + Bun workspaces, two apps and five packages.

apps/
├─ mobile/   ── Expo + React Native + Unistyles ─┐
└─ web/      ── Vite + React 19 + Tailwind ──────┤

packages/                                        │
├─ shared/        ── types · hooks · logic   ◀───┤
├─ auth/          ── PocketBase client       ◀───┤
├─ icons/         ── codegen'd SVGs          ◀───┤
├─ category-icon/ ── picker UI               ◀───┤
└─ i18n/          ── translations            ◀───┘

The split is deliberate. Anything that doesn’t render — recipes, ingredients, cake planner, ingredient parser, shopping list, query orchestration — lives in packages/shared and gets imported by both apps. Anything platform-specific (Unistyles on mobile, Tailwind on web) stays in the app it belongs to.

The mobile app recently moved off Tamagui to Unistyles — styling that resolves in C++ over JSI, so a theme switch never bounces through the React tree — paired with a native tab bar and a shared “Warm Sage” palette the web app mirrors in Tailwind. Same design language, two rendering stacks. Dropping Tamagui also took a chunk out of the bundle and stopped the build from breaking every time Expo ships a major.

~/przepisnik

$ bun run stats

  • platforms shipped from one repo 3 (ios / android / web)
  • shared business-logic loc 6 000
  • generated icon components 501
~/przepisnik/cross-platform

the same recipe on mobile and web — one shared core, two native renderers

The backend: PocketBase

Started on Firebase, moved off it. Native Firebase SDKs and Expo don’t always get along — every upgrade is an opportunity for the build to break in a creative new way. The whole thing now runs on PocketBase: a single Go binary that hands me auth, a database, and file storage behind a plain REST API, with the data sitting on a PocketBase instance I control — hosted on elest.io — instead of someone else’s dashboard.

Its client is just a typed wrapper over HTTP, so it behaves identically on mobile and web — nothing native to go feral when Expo bumps a major. Sessions persist through an AsyncAuthStore (Expo SecureStore on mobile, browser storage on web) with token refresh on a timer; password and OAuth2 sign-in both work. The auth context lives in packages/auth and is identical on both platforms.

The baker-specific bits

  • Recipes have nested steps with per-step ingredients, so “preheat the oven” and “add 200g of butter” are first-class objects, not lines in a paragraph
  • useIngredientParser turns “200g flour” or “1 1/2 tsp baking soda” into structured { amount, unit, name } so scaling actually works
  • useCakePlannerCore handles tier sizing, portion math, and ingredient roll-up across multi-recipe bakes
~/przepisnik/cake-planner

the cake planner — multi-tier ingredient roll-up

Offline + persistence

TanStack Query + persistQueryClient keep recipes available when you’re in a kitchen with bad signal — which, if you’ve ever tried to bake from a phone, is most of the time.

Where it’s going

This one has an actual written roadmap — each feature lives as a self-contained spec in the repo, with data model, architecture, and build phases sketched before any code. Recent releases shipped manual nutrition tracking, a baking knowledge base (Poradnik — glossary terms linked inline in recipe steps), and a home dashboard. Next up is the one with the biggest daily payoff: plan a week of meals, get one deduplicated shopping list compiled across everything.

~/przepisnik/roadmap

$ bun run roadmap

  • [x] manual nutrition + macro card v0.2.0
  • [x] poradnik — glossary + inline step terms v0.3.0
  • [x] home dashboard shipped
  • [>] meal planner → auto-compiled shopping list next
  • [ ] public recipes + discovery feed
  • [ ] pantry + "what can I cook?"
  • [ ] collections / cookbooks
  • [ ] household sharing
  • [ ] cooking mode — timers · voice · offline