Skip to content

live#78

Merged
yhaeul merged 53 commits into
mainfrom
develop
Jun 29, 2026
Merged

live#78
yhaeul merged 53 commits into
mainfrom
develop

Conversation

@dennis0405

Copy link
Copy Markdown
Collaborator

No description provided.

yabsed and others added 30 commits April 2, 2026 19:03
* Feature/Better-Search (#11)

* style: gitignore codex

* feature: 자모분리를 적용한 오타감지

* feature: 부분 문자열을 정답 후보에 삽입

* style: 불필요한 trim 삭제

* style: 읽으면서 가독성 개선

* docs: 주석 삽입

* fix: prettier 없어서 그런 듯 (#12)

* Refactor/college major (#14)

* refactor: 기존 API와 호환을 위해 college_major에서 major=null이면 기본값으로는 숨긴다

* refactor: club 테이블에 새 column 추가, college_major 테이블에 major가 null인 행 추가

---------

Co-authored-by: 양해울 <haeul1005@naver.com>

* Refactor/college major (#15)

* refactor: club테이블의 affiliation_type 값 채우기

* refactor: club 테이블의 college_major_id 채우기

* feat: club 테이블에 동아리 승인 관련 컬럼 추가

---------

Co-authored-by: 양해울 <haeul1005@naver.com>

* feature: club의 새로운 두 필드 afflication_type과 college_major_id (#16)

---------

Co-authored-by: 양해울 <haeul1005@naver.com>
…vice (#23)

ClubService가 클럽 CRUD와 검색 엔진 로직(오타 교정, 자모 분리, 편집거리 계산)을
모두 담당하고 있어 단일 책임 원칙을 위반하고 있었음.

변경 사항:
- server/service/search.service.ts (신규): 검색 관련 타입 및 메서드 이동
  - searchWithTypoCorrection, search, findCandidatesByName (public)
  - searchByQuery, findCorrectedSearchQuery, collectCorrectionCandidates (private)
  - 자모 분리/유사도 계산 유틸(normalizeSearchTerm, decomposeToJamo, calculateJamoSimilarity 등) 이동
  - ClubService를 @Inject로 주입받아 getClubReviews() 호출
- server/util/club-sort.ts (신규): sortByPopularAndEachRandom 공유 유틸로 분리
  - ClubService(findByCategory, findPopular)와 SearchService 양쪽에서 사용하므로 별도 파일로 추출
- server/service/club.service.ts: 검색 로직 전량 제거, getClubReviews public으로 변경
  - 불필요해진 import(ILike, Raw, IsNull, disassemble, leven) 제거
- pages/api/v1/clubs/search/index.ts: SearchService 사용하도록 변경
- pages/api/v1/managers/me/clubs/index.ts: findCandidatesByName을 SearchService로 위임

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor: extract search engine logic from ClubService into SearchService

ClubService가 클럽 CRUD와 검색 엔진 로직(오타 교정, 자모 분리, 편집거리 계산)을
모두 담당하고 있어 단일 책임 원칙을 위반하고 있었음.

변경 사항:
- server/service/search.service.ts (신규): 검색 관련 타입 및 메서드 이동
  - searchWithTypoCorrection, search, findCandidatesByName (public)
  - searchByQuery, findCorrectedSearchQuery, collectCorrectionCandidates (private)
  - 자모 분리/유사도 계산 유틸(normalizeSearchTerm, decomposeToJamo, calculateJamoSimilarity 등) 이동
  - ClubService를 @Inject로 주입받아 getClubReviews() 호출
- server/util/club-sort.ts (신규): sortByPopularAndEachRandom 공유 유틸로 분리
  - ClubService(findByCategory, findPopular)와 SearchService 양쪽에서 사용하므로 별도 파일로 추출
- server/service/club.service.ts: 검색 로직 전량 제거, getClubReviews public으로 변경
  - 불필요해진 import(ILike, Raw, IsNull, disassemble, leven) 제거
- pages/api/v1/clubs/search/index.ts: SearchService 사용하도록 변경
- pages/api/v1/managers/me/clubs/index.ts: findCandidatesByName을 SearchService로 위임

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: fix prettier formatting in clubs search handler

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feature: 동아리 승인/반려 관련 SQL문

* feature: 현재 등록된 모든 동아리를 APPROVED 상태로 만드는 SQL문
* feature : Zod 기반의 OpenAPI 자동 생성 방식

* fix: catch ZodError
* feature: 동아리 pending 기능

* fix: prettier 포맷팅 에러 & PUBLIC_CLUB_STATUS 확대하기

* style: /users/me/club-creation-requests를 /club-creation-requests로 변경
* feature: 동아리 pending 기능

* fix: prettier 포맷팅 에러 & PUBLIC_CLUB_STATUS 확대하기

* style: /users/me/club-creation-requests를 /club-creation-requests로 변경
* feature: Support New DB structures

* fix: add formatYearMonth

* feature: recruitment CRUD

* feature: 대표 recruitment 추가
* feature: ios universal link redirection logic

* feature: assetlinks.json

* fix: asset link

---------

Co-authored-by: Jeongyeon Lee <jylee05@snu.ac.kr>
* feat: add tables for announcement feature

* feat: create entities based on the tables created
* feat: add GET api/v1/announcements

* feat: add GET api/v1/terms

* chore: add apis to swagger docs
* fix: adjust to new db structures with the help of chatgpt

* fix: include newly added fields in clubManagerEntity
* chore: 새로운 old_club_manager 만들기

* fix: 오타수정

Co-authored-by: Copilot <copilot@github.com>

* chore: 기존 db 데이터만 삭제

Co-authored-by: Copilot <copilot@github.com>

---------

Co-authored-by: Copilot <copilot@github.com>
* feature: ios universal link redirection logic

* feature: assetlinks.json

* fix: asset link

* ios aasa file change

---------

Co-authored-by: Daniel <danielna1118@snu.ac.kr>
* POST clubs/register

* Remove POST /api/v1/club-creation-requests

* init PATCH /api/v1/managers/me/clubs/{uuid}

* 동아리 생성-수정 코드 재사용성 강화

* Update GET /api/v1/managers/me/clubs/

* feature: POST /managers/me/clubs/{uuid}/recruitments

* Add /api/v1/clubs/:uuid?/manager-requests

* feature: PATCH /managers/me/recruitments/{recruitment_id}

* feature: DELETE /managers/me/recruitments/{recruitment_id}

* feature: POST /managers/me/clubs/{uuid}/verifications

* fix: remove DeviceEntity

* Add ClubAccessService

---------

Co-authored-by: yhaeul <haeul1005@naver.com>
* Modify Recruitment Views

* Notion 글 Swagger에 반영하기
* feature: ios universal link redirection logic

* feature: assetlinks.json

* fix: asset link

* ios aasa file change

* fix: updated sha256 fingerprint in assetlinks

---------

Co-authored-by: Jeongyeon Lee <jylee05@snu.ac.kr>
* feature: ios universal link redirection logic

* feature: assetlinks.json

* fix: asset link

* ios aasa file change

* fix: updated sha256 fingerprint in assetlinks

* assetlinks for debug testing

---------

Co-authored-by: Jeongyeon Lee <jylee05@snu.ac.kr>
* feature: ios universal link redirection logic

* feature: assetlinks.json

* fix: asset link

* ios aasa file change

* fix: updated sha256 fingerprint in assetlinks

* assetlinks for debug testing

* fix: UUID change to work for iOS and android

---------

Co-authored-by: Jeongyeon Lee <jylee05@snu.ac.kr>
* feature: ios universal link redirection logic

* feature: assetlinks.json

* fix: asset link

* ios aasa file change

* fix: updated sha256 fingerprint in assetlinks

* assetlinks for debug testing

* fix: UUID change to work for iOS and android

* es lint fix

---------

Co-authored-by: Jeongyeon Lee <jylee05@snu.ac.kr>
* feature: ios universal link redirection logic

* feature: assetlinks.json

* fix: asset link

* ios aasa file change

* fix: updated sha256 fingerprint in assetlinks

* assetlinks for debug testing

* fix: UUID change to work for iOS and android

* es lint fix

* Revert "es lint fix"

This reverts commit c15dc14.

* Revert "fix: UUID change to work for iOS and android"

This reverts commit 5402817.

* fix: Updated fallback UUID link

---------

Co-authored-by: Jeongyeon Lee <jylee05@snu.ac.kr>
* feature: 승인 대기 중인 동아리 목록 조회 (운영진 전용)
- GET /admin/clubs/pending

* feature: 동아리 approve or reject

* feature: pending중인 동아리 view

* feature: 운영진 동아리 관리 API 일반화

* feature: swagger 문서 업데이트

---------

Co-authored-by: yhaeul <haeul1005@naver.com>
* feature: GET /admin/clubs/histories

* feature: GET /admin/clubs/manager-requests

* feature: GET /admin/clubs/verifications

* feature: PATCH /admin/clubs/manager-requests/{id}/status

* feature: PATCH /api/v1/admin/clubs/verifications/2/status
* API URL namespace를 v1에서 v2로 이동

기존 앱(v1) 호환을 위해 develop이 노출하는 API를 /api/v2/*로 옮긴다.
v1 폴더는 비어있는 상태가 되며, 이후 Step에서 main의 v1 코드를 이식한다.

- pages/api/v1/ → pages/api/v2/ (47개 endpoint git mv로 이동)
- middleware.ts matcher 28개 v2로 교체
- src/lib/openapi/register-paths.ts 경로 51개 v2로 교체
  (/api/health-check는 버전 prefix 없이 유지)
- 클라이언트 fetch 6개소 v2로 갱신
  (download/app, c/edit/[uuid], src/repositories/club.ts)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Web Kakao Login Callback도 v2로 변경

* v1 API endpoint를 develop으로 이식

기존 앱(v1) 호환을 위해 main의 v1 endpoint와 의존 서비스를 develop에 옮겨 격리한다.
v2 코드는 건드리지 않고, v1은 통째로 폴더 단위 격리되어 향후 v2 일원화 시 일괄 삭제 가능하다.

- pages/api/v1/ 27개 endpoint를 main에서 복사
- server/service/v1/ 5개 서비스 복사 (Auth/Club/Review/Slack/User)
  - Provider DI cache key 충돌을 피하려 클래스명에 V1 접미사 부여
- server/infra/database/entities/v1/club-manager-register-request.entity.ts 추가
  - develop이 새 테이블 club_manager_request로 entity를 옮긴 반면,
    원래 club_manager_register_request 테이블은 그대로 남아있어 v1 전용 entity로 격리
- middleware.ts matcher에 v1 인증 보호 path 12개 append
- user.service.ts: develop이 nullable로 바꾼 college/major 컬럼에 ?? undefined 처리

* v1 응답 shape을 main과 일치하도록 mapper 추가

develop의 Club 도메인은 main 대비 12개 신규 필드(shortDescription, affiliationType,
collegeMajorId, collegeMajor, isOfficialVerified, verifiedAt, dongbangLocation,
minActivityPeriod, activeMemberCount, sns, status, rejectReason)를 가진다.
또한 CollegeMajor는 college/major가 nullable로 바뀌었다.

v1 endpoint가 develop entity를 그대로 직렬화하면 main 응답과 shape이 어긋나
기존 앱 호환이 깨지므로 v1 service 안에 main과 동일한 shape의 mapper를 둔다.

- server/service/v1/club.service.ts: V1Club 타입 + toV1ClubDomain 함수 추가,
  develop의 toClubDomain 호출을 모두 toV1ClubDomain으로 교체
- server/service/v1/user.service.ts: V1CollegeMajor 타입 추가,
  getCollegeMajors의 nullable 컬럼을 ?? ''로 좁혀 main 계약 유지
- pages/api/v1/*: ResponseData 타입을 V1Club/V1CollegeMajor로 갱신

검증: dev DB(telepresence) 위에서 /api/v1/clubs/popular, /clubs/latest,
/clubs/categories, /users/majors 응답이 main의 필드 집합과 1:1 일치 확인.

* 이미지 업로드 성공 응답 처리 수정

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
kimnamheeee and others added 23 commits May 15, 2026 22:34
* chore: remove tally related contents in privacy policy

* chore: update docs renewal date information
웹 어드민 대시보드 생성

- 동아리 신청 현황 확인 + 승인/반려
- 기등록 동아리 관리자 매핑 요청 확인 + 승인/반려
- 총동연 공식 인증 요청 확인 + 승인/반려
- 동아리 수정 이력 확인
카카오 로그인 및 admin 전용 API 호출을 v1에서 v2로 변경
* refactor: restructure club search flow

SearchService를 orchestrator로 축소하고 검색 흐름을 component 단위로 분리한다.

- server/service/search/ 아래로 search-query, search-typo-correction, search-result-hydrator, search-sort, search-log component와 search.types를 추가
- 직접 검색을 name, shortDescription, college_major 기반으로 통합하고 fullName, tags 매칭은 제거
- 오타 보정 후보 source를 name과 tokenized shortDescription으로 좁힘
- 기본 정렬을 isOfficialVerified 우선 + 그룹 내부 random으로 변경
- club.uuid 기준 dedupe와 review hydration 유지, API 응답 계약 유지

* feat: add club search filters

GET /api/v2/clubs/search에 facet 필터 query를 추가한다. 원 검색어와 오타 보정어 검색 모두에 동일하게 적용된다.

- SearchFilterService 신설, club 컬럼 기반 필터(affiliation_type, recruit_type, has_dongbang, is_official_verified, min_activity_period)와 최신 유효 recruitment LATERAL JOIN 기반 필터(is_recruiting, has_membership_fee) 적용
- SearchQueryService를 QueryBuilder 기반으로 전환하여 텍스트 검색과 college_major 검색 모두 동일 필터를 거치도록 변경
- min_activity_period는 0, 1, 2, 2_plus 다중 선택을 지원하며 2_plus는 club.min_activity_period >= 2로 해석
- API handler에 parseSearchFilters 추가, boolean/enum/min_activity_period 잘못된 값은 400 invalid search filter 반환
- ClubSearchQuerySchema와 OpenAPI 문서를 확장
- sql/260510.sql에 club 필터 컬럼과 club_recruitment 인덱스 추가 (DB 수동 적용 필요)

* fix: update min activity period search filter

* [검색 TF] 사용자별 최근 검색어 API 추가 (#55)

* feat: add user recent searches

사용자별 최근 검색어 저장/조회/전체삭제 API를 v2에 추가한다. 오타 보정이 동작해도 저장 값은 무조건 원본 검색어이며, 검색 API와 별도 endpoint로 분리해 응답 계약을 건드리지 않는다.

- user_recent_search 테이블과 UserRecentSearchEntity 신설, datasource entities 배열에 등록 (sql/260514.sql 수동 적용 필요)
- UserService에 findRecentSearches / saveRecentSearch / deleteRecentSearches 추가. 저장은 delete-after-insert + FIFO eviction을 트랜잭션으로 처리해 사용자별 최대 8개를 유지한다
- GET / POST / DELETE /api/v2/users/me/recent-searches handler 추가. POST는 trim 후 빈 문자열이면 zod로 400을 반환한다
- CreateRecentSearchSchema, RecentSearchSchema, RecentSearchesResponseSchema 및 OpenAPI path 등록

* perf: collapse recent search save into upsert + single cleanup

같은 검색어 재저장과 8개 초과 정리 로직을 INSERT ON CONFLICT DO UPDATE와 NOT IN 단일 DELETE로 대체해 저장 경로의 DB 라운드트립을 4회에서 2회로 줄인다. 정렬 키도 created_at에서 updated_at으로 통일해 재검색 시 자연스럽게 최상단으로 올라오게 한다.

- saveRecentSearch에서 트랜잭션 + delete + insert + find + delete 흐름을 raw upsert + raw cleanup DELETE 2회로 교체. evictOldRecentSearches 헬퍼 제거
- findRecentSearches 정렬을 updatedAt DESC로 변경
- 인덱스를 ix_user_recent_search_service_user_updated_at (service_user_id, updated_at DESC)로 교체
- API 응답 createdAt 필드는 그대로 두고 내부 매핑만 it.updatedAt로 변경

* fix: align recent search API contract

* chore: add redis client configuration

* feat: autosave recent searches from search

* test: add recent search test APIs and swagger docs

* refactor: simplify recent search internals

* refactor: simplify recent search debug response
공식 인증 동아리를 먼저 배치하는 구조는 유지하되, 동일한 인증 상태 내에서는
Math.random() 기반 무작위 정렬 대신 query와 club.name의 일치 정도가 높은 순으로
정렬한다. (정확 일치 > 접두 일치 > 부분 일치 위치순 > 이름 길이 > 가나다순)

점수는 클럽당 한 번만 계산하는 decorate-sort로 처리해 비교자 내 중복 계산을 제거했다.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* feat: add app version policy service

* feat: expose app version policy APIs

* feat: protect app version policy updates
* feat: admin 동아리 상세 검토 UX 개선

- 동아리 목록 정렬을 최신순(DESC)으로 변경
- PENDING 상태일 때만 승인/반려 버튼 노출
- APPROVED/REJECTED 상태에서 '대기로 변경' 버튼 추가 (PENDING 복구)
- 승인·반려·대기 변경 전 확인 팝업 추가
- 반려 사유 미입력 시 에러 문구 표시
- 반려 상태 상세에 반려 사유 표시 (스키마·서비스 연동)
- 동아리 상세에 UUID 표시

* feat: 관리자 매핑 신청 탭 UX 개선 및 상태 관리 로직 보완

- 관리자 매핑 신청 목록에 reject_reason 필드 추가 (서비스, 스키마, API)
- PENDING 상태일 때만 승인/반려 버튼 노출, 그 외 '대기로 변경' 버튼 표시
- APPROVED → PENDING 복구 시 ClubManager 레코드 삭제 처리
- 승인/반려/대기 변경 전 확인 팝업 추가
- 반려 사유 미입력 시 에러 문구 표시
- 반려 사유를 카드 중간 컬럼에 표시 (3컬럼 레이아웃)
- 관리자 매핑 신청 카드에 동아리 상세 정보 모달 추가
- AdminClubManagerRequestStatusUpdate 스키마: PENDING 상태 허용으로 변경

* feat: 공식 인증 탭 UX 개선 및 상태 관리 로직 보완

- 공식 인증 목록에 reject_reason 필드 추가 (서비스, 스키마, API)
- PENDING 상태일 때만 승인/반려 버튼 노출, 그 외 '대기로 변경' 버튼 표시
- APPROVED → PENDING 복구 시 클럽 isOfficialVerified 초기화 처리
- 승인/반려/대기 변경 전 확인 팝업 추가
- 반려 사유 미입력 시에도 반려 가능 (validation 제거)
- 반려 사유를 카드 중간 컬럼에 표시 (3컬럼 레이아웃)
- 동아리 상세 정보 모달 추가

* feat: 동아리 수정이력에 동아리 UUID 표시 추가
* feat: 어드민 대시보드 로그인 인증로직 추가(user.role=admin)

* feat: 어드민 대시보드 UX 수정
- ClubDetailDialog + ClubInfoModal → ClubDetailModal 단일 컴포넌트로 통합
  (sidebar render prop으로 탭별 오른쪽 패널 주입, 전체 max-w-4xl)
- 관리자 매핑/공식 인증 상세보기에 현재 관리자 정보 추가
- 동아리 이미지 크기 축소(w-40) 및 왼쪽 배치
- 탭 버튼에 PENDING 건수 배지 표시 (30초 자동 갱신, 뮤테이션 후 즉시 반영)
- '대기' 상태 필터 버튼에 빨간 점 표시

* feat: 어드민 대시보드 처리 결과 토스트 알림 추가

- 승인/반려/대기로 변경 성공 시 초록 토스트 표시
- 처리 오류 시 실제 에러 메시지를 빨간 토스트로 표시
- 3초 후 자동 닫힘, × 버튼으로 수동 닫기 가능

* feat: 동아리 상세 모달 backdrop 클릭 시 닫기
* feat: add isSaved field to Club model and schema

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat: populate isSaved for the requesting user in club and search services

Add getSavedClubIdSet helper and thread an optional serviceUserId through
club lookups and search hydration so each returned club reflects whether
the current user has saved it.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat: resolve optional auth on club list, detail, and search endpoints

Resolve the optional caller identity and pass the resolved serviceUserId
to the club and search services so list, detail, and search responses
include the isSaved flag for authenticated users.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs: document optional auth and guest id header on club endpoints

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* fix: apply search filters synchronously

* fix: reuse latest recruitment search filter join
* feat: add internal API to update user role (admin/user)

* refactor: reuse APP_VERSION_POLICY_API_KEY for admin role update API

@yhaeul yhaeul left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

확인 완료

@yhaeul yhaeul merged commit 38dff87 into main Jun 29, 2026

@yabsed yabsed left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

지금 상태에서 뭐가 터질지를 예측하기 어려워 보입니다. 그렇지만 v2가 정상작동할 것이라고 봅니다. 하위호환성은 괜찮을 것으로 봅니다

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants