crafted by Mize ↗
Open Repository Intelligence Open Repository Intelligence
CodeLens ACTIVE
CodeLens Engine
StatusOnline
Versionv0.4
ModelClaude Sonnet
Latency—
0
GOOD
改善余地があります
mize1978/rewardme
「コメントで変更禁止」と書いてあるコードが本番に生きている時点で、ドキュメントへの信頼よりテストへの投資が急務——ゲームの完成度は高いが、コードベースはまだステージ1の卵状態。
⭐ 2 Stars
·
🍴 0 Forks
·
📝 238 Commits
·
💬 5 Issues
·
🔵 CSS
·
Ruby on Rails 7 (Stimulus.js / Hotwire)
🔍 重要ファイル 11 件を精査 全 421 ファイル中 AI が優先度順に選択
0
✦ 品質
0
🛡 セキュリティ
0
⚙ 保守性
📋 概要

Ruby on Rails 7 + Stimulus.js で構築された育成型タスク管理Webアプリ「RewardMe」。タスク完了によるキャラクター育成・ミニゲーム5種・ガチャ・マイルームなどゲーム要素をフルスクラッチ実装しており、completed_count を唯一のソース・オブ・トゥルースとして派生値をすべて計算で導出する設計が特徴。

🎯 今すぐ直すべき3点
  1. app/javascript/controllers/match_game_controller.js デバッグ用URLパラメータ(?fx=nostar,nozoom 等)を本番コードに残したまま公開している。connect() 内の `const fx = new URLSearchParams(location.search).get('fx')` ブロックを削除し、document.documentElement.dataset.mgFx への書き込みも除去すること。本番ユーザーがURLパラメータでUI挙動を操作できる状態は意図しない副作用を招く。
    ↗
  2. app/javascript/controllers/match_game_controller.js / potion_game_controller.js / flight_game_controller.js / tap_game_controller.js / puzzle_controller.js 各ゲームコントローラーが1ファイルあたり8,000〜24,000文字(読み取り範囲だけで3,000文字超)の巨大クラスになっている。ゲームロジック(物理演算・スコア計算・状態機械)・描画・サーバー通信・UI操作を単一クラスに詰め込んでいるため、バグ追跡と変更が困難。ロジック層(GameEngine)・描画層(Renderer)・通信層(ApiClient)に分割し、Stimulusコントローラーはオーケストレーションのみに絞ること。
    ↗
  3. app/javascript/controllers/puzzle_controller.js selectPuzzle() の fetch エラーハンドリングが `catch { /* silent */ }` で完全に握り潰されている。ネットワークエラー・CSRF失敗・サーバーエラーがユーザーに一切通知されず、パズル選択が失敗したまま進行する。catch ブロックでエラーメッセージをUIに表示し、少なくとも console.error でログを残すこと。
    ↗
🔍 検出された問題 (7件)
🟧 Warning 📄 app/javascript/controllers/match_game_controller.js
本番コードにデバッグ用URLパラメータ制御が残存
match_game_controller.js の connect() に `?fx=nostar,nozoom,noshadow,noorn` を解釈してdocument.documentElement.dataset.mgFxを書き換えるコードが残っている。コメントに「原因が確定したら削除する」とあるが未削除のまま本番公開されており、悪意あるユーザーがURLパラメータでUI挙動を意図的に変更できる状態にある。
🟧 Warning 📄 app/javascript/controllers/match_game_controller.js
ゲームコントローラーの責務過多(巨大クラス)
match_game_controller.js(24,289文字)・potion_game_controller.js(22,552文字)・flight_game_controller.js(13,900文字)がそれぞれ物理演算・状態管理・描画・サーバー通信・UI操作をすべて単一クラスに実装している。変更箇所の特定が困難で、バグ修正時の影響範囲が予測できない。
🟧 Warning 📄 app/javascript/controllers/puzzle_controller.js
fetch エラーの完全な握り潰し
puzzle_controller.js の selectPuzzle() が `catch { /* silent */ }` でネットワークエラー・HTTPエラーを無視している。パズル選択失敗がユーザーに通知されないため、誤った状態でゲームが進行しコイン付与等のサーバー側処理と不整合が生じる危険がある。
🟧 Warning 📄 app/models/user.rb
app/models/user.rb のインデント不統一
user.rb において create_guest! / cleanup_guests! は2スペースインデントで定義されているが、badge / ribbon_level 以降のメソッド群はインデントなし(0スペース)で定義されている。Rubyの動作には影響しないが、RuboCopが警告を出す状態であり、コードの可読性と一貫性を損なっている。
🟨 Suggestion 📄 app/models/user.rb
ribbon_exp / next_stage_tasks の境界値ハードコード重複
user.rb の ribbon_stage(10/20/40)・ribbon_exp・ribbon_exp_percent・next_stage_tasks の各メソッドで同じ閾値(10, 20, 40)がcase/when・計算式に重複して直書きされている。閾値を定数(STAGE_THRESHOLDS = [10, 20, 40])として抽出しないと、ゲームバランス変更時に複数箇所の修正漏れが発生する。
🟨 Suggestion 📄 app/javascript/controllers/ribbon_controller.js
ribbon_controller.js のセリフデータがコントローラーに直書き
ribbon_controller.js の ROOM_MESSAGES・SPECIAL_COMBOS が7,251文字のファイルのうち大半を占めるセリフデータとしてJavaScriptに直書きされている。セリフの追加・修正のたびにJSファイルを変更・デプロイする必要があり、非エンジニアによるコンテンツ管理が不可能な構造になっている。
🟨 Suggestion 📄 app/javascript/controllers/flight_game_controller.js
flight_game_controller.js の物理定数に「変更禁止」コメント
flight_game_controller.js で GRAV / LIFT / MAXV 等の物理定数に「移植・変更禁止」コメントが付与されている。意図は理解できるが、コメントによる制約はコードレビューなしでは強制できない。プロトタイプの値をテストで固定(スナップショットテスト等)し、変更を検知できる仕組みに置き換えることが望ましい。
✅ 良い点
  • app/models/user.rb の completed_count を唯一の永続値とし、ribbon_stage / ribbon_exp / ribbon_exp_percent / next_stage_tasks をすべて純粋な計算メソッドで導出する設計が優れている。DBスキーマの変更なしにゲームバランスを調整でき、テスト容易性も高い。
  • Dockerfile がマルチステージビルド(builder → runtime)を採用しており、ビルド時のみ必要な SECRET_KEY_BASE=dummy をランタイムイメージに含めない構成になっている。本番イメージへのシークレット漏洩リスクを構造的に排除している点が評価できる。
  • app/javascript/controllers/match_game_controller.js の定数 T(swap/revert/clear/fall/settle)と状態機械 S(idle/swapping/resolving)を冒頭に集約し、アニメーション時間と入力受付制御を一元管理している。以前の「各所に直書き」状態からの改善であり、タイミング調整のコスト削減に直結している。

作り切ることが第一歩。改善を続けることがエンジニアリング。

🔧 リファクタ提案
  • app/models/user.rb の ribbon_stage 閾値(10, 20, 40)を STAGE_THRESHOLDS = [10, 20, 40].freeze として定数化し、ribbon_exp / ribbon_exp_percent / next_stage_tasks の各メソッドがこの定数を参照するよう統一する。
  • match_game_controller.js / potion_game_controller.js 等の巨大Stimulusコントローラーから、ゲームロジック部分を純粋なJavaScriptクラス(例: MatchGameEngine, PotionSolver)として切り出し、Stimulusコントローラーはイベントのブリッジ役に徹する構成に分割する。
  • ribbon_controller.js の ROOM_MESSAGES / SPECIAL_COMBOS を Rails の I18n YAMLまたはJSONファイルに移動し、Railsのビューから data 属性経由でコントローラーに渡す設計にすることで、セリフ管理をJSビルドから切り離す。
🔒 セキュリティ注意点
  • puzzle_controller.js の selectPuzzle() は X-CSRF-Token を正しく付与してPATCHリクエストを送信しており、CSRF対策は機能している。ただし resp.ok チェック後のエラー処理が欠如しているため、サーバー側の認可チェック失敗(401/403)がクライアントに伝達されない点は要確認。
  • app/models/user.rb の create_guest! が SecureRandom.hex(8) でメールアドレスを生成しているため、ゲストアカウントの推測は困難。ただし cleanup_guests! の呼び出し元(定期ジョブ等)が読み取り範囲に含まれておらず、実際に定期削除が動作しているかは evidence_coverage の範囲では確認不能(unknown)。
📤 PRコメント出力

このレビューをGitHub PRコメントとして貼り付けられるMarkdown形式で出力します。