역할

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)가 PostgreSQL smahdbcmn 스키마를 직접 읽고 씀
  • 외부로 나가는 호출은 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/v1VUE_APP_API_URL로 프록시
별칭@core, @api(src/api), ~(src/views), @axios, @validations
백엔드Spring Boot 2.7.0, Java 8, Gradle, WAR 패키징(bootWarsysmngr.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|prodsrc/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_URLDB
productionhttps://homez-op.lh.or.kr/api/v1내부망 smahdb(포트 10882)
developmenthttps://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_cdSYS인 것만 SMC 화면에 뜸
  • server.config.upload.root — prod·dev /smahshare, local c:/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, prefix ENC[, suffix ]), spring.security.jwt.access.secret.key, spring.security.jwt.refresh.secret.key
  • 토큰 유효기간: access 10분(600000ms), refresh 30분(1800000ms). 프론트 쿠키 만료도 같은 값임. 커밋 ca8847c2에서 변경 이력 있음
  • frontend/public/robots.txtDisallow: /로 검색엔진 크롤링 전면 차단(커밋 477e2139)

화면 목록 39개

라우터는 frontend/src/router/index.js에서 7개 파일을 합침. meta.requiresAuth: true인 화면은 accessToken 쿠키가 없으면 로그인 후 이용해주세요. 알림 후 /login으로 보내짐.

#경로namerequiresAuth화면이 하는 일
1/loginloginfalse아이디/비밀번호 로그인 + SMS 2차 인증
2/login/resetPwdresetPwdfalse비밀번호 재설정(SMS 인증 후)
3/pages-profilepages-profile-사실상 미사용(로그인 화면이 뜸)
4/--루트 진입 시 /login으로 리다이렉트
5*--정의되지 않은 주소 → error-404
6/error-404error-404-페이지를 찾을 수 없습니다 안내 + 홈페이지 바로가기
7/dashboarddashboardtrue내용 없음(index 글자만 출력). 로그인 후 첫 화면
8/adm/mnu/mnuListmnu-listtrue메뉴 관리 목록(메뉴ID/상위메뉴ID/메뉴명/레벨/사용여부/화면경로)
9/adm/mnu/mnuDtlmnu-dtltrue메뉴 상세·사용여부 수정
10/adm/adm/admListadm-listtrue관리자 관리 목록 + 선택삭제/선택잠금/선택승인/등록
11/adm/adm/admDtladm-dtltrue관리자 정보 상세(아이디/이름/역할/지역/단지/업체/전화/이메일)
12/adm/adm/admRgsUpdadm-rgs-updtrue관리자 등록·수정. 역할에 따라 지역→단지→업체 선택박스가 단계적으로 열림
13/adm/admRol/admRolListadm-rol-listtrue관리자 역할 관리 목록
14/adm/admRol/admRolRgsUpdadm-rol-updtrue메뉴 권한 관리(역할별 메뉴 트리 + C/R/U/D 체크)
15/adm/admRol/admRolDtladm-rol-dtltrue역할 상세(등록·수정 화면 재사용)
16/usrAdm/usrAdm/usrListusr-list없음사용자 관리 목록(지역→단지 선택 후 조회)
17/usrAdm/usrAdm/usrDtlusr-dtl없음사용자 상세
18/usrAdm/usrAdm/usrUpdusr-upd없음사용자 수정(이름/전화/이메일/수신여부/상태코드/역할/세대아이디)
19/set/myInfoSet/myInfoSetmy-info-set없음내 설정(내 정보 확인·수정, 비밀번호 변경)
20/sysSet/hNetCo/hNetCoListh-net-co-list없음홈넷사 목록
21/sysSet/hNetCo/hNetCoDtlh-net-co-dtl없음홈넷사 상세(사업자번호/영문명/대표자/담당자/주소/전화)
22/sysSet/hNetCo/hNetCoRgsUpdh-net-co-rgs없음홈넷사 등록·수정
23/sysSet/lnkgSys/lnkgSysListlnkg-sys-list없음연동 시스템 상태 목록(업체명 검색)
24/sysSet/lnkgSys/lnkgSysDtllnkg-sys-dtl없음연동 시스템 상세 + 상태 뱃지(정상/오류)
25/sysSet/boardNotice/boardNoticeListboard-notice-list없음공지사항 목록(종류 APP/LHW/SYS 필터)
26/sysSet/boardNotice/boardNoticeDtlboard-notice-dtl없음공지사항 상세
27/sysSet/boardNotice/boardNoticeRgsUpdboard-notice-rgs없음공지사항 등록·수정(팝업 사용여부·기간, 첨부파일)
28/sysSet/board/:natTpCdboard-list없음공통 게시판. :natTpCd 값에 따라 제목이 공지사항/FAQ/자료실로 바뀜
29/sysSet/rsd-anncrsd-annc없음입주자 공지사항(목록+상세 래퍼)
30/sysSet/serviceClu/serviceCluListservice-clu-list없음서비스약관 관리 목록(필수여부/삭제여부/등록일자)
31/sysSet/serviceClu/serviceCluRgsUpdservice-clu-rgs없음서비스 이용약관 등록·수정
32/sysSet/block-ipblock-ip없음차단IP 목록·상세 래퍼
33/report/usConn/usConnListus-conn-listtrue접속·메뉴 사용이력(관리자 선택)
34/report/usConn/usConnHstus-conn-hsttrue선택 관리자의 접속·메뉴 사용 이력 목록
35/report/batchHst/batchHstListbatch-hst-listtrue배치 프로세스 모니터링 목록(프로시저명/주기코드/주기시간/사용여부)
36/report/batchHst/batchHstDtlbatch-hst-dtltrue배치 프로세스 세부 실행 내역
37/report/cldOprt/cldOprtListcld-oprt-listtrue클라우드 운영보고서 목록(기준년월/제목, 파일 다운로드)
38/report/cldOprt/cldOprtRgsUpdcld-oprt-rgsUpdtrue클라우드 운영보고서 등록·수정(파일 업로드)
39/report/inifTrtreport-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로 받아온 목록으로 그려짐.

  1. 로그인 → 레이아웃 로드 → GET /api/v1/mngr/comn/navmenu 호출
  2. 백엔드가 로그인 사용자의 역할(rol_id)과 서버 설정값 pgmDsCd=SYS로 메뉴 조회(mapper-rdb/mngrcomn/MngrComn_Comn_Mapper.xml:29)
    • 조건: menu.mnu_lvl > 0 AND menu.us_yn='Y' AND rol.us_yn='Y' AND rol_mnu_r.rol_id = 내 역할 AND menu.pgm_ds_cd = 'SYS'
    • 결과에 mnu_fnc_cds(C/R/U/D를 콤마로 이어붙인 문자열)가 함께 옴
  3. 프론트는 mnuLvl === 1을 1차 메뉴(드롭다운), mnuLvl === 2 && uppMnuId === 부모를 2차 메뉴로 그림. 맨 앞에 고정으로 대시보드가 붙고, tskId === 'dashboard'인 1차 메뉴는 제외함
  4. 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_MNGRLH광역관리자광역(widSn) — 선택 API가 없어 주석 처리, 동작 안 함
ARA_HDQ_MNGRLH지역본부관리자지역(grpSn)
SBD_MNGRLH단지관리자지역 → 단지(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 인증번호까지 입력해야 들어옴
  • 흐름
    1. 화면 유효성 검사 통과 → process.env.NODE_ENV === 'production'이면 SMS 인증 팝업(login-mob-ctf-modal), 아니면 바로 로그인(login.vue:170). 개발·로컬 빌드에서는 2차 인증을 건너뜀
    2. POST /api/v1/cert/certSms → 6자리 난수 생성 → 관리자 레코드의 sms_cfm_chr에 저장 → 내부 SMS API로 발송. 화면 문구 인증번호를 발송하였습니다.
    3. POST /api/v1/cert/checkSms로 검증 → 일치하면 sms_cfm_chr를 비우고, 상태가 PREJIN으로 승격
    4. POST /api/v1/cert/login → 차단IP 확인 → 사용자 조회 → 상태 확인 → 비밀번호(SHA-512, salt=아이디) 비교 → JWT access/refresh 발급
    5. 프론트가 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개월 뒤로 설정됨
  • 테이블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)
    1. RandomStringUtils.randomNumeric(6)으로 인증번호 생성
    2. 입력한 휴대폰번호에서 -를 빼고 ARIA로 암호화한 값과 DB의 mngr_mbl_tlno를 비교. 상태가 PRE·JIN(최초 가입 진행 중)이면 비교를 건너뛰고 입력값으로 갱신함
    3. 공통 상수 테이블(cmn.tb_cstt_m)에서 SMAH_INTERNAL_API_KEYSMAH_INTERNAL_API_WAS_ADR를 읽어, 헤더 ApiKey를 달고 POST {내부WAS}/api/smh/sms 호출(WebClient, 비동기)
    4. 전송 본문: 제목 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 시도 후 원 요청 재시도. 실패하면 로그인 화면으로
    • resCdSQI2011(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 (body mngrIds)
    잠금PUT /api/v1/mngr/managers-lock
    승인PUT /api/v1/mngr/managers-approve
  • 규칙

    • 신규 등록 시 상태는 무조건 RDY(승인대기)(ManagerService.java:125). 등록만으로는 로그인되지 않고 승인을 눌러야 USE가 됨
    • 승인 = mngr_ss_cdUSE로, 잠금 = 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/D 4개임(admRolRgsUpd.vue:46~85). 백엔드 상수 MENU_FUNCTIONS_CDS = "C, R, U, D"에는 A가 없음(추정: A는 대분류 접근 표시용)
    • 저장은 해당 역할+메뉴의 기존 권한을 전부 지우고 다시 넣는 방식(MenuRoleService.modifyMenuRole = clear → insert). 저장 도중 실패하면 권한이 비어 버릴 수 있음
    • 필수 파라미터 rolId;mnuId;mnuFncCds. 하위 메뉴가 있는 메뉴에 기능을 걸면 SQI7200
  • 화면 문구수정이 완료되었습니다., 저장하시겠습니까?

  • 테이블cmn.tb_rol_m, cmn.tb_rol_mnu_r

  • 운영 시 알아둘 점권한 변경이 즉시 반영되지 않음. SecurityConfig는 애플리케이션 기동 시 한 번만 역할-메뉴-기능을 읽어 시큐리티 매처를 구성함. 메뉴 권한을 바꾸면 화면 메뉴(navmenu API는 실시간)는 바뀌지만 API 접근 허용 규칙은 WAS를 재시작해야 반영됨. “메뉴는 보이는데 누르면 권한 없음(SQI3001)이 뜬다”는 문의의 유력한 원인임 → 기본매뉴얼/운영/tomcat과 배치 기동

메뉴 관리

  • 화면/adm/mnu/mnuList, /adm/mnu/mnuDtl
  • APIGET /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)으로 단지 목록을 좁힘
  • APIGET /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), 대표자명, 담당자명, 담당자 이메일, 우편번호, 주소, 전화번호. 화면에 단지·스마트홈 단지 항목도 있음
  • APIGET /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-keyUUID(하이픈 제거)를 새로 만들어 돌려줄 뿐 저장하지 않음(HomenetController.java:188). 화면에서 받은 값을 사람이 다른 곳에 옮겨 넣는 구조임. KeyUtil.apiKeyGen()return null인 빈 껍데기임
    • 필수값: 등록 frmNm, 수정 hnetFrmSn, 삭제 hnetFrmSns
  • 테이블cmn.tb_frm_m
  • 화면 문구저장하시겠습니까? / 수정하시겠습니까?

연동 시스템 상태

  • 무엇 — 홈넷사·외부 시스템과의 연동 설정과 가장 최근 연동 호출의 성공·실패 상태를 봄
  • 화면/sysSet/lnkgSys/lnkgSysList(목록: 업체명, 연동URL, 연동 시스템 상태), /sysSet/lnkgSys/lnkgSysDtl(상세)
  • APIGET /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) — hnetApiRspCdnull이면 회색(호출 이력 없음), 00이면 초록(정상), 01이면 빨강(오류)
  • 운영 시 알아둘 점
    • 목록 쿼리에서 상태·연동URL 관련 구문이 전부 주석 처리돼 있음. 목록 화면의 상태 표시는 현재 동작하지 않고, 상세를 열어야 상태가 보임. 목록 검색 조건 lnkgUrl도 주석 처리라 URL로는 검색되지 않음
    • 상세 API 응답에 연동키와 OAuth 시크릿이 그대로 실려 내려감. 화면에는 표시하지 않지만 브라우저 개발자도구·네트워크 탭에는 보임. 화면 공유·스크린샷 시 주의
    • 상세 조회 조건에서 frm_ty_cd = 'J' 필터가 주석 처리돼 있어 홈넷사가 아닌 업체도 조회됨
    • 필수값: 상세 hnetFrmSn. 실제 홈넷 연동 규격은 공개노트/기능/홈넷 서버 연동 참고

차단 IP 관리

  • 무엇 — 로그인 자체를 막을 IP를 등록함
  • 화면/sysSet/block-ip (내부에 blockList.vue, blockDtl.vue)
  • APIGET /api/v1/sysmngr/security/block-ip, GET .../block-ip/{ip}, POST / PUT / DELETE .../block-ip
  • 입력 항목 — 차단IP(connShtoIpad, PK), 차단사유(shtoRsnCts)
  • 규칙
    • 클라이언트 IP 판별은 IpUtil.getClientIP(). 헤더를 X-Forwarded-ForHTTP_CLIENT_IPHTTP_X_FORWARDED_FORHTTP_X_FORWARDEDHTTP_FORWARDED_FORHTTP_FORWARDEDProxy-Client-IPWL-Proxy-Client-IPHTTP_VIAIPV6_ADR 순으로 훑고, 값이 있으면 콤마로 잘라 첫 번째 IP만 씀. 헤더가 없으면 request.getRemoteAddr()
    • 이미 등록된 IP를 또 넣으면 SQI0003(중복)
    • 로그인 API(/cert/login)에서만 차단 검사를 함. 다른 API는 검사하지 않음
    • 필수값: 등록·수정 connShtoIpad, 삭제 connShtoIpads
  • 테이블cmn.tb_conn_shto_ipad_m
  • 화면 문구차단IP를 입력해주세요., 차단사유를 입력해주세요., 삭제하시겠습니까?, 차단IP 등록, 차단IP 상세
  • 운영 시 알아둘 점 — 차단은 완전일치임(부분·대역 차단 없음). 프록시·L4 뒤에 있으면 헤더 조작으로 우회 가능하니 실제 차단은 앞단 장비와 병행할 것. 커밋 a754fbcd에서 X-Forwarded-For 첫 IP만 취하도록 수정됨 → 공개노트/개발/웹 접속 제한

공지사항(시스템·앱) 관리

  • 무엇 — 관리자 웹(LHW)·앱(APP)·시스템(SYS)용 공지를 등록하고 팝업 노출 기간을 지정함
  • 화면/sysSet/boardNotice/boardNoticeList, boardNoticeDtl, boardNoticeRgsUpd
  • APIGET /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.stringifyx-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/:natTpCdnatTpCdann이면 공지사항, faq면 FAQ, arc면 자료실
  • APIGET / 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
  • 컬럼 — 유형, 제목, 내용, 공지일자, 팝업시작일, 팝업종료일, 첨부파일, 조회수, 등록자, 등록일시
  • 테이블cmn.tb_nat_m, cmn.tb_nat_ahfl_r, cmn.tb_ahfl_m
  • 화면 문구삭제하시겠습니까?, 선택하세요, 전체

입주자 공지사항

  • 무엇 — 특정 단지 입주민에게 나가는 공지를 등록함
  • 화면/sysSet/rsd-annc (내부 rsdAnncList.vue / rsdAnncDtl.vue)
  • APIGET / 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
  • APIGET / POST / PUT / DELETE /api/v1/mngr/boards/terms/{cluTpCd}(프론트는 SVC만 사용), 상세 GET .../terms/{cluTpCd}/{svcCluSn}
  • 약관 유형 enumEnumCluTp = 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(해당 관리자 이력)
  • APIGET /api/v1/mngr/log/sys-conn-log?mngrId=&pageSize=&pageNum=
  • 적재 APIPOST /api/v1/mngr/scl(body mnuId). 서버가 로그인 아이디·클라이언트 IP·yyyyMMdd(connYmdHHmm(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(세부 내역)
  • APIGET /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_cder_msg를 확인하고 실제 조치는 DB·스케줄러 쪽에서 할 것 → 기본매뉴얼/운영/tomcat과 배치 기동

클라우드 운영보고서

  • 무엇 — 월 단위 운영보고서 파일을 올리고 내려받음
  • 화면/report/cldOprt/cldOprtList, /report/cldOprt/cldOprtRgsUpd
  • APIGET /api/v1/mngr/report/cloud-operation(검색 stndYm, pclFctsSmr), GET .../cloud-operation/{stndYm}, POST / PUT(multipart), DELETE(body stndYms), 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, 주소)
  • APIGET /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
  • APIGET /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_ynN이거나 상위코드(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 발송 APISpring 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_mcron_xprssn_vl, pod_cd, pod_hr, run_scd, run_sqn)와 실행 이력(cmn.tb_proc_run_h)을 조회만

인터셉터·필터·공통 처리

  • JwtAuthenticationFilter(GenericFilterBean, UsernamePasswordAuthenticationFilter 앞) — 헤더 Authorization에서 토큰을 그대로 읽음(Bearer 접두어 없이 토큰 문자열만). 유효하면 DB에서 관리자를 다시 조회해 SecurityContext에 넣음. 토큰이 없으면 request attribute SQIExceptionSQI2000을 담음
  • JwtTokenProvider — JWT 클레임에 sub(아이디), rolId, hshId(세대), sbdId(단지), dngDs(동), hoDs(호)를 담음. 서명 HS256, 시크릿은 Base64 인코딩 후 사용
  • CustomAuthenticationEntryPoint — 401 응답. body는 {"resCode": ..., "resMsg": ...}(주의: **resCode**로, 정상 응답의 resCd와 키 이름이 다름). XSS 방지를 위해 <, >를 이스케이프함(2023-12-12 취약점 조치)
  • CustomAccessDeniedHandler — 403 응답, SQI3001
  • CorsConfigallowedOriginPattern("*"), 모든 헤더·메서드 허용, allowCredentials(true). 사실상 모든 출처 허용
  • CSRF 비활성화, 세션 STATELESS, HTTP Basic 비활성화
  • SQIFrameworkAspect(AOP @Around) — *Controller의 모든 메서드를 감싸 **요청 URI, 요청 파라미터 전체, 응답 전체, 처리 시간(ms)**을 INFO로 남김. @NoLogging이 붙은 메서드만 제외(현재 파일 다운로드 계열). SFWException을 잡아 & 구분자로 코드·메시지를 분리해 응답으로 변환함
  • TransationAspectkr.or.lh.smah..*Service.*(..) 전체에 트랜잭션 어드바이스 적용
  • RestExceptionHandlerNoHandlerFoundExceptionSQI9001
  • WebConfig/**, /*/*를 classpath 루트 정적 리소스로 매핑
  • PropertyEncryptConfig — jasypt로 ENC[...] 프로퍼티 복호화(PBEWithMD5AndDES, 1000 iterations, RandomSaltGenerator, base64 출력)
  • RDBMSConfig — HikariCP + MyBatis(classpath:/mapper-rdb/**/*_Mapper.xml), 캐시 끔, mapUnderscoreToCamelCase 켬, LongArrayHandler 타입핸들러 등록

알려진 이슈

  1. AOP가 요청·응답 전문을 로그에 남김. 로그인 요청의 usrPwd(평문), SMS 인증번호, 연동 시크릿이 Request parameters / Response parameters 로그에 그대로 찍힐 수 있음. 로그 접근 권한과 보관 기간을 반드시 확인할 것. 커밋 c673ae0d, ac09e2fb가 로그 경로 수정 이력임 → 기본매뉴얼/운영/WAS 로그 확인
  2. 메뉴 권한 변경이 API 접근 규칙에 즉시 반영되지 않음. SecurityConfig가 기동 시 1회만 DB를 읽음. WAS 재시작 필요
  3. SQI1015 enum의 코드값이 SQI1014로 잘못 들어가 있음(ApiResponseCode.java:86)
  4. unsetPassword API는 이름과 동작이 다름. “비밀번호 6개월 표시안함”이라 적혀 있으나 실제로는 비밀번호를 재설정함(CertController.java:270)
  5. 로그인 이력 적재가 호출되지 않음. loggerService.inputSysLogLogin(...)CertController에서 주석 상태임
  6. inputSysLogLogout이 로그아웃인데 로그인과 똑같은 코드임(SysConnLogService.java:53) — 구분 컬럼이 없어 로그아웃 기록이 로그인처럼 쌓임. 현재 호출되는 곳도 없음
  7. 연동 시스템 목록 화면의 상태 표시·URL 검색이 주석 처리돼 동작하지 않음(SysMngr_LinkSystem_Mapper.xml:41~61)
  8. CORS가 모든 출처를 허용함(CorsConfig)
  9. /api/v1/mngr/comn/codes/**가 인증 없이 열려 있음. 공통코드 전체가 비인증 조회 가능함
  10. 개발·로컬 빌드에서 SMS 2차 인증을 건너뜀(login.vue:170). NODE_ENV가 production이 아닌 산출물이 운영에 올라가면 2차 인증이 사라짐
  11. KeyUtil.apiKeyGen()return null인 빈 메서드임. 실제 API 키 발급은 uuidGen()으로 대체돼 있고 저장되지 않음
  12. dashboard.vueindex 문자열만 출력하는 빈 화면임. 로그인 직후 사용자는 빈 화면을 봄
  13. 우측 상단 사용자 드롭다운의 이름·역할이 하드코딩(관리자, admin)임. 소스에 // TODO: 유저 정보 API 필요 주석 있음(layouts/components/UserDropdown.vue:69)
  14. 라우터 push 오버라이드가 실패 시 window.location.reload()를 호출함(router/index.js:16). 잘못된 이동 시 화면이 새로고침되어 입력값이 날아갈 수 있음
  15. 취약점 수정 커밋 이력: 41021670(크로스사이트 요청 위조), 88dd19c6·f52ba99b(취약점 수정), 477e2139(robots.txt로 크롤링 차단)
  16. 로컬 프로필 설정 파일에 개발 DB 공인 IP와 jasypt 암호문이 커밋돼 있음
  17. 관리자 목록 화면의 광역(WID_SN) 선택 항목은 “API에 없음으로 주석 처리”되어 실제로는 쓸 수 없음(frontend/src/api/adm.js:9)
  18. 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
  • 프로그램 구분 코드 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 알림

관련

공개노트/개발/모듈/SMC API와 응답 코드 공개노트/개발/시스템 구성 공개노트/개발/모듈/비밀번호와 전화번호 암호화 공개노트/개발/모듈/SMS 발송 공개노트/개발/웹 접속 제한 공개노트/개발/스마트홈 대상단지 구분 공개노트/개발/공지사항 미리보기 공개노트/개발/관리자시스템 원패스 기기 목록 공개노트/기능/로그인과 세대 승인 기본매뉴얼/운영/보안 점검 기본매뉴얼/운영/tomcat과 배치 기동 기본매뉴얼/운영/WAS 로그 확인