fix(dashboard): address PR review 56
This commit is contained in:
@@ -54,38 +54,119 @@ Issue #9의 Dashboard 메뉴 전환 계약이다. REQ-001의 인증 경계, cook
|
||||
|
||||
메뉴는 정확히 다음 순서와 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하지 않는다.
|
||||
@@ -101,6 +182,10 @@ refresh control은 기존 `clear_cache` callable 계약을 유지하고, 메뉴
|
||||
|
||||
### 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가 유지된다.
|
||||
@@ -117,6 +202,10 @@ refresh control은 기존 `clear_cache` callable 계약을 유지하고, 메뉴
|
||||
|
||||
### 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를 선택한다.
|
||||
@@ -133,6 +222,10 @@ callback은 `page`만 갱신하고 sibling key를 보존하며, missing/unknown
|
||||
|
||||
### 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은 판정하지 않는다.
|
||||
@@ -149,6 +242,10 @@ Required real-browser evidence: `docs/evidence/issue-9-dashboard-menu-transition
|
||||
|
||||
### 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가 제거된다.
|
||||
@@ -162,10 +259,14 @@ slow renderer 동안 target label loading이 먼저 표시되고 완료 후 plac
|
||||
- 수준: 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의 2초 지연은 repository source가 아닌 fixture-only wrapper로 주입한다.
|
||||
- 한계: 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로 국소 대체되고 예외 상세가 노출되지 않는다.
|
||||
@@ -182,6 +283,10 @@ renderer 예외가 generic error/retry body로 국소 대체되고 예외 상세
|
||||
|
||||
### REQ-002.06-AC01 — latest selection
|
||||
|
||||
**Cases**: concurrency, unchanged-state
|
||||
|
||||
**State Invariants**: latest serialized selection is final.
|
||||
|
||||
**판정 기준**
|
||||
|
||||
연속 선택 `거래내역` → `자산/마감` → `Import` 후 query가 마지막 `Import`이고 sibling key가 보존된다.
|
||||
@@ -198,6 +303,10 @@ renderer 예외가 generic error/retry body로 국소 대체되고 예외 상세
|
||||
|
||||
### 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 전에 종료된다.
|
||||
@@ -214,6 +323,10 @@ valid cookie가 기존 Dashboard를 열고 cookie가 session state에 저장되
|
||||
|
||||
### 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 결과가 유지된다.
|
||||
@@ -230,6 +343,10 @@ valid cookie가 기존 Dashboard를 열고 cookie가 session state에 저장되
|
||||
|
||||
### 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` 계약을 유지한다.
|
||||
@@ -244,15 +361,67 @@ refresh control이 callable `clear_cache` 계약을 유지한다.
|
||||
- 백엔드: 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. 추적성
|
||||
## 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`
|
||||
- 관련 요구사항: `REQ-001`
|
||||
- 관련 설계 문서: `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`
|
||||
|
||||
Reference in New Issue
Block a user