BUZZ BASE モバイルアプリ

April 19, 2026 · View on GitHub

野球の個人成績をランキング形式で共有するモバイルアプリ。Expo SDK 55 + React Native + TypeScript で構築。

アーキテクチャ

システム全体図

graph LR
    App[モバイルアプリ] -->|https://API_URL/api/v1/| API[Rails API]
    API --> DB[(PostgreSQL)]
    App -->|プッシュ通知| Expo[Expo Push Server]
    Expo --> APNs[Apple APNs]
    Expo --> FCM[Firebase FCM]
    App -->|Google認証| Google[Google Sign-In]

画面構成

graph TD
    Root["_layout.tsx (Root)"]
    Root --> Auth["(auth)"]
    Root --> Tabs["(tabs)"]
    Root --> GameRecord["(game-record)"]

    Auth --> SignIn[sign-in]
    Auth --> SignUp[sign-up]
    Auth --> Username[username-registration]

    Tabs --> Dashboard["index (ダッシュボード)"]
    Tabs --> GameResults["(game-results)"]
    Tabs --> Record["record → game-record"]
    Tabs --> Groups["(groups)"]
    Tabs --> Profile["(profile)"]

    GameResults --> GameList[一覧]
    GameResults --> GameDetail["[id] 詳細"]

    Groups --> GroupList[一覧]
    Groups --> GroupDetail["[id] 詳細"]
    Groups --> GroupCreate[作成]

    Profile --> MyPage[index]
    Profile --> Edit[edit]
    Profile --> OtherUser["[userId]"]
    Profile --> Notes[notes]
    Profile --> Seasons[seasons]
    Profile --> Settings[settings]

状態管理

ライブラリ用途
React Queryサーバーステート(APIキャッシュ)useDashboard, useGameResults, useProfile
ZustandクライアントステートauthStore(認証状態), gameRecordStore(試合記録フロー)
SecureStoreトークン永続化access-token, client, uid

ディレクトリ構成

app/                        # Expo Router ファイルベースルーティング
├── (tabs)/                  # タブナビゲーション
│   ├── (game-results)/      # 試合結果 Stack
│   ├── (groups)/            # グループ Stack
│   ├── (profile)/           # マイページ Stack
│   ├── (notifications)/     # 通知 Stack
│   └── index.tsx            # ダッシュボード
├── (game-record)/           # 試合記録フロー(Step1→2→3→Summary)
├── (auth)/                  # 認証画面
└── _layout.tsx              # ルートレイアウト
components/                  # UIコンポーネント(画面ごと + 共通ui/)
hooks/                       # カスタムフック(ドメインごと, 23個)
services/                    # API通信(ドメインごと, 18個)
stores/                      # Zustandストア
types/                       # TypeScript型定義
constants/                   # 定数(API URL等)
utils/                       # ユーティリティ(axiosInstance等)
assets/                      # アイコン・画像
docs/                        # ストアメタデータ等

設計パターン

hooks/ でドメインロジックをカプセル化

各ドメインに対応するカスタムフックを提供。React QueryのuseQuery/useMutationをラップし、コンポーネントからAPI通信の詳細を隠蔽する。

useAuth        → authService        → /auth/sign_in
useDashboard   → dashboardService   → /v2/dashboard
useGameResults → gameResultService  → /v2/game_results
useProfile     → profileService     → /user

認証フロー

sequenceDiagram
    participant App
    participant SecureStore
    participant API as Rails API

    App->>SecureStore: access-token取得
    alt トークンあり
        App->>API: GET /user (ヘッダー付き)
        API-->>App: 200 OK → ログイン済み
    else トークンなし
        App-->>App: ログイン画面へ遷移
    end

ネイティブモジュールの遅延読み込み

Google Sign-In・Push NotificationsはExpo Goで動作しないため、Constants.appOwnership === "expo" を検出して require() で遅延読み込みする。

開発環境のセットアップ

前提条件

  • Node.js 20.19.4+
  • yarn
  • EAS CLI(npm install -g eas-cli
  • バックエンドが起動済み(docker compose up

Expo Go(基本機能の確認)

# iOSシミュレータ
npx expo run:ios
# Androidエミュレータ
npx expo run:android

Google認証・プッシュ通知はExpo Goでは動作しない

Development Build(ネイティブモジュール含む)

# iOS実機
eas build --profile development-device --platform ios
# → URLを実機で開いてインストール → yarn start で接続

# Androidエミュレータ
eas build --profile development --platform android
# → エミュレータにインストールされる → yarn start で接続

Preview Build(単体動作、本番API接続)

eas build --profile preview --platform ios
# → ローカルサーバー不要で単体動作

ビルド・配信(EAS Build)

プロファイル用途API接続先配布方法
developmentシミュレータ開発localhostローカル
development-device実機開発localhostAd Hoc
previewテスト配信本番APIAd Hoc / TestFlight
productionストア公開本番APIApp Store / Google Play

App Store 提出手順(iOS)

# 1. 本番ビルド(ビルド番号は autoIncrement で自動加算)
eas build --platform ios --profile production

# 2. ビルド完了後、App Store Connect に提出
eas submit --platform ios --profile production
# → 「Select a build from EAS」を選択 → 最新ビルドを選択

# ※ ビルドと提出を一括で実行する場合
eas build --platform ios --profile production --auto-submit

提出後の流れ:

  1. Appleの処理完了を待つ(5〜10分、メールで通知)
  2. App Store Connect → アプリ → 「App Store」タブ
  3. 「ビルド」セクションで新しいビルドを選択
  4. 「審査に提出」をクリック

バージョン更新が必要なケース

App Storeで既に承認済みのバージョン(例: 1.0.0)と同じバージョンでは、新しいビルドを提出できない。 submit時に以下のエラーが出た場合はバージョンを上げる必要がある:

90062: The value for key CFBundleShortVersionString [1.0.0] in the Info.plist
file must contain a higher version than that of the previously approved version [1.0.0].

対処手順:

# 1. app.json の version を更新(例: 1.0.0 → 1.0.1)
#    "version": "1.0.1"
#    ※ version はビルド時にバイナリに埋め込まれるため、既存ビルドの再submitでは解決できない

# 2. 再ビルド(buildNumber は autoIncrement で自動加算される)
eas build --platform ios --profile production

# 3. 提出
eas submit --platform ios --profile production

バージョニングルール:

  • version(CFBundleShortVersionString): ユーザーに表示されるバージョン。App Store承認後は上げる必要がある
  • buildNumber(CFBundleVersion): 同一version内のビルド識別子。autoIncrement: true で自動管理

開発コマンド

make help で全コマンドを確認可能。

コマンド説明
make startExpo開発サーバー起動
make iosiOSシミュレータで起動
make androidAndroidエミュレータで起動
make typecheckTypeScript型チェック
make lintESLint実行
make formatPrettier整形
make install依存関係インストール
make prebuildExpoプレビルド(ネイティブプロジェクト生成)

環境変数

開発時は .env に設定。EAS Buildでは eas.jsonenv で各プロファイルごとに設定。

変数名説明
EXPO_PUBLIC_API_URLバックエンドAPI URL
EXPO_PUBLIC_GOOGLE_WEB_CLIENT_IDGoogle OAuth(Web)
EXPO_PUBLIC_GOOGLE_IOS_CLIENT_IDGoogle OAuth(iOS)
EXPO_PUBLIC_GOOGLE_ANDROID_CLIENT_IDGoogle OAuth(Android)

関連リポジトリ

リポジトリ説明
buzzbaseルートリポジトリ(モノレポ)
buzzbase_frontフロントエンド(Next.js)
buzzbase_backバックエンド(Rails API)