
Overview
プロジェクト概要
建設・設備工事会社向けに、案件、顧客、見積、受注、発注、施工状況の情報を1つにまとめるWebの業務システムを新しく開発しました。営業、工事、購買、管理の各部門が、同じ情報をリアルタイムで見られるようにするための基盤です。案件の登録から見積、発注までを一続きの業務の流れとして扱い、一度登録した情報は後の業務にそのまま引き継がれます。
開発期間は約6か月、体制はPM・フロントエンドエンジニア・バックエンド/インフラエンジニアの3名です。利用者は、営業・工事・購買・管理者・経営層の約48名です。当社は、バックエンドとインフラを一貫して担当しました。LaravelによるAPIの設計・開発から、Google Cloud上の本番環境の構築、運用までを受け持っています。
※ お客様との守秘義務のため、お客様名・製品名は記載していません。掲載している画面とデータは、説明用に再構成したイメージです。
- 分類
- Webの業務システムの新規開発(案件・顧客・見積・発注の一元管理)
- 開発期間
- 約6か月
- 体制
- 3名(PM / フロントエンドエンジニア / バックエンド・インフラエンジニア)
- 利用者
- 約48名(営業 約20名 / 工事 約15名 / 購買 約5名 / 管理者 約5名 / 経営層 約3名)
- 業種
- 建設・設備工事
- ロール
- REST APIの設計・開発 / データベース設計 / 認証・認可 / 見積・発注の機能 / PDF・CSVの出力 / Google Cloudの環境構築 / CI/CD / 監視 / 本番への配置 / 障害調査・性能改善
- 技術
- React / TypeScript / PHP / Laravel / MySQL / Google Cloud(Cloud Run) / Cloud SQL / Cloud Storage / Cloud Build / Docker

01 — 導入前の課題
で、今の最新情報はどれ?
導入前は、案件の情報、見積、発注、施工状況が、Excel、メール、紙の帳票に分かれていました。営業は営業案件の一覧、購買は発注の一覧、工事は工事の進行表を、それぞれ別に更新します。納期の変更はメールで届き、紙の進行表には手書きで直しが入ります。更新する場所が違うので、どれが最新なのかが分からなくなっていました。管理の方法も営業担当者ごとに違い、最新の状況を知るには担当者に問い合わせる必要がありました。さらに、案件を登録した後も、見積用・発注用・売上管理用のExcelに同じ情報を入力し直していました。
- 案件の情報が、担当者ごとのExcelに分散
- 同じ情報を、見積・発注・売上管理用に何度も入力
- 発注済み・未発注・納期の遅れを、Excelとメールで確認
- 月次の集計が終わるまで、経営層が状況を把握できない

02 — 情報の引き継ぎ
一度入れた情報を、次の仕事へそのまま
案件を登録すると、顧客名、工事場所、工事内容、担当者、予定金額が、見積、発注、施工へそのまま引き継がれます。画像の例では、同じ案件番号のもとで、見積では材料費・人件費・外注費・諸経費と見積金額が、発注では発注先・発注金額・納期・ステータスが、施工では着工日・完了予定・進捗が管理されています。案件は「問い合わせ → 商談中 → 見積作成 → 見積提出 → 受注 → 施工中 → 完了」と、失注を合わせた8つのステータスで管理します。各部門は、同じ案件を起点に作業できます。
- 案件の情報を、見積・発注・施工へ引き継ぐ
- 入力は、基本的に1回で済む
- 案件を8つのステータスで管理
- 図面や契約書などのファイルを、案件単位で保存
開発中の課題と解決
Cloud Run上で、キューの処理と定期実行を安定して動かす
- 課題
- Cloud Runは、リクエストを受けたときに動くサーバーレスの環境です。標準の設定では、リクエストを処理している間しかCPUが割り当てられず、アクセスが無ければインスタンスは0まで減ります。そのため、キューの処理を常に動かしておく構成や、毎分スケジューラを起動する構成が、そのままでは成り立ちませんでした。
- 解決
- API用とは別にワーカー用のCloud Runサービスを用意し、非同期処理と定期処理をAPIから切り離しました。ワーカーは「CPUを常に割り当てる」設定と最小インスタンス数1で常に動かします。キューにはCloud SQL(MySQL)を使う方式を採用し、Redisなどのサービスを追加せず、構成を単純に保ちました。APIはリクエストの量に応じて増減させながら、非同期処理と定期処理を安定して動かせます。

03 — 見積と粗利の自動計算
計算する見積から、判断できる見積へ
以前は、過去の見積を探してコピーし、金額を手作業で直していました。このシステムでは、見積の明細を材料費・人件費・外注費・諸経費の4区分で登録すると、原価、粗利、粗利率が自動で計算されます。画像の例では、原価840万円、見積金額1,050万円に対して、粗利210万円・粗利率20.0%が表示され、その画面から承認の申請と見積書のPDF出力ができます。計算の結果は見積の履歴として保存され、粗利率の低い案件をダッシュボードで把握できます。見積の作成にかかる時間は、1件あたり平均約30分から約12分になりました(約60%削減)。
- 4区分の明細から、原価・粗利・粗利率を自動計算
- 過去の見積を参照して作成
- 承認ワークフローと、承認の履歴
- 見積書・発注書をPDFで出力
開発中の課題と解決
見積書・発注書を、日本語のPDFとして出力する
- 課題
- 見積書と発注書は、お客様や発注先にそのまま提出する帳票で、それまでExcelで作っていたレイアウトを再現することが求められました。しかし、PDFを生成するライブラリ(dompdf)の標準のフォントには日本語が含まれておらず、使えるCSSにも制約がありました。明細の行が多い見積書では、改ページの位置も課題になりました。
- 解決
- 日本語フォントをコンテナイメージに同梱して登録し、文字化けを解消しました。帳票のテンプレートは表を土台に組み、既存のExcelの帳票と見比べながら、余白、罫線、金額欄の配置を調整しています。明細が複数のページにまたがる場合は、表のヘッダーをページごとに繰り返し、合計欄が途中で分かれないように改ページを制御しました。

04 — ダッシュボード
月末を待たず、今日の会社が見える
ダッシュボードでは、見積中・受注・発注待ち・施工中・未承認の見積の件数と金額を、いつでも確認できます。受注金額、受注率、月別の売上と粗利、担当者別の案件の状況も表示されます。以前は、月次の集計が終わるまで約3営業日かかっていました。導入後は、経営層と営業責任者が、「いま、どの案件が見積中か」「受注の見込みはいくらか」「どの案件の粗利率が低いか」を、数時間以内に把握できます。利用者の所属と権限に応じて、参照・登録・編集・承認できるデータを分けています。
- 見積中・受注・発注待ち・施工中の件数と金額を表示
- 受注率・粗利率・月別売上をリアルタイムに確認
- 発注待ちの案件と、未承認の見積を見える化
- 5つのロールによる権限管理と、操作ログ
Scope
担当範囲
お客様との要件の調整と要件定義、進行の管理はPMが、Reactによる画面の開発はフロントエンドエンジニアが担当しました。当社は、バックエンドとインフラを一貫して担当しています。
| 工程 | 担当 |
|---|---|
| お客様との要件の調整、要件定義、進行・品質の管理 | PM |
| 画面の開発(React、TypeScript)、UI/UX | フロントエンドエンジニア |
| REST APIの設計・開発(案件・顧客・見積・発注) | 当社 |
| データベース設計、Cloud SQLの構築、パフォーマンスチューニング | 当社 |
| 認証・認可の機能 | 当社 |
| 見積・発注の機能、見積金額・粗利の計算ロジック | 当社 |
| PDF・CSVの出力、ファイルのアップロードとCloud Storageとの連携 | 当社 |
| Google Cloudの環境構築(Cloud Run、Cloud Storage、IAM) | 当社 |
| Dockerによる開発環境、Cloud BuildによるCI/CD | 当社 |
| 監視の設定、セキュリティの設定・対策 | 当社 |
| 本番環境への配置、障害の調査・対応、性能改善 | 当社 |
バックエンドとGoogle Cloudのインフラを同じ担当が受け持ったことで、システム全体の構成を見渡しながら開発を進めました。Cloud Runの動き方に合わせて非同期処理の構成を決めるなど、アプリケーションとインフラを切り分けずに設計しています。
Architecture
使用技術・システム構成
- フロントエンド
- React 18 / TypeScript / Vite / React Router / Axios / MUI / React Hook Form / Zod
- バックエンド
- PHP 8.2 / Laravel 10 / Laravel Sanctum(APIの認証) / Laravel Queue・Scheduler(非同期・定期実行) / dompdf(PDFの生成)
- データベース
- MySQL 8.0 / Cloud SQL for MySQL
- インフラ
- Google Cloud:Cloud Run(APIサービスとワーカーサービス) / Cloud Load Balancing / Cloud Storage / Artifact Registry / IAM
- CI/CD・監視
- Cloud Build / Cloud Logging / Cloud Monitoring
- 開発環境
- Docker / Docker Compose / Git / GitHub
主な技術の選定理由
APIとは別に、ワーカー用のCloud Runサービスを用意
非同期処理と定期処理をAPIから切り離すためです。APIはリクエストの量に応じて増減させ、ワーカーは常に動かしておけます。
キューにCloud SQL(MySQL)を使う方式を採用
Redisなどのサービスを追加せずに済み、構成を単純に保てるためです。
帳票のテンプレートを表で組む
PDFを生成するライブラリが対応するCSSに制約があり、FlexboxやGridが使えないためです。
日本語フォントをコンテナイメージに同梱
ライブラリに標準で入っているフォントには、日本語の文字が含まれないためです。
Process
開発の進め方
- 1
約6か月の開発を、「要件定義・基本設計 → データベース設計・API設計・UI設計 → 基本機能の開発 → 結合テスト・ユーザー受入テスト → 修正・性能改善・本番リリース」の順に進めました。
- 2
ソースコードはGitとGitHubで管理しました。Pull Requestを起点に、テスト、ビルド、コンテナイメージの作成、配置までを自動で行う仕組みを、Cloud Buildで構築しています。
- 3
開発環境は、DockerとDocker Composeでそろえました。
- 4
障害の調査と性能改善は、Cloud Loggingに集めたログと、Cloud Monitoringの計測値をもとに行いました。
Quality & Security
品質・セキュリティ・運用
認証・認可
Laravel SanctumによるAPIの認証を行い、パスワードはハッシュ化して保存します。管理者・営業・工事・購買・経理の5ロールで、参照・登録・編集・承認を制御します。
アプリケーションの対策
通信はHTTPSで暗号化します。CSRF対策、API側での入力値の検証、SQLインジェクション対策を行っています。
インフラの権限
Google CloudのIAMで、サービスとリソースの権限を管理し、Cloud SQLへの接続を制御します。
監査
操作ログとして、ログインの履歴、登録・更新の履歴、承認の履歴、削除の履歴、ユーザー別の操作の履歴を記録します。
テストと配置
結合テストとユーザー受入テストを行いました。Pull Requestを起点に、テスト、ビルド、Cloud Run(APIとワーカー)への配置までを自動化しています。
監視・運用
アプリケーションのログをCloud Loggingに集め、Cloud Monitoringで稼働の状況を監視します。
Results
成果
Excel、メール、紙の帳票に分かれていた案件・見積・発注の情報を1つのWebシステムにまとめ、各部門と経営層が同じ情報をリアルタイムで確かめられる業務の基盤を構築しました。年間の削減工数は約720時間、作業コストに換算すると年間 約216万円です(1時間あたり3,000円で換算)。
- 案件情報の検索:1件あたり平均 約10分 → 約1分(約90%削減)
- 見積の作成:1件あたり平均 約30分 → 約12分(約60%削減)
- 案件情報の入力回数:1案件あたり平均3回 → 基本的に1回(約67%削減)
- Excelへの転記・集計の作業:約80時間/月 → 約20時間/月(約75%削減)
- 発注漏れ:月平均8〜10件 → 月平均1〜2件(約80%削減)
- 見積の承認期間:平均2.0営業日 → 平均0.8営業日(約60%短縮)
- 月次集計:約3営業日 → 数時間以内
FAQ
技術面のよくあるご質問
- Q. Cloud Runで、キューや定期実行はどう動かしていますか?
- API用とは別に、ワーカー用のCloud Runサービスを用意しています。ワーカーは「CPUを常に割り当てる」設定と最小インスタンス数1で常に動かし、LaravelのQueueとSchedulerを実行します。キューにはCloud SQL(MySQL)を使っています。
- Q. なぜAPIとワーカーを分けたのですか?
- 同じサービスの中で動かすと、自動の増減でインスタンスの数が変わるたびに、ワーカーやスケジューラの数も変わってしまうためです。
- Q. 見積書・発注書のPDFは、日本語と帳票のレイアウトにどう対応しましたか?
- 日本語フォントをコンテナイメージに同梱して登録しました。テンプレートは表を土台に組み、既存のExcelの帳票と見比べて調整しています。明細が複数のページにまたがる場合は、表のヘッダーをページごとに繰り返し、合計欄が分かれないように改ページを制御します。
- Q. 原価や粗利はどこで計算していますか?
- API側で計算しています。見積の明細を材料費・人件費・外注費・諸経費の4区分で登録すると、原価、粗利、粗利率が自動で計算され、見積の履歴として保存されます。
- Q. 利用者ごとの権限はどう分けていますか?
- 管理者・営業・工事・購買・経理の5ロールによるアクセス制御です。所属と権限に応じて、参照・登録・編集・承認できるデータを制御しています。
- Q. だれが何をしたかは、後から追えますか?
- 操作ログとして、ログインの履歴、登録・更新の履歴、承認の履歴、削除の履歴、ユーザー別の操作の履歴を記録しています。
Tech Stack
