モノレポと開発環境Monorepo
松葉は、画面・業務 API・Drive 同期・ウイルス検査という性格の異なる 4 つのアプリを、1 つのリポジトリ(モノレポ。複数のアプリ・部品をまとめて 1 か所で管理する方式)に同居させています。しかも言語が TypeScript と Go の 2 種類にまたがります。これをばらばらに散らさず、整合の取れた状態で扱うために 4 つの仕組み(軸)を組み合わせました。あわせて、手元のパソコンで全サービスを起動できる開発環境も整えています。
1 リポジトリを束ねる 4 つの軸Four axes
「複数のアプリを 1 か所で管理する」と言葉にすると簡単ですが、言語もビルド方法も異なるものを矛盾なく束ねるには、役割の違う道具を組み合わせる必要があります。松葉では次の 4 つを使い分けています。
なぜ 1 リポジトリにまとめるのか: 4 つのアプリと 7 つの共通部品は、互いに型やルールを共有します。別々のリポジトリに分けると「片方だけ更新して食い違う」事故が起きがちです。1 か所にまとめ、上の 4 軸で束ねることで、常に全体が 1 つの整合した状態に保たれます。
| 軸(道具) | 束ねる対象 | 業務上の意味 |
|---|---|---|
pnpm workspace | TypeScript パッケージ 9 個 | 共通部品の使い回しと、依存関係の一括解決(同じものを各所で重複インストールしない) |
Turborepo | ビルド・検査などの作業(13 タスク) | 変更のあった部分だけを並列で実行し、前回と同じ結果はキャッシュから再利用して待ち時間を短縮 |
go.work | Go モジュール(sync / scanner + 生成した Go 型) | Go 側のアプリと、自動生成した型を、1 つの作業空間として参照 |
Buf | protobuf 定義(packages/events) | イベントの形を 1 か所で定義し、TypeScript と Go の両方へ型を生成(詳細は「型と契約」へ) |
同居する 4 アプリと 7 共通部品Apps & packages
リポジトリの中身は、大きく アプリ(apps/)と共通部品(packages/)に分かれます。アプリ名は @matsuba/*、共通部品は @repo/* という接頭辞で区別しています。名前と業務上の役割の対応は次のとおりです。
| 名前 | 種別 | 役割(業務上の意味) |
|---|---|---|
@matsuba/web | アプリ(Next.js) | 利用者が触る画面(ブラウザ側) |
@matsuba/api | アプリ(Hono) | 業務処理の本体(API)+ 定期バッチ(同じ部品を使い回し) |
@matsuba/sync | アプリ(Go) | Google ドライブへの同期 |
@matsuba/scanner | アプリ(Go) | アップロードされたファイルのウイルス検査 |
@repo/database | 共通部品 | テーブル定義と、安全に DB へ触る 3 経路を集約 |
@repo/shared | 共通部品 | 画面とサーバが共有する検証ルール(Zod スキーマ)・定数・型の唯一の置き場 |
@repo/auth | 共通部品 | 認証・権限(誰がログインでき、どの Box で何ができるか) |
@repo/events | 共通部品 | システム内の「出来事」の形(protobuf)。TypeScript と Go を自動生成 |
@repo/ui | 共通部品 | 画面の共通部品の土台 |
@repo/eslint-config | 共通部品 | コード品質ルールの共通化 |
@repo/typescript-config | 共通部品 | TypeScript 設定の共通化 |
名前の付け方にも意味があります: アプリ(@matsuba/*)はそのまま本番の 4 つの Cloud Run サービスに 1 対 1 で対応します(@matsuba/api だけは API サービスと定期バッチの 2 つを兼ねます)。共通部品(@repo/*)は単体では動かず、アプリから呼び出されて初めて働く「部品」です。
手元のパソコンで全部を動かすLocal development
開発者が手元で動作を確認できるよう、4 サービスをローカルで起動できる環境を整えました。性格に応じて起動方法を分けています。画面と API はそのままパソコン上で、Go の 2 つはコンテナ(Docker)で起動します。
本番に直接つなぐ理由: 現在は公開前のため、本番環境そのものをテスト環境として使っています。手元の 4 サービスは、本番のデータベース・ストレージ・Drive・メール基盤に直接つないで動作確認します。一方、Pub/Sub(メッセージ基盤)や Eventarc(イベント連携)を介する処理はクラウド側の仕組みなので、これらは本番にデプロイしてから本番側で確かめます。
web)と業務 API(api)がパソコン上で、Drive 同期(sync)とウイルス検査(scanner)がコンテナで立ち上がり、4 つすべてが本番のデータベースに繋がって /health(生存確認)に応答します。
| 必要なツール | バージョン | 用途 |
|---|---|---|
| Node.js | 22 | 画面・API をホストで起動 |
| pnpm | 9 以上 | TypeScript パッケージの管理・起動 |
| Go | 1.25(必須要件は 1.23 以上) | 同期・検査アプリのビルド・補完(コンテナ起動のため任意) |
| gcloud CLI + ADC | — | 本番 Google Cloud リソースへの認証 |
| buf CLI | — | protobuf からの型生成 |
| Docker Desktop | — | 同期・検査アプリのコンテナ起動 |
正直な注記: この開発環境を整えた段階では、各アプリの中身はまだ「起動雛形(空の骨格)」です。/health に応答することと、本番リソースに繋がることを先に確認し、業務処理は今後の開発で、この土台の上に実装します。なお、本番データベースへの構造変更(マイグレーション)は事故防止のため自動実行せず、人手で慎重に適用する運用にしています。