Back to Portfolio

Case Study · 03 · MVP Beta v0.1.0

muzulog

3 秒の記録 で、あなたの花粉体質を特定する — ログインレスのヘルスケア PWA

Problem

「結局、私は何の花粉症なの?」

毎年春先になると「なんとなく鼻がムズムズする」「目が痒い」と感じる。でも病院に行くほどでもないし、アレルギー検査は費用も時間もかかる。そして既存の花粉症アプリは ログイン必須・多機能・医療的トーン で重く、「そこまで管理したくない」と離脱してしまう。

必要なのは治療ツールでも管理ツールでもなく、ライト層向けの「体質発見ツール」 だった。「スギとヒノキ、どっちに反応してるんだろう」という素朴な疑問だけを、片手のスマホで片付けたかった。

Approach

"管理" を捨て、"発見" に寄せる。

入力は 3 ボタン (絶好調 / 違和感 / 辛い) に絞り、テキスト入力はゼロ。起動から記録完了までを 3 秒以内 に収めることを画面設計の前提にした。面倒なアプリは即削除されるターゲット層にとって、この一点が UX の生死を分ける。

推定はバックグラウンドで自動実行する。5 種類の花粉 (スギ / ヒノキ / イネ科 / ブタクサ / ヨモギ) × 5 リージョンの飛散カレンダーを TypeScript の静的データとして型付けし、SymptomRecord[] → EstimationResult[]純関数 として推定エンジンを実装。Vitest でユニットテスト 9 ケースをかけて挙動を固めた。

バックエンドを一切持たない設計に振り切り、ユーザーデータは LocalStorage だけに置く。Zustand + persist ミドルウェアで永続化は数行で完結。認証基盤・サーバー・課金導線が全部消えることで、プライバシー面と運用コスト面の問題が同時に解決した。

外部花粉データは Open-Meteo Pollen API を採用。API キー不要・商用利用可・無料で、個人識別情報を一切送信しない設計を API クライアント層に強制した。

3 ボタン記録 UI

絶好調 / 違和感 / 辛いの 3 ボタンをタップするだけ。

「辛い」を選んだ時のみ、 つらさの原因をボトムシートで追加入力できる。

自動推定エンジン

5 種花粉 × 5 リージョンの飛散カレンダーと症状記録を突き合わせ、「ピーク期重なり × 症状強度」の相関スコアで確率化。

カレンダービュー

月別の色ドットで症状履歴を可視化。

「いつから辛くなってきたか」を一目で把握できる。

リアルタイム花粉インジケーター

Open-Meteo API からその日の花粉飛散量を取得してメイン画面に表示。

1 時間キャッシュでネットワーク負荷を最小化。

オフラインファースト PWA

ServiceWorker でアプリシェルを事前キャッシュ。

圏外でも記録操作が止まらない。ホーム画面追加対応。

受診用カンペ生成 (予定)

過去記録を 1 タップで画像出力する機能をロードマップ上に配置。

「医師に見せるだけ」で受診時の説明を省略できる体験を狙う。

muzulog のオンボーディング画面。桜のロゴとタグライン「カジュアル花粉症チェッカー」、3 つの売り (3 秒で記録完了 / ログイン不要・データは端末に保存 / 記録を続けると花粉の種類を推定) を表示。
Onboarding3 つの約束だけで始められる
メイン記録画面。「いまの調子は?」の問いかけと、絶好調 (緑) / 違和感 (黄) / 辛い (赤) の 3 ボタンを大きく配置。ソフトパステルグラデーション + ガラスモーフィズムの UI。
3 ボタン記録タップだけで 3 秒以内に完了
詳細入力ボトムシート。「辛い」を選んだ時のみ表示され、鼻水・くしゃみ / 目のかゆみ / だるい・ぼんやり から任意選択。スキップも可能。
詳細入力「辛い」時だけ、軽く深堀りする
カレンダービュー。2026 年 4 月の月別グリッドで、症状記録のある日に色ドットを表示。凡例は絶好調 (緑) / 違和感 (黄) / 辛い (赤)。
カレンダー月別の色ドットで継続状況を可視化
Framework
Next.js 16.2 (App Router, SSG)
Language
TypeScript 5 (strict)
UI
React 19.2 + Tailwind CSS v4 + Framer Motion 12
State
Zustand 5 + persist (LocalStorage 同期)
Testing
Vitest 4 + Testing Library (推定エンジン 9 ケース)
Deploy
Cloudflare Pages (静的配信)
CI / CD
GitHub Actions (lint → type-check → test → build → deploy)
External API
Open-Meteo Pollen API (CC BY 4.0, 商用可, APIキー不要)
AI 協業
Claude Code (.claude/agents, .claude/rules, .claude/skills)

Result

数日で MVP を公開、サーバー費用はゼロ。

3 ボタン記録・カレンダー・推定エンジン・設定・初回オンボーディング・PWA 対応・CI/CD までを数日の Claude Code 駆動開発でまとめ上げた。Cloudflare Pages の静的配信のみで成立し、サーバー費用は実質ゼロ。

推定エンジンは Vitest の 9 ケースで型と挙動を固めてあり、記録データの形式が変わらない限り壊れない設計。UI は記事執筆時点で 2026 年モバイル UI/UX トレンド — ソフトパステルグラデーション + ガラスモーフィズム + Spring 物理アニメーション + ダークモード完全対応 — に寄せている。

最新版は muzulog.c12o.net で公開中。

Learnings

作ってみて分かったこと。

"やらないこと" を決めると、差別化は自動で決まる

ログイン / 多機能 / 医療トーンをすべて捨てた結果、"体質発見ツール" という既存アプリにないポジションが自然に立ち上がった。

MVP のコア体験は、機能を足すより引き算で作るほうが早い。

"3 秒ルール" を先に決めると画面設計の迷いが消える

起動から記録完了までのターゲット時間を決め打ちにしてからは、画面構成・遷移数・入力項目がすべて逆算で決まった。

定量の縛りを先に置くと、デザイン判断が揺れにくい。

推定エンジンは "過剰な自信" が最初の敵

単純なスコア計算だと、記録 2 件で「スギ 99%」のような過大評価が簡単に出る。

95% 上限キャップ記録数ベースの信頼度バッジ を導入し、"確度が低い" ことを UI 側で正直に見せる仕組みにした。

ログインレスでも個人特定は避けられる

外部 API 呼び出しで IP/UA が向こうに記録される懸念がある。

花粉データを 地域単位 だけで取得し、ユーザー固有情報を一切送信しない設計を .claude/rules/api-data.md に書いて強制した。

ルールをコードではなく規約で縛ると、AI ペアプロとも相性が良い。

Next.js 16 の破壊的変更は "ドキュメントを読ませる" で越える

Claude の学習データには 16 以前の API が残っている。

AGENTS.md に「node_modules/next/dist/docs/ を読んでから書く」ルールを明文化したら、破壊的変更に追従しながらコードを書けるようになった。

TypeScript strict × 純関数 × Vitest の三位一体

推定エンジンを SymptomRecord[] → EstimationResult[] の純関数にしたことで、挙動の検証が Vitest のテーブル駆動テストで完結した。

短期間で壊れにくい MVP を作るなら、コアロジックをこの三点セットで固めるのが最短経路だと実感した。