Skip to content

fix: Scratch URL loader migrates to CDK proxy and shows specific error messages#574

Merged
takaokouji merged 4 commits into
developfrom
fix/scratch-url-loader-error-messages
Apr 29, 2026
Merged

fix: Scratch URL loader migrates to CDK proxy and shows specific error messages#574
takaokouji merged 4 commits into
developfrom
fix/scratch-url-loader-error-messages

Conversation

@takaokouji
Copy link
Copy Markdown

Summary

Issue #573 (「Scratchから読み込む」が機能しない) の根本修正。原因は二重バグだった:

  1. proxy バグ: lambda/smalruby-scratch-api-proxy-get-project-info/lambda_function.rbNet::HTTP.get (ボディのみ取得) を使っていて、Scratch API が 404/403 を返しても常に statusCode 200 を返していた
  2. frontend バグ: url-loader-modal.jsx がエラー内容に関わらず固定メッセージ invalidUrlError を表示していた

両方を一本の PR で修正。proxy の機会を活かして既存 SAM スタック (smalruby-infra-prod) を CDK に移行し、stg 環境も新設した。

Changes

1. infra/smalruby-api/ (新規 CDK プロジェクト)

旧 SAM 実装 (smalruby/smalruby-infra リポジトリ) の 4 エンドポイントを TypeScript Lambda + HTTP API v2 で再実装:

Path Method Lambda
/cors-proxy GET smalruby-cors-proxy
/mesh-domain GET smalruby-mesh-zone-get
/scratch-api-proxy/projects/{projectId} GET smalruby-scratch-api-projects
/scratch-api-proxy/translate GET smalruby-scratch-api-translate

主な変更点:

  • REST API v1 → HTTP API v2 (built-in CORS で OPTIONS Lambda 不要に)
  • Ruby 3.3 → Node.js 20 ARM64 (TypeScript) で他 infra と統一
  • scratch-api-proxy/projects のステータスコード透過 バグ修正 (Issue bug: Scratchから読み込むが特定 URL で失敗する報告 (要追加情報) #573 の本丸)
  • mesh-zone-get の secret key を環境変数化 (旧実装はハードコード)
  • stg 環境を新設 (stg.api.smalruby.app)

stg 環境はデプロイ済み (https://stg.api.smalruby.app)。

2. CI + integration tests

3. frontend url-loader 修正

  • src/lib/url-loader.js を新設し、formatLoadErrorfetchProjectInfo を pure function として分離
  • HTTP status に応じた具体的なエラーメッセージを モーダル内に表示:
    • 404 → 「プロジェクトが見つかりません。共有が解除されたか、URLが間違っている可能性があります。」
    • 403 → 「このプロジェクトにはアクセスできません。」
    • 5xx → 「Scratchサーバー側でエラーが発生しました。しばらく経ってから再度お試しください。」
    • TypeError (ネットワーク失敗) → 「ネットワークエラーが発生しました。」
  • proxy 旧仕様 (200 + {code:"NotFound"}) との 後方互換 も実装 (proxy デプロイ前後どちらでも動く)
  • モーダルは送信時にクローズせず、成功時のみクローズ。失敗時は同一インスタンスにエラーを戻す UX に
  • 18 unit tests 追加 (status mapping / fetch flow)
  • ロケール (ja, ja-Hira, en) に新メッセージ追加

4. 環境変数追加

  • SCRATCH_API_PROXY_ENDPOINT を webpack DefinePlugin + ci-cd.yml の build-and-deploy 全 3 ジョブに追加
  • GitHub Actions Variables に登録済み (vars.SCRATCH_API_PROXY_ENDPOINT=https://api.smalruby.app)
  • ローカル開発時は .envhttps://stg.api.smalruby.app に上書き

動作確認

stg curl テスト

$ curl -o /dev/null -w "%{http_code}\n" 'https://stg.api.smalruby.app/scratch-api-proxy/projects/9999999999'
404

Playwright (dev server, stg エンドポイント使用)

  • 不正 URL → モーダル内に invalidUrl メッセージ表示 ✅
  • 存在しないプロジェクト ID (9999999999) → モーダル内に「プロジェクトが見つかりません」表示 ✅
  • 正常プロジェクト (108317385) → モーダル閉じて Stage + Squirrel ロード ✅

Test plan

  • infra/smalruby-api ユニットテスト 23 通過 (lint warning なし)
  • infra/smalruby-api integration テスト 18 通過 (stg)
  • packages/scratch-gui ユニットテスト (url-loader.test.js) 18 通過
  • packages/scratch-gui lint 通過 (zero warnings)
  • Playwright で 3 シナリオ目視確認
  • CI が green になる (この PR で確認)

prod カットオーバー (本 PR のスコープ外)

旧 SAM スタック (smalruby-infra-prod) と CDK 新スタックは 当面共存 する。prod ドメイン api.smalruby.app は SAM が保持。後続作業:

  1. MESH_ZONE_SECRET_KEY を旧 SAM の uXM1VAA6MO39yJ+djz4kbpVGy3Rg1V3Zinfra/smalruby-api/.env.prod に設定
  2. SAM スタックのドメインマッピング解除
  3. cdk deploy --context stage=prod で新スタックを api.smalruby.app に紐付け
  4. SAM スタック decommission

Related

Closes #573
Refs #572 (iOS Safari 対応は別 PR / 別 Issue)

旧 SAM 実装 (smalruby/smalruby-infra) の 4 エンドポイントを CDK プロジェクト
infra/smalruby-api/ に移行し、HTTP API v2 + TypeScript Lambda で再実装した。

- REST API v1 → HTTP API v2 (built-in CORS で OPTIONS Lambda 不要に)
- Ruby 3.3 → Node.js 20 ARM64 (TypeScript) で他 infra と言語統一
- scratch-api-proxy/projects のステータスコード透過バグを修正
  (旧実装は Net::HTTP.get でボディだけ取得 → 常に 200 だった)
- mesh-zone-get の secret key を環境変数化 (旧実装はハードコード)
- stg 環境を新設 (旧実装は prod のみ)
- 23 ユニットテスト追加 (mock fetch)

stg デプロイ完了:
- Custom domain: https://stg.api.smalruby.app
- 検証: 公開済みプロジェクトは 200, 存在しないプロジェクトは 404,
  CORS preflight は 204 + 適切なヘッダー、translate も透過動作

prod カットオーバーは別作業 (旧 SAM スタックのドメイン解放と協調が必要):
1. .env.prod に旧 secret_key を設定 (mesh domain identity を維持)
2. SAM スタック smalruby-infra-prod のドメインマッピング解除
3. cdk deploy --context stage=prod
4. SAM スタック decommission

Refs: #573
- .github/workflows/ci-infra.yml: rubytee-relay と同形式の 3 ジョブを追加
  - smalruby-api-unit-tests (npm test)
  - smalruby-api-cdk-build (build + cdk synth、ダミー env で実行)
  - smalruby-api-security (npm audit)
- jest.config.js: integration test を unit から除外 (.integration.test.ts)
- jest.integration.config.js を追加 (rubytee-relay と同様)
- package.json に test:integration スクリプト追加
- lambda/tests/*.integration.test.ts × 4 を追加 (合計 18 テスト)
  - scratch-api-projects: 200/404/CORS/不許可 origin (Issue #573 デグレ防止)
  - scratch-api-translate: 200/400/特殊文字エンコード/CORS
  - mesh-zone-get: hex domain 形式/決定性/CORS
  - cors-proxy: text 透過/PNG バイナリ/不正スキーム/CORS

stg エンドポイントに対して 18 テスト全パスを確認。
URL ローダーの失敗時、proxy のステータスコードに応じた具体的なエラーを
モーダル内に表示するようにする。Issue #573 の本丸 UX バグ修正。

修正前の挙動:
- proxy が 200/404/403/500 何を返してもアラートで「プロジェクトURLの読み
  込みに失敗しました。」を表示するのみ
- モーダル内のエラー表示は invalidUrl のメッセージで固定 (state.error の
  内容は無視)

修正後の挙動:
- proxy 修正前と修正後の両方に対応 (data.code === 'NotFound' 互換チェック)
- 404 → 「プロジェクトが見つかりません。共有が解除されたか、URLが間違って
  いる可能性があります。」
- 403 → 「このプロジェクトにはアクセスできません。」
- 5xx → 「Scratchサーバー側でエラーが発生しました。しばらく経ってから再度
  お試しください。」
- TypeError (ネットワーク失敗) → 「ネットワークエラーが発生しました。」
- proxy が 200 + project_token なし → 502 扱い
- 不正な URL → 既存の「有効なScratchプロジェクトURL...」メッセージ
- モーダルは送信時にクローズせず、成功時のみクローズ。失敗時はメッセージ
  を表示してリトライさせる

実装上の構造変更:
- src/lib/url-loader.js を新設し、formatLoadError と fetchProjectInfo を
  pure function として分離 (HOC からテスト容易な形に)
- src/lib/url-loader-hoc.jsx は React/Redux 連携の thin wrapper に縮小
- url-loader-modal.jsx の固定 FormattedMessage を動的 error string 表示に
- ロケール (ja, ja-Hira, en) に 4 つの新メッセージ追加
- data-testid="url-loader-error" を追加 (integration test 用)

エンドポイント設定:
- SCRATCH_API_PROXY_ENDPOINT 環境変数を追加
  - デフォルト: https://api.smalruby.app (prod)
  - ローカル開発時は .env で https://stg.api.smalruby.app に上書き
- webpack.config.js の DefinePlugin で注入 (Smalruby マーカー付き)
- .github/workflows/ci-cd.yml の build-and-deploy 3 ジョブ全部に追加
  (vars.SCRATCH_API_PROXY_ENDPOINT)

テスト: src/lib/url-loader.test.js に 18 ユニットテスト追加
- formatLoadError × 8 (404 / 403 / 5xx / TypeError / fallback)
- fetchProjectInfo × 10 (各 status / legacy NotFound / token 欠損 /
  特殊文字エンコード / TypeError 透過)

stg エンドポイントを使った Playwright 動作確認:
- 不正 URL → モーダル内に invalidUrl メッセージ表示 ✓
- 9999999999 (404) → 「プロジェクトが見つかりません」表示 ✓
- 108317385 (正常) → モーダル閉じてプロジェクトロード ✓

Refs: #573
@github-actions
Copy link
Copy Markdown

@takaokouji takaokouji merged commit d1d3ce7 into develop Apr 29, 2026
18 checks passed
@takaokouji takaokouji deleted the fix/scratch-url-loader-error-messages branch April 29, 2026 07:49
github-actions Bot pushed a commit that referenced this pull request Apr 29, 2026
…rl-loader-error-messages

fix: Scratch URL loader migrates to CDK proxy and shows specific error messages
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: Scratchから読み込むが特定 URL で失敗する報告 (要追加情報)

1 participant