コンテンツにスキップ

Development Standards and Tools

本プロジェクトにおける技術標準、コーディング規約、開発ツール、およびワークフローの定義です。

技術標準とツール

  • モノレポ構成: Nx + pnpm によるワークスペース管理
  • バックエンド: Vendure (Node.js/TypeScript)
  • フロントエンド: Vite + React (TypeScript/Tailwind CSS v4)
  • 共通パッケージ: @ritsubi/domain, @ritsubi/utils
  • デプロイ: Cloudflare Workers (Storefront), Cloudflare Workers (Dashboard), Fly.io (Vendure)
  • バージョン管理: mise による Node.js, pnpm 等のツール管理
  • 品質管理: oxlint (高速な広域リンター), ESLint (型依存/React Hooks ルール), knip (未使用依存関係チェック), Semgrep (CI 向け SAST), ShellCheck (shell script lint), vitest (テスト), tsc-files (高速型チェック)

UI テーマ方針

  • Storefront の UI テーマは light theme 固定 とし、ダークテーマは要件外とする。
  • prefers-color-scheme やテーマ切替 provider を使って、Storefront 全体の配色を dark に切り替えない。
  • shared UI 基盤に dark 用スタイル定義が存在しても、Storefront では light 前提の受け入れ・検証を行う。

主要コマンド

  • just dev-full: 開発サーバー起動(一括, CLI / Portless)
  • just build: ビルド(一括)
  • just lint: oxlint と ESLint を順番に実行
  • just lint-fix: oxlint 自動修正
  • just knip: Knip v6 の全体分析(未使用ファイル/依存関係/exports を調査)
  • just knip-gate: Knip の手動 gate(unlisted / unresolved
  • just scan-semgrep-changed origin/develop HEAD: changed JS/TS/PHP(.mjs / .cjs / .mts / .cts 含む)向け Semgrep SAST
  • just scan-shellcheck-changed origin/develop HEAD: changed .sh 向けShellCheck
  • just scan-trivy-fs: Trivy による repo 全体の misconfig / secret scan
  • just scan-trivy-image-vendure: Trivy による Vendure Fly image scan(pre-push と Trivy Vendure Image workflow の共通入口)
  • just env-status <staging|production>: Storefront / Vendure / Fly / Cloudflare の 実行状況を 1 窓口で確認するコマンド。--format json で AI エージェント向けの structured output を返す。
  • just env-status-all: staging / production をまとめて確認し、version / build metadata / health の差分まで出す。
  • just ai-rg <pattern>: tmp / node_modules / build artifact を除外した AI 向け全文検索。
  • just ai-find-agents: repo 管理下の AGENTS.md だけを列挙する。
  • just typecheck: TypeScript 型チェック (全体)
  • just vendure-migrate: データベースマイグレーション

重複 helper の正本

  • HTTP Set-Cookie 抽出は @ritsubi/utilsextractSetCookies / splitCombinedSetCookieHeader を使う。Fetch runtime ごとの getSetCookie() 差分と combined header split を各 app / test / ops script で再実装しない。
  • Node scripts の変更ファイル解決は scripts/lib/git-change-scope.mjs を使う。 --changed-only / --staged / GitHub / Nx の diff range fallback を各 lint guard に複製しない。
  • Vendure service を使う seed / repair / one-shot script は apps/vendure-server/scripts/lib/run-vendure-script.ts を使う。production guard、 port: 0app.close() は wrapper の責務。
  • traceparent の文字列化は @ritsubi/utilsformatTraceparent を使う。 Playwright / browser logger / Worker などの surface ごとに 00-... を手書きしない。
  • 通貨・日時 helper は @ritsubi/utilsformatCurrencyValue / formatVendurePriceValue / formatDateTimeMedium を使う。React Dashboard の utils/common.ts は互換 import の薄い re-export とし、formatter 実装を増やさない。
  • JSON の安定比較は @ritsubi/utilssortJsonValue / stableJsonStringify を使う。dirty 判定・drift hash・snapshot 比較で object key sort を再実装しない。Node .mjs ops script では scripts/lib/stable-json.mjs を使う。
  • Storefront で TanStack Router の location.search object を URLSearchParams に変換する場合は apps/storefront/src/lib/router-search.ts を使う。
  • Playwright E2E の navigation timing 取得は apps/storefront/tests/e2e/helpers/performance-metrics.ts を使う。
  • React Dashboard form の beforeunload guard は packages/plugins/src/standard-extensions/admin-extensions/dashboard/utils/use-dirty-form-state.ts を使う。route blocker 付きの dirty guard は同ファイルの useDirtyNavigationGuard を使う。
  • 再発防止は pnpm run lint:duplicated-helper-implementations で検査する。root の lint:static-checks にも含まれる。

Nx と キャッシュ戦略

本プロジェクトでは、モノレポの依存関係管理とタスク実行の最適化に Nx を使用しています。Nx Cloud(リモートキャッシュ)は使用せず、ローカル環境および GitHub Actions のネイティブキャッシュ(actions/cache)を利用して .nx/cache をプロジェクト間で共有・復元する戦略をとっています。

  • CI でのキャッシュ: ci-pr-develop.yml などで actions/cache を使用するが、pnpm store / .nx/cache は lockfile 共有だけでなく PR / branch ごとの trust boundary でも key を分離する。PR/fork と base branch / deploy 系 workflow で同じ cache key を共有しない。 Playwright browser bundle は公式 CI 手順に合わせて cache せず、 install-playwright-chromium から playwright install --with-deps chromium を実行する。
  • キャッシュの復元方針: broad な restore-keys fallback は原則禁止。exact-match key のみを復元し、closed PR の cache は Cleanup PR Caches workflow で削除する。
  • CI モード: CI 環境では NX_NO_CLOUD=true を設定し、リモートへの接続試行を無効化しています。
  • Storefront Cloudflare target の正本: dev* / build / cloudflare:build / cloudflare:types* / cloudflare:preview / cloudflare:deploy*apps/storefront/project.json の Nx target を正本とし、 local / CI / deploy の全経路で pnpm exec nx run ritsubi-storefront:<target> を通します。
  • Storefront guard の障害方針: 認証ガードは fail-closed を基本にしつつ、予期しない例外は login redirect へ degrade して Worker exception 化を避けます。メンテナンスガードは fail-open を基本にし、意図した redirect 以外の障害は観測して継続します。
  • Cloudflare 設定変更時の認証: local で Cloudflare の設定値やリソースを直接変更する wrangler 操作は、共有 token 注入より wrangler のユーザー認証を正とします。deploy 系 script が利用する CLOUDFLARE_API_TOKEN は自動化用途として扱い、手元の設定変更作業とは分離します。

Nx affected の基準

nx affected を使用し、「変更されたファイルに影響を受けるプロジェクトのみ」を対象に Lint、型チェック、テスト、ビルドを実行します。

  • PR: NX_BASE=origin/<base>, NX_HEAD=${{ github.sha }}
  • develop push(integration gate): NX_BASE=${{ github.event.before }}
  • main / hotfix/* push: NX_BASE=${{ github.event.before }}

主要コマンド例

# 影響を受けるプロジェクトのみ型チェック
pnpm exec nx affected --target=typecheck --base="$NX_BASE" --head="$NX_HEAD"

# 影響を受けるプロジェクトのみテスト(並列実行)
pnpm exec nx affected --target=test --base="$NX_BASE" --head="$NX_HEAD" --parallel=3

# プロジェクトの依存関係を可視化(ブラウザで開く)
pnpm exec nx graph

CI(GitHub Actions)とローカルフックの責務

GitHub Actions Runner(Blacksmith)

本リポジトリの GitHub Actions は GitHub-hosted runner ではなく Blacksmith runner を利用します。

  • 基本タグ: blacksmith-2vcpu-ubuntu-2404(軽いジョブ)
  • 重いジョブ: blacksmith-8vcpu-ubuntu-2404 (Nx の並列実行を活用するためリソースを多めに割り当て)
  • キャッシュ: actions/cache を使う場合でも、.nx/cache / pnpm store は workflow context ごとに scope を分離する。PR / fork 由来 cache を trusted branch / deploy job に再利用させない。Playwright browser bundle は cache 対象にせず、公式 CLI の install path を使う。

CI dependency / cache hardening

  • setup-pnpm-workspace / setup-pnpm-minimal / install-playwright-chromium / restore-nx-cache を、GitHub Actions cache の正本とする。workflow ごとに actions/cache を直書きして trust boundary をばらけさせない。
  • pnpm install は、scripts 実行が不要な workflow では --ignore-scripts を既定とする。特に workflow validation や軽量 PR guard は install-time 実行面を増やさない。
  • lifecycle script を許可する workflow は、build / codegen / DB dry-run など実行理由を説明できるものに限定する。必要性が曖昧なまま ignore-scripts: "false" を追加しない。
  • pull_request_target で untrusted code を checkout して install / build / cache restore しない。pull_request_target は bot metadata 処理など、PR 本文や review 操作に閉じた用途へ限定する。

CI の実行判定 (Nx への委譲)

手動のパスフィルター(dorny/paths-filterなど)は使用せず、どのプロジェクトをテスト・ビルドすべきかの判定はすべて Nx (nx affected) に委ねています。これにより、新しいパッケージを追加した際にも CI の設定ファイルをメンテナンスする必要がありません。

GitHub Actions / custom action の検証手順

.github/workflows/**.github/actions/** を変更した場合は、Nx 管理外の custom GitHub Actions も含めて次の順で確認します。

pnpm run typecheck:gha-actions
pnpm run lint:actions
pnpm run build:gha-actions
  • typecheck:gha-actions.github/actions/*/src/index.ts の正本検査です。 pnpm exec tsc .github/actions/.../src/index.ts のように files を直接渡すと、 root tsconfig.json の扱いと衝突して TS5112 などの手順由来エラーを起こしやすいため使用しません。
  • workflow YAML / action YAML の構文確認や actionlint、custom action dist の再生成確認は .github/actions/validate-workflows を通す CI の共通経路に揃えます。PR 向け workflow へ同じ処理を直書きしません。
  • .github/actions/validate-workflowsignore-scripts: true で install する。workflow lint / typecheck / build に不要な package lifecycle script は実行しない。
  • pnpm run build:gha-actions 後に .github/actions/**/dist が更新された場合は、 source と dist の drift を解消するため、意図した変更として差分を確認します。

ブランチ役割別ゲート(SSOT)

トリガー Workflow / Queue 重さ 役割
PR: feature/* → develop CI (PR -> develop) smoke gate(lint / typecheck / unit / coverage / worker)
merge_group(Mergify queue train) CI (PR -> develop) (merge_group event) full gate(integration / CT / Cloudflare build を追加)
push: develop(直push/マージ後) CI (push develop) post-merge build / typecheck
PR: develop → main(+ hotfix/* → main) CI (PR -> main) + Mergify queue (任意) 出荷判定ゲート。promotion PR は Mergify queue を利用できる
push: main deploy/release workflows 最小 配布・運用

GitHub Merge Queue は使わず、Mergify Merge Queue を採用する。branch protection は ci/required-develop / ci/required-main を正本とし、Mergify はその required checks を満たした PR だけを queue 経由でマージする。

PR smoke / merge queue full の 2 段ゲート設計:

  • PR (pull_request event): lint・typecheck・unit・coverage・dashboard-worker・storefront-smoke のみ必須。 高速(目標 < 12 min)でフィードバックを返す。
  • Merge queue (merge_group event): 上記に加えて integration shards × 2・provider-contract・dashboard-smoke・dashboard-pages-smoke・ storefront-ct × 2・storefront-cloudflare-build を必須化。 evaluate-required-gaterequire-heavy-gate: true で両グループを集約する。

CI (PR -> develop) は Nx affected ベースの incremental gate を基本にする。

Promote MainStaging Smoke Storefront 成功後にのみ動く。staging deploy 完了だけでは main への昇格は進めず、smoke を通った変更だけを promotion candidate とする。

Lighthouse CI は nightly と手動実行を基本にし、通常の push では常時実行しない。

Mergify Queue / Stacks

  • develop が default branch のため、Mergify 設定は develop 上の .mergify.yml を正本とする。
  • develop 向け PR は auto ラベルで Mergify queue に投入する。手動投入したい場合は PR へ @mergifyio queue コメントを使ってよい。
  • main 向け promotion PR は promotion + auto ラベルのときだけ Mergify queue に投入する。
  • Stacked PR は GitHub の head branch 自動削除を前提に、mergify-cli を使って運用する。
python3 -m pip install --user mergify-cli
mergify stack --setup

# feature branch 上で stack を作成 / 更新
mergify stack

「ローカルで落とす」「CIで保証する」

種類 lefthook(ローカル) GitHub Actions(CI)
format ✅(staged のみ)
lint ✅(staged/affected) ✅(affected)
typecheck ✅(affected) ✅(affected)
unit test ✅(affected/push前) ✅(affected)
integration/e2e
build ✅(affected/push前) ✅(affected)
security SAST ✅(CI (PR -> develop) / changed JS/TS/PHP)
shell script lint ✅(CI (PR -> develop) / changed .sh
dependency audit ✅(audit.yml / schedule + workflow_dispatch)
Trivy FS / image 任意実行 ✅(独立 workflow / schedule + PR + push + 手動)

ポイント:

  • lefthook は「即時・機械的・軽量」。pre-commit では staged files が属する project を優先して即時フィードバックを返し、transitive な影響確認は pre-push / CI の nx affected に委譲します。
  • CI は「非同期・網羅的」。ここでも Nx の並列実行を活用し、待ち時間を最小化します。
  • アプリコード向け SAST は CI (PR -> develop)bash scripts/ci/run-semgrep-changed.sh "$NX_BASE" "$NX_HEAD" を実行し、changed JS/TS/PHP(.mjs / .cjs / .mts / .cts 含む)files のみを Semgrep CE で検査します。explicit target では .semgrepignore に頼れないため、test/generated/build 系は runner 側でも除外します。初期導入では ERROR のみ blocker とし、workflow 向け p/ci ルールは別フェーズとします。
  • shell script lint は CI (PR -> develop)bash scripts/ci/run-shellcheck-changed.sh "$NX_BASE" "$NX_HEAD" を実行し、changed .sh のみを ShellCheck で検査します。設定の正本は .shellcheckrc とし、初期導入では style を除外するため severity=info で実行します。

開発ワークフローと Git Hooks

本プロジェクトでは lefthook を使用して、コミットおよびプッシュ時に自動チェックを行っています。Nx と統合することで、高速かつ漏れのない検証を実現しています。

コミット前チェック (pre-commit)

コミットを高速化するため、変更されたファイルとその影響範囲のみを対象にチェックを行います。

  • codegen-smart: Nx の依存関係グラフを利用し、必要なプロジェクトのみ GraphQL Codegen を実行。
  • oxlint / oxfmt: 変更された JS/TS と Markdown/YAML の静的解析とフォーマット。 docs 系は scripts/lefthook/docs-staged.shoxfmtmarkdownlint-cli2 --fix → Mermaid lint の順に直列実行し、parallel hook が同じ Markdown を同時に書き換えないようにします。
  • typecheck (touched projects): staged の TS/TSX が属する project だけ nx run-many --target=typecheck --projects=<touched-projects> で型チェックします。対象は Nx 管理下の apps/ packages/ tools/ に絞り、依存先への波及確認は pre-push の nx affected に委譲。
  • vendure-data-guards: scripts/hooks/pre-commit-vendure-data-guards.sh により、エンティティやマイグレーションの staged 変更がある場合のみ静的安全チェックを実行。 対象 path は scripts/ci/vendure-data-guard-paths.txt を正本にし、migration timestamp guard は LEFTHOOK_FAST=1 でも skip しません。
  • vendure-dist-guard: scripts/ci/vendure-dist-guard-paths.txt を正本に、Vendure の private dist import が staged 差分へ混入していないかを確認します。

プッシュ前チェック (pre-push)

プッシュ前に、影響を受けるプロジェクト全体の整合性を最終確認します。

  • Nx を正本にする gate: verify-affected のように project graph で安全に絞れるチェックだけを nx affected に載せます。
  • Nx を正本にしない gate: vendure-db-dry-runvendure-image-trivy は workspace 横断入力や Docker build 入力が正本のため、差分 path / build input ベースで判定します。

  • verify-affected: nx affected --target=typecheck --base=<push-base> --head=HEAD を実行し、今から push するコミット範囲で影響を受けるプロジェクトだけを型チェックします。重いテストは CI に委譲します。 docs/***.md / *.csv など文書系差分しかない push では、Nx 起動自体を skip します。

  • vendure-db-dry-run: scripts/ci/vendure-db-dry-run-paths.txt を正本に、Vendure の data-model に影響する path 変更がある場合のみ、使い捨て DB を用いてシード・マイグレーションの安全性をテストします。 対象差分がある場合、migration timestamp guard と vendure-data-guards は DB 接続設定の有無に関係なく必ず実行します。その後の db:reset:dry-runDATABASE_URL 未設定時にローカルの使い捨て PostgreSQL (postgres://vendure:vendure_dev_password@localhost:5433/vendure_dev) を使います。 明示的な接続先を使う場合は VENDURE_DRY_RUN_DATABASE_URL または DATABASE_URL を設定します。 dry-run 本体はデフォルトで localhost / 127.0.0.1 / ::1 以外を拒否します。 dry-run を明示的に迂回する場合だけ SKIP_VENDURE_DB_DRY_RUN=1 を使います。
  • knip: Knip は OOM しやすいため pre-push gate から外し、手動の just knip-gate / just knip で実行します。just knip-gatescripts/ci/knip-workspaces.txt を正本に対象 workspace を逐次実行し、単一 Node process に monorepo 全体の graph を載せないようにします。 必要な場合は RITSUBI_KNIP_NODE_MAX_OLD_SPACE_SIZE_MB で Knip 専用の heap 上限を調整できます。
  • vendure-image-trivy: scripts/hooks/pre-push-trivy-vendure-image.sh により、Vendure image の構成要素 (apps/vendure-server/src/**, apps/vendure-server/scripts/**, apps/vendure-server/static/**, apps/vendure-server/tsconfig*.json, apps/vendure-server/tests/vendure-test-utils/**, packages/config/**, packages/contract/**, packages/domain/**, packages/plugins/**, packages/utils/**, .dockerignore, .npmrc*, patches/**, lockfile, trivy.yaml など)に変更がある push だけ just scan-trivy-image-vendure 相当の image scan を実行します。差分判定の path list は scripts/ci/vendure-image-paths.txt を正本とし、local hook はこの manifest を読み、 CI は scripts/ci/validate-trivy-vendure-image-paths.mjs で workflow の on.pull_request.paths / on.push.paths との一致を検証します。通常の push で毎回 image build は走らせず、出荷 artifact に直結する差分だけを gate します。
  • dashboard-i18n-catalog: scripts/ci/dashboard-i18n-catalog-paths.txt を正本に、Dashboard i18n の source / catalog / compile 出力 / checker が変わった push だけ pnpm run lint:dashboard-i18n-catalog を実行します。無関係な push では skip 理由を出して終了します。
  • docs-strict / changeset-check: scripts/hooks/pre-push-common.shresolve_pre_push_range を使い、他の pre-push gate と同じ PRE_PUSH_BASE..HEAD を比較対象にします。

FAST モード

緊急時などで重い処理をスキップしたい場合は LEFTHOOK_FAST=1 を使用できます。

LEFTHOOK_FAST=1 git push

この場合、以下のジョブがスキップされます。

  • vendure-db-dry-run
  • vendure-image-trivy

Vendure image Trivy gate だけを明示的に外したい場合は SKIP_TRIVY_VENDURE_IMAGE=1 git push を使用します。通常運用では常用せず、 既知の triage 中や CI 側で結果を確認する意図が明確な場合に限ります。


アーキテクチャ層の定義と責務

プロジェクトの長期的なメンテナンス性と AI による理解しやすさを維持するため、以下の層を明確に分離します。

1. 純粋ドメイン層 (packages/domain)

  • 役割: ビジネスの「意味」と「不変条件(Invariants)」を保持する。
  • 制約: 依存関係ゼロ。Node.js, Web, DB, Framework, および Zod などのバリデーションライブラリにも依存しない。
  • 内容: エンティティ(POJO)、値オブジェクト、ドメインサービス。

2. 契約層 (packages/contract)

  • 役割: システム間や境界での「合意(契約)」を定義する。
  • 制約: Zod を中心としたスキーマ定義。I/O の形式を定義し、人間・機械・AI が共通して参照できる「正本」となる。
  • 内容: Zod スキーマ、推論された TypeScript 型、API リクエスト/レスポンス定義。環境変数の共通バリデーション関数・共通型定義もここに集約する(apps 側は薄い env.schema.ts)。
  • generated artifact ルール:
  • packages/contract/generated/*.ts は codegen の tracked 正本として扱う。
  • src/ 配下の *.js / *.d.ts / *.map は build artifact とみなし、tracked 正本にしない。
  • 検査は pnpm run lint:tracked-src-artifacts、掃除は pnpm run clean:src-artifacts を使う。

3. shared config / spec 層 (packages/config)

  • 役割: app 横断で共有する設定まわりの正本を保持する。
  • 内容:
  • src/env.schema.ts: shared env fragment
  • src/defaults.ts: runtime fallback / build defaults
  • src/spec.ts: cross-app shared immutable technical constants
  • 制約:
  • 業務不変条件は置かない(→ packages/domain
  • 境界契約の正本となるスキーマは置かない(→ packages/contract
  • 新規利用では bare import の @ritsubi/config ではなく subpath import を優先する

4. utility 層 (packages/utils)

  • 役割: low-level helper / runtime helper を提供する。
  • 内容: URL helper、Sentry helper、runtime helper、process/build step 判定など。
  • 制約: shared な defaults / spec / 業務定数の正本を持たない。

5. 実装・インフラ層 (packages/plugins, apps/*)

  • 役割: ドメイン知識と契約を使用して、具体的な機能を実装する。
  • 内容: Vendure プラグイン、TypeORM エンティティ、NestJS コントローラー、Storefront の route / page コンポーネント。
  • バリデーション: 境界(API 入力時など)で packages/contract の Zod スキーマを使用して実行時検証を行う。

コーディング規約

Git コミットルール (Conventional Commits + 日本語)

すべてのコミットメッセージは以下の形式で記載してください。 type: 日本語での説明

主要タイプ:

  • feat: 新機能追加
  • fix: バグ修正
  • docs: ドキュメント更新
  • style: コードスタイル修正
  • refactor: リファクタリング
  • test: テスト追加・修正
  • chore: ビルド・補助ツール関連

: feat: 顧客別価格設定プラグインを追加

開発ワークフロー

  • ブランチ戦略: Gitフロー(シンプル版)。詳細は docs/04-project-management/branch-strategy.md 参照。
  • デプロイ: GitHub Actions による自動デプロイ(develop -> staging, main -> production)。
  • Issue 管理: GitHub Issue を使用。完了条件 (DoD) を明確に定義すること。
  • gh issue の本文はファイル/ヒアドキュメントで渡す(バッククォート等のシェル展開を避ける)

    cat <<'EOF' > /tmp/issue.md
    ## 概要
    ここに本文を書く(バッククォートも安全)
    EOF
    gh issue create --title "..." --body-file /tmp/issue.md
    
  • 既存Issueの更新も同様に --body-file を使用する

コード品質とテスト

  • oxlint: 共通設定 .oxlintrc.json を使用。
  • コンポーネントテスト:
  • Storefront: UI 検証の正本は Playwright CT + fixture とする。見た目、interaction、状態差分は E2E mock より先に CT へ寄せる。
  • Storefront screenshot: コンポーネント単体で判断できる見た目は page 全体ではなく locator の toHaveScreenshot() で固定する。ユーザーへ提示する PNG は canonical snapshot path を直接使わず、同じ locator に captureFreshCtScreenshot() を呼び、pnpm -C apps/storefront run test:ct:fresh -- <ct spec> --grep "<test name>" --screenshot <name> で actual browser capture を timestamp 付き fresh 出力にする。actual capture が無い場合は失敗扱いにし、snapshot コピーの fallback は使わない。
  • Vitest + React Testing Library は、純粋関数・hook・小さな UI ロジック・jsdom で閉じる補助検証に使う。
  • Plugins (UI): 管理画面拡張などの UI コンポーネントは引き続き jsdom 環境でテスト可能。
  • インポート規則: CRITICAL: テストの安定性を高め、Element type is invalid エラーを撲滅するため、shadcn コンポーネントは一括インポートを禁止し、個別インポート(例: @/components/shadcn/button)を必須とする。
  • モック手法: Storefront では vi.mock による query hook 直接モックを第一選択にしない。まず fixture / CT support / preview 専用 provider で状態を再現し、直接モックは小さな単体検証に限定する。
  • E2E テスト: Playwright を使用。
  • Storefront: apps/storefront/tests/e2e/
  • Dashboard: apps/vendure-server/tests/dashboard-e2e/
  • data-testid: E2E 安定化のため、主要要素には必ず data-testid を付与すること。文言依存のセレクタは禁止。

UI 開発と shadcn/ui ガイドライン

本プロジェクトのフロントエンド開発では、最新の shadcn/ui と Tailwind CSS v4 を基盤としています。

shadcn/ui 活用の原則

  1. 車輪の再発明を避ける:
  2. Radix UI ベースのコンポーネント(Dialog, Popover, Sheet, Collapsible 等)は、アクセシビリティ(フォーカストラップ、スクロールロック、キーボード操作)を標準で備えています。
  3. これらを useEffect で手動実装(例: overflow: hidden の制御)することは禁止です。
  4. Tailwind CSS v4 への準拠:
  5. スタイルは CSS 変数(--color-primary 等)と data-slot 属性を用いて管理します。
  6. アニメーションは index.css 内の最新の @theme inline 定義を使用してください。
  7. グローバル・プロバイダーの管理:
  8. Toasterapps/storefront/src/layout/root-layout.tsxTooltipProviderapps/storefront/src/providers.tsx に配置します。
  9. 新しいグローバル機能を追加した際は、必ずルートレイアウト・プロバイダーへの配置状況を確認してください。
  10. モノレポ構成の維持:
  11. コンポーネントのソース(primitive)は packages/ui に置き、各アプリ(apps/storefront 等)の components/ui/ で export または必要に応じた wrapper を作成する構成を遵守してください。

ディレクトリ・ファイル管理

ディレクトリ管理ルール

  • ルートディレクトリ直下に一時ファイルやログを直接作成しない。
  • HMR / watch / build / Docker 転送の入力ではない生成物を app/package root 配下へ出さない。
  • 見返す成果物(Playwright / Vitest / Cosmos / coverage / screenshot / report / SMILE export など)は repo root の output/ を使用する。
  • 再生成可能な cache / state / pid / log / auth storage は repo root の tmp/ を使用する。
  • apps/*/tmpapps/*/test-resultsapps/*/coverageapps/*/.wranglerpackages/*/tmppackages/*/coverageplaywright-ct/.cachestatic/email/test-emailsexports/smile などを新しい生成先にしない。境界検査は pnpm run lint:generated-boundaries を使う。

命名安定化ルール

  • repo 管理対象の 文書・補助資料・補助スクリプト は、原則 ASCII の lowercase kebab-case に統一する。
  • README.md, AGENTS.md, SKILL.md, CHANGELOG.md, Dockerfile*, justfile, Makefile などの ecosystem 標準ファイル名は例外として維持する。
  • ソースコードは universal に kebab-case へ寄せず、各ディレクトリの AGENTS.md と framework / runtime 慣例を優先する。たとえば React Dashboard の PascalCase コンポーネント、TypeORM migration の timestamp+snake_case、GitHub Actions の *.yml はローカル規約として扱う。
  • TypeORM migration の timestamp は 13 桁 epoch-ms (Date.now()) を正本とする。 TypeORM/Vendure CLI の公式形式に揃え、pnpm migrate:generate で生成すれば 自動的にこの形式になる。手書きで作る場合も node -e 'console.log(Date.now())' を使い、<13桁>_<snake_case>.ts (Ritsubi 慣行) または <13桁>-<PascalCase>.ts (TypeORM CLI 既定) のどちらかにする。 class 名は <PascalCase><13桁> の形で末尾を timestamp で締める (name プロパティは class 名と完全一致させる)。 既存の 14 桁 YYYYMMDDhhmmss 形式は legacy で、prod DB の migrations テーブルに記録済みのため rename はしない。 scripts/ci/vendure-data-guards.mjs は HEAD に既に存在する 14 桁 file だけを grandfather し、HEAD に存在しない新規 14 桁 migration は fail させる。 新規での 14 桁採用は禁止。軽量検査は pnpm run lint:vendure-migration-timestamps で実行でき、pre-commit / pre-push でも migration 変更時に同じ検査が走る。
  • __screenshots__/ のような snapshot fixture 名、外部識別子(host 名・module 名・font 名・受領 asset 名)を写したファイル名も例外として扱う。 .playwright-cli/ / .playwright-mcp/ / .wrangler/ は tool state なので repo root / app root の正本にはしない。
  • docs/ 直下の新規トップレベルディレクトリ追加は既存 taxonomy を優先し、必要な場合でも docs/documentation-rules.md / docs/index.md / .mkdocs/dev.yml を同時更新する。

ACF スキーマ管理 (WordPress)

  • 正本は apps/wordpress-cms/plugins/ritsubi-ec-plugin/acf-json/ 配下の JSON。
  • 管理画面で直接編集せず、コードベースで更新する。

特定ツールの運用ルール

UI プレビュー運用ルール

  • ルールの正本: /docs/07-frontend/ui-preview-guidelines.md を参照。

VSCode Tasks & Launch

  • ルートのオーケストレーションは justfile を正とし、.vscode/tasks.jsonjust 経由で呼ぶ。
  • VSCode タスク定義はルート .vscode/tasks.json に集約し、アプリ配下には配置しない。
  • アプリ固有コマンドが必要な場合も、ルートタスクから just または pnpm を呼び出す。

Vitest

  • Vitest には Jest の --runInBand を渡さない。単一ファイルを確認する場合は pnpm --dir <app> exec vitest run <test-file> を使う。

依存関係管理 (pnpm catalogs)

  • 可能な限りルートの catalog: に共通化する。
  • catalogs.frontend / catalogs.backend はバージョン競合が発生するツールのみに使用。
  • wrangler は root catalog を正本とし、app ごとの個別 pin を増やさない。
  • wrangler の更新では npm の absolute latest をそのまま追わず、 minimumReleaseAge: 3 days を満たす「採用可能な最新成熟版」を選ぶ。必要性が明確でない限り minimumReleaseAgeExclude に追加しない。
  • overrides は原則使用禁止。

パフォーマンスとメモリ管理 (Storefront & Cloudflare)

Cloudflare Workers (Edge Runtime) のメモリ制限(通常 128MB)および、長時間セッションでのブラウザメモリ肥大化を防止するため、以下の最適化を適用しています。

1. Vite アセット配信 (Client-side)

ブラウザ側では Vite build のハッシュ付き /assets/* を長期キャッシュ前提で配信し、 Cloudflare Workers 側は ASSETS binding と SPA fallback に責務を限定します。

  • apps/storefront/vite.config.ts
  • apps/storefront/worker.js
  • apps/storefront/wrangler.toml

2. TanStack Query キャッシュ制御 (Client-side)

GraphQL 取得結果は queryKey ごとに管理し、古い値は gcTimeinvalidateQueries で制御します。

  • packages/sdk/shop/src/query-client.ts
  • staleTime: 30_000
  • gcTime: 5 * 60_000

3. Sentry サンプリングレート (Server/Client/Edge)

パフォーマンス監視のオーバーヘッドとバッファリングを最小限に抑えます。

  • tracesSampleRate:
  • Production: 0.1 (10%)
  • Development: 1.0 (100%)

4. ルート loader / バルクデータ取得の制限

route loader や Worker request 中に大量のデータをメモリへ読み込む処理は、Worker のメモリ制限超過 (500 Error) を招くため厳禁です。

  • WordPress 取得: 全件取得(バルク取得)を避け、可能な限り個別のクエリまたはページネーションを使用する。
  • MSW: 本番環境ではサーバーサイド MSW が絶対に起動しないようガードを徹底する。