Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions .claude/skills/eccube-asset/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
name: eccube-asset
description: EC-CUBE 4.4 のフロントエンドアセット(SCSS / JS バンドル)をビルド・改修するときの規約。「スタイルを変えて」「CSSを直して」「scssを編集して」「デザインを調整して」「JSを追加して」「アセットをビルドして」などと言われたとき、または html/template 配下の scss・js/bundle.js・webpack.config.js・gulpfile.js・gulp/ を作成・編集するときに使用する。生成物(css / min.css / map / html/bundle)は git 管理されているため、ソースだけコミットすると実機に反映されない。
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
---

# アセットビルド規約(EC-CUBE 4.4)

## 対象

- **ソース**: `html/template/{default,admin,install}/assets/scss/**/*.scss`, `html/template/*/assets/js/bundle.js`
- **ビルド定義**: `gulpfile.js`, `gulp/config.js`, `gulp/build/`, `gulp/task/`, `webpack.config.js`, `package.json`
- **生成物(すべて git 管理下)**: `html/template/*/assets/css/*.css` / `*.min.css` / `*.map`, `html/bundle/`

## 基本ルール

- **生成物は git 管理されている。ソースだけコミットしても実機には反映されない。**
`.scss` を変更したら必ずビルドし、生成された `css/` 配下も同じコミットに含める。
- **`css/` 配下を直接編集しない。** 次のビルドで上書きされて消える。変更は必ず `scss/` 側へ。
- **`.map` も追跡対象**(`style.css.map` 等)。生成物一式をコミットする。
- ビルドは `npm run build`(= gulp の既定タスク)。中身は `series(scss, scss-min, webpack)` で、
1 回で `.css` → `.min.css` → JS バンドルまで通る。個別タスクだけを流して片方だけ更新しない。
- **CI は生成物の鮮度を検査しない。** ソースと生成物の不一致は自動検出されないため、
コミット前に自分で `git status` を確認する(下記「実行・確認方法」)。

### 変換パイプライン(`gulp/task/` の実装)

| タスク | 入力 | 出力 | 処理 |
|---|---|---|---|
| `scss` | `html/template/**/scss/**/*.scss` | 同階層の `css/` へ `*.css` + `*.css.map` | sass → postcss(`postcss-import` / `autoprefixer` / `postcss-sort-media-queries`(mobile-first)) |
| `scss-min` | 同上 | 同階層の `css/` へ `*.min.css` + `*.min.css.map` | 上記 + `gulp-clean-css` |
| `webpack` | `html/template/{default,admin,install}/assets/js/bundle.js` | `html/bundle/{front,admin,install}.bundle.js` + `.map` + `.LICENSE.txt` | webpack(`mode: production`, `devtool: source-map`) |

`postcss-sort-media-queries` が `@media` を **mobile-first 順に並べ替え・統合**する点が重要。
手書きで `css` の末尾に `@media` を足した差分は、この並べ替えを通っていないため一目で判別できる。
レビューで「フルビルドか手書き追記か」を見分けるときはここを見る。

## 実装パターン

### スタイルを変える

```bash
# 1. scss を編集(例: 店頭)
# html/template/default/assets/scss/project/_15.1.cart.scss
# 2. ビルド(Docker 環境。ホストに node がある場合は npm ci && npm run build)
docker compose -f docker-compose.yml -f docker-compose.dev.yml -f docker-compose.nodejs.yml \
run --rm -T nodejs npm ci
docker compose -f docker-compose.yml -f docker-compose.dev.yml -f docker-compose.nodejs.yml \
run --rm -T nodejs npm run build
# 3. 生成物を含めてコミット
git status # scss と css/*.css *.min.css *.map が両方出ていることを確認
```

新しい部分ファイルを足すときは、エントリ(`style.scss` / `app.scss`)の `@import` へ追加する。
エントリから辿れない `.scss` はビルド対象にならない。
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

### JS を足す

エントリは 3 つ(`front` / `admin` / `install`)で、それぞれ `assets/js/bundle.js` が入口。
新しいスクリプトはこの `bundle.js` から `import` / `require` する。`webpack.config.js` の
`entry` を増やすのは、新しい画面区分を作るときだけ。

## よくある間違い

- ❌ `.scss` だけ変更してコミットする → ✅ 生成物(`css/*.css` `*.min.css` `*.map`)も同じコミットに含める。含めないと実機のスタイルが変わらない
- ❌ 反映されないので `css/style.css` を直接編集する → ✅ 次のビルドで消える。`scss/` を直して再ビルドする
- ❌ 「E2E が緑だから生成物は最新」と判断する → ✅ E2E のワークフローは自分で `npm run build` するため、コミット済み生成物が古くても緑になる
- ❌ `scss` タスクだけ流して `.min.css` を古いまま残す → ✅ `npm run build` で `scss` / `scss-min` / `webpack` を通す
- ❌ 生成された `css` に手で `@media` を追記する → ✅ `postcss-sort-media-queries` の並べ替えを通らず、次のビルドで消える
- ❌ 生成物のパーミッション差分(`.css` は 100755 / `.map` は 100644)に気づかずモードだけ変えてコミットする → ✅ `git diff` でモード変更が出たら戻す
- ❌ エントリ(`style.scss` / `app.scss`)へ `@import` せずに部分ファイルだけ追加する → ✅ 辿れない `.scss` はビルドされない
- ❌ ホストとコンテナでビルドを混在させ、sass のバージョン差で無関係な行まで差分が出る → ✅ どちらかに統一する(Docker 推奨)

## 実行・確認方法

```bash
# ビルド(Docker 環境。AGENTS.md「アセットビルド」の手順)
docker compose -f docker-compose.yml -f docker-compose.dev.yml -f docker-compose.nodejs.yml \
run --rm -T nodejs npm ci
docker compose -f docker-compose.yml -f docker-compose.dev.yml -f docker-compose.nodejs.yml \
run --rm -T nodejs npm run build

# 生成物の取りこぼしが無いか(scss を触ったのに css が出ていなければビルド漏れ)
git status --short html/template html/bundle

# モードだけの差分が混ざっていないか
git diff --summary | grep 'mode change' || echo 'モード変更なし'
```

- 生成物に**想定外の広範囲な差分**が出たときは、ホスト / コンテナのビルド環境差か依存更新を疑う。
意図した変更だけが出ているかを `git diff --stat` で確認してからコミットする。
- 実機での確認は `bin/console cache:clear` 後にブラウザのキャッシュを無効化して表示する。
18 changes: 18 additions & 0 deletions .claude/skills/eccube-controller/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: eccube-controller
description: EC-CUBE 4.4 のコントローラを実装・改修するときの責務分離規約。「コントローラを作って」「アクションを追加して」「このコントローラを直して」「ルーティングを追加して」などと言われたとき、または src/Eccube/Controller・app/Customize/Controller 配下を作成・編集するときに使用する。Fat コントローラを避け業務ロジックを Service へ寄せるための規約。

---

# Controller 規約 — 責務分離と Fat 化防止(EC-CUBE 4.4)
Expand Down Expand Up @@ -135,6 +136,23 @@ vendor/bin/php-cs-fixer fix # PSR-12 整形・ライセン
- ❌ `#[Template]` 付きアクションの「エラー時に再描画される」を前提にレビュー判断 → ✅ `#[Template]` は配列を返したときのみ engage。Response/Redirect を返すパス(例: フォーム失敗で `redirectToRoute`)では描画されない
- ❌ 管理アクションを `%eccube_admin_route%` 配下以外に置く → ✅ admin ファイアウォール配下に置く
- ❌ 同一アクションで `executePurchaseFlow()` を複数回呼ぶとき 2 回目以降の `FlowResult` を無視する → ✅ 毎回 `hasError()`/`hasWarning()` の分岐を 1 回目と同じに揃える(共通化可)
- ❌ 配列が来る可能性のあるリクエスト値を `getString()` でスカラーに強制する → ✅ `InputBag` は非スカラーで例外を投げるため強制できない。`all()` で受けて型を検査する

## 実行・確認方法

```bash
# ルーティングが意図どおり登録されたか(#[Route] の属性ミスはここで気づく)
bin/console debug:router | grep <ルート名>
bin/console cache:clear

# 該当コントローラのテストだけを回す
bin/phpunit tests/Eccube/Tests/Web/<対象>ControllerTest.php
```

- 実装後の整形・型・静的解析・テストは **AGENTS.md「開発コマンド」** に従って実行する
(PHP-CS-Fixer / PHPStan level 6 / PHPUnit)。
- 認可の入り口は `security.yaml` だけでは追えない(`access_control` は `EccubeExtension` が動的注入する)。
新規の管理アクションは Skill `eccube-security` の「アクセス制御モデル」を確認する。

---

Expand Down
22 changes: 22 additions & 0 deletions .claude/skills/eccube-entity/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: eccube-entity
description: EC-CUBE 4.4 の Doctrine エンティティを実装・改修するときの規約。「エンティティを作って」「テーブルを追加して」「Entityにフィールドを足して」「リレーションを定義して」「マスタを追加して」などと言われたとき、または src/Eccube/Entity・app/Customize/Entity 配下を作成・編集するときに使用する。

---

# Entity 規約(EC-CUBE 4.4)
Expand Down Expand Up @@ -109,3 +110,24 @@ if (!class_exists(Example::class)) {
- ❌ 金額を float で四則演算(丸め誤差)→ ✅ `bcmath`(`bcadd` / `bcmul` / `bccomp`、スケール 2)で計算する
- ❌ `create_date` / `update_date` を自前の `#[ORM\PrePersist]`(+`#[ORM\HasLifecycleCallbacks]`)でセット → ✅ コアの `SaveEventSubscriber`(グローバル Doctrine prePersist/preUpdate)が `method_exists` で `setCreateDate`/`setUpdateDate`/`setCreator` を自動セットする(`src/Eccube/Doctrine/EventSubscriber/SaveEventSubscriber.php`)。setter さえ生やせばよく、自前 PrePersist は二重実装になるので書かない
- ❌ 他エンティティ(特にコアの `Product`/`Customer` 等、自分で制御できない親)への関連で親削除時の挙動を未決定 → ✅ FK は既定で削除を止める(RESTRICT 相当)。未指定だと**退会・商品削除が FK 違反で失敗**したり孤児化する。`onDelete`(`SET NULL`/`CASCADE`)を指定するか、Service・プラグイン disable 等で後始末する(コアは `onDelete` を限定使用し[95 JoinColumn 中 2 件]、多くは Service 側で関連を整理している)
- ❌ `@deprecated` なゲッタを未使用と判断して削除する → ✅ CSV 出力項目(`dtb_csv`)のアクセサとして現役のことがあり、削除は仕様変更になる。先に CSV 定義と照合する

## 実行・確認方法

```bash
# 属性から導かれるスキーマ差分を SQL で確認(実行前に必ず目視する)
bin/console doctrine:schema:update --dump-sql
bin/console doctrine:schema:update --force

# トレイトで拡張した場合はプロキシを再生成する(忘れると列が生えない)
bin/console eccube:generate:proxies
bin/console cache:clear
```

- 実装後の整形・型・静的解析・テストは **AGENTS.md「開発コマンド」** に従って実行する
(PHP-CS-Fixer / PHPStan level 6 / PHPUnit)。
- カラム追加はマイグレーション不要(`schema:update` が反映する)。要否の判断は Skill `eccube-migration` を参照。

---

実装・改修後は、Skill `eccube-review-responsibility` で責務分離を点検すること。
20 changes: 20 additions & 0 deletions .claude/skills/eccube-formtype/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: eccube-formtype
description: EC-CUBE 4.4 のフォーム(FormType)を実装・改修するときの規約。「フォームを作って」「FormTypeを追加して」「入力項目を足して」「バリデーションを設定して」「検索フォームを作って」「既存フォームに項目を追加して」などと言われたとき、または src/Eccube/Form・app/Customize/Form 配下を作成・編集するときに使用する。

---

# FormType 規約(EC-CUBE 4.4)
Expand Down Expand Up @@ -79,3 +80,22 @@ class ExampleType extends AbstractType
- ❌ 具象クラス依存 → ✅ コンストラクタ DI + 必要なサービスの注入
- ❌ 既存フォームに二重送信防止/楽観ロック用の unmapped hidden を足し、サーバー側で値未送信を即エラー扱い → ✅ 値が空/未送信なら判定をスキップ(プログラム的 POST・既存テスト・外部連携を壊さない後方互換を保つ)
- ❌ 共通 FormType(RepeatedPasswordType 等)を子で使い `options.constraints` を渡す(親が定義した制約が全置換され消える) → ✅ 親の制約一式も再掲して付与する

## 実行・確認方法

```bash
# FormType の構成・オプション・拡張が効いているかを確認する
bin/console debug:form <FormType のクラス名または短縮名>
bin/console cache:clear

# フォームのテストだけを回す
bin/phpunit tests/Eccube/Tests/Form/Type/<対象>TypeTest.php
```

- 実装後の整形・型・静的解析・テストは **AGENTS.md「開発コマンド」** に従って実行する
(PHP-CS-Fixer / PHPStan level 6 / PHPUnit)。
- `FormTypeExtension` で拡張した場合は、`debug:form` の出力に追加項目が現れることで登録を確認できる。

---

実装・改修後は、Skill `eccube-review-responsibility` で責務分離を点検すること。
32 changes: 30 additions & 2 deletions .claude/skills/eccube-migration/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: eccube-migration
description: EC-CUBE 4.4 のデータベースマイグレーションを作成・編集するときの規約。「マイグレーションを作って」「マスタデータ/初期データを投入したい」「カラムの型を変えたい/リネームしたい」「スキーマを変えたい」などと言われたとき、または app/DoctrineMigrations 配下を作成・編集するときに使用する。注意: 単純なカラム追加は Entity 属性+schema:update で反映されるためマイグレーション不要(その判断にも本 Skill を参照)。

---

# マイグレーション規約(EC-CUBE 4.4)
Expand Down Expand Up @@ -32,6 +33,11 @@ bin/console doctrine:migrations:migrate --no-interaction
Entity 属性を足せば、新規は `schema:create`、既存は `schema:update` が拾う。
→ 例: PR #4912(Google アナリティクス機能)は `BaseInfo` にカラムを追加したが、
ALTER マイグレーションは作らず `schema:update` に委ねている。
> **ただし実際のコアには両方の前例がある**。`Version20260316234241` は `dtb_base_info` への
> カラム追加に対して `ALTER TABLE dtb_base_info ADD ...` を書いている。
> つまり「カラム追加にマイグレーションが付いている=規約違反」とは言い切れない。
> レビューで「マイグレーション欠落」「マイグレーション不要」を**断定しない**こと。
> 既定は不要(`schema:update` に委ねる)だが、既存行へ既定値を確実に入れたい等の理由があれば付けてよい。
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- **マイグレーションを書くのは次の場合に限る**:
1. **マスタ/初期データの INSERT**(`mtb_*` のレコード、`dtb_block` / `dtb_mail_template` / `dtb_csv` 等への初期レコード投入)。
2. **`schema:update` が安全に扱えない構造変更**(カラムの**型変更・リネーム**、データ移行を伴う変更、
Expand Down Expand Up @@ -120,10 +126,32 @@ final class Version20240101000000 extends AbstractMigration

## よくある間違い

- ❌ カラムを足したので `ALTER TABLE ... ADD COLUMN` のマイグレーションを書く
→ ✅ Entity 属性を足すだけ。新規は `schema:create`、既存は `schema:update --force` が反映する。
- ❌ カラムを足したので反射的に `ALTER TABLE ... ADD COLUMN` のマイグレーションを書く
→ ✅ 既定は Entity 属性を足すだけ(新規は `schema:create`、既存は `schema:update --force` が反映)。
既存行への既定値投入など理由があれば書いてよい(上記「両方の前例がある」を参照)。
- ❌ `doctrine:migrations:diff` で Entity 差分から ALTER を自動生成する
→ ✅ `doctrine:migrations:generate` で空の雛形を作り、必要な SQL(INSERT・型変更等)だけ手で書く。
- ❌ マイグレーションでテーブルを"新規定義"してスキーマの源泉にする → ✅ 源泉は Entity 属性。
- ❌ INSERT・構造変更でガードなし → 再実行や環境差で失敗。✅ 存在チェックで冪等にする。
- ❌ `down()` 未実装 → ロールバック不能。✅ `up()`/`down()` を対で実装。

## 実行・確認方法

```bash
# 属性から導ける差分(カラム追加・変更)は schema:update 側で反映される
bin/console doctrine:schema:update --dump-sql

# マイグレーション(INSERT・型変更等)を適用し、down() も往復で確かめる
bin/console doctrine:migrations:migrate
bin/console doctrine:migrations:migrate prev
bin/console doctrine:migrations:migrate
```

- 実装後の整形・型・静的解析・テストは **AGENTS.md「開発コマンド」** に従って実行する
(PHP-CS-Fixer / PHPStan level 6 / PHPUnit)。
- 冪等性は「同じマイグレーションを 2 回流しても失敗しない」ことで確認する。
- 新規インストール経路(`doctrine:schema:create` + 初期データ)でも通ることを確認する。

---

実装・改修後は、Skill `eccube-review-responsibility` で責務分離を点検すること。
3 changes: 3 additions & 0 deletions .claude/skills/eccube-purchase-flow/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ description: EC-CUBE 4.4 の受注処理(PurchaseFlow の Processor/Validator
メソッドを実装する**。PurchaseProcessor は `AbstractPurchaseProcessor` を継承すれば必要なメソッドだけ override 可。
- **`supports()` で早期 return**: フロー種別・`Order` か否か・店舗設定(`BaseInfo`)で適用可否を判定し、
対象外なら何もしない(`AddPointProcessor::supports()` が手本)。
- **トランザクション境界はリクエスト全体**: `TransactionListener` が `kernel.request` で `beginTransaction()`、
`kernel.terminate` で `commit()`、例外時に `rollback()` する。Processor 内の `flush()` は SQL を発行するだけで
**コミットではない**ため、在庫引当・採番の可視性や競合を論じるときは「flush 済み=確定」と読み替えないこと。
- **金額計算は `bcmath`**(`bcadd` / `bcsub` / `bcmul` / `bccomp`)。float 演算で組まない。
合計・税・送料・値引きの集計は `PurchaseFlow::calculateAll()` が各段階後に行うので、Processor 側は
**明細(Item)を足し引きする**ことに集中する(合計の手計算は不要)。
Expand Down
Loading
Loading