본문으로 건너뛰기

transact

transact는 클라이언트의 업무 거래 요청을 수신하고, 거래 계약의 CommandType에 따라 실행 모듈로 라우팅한 뒤 표준 응답을 반환하는 중심 모듈입니다. HandStack에서 화면, API, 배치, workflow가 공통 거래 모델로 만나는 지점입니다.

책임 범위​

  • 거래 계약을 로드하고 ApplicationID|ProjectID|TransactionID|ServiceID 기준으로 실행 대상을 찾습니다.
  • RoutingCommandUri를 사용해 dbclient, graphclient, function, command, prompter로 요청을 전달합니다.
  • 요청 검증, 공개 거래 허용 범위, 환경 구분, 코드 데이터 캐시를 적용합니다.
  • 거래 로그와 집계 데이터를 저장하고 필요 시 logger 모듈로 전송합니다.
  • workflow 계약의 단계 간 입력/출력 매핑과 assertion을 처리하고 단계 실패 시 실행을 중단합니다.
  • 외부 위임 호스트의 서명된 사용자 위임을 기존 Execute 경로에서 검증할 수 있습니다. ModuleConfig.McpDelegation은 기본 비활성화입니다.

주요 API​

메서드경로용도
GET/transact/api/transaction/has거래 계약 존재 여부를 확인합니다.
GET/transact/api/transaction/refresh거래 계약 캐시를 갱신합니다.
GET/transact/api/transaction/retrieve거래 계약 원문 또는 상세 정보를 조회합니다.
GET/transact/api/transaction/meta입력/출력 메타 정보를 반환합니다.
POST/transact/api/transaction/execute단일 거래를 실행합니다.
POST/transact/api/workflow/executeworkflow 거래를 실행합니다.
GET/transact/api/transaction/cache-clear코드 데이터 캐시를 초기화합니다.
GET/transact/api/aggregate/summary거래 집계 요약을 조회합니다.

계약 관리 API 공통 규칙​

transact, dbclient, function, command, graphclient, prompter는 계약을 조회·갱신하는 같은 이름의 관리 API(has, refresh, retrieve, meta)를 가집니다. 경로는 각 모듈 문서의 "주요 API" 표에 있고 파라미터와 인증 규칙은 다음과 같습니다.

API파라미터응답
hasapplicationID, projectID, transactionID, functionID (transact는 functionID 없음)계약이 로드되어 있는지 JSON 불리언
retrieveapplicationID, 선택 projectID, transactionID, functionID계약 원문 또는 상세 정보
meta없음로드된 계약 키 목록
refreshchangeType, filePath, 선택 userWorkID, applicationID변경된 계약 파일을 다시 읽어 캐시를 갱신

transact에는 코드 데이터 캐시 키를 보는 cache-keys, 계약을 base64 JSON으로 조회하는 get, test도 있습니다.

인증: 위 API는 AuthorizationKey가 모듈 설정 AuthorizationKey와 같거나, 호출 IP가 모듈 설정 AllowClientIP(* 포함)에 있으면 통과합니다. 통과하지 못하면 본문 없는 400 Bad Request가 돌아옵니다. 401이 아니라 400이므로 키 불일치와 AllowClientIP 누락을 먼저 확인하세요. AuthorizationKey 값은 호출이 루프백(로컬)이면 쿼리, 폼, 경로 값, 헤더 순으로 찾고, 원격이면 요청 헤더에서만 읽습니다.

  • AllowClientIP의 기본값 *는 개발용입니다. 운영에서는 호출 IP로 좁히세요.
  • transact의 관리 API는 SecurityHardening.LockdownMetadataEndpoints가 true이면 AllowClientIP의 * 와일드카드만으로는 통과하지 못하고, 키가 일치하거나 명시적으로 등록한 IP여야 합니다.
  • refresh는 운영 캐시를 바꾸므로 승인된 환경과 요청 범위에서만 호출합니다. 인증을 우회하려고 AllowClientIP나 공개 거래 범위를 넓히지 마세요.

핵심 구현​

  • Areas/transact/Controllers/TransactionController.cs: 단일 거래 API 진입점입니다.
  • Areas/transact/Controllers/WorkflowController.cs: workflow 실행 진입점입니다.
  • Areas/transact/Controllers/AggregateController.cs: 거래 집계 조회와 moved 상태 관리를 담당합니다.
  • Extensions/TransactClient.cs: 라우팅, 요청 검증, 실행 결과 검증의 핵심 구현입니다.
  • Events/TransactRequestHandler.cs: 모듈 내부 거래 실행 요청을 처리합니다.

계약과 식별자​

계약은 기본적으로 다음 위치에 둡니다.

contracts/transact/{ApplicationID}/{ProjectID}/{TransactionID}.json

거래 ID는 다음 형식입니다.

ApplicationID|ProjectID|TransactionID|ServiceID

거래 계약에는 CommandType, ReturnType, TransactionScope, 입력/출력 모델, 캐시와 검증 정보가 포함됩니다.

단일 거래와 workflow 단계 실행에서 Bearer 토큰의 Variable 항목은 $ 접두사가 붙은 입력 필드로 거래 입력 묶음에 추가됩니다. 요청 데이터맵 입력이 없어도 Variable이 있으면 Bearer 필드용 입력 묶음 하나를 생성합니다. Bearer 토큰의 정책 claim은 # 접두사로 같은 묶음에 추가됩니다.

CommandType 라우팅​

현재 기본 라우팅 대상은 다음과 같습니다.

CommandType실행 모듈기본 URL
Ddbclient/dbclient/api/query
Ggraphclient/graphclient/api/query
Ffunction/function/api/execution
Ccommand/command/api/execution
Pprompter/prompter/api/query

RoutingCommandUri의 key는 다음 형식입니다.

ApplicationID|ProjectID|CommandType|Environment

라우팅 예시는 다음과 같습니다.

{
"HDS|*|D|D": "http://localhost:8421/dbclient/api/query",
"HDS|*|G|D": "http://localhost:8421/graphclient/api/query",
"HDS|*|F|D": "http://localhost:8421/function/api/execution",
"HDS|*|C|D": "http://localhost:8421/command/api/execution",
"HDS|*|P|D": "http://localhost:8421/prompter/api/query"
}

주요 설정​

설정설명
AllowRequestTransactions애플리케이션별 요청 허용 프로젝트 범위입니다.
PublicTransactions인증 없이 공개할 거래 범위입니다.
AvailableEnvironment허용할 실행 환경 구분입니다.
RoutingCommandUriCommandType과 환경별 실행 모듈 URL입니다.
IsValidationRequest분산 캐시 기반 요청 검증 사용 여부입니다.
UseApiAuthorizeAPI 인증 토큰 검사 사용 여부입니다.
IsCodeDataCache, CodeDataCacheTimeout코드/기초 데이터 캐시 설정입니다.
IsTransactAggregate, IsTransactAggregateRolling거래 집계 저장과 롤링 방식입니다.
DynamicWorkflowTransaction, DynamicWorkflowServices동적 workflow 실행 허용 거래와 서비스 범위입니다.

요청 출처 및 API 키 검증​

POST /transact/api/transaction/execute와 POST /transact/api/workflow/execute는 HandStack.Web의 RequestOriginActionFilter([TypeFilter])로 요청 출처를 검사합니다. 설정은 호스트 appsettings.json의 AppSettings:Security:RequestOriginApiAccess입니다.

같은 필터가 모든 모듈의 ManagedController(/{module}/api/managed/*)에도 적용됩니다. 기존 AuthorizationKey/AllowClientIP 검사(IsAllowAuthorization)는 그대로 유지되고, 필터는 그 앞에 추가되는 조건입니다. 원격에서 관리 API를 호출하려면 X-Api-Key가 필요합니다.

"Security": {
"RequestOriginApiAccess": {
"Enabled": true,
"AllowLoopback": true,
"IsPortComparison": false,
"HeaderName": "X-Api-Key",
"AllowedReferers": [],
"ApiKeys": []
}
}
설정기본값설명
Enabledtruefalse이면 검사를 하지 않습니다.
AllowLoopbacktrue127.0.0.1/::1에서 X-Forwarded-For 없이 직접 들어온 요청을 키 없이 허용합니다. dbclient/function 같은 내부 모듈이 BusinessServerUrl(localhost)로 호출하는 경로가 여기에 해당합니다. 리버스 프록시 뒤에서는 false로 두고 내부 호출에도 키를 보내야 합니다.
IsPortComparisonfalsetrue이면 Referer/Origin 비교(동일 도메인, AllowedReferers)에서 호스트와 포트를 모두 비교하고, false이면 포트를 검증하지 않고 호스트만 비교합니다. 프록시 뒤에서 Host 포트가 외부 포트와 달라지는 환경은 false로 둡니다.
HeaderNameX-Api-Key인증키를 담는 헤더 이름입니다. 없으면 Authorization: Bearer <키>도 인정합니다.
AllowedReferers[]동일 도메인 외에 추가로 허용할 출처 목록입니다(예: https://portal.example.com). 호스트와 포트로 비교합니다.
ApiKeys[]허용할 인증키 목록입니다. 상수 시간 비교로 검증합니다.

판정 순서는 다음과 같습니다.

  1. Enabled=false이면 통과합니다.
  2. AllowLoopback=true이고 직접 loopback 접속이면 통과합니다.
  3. Referer(없으면 Origin)의 호스트와 포트가 Request.Host 또는 AllowedReferers와 같으면 통과합니다. syn.$w.executeTransaction을 쓰는 브라우저 호출은 별도 설정 없이 여기서 통과합니다.
  4. 그 외에는 X-Api-Key 또는 Authorization: Bearer의 값이 ApiKeys와 일치할 때만 통과하고, 아니면 401을 반환합니다.

운영 시 주의사항은 다음과 같습니다.

  • 키는 소스나 appsettings.json에 넣지 않고 환경 변수로 주입합니다. 예: AppSettings__Security__RequestOriginApiAccess__ApiKeys__0=<발급한 키>
  • 기본값이 활성이고 ApiKeys가 비어 있으므로, 키를 설정하기 전에는 Postman 같은 외부 프로그램 요청이 401을 받습니다.
  • Referer/Origin은 클라이언트가 위조할 수 있으므로 동일 도메인 허용은 브라우저 편의와 CSRF 완화용이며 강한 인증이 아닙니다. 페이지에 Referrer-Policy: no-referrer를 쓰는 경우 Origin으로 판별합니다.
  • JWT를 Authorization: Bearer로 보내는 프로그램 요청은 값이 ApiKeys와 같지 않으면 이 검사에서 401이 됩니다. 이 경우 X-Api-Key를 함께 보냅니다.
curl -X POST http://localhost:8421/transact/api/transaction/execute \
-H "Content-Type: application/json" \
-H "X-Api-Key: <발급한 키>" \
-d @request.json

Workflow 실행​

workflow는 여러 거래 단계를 하나의 요청으로 묶습니다. 계약 항목, 매핑, 검증 15종은 워크플로 계약, 일반 거래 계약의 항목은 거래 계약 명세에 있습니다. 각 단계의 CommandType이 D, G, F, C, P이면 기존 RoutingCommandUri 규칙으로 실행 모듈에 전달됩니다.

개발자가 확인해야 할 핵심 규칙은 다음과 같습니다.

  • transaction.dataFormat이 비어 있으면 J로 처리하며, J와 T만 허용합니다.
  • environment는 AvailableEnvironment에 포함되어야 합니다.
  • AllowRequestTransactions, PublicTransactions, AccessScreenID 규칙을 통과해야 합니다.
  • X-Workflow-Contract로 일회성 workflow를 보낼 때는 BearerToken과 DynamicWorkflow claim, 서버 설정의 동적 workflow 허용 범위를 모두 만족해야 합니다.
  • InputMappings, OutputMappings, Assertions는 단계 간 데이터 전달과 검증 실패 처리를 결정합니다.

운영 주의사항​

  • transact는 모든 업무 요청의 관문이므로 인증, 공개 거래, 라우팅 범위를 가장 먼저 점검합니다.
  • RoutingCommandUri가 누락되면 해당 CommandType 거래는 실행 모듈을 찾지 못합니다.
  • 거래 로그에는 요청/응답 데이터가 포함될 수 있으므로 IsDataMasking과 로그 보관 정책을 함께 설계합니다.
  • wwwroot의 개발용 테스트 계정 자동 로그인(/wwwroot/api/dev-account/sign-in)이 발급한 요청은 IsDevAutoSignIn claim으로 표시됩니다. TransactionController/WorkflowController는 이 claim을 감지하면 경고 로그를 남기고, AppSettings:IsEnabledDevAutoSignIn이 false이거나 RunningEnvironment가 D가 아닌데도 claim이 존재하면(위조 의심) 요청을 거부합니다.
  • workflow의 assertion과 단계 실패를 검증합니다. 현재 WorkflowController는 전체 단계의 일괄 롤백이나 취소 전파를 보장하지 않으므로 실행 모듈의 시간 제한과 재시도 여부를 별도로 확인합니다.