어드민 진단 세션 관리 목록 페이지 구현

ID: fd5dcd1a-fc2c-4bc6-9e24-aeaceaffa6ef

높음 완료

## 목표
어드민에서 전체 진단 세션을 관리할 수 있는 목록 페이지를 새로 만듭니다.

## 새 파일 생성

### 1. 컨트롤러: `app/controllers/admin/diagnosis_sessions_controller.rb`
기존 `admin/users_controller.rb` 패턴을 따르되:

```ruby
module Admin
class DiagnosisSessionsController < BaseController
PER_PAGE = 50

def index
@sessions = DiagnosisSession.includes(:user, :payment, :workspace_diagnoses, diagnosis_type: [:category, :target])
.where(status: "completed")
.order(created_at: :desc)

# 검색 (사용자 이름/이메일)
if params[:q].present?
q = "%#{params[:q]}%"
@sessions = @sessions.joins(:user).where("users.name ILIKE :q OR users.email_address ILIKE :q", q: q)
end

# 진단 유형 필터
if params[:diagnosis_type_id].present?
@sessions = @sessions.where(diagnosis_type_id: params[:diagnosis_type_id])
end

# 결제 상태 필터
case params[:payment_status]
when "paid"
@sessions = @sessions.where.not(payment_id: nil).joins(:payment).where(payments: { status: "completed" })
when "free"
@sessions = @sessions.where(payment_id: nil)
end

# 정렬
@sort = params[:sort].presence_in(%w[created_at end_time]) || "created_at"
@dir = params[:dir].presence_in(%w[asc desc]) || "desc"
@sessions = @sessions.order(@sort => @dir)

# 페이지네이션
@page = [params[:page].to_i, 1].max
@total_count = @sessions.count
@total_pages = [(@total_count.to_f / PER_PAGE).ceil, 1].max
@page = @total_pages if @page > @total_pages
@sessions = @sessions.offset((@page - 1) * PER_PAGE).limit(PER_PAGE)

@diagnosis_types = DiagnosisType.includes(:category, :target).order(:display_order)
end

def toggle_payment
session = DiagnosisSession.find(params[:id])
if session.report_purchased?
session.update!(payment: nil)
else
payment = Payment.create!(
user: session.user,
order_id: "admin_free_#{session.id}_#{Time.current.to_i}",
amount: 0,
status: "completed",
payment_type: "report",
currency: "KRW",
payment_key: "admin_granted",
approved_at: Time.current
)
session.update!(payment: payment)
end
redirect_to admin_diagnosis_sessions_path(request.query_parameters.except(:action, :controller, :id)), notice: "결제 상태가 변경되었습니다."
end
end
end
```

### 2. 뷰: `app/views/admin/diagnosis_sessions/index.html.erb`
테이블 컬럼:
1. **진단 유형**: `session.diagnosis_type.slug` (category_target 형태)
2. **사용자 이름**: `session.user&.name` (링크 → admin_user_path)
3. **사용자 이메일**: `session.user&.email_address`
4. **Top 5 DNA**: `session.json_data["scored_dna"]` 상위 5개 name을 작은 badge로
- `json_data["scored_dna"]`가 [{key, name, score},...] 배열
- 없으면 `json_data.dig("top_dna")` 확인
5. **완료일**: `session.end_time&.strftime("%Y-%m-%d")`
6. **진단 결과 보기**: 링크 → `"/#{session.locale}/diagnoses/#{session.id}"` (새 탭)
7. **PDF 다운로드**: 링크 → `"/#{session.locale}/diagnoses/#{session.id}/download_pdf"` (새 탭)
8. **결제 상태**: badge + 변경 버튼
- 유료: green badge "유료" + "무료로 변경" 링크
- 무료: gray badge "무료" + "유료로 변경" 링크
- 변경은 PATCH toggle_payment 호출
9. **워크스페이스**: `session.workspace_diagnoses.first&.workspace&.name` (있으면 표시)

상단:
- 검색바 (이름/이메일)
- 진단 유형 필터 (select)
- 결제 상태 필터 (전체/유료/무료)

하단:
- 페이지네이션 (기존 admin 패턴 - `@page`, `@total_pages` 사용)

### 3. 라우트 추가 (`config/routes.rb`)
admin namespace에:
```ruby
resources :diagnosis_sessions, only: %i[index] do
member { patch :toggle_payment }
end
```

## 스타일 참고
- 기존 `admin/users/index.html.erb` 테이블 패턴 따르기
- Tailwind CSS, admin 레이아웃
- `admin_helper.rb`의 `sort_link` 헬퍼 활용

## 주의사항
- workspace_diagnoses에서 workspace 이름 가져올 때 N+1 방지: `includes(:workspace_diagnoses => :workspace)` 또는 lazy load
- user가 nil일 수 있음 (optional: true) - nil 체크 필수
- WorkspaceDiagnosis 모델이 있는지 확인 (`app/models/workspace_diagnosis.rb`)

## 완료 기준
- /admin/diagnosis_sessions 에서 전체 진단 세션 목록 확인 가능
- 검색, 필터링, 페이지네이션 동작
- 결제 상태 토글 동작
- 워크스페이스 이름 표시

첨부 이미지

이미지 추가 (Ctrl+V로 붙여넣기 또는 클릭)

JPEG, PNG, GIF, WebP / 최대 10MB

담당자: admin-diagnosis-dev
생성일: 2026년 02월 27일 15:15

활동 로그

  • 팀리드 상태 변경: 리뷰 → 완료

    2026년 02월 27일 15:23:54

  • 팀리드 상태 변경: 할 일 → 리뷰

    2026년 02월 27일 15:23:41