2026-10-26 11:58:15 +00:00
/**
* hal/modules/index.mjs — 모듈 기술서(descriptor) 모음(§32).
*
* HAL 이 어떤 모듈을 어떤 서버에 어떻게 설치·갱신·건강 확인하는지를 데이터로 둔다. Agent 는 이 기술서를 작업 payload 로 받아 그대로 수행하므로
* Agent 바이너리는 모듈별 지식을 갖지 않는다(새 모듈을 더할 때 HAL 만 바꾸면 된다).
*
* 기술서 모양
* name 모듈 이름(릴리스 artifact 이름과 같다: <name>-<version>.tar.gz)
* roles 설치할 수 있는 서버 역할
* layout 'releases'(= /srv/ariweb/<name>/releases/<ver> + current) — 도입 모듈도 같은 틀을 쓰되 데이터 경로는 기존 것을 유지한다
* unit systemd 유닛 이름(도입 모듈은 서버에 이미 있는 이름을 쓸 수 있어 server.facts.units 로 덮어쓴다)
* unitTemplate deploy/units/<file>.tmpl — 없으면 기존 유닛을 그대로 두고 WorkingDirectory 만 current 심링크가 가리키게 한다
* health { url, expect } 내부 건강 확인(127.0.0.1)
* version 실제 실행 버전을 읽는 방법: { file:'package.json' } (current/package.json 의 version) 또는 { http:'/api/health', field:'version' }
* preStop/postStart Agent 가 실행할 추가 절차 이름(agent/jobs/module.mjs 가 아는 것만)
* dataDirs 절대 건드리지 않는 데이터 경로(검증·백업 대상 안내용)
*/
export const MODULES = {
hal : { name : 'hal' , roles : [ 'control' ], layout : 'releases' , unit : 'ariweb-hal' , unitTemplate : 'ariweb-hal.service.tmpl' , user : 'master' , port : 8900 ,
health : { url : 'http://127.0.0.1:8900/api/health' , expect : 'ok' }, version : { http : 'http://127.0.0.1:8900/api/health' , field : 'version' }, dataDirs : [ '/srv/ariweb/hal/data' ], selfUpdate : true },
portal : { name : 'portal' , roles : [ 'control' , 'web' ], layout : 'releases' , unit : 'ariweb-portal' , unitTemplate : 'ariweb-portal.service.tmpl' , user : 'master' , port : 8910 ,
health : { url : 'http://127.0.0.1:8910/api/health' , expect : 'ok' }, version : { http : 'http://127.0.0.1:8910/api/health' , field : 'version' }, dataDirs : [ '/srv/ariweb/portal/data' ] },
agent : { name : 'agent' , roles : [ 'control' , 'web' , 'mail' , 'backup' ], layout : 'releases' , unit : 'ariweb-agent' , unitTemplate : 'ariweb-agent.service.tmpl' , user : 'master' ,
health : { heartbeat : true }, version : { file : 'package.json' }, dataDirs : [ '/srv/ariweb/agent/data' ], selfUpdate : true },
2026-10-28 15:07:35 +00:00
// 도입 모듈: Webmaker(WebHosting_AI_agent 1.8.0 — 0.2.0 에서 직접 편집(시각 편집기) 포함; 0.1.1 은 1.7.3). 기존 서버 배치(/srv/webmaker/current, /data/webmaker, 유닛 webmaker, 포트 3080)를 존중한다 — install 은 releases 에 풀고 current 를 바꾸며,
2026-10-26 13:38:45 +00:00
// 유닛은 서버에 이미 있고 <appDir>/current 를 가리키면 그대로 둔다(keepExistingUnit — 운영 서버의 강화 지시문·ReadWritePaths 보존, 실제 환경 결함 수정). 없을 때만 deploy/units/webmaker.service.tmpl 로 만든다.
2026-10-28 15:07:35 +00:00
// 원본 deploy/remote-update.sh 의 절차(백업→전송→교체→재시작→확인)를 Agent 가 같은 순서로 수행한다. 실제 버전은 REVISION.json 의 Suite 릴리스 버전(package.json 1.8.0 은 upstreamVersion).
2026-10-26 13:38:45 +00:00
webmaker : { name : 'webmaker' , roles : [ 'web' ], layout : 'releases' , unit : 'webmaker' , unitTemplate : 'webmaker.service.tmpl' , keepExistingUnit : true , user : 'master' , port : 3080 , baseDir : '/srv/webmaker' ,
2026-10-26 11:58:15 +00:00
health : { url : 'http://127.0.0.1:3080/api/auth/csrf' , expect : 'any' }, version : { file : 'package.json' }, preStop : [ 'webmaker.backupData' ], postStart : [ 'webmaker.unitCheck' ], dataDirs : [ '/data/webmaker' , '/var/www/webmaker-sites' ], extraUnits : [ 'webmaker-setup' ] },
// 도입 모듈: AriMail 1.0.11. 서버마다 유닛 이름이 다르다(arihakdang-mail / arimail / heart-mail) — 서버 facts.arimail.unit 이 정한다. 설치는 원본 deploy/deploy.sh 와 같은 절차(테스트→릴리스 복사→DB 백업·마이그레이션→재시작→health)를 Agent 가 수행한다.
2026-10-26 13:38:45 +00:00
// 실행 계정이 Agent 와 다르면(ariweb.net 호스트의 arihakdang) Agent 가 deploy/module-as-user.sh 로 그 계정이 파일 작업을 하게 한다(실제 환경 결함 수정). 마이그레이션은 유닛의 EnvironmentFile(DB_FILE)을 같은 계정으로 읽어 실행한다.
2026-10-26 11:58:15 +00:00
arimail : { name : 'arimail' , roles : [ 'mail' ], layout : 'releases' , unit : 'arimail' , unitTemplate : null , user : null , port : 8790 ,
health : { url : 'http://127.0.0.1:8790/api/health' , expect : 'ok' }, version : { file : 'package.json' }, preStop : [ 'arimail.backupDb' ], postStart : [ 'arimail.migrate' , 'arimail.haraka' ], dataDirs : [ '<appDir>/data' ], copyPaths : [ 'server' , 'web' , 'lang' , 'migrations' , 'package.json' , 'haraka' ] },
backup : { name : 'backup' , roles : [ 'backup' , 'web' ], layout : 'agent-feature' , unit : null , health : { feature : 'backup' }, version : { agent : true }, dataDirs : [ '/srv/ariweb/backups' ] },
observability : { name : 'observability' , roles : [ 'control' , 'web' , 'mail' , 'backup' ], layout : 'agent-feature' , unit : null , health : { feature : 'metrics' }, version : { agent : true }, dataDirs : [] },
};
/** 릴리스 artifact 로 배포되는 모듈(agent-feature 는 Agent 안의 기능이라 별도 artifact 가 없다) */
export const ARTIFACT_MODULES = Object . values ( MODULES ). filter (( m ) => m . layout === 'releases' ). map (( m ) => m . name );
/** HAL 이 가장 먼저이고, 그다음 agent → portal → 도입 모듈 순으로 배포한다(§32.2) */
export const DEPLOY_ORDER = [ 'hal' , 'agent' , 'portal' , 'webmaker' , 'arimail' , 'backup' , 'observability' ];
export function descriptor ( name ) { const d = MODULES [ name ]; if ( ! d ) throw Object . assign ( new Error ( `알 수 없는 모듈: ${ name } ` ), { code : 'unknown_module' , status : 404 }); return d ; }