1. 朝礼を、チームに届けたかった
個人用の朝礼アプリがある。毎朝、登録した言葉を一つ選んで復唱する。声に出し、記録し、積み重ねていく。シンプルな仕組みだが、続けると確かに変化が起きる。
これを組織に届けられないか、という声があった。社訓を、理念を、創業者の言葉を——毎朝、全社員のスマートフォンに届ける。朝礼の代わりに、あるいは朝礼の補完として。
仕組みとしては単純に見えた。管理者が言葉を登録する。社員はアプリを開く。それだけだ。だが「テナントごとに異なる言葉を届ける」という要件は、思いのほか設計の問いを立てることになった。
2. 最初の設計——テナントごとにリポジトリを作る
最初に思いついた設計は、テナントごとにリポジトリを作ることだった。
組織Aが申し込む → リポジトリを自動作成 → GitHub Pagesで公開
組織BのURLにアクセスすると、組織B専用の設定で動く
実装した。決済が完了すると、Webhookが走り、GitHub Actionsがリポジトリを作成し、Pages設定を有効化し、初期設定ファイルを書き込む。数分後には専用URLが動く。
動いた。だが、問題がすぐに見えた。
アプリのコードを更新するたびに、全テナントのリポジトリに変更が伝わらない。テナントが増えるほど、管理するリポジトリが増える。100テナントになれば100リポジトリ。1000になれば1000。コードと設定が混在した、コピーの山が積み上がっていく。
3. 問い——何がテナントごとに違うのか
立ち止まって考えた。テナントごとに本当に違うものは何か。
アプリのコードは、すべてのテナントで同じだ。UIも、動作ロジックも、通知の仕組みも。違うのは、アプリ名と、配信する言葉と、いくつかの設定値だけだ。
それをまとめると、一枚のJSONファイルになる。
app_name: "朝礼 — ○○株式会社"
preset_words: [{ title: "社是", text: "誠実に、大胆に、素早く。" }]
lock_preset: true
これだけだ。テナントとは、この一枚のJSONファイルのことだった。
4. 新しい設計——一つのリポジトリに、ディレクトリを切るだけ
設計を変えた。
テナントの設定を一元管理するpublicリポジトリを一つ作る。テナントが増えるたびに、そのリポジトリにディレクトリを追加し、tenant.jsonを置くだけ。アプリ本体は変わらない。
tenants/
abc12345/tenant.json ← 組織A
xyz67890/tenant.json ← 組織B
...
アプリは起動時に、URLパラメータからテナントIDを読み取り、対応するtenant.jsonを取得する。それだけで、そのテナント専用の朝礼アプリになる。
アプリのコードを更新すれば、全テナントに即座に反映される。リポジトリは増えない。設定と実装が完全に分離した。
5. 削除・更新・請求——すべてがファイル操作に収束する
この設計の美しさは、テナントに関するあらゆる操作がファイル操作に収束することだ。
テナントを作るとは、tenant.jsonを追加することだ。設定を更新するとは、そのファイルを書き換えることだ。テナントを削除するとは、そのファイルを消すことだ。
更新のキューも、同じリポジトリの別ディレクトリに積まれる。管理者が「保存して配信する」を押すと、Cloudflare WorkerがJSONファイルをキューに書き込む。1分おきに処理が走り、tenant.jsonに反映される。700の組織が同時に設定を保存しても、Workerはキューに積むだけで即座に応答を返す。詰まらない。
複雑に見えた仕組みが、ファイルの読み書きに帰結した。
6. 請求書払いという問い
カード決済は自動化できた。だが、大きな組織ほどカード決済を使えないことがある。稟議、購買部門、請求書払い——そのような文化の中で動く人たちが、確実にいる。
最初は「お問い合わせください」で済ませようとした。だが、それでは「銀行振込で申し込んだのに、どこに進めばいいかわからない」という状況が生まれる。申し込んだ事実と、テナントの準備と、入金確認が、バラバラに浮遊する。
解決策は、申込み時点でorder_codeを発行することだった。カード決済でも請求書払いでも、最初にorder_codeが生まれる。そのコードが、申込みと、設定と、入金確認と、テナントの起動を、すべてつなぐ。処理のタイミングが違うだけで、流れは同じだ。
7. 設計の純度が、運用のシンプルさになる
マルチテナントの設計を通じて、改めて感じたことがある。複雑さは、設計の選択の積み重ねから生まれる。
最初の選択が「テナントごとにリポジトリを作る」だったとき、その下流にあらゆる複雑さが連鎖した。コードの重複、更新の困難、管理の煩雑さ。一つの選択が、何十もの問題を作り出した。
設計を変えて「一枚のJSONだけが違う」にしたとき、複雑さの連鎖が止まった。何が変わるのか、何が変わらないのかが明確になった。変わらないものはアプリ本体に置き、変わるものだけをJSONに切り出した。
設計の純度が高いとき、コードは短くなり、説明も短くなり、運用も軽くなる。朝礼アプリの設定がたった数行のJSONで表現できるとき、それは設計の純度が高い証拠だ。
テナントとは、一枚のJSONファイルのことだった。コードは変わらない。言葉だけが、組織ごとに違う。