본문으로 건너뛰기

운영 호스트

업무 화면과 거래를 처리하는 호스트는 ack입니다. 이 문서는 나머지 호스트(rdy, agent, deploy, forbes)의 역할, 포트, 인증, API를 정리합니다. 서버를 직접 운영하지 않는다면 필요하지 않습니다.

호스트와 기본 포트​

호스트기본 포트역할
ack8421메인 웹 호스트. 선택한 모듈 DLL을 동적으로 로드합니다
rdy8420ack와 비슷하지만 기본 모듈을 프로젝트 참조로 정적 결합합니다
forbes8420정적 파일 제공과 계약 파일 동기화
agent8422여러 ack 프로세스의 시작·중지·재시작과 설정·로그·통계 관리 API
deploy8520publish-package가 만든 업데이트 패키지와 매니페스트를 제공

rdy와 forbes의 기본 포트가 같으므로 한 호스트에 함께 띄우면 충돌합니다. rdy의 ServerPort(appsettings.json)나 forbes의 Kestrel 주소를 바꾸세요. rdy의 --port 도움말은 기본값을 8421로 쓰지만 실제로는 설정의 ServerPort(8420)가 먼저 적용됩니다.

rdy는 ack의 실행 옵션과 설정 구조를 공유합니다. 정적 결합되는 모듈은 command, dbclient, function, graphclient, logger, prompter, repository, transact, wwwroot 9개이고, 그 밖의 모듈은 ack와 같이 모듈 폴더의 DLL을 동적으로 로드합니다. 따라서 새 모듈을 넣는다고 해서 항상 rdy의 프로젝트 참조와 정적 사전(Extensions/ServiceCollectionExtensions.cs)을 고쳐야 하는 것은 아닙니다. 정적 결합이 필요할 때만 수정하세요.

agent​

appsettings.json의 Agent 섹션으로 관리 키, 제어 대상(Targets), 호스트 브리지, 감사 로그를 설정하고 Users 섹션으로 로그인 계정을 설정합니다.

인증: 관리 API는 헤더 X-Management-Key(설정 Agent:ManagementHeaderName)에 Agent:ManagementKey 값을 보내야 하며, 키가 맞지 않거나 설정되어 있지 않으면 401입니다.

경로인증설명
GET /없음헬스 체크. name, now, status
GET /validate/{key}없음관리 키 문자열 검증
POST /auth/login, GET /auth/me, POST /auth/logout로그인 쿠키(handstack-agent-auth)Users 계정 로그인
GET /targets, GET /targets/{id}/status, POST /targets/{id}/start|stop|restart관리 키대상 ack 프로세스 조회와 제어
GET /targets/{id}/manifest관리 키대상의 PackageMakeCommand를 실행해 deploy-filelist.txt 다운로드
GET /settings/{id}/diagnostics관리 키실행 중인 대상 ack의 진단 정보
GET·POST /settings/{id}관리 키appsettings.json 조회·저장. 저장하면 /globalconfiguration/apply로 런타임 적용을 시도하고 응답의 restartRequiredKeys로 재시작 필요 항목을 알려 줍니다
GET·POST /modules/{id}/{moduleId}관리 키module.json 조회·저장. EventAction·SubscribeAction이 있으면 MediatR 설정을 런타임 적용
GET /stats관리 키호스트 CPU·메모리·디스크·네트워크 통계
GET /logs/{id}?file=&rows=, GET /logtree/{id}관리 키대상의 WorkingDirectory/../log 로그 마지막 행과 디렉터리 트리. file을 생략하면 최신 app*.log, rows 기본 300행

호스트 브리지: Docker 컨테이너 안의 agent가 호스트의 ack 프로세스를 제어해야 할 때 호스트에도 브리지 agent를 하나 더 실행합니다. 브리지는 Agent:HostBridge:Enabled=true이고 헤더 X-Bridge-Key(Agent:HostBridge:HeaderName)로 인증하며 /bridge/targets/{id}/start|stop|restart|status를 제공합니다. 비활성 상태에서는 404입니다. 컨테이너 쪽 대상은 UseCommandBridge=true와 CommandBridgeUrl로 위임합니다.

AuditLog:Enabled=true이면 /targets API 호출자·시각·동작·대상·결과를 logger 모듈로 보냅니다.

deploy​

publish-package가 만든 deploy-<yyyy.MM.rollingno>.zip 패키지를 저장하고, updater가 읽는 공개 매니페스트를 제공합니다.

경로인증설명
GET /release/manifest.json없음updater가 읽는 최신 매니페스트
GET /release/packages/{fileName}없음패키지 ZIP 다운로드
GET /api/update-packages없음등록된 패키지 목록
POST /api/update-packagesX-Deploy-Key패키지 ZIP 업로드와 카탈로그 등록
POST /deploy-error없음updater 실패 로그 저장
ManagementKey가 비어 있으면 업로드 API에 인증이 없습니다

Deploy:ManagementKey가 비어 있으면 관리 키 검사가 통과 처리되어 누구나 POST /api/update-packages로 패키지를 올릴 수 있습니다. 업로드한 패키지는 updater가 클라이언트에 적용하므로 운영 전에 반드시 키를 설정하세요. 헤더 이름은 Deploy:ManagementHeaderName(기본 X-Deploy-Key)입니다.

매니페스트는 최신 버전(version, releaseDate, packageUri, packageSha256, packageSize)과 클라이언트가 현재 버전보다 높은 항목만 순차 적용하는 packages 목록을 담고, mandatory, maintenanceMode, releaseNotes를 포함합니다. maintenanceMode가 true이면 updater가 SHA-256 검증을 건너뜁니다.

Deploy 설정: StorageRoot(패키지·카탈로그·오류 로그 루트), PublicRootPath, PublicRequestPath(기본 release), Mandatory, MaintenanceMode, ReleaseNotes. DefaultChannel과 DefaultPlatform은 예약 항목이며 현재 코드가 참조하지 않습니다. 패키지는 PublicRootPath/packages, 카탈로그는 StorageRoot/update-catalog.json, 오류 보고는 StorageRoot/errors에 저장됩니다.

Invoke-RestMethod -Method Post -Uri http://localhost:8520/api/update-packages `
-Headers @{ 'X-Deploy-Key' = '<설정한 키>' } `
-Form @{ file = Get-Item .\packages\deploy-2026.05.001.zip; releaseNotes = 'May rollout'; releaseDate = '2026-05-01T09:00:00Z' }

forbes​

정적 파일을 제공하고 계약(Contracts) 파일을 원격과 동기화합니다. 로그는 <EntryDirectoryPath>\tracelog\trace-YYYY-MM-DD.log에 남습니다.

설정(appsettings.json)설명
ContractsBasePath, WWWRootBasePath계약·정적 파일 루트($HANDSTACK_HOME/... 형식 지원)
ContractViewPath계약 뷰 정적 파일 경로(선택). 비우면 ContractsBasePath/wwwroot/HDS가 있을 때 /view로 제공
AllowedOrigins정적 파일 CORS 허용 오리진. 비우면 모든 오리진 차단
CodeMergeMethodManual(동기화 없음), FileSync(변경 파일을 FileSyncServer로 전송), GitHub(시작할 때 동기화하고 변경을 GitHub에 반영)
Kestrel:Endpoints:Http:Url바인딩 주소(기본 http://localhost:8420)

동기화 대상은 Contracts 하위의 dbclient(*.xml), function(featureMain*, featureMeta.json, featureSQL.xml), transact(*.json), wwwroot(모든 파일)입니다. 모듈별 전용 확장자(.dbc, .txn, .fnc 등)는 이 목록에 없으므로 감시 대상인지 확인하세요(확인 필요).

sync-secrets.json(UserName, UserEmail, FileSyncServer, FileSyncAccessToken, GitHubPersonalAccessToken, GitHubRepository*)은 동기화 비밀이므로 토큰을 파일에 커밋하지 말고 환경 변수로 주입하세요. 조회·저장 API(GET·PUT /api/configuration/sync-secrets)는 루프백 요청만 허용하며 그 밖에는 403입니다. POST /api/dispatch/repository와 POST /api/dispatch/workflow는 GitHub repository_dispatch, workflow_dispatch를 트리거합니다.

서비스로 등록​

agent는 단일 호스트에서 서비스로 등록해 씁니다. Windows는 sc.exe create handstack-agent binPath= "C:\handstack\agent\agent.exe --urls http://0.0.0.0:8422" start= auto, Ubuntu는 ExecStart=/opt/handstack/agent/agent --urls http://0.0.0.0:8422로 systemd 유닛을 만듭니다. 0.0.0.0으로 바인딩할 때는 방화벽과 관리 키로 접근을 제한하세요.