feat: 둘러보기(데모)를 실제 화면 그대로 — 데모 모드 + API 더미 응답

- src/demo: demo.on 플래그 + DTO 형태 더미데이터 + mock API(읽기 더미/쓰기 차단)
- accountApi: Proxy 로 데모 시 읽기→더미, 쓰기→안내. 실제 뷰 그대로 렌더
- App: authed=인증||데모 → 실제 사이드바/셸 표시 + 데모 배너(로그인/나가기)
- 라우터: 데모 허용(가계부/고정/계좌/분류) 외 보호화면은 DemoLockedView(로그인 유도)
- 사이드바: 데모 시 잠금(🔒) 배지, 메뉴는 showMenu(인증||데모)
- 로그인/로그아웃 시 데모 자동 해제, 랜딩 '둘러보기'→enterDemo
- 기존 독립 DemoView 제거

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ByungCheol
2026-06-28 07:49:37 +09:00
parent 80e1faec09
commit 4ffc01f484
10 changed files with 331 additions and 483 deletions
+37 -1
View File
@@ -1,7 +1,8 @@
import http from './http'
import { demo, demoApi } from '@/demo'
// 백엔드 /api/account 엔드포인트와 매핑 (본인 데이터만)
export const accountApi = {
const realApi = {
list({ year, month, type, category, walletId, keyword, tagId } = {}) {
return http.get('/account/entries', { params: { year, month, type, category, walletId, keyword, tagId } })
},
@@ -198,3 +199,38 @@ export const accountApi = {
})
},
}
// ===== 둘러보기(데모) 모드 =====
// demo.on 이면 읽기는 더미 데이터, 쓰기는 차단(안내 메시지)으로 응답한다.
const DEMO_READS = {
list: demoApi.list,
summary: demoApi.summary,
wallets: demoApi.wallets,
netWorth: demoApi.netWorth,
categories: demoApi.categories,
recurrings: demoApi.recurrings,
quickEntries: demoApi.quickEntries,
pendingCount: demoApi.pendingCount,
tags: demoApi.tags,
walletEntries: demoApi.walletEntries,
}
const DEMO_WRITES = new Set([
'create', 'update', 'remove', 'parseText', 'createQuickEntry', 'removeQuickEntry', 'repayment',
'createRecurring', 'updateRecurring', 'removeRecurring', 'runRecurrings',
'createWallet', 'updateWallet', 'removeWallet', 'reorderWallets',
'createCategory', 'updateCategory', 'removeCategory', 'reorderCategories', 'importCategories',
'createTag', 'updateTag', 'removeTag', 'reorderTags', 'confirmEntry', 'ocrReceipt',
'createBudget', 'updateBudget', 'removeBudget', 'setExpectedIncome',
'createHolding', 'updateHolding', 'removeHolding', 'addTrade', 'updateTrade', 'removeTrade',
'refreshPrices', 'refreshAllPrices',
])
export const accountApi = new Proxy(realApi, {
get(target, prop) {
if (demo.on) {
if (DEMO_READS[prop]) return DEMO_READS[prop]
if (DEMO_WRITES.has(prop)) return () => demoApi.block()
}
return target[prop]
},
})