Files
jarca-ledger-mcp/docs/requirements/req-002_dashboard-menu-transition.md
T

18 KiB

schema, id, title, revision, status, depends_on, applies_to, language
schema id title revision status depends_on applies_to language
gitea-agent.requirement/v1 REQ-002 Dashboard 메뉴 전환 시 공통 화면 연속성 1.0 approved
REQ-001
dashboard
ko

REQ-002 — Dashboard 메뉴 전환 시 공통 화면 연속성

1. 목적

인증된 Dashboard에서 메뉴를 바꿀 때 문서 전체를 이동시키지 않고 공통 shell과 배경을 유지하며 body만 교체한다. 현재 메뉴 선택, URL 상태, 느린 렌더링, 렌더링 실패의 동작을 예측 가능하게 만든다.

2. 배경

Issue #9의 Dashboard 메뉴 전환 계약이다. REQ-001의 인증 경계, cookie, logout, page dispatch와 기존 금융 페이지 계약을 유지한 채 Streamlit 메뉴 전환을 연속적인 단일 화면으로 제공한다.

3. 범위

포함

  • Streamlit st.radio 기반 메뉴의 정확한 10개 label/order와 selected state
  • 메뉴 클릭 시 document navigation 없이 공통 shell/background를 유지하고 body만 교체
  • 느린 대상 page 렌더링 중 대상별 loading 표시
  • renderer 예외의 local generic error와 retry
  • 빠른 연속 선택에서 latest serialized selection wins
  • 직접 ?page= 접근, 누락/unknown page의 요약 fallback, sibling query key 보존
  • 기존 auth gate, cookie, logout, finance page, cache-clear 회귀 검증

제외

  • browser history/back-forward 동작, history API 계약, path URL 설계
  • 인증 방식·cookie 속성·MCP transport·SQLite schema 변경
  • page renderer의 금융 계산·gateway 의미 변경
  • 별도 document route 또는 full-document navigation 구현

4. 용어와 기준

  • 공통 shell: 인증 후 dashboard/app.py가 제공하는 sidebar, 메뉴, refresh control 및 앱 배경/CSS.
  • body: 선택된 page renderer가 공통 shell 안에서 채우는 주 콘텐츠 영역.
  • latest serialized selection: Streamlit rerun/콜백 직렬화 순서에서 마지막으로 반영된 dashboard_page 선택.
  • AppTest: Streamlit streamlit.testing.v1.AppTest의 synthetic runtime 검증. DOM, 실제 browser document navigation, 실제 paint/지연 체감은 검증하지 못한다.
  • real-browser evidence: 실제 browser에서 authenticated session으로 메뉴를 클릭하고 URL/document/body/shell을 관찰해 남기는 증거. AppTest를 대체하지 않으며 AppTest만으로 충족할 수 없는 browser-level 항목에 필수다.

5. 요구사항

REQ-002.01 — 메뉴 정체성

메뉴는 정확히 다음 순서와 label을 유지한다: 월정산, 요약, 자산/마감, 거래내역, 확인필요 큐, 미분류, 분류 규칙, 카테고리, 계좌, Import. selected state는 현재 page와 일치한다.

Impact

  • Interfaces: dashboard_page radio and page query parameter
  • Persistence: none
  • Consumers: dashboard page renderers
  • Migration: none
  • Compatibility: existing labels, order, and selected-state contract
  • Deployment prerequisites: none

REQ-002.02 — URL과 직접 접근

메뉴 선택은 query의 page만 대상 label로 갱신하고 month, account_id, filter 등 sibling query key를 보존한다. 직접 ?page=<known>은 해당 page를 렌더링하고, missing/unknown 값은 요약으로 fallback한다.

Impact

  • Interfaces: browser query parameters
  • Persistence: none
  • Consumers: direct links and page renderers
  • Migration: none
  • Compatibility: sibling query keys and direct page access
  • Deployment prerequisites: none

REQ-002.03 — 연속 화면

메뉴 클릭은 document navigation을 일으키지 않는다. 공통 shell과 background는 유지하고 body만 선택된 renderer의 내용으로 교체한다. history/back-forward와 path URL은 이 요구사항의 판정 범위가 아니다.

Impact

  • Interfaces: Streamlit shell/body rendering
  • Persistence: none
  • Consumers: authenticated dashboard users
  • Migration: none
  • Compatibility: existing shell, background, and path behavior
  • Deployment prerequisites: none

REQ-002.04 — 전환 중 표시

느린 renderer가 실행되는 동안 target page label을 포함한 불러오는 중… loading을 대상 body 영역에 표시하고, renderer 완료 후 loading placeholder를 제거한다.

Impact

  • Interfaces: target body loading state
  • Persistence: none
  • Consumers: dashboard users
  • Migration: none
  • Compatibility: existing renderer output after completion
  • Deployment prerequisites: none

REQ-002.05 — local failure와 retry

target renderer 예외는 공통 shell을 무너뜨리지 않고 body 영역을 generic error와 다시 시도 control로 교체한다. 예외 상세·secret은 UI에 노출하지 않는다.

Impact

  • Interfaces: body error and retry control
  • Persistence: none
  • Consumers: dashboard users and support operators
  • Migration: none
  • Compatibility: shell remains available; secrets remain redacted
  • Deployment prerequisites: none

REQ-002.06 — 최신 선택 우선

연속 메뉴 선택은 serialized callback 순서의 마지막 선택을 query와 body에 반영하며 이전 선택이 마지막 상태를 덮어쓰지 않는다.

Impact

  • Interfaces: serialized menu callback and query state
  • Persistence: none
  • Consumers: page selection state
  • Migration: none
  • Compatibility: latest-selection ordering contract
  • Deployment prerequisites: none

REQ-002.07 — 인증 경계 보존

모든 menu/page dispatch는 REQ-001 gate와 cookie 검증 뒤에만 실행된다. no-cookie/invalid-cookie는 page body에 도달하지 않으며 valid cookie는 기존 Dashboard에 접근한다.

Impact

  • Interfaces: REQ-001 authentication gate and cookie verification
  • Persistence: none
  • Consumers: authenticated dashboard dispatch
  • Migration: none
  • Compatibility: REQ-001 expiry, rotation, cleanup, and logout behavior
  • Deployment prerequisites: existing REQ-001 settings

REQ-002.08 — 금융 page 회귀 없음

요약, 자산/마감, 분류 규칙, 확인필요 큐, 월정산의 기존 synthetic fixture DB 핵심 내용과 기존 page query 계약을 유지한다.

Impact

  • Interfaces: existing page/query contracts
  • Persistence: existing synthetic fixture DB reads and writes
  • Consumers: financial page renderers
  • Migration: none
  • Compatibility: existing financial calculations and gateway semantics
  • Deployment prerequisites: existing fixture and page setup

REQ-002.09 — 운영 control 회귀 없음

refresh control은 기존 clear_cache callable 계약을 유지하고, 메뉴 전환은 cache-clear 동작을 변경하지 않는다.

Impact

  • Interfaces: clear_cache callable and refresh control
  • Persistence: none
  • Consumers: dashboard operators
  • Migration: none
  • Compatibility: existing cache-clear behavior
  • Deployment prerequisites: none

6. 제약과 불변조건

  • dashboard/app.py의 auth gate와 page dispatch는 유지하며 인증 전에 DB path를 resolve하지 않는다.
  • 메뉴 클릭은 full document reload 또는 path navigation을 추가하지 않는다.
  • body 교체는 stable st.empty container 안에서 수행하며 공통 shell/background를 삭제하지 않는다.
  • loading/error/retry는 target body에 국소적으로 표시하고 generic error 외 renderer exception 내용을 공개하지 않는다.
  • query update는 page key만 변경하며 sibling page-specific key를 삭제하거나 정규화하지 않는다.
  • REQ-001의 auth/cookie/logout, financial gateway/page, cache-clear, MCP 및 SQLite semantics는 변경하지 않는다.

7. 인수 기준

각 기준은 하나의 명시된 test/evidence target으로 판정한다. AppTest는 synthetic runtime 판정이며 real-browser evidence가 필요한 기준을 대신하지 않는다.

REQ-002.01-AC01 — label/order/selected

Cases: positive, unchanged-state

State Invariants: labels/order and selected state remain exact.

판정 기준

정확한 10개 label과 순서가 radio options로 전달되고 dashboard_page selected state가 유지된다.

검증

tests/test_dashboard_menu_transition.py::test_dashboard_menu_labels_and_order_are_preserved

검증 분류

  • 수준: unit
  • 백엔드: pytest monkeypatch
  • 증거: radio options, key, label visibility assertion

REQ-002.02-AC01 — query와 fallback

Cases: positive, boundary, unchanged-state

State Invariants: only page changes; sibling query keys remain unchanged.

판정 기준

callback은 page만 갱신하고 sibling key를 보존하며, missing/unknown은 요약, known direct query는 요청 page를 선택한다.

검증

tests/test_dashboard_menu_transition.py::test_sidebar_selection_updates_only_page_query_parameter, tests/test_dashboard_menu_transition.py::test_missing_or_unknown_page_falls_back_to_overview, tests/test_dashboard_menu_transition.py::test_direct_page_query_access_renders_requested_page

검증 분류

  • 수준: unit/integration
  • 백엔드: pytest monkeypatch
  • 증거: exact query mapping and selected renderer assertion

REQ-002.03-AC01 — body-only transition

Cases: positive, unchanged-state

State Invariants: document, shell, and background remain stable; body changes only.

판정 기준

실제 browser에서 authenticated menu click 후 document URL path와 full-document identity가 바뀌지 않고 공통 sidebar/background가 남으며 target body만 바뀐다. history/back-forward와 path URL은 판정하지 않는다.

검증

Required real-browser evidence: docs/evidence/issue-9-dashboard-menu-transition/의 authenticated 요약 → 분류 규칙 native click 연속 frame, screenshot, DOM, URL, document/sidebar identity와 background 관찰. manifest.json은 정확한 working-tree file hash, runtime viewport·interval·환경·제약, artifact hash 및 validator exit code를 기록한다. 이 실행은 local Chrome 부재 때문에 Playwright MCP browser runner로 수집했으며, 재현 가능한 local fail-closed harness는 scripts/streamlit_browser_evidence.py --mode transition과 tests/test_streamlit_browser_evidence.py로 유지한다. AppTest companion: tests/test_dashboard_menu_transition.py::test_streamlit_menu_click_updates_body_and_preserves_page_query_siblings.

검증 분류

  • 수준: browser evidence + integration companion
  • 백엔드: real browser, Streamlit AppTest
  • 한계: AppTest는 실제 document navigation, browser paint, focus/scroll, network request, perceived continuity를 증명하지 못한다.

REQ-002.04-AC01 — target loading

Cases: positive, boundary

State Invariants: loading appears before completion and is removed after rendering.

판정 기준

slow renderer 동안 target label loading이 먼저 표시되고 완료 후 placeholder가 제거된다.

검증

tests/test_dashboard_menu_transition.py::test_slow_transition_clears_previous_body_and_shows_target_loading; real-browser frames: docs/evidence/issue-9-dashboard-menu-transition/browser-observations.json

검증 분류

  • 수준: unit + browser evidence
  • 백엔드: pytest fake Streamlit placeholder, authenticated Playwright browser
  • 증거: ordered event list와 50 ms 연속 frame에서 loading=true, previous_body_visible=false, 최종 loading=false
  • 한계: browser evidence는 실제 authenticated transition을 50 ms 간격으로 표본화했으며 loading은 2개 frame에서 관찰됐다. 표본 사이의 모든 순간을 보장하지 않는다.

REQ-002.05-AC01 — local error/retry

Cases: negative, positive

State Invariants: shell remains intact; renderer details and secrets are not exposed.

판정 기준

renderer 예외가 generic error/retry body로 국소 대체되고 예외 상세가 노출되지 않는다.

검증

tests/test_dashboard_menu_transition.py::test_body_error_is_local_and_retry_rerenders_target

검증 분류

  • 수준: unit
  • 백엔드: pytest monkeypatch
  • 증거: error text, retry event, secret-detail absence assertion

REQ-002.06-AC01 — latest selection

Cases: concurrency, unchanged-state

State Invariants: latest serialized selection is final.

판정 기준

연속 선택 거래내역 → 자산/마감 → Import 후 query가 마지막 Import이고 sibling key가 보존된다.

검증

tests/test_dashboard_menu_transition.py::test_rapid_menu_clicks_commit_latest_selection_only

검증 분류

  • 수준: unit
  • 백엔드: pytest monkeypatch
  • 증거: final query mapping

REQ-002.07-AC01 — auth regression

Cases: negative, positive

State Invariants: auth gate precedes DB/page dispatch; cookie semantics remain REQ-001.

판정 기준

valid cookie가 기존 Dashboard를 열고 cookie가 session state에 저장되지 않으며 gate rejection은 DB/page dispatch 전에 종료된다.

검증

tests/test_dashboard_authentication_app.py::test_valid_cookie_allows_dashboard_and_is_not_stored_in_session_state, tests/test_dashboard_authentication_app.py::test_main_does_not_resolve_database_or_dispatch_when_authentication_rejects

검증 분류

  • 수준: integration regression
  • 백엔드: Streamlit AppTest, synthetic fixture DB
  • 증거: authenticated body and pre-gate forbidden DB sentinel

REQ-002.08-AC01 — finance page regression

Cases: positive, unchanged-state

State Invariants: existing financial page results and query contracts remain unchanged.

판정 기준

기존 핵심 금융 page의 expected text와 synthetic fixture DB 결과가 유지된다.

검증

tests/test_dashboard_app.py::test_streamlit_apptest_core_pages_use_synthetic_fixture_db

검증 분류

  • 수준: regression integration
  • 백엔드: Streamlit AppTest, synthetic SQLite
  • 증거: page expectation and metric assertions

REQ-002.09-AC01 — cache-clear regression

Cases: positive, unchanged-state

State Invariants: clear_cache remains callable and menu transition does not alter it.

판정 기준

refresh control이 callable clear_cache 계약을 유지한다.

검증

tests/test_dashboard_menu_transition.py::test_refresh_control_preserves_cache_clear_contract

검증 분류

  • 수준: regression unit
  • 백엔드: pytest
  • 증거: callable/name assertion

Acceptance Criteria canonical fields

Each Acceptance Criterion has explicit Cases and State Invariants in addition to the existing Korean verification text.

Acceptance Criterion Cases State Invariants
REQ-002.01-AC01 positive, unchanged-state labels/order and selected state remain exact
REQ-002.02-AC01 positive, boundary, unchanged-state only page changes; sibling query keys remain unchanged
REQ-002.03-AC01 positive, unchanged-state document, shell, and background remain stable; body changes only
REQ-002.04-AC01 positive, boundary loading appears before completion and is removed after rendering
REQ-002.05-AC01 negative, positive shell remains intact; renderer details and secrets are not exposed
REQ-002.06-AC01 concurrency, unchanged-state latest serialized selection is final
REQ-002.07-AC01 negative, positive auth gate precedes DB/page dispatch; cookie semantics remain REQ-001
REQ-002.08-AC01 positive, unchanged-state existing financial page results and query contracts remain unchanged
REQ-002.09-AC01 positive, unchanged-state clear_cache remains callable and menu transition does not alter it

8. 오류 및 충돌 계약

인증 실패는 항상 REQ-001 gate가 우선하며 메뉴·query로 우회할 수 없다. renderer 실패는 해당 body만 generic error/retry로 대체한다. 빠른 선택은 Streamlit serialized callback 순서를 따르며 마지막 serialized selection이 최종 상태다. history/back-forward와 path URL은 요구하지 않는다.

9. 데이터 및 인터페이스 계약

  • dashboard_page is the canonical selected menu field; page is the only query field written by menu selection.
  • month, account_id, filter, and other sibling query keys are preserved verbatim.
  • Body loading, error, retry, and renderer output are local to the stable body container; shell/background are not replaced.

10. 하위호환성

  • Authentication expiry, rotation, invalid-cookie cleanup, and explicit logout remain governed by REQ-001.05-AC01, REQ-001.07-AC01, REQ-001.08-AC01, and REQ-001.09-AC01.
  • Existing exact tests remain the authority: tests/test_dashboard_persistent_authentication.py::test_token_expiry_is_absolute_and_not_sliding, tests/test_dashboard_persistent_authentication.py::test_tampering_and_rotations_invalidate_token, and tests/test_dashboard_auth_server.py::test_logout_clears_cookie_with_matching_scope.
  • Menu/query reruns/rendering do not initiate or replay financial writes or external calls. Financial writes and external calls remain behind explicit page user actions; this adds no new idempotency contract.

11. 검증 계획

  • Menu transition tests and required browser evidence verify REQ-002 criteria; REQ-001 authentication tests above verify expiry, rotation, and logout regressions.

Test Traceability Contract

Test definitions reference the exact Acceptance Criterion IDs and execution evidence records revision, commit, environment, and result separately.

12. 추적성

  • 근거 이슈: #9
  • 구현 PR: #10
  • 관련 설계 문서: docs/project-structure.md, docs/runtime-flow.md
  • 관련 requirement: REQ-001
  • 구현 진입점: dashboard/app.py::main, dashboard/common.py::render_sidebar_nav, dashboard/common.py::validate_dashboard_page, dashboard/common.py::render_dashboard_body, dashboard/common.py::_sync_dashboard_page_query
  • 검증 파일: tests/test_dashboard_menu_transition.py, tests/test_streamlit_browser_evidence.py, tests/test_dashboard_app.py, tests/test_dashboard_authentication_app.py
  • browser evidence 도구: scripts/streamlit_browser_evidence.py --mode transition

13. 확정된 결정

  • Keep the authenticated shell and background stable while replacing only the body.
  • Preserve REQ-001 authentication semantics and keep financial writes/external calls behind explicit page actions.

14. Open Questions

  • 없음

15. 승인 기록

  • 상태: approved
  • 승인 주체: existing requirement approval
  • 승인 근거: REQ-002 revision 1.0