사용자 관리¶
/admin/users admin
조직 구성원을 추가하고 역할을 주는 화면입니다. 탭이 둘입니다.
이 화면에서 지금 안 되는 것 셋
- 초대 메일이 가지 않습니다. "Invite User" 는 메일도, 자격증명도, 토큰도 만들지 않습니다
- Generate Invite Link 는 동작하지 않습니다. 서버가 자리막음이고 수락 라우트도 없습니다
- Role Permissions 탭은 효력이 없습니다. 브라우저에만 저장됩니다
아래에 각각 적어 두었습니다. 지금 사람을 넣는 길은 이미 있는 사용자를 이메일로 찾아 구성원으로 추가하는 것뿐입니다.

Users 탭¶
- 이름·이메일 검색, 역할 탭 필터
- 행마다 역할 선택 상자 — 고르면 바로 저장됩니다
- Deactivate 버튼 (확인 창)
- Edit 창 — 이름·이메일·역할
사용자 추가 (Invite User)¶
이름 + 이메일 + 역할을 넣습니다. 이메일을 세 자 넘게 치고 @ 가 들어가면 300ms
뒤 기존 사용자를 찾아보고, 있으면 이름을 자동으로 채웁니다.
이름이 "Invite" 지만 실제 동작은 둘 중 하나입니다.
| 그 이메일의 사용자가 | 결과 |
|---|---|
| 이미 있다 | 조직 구성원으로 추가 — 바로 쓸 수 있습니다 |
| 없다 | 사용자 행을 비활성(is_active = false) 으로 만들고 구성원으로 추가 |
두 번째 경우는 로그인할 수 없는 상태로 남습니다. 메일 발송·자격증명 생성·초대 토큰이 모두 없기 때문입니다.
Generate Invite Link¶
역할과 유효기간(1·3·7·30일, 기본 7일)을 고르면 링크를 클립보드에 복사합니다.
그런데 서버의 초대 엔드포인트 세 개가 빈 응답을 돌려주는 자리막음입니다
({"items":[]}, 빈 토큰, 204). 목록은 화면 안의 가짜 데이터이고, 생성이 실패하면
inv-<타임스탬프> 같은 가짜 주소를 만들어 복사합니다. /invite/:token 라우트도
앱에 없어서 진짜 링크가 있어도 404 이고, 수락 엔드포인트도 없습니다.
Role Permissions 탭¶
권한 목록이 화면에 고정값으로 박혀 있습니다. View/Edit 칩을 눌러 Save Changes 를 누르면 브라우저 localStorage 에 저장됩니다 — 서버로 가지 않고 실제 권한을 바꾸지도 않습니다. 실제 권한은 권한 표에 적힌 대로 코드에 박혀 있습니다.
호출하는 API¶
| 동작 | 엔드포인트 | 비고 |
|---|---|---|
| 이메일로 찾기 | GET /api/v1/admin/users/search?email= |
오류가 나도 {found:false} 를 돌려줍니다 |
| 구성원 목록 | GET /api/v1/admin/organizations/{orgId}/members |
|
| 구성원 추가 | POST …/members |
감사 로그 남김 |
| 수정 | PATCH …/members/{memberId} |
한 항목 이상 필요. 감사 로그 없음 |
| 비활성화 | POST …/members/{memberId}/deactivate |
is_active=false 만. 감사 로그 없음 |
| 삭제 | DELETE …/members/{memberId} |
사용자 행을 실제로 지웁니다 |
비활성화는 접속 중인 사람을 끊지 않습니다
이미 발급된 토큰은 그대로 유효합니다. 즉시 차단해야 한다면 IdP(Keycloak) 에서 세션을 끊으세요. 화면의 Deactivate 만으로는 막히지 않습니다.
비밀번호 로그인에 대해¶
정상 경로는 Keycloak OIDC 입니다. ID/PW 로그인은 어떤 계정으로도 성공할 수 없습니다 — 비밀번호 해시를 담는 자리와 해시 함수는 있지만 제품 코드 어디에서도 그 값을 쓰지 않습니다. 시드도, 구성원 추가도 해시를 넣지 않습니다. 비상용으로 쓰려면 운영자가 데이터베이스에 bcrypt 해시를 직접 넣어야 합니다.