역할
APW(API WAS)는 스마트홈 클라우드가 바깥과 주고받는 모든 통신의 관문임. 전체 그림은 공개노트/개발/시스템 구성.
- 받는 쪽: 홈넷서버(코맥스·코콤 등), 에너지플랫폼(이음), 층간소음센서, 내부 WAS(MAW·SCW·LMW·SMW)
- 부르는 쪽: 홈넷서버, 뿌리오(SMS), Google FCM(푸시), 삼성 SmartThings 커넥터, OAW(토큰 검증), PIW(기기 상태 중계), WISE(임대료)
- 외부 진입:
homez-api.lh.or.kr:8094로 들어온 요청은 Apache가 전부 APW로 넘김./api/ccg/authcheck만 OAW로 감 - OAuth2 리소스 서버. 홈넷사가 들고 오는 AccessToken은 OAW(같은 서버 8082)에 넘겨 검증함
APW에는 동작하는 스케줄러가 없음. 스케줄러 클래스 9개가 남아 있으나 전부 주석 처리됨. 주기 작업은 모두 공개노트/개발/모듈/SCW 스케줄러 서버에서 돎. 예외로 LMW의 “홈넷서버 전체 세대단말기 조회” 요청만 APW가 동기 실행함.
기술 스택
| 항목 | 값 |
|---|---|
| 프레임워크 | Spring Boot 2.7.0, Java 1.8, Gradle, war 패키징(apw.war), SqiEnergyFramework-2022 기반 |
| 영속성 | JPA(Hibernate) + MyBatis 혼용 |
| DB | PostgreSQL smahdb. 운영 접속 정보는 담당자 문의 |
| 포트 | 운영 WAS 8084 |
| HTTP 클라이언트 | Spring WebFlux WebClient. 응답 타임아웃 600초(10분) |
| 인증 | spring-security-oauth2 2.3.8(리소스 서버) + jjwt |
| 푸시 | firebase-admin 9.1.1 (FCM HTTP v1) |
| 캐시 | Redis (Sentinel 3노드) |
| 설정 암호화 | jasypt. ENC[...]로 감싼 값만 복호화 |
| 전화번호 암호화 | ARIA 128bit. tb_usr_m의 휴대폰 번호가 암호화 저장됨 |
| 톰캣 | /usr/local/tomcat-apw/. 기동은 startup_proxy.sh(외부 호출이 Squid 프록시를 타야 하므로 startup.sh 아님) |
| 로그 | /app/logs/was/tomcat-apw/apw.log, apw_error.log (일별 롤링, 30일 보관). 기본매뉴얼/운영/WAS 로그 확인 |
프로필 (local / dev / prod)
설정 키는 세 프로필이 같고 값만 다름. 실질 차이는 두 가지임.
notification.receiver.ids— local/dev는 여기 적힌 테스트 계정으로만 푸시·SMS가 나감(오발송 방지). 운영은 비어 있어야 실사용자에게 발송됨.- FCM 토픽 조건에 운영은
'PRD' in topics, 그 외는'DEV' in topics가 자동으로 붙음. 개발 서버에서 쏜 푸시는 DEV 토픽 구독자(개발 빌드 앱)에게만 감.
sqi.tha 플래그가 true면 홈넷서버 대신 테스트용 echo 서버(THA)로 우회함. 운영·개발 모두 현재 false.
주요 설정 키 (값은 마스킹)
server.port=8084
spring.security.matchers.permitall=/api/smh/**,/api/proxy-homenet/**,/api/em/**
spring.security.matchers.authenticated=/api/hn2lh/**
spring.security.oauth.checktoken.endpointurl=http://localhost:8082/api/ccg/tokencheck # OAW
firebase.credential.path=oAuthPrivateKeyByGoogleFcm/<service-account>.json
from.eepapi.api.key=EEP_TO_SMAH_API_KEY # 값이 아니라 tb_cstt_m의 cstt_id
notification.receiver.ids= # 운영은 비움
https.proxyHost / http.proxyHost=[내부 프록시]:13128 (squid)
wise.contract-url / wise.rental-fee-url / wise.service-name / use-system-code
war로 톰캣 구동 시 application.properties의 프록시 설정이 안 먹고 catalina.sh에 넣어야 함. 그래서 기동 스크립트가 startup_proxy.sh임.
API 그룹과 인증
URL 접두사로 성격과 인증 방식이 갈림.
| 접두사 | 호출자 | 인증 |
|---|---|---|
/api/hn2lh/** | 홈넷서버 | OAuth AccessToken 필수(Authorization: Bearer) → OAW로 검증 |
/api/em/** | 에너지플랫폼(이음) | API Key(auth 헤더). tb_cstt_m.EEP_TO_SMAH_API_KEY와 대조 |
/api/smh/** | 내부 WAS | API Key(ApiKey 헤더). tb_cstt_m.SMAH_INTERNAL_API_KEY와 대조 |
/api/proxy-homenet/** | 내부 WAS (앱 → MAW → APW) | ApikeyValidateFilter |
/api/fns/** | 층간소음센서 | 센서 MAC 주소로 식별 |
/api/wise/** | 내부 | 없음 |
홈넷서버 → LH 수신 (/api/hn2lh)
모든 메서드가 공통으로 3단계 검증을 먼저 함. 인증된 홈넷서버 ID 없음 → 5016, 요청 단지에 권한 없음 → 5017, 동/호 없음 → 5011.
| 메서드 | 경로 | 하는 일 | 테이블 |
|---|---|---|---|
| POST | /api/hn2lh/deviceEvent | 세대 기기 상태변경 수신 → PIW로 중계(DB 저장 없음) | - |
| POST | /api/hn2lh/event | 세대 이벤트 수신(방범·비상호출·입출차·층간소음 등) → SMS/푸시 발송. 공개노트/기능/홈넷 이벤트 알림 | smah.tb_hnet_evn_rcv_l, cmn.tb_evn_occ_l |
| POST | /api/hn2lh/heartbeat | 홈넷서버 생존 신고 | smah.tb_hnsvr_brf_l |
| POST | /api/hn2lh/homeDevices | 세대 단말기·기기 목록 보고 | cmn.tb_hsh_ter_m, cmn.tb_hsh_dvc_m |
| GET | /api/hn2lh/noticeList, noticeDetail | 단지 공지사항 | cmn.tb_rsd_annc_fcts_l |
| GET | /api/hn2lh/managementExpenseList, managementExpenseDetail | 세대 관리비 | smah.tb_hsh_mngexp_m |
| GET | /api/hn2lh/safetyServiceHouseholds | 주거약자(안전서비스) 세대 목록 | cmn.tb_sft_svc_hsh_m |
| GET | /api/hn2lh/voteList, voteDetail | 전자투표 | smah.tb_elc_vt_m |
deviceEvent는 변경분만 고르는 Redis 비교 로직이 주석 처리돼 있어 받은 전체 장치를 그대로 PIW(localhost:8087)로 넘김. PIW가 죽어 있으면 기기 상태가 가전사 쪽에 반영되지 않음. 로그 키워드postMonoBody,Connection refusedhomeDevices는 동일 단말기가 중복 보고되면 PK 충돌 가능(소스 주석)
에너지플랫폼 → LH 수신 (/api/em)
| 메서드 | 경로 | 하는 일 |
|---|---|---|
| POST | /api/em/autoDRControl | AutoDR 발령 수신 → DB 저장만. 실제 제어는 SCW. 공개노트/기능/AutoDR |
| POST | /api/em/autoDRControlResult | DR 제어 결과 조회 |
| GET | /api/em/homenetServerList | CZEMS 연동용 홈넷서버 목록 (2024 추가) |
내부 WAS 연계 (/api/smh)
| 메서드 | 경로 | 하는 일 |
|---|---|---|
| POST | /api/smh/sms | SMS 발송 요청 → 뿌리오. 공개노트/개발/모듈/SMS 발송 |
| POST | /api/smh/push | 푸시 발송 요청 → FCM. 공개노트/개발/push 알림 |
| POST | /api/smh/event | 내부 이벤트 수신 → DB 저장·홈넷 전달 |
| GET | /api/smh/getHomenetServerAccessToken | 내부 WAS가 홈넷을 직접 부를 때 쓰는 토큰 제공 |
| GET | /api/smh/getHomenetServerGateways | LMW용 홈넷서버 전체 세대단말기 조회 (건별 save라 느림) |
| GET | /api/smh/gateways | 세대별 단말기 상태 |
| GET | /api/smh/{hshId}/devices | 세대 전입 상태 확인 (전용 API가 없어 기기목록 조회로 대체) |
| POST | /api/smh/lhHouseholdEvent | 세대 이벤트를 홈넷에 전달만 |
| POST | /api/smh/cogo/move-in | 전입 처리 (2025 추가) |
| POST | /api/smh/cogo/move-out | 전출 처리 (2025 추가) |
전입·전출 처리 내용은 공개노트/기능/로그인과 세대 승인 “전출입 상태” 참고.
홈넷 프록시 (/api/proxy-homenet) — 가전사 앱 기기 제어 경로
이 경로를 쓰는 것은 가전사 앱(삼성 SmartThings·LG ThinQ) 쪽임 → 공개노트/개발/모듈/PIW 연계 서버. 입주민 앱(MAW)은 이 프록시를 쓰지 않고 홈넷서버를 직접 호출함(2026-09-18 확정, MAW 코드 1~3편 전 범위에 이 경로를 부르는 곳이 없음). 예전 정리본의 “앱 → MAW → APW” 표기는 가전사 앱 경로를 입주민 앱으로 잘못 적은 것임.
| 앱 | 홈넷 경로 | 응답 타임아웃 |
|---|---|---|
| 입주민 앱 | MAW → 홈넷서버 직접 | 3초 |
| 가전사 앱 | PIW → APW 홈넷 프록시 → 홈넷서버 | 10분 |
입주민 앱 쪽 동작은 공개노트/기능/우리집제어 · 공개노트/개발/모듈/MAW 앱 API 서버.
| 메서드 | 경로 | 홈넷 호출 | 하는 일 |
|---|---|---|---|
| GET | /api/proxy-homenet/hshs/{hshId}/devices | GET /api/um/devices | 세대 기기 목록·상태 |
| PATCH | /api/proxy-homenet/devices/{dvcId} | POST /api/um/devices/command | 기기 제어 |
| POST | /api/proxy-homenet/subscribeDeviceEvent | POST /api/um/subscribeDeviceEvt | 상태변경 이벤트 구독·해지 |
| POST | /api/proxy-homenet/elevator | POST /api/um/elevator | 승강기 호출. 공개노트/기능/승강기 호출 |
- 홈넷 URL은
tb_hnsvr_m.hnsvr_ipad에 포트가 없으면:8094를 자동으로 붙임. 홈넷사가 다른 포트를 쓰면 DB에호스트:포트로 넣어야 함 4102“보안상의 사유로 안전·층간소음·가스 ON, 방범 OFF, 외출 OFF 설정 불가”는 버그가 아니라 의도된 차단임. 공개노트/기능/방범- 기기 제어가 오래 걸리면 WebClient 응답 타임아웃 10분 때문. 홈넷서버가 응답을 안 줘도 10분을 기다림. 이 10분은 가전사 앱 경로에만 해당함. 입주민 앱은 3초에 끊김
4102차단도 이 프록시 경로의 규칙임. 입주민 앱은 이 차단을 타지 않음
홈넷 토큰 조회 부하
GET /api/smh/getHomenetServerAccessToken을 MAW가 홈넷 호출마다 한 번씩 부름. MAW는 토큰을 캐시하지 않음(관련 테이블·엔티티가 전부 주석 처리돼 있음). 즉 입주민 앱의 기기 목록 조회 1건에 APW 토큰 조회 1회가 붙고, 방문 내역처럼 홈넷을 여러 번 부르는 화면은 그 배수만큼 붙음. APW 부하·응답시간을 볼 때 이 배수를 감안할 것.
층간소음센서 수신 (/api/fns)
공개노트/기능/홈넷 이벤트 알림 “층간소음 센서” 참고.
WISE 임대료 프록시 (/api/wise)
POST /api/wise/rfe로 임대료 조회. 전입 처리 시 WISE 계약 여부도 여기서 확인함(wise.contract-url). 2025 추가.
외부 연동
홈넷서버 토큰 (LH → 홈넷 방향)
LH가 홈넷서버를 부를 때 쓰는 토큰. 반대 방향(홈넷 → LH)은 OAW가 발급함. 상세는 공개노트/기능/홈넷 서버 연동 “LH → 홈넷 방향 토큰”.
OAW
같은 서버 8082 포트로 토큰 검증 요청(/api/ccg/tokencheck). OAW가 죽으면 /api/hn2lh/** 전체가 4013(인증 서버 장애)로 401 응답. 서버 상세는 공개노트/개발/모듈/OAW 인증 서버.
- 홈넷사가 들고 오는 토큰은 OAW가
POST /api/ccg/authcheck로 발급함. 클라이언트당 유효 토큰이 1개라 재발급하면 이전 토큰은 즉시 무효가 됨 - APW 자신도 OAW의 클라이언트임. client_id는
tb_cstt_m의 내부 상수 ID를 씀 - 신규 홈넷사 등록은 별도 화면 없이
cmn.tb_hnsvr_m에 행을 넣는 것이 전부임. 연동상태코드를ON으로 올리지 않으면 토큰 발급이 실패함 - 플랫폼 전체의 토큰 종류 정리는 공개노트/개발/모듈/OAW 인증 서버 “토큰 종류” 표 참고
Google FCM
- 기동 시 서비스 계정 JSON(
firebase.credential.path)을 읽음. 파일이 없으면 APW 기동 자체가 실패함 - 발송 규칙(토픽 배열, 25개 배치, 토큰 미등록 처리)은 공개노트/개발/push 알림 “서버 발송 규칙”
뿌리오 SMS
삼성 SmartThings (전출 시 파트너 해지)
- 파트너 ID
sse. 주소는tb_cstt_m.SAMSUNG_SCI_API_ADR+/partner - 순서: 커넥터에 퇴거 알림 → 성공 시에만 10초 대기 → InstalledApp 제거. 알림 실패 시 제거를 생략하고 로그
Samsung 커넥터 알림 전송 실패로 InstalledApp 제거를 생략합니다 - Redis의 OAuth 토큰과
cmn.tb_oauth_m삭제
PIW
localhost:8087/api/eum/partner/devices. 홈넷에서 받은 기기 상태변경을 그대로 중계함. 헤더 인증값이 소스에 하드코딩됨.
데이터
스키마
| 스키마 | 용도 |
|---|---|
cmn | 공통 마스터(사용자, 세대, 단지, 홈넷서버, 코드, 상수) |
smah | 스마트홈 업무(이벤트, 투표, 관리비, DR, 제어 예약) |
alog | API 송수신 로그 |
hc | 헬스케어·날씨(SCW가 씀) |
자주 보는 테이블
| 테이블 | 용도 |
|---|---|
cmn.tb_cstt_m | 상수 마스터. API Key, 외부 주소, 뿌리오 계정이 전부 여기 있음 |
cmn.tb_usr_m | 사용자(휴대폰 번호 ARIA 암호화, 푸시 토큰) |
cmn.tb_hnsvr_m | 홈넷서버 마스터(주소, 컨텍스트 경로, LH플랫폼 인증정보, 연동상태코드, 삭제여부) |
cmn.tb_hnsvr_lnkg_tkn_d | 홈넷서버 연계 토큰(accs_tkn varchar(2048)) |
cmn.tb_evn_m | 이벤트 코드 마스터. 홈넷 코드 → 스마트홈 코드 변환 기준 |
cmn.tb_emcrt_l | 비상연락처 |
cmn.tb_cogo_h | 전출입 이력 |
cmn.tb_sms_sndg_l | SMS 발송 이력 |
cmn.tb_push_sndg_l | 푸시 발송 이력(rcvr_key_list varchar(4096)) |
cmn.tb_oauth_m / tb_hmapp_dvc_m | 파트너(삼성·LG) OAuth 토큰 / 가전 기기 연동 |
cmn.tb_nsba_dvc_m 외 _brf_h, _nc_h, _cont_h | 층간소음센서 기본·생존보고·소음내역·제어설정 |
smah.tb_hnet_evn_rcv_l | 홈넷 이벤트 수신 내역 |
smah.tb_hnsvr_brf_l | 홈넷서버 heartbeat 내역 |
smah.tb_dr_goo_l / tb_dr_ctctr_m | DR 발령 내역 / DR 계약자 |
alog.tb_hnet_lh_api_rcv_l, _rsp_l | 홈넷 → LH 요청·응답 로그 |
alog.tb_lh_hnet_api_req_l, _rsp_l | LH → 홈넷 요청·응답 로그 |
alog.tb_oauth_ctf_l | OAuth 인증 내역 |
tb_cstt_m 상수 ID
| cstt_id | 용도 |
|---|---|
SMAH_INTERNAL_API_KEY | 내부 WAS 연계 API Key |
EEP_TO_SMAH_API_KEY | 에너지플랫폼 → LH 수신 API Key |
PURRIO_SMS_SENDER_INFO | `뿌리오ID |
SAMSUNG_SCI_API_ADR | 삼성 커넥터 주소 |
SMAH_APP_NOISE_LEVEL_1_PUSH_IMAGE_URL, ..._2_... | 층간소음 푸시 이미지 |
응답 코드
홈넷 연동 응답 코드(/api/hn2lh)는 공개노트/기능/홈넷 서버 연동 “결과 코드”에 있음.
내부 연계 (/api/smh, /api/proxy-homenet)
| 코드 | 뜻 |
|---|---|
2000 | 정상 |
1998 / 1999 | 부분 성공 / 실패 |
4011 / 4017 | API KEY 누락 / 잘못된 API KEY |
4101 | 명령 대상 기기 아이디 미존재 |
4102 | 보안상 사유로 안전·층간소음·가스 ON, 방범 OFF, 외출 OFF 설정 불가 (의도된 차단) |
5011 | 해당 세대정보 없음 |
5012 / 5013 | 필수 파라미터 누락 |
5021 | 대상 정보 없음 |
5022 / 5023 / 5024 | SMS 발송 완료 / 실패 / 일부 오류 |
5025 / 5026 | 푸시 발송 완료 / 실패 |
5027 | 잘못된 파라미터 (존재하지 않는 단지·세대 ID로 토픽 생성 등) |
5028 | 푸시 토픽 개수 초과 (최대 4개) |
5999 | 서버 내부 오류 |
에너지플랫폼 (/api/em)
| 코드 | 뜻 |
|---|---|
200 | 정상 |
500 / 505 | 오류 / 실패 |
507 / 508 | API KEY 누락 / 잘못된 API KEY |
511 / 512 / 513 | 세대정보 없음 / 필수 파라미터 누락 / 데이터 없음 |
599 | 서버 오류 |
층간소음센서 (/api/fns)
2000 정상 / 4011 인증정보 불일치(미등록 MAC) / 5001 서버 내부 오류
알려진 이슈
SecurityConfig가 동작하지 않음. OAuth 리소스 서버라서config/oauth/Oauth2ResourceServerConfig.java로 처리해야 함- 오류 응답은 홈넷 연동규격 표준
{"trace_id","result_code"}형태.result_message는 규격에서 삭제돼 내려주지 않음 CustomTokenFilter가 모든 요청의 헤더·파라미터·본문을 INFO 레벨로 통째로 로그에 남김.Authorization헤더와 개인정보가apw.log에 그대로 남음. 디스크 용량·개인정보 양쪽 문제getHouseholdTerminalByHomenetServerId(LMW의 홈넷서버 전체 세대단말기 조회)가 건별 save라 매우 느림. 일괄 save로 개선 필요- 하드코딩된 내부 주소: PIW
localhost:8087, OAWlocalhost:8082, PIW 인증값. 포트 변경 시 소스 수정 필요 - 테스트 메서드
sendFcmPushMessage(String)에 실제 FCM 토큰 5개가 하드코딩돼 있고ALL_USERS등 토픽을 구독 해제함. 실수로 호출되면 해당 단말이 전체 공지를 못 받음 - 죽은 코드 다수: 스케줄러 9개와 대응 서비스·매퍼(SCW로 이관 후 잔재),
api/*패키지(프레임워크 스캐폴딩) - API 버전 관리 없음(단일 버전). 재배포 시 기존 연동 시스템이 깨질 위험
- 홈넷 연동규격 V1.1 개선안(이벤트 코드 변경) 미적용
- 코맥스 전기차 기능 없음. 단
CA(충전완료) 이벤트 수신 코드는 이미 있음 - JWT access token 유효기간이 prod 약 208일로 SCW(30분)와 크게 다름. 오타로 추정
- 2024-07 성능 개선 커밋: API 로깅이 트랜잭션에 묶여 느려지던 문제 수정됨
확인 필요
확인 필요
notification.receiver.ids가 운영에서 비어 있어야 실사용자에게 발송됨. 배포 시 dev 설정이 섞이면 전 입주민 알림이 테스트 계정으로만 가고 아무도 모르게 됨. 배포 후 이 값을 확인하는 절차가 있는지sqi.tha플래그가 과거 커밋에서 true/false를 여러 번 오감. 배포 때 true가 되면 모든 홈넷 호출이 테스트 서버로 감. 배포 체크리스트에 포함돼 있는지tb_cstt_m의 상수(SMAH_INTERNAL_API_KEY,EEP_TO_SMAH_API_KEY,PURRIO_SMS_SENDER_INFO) 변경 이력 관리 주체- ARIA 키·jasypt 비밀번호·JWT 시크릿이
application.properties에 평문으로 있음. 키 로테이션 정책deviceEvent의 Redis 델타 비교가 주석 처리된 이유(성능인지 정확도인지). 되살리면 PIW 트래픽이 크게 줄어듦deviceEvent는 PIW 중계 실패를 응답에 반영하지 않음. 홈넷사가 재시도해야 하는 상황인지- WebClient 응답 타임아웃 600초가 의도된 값인지
관련
공개노트/개발/시스템 구성 공개노트/개발/모듈/MAW 앱 API 서버 공개노트/개발/모듈/SCW 스케줄러 서버 공개노트/개발/모듈/OAW 인증 서버 공개노트/기능/홈넷 서버 연동 공개노트/기능/홈넷 이벤트 알림 공개노트/개발/push 알림 공개노트/개발/모듈/SMS 발송 공개노트/기능/AutoDR 공개노트/기능/우리집제어 기본매뉴얼/운영/WAS 로그 확인 기본매뉴얼/운영/tomcat과 배치 기동