본문으로 건너뛰기

JunkBox apps/message-ui 가이드

1. 애플리케이션 역할

  • apps/message-ui는 Message 관리 화면 전용 Vite 6 기반 React + TypeScript SPA임.
  • message-api가 제공하는 서버 렌더링 Message 앱 셸 위에 단일 React 엔트리를 마운트함.
  • 즉시 발송, 발송 이력, 예약 메시지, 정기 메시지 화면과 화면 간 클라이언트 라우팅을 소유함.
  • 실제 메시지 생성·Apprise 호출·이력 저장·스케줄 실행은 UI가 아닌 message-api 서비스 계층이 담당함.

2. 런타임과 엔트리

  • 개발 서버 기본 포트는 15004임.
  • 운영 산출물은 apps/message-ui/dist에 생성되며 message-api/message-ui 경로로 서빙함.
  • /, /message-ui, /message-ui/ 개발 진입은 /message-ui/messages로 리다이렉트됨.
  • 단일 엔트리 src/main.tsx는 shared-ui bootstrap()BrowserRoutermessage-ui-root에 마운트함.
  • 배포 자산은 Vite manifest 기준으로 해석하며 해시된 JavaScript 파일명을 템플릿에 하드코딩하지 않음.

3. 라우팅과 앱 셸 연동

  • /messages: 즉시 발송 화면임.
  • /message-history: 발송 이력 목록 화면임.
  • /message-schedules: 예약 메시지 목록 화면임.
  • /message-schedules/new: 예약 메시지 등록 화면임.
  • /message-recurrences: 정기 메시지 목록 화면임.
  • /message-recurrences/new: 정기 메시지 등록 화면임.
  • 공통 앱 셸은 spa_navigation=true에서 같은 origin 메뉴 클릭을 junkbox:spa-navigate 이벤트로 발행함.
  • Message React 앱은 이 이벤트를 수신해 shared-ui createSpaNavigateOptions(), runSpaViewTransition()과 React Router navigate()로 화면을 이동함.
  • 라우트 변경 시 resolveActiveNav()applyActiveNavState()로 앱 셸 메뉴 활성 상태를 동기화함.
  • 라우트 본문은 SpaRouteTransition으로 감싸고 useSpaRouteSettling()으로 스크롤 초기화와 모바일 고정 액션바 안착 상태를 처리함.
  • 메뉴 클릭 뒤 shared-ui closeAppDrawer()를 호출하여 모바일 드로어를 닫음.

4. 개발 서버 프록시

  • /api/message, /shared-ui, /messages, /message-history, /message-schedules, /message-recurrencesmessage-api 개발 서버 18004로 프록시함.
  • /message-ui/messages, /message-ui/message-history, /message-ui/message-schedules, /message-ui/message-recurrences도 base 경로를 제거해 message-api 웹 라우트로 프록시함.
  • 개발 페이지 HTML은 message-api가 렌더링하고 React 엔트리, Vite client, React refresh 자산은 15004/message-ui/*에서 로드함.

5. 화면 구조

  • 모든 화면은 jb-mobile-page 기반의 모바일 전용 360px 고정 폭과 safe-area 규칙을 사용함.
  • 페이지 제목은 앱 셸 아래 jb-screen-head, jb-page-title-section 구조로 표시함.
  • 즉시 발송 화면은 출처, 제목, 본문, 메시지 유형, Apprise 설정 키를 입력하고 하단 고정 발송 버튼으로 요청함.
  • 발송 이력 화면은 최근 메시지 우선 카드 목록과 재발송 액션을 제공함.
  • 예약·정기 목록 화면은 각각의 목록과 하단 고정 신규 등록 버튼을 제공함.
  • 예약 등록 화면은 공통 메시지 필드와 예약 시각을 입력함.
  • 정기 등록 화면은 일정 이름, 공통 메시지 필드, 반복 유형, 반복 설정을 입력함.
  • 화면별 CUD 주요 액션은 jb-mobile-bottom-bar의 공통 버튼 정책을 사용함.

6. 선택 UI와 공통 자산

  • 공통 React 계층은 @shared-ui/* alias로 libs/shared-ui/src/react를 참조함.
  • 메시지 유형과 정기 반복 유형은 네이티브 <select>를 사용하지 않음.
  • 선택 필드는 jb-select 외형의 버튼과 BottomOptionPicker 하단 선택 시트를 사용함.
  • BottomOptionPicker 옵션값은 API 계약값을 유지하며, 화면에는 사용자 이해용 라벨을 표시함.
  • 앱은 자체 CSS 파일, <style> 태그, inline style, 앱별 font-family 선언을 소유하지 않음.
  • 공통 CSS는 서버 템플릿의 stylesheet 매크로가 제공하는 hub-ui-base.css + hub-ui-mobile.css만 사용함.
  • 한글·영문·숫자 폰트는 shared-ui PretendardVariable.woff2와 중앙 --jb-font-family 선언을 사용하며 로컬 설치 폰트나 외부 폰트를 우선하지 않음.
  • 공통 아이콘, 토스트, 바텀시트, 앱 셸, 모바일 고정 액션바가 필요하면 화면 로직에서 복제하지 않고 shared-ui를 우선 사용함.

7. UI 문구와 오류 표시

  • 버튼, 라벨, placeholder, 빈 목록, 오류 문구는 소스에 한국어로 직접 작성함.
  • 일반 UI 텍스트를 위해 DB message code나 마스터데이터 키를 만들지 않음.
  • 문장형 사용자 노출 메시지는 하십시오체와 마침표를 사용함.
  • 목록·발송 요청 오류는 API 오류 응답의 안전한 상세 문구 또는 화면의 기본 오류 문구로 표시함.

8. 구현 제약

  • Message UI는 Apprise URL, 기본 설정 키, 인증 정보, SQLite 파일을 직접 읽거나 노출하지 않음.
  • 외부 셸 스크립트는 UI가 아닌 /api/message/messages API를 사용함.
  • 새 Tailwind utility class를 추가하면 Message UI Vite 빌드와 별도로 shared-ui 스타일 자산을 빌드해야 함.
  • 인증·권한 UI를 추가하는 경우 message-api의 실제 API 인증 정책과 Hub JWT/Cookie/Header 계약을 함께 정리해야 하며, 화면만으로 접근 제어를 구현하지 않음.