9WAY 2.0.0 - 프로젝트 타임라인

프로젝트 요약

0
백로그
11
할 일
0
진행 중
18
리뷰
167
완료
196
전체

전체 티켓 목록 (196)

완료 보통 팀리드
완료 높음 팀리드
완료 보통 팀리드
완료 높음 팀리드

활동 타임라인 (744)

  • 2026년 06월 10일
  • C
    claude PR4 캠페인 작성·발송(Resend 배치) TDD 구현 완료 — MVP 완성 (커밋 3ccbcf1)
    상세 보기

    ## 변경 사항
    - resend gem 1.3.0 + config/initializers/resend.rb (마케팅 전용, delivery_method 전역 변경 X).
    - email_campaigns 테이블 + EmailCampaign 모델(enum status, deliveries 연관, sendable?). email_deliveries.campaign_id FK 연결(on_delete nullify) + EmailDelivery belongs_to :campaign.
    - app/services/marketing/campaign_sender.rb: eligible_recipients(segment.members → marketing_subscribed & not_suppressed & email 존재) → 100명 배치 → build_email(토큰 렌더 + 레이아웃 + List-Unsubscribe 헤더 + unsubscribe URL) → ResendClient.send_batch → EmailDelivery 생성. 배치 예외 시 해당 수신자 failed(부분 성공). send_test(본인, 로그 미기록).
    - app/services/marketing/resend_client.rb: Resend::Batch.send 래퍼(주입형).
    - app/jobs/marketing/send_campaign_job.rb (Solid Queue): deliver/test 분기.
    - Admin::Marketing::CampaignsController: CRUD + send_test/deliver(Job enqueue, 동기 발송 X), sendable? 가드.
    - ⚠️ 네임스페이스 충돌 해결: Admin::Marketing 내부에서 ::Marketing::SendCampaignJob 으로 최상위 명시.
    - Webhooks::ResendController: 캠페인 카운터(delivered/opened/clicked/bounced/unsubscribed) 최초 전이 시에만 증가.
    - 뷰: campaigns index/_form/new/edit/show(성과 6지표 + 발송 로그). 사이드바 "캠페인". 세그먼트 show "캠페인 만들기" 버튼(PR2 보류분). ko.yml i18n.

    ## 테스트
    - 신규: email_campaign(5), campaign_sender(6: 게이트/배치분할/토큰/부분실패/send_test), campaigns_controller(10: CRUD/enqueue 검증/sent 차단), 웹훅 카운터(1).
    - 전체 스위트 2793 runs, 0 errors. 실패 5건은 전부 기존 vuild 랜딩(본 작업 무관, 커밋 fd65e8b 이후 미갱신).
    - 실제 Resend 호출은 FakeClient 주입 / Job enqueue 단언으로 회피(테스트에서 발송 없음).

    ## 운영 TODO (발송 활성화 전)
    - MARKETING_FROM_EMAIL=marketing@9way.co.kr, RESEND_WEBHOOK_SECRET 를 .env / .kamal/secrets / .env.deploy 에 추가.
    - Resend 대시보드에서 https://9way.co.kr/webhooks/resend 웹훅 등록.

    ## Fast-follow (범위 외)
    - 진단 결과 유형(WAY/DOMAIN) 세그먼트 조건 — 결과 점수 저장 위치 스파이크 후 SegmentQuery + TokenRenderer({{primary_way}}) 추가.

  • C
    claude 상태 변경: 진행 중 → 리뷰
  • C
    claude 상태 변경: 할 일 → 진행 중
  • C
    claude PR3 Resend 발송 기반(웹훅·수신거부·suppression) TDD 구현 완료 (커밋 c23026c)
    상세 보기

    ## 변경 사항
    - 마이그레이션 3종: email_deliveries(campaign_id[FK는 PR4], user, resend_email_id[uniq], status, *_at, open/click_count, error_message), email_suppressions(email_address[uniq], reason, suppressed_at), email_webhook_events(event_id[uniq] 멱등키).
    - 모델: EmailDelivery(mark_delivered!/record_open!/record_click!/mark_bounced!/mark_complained!, PROGRESS 단계 역행 방지), EmailSuppression(normalizes + 멱등 suppress!), EmailWebhookEvent(already_processed?/record!).
    - User: not_suppressed 스코프, unsubscribe_token/find_by_unsubscribe_token(message_verifier).
    - app/services/webhooks/svix_verifier.rb: Svix HMAC-SHA256 직접 검증(svix gem 불필요).
    - app/services/marketing/token_renderer.rb: {{name}}/{{funnel_stage}} 치환 + HTML 이스케이프, 미지원 토큰 원형 유지.
    - Webhooks::ResendController(ActionController::Base 상속 → allow_browser/CSRF/locale 우회, skip_forgery_protection): 서명검증 → 멱등 → 이벤트 처리. bounced→hard_bounce suppression, complained→complaint suppression + email_subscription=false.
    - EmailSubscriptionsController#unsubscribe(allow_unauthenticated_access) + 확인 뷰.
    - 공개 라우트: POST /webhooks/resend, GET /email/unsubscribe.

    ## 설계 결정
    - resend gem + 실제 발송은 PR4로 격리(외부 의존성 최소화). 웹훅 검증은 수동 HMAC.
    - 캠페인 카운터 갱신(delivered_count 등)은 EmailCampaign 생성(PR4) 후 연결.

    ## 테스트
    - 신규 67개: email_delivery(6)/email_suppression(5)/user_funnel 추가(3)/token_renderer(7)/svix_verifier(6, 공식 벡터)/resend_controller(6)/email_subscriptions(2) 등.
    - 웹훅 멱등(같은 svix-id 재전송), 서명 실패 401, complained→unsubscribe 검증.

    ## 운영 TODO (배포 전)
    - RESEND_WEBHOOK_SECRET 를 .env / .kamal/secrets / .env.deploy 에 추가.
    - Resend 대시보드에서 https://9way.co.kr/webhooks/resend 웹훅 등록(이벤트: delivered/opened/clicked/bounced/complained).

    ## 참고
    - 전체 스위트의 vuild 랜딩 테스트 5건 실패는 본 작업과 무관(커밋 fd65e8b가 _timeline/_claude_pro/_faq partial 삭제 후 테스트 미갱신, 증거 확인).

  • C
    claude 상태 변경: 진행 중 → 리뷰
  • C
    claude 상태 변경: 할 일 → 진행 중
  • C
    claude PR2 세그먼트(조건 저장형 동적 세그먼트) TDD 구현 완료 (커밋 f5d7206)
    상세 보기

    ## 변경 사항
    - `app/services/marketing/segment_query.rb`: conditions(jsonb)→User 관계. 화이트리스트(알려진 키만 처리, 나머지 무시) + 전 바인드 파라미터 → SQL 인젝션 차단. 지원: funnel_stages(OR), facts(AND: has_completed/paid_diagnosis, is_applicant/graduate), diagnosis_target, locale, email_subscription, created_after, first_diagnosis_after, days_since_diagnosis_gte, utm_source.
    - `db/migrate/20260610071005_*` + `app/models/marketing_segment.rb`: name(unique), description, conditions(jsonb), cached_count, count_refreshed_at, created_by. `members`(실시간), `refresh_count!`.
    - `app/controllers/admin/marketing/segments_controller.rb`: CRUD + `refresh_count`. strong params로 conditions 구조 허용 + 빈 값 정리(cleaned_conditions).
    - 뷰: index/new/edit/_form(조건 빌더: 퍼널 단계·언어·진단대상 체크박스 + 수신동의/경과일/가입일) / show(실시간 대상 수 + 샘플 20명).
    - `app/helpers/admin/marketing/segments_helper.rb`: 조건 요약 칩 라벨.
    - 사이드바 "세그먼트" + ko.yml i18n.

    ## 테스트
    - 신규: segment_query(11, 인젝션/OR/AND/경계값 포함), marketing_segment(5), segments_controller(8)
    - 회귀: admin+models+services **1530 runs, 0 failures**

    ## 참고
    - "이 세그먼트로 캠페인 만들기" 버튼은 campaigns 라우트(PR4) 생성 후 show에 추가 예정.
    - 결과유형(WAY/DOMAIN) 조건은 스파이크 후 fast-follow(범위 외).

  • C
    claude 상태 변경: 진행 중 → 리뷰
  • C
    claude 상태 변경: 할 일 → 진행 중
  • C
    claude PR1 리드 목록 + 퍼널 스코프 TDD 구현 완료 (커밋 c65dcdf)
    상세 보기

    ## 변경 사항
    - `app/models/user.rb`: 퍼널 스코프/메서드 추가
    - `FUNNEL_STAGES = %i[subscriber free paid applicant graduate]`
    - fact 스코프: `marketing_subscribed`, `with_completed_diagnosis`, `with_paid_diagnosis`, `free_diagnosis_only`, `course_applicants`, `course_graduates`
    - `at_funnel_stage(stage)`: 배지와 동일한 **상호배타 현재 단계** 필터
    - `funnel_stage`(단건) / `self.funnel_stage_map(ids)`(배치, 목록 N+1 방지)
    - `db/migrate/20260610065545_*`: `diagnosis_sessions.is_report_purchased` 부분 인덱스(`where is_report_purchased=true`, `algorithm: :concurrently`). migrate→rollback→migrate 3단계 검증 완료.
    - `config/routes.rb`: `namespace :marketing { resources :leads, only: [:index] }`
    - `app/controllers/admin/marketing/leads_controller.rb`: 검색(이름/이메일/전화)+퍼널 단계 필터+수신동의 필터+수동 페이지네이션. 페이지 단위 `funnel_stage_map`/진단수/last_active 일괄 조회.
    - `app/views/admin/marketing/leads/index.html.erb`: 단계 칩 + 필터바 + 테이블(퍼널 배지/진단수/수신동의)
    - `app/views/admin/shared/_sidebar.html.erb` + `_nav_item.html.erb`(funnel 아이콘) + `config/locales/ko.yml`(admin.nav.leads, admin.marketing.* — ko 전용)
    - `docs/features/admin_lead_management.md`: 전체 기능 계획서

    ## 설계 결정
    - 스코프를 denorm(`first_diagnosis_completed_at`)이 아닌 **실제 세션 기준**으로 산출 → 마케팅 오분류(잘못된 발송) 방지. 픽스처가 콜백을 안 거치는 점도 고려.
    - `NOT IN (subquery)` NULL 함정을 `where.not(user_id: nil)`로 차단.
    - PR1에서는 사이드바에 leads 메뉴만 추가(segments/campaigns 경로는 PR2/PR4에서 생성, 미존재 경로 참조 방지).

    ## 테스트
    - 신규: `test/models/user_funnel_test.rb`(14), `test/controllers/admin/marketing/leads_controller_test.rb`(7)
    - 회귀: `test/controllers/admin` + `test/models` 전체 **902 runs, 0 failures**
    - Tailwind dev 빌드 재실행(새 배지 클래스 반영)

    ## 완료 기준 충족
    어드민 사이드바 "리드 관리"에서 퍼널 단계별 필터·검색·페이지네이션 동작.

  • C
    claude 상태 변경: 진행 중 → 리뷰
  • C
    claude 상태 변경: 할 일 → 진행 중
  • 2026년 04월 15일
  • 팀리드 배포 완료 - feature/big5-report-renewal → main 머지 + kamal deploy
    상세 보기

    ## 배포 정보
    - 배포 시각: 2026-04-15
    - 배포 환경: production (9way.org)
    - 배포 시간: 141.3초
    - 커밋: 635aafe

    ## 포함된 주요 커밋 (이번 배포)
    - `635aafe` feat: implement inline editing for blog post category and status
    - `851b26d` refactor: modernize discount code service, improve UI accessibility
    - `0d9bf3e` refactor: replace applies_to_all with polymorphic apply_scope
    - `612cb57` fix(growth-mindset): remove all hardcoded Korean default fallbacks
    - `d4e82eb` i18n: replace hardcoded Korean in summary card with t() keys
    - `e0d9d53` i18n(growth-mindset): add renewal keys for zh, en, vi locales
    - `2f860a2` i18n: add Big5 report renewal keys for en, zh, vi
    - 외 30+ 커밋 (Big5/Growth Mindset 리포트 리뉴얼, 할인코드 확장, 블로그 인라인 편집)

    ## 변경된 기능
    - **블로그 관리**: 상태/카테고리 인라인 편집 (클릭하여 바로 변경)
    - **할인코드 확장**: apply_scope enum + discount_code_items polymorphic
    - **Big5 리포트**: 전면 리뉴얼 (아코디언, 레이더 차트, 요약 카드)
    - **Growth Mindset 리포트**: 전면 리뉴얼 (디자인 시스템 통일)
    - **i18n**: Big5/Growth Mindset 리포트 다국어 키 추가 (ko, en, zh, vi)

    ## 확인 사항
    - 컨테이너 healthy 확인
    - 96 파일 변경, +6198 / -1113 lines

  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 백로그 → 진행 중
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 백로그 → 진행 중
  • 팀리드 상태 변경: 백로그 → 리뷰
  • 팀리드 상태 변경: 백로그 → 리뷰
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 백로그 → 진행 중
  • 팀리드 기능 계획 수립 - 할인코드 적용 범위 확장
    상세 보기

    ## 기능 개요
    - 할인코드 적용 범위를 Product(report/credit_pack)에서 Expert::Course(교육프로그램) + Study::Course(온라인강좌)까지 확장
    - apply_scope enum (all/report/education/specific) + polymorphic discount_code_items 조인테이블

    ## 분석 결과
    - 영향 범위: 모델 3개, 서비스 4개, 컨트롤러 3개, 뷰 2개, 마이그레이션 2개
    - 기존 패턴: string enum, Result 패턴 (Data.define), Payments::CheckoutService 재사용
    - 핵심: CheckoutService가 이미 discount_amount/discount_code_id 지원 → Expert 연동 간단

    ## 생성된 티켓 (5개)
    1. [할인코드확장 PR1] DB + 모델 (priority: high)
    2. [할인코드확장 PR2] ValidationService (priority: high)
    3. [할인코드확장 PR3] Expert/Study 서비스 (priority: high)
    4. [할인코드확장 PR4] Admin UI (priority: medium)
    5. [할인코드확장 PR5] 결제 UI + 정리 (priority: medium)

    ## 리스크
    - 기존 할인코드 깨짐 → ignored_columns + 기존 테스트 전수 통과로 방어
    - 데이터 이관 → 마이그레이션 트랜잭션 + 롤백 검증

    ## 기술적 결정
    - applies_to_all → apply_scope string enum (프로젝트 컨벤션 일관성)
    - 2단계 제거 패턴 (ignored_columns → 컬럼 삭제)
    - polymorphic 조인테이블로 Product/Expert::Course/Study::Course 통합

  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 2026년 03월 30일
  • 팀리드 크레딧 통합 PR1~PR5 전체 구현 완료
    상세 보기

    ## 수정된 기능
    - 2가지 개인 크레딧(리포트/진단) → 단일 크레딧으로 통합
    - 1크레딧 = 19,800원, 리포트=1.0, 심화진단=0.2, 추천보상=0.2
    - 워크스페이스 선물: 1크레딧 단위, 자기 선물 가능
    - diagnosis_balance 컬럼 DB에서 완전 제거

    ## 변경 규모
    - 39 파일, +187 / -1,030 lines
    - 삭제: DiagnosisCreditPurchaseService, DiagnosisCreditsController, 진단 크레딧 구매 뷰/JS

    ## UX/UI 검토 결과
    - 전체 평가: 기능적 통과, P2/P3 개선사항은 후속 작업
    - 선물 모달 2종 통합, 사이드바 단일 뱃지, 크레딧 대시보드 단일 잔액

    ## 테스트/보안 검증
    - 1635 runs, 13 failures, 8 errors (모두 크레딧 무관 기존 이슈)
    - 크레딧 관련 실패: 0건
    - add!에 lock! 추가 (race condition 방지)
    - BigDecimal 사용으로 부동소수점 오류 방지

    ## 해결된 문제
    - ConfirmationService 테스트가 workspace_id 분기 미반영 → 수정 완료
    - admin 뷰 하드코딩 한국어 → i18n 처리

    ## 남은 이슈
    - blog/posts Dangerous Send (크레딧 무관, 별도 티켓 필요)
    - Payment.diagnosis_credit enum 유지 (기존 레코드 3건 존재)

  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 티켓 클레임 완료
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 백로그 → 완료
  • 팀리드 상태 변경: 백로그 → 완료
  • 팀리드 상태 변경: 백로그 → 완료
  • 팀리드 크레딧 통합 작업 시작 - PR1~PR5 순차 진행
    상세 보기

    ## 작업 계획
    - 목표: 2가지 개인 크레딧(리포트/진단)을 단일 크레딧으로 통합
    - 접근 방식: PR1→PR2→PR3→PR4→PR5 순차 진행 (의존성 체인)

    ## 현재 상태
    - 보드 현황: backlog 9 / todo 11 / in_progress 1 / review 9 / done 158
    - PR1: DB 마이그레이션 (balance decimal 변환)
    - PR2: 모델 통합
    - PR3: 서비스 통합
    - PR4: 컨트롤러/라우트 통합
    - PR5: 뷰/UI/i18n 통합

  • 팀리드 티켓 클레임 완료
  • 팀리드 기능 계획 수립 — 크레딧 시스템 통합
    상세 보기

    ## 기능 개요
    - 2가지 개인 크레딧(리포트/진단)을 단일 크레딧으로 통합
    - 1크레딧 = 19,800원 (세전 18,000원 + VAT 10%)
    - 강점 리포트 = 1.0 크레딧, 심화 진단 = 0.2 크레딧
    - 워크스페이스 → 개인 크레딧 선물 (자기 선물 포함)

    ## 분석 결과
    - 영향 범위: 모델 6개, 서비스 7개, 컨트롤러 5개, 뷰 11개, JS 1개, i18n 4언어
    - 삭제 대상: DiagnosisCreditPurchaseService, DiagnosisCreditsController, 진단 크레딧 구매 뷰/JS

    ## 생성된 티켓 (5개)
    1. [크레딧통합 PR1] DB 마이그레이션 (priority: high)
    2. [크레딧통합 PR2] 모델 통합 (priority: high)
    3. [크레딧통합 PR3] 서비스 통합 (priority: high)
    4. [크레딧통합 PR4] 컨트롤러/라우트 통합 (priority: high)
    5. [크레딧통합 PR5] 뷰/UI/i18n 통합 (priority: medium)

    ## 기술적 결정
    - balance: integer → decimal(10,1) (0.2 단위 차감)
    - diagnosis_balance: 2단계 제거 패턴 (ignored_columns → 별도 마이그레이션)
    - credit_type: 기존 이력 유지, 신규 "unified"
    - DiagnosisType#credit_cost로 진단별 차감량 캡슐화

  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 일괄다운로드 비동기 처리 전체 구현 완료
    상세 보기

    ## 구현 완료된 PR (5개)

    ### PR1: BulkReportDownload 모델 + 마이그레이션
    - `db/migrate/20260330012810_create_bulk_report_downloads.rb`
    - `app/models/bulk_report_download.rb` (enum status, scope expired/active, has_one_attached :file)
    - `test/models/bulk_report_download_test.rb` (17 tests)
    - `test/fixtures/bulk_report_downloads.yml` (5 fixtures)

    ### PR2: BulkReportGenerateJob + CleanupJob
    - `app/jobs/bulk_report_generate_job.rb` (PDF→ZIP→Active Storage, 순차 처리, GC 관리)
    - `app/jobs/bulk_report_cleanup_job.rb` (7일 만료 삭제)
    - `config/recurring.yml` 에 매일 2am cleanup 등록
    - 테스트 9 runs

    ### PR3: BulkReportMailer
    - `app/mailers/bulk_report_mailer.rb` (completed/failed)
    - `app/views/bulk_report_mailer/completed.html.erb`, `failed.html.erb`
    - i18n 4개 언어 (ko, en, zh, vi)
    - 테스트 6 runs

    ### PR4: Controller + Routes 비동기 전환
    - `handle_bulk_download` 동기→비동기 전환 (Job enqueue)
    - `bulk_download_status` (JSON 폴링), `bulk_download_file` (파일 다운로드)
    - 중복 요청 방지
    - 테스트 10 runs

    ### PR5: View + Stimulus 폴링 배너
    - `bulk_download_status_controller.js` (3초 폴링, 상태별 UI)
    - `_bulk_download_banner.html.erb` (progress bar, download button)
    - i18n 4개 언어

    ## 전체 테스트
    - **42 runs, 90 assertions, 0 failures, 0 errors**

  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 티켓 클레임 완료
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 티켓 클레임 완료
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 작업 시작 - 일괄다운로드 PR1 (모델 + 마이그레이션)
    상세 보기

    ## 작업 계획
    - 목표: BulkReportDownload 모델 + 마이그레이션 + 테스트 + fixture
    - 접근 방식: TDD (테스트 먼저 → 구현)

    ## 전체 일괄다운로드 진행 순서
    1. **PR1 (현재)**: 모델 + 마이그레이션
    2. PR2 + PR3 (PR1 완료 후 병렬): Job + Mailer
    3. PR4 (PR2 완료 후): Controller + Routes
    4. PR5 (PR4 완료 후): View + Stimulus

  • 팀리드 티켓 클레임 완료
  • 팀리드 기능 계획 수립 - 워크스페이스 리포트 일괄 다운로드 비동기 ��리
    상세 보기

    ## 기능 개요
    - 일괄 리포트 ��운로드 시 동기 PDF 생성으로 인한 HTTP 타임아웃 해결
    - 백그라운드 Job으로 전환 + 폴링 방식 상태 표시 + 이메일 알림

    ## 분석 결과
    - 영향 범위: members_controller, PdfGenerator, routes, members views, i18n
    - 기존 패턴: AiInsightGenerateJob(폴링), GiftMailer(���메일), Active Storage(4개 모델)
    - Turbo Stream broadcast 미사용 → 폴링 방식 채택

    ## 생성된 티켓 (5개)
    - [PR1] BulkReportDownload 모델 + 마이그레이��� (high)
    - [PR2] BulkReportGenerateJob + CleanupJob (high)
    - [PR3] BulkReportMailer (medium)
    - [PR4] Controller + Routes 비동기 전환 (high)
    - [PR5] View + Stimulus 폴링 배너 UI (high)

    ## 리스크
    - Grover 메모리 → 순차 처리 + 주기적 GC
    - 디스크 누적 → 7일 만료 CleanupJob (매일 2am)
    - 중복 요청 → pending/processing 존재 시 거부

    ## 기술적 결정
    - ActionCable 인프라 없음 → Turbo Stream broadcast 대신 Stimulus 폴링 (3초)
    - Active Storage local disk 사용 (프로덕션 전환 시 S3 검토)

  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 2026년 03월 26일
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 팀 작업 완료 - [리퍼럴 PR5] 뷰/UI
    상세 보기

    ## 수정된 기능
    - 크레딧 현황 페이지: 리포트/진단 2종류 분리 표시, 리퍼럴 현황 N/10
    - 진단 크레딧 구매 페이지: 디자인 개선, 무료 획득 안내
    - 크레딧 부족 안내 partial: 구매/공유 2가지 옵션
    - i18n: 4개 언어 완료

    ## 테스트 결과
    - 14 runs 통과 (credits 6 + diagnosis_credits 8)

    ## 수정 파일
    - 컨트롤러 1개, 헬퍼 1개, 뷰 3개, i18n 4개

  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 위임: developer-1에게 '크레딧 현황 UI + 리퍼럴 대시보드 + 구매 페이지 + 크레딧 부족 안내' 작업 배정
  • 팀리드 티켓 클레임 완료
  • 팀리드 팀 작업 완료 - [리퍼럴 PR4] 진단 크레딧 구매
    상세 보기

    ## 수정된 기능
    - DiagnosisCreditPurchaseService: 3,000원/크레딧, Toss Payments 연동
    - Payment 모델: diagnosis_credit 타입 추가
    - ConfirmationService: 결제 완료 후 자동 크레딧 지급
    - DiagnosisCreditsController: 구매 페이지 + checkout 연동
    - 라우트 추가

    ## 테스트 결과
    - 18 runs 통과 (서비스 12 + 컨트롤러 6)

    ## 기술적 결정
    - 멱등성: metadata.credits_added 플래그로 중복 방지
    - VAT 10% 포함 처리

  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 위임: developer-1에게 '진단 크레딧 구매 서비스 + 컨트롤러 + 라우트' 작업 배정
  • 팀리드 티켓 클레임 완료
  • 팀리드 팀 작업 완료 - [리퍼럴 PR3] 컨트롤러 연동
    상세 보기

    ## 수정된 기능
    - ApplicationController: ref 파라미터 → 쿠키 저장 (30일)
    - DiagnosesController: Big5/성장/행복도 진단 시작 시 크레딧 차감
    - DiagnosisSessionsController: 강점 진단 완료 시 리퍼럴 보상 트리거
    - OAuth/매직링크 가입: 리퍼럴 추적 기록 + 쿠키 삭제
    - 공유 URL: referral_url 헬퍼로 ?ref= 파라미터 자동 추가
    - i18n: 크레딧 부족 메시지 4개 언어

    ## 테스트 결과
    - 22 runs 통과 (신규 10 + 기존 12)

    ## 수정 파일
    - 컨트롤러 5개, 모델 1개, 헬퍼 1개, 뷰 2개, i18n 4개, 테스트 1개

  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 PART2 쌍대비교 전환 구현 완료
    상세 보기

    ## 변경 사항

    ### 컨트롤러 (`diagnosis_sessions_controller.rb`)
    - `PART2_DOMAIN_PAIRS`, `PART2_QUESTIONS_PER_ROUND` 상수 추가
    - `prepare_part2_round_sequence`: 54라운드 사전 생성 (deterministic, session_seed 기반)
    - `next_part2_round`: 시퀀스에서 미응답 페어 반환
    - `setup_part2_state`: total_rounds = 시퀀스 크기
    - `current_round_number`: / 2로 변경

    ### 뷰
    - `_part2_round.html.erb`: 2버튼 + "둘 다 해당 안됨" 버튼
    - `_part2_guide.html.erb`: 미리보기 2개 + "해당없음"

    ### JS (`diagnosis_controller.js`)
    - `skipPart2Round` 메서드 추가
    - 선택자: `[data-part2-choice]`로 구분
    - response_time null 처리 개선

    ### i18n (ko, en, zh, vi)
    - `none_of_above` 키 추가
    - instruction/description 텍스트 변경
    - preview_3 제거

    ### 테스트
    - 기존 테스트 2개→3개로 수정 (pairwise, skip, constants)
    - 진단 관련 54개 테스트 전체 통과

  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 위임: developer-1에게 '컨트롤러 연동: ref 추적 + 크레딧 차감 + 보상 트리거 + 공유 URL' 작업 배정
  • 팀리드 티켓 클레임 완료
  • 팀리드 상태 변경: 할 일 → 진행 중
  • 팀리드 팀 작업 완료 - [리퍼럴 PR2] 비즈니스 로직
    상세 보기

    ## 수정된 기능
    - Referrals::TrackingService: 신규 가입 시 referral_code → Referral(pending) 생성
    - Referrals::RewardService: strength 진단 완료 → referrer diagnosis_balance +1, 월 10개 상한

    ## 테스트 결과
    - 12 runs, 24 assertions, 0 failures

    ## 기술적 결정
    - DiagnosisType 연관관계: `category` (not `diagnosis_category`)
    - 테스트에서 referral_code는 update_column으로 설정 (fixture에 없으므로)

  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 위임: developer-1에게 'Referrals::TrackingService + RewardService TDD 구현' 작업 배정
  • 팀리드 팀 작업 완료 - [리퍼럴 PR1] DB 레이어
    상세 보기

    ## 수정된 기능
    - UserCredit에 diagnosis_balance 컬럼 추가 (진단 크레딧)
    - CreditTransaction에 credit_type 컬럼 추가 (report/diagnosis 구분)
    - User에 referral_code 컬럼 추가 (공유 URL용)
    - Referral 모델 신규 생성 (리퍼럴 추적)

    ## 테스트 결과
    - 57 runs, 103 assertions, 0 failures (관련 테스트)
    - 기존 테스트 영향 없음

    ## 마이그레이션
    - 4개 모두 가역적, rollback 검증 완료

    ## 남은 이슈
    - 기존 유저의 referral_code는 nil (필요 시 별도 마이그레이션으로 채울 수 있음)

  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 위임: developer-1에게 '마이그레이션 + 모델 구현 (TDD)' 작업 배정
  • 팀리드 작업 시작 - [리퍼럴 PR1] DB 레이어
    상세 보기

    ## 작업 계획
    - 목표: 진단 크레딧 + 리퍼럴 보상 시스템의 DB 기반 구축
    - 접근 방식: 마이그레이션 4개 + 모델 변경/생성을 developer-1에게 위임, QA 검증 후 완료

    ## 현재 상태
    - 보드 현황: backlog 8 / todo 11 / in_progress 1 / review 4 / done 147
    - 관련 기존 작업: UserCredit, CreditTransaction 모델 기존 존재

  • 팀리드 티켓 클레임 완료
  • 팀리드 기능 계획 수립 - 공유 리퍼럴 크레딧 시스템
    상세 보기

    ## 기능 개요
    - 카카오톡/링크 공유로 유입된 신규 회원이 강점 진단 완료 시 공유자에게 진단 크레딧 +1 보상
    - 진단 크레딧으로 Big5/성장 마인드셋/행복도 진단 가능 (1크레딧=1검사)
    - 진단 크레딧 개인 구매 가능 (3,000원/개)
    - 리포트 크레딧(기존 18,000원)과 분리 운영

    ## 분석 결과
    - 영향 범위: UserCredit, CreditTransaction, User, DiagnosisSession, 결제 플로우
    - 기존 패턴: ReportPurchaseService, CreditPurchaseService(워크스페이스), share_token 공유

    ## 생성된 티켓
    - [리퍼럴 PR1] DB 레이어 (priority: high)
    - [리퍼럴 PR2] 비즈니스 로직 (priority: high)
    - [리퍼럴 PR3] 컨트롤러 (priority: high)
    - [리퍼럴 PR4] 진단 크레딧 구매 (priority: medium)
    - [리퍼럴 PR5] 뷰/UI (priority: medium)

    ## 핵심 설계 결정
    - UserCredit에 diagnosis_balance 컬럼 추가 (별도 모델 X)
    - Referral 모델 신규 생성 (referrer/referee 추적)
    - 공유 URL에 ?ref=referral_code 파라미터
    - 월 10개 보상 상한, 1인 1추천인

  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 2026년 03월 17일
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 위임: developer-2에게 'EngagementSurveyResponsesController 공개 응답 플로우 구현' 작업 배정
  • 팀리드 위임: developer-1에게 'Workspaces::EngagementSurveysController 구현' 작업 배정
  • 팀리드 작업 시작 - [조직문화 PR3+PR4] 컨트롤러 레이어 (병렬 진행)
    상세 보기

    ## 작업 계획
    - PR3: Workspaces::EngagementSurveysController (관리자 CRUD + 결과)
    - PR4: EngagementSurveyResponsesController (비인증 공개 응답)
    - 접근 방식: developer-1 = PR3, developer-2 = PR4 병렬 진행 (파일 충돌 없음)

  • 팀리드 팀 작업 완료 - [조직문화 PR2] 서비스 레이어
    상세 보기

    ## 수정된 기능
    - CreateService: 설문 생성 + 중복 방지 + title 자동 생성
    - SubmitResponseService: DiagnosisSession 기반 응답 저장 + EngagementCalculator 채점
    - ResultAggregator: 전체/그룹별 집계, 3명 이하 필터링, 몰입 유형 비율, 3요인/9요인 분석, 강약점

    ## 생성 파일
    - `app/services/engagement_surveys/create_service.rb`
    - `app/services/engagement_surveys/submit_response_service.rb`
    - `app/services/engagement_surveys/result_aggregator.rb`
    - `test/services/engagement_surveys/create_service_test.rb`
    - `test/services/engagement_surveys/submit_response_service_test.rb`
    - `test/services/engagement_surveys/result_aggregator_test.rb`

    ## 기술적 결정
    - DiagnosisSession 재사용 (context_type="b2b", scoring_framework="engagement_3factor")
    - 기존 EngagementCalculator + ScoreCalculatorFactory 완전 재사용
    - Data.define Result 패턴 (기존 서비스 패턴 준수)
    - MINIMUM_RESPONSES=3 상수로 3명 이하 필터링

    ## 테스트: 17 runs, 59 assertions, 0 failures

  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 위임: developer-1에게 'EngagementSurveys 서비스 3개 TDD 구현' 작업 배정
  • 팀리드 작업 시작 - [조직문화 PR2] 서비스 레이어
    상세 보기

    ## 작업 계획
    - 목표: 3개 서비스 객체 구현 (CreateService, SubmitResponseService, ResultAggregator)
    - 접근 방식: developer-1이 TDD로 구현

    ## 핵심 로직
    - CreateService: 설문 생성 + 중복 방지
    - SubmitResponseService: DiagnosisSession으로 응답 저장 + EngagementCalculator 채점
    - ResultAggregator: 전체/그룹별 집계, 3명 이하 필터링, 몰입 유형 비율, 3요인/9요인 분석

  • 팀리드 팀 작업 완료 - [조직문화 PR1] DB 레이어
    상세 보기

    ## 수정된 기능
    - WorkspaceEngagementSurvey 모델: 분기별 설문 관리 (draft/active/closed, access_token 자동 생성)
    - DiagnosisSession 확장: workspace_engagement_survey_id, workspace_group_id FK 추가

    ## 생성/수정 파일
    - `db/migrate/20260317080753_create_workspace_engagement_surveys.rb`
    - `db/migrate/20260317080816_add_engagement_survey_to_diagnosis_sessions.rb`
    - `app/models/workspace_engagement_survey.rb`
    - `app/models/diagnosis_session.rb` (연관관계 추가)
    - `app/models/workspace.rb` (has_many :engagement_surveys)
    - `test/fixtures/workspace_engagement_surveys.yml` (3개 fixture)
    - `test/models/workspace_engagement_survey_test.rb` (21 tests)

    ## 테스트 결과
    - 모델 테스트: 508 tests, 0 failures, 0 errors
    - 신규 테스트: 21 tests (유효성, 연관관계, enum, 스코프, access_token)

  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 위임: developer-1에게 'WorkspaceEngagementSurvey 마이그레이션 + 모델 + DiagnosisSession 확장' 작업 배정
  • 팀리드 작업 시작 - [조직문화 PR1] DB 레이어
    상세 보기

    ## 작업 계획
    - 목표: WorkspaceEngagementSurvey 모델 생성 + DiagnosisSession FK 확장
    - 접근 방식: developer-1이 마이그레이션+모델+테스트, 완료 후 QA 검증

    ## 서브 태스크
    1. 마이그레이션 2개 생성 (WorkspaceEngagementSurvey + DiagnosisSession 확장)
    2. 모델 구현 (유효성, 연관관계, 스코프, enum)
    3. fixture + seed 확인
    4. 테스트 작성 및 통과

  • 팀리드 티켓 클레임 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 기능 계획 수립 - 조직문화 진단 (Engagement B2B)
    상세 보기

    ## 기능 개요
    워크스페이스 대시보드에 조직문화(Engagement B2B) 진단 기능 추가. 분기별 설문 생성 → QR/링크로 익명 응답 → 결과 대시보드 집계.

    ## 분석 결과
    - 영향 범위: Workspace, DiagnosisSession, EngagementCalculator, admin/survey_questions
    - 기존 패턴: engagement B2C 플로우, QrCodeHelper, WorkspaceAuthorization
    - 재사용: EngagementCalculator(채점), EngagementResultFormatter(B2B 분기 지원), _engagement_question.html.erb(문항 뷰)

    ## 생성된 티켓 (7개)
    - [PR1] DB: WorkspaceEngagementSurvey + DiagnosisSession 확장 (high)
    - [PR2] 서비스: 생성/응답/집계 (high)
    - [PR3] 컨트롤러: 설문 관리 CRUD + 결과 (high)
    - [PR4] 공개 응답 플로우: 비인증 컨트롤러 (high)
    - [PR5] 뷰: 결과 대시보드 UI (medium)
    - [PR6] 뷰: 공개 응답 UI (medium)
    - [PR7] Admin: B2B 문항 분리 + 네비게이션 (low)

    ## 핵심 설계 결정
    - DiagnosisSession 재사용 (Option A): 기존 EngagementCalculator/ResultFormatter 완전 활용
    - 익명성: user_id는 로그인 시 참고용 기록, 결과 집계에서 미사용
    - 3명 이하 그룹 결과 비공개

    ## 리스크
    - 익명 응답 중복 방지: localStorage 기반 soft 방지
    - 기존 EngagementCalculator는 개인용 → B2B 집계 로직은 ResultAggregator에서 별도 구현

  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 팀 작업 완료 - [함께보기 PR5] 네비게이션 + i18n
    상세 보기

    ## 수정된 기능
    - 사이드바에 "함께 보기" 메뉴 추가 (커리어테크 아래)
    - 하단 탭에 "함께 보기" 메뉴 추가
    - 4개 locale i18n (ko, en, zh, vi)
    - "together" 그룹 아이콘 SVG 추가

    ## 수정 파일
    - `app/views/shared/_sidebar.html.erb`
    - `app/views/shared/_bottom_tabs.html.erb`
    - `app/views/shared/_sidebar_nav_item.html.erb`
    - `app/views/shared/_bottom_tab_item.html.erb`
    - `config/locales/{ko,en,zh,vi}.yml`

    ## QA 검증 결과
    - 테스트: 37/37 통과, Critical/Major 이슈 없음
    - 전 locale 표시, 비로그인 미표시, active 상태 정상
    - 배포 가능 상태

  • 팀리드 상태 변경: 할 일 → 완료
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 위임: developer-1에게 '사이드바 + 하단탭 메뉴 추가 + 4개 locale i18n' 작업 배정
  • 팀리드 작업 시작 - [함께보기 PR5] 네비게이션 + i18n
    상세 보기

    ## 작업 계획
    - 목표: 사이드바 + 하단탭에 "함께 보기" 메뉴 추가, 4개 locale i18n
    - 접근 방식: developer 1명 구현 → QA 검증

    ## 현재 상태
    - PR1~PR4 모두 review 상태
    - PR5 네비게이션: in_progress (마지막 PR)

  • 팀리드 팀 작업 완료 - [함께보기 PR4] 뷰 구현
    상세 보기

    ## 수정된 기능
    - 5개 뷰 완성: index(그룹 목록), show(QR코드/멤버), new(생성 폼), join(참여 확인), team_strength(팀강점 매트릭스)
    - i18n 키 추가 (ko.yml)
    - shared/_input.html.erb 버그 수정

    ## UX/UI 검토 결과
    - P0 border 토큰 수정, P1 반응형/빈 상태 수정, 접근성 aria-label 추가
    - 잔여 Minor (shared/_button Partial 교체, 빈 상태 CTA 개선) → 별도 티켓으로

    ## QA 검증 결과
    - 테스트: 72/72 통과 (219 assertions, 0 failures)
    - 보안: Brakeman 0 warnings, XSS 안전
    - N+1 쿼리: index/show eager loading 수정 완료

    ## QA/UX 피드백 반영
    - N+1 쿼리 3곳 수정 (includes 추가)
    - border-border-default → border-gray-200 통일
    - 시너지 그리드 반응형 처리
    - join 빈 세션 상태 처리 + i18n 키 추가
    - aria-label 접근성 추가 (복사 버튼, DNA 매트릭스)

  • 팀리드 상태 변경: 할 일 → 완료
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 위임: developer-1에게 '함께 보기 전체 뷰 구현 (index, show, new, join, team_strength)' 작업 배정
  • 팀리드 작업 시작 - [함께보기 PR4] 뷰 구현
    상세 보기

    ## 작업 계획
    - 목표: 함께 보기 기능의 전체 뷰 구현 (index, show, new, join, team_strength)
    - 접근 방식: developer 1명 구현 → UX 리뷰어 검토 → QA 검증

    ## 현재 상태
    - PR1 DB: review, PR2 서비스: review, PR3 컨트롤러: review
    - PR4 뷰: in_progress (현재)

  • 팀리드 티켓 클레임 완료
  • 팀리드 팀 작업 완료 - [함께보기 PR3] 컨트롤러 + 라우트
    상세 보기

    ## 수정된 기능
    - ViewGroupsController 8개 액션 (index, show, new, create, destroy, join, process_join, leave, team_strength)
    - 라우팅: locale scope 내 view_groups 리소스 + join/process_join 커스텀 라우트
    - i18n: flash 메시지 17개 키 (ko.yml)

    ## 생성/수정 파일
    - `app/controllers/view_groups_controller.rb` (신규)
    - `config/routes.rb` (수정)
    - `config/locales/ko.yml` (수정)
    - `app/views/view_groups/` — 최소 스텁 뷰 5개 (PR4에서 완성)
    - `test/controllers/view_groups_controller_test.rb` (37개 테스트)

    ## QA 검증 결과
    - 테스트: 37/37 통과, 102 assertions, 0 failures
    - 보안: Brakeman 0 warnings, IDOR 방지 확인
    - Rubocop: 0 offenses (수정 후)
    - Major 이슈 1건(set_view_group return 누락) → guard clause로 수정 완료

    ## QA 피드백 반영
    - set_view_group: guard clause 패턴으로 리팩토링 (DoubleRenderError 방지)
    - Rubocop offense 2건 수정

  • 팀리드 상태 변경: 할 일 → 완료
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 위임: developer-1에게 'ViewGroupsController + 라우트 + 컨트롤러 테스트 구현' 작업 배정
  • 팀리드 작업 시작 - [함께보기 PR3] 컨트롤러 + 라우트
    상세 보기

    ## 작업 계획
    - 목표: ViewGroupsController CRUD, 참여(join), 나가기(leave), 팀강점(team_strength) + 라우팅
    - 접근 방식: developer 1명이 TDD로 컨트롤러 + 라우트 + 테스트 구현, qa-verifier가 검증

    ## 현재 상태
    - PR1 DB 레이어: review
    - PR2 서비스: review
    - PR3 컨트롤러: in_progress (현재)

  • 팀리드 티켓 클레임 완료
  • 팀리드 팀 작업 완료 - [함께보기 PR2] TeamStrengthAnalyzer 서비스
    상세 보기

    ## 수정된 기능
    - ViewGroups::TeamStrengthAnalyzer 서비스 구현 (Workspace 버전과 동일 출력 구조)

    ## 생성 파일
    - `app/services/view_groups/team_strength_analyzer.rb` (신규)
    - `test/services/view_groups/team_strength_analyzer_test.rb` (11개 테스트)

    ## QA 검증 결과
    - 테스트: 11/11 통과, 79 assertions, 0 failures
    - N+1: eager loading 올바르게 적용 (includes :user, diagnosis_session: :diagnosis_type)
    - 보안: Brakeman 경고 0건, 서비스 레벨 cross-group 접근 불가
    - 종합: 리뷰 진행 가능 (Critical/High 이슈 없음)

    ## Minor 이슈 (선택적 개선)
    - `view_group_members.count` 중복 호출 → 캐싱 가능
    - way_scores 합계 0 케이스 테스트 없음 (코드는 방어됨)

  • 팀리드 상태 변경: 할 일 → 완료
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 위임: developer-1에게 'ViewGroups::TeamStrengthAnalyzer 서비스 + 테스트 구현' 작업 배정
  • 팀리드 작업 시작 - [함께보기 PR2] TeamStrengthAnalyzer 서비스
    상세 보기

    ## 작업 계획
    - 목표: 기존 Workspaces::TeamStrengthAnalyzer를 참고하여 ViewGroups 전용 서비스 생성
    - 접근 방식: developer 1명이 TDD로 서비스 + 테스트 구현, qa-verifier가 검증

    ## 현재 상태
    - PR1 DB 레이어 완료 (review 상태)
    - 이번 PR2는 서비스 레이어 구현

  • 팀리드 티켓 클레임 완료
  • 팀리드 팀 작업 완료 - [함께보기 PR1] DB 레이어
    상세 보기

    ## 수정된 기능
    - ViewGroup + ViewGroupMember 모델, 마이그레이션, 테스트, fixtures 구현 완료

    ## 생성/수정 파일
    - `db/migrate/20260317064325_create_view_groups.rb`
    - `db/migrate/20260317064334_create_view_group_members.rb`
    - `app/models/view_group.rb` (신규)
    - `app/models/view_group_member.rb` (신규)
    - `app/models/user.rb` (has_many 추가)
    - `test/fixtures/view_groups.yml`, `view_group_members.yml` (신규)
    - `test/models/view_group_test.rb` (13개 테스트)
    - `test/models/view_group_member_test.rb` (11개 테스트)

    ## QA 검증 결과
    - 테스트: 24/24 통과, 38 assertions, 0 failures
    - 보안: FK 제약, unique 인덱스, 이중 보호 모두 정상
    - 종합: 리뷰 진행 가능 (Critical/High 이슈 없음)

    ## Minor 이슈 (즉각 수정 불필요)
    - `is_report_purchased` → `is_report_purchased?` 권장
    - `diagnosis_session_id` 단독 인덱스 미추가 (향후 필요 시 추가)

  • 팀리드 상태 변경: 할 일 → 완료
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 위임: developer-1에게 '마이그레이션 + 모델 + 테스트 + fixtures 구현' 작업 배정
  • 팀리드 작업 시작 - [함께보기 PR1] DB 레이어
    상세 보기

    ## 작업 계획
    - 목표: ViewGroup + ViewGroupMember 모델, 마이그레이션, 테스트, fixtures 생성
    - 접근 방식: developer 1명이 TDD로 전체 구현, qa-verifier가 검증

    ## 현재 상태
    - 보드 현황: backlog 5 / in_progress 1 / done 137
    - 관련 기존 작업: 함께보기 기능 계획 (5개 PR 시리즈의 첫 번째)

  • 팀리드 티켓 클레임 완료
  • 팀리드 기능 계획 수립 - 함께 보기
    상세 보기

    ## 기능 개요
    - 커리어테크 아래 "함께 보기" 메뉴 신설
    - 개인이 그룹 생성 → QR코드로 초대 → 팀강점 매트릭스 함께 보기
    - Workspace와 달리 경량 구조 (승인/크레딧/결제 없음)

    ## 분석 결과
    - 영향 범위: 모델 2개 신규, 컨트롤러 1개 신규, 뷰 5개, 서비스 1개, 사이드바/하단탭 수정
    - 기존 패턴: Workspace의 invite_code, QrCodeHelper, TeamStrengthAnalyzer 참고
    - 재사용: rqrcode gem, QrCodeHelper#qr_code_svg, 팀강점 차트 데이터 구조

    ## 생성된 티켓 (5개)
    1. [함께보기 PR1] DB 레이어 (priority: high)
    2. [함께보기 PR2] TeamStrengthAnalyzer 서비스 (priority: high)
    3. [함께보기 PR3] 컨트롤러 + 라우트 (priority: high)
    4. [함께보기 PR4] 뷰 (priority: high)
    5. [함께보기 PR5] 네비게이션 + i18n (priority: medium)

    ## 의사결정 사항
    - 참여 시 진단 세션 선택 필수 (report_purchased: true만)
    - 소유자 나가기 → 그룹 삭제
    - 전 locale에서 메뉴 표시
    - 무료 검사로는 참여 불가

    ## 리스크
    - TeamStrengthAnalyzer 결합도 → 별도 서비스로 분리하여 기존 코드 영향 없음
    - 모바일 비로그인 QR → return_to 리다이렉트 활용

  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 2026년 03월 11일
  • 팀리드 전체 리뷰 완료 — 25개 티켓 승인 및 이슈 수정
    상세 보기

    ## 리뷰 결과
    - bin/ci: 통과 (Rubocop 0 offenses, Brakeman 0 warnings, 테스트 전체 통과)
    - 25개 티켓 모두 done 처리

    ## 보안 수정 (Critical/High)
    - `blog/posts/show.html.erb`: `raw` → `sanitize` (XSS 방지)
    - `study/enrollments_controller.rb`: 무료 등록 바이패스 차단
    - `study/workshop_payments_controller.rb`: IDOR 수정 (`Current.user.payments.find_by!`)
    - `study/assignment.rb`: 파일 content_type 검증 추가
    - `config/brakeman.ignore`: 기존 admin mass assignment 4건 무시 처리

    ## 코드 품질 수정
    - `blog/posts_controller.rb`, `admin/blog_posts_controller.rb`: LIKE wildcard injection → `sanitize_sql_like`
    - `blog/posts_controller.rb`: N+1 → `includes(:author, :category)`
    - `study/workshops_controller.rb`: N+1 → `includes(:course_applications)`

    ## UX/접근성 수정
    - `blog/comments/_comment.html.erb`: reply-form Stimulus scope 수정
    - `study/lessons/show.html.erb`: iframe title 속성 추가
    - `blog/posts/index.html.erb`, `blog/categories/show.html.erb`: 검색 aria-label
    - `blog/likes/_button.html.erb`: 좋아요 버튼 aria-label
    - `accordion_controller.js`: aria-expanded 토글 추가
    - `video_player_controller.js`: YouTube interval cleanup in disconnect()

  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 배치 3 전체 완료 — 1266 tests, 85개 신규 테스트 추가, 기존 이슈만 잔존
    상세 보기

    ## 배치 3 완료 요약
    - PR 5-3, 7-1, 7-2, 7-3 모두 review 상태 전환
    - Fixture FK 수정 (assignments, certificates)
    - 병렬 테스트 워커 DB 12개 스키마 동기화
    - todo 티켓 0개, 전 배치 review 대기 중

  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 4개 티켓 병렬 작업 시작 (PR 5-3, 7-1, 7-2, 7-3)
    상세 보기

    ## 작업 배정
    - PR 5-3 비디오 진도 추적 → developer-1
    - PR 7-1 수강료 결제 → developer-2
    - PR 7-2 워크숍 결제 → developer-3
    - PR 7-3 과제+인증서 → developer-4

    ## 충돌 방지
    - PR 5-3: study/progresses, video_player Stimulus
    - PR 7-1: study/payments (수강료)
    - PR 7-2: study/workshop_payments (워크숍)
    - PR 7-3: study/assignments + study/certificates + admin
    - routes.rb: 각자 담당 영역만 수정

  • 팀리드 위임: developer-4에게 'PR 7-3: 과제 제출 + 인증서 PDF 구현' 작업 배정
  • 팀리드 위임: developer-3에게 'PR 7-2: 워크숍 Toss Payments 결제 연동' 작업 배정
  • 팀리드 위임: developer-2에게 'PR 7-1: 수강료 Toss Payments 결제 연동' 작업 배정
  • 팀리드 위임: developer-1에게 'PR 5-3: 비디오 진도 추적 Stimulus + API' 작업 배정
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 3개 티켓 병렬 작업 시작 (PR 2-3, 5-2, 6-2)
    상세 보기

    ## 작업 배정
    - PR 2-3 TipTap 에디터 → developer-1
    - PR 5-2 교육 공개 페이지 → developer-2
    - PR 6-2 Workshop Admin+공개 → developer-3

    ## 충돌 방지
    - PR 2-3: admin/blog_posts/ 영역만
    - PR 5-2: study/ 컨트롤러+뷰, edu subdomain 라우트
    - PR 6-2: admin/expert_courses/ + study/workshops/, admin sidebar 수정
    - routes.rb: 각자 담당 영역만 수정 (admin namespace / edu subdomain)

  • 팀리드 위임: developer-3에게 'PR 6-2: Workshop Admin + 공개 페이지 구현' 작업 배정
  • 팀리드 위임: developer-2에게 'PR 5-2: 교육 공개 페이지 구현' 작업 배정
  • 팀리드 위임: developer-1에게 'PR 2-3: TipTap 에디터 통합 구현' 작업 배정
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 4개 티켓 병렬 작업 시작
    상세 보기

    ## 작업 배정
    - PR 3-2 SEO+RSS → developer-1
    - PR 3-3 댓글+좋아요 → developer-2
    - PR 5-1 Enrollment+Progress → developer-3
    - PR 6-1 Workshop 모델 → developer-4

    ## 충돌 방지
    - PR 3-2/3-3: routes.rb blog subdomain 분리 (feed vs comments/likes)
    - PR 3-2: show.html.erb 수정 금지
    - PR 5-1/6-1: 완전 독립 모듈

  • 팀리드 위임: developer-4에게 'PR 6-1: Workshop(Expert) 모델 구현' 작업 배정
  • 팀리드 위임: developer-3에게 'PR 5-1: Enrollment + Progress 모델 구현' 작업 배정
  • 팀리드 위임: developer-2에게 'PR 3-3: 블로그 댓글 + 좋아요 구현' 작업 배정
  • 팀리드 위임: developer-1에게 'PR 3-2: 블로그 SEO + RSS 구현' 작업 배정
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • D
    developer-1 Blog Admin CRUD 구현 완료 (24 tests, 0 failures)
    상세 보기

    ## 생성된 파일
    ### 컨트롤러 (2)
    - admin/blog_posts_controller.rb — CRUD + 필터/검색/페이지네이션
    - admin/blog_categories_controller.rb — CRUD

    ### 뷰 (9)
    - admin/blog_posts/ — index, show, new, edit, _form
    - admin/blog_categories/ — index, new, edit, _form

    ### 테스트 (2파일, 24 tests)
    - admin/blog_posts_controller_test.rb (14)
    - admin/blog_categories_controller_test.rb (10)

    ### 시드
    - db/seeds/seed_blog_categories.rb — 12개 기본 카테고리

    ### 수정
    - routes.rb — admin blog_posts, blog_categories 추가
    - sidebar — 블로그 메뉴 추가
    - ko.yml — admin 번역 추가

  • D
    developer-1 상태 변경: 진행 중 → 리뷰
  • D
    developer-2 블로그 공개 페이지 구현 완료 (73 tests, 0 failures)
    상세 보기

    ## 생성된 파일
    - blog/categories_controller.rb — show (slug, 페이지네이션)
    - blog/posts/show.html.erb — 상세 (breadcrumbs, 관련글)
    - blog/posts/_post_card.html.erb — 카드 partial
    - blog/categories/show.html.erb — 카테고리별 목록
    - blog/shared/_sidebar.html.erb — 카테고리 + 최근글
    - blog/shared/_pagination.html.erb — 수동 페이지네이션

    ## 수정된 파일
    - blog/posts_controller.rb — index(12/page), show(slug, 조회수), search(ILIKE)
    - blog/posts/index.html.erb — Coming Soon → 실제 목록
    - routes.rb — blog subdomain에 posts, categories, search 추가

    ## 주요 구현
    - 페이지네이션: 수동 offset/limit (12/page)
    - 조회수: increment_counter 동시성 안전
    - N+1 방지: includes(:author, :category)
    - 비로그인 열람 가능

  • D
    developer-2 상태 변경: 진행 중 → 리뷰
  • D
    developer-3 Study Admin CRUD 구현 완료 (29 tests, 0 failures)
    상세 보기

    ## 생성된 파일
    ### 컨트롤러 (3)
    - admin/study_courses_controller.rb — CRUD + toggle_active
    - admin/study_chapters_controller.rb — CRUD (nested under course)
    - admin/study_lessons_controller.rb — CRUD (nested under chapter)

    ### 뷰 (12)
    - admin/study_courses/ — index, show (트리 구조), new, edit, _form
    - admin/study_chapters/ — new, edit, _form
    - admin/study_lessons/ — new, edit, _form

    ### 테스트 (3파일, 29 tests)
    - admin/study_courses_controller_test.rb (13)
    - admin/study_chapters_controller_test.rb (8)
    - admin/study_lessons_controller_test.rb (8)

    ### 수정
    - config/routes.rb — admin study routes 추가
    - admin/shared/_sidebar.html.erb — 교육 메뉴 추가
    - admin/shared/_nav_item.html.erb — education 아이콘 추가

  • D
    developer-3 상태 변경: 진행 중 → 리뷰
  • 팀리드 작업 시작 - Blog Admin + 블로그 공개 + Study Admin 3개 병렬
    상세 보기

    ## 작업 계획
    - developer-1: PR 2-2 Blog Admin CRUD (admin/blog_posts, admin/blog_categories)
    - developer-2: PR 3-1 블로그 공개 페이지 (blog/posts, blog/categories)
    - developer-3: PR 4-2 Study Admin CRUD (admin/study_courses, chapters, lessons)

    ## 파일 충돌 방지 전략
    - routes.rb: 각 에이전트가 담당 영역만 수정
    - admin sidebar: developer-1이 블로그 메뉴, developer-3이 교육 메뉴 담당
    - developer-2는 blog subdomain 영역만 수정 (admin 미접촉)

  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 리뷰 완료 - 승인 [Phase 2] PR 2-1 + [Phase 4] PR 4-1
    상세 보기

    ## 리뷰 결과
    - 상태: 승인
    - 테스트: 98 runs, 147 assertions, 0 failures

    ## 코드 품질
    - 판정: 조건부 승인 (Critical 0, High 4, Medium 6)
    - High 이슈는 모두 향후 관련 PR에서 처리:
    - Sluggable concern 추출 → PR 2-2/3-1
    - slug 중복 suffix → PR 2-2/3-1
    - 복합 인덱스 [status, published_at] → PR 3-1
    - counter_cache (comments_count, likes_count) → PR 3-3

    ## 보안
    - 판정: PASS (Critical 0, High 0, Medium 2)
    - Brakeman: 경고 0건
    - 의존성: 취약 Gem 0개
    - Medium: comment content 길이 제한, materials_url 형식 검증 권장

    ## UX/UI
    - P0/P1 이슈 5건 수정 완료
    - default_scope 제거, 한글 slug fallback, Finish 레슨 추가, visible scope, inverse_of

  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 팀 작업 완료 - Blog 모델 + Study 모델 병렬 구현
    상세 보기

    ## 구현 결과
    - Blog 모델 4개: Category, Post, Comment, Like (마이그레이션 + 테스트 + fixtures)
    - Study 모델 3개: Course, Chapter, Lesson (마이그레이션 + 테스트 + fixtures + 시드)
    - 테스트: 98 runs, 147 assertions, 0 failures

    ## P0/P1 수정 완료
    - default_scope 제거 → has_many ordering 람다로 이동
    - 한글 slug fallback 추가 (Blog::Post, Category)
    - Finish 레슨 시드 추가
    - visible scope + published_at 자동설정
    - Blog 모델 inverse_of 추가

    ## UX/UI 검토 결과
    - 모델 구조가 향후 UI 구현을 잘 지원
    - P2/P3 이슈는 컨트롤러 구현 시 함께 처리 예정

    ## 테스트/보안 검증 결과
    - brakeman: 경고 0건
    - FK/인덱스 모두 적절
    - bin/ci rubocop 실패는 기존 코드 문제 (새 코드는 OK)

  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • D
    developer-2 상태 변경: 리뷰 → 완료
  • D
    developer-1 상태 변경: 리뷰 → 완료
  • Q
    qa-verifier 상태 변경: 할 일 → 완료
  • U
    ux-reviewer 상태 변경: 할 일 → 완료
  • 팀리드 UX/QA 리뷰 완료 - P0/P1 수정 진행
    상세 보기

    ## UX 리뷰 결과
    - 평가: 개선 필요 (Minor~Medium)
    - P0: default_scope 제거, 한글 slug fallback
    - P1: Finish 레슨 누락, visible scope, published_at 자동설정

    ## QA 검증 결과
    - bin/ci: rubocop 실패 (기존 코드 문제, 새 코드는 OK)
    - 테스트: 91 runs, 0 failures
    - brakeman: 경고 0건
    - 종합: 리뷰 진행 가능

    ## 수정 계획
    P0/P1 이슈 5건을 developer로 수정 후 완료 처리

  • D
    developer-2 Study 모델 3개 구현 완료 (46/46 테스트 통과)
    상세 보기

    ## 생성된 파일

    ### 마이그레이션 (3)
    - `db/migrate/20260311110000_create_study_courses.rb`
    - `db/migrate/20260311110001_create_study_chapters.rb`
    - `db/migrate/20260311110002_create_study_lessons.rb`

    ### 모델 (4)
    - `app/models/study.rb` — table_name_prefix "study_"
    - `app/models/study/course.rb` — recalculate_totals!, slug 자동생성(한글 처리)
    - `app/models/study/chapter.rb` — preview/ordered scopes
    - `app/models/study/lesson.rb` — video_type enum (vimeo/youtube)

    ### 테스트 (3파일, 46 tests)
    - `test/models/study/course_test.rb` (18)
    - `test/models/study/chapter_test.rb` (12)
    - `test/models/study/lesson_test.rb` (16)

    ### 시드
    - `db/seeds/seed_study_courses.rb` — 강점코치 입문 과정 (11챕터, 24레슨, 353분)

    ## 검증
    - 46/46 테스트 통과
    - 마이그레이션 → 롤백 → 재마이그레이션 성공
    - 시드 idempotent 확인
    - recalculate_totals! 정상 동작

  • D
    developer-2 상태 변경: 할 일 → 리뷰
  • D
    developer-1 Blog 모델 4개 구현 완료 (45/45 테스트 통과)
    상세 보기

    ## 생성된 파일

    ### 마이그레이션 (4)
    - `db/migrate/20260311100000_create_blog_categories.rb`
    - `db/migrate/20260311100001_create_blog_posts.rb`
    - `db/migrate/20260311100002_create_blog_comments.rb`
    - `db/migrate/20260311100003_create_blog_likes.rb`
    - `db/migrate/20260311123734_create_active_storage_tables.active_storage.rb`

    ### 모델 (5)
    - `app/models/blog.rb` — table_name_prefix "blog_"
    - `app/models/blog/category.rb`
    - `app/models/blog/post.rb`
    - `app/models/blog/comment.rb`
    - `app/models/blog/like.rb`

    ### 테스트 (4파일, 45 tests)
    - `test/models/blog/category_test.rb` (9)
    - `test/models/blog/post_test.rb` (21)
    - `test/models/blog/comment_test.rb` (9)
    - `test/models/blog/like_test.rb` (6)

    ### Fixtures (4)
    - `test/fixtures/blog/categories.yml`
    - `test/fixtures/blog/posts.yml`
    - `test/fixtures/blog/comments.yml`
    - `test/fixtures/blog/likes.yml`

    ### 수정된 파일
    - `app/models/user.rb` — has_many :blog_posts, :blog_comments, :blog_likes 추가

    ## 검증
    - 45/45 테스트 통과
    - 마이그레이션 → 롤백 → 재마이그레이션 성공
    - Development DB 무사 (users: 9066, sessions: 8509)

  • D
    developer-1 상태 변경: 할 일 → 리뷰
  • 팀리드 위임: qa-verifier에게 '테스트 및 품질 검증 (Blog + Study 모델)' 작업 배정
  • 팀리드 위임: ux-reviewer에게 'UX/UI 디자인 검토 (Blog + Study 모델)' 작업 배정
  • 팀리드 위임: developer-2에게 'Study 모델 3개 + 마이그레이션 + 시드 구현 (TDD)' 작업 배정
  • 팀리드 위임: developer-1에게 'Blog 모델 4개 + 마이그레이션 구현 (TDD)' 작업 배정
  • 팀리드 작업 시작 - Blog 모델 + Study 모델 병렬 진행
    상세 보기

    ## 작업 계획
    - PR 2-1 (Blog 모델)과 PR 4-1 (Study 모델) 병렬 구현
    - developer-1: Blog::Post, Category, Comment, Like 모델 + 마이그레이션
    - developer-2: Study::Course, Chapter, Lesson 모델 + 시드 데이터
    - 완료 후 UX/UI 리뷰 + QA 검증

    ## 접근 방식
    - 각 developer가 독립적인 테이블/모델을 담당하여 파일 충돌 없음
    - TDD 방식: 테스트 먼저 → 구현

  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 리뷰 완료 - 승인 (서브도메인 라우팅 설정)
    상세 보기

    ## 리뷰 결과
    - 상태: 승인
    - 테스트: 6/6 통과, regression 없음

    ## 코드 품질
    - BaseController 상속 구조 적절 (ApplicationController → BaseController → PostsController)
    - default_url_options 오버라이드로 locale 파라미터 깔끔하게 제거
    - skip_before_action :set_sidebar_workspaces 적절 (비인증 페이지)
    - strict locals 사용 (_navbar_subdomain)

    ## 보안
    - csrf_meta_tags, csp_meta_tag 포함
    - allow_unauthenticated_access 적절 (공개 페이지)
    - html_safe/raw 사용 없음

    ## UX/UI
    - shared/footer 재사용 (법적 정보 포함)
    - shared/_navbar_subdomain 추출로 DRY
    - yield :head 추가 (SEO 확장성)
    - 디자인 토큰 올바르게 사용

  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 팀 작업 완료 - 서브도메인 라우팅 설정
    상세 보기

    ## 수정된 기능
    - blog./edu. 서브도메인 라우팅 constraints
    - Blog::BaseController, Study::BaseController
    - blog.html.erb, study.html.erb 레이아웃
    - shared/_navbar_subdomain.html.erb (공통 navbar)
    - 임시 컨트롤러/뷰 (Coming Soon)

    ## UX/UI 검토 결과
    - P1 수정 완료: footer → shared/footer, yield :head 추가
    - P2 수정 완료: navbar partial 추출, skip_before_action 추가
    - P3 후속 처리: 배경색 토큰 통일, max-w 통일, 메타태그 보완

    ## 테스트/보안 검증 결과
    - 신규 6개 테스트 통과
    - 기존 테스트 regression 없음 (기존 8개 실패는 무관)
    - CSRF/CSP/XSS 보안 처리 적절

    ## 생성/수정 파일
    - config/routes.rb (서브도메인 constraints)
    - config/environments/development.rb (hosts 추가)
    - app/controllers/blog/base_controller.rb
    - app/controllers/study/base_controller.rb
    - app/controllers/blog/posts_controller.rb
    - app/controllers/study/courses_controller.rb
    - app/views/layouts/blog.html.erb
    - app/views/layouts/study.html.erb
    - app/views/shared/_navbar_subdomain.html.erb
    - app/views/blog/posts/index.html.erb
    - app/views/study/courses/index.html.erb
    - test/controllers/blog/posts_controller_test.rb
    - test/controllers/study/courses_controller_test.rb

  • 팀리드 상태 변경: 진행 중 → 리뷰
  • D
    developer-1 상태 변경: 할 일 → 완료
  • 팀리드 위임: developer-1에게 '서브도메인 라우팅 + 베이스 컨트롤러 + 레이아웃 구현' 작업 배정
  • 팀리드 작업 시작 - 서브도메인 라우팅 설정
    상세 보기

    ## 작업 계획
    - 목표: blog./edu. 서브도메인 라우팅 인프라 구축
    - 접근: developer 1명으로 라우팅+컨트롤러+레이아웃+테스트 구현

    ## 현재 상태
    - 보드: todo 17 / in_progress 1 / done 104
    - 이 티켓이 모든 후속 Phase의 기반

  • 팀리드 티켓 클레임 완료
  • 팀리드 블로그 + 교육 서브도메인 기능 계획 수립 완료 — 17개 백로그 티켓 생성
    상세 보기

    ## 기능 개요
    - blog.9way.co.kr: 블로그 (포스트, 카테고리, 댓글, 좋아요, SEO)
    - edu.9way.co.kr: 교육 LMS (코스, 레슨, 수강, 진도추적) + 워크숍 (오프라인)

    ## 분석 결과
    - 기존 앱에 Blog/Education 관련 코드 없음 — 완전 신규
    - ActiveStorage 설정됨(미사용), Grover(PDF) 사용 가능
    - 기존 결제 서비스(Toss Payments) 재사용 가능

    ## 생성된 티켓 (17개, 7 Phase)
    - Phase 1: 서브도메인 라우팅 (1개, HIGH)
    - Phase 2: 블로그 코어 (3개, HIGH)
    - Phase 3: 블로그 퍼블릭 (3개, HIGH)
    - Phase 4: 교육 코스 (2개, MEDIUM)
    - Phase 5: 교육 수강 (3개, MEDIUM)
    - Phase 6: 워크숍 (2개, MEDIUM)
    - Phase 7: 결제+고급 (3개, LOW)

    ## 기술적 결정
    - 리치 텍스트: text 컬럼 + TipTap (ActionText 대신)
    - 이미지: ActiveStorage
    - PDF: Grover
    - 네임스페이스: Blog::, Study::, Expert::

    ## 계획서
    - docs/plans/blog-edu-subdomain.md

  • 2026년 03월 10일
  • 팀리드 k6 부하 테스트 스크립트 완료 - 스모크 테스트 통과
    상세 보기

    ## 변경 사항
    - `test/load/diagnosis_flow.js` 생성
    - slug 수정: `big5-adult` → `big5` (실제 DB slug과 일치)

    ## 스모크 테스트 결과 (로컬 dev, 2 VU, 30초)
    - 진단 시작 p95: 53ms (기준 < 2000ms)
    - 문항 로드 p95: 245ms (기준 < 1500ms)
    - 응답 제출 p95: 73ms (기준 < 3000ms)
    - 결과 로드 p95: 16ms (기준 < 2000ms)
    - 플로우 완료: 4건
    - 에러: 0건

    ## 실행 방법
    ```
    docker run --rm --network host \
    -v $(pwd)/test/load:/scripts \
    grafana/k6:latest run \
    --env BASE_URL=https://9way.org \
    /scripts/diagnosis_flow.js
    ```

  • 팀리드 상태 변경: 리뷰 → 완료
  • 2026년 03월 09일
  • 팀리드 k6 부하 테스트 스크립트 작성 완료
    상세 보기

    ## 생성 파일
    - `test/load/diagnosis_flow.js` (신규)

    ## 주요 기능
    - Big5 진단 전체 플로우 시뮬레이션 (5단계)
    - ramp-up: 10 → 50 → 100 → 500 → 0
    - 커스텀 메트릭 4개 + 실패율 메트릭
    - CSRF 토큰 자동 파싱
    - 실제 question ID 기반 응답 생성
    - 5% 확률 "해당 사항 없음" 시뮬레이션
    - thresholds: p95 < 1s, 에러율 < 1%

  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 작업 시작 - k6 부하 테스트 스크립트 작성
    상세 보기

    ## 작업 계획
    - 목표: Big5 진단 전체 플로우의 부하 테스트 스크립트 작성
    - 접근 방식: 에이전트가 기존 라우트와 API를 분석하여 k6 스크립트 생성

    ## 현재 상태
    - 단일 티켓으로 서브 티켓 불필요
    - 코드 변경 없이 신규 파일 1개 생성

  • 팀리드 티켓 클레임 완료
  • 팀리드 리뷰 완료 - 승인 (Big5 응답 일괄 제출)
    상세 보기

    ## 리뷰 결과
    - 상태: 승인 (서브 티켓 2건 모두 완료)

    ## 서브 티켓 결과
    1. Server API: 승인 — upsert_all 벌크 저장, 타입 안전성 수정 완료, 테스트 12건 통과
    2. Client Stimulus: 승인 — ARIA 접근성, i18n 4개 언어, 타임아웃 토스트 추가 완료

    ## 보안
    - Brakeman 0건, bundler-audit 0건
    - CWE 스캔 Critical 0건
    - XSS 방어 적절 (_escapeHTML, textContent, ERB 자동 이스케이프)

    ## 성과
    - HTTP 요청 30배 감소 (30라운드 × AJAX → 최종 1회 제출)
    - sessionStorage crash recovery 구현
    - 4개 언어 i18n 완전 지원

  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 재리뷰 완료 - 승인 (Client: Stimulus 컨트롤러)
    상세 보기

    ## 리뷰 결과
    - 상태: 승인
    - 코드 품질: 반려사유 3건 모두 수정 확인 (ARIA 접근성, i18n 7개 value, 타임아웃 토스트)
    - 보안: PASS — innerHTML은 _escapeHTML()로 보호, 토스트는 textContent 사용, ERB 자동 이스케이프 적용
    - i18n: 4개 언어(ko, en, zh, vi) 모두 7개 키 존재 확인

  • 팀리드 재리뷰 완료 - 승인 (Server: 일괄 제출 API)
    상세 보기

    ## 리뷰 결과
    - 상태: 승인
    - 코드 품질: 반려사유 3건 모두 수정 확인 (Boolean cast, question_id 타입 통일, index 키 타입 통일)
    - 보안: PASS — ActiveModel::Type::Boolean.new.cast() 안전, .to_s 변환 SQL injection 무관
    - 테스트: 타입 안전성 테스트 2건 추가, 전체 12 runs 0 failures

  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • F
    frontend-dev 반려 사유 3건 수정 완료
    상세 보기

    ## 변경 사항
    ### big5_batch_controller.js
    - ARIA: role="radiogroup", role="radio", aria-checked 추가
    - ARIA: neither 버튼에 aria-label 추가
    - ARIA: selectCard()/selectNeither()에서 aria-checked 토글
    - i18n: 7개 Stimulus value 추가 (submittingText, completeTitle 등)
    - i18n: _showSubmitting/_showComplete/_showError의 하드코딩 텍스트를 value로 교체
    - 타임아웃: _showTimeoutToast() 메서드 추가, 1.5초 토스트 표시 후 다음 라운드 전환

    ### big5_show.html.erb
    - 카운트다운에 role="timer" aria-live="polite" 추가
    - 7개 data-big5-batch-*-value 속성 추가 (t() 헬퍼로 번역 전달)

    ### i18n 파일 (4개 언어)
    - diagnosis.big5.batch.* 키 추가 (ko, en, zh, vi)

  • B
    backend-dev 반려 사유 3건 수정 완료
    상세 보기

    ## 변경 사항
    ### diagnosis_sessions_controller.rb
    - `ActiveModel::Type::Boolean.new.cast(r[:selected])` 적용 — 문자열 "false" 안전 처리
    - `submitted_ids`를 `.to_s` 변환하여 타입 통일
    - `valid_question_id_strings` Set 생성으로 검증 로직 타입 일치
    - `string_keyed_index` 변환으로 dna_type nil 방지

    ### diagnosis_sessions_controller_test.rb
    - 문자열 "true"/"false" selected 필드 테스트 추가
    - 문자열 question_id 검증 및 dna_type 조회 테스트 추가

    ## 테스트 결과
    - 12 runs, 63 assertions, 0 failures, 0 errors

  • F
    frontend-dev 상태 변경: 진행 중 → 리뷰
  • B
    backend-dev 상태 변경: 진행 중 → 리뷰
  • 팀리드 리뷰 완료 - 승인 (Puma 스레드 5→7)
    상세 보기

    ## 리뷰 결과
    - 상태: 승인
    - 코드 품질: 2×7=14 슬롯, 메모리 영향 미미(~14MB). DB pool 자동 연동 확인
    - 보안: 이슈 없음
    - UX/UI: 해당 없음
    - 참고: 배포 후 메모리 사용량 모니터링 권장

  • 팀리드 리뷰 완료 - 승인 (response_timeout 120→60초)
    상세 보기

    ## 리뷰 결과
    - 상태: 승인
    - 코드 품질: 이슈 없음. PDF 생성(10-30초) 고려한 60초 설정 합리적
    - 보안: 이슈 없음
    - UX/UI: 해당 없음

  • 팀리드 리뷰 완료 - 승인 (Big5Description 쿼리 캐싱)
    상세 보기

    ## 리뷰 결과
    - 상태: 승인
    - 코드 품질: locale별 캐싱 적절. 이중 캐싱(Rails.cache + 메모이제이션) 효율적
    - 보안: 이슈 없음
    - UX/UI: 해당 없음

  • 팀리드 리뷰 완료 - 승인 (N+1 제거 + upsert_all)
    상세 보기

    ## 리뷰 결과
    - 상태: 승인
    - 코드 품질: upsert_all 벌크 저장 적절. where(id:).index_by 패턴으로 N+1 제거 확인
    - 보안: SQL Injection 위험 없음
    - UX/UI: 해당 없음

  • 팀리드 리뷰 완료 - 승인 (prepare_all_big5_rounds 캐싱)
    상세 보기

    ## 리뷰 결과
    - 상태: 승인
    - 코드 품질: 캐시 키 설계(session.id + locale) 적절. includes(:translations)로 N+1 방지
    - 보안: 캐시 오염 불가 확인
    - UX/UI: 해당 없음

  • 팀리드 리뷰 완료 - 승인 (database.yml pool 키 수정)
    상세 보기

    ## 리뷰 결과
    - 상태: 승인
    - 코드 품질: 이슈 없음. test 환경 url 고정으로 DATABASE_URL 침투 방지 확인
    - 보안: DB 설정 적절
    - UX/UI: 해당 없음

  • 팀리드 리뷰 완료 - 반려 (Client: Stimulus 컨트롤러)
    상세 보기

    ## 리뷰 결과
    - 상태: 반려
    - bin/ci: 통과

    ## 코드 품질
    - sessionStorage crash recovery 잘 구현됨
    - XSS 방어 (_escapeHTML) 적절
    - catch 블록 에러 무시 (medium) — console.warn 추가 권장

    ## 보안
    - CSRF 토큰 헤더 전송 OK
    - sessionStorage 동일 탭 한정 OK

    ## UX/UI
    - [MUST-FIX] 진단 카드 ARIA 속성 누락 (role="radio", aria-checked, role="radiogroup")
    - [MUST-FIX] locale_dropdown ARIA 누락 (aria-expanded, role="menu")
    - [MUST-FIX] JS 내 한국어 텍스트 하드코딩 — 4개 언어 지원인데 i18n 미적용
    - [MUST-FIX] 타임아웃 자동 스킵 시 사용자 피드백 없음

    ## 수정 필요 사항
    - ARIA 접근성 속성 추가
    - Stimulus value로 번역 텍스트 전달 또는 서버 렌더링 template 사용
    - 타임아웃 스킵 토스트 메시지 추가

  • 팀리드 리뷰 완료 - 반려 (Server: 일괄 제출 API)
    상세 보기

    ## 리뷰 결과
    - 상태: 반려
    - bin/ci: 통과 (payments 관련 기존 실패 제외)

    ## 코드 품질
    - [CRITICAL] r[:selected] 타입 안전성 — 문자열 "false"가 truthy로 처리되어 모든 응답이 1로 저장될 위험
    - [HIGH] question_id 타입 불일치 — String vs UUID Set 비교로 검증 무력화 가능
    - [HIGH] valid_questions_index 키 타입 불일치 — dna_type이 nil로 저장될 위험

    ## 보안
    - Brakeman/bundler-audit 통과
    - upsert_all SQL Injection 위험 없음
    - value 필드 Boolean→0/1 변환으로 임의값 주입 불가

    ## UX/UI
    - 해당 없음 (서버 API)

    ## 수정 필요 사항
    - ActiveModel::Type::Boolean.new.cast() 사용
    - r[:question_id].to_s로 타입 통일
    - 타입 안전성 테스트 추가

  • 팀리드 상태 변경: 리뷰 → 진행 중
  • 팀리드 상태 변경: 리뷰 → 진행 중
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 팀 작업 완료 - 성능 최적화 2단계 코드 변경 5건
    상세 보기

    ## 수정된 기능
    - database.yml: `max_connections` → `pool` 키 수정 (AR 표준 키)
    - deploy.yml: response_timeout 120→60초, RAILS_MAX_THREADS 5→7
    - prepare_all_big5_rounds: Rails.cache.fetch 캐싱 (세션별, 1일 TTL)
    - build_description_cache: Rails.cache.fetch 캐싱 (locale별, 1일 TTL)

    ## 테스트/보안 검증 결과
    - bin/ci: 855 runs, 3 failures/7 errors (모두 pre-existing)
    - Brakeman: 신규 이슈 없음
    - N+1 쿼리: 없음
    - 캐시 키 안전성: 확인 (사용자 입력 미포함)

    ## 변경 파일
    - config/database.yml
    - config/deploy.yml
    - app/controllers/diagnosis_sessions_controller.rb
    - app/services/diagnosis/big5_result_formatter.rb
    - test/controllers/diagnosis_sessions_controller_test.rb
    - test/services/diagnosis/big5_result_formatter_test.rb

  • Q
    qa-verifier 재검증 완료 - 검증 통과
    상세 보기

    ## 재검증 결과

    ### ✅ 캐싱 구현 확인

    **prepare_all_big5_rounds (diagnosis_sessions_controller.rb:364)**
    ```ruby
    Rails.cache.fetch(["big5_rounds", @session.id, I18n.locale], expires_in: 1.day)
    ```
    - 캐시 키: 세션 ID + 로케일 조합 ✅
    - 만료: 1일 TTL ✅
    - 사용자 입력 미포함: session.id(UUID), I18n.locale(시스템값) ✅
    - RNG 시드도 `Digest::MD5.hexdigest(@session.id.to_s)` 방식으로 개선 (process 재시작에도 동일 시드 보장) ✅

    **build_description_cache (big5_result_formatter.rb:36)**
    ```ruby
    Rails.cache.fetch("big5:descriptions:#{locale}", expires_in: 1.day)
    ```
    - 캐시 키: 로케일 기반 ✅
    - 만료: 1일 TTL ✅
    - 사용자 입력 미포함 ✅

    ### ✅ 테스트 결과
    - 컨트롤러: 10 runs, 23 assertions, 0 failures, 0 errors ✅
    - Formatter: 4 runs, 6 assertions, 0 failures, 0 errors ✅
    - 전체: 855 runs, 2135 assertions, 3 failures, 7 errors (모두 pre-existing)
    - CustomPayments 라우팅 7건 (pre-existing)
    - Admin::Payments 3건 (pre-existing)

    ### ✅ 보안 (Brakeman)
    - 신규 이슈 없음 (기존 4건 동일)

    ### ✅ N+1 쿼리 없음
    - `includes(:translations)` 적용
    - `find_quality_code`는 `Rails.cache.fetch("big5:quality_code_map")` 유지

    ### 종합 판정
    **검증 통과** — 모든 캐싱 구현이 올바르게 완료됨

  • R
    rails-dev 캐싱 최적화 2건 구현 완료
    상세 보기

    ## 변경 사항

    ### 1. `prepare_all_big5_rounds` 세션별 캐싱
    - **파일**: `app/controllers/diagnosis_sessions_controller.rb`
    - `Rails.cache.fetch(["big5_rounds", @session.id, I18n.locale], expires_in: 1.day)` 적용
    - 세션 ID + locale 기반 캐시 키로 동일 세션 재방문 시 라운드 재생성 방지

    ### 2. `build_description_cache` 쿼리 캐싱
    - **파일**: `app/services/diagnosis/big5_result_formatter.rb`
    - `Rails.cache.fetch("big5:descriptions:#{locale}", expires_in: 1.day)` 적용
    - Big5Description 테이블 쿼리를 locale별로 1일 캐싱

    ### 3. 테스트 추가
    - **파일**: `test/controllers/diagnosis_sessions_controller_test.rb` — 캐시 히트/미스, locale별 분리 2건
    - **파일**: `test/services/diagnosis/big5_result_formatter_test.rb` — 캐시 동작, DB 쿼리 스킵, locale별 분리, nil json_data 4건

    ### 테스트 결과
    - 14 runs, 29 assertions, 0 failures, 0 errors (관련 테스트 전체 통과)
    - 기존 실패는 Admin::PaymentsTest, CustomPaymentsTest (변경과 무관)

  • R
    rails-dev 상태 변경: 진행 중 → 리뷰
  • R
    rails-dev 상태 변경: 진행 중 → 리뷰
  • Q
    qa-verifier 품질 검증 완료 - 캐싱 미구현 및 테스트 오류 2건 발견
    상세 보기

    ## 검증 결과

    ### ✅ 합격 항목
    - **config/database.yml**: `max_connections` → `pool` 수정 올바름 (Rails 표준 키)
    - **config/deploy.yml**: `response_timeout: 60` ✅, `RAILS_MAX_THREADS: 7` ✅
    - **Brakeman 보안 스캔**: 신규 이슈 없음 (기존 4건 pre-existing: admin Mass Assignment 3건, payments XSS 1건)
    - **N+1 쿼리**: `prepare_all_big5_rounds`에서 `includes(:translations)` 사용 ✅
    - **캐시 키 안전성**: `find_quality_code`의 `"big5:quality_code_map"` — 사용자 입력 미포함 ✅
    - **Rubocop**: 기존 254건 동일 (pre-existing, 신규 없음)

    ### ❌ 문제 발견

    #### 1. 캐싱 미구현 (Critical)
    - `prepare_all_big5_rounds`에 `Rails.cache.fetch`가 없음
    - `build_description_cache`도 인스턴스 변수 캐시만 있고 Rails.cache 미사용
    - 태스크 #2(cache-dev)가 아직 in_progress 상태

    #### 2. 테스트 오류 2건 (New - 테스트 코드 버그)
    ```
    DiagnosisSessionsControllerTest#test_prepare_all_big5_rounds_caches_result_per_session_and_locale:
    NoMethodError: undefined method 'stub' for module Rails

    DiagnosisSessionsControllerTest#test_prepare_all_big5_rounds_cache_varies_by_locale:
    NoMethodError: undefined method 'stub' for module Rails
    ```
    - 원인: `Rails.stub(:cache, cache_store)`는 Minitest에서 module에 사용 불가
    - 수정 필요: `Rails.cache` stub 대신 `Rails.cache.write/read` 패턴 또는 `assert_called` 사용

    #### 3. 미커밋 변경사항
    - `config/database.yml`, `config/deploy.yml` 변경이 staged되지 않은 상태
    - 커밋 전 확인 필요

    ### 종합 판정
    **검증 미통과** — cache-dev 작업 완료 후 재검증 필요

  • R
    rails-dev 설정 최적화 3건 구현 완료
    상세 보기

    ## 변경 사항

    ### 1. database.yml pool 키 수정
    - `config/database.yml` 4행: `max_connections` → `pool`
    - `ActiveRecord::Base.connection_pool.size` = 5 확인 (pool 키 정상 인식)

    ### 2. response_timeout 축소
    - `config/deploy.yml` 17행: `response_timeout: 120` → `60`

    ### 3. Puma 스레드 증가
    - `config/deploy.yml` 47행: `RAILS_MAX_THREADS: 5` → `7`
    - 배포 시 2×7=14 동시 슬롯 (40% 증가)

    ## 테스트 결과
    - 851 tests, 2114 assertions
    - 실패 6건 + 에러 9건 = 모두 기존 코드 이슈 (Workspaces, CustomPayments, Admin::Payments, DiagnosisSessionsController)
    - config 변경과 무관한 기존 실패
    - 개발 DB 정상 (Users: 5)

  • R
    rails-dev 상태 변경: 진행 중 → 리뷰
  • R
    rails-dev 상태 변경: 진행 중 → 리뷰
  • R
    rails-dev 상태 변경: 진행 중 → 리뷰
  • R
    rails-dev 캐싱 최적화 시작
    상세 보기

    ## 작업 범위
    - `prepare_all_big5_rounds` 세션별 캐싱 (diagnosis_sessions_controller.rb)
    - `build_description_cache` 쿼리 캐싱 (big5_result_formatter.rb)
    - 이중 쿼리 제거
    - 캐싱 관련 테스트 작성

  • R
    rails-dev 설정 최적화 시작
    상세 보기

    ## 작업 범위
    - `config/database.yml`: max_connections → pool 키 수정
    - `config/deploy.yml`: response_timeout 120 → 60
    - `config/deploy.yml`: RAILS_MAX_THREADS 5 → 7

  • 팀리드 작업 시작 - 성능 최적화 2단계 코드 변경 5건
    상세 보기

    ## 작업 계획
    - 목표: 설정 수정 3건 + 캐싱 추가 2건
    - 접근 방식: config-dev(설정 3건) + cache-dev(캐싱 2건) 병렬 → qa-verifier 검증

    ## 작업 분배
    - config-dev: database.yml pool 키 + response_timeout 60초 + Puma 스레드 7
    - cache-dev: prepare_all_big5_rounds 캐싱 + Big5Description 캐싱

    ## 현재 상태
    - 보드 현황: backlog 2 / in_progress 5 / review 4 / done 93

  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 성능 최적화 2단계 계획 수립 - 7개 백로그 생성
    상세 보기

    ## 계획 프로세스
    - 3명 에이전트 팀 (analyst, planner, critic) 비평적 상호 평가
    - analyst: 10개 핵심 파일 분석, P0~P3 병목 분류
    - planner: 8개 PR 분해, ROI 매트릭스 작성
    - critic (Devil's Advocate): 수치 근거 검증, 과대평가 반박

    ## 핵심 합의
    - 현실적 목표: 1,000명 동시 처리 (3,000명은 단일 서버 불가)
    - 가장 큰 병목: `prepare_all_big5_rounds` (300-500ms, 캐싱 가능)
    - complete 비동기화: ROI 낮음 (100ms 작업), k6 결과 후 결정으로 보류
    - response_timeout: 60초 (PDF 생성 안전 고려)

    ## 생성된 백로그
    1. database.yml pool 키 수정 (critical)
    2. prepare_all_big5_rounds 캐싱 (critical)
    3. Big5Description 캐싱 (high)
    4. response_timeout 60초 (high)
    5. Puma 스레드 7개 (medium)
    6. Cloudflare CDN (high)
    7. k6 부하 테스트 (medium)

  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 팀 작업 완료 - Big5 일괄 제출 + N+1 제거
    상세 보기

    ## 수정된 기능
    - Big5 일괄 제출 API (submit_all_big5_responses): 30라운드 × AJAX → 최종 1회 POST
    - Stimulus big5_batch_controller: 클라이언트 라운드 전환 + sessionStorage 백업
    - upsert_all: 90개 응답 1회 DB 쿼리 저장
    - N+1 제거: SurveyQuestion.find × N → where(id:).index_by

    ## 변경 파일
    - app/controllers/diagnosis_sessions_controller.rb (새 액션 + N+1 수정)
    - app/services/diagnosis/session_manager.rb (save_responses_bulk)
    - config/routes.rb (submit_all_big5_responses 라우트)
    - app/javascript/controllers/big5_batch_controller.js (새 파일)
    - app/views/diagnosis_sessions/big5_show.html.erb (batch mode)
    - app/views/diagnosis_sessions/_big5_guide.html.erb (시작 버튼)
    - config/locales/diagnosis/ko.yml (big5_adult i18n)
    - test 파일 다수

    ## 테스트/보안 검증 결과
    - 새 기능 테스트: 27 runs, 0 failures ✅
    - 보안: CSRF, SQL injection, XSS 이슈 없음 ✅
    - 기존 실패: CustomPayments 라우팅 (무관)

    ## 해결된 문제
    - question_id 검증 불일치: exact match → subset 검증으로 수정
    - fixture 부작용: i18n 키 + assert_response 수정

  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • R
    rails-dev fixture 부작용 테스트 2건 수정 완료
    상세 보기

    ## 수정 1: DiagnosisFlowTest#test_index_page_renders_diagnosis_types
    - **원인**: `big5_adult` fixture의 `name_key: "diagnosis.types.big5_adult"`에 대한 i18n 키가 locale 파일에 없어서 `feature_tags`가 String 반환 → `.each` 에러
    - **수정**: `config/locales/diagnosis/ko.yml`에 `big5_adult` 키 추가 (title, description, features)

    ## 수정 2: DiagnosisFlowTest#test_start_shows_confirm_resume_when_duplicate_within_1_hour
    - **원인**: `confirm_resume`는 `status: :unprocessable_entity` (422)로 렌더링하지만 테스트가 `assert_response :success` (200) 기대
    - **수정**: `assert_response :success` → `assert_response :unprocessable_entity`
    - **추가**: big5 fixture의 `created_at`을 2~3시간 전으로 설정 (duplicate check 영향 방지)

    ## 변경 파일
    - `config/locales/diagnosis/ko.yml` — big5_adult i18n 키 추가
    - `test/integration/diagnosis_flow_test.rb` — assert_response 수정
    - `test/fixtures/diagnosis_sessions.yml` — big5 fixture created_at 조정

    ## 테스트 결과
    57 runs, 146 assertions, 0 failures, 0 errors

  • Q
    qa-verifier 테스트 및 품질 검증 완료
    상세 보기

    ## 검증 결과

    ### 1. 새로운 테스트 (18개 모두 통과 ✅)
    - `submit_all_big5_responses` 액션 테스트 5개: 모두 통과
    - `save_responses_bulk` 서비스 테스트 2개: 모두 통과
    - `submit_big5_round`, `submit_part2_round` 테스트 포함

    ### 2. N+1 쿼리 제거 확인 ✅
    - `submit_big5_round`, `submit_part2_round`: `SurveyQuestion.where(id:).index_by` 패턴 사용
    - `submit_all_big5_responses`: `valid_questions_index` memoization 적용

    ### 3. 보안 점검
    - **CSRF**: Stimulus 컨트롤러에서 `X-CSRF-Token` 헤더 사용 ✅
    - **Strong Parameters**: `params.require(:responses)` 사용 ✅
    - **SQL injection**: upsert_all에서 records 값이 서버 검증 후 빌드, unique_by/update_only 하드코딩 ✅
    - **sessionStorage XSS**: `_escapeHTML()` 처리, 서버 재검증 ✅
    - **subset 검증**: invalid_ids 체크로 외부 question_id 주입 차단 ✅
    - **Brakeman**: 신규 코드에서 추가 이슈 없음 (기존 이슈만 존재)

    ### 4. 기존 실패 분류
    - `CustomPaymentsTest` (7개 오류): 기존 라우팅 오류, 새 코드와 무관 (stash 후 테스트로 확인)
    - `DiagnosisFlowTest#test_index_page_renders_diagnosis_types`: **새 fixture(big5_adult) 추가 부작용** - i18n 번역 키 `diagnosis.types.big5_adult.features` 누락
    - `DiagnosisFlowTest#test_start_shows_confirm_resume_when_duplicate_within_1_hour`: **새 fixture 부작용** - big5_in_progress 세션 추가로 인해 duplicate 체크 로직에 영향 가능성

    ### 5. Minor 코드 이슈
    - `submit_all_big5_responses`에서 `valid_question_ids`(Set)와 `valid_questions_index`(Hash)를 별도 쿼리 (통합 가능)
    - question_id 타입 비교: JSON 파싱 시 Integer vs String 불일치 가능성

    ### 종합 판정
    ✅ 핵심 기능 테스트 통과 | ⚠️ fixture 추가로 인한 2개 기존 테스트 실패 수정 필요

  • R
    rails-dev question_id 검증 로직 subset 방식으로 수정 완료
    상세 보기

    ## 문제
    - 기존: `submitted_ids.sort == valid_question_ids.sort` (정확 일치 요구)
    - 클라이언트는 90개(60긍정 + 30선택부정) 전송, 서버에는 105개(60긍정 + 45부정)
    - → 항상 422 실패

    ## 수정 내용
    - subset 검증으로 변경: `submitted_ids`가 `valid_question_ids`의 부분집합인지 확인
    - 최소 응답 수 검증: `valid_question_ids.size / 2` 이상 필요
    - invalid ID 검증: 비-big5 문항 ID 거부

    ## 테스트 변경
    - fixture: quality당 부정 문항 1개 → 3개 (production과 동일 구조)
    - 새 테스트: subset 수락, 비-big5 ID 거부, 너무 적은 응답 거부
    - 48 runs, 129 assertions, 0 failures

    ## 변경 파일
    - `app/controllers/diagnosis_sessions_controller.rb`
    - `test/controllers/diagnosis_sessions_controller_test.rb`
    - `test/fixtures/survey_questions.yml`

  • C
    client-dev Stimulus 컨트롤러 구현 완료
    상세 보기

    ## 변경 파일

    ### 새 파일
    - `app/javascript/controllers/big5_batch_controller.js` — Big5 일괄 처리 Stimulus 컨트롤러

    ### 수정 파일
    - `app/controllers/diagnosis_sessions_controller.rb` — `prepare_all_big5_rounds` + `generate_big5_round_sequence` private 메서드 추가, show 액션에 1줄 추가
    - `app/views/diagnosis_sessions/big5_show.html.erb` — batch mode로 전면 재작성 (big5-batch 컨트롤러 사용)
    - `app/views/diagnosis_sessions/_big5_guide.html.erb` — 시작 버튼 action을 big5-batch#startDiagnosis으로 변경

    ## 주요 구현 내용

    ### Stimulus 컨트롤러 (big5_batch_controller.js)
    - 서버에서 모든 라운드 데이터를 JSON으로 받아 클라이언트에서 라운드 전환 (서버 왕복 0회)
    - 카드 선택 → 시각 피드백(250ms) → 자동 다음 라운드
    - "둘 다 해당 안됨" 버튼 지원
    - 30초 카운트다운 타이머 (5초 이하 빨간색 경고)
    - 타임아웃 시 자동으로 "neither"로 제출

    ### sessionStorage 관리
    - 키: `big5_session_${sessionId}`
    - 매 라운드 선택 시 자동 저장 (currentRound + responses 배열)
    - 페이지 새로고침 시 복원하여 이어하기
    - 완료 시 자동 삭제

    ### 최종 제출
    - 마지막 라운드 완료 → fetch POST `/submit_all_big5_responses` (JSON)
    - 성공: server redirect_url → Turbo.visit(), 또는 완료 화면 표시
    - 실패: 에러 화면 + "다시 시도" 버튼

    ### 라운드 사전 생성 (서버)
    - `prepare_all_big5_rounds`: session ID 시드 기반 결정론적 RNG 사용
    - 페이지 새로고침해도 같은 라운드 순서 (sessionStorage 호환)
    - N+1 방지: `includes(:translations)` 사용
    - 번역 없는 문항 자동 필터링

    ## 주의 사항
    - backend-dev의 `submit_all_big5_responses` 액션이 submitted_ids == valid_question_ids 검증 사용 중. 클라이언트는 90개(60긍정 + 30선택부정)만 보내는데, valid는 105개(45부정 포함)이므로 검증 불일치 가능. 검증 로직 조정 필요.

    ## 테스트
    - 기존 controller 테스트 6개 모두 통과
    - 전체 테스트 847개 중 기존 실패(custom_payments, diagnosis_e2e) 외 추가 실패 없음

  • C
    client-dev 상태 변경: 할 일 → 리뷰
  • R
    rails-dev Server API 구현 완료
    상세 보기

    ## 변경 파일

    ### 구현 파일
    - `app/controllers/diagnosis_sessions_controller.rb` — submit_all_big5_responses 액션 추가, N+1 제거 (submit_big5_round, submit_part2_round), RecordNotUnique rescue 추가
    - `app/services/diagnosis/session_manager.rb` — save_responses_bulk 메서드 추가 (upsert_all 사용), save_response에 RecordNotUnique retry 추가
    - `config/routes.rb` — post :submit_all_big5_responses 라우트 추가

    ### 테스트 파일
    - `test/controllers/diagnosis_sessions_controller_test.rb` — 신규 (6개 테스트: submit_all_big5_responses 4개 + N+1 제거 검증 2개)
    - `test/services/diagnosis/session_manager_test.rb` — save_responses_bulk 테스트 2개 추가
    - `test/fixtures/diagnosis_categories.yml` — big5 category 추가
    - `test/fixtures/diagnosis_types.yml` — big5_adult type 추가
    - `test/fixtures/diagnosis_sessions.yml` — big5 세션 2개 추가
    - `test/fixtures/survey_questions.yml` — big5 문항 12개 추가
    - `test/controllers/admin/users_controller_test.rb` — fixture 수 변경 반영
    - `test/integration/admin/users_test.rb` — fixture 수 변경 반영

    ## 주요 변경 사항
    1. **submit_all_big5_responses**: 90개 응답 일괄 제출 API. 세션 상태, question_id 유효성, 응답 수 검증 후 upsert_all로 저장 → complete 처리
    2. **save_responses_bulk**: DiagnosisResponse.upsert_all로 1회 쿼리에 전체 응답 저장. unique index(idx_responses_session_question) 기반 upsert
    3. **N+1 제거**: submit_big5_round와 submit_part2_round에서 SurveyQuestion.find(qid)를 SurveyQuestion.where(id:).index_by(&:id)로 변경
    4. **RecordNotUnique rescue**: save_response의 find_or_initialize_by 레이스 컨디션 방어

    ## 테스트 결과
    - 46 runs, 124 assertions, 0 failures, 0 errors, 0 skips

  • R
    rails-dev 상태 변경: 할 일 → 리뷰
  • C
    client-dev Stimulus 컨트롤러 구현 시작
    상세 보기

    ## 작업 시작
    - Big5 일괄 처리 Stimulus 컨트롤러 구현
    - sessionStorage 백업/복원
    - 클라이언트 라운드 전환
    - 최종 일괄 제출 (fetch POST)

  • R
    rails-dev Server API 구현 시작
    상세 보기

    ## 작업 범위
    - submit_all_big5_responses 컨트롤러 액션
    - save_responses_bulk 서비스 메서드
    - N+1 제거 (submit_big5_round, submit_part2_round)
    - 라우트 추가
    - TDD 기반 개발

  • 팀리드 위임: frontend-dev에게 'Client: Stimulus 컨트롤러 + sessionStorage + 라운드 전환' 작업 배정
  • 팀리드 위임: backend-dev에게 'Server: 일괄 제출 API + upsert_all + N+1 제거' 작업 배정
  • 팀리드 작업 시작 - Big5 일괄 제출 + N+1 제거
    상세 보기

    ## 작업 계획
    - 목표: Big5 진단 HTTP 요청 30배 감소 + DB 쿼리 최적화
    - 접근 방식: 서버/클라이언트 분리하여 2명 병렬 개발

    ## 서브 티켓 분해
    1. Server: 일괄 제출 API + upsert_all + N+1 제거 (backend-dev)
    2. Client: Stimulus 컨트롤러 + sessionStorage + 라운드 전환 (frontend-dev)

    ## 현재 상태
    - 보드 현황: backlog 0 / todo 0 / in_progress 3 / review 0 / done 93

  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 2026년 03월 06일
  • C
    code-reviewer 캐싱 코드 품질 리뷰 완료 — Major 이슈 3건 발견
    상세 보기

    ## 리뷰 결과: diagnoses_controller.rb + big5_result_formatter.rb

    ### ✅ 잘된 점
    - `Big5ResultFormatter#find_quality_code`: 인스턴스 변수(`@quality_code_map`) + Redis 2단계 캐싱 설계 우수
    - `build_description_cache`: locale별 일괄 로드로 N+1 완전 방지
    - `expires_in: 30.days`: 불변 진단 결과에 적합한 장기 캐시 설정

    ### 🔴 Major 이슈

    **1. 캐시 무효화 전략 누락** (`diagnoses_controller.rb:58, 324`)
    - 캐시 키: `["diagnosis_result", @session.id, I18n.locale]`
    - 문제: `@session.updated_at` 미포함 → 데이터 변경 후 30일간 stale 캐시 노출 가능
    - 수정: `["diagnosis_result", @session.id, @session.updated_at.to_i, I18n.locale]`

    **2. DRY 위반** (`diagnoses_controller.rb:57-75, 319-341`)
    - `show`/`shared` 메서드에서 동일한 캐시+포맷터 분기 코드 약 20줄 중복
    - 수정: `cached_diagnosis_result(session)` private 헬퍼 추출

    **3. edit_branding 캐시 미사용** (`diagnoses_controller.rb:256`)
    - `show`와 동일한 포맷터를 매번 재계산 (불일관)
    - 수정: `cached_diagnosis_result(@session)` 헬퍼로 통일

    ### 🔵 Minor 이슈
    **locale 파라미터 dead code** (`big5_result_formatter.rb:54,68,87,110`)
    - `format_big5_chart(locale)` 등 메서드에 locale 파라미터가 있지만 내부에서 `@name_suffix` 사용
    - tidy-remove-dead-code: 파라미터 제거 권장

    ### 📋 테스트 커버리지
    - 캐싱 관련 테스트: **전무**
    - Big5ResultFormatter 단위 테스트: **없음**
    - DiagnosesController 직접 테스트: **없음** (API v1만 존재)
    - 추가 필요: 캐시 hit/miss 시나리오, 무효화 테스트

    ### 판정: 조건부 승인 (캐시 키 무효화 전략 수정 후 승인)

  • 팀리드 리뷰 완료 - 승인 (결과 캐싱)
    상세 보기

    ## 리뷰 결과
    - 상태: 승인
    - bin/ci: 기존 이슈만 (변경 파일 관련 신규 이슈 없음)

    ## 코드 품질
    - Rails.cache.fetch 키 설계 적절 (session.id + locale)
    - expires_in: 30.days — 불변 데이터에 적합
    - find_quality_code 2단계 캐싱 (인스턴스 + Rails.cache) 효율적
    - DRY 개선 가능: show/shared 캐싱 코드 헬퍼 추출 권장

    ## 보안
    - PASS (Critical/High 0건)
    - 캐시 키 조작 불가 (DB PK + 서버 locale)
    - 인증/인가 정상 (set_session before_action)

    ## 개선 제안 (별도 티켓)
    - 캐싱 코드 DRY 리팩토링 (private 헬퍼 추출)
    - edit_branding에도 캐시 적용

  • C
    code-reviewer Puma 설정 코드 품질 리뷰 완료 — 조건부 승인
    상세 보기

    ## 리뷰 결과: config/puma.rb + config/deploy.yml

    ### ✅ 잘된 점
    - `WEB_CONCURRENCY: 2`, `RAILS_MAX_THREADS: 5` — 4GB 서버(DigitalOcean) 기준 적절한 설정
    - `preload_app!` 추가로 Copy-on-Write 메모리 최적화 활성화
    - Solid Queue in Puma 단일 서버 배포 최적화

    ### ⚠️ Critical 이슈 (즉시 수정 필요)
    **`config/database.yml:4` — DB Connection Pool 부족**
    - 현재: `max_connections: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>` = 5
    - 문제: workers=2, threads=5이면 필요 연결수 = 2×5 = 10 + SolidQueue
    - 위험: 프로덕션에서 `ActiveRecord::ConnectionTimeoutError` 발생 가능
    - 수정 방안: `DB_POOL: 10`을 deploy.yml에 추가하고 database.yml에서 참조

    ### 🔵 Minor 이슈
    **`config/puma.rb:40` — preload_app! 조건 없음**
    - workers=0일 때도 무조건 실행 (기능적 문제는 없으나 명확성 부족)
    - 개선: `preload_app! if ENV.fetch("WEB_CONCURRENCY", 0).to_i > 0`

    ### 판정: 조건부 승인 (DB pool Critical 수정 후 최종 승인)

  • 팀리드 리뷰 완료 - 승인 (Puma 튜닝)
    상세 보기

    ## 리뷰 결과
    - 상태: 승인
    - bin/ci: 기존 이슈만 (변경 파일 관련 신규 이슈 없음)

    ## 코드 품질
    - Puma workers 2 + threads 5 설정 적절 (4GB 서버 기준)
    - preload_app! Copy-on-Write 활용 정상
    - database.yml `max_connections` → `pool` 키 변경 필요 (기존 이슈, 별도 티켓)

    ## 보안
    - PASS (Critical/High 0건)
    - deploy.yml 시크릿 관리 정상, localhost 바인딩 확인

    ## 개선 제안 (별도 티켓)
    - database.yml pool 키 수정

  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 팀 작업 완료 - Puma 튜닝 + 결과 캐싱
    상세 보기

    ## 수정된 기능
    - Puma 2워커/5스레드 (동시처리 3→10)
    - 진단 결과 Rails.cache.fetch 캐싱 (Big5/9Way/Engagement)
    - find_quality_code 맵핑 캐시

    ## 변경 파일
    - `config/puma.rb` — workers + preload_app!
    - `config/deploy.yml` — WEB_CONCURRENCY: 2, RAILS_MAX_THREADS: 5
    - `app/controllers/diagnoses_controller.rb` — show/shared 캐싱
    - `app/services/diagnosis/big5_result_formatter.rb` — quality_code_map 캐싱

    ## 테스트 결과
    - 839 runs, 2102 assertions, 5 failures, 7 errors (기존과 동일, 신규 회귀 없음)

    ## QA 발견 사항
    - database.yml의 `max_connections` 키가 Rails `pool`이 아님 — 기존 이슈, 별도 티켓 권장
    - 캐시 무효화 로직 미구현 — 재채점 시 stale 가능, 향후 추가 권장

  • 팀리드 상태 변경: 진행 중 → 리뷰
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • C
    cache-dev 결과 캐싱 구현 완료
    상세 보기

    ## 변경 파일
    - `app/controllers/diagnoses_controller.rb` — show/shared 액션 캐싱
    - `app/services/diagnosis/big5_result_formatter.rb` — quality_code_map 캐싱

    ## 변경 내용
    ### diagnoses_controller.rb (show + shared)
    - 3개 scoring_framework 분기 모두에 `Rails.cache.fetch` 적용
    - 캐시 키: `["diagnosis_result", session.id, I18n.locale]`
    - TTL: 30일 (완료된 진단 결과는 불변)
    - show와 shared 액션 모두 동일 캐시 키 → 같은 결과 공유

    ### big5_result_formatter.rb (find_quality_code)
    - `Rails.cache.fetch("big5:quality_code_map", expires_in: 1.day)` 적용
    - DB pluck 쿼리를 1일 캐싱으로 변경
    - 인스턴스 변수(`@quality_code_map`)는 그대로 유지 → 요청 내 이중 캐싱

    ## 테스트 결과
    - `bin/rails test` 전체 통과 (기존 실패 12건은 캐싱 무관 — custom_payments, admin/payments 등)

  • C
    cache-dev 상태 변경: 할 일 → 리뷰
  • I
    infra-dev Puma 설정 변경 완료
    상세 보기

    ## 변경 사항

    ### config/deploy.yml
    - `WEB_CONCURRENCY: 2` 추가 (env.clear)
    - `RAILS_MAX_THREADS: 5` 추가 (env.clear)

    ### config/puma.rb
    - `workers ENV.fetch("WEB_CONCURRENCY", 0)` 추가
    - `preload_app!` 추가 (CoW 메모리 절약)

    ### config/database.yml
    - 변경 없음 (이미 `RAILS_MAX_THREADS` 기본값 5 사용 중)

    ## 프로덕션 예상 구성
    - 2 workers × 5 threads = 최대 10 동시 요청 처리
    - DB pool: 5 (RAILS_MAX_THREADS와 동일)
    - SOLID_QUEUE_IN_PUMA와 충돌 없음 확인

    ## 테스트
    - `bin/rails test` 실행: 기존 실패(locale 관련) 외 새로운 실패 없음

  • I
    infra-dev 상태 변경: 할 일 → 리뷰
  • C
    cache-dev 결과 캐싱 구현 시작
    상세 보기

    ## 작업 범위
    - `diagnoses_controller.rb` show 액션에 Rails.cache.fetch 적용
    - `big5_result_formatter.rb`의 quality_code_map 캐싱
    - 캐시 키: `["diagnosis_result", session.id, locale]`, expires_in: 30.days

  • I
    infra-dev Puma 설정 변경 시작
  • 팀리드 위임: cache-dev에게 '진단 결과 Rails.cache.fetch 적용' 작업 배정
  • 팀리드 위임: infra-dev에게 'Puma 워커/스레드 + DB 풀 설정' 작업 배정
  • 팀리드 작업 시작 - Puma 튜닝 + 결과 캐싱 병렬 진행
    상세 보기

    ## 작업 계획
    - 목표: Puma 2워커/5스레드 + Big5 결과 캐싱
    - 접근: 2명 개발자 병렬 → QA 검증

    ## 팀 구성
    - infra-dev: Puma/DB 설정 변경
    - cache-dev: 결과 캐싱 구현
    - qa-verifier: 테스트/품질 검증

  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 팀리드 상태 변경: 할 일 → 백로그
  • 2026년 03월 03일
  • C
    claude 상태 변경: 할 일 → 진행 중
  • 2026년 03월 01일
  • 팀리드 팀 작업 완료 - Consumer 연동 가이드 + OmniAuth Strategy
    상세 보기

    ## 수정된 기능
    - **OmniAuth Strategy**: `lib/omniauth/strategies/nineway.rb` — PKCE 지원, /api/v1/me 기반 사용자 정보 조회
    - **연동 가이드**: `docs/api/consumer_integration_guide.md` — 10개 섹션, curl + Rails 코드 예시 포함

    ## 테스트 결과
    - nineway strategy 테스트: 9개 통과
    - 기존 테스트 regression 없음

    ## 생성된 파일
    - `lib/omniauth/strategies/nineway.rb`
    - `test/lib/omniauth/strategies/nineway_test.rb`
    - `docs/api/consumer_integration_guide.md`

    ## 전체 OAuth2 통합 완료 요약
    - 티켓 1: doorkeeper 도입 (OAuth2 Provider) — done
    - 티켓 2: Resource API 구축 (/api/v1) — done
    - 티켓 3: Consumer 연동 가이드 + OmniAuth Strategy — done

  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • D
    docs-dev 상태 변경: 할 일 → 리뷰
  • D
    docs-dev Consumer 연동 가이드 문서 작성 완료
    상세 보기

    ## 작성 파일\n- `docs/api/consumer_integration_guide.md`\n\n## 문서 구성 (10개 섹션)\n1. 개요 - OAuth2 Provider, 지원 Grant Type\n2. 사전 준비 - Application 등록, Scopes 설명\n3. Authorization Code Grant - PKCE 포함 단계별 흐름, curl 예시\n4. Client Credentials Grant - curl 예시\n5. API Endpoints - /me, /diagnoses, /strength_profile 실제 응답 JSON\n6. 사용자 식별 - provider_uid 매핑\n7. 에러 처리 - 401/403/404, Refresh Token\n8. Rails Consumer 빠른 시작 - Gemfile, Strategy, Controller, API Client\n9. Consumer 마이그레이션 테이블\n10. CORS 설정\n\n## 실제 코드 반영\n- doorkeeper.rb: 스코프(profile, email, diagnoses, strengths), 2시간 만료, PKCE 강제\n- profiles_controller.rb: /me 응답 (id, email, name, locale, role 등)\n- diagnoses_controller.rb: diagnoses 응답 (status, locale, diagnosis_type 등)\n- strength_profiles_controller.rb: strength_profile 응답 (top_dna, top_way, scores 등)\n- kakao.rb: OmniAuth strategy 패턴 참고하여 nineway strategy 예시 작성

  • S
    strategy-dev 상태 변경: 할 일 → 리뷰
  • S
    strategy-dev OmniAuth Strategy 구현 및 테스트 완료
    상세 보기

    ## 생성한 파일
    - `lib/omniauth/strategies/nineway.rb` — OmniAuth OAuth2 Strategy
    - `test/lib/omniauth/strategies/nineway_test.rb` — 9개 테스트 (전부 통과)

    ## Strategy 구성
    - **name**: `nineway`
    - **site**: `ENV['NINEWAY_SITE_URL']` (기본값: `https://9way.example.com`)
    - **authorize_url**: `/oauth/authorize`
    - **token_url**: `/oauth/token`
    - **scope**: `profile email`
    - **PKCE**: 활성화 (Doorkeeper의 `force_pkce` 설정에 대응)
    - **raw_info endpoint**: `/api/v1/me`
    - **info 매핑**: `name` → `raw_info["name"]`, `email` → `raw_info["email_address"]`

    ## 테스트 결과
    - 9 runs, 10 assertions, 0 failures, 0 errors
    - 기존 테스트 regression 없음 (기존 3 failures, 7 errors는 Payment/CustomPayment 관련 기존 이슈)

    ## 참조한 파일
    - `lib/omniauth/strategies/kakao.rb` — 기존 패턴 참조
    - `config/initializers/doorkeeper.rb` — scope, PKCE 설정 확인
    - `app/controllers/api/v1/profiles_controller.rb` — 응답 구조 확인 (`email_address` 필드명)

  • D
    docs-dev 작업 시작 - 연동 가이드 문서
    상세 보기

    ## 작업 계획\n- 실제 코드 파악 (doorkeeper, routes, controllers)\n- docs/api/consumer_integration_guide.md 작성\n- 한국어로 작성, 실제 응답 구조 반영

  • S
    strategy-dev 작업 시작 - OmniAuth Strategy
    상세 보기

    ## 작업 범위
    - `lib/omniauth/strategies/nineway.rb` 생성
    - `test/lib/omniauth/strategies/nineway_test.rb` 테스트 작성
    - 기존 kakao strategy 패턴 참조

  • 팀리드 위임: docs-dev에게 'Consumer 서비스 연동 가이드 문서 작성' 작업 배정
  • 팀리드 위임: strategy-dev에게 'OmniAuth Strategy (omniauth-9way) 작성 + 테스트' 작업 배정
  • 팀리드 작업 시작 - Consumer 연동 가이드 + OmniAuth Strategy
    상세 보기

    ## 작업 계획
    - 목표: 외부 서비스가 9WAY OAuth2 Provider에 쉽게 연동할 수 있도록 Strategy + 가이드 제공
    - 접근 방식: 2개 서브 티켓으로 분해
    1. OmniAuth Strategy 작성 + 테스트 (strategy-dev)
    2. 연동 가이드 문서 작성 (docs-dev) — 1번과 병렬 가능

    ## 현재 상태
    - doorkeeper 도입 완료 (티켓 1 done)
    - Resource API 구축 완료 (티켓 2 done)
    - 기존 카카오 strategy (lib/omniauth/strategies/kakao.rb) 참고 가능

  • 팀리드 티켓 클레임 완료
  • 팀리드 팀 작업 완료 - Resource API 구축
    상세 보기

    ## 수정된 기능
    - **API Base Controller**: ActionController::API 기반, doorkeeper 토큰 인증, JSON 에러 핸들링
    - **GET /api/v1/me**: 현재 사용자 프로필 (profile scope)
    - **GET /api/v1/users/:id/diagnoses**: 진단 이력 조회 (diagnoses scope)
    - **GET /api/v1/users/:id/strength_profile**: 강점 프로필 (strengths scope, top_dna/way/domain/scores)
    - **CORS**: rack-cors gem, /api/* 경로만 허용
    - **권한 제어**: Auth Code는 자기 자신만, Client Credentials는 모든 사용자 조회 가능

    ## 테스트 결과
    - API controller 테스트: 28개 통과
    - API 통합 테스트: 14개 통과
    - 기존 doorkeeper 테스트: 20개 통과
    - 기존 인증 테스트: 11개 통과

    ## 생성된 파일
    - `app/controllers/api/v1/base_controller.rb`
    - `app/controllers/api/v1/profiles_controller.rb`
    - `app/controllers/api/v1/users/diagnoses_controller.rb`
    - `app/controllers/api/v1/users/strength_profiles_controller.rb`
    - `config/initializers/cors.rb`
    - `test/controllers/api/v1/` (테스트 파일들)
    - `test/integration/api_v1_test.rb`

    ## 수정된 파일
    - `Gemfile` — rack-cors 추가
    - `config/routes.rb` — API namespace 추가

  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • T
    test-dev 상태 변경: 할 일 → 리뷰
  • T
    test-dev API 통합 테스트 14개 작성 완료 - 전체 통과
    상세 보기

    ## 작성된 테스트 (test/integration/api_v1_test.rb)

    ### GET /api/v1/me (3개)
    - ✅ 유효한 profile scope 토큰으로 200 + id/email/name 확인
    - ✅ 토큰 없이 401
    - ✅ profile scope 없는 토큰으로 403

    ### GET /api/v1/users/:id/diagnoses (4개)
    - ✅ Authorization Code 토큰으로 자기 진단 조회 성공
    - ✅ Client Credentials 토큰으로 조회 성공
    - ✅ diagnoses scope 없으면 403
    - ✅ 다른 사용자 진단 조회 시 403 (Authorization Code)
    - ✅ 응답 필드 검증 (status, diagnosis_type, slug)

    ### GET /api/v1/users/:id/strength_profile (3개)
    - ✅ 강점 프로필 조회 성공 + 응답 구조 검증
    - ✅ strengths scope 없으면 403
    - ✅ 진단 결과 없는 사용자 404

    ### 공통 토큰 검증 (3개)
    - ✅ 만료 토큰 401
    - ✅ 잘못된 토큰 문자열 401
    - ✅ 취소된 토큰 401

    ## 결과
    - 14 tests, 40 assertions, 0 failures, 0 errors
    - 기존 doorkeeper 테스트 20개와 함께 실행해도 전부 통과

  • T
    test-dev 작업 시작 - API 통합 테스트
    상세 보기

    ## 시작 계획
    - GET /api/v1/me 테스트
    - GET /api/v1/users/:id/diagnoses 테스트
    - GET /api/v1/users/:id/strength_profile 테스트
    - 공통: 만료/잘못된 토큰, scope 검증

  • A
    api-dev 상태 변경: 할 일 → 리뷰
  • A
    api-dev 진단/강점 API 구현 완료 - 테스트 20개 전체 통과
    상세 보기

    ## 생성한 파일
    - `app/controllers/api/v1/users/diagnoses_controller.rb` - 진단 세션 목록 API
    - `app/controllers/api/v1/users/strength_profiles_controller.rb` - 강점 프로필 API
    - `test/controllers/api/v1/users/diagnoses_controller_test.rb` - 진단 API 테스트 (10개)
    - `test/controllers/api/v1/users/strength_profiles_controller_test.rb` - 강점 API 테스트 (10개)

    ## 구현 내용

    ### DiagnosesController
    - `GET /api/v1/users/:user_id/diagnoses`
    - `doorkeeper_authorize! :diagnoses` scope 검증
    - Authorization Code: 자기 자신만 조회 가능 (user_id 일치 확인)
    - Client Credentials: user_id로 조회 (제한 없음)
    - 응답: 진단 세션 목록 (id, status, locale, is_primary, start_time, end_time, diagnosis_type)
    - 민감 정보(json_data, share_token, payment_id) 제외

    ### StrengthProfilesController
    - `GET /api/v1/users/:user_id/strength_profile`
    - `doorkeeper_authorize! :strengths` scope 검증
    - 가장 최근 completed 진단의 강점 결과 반환
    - 진단 결과 없으면 404
    - 응답: top_dna(5개), top_way, top_domain, way_scores, domain_scores, session 메타데이터

    ## 테스트 결과
    - API 전체 48개 테스트 통과 (기존 28 + 신규 20)
    - 기존 테스트 regression 없음

  • A
    api-dev 작업 시작 - 진단/강점 API
    상세 보기

    ## 구현 대상
    - `app/controllers/api/v1/users/diagnoses_controller.rb` - 진단 세션 목록 API
    - `app/controllers/api/v1/users/strength_profiles_controller.rb` - 강점 프로필 API

    ## 모델 구조 파악 완료
    - DiagnosisSession: status, json_data, user_id, diagnosis_type_id
    - DiagnosisType → DiagnosisCategory + DiagnosisTarget
    - Diagnosis::ResultFormatter → json_data에서 강점 데이터 추출
    - Doorkeeper scopes: diagnoses, strengths

  • B
    backend-dev 상태 변경: 할 일 → 리뷰
  • B
    backend-dev API Base Controller + /me endpoint 구현 완료
    상세 보기

    ## 변경 사항

    ### 신규 파일
    - `app/controllers/api/v1/base_controller.rb` — API 기본 컨트롤러
    - `ActionController::API` 기반 (세션/CSRF 없음)
    - `doorkeeper_authorize!` 인증
    - JSON 에러 핸들링 (RecordNotFound, DoorkeeperError)
    - `doorkeeper_unauthorized_render_options` / `doorkeeper_forbidden_render_options` 오버라이드
    - `current_resource_owner` 헬퍼 메서드
    - `app/controllers/api/v1/profiles_controller.rb` — GET /api/v1/me
    - `profile` 스코프 필수
    - 응답: id, email, name, locale, role, email_verified_at, created_at
    - `config/initializers/cors.rb` — CORS 설정
    - `/api/*` 경로만 모든 origin 허용
    - `test/controllers/api/v1/base_controller_test.rb` — Base 컨트롤러 테스트 (2개)
    - `test/controllers/api/v1/profiles_controller_test.rb` — Profiles 컨트롤러 테스트 (6개)

    ### 수정 파일
    - `Gemfile` — `rack-cors` gem 추가
    - `config/routes.rb` — `namespace :api / :v1` 추가 (me, users/diagnoses, users/strength_profile)

    ### 라우트
    | Method | Path | Controller#Action |
    |--------|------|-------------------|
    | GET | /api/v1/me | api/v1/profiles#show |
    | GET | /api/v1/users/:user_id/diagnoses | api/v1/users/diagnoses#show |
    | GET | /api/v1/users/:user_id/strength_profile | api/v1/users/strength_profiles#show |

    ### 테스트 결과
    - API 테스트 8개 + 기존 doorkeeper 테스트 20개 = 28개 모두 통과
    - 기존 테스트 regression 없음

  • B
    backend-dev 작업 시작 - API Base Controller + /me endpoint 구현
  • 팀리드 위임: test-dev에게 'Resource API 통합 테스트' 작업 배정
  • 팀리드 위임: api-dev에게 'diagnoses + strength_profile API endpoints' 작업 배정
  • 팀리드 위임: backend-dev에게 'API Base Controller + routes + /me endpoint' 작업 배정
  • 팀리드 작업 시작 - Resource API 구축
    상세 보기

    ## 작업 계획
    - 목표: doorkeeper Bearer 토큰 기반 Resource API 구축
    - 접근 방식: 3개 서브 티켓으로 분해
    1. API Base Controller + routes + /me endpoint (backend-dev)
    2. diagnoses + strength_profile endpoints (api-dev) — 1번 의존
    3. API 통합 테스트 (test-dev) — 1, 2번 의존

    ## 현재 상태
    - doorkeeper 도입 완료 (티켓 1 done)
    - 현재 API 구조 없음 — 전체 신규 생성

  • 팀리드 티켓 클레임 완료
  • 팀리드 팀 작업 완료 - doorkeeper 도입
    상세 보기

    ## 수정된 기능
    - **OAuth2 Provider**: doorkeeper v5.8.2 설치, Authorization Code + Client Credentials Grant 지원
    - **DB 마이그레이션**: oauth_applications, oauth_access_grants, oauth_access_tokens 테이블 (UUID PK)
    - **PKCE 지원**: code_challenge/code_challenge_method 칼럼 추가
    - **어드민 UI**: OAuth Application CRUD (검색, 정렬, 페이지네이션), client_secret 1회 노출
    - **인증 통합**: 기존 Cookie Session/OmniAuth/Magic Link와 병행 운영

    ## 테스트 결과
    - doorkeeper 통합 테스트: 20개 통과
    - 어드민 OAuth App 테스트: 16개 통과
    - 기존 인증 회귀 테스트: 11개 통과

    ## 생성된 파일
    - `config/initializers/doorkeeper.rb`
    - `db/migrate/*_create_doorkeeper_tables.rb`
    - `db/migrate/*_enable_pkce.rb`
    - `app/controllers/admin/oauth_applications_controller.rb`
    - `app/views/admin/oauth_applications/` (5개 뷰)
    - `test/integration/doorkeeper_oauth_test.rb`
    - `test/controllers/admin/oauth_applications_controller_test.rb`

    ## 수정된 파일
    - `Gemfile` — doorkeeper 추가
    - `config/routes.rb` — use_doorkeeper + admin routes
    - `app/models/user.rb` — doorkeeper 관계 추가
    - `app/views/admin/shared/_sidebar.html.erb` — OAuth 앱 메뉴
    - `config/locales/ko.yml` — 번역 추가

    ## 남은 이슈
    - 기존 payments 관련 테스트 실패 10건 (doorkeeper 무관, 기존 버그)

  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • B
    backend-dev PKCE 마이그레이션 추가 완료
    상세 보기

    ## 변경사항
    - `db/migrate/20260301002523_enable_pkce.rb` 실행
    - `oauth_access_grants` 테이블에 `code_challenge`(string, nullable) 칼럼 추가
    - `oauth_access_grants` 테이블에 `code_challenge_method`(string, nullable) 칼럼 추가
    - UUID 관련 영향 없음 (칼럼 추가만)
    - 인증 테스트 11/11 통과 확인

  • A
    admin-dev 상태 변경: 할 일 → 리뷰
  • A
    admin-dev OAuth Application 어드민 관리 UI 구현 완료
    상세 보기

    ## 변경 사항

    ### 새로 생성한 파일
    - `app/controllers/admin/oauth_applications_controller.rb` - CRUD 컨트롤러 (index, show, new, create, edit, update, destroy)
    - `app/views/admin/oauth_applications/index.html.erb` - 목록 (검색, 정렬, 페이지네이션)
    - `app/views/admin/oauth_applications/show.html.erb` - 상세 (client_id, secret 경고, 토큰 목록)
    - `app/views/admin/oauth_applications/new.html.erb` - 생성 폼
    - `app/views/admin/oauth_applications/edit.html.erb` - 수정 폼
    - `app/views/admin/oauth_applications/_form.html.erb` - 공유 폼 partial
    - `test/controllers/admin/oauth_applications_controller_test.rb` - 16개 테스트 (전체 통과)

    ### 수정한 파일
    - `config/routes.rb` - `resources :oauth_applications` 추가
    - `app/views/admin/shared/_sidebar.html.erb` - OAuth 앱 메뉴 추가
    - `app/views/admin/shared/_nav_item.html.erb` - OAuth 아이콘(key) 추가
    - `config/locales/ko.yml` - 한국어 번역 추가

    ### 주요 기능
    - Doorkeeper::Application 모델 CRUD
    - client_secret은 생성 직후에만 flash로 1회 표시
    - 이름 검색, 정렬(name, created_at, confidential)
    - Access Token 목록 (최근 10개, 상태 표시)
    - 기존 어드민 UI 패턴(Tailwind) 일관성 유지
    - 권한 보호 (admin only)

    ### 테스트 결과
    - 16 tests, 50 assertions, 0 failures, 0 errors

  • T
    test-dev 상태 변경: 진행 중 → 리뷰
  • T
    test-dev doorkeeper 통합 테스트 20개 작성 완료 - 전체 통과
    상세 보기

    ## 테스트 파일
    `test/integration/doorkeeper_oauth_test.rb`

    ## 테스트 항목 (20개, 전체 통과)

    ### Authorization Code Grant (5개)
    - ✅ 전체 흐름: authorize → code → token 교환 (confidential client)
    - ✅ token info 엔드포인트 정상 응답
    - ✅ 잘못된 code → invalid_grant 에러
    - ✅ 비인증 사용자 → 로그인 페이지 리다이렉트
    - ✅ 잘못된 redirect_uri → 400 에러

    ### PKCE - Public Client (2개)
    - ✅ code_challenge/code_verifier 포함 시 정상 동작
    - ✅ code_challenge 없는 public client 요청 → 400 에러

    ### Client Credentials Grant (3개)
    - ✅ confidential client → token 발급 성공
    - ✅ 잘못된 secret → invalid_client 에러
    - ✅ 존재하지 않는 client → invalid_client 에러

    ### Refresh Token (2개)
    - ✅ refresh_token → 새 access_token 발급
    - ✅ 잘못된 refresh_token → invalid_grant 에러

    ### Token Revocation (1개)
    - ✅ revoke 후 token 무효화 확인

    ### Token Expiration (1개)
    - ✅ 만료된 token → unauthorized

    ### Scope Validation (1개)
    - ✅ 존재하지 않는 scope → 400 에러

    ### Admin Application Management (2개)
    - ✅ admin → OAuth 앱 관리 접근 가능
    - ✅ 일반 사용자 → 리다이렉트

    ### 기존 인증 회귀 테스트 (3개)
    - ✅ magic link 로그인 정상 동작
    - ✅ 세션 로그아웃 정상 동작
    - ✅ 비인증 홈페이지 접근 정상 동작

    ## 기존 인증 테스트 회귀 검증
    - `test/integration/authentication_test.rb`: 11개 전체 통과 ✅

    ## 발견 이슈 (참고)
    - **PKCE 칼럼 미생성**: `oauth_access_grants` 테이블에 `code_challenge`, `code_challenge_method` 칼럼이 없어 PKCE 검증이 불완전함. `rails g doorkeeper:pkce` 마이그레이션 필요.
    - 기존 실패 (doorkeeper 무관): Admin::PaymentsTest 3 failures, CustomPaymentsTest 7 errors

    ## 전체 테스트 실행 결과
    - 788 runs, 1994 assertions
    - doorkeeper 관련 0 failures, 0 errors
    - 기존 3 failures, 7 errors (doorkeeper 무관)

  • A
    admin-dev 작업 시작 - 어드민 OAuth App UI
    상세 보기

    ## 작업 계획
    - Admin::OauthApplicationsController CRUD 생성
    - 뷰 파일 생성 (index, show, new, edit, _form)
    - 라우트 추가
    - 사이드바 네비게이션 메뉴 추가
    - 한국어 locale 추가

  • T
    test-dev 작업 시작 - doorkeeper 통합 테스트 작성
    상세 보기

    ## 사전 분석 완료
    - 기존 인증 패턴 파악 (cookie-based session, magic link)
    - test_helper.rb의 sign_in_as 헬퍼 확인
    - fixtures 구조 파악 (users.yml 등)
    - doorkeeper 설정 확인 (grant_flows, scopes, PKCE 등)

    ## 작업 계획
    1. doorkeeper 최종 설정 확인
    2. OAuth Application fixture 생성
    3. Authorization Code Grant 흐름 테스트
    4. Client Credentials Grant 테스트
    5. Refresh Token 테스트
    6. 기존 인증 회귀 테스트
    7. 전체 테스트 실행 검증

  • T
    test-dev 티켓 클레임 완료
  • B
    backend-dev 상태 변경: 진행 중 → 리뷰
  • B
    backend-dev doorkeeper 설치 + DB 마이그레이션 + 설정 + 인증 통합 완료
    상세 보기

    ## 변경한 파일

    ### 1. `Gemfile` — doorkeeper gem 추가
    - `gem "doorkeeper"` 추가 (v5.8.2 설치됨)

    ### 2. `db/migrate/20260301001535_create_doorkeeper_tables.rb` — UUID PK 마이그레이션
    - `oauth_applications` — UUID PK
    - `oauth_access_grants` — UUID PK, `resource_owner_id`(uuid → users FK), `application_id`(uuid → oauth_applications FK)
    - `oauth_access_tokens` — UUID PK, `resource_owner_id`(uuid → users FK), `application_id`(uuid → oauth_applications FK)
    - 모든 FK에 인덱스 추가

    ### 3. `config/initializers/doorkeeper.rb` — OAuth2 Provider 설정
    - `resource_owner_authenticator`: 기존 cookie 기반 세션 인증 활용 (cookies.signed[:session_id])
    - `admin_authenticator`: admin? 체크
    - `grant_flows`: authorization_code, client_credentials
    - `access_token_expires_in`: 2시간
    - `use_refresh_token`: 활성화
    - `default_scopes`: :profile
    - `optional_scopes`: :email, :diagnoses, :strengths
    - `force_pkce`: 공개 클라이언트 보안 강화
    - `force_ssl_in_redirect_uri`: production에서 강제

    ### 4. `config/routes.rb` — `use_doorkeeper` 추가
    - `/oauth/authorize`, `/oauth/token`, `/oauth/revoke`, `/oauth/introspect` 등 엔드포인트 활성화
    - `/oauth/applications` 관리 UI 라우트 포함

    ### 5. `app/models/user.rb` — doorkeeper 관계 추가
    - `has_many :access_grants` (Doorkeeper::AccessGrant)
    - `has_many :access_tokens` (Doorkeeper::AccessToken)

    ### 6. `config/locales/doorkeeper.en.yml` — doorkeeper 기본 로케일 (자동 생성)

    ## 테스트 결과
    - 기존 인증 테스트(authentication_test.rb): **11/11 통과** ✅
    - 전체 테스트: 기존 실패(payments 3건, custom_payments 7건)는 doorkeeper와 무관한 기존 버그
    - doorkeeper가 기존 인증(Cookie Session, OmniAuth, Magic Link)에 영향 없음 확인

  • T
    test-dev 대기 중 - #1 태스크(doorkeeper 설치) 완료 대기, 기존 테스트 패턴 사전 분석 시작
  • B
    backend-dev 작업 시작 - doorkeeper 설치
    상세 보기

    ## 작업 계획
    1. 기존 프로젝트 구조 파악 (인증, 모델, 라우트)
    2. Gemfile에 doorkeeper 추가 + bundle install
    3. doorkeeper:install 제너레이터 실행
    4. 마이그레이션 UUID PK로 수정
    5. db:migrate 실행
    6. initializer 설정
    7. routes 설정
    8. 기존 인증 테스트 확인

  • B
    backend-dev 티켓 클레임 완료
  • 팀리드 위임: test-dev에게 'doorkeeper 통합 테스트' 작업 배정
  • 팀리드 위임: admin-dev에게 'OAuth Application 어드민 관리 UI' 작업 배정
  • 팀리드 위임: backend-dev에게 'doorkeeper 설치 + DB 마이그레이션 + 설정 + 인증 통합' 작업 배정
  • 팀리드 작업 시작 - doorkeeper 도입
    상세 보기

    ## 작업 계획
    - 목표: 9WAY를 OAuth2 Provider로 전환 (doorkeeper gem)
    - 접근 방식: 3개 서브 티켓으로 분해하여 팀 병렬 작업
    1. doorkeeper 설치 + 마이그레이션 + 설정 + 인증 통합 (backend-dev)
    2. OAuth Application 어드민 관리 UI (admin-dev) — 1번 의존
    3. 통합 테스트 (test-dev) — 1번 의존

    ## 현재 상태
    - 보드 현황: backlog 0 / todo 2 / in_progress 1 / review 0 / done 78
    - 관련 기존 작업: 기존 인증 시스템 (OmniAuth, Magic Link, Session) 유지하면서 병행

  • 팀리드 티켓 클레임 완료
  • 2026년 02월 28일
  • 팀리드 기능 계획 수립 - Consumer 연동 가이드
    상세 보기

    ## 배경
    - 기존 카카오 OmniAuth strategy(lib/omniauth/strategies/kakao.rb) 참고하여 9WAY strategy 작성
    - 티켓 1, 2 완료 후 진행

    ## 의존성
    - 티켓 1 (doorkeeper 도입) + 티켓 2 (API 구축) 완료 후 진행

  • 팀리드 기능 계획 수립 - Resource API
    상세 보기

    ## 배경
    - 현재 API 구조 없음 (app/controllers/api/ 부재)
    - 전체 신규 설계 필요
    - doorkeeper 티켓 완료 후 착수

    ## 의존성
    - 티켓 1 (doorkeeper 도입) 완료 후 진행

  • 팀리드 기능 계획 수립 - OAuth2 Provider 통합
    상세 보기

    ## 기능 개요
    - 9WAY를 OAuth2 Provider로 전환하여 커리어 관리, 채용, 교육 서비스가 9WAY 계정으로 SSO 로그인

    ## 분석 결과
    - 영향 범위: User 모델(관계 추가), routes.rb, Gemfile
    - 기존 패턴: OmniAuth(Google/Kakao), Magic Link, Cookie Session — 모두 충돌 없이 병행 가능
    - DB: doorkeeper 테이블 4개 추가 (기존 테이블 변경 없음, UUID 설정 필요)

    ## 생성된 티켓
    1. 9WAY에 doorkeeper 도입 (priority: high)
    2. Resource API 구축 (priority: high)
    3. Consumer 연동 가이드 (priority: medium)

    ## 리스크
    - 기존 인증과 충돌: 🟢 낮음 (웹=Cookie, API=Bearer 이원화)
    - DB 마이그레이션: 🟢 낮음 (추가만, 변경 없음)
    - UUID 호환: 🟡 중간 (doorkeeper 기본 integer → UUID 설정 필요)

    ## 기술적 결정
    - doorkeeper gem 사용 (Rails OAuth2 Provider 표준)
    - 웹 인증과 API 인증 이원화 (기존 시스템 보존)
    - Authorization Code Grant (사용자 로그인) + Client Credentials Grant (서버 간 통신)

  • 팀리드 팀 작업 완료 - 할인코드
    상세 보기

    ## 수정된 기능

    ### 1. DB + 모델 (model-dev)
    - `discount_codes` 테이블 (이름, 코드, 유형, 값, 적용상품, 사용횟수, 최소금액, 만료일, 활성화)
    - `discount_code_products` 조인 테이블
    - `payments.discount_code_id` string→UUID FK 변환
    - DiscountCode 모델 (enum, scopes, validations, calculate_discount, usable?, use!)
    - DiscountCodeProduct 모델
    - Payment 모델에 belongs_to :discount_code 추가

    ### 2. 서비스 (model-dev)
    - `DiscountCodes::ValidationService` - 코드 유효성 검증 (존재, 활성, 만료, 사용횟수, 최소금액, 상품 적용)
    - `DiscountCodes::ApplyService` - 사용 기록 (current_uses 증가 + payment 연결)

    ### 3. 어드민 CRUD (admin-dev)
    - `Admin::DiscountCodesController` (index, show, new, create, edit, update, toggle_active)
    - 뷰: index(검색/필터/정렬/페이지네이션), show, _form, new, edit
    - 사이드바에 "Discount Codes" 메뉴 추가
    - 라우트: admin 네임스페이스에 discount_codes 리소스
    - 로케일: en, ko, zh, vi 4개 언어

    ### 4. 결제 통합 (payment-dev)
    - `DiscountCodesController#validate` JSON API (POST /discount_codes/validate)
    - Stimulus `discount_code_controller.js` (입력→검증→UI 업데이트)
    - `_discount_code.html.erb` partial
    - PaymentsController checkout/success에 할인코드 로직 통합
    - CheckoutService에 discount_code_id 파라미터 추가
    - 서버측 재검증으로 보안 강화

    ## 테스트 결과
    - 전체: **752 runs, 1916 assertions, 0 failures, 0 errors**
    - 신규 테스트: 모델 37개 + 서비스 16개 + 어드민 통합 25개 + 결제 컨트롤러 16개

    ## 남은 이슈
    - 없음

  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • P
    payment-dev 상태 변경: 진행 중 → 리뷰
  • P
    payment-dev 결제 흐름 할인코드 통합 구현 완료
    상세 보기

    ## 변경 사항

    ### 새 파일 생성
    - `app/controllers/discount_codes_controller.rb` - 할인코드 검증 API 엔드포인트
    - `app/javascript/controllers/discount_code_controller.js` - Stimulus 할인코드 UI 컨트롤러
    - `app/views/payments/_discount_code.html.erb` - 할인코드 입력 재사용 Partial
    - `test/controllers/discount_codes_controller_test.rb` - 검증 API 테스트 (9건)
    - `test/controllers/payments_controller_test.rb` - 결제+할인코드 통합 테스트 (7건)

    ### 수정 파일
    - `config/routes.rb` - `POST /discount_codes/validate` 라우트 추가
    - `app/controllers/payments_controller.rb` - checkout에 할인코드 검증/적용 로직, success에 ApplyService 호출
    - `app/services/payments/checkout_service.rb` - `discount_code_id:` 파라미터 추가
    - `config/locales/ko.yml` - discount_codes 번역 추가
    - `config/locales/en.yml` - discount_codes 번역 추가
    - `config/locales/zh.yml` - discount_codes 번역 추가
    - `config/locales/vi.yml` - discount_codes 번역 추가

    ### 보안 수정
    - 클라이언트가 임의의 discount_amount를 전달해도 서버에서 항상 재검증
    - discount_code_id가 유효하지 않으면 discount_amount = 0으로 강제

    ### 테스트 결과
    - 752 runs, 1916 assertions, 0 failures, 0 errors, 0 skips

  • A
    admin-dev 상태 변경: 진행 중 → 리뷰
  • A
    admin-dev 어드민 할인코드 CRUD 구현 완료 - 전체 테스트 통과
    상세 보기

    ## 구현 완료 내역

    ### 생성된 파일
    - `app/controllers/admin/discount_codes_controller.rb` - CRUD + toggle_active (7 actions)
    - `app/views/admin/discount_codes/index.html.erb` - 검색/필터/정렬/페이지네이션
    - `app/views/admin/discount_codes/show.html.erb` - 상세 뷰 (적용 상품, 최근 결제)
    - `app/views/admin/discount_codes/_form.html.erb` - 생성/수정 폼
    - `app/views/admin/discount_codes/new.html.erb` - 신규 생성
    - `app/views/admin/discount_codes/edit.html.erb` - 수정
    - `test/integration/admin/discount_codes_test.rb` - 25개 통합 테스트

    ### 수정된 파일
    - `config/routes.rb` - admin 네임스페이스에 discount_codes 리소스 추가
    - `app/views/admin/shared/_sidebar.html.erb` - 할인코드 네비 아이템 추가
    - `app/views/admin/shared/_nav_item.html.erb` - discount_codes 아이콘 추가
    - `config/locales/en.yml` - 영어 번역 추가
    - `config/locales/ko.yml` - 한국어 번역 추가
    - `config/locales/zh.yml` - 중국어 번역 추가
    - `config/locales/vi.yml` - 베트남어 번역 추가

    ### 테스트 결과
    - 할인코드 테스트: 25 runs, 48 assertions, 0 failures, 0 errors
    - 전체 테스트: 736 runs, 1876 assertions, 0 failures, 0 errors

    ### 구현 기능
    - 접근 제어 (admin only)
    - 목록 (검색/필터/정렬/페이지네이션)
    - 상세 조회 (적용 상품, 최근 결제 내역)
    - 생성 (코드 자동생성, 상품 선택)
    - 수정
    - 활성/비활성 토글

  • M
    model-dev 상태 변경: 진행 중 → 리뷰
  • M
    model-dev 모델/서비스 구현 완료
    상세 보기

    ## 생성한 파일
    ### 마이그레이션
    - `db/migrate/20260228140000_create_discount_codes.rb` - discount_codes 테이블 생성
    - `db/migrate/20260228140001_create_discount_code_products.rb` - 조인 테이블 생성
    - `db/migrate/20260228140002_convert_discount_code_id_to_reference.rb` - payments.discount_code_id를 string→uuid FK 변환

    ### 모델
    - `app/models/discount_code.rb` - enum, validations, scopes, calculate_discount, usable?, use!, applicable_to?
    - `app/models/discount_code_product.rb` - belongs_to 연관관계, uniqueness 검증

    ### 서비스
    - `app/services/discount_codes/validation_service.rb` - 할인코드 유효성 검증 (Result 패턴)
    - `app/services/discount_codes/apply_service.rb` - 할인코드 적용 (current_uses 증가, payment 연결)

    ### Fixture
    - `test/fixtures/discount_codes.yml` - 7개 (percentage_active, fixed_active, expired, maxed_out, inactive, applies_to_specific, unlimited_uses)
    - `test/fixtures/discount_code_products.yml` - 1개

    ### 테스트
    - `test/models/discount_code_test.rb` - 33개 테스트
    - `test/models/discount_code_product_test.rb` - 4개 테스트
    - `test/services/discount_codes/validation_service_test.rb` - 12개 테스트
    - `test/services/discount_codes/apply_service_test.rb` - 4개 테스트

    ### 기존 모델 수정
    - `app/models/payment.rb` - `belongs_to :discount_code, optional: true` 추가

    ## 테스트 결과
    전체 711개 테스트 통과, 0 failures, 0 errors

  • P
    payment-dev 결제 할인코드 통합 시작
    상세 보기

    ## 기존 코드 분석 완료
    - PaymentsController: checkout/success 흐름 파악
    - CheckoutService: discount_amount 이미 지원
    - ConfirmationService: 결제 확인 후 후처리 흐름 파악
    - config/routes.rb 구조 파악
    - 결제 뷰 파악 (payments/show, custom_payments/show)

    ## 다음 단계
    - model-dev의 DiscountCode 모델/서비스 완료 대기
    - 그 동안 CSRF 안전한 validate 컨트롤러 + 라우트 + Stimulus + 테스트 준비

  • P
    payment-dev 티켓 클레임 완료
  • A
    admin-dev 어드민 CRUD 구현 시작
    상세 보기

    기존 어드민 패턴(컨트롤러, 뷰, 라우트, 로케일) 분석 시작

  • A
    admin-dev 티켓 클레임 완료
  • M
    model-dev 모델/서비스 구현 시작
    상세 보기

    기존 코드 구조 파악 및 TDD 기반 구현 시작

  • M
    model-dev 티켓 클레임 완료
  • 팀리드 위임: payment-dev에게 '결제 흐름에 할인코드 통합' 작업 배정
  • 팀리드 위임: admin-dev에게 '할인코드 어드민 CRUD + UI' 작업 배정
  • 팀리드 위임: model-dev에게 '할인코드 DB 마이그레이션 + 모델 + 서비스' 작업 배정
  • 팀리드 작업 시작 - 할인코드
    상세 보기

    ## 작업 계획
    - 목표: 할인코드 테이블 생성, 결제 시 할인코드 적용, 어드민 관리 메뉴 구현
    - 접근 방식: 3명의 에이전트로 병렬 작업 (모델/서비스, 어드민 UI, 결제 통합)

    ## 코드베이스 분석 결과
    - Payment 모델에 이미 `discount_amount`, `discount_code_id` 필드 존재
    - CheckoutService에 `discount_amount` 파라미터 이미 지원
    - 어드민 CRUD 패턴 확립됨 (Products 참고)
    - DiscountCode 모델만 추가하면 기존 인프라와 자연스럽게 통합 가능

    ## 서브 티켓 분해
    1. **model-dev**: DB 마이그레이션 + 모델 + 서비스 + 테스트
    2. **admin-dev**: 어드민 CRUD (컨트롤러/뷰/라우트/사이드바/로케일) + 테스트
    3. **payment-dev**: 결제 흐름 통합 (할인코드 입력/검증/적용) + 테스트

    ## 현재 상태
    - 보드 현황: backlog 0 / todo 0 / in_progress 1 / review 0 / done 74
    - 관련 기존 작업: 개인 결제/크레딧 기능 (done)

  • 팀리드 티켓 클레임 완료
  • C
    claude 페이지 이탈 분석 기능 구현 완료
    상세 보기

    ## 생성된 파일
    - `db/migrate/20260228124836_create_page_views.rb` - 마이그레이션
    - `app/models/page_view.rb` - 모델
    - `app/controllers/concerns/track_page_view.rb` - 추적 Concern
    - `app/jobs/record_page_view_job.rb` - 비동기 기록 Job
    - `app/jobs/cleanup_page_views_job.rb` - 90일 정리 Job
    - `app/javascript/controllers/page_tracker_controller.js` - Stimulus 컨트롤러
    - `app/controllers/page_views_controller.rb` - 체류 시간 업데이트 엔드포인트
    - `app/views/admin/statistics/page_analysis.html.erb` - 분석 대시보드 뷰
    - `test/models/page_view_test.rb` - 모델 테스트 (14건)
    - `test/integration/admin/statistics_page_analysis_test.rb` - 통합 테스트 (5건)
    - `test/fixtures/page_views.yml` - 테스트 fixture

    ## 수정된 파일
    - `config/routes.rb` - 페이지 분석 라우트 + sendBeacon 엔드포인트
    - `app/controllers/admin/statistics_controller.rb` - page_analysis 액션
    - `app/controllers/application_controller.rb` - include TrackPageView
    - `app/views/admin/statistics/_tab_navigation.html.erb` - 탭 추가
    - `app/views/layouts/application.html.erb` - page-tracker 부착
    - `app/views/layouts/authenticated.html.erb` - page-tracker 부착
    - `app/views/layouts/admin.html.erb` - page-tracker 부착
    - `config/locales/ko.yml` - i18n 키 추가
    - `config/recurring.yml` - 정리 Job 스케줄

    ## 테스트 결과
    636 runs, 1701 assertions, 0 failures, 0 errors

  • C
    claude 상태 변경: 진행 중 → 완료
  • C
    claude 인프라 에이전트 작업 시작
    상세 보기

    infra-dev 에이전트가 DB 마이그레이션, 모델, Job, Concern, Stimulus 컨트롤러, PageViewsController를 구현 중

  • C
    claude 티켓 클레임 완료
  • 팀리드 모든 서브 티켓 완료, 전체 테스트 613개 통과, 부모 티켓 완료 처리
    상세 보기

    ## 완료 요약

    ### 서브 티켓 1: 프로필 탭 네비게이션 (agent-nav) ✅
    - `shared/_profile_tabs.html.erb` 생성 (3탭: 내 정보/결제/크레딧)
    - `profiles/show.html.erb`에 탭 통합
    - `routes.rb`에 credits 라우트 추가
    - 4개 언어 i18n 키 추가

    ### 서브 티켓 2: 개인 크레딧 페이지 (agent-credit) ✅
    - `credits_controller.rb` 구현 (잔액 + 거래내역)
    - `credits/index.html.erb` 구현 (반응형, 빈 상태 처리)
    - `credits_helper.rb` 생성 (거래유형 레이블/배지)

    ### 서브 티켓 3: 결제 UI + 취소 정책 (agent-payment) ✅
    - `payments/index.html.erb`에 탭 + 영수증 링크 + 취소불가 배지
    - `payments/show.html.erb`에 탭 + 리포트 취소 안내
    - `payment.rb` refundable?에 REPORT 제외 조건 추가
    - `cancellation_service.rb`에 REPORT 전용 에러 메시지

    ### 테스트 결과
    613 tests, 1652 assertions, 0 failures, 0 errors

  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 진행 중 → 리뷰
  • A
    agent-payment 결제 UI 개선 및 리포트 취소 불가 정책 구현 완료
    상세 보기

    ## 변경 사항

    ### 1. 모델 수정: `app/models/payment.rb`
    - `refundable?` 메서드에 `&& !payment_type_report?` 조건 추가
    - REPORT 결제는 항상 환불 불가

    ### 2. 서비스 수정: `app/services/payments/cancellation_service.rb`
    - `validate_cancellation!`에 REPORT 전용 에러 메시지 추가
    - "리포트 결제는 취소할 수 없습니다" (refundable? 체크 전에 별도 체크)

    ### 3. 뷰 수정: `app/views/payments/index.html.erb`
    - 상단에 `shared/_profile_tabs` 렌더링 (current_tab: "payments")
    - 리포트 결제에 빨간색 "취소불가" 배지 표시
    - 영수증 URL 존재 시 "영수증 보기" 텍스트 표시

    ### 4. 뷰 수정: `app/views/payments/show.html.erb`
    - 상단에 `shared/_profile_tabs` 렌더링
    - 리포트 결제: 취소 버튼 대신 "리포트 결제는 취소할 수 없습니다" 안내
    - 일반 결제 + refundable?: 기존 취소 버튼 유지

    ### 5. i18n 추가: `config/locales/payments/{ko,en,zh,vi}.yml`
    - `payments.index.non_refundable` (취소불가)
    - `payments.show.report_no_cancel` (리포트 결제는 취소할 수 없습니다)

    ### 6. Fixture 추가: `test/fixtures/payments.yml`
    - `completed_credit_payment` (환불 가능한 일반 결제)
    - `old_completed_credit_payment` (7일 초과 결제)
    - `canceled_payment` (이미 취소된 결제)

    ### 7. 테스트 생성
    - `test/models/payment_test.rb`: refundable? 5개 테스트
    - `test/integration/payments_profile_tab_test.rb`: 탭/배지/취소버튼 6개 테스트

    ## 테스트 결과
    - 전체 613개 테스트 통과, 0 실패

  • A
    agent-credit 상태 변경: 할 일 → 리뷰
  • A
    agent-credit 개인 크레딧 페이지 구현 완료
    상세 보기

    ## 변경 사항
    - `app/controllers/credits_controller.rb` - ensure_credit!, @credit, @transactions 로드 추가
    - `app/views/credits/index.html.erb` - 잔액 카드 + 거래내역 테이블(데스크톱/모바일 반응형) + 빈 상태
    - `app/helpers/credits_helper.rb` - transaction_type_label, transaction_type_badge_class 헬퍼
    - `test/controllers/credits_controller_test.rb` - 6개 통합 테스트 (인증, 잔액 표시, 거래내역, 빈 상태, 탭 표시)

    ## 테스트 결과
    - 전체 602 tests, 0 failures, 0 errors

  • A
    agent-payment 결제 UI 개선 및 취소 정책 구현 시작
    상세 보기

    ## 분석 완료
    - `payment.rb`: refundable?에 REPORT 조건 추가 필요
    - `cancellation_service.rb`: REPORT 전용 에러 메시지 추가 필요
    - `payments/index.html.erb`: 프로필 탭 + 영수증 링크 + 취소불가 배지
    - `payments/show.html.erb`: 프로필 탭 + 리포트 취소 안내
    - `shared/_profile_tabs.html.erb`: 이미 완성됨 (agent-nav)

    ## TDD 순서
    1. Fixture 추가 (analysis_credit 결제)
    2. 모델 테스트 작성 → RED
    3. 모델 구현 → GREEN
    4. CancellationService 업데이트
    5. 통합 테스트 작성 → RED
    6. View 구현 → GREEN

  • A
    agent-payment 티켓 클레임 완료
  • A
    agent-credit 개인 크레딧 페이지 구현 시작
    상세 보기

    ## 작업 범위
    - `app/controllers/credits_controller.rb` 보강
    - `app/views/credits/index.html.erb` 보강
    - `test/controllers/credits_controller_test.rb` 신규 작성

    ## 접근 방식
    TDD: 테스트 작성 → 구현 → 검증

  • 팀리드 이메일 초대 기능 전체 구현 완료
    상세 보기

    ## 완료 내역

    ### 1. Mailer 생성 및 이메일 발송 (mailer-dev)
    - WorkspaceInvitationMailer 생성 (HTML/Text 템플릿)
    - InvitationService.create!에서 target_email 있으면 자동 발송
    - 재발송(resend) 기능 추가

    ### 2. 벌크 이메일 초대 (bulk-dev)
    - bulk_create 액션 + bulk_create! 서비스 메서드
    - textarea 기반 벌크 UI + Stimulus 컨트롤러
    - 이메일 파싱/검증/중복 제거

    ### 3. 멤버 승인 상태 표시 (status-dev)
    - accepted?/accepted_member 모델 헬퍼
    - Pending/Accepted 배지 UI
    - 4개 언어 i18n (en/ko/zh/vi)

    ## 테스트 결과
    - 모델/서비스/Mailer: 48 tests, 100 assertions, 0 failures
    - 컨트롤러: 31 tests, 97 assertions, 0 failures
    - **총 79 tests, 197 assertions, 0 failures**

  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 커스텀 결제 메뉴 기능 구현 완료
    상세 보기

    ## 완료 요약
    3명의 에이전트 팀으로 작업 완료. 총 45건 테스트 통과 (0 failures).

    ## 구현 내역

    ### 1. 백엔드 (모델 + 마이그레이션 + 라우팅 + 서비스)
    - `CustomPaymentLink` 모델 (UUID PK, enum status, token 기반)
    - DB 마이그레이션 (custom_payment_links 테이블)
    - Admin + 공개 라우팅
    - `CreateService`, `CancelService`
    - 모델 테스트 18건 + 서비스 테스트 6건 = 24건 통과

    ### 2. 관리자 UI
    - `Admin::CustomPaymentLinksController` (index, new, create, cancel, qr_code)
    - 결제 링크 목록 (테이블 + 상태 배지 + 복사/취소/QR)
    - 결제 링크 생성 폼
    - 사이드바 메뉴 추가
    - i18n 번역
    - Stimulus 컨트롤러 (clipboard, qr_modal)
    - 통합 테스트 9건 통과

    ### 3. 고객 결제 페이지
    - `CustomPaymentsController` (show, checkout, success, fail)
    - Toss Payments SDK 연동
    - 상태별 뷰 (결제/성공/실패/만료/취소/완료)
    - 전용 레이아웃 (custom_payment)
    - 통합 테스트 12건 통과

  • A
    agent-nav 상태 변경: 할 일 → 완료
  • A
    agent-nav 프로필 탭 네비게이션 + 라우트 + i18n 구현 완료
    상세 보기

    ## 완료 사항

    ### 생성 파일
    - `app/views/shared/_profile_tabs.html.erb` - 3탭(내 정보/결제/크레딧) Partial
    - `app/controllers/credits_controller.rb` - 크레딧 컨트롤러
    - `app/views/credits/index.html.erb` - 크레딧 페이지 (플레이스홀더)
    - `test/integration/profile_tabs_test.rb` - 통합 테스트 6개

    ### 수정 파일
    - `app/views/profiles/show.html.erb` - 탭 렌더 추가
    - `config/routes.rb` - credits 라우트 추가
    - `config/locales/ko.yml` - tabs i18n 추가
    - `config/locales/en.yml` - tabs i18n 추가
    - `config/locales/zh.yml` - tabs i18n 추가
    - `config/locales/vi.yml` - tabs i18n 추가

    ### 테스트 결과
    - 6 tests, 27 assertions, 0 failures
    - 전체 596 tests 통과

  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상품 관리 기능 구현 완료
    상세 보기

    ## 완료 내역

    ### 백엔드 (backend-dev)
    - `config/routes.rb`: admin/products 라우트 추가 (CRUD + toggle_active)
    - `app/controllers/admin/products_controller.rb`: 신규 생성
    - `app/models/product.rb`: accepts_nested_attributes_for 추가

    ### 프론트엔드 (frontend-dev)
    - `app/views/admin/products/`: index, show, new, edit, _form 5개 파일
    - `app/views/admin/shared/_sidebar.html.erb`: products 메뉴 추가
    - `app/views/admin/shared/_nav_item.html.erb`: products 아이콘 추가
    - `config/locales/ko.yml`, `en.yml`: i18n 번역 추가

    ### 테스트 (tester)
    - `test/integration/admin/products_test.rb`: 25개 테스트, 64 assertions, 전체 통과
    - fixtures 보완 (products.yml, product_prices.yml)

  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 통계 관리 기능 구현 완료
    상세 보기

    ## 구현 완료 항목

    ### 인프라
    - Chartkick + Groupdate gem 추가
    - Chart.js importmap 설정
    - 4개 라우트: /admin/statistics, /users, /diagnoses, /revenue
    - 사이드바에 통계 메뉴 + 아이콘 추가

    ### 컨트롤러
    - `Admin::StatisticsController` (4개 액션)
    - show: KPI 카드 + 추이 차트
    - users: 가입 추이, 역할 분포, 활성 사용자
    - diagnoses: 완료 추이, 상태/유형 분포, 완료율
    - revenue: 매출 추이, 결제 유형, 크레딧 사용

    ### 뷰 (5개 파일)
    - `show.html.erb`: 개요 대시보드 (KPI 6개 + 차트 3개)
    - `users.html.erb`: 사용자 분석 (차트 3개 + 테이블)
    - `diagnoses.html.erb`: 진단 분석 (차트 3개 + 테이블)
    - `revenue.html.erb`: 매출 분석 (차트 5개 + 테이블)
    - `_tab_navigation.html.erb`: 공유 탭 네비게이션

    ### 테스트
    - `test/integration/admin/statistics_test.rb` (17 runs, 65 assertions)

    ### 검증
    - Ruby 구문 검증: OK
    - ERB 구문 검증: 5개 파일 모두 OK
    - 라우트 확인: 4개 정상 등록

  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • T
    tester 상태 변경: 할 일 → 리뷰
  • T
    tester Admin Products 통합 테스트 구현 완료, 25개 테스트 전체 통과
    상세 보기

    ## 작업 내용

    ### Fixtures 보완
    - `test/fixtures/products.yml`: `credit_pack_10` (크레딧팩, active), `inactive_product` (비활성 리포트) 추가
    - `test/fixtures/product_prices.yml`: `credit_pack_10_krw` 추가

    ### 통합 테스트 작성 (25개)
    파일: `test/integration/admin/products_test.rb`

    **인증/권한 (3개)**
    - 비인증 사용자 → session/new 리다이렉트
    - 일반 사용자 → root_path 리다이렉트
    - admin 사용자 → 접근 성공

    **Index (8개)**
    - 목록 표시, name 검색(q 파라미터)
    - product_type 필터 (report/credit_pack)
    - active 필터 (true/false)
    - 정렬 (name asc/created_at desc)
    - 복합 검색+필터

    **CRUD (8개)**
    - show: 상세 표시, product_prices 테이블
    - new: 폼 렌더링
    - create: 성공, slug 중복 실패, 필수값 누락 실패
    - edit: 폼 렌더링
    - update: 성공, 실패, nested product_prices

    **Toggle Active (2개)**
    - active → inactive
    - inactive → active

    ### 결과
    - 25 runs, 64 assertions, **0 failures, 0 errors**

  • 결제-페이지 상태 변경: 진행 중 → 리뷰
  • 결제-페이지 고객 결제 페이지 + Toss Payments 연동 구현 완료, 12개 테스트 전부 통과
    상세 보기

    ## 생성된 파일
    - `app/controllers/custom_payments_controller.rb` - 공개 결제 컨트롤러 (show/checkout/success/fail)
    - `app/views/layouts/custom_payment.html.erb` - 심플 레이아웃 (Toss SDK 포함)
    - `app/views/custom_payments/show.html.erb` - 결제 페이지 (로고+상품정보+결제버튼)
    - `app/views/custom_payments/success.html.erb` - 결제 성공 페이지
    - `app/views/custom_payments/fail.html.erb` - 결제 실패 페이지
    - `app/views/custom_payments/expired.html.erb` - 만료 안내 페이지
    - `app/views/custom_payments/canceled.html.erb` - 취소 안내 페이지
    - `app/views/custom_payments/completed.html.erb` - 이미 완료 안내 페이지
    - `app/javascript/controllers/toss_custom_payment_controller.js` - Toss Payments Stimulus 컨트롤러
    - `test/integration/custom_payments_test.rb` - 통합 테스트 12개

    ## 테스트 결과
    12 runs, 33 assertions, 0 failures, 0 errors, 0 skips

    ## 주요 구현 내용
    - `allow_unauthenticated_access`로 인증 skip (공개 페이지)
    - `Payments::CheckoutService` 연동 (checkout 액션)
    - `Payments::ConfirmationService` 연동 (success 액션)
    - 결제 링크 상태별 분기 렌더링 (pending/completed/canceled/expired)
    - Toss Payments v2 SDK + Stimulus 컨트롤러로 결제 플로우 연동
    - locale scope 밖 라우트를 위해 `default_url_options` 오버라이드

  • 팀리드 사용자 관리 기능 전체 완료
    상세 보기

    ## 최종 결과
    - 구현: impl-dev 완료 (5개 태스크)
    - 테스트: test-dev 완료 (30 tests, 90 assertions, 0 failures)

    ## 구현된 기능
    1. 인덱스에 이름/이메일/전화번호/역할/소속워크스페이스/생성일/진단 표시
    2. 역할 뱃지 클릭 시 드롭다운으로 즉시 수정 가능
    3. 진단 수 클릭 시 모달로 진단 목록 표시
    4. 전화번호 검색 지원
    5. i18n 처리 완료

    ## 변경 파일
    - `app/controllers/admin/users_controller.rb`
    - `app/views/admin/users/index.html.erb`
    - `app/views/admin/users/_role_cell.html.erb` (신규)
    - `app/views/admin/users/_diagnosis_modal.html.erb` (신규)
    - `config/routes.rb`
    - `config/locales/ko.yml`
    - `test/controllers/admin/users_controller_test.rb` (신규)
    - `test/integration/admin/users_test.rb` (확장)
    - `test/fixtures/user_profiles.yml` (수정)

  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • T
    test-dev 상태 변경: 진행 중 → 리뷰
  • T
    test-dev 컨트롤러 + 통합 테스트 작성 완료 (30 tests, 90 assertions, 0 failures)
    상세 보기

    ## 작성한 테스트 파일

    ### 1. test/controllers/admin/users_controller_test.rb (신규, 12 tests)
    - 전화번호 검색: 전체 번호, 부분 번호, 미매칭 케이스
    - 인덱스 컬럼: 전화번호, 워크스페이스명, 진단 수 표시 확인
    - update_role: HTML 요청 성공, turbo_stream 응답 성공, 유효하지 않은 역할 에러
    - 권한: 비admin 접근 거부, 비admin 역할 변경 거부, 미인증 리다이렉트

    ### 2. test/integration/admin/users_test.rb (확장, 18 tests)
    - 기존 9개 테스트 유지
    - 추가: coach/org_admin 접근 거부, 전화번호 컬럼, 워크스페이스 컬럼, 진단 수 컬럼, 전화번호 검색, update_role 플로우 (HTML + turbo_stream), 비admin update_role 거부

    ### 3. test/fixtures/user_profiles.yml (수정)
    - daniel_profile에 phone_number/phone_country_code 추가

    ### 인프라 이슈
    - test DB에 CustomPaymentLink 테이블이 누락되어 있었음 → db:schema:load로 해결

  • A
    analytics-dev-2 상태 변경: 할 일 → 리뷰
  • A
    analytics-dev-2 매출 분석 뷰 + 통합 테스트 구현 완료
    상세 보기

    ## 생성된 파일

    ### 1. app/views/admin/statistics/revenue.html.erb
    - KPI 카드 3개: 총 매출, 이번달 매출, 결제 건수
    - 일별 매출 추이 (area_chart, full width)
    - 월별 매출 + 결제 유형별 매출 (column_chart + pie_chart)
    - 결제 상태 분포 + 워크스페이스 크레딧 사용 (pie_chart + bar_chart)
    - 상위 결제 사용자 테이블 (순위, 이름, 이메일, 금액)
    - Tailwind CSS, i18n, Chartkick 헬퍼 활용

    ### 2. test/integration/admin/statistics_test.rb
    - 17개 테스트 케이스, 65개 assertions, 모두 통과
    - 비인증 사용자 접근 차단 (4개 액션)
    - 일반 사용자 접근 차단 (4개 액션)
    - 관리자 정상 접근 (4개 액션 + 제목 확인)
    - revenue 페이지 콘텐츠 검증 (탭, KPI, 차트, 테이블)
    - show 페이지 탭 네비게이션 검증

  • 백엔드 상태 변경: 진행 중 → 리뷰
  • 백엔드 CustomPaymentLink 모델, 마이그레이션, 라우팅, 서비스 구현 완료
    상세 보기

    ## 완료 사항
    - DB 마이그레이션: `20260228072648_create_custom_payment_links.rb` 생성 및 실행 완료
    - 모델: `app/models/custom_payment_link.rb` (enum, validations, scopes, callbacks)
    - 서비스: `CreateService`, `CancelService` 생성
    - 라우팅: admin namespace + 공개 결제 라우트 추가
    - Fixture: pending/completed/canceled/expired 4종 생성
    - 테스트: 모델 테스트 18건 + 서비스 테스트 6건 = 24건 전체 통과

    ## 생성/수정 파일
    - `db/migrate/20260228072648_create_custom_payment_links.rb`
    - `app/models/custom_payment_link.rb`
    - `app/services/custom_payment_links/create_service.rb`
    - `app/services/custom_payment_links/cancel_service.rb`
    - `config/routes.rb`
    - `test/fixtures/custom_payment_links.yml`
    - `test/models/custom_payment_link_test.rb`
    - `test/services/custom_payment_links/create_service_test.rb`
    - `test/services/custom_payment_links/cancel_service_test.rb`

  • M
    mailer-dev 상태 변경: 할 일 → 리뷰
  • M
    mailer-dev Mailer 생성 및 이메일 발송 연동 완료
    상세 보기

    ## 구현 완료 내역

    ### 1. WorkspaceInvitationMailer 생성
    - `app/mailers/workspace_invitation_mailer.rb` - invitation_email 액션
    - `app/views/workspace_invitation_mailer/invitation_email.html.erb` - HTML 템플릿 (MagicLinkMailer 스타일)
    - `app/views/workspace_invitation_mailer/invitation_email.text.erb` - 텍스트 템플릿

    ### 2. InvitationService 이메일 발송 연동
    - `app/services/workspaces/invitation_service.rb`
    - `create!` 메서드 끝에서 target_email이 있으면 이메일 발송 (`deliver_later`)
    - `send_invitation_email` 클래스 메서드 추가 (resend에서도 재사용)
    - rescue로 이메일 발송 실패 시에도 초대 생성은 유지

    ### 3. resend 기능
    - `config/routes.rb` - invitations에 `member { post :resend }` 추가
    - `app/controllers/workspaces/invitations_controller.rb` - resend 액션 추가

    ### 4. i18n (ko/en)
    - `workspace_invitation_mailer.invitation_email.*` 키 추가 (subject, greeting, instruction, button, expires_info, ignore)
    - `workspaces.invitations.flash.resent`, `no_email` 키 추가

    ### 5. 테스트 (34 tests, 105 assertions, 0 failures)
    - `test/mailers/workspace_invitation_mailer_test.rb` - 5 tests
    - `test/services/workspaces/invitation_service_test.rb` - 이메일 관련 3 tests 추가
    - `test/controllers/workspaces/invitations_controller_resend_test.rb` - 3 tests

  • A
    analytics-dev-1 상태 변경: 할 일 → 리뷰
  • A
    analytics-dev-1 사용자 + 진단 분석 뷰 구현 완료
    상세 보기

    ## 생성된 파일
    - `app/views/admin/statistics/users.html.erb` - 사용자 분석 뷰
    - `app/views/admin/statistics/diagnoses.html.erb` - 진단 분석 뷰

    ## users.html.erb
    - KPI 카드 3개: 프로필 완성률, 총 사용자 수, 역할 수
    - 차트: 일별 가입자 추이 (line_chart), 역할 분포 (pie_chart)
    - 월별 활성 사용자 (column_chart, full width)
    - 상위 사용자 테이블 (이름, 이메일, 완료 수)

    ## diagnoses.html.erb
    - KPI 카드 3개: 평균 완료 시간(분 변환), 총 세션, 완료율
    - 차트: 일별 완료 추이 (line_chart), 상태별 분포 (pie_chart)
    - 유형별 분포 (column_chart, full width)
    - 유형별 완료율 테이블 (색상 뱃지: >=70% 녹색, >=40% 노란색, 나머지 빨간색)

    ## 공통 패턴
    - show.html.erb의 디자인 패턴 일관 유지
    - Tailwind CSS + Chartkick
    - i18n 키 활용 (ko.yml의 statistics.users/diagnoses 키)
    - 모바일 반응형 (grid-cols-1 → md/lg breakpoints)

  • 관리자-UI 상태 변경: 진행 중 → 리뷰
  • 관리자-UI 관리자 커스텀 결제 링크 UI 구현 완료, 테스트 9/9 통과
    상세 보기

    ## 생성된 파일
    - `app/controllers/admin/custom_payment_links_controller.rb` - 컨트롤러 (index, new, create, cancel, qr_code)
    - `app/views/admin/custom_payment_links/index.html.erb` - 목록 페이지 (테이블 + QR 모달)
    - `app/views/admin/custom_payment_links/new.html.erb` - 생성 폼
    - `app/javascript/controllers/qr_modal_controller.js` - QR 모달 Stimulus 컨트롤러
    - `test/integration/admin/custom_payment_links_test.rb` - 통합 테스트 9개

    ## 수정된 파일
    - `app/views/admin/shared/_sidebar.html.erb` - 커스텀 결제 메뉴 추가
    - `app/views/admin/shared/_nav_item.html.erb` - custom_payments 아이콘 추가
    - `config/locales/ko.yml` - i18n 키 추가 (nav + custom_payment_links 전체)

    ## 재사용한 기존 코드
    - `clipboard_controller.js` - 복사 기능
    - Admin::BaseController - 인증/권한
    - 기존 admin 테이블 UI 패턴

    ## 테스트 결과
    - 9 runs, 31 assertions, 0 failures, 0 errors

  • A
    analytics-dev-2 매출 분석 뷰 + 통합 테스트 구현 시작
  • A
    analytics-dev-1 사용자 + 진단 분석 뷰 구현 시작
  • 팀리드 인프라 + 컨트롤러 + 개요 대시보드 구현 완료 확인
    상세 보기

    ## 완료된 서브 티켓
    - 서브 티켓 #1 (3fce970e): 인프라 설정 + 통계 컨트롤러 + 개요 대시보드 → review 상태

    ## 다음 단계
    - 서브 티켓 #2: 사용자 + 진단 분석 뷰 (analytics-dev-1 배정)
    - 서브 티켓 #3: 매출 분석 뷰 + 테스트 (analytics-dev-2 배정)
    - 두 에이전트 동시 spawn 진행

  • B
    backend-dev 상태 변경: 할 일 → 리뷰
  • B
    backend-dev 인프라 설정 + 통계 컨트롤러 + 개요 대시보드 구현 완료
    상세 보기

    ## 변경 사항

    ### 1. Gemfile
    - `chartkick` gem 추가 (차트 렌더링)
    - `groupdate` gem 추가 (group_by_day/month 메서드)

    ### 2. importmap + JS 설정
    - `config/importmap.rb`에 chartkick, Chart.bundle pin 추가
    - `app/javascript/application.js`에 import 추가

    ### 3. 라우트
    - `config/routes.rb`의 admin 네임스페이스에 statistics 라우트 4개 추가
    - GET /admin/statistics → show (개요)
    - GET /admin/statistics/users → users
    - GET /admin/statistics/diagnoses → diagnoses
    - GET /admin/statistics/revenue → revenue

    ### 4. 사이드바 + 아이콘
    - `_sidebar.html.erb`에 통계 메뉴 추가
    - `_nav_item.html.erb`에 statistics 아이콘 SVG 추가

    ### 5. 컨트롤러
    - `app/controllers/admin/statistics_controller.rb` 생성
    - show: KPI 메트릭 + 추이 차트 데이터
    - users: 사용자 분석 데이터
    - diagnoses: 진단 분석 데이터
    - revenue: 매출 분석 데이터

    ### 6. 뷰
    - `app/views/admin/statistics/show.html.erb` - 개요 대시보드 (KPI 카드 6개 + 차트 3개)
    - `app/views/admin/statistics/_tab_navigation.html.erb` - 탭 네비게이션 파셜

    ### 7. i18n
    - `config/locales/ko.yml`에 admin.nav.statistics 및 admin.statistics 번역 키 전체 추가

    ### 검증
    - `bin/rails routes | grep statistics` → 4개 라우트 확인
    - Chartkick, Groupdate, Controller 로드 확인

  • F
    frontend-dev 상태 변경: 할 일 → 리뷰
  • F
    frontend-dev 뷰 + 사이드바 + i18n 구현 완료
    상세 보기

    ## 변경 사항

    ### 뷰 파일 (app/views/admin/products/)
    - `index.html.erb`: 검색/필터, 테이블(slug, name, product_type, price, active, created_at), 페이지네이션
    - `show.html.erb`: 상품 정보 카드, active 토글 버튼, 다통화 가격 테이블, metadata 표시
    - `new.html.erb`: 새 상품 등록 폼 래퍼
    - `edit.html.erb`: 상품 수정 폼 래퍼
    - `_form.html.erb`: 공유 폼 (name, slug, description, price, currency, product_type, active, nested product_prices)

    ### 사이드바
    - `_sidebar.html.erb`: diagnosis_sessions과 workspaces 사이에 products 메뉴 추가
    - `_nav_item.html.erb`: "products" 쇼핑백 아이콘 SVG 추가

    ### i18n
    - `ko.yml`: admin.nav.products, admin.products 전체 번역 추가
    - `en.yml`: 동일 구조 영문 번역 추가

    ### 스타일
    - 기존 admin 뷰(workspaces) 패턴과 동일한 CSS 클래스 사용
    - sort_link 헬퍼 활용
    - admin/shared/_pagination 사용

  • 결제-페이지 기존 코드 분석 완료, 컨트롤러/뷰/테스트 작성 시작
    상세 보기

    ## 분석 완료 항목
    - ApplicationController: `Authentication` concern, `allow_unauthenticated_access` 사용
    - PaymentsController: checkout/success/fail 패턴 확인
    - Payments::CheckoutService, ConfirmationService 패턴 확인
    - 기존 toss_payment_controller.js Stimulus 패턴 확인
    - CustomPaymentLink 모델 + fixtures 확인
    - 라우트: locale scope 밖 `/pay/:token` 설정 확인

    ## 구현 계획
    1. CustomPaymentsController (인증 skip, show/checkout/success/fail)
    2. custom_payment 레이아웃
    3. show/success/fail/expired/canceled/completed 뷰
    4. toss_custom_payment Stimulus 컨트롤러
    5. 통합 테스트

  • 결제-페이지 티켓 클레임 완료
  • 관리자-UI 기존 구조 분석 완료, 코드 작성 시작
    상세 보기

    ## 분석 완료 항목
    - Admin::BaseController 패턴 확인
    - 기존 payments/users 컨트롤러 패턴 확인
    - _sidebar.html.erb, _nav_item.html.erb 구조 확인
    - clipboard_controller.js, qr_code_controller.js 이미 존재 확인
    - 기존 integration test 패턴 확인 (sign_in_as)
    - ko.yml 구조 확인

    ## 재사용할 것
    - Admin::BaseController (인증/권한)
    - clipboard_controller.js (복사 기능)
    - qr_code_controller.js (QR 다운로드/복사)
    - 기존 admin 테이블 UI 패턴

  • B
    backend-dev 상태 변경: 할 일 → 리뷰
  • B
    backend-dev 라우트 + 컨트롤러 + 모델 수정 완료
    상세 보기

    ## 변경 사항

    ### 1. app/models/product.rb
    - `accepts_nested_attributes_for :product_prices, allow_destroy: true` 추가

    ### 2. config/routes.rb
    - admin 네임스페이스에 `resources :products, except: :destroy` 추가
    - `member { patch :toggle_active }` 추가

    ### 3. app/controllers/admin/products_controller.rb (신규)
    - Admin::BaseController 상속
    - 액션: index, show, new, create, edit, update, toggle_active
    - index: 검색(q→name ILIKE), 필터(product_type, active), 정렬, 페이지네이션(PER_PAGE=30)
    - show: includes(:product_prices)
    - create/update: nested product_prices_attributes 지원
    - toggle_active: toggle!(:active)
    - flash 메시지: I18n.t 사용

    ### 참고
    - workspaces_controller.rb 패턴 동일하게 적용
    - 라우트 확인 완료 (bin/rails routes)

  • B
    backend-dev 인프라 설정 및 통계 컨트롤러 구현 시작
  • 관리자-UI 티켓 클레임 완료
  • A
    agent-nav 프로필 탭 네비게이션 구현 시작
  • 팀리드 결제 관리 기능 구현 완료
    상세 보기

    ## 완료된 작업

    ### 신규 생성 파일
    - `app/controllers/admin/payments_controller.rb` - 결제 목록 조회 + 취소 컨트롤러
    - `app/views/admin/payments/index.html.erb` - 결제 관리 목록 뷰 (10컬럼 테이블)
    - `test/integration/admin/payments_test.rb` - 통합 테스트 18개

    ### 수정 파일
    - `config/routes.rb` - admin 네임스페이스에 payments 리소스 추가
    - `app/views/admin/shared/_sidebar.html.erb` - 결제 관리 메뉴 추가
    - `app/views/admin/shared/_nav_item.html.erb` - payments 아이콘 추가
    - `config/locales/ko.yml` - i18n 키 추가

    ### 테스트 결과
    - 신규 테스트 18개 전부 통과
    - 전체 admin 테스트 82개 전부 통과 (회귀 없음)

    ### 구현된 기능
    - 결제 목록 조회 (검색, 상태/유형 필터, 정렬, 페이지네이션)
    - 관리자 결제 취소 (무료/유료 분기, PG API 연동)
    - 사이드바 결제 관리 메뉴

  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 할 일 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 백엔드 작업 시작: CustomPaymentLink 모델, 마이그레이션, 라우팅, 서비스 구현
  • 백엔드 티켓 클레임 완료
  • S
    status-dev 상태 변경: 진행 중 → 리뷰
  • S
    status-dev 멤버 승인 상태 표시 및 i18n 구현 완료
    상세 보기

    ## 변경 사항

    ### 1. WorkspaceInvitation 모델 (`app/models/workspace_invitation.rb`)
    - `accepted?` 메서드 추가: target_email의 사용자가 워크스페이스 멤버인지 확인
    - `accepted_member` 메서드 추가: 수락한 멤버 객체 반환

    ### 2. _invitation.html.erb 뷰 수정
    - 이메일 초대에 승인 상태 배지 추가
    - Accepted: 초록색 배지 + 체크 아이콘 + 사용자 이름
    - Pending: 주황색 배지 + 시계 아이콘
    - N+1 방지를 위해 accepted_member 로컬 변수 캐싱

    ### 3. i18n 키 추가 (en/ko/zh/vi)
    - `invitations.status.pending` / `accepted`
    - `invitations.resend`, `resend_tooltip`
    - `invitations.bulk_invite`, `bulk_placeholder`, `bulk_submit`, `bulk_email_count`
    - `invitations.flash.bulk_result`, `resent`
    - `invitations.mailer.invitation_email.*` (subject, greeting, body, action, expiry)

    ### 4. 테스트 추가 (`test/models/workspace_invitation_test.rb`)
    - accepted? 테스트 4건 (멤버/비멤버/blank/존재하지만비멤버)
    - accepted_member 테스트 3건 (멤버/비수락/blank)
    - 전체 25건 통과

  • 팀리드 위임: tester에게 'Admin Products 통합 테스트 구현' 작업 배정
  • B
    backend-dev 상태 변경: 진행 중 → 리뷰
  • 팀리드 위임: agent-payment에게 '결제 내역 UI 개선 + 취소 정책' 작업 배정
  • B
    backend-dev Admin::PaymentsController + 라우팅 + 테스트 구현 완료
    상세 보기

    ## 변경 사항

    ### 1. 라우팅 (config/routes.rb)
    - admin 네임스페이스에 `resources :payments, only: [:index]` + `member { patch :cancel }` 추가

    ### 2. Admin::PaymentsController (app/controllers/admin/payments_controller.rb) - 신규
    - `Admin::BaseController` 상속
    - **index**: `Payment.includes(user: :profile).order(created_at: :desc)`
    - 검색: `params[:q]` → users.name, users.email_address, user_profiles.phone_number ILIKE 검색
    - 필터: `params[:status]` (validated), `params[:payment_type]` (validated)
    - 정렬: created_at, amount, status / asc, desc
    - 수동 페이지네이션 (PER_PAGE=50)
    - **cancel**: completed 상태 확인 + free/유료 분기
    - free: 바로 `payment.cancel!`
    - 유료: `ProviderResolver` → `provider.cancel` 호출 후 `payment.cancel!`
    - turbo_stream / html respond_to 지원
    - 에러 처리: rescue → flash alert redirect

    ### 3. 테스트 (test/integration/admin/payments_test.rb) - 신규
    - 18개 테스트 전부 통과
    - 접근 제어 (2), index 조회 (1), 검색 (2), 상태 필터 (3), 유형 필터 (2), 정렬 (2), 페이지네이션 (1), 취소 (5)
    - PG API 호출 mock: `define_singleton_method`로 ProviderResolver 패치

    ### 참고
    - 뷰 템플릿(index.html.erb) 및 i18n 키는 이미 존재
    - 기존 admin 테스트 82개 전부 통과 확인

  • 팀리드 위임: frontend-dev에게 'Admin Products 뷰 + 사이드바 + i18n 구현' 작업 배정
  • 팀리드 문항 관리 언어 선택 버그 수정 완료
    상세 보기

    ## 수정 내용
    1. `Admin::BaseController`에 `switch_locale` override 추가 → Admin 영역은 항상 기본 locale(ko) 유지
    2. `SurveyQuestionsController#group_detail`에서 `params[:locale]` → `params[:lang]`으로 변경
    3. 뷰 파일(index, group_detail)에서 언어 버튼 파라미터 `locale:` → `lang:` 변경

    ## 테스트 결과
    - 19 runs, 50 assertions, 0 failures, 0 errors

    ## 수정 파일
    - `app/controllers/admin/base_controller.rb`
    - `app/controllers/admin/survey_questions_controller.rb`
    - `app/views/admin/survey_questions/index.html.erb`
    - `app/views/admin/survey_questions/group_detail.html.erb`
    - `test/controllers/admin/base_controller_test.rb` (신규)
    - `test/controllers/admin/survey_questions_controller_test.rb` (신규)
    - `test/integration/admin/survey_questions_test.rb` (수정)

  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 위임: agent-credit에게 '개인 크레딧 페이지 생성' 작업 배정
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 위임: backend-dev에게 'Admin Products 라우트 + 컨트롤러 구현' 작업 배정
  • 팀리드 위임: agent-nav에게 '프로필 탭 네비게이션 + 라우트 + i18n' 작업 배정
  • 팀리드 위임: analytics-dev-2에게 '매출 분석 뷰 + 통합 테스트' 작업 배정
  • 팀리드 위임: analytics-dev-1에게 '사용자 + 진단 분석 뷰' 작업 배정
  • 팀리드 위임: backend-dev에게 '인프라 설정 + 통계 컨트롤러 + 개요 대시보드' 작업 배정
  • T
    test-dev 테스트 작성 시작 - 기존 코드 및 패턴 분석 중
  • T
    test-dev 티켓 클레임 완료
  • F
    frontend-dev 상태 변경: 할 일 → 리뷰
  • F
    frontend-dev 뷰 파일 수정 및 테스트 통과 완료
    상세 보기

    ## 변경 사항
    - `app/views/admin/survey_questions/index.html.erb`: `locale:` → `lang:` 파라미터 변경
    - `app/views/admin/survey_questions/group_detail.html.erb`: `locale:` → `lang:` 파라미터 변경
    - `test/integration/admin/survey_questions_test.rb`: 기존 테스트 업데이트 + 3개 테스트 추가

    ## 추가된 테스트
    1. `lang parameter does not change UI locale` - lang=en으로 접속해도 UI가 한국어 유지되는지 검증
    2. `index language buttons use lang parameter instead of locale` - 인덱스 페이지 링크에 locale 없고 lang 사용 확인
    3. `group detail language buttons use lang parameter instead of locale` - 상세 페이지 링크에 locale 없고 lang 사용 확인

    ## 테스트 결과
    11 runs, 34 assertions, 0 failures, 0 errors

  • I
    impl-dev 상태 변경: 할 일 → 리뷰
  • 팀리드 impl-dev 구현 완료 확인, 테스트 에이전트 시작
    상세 보기

    ## 완료된 작업
    - 컨트롤러 eager loading, 전화번호 검색, update_role 액션
    - 인덱스 뷰에 전화번호/워크스페이스/진단 컬럼 추가
    - 인라인 역할 수정 (Stimulus inline-edit 재사용)
    - 진단 목록 모달 (Stimulus toggle 재사용)
    - i18n 번역 키 추가

    ## 변경 파일
    - `app/controllers/admin/users_controller.rb`
    - `app/views/admin/users/index.html.erb`
    - `app/views/admin/users/_role_cell.html.erb` (신규)
    - `app/views/admin/users/_diagnosis_modal.html.erb` (신규)
    - `config/routes.rb`
    - `config/locales/ko.yml`

    기존 테스트 8건 통과 확인

  • B
    backend-dev 상태 변경: 진행 중 → 리뷰
  • B
    backend-dev Admin BaseController switch_locale override 및 SurveyQuestions 필터링 수정 완료
    상세 보기

    ## 변경 사항

    ### 1. `app/controllers/admin/base_controller.rb`
    - `switch_locale` 메서드 override 추가
    - Admin 영역에서는 `params[:locale]`을 무시하고 항상 `I18n.default_locale`(ko) 사용

    ### 2. `app/controllers/admin/survey_questions_controller.rb`
    - `group_detail` 액션에서 `params[:locale]` → `params[:lang]`으로 변경
    - URL 파라미터명 변경으로 locale 간섭 방지

    ### 3. 신규 테스트 파일
    - `test/controllers/admin/base_controller_test.rb` (2 tests)
    - locale=en 파라미터 전달해도 Admin은 ko 유지
    - locale=vi 파라미터 전달해도 Admin은 ko 유지
    - `test/controllers/admin/survey_questions_controller_test.rb` (6 tests)
    - group_detail에서 lang 파라미터 사용 확인
    - lang 미전달 시 기본값 ko
    - locale 파라미터는 무시됨
    - I18n.locale은 항상 ko 유지
    - index 접근 가능
    - 비관리자 리다이렉트

    ### 테스트 결과
    - 8 runs, 16 assertions, 0 failures, 0 errors

  • B
    bulk-dev 상태 변경: 할 일 → 리뷰
  • B
    bulk-dev 벌크 이메일 초대 기능 구현 완료
    상세 보기

    ## 변경 사항

    ### 1. InvitationService (app/services/workspaces/invitation_service.rb)
    - `bulk_create!` 메서드 추가: 여러 이메일을 한번에 초대, 성공/실패 결과 반환
    - `parse_emails` 메서드 추가: 쉼표/세미콜론/줄바꿈/공백으로 이메일 파싱, 중복 제거, 형식 검증

    ### 2. InvitationsController (app/controllers/workspaces/invitations_controller.rb)
    - `bulk_create` 액션 추가: bulk_create! 호출 후 결과에 따른 flash 메시지 표시

    ### 3. 라우트 (config/routes.rb)
    - `post :bulk_create, on: :collection` 추가

    ### 4. UI (app/views/workspaces/invitations/index.html.erb)
    - 이메일 탭 내 "Or bulk invite" 구분선 추가
    - textarea로 여러 이메일 입력 가능
    - 역할/그룹 선택 옵션
    - 이메일 카운트 실시간 표시

    ### 5. Stimulus (app/javascript/controllers/bulk_invite_controller.js)
    - textarea 입력 시 이메일 수 실시간 카운트
    - 이메일 없으면 제출 버튼 비활성화

    ### 6. 테스트 (test/controllers/workspaces/invitations_controller_bulk_test.rb)
    - 8개 테스트 모두 통과
    - 다중 이메일, 줄바꿈/세미콜론 구분, 중복 제거, 무효 이메일 무시, 빈 텍스트, 권한 검증, 역할 지정

  • I
    impl-dev Task 1~5 구현 완료, 기존 테스트 모두 통과
    상세 보기

    ## 변경 사항

    ### Task 1: 컨트롤러 개선
    - `app/controllers/admin/users_controller.rb`
    - `includes(:profile, :workspaces, :diagnosis_sessions)` eager loading 추가
    - 검색: `left_joins(:profile)` + `user_profiles.phone_number ILIKE` 추가
    - `update_role` 액션 추가 (PATCH, Turbo Stream 응답)
    - `before_action :set_user`에 `update_role` 추가
    - `config/routes.rb`에 `patch :update_role` 라우트 추가

    ### Task 2: 인덱스 뷰 개선
    - `app/views/admin/users/index.html.erb`
    - 전화번호 컬럼 추가 (phone_country_code + phone_number)
    - 소속 워크스페이스 컬럼 추가 (truncate + title tooltip)
    - 진단 컬럼 추가 (클릭 가능한 진단 수)

    ### Task 3: 인라인 역할 수정
    - `app/views/admin/users/_role_cell.html.erb` 생성
    - 기존 `inline-edit` Stimulus 컨트롤러 재사용
    - 뱃지 클릭 → select 드롭다운 표시
    - 선택 시 `onchange`로 즉시 PATCH 요청
    - Turbo Stream으로 뱃지 교체 응답

    ### Task 4: 진단 목록 뷰어
    - `app/views/admin/users/_diagnosis_modal.html.erb` 생성
    - `toggle` Stimulus 컨트롤러로 모달 토글
    - 진단 유형, 상태, 완료일, 상세 링크 표시

    ### Task 5: i18n
    - `config/locales/ko.yml`에 번역 키 추가
    - phone, workspaces, diagnosis_count, role_updated
    - diagnosis_modal 섹션 (title, type, status, completed_at, view, empty)

    ## 테스트 결과
    - 기존 admin 컨트롤러 테스트: 8 runs, 16 assertions, 0 failures

  • F
    frontend-dev Admin Payments 뷰 + 사이드바 메뉴 구현 완료
    상세 보기

    ## 수정/생성된 파일

    ### 1. app/views/admin/shared/_nav_item.html.erb (수정)
    - `payments` 아이콘(credit-card SVG path) 추가

    ### 2. app/views/admin/shared/_sidebar.html.erb (수정)
    - 워크스페이스 메뉴 아래에 "결제 관리" nav_item 추가
    - `admin_payments_path` 링크, `controller_name == "payments"` 활성 조건

    ### 3. app/views/admin/payments/index.html.erb (신규 생성)
    - 헤더: 제목 + 전체 건수
    - 검색 & 필터: 텍스트 검색(사용자명/이메일/전화번호), 상태 필터, 결제유형 필터
    - 테이블 10컬럼: 사용자, 이메일, 전화번호, 상품명, 가격, 상태, 할인금액, 결제일, 영수증, 취소
    - 상태 배지: completed→green, pending→yellow, failed→red, canceled→gray
    - 취소 버튼: `button_to cancel_admin_payment_path` + turbo_confirm
    - 빈 상태 메시지
    - 페이지네이션: `admin/shared/pagination` partial 사용
    - 기존 diagnosis_sessions/index.html.erb 패턴과 완전히 일관된 Tailwind CSS

    ### 4. config/locales/ko.yml (수정)
    - `admin.nav.payments`: "결제 관리"
    - `admin.payments.*`: title, subtitle, search_placeholder, all_statuses, all_types, empty, confirm_cancel, cancel_button, canceled_label, table.*, flash.*

  • 팀리드 위임: 결제-페이지에게 '고객 결제 페이지 + Toss Payments 연동' 작업 배정
  • 팀리드 코드베이스 분석 완료, 서브 티켓 분해 시작
    상세 보기

    ## 분석 결과 요약
    - 프로필 페이지: `/:locale/profile` (show/edit/update) 존재하나 결제/크레딧 정보 없음
    - 결제 시스템: Payment 모델, PaymentsController (index/show/cancel), Toss PG 연동 완비
    - 크레딧 시스템: UserCredit + CreditTransaction 모델 존재하나 개인 크레딧 뷰 없음
    - 사이드바: 결제/크레딧 링크 없음
    - 영수증: receipt_url 컬럼 존재, show 페이지에 링크 있음
    - 취소: CancellationService 존재하나 상품별 분기 없음 (현재 7일 이내 completed만 체크)

    ## 필요 작업
    1. 프로필 탭 네비게이션 (내 정보/결제/크레딧)
    2. 개인 크레딧 페이지 생성
    3. 결제 내역 UI 개선 (프로필 탭 통합)
    4. 리포트 결제 취소 불가 정책 적용
    5. i18n 다국어 키 추가

  • 팀리드 위임: 관리자-UI에게 '관리자 커스텀 결제 링크 UI (컨트롤러 + 뷰 + 사이드바)' 작업 배정
  • F
    frontend-dev 코드 분석 완료, 뷰 파일 수정 시작
    상세 보기

    ## 분석 결과
    - `index.html.erb` 63행: `locale:` 파라미터 사용 → `lang:`으로 변경 필요
    - `group_detail.html.erb` 32행: `locale:` 파라미터 사용 → `lang:`으로 변경 필요
    - 기존 테스트 25, 31행: `locale:` 파라미터 사용 → `lang:`으로 변경 필요

  • 팀리드 위임: 백엔드에게 'CustomPaymentLink 모델 + 마이그레이션 + 라우팅 + 서비스' 작업 배정
  • B
    backend-dev 티켓 클레임 완료
  • S
    status-dev 멤버 승인 상태 표시 및 i18n 작업 시작
  • S
    status-dev 티켓 클레임 완료
  • 팀리드 에이전트 팀 구성 완료, 3명 병렬 작업 시작
    상세 보기

    ## 팀 구성
    - **mailer-dev**: Mailer 생성 + 이메일 발송 연동 (worktree 격리)
    - **bulk-dev**: 벌크 이메일 초대 기능 (worktree 격리)
    - **status-dev**: 멤버 승인 상태 표시 + i18n (worktree 격리)

    ## 서브 티켓
    1. a9e36ce3: Mailer 생성 및 이메일 발송 연동 (high)
    2. c2083743: 벌크 이메일 초대 기능 (high)
    3. 1bcfa5ea: 멤버 승인 상태 표시 및 i18n (medium)

    3명 모두 worktree 격리 환경에서 병렬 작업 중

  • F
    frontend-dev 기존 admin 뷰 패턴 분석 완료, 구현 시작
    상세 보기

    ## 분석 완료 항목
    - `_sidebar.html.erb`: nav_item partial 사용, icon SVG 경로 매핑 방식
    - `_nav_item.html.erb`: icon 키 → SVG path 매핑, active 조건
    - `diagnosis_sessions/index.html.erb`: 검색/필터/테이블/페이지네이션 패턴
    - `_pagination.html.erb`: page/total_pages/total_count locals
    - `Payment` 모델: status enum, payment_type enum, 필드 구조 확인
    - i18n: admin 네임스페이스 패턴 확인

    ## 구현 계획
    1. 사이드바에 payments nav_item 추가
    2. nav_item에 payments 아이콘 추가
    3. admin/payments/index.html.erb 생성
    4. i18n에 admin.payments 키 추가

  • B
    bulk-dev 벌크 이메일 초대 기능 작업 시작
    상세 보기

    ## 작업 범위
    - InvitationService에 bulk_create! 메서드 추가
    - InvitationsController에 bulk_create 액션 추가
    - 라우트 추가
    - 벌크 UI (textarea + 카운트)
    - Stimulus 컨트롤러
    - 테스트 작성

  • I
    impl-dev 코드베이스 분석 완료, Task 1 (컨트롤러 개선) 및 Task 5 (i18n) 작업 시작
    상세 보기

    ## 분석 완료 항목
    - `app/controllers/admin/users_controller.rb` - 현재 eager loading 없음, 검색에 이름/이메일만 지원
    - `app/views/admin/users/index.html.erb` - 이름/이메일/역할/가입일 4컬럼만 표시
    - `app/helpers/admin_helper.rb` - role_badge_class, role_label 헬퍼 확인
    - `app/javascript/controllers/inline_edit_controller.js` - 기존 인라인 편집 Stimulus 컨트롤러 존재
    - `config/locales/ko.yml` - admin.users 섹션 확인
    - User 모델: has_one :profile, has_many :workspaces (through), has_many :diagnosis_sessions
    - UserProfile 모델: phone_number, phone_country_code 필드 확인

  • 팀리드 코드베이스 분석 완료, 서브 티켓 설계 시작
    상세 보기

    ## 분석 결과
    - 기존 Payment 모델에 `custom` payment_type 존재
    - Toss Payments 연동 완료 (providers/toss.rb)
    - rqrcode gem 설치됨 (QR 코드 생성 가능)
    - Admin namespace 패턴 확립

    ## 구현 계획
    - CustomPaymentLink 신규 모델 생성 필요
    - Admin CRUD + 공개 결제 페이지 구현
    - 3개 서브 티켓으로 분할 예정

  • M
    mailer-dev Mailer 생성 및 이메일 발송 연동 작업 시작
    상세 보기

    ## 작업 범위
    - WorkspaceInvitationMailer 생성
    - 이메일 템플릿 (HTML/Text)
    - InvitationService.create!에 이메일 발송 연동
    - resend 기능
    - 테스트 작성

  • 팀리드 위임: frontend-dev에게 '문항 관리 뷰 언어 선택 파라미터 수정' 작업 배정
  • 팀리드 위임: backend-dev에게 'Admin BaseController switch_locale override 및 SurveyQuestions 필터링 수정' 작업 배정
  • B
    backend-dev 티켓 클레임 완료
  • 팀리드 통계 관리 기능 분석 시작
    상세 보기

    ## 코드베이스 분석 완료

    ### 현재 상태
    - 어드민 대시보드에 기본 통계 카드 4개 (총 사용자, 완료 세션, 진단 유형, 설문 문제)
    - 차트/그래프 라이브러리 없음
    - Tailwind CSS + Hotwire 기반 서버사이드 렌더링

    ### 구현 계획
    - Chartkick + Chart.js로 차트 시각화
    - 4개 탭: 개요, 사용자, 진단, 매출
    - 서브 티켓 3개로 분할하여 팀 작업 진행

  • 팀리드 위임: status-dev에게 '멤버 승인 상태 표시 및 i18n' 작업 배정
  • 팀리드 상품 관리 기능 분석 시작
    상세 보기

    ## 작업 계획
    - 레거시 사이트(https://9way.org/admin/workspaces) 분석
    - 현재 코드베이스의 관련 모델/라우트 파악
    - 서브 티켓 분해 후 에이전트 팀 구성

  • 팀리드 위임: bulk-dev에게 '벌크 이메일 초대 기능' 작업 배정
  • 팀리드 티켓 클레임 완료
  • 팀리드 위임: mailer-dev에게 'Mailer 생성 및 이메일 발송 연동' 작업 배정
  • 팀리드 위임: test-dev에게 '사용자 관리 기능 테스트 작성' 작업 배정
  • 팀리드 위임: impl-dev에게 '사용자 관리 인덱스 개선 + 인라인 역할 수정 + 진단 뷰어' 작업 배정
  • 팀리드 위임: frontend-dev에게 'Admin Payments 뷰 + 사이드바 메뉴' 작업 배정
  • 팀리드 티켓 클레임 완료
  • 팀리드 문항 관리 버그 분석 시작
    상세 보기

    ## 이슈
    - 문항관리에서 언어 선택 시 해당 언어의 질문만 보여야 하는데, 전체 메뉴 언어가 변경되는 버그
    - 영어 선택 시 메뉴 전체가 영어로 바뀌는 문제

    ## 계획
    - 코드 분석 후 서브 태스크 분해 및 팀 구성 예정

  • 팀리드 위임: backend-dev에게 'Admin Payments 컨트롤러 + 라우팅 + 테스트' 작업 배정
  • 팀리드 티켓 클레임 완료
  • 팀리드 사용자 관리 기능 분석 완료, 서브 티켓 생성 시작
    상세 보기

    ## 현재 상태
    - admin/users 컨트롤러/뷰 이미 존재
    - index: 이름, 이메일, 역할, 생성일만 표시
    - show: 사용자 정보 + 진단 이력

    ## 필요 변경사항
    1. index에 전화번호, 소속 워크스페이스, 진단 수 컬럼 추가
    2. 역할 인라인 수정 (드롭다운)
    3. 진단 클릭 시 해당 사용자 진단 목록 표시
    4. 전화번호 검색 지원

    ## 핵심 파일
    - `app/controllers/admin/users_controller.rb`
    - `app/views/admin/users/index.html.erb`
    - `app/views/admin/users/show.html.erb`
    - 전화번호는 `user_profiles` 테이블에 저장됨
    - 워크스페이스는 `workspace_members` 통해 연결

  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 결제 관리 기능 분석 시작
    상세 보기

    ## 분석 범위
    - 기존 결제 모델/테이블 구조 파악
    - 관리자 페이지 구조 파악
    - 서브 티켓 분해 및 팀 구성 계획

  • 팀리드 티켓 클레임 완료
  • 팀리드 이메일 초대 티켓 분석 시작
    상세 보기

    ## 작업 범위
    - 이메일 초대 시 실제 이메일 발송
    - 벌크 이메일 등록/발송
    - 멤버 승인 상태 표시

    코드베이스 분석 후 서브 티켓 분해 예정

  • 팀리드 티켓 클레임 완료
  • 팀리드 배포 완료 - 관리자 메뉴 기능 프로덕션 반영
    상세 보기

    ## 배포 정보
    - 커밋: a58c601
    - 서버: 143.198.211.253 (9way.org)
    - 소요 시간: 64초
    - 상태: 성공 (healthy)

    ## 배포된 변경사항
    - 사이드바에 관리자 메뉴 링크 추가 (admin 사용자만)
    - 4개 언어 번역 추가 (ko/en/zh/vi)
    - 통합 테스트 2건 추가

  • 팀리드 워크스페이스 메뉴 권한 기능 구현 완료
    상세 보기

    ## 완료 내역

    ### 구현 (sidebar-dev)
    - `app/views/shared/_sidebar.html.erb`: 표시 조건 `staff?`로 변경
    - `app/views/shared/_sidebar_workspace_section.html.erb`: "+ 워크스페이스 생성" 링크 추가, 빈 상태 처리

    ### 테스트 (test-dev)
    - `test/integration/sidebar_workspace_menu_test.rb`: 5개 통합 테스트 작성
    - `test/fixtures/users.yml`: coach_basic, org_admin_basic 픽스처 추가
    - 전체 테스트: 427 runs, 1134 assertions, 0 failures

  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • T
    test-dev 테스트 작성 완료 - 모든 권한별 시나리오 통과
    상세 보기

    ## 변경 사항

    ### 새 파일
    - `test/integration/sidebar_workspace_menu_test.rb` - 사이드바 워크스페이스 메뉴 권한 통합 테스트 (5개 시나리오)

    ### 수정 파일
    - `test/fixtures/users.yml` - coach_basic_user, org_admin_basic_user 픽스쳐 추가

    ## 테스트 시나리오
    1. regular 사용자 → 워크스페이스 섹션 미표시
    2. coach_basic (워크스페이스 없음) → 섹션 표시 + 생성 링크
    3. coach_pro (워크스페이스 있음) → 목록 표시 + 생성 링크
    4. org_admin_basic → 섹션 표시 + 생성 링크
    5. admin → 목록 + 생성 링크

    ## 테스트 결과
    - 신규 테스트: 5 runs, 30 assertions, 0 failures
    - 전체 테스트: 427 runs, 1134 assertions, 0 failures, 0 errors

  • T
    test-dev 상태 변경: 할 일 → 리뷰
  • S
    sidebar-dev 상태 변경: 할 일 → 리뷰
  • S
    sidebar-dev 구현 완료 - 사이드바 워크스페이스 권한 조건 변경 및 생성 링크 추가
    상세 보기

    ## 변경 사항

    ### 1. `app/views/shared/_sidebar.html.erb`
    - 워크스페이스 섹션 표시 조건: `@sidebar_workspaces&.any?` → `Current.user&.staff?`
    - staff? 사용자(admin, coach, org_admin)만 워크스페이스 섹션 표시
    - workspaces 변수를 `@sidebar_workspaces || []`로 전달하여 nil 안전 처리

    ### 2. `app/views/shared/_sidebar_workspace_section.html.erb`
    - `return if workspaces.blank?` 가드 절 제거 → 빈 상태에서도 렌더링
    - `selected_ws.id` → `selected_ws&.id`로 nil 안전 처리
    - 하단에 "+ 워크스페이스 생성" 링크 추가 (Heroicon plus 아이콘, 기존 스타일 패턴 유지)
    - 워크스페이스가 0개일 때도 헤더 + 생성 링크 표시

    ### 테스트 결과
    - 422 runs, 1104 assertions, 0 failures, 0 errors, 0 skips

  • 팀리드 위임: test-dev에게 '워크스페이스 메뉴 권한 테스트 작성' 작업 배정
  • 팀리드 위임: sidebar-dev에게 '사이드바 워크스페이스 섹션 권한 조건 변경 및 생성 링크 추가' 작업 배정
  • 팀리드 워크스페이스 메뉴 권한 기능 분석 시작
    상세 보기

    ## 분석 범위
    - 사용자 권한 시스템 파악
    - 현재 사이드바/메뉴 구조 확인
    - 워크스페이스 모델 및 관계 분석
    - 필요한 서브 티켓 도출

  • 팀리드 티켓 클레임 완료
  • 팀리드 관리자 메뉴 구현 완료
    상세 보기

    ## 변경 사항
    - `app/views/shared/_sidebar.html.erb`: admin 사용자 조건부 관리자 메뉴 추가
    - `app/views/shared/_sidebar_nav_item.html.erb`: admin 톱니바퀴 아이콘 추가
    - `config/locales/ko.yml`: `nav.sidebar.admin: "관리자"` 추가
    - `config/locales/en.yml`: `nav.sidebar.admin: "Admin"` 추가
    - `config/locales/zh.yml`: `nav.sidebar.admin: "管理员"` 추가
    - `config/locales/vi.yml`: `nav.sidebar.admin: "Quản trị"` 추가
    - `test/integration/sidebar_test.rb`: 통합 테스트 2건 작성

    ## 테스트 결과
    - 422개 전체 테스트 통과 (0 failures, 0 errors)

  • 팀리드 상태 변경: 리뷰 → 완료
  • D
    dev-1 상태 변경: 진행 중 → 리뷰
  • D
    dev-1 사이드바 관리자 메뉴 구현 완료
    상세 보기

    ## 변경 파일
    - `app/views/shared/_sidebar_nav_item.html.erb` - admin 톱니바퀴 아이콘 SVG path 추가
    - `app/views/shared/_sidebar.html.erb` - `Current.user&.admin?` 조건부 관리자 메뉴 렌더링 추가
    - `config/locales/ko.yml` - `nav.sidebar.admin: "관리자"` 추가
    - `config/locales/en.yml` - `nav.sidebar.admin: "Admin"` 추가
    - `config/locales/zh.yml` - `nav.sidebar.admin: "管理员"` 추가
    - `config/locales/vi.yml` - `nav.sidebar.admin: "Quản trị"` 추가
    - `test/integration/sidebar_test.rb` - 신규 생성 (admin 링크 표시/비표시 테스트)

    ## 테스트 결과
    - 152 integration tests 전체 통과 (0 failures, 0 errors)

  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 관리자 메뉴 기능 확인 완료 - 이미 구현되어 있음
    상세 보기

    ## 분석 결과
    관리자 사이드 메뉴 기능이 이미 완전히 구현되어 있음을 확인했습니다.

    ## 구현 내용
    1. **사이드바 HTML** (`app/views/shared/_sidebar.html.erb` 32-38줄)
    - `Current.user&.admin?` 조건부 표시
    - `admin_root_path`로 링크
    - `controller_path.start_with?("admin")`으로 active 상태 판별

    2. **아이콘** (`app/views/shared/_sidebar_nav_item.html.erb` 9줄)
    - "admin" 키로 톱니바퀴 SVG 아이콘 정의

    3. **다국어 번역** (`nav.sidebar.admin`)
    - ko: "관리자"
    - en: "Admin"
    - zh: "管理员"
    - vi: "Quản trị"

    ## 비고
    - 기존 Admin::UsersTest에서 `phone_number` 메서드 누락 에러 1건 발견 (본 티켓과 무관)

  • D
    dev-1 티켓 클레임 완료
  • 팀리드 코드베이스 분석 시작 - 사이드 메뉴 및 관리자 페이지 구조 파악
  • 팀리드 위임: dev-1에게 '사이드바에 관리자 메뉴 링크 추가' 작업 배정
  • 팀리드 관리자 메뉴 티켓 분석 시작
    상세 보기

    ## 작업 시작
    - 티켓 claim 완료
    - 코드베이스 분석 중: 사이드 메뉴 구조, 관리자 페이지 현황 파악

  • 팀리드 티켓 클레임 완료
  • 2026년 02월 27일
  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 메인페이지 다국어 번역 수정 완료
    상세 보기

    ## 변경 사항
    - `config/locales/zh.yml` — `home` 섹션 전체 추가 (중국어 번역 ~100줄)
    - `config/locales/vi.yml` — `home` 섹션 전체 추가 (베트남어 번역 ~100줄)
    - `config/locales/ko.yml` — `home.social_proof.count_suffix` 키 추가
    - `config/locales/en.yml` — `home.social_proof.count_suffix` 키 추가
    - `app/views/pages/home.html.erb` — 하드코딩된 한국어 텍스트를 i18n 키로 교체 (line 466)

    ## 검증
    - 4개 YAML 파일 파싱 정상 확인
    - ko/en/zh/vi 모든 locale의 home 섹션 키 일치 확인

  • 팀리드 분석 완료: ZH/VI에 home 섹션 전체 누락 확인
    상세 보기

    ## 분석 결과
    - KO/EN: 완전
    - ZH/VI: `home` 섹션 전체 누락 (약 50개 키)
    - 하드코딩된 한글 텍스트 1건 (467줄)
    - navbar auth 키도 ZH/VI에서 누락

    ## 작업 계획
    1. ZH에 home 섹션 번역 추가
    2. VI에 home 섹션 번역 추가
    3. 하드코딩 텍스트 i18n화
    4. auth 키 누락분 추가

  • 팀리드 티켓 클레임 완료
  • 팀리드 프로덕션 배포 완료 (9way.org)
  • 팀리드 프로덕션 배포 완료 (9way.org)
  • 팀리드 프로덕션 배포 완료 (9way.org)
    상세 보기

    ## 배포 정보
    - **커밋**: `da60c50` feat: Add admin management features, PDF improvements, and AI analysis locale support
    - **커밋**: `62243db` fix: Increase Kamal deploy timeout to 90s for slow boot
    - **서버**: 143.198.211.253 (DigitalOcean SGP1)
    - **도메인**: https://9way.org
    - **배포 소요**: 71.6초 (컨테이너 헬스체크 31.35초)

    ## 배포된 기능
    - 사용자 상세 페이지 진단 이력 확장 (DNA 5개, 결제상태 토글, 메모)
    - 어드민 진단 세션 관리 목록 페이지
    - 문항관리 리디자인 (유형/대상/언어 그룹 + 응답 통계)
    - PDF 리포트 개선 및 AI 분석 다국어 지원

  • 팀리드 어드민 3개 기능 구현 완료
    상세 보기

    ## 완료 요약

    ### 1. 사용자 진단 이력 확장
    - `admin/users_controller.rb` - includes 확장, toggle_payment 액션
    - `admin/users/show.html.erb` - 테이블 형태로 전면 개편 (유형, DNA 5개, 결제상태, 메모, 완료일)
    - 결제 상태 토글 (유료↔무료) 동작

    ### 2. 진단 세션 관리 목록
    - `admin/diagnosis_sessions_controller.rb` 신규 생성 - 검색, 필터, 페이지네이션
    - `admin/diagnosis_sessions/index.html.erb` 신규 생성 - 전체 진단 세션 테이블
    - 사이드바에 네비게이션 항목 추가
    - 결제 상태 토글, 결과보기/PDF 링크, 워크스페이스명 표시

    ### 3. 문항관리 리디자인
    - `admin/survey_questions_controller.rb` - index 리디자인 + group_detail 액션
    - `admin/survey_questions/index.html.erb` - 유형/대상별 카드 그리드
    - `admin/survey_questions/group_detail.html.erb` 신규 - Part1 리커트 분포 + Part2 선택 비율
    - 테스트 420건 전체 통과

    ### routes.rb 통합 확인
    - 충돌 없이 깔끔하게 3개 라우트 추가됨

  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 위임: admin-survey-dev에게 '문항관리 리디자인 - 유형/대상/언어 그룹 + 응답 통계' 작업 배정
  • 팀리드 위임: admin-diagnosis-dev에게 '어드민 진단 세션 관리 목록 페이지 구현' 작업 배정
  • 팀리드 위임: admin-user-dev에게 '사용자 상세 - 진단 이력 확장 (DNA 5개, 결제상태 변경, 메모)' 작업 배정
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 요약 탭 커스텀 브랜딩 표시 + 연필 아이콘 편집 진입 + PDF 표지 커스텀 브랜딩 분기 완료. 전체 테스트 통과.
  • 팀리드 강점 브랜딩 수정 위자드 UI 완료. branding_wizard_controller.js (4단계: DNA→수식어→WAY+되고싶은모습→AI미리보기) + _tab_summary.html.erb 인라인 모달 통합. 전체 36개 테스트 통과.
  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 상태 변경: 할 일 → 완료
  • 팀리드 상태 변경: 할 일 → 완료
  • 팀리드 상태 변경: 할 일 → 완료
  • 팀리드 상태 변경: 할 일 → 완료
  • 팀리드 상태 변경: 할 일 → 완료
  • 팀리드 상태 변경: 할 일 → 완료
  • 팀리드 상태 변경: 할 일 → 완료
  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 리뷰 → 완료
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 상태 변경: 할 일 → 리뷰
  • 팀리드 위임: front-b에게 '강점 프로파일 + 탁월한 역할 + AI 분석 파트셜 신규 생성' 작업 배정
  • 팀리드 위임: dna-dev에게 'DNA 차별성 Top5 파트셜 리디자인 (10p)' 작업 배정
  • 팀리드 위임: front-a에게 '표지 + 해석가이드 + 요약 파트셜 리팩토링' 작업 배정
  • 팀리드 PDF 리포트 전면 재설계 시작. 에이전트 3명 팀 구성하여 7개 섹션 병렬 작업 + 팀리드가 오케스트레이터/CSS 담당.
  • 팀리드 상태 변경: 진행 중 → 완료
  • P
    premium-dev 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 진행 중 → 완료
  • D
    domain-dev 상태 변경: 진행 중 → 완료
  • 팀리드 이전 세션 에이전트 종료됨. 새 팀 구성하여 Premium Content 구현 재개.
  • 팀리드 이전 세션 에이전트 종료됨. 새 팀 구성하여 Domain Detail 마무리 + Premium Content 구현 재개.
  • P
    premium-dev 상태 변경: 할 일 → 진행 중
  • D
    domain-dev 상태 변경: 할 일 → 진행 중
  • 팀리드 위임: premium-dev에게 '유료 콘텐츠 PDF 파트셜 + 오케스트레이터 연동' 작업 배정
  • 팀리드 위임: domain-dev에게 'Domain 상세 페이지 - 1위 중심 레이아웃 + 비율 바차트' 작업 배정
  • 팀리드 두 PDF 티켓 동시 진행 시작. 코드베이스 분석 후 서브 티켓 생성 예정.
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 WAY 타입별 8개 섹션 구현 완료. _way_sections.html.erb 신규 생성, _way_detail.html.erb에서 WAY 하이라이트 분리, pdf.html.erb 페이지 순서 조정. Adult(701KB), Leader(730KB) PDF 생성 검증 완료. 모든 타입(adult/student/leader)에서 8개 섹션 정상 렌더링 확인.
  • 팀리드 티켓 클레임 완료
  • 팀리드 멤버 결과 보기 기능 3개 티켓 모두 완료. 전체 394개 테스트 통과. 변경: DiagnosesController 권한 로직(workspace admin 허용), 멤버 카드/목록 뷰 보기 버튼 추가, 권한 통합 테스트 6개 작성.
  • 팀리드 상태 변경: 할 일 → 완료
  • 팀리드 상태 변경: 할 일 → 완료
  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 할 일 → 완료
  • 팀리드 상태 변경: 할 일 → 완료
  • 팀리드 위임: guide-dev에게 '가이드 텍스트 i18n + PDF 파트셜 + 오케스트레이터 수정' 작업 배정
  • 팀리드 위임: chart-dev에게 'SVG 원형 차트 헬퍼 + PDF 파트셜 생성' 작업 배정
  • 팀리드 차트+가이드 2개 티켓 일괄 작업 시작. chart-dev, guide-dev 2인 팀 구성 예정.
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 상태 변경: 진행 중 → 완료
  • 팀리드 멤버 결과 보기 기능 3개 티켓 일괄 처리 시작. 팀 구성: backend-dev(권한 로직+테스트), frontend-dev(뷰 수정)
  • 팀리드 티켓 클레임 완료
  • 팀리드 3개 티켓 일괄 작업 시작. backend-dev, frontend-dev 2인 팀 구성 예정.
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료
  • 팀리드 티켓 클레임 완료