Skip to content

[feat] 백오피스에서 관리자(허용 이메일) DB 관리 - #33

Merged
theminjunchoi merged 4 commits into
devfrom
feat/32-admin-members
Jul 24, 2026
Merged

[feat] 백오피스에서 관리자(허용 이메일) DB 관리#33
theminjunchoi merged 4 commits into
devfrom
feat/32-admin-members

Conversation

@theminjunchoi

@theminjunchoi theminjunchoi commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

🔗 연관 이슈

📌 개요

백오피스 접근 허용 관리자를 지금은 ADMIN_EMAILS 환경 변수로만 관리해 추가/삭제에 GitHub 접근 + 재배포가 필요하다. 이를 DB로 관리 + 백오피스 UI에서 추가/삭제해 재배포 없이 즉시 반영되게 한다.

🔧 주요 변경사항

  • admin_accounts 테이블 + AdminAccount 엔티티(email UNIQUE·정규화 저장·불변식 가드, 추가한 관리자·시각 기록)
  • 허용 판정 = ADMIN_EMAILS 부트스트랩 ∪ DB 합집합 — AdminAuthService가 DB까지 조회
    • 부트스트랩(ENV)은 UI에서 지울 수 없는 break-glass → 전 관리자 자기잠금(lockout) 방지
  • AdminAccountService: 허용 판정 / 목록(ENV+DB 병합) / 추가(중복·형식 검증, 동시 추가 유니크 처리) / 삭제(자기 자신 삭제 방지)
  • 백오피스 "관리자 관리" 페이지 — 이메일 추가 폼 + 목록(출처 배지, 삭제 확인 다이얼로그), ENV 항목 읽기 전용

🌐 API · DB 영향

  • API 변경(신규, ROLE_ADMIN):
    • GET /api/admin/accounts — 허용 관리자 목록(ENV+DB 병합)
    • POST /api/admin/accounts {email} — 추가(다음 로그인부터 즉시 허용)
    • DELETE /api/admin/accounts/{id} — 삭제(자기 자신 불가)
    • 에러코드 추가: ADMIN_ACCOUNT_ALREADY_EXISTS(409) · ADMIN_ACCOUNT_NOT_FOUND(404) · CANNOT_REMOVE_SELF(409)
  • DB 마이그레이션: V5__admin_accounts.sql(email UNIQUE)
  • 하위 호환: 호환. 기존 ADMIN_EMAILS 그대로 동작(부트스트랩으로 흡수), 로그인 계약 변경 없음

💬 리뷰 포인트

Summary by CodeRabbit

  • 새로운 기능

    • 관리자 관리 화면이 추가되어 관리자 계정 목록을 조회하고 이메일로 새 관리자를 등록할 수 있습니다.
    • 등록된 관리자를 삭제할 수 있으며, 본인 및 환경 설정으로 등록된 관리자는 삭제할 수 없습니다.
    • 관리자 목록에서 계정 출처와 등록 정보를 확인할 수 있습니다.
    • 등록된 관리자 계정도 백오피스 로그인 권한을 부여받습니다.
  • 개선 사항

    • 중복 이메일, 잘못된 이메일, 존재하지 않는 계정 등에 대한 안내가 제공됩니다.
    • 목록 조회에 실패하면 재시도할 수 있습니다.

- admin_accounts 테이블 + 허용 판정을 ENV 부트스트랩 ∪ DB 합집합으로 변경(재배포 없이 즉시 반영)
- /api/admin/accounts 목록·추가·삭제(ROLE_ADMIN), 자기삭제·중복·형식 검증
- ENV 부트스트랩은 UI 삭제 불가(자기잠금 방지 break-glass)
- 백오피스 '관리자 관리' 페이지(추가/삭제 UI)
@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

Test Results

219 tests  +18   219 ✅ +18   1m 7s ⏱️ +7s
 39 suites + 2     0 💤 ± 0 
 39 files   + 2     0 ❌ ± 0 

Results for commit d1ccbce. ± Comparison against base commit 91f70a9.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

Test Coverage

Overall Project 71.53% -1.88% 🍏
Files changed 72.04% 🍏

File Coverage
AdminAuthService.kt 100% 🍏
AdminAccountSource.kt 100% 🍏
ErrorCode.kt 100% 🍏
AdminAccountService.kt 96.65% -3.35% 🍏
AdminProperties.kt 93.85% 🍏
AdminAccount.kt 89.41% -10.59% 🍏
AdminAccountEntry.kt 85.94% -14.06% 🍏
AdminAccountController.kt 9.84% -90.16% 🍏
AddAdminAccountRequest.kt 0% 🍏
AdminAccountResponse.kt 0% 🍏

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

ENV 부트스트랩 관리자와 DB 관리자를 통합 관리하는 백엔드 모델·서비스·API를 추가하고, 관리자 인증이 DB 허용 여부를 반영하도록 변경했다. 백오피스에는 관리자 조회·추가·삭제 화면과 라우팅·내비게이션을 연결했다.

Changes

관리자 계정 관리

Layer / File(s) Summary
관리자 계정 저장 모델
src/main/kotlin/com/nexters/gamss/admin/{config,domain,repository,service}/*, src/main/resources/db/migration/V7__admin_accounts.sql, src/test/kotlin/com/nexters/gamss/admin/domain/*
admin_accounts 테이블과 JPA 엔티티·저장소를 추가하고, ENV/DB 계정을 통합 표현하는 AdminAccountEntry와 출처 enum을 정의했다. 이메일 정규화 및 생성 시각을 저장하고 관련 테스트를 추가했다.
허용 판정 및 계정 서비스
src/main/kotlin/com/nexters/gamss/admin/service/*, src/main/kotlin/com/nexters/gamss/admin/config/AdminProperties.kt, src/main/kotlin/com/nexters/gamss/admin/service/AdminAuthService.kt, src/main/kotlin/com/nexters/gamss/global/exception/ErrorCode.kt, src/test/kotlin/com/nexters/gamss/admin/service/*
ENV 또는 DB 기준으로 로그인 허용 여부를 판정하고, 관리자 목록 병합·추가·삭제 정책을 구현했다. 중복·미존재·자기 삭제 오류와 인증 서비스 연계를 테스트했다.
관리자 계정 API
src/main/kotlin/com/nexters/gamss/admin/controller/*
관리자 목록 조회, 이메일 추가, ID 삭제 API와 요청·응답 DTO를 추가했다. 인증 주체의 이메일을 서비스 호출과 응답 매핑에 사용한다.
백오피스 관리자 관리 화면
admin-web/src/App.tsx, admin-web/src/components/layout/AdminLayout.tsx, admin-web/src/pages/admin-accounts/*, admin-web/src/types/adminAccount.ts
보호 라우트와 내비게이션에 /admin-accounts를 추가하고, 관리자 목록 조회·추가·삭제, 오류·재시도·로딩 상태 및 ENV 읽기 전용 표시를 구현했다.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  actor Admin
  participant AdminAccountList
  participant AdminAccountController
  participant AdminAccountService
  participant AdminAccountRepository

  Admin->>AdminAccountList: 관리자 관리 페이지 접근
  AdminAccountList->>AdminAccountController: GET /api/admin/accounts
  AdminAccountController->>AdminAccountService: list(principal.email)
  AdminAccountService->>AdminAccountRepository: DB 관리자 목록 조회
  AdminAccountService-->>AdminAccountController: ENV 및 DB 관리자 목록
  AdminAccountController-->>AdminAccountList: 관리자 응답 반환
  Admin->>AdminAccountList: 이메일 추가 또는 삭제
  AdminAccountList->>AdminAccountController: POST 또는 DELETE 요청
  AdminAccountController->>AdminAccountService: add 또는 remove 호출
  AdminAccountService->>AdminAccountRepository: 계정 저장 또는 삭제
  AdminAccountController-->>AdminAccountList: 작업 결과 반환
Loading

Possibly related PRs

  • Nexters/GAMSS-Server#18: 동일한 App.tsxAdminLayout.tsx 라우팅·내비게이션 구조를 기반으로 관리자 관리 경로를 확장했다.

Suggested reviewers: kite707

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.95% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 백오피스에서 관리자 허용 이메일을 DB로 관리한다는 핵심 변경과 잘 맞습니다.
Description check ✅ Passed 필수 섹션(개요, 주요 변경사항, API·DB 영향, 리뷰 포인트)이 모두 있고 내용도 PR 범위를 충분히 설명합니다.
Linked Issues check ✅ Passed ENV 부트스트랩+DB 합집합, 관리자 CRUD API, 읽기 전용 ENV, 중복·형식·자기 삭제 방지, 테스트까지 요구를 충족합니다.
Out of Scope Changes check ✅ Passed 관리자 계정 관리에 필요한 서비스·DTO·UI·테스트 중심 변경뿐이라 별도 범위를 벗어난 작업은 보이지 않습니다.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/32-admin-members

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

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@admin-web/src/pages/admin-accounts/list.tsx`:
- Around line 175-180: Update the icon-only delete Button within the
account.removable condition to include an accessible aria-label containing the
account’s email, so assistive technology identifies which account will be
deleted.
- Around line 25-38: 관리자 계정 요청의 onError가 e.message를 오류 코드로 직접 전달하지 않도록 수정하세요.
apiFetch의 실패 응답에서 표준 error.code를 읽을 수 있는 타입으로 오류를 파싱하고, mapError가 해당 코드만 받아 사용자
메시지로 변환하게 하세요. 전역 오류 처리 계약을 사용하는 경우에도 message 대신 표준 오류 코드 필드를 전달하도록 일관되게 맞추세요.

In
`@src/main/kotlin/com/nexters/gamss/admin/controller/dto/AdminAccountResponse.kt`:
- Around line 23-30: Update AdminAccountResponse.from so removable is true only
when the account source is DB and entry.email differs from the current
principal’s email; pass the current email into this mapping flow and preserve
the existing false behavior for non-DB accounts.

In `@src/main/kotlin/com/nexters/gamss/admin/service/AdminAccountService.kt`:
- Around line 33-40: Update AdminAccountService so bootstrapEmails() takes
precedence over database entries: build the ENV email set, exclude matching DB
entries from the displayed list, and always expose ENV entries as
bootstrap/read-only entries. Also update the delete flow to reject any email
present in the ENV set, preserving isAllowed() behavior and preventing
ENV-backed accounts from being deleted.

In `@src/test/kotlin/com/nexters/gamss/admin/service/AdminAccountServiceTest.kt`:
- Around line 58-65: Update AdminAccountService.list and the corresponding test
so duplicate emails present in both ENV bootstrap accounts and the database
retain the ENV-sourced entry, with the test expecting AdminAccountSource.ENV.
Ensure the DB duplicate is omitted from the returned list so ENV accounts remain
read-only and cannot appear deletable.

In `@src/test/kotlin/com/nexters/gamss/admin/service/AdminAuthServiceTest.kt`:
- Around line 21-26: Update the AdminAuthServiceTest service helper to configure
accountRepository.existsByEmail for DB-approved emails, while preserving the
existing email configuration. Add a test covering an email where existsByEmail
returns true and verify that AdminAuthService issues an administrator token,
optionally mocking AdminAccountService directly to keep the
authentication-service boundary explicit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f43f1acd-d24c-4d0b-a47d-5eb0495a79be

📥 Commits

Reviewing files that changed from the base of the PR and between f513dc7 and 30fccea.

📒 Files selected for processing (18)
  • admin-web/src/App.tsx
  • admin-web/src/components/layout/AdminLayout.tsx
  • admin-web/src/pages/admin-accounts/list.tsx
  • admin-web/src/types/adminAccount.ts
  • src/main/kotlin/com/nexters/gamss/admin/config/AdminProperties.kt
  • src/main/kotlin/com/nexters/gamss/admin/controller/AdminAccountController.kt
  • src/main/kotlin/com/nexters/gamss/admin/controller/dto/AddAdminAccountRequest.kt
  • src/main/kotlin/com/nexters/gamss/admin/controller/dto/AdminAccountResponse.kt
  • src/main/kotlin/com/nexters/gamss/admin/domain/AdminAccount.kt
  • src/main/kotlin/com/nexters/gamss/admin/repository/AdminAccountRepository.kt
  • src/main/kotlin/com/nexters/gamss/admin/service/AdminAccountEntry.kt
  • src/main/kotlin/com/nexters/gamss/admin/service/AdminAccountService.kt
  • src/main/kotlin/com/nexters/gamss/admin/service/AdminAccountSource.kt
  • src/main/kotlin/com/nexters/gamss/admin/service/AdminAuthService.kt
  • src/main/kotlin/com/nexters/gamss/global/exception/ErrorCode.kt
  • src/main/resources/db/migration/V5__admin_accounts.sql
  • src/test/kotlin/com/nexters/gamss/admin/service/AdminAccountServiceTest.kt
  • src/test/kotlin/com/nexters/gamss/admin/service/AdminAuthServiceTest.kt

Comment thread admin-web/src/pages/admin-accounts/list.tsx
Comment thread admin-web/src/pages/admin-accounts/list.tsx
Comment thread src/main/kotlin/com/nexters/gamss/admin/service/AdminAccountService.kt Outdated
Comment thread src/test/kotlin/com/nexters/gamss/admin/service/AdminAccountServiceTest.kt Outdated
Comment thread src/test/kotlin/com/nexters/gamss/admin/service/AdminAuthServiceTest.kt Outdated
- 목록에서 ENV를 DB보다 우선(ENV와 중복된 DB 항목 숨김) → '삭제=즉시 차단' 안내 일관성 유지
- 본인 계정은 removable=false로 표시해 자기삭제 방지와 UI 일치
- 삭제 버튼에 이메일 포함 aria-label 추가
- DB 허용 로그인 경로 테스트 추가
- 정규화(공백 제거·소문자)되지 않은 이메일이면 init require로 저장 전 차단
- unique 제약·isAllowed 조회가 정규화를 전제하므로 도메인이 fail-fast로 가드
@theminjunchoi
theminjunchoi requested a review from kite707 July 23, 2026 16:39
- ErrorCode: 카드·관리자 에러코드 둘 다 유지
- App.tsx·AdminLayout: LLM설정·관리자관리 라우트·nav 둘 다 유지
- 마이그레이션 V5→V7 (dev의 V5 llm_settings·V6 cards 뒤로)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
admin-web/src/pages/admin-accounts/list.tsx (2)

66-67: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

표준 오류 코드 필드를 사용하도록 오류 계약을 고정하세요.

두 호출부가 e?.message를 직접 mapError에 전달합니다. 현재 data provider가 우연히 message에 코드 값을 넣는 구현이라면 동작하지만, 표준 응답의 error.code가 별도 필드로 전달될 때 모든 오류가 기본 문구로 뭉개집니다. 타입화된 오류 객체에서 code를 읽어 전달하도록 통일하세요.

Also applies to: 77-78

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@admin-web/src/pages/admin-accounts/list.tsx` around lines 66 - 67, Update the
onError handlers in the affected account operations to read the standard error
code field from the typed error object and pass that value to mapError instead
of e?.message. Apply the same change to both call sites while preserving the
existing setError behavior.

45-46: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

삭제 요청 중 중복 클릭을 막아 주세요.

삭제 뮤테이션의 진행 상태를 사용하지 않아 확인 버튼을 빠르게 여러 번 누르면 같은 ID에 DELETE가 중복 전송될 수 있습니다. 첫 요청이 성공한 뒤 두 번째 요청이 404가 되어 성공 작업 뒤 오류가 표시될 수 있으므로, 삭제 진행 중 확인 버튼을 비활성화하세요.

권장 수정 방향
-  const { mutate: removeMutate } = useCustomMutation()
+  const { mutate: removeMutate, isLoading: removing } = useCustomMutation()

-  <AlertDialogAction onClick={() => remove(account.id as number)}>삭제</AlertDialogAction>
+  <AlertDialogAction disabled={removing} onClick={() => remove(account.id as number)}>
+    삭제
+  </AlertDialogAction>

Also applies to: 71-79

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@admin-web/src/pages/admin-accounts/list.tsx` around lines 45 - 46, Update the
removeMutate setup to capture its loading state (for example, removing) and use
that state in the delete confirmation UI around the affected lines to disable
the confirm button while deletion is in progress. Preserve the existing add
mutation state and re-enable the button after the deletion completes.
src/main/kotlin/com/nexters/gamss/admin/service/AdminAccountService.kt (2)

61-65: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

무결성 오류 전체를 중복 오류로 변환하지 마세요.

DataIntegrityViolationException은 이메일 UNIQUE 위반 외에도 길이 초과나 NOT NULL 위반을 포함할 수 있습니다. 현재는 이런 오류도 ADMIN_ACCOUNT_ALREADY_EXISTS로 바뀌어 잘못된 409 응답을 반환합니다. uk_admin_accounts_email 위반만 식별해 변환하고, 나머지는 원래 예외로 처리하세요.

권장 수정 방향
 } catch (e: DataIntegrityViolationException) {
-    throw BusinessException(ErrorCode.ADMIN_ACCOUNT_ALREADY_EXISTS, e.message)
+    if (isEmailUniqueViolation(e)) {
+        throw BusinessException(ErrorCode.ADMIN_ACCOUNT_ALREADY_EXISTS)
+    }
+    throw e
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/kotlin/com/nexters/gamss/admin/service/AdminAccountService.kt`
around lines 61 - 65, Update the exception handling around AdminAccountService’s
adminAccountRepository.saveAndFlush call to convert only violations of the
uk_admin_accounts_email unique constraint into ADMIN_ACCOUNT_ALREADY_EXISTS.
Re-throw other DataIntegrityViolationException instances unchanged so length,
NOT NULL, and unrelated integrity failures retain their original handling.

74-81: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

ENV와 중복된 DB 행도 삭제 경로에서 차단해야 합니다.

list()에서는 ENV 이메일과 동일한 DB 행을 숨기지만, remove()는 본인 여부만 검사합니다. 따라서 ENV에 나중에 추가된 이메일의 기존 DB 행은 다른 관리자가 ID를 직접 호출해 삭제할 수 있습니다. ENV 이메일도 삭제 불가 조건에 포함하거나, 숨겨진 행을 NOT_FOUND로 처리해 부트스트랩 계정을 일관되게 읽기 전용으로 유지하세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/kotlin/com/nexters/gamss/admin/service/AdminAccountService.kt`
around lines 74 - 81, Update the remove() deletion guard to also reject accounts
whose email matches any normalized ENV-configured admin email, not only
currentEmail. Preserve the existing CANNOT_REMOVE_SELF behavior and ensure such
duplicate bootstrap-account rows cannot be deleted through direct IDs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@admin-web/src/pages/admin-accounts/list.tsx`:
- Around line 66-67: Update the onError handlers in the affected account
operations to read the standard error code field from the typed error object and
pass that value to mapError instead of e?.message. Apply the same change to both
call sites while preserving the existing setError behavior.
- Around line 45-46: Update the removeMutate setup to capture its loading state
(for example, removing) and use that state in the delete confirmation UI around
the affected lines to disable the confirm button while deletion is in progress.
Preserve the existing add mutation state and re-enable the button after the
deletion completes.

In `@src/main/kotlin/com/nexters/gamss/admin/service/AdminAccountService.kt`:
- Around line 61-65: Update the exception handling around AdminAccountService’s
adminAccountRepository.saveAndFlush call to convert only violations of the
uk_admin_accounts_email unique constraint into ADMIN_ACCOUNT_ALREADY_EXISTS.
Re-throw other DataIntegrityViolationException instances unchanged so length,
NOT NULL, and unrelated integrity failures retain their original handling.
- Around line 74-81: Update the remove() deletion guard to also reject accounts
whose email matches any normalized ENV-configured admin email, not only
currentEmail. Preserve the existing CANNOT_REMOVE_SELF behavior and ensure such
duplicate bootstrap-account rows cannot be deleted through direct IDs.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5bfb6510-7aea-4be1-83e4-6028ae2ec3a0

📥 Commits

Reviewing files that changed from the base of the PR and between 30fccea and d1ccbce.

📒 Files selected for processing (13)
  • admin-web/src/App.tsx
  • admin-web/src/components/layout/AdminLayout.tsx
  • admin-web/src/pages/admin-accounts/list.tsx
  • src/main/kotlin/com/nexters/gamss/admin/controller/AdminAccountController.kt
  • src/main/kotlin/com/nexters/gamss/admin/controller/dto/AdminAccountResponse.kt
  • src/main/kotlin/com/nexters/gamss/admin/domain/AdminAccount.kt
  • src/main/kotlin/com/nexters/gamss/admin/service/AdminAccountEntry.kt
  • src/main/kotlin/com/nexters/gamss/admin/service/AdminAccountService.kt
  • src/main/kotlin/com/nexters/gamss/global/exception/ErrorCode.kt
  • src/main/resources/db/migration/V7__admin_accounts.sql
  • src/test/kotlin/com/nexters/gamss/admin/domain/AdminAccountTest.kt
  • src/test/kotlin/com/nexters/gamss/admin/service/AdminAccountServiceTest.kt
  • src/test/kotlin/com/nexters/gamss/admin/service/AdminAuthServiceTest.kt

@kite707 kite707 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.

백오피스에서 관리자를 추가할 수 있게 개발해주셨네요! 고생하셨습니다~

@theminjunchoi
theminjunchoi merged commit 4e1f50f into dev Jul 24, 2026
5 checks passed
@theminjunchoi
theminjunchoi deleted the feat/32-admin-members branch July 24, 2026 17:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] 백오피스에서 관리자(허용 이메일) DB 관리

2 participants