Alexandriteの技術スタックを考える

alexandriete logo type アーキテクチャ

個人の本棚から、つながる図書館へ

Alexandriteは、最初から大規模な図書館システムとして作り始めるわけではない。まず作るのは、個人の本棚を管理するための小さなアプリだ。

けれど、最終的に目指しているものは単なる蔵書管理アプリではない。個人の本棚、地域の小さな図書館、学校図書室、大学図書館、公共図書館、喫茶店の棚。そうした「本のある場所」を、将来的にゆるやかにつなげていきたい。

この記事は、技術スタックを確定するものではない。個人開発として小さく始めながら、将来の図書館連携やFederationに広げるために、どのような土台を選ぼうとしているのかを整理する記録だ。実装していく中で、選択は変わるかもしれない。むしろ、変わる余地を残しておくことも大切だと思っている。

現時点の技術スタック案

現時点の案を一覧にすると次のようになる。技術名そのものより、それぞれがAlexandriteのどの部分を支えるためのものなのかを意識している。

領域技術案役割
モバイルアプリReact Native / Expoバーコードスキャンや撮影を含む本の登録体験
WebフロントエンドNext.js管理画面、公開ページ、職員向け画面
バックエンドGoAPI、非同期処理、将来の分散構成
APIREST中心、将来的にgRPCアプリやWeb画面とサーバーのやり取り
データベースPostgreSQL本、利用者、貸出、履歴などの整合性が必要なデータ
モバイルローカルDBSQLite候補オフライン時やスキャン中の一時保存、高速表示
インフラ初期構成VPS / Docker Compose個人開発として小さく始めるための構成
将来のインフラKubernetes複数サービスやクラスター運用への拡張候補
非同期処理Job Queueから開始書誌データ取得や画像処理を待たせずに行う
メッセージング将来的にNATS横断検索やFederationの通信基盤候補
認証ID/PW + OAuth/OIDC複数のログイン手段や外部認証連携
拡張機構Module図書館ごとの機能差や将来の拡張

最初からすべてを作るつもりはない。個人本棚アプリとして始める段階で必要なのは、スマートフォンで本を登録できること、登録した本を見られること、データを安全に保存できること。それだけだ。

ただ、あとで広げるなら、最初の設計があまりにも閉じていると苦しくなる。だから、最初は小さく作る。でも、あとで広げられる余地を残す。

技術名より、何を支えるための土台か

Alexandriteの技術スタックは、単なる好みの問題ではない。

個人の本棚から始めて、将来的には複数の図書館や本のある場所をつなげていく。公式SaaSとして運用する可能性もあるし、OSSとして公開しセルフホストされる可能性もある。図書館の業務データと、ユーザー個人の読書履歴をきちんと分けて扱う必要もある。

技術スタックは、Alexandriteの思想を支えるための土台だ。

小さく始められること。一人でも開発を進められること。あとから図書館業務に広げられること。OSSとして公開しやすいこと。公式SaaSとして運用しやすいこと。Federationに向けて拡張できること。

これらをすべて完璧に満たす選択はない。だからこそ、「今の現実」と「将来の方向性」の両方を見ながら、無理のない構成を選んでいきたい。

最初から完璧な構成にはしない

Alexandriteの構想は大きい。図書館システム、個人本棚、横断検索、利用者アカウント、貸出・返却、予約、書誌データ、Federation、Registry、Module、Account Data Store。考えるべきことは多い。

でも、最初からそれらをすべて実装しようとすると、たぶん何も完成しない。

技術スタックを考えるうえでも、最初から理想の分散システムを作ろうとはしない。まずは個人開発として無理なく動かせる構成にする。そのうえで、将来的に図書館やFederationに広げられる余地を残す。

小さく作る。でも、あとで全部作り直しにならないようにする。これがAlexandriteの技術選定の基本方針だ。


ここから先は技術要素ごとの整理になる。すべてを細かく読む必要はない。それぞれの冒頭にある「何のためのものか」だけ拾ってもらえれば十分だ。

モバイルアプリ:React Native / Expo

Alexandriteの最初の入口は、スマートフォンアプリになる予定だ。

ISBNバーコードを読み取る。書影を撮影する。棚に並んでいる本をその場で記録する。こうした操作は、PCよりもスマートフォンの方が自然だ。

最初はPWAも候補に入れていた。配布が楽で、ストア審査も不要。個人開発としてはかなり魅力的だった。しかし実際に試してみると、iPhone上のブラウザではカメラやバーコード読み取りまわりに制約がある。特に連続スキャンや安定したカメラ制御を考えると、PWAだけでは難しそうだった。

そのため、現時点ではReact NativeとExpoを中心に考えている。Expoを使えば、ネイティブアプリに近い体験を作りつつ、開発環境をある程度シンプルに保てる。最初はExpo GoやDevelopment Buildで試し、必要に応じてTestFlightやストア配布に進む構成を想定している。

しかし、Expoで何でもできるわけではない。カメラ制御、バーコードスキャン、画像処理、ローカルDB、バックグラウンド処理など、後からネイティブ寄りの制約にぶつかる可能性はある。それでも、個人開発として始めるには現実的な選択肢だと思っている。

Webフロントエンド:Next.js

スマートフォンアプリが最初の入口になるとしても、AlexandriteにはWeb画面も必要になる。

図書館や地域の小さな図書館の管理画面は、スマートフォンだけでは操作しづらい。蔵書一覧を確認する、利用者を管理する、貸出状況を見る、設定を変更する。こうした操作はPCブラウザの方が向いている。

WebフロントエンドにはNext.jsを使う案を考えている。個人開発でも扱いやすく、管理画面や公開ページを作りやすい。React Nativeと同じReact系の知識を活かせる点も大きい。

Alexandriteでは将来的にいくつかのWeb画面が必要になる。個人の本棚をWebで見る画面。地域の小さな図書館の公開ページ。図書館の管理画面。職員向けの貸出・返却画面。RegistryやDiscoveryに関わる画面。すべてを最初から作るわけではないが、Web側の基盤としてNext.jsを置いておくと後から拡張しやすい。

バックエンド:Go

バックエンドにはGoを使う案を考えている。

Goはサーバーサイドのアプリケーションを比較的シンプルに書きやすい。並行処理にも強く、APIサーバーやワーカー、内部サービスを作りやすい。

Alexandriteでは、将来的に単なるCRUDアプリ以上の処理が必要になる。ISBNを読み取ったあと外部の書誌データソースに問い合わせる。書影や写真を扱う。横断検索のリクエストを受けて複数の図書館サーバーへ問い合わせる。Moduleを読み込んで機能を拡張する。こうした処理を考えると、Goは相性がよさそうだ。

また、OSSとして公開することを想定しているため、単一バイナリとして配布しやすく、セルフホストしたい人にとっても扱いやすいGoは向いていると思っている。

Ruby on RailsやNode.jsでも作ることはできる。特にRailsは管理画面や業務アプリを素早く作るには強い選択肢だ。ただ、将来的なFederation、非同期処理、複数サービス構成、セルフホストのしやすさを考えると、Goを中心に据えるのが自分には合っている。

API:RESTから始め、必要に応じてgRPC

最初はRESTを基本にするつもりだ。

本を登録する、一覧を取得する、書誌情報を更新する、コレクションに追加する、図書館への利用申請を行う。こうした操作はRESTで素直に作れる。

将来的にはgRPCも使う可能性がある。特にサーバー間通信や内部サービス間通信では、gRPCの方が向いている場面が出てくるかもしれない。Library ClusterとSearch Service、Registry、Module Runtime、Federation Gatewayのようなコンポーネントが分かれてきた場合、型定義を共有しやすいgRPCは有力な選択肢になる。

ただし、最初からgRPCを全面採用するつもりはない。最初はRESTで開発速度を優先し、内部構造が見えてきた段階でgRPCを導入するほうが現実的だと思っている。

データベース:PostgreSQL

データベースには、現時点ではPostgreSQLを第一候補として考えている。

Alexandriteで扱うデータの多くは、リレーショナルデータベースと相性がいい。ユーザー、Account、Credential、Membership、書誌、所蔵、コレクション、貸出、予約、図書館、権限、操作ログ。これらは関係性を持つデータであり、整合性も重要になる。

特に、Alexandriteは将来的に図書館業務に近づいていく。貸出中の資料を二重に貸し出さないこと、予約順序を守ること、図書館側の正式な業務記録とユーザー個人の読書履歴を分けること。こうした要件を考えると、データベース側でもしっかり制約を持たせたい。

PostgreSQLは、複雑な制約、トランザクション、JSONB、全文検索、拡張機能に強い。外部書誌データのように構造が揺れやすいデータを扱いつつ、貸出や予約のような整合性が重要なデータも扱うAlexandriteには相性がよい。

MySQLやMariaDBでも基本的な機能は実現できる。将来的にセルフホストや第三者運用を考えるなら、DBMS非依存性を完全に無視するべきではない。ただし、Alexandriteの性格を考えると、標準構成はPostgreSQLに寄せてよいと思っている。DBアクセス層を整理し、PostgreSQL固有の処理は局所化する。将来的に需要があればMySQL/MariaDB対応も検討できる余地を残す。このくらいの距離感が現実的だ。

ローカルデータ:SQLiteも検討

モバイルアプリ側では、ローカルデータの持ち方も重要になる。

本棚一覧をすばやく表示する。スキャンした本を一時的に保存する。ネットワークが不安定でも登録作業を続ける。未解決アイテムを端末側に保持する。こうした体験を考えると、ローカル保存は必要になる。

最初はAsyncStorageのようなシンプルな保存方法でもよいかもしれない。ただ、書籍一覧やスキャン結果、未解決アイテム、同期状態などを扱うようになると、SQLiteを使った方がよさそうだ。

Alexandriteでは将来的にすべてのユーザーデータを常に中央サーバーに置くのではなく、端末側やAccount Data Storeに保存する方向を考えている。図書館側が持つ正式な貸出記録と、ユーザーが持つ個人の読書履歴を分ける。こうした設計を考えると、クライアント側のデータ管理は後から重要になってくる。最初は単純でよい。でも、完全にサーバー依存の設計にはしすぎない。

インフラ:小さく始める

最初から大規模なクラウド構成で始める必要はない。

個人開発の段階では、VPSや小さなクラウド環境で十分だ。APIサーバー、Webフロント、PostgreSQL、必要なバッチ処理やワーカーを動かす。知人に使ってもらう程度であれば、単純な構成から始められる。

将来的にはKubernetesも視野に入れている。Library Cluster、Account Data Store、Registry、Search Service、Federation Gateway、Module Runtime、Background Workerのような構成になると、コンテナ単位でサービスを分けて運用したくなる。

ただし、最初からKubernetesを前提にすると開発が重くなる。まずはDocker Composeや単一サーバー構成で始め、必要になった段階で移行できるようにしておく。

非同期処理:書誌データ取得を待たせない

書誌データの取得は、非同期処理を前提にしたい。

ISBNを読み取ったら、まずスキャン結果として登録する。その後、バックグラウンドで書誌データを取得する。取得できたものから順に画面へ反映する。取得できなかったものは未解決アイテムとして残す。

ユーザーを待たせずにスキャン作業を続けられる。「登録できるまで待つ」のではなく、「まず受け取って、あとから補完する」。この考え方は、書誌データだけでなく、写真、書影、外部連携、Federation検索にもつながっていく。

メッセージング:将来的にNATS

Alexandriteでは、将来的にサーバー間通信が重要になる。横断検索や図書館同士の連携を考えると、間にメッセージング基盤を置く構成も考えられる。その候補として、NATSを検討している。

ただし、最初から必須ではない。個人本棚アプリの段階では単純な非同期ジョブやキューで十分だ。NATSが必要になるのは、Library Cluster、Search Service、Registry、Federation Gatewayのような構成が見えてきてからでよい。

Module構成を見据えた設計

Alexandriteでは、拡張機能の単位として「Module」という言葉を使う方針にしている。

図書館システムは、利用する組織によって必要な機能が大きく変わる。個人の本棚管理。地域の小さな図書館の貸出。公共図書館の利用者管理。大学図書館の認証連携。すべてをひとつの固定された機能セットで扱うのは難しい。

Moduleは単なるプラグインではない。何でも自由に読み込めるようにすると、セキュリティや運用が難しくなる。現時点では、Moduleの導入判断はLifecycleServiceが行い、ModuleLoaderがその指示に基づいて実際の読み込みや初期化を行うという考え方をしている。読み込む仕組みと、読み込んでよいか判断する責務を分ける。

将来的にOSSとして外部の開発者がModuleを作るようになった場合でも、Alexandrite本体が安全に制御できる余地を残しておきたい。

AccountとLibraryを分けて考える

Alexandriteではアカウント設計も重要になる。

Accountは、利用者本人を表す。Credentialは、ログイン手段を表す(Google、Apple、大学SSO、自治体ID、IDとパスワードなど)。Membershipは、特定の図書館を利用できる権利を表す。

Account : Credential = 1:N であり、AccountとMembershipも分離する。この設計にすると、ひとりの利用者が複数の図書館を使う状況を自然に表現できる。大学図書館、公共図書館、地域の小さな図書館、自分の本棚を、ひとつのアカウント体験の中で扱える。

将来的にはAccount Data Storeという考え方も重要になる。個人設定、図書カード一覧、個人の読書履歴、本棚データをどこに置くのか。公式のAccount Clusterに置くのか。セルフホストするのか。ローカルに持つのか。

図書館の業務データは図書館側が持つ。ユーザーの個人データはユーザー側に寄せる。この分離を、最初から少しずつ意識しておきたい。

Federationは既存標準をできるだけ利用する

将来的にFederationを考えているが、独自プロトコルを最初からすべて作るつもりはない。

ActivityPub、OIDC、OpenSearchなど、既存の仕組みを活用できる部分は活用したい。Alexandrite専用のプロトコルを一から定義すると、実装も運用も重くなる。外部の開発者や図書館、ベンダーにとっても参加しづらくなるかもしれない。

基本方針としては、既存標準を最大限利用し、Alexandrite固有の部分だけを薄く定義する方向を考えている。

ただし、図書館業務には図書館業務特有の事情がある。貸出状況、予約、利用資格、個人情報、所蔵情報、公開範囲。これらは一般的なSNSのFederationとは違う。既存標準を使う。でも、図書館業務の意味を無理に歪めない。このバランスが必要だ。

Federationの複雑さはユーザーに見せない

技術的にFederationを考えるとしても、利用者にその複雑さを見せるべきではない。

利用者は、自分がどのRegistryを使っているか、どのLibrary Clusterに接続しているか、どのAccount Data Storeにデータを持っているかを、普段は意識しなくてよい。

アプリを開く。本を探す。近くの図書館にあるか見る。借りられるなら申し込む。体験としては、それだけでよい。

「分散システムを、ただの図書館体験に変換すること」。これはAlexandriteの設計原則だが、技術スタックの選定にも関わっている。

OSSとして公開しやすい構成にする

AlexandriteはOSSとして公開することを想定している。

特定のクラウドサービスに強く依存しすぎない。ローカルやVPSでも動かせる。Dockerで立ち上げられる。設定を変えれば公式SaaSにもセルフホストにも使える。こうした条件を意識する必要がある。

OSS本体はできるだけ汎用的にする。公式SaaSは、その上に運用価値を乗せる。この分け方がよさそうだと考えている。

セキュリティとプライバシーは後回しにしない

本棚データや読書履歴は、かなり個人的な情報になりうる。図書館機能が入ると、利用者情報、貸出記録、予約情報、住所、所属、連絡先などを扱う可能性がある。だから、セキュリティとプライバシーを完全に後回しにはできない。

最初の段階から最低限の方針は決めておきたい。HTTPSを前提にする。パスワードを安全に扱う。個人情報を不用意にログへ出さない。権限を分ける。データ削除の意味を明確にする。

特に、履歴については慎重に考えたい。Alexandriteでは、貸出に関するデータを三層に分けて考えている。

  • Library Circulation Record:図書館が業務上保持する正式な記録
  • Loan History Projection:ユーザーに見せる履歴ビュー
  • Personal Reading History:ユーザー個人が所有する読書履歴

技術スタックも、この考え方を支えられる構成にしていく。誰のデータなのか。誰が見ることができるのか。誰が削除できるのか。こうした意味の違いを、最初から設計に含めておくことが重要だ。

技術スタックは段階的に育てる

技術スタックを考えていると、つい最初から完成形を作りたくなる。最初からKubernetesにする。最初からgRPCにする。最初からFederation前提にする。最初からModuleを完全に分離する。

でも、それを全部やろうとすると、たぶん最初の本棚アプリが完成しない。

Alexandriteでは、技術スタックも段階的に育てていきたい。

最初は、個人の本棚を登録できること。次に、スキャン体験を気持ちよくすること。その次に、書誌データ取得や画像管理を安定させること。さらに、地域の小さな図書館や学校図書室でも使えるようにすること。その先で、図書館同士や本のある場所をつなげていくこと。

技術も、その順番に合わせて育てればよい。

最初から理想の分散システムを作るのではなく、あとで分散できるように境界を意識しておく。最初から全機能をModule化するのではなく、あとでModuleとして分離できるように責務を分けておく。

小さく始めて、広がる余地を残す

Alexandriteは、まず個人の本棚管理アプリとして始まる。でも、その先には、地域の小さな図書館や、公共図書館や、誰かの本棚がゆるやかにつながる未来を見ている。

その未来に向けて、今の技術スタックは派手である必要はない。

小さく始められること。一人でも作り続けられること。OSSとして公開できること。公式SaaSとして運用できること。図書館業務に耐えられること。将来のFederationに向けて、広がる余地を残しておくこと。

技術スタックは、そのための土台だ。

今はまだ構想段階の部分も多い。実装していく中で、選択を変えることもあると思う。それでも、Alexandriteが目指している方向は変わらない。本のある場所を見えるようにする。個人の本棚から始めて、図書館や地域の本棚へ広げていく。そのために今は、無理なく作れて、あとから広げられる土台を選んでいきたい。


前回の記事:Alexandrite v0.1.0 開発記録

次回の記事:

タイトルとURLをコピーしました