holidays-webhook のサーバーサイド
AIエージェント(Codex等)がこのリポジトリで作業する場合は、先に AGENTS.md を読み、安全上のルール(mainへ直接コミットしない、破壊的なDocker操作を無断で行わない等)に従うこと。
- Docker DesktopまたはDocker Engine
- Docker Compose v2
- Make
ローカル環境では、Docker内のPHP 8.5.9、Composer 2.8.12、MySQL 5.7.35を使用する(Issue #220でPHP 8.2.30から昇格)。ホスト側にPHPやComposerをインストールする必要はない。
このリポジトリはLaravel 13(composer.jsonのlaravel/frameworkは^13.0、最低PHP要件は^8.3)を使用している。ただし本番環境(XServer)は現時点でPHP 8.2.30のままであり、Laravel 13はPHP 8.3未満では動作しない。本番のPHPバージョン切り替えはIssue #226の範囲であり、Issue #226が完了するまでこのLaravel 13版を現在の本番(PHP 8.2.30)へデプロイしてはならない。デプロイはv*タグのpushでのみ起動する(.github/workflows/deploy.yaml)。
make setupこのコマンドは、次を順番に実行する。
src/.envがない場合だけ、.env.exampleから作成する。- Dockerイメージをビルドする。
- WebコンテナのPHPと固定版Composerで依存関係を導入する。
- Webサーバーとデータベースを起動し、データベースの応答を待つ。
- 初回のMySQLコンテナ作成時に
docker/db/sqlのテーブル定義を適用し、データベースシーダーを実行する。現在のシーダーはデータを投入しない。
.env.example の値はローカル開発・テスト専用であり、本番環境では使用しない。Google連携を使用しない起動とテストに外部の秘密情報は不要である。
make setup は再実行できる。既存の src/.env を上書きせず、既存のデータベースコンテナを再利用する。
make setup、make up、make rebuild、make test、make check は、Dockerやアプリケーションを実行する前に src/.env と同名の実行環境変数を検査する。次のローカル固定値だけを許可し、条件を満たさない場合は設定値を表示せずに中止する。
APP_ENV=localDB_CONNECTION=mysqlDB_HOST=dbDB_PORT=3306DB_DATABASE=hwDB_USERNAME=userDATABASE_URLが存在しない
ガード通過後、Laravelが古い接続設定を使用しないよう src/bootstrap/cache/config.php を削除してから処理を続ける。本番または外部データベース用の .env では、これらのローカル開発用コマンドを実行できない。
make up既存のWebサーバーとデータベースを起動し、データベースの応答を待つ。
make stopコンテナを削除せずに停止するため、ローカルデータベースの内容は保持される。MySQLのデータは /var/lib/mysql をnamed volumeへ保存しているため(後述)、docker compose down(--volumes を付けない場合)やコンテナの再作成でもデータは失われない。
make rebuildWebイメージだけをキャッシュなしで再構築する。データベースコンテナは再作成しない。
MySQLのデータディレクトリ /var/lib/mysql は、docker-compose.yml で db_data というnamed volumeへ保存している(Issue #233)。このvolumeには固定名(name:)を指定していないため、Composeのproject名(既定では holidays-webhook-server)ごとに別のvolumeとして扱われる。
make stop→make up、make rebuild、通常のdocker compose down(--volumesなし)、dbコンテナの再作成では、db_dataは削除されずデータが保持される。- データを完全に削除するのは、
--volumesを明示的に付けたdocker compose down、docker volume rm、または後述のmake db-wipeを実行した場合だけである。 make check(後述)は開発用とは別のCompose project・別のDB(volumeなし・使い捨て)を使うため、make checkを実行しても開発用DBのデータには影響しない。
make db-backupdocker compose exec db mysqldump の出力を backups/ 内の一時ファイルへ書き出し、成功かつ0バイトでないことを確認できた場合だけ backups/hw-<日時>.sql へmvする(backups/ はGit管理対象外)。mysqldumpが失敗した場合や出力が空だった場合は一時ファイルを削除し、成功メッセージは表示しない。
make db-restore FILE=backups/hw-20260101120000.sql指定したバックアップファイルの内容を開発用DBへ流し込む。既存データを上書きするため、FILE は必ず明示的に指定する必要がある(省略時はエラーで停止する)。指定ファイルが通常ファイルとして存在し、かつ0バイトでないことを確認してから投入する。MySQLへの投入が失敗した場合は成功メッセージを表示しない。
make db-wipe CONFIRM=yes開発用DBのvolumeを削除し、docker/db/sql の定義から作り直す。開発用DBの内容がすべて失われる。 誤実行を防ぐため CONFIRM=yes を明示しない限り実行されない。実行前に make db-backup でバックアップを取ることを推奨する。
開発用Composeプロジェクトに対する docker compose down --volumes は使わない。Composeが自動で付与する com.docker.compose.project/com.docker.compose.volume ラベルで開発用DBのvolumeを1件だけ特定し、該当が0件または複数件の場合は削除せずエラーで停止する。特定できた場合だけ db サービスのコンテナとそのvolumeを削除して作り直すため、開発用webコンテナや、make check が使う検証専用environment(Compose project)には一切触れない。
この操作(および docker volume rm、docker compose down --volumes など、開発用volumeやコンテナを削除しうるDocker操作全般)は、利用者から明示的な許可を得た場合を除き、AIエージェントや自動化から無断で実行してはならない。 検証や調査の過程で誤って実行してしまった場合、実行してよいか判断がつかない場合、既存の開発環境と衝突しそうな場合は、その時点で作業を止め、状況を日本語で具体的に報告すること。
make check は、開発用とは異なるCompose project(既定では holidays-webhook-server-check)と docker-compose.check.yml を使って、依存関係の導入からテストまでを実行する(Issue #233)。
- 開発用のcontainer・network・volume・host portには一切触れない。開発環境を起動したままでも、停止したままでも実行できる。
- 検証用のcontainer・networkは開発用と別名になり、host portは公開しない。
- 検証用DBはnamed volumeを持たない使い捨てで、
make checkの成功・失敗にかかわらず、検証用Compose projectだけを対象にcleanup(docker compose down --volumes --remove-orphans)する。 - 一時的な
docker-compose.override.ymlは使用しない。検証用の構成はdocker-compose.check.ymlとしてリポジトリに含まれている。
PHP 8.5系での互換確認環境は、Issue #215で標準のPHP 8.2.30とは別に追加していた(docker-compose.check-php85.yml、make check-php85、GitHub Actionsのphp85-compatジョブ)。Issue #220でローカル・CIの標準PHPそのものをPHP 8.5.9へ昇格したため、make checkが常にPHP 8.5.9で実行されるようになり、この移行期間用の重複構成とは完全に同等になった。そのためIssue #220でこれらを削除し、make checkへ統合した(docker-compose.check-php85.ymlの削除、Makefileのcheck-php85/check-php85-cleanターゲットの削除、GitHub Actionsのphp85-compatジョブの削除。リポジトリにbranch protectionは設定されておらず、php85-compatはrequired checkではないことをIssue #220着手時に確認済み)。
make test環境構築からPHP・Composer・必要なPHP拡張・フォーマット確認・静的解析・テストまでをまとめて確認する場合は、次を実行する。
make checkmake check は最後に composer check(composer:validate → composer:audit → composer:prod-check → composer format:check → composer analyse → php artisan test)を実行する。どれか1つでも失敗すると後続は実行されない。個別に確認・修正する場合は、src 配下でそれぞれ次を使う。
composer composer:validate # composer.json/composer.lockの整合性をstrictに検証する
composer composer:audit # 監査ラッパー(scripts/audit-guard.php)経由でcomposer.lockの既知の脆弱性を監査する
composer composer:prod-check # 本番向け(--no-dev)の依存関係が解決できるかをdry-runで確認する(vendorは変更しない)
composer format # Laravel Pintでコードを整形する
composer format:check # 整形せず、フォーマット違反があれば失敗する
composer analyse # PHPStan/Larastanを実行するcomposer:audit は素のcomposer auditを直接呼ばず、scripts/audit-guard.phpという監査ラッパーを経由する(Issue #214)。Composer 2.8.12はPackagistへのアドバイザリ取得自体に失敗した場合、例外を捕捉せず異常終了(終了コード100・標準出力は空)する挙動を隔離環境で確認済みだが、この挙動に依存せず将来のComposerの変更にも耐えられるよう、ラッパーはcomposer audit --locked --format=jsonの終了コードとJSON構造の両方を検証し、次のいずれかに該当する場合は「監査取得失敗」として失敗させる。
- 終了コードが正常完了時のビットマスク(0/1/2/3)以外
- 標準出力が空、またはJSONとして解析できない
advisories・abandonedフィールドが欠落している
これにより、「監査に成功しbaseline外の脆弱性がなかった」場合と「アドバイザリ取得先に到達できず結果を取得できなかった」場合を区別し、後者を「脆弱性なし」として誤成功させない。
composer:audit(ラッパー)は、既知の脆弱性アドバイザリをcomposer.jsonのconfig.audit.ignoreへ理由付きで記録し、新規のアドバイザリが増えた場合だけ失敗する構成にしている。Issue #214時点では44件だったbaselineは、Issue #216のLaravel 9更新で33件(依存更新)+7件(larastan/larastan更新に伴うcomposer/composerの除去)が解消し、Issue #217のLaravel 10更新(laravel/framework 10.50.2)でファイルバリデーション不備(CVE-2025-27515)の1件がさらに解消したため3件になった。Issue #218のLaravel 11更新(laravel/framework 11.55.0)では同じ3件を再確認したが増減はなかった。Issue #219のLaravel 12更新(laravel/framework 12.65.0)で残る3件(PKSA-3r5d-mb8f-1qw9・PKSA-mdq4-51ck-6kdq・PKSA-m5cs-t1y6-qpcs、いずれもLaravel 12.60.0または12.61.1以降で修正)が解消し、baselineは0件になったため、config.audit.ignoreは削除した。abandoned packageは引き続き0件。0件になったのはIssue #216でfruitcake/laravel-corsをLaravel 9内蔵のIlluminate\Http\Middleware\HandleCorsへ置き換えたためであり、Issue #217では未使用のlaravel/sanctumも削除したが、laravel/sanctumはabandoned packageではないため件数には影響していない。Issue #220のLaravel 13更新(laravel/framework 13.24.0)でも引き続きadvisories 0件・abandoned package 0件を確認しており、config.audit.ignoreは追加していない。baseline解消の追跡はIssue #236、詳細はIssue #216のPull Request(#238)・Issue #217のPull Request(#239)・Issue #218のPull Request(#240)・Issue #219のPull Request(#242)・Issue #220のPull Requestを参照。
lib配下にgoogle_client_secretを配置google_client_secretは管理者が必要に応じて渡す
php lib/google_client_export.phpを実行./cache_clear.shを実行(必要に応じて)
Pull Requestの作成・更新、mainへのpush、Dependabotが作成するPull Requestでは、GitHub Actionsがローカルと同じ固定PHP 8.5.9・Composer 2.8.12・MySQL 5.7.35で make check を実行する。make check はLaravel Pintによるフォーマット確認、PHPStan/Larastanによる静的解析、既存テストを実行するため、フォーマット違反または新規の静的解析違反があるとCIは失敗する。make check自体がPHPバージョンをPHP_VERSION === '8.5.9'で機械的に検証するため、ビルド引数の設定誤りがあればCIはここで失敗する。mainにプッシュした場合だけ、テスト結果をGitHub Pagesへアップし、Slackへ通知する。
旧php85-compatジョブ(PHP 8.5系での互換確認専用、Issue #215)は、標準のtestジョブがPHP 8.5.9で実行されるようになったため、Issue #220で完全に重複するものとして削除した。
- mainブランチへ直接コミットしない。Issueごとに専用のbranch / worktreeで作業し、通常のPull Requestを作成する。
src/.envは初回作成後に不要な上書き・再生成をしない。make setupは既存のsrc/.envを上書きしない。- 開発用DBを破壊する操作(
make db-wipe、--volumesを付けたdocker compose down、docker volume rm等)は、明示的な許可なく実行しない。詳細は上記「完全初期化(危険な操作)」節を参照する。 - 通常の検証(フォーマット確認・静的解析・テスト)には、開発環境から分離された
make checkを使う。開発用のcontainer・network・volume・DBには触れない。 - 秘密情報(
.envの実値、APIキー、トークン、SSH鍵等)をコード・ログ・Issue・Pull Requestへ書かない。詳細はdocs/secrets-management.mdを参照する。 - 本番環境(XServer)は現時点でPHP 8.2.30のままであり、Laravel 13はPHP 8.3未満では動作しない。Issue #226が完了するまで、このLaravel 13版を現在の本番へデプロイしてはならない。 デプロイは
v*タグのpushでのみ起動する(.github/workflows/deploy.yaml)。 - AIエージェントとして作業する場合の詳細な安全ルールは
AGENTS.mdを参照する。
| 文書 | 内容 |
|---|---|
AGENTS.md |
AIエージェント向けの作業ルール・安全上の必須事項 |
docs/architecture.md |
継続運用向けの現行アーキテクチャ(責務・エントリーポイント・外部連携の境界) |
docs/domain.md |
コードから読み取れる主要ドメインルール |
docs/current-architecture.md |
Issue #208時点の詳細な実装棚卸し(現状差異・後続Issue候補を含む) |
docs/current-operations.md |
ローカル・CI・本番の運用詳細と確認状況 |
docs/monitoring.md |
GET /health・scheduler heartbeat・外部連携失敗時の確認方法 |
docs/secrets-management.md |
秘密情報・個人情報・ログの管理方針 |
docs/dependency-updates.md |
Dependabotによる依存関係更新の運用方針 |
doc/api/ |
一部APIの詳細仕様 |