역할
SMC(System Manager Web Client)는 LH 스마트홈 플랫폼의 시스템 운영자용 관리자 웹임. 전체 그림은 공개노트/개발/시스템 구성.
- 화면 제목:
LH 스마트홈 통합운영시스템(frontend/public/index.html:20), 로그인 화면 헤더LH스마트홈 통합 운영시스템 - 다루는 대상: 관리자 계정·역할/메뉴 권한·홈넷사(업체)·연동 시스템 상태·차단 IP·공지/게시판/약관·앱 사용자·접속이력·배치 모니터링·클라우드 운영보고서·개인정보 취급내역
- 프론트(Vue 2 SPA)는
/api/v1/**REST API만 호출함. 백엔드(Spring Boot, WAR 이름sysmngr.war)가 PostgreSQLsmahdb의cmn스키마를 직접 읽고 씀 - 외부로 나가는 호출은 SMS 인증 발송 1건뿐임(내부 API WAS 경유)
- 같은 저장소(
lh-home-2022-web)의 형제 모듈:LMC(지역/단지 관리자용으로 추정),smc-enc→ 공개노트/개발/모듈/비밀번호와 전화번호 암호화
SMC는 시스템 관리자(
SYS_MNGR) 계정만 로그인됨. 로그인 조회 조건에 역할이 고정돼 있음(backend/.../api/cert/service/CertService.java:19). 다만 화면 메뉴 자체는 DB의 역할-메뉴 매핑으로 결정됨.
API 전체 목록·응답 코드·테이블 목록은 공개노트/개발/모듈/SMC API와 응답 코드에 있음.
기술 스택
| 항목 | 값 |
|---|---|
| 프론트 | Vue 2.6.14 + Vue Router 3.4.9(history 모드) + Vuex 3.6 + BootstrapVue 2.21 + @vue/composition-api. Vuexy 계열 어드민 테마(src/@core) |
| 프론트 패키지 | smah-project 버전 6.4.0 |
| 주요 라이브러리 | vue-good-table(목록 그리드), vue-quill-editor(공지 본문), vue-sweetalert2(확인·알림 팝업), vue-js-modal(SMS 인증 팝업), axios, vue-cookies, vuex-persistedstate, xlsx, vee-validate |
| 프론트 빌드 | serve(local) / dev / build(production) / build-dev. 개발 서버 포트 9091, ^/api/v1을 VUE_APP_API_URL로 프록시 |
| 별칭 | @core, @api(src/api), ~(src/views), @axios, @validations |
| 백엔드 | Spring Boot 2.7.0, Java 8, Gradle, WAR 패키징(bootWar → sysmngr.war). ServletInitializer.java 있어 외부 톰캣 배포 가능 |
| 백엔드 프로젝트명 | SMAH-Framework-SYS_MNGR, group kr.or.lh.smah.sysmngr, 진입점 kr.or.lh.smah.SmahApplication |
| 데이터 접근 | JPA와 MyBatis 이중. 단건 등록/수정/삭제는 JPA(QueryDSL 5.0 설정은 있으나 실사용 흔적 적음), 목록 조회·조인·페이징은 MyBatis XML |
| 주요 의존성 | spring-boot-starter(web, security, data-jpa, validation, mail, aop, webflux), mybatis-spring-boot-starter:2.2.2, jjwt:0.9.1, jasypt-spring-boot-starter:3.0.4, log4jdbc-log4j2, modelmapper, org.json, tika-core·tika-parsers-standard-package:2.9.0, 전자정부표준프레임워크 org.egovframe.rte.fdl.cmmn:4.1.0, PostgreSQL 드라이버 |
| 포트 | 8086(local·dev·prod 공통) |
| 프로필 | -Pprofile=local|dev|prod → src/main/resources-${profile} 사용. 공통 리소스에는 MyBatis 매퍼 XML과 banner.txt만 있음 |
백엔드 패키지 구조
| 패키지 | 역할 |
|---|---|
api/** | 프레임워크 원형 API(cert/code/menu/rolenauth/user/token/apicomn). 일부는 SMC 화면에서 안 쓰는 잔재 |
mngrcomn/** | 관리자 공통 업무(관리자, 앱사용자, 게시판/공지/약관, 코드, 로그, 배치, 운영보고서, 첨부파일, 토큰) |
sysmngr/** | 시스템 관리 전용(홈넷사, 연동시스템, 차단IP, 시스템메뉴, 역할/메뉴권한) |
config/** | security, jwt, database, web, 프로퍼티 암복호화 |
aop/** | 컨트롤러 전역 로깅, 트랜잭션 일괄 적용 |
utils/** | ARIA, SHA, 날짜, 문자열, 업로드 경로, 필수필드 체크 |
환경별 주소·설정
| 프로필 | 프론트 VUE_APP_API_URL | DB |
|---|---|---|
| production | https://homez-op.lh.or.kr/api/v1 | 내부망 smahdb(포트 10882) |
| development | https://homezdev-op.lh.or.kr/api/v1 | 내부망 smahdb(포트 10883) |
| local | 로컬 8086 포트 | 개발DB(공인IP [IP], 포트 10883) |
- DB 계정·비밀번호는 jasypt
ENC[...]암호문[REDACTED] - 커넥션풀 max 30 / min idle 5 / connection-timeout 30초 / idle 60초. 멀티파트 파일 512MB·요청 512MB.
spring.jpa.show-sql은 prod만 false server.config.pgmDsCd=SYS— 메뉴 필터의 핵심 값임. 메뉴 테이블의pgm_ds_cd가SYS인 것만 SMC 화면에 뜸server.config.upload.root— prod·dev/smahshare, localc:/smahshare- 업로드 하위 폴더:
cloudOpr=op_rpt,notice=ann,ann=ann,faq=faq,qna=qna,arc=fil,resident=resident,unknown=UNKNOWN - 인증 없이 허용되는 URL(
spring.security.matchers.permitall):/,/login,/api/v1/cert/*,/api/v1/mngr/comn/codes/**,/api/v1/token/refresh,/api/v1/token/delete - 암호화 키는 모두
[REDACTED]. 키 이름만 적으면sqiframework.aria.encrypt.key(bit=128),jasypt.encryptor.password(알고리즘PBEWithMD5AndDES, prefixENC[, suffix]),spring.security.jwt.access.secret.key,spring.security.jwt.refresh.secret.key - 토큰 유효기간: access 10분(600000ms), refresh 30분(1800000ms). 프론트 쿠키 만료도 같은 값임. 커밋
ca8847c2에서 변경 이력 있음 frontend/public/robots.txt는Disallow: /로 검색엔진 크롤링 전면 차단(커밋477e2139)
화면 목록 39개
라우터는 frontend/src/router/index.js에서 7개 파일을 합침. meta.requiresAuth: true인 화면은 accessToken 쿠키가 없으면 로그인 후 이용해주세요. 알림 후 /login으로 보내짐.
| # | 경로 | name | requiresAuth | 화면이 하는 일 |
|---|---|---|---|---|
| 1 | /login | login | false | 아이디/비밀번호 로그인 + SMS 2차 인증 |
| 2 | /login/resetPwd | resetPwd | false | 비밀번호 재설정(SMS 인증 후) |
| 3 | /pages-profile | pages-profile | - | 사실상 미사용(로그인 화면이 뜸) |
| 4 | / | - | - | 루트 진입 시 /login으로 리다이렉트 |
| 5 | * | - | - | 정의되지 않은 주소 → error-404 |
| 6 | /error-404 | error-404 | - | 페이지를 찾을 수 없습니다 안내 + 홈페이지 바로가기 |
| 7 | /dashboard | dashboard | true | 내용 없음(index 글자만 출력). 로그인 후 첫 화면 |
| 8 | /adm/mnu/mnuList | mnu-list | true | 메뉴 관리 목록(메뉴ID/상위메뉴ID/메뉴명/레벨/사용여부/화면경로) |
| 9 | /adm/mnu/mnuDtl | mnu-dtl | true | 메뉴 상세·사용여부 수정 |
| 10 | /adm/adm/admList | adm-list | true | 관리자 관리 목록 + 선택삭제/선택잠금/선택승인/등록 |
| 11 | /adm/adm/admDtl | adm-dtl | true | 관리자 정보 상세(아이디/이름/역할/지역/단지/업체/전화/이메일) |
| 12 | /adm/adm/admRgsUpd | adm-rgs-upd | true | 관리자 등록·수정. 역할에 따라 지역→단지→업체 선택박스가 단계적으로 열림 |
| 13 | /adm/admRol/admRolList | adm-rol-list | true | 관리자 역할 관리 목록 |
| 14 | /adm/admRol/admRolRgsUpd | adm-rol-upd | true | 메뉴 권한 관리(역할별 메뉴 트리 + C/R/U/D 체크) |
| 15 | /adm/admRol/admRolDtl | adm-rol-dtl | true | 역할 상세(등록·수정 화면 재사용) |
| 16 | /usrAdm/usrAdm/usrList | usr-list | 없음 | 사용자 관리 목록(지역→단지 선택 후 조회) |
| 17 | /usrAdm/usrAdm/usrDtl | usr-dtl | 없음 | 사용자 상세 |
| 18 | /usrAdm/usrAdm/usrUpd | usr-upd | 없음 | 사용자 수정(이름/전화/이메일/수신여부/상태코드/역할/세대아이디) |
| 19 | /set/myInfoSet/myInfoSet | my-info-set | 없음 | 내 설정(내 정보 확인·수정, 비밀번호 변경) |
| 20 | /sysSet/hNetCo/hNetCoList | h-net-co-list | 없음 | 홈넷사 목록 |
| 21 | /sysSet/hNetCo/hNetCoDtl | h-net-co-dtl | 없음 | 홈넷사 상세(사업자번호/영문명/대표자/담당자/주소/전화) |
| 22 | /sysSet/hNetCo/hNetCoRgsUpd | h-net-co-rgs | 없음 | 홈넷사 등록·수정 |
| 23 | /sysSet/lnkgSys/lnkgSysList | lnkg-sys-list | 없음 | 연동 시스템 상태 목록(업체명 검색) |
| 24 | /sysSet/lnkgSys/lnkgSysDtl | lnkg-sys-dtl | 없음 | 연동 시스템 상세 + 상태 뱃지(정상/오류) |
| 25 | /sysSet/boardNotice/boardNoticeList | board-notice-list | 없음 | 공지사항 목록(종류 APP/LHW/SYS 필터) |
| 26 | /sysSet/boardNotice/boardNoticeDtl | board-notice-dtl | 없음 | 공지사항 상세 |
| 27 | /sysSet/boardNotice/boardNoticeRgsUpd | board-notice-rgs | 없음 | 공지사항 등록·수정(팝업 사용여부·기간, 첨부파일) |
| 28 | /sysSet/board/:natTpCd | board-list | 없음 | 공통 게시판. :natTpCd 값에 따라 제목이 공지사항/FAQ/자료실로 바뀜 |
| 29 | /sysSet/rsd-annc | rsd-annc | 없음 | 입주자 공지사항(목록+상세 래퍼) |
| 30 | /sysSet/serviceClu/serviceCluList | service-clu-list | 없음 | 서비스약관 관리 목록(필수여부/삭제여부/등록일자) |
| 31 | /sysSet/serviceClu/serviceCluRgsUpd | service-clu-rgs | 없음 | 서비스 이용약관 등록·수정 |
| 32 | /sysSet/block-ip | block-ip | 없음 | 차단IP 목록·상세 래퍼 |
| 33 | /report/usConn/usConnList | us-conn-list | true | 접속·메뉴 사용이력(관리자 선택) |
| 34 | /report/usConn/usConnHst | us-conn-hst | true | 선택 관리자의 접속·메뉴 사용 이력 목록 |
| 35 | /report/batchHst/batchHstList | batch-hst-list | true | 배치 프로세스 모니터링 목록(프로시저명/주기코드/주기시간/사용여부) |
| 36 | /report/batchHst/batchHstDtl | batch-hst-dtl | true | 배치 프로세스 세부 실행 내역 |
| 37 | /report/cldOprt/cldOprtList | cld-oprt-list | true | 클라우드 운영보고서 목록(기준년월/제목, 파일 다운로드) |
| 38 | /report/cldOprt/cldOprtRgsUpd | cld-oprt-rgsUpd | true | 클라우드 운영보고서 등록·수정(파일 업로드) |
| 39 | /report/inifTrt | report-inifTrt | 없음 | 개인정보 취급 내역(열람자/소유자/접속IP 검색) |
라우터에 없고 부모 화면 안에서만 쓰이는 컴포넌트: sysSet/board/rsdAnncList.vue, rsdAnncDtl.vue, sysSet/security/blockList.vue, blockDtl.vue, set/myInfoSet/pwdResetModal.vue, login/components/LoginMobCtfModal.vue.
메뉴 트리는 DB가 결정함
상단 메뉴바(frontend/src/layouts/components/NavMenu.vue)는 하드코딩이 아니라 로그인 후 API로 받아온 목록으로 그려짐.
- 로그인 → 레이아웃 로드 →
GET /api/v1/mngr/comn/navmenu호출 - 백엔드가 로그인 사용자의 역할(
rol_id)과 서버 설정값pgmDsCd=SYS로 메뉴 조회(mapper-rdb/mngrcomn/MngrComn_Comn_Mapper.xml:29)- 조건:
menu.mnu_lvl > 0ANDmenu.us_yn='Y'ANDrol.us_yn='Y'ANDrol_mnu_r.rol_id = 내 역할ANDmenu.pgm_ds_cd = 'SYS' - 결과에
mnu_fnc_cds(C/R/U/D를 콤마로 이어붙인 문자열)가 함께 옴
- 조건:
- 프론트는
mnuLvl === 1을 1차 메뉴(드롭다운),mnuLvl === 2 && uppMnuId === 부모를 2차 메뉴로 그림. 맨 앞에 고정으로대시보드가 붙고,tskId === 'dashboard'인 1차 메뉴는 제외함 - 2차 메뉴 클릭 시
POST /api/v1/mngr/scl로 메뉴 접속 로그가 남음(mnuId,mnuFncCd:"R")
- 즉 메뉴 이름·순서·노출 여부는 모두
cmn.tb_mnu_m/cmn.tb_rol_mnu_r데이터임. “화면이 안 보인다”는 문의가 오면 코드가 아니라 이 두 테이블(그리고us_yn,pgm_ds_cd)을 볼 것 frontend/src/navigation/vertical/index.js에 하드코딩 메뉴(Home,관리자 관리)가 남아 있으나 현재 레이아웃은 이를 쓰지 않음
역할별 차이
코드에서 확인되는 역할 ID는 5개임.
| 역할 ID | 화면 표기 | 등록 시 추가로 골라야 하는 값 |
|---|---|---|
SYS_MNGR | 시스템 관리자 | 없음 |
WAR_MNGR | LH광역관리자 | 광역(widSn) — 선택 API가 없어 주석 처리, 동작 안 함 |
ARA_HDQ_MNGR | LH지역본부관리자 | 지역(grpSn) |
SBD_MNGR | LH단지관리자 | 지역 → 단지(sbdId) |
HNETCO_ISTLR | 홈넷사설치자 | 지역 → 단지 → 업체(frmSn) |
- 분기는
frontend/src/views/adm/adm/admRgsUpd.vue:262이후onChangeState()에 있음. 지역 값이11(전국)이면 단지 목록을 불러오지 않음 - 로그인 가능 역할:
CertService.loadUserByUsernameAndUserState()가findByMngrIdAndRolId(usrId, "SYS_MNGR")로 조회함. 따라서SYS_MNGR역할 계정만 로그인됨. 다른 역할이면사용자 정보가 존재 하지 않습니다.(SQI0010)가 뜸.CertController.java:132에 역할 체크 코드가 따로 있었으나 주석 처리됨 - API 단위 권한도 역할로 걸림. 기동 시
SecurityConfig.setMatcherWithAuthorityUserbyRole()이 DB의 역할-메뉴-기능 목록을 읽어/api/v1/{tskId}/**패턴에 HTTP 메서드별로hasAnyAuthority(역할들)를 검. 매핑은 C→POST, R→GET, U→PUT, D→DELETE - 마지막에
anyRequest().denyAll()이 걸려 있어 명시적으로 허용되지 않은 모든 요청은 차단됨
기능
로그인 (아이디·비밀번호 + SMS 2차 인증)
- 무엇 — 관리자가 아이디·비밀번호를 넣고, 운영 환경에서는 휴대폰 SMS 인증번호까지 입력해야 들어옴
- 흐름
- 화면 유효성 검사 통과 →
process.env.NODE_ENV === 'production'이면 SMS 인증 팝업(login-mob-ctf-modal), 아니면 바로 로그인(login.vue:170). 개발·로컬 빌드에서는 2차 인증을 건너뜀 POST /api/v1/cert/certSms→ 6자리 난수 생성 → 관리자 레코드의sms_cfm_chr에 저장 → 내부 SMS API로 발송. 화면 문구인증번호를 발송하였습니다.POST /api/v1/cert/checkSms로 검증 → 일치하면sms_cfm_chr를 비우고, 상태가PRE면JIN으로 승격POST /api/v1/cert/login→ 차단IP 확인 → 사용자 조회 → 상태 확인 → 비밀번호(SHA-512, salt=아이디) 비교 → JWT access/refresh 발급- 프론트가 access/refresh 토큰을 쿠키(
accessToken,refreshToken)에 저장하고/dashboard로 이동
- 화면 유효성 검사 통과 →
- 규칙
- 접속 IP가
cmn.tb_conn_shto_ipad_m에 있으면 즉시SQI3001(해당 요청에 대한 권한이 없습니다) - 계정 상태별 차단:
RDY→SQI1003(승인대기),LCK→SQI1004(5회 오류 잠김),DEN→SQI1005(승인거부),STP→SQI1006(중지) - 비밀번호 연속 실패 카운트가 4가 되는 순간 상태가
LCK으로 바뀜 — 즉 5번째 실패에서 잠김 - 이미 로그인 중이면 응답에
isLogin: 'Y'가 실려 오고 화면에회원님의 아이디는 이미 로그인 중입니다.확인창이 뜸.기존 로그인 해제하기를 누르면POST /api/v1/token/update로 리프레시 토큰을 새 접속자 것으로 교체함(= 기존 세션 강제 종료) - 비밀번호 만료일(
mngr_pwd_epi_ymd)이 지났으면 응답에isPwdExp: 'Y'. 신규 등록·변경 시 만료일은 6개월 뒤로 설정됨
- 접속 IP가
- 테이블 —
cmn.tb_mngr_m(상태/실패횟수/인증번호),cmn.tb_mngr_refsh_tkn_m(리프레시 토큰),cmn.tb_mngr_lgn_l(로그인 이력) - 운영 시 알아둘 점
- “로그인이 안 된다”는 문의는 ① 계정 상태(
mngr_ss_cd) ② 실패횟수(mngr_pwd_fail_cnt) ③ 비밀번호 만료일 ④ 차단IP 등록 여부 순으로 볼 것 inputSysLogLogin(로그인 이력 적재)이CertController에서 주석 처리돼 호출되지 않음.tb_mngr_lgn_l에 로그인 기록이 안 쌓일 수 있음. 접속내역 화면이 비어 보이면 이 점을 의심할 것- 로그 검색 키워드:
[SMAH-Framework] login start,SQIFrameworkException - 관련 커밋:
48825902(로그인 시 응답 오류 메세지 수정)
- “로그인이 안 된다”는 문의는 ① 계정 상태(
SMS 인증번호 발송·검증
- 무엇 — 로그인 2차 인증과 비밀번호 재설정 본인확인에 쓰는 6자리 숫자를 문자로 보냄
- 흐름(
CertService.java:126)RandomStringUtils.randomNumeric(6)으로 인증번호 생성- 입력한 휴대폰번호에서
-를 빼고 ARIA로 암호화한 값과 DB의mngr_mbl_tlno를 비교. 상태가PRE·JIN(최초 가입 진행 중)이면 비교를 건너뛰고 입력값으로 갱신함 - 공통 상수 테이블(
cmn.tb_cstt_m)에서SMAH_INTERNAL_API_KEY와SMAH_INTERNAL_API_WAS_ADR를 읽어, 헤더ApiKey를 달고POST {내부WAS}/api/smh/sms호출(WebClient, 비동기) - 전송 본문: 제목
LH스마트홈OTP인증, 내용{6자리}를 입력하세요.,addtInf.evnCd = "CERT",traceId = "SMW:yyyyMMddHHmmssms"
- 진입점 —
POST /api/v1/cert/certSms,POST /api/v1/cert/checkSms - 규칙 — 전화번호 불일치
SQI1014, 계정 없음SQI1013, 그 외 발송 실패는 모두SQI1009(SMS 발송 중 오류 발생)로 뭉뚱그려짐 - 화면 문구 —
인증번호를 발송하였습니다.,인증번호를 확인해주세요.,인증번호를 재전송 하시겠습니까?,인증번호가 오지 않았습니까,휴대폰 인증 - 운영 시 알아둘 점
- 발송 대상 번호도 ARIA 암호문 상태로 내부 SMS API에 넘어감. 수신 쪽에서 복호화하는 구조임. 발송 자체는 APW가 맡음 → 공개노트/개발/모듈/SMS 발송
traceId접두어가SMW:임(SMC인데 SMW). 로그 추적 시 혼동 주의- 인증번호에 서버 유효시간이 없음. 화면 타이머만 있고 서버는
sms_cfm_chr가 일치하기만 하면 통과시킴 - 커밋 이력:
35aad65f(SMS 인증 응답 문구 수정 및 APW 호출 url 취득 방법 변경),236af89c(sms 인증 오류 수정). 로그 키워드SMS 발송 중 오류 발생
비밀번호 재설정·변경·만료 연장
- 비밀번호 재설정(로그인 전) — 화면
/login/resetPwd. SMS 인증 후PUT /api/v1/cert/resetPassword. 신규·확인 값이 다르면SQI0011. 성공 시 실패횟수 0, 상태USE, 만료일 6개월 뒤로 재설정. 화면 문구비밀번호가 변경되었습니다. - 비밀번호 변경(로그인 후) — 내 설정 화면의 모달.
PUT /api/v1/cert/change-password. 기존 비밀번호가 틀리면SQI1000 - 6개월 표시안함 —
PUT /api/v1/cert/unsetPassword. 이름과 달리 내부적으로processResetPassword를 그대로 호출함(= 비밀번호를 재설정함). 이름과 동작이 어긋나 있어 호출 주의 - 만료일 연장 —
PUT /api/v1/mngr/password-expiration-extension(관리자),PUT /api/v1/user/extendUserPasswordExpireDate(사용자, 프론트 미사용) - 테이블 —
cmn.tb_mngr_m - 비밀번호 해시 방식은 공개노트/개발/모듈/비밀번호와 전화번호 암호화 참고
토큰 갱신·로그아웃
POST /api/v1/token/refresh— 리프레시 토큰으로 새 access 토큰 발급POST /api/v1/token/update— “기존 로그인 해제하기”에 쓰임. 리프레시 토큰을 새 값으로 교체DELETE /api/v1/token/delete— 로그아웃 시 토큰 삭제- 프론트 인터셉터(
frontend/src/auth/jwt/jwtService.js)- 모든 요청 헤더에
Authorization으로 accessToken을 그대로 넣음(Bearer접두어 없음) - 응답 HTTP 401이면 자동으로 refresh 시도 후 원 요청 재시도. 실패하면 로그인 화면으로
resCd가SQI2011(Refresh token 만료)이면일정시간 미사용으로 접속이 종료되었습니다.</br>다시 로그인해 주십시오.알림 후localStorage.vuex삭제 → 로그인 화면- 그 외 실패 응답은 서버가 준
resMsg를 그대로 팝업에 띄움
- 모든 요청 헤더에
- 관련 커밋:
32239d35(엑세스/리프레시 토큰 만료 시 로그인페이지 이동 버그 수정),73f961f0(리프레시 토큰 만료 시 팝업 후 이동 추가)
관리자 관리
-
무엇 — 관리자 계정을 조회·등록·수정·삭제하고, 가입 신청을 승인하거나 계정을 잠금함
-
화면 —
/adm/adm/admList(목록),/adm/adm/admDtl(상세),/adm/adm/admRgsUpd(등록·수정) -
검색 조건 — 아이디(
mngrId), 이름(mngrNm), 역할(rolId), 단지(sbdId), 지역그룹(grpSn), 업체(frmSn) + 페이징 -
API
동작 메서드/경로 목록 GET /api/v1/mngr/managers상세 POST /api/v1/mngr/managers/{mngrId}등록 POST /api/v1/mngr/managers수정 PUT /api/v1/mngr/managers삭제 DELETE /api/v1/mngr/managers(bodymngrIds)잠금 PUT /api/v1/mngr/managers-lock승인 PUT /api/v1/mngr/managers-approve -
규칙
- 신규 등록 시 상태는 무조건
RDY(승인대기)(ManagerService.java:125). 등록만으로는 로그인되지 않고 승인을 눌러야USE가 됨 - 승인 =
mngr_ss_cd를USE로, 잠금 =LCK으로 일괄 UPDATE - 선택 건수와 DB 조회 건수가 다르면 승인은
SQI0004, 잠금·삭제는SQI0005 - 휴대폰·전화번호는 하이픈 제거 후 ARIA 암호화해 저장하고, 조회 DTO의 getter가 복호화해 내려줌(
ManagerListItemDto.java:86) - 비밀번호는 SHA-512(salt=관리자ID)
- 필수값: 등록
mngrId;rolId, 수정mngrId, 삭제mngrIds, 승인mngrIds
- 신규 등록 시 상태는 무조건
-
화면 문구 —
삭제할 데이터를 선택해주세요./삭제하시겠습니까?/잠금 처리할 관리자를 선택해주세요./잠금 처리 하시겠습니까?/승인 처리할 관리자를 선택해주세요./승인 처리 하시겠습니까?/수정하시겠습니까?/저장하시겠습니까? -
테이블 —
cmn.tb_mngr_m(조인tb_rol_m,tb_sbd_m,tb_frm_m,TB_MNGR_LGN_L) -
운영 시 알아둘 점 — 관리자 상세 조회가 POST임. 커밋
c3ed2682에서 GET으로 바꿨다가d9ea3dd3에서 되돌림. 승인 기능은 커밋080ab1c0에서 추가됨
관리자 역할 관리 · 메뉴 권한 관리
-
무엇 — 역할(role)을 조회하고, 역할마다 어떤 메뉴에 어떤 기능(C/R/U/D)을 줄지 체크박스로 설정함
-
화면 —
/adm/admRol/admRolList(역할 목록),/adm/admRol/admRolRgsUpd(메뉴 권한 관리) -
API
동작 경로 역할 목록·상세 GET /api/v1/sysmngr/roles,GET /api/v1/sysmngr/roles/{rolId}역할 등록·수정·삭제 POST/PUT/DELETE /api/v1/sysmngr/roles역할별 메뉴 목록 GET /api/v1/sysmngr/menuroles/{rolId}역할+메뉴 상세 GET /api/v1/sysmngr/menuroles/{rolId}/{mnuId}메뉴 권한 저장 PUT /api/v1/sysmngr/menuroles -
규칙
- 1차 메뉴(레벨1)는 체크박스가
A하나뿐이고, 2차 메뉴(레벨2)는C/R/U/D4개임(admRolRgsUpd.vue:46~85). 백엔드 상수MENU_FUNCTIONS_CDS = "C, R, U, D"에는A가 없음(추정:A는 대분류 접근 표시용) - 저장은 해당 역할+메뉴의 기존 권한을 전부 지우고 다시 넣는 방식(
MenuRoleService.modifyMenuRole= clear → insert). 저장 도중 실패하면 권한이 비어 버릴 수 있음 - 필수 파라미터
rolId;mnuId;mnuFncCds. 하위 메뉴가 있는 메뉴에 기능을 걸면SQI7200
- 1차 메뉴(레벨1)는 체크박스가
-
화면 문구 —
수정이 완료되었습니다.,저장하시겠습니까? -
테이블 —
cmn.tb_rol_m,cmn.tb_rol_mnu_r -
운영 시 알아둘 점 — 권한 변경이 즉시 반영되지 않음.
SecurityConfig는 애플리케이션 기동 시 한 번만 역할-메뉴-기능을 읽어 시큐리티 매처를 구성함. 메뉴 권한을 바꾸면 화면 메뉴(navmenu API는 실시간)는 바뀌지만 API 접근 허용 규칙은 WAS를 재시작해야 반영됨. “메뉴는 보이는데 누르면 권한 없음(SQI3001)이 뜬다”는 문의의 유력한 원인임 → 기본매뉴얼/운영/tomcat과 배치 기동
메뉴 관리
- 화면 —
/adm/mnu/mnuList,/adm/mnu/mnuDtl - API —
GET /api/v1/sysmngr/menus(목록, 페이징),GET /api/v1/sysmngr/menus/{mnuId}(상세),PUT /api/v1/sysmngr/menus(사용여부 수정) - 컬럼 — 메뉴 아이디, 상위 메뉴 ID, 메뉴명, 메뉴 레벨, 메뉴 설명, 업무 아이디(
tskId), 화면 경로(scrnPth), 사용 여부, 수정 일시 - 규칙 — SMC에서는 수정(사용여부)만 가능하고 메뉴 신규 등록·삭제 API가
sysmngr쪽에 없음. 등록·삭제는 구버전/api/v1/menu/**에 남아 있으나 프론트가 호출하지 않음. 필수값mnuId;usYn - 테이블 —
cmn.tb_mnu_m - 화면 문구 —
저장하시겠습니까?→저장되었습니다./ 실패 시저장에 실패했습니다.
사용자(앱 사용자) 관리
- 무엇 — 입주민 앱 사용자 계정을 조회하고 일부 정보를 수정함
- 화면 —
/usrAdm/usrAdm/usrList,usrDtl,usrUpd - 검색 조건 — 아이디(
usrId), 이름(usrNm), 세대아이디(hshId), 단지(sbdId). 지역(grpSn)으로 단지 목록을 좁힘 - API —
GET /api/v1/mngr/appusers,GET /api/v1/mngr/appusers/{usrId},PUT /api/v1/mngr/appusers - 수정 가능 항목 — 이름, 전화번호, 이메일 주소, 이메일 수신여부(수신/수신 안함), 사용자 상태코드(
usrSsCd), 역할 아이디, 세대 아이디 - 규칙 — 경로 변수에
{usrId:.+}정규식이 붙어 있음(아이디에 점이 있어도 잘리지 않게). 전화번호는 ARIA 암복호화 대상. 필수값 수정usrId - 테이블 —
cmn.tb_usr_m(조인tb_rol_m,tb_sbd_m) - 화면 문구 —
단지를 선택해 주세요,단지가 선택되지 않았습니다.,데이터가 존재하지 않습니다.,저장하시겠습니까?,저장되었습니다.,저장에 실패했습니다. - 운영 시 알아둘 점 — 단지를 고르지 않으면 조회 자체가 막힘. 전국 단위 조회는 이 화면에서 불가. 앱 사용자 계정 상태의 뜻은 공개노트/기능/로그인과 세대 승인 참고
홈넷사 관리
- 무엇 — 월패드를 공급하는 홈넷 업체 정보를 등록·수정·삭제함
- 화면 —
/sysSet/hNetCo/hNetCoList,hNetCoDtl,hNetCoRgsUpd - 입력 항목 — 홈넷사명, 업체 영문명, 사업자번호(
brn), 대표자명, 담당자명, 담당자 이메일, 우편번호, 주소, 전화번호. 화면에단지·스마트홈 단지항목도 있음 - API —
GET /api/v1/sysmngr/hnets(목록,searchTerm),GET /api/v1/sysmngr/hnets/{hnetFrmSn},POST/PUT/DELETE /api/v1/sysmngr/hnets,GET /api/v1/sysmngr/hnets-key(API 키 생성) - 규칙
- 홈넷사는 별도 테이블이 아니라 업체 테이블
cmn.tb_frm_m에서frm_ty_cd = 'J'인 행임(SysMngr_Homenet_Mapper.xml:31). 등록 시 자동으로J가 박힘 - 수정은 값이 비어 있지 않은 필드만 덮어씀(빈 문자열로 지우기 불가)
- 삭제는 선택 건수와 조회 건수가 다르면
SQI0005 GET /hnets-key는 UUID(하이픈 제거)를 새로 만들어 돌려줄 뿐 저장하지 않음(HomenetController.java:188). 화면에서 받은 값을 사람이 다른 곳에 옮겨 넣는 구조임.KeyUtil.apiKeyGen()은return null인 빈 껍데기임- 필수값: 등록
frmNm, 수정hnetFrmSn, 삭제hnetFrmSns
- 홈넷사는 별도 테이블이 아니라 업체 테이블
- 테이블 —
cmn.tb_frm_m - 화면 문구 —
저장하시겠습니까?/수정하시겠습니까?
연동 시스템 상태
- 무엇 — 홈넷사·외부 시스템과의 연동 설정과 가장 최근 연동 호출의 성공·실패 상태를 봄
- 화면 —
/sysSet/lnkgSys/lnkgSysList(목록: 업체명, 연동URL, 연동 시스템 상태),/sysSet/lnkgSys/lnkgSysDtl(상세) - API —
GET /api/v1/sysmngr/linkSystem(검색frmNm,lnkgUrl),GET /api/v1/sysmngr/linkSystem/{hnetFrmSn} - 상세에서 내려오는 값(
SysMngr_LinkSystem_Mapper.xml:104) —frm.lnkg_url(홈넷사 연동 서버 URL),frm.lnkg_key(연동 인증키[REDACTED]),frm.oauth_clnt_id,frm.oauth_scrtkey([REDACTED]),hnet_api_rsp_cd·hnet_api_rsp_nm(공통코드ONL_DS_CD),trc_id,mth_nm,sbd_id,rq_was_nm,rsp_dttm - 흐름 — 연동 API 요청 로그(
alog.tb_cld_lnkg_api_req_l)에서 URL의 호스트 부분만 잘라frm.lnkg_url과 매칭하고, 같은trc_id의 최신 응답 로그(alog.tb_cld_lnkg_api_rsp_l)를 붙여 마지막 응답코드를 보여줌 - 화면 표시 규칙(
lnkgSysDtl.vue:32) —hnetApiRspCd가null이면 회색(호출 이력 없음),00이면 초록(정상),01이면 빨강(오류) - 운영 시 알아둘 점
- 목록 쿼리에서 상태·연동URL 관련 구문이 전부 주석 처리돼 있음. 목록 화면의 상태 표시는 현재 동작하지 않고, 상세를 열어야 상태가 보임. 목록 검색 조건
lnkgUrl도 주석 처리라 URL로는 검색되지 않음 - 상세 API 응답에 연동키와 OAuth 시크릿이 그대로 실려 내려감. 화면에는 표시하지 않지만 브라우저 개발자도구·네트워크 탭에는 보임. 화면 공유·스크린샷 시 주의
- 상세 조회 조건에서
frm_ty_cd = 'J'필터가 주석 처리돼 있어 홈넷사가 아닌 업체도 조회됨 - 필수값: 상세
hnetFrmSn. 실제 홈넷 연동 규격은 공개노트/기능/홈넷 서버 연동 참고
- 목록 쿼리에서 상태·연동URL 관련 구문이 전부 주석 처리돼 있음. 목록 화면의 상태 표시는 현재 동작하지 않고, 상세를 열어야 상태가 보임. 목록 검색 조건
차단 IP 관리
- 무엇 — 로그인 자체를 막을 IP를 등록함
- 화면 —
/sysSet/block-ip(내부에blockList.vue,blockDtl.vue) - API —
GET /api/v1/sysmngr/security/block-ip,GET .../block-ip/{ip},POST/PUT/DELETE .../block-ip - 입력 항목 — 차단IP(
connShtoIpad, PK), 차단사유(shtoRsnCts) - 규칙
- 클라이언트 IP 판별은
IpUtil.getClientIP(). 헤더를X-Forwarded-For→HTTP_CLIENT_IP→HTTP_X_FORWARDED_FOR→HTTP_X_FORWARDED→HTTP_FORWARDED_FOR→HTTP_FORWARDED→Proxy-Client-IP→WL-Proxy-Client-IP→HTTP_VIA→IPV6_ADR순으로 훑고, 값이 있으면 콤마로 잘라 첫 번째 IP만 씀. 헤더가 없으면request.getRemoteAddr() - 이미 등록된 IP를 또 넣으면
SQI0003(중복) - 로그인 API(
/cert/login)에서만 차단 검사를 함. 다른 API는 검사하지 않음 - 필수값: 등록·수정
connShtoIpad, 삭제connShtoIpads
- 클라이언트 IP 판별은
- 테이블 —
cmn.tb_conn_shto_ipad_m - 화면 문구 —
차단IP를 입력해주세요.,차단사유를 입력해주세요.,삭제하시겠습니까?,차단IP 등록,차단IP 상세 - 운영 시 알아둘 점 — 차단은 완전일치임(부분·대역 차단 없음). 프록시·L4 뒤에 있으면 헤더 조작으로 우회 가능하니 실제 차단은 앞단 장비와 병행할 것. 커밋
a754fbcd에서X-Forwarded-For첫 IP만 취하도록 수정됨 → 공개노트/개발/웹 접속 제한
공지사항(시스템·앱) 관리
- 무엇 — 관리자 웹(LHW)·앱(APP)·시스템(SYS)용 공지를 등록하고 팝업 노출 기간을 지정함
- 화면 —
/sysSet/boardNotice/boardNoticeList,boardNoticeDtl,boardNoticeRgsUpd - API —
GET /api/v1/mngr/boards/common-notice(목록,natTl검색),GET .../common-notice/{pgmDsCd}/{natSn},POST/PUT/DELETE /api/v1/mngr/boards/common-notice - 입력 항목 — 제목, 내용(Quill 에디터), 상세유형, 공지일자, 팝업 여부(팝업사용/팝업미사용), 팝업시작일자·팝업종료일자, 첨부파일, 조회수(읽기전용), 종류
- 규칙
- 공지 종류는 공통코드로 가져옴:
uppCdDtlId = "ANN"으로 조회. 값은APP,LHW,SYS - 저장 시 프론트가
qs.stringify로x-www-form-urlencoded로 바꿔 보냄 - PUSH 발송된 공지는 수정 불가:
SQI1015— 다만 이 enum은 코드값이SQI1014로 잘못 들어가 있음 CommonNoticeController는 목록 조회 1개만 살아 있고 상세·등록·수정은 전부 주석 처리됨. 실제 등록·수정은CommonBoardController(/api/v1/mngr/boards/{natTpCd})로 감
- 공지 종류는 공통코드로 가져옴:
- 테이블 —
cmn.tb_nat_m, 첨부 관계cmn.tb_nat_ahfl_r, 첨부 원본cmn.tb_ahfl_m, 앱 공지 조인cmn.tb_rsd_annc_fcts_l - 화면 문구 —
제목을 입력해주세요.,내용을 입력해주세요.,상세유형을 선택하세요.,공지시작일을 선택해주세요.,공지종료일을 선택해주세요. - 앱에서 공지가 어떻게 보이는지는 공개노트/개발/공지사항 미리보기 참고
공통 게시판 (공지사항 / FAQ / 자료실)
- 무엇 — 게시판 유형별 글을 관리함. 하나의 화면(
boardList.vue)이 URL 파라미터에 따라 제목과 호출 경로를 바꿈 - 화면 —
/sysSet/board/:natTpCd—natTpCd가ann이면 공지사항,faq면 FAQ,arc면 자료실 - API —
GET/POST/PUT/DELETE /api/v1/mngr/boards/{natTpCd}, 상세GET /api/v1/mngr/boards/{natTpCd}/{natSn}, 첨부 다운로드GET /api/v1/mngr/boards/attach-file/{ahflSn}, 첨부 삭제DELETE /api/v1/mngr/boards/attach-file - 규칙
- 유형 enum
EnumNatTp=ANN(시스템공지),FAQ,ARC(자료실),QNA,NOTICE,CLOUDOPR,UNKNOWN - 상세유형은 공통코드
NAT_DTL_TP_CD를 상위코드(대문자 유형)로 걸어 가져옴 - 등록·수정은 multipart로
nat(JSON 파트) +uploadFiles(파일 파트)를 함께 보냄 - 필수값: 목록
natTpCd, 상세natSn, 등록natTpCd;natDtlTpCd;natTl;natCts, 삭제natSns;natTpCd
- 유형 enum
- 컬럼 — 유형, 제목, 내용, 공지일자, 팝업시작일, 팝업종료일, 첨부파일, 조회수, 등록자, 등록일시
- 테이블 —
cmn.tb_nat_m,cmn.tb_nat_ahfl_r,cmn.tb_ahfl_m - 화면 문구 —
삭제하시겠습니까?,선택하세요,전체
입주자 공지사항
- 무엇 — 특정 단지 입주민에게 나가는 공지를 등록함
- 화면 —
/sysSet/rsd-annc(내부rsdAnncList.vue/rsdAnncDtl.vue) - API —
GET/POST/PUT/DELETE /api/v1/mngr/rsd-annc, 상세GET /api/v1/mngr/rsd-annc/{anncFtcsSn}, 첨부 삭제DELETE /api/v1/mngr/rsd-annc/attach-file - 입력 항목 — 구분(
anncFctsDsCd, 공통코드ANNC_FCTS_DS_CD), 공지 대상(anncTrgMchCd, 공통코드ANNC_TRG_MCH_CD), 단지(sbdId), 제목, 내용, 일자, 시간, 첨부파일 - 필수값 — 등록
anncFctsDsCd;anncTrgMchCd;anncFctsTl;anncFctsCts;sbdId, 상세anncFctsSn, 삭제anncFctsSns - 테이블 —
cmn.tb_rsd_annc_fcts_l(단지명 조인cmn.tb_sbd_m) - 화면 문구 —
구분을 선택하세요.,대상을 선택하세요.,단지를 선택하세요.,날짜를 선택하세요.,시간을 선택하세요.,파일을 선택하세요.,제목을 입력해주세요.,내용을 입력해주세요.
서비스약관 관리
- 무엇 — 앱에 표시되는 이용약관·동의서 문서를 관리함
- 화면 —
/sysSet/serviceClu/serviceCluList,serviceCluRgsUpd - API —
GET/POST/PUT/DELETE /api/v1/mngr/boards/terms/{cluTpCd}(프론트는SVC만 사용), 상세GET .../terms/{cluTpCd}/{svcCluSn} - 약관 유형 enum —
EnumCluTp=SVC(서비스이용약관),IPA(정보제공동의서),OSS(오픈소스 소프트웨어 라이센스) - 입력 항목 — 제목(
cluTl), 내용(cluCts), 필수 여부(esnYn), 삭제 여부(delYn), 등록일자 - 필수값 — 목록
cluTpCd, 등록cluTpCd;cluTl;cluCts;esnYn, 상세svcCluSn, 삭제cluTpCd;svcCluSns - 테이블 —
cmn.tb_svc_clu_m - 화면 문구 —
제목을 입력해주세요.,내용을 입력해주세요.,필수 여부를 선택해주세요.,삭제 여부를 선택해주세요.
접속·메뉴 사용이력
- 무엇 — 관리자가 언제 어느 IP로 어떤 메뉴에 들어갔는지 봄
- 화면 —
/report/usConn/usConnList(관리자 선택: 아이디/이름/권한/단지),/report/usConn/usConnHst(해당 관리자 이력) - API —
GET /api/v1/mngr/log/sys-conn-log?mngrId=&pageSize=&pageNum= - 적재 API —
POST /api/v1/mngr/scl(bodymnuId). 서버가 로그인 아이디·클라이언트 IP·yyyyMMdd(connYmd)·HHmm(connHm)을 채워 저장함. 프론트는 2차 메뉴 클릭마다 호출함. 필수값mnuId - 테이블 —
cmn.tb_sys_conn_l(메뉴 접속),cmn.tb_mngr_lgn_l(로그인) - 운영 시 알아둘 점
mngrId가 비어 있으면 전체 조회임(필수 파라미터 없음)- 메뉴 클릭 로그는 2차 메뉴를 클릭할 때만 남음. 주소창에 직접 URL을 치거나 화면 안 버튼으로 이동하면 기록되지 않음
- 커밋
532dd455,54d26c71이 “SMW 시스템 접속내역 버그 디버깅” — 이 화면에 과거 문제가 있었음
배치 프로세스 모니터링
- 무엇 — DB 프로시저 기반 배치의 등록 정보와 실행 이력·결과를 봄
- 화면 —
/report/batchHst/batchHstList(목록),/report/batchHst/batchHstDtl(세부 내역) - API —
GET /api/v1/mngr/log/batchs(검색procNm,podCd,podHr,usYn),GET /api/v1/mngr/log/batchs/{procNm}(상세),GET /api/v1/mngr/log/batch-logs?procNm=(실행 이력) - 보이는 항목
- 목록: 프로시저명(
proc_nm), 프로시저 설명, 실행대상 서버ID, 주기코드(POD_CD), 주기시간(pod_hr), 실행스케줄(run_scd), 실행순서(run_sqn), 사용여부 - 상세: 위 항목 + cron 사용여부(
cron_schdl_yn), cron 표현식(cron_xprssn_vl), 실행대상 서버 IP, 등록·수정 일시·자 - 실행이력: 실행일련번호, 시작·종료일시, 소요시간(
tatm), 실행유형(RUN_TY_CD), 결과코드(RSL_CD), 결과 건수(rsl_row_cnt), 에러 메시지(er_msg)
- 목록: 프로시저명(
- 필수값 — 상세
procNm - 테이블 —
cmn.tb_proc_m(배치 정의),cmn.tb_proc_run_h(실행 이력) - 화면 문구 —
데이터가 존재하지 않습니다.,배치 프로세스 모니터링,프로시저명,주기코드,주기시간,사용 여부 - 운영 시 알아둘 점 — SMC는 조회 전용임. 배치를 켜고 끄거나 즉시 실행하는 API가 없음. 배치가 안 돌 때는 여기서
rsl_cd와er_msg를 확인하고 실제 조치는 DB·스케줄러 쪽에서 할 것 → 기본매뉴얼/운영/tomcat과 배치 기동
클라우드 운영보고서
- 무엇 — 월 단위 운영보고서 파일을 올리고 내려받음
- 화면 —
/report/cldOprt/cldOprtList,/report/cldOprt/cldOprtRgsUpd - API —
GET /api/v1/mngr/report/cloud-operation(검색stndYm,pclFctsSmr),GET .../cloud-operation/{stndYm},POST/PUT(multipart),DELETE(bodystndYms),GET .../cloud-operation/attach-file/{stndYm}(다운로드,responseType: blob) - 규칙
- 기준년월(
stndYm)이 키임. 같은 달에 두 건을 올릴 수 없음 - 등록 필수값
stndYm;attachFile. 파일명이 비어 있으면[클라우드 운영보고서 파일] 등록중 오류가 발생하였습니다.(SQI0006) - 저장 경로
{server.config.upload.root}/op_rpt/ - 다운로드 API에는
@NoLogging이 붙어 AOP 로깅에서 제외됨
- 기준년월(
- 테이블 —
cmn.tb_cld_opr_rpt_l, 첨부cmn.tb_ahfl_m - 화면 문구 —
저장하시겠습니까?,파일선택,현재 파일,클라우드 운영보고서 관리 - 운영 시 알아둘 점 — 커밋
9bb7672e(파일 다운로드 버그 수정),9681206c(게시판 파일 저장 경로 수정) 이력 있음. 다운로드가 안 되면 실제 파일이/smahshare아래에 있는지 먼저 볼 것
개인정보 취급 내역
- 무엇 — 누가(열람자) 누구의(소유자) 개인정보를 어떤 IP로 조회했는지 감사 기록을 봄
- 화면 —
/report/inifTrt(컬럼: 열람자, 소유자, 접속IP, 주소) - API —
GET /api/v1/report/inif-trt?pageSize=&pageNum=&searchTerm=&searchField= - 검색 필드 —
picId(열람자 ID),inifOwnrId(정보 소유자 ID),picConnIpad(접속IP). 그 외 값이면 전체 조회 - 정렬 — 등록일시(
rgsDttm) 내림차순 고정 - 테이블 —
cmn.tb_inif_trt_l(컬럼dtls_sn,pic_id,inif_trt_tp_cd,pic_conn_ipad,inif_ownr_id,inif_ownr_rol_id) - 화면 문구 —
선택하세요,데이터가 존재하지 않습니다.,개인정보 취급 내역 - 운영 시 알아둘 점 — 조회만 가능함. 기록을 적재하는 주체는 SMC가 아님(SMC 코드에 insert 없음). 다른 모듈에서 쌓는 것으로 추정됨. 월간 개인정보 접속 감사 때 쓰는 화면임 → 기본매뉴얼/운영/보안 점검
내 설정
- 화면 —
/set/myInfoSet/myInfoSet+pwdResetModal.vue - API —
GET /api/v1/mngr/myinfo,PUT /api/v1/mngr/myinfo, 비밀번호 변경PUT /api/v1/cert/change-password - 보이는 항목 — 아이디, 이름, 역할, 지역, 단지, 업체, 전화번호, 휴대폰, 이메일, 메일 수신여부, 직위, 직책, 상태, 비밀번호 만료일, 비밀번호 실패횟수
- 규칙 —
PUT /myinfo는 토큰의 로그인 아이디와 요청 body의mngrId가 다르면SQI3001로 거부함(ManagerController.java:379) - 화면 문구 —
이름을 입력하세요,기존 비밀번호를 입력하세요.,새 비밀번호를 입력하세요.,새 비밀번호 확인을 입력하세요.,새 비밀번호가 일치하지 않습니다.,기존 비밀번호와 새 비밀번호가 동일합니다,비밀번호를 변경하시겠습니까?,비밀번호가 변경되었습니다.,비밀번호 변경에 실패했습니다.,~는 필수입력 값입니다,저장하시겠습니까?,저장되었습니다. - 커밋
065017f2(내설정 필수 값 변경 & 필수 체크 추가) 이력 있음
공통코드 조회 · 단지·업체 선택목록
-
무엇 — 화면의 선택목록(드롭다운)을 채우는 공통 코드·마스터 목록을 내려줌. SMC에는 공통코드를 편집하는 화면이 없음(조회 API만 있음)
-
API 목록(모두
GET)경로 내용 /api/v1/mngr/comn/codes/{cdGrpId}그룹별 상세코드 목록. div(코드 접두어),uppCdDtlId(상위코드) 필터. 인증 없이 호출 가능/api/v1/mngr/comn/navmenu내 역할의 메뉴 트리 /api/v1/mngr/comn/grp-codes지역그룹( grpDsCd필터)/api/v1/mngr/comn/ara-codes지역본부(grp-codes에 ARA고정)/api/v1/mngr/comn/sbd-codes단지 목록( grpSn으로 필터)/api/v1/mngr/comn/smah-sbd-codes스마트홈 대상 단지 목록 /api/v1/mngr/comn/frm-codes업체 목록( frmTyCd필터)/api/v1/mngr/comn/hnet-codes홈넷사 목록(frm-codes에 frmTyCd='J'고정)/api/v1/mngr/comn/role-codes[/{rolDesc}]역할 목록 /api/v1/mngr/grpcodes,/grpcodes/{cdGrpId},/dtlcodes,/dtlcodes/{cdGrpId}/{cdDtlId}코드 그룹·상세코드 조회 -
스마트홈 대상 단지 구분 — 일반 단지는
cmn.tb_sbd_m전체, 스마트홈 대상 단지는cmn.tb_smah_sbd_d에 행이 있는 단지만임(MngrComn_Comn_Mapper.xml:114) → 공개노트/개발/스마트홈 대상단지 구분 -
코드 조회 조건 —
us_yn='Y'인 것만,srt_sqn순서로. 상세코드에는addt_inf_1~5부가 컬럼이 함께 내려감(단지의 경우 격자X/격자Y/위도/경도/전체건수) -
테이블 —
cmn.tb_cd_grp_m,cmn.tb_cd_dtl_m,cmn.tb_grp_m,cmn.tb_sbd_m,cmn.tb_grp_sbd_r,cmn.tb_smah_sbd_d,cmn.tb_frm_m,cmn.tb_rol_m -
운영 시 알아둘 점 — 드롭다운이 비어 있다는 문의는 대부분 해당 공통코드의
us_yn이N이거나 상위코드(upp_cd_dtl_id) 연결이 끊긴 경우임./mngr/comn/codes/**는 인증 없이 열려 있어 코드 값이 외부에 노출됨
첨부파일 업로드·다운로드 규칙
- 저장 루트
server.config.upload.root(운영/smahshare, 로컬c:/smahshare). 하위 폴더는 용도별 상수로 나뉨 - 저장 파일명 규칙
{하위폴더}/{prefix}-{원본파일명의 공백을 _ 로 치환}(AttachFileService.java:400) - 확장자 차단은 파일명이 아니라 Tika로 내용 판별함.
application/x-msdownload,application/x-bat,text/javascript로 감지되면SQI4000— 화면 문구실행파일(.exe, .bat, .com, .dll), 스크립트파일은 등록하실 수 없습니다.(AttachFileService.java:316) - 업로드 용량 한도: 파일당 512MB, 요청당 512MB
- 수정 시 새 파일이 오면 기존 물리 파일을 지우고 새로 씀
- 첨부 메타는
cmn.tb_ahfl_m, 게시글 연결은cmn.tb_nat_ahfl_r - 운영 시 알아둘 점 — 확장자만 바꾼 실행파일도 Tika가 잡음. 반대로 정상 문서가 오탐으로 막힐 수 있음. 차단 목록이 3종뿐이라
.vbs,.ps1,.jar등은 통과함
외부 연동
| 대상 | 방식 | 엔드포인트 | 인증 | 실패 시 |
|---|---|---|---|---|
| 내부 SMS 발송 API | Spring WebClient, 비동기(toFuture()) | {SMAH_INTERNAL_API_WAS_ADR}/api/smh/sms | 헤더 ApiKey(값 [REDACTED]) | 예외를 잡아 SQI1009 반환. 재시도·타임아웃 설정 없음 |
- 주소와 키는 하드코딩이 아니라 **DB 공통 상수 테이블
cmn.tb_cstt_m**에서 읽음(csttId=SMAH_INTERNAL_API_WAS_ADR,SMAH_INTERNAL_API_KEY). 커밋35aad65f,033aafdd가 주소 취득 방식·도메인을 바꾼 이력임 - 홈넷사(코맥스·코콤·현대통신 등)·에너지플랫폼·FCM·SMS(뿌리오)·LG ThinQ·삼성 SmartThings 등 직접 호출은 SMC에 없음. 연동 결과 로그(
alog.tb_cld_lnkg_api_req_l·_rsp_l)를 읽어 상태만 보여줌 spring-boot-starter-mail의존성이 있으나 메일 발송 코드는 없음
스케줄·배치
- SMC 자체에는
@Scheduled가 없음(스케줄러 코드 없음) - 배치는 DB 프로시저로 돌고 SMC는 그 정의(
cmn.tb_proc_m의cron_xprssn_vl,pod_cd,pod_hr,run_scd,run_sqn)와 실행 이력(cmn.tb_proc_run_h)을 조회만 함
인터셉터·필터·공통 처리
JwtAuthenticationFilter(GenericFilterBean,UsernamePasswordAuthenticationFilter앞) — 헤더Authorization에서 토큰을 그대로 읽음(Bearer접두어 없이 토큰 문자열만). 유효하면 DB에서 관리자를 다시 조회해SecurityContext에 넣음. 토큰이 없으면 request attributeSQIException에SQI2000을 담음JwtTokenProvider— JWT 클레임에sub(아이디),rolId,hshId(세대),sbdId(단지),dngDs(동),hoDs(호)를 담음. 서명 HS256, 시크릿은 Base64 인코딩 후 사용CustomAuthenticationEntryPoint— 401 응답. body는{"resCode": ..., "resMsg": ...}(주의: **resCode**로, 정상 응답의resCd와 키 이름이 다름). XSS 방지를 위해<,>를 이스케이프함(2023-12-12 취약점 조치)CustomAccessDeniedHandler— 403 응답,SQI3001CorsConfig—allowedOriginPattern("*"), 모든 헤더·메서드 허용,allowCredentials(true). 사실상 모든 출처 허용임- CSRF 비활성화, 세션
STATELESS, HTTP Basic 비활성화 SQIFrameworkAspect(AOP@Around) —*Controller의 모든 메서드를 감싸 **요청 URI, 요청 파라미터 전체, 응답 전체, 처리 시간(ms)**을 INFO로 남김.@NoLogging이 붙은 메서드만 제외(현재 파일 다운로드 계열).SFWException을 잡아&구분자로 코드·메시지를 분리해 응답으로 변환함TransationAspect—kr.or.lh.smah..*Service.*(..)전체에 트랜잭션 어드바이스 적용RestExceptionHandler—NoHandlerFoundException→SQI9001WebConfig—/**,/*/*를 classpath 루트 정적 리소스로 매핑PropertyEncryptConfig— jasypt로ENC[...]프로퍼티 복호화(PBEWithMD5AndDES, 1000 iterations, RandomSaltGenerator, base64 출력)RDBMSConfig— HikariCP + MyBatis(classpath:/mapper-rdb/**/*_Mapper.xml), 캐시 끔,mapUnderscoreToCamelCase켬,LongArrayHandler타입핸들러 등록
알려진 이슈
- AOP가 요청·응답 전문을 로그에 남김. 로그인 요청의
usrPwd(평문), SMS 인증번호, 연동 시크릿이Request parameters/Response parameters로그에 그대로 찍힐 수 있음. 로그 접근 권한과 보관 기간을 반드시 확인할 것. 커밋c673ae0d,ac09e2fb가 로그 경로 수정 이력임 → 기본매뉴얼/운영/WAS 로그 확인 - 메뉴 권한 변경이 API 접근 규칙에 즉시 반영되지 않음.
SecurityConfig가 기동 시 1회만 DB를 읽음. WAS 재시작 필요 SQI1015enum의 코드값이SQI1014로 잘못 들어가 있음(ApiResponseCode.java:86)unsetPasswordAPI는 이름과 동작이 다름. “비밀번호 6개월 표시안함”이라 적혀 있으나 실제로는 비밀번호를 재설정함(CertController.java:270)- 로그인 이력 적재가 호출되지 않음.
loggerService.inputSysLogLogin(...)이CertController에서 주석 상태임 inputSysLogLogout이 로그아웃인데 로그인과 똑같은 코드임(SysConnLogService.java:53) — 구분 컬럼이 없어 로그아웃 기록이 로그인처럼 쌓임. 현재 호출되는 곳도 없음- 연동 시스템 목록 화면의 상태 표시·URL 검색이 주석 처리돼 동작하지 않음(
SysMngr_LinkSystem_Mapper.xml:41~61) - CORS가 모든 출처를 허용함(
CorsConfig) /api/v1/mngr/comn/codes/**가 인증 없이 열려 있음. 공통코드 전체가 비인증 조회 가능함- 개발·로컬 빌드에서 SMS 2차 인증을 건너뜀(
login.vue:170).NODE_ENV가 production이 아닌 산출물이 운영에 올라가면 2차 인증이 사라짐 KeyUtil.apiKeyGen()이return null인 빈 메서드임. 실제 API 키 발급은uuidGen()으로 대체돼 있고 저장되지 않음dashboard.vue가index문자열만 출력하는 빈 화면임. 로그인 직후 사용자는 빈 화면을 봄- 우측 상단 사용자 드롭다운의 이름·역할이 하드코딩(
관리자,admin)임. 소스에// TODO: 유저 정보 API 필요주석 있음(layouts/components/UserDropdown.vue:69) - 라우터
push오버라이드가 실패 시window.location.reload()를 호출함(router/index.js:16). 잘못된 이동 시 화면이 새로고침되어 입력값이 날아갈 수 있음 - 취약점 수정 커밋 이력:
41021670(크로스사이트 요청 위조),88dd19c6·f52ba99b(취약점 수정),477e2139(robots.txt로 크롤링 차단) - 로컬 프로필 설정 파일에 개발 DB 공인 IP와 jasypt 암호문이 커밋돼 있음
- 관리자 목록 화면의
광역(WID_SN) 선택 항목은 “API에 없음으로 주석 처리”되어 실제로는 쓸 수 없음(frontend/src/api/adm.js:9) - 16~32번, 39번 화면에
meta.requiresAuth가 없음. 라우터 가드를 통과하므로 로그인하지 않고 주소를 직접 치면 화면 껍데기가 뜸. 다만 데이터 조회 API가 401을 돌려주므로 목록은 비고 오류 팝업이 뜸
확인 필요
확인 필요
- 16~32번, 39번 화면에
meta.requiresAuth가 빠져 있음. 의도인지 누락인지 확인 필요.WAR_MNGR(LH광역관리자) 역할은 화면 분기 코드가 있으나 광역 선택 API(WID_SN)가 없어 동작하지 않음. 이 역할이 현재 운영에서 쓰이는지 확인 필요./adm/adm/admDtl과/adm/admRol/admRolDtl에 어떤 경로로 진입하는지 확인 필요(메뉴에는 없음).- 배치(
tb_proc_m)를 실제로 실행하는 주체(DB 스케줄러/외부 잡 스케줄러)가 무엇인지 코드만으로는 알 수 없음.- 홈넷사 등록 화면에 보이는
단지/스마트홈 단지항목이 어느 테이블에 저장되는지 확인 필요(백엔드FrmInputDto에 대응 필드가 없음).
LMC와 대조해 확인된 것 (2026-09-18)
- 개인정보 취급 내역(
cmn.tb_inif_trt_l)을 적재하는 쪽은 LMC 관리자 웹임. LMC 세대정보 상세 화면 한 곳에서만, 세대의 앱 사용자 수만큼 유형 “조회”(R) 고정으로 1건씩 남김. SMC는 이 데이터를 조회만 함(개인정보 취급 내역 화면) → 공개노트/개발/모듈/LMC 기능 상세- 입주민 앱 서버(MAW)도 이 테이블에 적재하지 않음(2026-09-18 확인, MAW 코드 전체 검색 0건). 즉 입주민이 앱에서 자기 정보를 보는 것은 개인정보 취급 내역에 남지 않음. 앱 쪽에 남는 것은 API 감사 로그(
alog스키마)와 앱 접속 로그뿐임 → 공개노트/개발/모듈/MAW 세대·헬스케어 API
- 입주민 앱 서버(MAW)도 이 테이블에 적재하지 않음(2026-09-18 확인, MAW 코드 전체 검색 0건). 즉 입주민이 앱에서 자기 정보를 보는 것은 개인정보 취급 내역에 남지 않음. 앱 쪽에 남는 것은 API 감사 로그(
- 프로그램 구분 코드
server.config.pgmDsCd는 SMC가SYS, LMC가LHW임. 다만 LMC는 이 설정을 읽는 자바 코드가 없고 매퍼 SQL에 문자열'LHW'가 직접 박혀 있어 설정 값을 바꿔도 동작이 달라지지 않음 - SMC에 없는 화면들의 실제 위치
- 원패스 기기 목록 — LMC에 있음(
/sbd-mng/opas-dvc-mng/OpasDvcList) → 공개노트/개발/관리자시스템 원패스 기기 목록 - 원패스 통계 — 독립 메뉴 없음. LMC 대시보드 위젯(설치 현황 / 운영 현황 / 동작 현황 / 점검대상 원패스)으로만 있음
- 경영평가 성과지표 — LMC의 LH 관리자용 운영보고서 안의 두 표임 → 공개노트/개발/경영평가 성과지표
- 앱 버전 관리 — LMC에도 없음(라우트·컨트롤러·테이블 모두 없음). LMC 목업 HTML의 “앱 버전” 표기는 입주민 앱 목업이고 실제 기능이 아님
- 푸시 발송 화면 — LMC에도 없음. 푸시는 전입 승인 성공 시와 전출·반려 시 자동으로 1건 나가는 것뿐이고, 운영자가 작성·발송하는 화면이 없음. SMS도 발송 내역 조회만 있음 → 공개노트/개발/push 알림
- 원패스 기기 목록 — LMC에 있음(
관련
공개노트/개발/모듈/SMC API와 응답 코드 공개노트/개발/시스템 구성 공개노트/개발/모듈/비밀번호와 전화번호 암호화 공개노트/개발/모듈/SMS 발송 공개노트/개발/웹 접속 제한 공개노트/개발/스마트홈 대상단지 구분 공개노트/개발/공지사항 미리보기 공개노트/개발/관리자시스템 원패스 기기 목록 공개노트/기능/로그인과 세대 승인 기본매뉴얼/운영/보안 점검 기본매뉴얼/운영/tomcat과 배치 기동 기본매뉴얼/운영/WAS 로그 확인