初回コミットから4カ月未満でApp Store・Google Playに公開。VAONが共同開発したミニサッカー場予約・チーム管理アプリ「BallBall」

iOS Android API Web アプリ 2026
初回コミットから4カ月未満でApp Store・Google Playに公開。VAONが共同開発したミニサッカー場予約・チーム管理アプリ「BallBall」

プロジェクトの背景

ベトナムの草サッカーは、今も多くがZalo(ベトナムで最も使われているメッセージアプリ)と電話で段取りされています。施設に電話して空き枠を確かめ、メンバーを集め、費用の精算を呼びかける。BallBallはこの一連の作業を1つのアプリにまとめました。プレーヤーは単発または毎週固定でコート(5人制・7人制のミニサッカー用ピッチ)を予約し、チームを作り、メンバーを募集し、チャットできます。施設オーナーは予約枠、料金、コートの組み合わせを同じシステムで管理します。 BallBallは、創業者のグエン・ヴァン・ハオ氏とVAONの共同開発です。ハオ氏がビジネスモデルと施設オーナーとの関係づくりを担い、VAONがプロダクト設計と技術全般(Flutterアプリ、Laravelバックエンド、管理画面、ストア公開)を担当しました。初回コミットは2025年11月25日、App StoreとGoogle Playでの公開は2026年7月です。

課題

1

7人制コートは5人制コート2面をつなげたものが多く、一方を予約したらもう一方も押さえる必要があった

小規模な施設では、同じ人工芝を「5人制2面」としても「7人制1面」としても貸し出します。これを独立した3面として扱うと、19時に7人制が予約された一方で、同じ時間の5人制も別のチームに押さえられている状態が起こり得ます。施設側が気づくのは、両チームが現地に来てからです。

2

毎週同じ枠を数カ月押さえつつ、ときどき1回だけ休むチームへの対応

草サッカーのチームは、毎週決まった時間帯を数カ月単位で押さえることがよくあります。1回ずつ別の予約として保存すると、3カ月で約13件のレコードになり、時間変更のたびにすべてを修正しなければなりません。直前のキャンセルは売上の損失になるため、施設オーナーが休みを承認できる仕組みも必要でした。

3

ZaloやMessengerで送った招待リンクが、アプリではなくWebページで開いてしまう

プレーヤー同士の誘い合いは、主にZaloとMessengerで行われます。これらのアプリ内ブラウザでは、Universal Links(iOS)やApp Links(Android)がアプリに引き渡されないことが多く、試合やチームへの招待リンクがWebView内で開いてしまいます。立ち上げ直後のサービスにとって、リンクの不具合はそのまま利用者の離脱につながります。

4

コート周辺の不安定な4G回線でも、チームチャットを取りこぼさずに届ける必要があった

チーム内のやり取りが最も増えるのは試合直前で、移動中や電波の弱いコートにいる時間帯です。数秒の切断でもメッセージの取りこぼし、再送ボタンによる重複、すでにその会話を開いている相手へのプッシュ通知の誤送信が起こり得ます。

5

ベトナムの電話番号によるOTPログインとユーザー投稿コンテンツは、どちらもストア審査で指摘されやすい

新規ユーザーは、ベトナムの電話番号にSMSまたはZaloで届くワンタイムコードでログインします。海外にいるAppleの審査担当者はこのコードを受け取れず、Guideline 2.1に該当します。またチャット、コートのレビュー、公開プロフィールはユーザー投稿コンテンツにあたるため、Guideline 1.2に沿ったブロック・通報機能が必要でした。

6

行政区画が3層から2層に変わった一方、コートのデータとアプリは「区・郡(quận・huyện)」の単位を前提にしていた

ベトナムは2025年に省(tỉnh)を統合し、日本の「郡」に近い中間の行政単位(quận・huyện)を廃止しました。コートの住所、プレーヤーの活動エリア、コート検索の絞り込みをすべて新しい区画に合わせる必要がありました。一方、利用者の端末にインストール済みのアプリは旧構造のままAPIを呼び出しており、全員に一斉更新を求めることはできません。

VAONのソリューション

VAONはBallBallのプラットフォーム全体を設計・構築しました。二重予約を防ぐ組み合わせコートの予約エンジン、オーナー承認による定期予約の休み申請、ZaloやMessengerから確実にアプリを開くディープリンク、不安定な回線でも途切れないWebSocketのリアルタイムチャット、App Store・Google Playの審査対応、そして旧バージョンのアプリを壊さずに新しい行政区画へ移行する仕組みまでを担当しました。

予約・スケジュール

組み合わせコートを専用の関連テーブルで管理し、組み合わせコートごとに構成するコートを明示しました。空き枠の確認では、選択されたコートと関連するすべてのコートについて、単発予約・定期予約・メンテナンス枠を確認します。新規予約はオーナーの承認待ちとし、期限を過ぎたものは10分ごとに動くジョブが自動で取り消して枠を解放します。

定期予約は1件のレコード(曜日、開始日、期間3カ月)として保存し、休みの日は別テーブルに記録しました。全回分を事前に生成する方式ではなくこの方式を選んだのは、変更や終了が1行の更新で済むためです。その代わり、空き枠の検索ではコード側で日付を展開する必要があります。休みの申請はプレーヤーが送り、施設オーナーが承認または却下します。料金は予約時点で予約データに記録するため、オーナーが後から料金表を変えても既存の予約には影響しません。

共有リンクはアプリに直接飛ばすのではなく、BallBallのドメイン上の中継ページに向けました。中継ページは `ballball://` スキームでアプリの起動を試み、2.5秒経っても起動しなければ端末に応じてApp StoreまたはGoogle Playへ案内します。リンク切れや削除済みのコンテンツでも404は返さず、共通の紹介ページを表示します。

安定性とストア審査対応

送信前に端末側で各メッセージにUUIDを付与し、画面にすぐ表示したうえでサーバー側の保存データと突き合わせる方式にしました。メッセージはWebSocket(Laravel Reverb)で配信し、再接続時には最後に受け取ったメッセージID以降をREST APIで取得して欠落を埋めます。プッシュ通知の前には、受信者がその会話を開いているかをサーバーが確認し、開いていれば送信しません。

AppleとGoogleの審査担当者がベトナムのSIMなしでログインできるよう、審査用アカウントをバックエンドに用意しました。申請前に、ユーザーのブロック、4種類のコンテンツの通報、管理画面からの非表示化とアカウント停止、アプリ内でのアカウント削除、iOSのプライバシーマニフェストを実装しています。

旧・新の行政区画テーブルを並行して保持し、新しいデータを旧来の項目名のままAPIで返すことで、インストール済みのアプリがそのまま動くようにしました。今後の互換性のない変更に備え、2026年7月22日からはバックエンドに最低アプリバージョンの確認を追加し、必要な場合に限り旧バージョンへ更新を促せるようにしています。

主な機能

1

組み合わせコートの二重予約を防ぐ予約エンジン

2

オーナー承認による定期予約の休み申請

3

ZaloやMessengerから確実にアプリを開くディープリンク

4

不安定な4G回線でも途切れないWebSocketのリアルタイムチームチャット

提供価値

初回コミットから4カ月未満で、App Store・Google Playで利用可能に

1.0.0公開後の3週間で、新たに5つのビルドを作成

3つの利用者区分を1つのバックエンドで支え、APIルート125本・自動テストファイル38本

座標付きのコートデータ5,399件を事前に登録し、初日からコートを探せる状態に