Streamlit 사용자 화면 만들기
현재 구현 상태
이 페이지의 app_surface + streamlit discovery, hosted px.client() 주입, authenticated gateway route와 Project별 isolated App Surface runtime은 계약 전용이며 아직 구현되지 않았습니다. 현재 공개 SDK에는 explicit px.Client(workspace=..., project=...)가 있고, Component package의 설치·executor code path는 contract/runtime 감사 대상으로 존재하지만 production third-party admission 기능이 아닙니다. production Flow reader는 Component를 read-only unsupported로 표시합니다. exact ProjectScope data-path isolation은 구현됐지만 현재 third-party Component activation(install admission·execution)은 Project authorization과 execution-trust closure가 닫힐 때까지 차단합니다. 아래 surface metadata와 hosted lifecycle 예제는 향후 구현 목표입니다.
먼저 Flow와 화면을 연결하기
Streamlit은 엔지니어가 입력값을 넣고 계산 결과를 바로 확인하는 전용 사용자 화면을 만들 때 사용합니다. PipelineXLab SDK가 계산, 타입·단위, 권한, 실행과 결과 출처를 담당하고 Streamlit은 widget과 화면 배치만 담당합니다.
SDK Adapter 체계의 목표 계약은 Streamlit을 app_surface category의 streamlit format으로 등록합니다. Component V2 Canvas는 host-owned component.declarative@2만 사용하며 rich editor는 RFC-016의 component-rich-surface-declaration@1이 소유합니다.
향후 Streamlit UI Extension은 parameter form, data grid와 metric board 같은 Canvas용 @px.component도 함께 제공할 수 있습니다. Component contribution과 standalone Streamlit surface를 서로 다른 category·target으로 발견하는 동작은 아직 contract-only입니다.
Streamlit에서는 기존 Flow를 import하고 widget 값을 exact portKey keyword로 전달합니다. PXFLOW Studio, 현재 지원되는 Function·product-built first-party Node, MCP와 Streamlit이 같은 flowKey, nodeKey와 portKey를 사용합니다.
필요한 화면 유형 고르기
| 필요한 결과 | 선택할 화면 |
|---|---|
| 본문·작성값·표와 Flow Result를 한 문서로 작성·검토 | Report Workbench |
| 입력 중심의 간단한 계산기나 업무용 대시보드 | Streamlit app |
| 계산 순서와 연결을 Flow Canvas에서 편집 | PXFLOW Studio |
| 특정 업무에 맞는 rich editor | RFC-016의 component-rich-surface-declaration@1 소유 |
Report Workbench와 Streamlit은 같은 Flow의 public input과 result를 사용합니다. Report는 연결을 .pxreport에 저장하고, Streamlit은 SDK client로 exact Flow revision을 실행합니다. 현재 지원되는 Function과 product-built first-party Node만 같은 Run에 참여합니다. third-party Component의 Validate/Run은 위 closure 전까지 거부합니다.
전체 예제
먼저 계산과 Flow를 일반 SDK package에 정의합니다.
# structural_checks/flows/bearing_review.py
from pipelinexlab import px
class BearingResults(px.Results):
utilization: float
@px.function(
key="bearing_check",
version="1.0.0",
description="Checks bearing pressure against the design resistance.",
)
def bearing_check(
load: float,
area: float,
resistance: float,
) -> BearingResults:
return (load / area) / resistance
flow = px.Flow(
"bearing_review",
label="Bearing check",
description="Runs the bearing pressure check.",
)
load = flow.input("load", float, unit="kN", description="Factored vertical load.")
area = flow.input("area", float, unit="m2", description="Effective bearing area.")
resistance = flow.input(
"resistance",
float,
unit="kN/m2",
description="Design bearing resistance.",
)
check = flow.node("bearing_check", bearing_check)
flow.connect(load, check.inputs.load)
flow.connect(area, check.inputs.area)
flow.connect(resistance, check.inputs.resistance)
flow.result("utilization", check.results.utilization)Streamlit에서는 이 Flow를 import한 뒤 화면 입력을 exact port keyword로 전달합니다.
# structural_checks/apps/bearing.py
import streamlit as st
from pipelinexlab import px
from structural_checks.flows.bearing_review import flow as bearing_review
client = px.Client(workspace="engineering", project="bridge_project")
st.title("Bearing check")
load = st.number_input("Factored load (kN)", min_value=0.0, value=1850.0)
area = st.number_input("Effective area (m²)", min_value=0.001, value=0.72)
resistance = st.number_input(
"Design resistance (kN/m²)",
min_value=0.001,
value=3500.0,
)
if st.button("Run", type="primary"):
run = client.run(
bearing_review,
load=load,
area=area,
resistance=resistance,
)
snapshot = run.wait()
st.metric("Utilization", f"{snapshot.results.utilization:.3f}")현재 SDK에서는 px.Client(workspace="...", project="...")를 명시적으로 만듭니다. PipelineXLab이 로그인 session과 Project 범위를 주입하는 px.client() 편의 API는 hosted App Surface와 함께 구현할 계획이며 지금은 호출할 수 없습니다. access token, server URL, workspace path와 내부 artifact ID를 host configuration에서 관리하는 경계도 같은 계획에 속합니다.
계획된 Package surface 선언
목표 계약에서 Streamlit source는 같은 Python package release가 소유하고, pyproject.toml의 공통 App Surface table에 semantic key, format과 import module을 선언합니다. .pxflow는 Flow 연결 구조와 interface를 소유합니다.
[tool.pipelinexlab.surfaces.bearing_check]
format = "streamlit"
format-contract = 1
title = "Bearing check"
description = "Interactive bearing pressure check."
entry = { kind = "python_module", module = "structural_checks.apps.bearing" }
targets = [{ kind = "flow", key = "bearing_review" }]
host-capabilities = []- table 이름의
bearing_check가 stablesurfaceKey입니다. surfacestable이adapterCategory="app_surface"를 결정하고format이 그 아래의 화면 형식을 선택합니다.format-contract는 Streamlit 설정과 lifecycle 계약 version입니다. Streamlit library exact version은 dependency lock이 별도로 고정합니다.entry.module에는 package 안의 import module을 씁니다.targets는 이 화면에서 사용할 수 있는 typed target allowlist이며 Runtime은 Project 권한을 별도로 확인합니다.host-capabilities는 App Surface가 host에 요청할 수 있는 기능의 상한입니다. 빈 목록이 기본입니다.- Function, port와 unit은 target Flow descriptor에서 읽습니다.
- surface source와 dependency는 package lock과 descriptor digest에 고정합니다. 현재 Component installer는 trust authority 없이 signed input을 기록하지 않고, 명시적으로 수용한 unsigned Component만
absent·not-checked로 기록합니다. marketplace admission에서 publisher signature와 revocation을 검증한 release만 verified라고 부릅니다.
개발 중에는 로그인된 Local 환경에서 표준 Streamlit 개발 서버로 화면을 확인할 수 있습니다.
streamlit run src/structural_checks/apps/bearing.py브라우저에서 Bearing check 제목, 세 입력 widget과 Run 버튼이 보여야 합니다. 값을 입력하고 Run을 누르면 일반 PXFLOW Run이 생성되고 Utilization metric에 snapshot.results.utilization 값이 표시됩니다.
목표 Local·SaaS App Surface host는 같은 module을 Project별 격리 runtime에서 시작하고 인증된 gateway route만 브라우저에 노출합니다. 이 Project-scoped isolation과 launcher는 아직 구현되지 않았습니다.
입력 연결 규칙
client.run(target, **inputs)의 keyword가 유일한 input mapping입니다.
run = client.run(
bearing_review,
load=load,
area=area,
resistance=resistance,
)- keyword는 target Flow의 exact
portKey와 같아야 합니다. - type, unit, nullable, default와 constraints는 Flow descriptor에서 읽습니다.
- 화면 label은 자유롭게 번역하고 연결 주소에는 exact
portKey를 사용합니다. - 누락되거나 알 수 없는 keyword는 실행 전에 validation error입니다.
- input mapping은
st.session_state, widget 순서와 화면 위치에서 독립적입니다.
표 입력은 @px.record row와 px.Table 구조로 만들고 dataframe column을 exact field key에 명시적으로 매핑합니다.
cases = [
LoadCase(
case_key=row["case_key"],
permanent_g=row["permanent_g"],
variable_q=row["variable_q"],
)
for row in edited_rows
]
run = client.run(girder_design, span=span, design_cases=cases)실행과 결과 규칙
client.run(...)은 target을 고정된 Flow revision으로 resolve하고 일반 PXFLOW Run을 요청합니다. 계산은 격리된 PXFLOW Runtime에서 실행됩니다.
run = client.run(bearing_review, load=load, area=area, resistance=resistance)
snapshot = run.wait()run은 진행, 취소와 복구에 사용하는 durable Run handle입니다.wait()는 terminal 상태까지 기다린 뒤 성공하면 immutableResultSnapshot을 반환합니다.- named result는
snapshot.results.<port_key>로 읽습니다. - app 재실행이나 browser refresh 뒤에도 기존 immutable
ResultSnapshot을 다시 표시할 수 있습니다. - network retry는 SDK client가 같은 command의 idempotency key를 유지합니다.
- 오래 걸리는 작업은 Run handle 상태와 cancel 동작을 표시합니다.
Streamlit session에는 widget 상태, 선택한 runRef와 표시할 snapshotRef를 둡니다. 결과 원본과 실행 ledger는 PXFLOW Runtime이, 권한은 Project ACL이 소유합니다.
계획된 보안과 배포 경계
- App Surface runtime은 사용자 session, Project ACL과 license를 모두 검사합니다.
- Flow가 선언한 file, network, secret과 GPU capability는 Runtime에서 다시 승인합니다.
- token, secret과 host path는 runtime의 protected storage와 redacted log 경계 안에 둡니다.
- browser에는 gateway가 발급한 app route만 보이며 내부 process port와 filesystem 위치는 숨깁니다.
- Local과 SaaS는 같은
app_surface + streamlitdescriptor를 사용하고 Desktop/Web Host Adapter와 실제 process placement만 다르게 둡니다. - Runtime은 package와
targetsallowlist에 포함된 typed target만 resolve합니다.
AI와 MCP가 이해하는 방식
AI는 먼저 adapterCategory="app_surface", formatKey="streamlit"과 surfaceKey를 읽고, FunctionDescriptor와 Flow direct object에서 input, result, unit과 설명을 읽습니다. Streamlit surface는 typed targets로 사용자 화면에 노출할 Flow를 지정합니다.
AI는 flowKey와 exact input/result portKey를 사용해 기존 MCP 실행 경로를 호출합니다.
배포 검증에서 차단할 구현
- Streamlit surface마다 같은 계산 함수를 복사합니다.
st.session_state["result"]같은 특별한 key를 전체 시스템 연결 규약으로 사용합니다.- Streamlit widget label을 정규화해 port에 자동 연결합니다.
- surface process에서 decorated Flow를 일반 Python 함수처럼 직접 호출합니다.
- surface 자체를 PXFLOW Node로 저장하거나 iframe URL을
.pxflow에 기록합니다. - Streamlit 전용 result JSON을 만들어 Report와 MCP가 다시 변환하게 합니다.
- source에 access token, SaaS URL 또는 Local 절대 경로를 넣습니다.
streamlit을 별도 최상위 adapter category로 등록합니다.
구현 완료 gate
다음 조건을 모두 만족하면 같은 SDK 계산을 사용하는 Streamlit 화면으로 볼 수 있습니다.
- surface가 설치된 exact Flow를 import합니다.
- 모든 입력이 exact
portKeykeyword로 전달됩니다. - 실행이 일반 Run과 immutable
ResultSnapshot을 만듭니다. - PXFLOW Studio와 MCP에서 같은 입력으로 실행했을 때 같은 named result를 얻습니다.
- browser refresh 뒤에도 Run 출처와 결과를 다시 찾을 수 있습니다.
- token, internal port와 host path가 runtime 보호 경계 안에 있습니다.
공통 category·format 규칙은 SDK Adapter 체계, Component 작성은 Component 만들기, 공통 SDK 문법은 Python SDK 문법, 실행 상태와 결과 복구는 실행과 결과를 참고하세요.