Files
jarca-ledger-mcp/docs/runtime-flow.md
T

24 KiB

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
  • 시작 이벤트: 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
  • 시작 이벤트: 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

canonical transition and failure semantics

valuation-02 validates principal/interest/fee, source_ref account-scoped identity, parent scope, cyclic/self parent, one child, reason, and key/source mismatch before valuation-03; each failure is no-write with validation_error, idempotency_conflict, or correction_conflict. close-01 computes actual valuation_date, age, carry, verification, reconciliation completeness, investment unavailable, and loan purpose/definition/ambiguity. close-02 returns live authority, close_status, warnings, and exclusions without writing; close-03 records explicit run/approval/correction; close-04 atomically persists immutable rows. Drift, missing approval, unsafe evidence, and SQLite failure transition to close-fail with no partial write.

The close response exposes top-level run, approval, correction, warnings, excluded_items, and carried_items; its nested provenance exposes actual valuation date, age, carry, verification, approval/correction, warnings, and redacted exclusions. Live/closed/timeseries/monthly read models propagate the same meanings in their documented top-level and nested provenance fields. monthly_source_snapshot_id is a read-model alias of snapshot_run_id, not a persistence field. last_balance is external current comparison rather than opening evidence; missing balance_after/opening evidence transitions to INCOMPLETE_CALCULATION. No fake writes are made for unavailable investment or valuation-managed reconciliation.

C13 database lifecycle transitions

auth-before-DB is the first Dashboard boundary. write-first-use-01 explicitly calls init_db() and may migrate. db-read-01 calls read_db() in SQLite mode=ro; a missing database becomes db_not_initialized. db-read-02 succeeds without mkdir, migrate, or commit. An initialized database's schema or SQLite read failure becomes generic db_error, never db_not_initialized, and raw engine details are not exposed.

D06 runtime decision guards

  • Current-cache no rollback: a late historical valuation may update historical authority but cannot roll back the newer current cache (last_balance); current display and historical basis selection are separate decisions.
  • Reconciliation decision: return reconciliation complete only when required ledger/evidence inputs are complete. If required evidence is absent or unreadable, return reconciliation unavailable with provenance and do not infer a balance or create a transaction.
  • Preview drift revalidation: preview is read-only and records the authority/evidence fingerprint observed. Before close writes, revalidate current authority, approval policy, exclusions, carried items, and the preview fingerprint. Drift routes back to preview/review with a stale-preview or conflict decision and no partial write; only a revalidated preview reaches close-04.

The fingerprint input is exactly basis date, selection policy, included and excluded evidence state hashes, warnings (excluding the informational existing-run warning), and candidate state hashes. The preview returns preview_fingerprint; close recomputes it before any insert. A changed authority returns authority_drift, and the transaction produces no partial write.

An idempotent close is replayed only for equal request fingerprints. Replay reconstructs the response from the persisted run/evidence (no replay-only reused payload), while a different payload returns idempotency_conflict. Recursive close metadata is allowlisted and redacted before it reaches Dashboard/MCP.

Dashboard missing-DB reads return stable unavailable db_not_initialized without create/migrate/commit. The missing DB stable unavailable contract is no-create. Initialized read failures return db_error; successful initialized reads are read-only. The initialized DB read failure is db_error and initialized read has no write. Reconciliation requires opening evidence and coverage through the requested basis; otherwise it reports INCOMPLETE_CALCULATION/reconciliation unavailable with provenance, no inferred balance, and no fake transaction.

settlement-draft-create — 월정산 초안 lifecycle (Issue #15)

create → edit → review → approve → finalize

단계 ID 실행 주체 처리 / guard 상태 경계 실패 전이
settlement-draft-create adapter/service Strict month/date/actor/key validation; explicit correction prior run/reason; acquire BEGIN IMMEDIATE; idempotent equal replay; enforce one active draft/month. Persist draft and initial target items only; no snapshot run/rows/close. validation/conflict; rollback
settlement-draft-edit shared service Expected version; targets change only through explicit refresh; item include/exclude and valuation selection audited; mutation clears approval. Increment draft/item versions; retain history/reasons. stale version or invalid scope, no write
settlement-draft-review shared service Read frozen source/valuation evidence, warning and correction-child drift; compute review fingerprint/totals/missing; no auto future selection. Read-only; unverified candidate_amount with authority amount NULL. drift/missing warnings; no authority mutation
settlement-draft-approve authorized caller Require matching current fingerprint/version and explicit actor/reason/reference/flags. Persist approval binding and flags. mismatch/unsafe unknown/rejected evidence rejected
settlement-draft-finalize shared service/SQLite Idempotency persisted-response lookup first; then active/version/approval/fingerprint/drift/correction-parent checks; insert run, rows and completed/link within one BEGIN IMMEDIATE. Atomic immutable close and draft completion. conflict or injected DB failure rolls back all writes

Exact requires same-date verified evidence; carried_before uses verified prior with reason; manual_substitute requires explicit ID and reason, with signed date_difference_days = valuation_date - basis_date. age_days keeps its existing direction/meaning. Corrected valuation children are never followed automatically: explicit reselection then fresh review/approval. Missing and substitution remain orthogonal; manual evidence drift requires explicit refresh. Existing row-only legacy close uses established latest row-group ordering and available run identity; never infer a registry row or fall back to live authority.

failure/recovery and read-only guards

Draft create/update/finalize use transaction-scoped writes; any DB failure rolls back run, rows and completion. Same finalize request returns persisted response, not a replay-only reused field; different request conflicts. Monthly summary and review do not mutate; transaction readiness remains independent. read_db() missing path is db_not_initialized, with no-create/no mkdir/no migrate/no commit. Dashboard gate precedes every protected DB access; existing auth cookie lifecycle and exact menu/query/shell/browser semantics remain unchanged.