NewCode with Beto MCP

Kujun

Local-first iOS habit tracker with optional NFC check-ins, a GitHub-style consistency heat map, streaks, and a Home Screen widget

Overview

Kujun (from Korean 꾸준, kkujun: "steady, consistent") is a local-first habit tracker for iOS. Pair a habit with an inexpensive NFC tag, place it where the action happens, and scan there to check in. It also includes a GitHub-style consistency heat map, streaks, and a Home Screen widget.

Built with Expo SDK 57 as a real-world example, not a template you are meant to ship as-is. Use it to study file-based routing, SQLite, SwiftUI widgets, local notifications, and iOS 26 liquid glass wired together in one app.

No accounts and no backend. Everything lives in a local SQLite database on the device.

Key Features

This project includes:

  • NFC check-ins - Pair a habit with an inexpensive NTAG213/216 sticker, place it where the habit happens, and scan it to complete the habit
  • Optional by design - Habits without a tag still work with a normal tap. NFC is recommended, never required
  • Track habits - Choose a name, SF Symbol icon, accent color, and weekly schedule
  • Today view - Scan or tap what is due today, with haptics and a small celebration
  • Consistency heat map - A GitHub-style contribution grid per habit, plus current/best streaks and completion rate
  • Home Screen widget - A SwiftUI widget (small and medium) showing your last 7-14 days and streaks, tappable straight into the app
  • Reminders - Optional per-habit local notifications at a chosen time
  • Onboarding - A focused first-run welcome that leads into creating the first habit. Reminders and NFC are introduced only when relevant
  • Private by design - No account, no server, no tracking. Your habits stay on the device

Why it is useful to study

Most habit apps let you tap a checkbox from the couch. Kujun adds a little real-world friction: the check-in happens where the habit happens. Tags are a personal commitment device, not a security system. Unpairing or disabling NFC verification takes 24 hours, so the friction means something.

The widget is the trickiest part of the project. Widget code is serialized and runs inside the native widget extension, so it cannot reference anything from module scope. The app sends it a plain snapshot of props after every state change. That pattern is worth studying if you want to build widgets with Expo.

Tech Stack

Run it

Requires Xcode. This app uses a Home Screen widget and iOS 26 APIs, so it cannot run in Expo Go.

bun install
bun run ios

On a physical device:

bun run ios:device

What You Get with Pro Lifetime Access

When you become a Pro member at Code with Beto, you unlock lifetime access to all our premium resources. Including: complete source code, templates, and tools through our private GitHub organization. Every project we release is available there, searchable and ready to use.

We actively maintain everything to ensure a smooth dev experience on iOS (with Android support coming soon), with easy setup and up-to-date dependencies. Pro access also includes entry to our private Discord community, where you can ask questions, get support, and connect with other developers.

Get Started Today

Get access now and start exploring this local-first iOS habit app today.

Questions? Join our Discord server where our community of developers is ready to help! Or if you prefer, send us an email at beto@codewithbeto.dev