FuelBuddyのUAE展開には、地域の運用要件に合わせた専用のフランチャイズアプリケーションが必要でした。私はドバイ・フランチャイズ・アプリケーションを、フロントエンドとデータAPIの両面にわたってゼロから構築しました。
作ったもの
- グリーンフィールドのフロントエンド: コンポーネントシステムとアプリケーション構成をゼロから構築し、フランチャイズ運用のためのすっきりとしたレスポンシブなインターフェースを実現しました。
- Hasura GraphQL API: Hasura GraphQLエンジン上にバックエンドのデータ層を構築し、アプリケーションに必要なCRUD操作とデータモデルを定義しました。
- 地図、スケジューリング、エクスポート: ライブ地図、カレンダー/ガントチャートのスケジューリングビュー、そしてフランチャイズ向けレポートのスプレッドシート/PDFエクスポートを統合しました。
- 認証とセキュリティ: Firebaseによる認証を設定し、Hasura自身のJWTクレームを通じてロールベースのアクセス制御を適用しました。
なぜ意味があったか
専用のプラットフォームを提供したことで、FuelBuddyのUAEフランチャイズ事業者は、リアルタイムの地図データと重いレポーティングのために作られたスタックの上で、地域運用に特化したツールを手にしました。
データ層
このアプリは、型付けされたコード生成済みSDKに対してgraphql-requestでデータを取得し、クライアントの状態はPiniaストアが保持します。依存関係のツリーのどこにもTanStack Queryはありません。認証はFirebase上で動作し、ロールベースのアクセス制御は、別途構築された権限システムではなくHasura自身のJWTカスタムクレーム(x-hasura-default-role、x-hasura-user-id)に由来します。
単なるフォームビルダー以上のもの
薄いCRUDツールで済ませることもできたはずのところを、これは本当に機能の詰まったアプリです。地図上でフランチャイズゾーンを直接描画・編集するためのMapbox GLとmapbox-gl-draw、ガント形式のスケジューリングのためのvue-ganttasticと組み合わせたFullCalendar、レポーティングダッシュボード用のChart.js、そして完全なエクスポートパイプライン(xlsx、papaparse、jszip、html2pdf.js、dom-to-image、html-to-image)を備えており、フランチャイズレポートは単一の固定フォーマットではなく、事業者が必要とする形に応じてスプレッドシート、PDF、画像としてアプリから出力されます。
手書きのクエリではなくコード生成
GraphQLの操作は、codegen.ymlに基づいてvite-plugin-graphql-codegenによりビルド時に生成され、Hasuraのスキーマから型付けされたsrc/sdk.tsクライアントを作り出します。すべてのクエリとミューテーションは、バックエンドが変わると気づかぬうちにずれていく手書きの文字列ではなく、実際のスキーマに対して型付けされています。
テストの重点
Playwrightは、ログインと注文管理という2つのフローをエンドツーエンドでカバーしています。これは他のすべての画面の手前にあるゲートであり、このアプリが存在する理由そのものであるコアな取引です。この2つより後段にあるもの(スケジューリング、エクスポート、レポーティング)は、テストの見落としではなく、テストより新しい領域です。
Stack
Vue 3、Vite、Pinia、Hasuraに対してGraphQL Code Generatorと組み合わせたgraphql-request、認証にFirebase、mapbox-gl-drawを伴うMapbox GL、vue-ganttasticを伴うFullCalendar、レポーティングにChart.js、テストにPlaywright。