VaultはVizend内のファイル管理サービスです。Vaultでは、ファイルのデータ構造が参照ファイルと物理ファイルに分けられています。
参照ファイルは物理ファイルを参照する構造であり、実際のファイルを複数人が所有することになっても、実際に使用されるストレージ容量は1つのファイル分だけです。
私がVaultの機能を保守する中で経験した限りでは、大きく3種類に分かれるようです。
vaultは大きく3種類のストレージに分かれます。
ストレージの種類
1) 個人ストレージ:Stash
-
フォルダー構造を持つ個人ストレージ
2) 一般ストレージ:Cabinet / Clip
告知や投稿の添付ファイルなど、「一般的な添付ファイルストレージ」として使用されます。
-
Cabinet:Clipのまとまり(コンテナ)という概念
-
Clip:ClipFile(参照ファイル)のまとまりという概念
-
適用範囲/単位は、サービス(devlime、vizend、班長ノートなど)のビジネスロジックによって異なる場合があります。
-
「サービス全体のストレージを1 cabinet」として扱う場合もあれば
-
「掲示板ごとにcabinetを分ける」場合もあります
3) 写真ストレージ:MiniAlbum / Minipix
-
Minipix:写真ストレージの「サービス名」
-
MiniAlbum:実際のドメイン(管理単位)
共通概念:「参照ファイルストレージ」
3つのストレージ(Stash / Clip / Photo)は共通してreference file(参照ファイル)を保存します。
-
保存されるファイル
-
Stash: StashFile
-
Clip: ClipFile
-
MiniAlbum: PhotoFile
これらはすべて、実際のファイルであるVaultFileを指す参照です。そのため、参照ファイルを大量に複製しても、実際のストレージ容量がすぐに増加する構造ではありません。
他サービスへの適用時に直面した課題
私がVaultを担当している間に、Vaultを実際に別のサービスへ適用する業務を担当することになりました。そのサービス名は班長ノートです。班長ノートは人員管理アプリと言うことができ、2026年上半期現在、開発中です。詳しいサービス内容については、セキュリティ上の理由から説明に制限があるため、ご了承ください。
バンジャンノートでVaultが必要な機能には、自分の書類や告知への書類提出がありました。
当初はここでVaultを簡単に適用できると考えていましたが、いくつかの適用上の制約がありました。
まず、「自分の書類」はStashを使用して適用する必要がありましたが、Stashは根本的にフォルダー構造でした。
班長ノートでは、マイドキュメントに保存する書類の種類がきっちり決められていて、これはフォルダー構造には合いませんでした。しかしVaultはMSAサービスの1つであり、汎用サービスとして機能する必要があるため、他の1つのサービスに適用するという理由でVault Stashドメインを変更することはできませんでした。したがって、Stashの構造を維持したまま、班長ノートに適用する必要がありました。
1. Vaultの汎用性の逆説
そこで検討を重ねた結果、フォルダーをあらかじめ固定的に作成し、ユーザーにはフォルダーを変更・削除するロジックを提供しない方式で実装しました。この問題を解決すると、別の問題が待っていました。Vaultは保存とアップロード/ダウンロード機能のみを提供し、アップロードした各ファイルのメタデータを、バンジャンノートのバックエンド側でVaultの構造に似た書類ドメインを作成してバンジャンノートに保存するかどうかを決める必要がありました。Vaultがファイル管理機能を完全に担うためには、メタデータも保存する構造が望ましかったため、この問題を解決するために代表が各clipfile、stashfile、photofileにJSON形式の文字列カラムを追加しました。例えば、stashfileで身分証明書の写真をアップロードする際、fileMetaData = { documentType: "ID_CARD" } のように、ファイルとともにメタデータを追加しました。これにより、バンジャンノート側で自分の書類ドメインを別途設計し、バックエンドに適用する必要がなくなりました。
2. Backend to backend vs frontend to backend
他のサービスでvault機能を使用する場合、2つの方式があります。
-
他のサービスのバックエンドからvaultバックエンドをクライアント形式で直接呼び出す
-
他のサービスのフロントエンドからvaultフロントエンドのapi状態管理コンポーネントをインポートした後に呼び出す
最初は1つ目の方法を試しましたが、プロジェクトを進める中で、この方法はサーバーに負荷をかける方式であることが分かりました。例えば、バンジャンノートのフロントエンドでアップロードを行う際、まずバンジャンノートのバックエンドにアップロードリクエストを送り、ファイルをバックエンドに送信したうえで、さらにバンジャンノートのバックエンドからvaultのバックエンドへ転送すると、バンジャンノートとvaultのサーバーメモリを不必要に大量消費するためです。したがって、バンジャンノートのフロントエンドからvaultのバックエンドを直接呼び出す方式にする必要がありました。また、vaultのフロントエンドにはすでにAPIごとに状態管理を自動的に行うカスタムフックコンポーネントが作成されているため、そのフロントエンドコンポーネントをインポートする方式が望ましいことが分かりました。
3. CabinetとClipの範囲
CabinetはClipの集合であり、ClipはClipFilesの集合です。この問題は、Vaultを担当していた私にとって最大の挑戦でした。各サービスにおいてCabinetの範囲、Clipの範囲をどのように定めるのがよいかという問い合わせが多く寄せられていましたが
簡単に答えるのは難しいものでした。掲示板ごとにcabinet、投稿ごとにclipと考える場合もあれば、clipだけで分ける場合もありました。今でも明確な答えを出すのは難しいですが、私の経験では、cabinetはサービス全体で1つを共有し、投稿に写真や添付ファイルを追加する際にはclipを生成し、その投稿に書類を提出する際には専用のclipを別途生成する構成で、ほとんどのファイルのまとまりをclipとして定義するのが最も柔軟な構造だったと思います。また、clipは個人が保有するすべてのファイルを担当し、アップロード時にはメタデータも一緒に渡してアップロードする方式で進めました。ただし、後になってメタデータをvaultに渡すか班長ノートに渡すかを議論した結果、後者に決まりました。メタデータを班長ノートで管理する必要性があったためだと思います。
そのため、班長ノートの適用は、次のようなフローで行いました。
構造
-
班長ノートは告知用clip と 提出書類用clip を分離
-
cabinetは班長ノート全体が1つを共有
-
cabinetKey、cabinetIdは 常に同じでなければならない
フロー
1) リーダー(チーム長)が告知を作成
-
班長ノートのバックエンドでregisterJobPost(例)
-
告知に画像を登録する際にregisterClipFilesを呼び出す
-
成功時に返されたclipIdを、パンジャンノートのバックエンドにある該当するJobPostに保存する
2) 班長が告知をクリック → 提出
-
班長ノートのバックエンドでfindJobPostDetail(例)
-
提出する → 提出書類リスト → 身分証明書をクリック
-
ファイルをアップロード、または「自分の書類から読み込む」
-
ファイルをアップロードする場合
- registerClipFilesを呼び出す
- 返されたclipId、clipFileIdsをjobApplication(例)に保存
- jobApplicationに該当する書類タイプがない場合はregisterClipFile、ある場合はaddClipFileを使用
-
自分の書類から読み込む場合
- registerClipFilesFromstashを使用
- 特定の書類のstashFolderIdを取得できる場合は、メタデータを保存せずにregisterClipFilesFromstashで処理した後、バンジャンノートのバックエンドに保存
3) チーム長が応募者の書類を照会
-
バンジャンノートのバックエンドでclipIdを含むjobApplicationを検索 → clipIdを抽出
-
vaultバックエンドでclipFileIdsを照会した後、downloadFile(s)でサムネイルをプレビュー
振り返り
パンジャンノートにvaultサービスを適用する過程で多くのことを学び、まだ学ぶべきことがたくさんあることにも気づきました。汎用性を高めるには犠牲にしなければならない部分があり、それを補う過程で成長できたように思います。今後もvault担当者として、パンジャンノートチームに対して何をどのように定めるのかを明確にすることが、開発の進捗に大きく役立つと思います。もし他のサービスでも適用業務を担当することになれば、vaultの構造をより簡潔に説明し、これまでの経験を生かしてドメイン構造の設計にも積極的に関わり、確信を持って進めながら、間違いがあれば受け入れて改善する姿勢で取り組みたいと決意しました。
LEE DAVID