Runtime Flow — Dashboard 관리자 인증
목적과 범위
ASGI startup부터 login, token restoration, invalid-cookie cleanup, explicit logout까지의 실행 순서와 상태 계약을 정의한다.
- 포함 범위: config, HTTPS routes, cookie verification, Streamlit gate, cleanup/deletion
- 제외 범위: MCP request authentication, DB session/token registry, per-token revocation
- 시작 조건: trusted ASGI process receives request
- 성공 종료 상태: authenticated Dashboard page executes
- 실패 종료 상태: matching cookie deletion and unauthenticated login page
흐름
startup — ASGI startup
- 시작 이벤트: process startup
- 선행조건: deployment injects configuration without recording values
- 실행 방식: synchronous startup/request handling
- 트랜잭션·영속성 경계: no auth persistence; existing financial SQLite is untouched
| 단계 ID |
실행 주체 |
시작 조건·입력 |
처리 |
읽기·쓰기 상태 |
외부 호출 |
성공 시 다음 단계 |
실패 시 전이 |
startup-01 |
Uvicorn |
process command |
load dashboard.server:app |
process memory only |
none |
startup-02 |
startup-fail |
startup-02 |
ASGI app |
app loaded |
mount auth routes and Streamlit runtime |
route table only |
none |
gate-01 |
startup-fail |
login — Credential login
- 시작 이벤트: same-origin HTTPS form POST
- 선행조건: valid trusted scheme, origin and bounded body
- 실행 방식: synchronous request
- 트랜잭션·영속성 경계: no DB transaction; cookie is browser state
| 단계 ID |
실행 주체 |
시작 조건·입력 |
처리 |
읽기·쓰기 상태 |
외부 호출 |
성공 시 다음 단계 |
실패 시 전이 |
login-01 |
auth server |
POST /api/auth/login |
validate scheme/origin/body |
request only |
none |
login-02 |
login-reject |
login-02 |
authentication |
validated form |
load three settings, fail closed |
server memory |
secret provider/environment |
login-03 |
config-fail |
login-03 |
authentication |
configured settings |
constant-time compare ID/password |
no persistent write |
none |
login-04 |
login-fail |
login-04 |
authentication |
valid credential |
issue exactly v, sub=dashboard-admin, iat, exp, jti; fix iat/exp at login success for default 24 hours or remember_me=on 30 days |
server memory |
none |
login-05 |
login-fail |
login-05 |
auth server |
signed token |
set hardened cookie with selected absolute expiry and redirect; later activity never reissues or extends it |
browser cookie write |
response |
gate-01 |
login-fail |
restore — Existing cookie restoration
- 시작 이벤트: new request/session with browser cookie
- 선행조건: cookie present or absent; current configuration available
- 실행 방식: synchronous gate
- 트랜잭션·영속성 경계: no server-side session; financial DB begins only after gate success
| 단계 ID |
실행 주체 |
시작 조건·입력 |
처리 |
읽기·쓰기 상태 |
외부 호출 |
성공 시 다음 단계 |
실패 시 전이 |
gate-01 |
dashboard app |
page startup |
call authentication before DB path/page dispatch |
no DB access |
none |
gate-02 |
unauthenticated |
gate-02 |
authentication |
current config and cookie |
verify signature, exact v/sub=dashboard-admin/iat/exp/jti claims, current admin-ID/password/signing-secret binding and absolute exp; never refresh or extend on restoration, rerun or activity |
no session or token write |
none |
dashboard-01 |
cleanup-01 |
dashboard-01 |
dashboard app |
accepted token |
resolve DB path and dispatch requested page |
existing SQLite reads/writes |
gateway/page code |
authenticated |
dashboard-fail |
cleanup — Invalid cookie cleanup
- 시작 이벤트: gate rejects malformed, expired, tampered, claim-invalid, or config-failure cookie
- 선행조건: same-origin HTTPS cleanup request
- 실행 방식: synchronous request
- 트랜잭션·영속성 경계: no DB or token registry write
| 단계 ID |
실행 주체 |
시작 조건·입력 |
처리 |
읽기·쓰기 상태 |
외부 호출 |
성공 시 다음 단계 |
실패 시 전이 |
cleanup-01 |
browser/auth gate |
invalid cookie |
navigate to GET /api/auth/cleanup |
request only |
auth route |
cleanup-02 |
cleanup-reject |
cleanup-02 |
auth server |
same-origin HTTPS Referer |
emit matching deletion (Max-Age=0) and root redirect |
browser cookie deletion |
response |
unauthenticated |
cleanup-reject |
logout — Explicit logout
- 시작 이벤트: user submits logout form
- 선행조건: same-origin HTTPS POST
- 실행 방식: synchronous request
- 트랜잭션·영속성 경계: no financial DB change and no per-token revocation
| 단계 ID |
실행 주체 |
시작 조건·입력 |
처리 |
읽기·쓰기 상태 |
외부 호출 |
성공 시 다음 단계 |
실패 시 전이 |
logout-01 |
browser |
POST /api/auth/logout |
validate same-origin HTTPS |
request only |
none |
logout-02 |
logout-reject |
logout-02 |
auth server |
validated request |
matching deletion and root redirect |
browser cookie deletion |
response |
unauthenticated |
logout-reject |
실패와 복구
| 대상 단계 |
실패 조건 |
추가 쓰기 중단 |
재시도 계약 |
중복 방지 |
보상·수동 복구 |
최종 상태 |
login-02 |
missing/empty/read-error/short secret |
yes |
fix deployment config |
no cookie |
operator injects secret |
config-fail |
login-03 |
wrong ID/password |
yes |
retry after generic error and 1s delay |
no lock |
external rate limit |
login-fail |
gate-02 |
expired, malformed/tampered claims, or admin-ID/password/signing-secret rotation failure |
yes |
cleanup then login |
matching deletion |
user logs in again |
unauthenticated |
cleanup-02 |
non-HTTPS/cross-origin |
yes |
retry same origin |
deletion is idempotent |
browser clears manually if needed |
cleanup-reject |
logout-02 |
non-HTTPS/cross-origin |
yes |
retry same origin |
deletion is idempotent |
browser clears manually if needed |
logout-reject |
동시성과 순서
- 동시 실행 허용 여부: independent requests allowed; no application-wide auth lock
- 잠금·직렬화 단위: none for authentication; existing SQLite rules remain for financial writes
- 순서 보장: config/cookie gate precedes DB path, gateway and page dispatch
- 충돌 검출·처리: token is stateless; password/signing-secret/admin-ID rotation invalidates old claims
- 만료 불변조건: login 성공 시 고정한
iat와 exp는 복원·rerun·활동 동안 바뀌지 않으며 token을 재발급하거나 만료를 연장하지 않음
- rotation 불변조건: admin ID, password 또는 signing secret 변경은 이전 설정으로 발급한 모든 token을 무효화하고
cleanup-01로 전이
관찰 가능성
| 신호 종류 |
이름 |
발생 단계·조건 |
상관 식별자 |
진단 속성 |
민감정보 처리 |
| event log |
authentication_required |
gate-01 rejects |
non-sensitive correlation ID |
event class only |
no cookie/token/reason |
| event log |
login_succeeded |
login-05 |
non-sensitive correlation ID |
TTL class only |
no credential/token |
| event log |
login_failed |
login-03 |
non-sensitive correlation ID |
generic failure class |
no ID/password |
| event log |
cleanup |
cleanup-02 |
non-sensitive correlation ID |
generic cleanup class |
no cookie header |
| event log |
logout |
logout-02 |
non-sensitive correlation ID |
operation result |
no token/cookie value |
검증
- 정상 흐름: auth server tests plus loopback HTTPS login and fresh session restoration
- 실패 흐름: configuration, wrong credential, malformed/tampered/expired cookie and origin rejection tests
- 경계 흐름: TTL boundary, rotation, oversized token, same-host different-port origin
- 동시성 흐름: independent failed submissions and no application lock; ingress rate-limit configuration review
- 운영 진입점과 기대 결과:
uvicorn dashboard.server:app --host 0.0.0.0 --port 8501; valid HTTPS reaches login or authenticated page, invalid cookie receives matching deletion before unauthenticated page
메뉴 전환 — REQ-002
인증 gate와 기존 dashboard-01 page dispatch의 선행 순서는 변하지 않는다. valid cookie를 통과한 뒤에만 menu transition flow가 실행되며, auth 실패는 기존 cleanup/unauthenticated 흐름으로 종료된다.
transition — authenticated body replacement
- 시작 이벤트: authenticated browser selects a value in
st.radio(key="dashboard_page")
- 선행조건:
gate-02 success; current page/query resolved
- 실행 방식: Streamlit callback and rerun, no document/path navigation
- 트랜잭션·영속성 경계: no new persistence; existing financial SQLite rules unchanged
| 단계 ID |
실행 주체 |
시작 조건·입력 |
처리 |
읽기·쓰기 상태 |
외부 호출 |
성공 시 다음 단계 |
실패 시 전이 |
transition-01 |
dashboard app/common |
authenticated selected menu |
render_sidebar_nav reads exact 10 options and selected state |
session state dashboard_page |
Streamlit radio callback |
transition-02 |
dashboard-fail |
transition-02 |
common callback |
selected dashboard_page |
write query page only; preserve sibling query keys |
browser query state |
Streamlit query params |
transition-03 |
transition-03 |
transition-03 |
dashboard app |
validated page |
open stable st.empty body, show target loading, invoke target renderer |
body placeholder only; existing DB reads/writes |
page/gateway code |
transition-04 |
transition-error |
transition-04 |
dashboard app |
renderer completed |
remove target loading and leave target body; shell/background remain |
body replacement only |
none |
authenticated |
dashboard-fail |
transition-error |
dashboard app |
renderer exception |
clear partial body and show generic error/retry locally |
body error state only |
none |
retry reruns target |
authenticated with shell intact |
transition invariants
- known direct
?page= selects that page; missing/unknown selects 요약.
- serialized rapid selections commit the latest selection only.
- menu transition never runs before auth and never changes cookie/logout/DB schema/MCP semantics.
- menu/query reruns and rendering do not initiate or replay financial writes or external calls; those remain behind explicit page user actions, with no new idempotency contract.
- history/back-forward and path URL behavior are explicitly outside this flow.
transition verification boundary
tests/test_dashboard_menu_transition.py provides exact AppTest/unit evidence for labels, query preservation, fallback/direct access, loading, local error, latest selection, and cache-clear. tests/test_dashboard_app.py::test_streamlit_apptest_core_pages_use_synthetic_fixture_db and tests/test_dashboard_authentication_app.py::test_valid_cookie_allows_dashboard_and_is_not_stored_in_session_state cover finance/auth regressions. AppTest is synthetic and cannot establish actual browser document continuity, paint timing, focus/scroll, or network behavior; scripts/streamlit_browser_evidence.py --mode transition의 authenticated HTTPS frame/DOM/document/shell evidence가 REQ-002.03-AC01에 필수다. tests/test_streamlit_browser_evidence.py는 이 manifest가 실제 teardown 이후에만 성공하고 document navigation, shell identity drift, 누락 관찰 또는 secret 포함 시 fail-closed하는지 검증한다.
REQ-003 런타임 흐름
valuation-register — register/select/correct
- 시작 이벤트: account form, MCP call, account/import write with dated evidence
- 선행조건: DB initialized; Dashboard path passed auth gate; account exists
- 실행 방식: synchronous SQLite transaction
- 트랜잭션·영속성 경계: one valuation insert or no write on validation/conflict
| 단계 ID |
실행 주체 |
시작 조건·입력 |
처리 |
읽기·쓰기 상태 |
외부 호출 |
성공 시 다음 단계 |
실패 시 전이 |
valuation-01 |
adapter |
typed request |
delegate shared service |
read account |
none |
valuation-02 |
valuation-fail |
valuation-02 |
account valuation service |
basis/amount/scope |
validate exact integer, date, purpose, loan definition |
no write |
none |
valuation-03 |
valuation-fail |
valuation-03 |
SQLite |
valid payload |
reuse idempotent row or insert append-only row |
account_valuations write |
SQLite |
valuation-04 |
valuation-fail |
valuation-04 |
selector/report |
requested basis |
select verified leaf exact/as_of; warn candidates |
read only |
none |
valuation-success |
valuation-fail |
snapshot-preview-close — preview/conditional close
- 시작 이벤트: assets page or MCP preview/close
- 선행조건: basis date; auth before Dashboard DB; explicit approval for conditional state
- 실행 방식: preview synchronous read; close synchronous atomic write
- 트랜잭션·영속성 경계: preview no write; close writes run and rows together
| 단계 ID |
실행 주체 |
시작 조건·입력 |
처리 |
읽기·쓰기 상태 |
외부 호출 |
성공 시 다음 단계 |
실패 시 전이 |
close-01 |
assets service |
basis/policy |
gather verified account/manual items and warnings |
read accounts/valuations/manual_assets |
none |
close-02 |
close-fail |
close-02 |
Dashboard/MCP |
preview request |
return live authority and status |
no write |
none |
close-end |
close-fail |
close-03 |
operator/service |
explicit close + approval if needed |
enforce conditions and correction reason |
transaction begins |
none |
close-04 |
close-fail |
close-04 |
SQLite |
approved payload |
insert run and immutable snapshot rows |
runs/snapshots write |
SQLite |
close-end |
close-fail |
import-candidate-reconciliation-monthly-ui — propagation
- import updates transactions/account balance then records only dated unverified candidate; reconciliation uses valuation-managed investment without fake transaction; monthly/UI reads shared reports and explicit form actions only.
| 단계 ID |
실행 주체 |
시작 조건·입력 |
처리 |
읽기·쓰기 상태 |
외부 호출 |
성공 시 다음 단계 |
실패 시 전이 |
prop-01 |
import/account write |
real dated balance |
_record_*_valuation_candidate |
account_valuations unverified insert |
parser |
prop-02 |
prop-fail |
prop-02 |
reconciliation service |
account baseline |
calculate signed ledger with provenance; investment verified => VALUATION_MANAGED |
read only |
none |
prop-03 |
prop-fail |
prop-03 |
monthly/UI page |
month/basis query |
read snapshot/report and render |
read only unless explicit button |
Streamlit |
prop-end |
prop-fail |
실패와 복구 추가
| 대상 단계 |
실패 조건 |
추가 쓰기 중단 |
재시도 계약 |
중복 방지 |
보상·수동 복구 |
최종 상태 |
valuation-03 |
idempotency/correction conflict |
yes |
same payload inspect/reuse; changed payload no blind retry |
unique indexes |
operator chooses new correction |
valuation-fail |
close-03 |
missing/future/unverified/unknown or missing approval |
yes |
preview then explicit approval |
close idempotency key |
manual evidence review |
close-fail |
close-04 |
SQLite exception/concurrency |
transaction rollback |
retry same key after lock resolution |
unique run key |
restore from backup if needed |
close-fail |
prop-01 |
no real dated evidence |
yes |
no candidate write |
source hash/date key |
wait for evidence |
prop-end without candidate |
동시성과 순서 추가
- 동시 실행 허용 여부: independent reads; SQLite writes serialized by transaction
- 잠금·직렬화 단위: account valuation/idempotency and snapshot close transaction
- 순서 보장: auth → DB → read/preview → explicit approval → close; latest run selected after correction
- 충돌 검출·처리: unique idempotency/single correction indexes and explicit error codes
관찰 가능성 추가
| 신호 종류 |
이름 |
발생 단계·조건 |
상관 식별자 |
진단 속성 |
민감정보 처리 |
| result/event |
valuation_registered |
valuation-03 success |
request/idempotency key surrogate |
basis/kind/status only |
no source secret |
| result/event |
snapshot_previewed |
close-02 |
request correlation |
basis/status/warning codes |
no account number |
| result/event |
snapshot_closed |
close-04 |
snapshot_run_id |
status/count/formula |
evidence redacted |
| result/event |
valuation_conflict |
validation/idempotency failure |
correlation ID |
error_code only |
no payload secrets |
REQ-003 검증
- 정상 흐름:
tests/test_account_valuations.py, tests/test_asset_snapshots.py, tests/test_contract_regression.py
- 실패 흐름: conflict, conditional approval, validation tests
- 경계 흐름: exact/as_of, stale/carry-forward, correction/re-close, empty fallback
- 동시성 흐름: SQLite unique/idempotency and transaction rollback review
- 운영 진입점과 기대 결과: Dashboard authenticated
자산/마감/계좌, MCP tools; preview leaves row count unchanged, explicit close returns run id