概要
Google OR-Tools(CP-SAT)を用いたSaaS型の自動シフト作成システム。勤務条件や各種制約をもとに最適なシフトを自動生成し、Web画面から管理・編集・エクスポートまで一貫して行える。求解エンジン(Solver Core)を独立モジュールとして設計し、Web層から完全に分離することで高い保守性と拡張性を実現した。また、RailwayからAWS(EC2 / RDS / S3 / DynamoDB)への移行も行い、クラウドインフラの設計・構築・運用まで一貫して担当した。
対象ユーザー
- 病院・介護施設・コールセンターなど、複雑なシフト制を運用する事業者
- 勤務パターンが多く、人手で公平なシフトを組むのに時間がかかっている現場
- シフト作成の根拠をスタッフに説明できる仕組みが欲しい管理者
Demo / GitHub
🔗 Demo を試す
スクリーンショット
シフト結果画面 — スコア明細・排班表
勤務ルール設定 — 連続勤務禁止・パターンチェーン
三方案比較 — 均衡方案・人力優先・個人優先
開発背景
以前Lancers案件でPuLPベースのシフト生成スクリプトを開発した経験があり、その際に「制約の追加・変更に柔軟に対応できるアーキテクチャが必要」と感じた。今回はその知見を活かし、Constraint Managerアーキテクチャを採用。Solver Coreを独立モジュール化し、求解エンジンの差し替えやテストが容易な設計で一から作り直した。
解決した課題
- 複雑な勤務制約を自動で考慮し、手作業によるシフト作成を削減
- 休暇希望や勤務条件を反映した公平なシフトを自動生成
- 複数案を比較し、現場状況に応じたシフト選択を可能に
- シフト作成理由を可視化し、管理者の説明負担を軽減
- 個人がスマホから休み希望を提出し、自動的に制約として反映されるフロー
主な機能
- 勤務条件管理: 11種類の制約に対応(固定勤務 / 連勤制限 / 勤務時間 / 休暇希望 / 必要人数 / グループ需要 / パターン均衡 など)
- 自動シフト生成: 実行可能なシフトを生成した後、品質を段階的に改善する多段階最適化
- 三方案比較: 均衡型 / 人員配置優先 / 個人優先の3パターンを生成し、スコアで比較・選択
- 違反分析: 制約違反が発生した場合、原因を分析し調整提案を自動生成
- 休み希望フロー: 個人がスマホでカレンダーから日付選択 → 確定提出 → 締切処理で自動反映
- Excel/PDF導出入: シフト表・統計・違反レポートの出力、パターン一括インポート、結果再インポート(差分表示付き)
- 多テナント対応: JWT認証 + テナント単位のデータ隔離
使用技術
- 求解エンジン: Google OR-Tools CP-SAT(制約充足+最適化求解)
- バックエンド: Python FastAPI / SQLAlchemy 2 (async) / Pydantic
- フロントエンド: React 19 / TypeScript / Vite / Ant Design 5
- データベース: PostgreSQL(本番)/ SQLite(開発)
- 認証: JWT(python-jose + passlib)
- Excel: openpyxl
- インフラ: Railway → AWS移行(EC2 / RDS / S3 / DynamoDB)/ VPC(Public/Private Subnet)/ Security Group / IAM Role + Instance Profile
- CI/CD: GitHub Actions(pytest → SSH deploy → ヘルスチェック)
設計上の工夫
- Solver Coreの完全独立: 求解エンジンはFastAPI・React・DBに一切依存しない独立モジュール。入出力はJSON。CLI単体でも実行・テスト可能で、将来求解器をGurobiなどに差し替えても制約定義は変更不要
- Constraint Compiler: 制約定義(何を制約するか)と求解器指令(どう翻訳するか)を中間表現で分離。制約の追加時に求解器の知識が不要な構造
- 双層スコア: 内部の最適化目標(Penalty)と顧客向けスコア(0〜100点)を分離。内部の数値が増大しても、外部表示は常に直感的
アーキテクチャ
ブラウザ (React + TypeScript + Ant Design)
│
▼
FastAPI (REST API / JWT認証 / 多テナント隔離)
│
┌───┴──────────────────────┐
│ │
Solver Core (独立モジュール) Web Layer (CRUD / Export / Import)
│ │
├── Constraint Manager ├── PostgreSQL (RDS Private Subnet)
│ └── 11 Constraints ├── DynamoDB (監査ログ)
├── Constraint Compiler └── S3 (Excel/PDF保存)
└── CP-SAT Engine
CI/CD: GitHub Actions → test → SSH deploy → EC2 systemd restart
開発周期
7日(Solver Core + Web層 + テスト) + AWS移行
担当範囲
要件定義 / 数理モデル設計 / 制約体系設計 / Solver Core実装 / バックエンドAPI / フロントエンドUI / テスト(56件 + 性能テスト) / Railway デプロイ / AWS移行(VPC・EC2・RDS・S3・DynamoDB・IAM・CI/CD)
成果・実現したこと
- 高性能な求解: 10人×31日 → 0.5秒 / 20人×31日 → 1.4秒 / 50人×31日 → 6.7秒 / 100人×31日 → 22.7秒
- Solver Coreの独立設計: Solver Coreを独立モジュールとして実装し、JSONベースの入出力インターフェースを採用。Web API・CLI・テストコードから共通利用できる構成を実現
- 品質保証: 56件のユニットテスト + API統合テスト + 性能テスト全パス
- AWS移行: 同一アプリをPaaS(Railway)とIaaS(AWS)の両方にデプロイし、クラウドインフラの設計・構築を実施
想定導入効果
- 手作業で数時間かかるシフト作成を数秒〜数十秒に短縮
- 制約違反の原因を可視化し、管理者がスタッフに根拠をもって説明可能
- 複数のシフト案の比較により、現場の状況に応じた最適なシフトを選択可能
- 個人の休み希望提出フローにより、紙やLINEでの収集作業を解消
開発で直面した課題と解決方法
- 求解性能の最適化: 初期実装では20人規模で40秒超だったが、最適解到達後の後続処理スキップと並列探索の導入で1.4秒に改善
- RailwayとAWSの環境差異: Railway(Docker)とAWS(EC2 systemd)で同一コードを動作させるため、環境変数による設定切替を徹底
- 制約間の優先度制御: Penalty重みに数量級の差を設けることで、高優先制約が低優先の最適化に犠牲にされない構造を実現
このプロジェクトで学んだこと
- 求解エンジンをWeb層から分離する設計は、テスト容易性・保守性・将来の求解器差し替えに大きく寄与する。独立モジュール化は初期コストがかかるが、開発後半のデバッグ効率を大幅に向上させた
- 制約のPenalty重みは「数量級の差」が重要。微妙な差では高優先制約が犠牲にされる場面が発生した
- 同一アプリをPaaS(Railway)とIaaS(AWS EC2/RDS)の両方にデプロイすることで、各基盤の長所・制約・運用コストの違いを体感的に理解できた
- AWSでは設定方法だけでなく、「なぜその構成を採用するのか」を説明できるレベルで理解することが、実運用を見据えた設計には重要であると学んだ