MeadMate

Brew Day Companion — Built on Cloudflare

React Native · Cloudflare Workers · D1 · Pages

RNCross Platform
D1Edge Database
$0Infra Cost
100%Offline
Why it exists

I brew mead. I have a terrible memory.

🍯

Mead is complicated

Nutrient additions at precise times. Gravity readings every few days. Miss a step and you get stuck fermentation or off-flavours. Spreadsheets were not cutting it.

🧠

My memory is bad

Literally forgot to add nutrients on day 2 because I was watching TV. Built an app with push reminders. Problem solved.

🚫

I hate ads and tracking

Every existing app wants an account, has analytics SDKs, or runs ads. I wanted one that does nothing you didn't ask for.

🔧

Excuse to build stuff

Honestly this is also just a good excuse to build something with React Native and mess around with the Cloudflare stack at the same time.

The App

One app.
Full lifecycle.

From recipe planning through brew day, fermentation, racking, conditioning, to bottling. Every stage guided and tracked.

  • 🍯Mead — Traditional, melomel, cyser, braggot, pyment
  • 🍎Cider — Still, sparkling, hopped, spiced
  • 🍺Beer — BIAB, all-grain, kit, extract, partial-mash
  • 🧪Wash — Simple sugar fermentation with ABV targeting
React Native + Expo — one codebase, Android and iOS. No account. No ads. No tracking. One-time purchase.
Dashboard
Feature Tour

What it looks like

Brew Day
Brew Day
Sanitisation
Sanitisation
Gravity Log
Gravity Log
Brew Details
Batch Details
Calculators
Calculators
Shopping
Shopping List
Racking
Racking Day
Engineering — Fermentation Prediction

Gravity prediction model

Fermentation follows an exponential decay curve. Given a few gravity readings, the app fits the model and tells you when you'll hit target FG.

SG(t) = FG + (OG − FG) · e−kt
  • 1.Fit k via non-linear least squares over your gravity log
  • 2.Solve for t when SG(t) = target FG
  • 3.Show R² — below 0.9 it warns you the data is too sparse to trust
  • 4.Refits live every time you log a new reading
Gravity Log
Cloudflare Workers API

The backend: Hono + D1

📱 RN App TypeScript
Worker Hono + TS
🗄️ D1 SQLite at edge

Routes

/recipes /yeasts /equipment /share /ratings /api/hydrometer/ispindel

Auth / Security

Admin token via wrangler secret. Cloudflare Turnstile for bot protection. CORS locked to the app domain.

Cron trigger

Daily at 03:00 UTC — purges expired shared brews from D1 automatically.

D1 Migrations

9 migrations so far. Versioned SQL files, applied via wrangler d1 migrations apply.

// wrangler.toml (api)
name = "meadmate-api"
main = "src/index.ts"
compatibility_date = "2024-11-01"
compatibility_flags = ["nodejs_compat"]

[[d1_databases]]
binding = "DB"
database_name = "meadmate-db"
database_id = "c6a6bc16-..."

[triggers]
crons = ["0 3 * * *"]

# secrets set via wrangler CLI:
# ADMIN_TOKEN
# TURNSTILE_SECRET
# MOBILE_APP_SECRET
Hardware Integration

Auto-logging gravity with WiFi hydrometers

The iSpindel and RAPT Pill are WiFi hydrometers you float in your fermenter. They measure tilt angle, convert to gravity, and POST readings to a URL you configure. Both are integrated.

  • 1.Device POSTs to /api/hydrometer/ispindel — no auth required, device auto-registers by hardware ID
  • 2.Rate limited at 10 seconds between pushes from the same device
  • 3.App claims the device by hardware ID, binds it to a batch
  • 4.App polls for latest reading and history — auto-populates the gravity log
Calibrated gravity (corr-gravity field) is preferred over raw when present. Raw values greater than 2.0 are normalised from SG×1000 format automatically.
iSpindel Clone
// Device POSTs:
{
  "name": "MySpindel",
  "ID": "abc123",
  "angle": 35.2,
  "temperature": 20.1,
  "battery": 4.1,
  "gravity": 1.065,
  "corr-gravity": 1.063
}
Brew Sharing

Share a brew — no account needed

  • 1.App packages the batch: name, type, gravity log, recipe, optional notes
  • 2.Worker validates the payload, generates an 8-char short code from an unambiguous charset (no I/O/1/0)
  • 3.Stored in D1 with a 90-day expiry. Rate-limited at 10 minutes per device ID.
  • 4.Anyone can view via the short code — no login, no app required
  • 5.Cron job deletes expired rows nightly
Short code charset: ABCDEFGHJKMNPQRSTUVWXYZ23456789
Strips I, L, O, 0, 1 to avoid visual confusion when sharing verbally or on paper.
// Short code generator
const chars =
  'ABCDEFGHJKMNPQRSTUVWXYZ23456789';
const bytes = new Uint8Array(8);
crypto.getRandomValues(bytes);
return Array.from(bytes,
  b => chars[b % chars.length]
).join('');

// Stored in D1:
// code, data (JSON), brewer,
// created_at, expires_at,
// view_count, device_id
Cloudflare Pages

The web presence — $0/month

Basic site + developer docs + recipe feed — all on Pages free tier

Static HTML. No build step. Three lines of config. Global CDN, auto TLS, preview deployments on every branch.

⚙️

wrangler.toml (3 lines)

name, compatibility_date, pages_build_output_dir = ".". That's the entire config.

🔒

_headers file

X-Frame-Options, X-Content-Type-Options, cache control for screenshots. Declarative, no server needed.

↗️

_redirects file

Short URL to Play Store. Works like Netlify redirects - just a text file.

What's next

Roadmap

Shipped

Android App

Full lifecycle, 20+ calculators, TOSNA, gravity prediction

Shipped

Workers API

Hono + D1, recipes, sharing, ratings, iSpindel, cron cleanup

Shipped

iSpindel

Auto gravity logging from WiFi hydrometer hardware

Considering

Google Play

Privacy concern — Google requires your legal name and address on the listing.

Planned

Community Library

Static JSON on Pages, Git-backed, PR-contributed

Planned

iOS

RN codebase is already cross-platform, mostly just testing

Key takeaways

  • 1.Offline-first removes a ton of complexity — no auth, no sync, no GDPR headaches
  • 2.React Native + Expo is genuinely good for cross-platform now. One codebase, TypeScript throughout.
  • 3.Hono + D1 + Workers is a really clean stack. Cron triggers, edge SQLite, custom domains — all free tier.
  • 4.Static JSON can be an API — the recipe feed needs no server. A file on Pages is enough.
  • 5.Build the thing that annoys you — personal itch projects teach you more than tutorials

meadmate.app  ·  meadmate@perpetualprototypes.io