내 정보 폼 (MyInfoForm)
직원이 자기 정보를 보고 고치는 「내 정보」 모달입니다. 무엇을 고칠 수 있는지는 조직 설정이 정합니다 — 그게 이 컴포넌트의 유일한 축입니다.
Alpine 컴포넌트 · Web · 진행 중(WIP) · 문서 포맷 시범 적용
Interactive playground
selfEditableFields 하나입니다. 사번·팀·입사일·이메일은 설정으로도 열 수 없는 읽기 전용입니다. <!-- 넘길 옵션이 없다 — 9개 앱이 글자 하나까지 같다 -->
<div x-data="myInfoForm">
<!-- include "../../packages/components/html/my-info-form.html" -->
</div>
// 조직이 selfEditableFields 를 안 정했을 때 — canEdit() 안의 기본값이 걸린다
return ["address", "emergencyContact", "profilePicture"].includes(field);조직이 설정을 안 했을 때 — 기본 3종(주소 · 비상연락처 · 프로필 사진)만 열립니다
전부 열어 준 조직 — 연락처·계좌까지 고칠 수 있습니다
⚠️ 전부 잠근 조직 — 연필이 하나도 없고 안내 한 줄이 뜹니다. 화면이 텅 빈 게 아니라 정상 상태입니다
비밀번호 변경 1단계 — 본문이 통째로 대체됩니다(프로필·섹션이 사라짐)
이 컴포넌트는 넘길 옵션이 하나도 없습니다 — 9개 앱이 x-data="myInfoForm" 로 글자 하나까지 같이 씁니다. 그래서 코드 탭에는 호출이 아니라 조직 설정(selfEditableFields)이 어떻게 읽히는지가 나옵니다.
모달 전체는 재현하지 않았습니다
마크업이 476줄이고, 화면이 실제로 갈리는 축은 하나뿐입니다. 섹션 목록과 편집 연필이 어디에 붙는지에 집중했습니다.
규칙 (강제) · 코딩 에이전트용
MyInfoForm 강제 규칙. 상세는 아래 본문.
마크업 / 마운트
- 앱마다 한 번만 —
x-data="myInfoForm"+packages/components/html/my-info-form.htmlinclude. 옵션을 넘기지 마세요(팩토리가 인자를 받지 않습니다). - 카드는
.ds-modal— 모달 3종 중 일반 모달입니다. 패널 폼의 패널 모달이 아닙니다.
⚠️ 트랩 ① 무엇을 고칠 수 있는지는 앱이 아니라 조직이 정합니다canEdit(field) 가 currentUser.selfEditableFields 를 읽습니다. 설정이 없거나 빈 객체면 기본값 ["address", "emergencyContact", "profilePicture"] 가 걸립니다 — 이 목록은 코드 안에 박혀 있으니 「기본은 전부 허용」이라고 가정하지 마세요.
⚠️ 트랩 ② 사번·팀·입사일·이메일은 설정으로도 못 엽니다 조직이 관리하는 값이라 canEdit 대상 자체가 아닙니다. 「연필을 붙여 달라」는 요청이 오면 설정이 아니라 정책 문제입니다.
⚠️ 트랩 ③ 전부 잠긴 상태가 정상입니다 자가수정을 모두 끈 조직에서는 연필이 하나도 없고 「수정이 필요한 경우 관리자에게 문의해 주세요.」 한 줄만 남습니다. 그 안내가 유일한 설명이니 지우지 마세요.
⚠️ 트랩 ④ 비밀번호 변경은 본문을 통째로 대체합니다passwordStep 이 '' 이 아니면 프로필·섹션이 전부 사라지고 그 단계만 보입니다('' → verify → newpw → done). 모달 위에 또 띄우는 구조가 아닙니다.
⚠️ 트랩 ⑤ 서명/도장은 캔버스로 줄여 PNG data URI 로 저장합니다360×160 박스 안으로 줄이고 투명 배경을 보존합니다(도장 PNG). 서버 스키마 크기 제한(약 300KB) 때문이고, 결재 문서 서식의 {{서명}} 자리에 그대로 들어갑니다 — 원본 파일을 그대로 보내도록 바꾸지 마세요.
알림은 DS 다이얼로그를 씁니다showAlert / showError (../dialog)를 씁니다 — 패널의 자체 notice와 다릅니다. 이쪽이 맞는 방향입니다.
- 다크 모드(2026-10-19, 일부) — 공용
my-info-form.html은 팔레트 유틸 73곳 중 48곳만 옮겼고 회색 글자 · 경계 25곳(text-gray-900·border-gray-200등)이 남아 있다. 이 파셜은 테마를 켠 앱(직원 앱 · 관리자 앱)이 쓰지 않고 hr-system · drive 등 라이트 고정 앱만 써서 보류했다 — 그 앱이 테마를 켜기 전에 마저 옮긴다. 보안 설정 몸체(security-settings-body.html, 37곳)는 전부 옮겼고, 라인 버튼은ds-btn--outline글자색 함정(로그인 폼과 같음)을text-label-normal로 막아 두었다. 확인: Playground 「미리보기 테마 → 다크」.
무엇이 들어 있나
Google 계정 화면처럼 섹션마다 따로 편집하는 모달입니다.
| 묶음 | 항목 | 고칠 수 있나 |
|---|---|---|
| 조직이 관리 | 사번 · 소속 팀 · 입사일 · 이메일 · 생년월일 | 설정으로도 불가 |
| 자가수정 대상 | 연락처 · 주소 · 비상연락처 · 계좌정보 · 프로필 사진 | 조직 설정이 정함 |
| 별도 흐름 | 비밀번호 변경 · 서명/도장 · 휴대폰 인증 로그인 · 알림 설정 | 각자 규칙 |
편집 가능 여부는 조직이 정합니다
canEdit(field) 한 함수가 화면 전체를 좌우합니다.
const selfEditable = currentUser?.selfEditableFields;
// 설정이 없거나 빈 객체면 — 코드에 박힌 기본값
if (!selfEditable || Object.keys(selfEditable).length === 0) {
return ["address", "emergencyContact", "profilePicture"].includes(field);
}
return !!selfEditable[field];기본값이 「전부 허용」이 아닙니다
설정을 안 한 조직에서는 주소 · 비상연락처 · 프로필 사진 셋만 열립니다. 연락처와 계좌정보는 명시적으로 켜야 보입니다.
전부 잠기면 안내 한 줄만 남습니다
그때는 연필이 하나도 없고 화면이 읽기 전용 카드가 됩니다. 「수정이 필요한 경우 관리자에게 문의해 주세요.」 가 유일한 설명이므로 지우면 안 됩니다 — 사용자는 왜 못 고치는지 알 방법이 없어집니다.
비밀번호 변경
모달 위에 또 띄우는 게 아니라 본문을 통째로 대체합니다.
각 단계에 뒤로 가기가 있고, 뒤로 갈 때 그 단계의 입력과 오류를 지웁니다.
서명/도장
결재 문서 서식의 {{서명}} 자리에 들어가는 이미지입니다. 올린 파일을 그대로 저장하지 않고 캔버스로 줄여 PNG data URI 로 만듭니다.
| 항목 | 값 | 왜 |
|---|---|---|
| 최대 크기 | 360 × 160 박스 | 서버 스키마 제한(약 300KB) |
| 형식 | PNG data URI | 투명 배경 보존(도장) |
| 비율 | 유지 (Math.min(1, …)) | 작은 이미지는 확대하지 않음 |
주소 검색
패널 폼과 같은 Daum 우편번호 흐름입니다.
코드는 공유가 아니라 복사본입니다
MyInfoForm 은 패널 둘과 같은 로더를 자기 안에 또 갖고 있습니다 — 로더 세 벌 중 하나입니다. packages/components/src/utils/ 에 공용 자리가 있는데 주소 검색만 안 빠져 있습니다.
알림 처리
showAlert / showError — DS 다이얼로그를 씁니다. 패널이 쓰는 자체 notice 팝업과 다르고, 이쪽이 맞는 방향입니다. 새로 만드는 화면은 이 쪽을 따라가세요.
섹션과 상태
| 상태 | 화면 |
|---|---|
| 기본 (설정 없음) | 주소 · 비상연락처 · 프로필 사진에만 연필 |
| 조직이 전부 허용 | 연락처 · 계좌정보까지 연필 |
| 조직이 전부 잠금 | 연필 0개 + 안내 한 줄 |
| 비밀번호 변경 중 | 본문이 통째로 그 단계로 대체 |
읽기 전용 항목
사번 · 소속 팀 · 입사일 · 이메일 · 생년월일은 canEdit 대상이 아닙니다. 설정을 켜도 연필이 안 생깁니다 — 조직이 관리하는 값이기 때문입니다.
그래서 「이메일을 직원이 바꾸게 해 달라」는 요청은 설정 문제가 아니라 정책 문제입니다. 코드에서 목록을 늘리기 전에 그 결정을 받으세요.
주소 표기
저장된 주소를 한 줄로 합칠 때 레거시 데이터를 고려합니다.
street · detail · city · postalCode (빈 값은 건너뜀)street(도로명/지번) + detail(상세)을 앞에 두고, 옛 데이터의 city · postalCode 를 뒤에 이어 붙입니다. 둘 다 있으면 detail 이 먼저입니다.
전화번호 표기
입력할 때마다 010-1234-5678 꼴로 하이픈을 넣고 11자리에서 자릅니다 — 가입 폼과 같은 규칙이지만 코드는 각자입니다.
마운트
앱마다 한 번만 둡니다.
<div x-data="myInfoForm">
<!-- include "../../packages/components/html/my-info-form.html" -->
</div>여는 법
openMyInfo() 를 부르거나 showMyInfo 를 켭니다. 보통 앱 헤더나 페이지 헤더 아바타의 「내 정보」 메뉴가 부릅니다.
openMyInfo() 는 열 때 비밀번호 단계 · 편집 중 섹션 · 사진 오류를 전부 초기화합니다 — 지난번에 열어 둔 상태가 남지 않습니다.
함께 필요한 것
hereby스토어 — 문구(t()),sdk,currentUser.selfEditableFields(편집 가능 여부의 출처).- DS 다이얼로그 —
showAlert/showError를 렌더할ds-dialog.html이 앱에 있어야 합니다. - 네트워크 — 주소 검색이 외부 CDN 스크립트를 lazy 로드합니다.
API
myInfoForm Alpine.data factory. 인자를 받지 않습니다.
주요 상태
| 멤버 | 설명 |
|---|---|
showMyInfo | 모달 열림 |
editingSection | 지금 편집 중인 섹션 ("" · phone · address · shift) |
myInfo | 편집 대상 값 — 연락처 · 주소 · 비상연락처 · 계좌 |
passwordStep | "" · verify · newpw · done — 본문을 통째로 대체 |
profilePictureUrl · photoError | 프로필 사진 · 업로드 오류 |
signatureUrl · signatureError | 서명/도장 · 오류 |
주요 메서드
| 멤버 | 설명 |
|---|---|
openMyInfo() | 열면서 단계·편집 섹션·오류를 전부 초기화 |
canEdit(field) | 조직 설정 → 편집 가능 여부. 설정이 비면 기본 3종 |
formatPhone(v) | 010-1234-5678 꼴, 11자리에서 자름 |
formatAddress(addr) | street · detail · city · postalCode 순으로 합침(빈 값 건너뜀) |
verifyCurrentPassword() · submitNewPassword() | 비밀번호 2단계 |
편집 가능 필드 키
phone · address · emergencyContact · bankAccount · profilePicture
설정이 비었을 때의 기본값은 address · emergencyContact · profilePicture 셋입니다.
사용처
9개 앱이 모두 옵션 없이 씁니다.
admin · drive · employee-app · general-affairs · hr-system · inventory · management-dashboard · module-manager · team-manager
단일 출처
| 파트 | 파일 |
|---|---|
| Alpine 컴포넌트 | packages/components/src/components/MyInfoForm.ts |
| HTML partial | packages/components/html/my-info-form.html |
| 편집 가능 설정 | currentUser.selfEditableFields (조직 설정) |
| 알림 | packages/components/src/dialog.ts (showAlert · showError) |
검토 필요 사항
- 주소 검색 로더가 여기에도 복사돼 있습니다 — 패널 둘과 합쳐 세 벌입니다.
utils/에 공용 자리가 있는데 이것만 안 빠져 있습니다. - 전화번호 포맷도 각자입니다. 가입 폼과 규칙이 같은데 코드는 따로 있습니다. 한쪽만 고치면 어긋납니다.
- 읽기 전용 항목 목록이 코드에 박혀 있습니다. 사번·팀·입사일·이메일을 조직이 열 수 있게 할지는 정책 결정인데, 지금은 설정에 그 축이 아예 없습니다.
editingSection이 세 값만 씁니다(phone·address·shift). 비상연락처·계좌정보는 다른 방식으로 편집되는데, 한 컴포넌트 안에 편집 패턴이 둘인 이유가 문서화돼 있지 않습니다.
변경 이력
| 날짜 | 내용 |
|---|---|
| 2026-09-08 | MyInfoForm 페이지 신규 작성 — 조직 설정(selfEditableFields) 축 Playground + 모아보기 4상태. 비밀번호 3단계 다이어그램, 서명/도장 규격, 읽기 전용 항목 구분 포함. 모달 마크업(476줄)은 재현하지 않았습니다 |