Mirobody
The canonical registry of human health — roughly two thousand standardized indicators, clinical and lifestyle, resolved into one language.
翻訳待ち
No updates detected yet. GitHub releases will appear here.
Poopのゲーミフィケーション
Loading the full README.
Read the full README ↗AI駆動でうんこ支援開発するぞ
モバイルWebで「戦う → 排便ログを残す → 仲間になる」体験を提供するアプリ。
この説明と下の技術スタックは現行の実装(旧ループ・web版)のもの。新しい企画は docs/IDEA.md、資料の一覧は docs/README.md。現行web版の構成は docsArchive/web/architecture.md、うんちくんの見た目は docsArchive/poopm-3d.md。
| 領域 | 技術 |
|---|---|
| Webアプリ | Next.js 16 (App Router) + TypeScript |
| UI | Tailwind CSS v4 + shadcn/ui |
| アニメーション | Framer Motion |
| 一時状態 | Zustand (persist) |
| 認証・DB・画像 | Supabase (@supabase/supabase-js, @supabase/ssr) |
| デプロイ | Vercel |
apps/native は同じ Supabase を使う React Native 版。ネイティブモジュール(vision-camera / fast-tflite / expo-gl)を使うため Expo Go では動かず、dev build が必要。
cp apps/native/.env.example apps/native/.env.local # EXPO_PUBLIC_SUPABASE_URL / ANON_KEY を設定
npm run ios -w apps/native # 初回は prebuild + ビルド
npm run start -w apps/native # 2回目以降は dev client へ接続
実機・クラウドビルドは apps/native/eas.json(development / preview / production)を使う。課金は RevenueCat 経由で、EXPO_PUBLIC_REVENUECAT_APPLE_API_KEY が未設定だと購入は利用不可として扱われる(iap-gateway.ts の no-api-key)。
画面構成は docs/native/screen-sequence.md、現行実装の仕様は docsArchive/web/web-spec.md。
flake.nix で固定)direnv と Nix を使う場合は、リポジトリ直下で
direnv allow を実行すると flake.nix の開発シェル(Node.js 24)が自動で有効になる。
使わない場合は Node.js 24 を各自で用意する。
.envrcは Node.js のツールチェーンを用意するだけで、アプリの環境変数は読み込まない。 環境変数は次節の.env.localから Next.js が読み込む。
# 1. 依存関係をインストール(ロックファイルどおりに固定して導入)
npm ci
# 2. 環境変数ファイルを作成
cp apps/web/.env.local.example apps/web/.env.local
# 3. .env.local に Supabase の値を記入する
apps/web/.env.local に以下を設定する。値は Supabase Dashboard の
Project Settings > API から取得する。
| 変数名 | 内容 |
|---|---|
NEXT_PUBLIC_SUPABASE_URL | SupabaseプロジェクトのURL |
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY | 公開可能キー(Publishable key / anon key) |
読み込みの仕組み:
.env.local を自動で読み込む。dotenv 等の追加設定は不要。NEXT_PUBLIC_ を付けた変数のみがブラウザへ配信される。付けない変数はサーバー側
(Server Component / Server Action / Route Handler)からのみ参照できる。.env.local は .gitignore 済みでコミットされない。コミットするのは
apps/web/.env.local.example のみ。apps/web/.env.local.example にも置かない。NEXT_PUBLIC_ を付けない。付けるとクライアントバンドルへ埋め込まれる。./scripts/setup-vercel-env.sh production。レポート分析の課金を本番で動かすには、環境変数の設定だけでは足りない。 以下を上から順に行う。
subscriptions テーブルが無いと、デプロイ後にレポート画面が落ちる。
supabase link --project-ref <本番のproject-ref>
supabase db push
テストモードの価格IDは本番モードには存在しない。 作り直しが要る。
STRIPE_SECRET_KEY=sk_live_xxx ./scripts/create-stripe-price.sh
金額を変えるなら AMOUNT=980 のように渡す(単位は円)。
前提として、Stripe Dashboard で事業者情報の登録・審査を済ませ、本番の鍵
(sk_live_...)が発行されている必要がある。サンドボックスのままでは
charges_enabled が false で、本番の課金はできない。
ローカルは stripe listen が転送するが、本番は Dashboard での手動登録が要る。
登録して初めて whsec_... が発行される。これを忘れると
「決済は通るのに権利が付かない」状態になる。
URL: https://<本番ドメイン>/api/stripe/webhook
購読するイベント:
checkout.session.completedcheckout.session.async_payment_succeededcheckout.session.async_payment_failedcustomer.subscription.updatedcustomer.subscription.deleted遅延通知型の支払い方法(コンビニ払い等)では completed が未払いのまま先に
届き、実際の成否は async_payment_* で後から知らされる。この2つを購読しないと、
正しく支払った利用者に権利が付かない。
解約・支払い方法の変更は Stripe の Customer Portal へ委ねている。 本番モードでは既定の設定が有効になっていないため、Dashboard の Settings > Billing > Customer portal で有効化する。
これを忘れると、createBillingPortalSessionAction がセッションを作れず、
課金中の利用者が解約できない状態になる。
npx vercel login
npx vercel link
./scripts/setup-vercel-env.sh production
値はローカルの .env.local からコピーしないこと。 5変数すべて本番用の
別の値になる。
| 変数 | 本番で入れる値 |
|---|---|
STRIPE_SECRET_KEY | sk_live_...(テストの鍵は使えない) |
STRIPE_PRICE_ID | 手順2で作った price_... |
STRIPE_WEBHOOK_SECRET | 手順3で発行された whsec_... |
NEXT_PUBLIC_APP_URL | https://<本番ドメイン>(末尾スラッシュ無し) |
SUPABASE_SERVICE_ROLE_KEY | 本番Supabaseプロジェクトの Service Role キー |
Preview 環境にはテストモードの鍵(sk_test_)を入れる。本番の鍵を入れると、
PRのプレビュー環境から本物の決済ができてしまう。
npm run dev # 開発サーバー (http://localhost:3000)
npm run build # 本番ビルド
npm run start # 本番サーバー
npm run lint # ESLint
スキーマは Supabase CLI のマイグレーションで管理し、TypeScript の型は
そこから生成する。詳細な手順は supabase/README.md を参照。
flake.nix の開発シェルに含まれる)--local でローカルDBに接続するため必要)db:types は起動中のDBの現状から型を作る。マイグレーションのファイルを
読むわけではないので、次の2つを先に済ませておく必要がある。
supabase start # 未起動なら起動する
supabase db reset # migrations を適用してスキーマを最新にする
npm run db:types # packages/domain/src/types/database.types.ts を生成する
supabase start は既存のDBを立ち上げるだけで、追加したマイグレーションを
適用しない。db reset を飛ばすと、スキーマ変更が反映されていない古い型が
そのまま生成される(エラーにならないので気づきにくい)。
db reset はDBを作り直すためローカルのデータは消える。
検証だけなら事前の起動は不要。db:types:check は未起動のときに一時的にDBだけ
起動し、いずれの場合も db reset でマイグレーションを適用してから検証する。
このコマンドもローカルDBを作り直すため、データは消える。
npm run db:types:check # 生成物がマイグレーションと一致するか検証する
マイグレーションを追加・変更したら必ず上記の手順で型を生成し直し、生成された
packages/domain/src/types/database.types.ts を同じコミットに含める。 再生成漏れは pre-commit
フック(型がステージされていなければ落ちる)と CI(実際に生成し直して差分を検証)
の2段階で検出する。
生成された型は apps/web/src/lib/supabase/ の各クライアントに型引数として渡してあるため、
テーブル名・カラム名・列挙値の補完と検査がそのまま効く。
Supabase クライアントを生成してよいのは features/<機能名>/actions.ts、
lib/supabase/、apps/web/src/proxy.ts の3か所だけ。ESLint は apps/web/src/ 全体を既定で
禁止し、この3か所だけを解除する許可リスト方式で構成してある。新しく
ディレクトリが増えても自動的に禁止側に入るため、黙って穴が空かない。
塞いでいる経路は次のとおり。
This is the beginning of the README. Read the rest at the original. Read the full README ↗