Files
zzabisagent-labandClaude Fable 5.1 d1eefaa15f 실제 환경 배포·검증 기록(0.1.1): ariweb.net 호스트 배포 완료, 34개 흐름 실환경 판정(실제 7·부분 7·미수행 20), RUNBOOK 운영 사실, 로컬 E2E 보고서 갱신
- docs/verification/real-env-0.1.1.md/.json: 배포 경과·결함 수정 요약, 흐름별 단계·증거, 재검증(systemd/nginx/HAL·포털 건강/배포 영수증/모듈 버전) 기록
- docs/RUNBOOK-0.1.1.md: 서버 한 대 운영, 메일 서버 등록 값, 발신 메일, 같은 릴리스 재등록 절차
- VERSION_HISTORY.md 알려진 제한에 실환경 검증 결과 기입. 출시 완료는 선언하지 않음

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-26 14:35:04 +00:00

32 KiB

0.1.1 실제 환경 배포·검증 기록 (ariweb.net 호스트, 2026-10-26)

생성: 2026-10-26T14:33:19.592Z · 검증기 real-env-check.mjs(서버에서 실행, 실제 HAL·포털·Node Agent·Webmaker·AriMail 대상) · 배포 기준 main 3951be5

상태 요약

  • 배포: HAL 부트스트랩(deploy/bootstrap-hal.sh) → 첫 운영자 → 첫 Node Agent(역할 control, 승인 → 부트스트랩 완료·수동 설치 잠김) → link-portal → HAL 작업으로 portal → webmaker → arimail 배포, 이후 수정 artifact 를 같은 릴리스 0.1.1 로 재등록해 HAL 작업으로 agent·hal·portal 갱신. 모든 모듈의 실제 버전 0.1.1·건강 ok(아래 재검증).
  • 공개 DNS: hal.ariweb.net·my.ariweb.net A 레코드는 아직 없다(이번 작업은 공개 DNS 를 바꾸지 않았다). 서버 /etc/hosts 임시 항목으로 같은 서버 안 통신만 확인했고, 외부 주소 접속(흐름 8 등)은 레코드 생성 뒤 확인한다.
  • 실제 외부 발신 1건: 포털 mailer(Resend, no-reply@ariweb.net)로 icqmomo@gmail.com 에 확인 메일 발송 — Resend 수락 id 01a17899-8c6e-7574-b85b-3c1015fe94b5(14:24 UTC). 수신함 도착은 사람이 확인한다.
  • 흐름 판정(34개): 실제 확인 7 · 부분 확인 7 · 미수행 20 · 실패 0. 0.1.1 출시 완료는 선언하지 않는다 — 지시서 기준(최종 화면·외부 접속·실제 메일 왕복·실제 사용량·실제 배포 버전) 중 외부 접속·메일 왕복·Webmaker 페이지 제작이 남아 있다.

사람이 해야 남는 일

  1. hosting.co.kr 패널에 hal.ariweb.net·my.ariweb.net A 레코드(187.53.133.173) 생성 → 흐름 8·외부 접속 확인.
  2. 메일 왕복 검증용 수신 주소(자동 응답 메일함) 설정(PUT /internal/ops/mail/policy {verifier}) → 흐름 11.
  3. Webmaker 제작 화면에서 검증 사이트의 페이지를 만들어 저장 → 흐름 5·6·13·14 의 나머지(관리형 배포·백업 실행·복원·외부 확인).

배포 경과와 발견한 결함(모두 코드로 수정해 main 에 반영, VERSION_HISTORY "실제 환경 배포에서 발견한 결함 수정")

  1. 부트스트랩 4단계 중단 — /etc/letsencrypt/live 는 root 전용이라 일반 계정의 인증서 존재 확인이 거짓 → sudo -n test -f.
  2. 포털 artifact 에 상품정책 시드(catalog/) 누락 → 릴리스 빌더 경로 추가.
  3. AriMail 은 다른 계정(arihakdang)으로 운영 → Agent 실행 계정 모드(deploy/module-as-user.sh, sudoers 최소 규칙). 내려받은 artifact 0600·현재 경로 심링크·umask 077 로 만들어진 0700 디렉터리(릴리스 빌더 모드 정규화) 등 권한 문제 4건.
  4. AriMail 마이그레이션이 DB_FILE 없이 릴리스 디렉터리에 빈 DB 를 만들 뻔함 → 유닛 EnvironmentFile 을 실행 계정으로 읽어 실행(공백 값 파싱 포함). 사후 절차 실패 시 current 되돌리기.
  5. 도입 모듈 실제 버전이 상류 버전(1.7.3·1.0.11)으로 보고돼 HAL 판정·drift 표시 오류 → REVISION.json 의 Suite 버전 사용(설치 결과·heartbeat 모두).
  6. Webmaker 운영 유닛의 강화 지시문이 템플릿에 지워질 뻔함 → keepExistingUnit. 데이터 백업이 root 소유 파일(이전 마이그레이션 기록)에 막힘 → 읽기 실패 관대 처리(+서버의 해당 파일 소유권 정정).
  7. 같은 버전 재설치가 실행 중인 디렉터리를 지움 → 임시 풀기·<ver>.prev-<시각> 보존. 새 유닛(포털) enable 누락. 부트스트랩 릴리스 기록 행 없음(UPDATE 무효).
  8. my.ariweb.net nginx 접근 경로가 어디서도 만들어지지 않음 → 부트스트랩이 설치.
  9. 서버 한 대(control)라 web·backup 역할 서버를 고를 수 없음 → control 대체. AriMail 설정 API 는 기본 도메인 호스트에서만 응답(Node fetch 는 Host 변경 불가) → 설정 주소를 기본 도메인 이름으로, 서버 hosts 항목.

Release 0.1.1 완료 조건 34개 — 실제 환경 판정

# 흐름 판정 비고
1 신규 고객 가입과 이메일 확인 실제 확인 실제 포털·실제 mailer 경로(포획 서버) — 외부 수신함 도착은 별도 1건으로 확인
2 개인 사용자 그룹 생성과 다른 사용자 초대 실제 확인
3 상품 주문, 결제 확인, 권리 활성화 실제 확인
4 초안 사이트 생성 실제 확인 실제 Webmaker 에 프로젝트 생성(내부 API 서명 호출)
5 Webmaker에서 페이지 제작 부분 확인 제작 화면 진입(SSO)은 실제 Webmaker 로 확인 · 페이지 제작(AI 생성·저장)은 사람이 Webmaker 화면에서 수행해야 하므로 미수행
6 관리형 배포 부분 확인 배포 요청이 거부됨: precheck_failed — 배포 전 확인에서 차단된 항목이 있습니다 (저장본이 없어 배포할 내용이 없음; 사람이 Webmaker 에서 페이지를 저장한 뒤 수행)
7 도메인 연결과 HTTPS 발급 미수행 실제 소유 도메인과 공개 DNS(TXT·A) 변경이 필요 — 이번 작업은 공개 DNS 를 바꾸지 않음
8 외부 주소에서 사이트 확인 미수행 공개 DNS(my/hal/사이트 도메인) 생성 전 — 외부 주소 접속은 레코드 생성 뒤 확인
9 사이트 정보와 접속·사용량 통계 확인 부분 확인 화면 데이터 제공 확인 · 실제 접속 통계(awstats 로그 집계)는 공개 DNS 로 외부 방문이 생긴 뒤 확인 가능
10 사이트 대표 메일과 메일함 생성 부분 확인 실제 AriMail 테넌트·메일함 생성 확인 · 활성화는 도메인 DNS(MX/SPF/DKIM) 반영이 필요해 외부 대기
11 외부 송신, 수신, 회신 확인 미수행 검증용 수신 주소(자동 응답 메일함)와 고객 도메인 MX 반영 필요
12 독립 메일 서비스 생성 실제 확인
13 백업 옵션 구매와 첫 백업 확인 부분 확인 백업 옵션 주문·승인·활성화는 실제 확인. 수동 백업 실행은 사이트가 초안(미배포)이라 정기 실행기가 옵션을 site_not_deployed 로 중지해 Agent 백업까지 가지 않음(설계대로) — Webmaker 에서 페이지를 저장·배포한 뒤 다시 수행. 판정은 검증기의 시간 초과를 운영자가 DB 상태(옵션 paused: site_not_deployed)로 확인해 부분 확인으로 정정
14 백업 복원과 외부 사이트 확인 미수행 복원 승인(3단계)·외부 사이트 확인은 공개 DNS 와 복원 대상 배포본 필요(흐름 6 선행)
15 관리형 사이트 서버 이전과 외부 확인 미수행 관리 서버가 1대뿐이라 서버 간 이전 미수행
16 외부 배포 사이트 생성과 배포 미수행 외부 Linux 서버 없음
17 사용량 경고와 한도 동작 확인 미수행 실제 사용량이 한도에 이르려면 운영 트래픽·시간 경과 필요
18 상품 축소 보류와 정리 후 적용 미수행 축소 보류는 실제 사용 중 리소스가 필요(로컬 E2E 확인)
19 사이트 수 반환과 대표 메일의 독립 전환 미수행 사이트 수 반환·독립 전환은 흐름 10 활성화(외부 DNS) 뒤 가능
20 사이트 소유권 이전 미수행 두 번째 소유자 그룹의 심사 절차를 포함해 로컬 E2E 로 확인, 실환경 미수행
21 중지, 해지, 보존 예정일 표시 미수행 보존 예정일 표시는 시간 경과 필요(로컬 E2E 확인)
22 HAL 우선 배포 후 HAL을 통한 전체 모듈 배포 실제 확인 HAL 부트스트랩 → 첫 Agent → HAL 작업으로 portal·webmaker·arimail·agent 배포, 실제 버전 0.1.1·건강 ok
23 실패 작업의 재시도와 되돌리기 미수행 실패 작업 재시도·되돌리기는 배포 중 실제로 2회 발생(백업 실패→재시도 성공, 마이그레이션 실패→되돌리기) — 기록은 VERSION_HISTORY·이 문서의 배포 경과 참고
24 운영자 승인, 감사 기록, 고객 알림의 일치 부분 확인
25 HAL, 로그인, 비밀정보 관리, 인증서 기반의 재해복구 훈련 미수행 재해복구 훈련은 다른 호스트 복원이 필요(로컬 E2E 부분 확인)
26 새로 고침, 재로그인, HAL 재시작 후 진행 작업 상태 유지 실제 확인
27 마지막 사이트 수·용량·메일함 동시 요청 시 하나만 성공 미수행 동시 요청 경합은 로컬 E2E 로 확인, 실환경 미수행
28 외부 Linux 서버 Agent 연결·배포·재배포·제거·실패 정리 미수행 외부 Linux 서버 없음
29 HAL 장애 중 기존 서비스 유지와 신규 변경 제한 표시 미수행 HAL 장애 상태 표시는 로컬 E2E 로 확인(흐름 26 에서 재시작 중 복구만 실환경 확인)
30 모듈 업데이트, 일부 서버 실패, 대상별 되돌리기와 상태 조정 부분 확인 모듈 갱신(수정 artifact 재등록 → HAL 작업으로 agent·hal 갱신) 4건 완료 확인 · 일부 서버 실패·대상별 되돌리기는 서버 1대뿐이라 미수행
31 긴급 복구의 승인 부족·만료 자격·허용 범위 밖 작업 거부와 정상 복구 미수행 긴급 복구 절차는 로컬 E2E 로 확인
32 Source 옵션 만료 후 30일 read-only, clone·export와 삭제 완료 미수행 Source 옵션 30일 만료는 시간 경과 필요
33 메일 서비스의 사이트 대표→독립 전환 후 항목 유지 미수행 흐름 19 와 같은 외부 DNS 선행 조건
34 일시 중지·해지 예약·보존·삭제 단계의 표시 일치 미수행 시간 경과 필요(로컬 E2E 확인)

흐름별 단계와 증거

1. 신규 고객 가입과 이메일 확인 — 실제 확인

실제 포털·실제 mailer 경로(포획 서버) — 외부 수신함 도착은 별도 1건으로 확인

  • ✔ 가입 → 세션 발급(실제 포털 https://my.ariweb.net) — {"status":200}
  • ✔ 확인 전 그룹 생성 차단(403 email_unverified) — "email_unverified"
  • ✔ 확인 메일이 실제 발신 경로(mailer resend → 포획 서버)로 나감 · 토큰 추출 — {"subject":"[Ariweb] 이메일 주소를 확인해 주세요","from":"no-reply@ariweb.net","linkHost":"https://my.ariweb.net"}
  • ✔ 이메일 확인(1회용) → 재사용 거부 — {"first":200,"second":"token_used"}
  • ✔ 내 정보: 확인됨 · 개인 그룹 · owner — {"verifiedAt":"2026-10-26T14:31:15.078Z","group":"personal","role":"owner"}
  • ✔ 중복 가입은 존재를 드러내지 않는 안내(409) — "signup_unavailable"
  • ✔ 로그인 화면(로그인 상태면 302, 아니면 200)·기기(세션) 목록 — {"loggedIn":302,"anonymous":200,"sessions":"[redacted]"}
{
 "verifiedAt": "2026-10-26T14:31:15.078Z",
 "group": "personal",
 "role": "owner"
}

2. 개인 사용자 그룹 생성과 다른 사용자 초대 — 실제 확인

  • ✔ 팀 그룹 만들기 → 현재 그룹 전환 — "g_01a1789f67b12a216acd1955fa"
  • ✔ 이메일 초대 → 초대 메일(포획)에서 링크 — "upaCVcL43bFzzZaGTtGZi_tU2J64oJEA"
  • ✔ 초대 수락(1회용) → member · 재사용 거부 — {"reuse":"invite_invalid"}
  • ✔ 권한 없는 구성원의 변경 API → 403 — {"requiredRole":["owner","admin"],"yourRole":"member"}

3. 상품 주문, 결제 확인, 권리 활성화 — 실제 확인

  • ✔ 상품 목록(공개 버전·가격·한도) — {"count":2,"id":"pv_01a178834fac072b5600ce1e60","name":"팀","price":49000,"sites":3}
  • ✔ 주문 제출(수동 결제, 독립 메일 옵션 포함) → 결제 대기 — {"id":"o_01a1789f68c3298aec8ad337e8","group_id":"g_01a1789f67b12a216acd1955fa","order_no":"AW-20261026-0003","kind":"new","product_version_id":"pv_01a178834fac072b5600ce1e60","items_json":"[{"type":"product","id":"team","name":"팀","qty":1,"unit_price":49000,"amount":49000,"tax":4900,"target_type":"group","target_id":null,"grants":{"sites":3,"web_disk":21474836480,"
  • ✔ 입금 확인 전 승인 거부(409) — "payment_not_confirmed"
  • ✔ 운영자 입금 확인 → 승인 → 권리 활성화 — {"paid":"awaiting_approval","approved":"approved","granted":10}
  • ✔ 고객 결제 화면: 활성 상품·권리·다음 청구일 — {"subs":1,"nextBilling":"2026-11-26T14:31:15.451Z"}
{
 "orderNo": "AW-20261026-0003",
 "bill": {
  "subs": 1,
  "nextBilling": "2026-11-26T14:31:15.451Z"
 }
}

4. 초안 사이트 생성 — 실제 확인

실제 Webmaker 에 프로젝트 생성(내부 API 서명 호출)

  • ✔ 사이트 생성(새 Webmaker 프로젝트 · 관리형) → 초안 — {"id":"s_01a1789f690cb9115f0330d2e8","group_id":"g_01a1789f67b12a216acd1955fa","name":"검증 사이트 mvpcu283","purpose":"실제 환경 검증","webmaker_project_id":"85e1859a8638022beb761f1ec4ccfc93","template":null,"lang":"ko","timezone":"Asia/Seoul","lifecycle":"draft","deploy_mode":"managed","primary_domain":null,"site_count_state":"none","site_count_reservation_id":null,"server_id":null,"external_agent_id":null
  • ✔ 초안 목록·사용량(사이트 수 미소비) — {"drafts":1,"lifecycle":"draft","projectId":null}

5. Webmaker에서 페이지 제작 — 부분 확인

제작 화면 진입(SSO)은 실제 Webmaker 로 확인 · 페이지 제작(AI 생성·저장)은 사람이 Webmaker 화면에서 수행해야 하므로 미수행

  • ✔ 제작 화면 열기: 포털 SSO 티켓 → 실제 Webmaker /api/auth/sso 302(1회용) — {"portal":302,"webmaker":302,"webmakerLocation":"/?site=85e1859a8638022beb761f1ec4ccfc93","reuse":403}
  • ✔ 저장본 목록·배포 전 확인(실제 Webmaker 프로젝트) — {"versionsStatus":200,"versions":0,"precheck":true}
{
 "sso": {
  "portal": 302,
  "webmaker": 302,
  "webmakerLocation": "/?site=85e1859a8638022beb761f1ec4ccfc93",
  "reuse": 403
 },
 "ver": {
  "versionsStatus": 200,
  "versions": 0,
  "precheck": true
 }
}

6. 관리형 배포 — 부분 확인

배포 요청이 거부됨: precheck_failed — 배포 전 확인에서 차단된 항목이 있습니다 (저장본이 없어 배포할 내용이 없음; 사람이 Webmaker 에서 페이지를 저장한 뒤 수행)

  • ✔ 배포 요청(관리형) → HAL 작업·사이트 수 예약 — {"status":409,"error":"precheck_failed","message":"배포 전 확인에서 차단된 항목이 있습니다"}

9. 사이트 정보와 접속·사용량 통계 확인 — 부분 확인

화면 데이터 제공 확인 · 실제 접속 통계(awstats 로그 집계)는 공개 DNS 로 외부 방문이 생긴 뒤 확인 가능

  • ✔ 사이트 정보·배포 이력·사용량 화면 — {"overviewKeys":["ok","overview","refreshJob"],"usageKeys":["ok","overview","allocations","samples"],"deployments":0}
{
 "overviewKeys": [
  "ok",
  "overview",
  "refreshJob"
 ],
 "usageKeys": [
  "ok",
  "overview",
  "allocations",
  "samples"
 ],
 "deployments": 0
}

10. 사이트 대표 메일과 메일함 생성 — 부분 확인

실제 AriMail 테넌트·메일함 생성 확인 · 활성화는 도메인 DNS(MX/SPF/DKIM) 반영이 필요해 외부 대기

  • ✔ 사이트 연결 도메인 등록(검증 전용 이름, 소유 확인은 외부 대기) — {"id":"d_01a1789f6a07e57873e2f0c05f"}
  • ✔ 사이트 대표 메일 생성 → 실제 AriMail 테넌트 준비 — {"id":"msv_01a1789f6a0d5f702a1581f2fd","status":"needs_setup","kind":"site_bound"}
  • ✔ 메일함 생성(초기 비밀번호 1회 표시) → 재조회에 비밀번호 없음 · 실제 AriMail 계정 — {"id":"mb_01a1789f6e723ade68602baaf9","address":"kim@check-mvpcu283.ariweb.net","shownOnce":true,"leakedOnReload":false}
  • ✔ DNS 확인(미반영 구분) → 활성화 작업은 외부 대기 — {"dnsOk":true,"items":[],"activate":200,"job":"queued","waitReason":""}
{
 "d": {
  "id": "d_01a1789f6a07e57873e2f0c05f"
 },
 "svc": {
  "id": "msv_01a1789f6a0d5f702a1581f2fd",
  "status": "needs_setup",
  "kind": "site_bound"
 },
 "mb": {
  "id": "mb_01a1789f6e723ade68602baaf9",
  "address": "kim@check-mvpcu283.ariweb.net",
  "shownOnce": true,
  "leakedOnReload": false
 },
 "dns": {
  "dnsOk": true,
  "items": [],
  "activate": 200,
  "job": "queued",
  "waitReason": ""
 }
}

12. 독립 메일 서비스 생성 — 실제 확인

  • ✔ 메일 전용 도메인 등록(purpose mail) — "d_01a1789f6e94cf197bdcb0cb81"
  • ✔ 독립 메일 서비스 생성(독립 옵션 소비·사이트 수 미소비) — {"id":"msv_01a1789f6e9604bd5f49bb08e1","kind":"standalone","status":"needs_setup","usage":{}}
{
 "id": "msv_01a1789f6e9604bd5f49bb08e1",
 "kind": "standalone",
 "status": "needs_setup",
 "usage": {}
}

13. 백업 옵션 구매와 첫 백업 확인 — 부분 확인

백업 옵션 주문·승인·활성화는 실제 확인. 수동 백업 실행은 사이트가 초안(미배포)이라 정기 실행기가 옵션을 site_not_deployed 로 중지해 Agent 백업까지 가지 않음(설계대로) — Webmaker 에서 페이지를 저장·배포한 뒤 다시 수행. 판정은 검증기의 시간 초과를 운영자가 DB 상태(옵션 paused: site_not_deployed)로 확인해 부분 확인으로 정정

  • ✔ 백업 옵션 주문(대상 사이트 지정) → 입금 확인 → 승인 — {"orderNo":"AW-20261026-0004","approved":"approved"}
  • ✔ 백업 화면(옵션 보유 여부) — {}
  • ✔ 옵션 활성화(확인 필수) → 첫 백업 예정 — {"status":"active"}
  • ✘ 지금 백업 실행 → 실제 Agent 가 사이트 파일·데이터를 묶어 저장(완료 대기 120초) — 백업 완료 대기 시간 초과
{
 "optionState": {
  "status": "paused",
  "paused_reason": "site_not_deployed",
  "updated_at": "2026-10-26T14:32:11.943Z"
 },
 "siteLifecycle": "draft",
 "lastJob": {
  "status": "failed",
  "error": "대상 서버 또는 Agent 가 필요합니다"
 }
}

22. HAL 우선 배포 후 HAL을 통한 전체 모듈 배포 — 실제 확인

HAL 부트스트랩 → 첫 Agent → HAL 작업으로 portal·webmaker·arimail·agent 배포, 실제 버전 0.1.1·건강 ok

  • ✔ HAL 릴리스·모듈 목표/실제 버전(배포 영수증) — {"running":{"complete":true,"firstInstall":false,"releaseVersion":"0.1.1","mainCommit":"[redacted]","artifactSha256":"[redacted]","halRunningVersion":"0.1.1","firstAgent":"[redacted]","manualInstallLocked":true},"targets":[{"module":"agent","target":"0.1.1","actual":"0.1.1","health":"ok"},{"module":"arimail","target":"0.1.1","actual":"0.1.1","health":"ok"},{"module":"backup","target":null,"actual"
  • ✔ HAL 을 통한 모듈 배포 작업(module.deploy) 결과 — [{"label":"portal 0.1.1 배포","status":"done"},{"label":"hal 0.1.1 배포","status":"done"},{"label":"portal 0.1.1 배포","status":"done"},{"label":"portal 0.1.1 배포","status":"done"},{"label":"agent 0.1.1 배포","status":"done"},{"label":"arimail 0.1.1 배포","status":"done"},{"label":"hal 0.1.1 배포","status":"done"},{"label":"agent 0.1.1 배포","status":"done"},{"label":"arimail 0.1.1 배포","status":"failed"},{"label
{
 "rel": {
  "running": {
   "complete": true,
   "firstInstall": false,
   "releaseVersion": "0.1.1",
   "mainCommit": "[redacted]",
   "artifactSha256": "[redacted]",
   "halRunningVersion": "0.1.1",
   "firstAgent": "[redacted]",
   "manualInstallLocked": true
  },
  "targets": [
   {
    "module": "agent",
    "target": "0.1.1",
    "actual": "0.1.1",
    "health": "ok"
   },
   {
    "module": "arimail",
    "target": "0.1.1",
    "actual": "0.1.1",
    "health": "ok"
   },
   {
    "module": "backup",
    "target": null,
    "actual": "0.1.1",
    "health": "ok"
   },
   {
    "module": "hal",
    "target": "0.1.1",
    "actual": "0.1.1",
    "health": "ok"
   },
   {
    "module": "observability",
    "target": null,
    "actual": "0.1.1",
    "health": "ok"
   },
   {
    "module": "portal",
    "target": "0.1.1",
    "actual": "0.1.1",
    "health": "ok"
   },
   {
    "module": "webmaker",
    "target": "0.1.1",
    "actual": "0.1.1",
    "health": "ok"
   }
  ]
 },
 "jobs": [
  {
   "label": "portal 0.1.1 배포",
   "status": "done"
  },
  {
   "label": "hal 0.1.1 배포",
   "status": "done"
  },
  {
   "label": "portal 0.1.1 배포",
   "status": "done"
  },
  {
   "label": "portal 0.1.1 배포",
   "status": "done"
  },
  {
   "label": "agent 0.1.1 배포",
   "status": "done"
  },
  {
   "label": "arimail 0.1.1 배포",
   "status": "done"
  },
  {
   "label": "hal 0.1.1 배포",
   "status": "done"
  },
  {
   "label": "agent 0.1.1 배포",
   "status": "done"
  },
  {
   "label": "arimail 0.1.1 배포",
   "status": "failed"
  },
  {
   "label": "webmaker 0.1.1 배포",
   "status": "done"
  },
  {
   "label": "portal 0.1.1 배포",
   "status": "done"
  }
 ]
}

24. 운영자 승인, 감사 기록, 고객 알림의 일치 — 부분 확인

  • ✔ 고객 감사 기록(order.approve) · 알림 · 운영자 주문 상태 일치 — {"auditEntries":0,"notifications":6,"status":"approved"}
  • ✔ HAL 감사 기록(deploy.module) — 10
{
 "a": {
  "auditEntries": 0,
  "notifications": 6,
  "status": "approved"
 },
 "halDeployAudit": 10
}

26. 새로 고침, 재로그인, HAL 재시작 후 진행 작업 상태 유지 — 실제 확인

  • ✔ HAL 재시작 전: 운영자 세션·작업 수·서버 등록 — {"jobs":23,"servers":1}
  • ✔ systemctl restart ariweb-hal → 건강 회복 → 같은 세션으로 작업 수·서버 유지 — {"uptimeSec":1,"sessionKept":"[redacted]","jobs":23,"servers":1,"agentOnline":true}
  • ✔ Agent 가 재접속(heartbeat) 해 서버 ready 유지 — [{"name":"srv1953374 (ariweb.net)","status":"ready","lastSeen":"2026-10-26T14:33:13.381Z"}]
{
 "before": {
  "jobs": 23,
  "servers": 1
 },
 "after": {
  "uptimeSec": 1,
  "sessionKept": "[redacted]",
  "jobs": 23,
  "servers": 1,
  "agentOnline": true
 },
 "ag": [
  {
   "name": "srv1953374 (ariweb.net)",
   "status": "ready",
   "lastSeen": "2026-10-26T14:33:13.381Z"
  }
 ]
}

검증에 쓴 테스트 데이터(정리 대상)

  • 고객 계정 alice-mvpcu283@check.ariweb.net(및 bob-, 이전 실행분 alice-/bob-*), 사이트 s_01a1789f690cb9115f0330d2e8, 도메인 check-mvpcu283.ariweb.net·solo-*.ariweb.net(AriMail 테넌트는 운영자 취소 → 보존 기간 뒤 삭제), 주문 o_01a1789f68c3298aec8ad337e8. 모두 @check.ariweb.net 주소의 검증 전용 데이터다.

성공 선언 전 재검증(서버에서 읽은 값, 90-verify.sh)

### systemd
ariweb-hal                 active / enabled=enabled
ariweb-agent               active / enabled=enabled
ariweb-portal              active / enabled=enabled
webmaker                   active / enabled=enabled
webmaker-setup             active / enabled=enabled
arihakdang-mail            active / enabled=enabled
arihakdang-mail-haraka     active / enabled=enabled
nginx                      active / enabled=enabled
### nginx
nginx: configuration file /etc/nginx/nginx.conf test is successful
ariweb-hal.conf
ariweb-portal.conf
webmail.ariweb.net.conf
webmaker.ariweb.net.conf
webmaker.ariweb.net.conf.bak-1.5.27
### HAL health (127.0.0.1:8900)
{"ok":true,"version":"0.1.1","uptimeSec":5,"db":true,"jobs":true,"bootstrap":{"complete":true,"firstInstall":false,"releaseVersion":"0.1.1","mainCommit":"3951be5836a753e60f11d6b363025059fcf6d448","artifactSha256":"e7741899cd7387b0155c9d3bf8ff14cc4026880db999c9d59347744390415e84","halRunningVersion":"0.1.1","firstAgent":"ag_01a178829f1c3d88381d2c0c75","manualInstallLocked":true},"instanceId":"hal_01a178a14a3deef408f7ddfa91"}
### HAL health via nginx https (resolve 127.0.0.1)
{"ok":true,"version":"0.1.1","db":true,"bootstrap":true}
### portal health
{"ok":true,"version":"0.1.1","db":true,"jobs":17,"time":"2026-10-26T14:33:23.567Z"}
{"ok":true,"version":"0.1.1"}
my.ariweb.net /login → 200
### ops console
/ops/ (127.0.0.1) → 200
/ops/ via nginx (외부 IP 흉내 X-Real-IP 8.8.8.8) → 200
### modules (HAL 기록)
{
 "running": {
  "complete": true,
  "firstInstall": false,
  "releaseVersion": "0.1.1",
  "mainCommit": "3951be5836a753e60f11d6b363025059fcf6d448",
  "artifactSha256": "e7741899cd7387b0155c9d3bf8ff14cc4026880db999c9d59347744390415e84",
  "halRunningVersion": "0.1.1",
  "firstAgent": "ag_01a178829f1c3d88381d2c0c75",
  "manualInstallLocked": true
 },
 "releases": [
  {
   "v": "0.1.1",
   "status": "approved",
   "halDeployedAt": "2026-10-26T14:30:34.618Z"
  }
 ],
 "targets": [
  {
   "module": "agent",
   "target": "0.1.1",
   "actual": "0.1.1",
   "health": "ok",
   "active": 1,
   "checkedAt": "2026-10-26T14:33:13.381Z",
   "err": null
  },
  {
   "module": "arimail",
   "target": "0.1.1",
   "actual": "0.1.1",
   "health": "ok",
   "active": 1,
   "checkedAt": "2026-10-26T14:33:13.381Z",
   "err": null
  },
  {
   "module": "backup",
   "target": null,
   "actual": "0.1.1",
   "health": "ok",
   "active": 1,
   "checkedAt": "2026-10-26T14:33:13.381Z",
   "err": null
  },
  {
   "module": "hal",
   "target": "0.1.1",
   "actual": "0.1.1",
   "health": "ok",
   "active": 1,
   "checkedAt": "2026-10-26T14:33:13.381Z",
   "err": null
  },
  {
   "module": "observability",
   "target": null,
   "actual": "0.1.1",
   "health": "ok",
   "active": 1,
   "checkedAt": "2026-10-26T14:33:13.381Z",
   "err": null
  },
  {
   "module": "portal",
   "target": "0.1.1",
   "actual": "0.1.1",
   "health": "ok",
   "active": 1,
   "checkedAt": "2026-10-26T14:33:13.381Z",
   "err": null
  },
  {
   "module": "webmaker",
   "target": "0.1.1",
   "actual": "0.1.1",
   "health": "ok",
   "active": 1,
   "checkedAt": "2026-10-26T14:33:13.381Z",
   "err": null
  }
 ]
}
### modules (디스크)
/srv/ariweb/hal          current → /srv/ariweb/hal/releases/0.1.1  REVISION=0.1.1(상류 0.1.1) pkg=0.1.1
/srv/ariweb/portal       current → /srv/ariweb/portal/releases/0.1.1  REVISION=0.1.1(상류 0.1.1) pkg=0.1.1
/srv/ariweb/agent        current → /srv/ariweb/agent/releases/0.1.1  REVISION=0.1.1(상류 0.1.1) pkg=0.1.1
/srv/webmaker            current → /srv/webmaker/releases/0.1.1  REVISION=0.1.1(상류 1.7.3) pkg=1.7.3
/srv/arihakdang-mail     current → /srv/arihakdang-mail/releases/0.1.1  REVISION=0.1.1(상류 1.0.11) pkg=1.0.11
### 서비스 자체 보고 버전
{"ok":true,"version":"1.0.11","domains":6}
webmaker csrf → 401
webmaker.ariweb.net → 302
webmail.ariweb.net → 200
### 배포 영수증(감사 기록 deploy.*)
[
 {
  "at": "2026-10-26T14:30:45.633Z",
  "actor": "op_01a178829b90905c15a3191caa",
  "subject": "portal",
  "detail": {
   "version": "0.1.1",
   "serverIds": [
    "srv_01a178829d5848f93a15f93a17"
   ],
   "overall": "done"
  }
 },
 {
  "at": "2026-10-26T14:30:35.618Z",
  "actor": "op_01a178829b90905c15a3191caa",
  "subject": "hal",
  "detail": {
   "version": "0.1.1",
   "serverIds": [
    "srv_01a178829d5848f93a15f93a17"
   ],
   "overall": "done"
  }
 },
 {
  "at": "2026-10-26T14:23:37.819Z",
  "actor": "op_01a178829b90905c15a3191caa",
  "subject": "portal",
  "detail": {
   "version": "0.1.1",
   "serverIds": [
    "srv_01a178829d5848f93a15f93a17"
   ],
   "overall": "done"
  }
 },
 {
  "at": "2026-10-26T14:16:46.605Z",
  "actor": "op_01a178829b90905c15a3191caa",
  "subject": "portal",
  "detail": {
   "version": "0.1.1",
   "serverIds": [
    "srv_01a178829d5848f93a15f93a17"
   ],
   "overall": "done"
  }
 },
 {
  "at": "2026-10-26T14:16:41.094Z",
  "actor": "op_01a178829b90905c15a3191caa",
  "subject": "agent",
  "detail": {
   "version": "0.1.1",
   "serverIds": [
    "srv_01a178829d5848f93a15f93a17"
   ],
   "overall": "done"
  }
 },
 {
  "at": "2026-10-26T14:09:32.947Z",
  "actor": "op_01a178829b90905c15a3191caa",
  "subject": "arimail",
  "detail": {
   "version": "0.1.1",
   "serverIds": [
    "srv_01a178829d5848f93a15f93a17"
   ],
   "overall": "done"
  }
 },
 {
  "at": "2026-10-26T14:09:24.433Z",
  "actor": "op_01a178829b90905c15a3191caa",
  "subject": "hal",
  "detail": {
   "version": "0.1.1",
   "serverIds": [
    "srv_01a178829d5848f93a15f93a17"
   ],
   "overall": "done"
  }
 },
 {
  "at": "2026-10-26T14:08:47.250Z",
  "actor": "op_01a178829b90905c15a3191caa",
  "subject": "agent",
  "detail": {
   "version": "0.1.1",
   "serverIds": [
    "srv_01a178829d5848f93a15f93a17"
   ],
   "overall": "done"
  }
 },
 {
  "at": "2026-10-26T14:00:26.918Z",
  "actor": "op_01a178829b90905c15a3191caa",
  "subject": "webmaker",
  "detail": {
   "version": "0.1.1",
   "serverIds": [
    "srv_01a178829d5848f93a15f93a17"
   ],
   "overall": "done"
  }
 },
 {
  "at": "2026-10-26T14:00:17.400Z",
  "actor": "op_01a178829b90905c15a3191caa",
  "subject": "portal",
  "detail": {
   "version": "0.1.1",
   "serverIds": [
    "srv_01a178829d5848f93a15f93a17"
   ],
   "overall": "done"
  }
 }
]
### 배포 작업
[
 {
  "id": "j_01a1789ee309d1bc1102a6d949",
  "label": "portal 0.1.1 배포",
  "status": "done",
  "ended": "2026-10-26T14:30:45.633Z"
 },
 {
  "id": "j_01a1789eba1aac59f8518c92b3",
  "label": "hal 0.1.1 배포",
  "status": "done",
  "ended": "2026-10-26T14:30:35.618Z"
 },
 {
  "id": "j_01a178985cf9fa2f2e76fa7735",
  "label": "portal 0.1.1 배포",
  "status": "done",
  "ended": "2026-10-26T14:23:37.819Z"
 },
 {
  "id": "j_01a17892166e8460c04de6a7d6",
  "label": "portal 0.1.1 배포",
  "status": "done",
  "ended": "2026-10-26T14:16:46.605Z"
 },
 {
  "id": "j_01a17892094ddcff01ba7b8002",
  "label": "agent 0.1.1 배포",
  "status": "done",
  "ended": "2026-10-26T14:16:41.094Z"
 },
 {
  "id": "j_01a1788b794d0d3545ca8bedd0",
  "label": "arimail 0.1.1 배포",
  "status": "done",
  "ended": "2026-10-26T14:09:32.947Z"
 },
 {
  "id": "j_01a1788b53ed98904ed1127166",
  "label": "hal 0.1.1 배포",
  "status": "done",
  "ended": "2026-10-26T14:09:24.433Z"
 },
 {
  "id": "j_01a1788acd103d85194bbb8bba",
  "label": "agent 0.1.1 배포",
  "status": "done",
  "ended": "2026-10-26T14:08:47.250Z"
 },
 {
  "id": "j_01a17883416842d8acc7909136",
  "label": "arimail 0.1.1 배포",
  "status": "failed",
  "ended": "2026-10-26T14:00:33.432Z"
 },
 {
  "id": "j_01a178831b657e19aaed13d7d8",
  "label": "webmaker 0.1.1 배포",
  "status": "done",
  "ended": "2026-10-26T14:00:26.918Z"
 },
 {
  "id": "j_01a178830202223b4852e6cb6a",
  "label": "portal 0.1.1 배포",
  "status": "done",
  "ended": "2026-10-26T14:00:17.401Z"
 }
]
### 서버·Agent
[
 {
  "id": "srv_01a178829d5848f93a15f93a17",
  "name": "srv1953374 (ariweb.net)",
  "role": "control",
  "status": "ready",
  "agent": "ag_01a178829f1c3d88381d2c0c75",
  "agentVersion": "0.1.1",
  "lastSeen": "2026-10-26T14:33:13.381Z",
  "modules": {
   "webmaker": {
    "target": "0.1.1",
    "actual": "0.1.1",
    "drift": false,
    "health": "ok",
    "active": true,
    "lastCheckAt": "2026-10-26T14:33:13.381Z",
    "lastError": null
   },
   "arimail": {
    "target": "0.1.1",
    "actual": "0.1.1",
    "drift": false,
    "health": "ok",
    "active": true,
    "lastCheckAt": "2026-10-26T14:33:13.381Z",
    "lastError": null
   },
   "hal": {
    "target": "0.1.1",
    "actual": "0.1.1",
    "drift": false,
    "health": "ok",
    "active": true,
    "lastCheckAt": "2026-10-26T14:33:13.381Z",
    "lastError": null
   },
   "agent": {
    "target": "0.1.1",
    "actual": "0.1.1",
    "drift": false,
    "health": "ok",
    "active": true,
    "lastCheckAt": "2026-10-26T14:33:13.381Z",
    "lastError": null
   },
   "observability": {
    "target": null,
    "actual": "0.1.1",
    "drift": false,
    "health": "ok",
    "active": true,
    "lastCheckAt": "2026-10-26T14:33:13.381Z",
    "lastError": null
   },
   "backup": {
    "target": null,
    "actual": "0.1.1",
    "drift": false,
    "health": "ok",
    "active": true,
    "lastCheckAt": "2026-10-26T14:33:13.381Z",
    "lastError": null
   },
   "portal": {
    "target": "0.1.1",
    "actual": "0.1.1",
    "drift": false,
    "health": "ok",
    "active": true,
    "lastCheckAt": "2026-10-26T14:33:13.381Z",
    "lastError": null
   }
  }
 }
]
### 공개 DNS(참고)
hal.ariweb.net → 
my.ariweb.net →