Skip to content

feat: #103 /gradesページに最高ランク表示を追加#113

Merged
Neon-straySheep merged 3 commits intodevelopfrom
feature/issue-103-highest-rank-display
Feb 21, 2026
Merged

feat: #103 /gradesページに最高ランク表示を追加#113
Neon-straySheep merged 3 commits intodevelopfrom
feature/issue-103-highest-rank-display

Conversation

@Neon-straySheep
Copy link
Contributor

PR: /gradesページに最高ランク表示を追加 #103

概要

/gradesページの統計カードに「最高ランク」表示を追加しました。
現在の「連続記録」と「修了した問題」の左側に新しい項目として配置されています。

fixes #103

変更内容

バックエンド

新規ファイル

  • backend/app/schemas/grades.py: 成績統計情報のスキーマを定義

    • HighestRank: 最高ランク情報(rank, category, categoryName, rankName, color)
    • GradeStats: 成績統計(consecutiveDays, completedQuests, highestRank)
  • backend/app/services/grades_service.py: 成績・統計情報の計算ロジック

    • カテゴリ色・名称マッピング定数
    • ランク名マッピング(0: "種子" 〜 9: "世界樹")
    • calculate_skill_tree_progress(): スキルツリー進捗率計算
    • get_highest_progress_category(): 最も進捗が高いカテゴリを取得
    • get_completed_quests_count(): 修了クエスト数を取得
    • get_consecutive_days(): 連続記録日数(現在は0を返す)

変更ファイル

  • backend/app/api/endpoints/users.py
    • 新規エンドポイント GET /api/v1/users/me/grade-stats を追加
    • grades_serviceとgradesスキーマをインポート
    • 全体ランク(users.rank)と最も進捗が高いカテゴリを組み合わせて返却

フロントエンド

変更ファイル

  • frontend/src/features/grades/types/index.ts

    • HighestRankインターフェースを追加(rank, category, categoryName, rankName, color)
    • GradeStatshighestRankプロパティを追加
  • frontend/src/features/grades/components/StatusCard.tsx

    • 最高ランク表示セクションを追加(3カラムレイアウト)
    • ランク名マッピング定数を追加(0-9のマッピング)
    • ランク画像サイズ: 180×180ピクセル、背景透過
    • ランク名(種子、苗木、林、森、世界樹など)を表示
  • frontend/src/features/grades/api/mock.ts

    • モックデータにhighestRankを追加(rank: 5, rankName: "林")

実装の特徴

全体ランク方式

要件に従い、現在の実装では全体で一つのrankusers.rank)を使用しています。

  • 表示するランクは全カテゴリ共通のusers.rank
  • カテゴリは最も進捗が高いスキルツリーを選択
  • カテゴリ名ではなく、ランク名(林、森など)を表示

連続記録日数

ログイン履歴機能が未実装のため、現時点では0を返します。将来的な実装が必要です。

UI/UX

表示レイアウト

[最高ランク]  [連続記録]  [修了した問題]

最高ランク表示

  • ランク画像(PNG、背景透過): 180×180ピクセル
  • ランク名: "種子", "苗木", "若木", "巨木", "母樹", "林", "森", "霊樹", "古樹", "世界樹"
  • レスポンシブ対応

テスト

  • バックエンド構文チェック完了
  • フロントエンドビルド成功
  • TypeScriptエラーなし
  • /gradesページで3つの統計カードが表示される
  • ランク画像が背景透過で表示される
  • ランク名(林、森など)が正しく表示される

スクリーンショット

(動作確認後に追加)

チェックリスト

  • コードはコーディング規約に準拠している
  • セキュリティ上の問題がない(機密情報のハードコード等なし)
  • 既存機能への影響を確認済み
  • エラーハンドリングが適切
  • TypeScript型定義が正確
  • レスポンシブデザイン対応

- 新規エンドポイント GET /api/v1/users/me/grade-stats を追加
- 成績統計スキーマ(GradeStats, HighestRank)を実装
- grades_serviceで進捗計算・ランク判定ロジックを実装
- StatusCardに最高ランク表示セクションを追加(3カラムレイアウト)
- ランク名(種子〜世界樹)を表示、画像背景透過対応
- 全体ランク方式(users.rank)を採用、最も進捗が高いカテゴリと組み合わせ

fixes #103
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

このPRは、/gradesページに最高ランク表示機能を追加するものです。ユーザーの全体ランク(users.rank)と最も進捗が高いスキルツリーのカテゴリを組み合わせて、統計カードに最高ランク情報を表示します。

Changes:

  • バックエンドに成績統計APIエンドポイント(GET /api/v1/users/me/grade-stats)を追加
  • 最高ランク計算ロジックをサービス層に実装(カテゴリ別進捗率計算、修了クエスト数取得)
  • フロントエンドの統計カードに最高ランク表示セクションを追加(ランク画像とランク名を表示)

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
backend/app/schemas/grades.py 成績統計情報のPydanticスキーマを定義(HighestRank, GradeStats)
backend/app/services/grades_service.py 成績統計の計算ロジックを実装(進捗率計算、最高カテゴリ取得、クエスト数カウント)
backend/app/api/endpoints/users.py 新規エンドポイント /me/grade-stats を追加
frontend/src/features/grades/types/index.ts TypeScript型定義に HighestRank インターフェースを追加
frontend/src/features/grades/components/StatusCard.tsx 最高ランク表示セクションを追加(3カラムレイアウト)
frontend/src/features/grades/api/mock.ts モックデータに highestRank を追加
Comments suppressed due to low confidence (1)

backend/app/services/grades_service.py:75

  • 関数の戻り値の型アノテーションが正確ではありません。この関数は (カテゴリ名, 進捗率) のタプルを返すとコメントされていますが、実際には文字列のカテゴリ値("web", "ai", など)を返しています。より正確には「(カテゴリ値, 進捗率)」とするべきです。または、より厳密な型安全性のために tuple[SkillCategory, float] を使用することを検討してください。ただし、その場合は SkillCategory.WEB.value のように値に変換する必要があります。
def get_highest_progress_category(db: Session, user_id: int) -> tuple[str, float]:
    """最も進捗が高いカテゴリを取得

    Args:
        db: データベースセッション
        user_id: ユーザーID

    Returns:
        (カテゴリ名, 進捗率) のタプル

Comment on lines +48 to +50
<span className="text-3xl text-[#006400] font-medium ml-3 pb-2">
{displayRankName}
</span>
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

元の要件(Issue #103)では、ランク画像の横にカテゴリ名("Web/App", "AI", など)を表示することが指定されていましたが、現在の実装ではランク名("種子", "苗木", "林", など)を表示しています。

要件との不一致が意図的なものか確認してください。PR説明には「カテゴリ名ではなく、ランク名(林、森など)を表示」と記載されているため、仕様変更の可能性がありますが、Issue との整合性を確認することを推奨します。

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +13
category_name: str # 表示用名称(例: "Web/App")
rank_name: str # ランク名(例: "林", "森", "世界樹")
color: str # 背景色(例: "#55aaff")
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

バックエンドとフロントエンドでフィールド名の命名規則に不一致があります。バックエンドでは snake_case(category_name, rank_name)を使用していますが、フロントエンド(frontend/src/features/grades/types/index.ts)では camelCase(categoryName, rankName)を期待しています。このままでは API レスポンスをフロントエンドが正しく処理できません。

解決方法として、Pydantic の ConfigDict で alias_generator を設定し、自動的に camelCase に変換するか、フィールドに個別に alias を設定してください。

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +21
consecutive_days: int # 連続記録日数
completed_quests: int # 修了したクエスト数
highest_rank: HighestRank # 最高ランク情報
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

バックエンドとフロントエンドでフィールド名の命名規則に不一致があります。バックエンドでは snake_case(consecutive_days, completed_quests, highest_rank)を使用していますが、フロントエンド(frontend/src/features/grades/types/index.ts)では camelCase(consecutiveDays, completedQuests, highestRank)を期待しています。このままでは API レスポンスをフロントエンドが正しく処理できません。

解決方法として、Pydantic の ConfigDict で alias_generator を設定し、自動的に camelCase に変換するか、フィールドに個別に alias を設定してください。

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +30

console.log('Grade Stats:', stats); // デバッグ用
console.log('Display Rank Name:', displayRankName); // デバッグ用
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

デバッグ用の console.log が本番コードに残っています。これらは開発時のみ有効にするか、削除してください。本番環境では不要なログ出力はパフォーマンスに影響を与える可能性があります。

Suggested change
console.log('Grade Stats:', stats); // デバッグ用
console.log('Display Rank Name:', displayRankName); // デバッグ用

Copilot uses AI. Check for mistakes.

export const StatusCard: React.FC<StatusCardProps> = ({ stats }) => {
// ランク名を取得(rankNameがあればそれを使用、なければrankから取得)
const displayRankName = stats.highestRank.rankName || RANK_NAMES[stats.highestRank.rank] || "種子";
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rankName が提供されない場合のフォールバック処理が実装されていますが、stats.highestRank 自体が null または undefined の場合にエラーが発生します。GradeStats インターフェースでは highestRank が必須プロパティとして定義されていますが、API からのレスポンスが期待通りでない場合に備えて、オプショナルチェーン(?.)を使用することを推奨します。

例: const displayRankName = stats.highestRank?.rankName || RANK_NAMES[stats.highestRank?.rank ?? 0] || "種子";

Copilot uses AI. Check for mistakes.
Comment on lines +39 to +47
<div className="relative h-48 w-48 flex items-center justify-center">
<Image
src={`/images/ranks/rank_tree_${stats.highestRank.rank}.png`}
alt={`Rank ${stats.highestRank.rank}`}
width={180}
height={180}
className="object-contain"
/>
</div>
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

元の要件(Issue #103)では、ランク画像の背景にカテゴリ色を表示することが指定されていました(style={{ backgroundColor: categoryColor }})が、現在の実装ではカテゴリ色が使用されていません。要件との不一致が意図的なものか確認してください。

もし意図的な変更であれば問題ありませんが、カテゴリ色の背景を追加する場合は、以下のように実装できます:

<div className="relative h-48 w-48 flex items-center justify-center rounded-lg" 
     style={{ backgroundColor: stats.highestRank.color }}>

Copilot uses AI. Check for mistakes.
- ruff lintエラーF401を修正
- app/services/grades_service.pyから未使用のSkillCategoryインポートを削除
@Neon-straySheep Neon-straySheep merged commit e178ed5 into develop Feb 21, 2026
5 checks passed
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.

/gradesにランク表示を追加する

2 participants