Skip to content

OAuth APIをpjord向けに拡張(全API Doorkeeper対応 + 研修生進捗エンドポイント)#9830

Merged
komagata merged 6 commits intomainfrom
feature/oauth-api-for-pjord
Mar 26, 2026
Merged

OAuth APIをpjord向けに拡張(全API Doorkeeper対応 + 研修生進捗エンドポイント)#9830
komagata merged 6 commits intomainfrom
feature/oauth-api-for-pjord

Conversation

@komagata
Copy link
Copy Markdown
Member

@komagata komagata commented Mar 26, 2026

概要

pjord(AIアシスタント)がbootcampのデータにアクセスできるよう、APIをOAuth (Doorkeeper) 対応に拡張します。

変更内容

1. 全APIエンドポイントをOAuth対応

  • API::BaseControllerdoorkeeper_authorize! を統合
  • OAuthトークンがあればDoorkeeper認証、なければ従来のセッション/JWT認証
  • CSRFトークン検証もOAuth時はスキップ
  • CommentsController / UsersController の重複設定を整理

2. 日報API強化

  • GET /api/reports — レスポンスに description(本文)追加
  • GET /api/reports/:id — 個別日報取得(コメント・プラクティス付き)

3. 企業研修生進捗エンドポイント(新規)

  • GET /api/trainee_progresses — 全研修生の進捗一覧
  • GET /api/trainee_progresses?company_id=123 — 企業別フィルタ
  • GET /api/trainee_progresses?week_start=2026-03-16 — 対象週指定
  • レスポンス: 日報提出日数/5日、プラクティスステータス変化、現在のプラクティス滞留日数、全体進捗率

関連

Summary by CodeRabbit

  • 新機能

    • レポート詳細取得API(show)を追加し、関連ユーザー・プラクティス・コメントを含む詳細レスポンスを提供
    • 研修生の週間進捗を返すAPIを追加(週開始/終了、個別の週次アクティビティ、現行のプラクティス、全体進捗含む)
  • 改善

    • レポートのJSON出力に説明フィールドを追加
    • APIの認証フローを整理し、トークン利用時と通常利用時で適切な認可を適用するよう調整

Masaki Komagata added 2 commits March 24, 2026 18:39
- BaseControllerにDoorkeeper OAuth認証を統合(全APIエンドポイント対応)
- CommentsController/UsersControllerの重複doorkeeper設定を整理
- 日報APIレスポンスにdescription(本文)を追加
- 日報showアクション追加(個別日報+コメント+プラクティス取得)
- 企業研修生進捗エンドポイント追加(GET /api/trainee_progresses)
- week_startパラメータで対象週を指定可(デフォルト: 今週)
- 週次アクティビティ: 日報提出日数/5日、提出日一覧
- プラクティスステータス変化の一覧
- 現在取り組み中プラクティスの滞留日数
- 全体進捗(完了率、完了/必須プラクティス数)
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 26, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 147a9938-8368-4d1e-98db-3bffd1bceb34

📥 Commits

Reviewing files that changed from the base of the PR and between e533ede and 4208602.

📒 Files selected for processing (4)
  • app/controllers/api/trainee_progresses_controller.rb
  • app/views/api/reports/show.json.jbuilder
  • app/views/api/trainee_progresses/index.json.jbuilder
  • config/routes/api.rb
✅ Files skipped from review due to trivial changes (1)
  • app/views/api/reports/show.json.jbuilder
🚧 Files skipped from review as they are similar to previous changes (3)
  • config/routes/api.rb
  • app/controllers/api/trainee_progresses_controller.rb
  • app/views/api/trainee_progresses/index.json.jbuilder

📝 Walkthrough

Walkthrough

API 認可の条件付き統合を BaseController に導入、Comments/Users の認証コールバックを整理。Reports に show アクションと JSON 出力を追加し、TraineeProgresses の週次インデックス API を新設。ルーティングをそれに合わせて更新。

変更内容

Cohort / File(s) Summary
認証・認可一元化
app/controllers/api/base_controller.rb, app/controllers/api/comments_controller.rb, app/controllers/api/users_controller.rb
BaseController が doorkeeper_token の有無で CSRF スキップと doorkeeper_authorize! を条件付け。Comments は doorkeeper_authorize! :write を該当アクションに適用。UsersController から API 認証コールバックを削除。
Reports: show 実装 & JSON 出力
app/controllers/api/reports_controller.rb, app/views/api/reports/_report.json.jbuilder, app/views/api/reports/show.json.jbuilder
show アクション追加(Report.includes(:user, :practices, :checks, comments: :user).find(params[:id]))。Jbuilder に description を追加し、show 用テンプレートで report/checks/user/practices/comments をシリアライズ。
TraineeProgresses: 週次進捗API
app/controllers/api/trainee_progresses_controller.rb, app/views/api/trainee_progresses/index.json.jbuilder
新規コントローラと JSON ビューを追加。@trainees をプリロードし、week_start/week_end を計算、週内のレポート・学習状態変化・current practice・overall progress を生成して返却。
ルーティング
config/routes/api.rb
resources :reportsshow を追加。resources :trainee_progresses, only: %i(index) を追加。

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • ryufuta
  • jun-kondo

🐰✨
トンネル抜けてキーが回ると
レポートのページがひらくよ
週の足跡、コメントの声、
ニンジン抱えて跳ねる朝 — ピョン! 🥕

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive プルリクエストの説明には、変更内容が詳細に記載されている(概要、変更内容の3つの主要セクション)が、テンプレートで要求されている「Issue」「変更確認方法」「Screenshot」セクションが完全には従っていない。 テンプレートの「Issue」番号、「変更確認方法」の具体的なステップ、必要に応じて「Screenshot」を追加することで、より標準化された形式に統一してください。
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed タイトルはプルリクエストの主要な変更内容を明確に表現しており、OAuth API拡張と研修生進捗エンドポイント追加という2つの重要な変更を簡潔に説明している。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/oauth-api-for-pjord

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (3)
app/views/api/trainee_progresses/index.json.jbuilder (2)

67-71: UserCoursePracticeによる追加クエリの発生に注意してください。

UserCoursePracticeは各研修生ごとにインスタンス化され、completed_required_practices.sizerequired_practices.sizecompleted_percentageの呼び出しで個別にDBクエリが発行されます。研修生数が多い場合、パフォーマンスに大きな影響を与える可能性があります。

現時点で大規模なリファクタリングは必要ないかもしれませんが、研修生数が増加した際にはバッチクエリやキャッシュの検討をお勧めします。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/views/api/trainee_progresses/index.json.jbuilder` around lines 67 - 71,
The view is causing N+1 queries by calling UserCoursePractice methods
(completed_required_practices, required_practices, completed_percentage) per
trainee; fix by precomputing or eager-loading the needed data in the controller
and passing simple primitives to the template (e.g., a collection like
user_course_practice_summaries with completed_count, required_count,
completed_percentage for each trainee) or by eager-loading the associations used
by UserCoursePractice so those method calls do not hit the DB; update the
controller that builds user_course_practices and the template to read those
precomputed attributes instead of calling the methods directly.

14-23: learningsへの重複クエリを統合できます。

現在、trainee.learningsに対して2回別々にクエリを発行しています:

  • Lines 14-17: 週次の学習状況取得
  • Lines 20-23: 現在取り組み中のプラクティス取得

これらをRubyで処理することで、クエリ数を削減できます。

♻️ クエリを統合する修正案
-  # 対象週にステータスが変化したlearning
-  week_learnings = trainee.learnings
-                          .where(updated_at: `@week_start.beginning_of_day`..@week_end.end_of_day)
-                          .where.not(status: :unstarted)
-                          .includes(:practice)
-
-  # 現在取り組み中のプラクティスの滞留日数
-  current_learning = trainee.learnings
-                            .where(status: :started)
-                            .order(updated_at: :desc)
-                            .first
+  # learningsを一度取得してフィルタリング
+  all_learnings = trainee.learnings.includes(:practice).to_a
+
+  week_learnings = all_learnings.select do |l|
+    l.updated_at >= `@week_start.beginning_of_day` &&
+    l.updated_at <= `@week_end.end_of_day` &&
+    l.status != 'unstarted'
+  end
+
+  current_learning = all_learnings
+                       .select { |l| l.status == 'started' }
+                       .max_by(&:updated_at)

注意: この最適化はコントローラー側でlearnings: :practiceをプリロードしている前提です。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/views/api/trainee_progresses/index.json.jbuilder` around lines 14 - 23,
Querying trainee.learnings twice is redundant; fetch once into a Ruby array and
derive both results from it: replace the two separate queries with a single load
like all_learnings = trainee.learnings.includes(:practice).where.not(status:
:unstarted).to_a, then compute week_learnings = all_learnings.select { |l|
l.updated_at.between?(`@week_start.beginning_of_day`, `@week_end.end_of_day`) } and
current_learning = all_learnings.select { |l| l.status == "started"
}.max_by(&:updated_at) (or .find / .max_by as appropriate) so no duplicate DB
calls are made while keeping the existing variable names week_learnings and
current_learning.
app/views/api/reports/show.json.jbuilder (1)

13-13: 昇順の明示的な指定は省略可能です。

プロジェクトの慣例として、昇順(ASC)はRailsのデフォルト動作に依存し、明示的な:asc指定を省略することが推奨されています。

♻️ 修正案
-json.comments `@report.comments.order`(created_at: :asc) do |comment|
+json.comments `@report.comments.order`(:created_at) do |comment|

Based on learnings: "In fjordllc/bootcamp, when using ActiveRecord.order to specify ascending order, omit the explicit :asc and rely on Rails' default ASC behavior."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/views/api/reports/show.json.jbuilder` at line 13,
該当行で明示的な昇順指定をしているため冗長です:json.comments `@report.comments.order`(created_at: :asc)
do |comment|。慣例に合わせて明示的な :asc を削除し、@report.comments.order(:created_at) のように
Rails のデフォルト ASC に依存する形に置き換えてください(対象シンボル:@report.comments.order と created_at)。
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/controllers/api/reports_controller.rb`:
- Around line 17-19: showアクションで単純に Report.find を使っているため、show.json.jbuilder
で参照している `@report.user`、@report.practices、@report.comments(および各
comment.user)、@report.checks(および checks.last.user.login_name)に対してN+1が発生します。修正は
show 内の Report.find(params[:id]) を関連をプリロードするように変更し、includes で
user、practices、comments: :user、checks: :user を指定して `@report`
を取得するようにしてください(メソッド名:show、変数:@report、参照箇所:@report.user/@report.practices/@report.comments->comment.user/@report.checks->checks.last.user.login_name
を目安に実装)。

In `@app/controllers/api/trainee_progresses_controller.rb`:
- Around line 5-7: index.json.jbuilder is accessing trainee.reports and
trainee.learnings causing N+1 queries; update the controller where `@trainees` is
built (the User.trainees preload chain that sets `@trainees`) to include :reports
and :learnings in the preload call (in addition to :company, :course,
:avatar_attachment, :active_practices) so those associations are eager-loaded
for the index view, or if concerned about overhead for large trainee sets,
implement a scoped/preloaded query for only the date ranges used by
index.json.jbuilder.
- Around line 10-14: Wrap the Date.parse call for params[:week_start] in a
begin/rescue that catches ArgumentError and Date::Error, and handle invalid
input by returning a 400 Bad Request (render json with an error message) or
falling back to Date.current.beginning_of_week; specifically update the code
that sets `@week_start` (the Date.parse(params[:week_start]) branch) to rescue
those exceptions, use API::BaseController-compatible response handling (e.g.,
render json: { error: "invalid week_start" }, status: :bad_request) or assign
the safe default, and optionally log the invalid params[:week_start] value for
debugging.

In `@app/views/api/trainee_progresses/index.json.jbuilder`:
- Around line 37-40: The json.course block accesses trainee.course.id without
guarding against nil; wrap the course rendering in the same style as company
(e.g., check if trainee.course.present? before the json.course do block) or use
safe navigation (trainee.course&.id / trainee.course&.title) so NoMethodError is
avoided; update the view in index.json.jbuilder around the json.course block to
conditionally render or output nil when trainee.course is absent.
- Around line 56-64: The view accesses current_learning.practice.title without
preloading practice, which can cause N+1 queries; modify the code that builds
current_learning (the query that sets current_learning) to include the
association (use .includes(:practice)) so practice is eager-loaded, mirroring
how week_learnings is already loaded with .includes(:practice).

---

Nitpick comments:
In `@app/views/api/reports/show.json.jbuilder`:
- Line 13: 該当行で明示的な昇順指定をしているため冗長です:json.comments
`@report.comments.order`(created_at: :asc) do |comment|。慣例に合わせて明示的な :asc
を削除し、@report.comments.order(:created_at) のように Rails のデフォルト ASC
に依存する形に置き換えてください(対象シンボル:@report.comments.order と created_at)。

In `@app/views/api/trainee_progresses/index.json.jbuilder`:
- Around line 67-71: The view is causing N+1 queries by calling
UserCoursePractice methods (completed_required_practices, required_practices,
completed_percentage) per trainee; fix by precomputing or eager-loading the
needed data in the controller and passing simple primitives to the template
(e.g., a collection like user_course_practice_summaries with completed_count,
required_count, completed_percentage for each trainee) or by eager-loading the
associations used by UserCoursePractice so those method calls do not hit the DB;
update the controller that builds user_course_practices and the template to read
those precomputed attributes instead of calling the methods directly.
- Around line 14-23: Querying trainee.learnings twice is redundant; fetch once
into a Ruby array and derive both results from it: replace the two separate
queries with a single load like all_learnings =
trainee.learnings.includes(:practice).where.not(status: :unstarted).to_a, then
compute week_learnings = all_learnings.select { |l|
l.updated_at.between?(`@week_start.beginning_of_day`, `@week_end.end_of_day`) } and
current_learning = all_learnings.select { |l| l.status == "started"
}.max_by(&:updated_at) (or .find / .max_by as appropriate) so no duplicate DB
calls are made while keeping the existing variable names week_learnings and
current_learning.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 315e1039-ad96-4bfd-87a3-3c7f8ab6dd73

📥 Commits

Reviewing files that changed from the base of the PR and between 8b9c055 and 38f8329.

📒 Files selected for processing (9)
  • app/controllers/api/base_controller.rb
  • app/controllers/api/comments_controller.rb
  • app/controllers/api/reports_controller.rb
  • app/controllers/api/trainee_progresses_controller.rb
  • app/controllers/api/users_controller.rb
  • app/views/api/reports/_report.json.jbuilder
  • app/views/api/reports/show.json.jbuilder
  • app/views/api/trainee_progresses/index.json.jbuilder
  • config/routes/api.rb
💤 Files with no reviewable changes (2)
  • app/controllers/api/comments_controller.rb
  • app/controllers/api/users_controller.rb

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 26, 2026

🚀 Review App

URL: https://bootcamp-pr-9830-fvlfu45apq-an.a.run.app

Basic認証: fjord / (ステージングと同じ)
PR更新時に自動で再デプロイされます。

- reports#show: includes で user, practices, checks, comments を プリロード(N+1解消)
- trainee_progresses: reports, learnings をpreload(N+1解消)
- trainee_progresses: learningsクエリを統合(Rubyフィルタリングに変更)
- trainee_progresses: Date.parseのエラーハンドリング追加
- trainee_progresses: course nilガード追加
- reports/show: order(:created_at) のasc省略(Rails慣例に準拠)
@komagata
Copy link
Copy Markdown
Member Author

CodeRabbitのレビュー指摘に全て対応しました (e533ede):

  • reports#show N+1: includes(:user, :practices, :checks, comments: :user) でプリロード
  • trainee_progresses N+1: :reports, learnings: :practice をpreloadに追加
  • Date.parseエラーハンドリング: Date::Error, ArgumentError をrescueしてデフォルト値にフォールバック
  • course nilガード: trainee.course.present? で条件分岐
  • learningsクエリ統合: 2回のDBクエリを1回のpreload + Rubyフィルタリングに統合
  • order(:created_at): 明示的な :asc を省略(Rails慣例準拠)
  • current_learning.practice: learnings preloadに :practice を含めて解消

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/controllers/api/trainee_progresses_controller.rb`:
- Around line 4-9: The index action in trainee_progresses_controller.rb
currently returns all trainees without role checks; add an authorization guard
that restricts access to admins or mentors by invoking the same authorization
used in API::ReportsController (e.g., call admin_or_mentor? or
current_user.admin_or_mentor? at the start of the index method), and
return/raise an unauthorized response if the check fails before executing
User.trainees/preload/order/where; ensure the authorization check is applied to
the index method only and mirrors the behavior/response shape used in
API::ReportsController.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b8a0ab14-3ac4-4105-8c63-1381857e7c15

📥 Commits

Reviewing files that changed from the base of the PR and between 38f8329 and e533ede.

📒 Files selected for processing (4)
  • app/controllers/api/reports_controller.rb
  • app/controllers/api/trainee_progresses_controller.rb
  • app/views/api/reports/show.json.jbuilder
  • app/views/api/trainee_progresses/index.json.jbuilder
✅ Files skipped from review due to trivial changes (1)
  • app/views/api/reports/show.json.jbuilder
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/controllers/api/reports_controller.rb
  • app/views/api/trainee_progresses/index.json.jbuilder

@komagata komagata removed the request for review from okuramasafumi March 26, 2026 08:47
showアクション追加により /api/reports/unchecked が
reports#show(id: 'unchecked') として解釈されていた問題を修正。
namespace 'reports' を resources :reports より前に配置することで
unchecked/recents のルートが優先されるようにした。
- ShadowedException: Date::ErrorはArgumentErrorのサブクラスなのでArgumentErrorのみrescue
- StringLiterals: シングルクォートに統一
- FrozenStringLiteralComment追加
- InverseMethods: select+!=をrejectに変更
- Layout修正(インデント等)
- AmbiguousBlockAssociation修正
- Metrics/BlockLength: jbuilderブロックはinline disableで対応
@komagata komagata merged commit a427a95 into main Mar 26, 2026
3 checks passed
@komagata komagata deleted the feature/oauth-api-for-pjord branch March 26, 2026 11:35
@github-actions github-actions bot mentioned this pull request Mar 26, 2026
2 tasks
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.

1 participant