LS-Finderの作り方

こんにちは、開発担当です。
記念すべきブログ第1回は、LS-Finder が どんな構成で動いているのか という話です。 LS-Finder は、FINAL FANTASY XIV(FFXIV)の Lodestone 公開情報をもとに、キャラクターや コミュニティ(FC / CWLS / LS / PvP)を検索できる支援サイトです。私は新生エオルゼアの頃から プレイしているヒカセンなのですが、本職はバックエンドエンジニアでして、「LS 探しがもっと 楽にならないかな」という自分の欲望に技術で応えた結果がこのサイトです。今日はその裏側を、 システム構成図を交えて紹介します。
全体の構成
LS-Finder は大きく分けて「画面(フロントエンド)」「API(バックエンド)」「データ収集(ワーカー)」 「データベース」の4つで構成され、すべて Render.com 上にホスティングしています。 データの大元は FFXIV 公式の Lodestone です。パーティで言えば、タンク・ヒーラー・DPS ならぬ 「見せる係・答える係・集める係・覚える係」の4人編成ですね。
各コンポーネントの役割
フロントエンド(apps/web)
みなさんが実際に触れる画面です。React + TypeScript で作っており、Vite でビルドして Render の Static Site として配信しています。キャラクター検索・コミュニティ検索・各情報画面・ コミュニティ数ランクなどの UI を提供し、表示に必要なデータは後述の API から取得します。
API(apps/api)
フロントエンドからのリクエストを受け取り、データベースを参照して JSON で返す REST API です。
GET /users や GET /communities といったエンドポイントを提供します。Node.js 製で、
Render の Web Service として動いています。本職がバックエンドなもので、ここは一番の
得意分野です。
ワーカー(apps/worker)
LS-Finder の心臓部とも言える、データ収集を担うバックグラウンドワーカーです。Node.js に
got(HTTP クライアント)と cheerio(HTML パーサ)を組み合わせ、Lodestone の公開ページを
定期的に巡回(スクレイピング)して、キャラクターやコミュニティの情報・コミュニティ数の統計などを
データベースへ書き込み続けます。みなさんがエオルゼアで冒険している間も、こいつは黙々と
ギャザラーのように情報を採集しています。働き者です。
データベース(PostgreSQL)
ワーカーが収集したデータの保存先であり、API が参照する読み取り元でもあります。Render の Managed Postgres を利用しています。「収集(書き込み)」と「閲覧(読み取り)」を分けることで、 みなさんの検索は常に保存済みのデータに対して高速に行えます。
データの流れ
- ワーカー が Lodestone を定期的に巡回し、最新のキャラクター・コミュニティ情報を取得する
- 取得した情報を整形して PostgreSQL へ保存する
- ユーザーが画面で検索すると、フロントエンド が API にリクエストを送る
- API が PostgreSQL を参照し、結果を JSON で返す
- フロントエンド が受け取った結果を一覧や詳細画面として表示する
このように「収集する仕組み」と「見せる仕組み」を分離しているため、みなさんの検索体験を 損なわずに、裏側でコツコツとデータを最新化し続けられます。リテイナーに任せた獲得物が いつの間にか揃っているような、そんなイメージで受け取ってもらえれば大体合っています。
技術スタック
- 言語: TypeScript(フロント・API・ワーカーすべて)
- フロントエンド: React + Vite、i18n(日本語 / 英語)対応
- API: Node.js
- ワーカー: Node.js + got + cheerio
- データベース: PostgreSQL
- ホスティング: Render.com(Static Site / Web Service / Background Worker / Managed Postgres)
おわりに
今日は LS-Finder の裏側を紹介しました。役割ごとにシンプルなコンポーネントへ分けた、 素直な構成で動いています。今後もこのブログで、機能追加や運用の裏側をゆるゆると 紹介していく予定です。
【それではよい旅を!】