尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证マリーンズを応援する毎日を、記録し、つなぎ、未来へ積み立てる。ロッテ貯金と割り勘を統合した個人利用アプリ
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
マリーンズを応援する毎日を、記録し、つなぎ、未来へ積み立てる。 千葉ロッテマリーンズの観戦体験を軸に、ロッテ貯金と割り勘を1つのアプリへ統合した個人利用アプリです。 仕様は docs/marine-wallet-spec-v0.1.md、統合方針は docs/integration-plan.md を参照してください。 • 完全個人利用 / 非商用 • Marine Wallet 自身は資金を保有・移動しません(外部アプリへの誘導のみ) 旧アプリのリポジトリ・Vercelプロジェクト・Supabaseプロジェクトはいずれも削除または PAUSED 済みです。データは移行済みで、旧ロッテ貯金の試合116件(合計 54,600円)と 旧割り勘の92件はすべて本アプリのDBにあります。 • Next.js 16(App Router / Turbopack / proxy.ts) • React 19 • Tailwind CSS v4 • Supabase(Auth / PostgreSQL / RLS) • Vercel チャートは外部ライブラリを使わず SVG で自前描画しています(components/charts/CumulativeChart.tsx)。查看完整 README ↗
マリーンズを応援する毎日を、記録し、つなぎ、未来へ積み立てる。
千葉ロッテマリーンズの観戦体験を軸に、ロッテ貯金と割り勘を1つのアプリへ統合した個人利用アプリです。 仕様は docs/marine-wallet-spec-v0.1.md、統合方針は docs/integration-plan.md を参照してください。
| リポジトリ | minatani-01/marine-wallet(旧 baseball-savings を改称) |
| 公開URL | https://marine-wallet.vercel.app |
| Vercelプロジェクト名 | marine-wallet |
| Supabase | Marine Wallet(ref xliszlnpypvqghrwplxa) |
| 旧アプリ | 旧スタック | 統合後 |
|---|---|---|
| ロッテ貯金(baseball-savings) | Vite + React + Supabase | 貯金タブ |
| 割り勘アプリ(warikan-app) | Next.js + Supabase | 割り勘タブ |
旧アプリのリポジトリ・Vercelプロジェクト・Supabaseプロジェクトはいずれも削除または PAUSED 済みです。データは移行済みで、旧ロッテ貯金の試合116件(合計 54,600円)と 旧割り勘の92件はすべて本アプリのDBにあります。
proxy.ts)チャートは外部ライブラリを使わず SVG で自前描画しています(components/charts/CumulativeChart.tsx)。
npm install
cp .env.example .env.local # Supabase の URL とキーを設定する
npm run dev
.env.local:
NEXT_PUBLIC_SUPABASE_URL=https://<project-ref>.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=<publishable key>
Supabase の SQL Editor で番号順に実行します(何度実行しても安全な冪等スクリプトです)。 本番プロジェクトへは適用済みで、新しく環境を作るときだけ必要になります。
| ファイル | 内容 |
|---|---|
0001_marine_wallet_core.sql | 共通スキーマ(profiles / saving_rules / games / saving_entries / monthly_savings)とRLS。saving_rules は 0017 で saving_rule_settings に置き換え |
0002_import_legacy_games.sql | 旧ロッテ貯金アプリからのデータ移行(実施済みの記録。再実行用のクエリを含む) |
0003_confirmed_ui.sql | 確定UIに合わせたボーナス項目とカスタム貯金の追加 |
0004_home_away_nullable.sql | 旧アプリが未記録だったホーム/ビジターを null 許容にする |
0005_marine_link.sql | Marine Link(marine_links / link_permissions / 判定関数 / RPC / 共有用ポリシー) |
0006_shared_goals.sql | 共同貯金(shared_goals / shared_goal_members / 進捗RPC) |
0007_split_member_marine_id.sql | メンバーの Marine ID と、参加者単位の割り勘共有 |
0008_member_participation.sql | メンバーの参加機能(割り勘 / 貯金)と、貯金の参加者別集計RPC |
0009_drop_deposit_pending.sql | 月末フローから「入金手続き中」を外す |
0010_member_avatar.sql | メンバーの写真アイコン(member-avatars バケットと、自分のフォルダだけ読み書きできるRLS) |
0011_profile_avatar.sql | 自分のプロフィールアイコン(profiles.avatar_path) |
0012_annual_goal.sql | 目標金額を月間から年間へ(monthly_goal_amount → annual_goal_amount)。0020 で廃止 |
0013_master_auto_accept.sql | マスター権限(profiles.is_master)。マスターからの接続リクエストは承認なしで接続する |
0014_confirm_month_for_circle.sql | 月末の確定を、貯金に参加している接続済みメンバーにも反映する |
0015_totals_by_deposited.sql | 累計貯金額の基準を「確定した月」から「入金した月」へ |
0016_circle_by_link.sql | 総累計貯金額を、メンバー登録ではなく Marine Link の接続で決める |
0017_shared_saving_rules.sql | 貯金ルールを全アカウント共通の1行にし、共有設定の「貯金ルール」を変更権限に変える |
0018_auto_saving_entries.sql | つみたての自動生成(試合の登録時と接続の成立時)。確定の対象も接続で決める |
master への push で Vercel が Production を自動デプロイします。環境変数は
NEXT_PUBLIC_SUPABASE_URL と NEXT_PUBLIC_SUPABASE_ANON_KEY の2つだけです。
NEXT_PUBLIC_* はビルド時にバンドルへ埋め込まれるため、環境変数を変更したときは
ビルドキャッシュを使わずに再デプロイしてください。変更していないときはキャッシュを
使って構いません。
ビルド設定は vercel.json(framework: nextjs)でリポジトリ側に固定しています。
旧 Vite 構成のプロジェクト設定が残っていてもこちらが優先されます。
ホーム 更新ボタン / 累計貯金・前月比 / 今月のつみたて額・継続日数
/ 未精算の立替・今季の勝率 / 貯金推移(月別・年別)
貯金 試合登録・カスタム貯金 / 月間集計 / 月末確定・ワンバンク入金
/ 未登録の試合 / 記録 / 貯金ルール
割り勘 精算額と支払い状況 / メンバーごとの支払額(受取はマイナス)/ 精算(PayPay誘導)/ 未精算・すべて・完了
履歴 取引履歴(貯金と割り勘をまとめた時系列)
マイページ Marine ID / アイコン・表示名・ログアウト / お知らせ / メンバー(マスターのみ)
└ メンバー 一緒に使う人を1画面で管理
あなたの Marine ID / 届いているリクエスト / メンバー一覧
(写真アイコン・Marine ID・接続・共有設定・割り勘と貯金の指定)
/ メンバー未登録の接続 / 共同貯金 / 月間比較
仕様書 40章のフェーズ区分に対応します。
| フェーズ | 状態 |
|---|---|
| Phase 1 統合基盤 | 実装済み |
| Phase 2 ロッテ貯金自動化 | 手動登録のみ実装。NPBからの自動取得は未着手 |
| Phase 3 外部アプリ連携 | 金額コピーと起動URLは実装済み。入金ステータスは月末フローに内包 |
| Phase 4 Marine Link | 実装済み(Marine ID / リクエスト / 権限管理 / データ共有 / 月間比較 / 共同貯金) |
| Phase 5 Marine Day | 未着手 |
| Phase 6 Insight | 履歴・推移は実装済み。Season Report / Fan Score / 通知は未着手 |
確定アイコンの置き場所は public/brand/README.md を参照。
public/brand/mark.png が無い場合はワードマークのみを表示するため、画面は崩れない。
saving_rule_settings に1行だけ置きます。
変更できるのはマスターと、マスターが接続の共有設定で「貯金ルール」をONにした相手だけです
(can_edit_saving_rules())。権限が無い人には読み取り専用で見せます。
共有設定の「貯金ルール」は、見せるかどうかではなく変更権限を渡すかどうかです。games は全ユーザー共通で、
saving_entries がユーザーごとの積立額を持ちます。sync_saving_entries_for_game)。あとから接続した人には、
接続が成立した時点で過去ぶんをまとめて作ります(sync_saving_entries_for_user)。
金額は共通ルールで計算するので全員同じです。すでにある記録は触りません
(手で直した額を黙って書き換えないため)。貯金タブの「未登録の試合」は
取りこぼしを拾うための手動の受け皿として残してあります。
つみたてと確定は自動、入金済みだけが各自の操作です。確定の連動はマスターが押した
時点でしか動かないため、あとから接続した人にはマスターが確定済みの月を
接続時にまとめて反映します(sync_monthly_status_for_user)。作るのは確定(ready)までで、
入金済みは実際に送金した本人しか分からないので触りません。monthly_savings が
calculating → ready → deposited の状態を管理します。
入金はワンバンク側で一度に終わるため、間に「手続き中」は挟みません。games を別に引かずに済みます。/split/members に置くと操作中ずっと「割り勘」が点いたままになる。マイページからの
導線なので /me/members に移し、古いURLは転送だけ残してある。/me/link は /me/members へ転送する。member-avatars バケットは public=false で、
<ユーザーID>/… の先頭フォルダが自分と一致するオブジェクトだけ読み書きできる
(本番DBで、別アカウントからも未ログインからも見えないことを確認済み)。
表示のたびにサーバー側で署名付きURLを発行する。アップロード時は端末側で中央を
正方形に切り出して 256px の JPEG に変換してから上げるため、元の写真の大きさは問わない。
署名が切れたり読めなかったときは名前の頭文字表示に戻す。components/icons.tsx の SVG ラインアイコンです。monthly_savings.status = 'deposited' の月の合計です。まだ入金していない分は
「未入金」として別に出します(確定済みの月は確定額で、確定前の月は積立予定額で数えます)。
定義は lib/insights.ts の depositedTotal と、DB側の deposited_total_for() に
1つずつだけ置いてあります。1人分の累計と、貯金に参加している接続済みメンバーを
合算した総累計を分けて出します。npm run dev # 開発サーバー
npm run build # 本番ビルド
npm run start # 本番サーバー
npm run typecheck # 型チェック
0019_sync_monthly_status_on_link.sql | マスターが確定済みの月を、接続しているアカウントにも反映する |
0020_drop_annual_goal.sql | 年間の目標金額をやめる |
confirm_month_for_circle)。相手の確定額は
相手自身の積立額で、こちらの金額は入れません。すでに確定済み・入金済みの相手は触りません。
ワンバンクへの入金は各自の財布の話なので、「入金済み」は自分の行だけを更新します。shared_goal_progress() が
メンバーごとの合計だけを返します。profiles.is_master が true の
アカウントが送った接続リクエストは、その場で接続済みになります。接続時に双方の
共有権限を作る既定(貯金と割り勘はON)はそのままなので、相手が操作しなくても
相手の貯金と割り勘がマスターから見える状態で接続が始まります。相手は接続後に
個別にOFFにでき、解除もどちらからでもできます。このフラグはアプリからは立てられません
(guard_profile_is_master が authenticated / anon からの書き換えを無視します)。link_permissions に owner_id
を足し、「AがBに見せるもの」と「BがAに見せるもの」を別に持ちます。共有相手に開くのは
SELECT だけで、書き換えの経路は作りません。判定は marine_link_allows() を通した
RLS で行うため、アプリ側の実装ミスでは漏れません。lib/queries.ts は取得エラーを握りつぶさず
QueryError を投げ、app/(app)/error.tsx が再読み込みを促します。
Supabase の Free プランはアイドル後の初回アクセスで 504 を返すことがあるため、
読み取りは1回だけ自動で再試行します(読み取りは冪等なので安全)。getUser() は毎回 Auth サーバーへ往復するため、
proxy.ts と lib/queries.ts では getClaims() を使い、JWT(ES256)の署名を
JWKS でローカル検証します。サーバークライアントと getSessionUser() は
React の cache() でリクエスト単位に共有します。lib/constants.ts の
EXTERNAL_APPS[].defaultUrl を使うため、設定なしで起動できます。設定UIは画面から外し、
端末ごとの上書き(localStorage)は仕組みとしてだけ残してあります。signInWithOAuth →
/auth/callback でセッションへ交換します。このパスは proxy.ts の認証ガードから
除外してあります(除外しないと、セッションが無い状態で /login へ飛ばされ、
code を交換する前に流れが切れます)。
同じメールアドレスなら Supabase が既存ユーザーへ自動で紐付けます。