REUSABLE PRODUCT ARCHITECTURE · v1.2

모바일·PC 듀얼 UI 웹앱 아키텍처 기획 가이드

모바일 웹·PWA·설치 앱의 안정성을 보존하면서 하나의 서비스에 PC 최적화 화면을 추가하는 실전 표준입니다. 핵심은 반응형 CSS가 아니라 공통 기능 코어와 독립된 두 UI 셸입니다.

One CoreTwo UI ShellsFeature FlagNative Mobile FirstPaperlogy

1. 하나의 Core, 두 개의 Shell

Language · Theme · Auth · Audio · Billing · Storage · API Providers
검색, 결제, 재생, 권한, 저장은 한 번만 구현
MOBILE SHELL

Touch & Safe Area

세로 흐름, 하단 내비게이션, PWA, Android/iOS

DESKTOP SHELL

Pointer & Wide Layout

사이드바, 다열 대시보드, 키보드, 전역 플레이바

선택 렌더링

모바일과 PC 트리를 동시에 실행하지 않습니다. 선택된 앱 하나만 렌더링해 중복 API·effect·결제를 막습니다.

네이티브 보호

설치 앱은 넓은 화면이나 DeX에서도 검증된 모바일 UI를 기본으로 강제합니다.

공통 Provider

UI 분기 위에 Provider를 두어 화면 전환 후에도 재생, 로그인, 언어와 결제 상태를 유지합니다.

점진 공개

PC 번들은 지연 로딩하고 기능 플래그 기본값은 OFF로 두어 즉시 모바일 폴백할 수 있습니다.

2. UI 모드 판정 정책

우선순위조건결과이유
1Android/iOS 네이티브모바일 강제설치 앱 회귀 방지
2로컬 ui 쿼리요청 모드안전한 비교 테스트
3PC 기능 플래그 OFF모바일 폴백운영 롤백
4저장된 사용자 선택선택 모드사용자 의도
5폭 ≥ 1100px + 정밀 포인터PC 자동태블릿 오판 방지
6그 외모바일안전 기본값
if (isNative) return 'mobile'
if (localOverride) return localOverride
if (!featureEnabled) return 'mobile'
if (storedMode !== 'auto') return storedMode
return width >= 1100 && finePointer ? 'desktop' : 'mobile'

Moodify에는 UI 모드 저장 API가 있지만 사용자가 자동·모바일·PC를 고르는 설정 화면은 아직 연결되지 않았습니다. 제품 기능으로 표시하려면 설정 UI·다국어·접근성·장치 QA가 추가로 필요합니다.

3. 프로젝트 구조와 앱 셸

공통 계층

contexts, services, utils에 인증·오디오·결제·검색·저장·정규화를 둡니다.

표현 계층

pages는 모바일, desktop은 PC 앱 셸과 전용 페이지를 담당합니다.

src/
  App.jsx                 # Provider + 모드 분기
  contexts/               # 장기 전역 상태
  services/ utils/        # 공통 비즈니스 로직
  pages/                  # 모바일 UI
  desktop/                # PC shell, pages, css
  hooks/useUiMode.js
  utils/uiMode.js
scripts/test-ui-mode.mjs

PC 사이드바가 있으면 모바일 BottomNav는 CSS로만 숨기지 말고 렌더링하지 않습니다. body 포털은 부모 레이아웃 범위를 벗어날 수 있습니다.

4. 상태와 데이터 소유권

데이터저장 위치예시
즉시 재생 상태Context / 상태 저장소현재 곡, 재생, 시간, 반복
화면 이동 후 임시 유지sessionStorage검색 목록, 제목, 필터
사용자 설정localStorage / 서버언어, 테마, UI 모드
결제·자격서버 원본구독, 크레딧, 구매 이력
공유 상태URL / 서버 ID공유 목록, 검색어
일회성 전달router state새 사진, 전환 힌트

복원 우선순위

새 라우트 데이터 → 활성 전역 데이터 → 세션 데이터 → 재조회 → 빈 상태

router state만으로 플레이리스트를 유지하면 프로필이나 설정을 다녀온 뒤 목록이 사라집니다.

5. 모바일·PC UX 표준

모바일

  • 100dvh와 visual viewport 동기화
  • 상·하단 safe area 적용
  • 주소창·키보드·회전·결제 복귀 처리
  • 최소 44×44px 터치 영역
  • 절대 종료 시각 기반 백그라운드 타이머
  • PWA 업데이트 후 완전 재실행 안내

PC

  • 1100/1280/1440/1920px 검증
  • 사이드바·중앙 작업·우측 보조 목록
  • 페이지 이동 없는 즉시 재생
  • hover와 키보드 focus 동시 지원
  • 긴 이름 말줄임과 고정 배지 폭
  • reduced motion 지원

6. 공통 기능 연결

검색

한 검색 함수와 정규화 결과를 모바일 세로 카드와 PC 우측 목록이 공유합니다.

재생

모든 플레이어가 하나의 Audio Context와 동일한 재생·반복 상태를 사용합니다.

외부 음원

자동 큐는 외부 전용곡을 건너뛰고 직접 선택에서만 앱·새 탭을 엽니다.

결제

UI는 달라도 주문·서버 검증·권한 반영은 공통 서비스가 담당합니다.

AI 분석

최신 결과 재열람은 저장본을 사용하며 재호출·재차감하지 않습니다.

데이터 진실성

없는 BPM·점수·출처를 만들지 않고 확인 불가 값은 대시로 표시합니다.

7. 단계별 개발 To-do

  1. 기존 모바일 핵심 흐름과 회귀 기준을 확보합니다.
  2. API·저장·재생·결제 로직을 UI 밖 공통 계층으로 분리합니다.
  3. 네이티브·플래그·폭·포인터 모드 판정과 단위 테스트를 구현합니다.
  4. PC lazy entry, 사이드바와 라우트 뷰포트를 추가합니다.
  5. 전역 상태와 동기화된 PC 미니 플레이어를 구현합니다.
  6. Home·Discover부터 PC 전용화하고 검색→재생→복귀를 검증합니다.
  7. Library·Analysis·Settings·Store를 순차 적용합니다.
  8. 스테이징 플래그를 열고 전체 장치 QA를 수행합니다.
  9. 승인 후 운영에 점진 공개하고 공개 버전을 검증합니다.

8. 필수 QA 체크리스트

9. 배포와 롤백

  1. PC 기능 플래그 OFF 상태로 먼저 배포합니다.
  2. 로컬 desktop 강제 모드와 스테이징에서 검증합니다.
  3. 모바일·PWA·설치 앱 회귀 테스트를 완료합니다.
  4. 사용자 승인 후 운영 플래그를 ON으로 변경합니다.
  5. Git 커밋, 배포 ID, 공개 버전 manifest 일치를 확인합니다.
  6. 이상 발생 시 플래그 OFF로 다시 빌드·배포하거나 직전 정상 배포로 롤백합니다.

운영 완료 기준은 빌드 성공이 아니라 공개 URL에서 올바른 버전과 UI 모드가 확인되는 시점입니다.

운영 PC UI 활성화 필수 설정

Vite 기능 플래그는 빌드 시점에 번들에 고정됩니다. PC UI 코드가 있어도 운영 환경에 다음 값이 없거나 false이면 모든 웹 사용자가 모바일 UI로 폴백합니다.

VITE_DESKTOP_UI_ENABLED=true

Cloudflare Pages 설정

  1. Workers & Pages에서 대상 프로젝트를 엽니다.
  2. Settings → Variables and Secrets에서 Production을 선택합니다.
  3. VITE_DESKTOP_UI_ENABLEDtrue로 저장합니다.
  4. 환경변수 저장 후 최신 커밋을 다시 배포합니다.
  5. Preview 검증이 필요하면 Preview 변수도 별도로 등록합니다.

자동 PC 판정 조건

  • Capacitor 네이티브 앱이 아닌 일반 웹 브라우저
  • window.innerWidth ≥ 1100
  • 마우스·트랙패드의 hover + fine pointer
  • 공개 webVersion과 main 커밋 일치
  • PC 셸·lazy chunk·업데이트 안내 로딩

VITE_ 변수는 브라우저 번들에 공개됩니다. 이 플래그는 일반 환경변수로 관리하고 API 키·토큰·비밀번호는 절대 넣지 않습니다.

배포 방식별 플래그 주입 위치

배포 방식설정 위치주의 사항
Git 연동 ProductionProduction Variables저장 후 새 Production 배포
Git 연동 PreviewPreview VariablesProduction 값 상속을 가정하지 않음
로컬 Vite로컬 .env / 실행 환경localhost 쿼리 강제 가능
Wrangler 직접 업로드로컬 빌드 프로세스 환경대시보드 변수는 기존 dist에 소급 적용되지 않음
# PowerShell
$env:VITE_DESKTOP_UI_ENABLED='true'
npm run build
npx wrangler pages deploy dist --project-name ai-moodify --branch main

# macOS / Linux
VITE_DESKTOP_UI_ENABLED=true npm run build
npx wrangler pages deploy dist --project-name ai-moodify --branch main

창 분할, 개발자 도구 도킹, 높은 확대율로 콘텐츠 폭이 1100px 미만이면 PC에서도 모바일 UI가 표시될 수 있습니다. 창을 최대화하고 확대율을 100%로 맞춘 뒤 확인합니다.

?ui=desktop은 localhost 개발 환경 전용입니다. 운영에서는 쿼리를 무시하며, 저장된 desktop 선택값도 기능 플래그가 OFF이면 적용하지 않습니다.

빌드형 플래그와 런타임 플래그

현재 Vite 플래그는 빌드 시 번들에 고정되므로 대시보드에서 값만 바꿔서는 즉시 롤백되지 않습니다. 새 번들을 배포하고 PWA 업데이트까지 전달해야 합니다. 수초 단위 긴급 차단이 필요하면 실패 시 모바일로 폴백하는 별도의 Edge 런타임 설정과 캐시·서명·접근 제어 정책을 설계합니다.

문제 진단 순서

운영 환경변수와 철자 확인
→ 환경변수 저장 후 재배포 확인
→ app-version.json과 main SHA 대조
→ 네이티브 앱 여부 확인
→ window.innerWidth와 포인터 조건 확인
→ PWA 캐시 갱신 및 완전 종료·재실행

CI 또는 배포 검증에서 운영 플래그 값, main SHA와 app-version.json, PC 전용 청크 HTTP 200을 자동 확인하는 것을 권장합니다.

10. 피해야 할 구현

두 앱을 동시에 렌더링하고 CSS로 숨기기

PC 페이지에 별도 결제·오디오·저장 로직 복제

화면 폭만으로 태블릿·DeX를 PC로 오판

router state만으로 검색·재생목록 유지

없는 BPM·분석 점수·출처 생성

빌드만 확인하고 공개 버전·PWA 갱신 생략