幹事を「仕事」から「楽しみ」へ。 飲み会の集金・割り勘・日程調整をワンストップで管理するフルスタックWebアプリ/ネイティブアプリ。
「幹事が一番楽しめない」という当たり前を変えるために、学生起業として0から企画・設計・開発しました。
飲み会幹事の3大作業(名簿管理・集金確認・未払い催促)をテクノロジーで自動化し、幹事も参加者と同じように場を楽しめる世界を目指しています。
| 🌐 Web版 | kanpai-lock.com — インストール不要、LINEからそのまま起動 |
| 📱 iOS App | App Store(Capacitor製ネイティブアプリ) |
| � 開発体制 | チーム(企画/広報 + 設計/開発)、設計と実装を全て自分が担当 |
📂 ソースコードは非公開リポジトリで管理しています。閲覧をご希望の方は kanpailock@gmail.com までお気軽にご連絡ください。
| 機能 | 詳細 |
|---|---|
| リアルタイム支払い管理 | Firestoreリアルタイムリスナーで参加者全員の支払い状況を即時同期 |
| 傾斜割り勘計算 | 役割ごとの重み付けで不均等な割り勘を自動計算(幹事/一般/固定金額など) |
| PayPayリンク連携 | URLを共有するだけで現金不要の即時集金 |
| 自動精算通知 | 精算開始時にLINE or FCMプッシュ通知を全員に自動送信 |
| 未払い自動リマインド | Cloud Functionsのスケジュールトリガーで毎日18時に未払い者へ自動催促 |
| 機能 | 詳細 |
|---|---|
| n次会(複数ラウンド)対応 | 途中参加・抜けに応じてラウンドごとに参加者と金額を独立管理 |
| 定員管理 | 満員時の自動ブロック・定員オーバー通知 |
| LINEグループ一括取込 | LINEのグループメンバーをAPIでインポートし事前登録 |
| 日程調整モード | ○△× 投票 + スコア自動集計でベスト日程をランキング表示 |
| リアルタイムチャット | 日程調整中のメッセージング機能 |
| 機能 | 詳細 |
|---|---|
| マルチ認証 | LINE LIFF / Google / Apple Sign-In の3プロバイダ対応 |
| DeepLink | URLパラメータでルームIDを共有・直接参加、ブラウザ→アプリ連携 |
| オフライン対応 | ネットワーク切断時もUIを維持し、復帰時に自動再接続 |
課題: Capacitor の WKWebView 環境では、Firebase JS SDK の setDoc / getDoc がハングする問題が発生。
解決策: ネイティブ環境では Firestore REST API 経由でデータアクセスするアダプタ層 (nativeFirestore.ts) を設計。isNativeEnvironment() でランタイム判定してWeb/ネイティブを自動分岐。
// 環境に応じて透過的に使い分けられるAPI設計
export async function getDocNative(collectionPath, docId) {
if (isNativeEnvironment()) {
return await firestoreRestGet(collectionPath, docId); // REST API
}
return await getDoc(doc(db, collectionPath, docId)); // JS SDK
}🎯 学び: クロスプラットフォーム開発では、SDK が「動かない」ケースを想定したフォールバック設計が重要。
課題: Capacitor の Apple Sign-In プラグインでは idToken と nonce を直接取得できず、Firebase 認証の OAuthCredential を生成できない。
解決策: カスタム Swift プラグインを自作し、ASAuthorizationController で直接 Apple 認証を実行。SHA256 nonce を生成してFirebase に渡す一連の処理をネイティブコードで実装。
🎯 学び: プラグインの既存API に依存せず、ネイティブコードまで降りて問題解決する経験。
課題: participants[userId] のみに依存すると、Firestore書き込み失敗時にユーザーがルームを見失う。
解決策: ユーザープロフィール (users/{uid}/profile) にも joinedRooms として参加記録を保存する二重保存設計を採用。再アクセス時にフォールバックとして自動復帰可能。
[ルームデータ] [ユーザープロフィール]
rooms/{roomId} users/{uid}/profile
└── participants/{uid} ←→ └── joinedRooms/{roomId}
(正データ) (フォールバック)
🎯 学び: 分散システムにおけるデータ整合性と可用性のトレードオフを実践で体得。
課題: Firebase onAuthStateChanged はWeb用設計のため、iOSネイティブでは認証復元に1-2秒かかり、ユーザーがログイン画面にフラッシュバックする。
解決策: onAuthStateChanged を待たず、iOS Keychain からネイティブ SDK で即座にユーザー情報を復元する tryEarlyNativeAuth() パターンを実装。Web版は800ms、iOS版は1500msのフォールバックタイマーを設定し、UXを損なわない。
[起動]
├── tryEarlyNativeAuth() ← iOS: Keychainから即座に復元
├── onAuthStateChanged() ← Web: Firebase標準の認証復元
└── setTimeout(fallback) ← どちらも来なかったらログイン画面へ
🎯 学び: 体感速度のチューニングは数値(msオーダー)で管理し、プラットフォーム別に最適化する。
課題: LINE LIFF で認証したユーザーと Firebase Authentication のユーザーIDは別物。同一ユーザーがLINEとGoogleで参加した場合の紐付けが複雑。
解決策: firebaseUid / lineUserId / linkedUserId の3属性を参加者データに持たせ、統合検索ヘルパー (findMyParticipantData) で全方向から自分を特定。LINEグループからインポートした事前登録メンバーとの紐付けもスムーズに処理。
🎯 学び: 複数認証プロバイダの統合は「IDの正規化」が鍵。設計を後から変えるとコスト大。
認証済みユーザーのみアクセス可能、幹事のみ削除可能、プロフィールはオーナーのみ R/W、LINEグループ情報は Cloud Functions (Admin SDK) からのみ書き込み可能——といったロールベースのアクセス制御を Firestore Security Rules で実装。
| 技術 | 用途 |
|---|---|
| Next.js 16 (App Router) | ルーティング・SSR |
| TypeScript 5.9 | 型安全な開発(32,000+ 行) |
| Tailwind CSS 4 | レスポンシブUI |
| React 19 | コンポーネント設計(28カスタムフック) |
| Capacitor 8 | Web → iOS/Android ネイティブラッパー |
| LINE LIFF SDK | LINEミニアプリ統合 |
| 技術 | 用途 |
|---|---|
| Firebase Firestore | リアルタイムDB + セキュリティルール |
| Firebase Authentication | LINE / Google / Apple 認証 |
| Firebase Cloud Functions | サーバーレスAPI(10ファイル / 95KB) |
| Firebase Cloud Messaging | iOS/Webプッシュ通知 |
| Vercel | Webホスティング・CDN |
| 技術 | 用途 |
|---|---|
| Swift (カスタムプラグイン) | Apple Sign-In 実装 |
| APNs → FCM | プッシュ通知チェーン |
| iOS Widget (WidgetKit) | ホーム画面ウィジェット |
| 技術 | 用途 |
|---|---|
| Vitest + Testing Library | ユニットテスト |
| ESLint | コード品質 |
| Firestore Security Rules | アクセス制御 |
| Rate Limiting | Cloud Functions API保護 |
| 指標 | 数値 |
|---|---|
| 総コミット数 | 1,228+ |
| TypeScript総行数 | 32,000+ 行 |
| Reactコンポーネント | 46ファイル |
| カスタムフック | 28個 |
| ユーティリティ | 24ファイル |
| Cloud Functions | 10ファイル / 95KB |
| 開発期間 | 約3ヶ月 |
[ユーザー]
├── Web (PWA / LINE LIFF)
├── iOS App (Capacitor)
└── LINE Mini App
│
▼
┌──────────────────────────────┐
│ Next.js 16 / Vercel │
│ ├── App Router (SSR/CSR) │
│ ├── Components (46ファイル) │
│ │ ├── room/ 精算UI │
│ │ ├── views/ 画面 │
│ │ ├── schedule/ 日程 │
│ │ └── modals/ モーダル│
│ ├── Hooks (28個) │
│ │ ├── useAuthController │
│ │ ├── useRoomOperations │
│ │ ├── useSettlement │
│ │ └── useScheduleVoting │
│ └── Utils (24個) │
│ ├── nativeFirestore │
│ ├── nativeAuth │
│ └── nativeStorage │
└──────────┬───────────────────┘
│
┌──────────▼───────────────────┐
│ Firebase │
│ ├── Firestore (リアルタイム) │
│ ├── Authentication │
│ │ ├── LINE (LIFF→Custom) │
│ │ ├── Google (OAuth) │
│ │ └── Apple (Swift) │
│ ├── Cloud Functions │
│ │ ├── LINE Webhook │
│ │ ├── 自動リマインド通知 │
│ │ ├── プッシュ通知 │
│ │ └── レートリミット │
│ └── Cloud Messaging (FCM) │
└──────────────────────────────┘
kanpai-lock/
├── app/ # Next.js App Router
│ ├── page.tsx # メインSPA (8.6KB)
│ ├── layout.tsx # レイアウト・メタデータ
│ ├── payment/ # 支払いページ
│ └── privacy/, terms/ # 法務ページ
├── components/ # Reactコンポーネント (46ファイル)
│ ├── KanpaiUI.tsx # メインUIコントローラ (14KB)
│ ├── LandingPage.tsx # LP兼ログイン画面 (45KB)
│ ├── room/ # 部屋管理UI (26ファイル)
│ ├── views/ # 画面コンポーネント
│ ├── schedule/ # 日程調整UI
│ └── modals/ # モーダル群
├── hooks/ # カスタムReactフック (28個)
│ ├── useAuthController # 認証制御 (799行)
│ ├── useRoomOperations # ルーム操作 (577行)
│ ├── useSettlement # 精算ロジック
│ └── useScheduleVoting # 日程調整投票 (410行)
├── utils/ # ユーティリティ (24ファイル)
│ ├── nativeFirestore.ts # iOS環境分岐アダプタ
│ ├── nativeAuth.ts # 認証環境分岐
│ └── kanpaiUtils.ts # ビジネスロジック
├── functions/ # Cloud Functions
│ └── src/
│ ├── lineHandlers.ts # LINE Webhook (29KB)
│ ├── notifications.ts # LINE通知 (20KB)
│ ├── pushNotifications.ts # FCM通知 (17KB)
│ ├── auth.ts # カスタム認証
│ └── rateLimit.ts # レートリミット
├── ios/ # Capacitor iOSプロジェクト
├── android/ # Capacitor Androidプロジェクト
├── __tests__/ # テストスイート
├── firestore.rules # セキュリティルール
└── locales/ # i18n (ja/en)
# 依存パッケージのインストール
npm install
# 環境変数を設定
cp .env.local.example .env.local
# Firebase / LINE API キーを設定
# 開発サーバー起動
npm run dev
# テスト実行
npm run test:run
# iOS(要Xcode)
npx cap sync ios && npx cap open ios- Firestore Security Rules: ロールベースアクセス制御(幹事のみ削除可、プロフィールはオーナーのみ)
- Apple Sign-In: SHA256 nonce 検証をカスタム Swift プラグインで実装
- Cloud Functions: レートリミットでAPI乱用を防止
- 環境変数: Vercel / Firebase Secrets で管理、
.env.localはGitignore済み - LINEグループ情報: Admin SDK(Cloud Functions)からのみ書き込み可能
| 名前 | 役割 | 担当 |
|---|---|---|
| 関屋 | Founder | 企画・広報・マーケティング |
| 上嶋 | Developer | 設計・開発・インフラ・テスト |
Yohaku Lab © 2026