RIDM Apps 部署指南

RIDM Apps 是連結 GitHub 儲存庫後自動建置、部署,並以 <name>.ridm.ai 公開的託管服務。請在主控台的 我的應用程式 申請,價格請見 價格頁面。使用條件由 服務條款 第3章(韓文) 規定。想一眼看懂包含哪些功能,請見 應用程式託管介紹。

部署流程

  1. 申請 — 在「我的應用程式」選擇方案與網址(子網域)。網址之後無法變更。
  2. 連結 GitHub — 在應用程式畫面安裝 GitHub App ridm-apps-builder,選擇儲存庫與分支。權限只有儲存庫的讀取權。
  3. Push — 每次 push 到連結的分支都會開始建置。建置紀錄與失敗日誌會顯示在應用程式畫面上。
  4. 首次部署 — 建置成功後會經過自動檢查,隨即公開(見下文)。之後的 push 也會自動反映。

Dockerfile 需求

Next.js 入門範本

在 next.config.js 加入 output: 'standalone',並把下面的 Dockerfile 放在儲存庫根目錄。若沒有 public 資料夾,請刪除那一行。

FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM node:22-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM node:22-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build --chown=1000:1000 /app/public ./public
COPY --from=build --chown=1000:1000 /app/.next/standalone ./
COPY --from=build --chown=1000:1000 /app/.next/static ./.next/static
USER 1000
EXPOSE 3000
CMD ["node", "server.js"]

不是 Next.js 也可以。只要是在連接埠 3000 回應的容器,任何技術堆疊都能運作。

執行環境

Cookie

由於許多合作夥伴的應用程式都在 ridm.ai 底下,閘道會把 Cookie 只綁定在各應用程式自己的網址。應用程式的程式碼照常使用 Cookie 即可。不過請注意:

資料庫

每個應用程式都會建立專屬的 PostgreSQL 資料庫,連線資訊以環境變數提供:DATABASE_URL(必須使用 SSL)以及 PGHOST、PGPORT、PGDATABASE、PGUSER、PGPASSWORD、PGSSLMODE。容量上限依方案而不同,使用量會顯示在應用程式畫面上。

資料庫連線使用連憑證都會完整驗證的 TLS。憑證簽發機構(Amazon RDS)的憑證已預先安裝在容器中(NODE_EXTRA_CA_CERTS、PGSSLROOTCERT),程式碼中不需要另外加 SSL 選項 — new Pool({ connectionString: process.env.DATABASE_URL, max: 2 }) 就夠了。每個應用程式最多 3 個連線,因此連線池大小請設在 2 以下。

環境變數

在主控台加入機密金鑰(由人操作)

任何名稱都可以由人在主控台加入。AI 工具無法設定的名稱(見下文)也用這個方法加入。

  1. 登入 console.hrum.ai,打開左側選單的我的應用程式。
  2. 把應用程式卡片往下捲,找到環境變數區塊。已儲存的名稱會以 •••••••• 代替值顯示。
  3. 在第一欄名稱(例如:STRIPE_SECRET_KEY)輸入名稱。小寫或其他字元會在輸入時自動轉成大寫與底線。
  4. 在第二欄值貼上值。這個欄位會像密碼一樣隱藏顯示。
  5. 按下儲存,會顯示變數已儲存、應用程式即將重新啟動的確認訊息。以相同名稱再次儲存即可變更值。
  6. 要刪除時,按該列的刪除,再在確認視窗按刪除。刪除後應用程式會重新啟動,值無法復原。

搬移值的時候請注意:

用 AI 加入機密金鑰(AI 營運 token)

要讓 AI 程式開發工具代替人設定環境變數,需要 AI 營運 token。這是在核發主控台管理 token(hrum_cm_…,請見 用 AI 管理主控台)時,由人勾選 hosting_ops 權限的 token。有了這個權限,工具就不必每次作業都重新取得同意。為了不讓值經過 AI 模型,設定環境變數的功能沒有放進 HRUM MCP,請使用下面的 HTTP 路徑。

可透過 AI 途徑設定的名稱,只有以 _KEY、_SECRET、_TOKEN、_PASSWORD、_PASSWD、_PASS、_SALT、_CLIENT_ID 結尾的名稱(例如:STRIPE_SECRET_KEY、MASTER_KEY)。其中,會改變執行環境或連線位址的名稱也會被拒絕:以 _URL、_URI、_ENDPOINT、_HOST、_PROXY 結尾的名稱,以 NODE_、LD_、DYLD_、PYTHON、JAVA_、_JAVA_、JDK_、RUBY、PERL、GIT_、NPM_CONFIG_、GLOBAL_AGENT_、AWS_ENDPOINT_URL 開頭的名稱,以及 HTTP_PROXY、HTTPS_PROXY、NODE_TLS_REJECT_UNAUTHORIZED、SSL_CERT_FILE、PATH、OPENAI_API_BASE 等名稱。其他名稱(例如:ADMIN_PATH、SMTP_HOST)請由人 在主控台 加入。刪除也可以透過 AI 途徑進行(保留名稱除外)。

取得 token — 有效期間 30 天。

  1. AI 不需驗證,直接對 POST https://api.hrum.ai/api/v1/partners/v1/console-ai/consents 送出 {"action":"token_issue","payload":{"scopes":["hosting_ops"],"label":"My app ops"}}。回應的 data 中會有 consentUrl、userCode(8 碼)、code、pollSecret。
  2. AI 只向使用者顯示 consentUrl 與 8 碼代碼,不顯示 pollSecret。
  3. 由人在 10 分鐘內,用已登入主控台的瀏覽器打開連結,在確認碼欄位輸入 AI 工具畫面上的 8 碼代碼,勾選 hosting_ops 後按下同意。按下前請先閱讀勾選框下方的警告(token 外洩時,他人可能覆寫環境變數、部署、重新啟動)。
  4. AI 帶著 X-Consent-Poll-Secret 標頭呼叫 GET …/console-ai/consents/{code},在核准後的第一次回應中,會從 data.token.value 取得 token,僅此一次。請不要顯示在畫面上,直接存進機密儲存區(鑰匙圈、權限 600 的檔案等)。
  5. 不再需要時,在主控台 API 金鑰 畫面的「AI 主控台管理 token」按下撤銷,即刻失效。每個帳號有效的 token 最多 10 個。

呼叫 — 基本網址為 https://api.hrum.ai,標頭為 Authorization: Bearer hrum_cm_…。應用程式 ID 是 GET /api/v1/partners/v1/console-ai/hosting 回應中的 data.apps[].id(UUID)。

作業請求回應
名稱清單GET /api/v1/partners/v1/console-ai/hosting/apps/{appId}/env{"success":true,"data":{"env":{"names":[…]}}} — 不含值
新增、變更PUT …/hosting/apps/{appId}/env/{NAME},內容 {"value":"…"}更新後的名稱清單。應用程式會重新啟動
刪除DELETE …/hosting/apps/{appId}/env/{NAME}更新後的名稱清單。應用程式會重新啟動

範例(bash 或 zsh)。值與 token 不以命令列參數傳遞,值以標準輸入送出。$APP_ID 與鑰匙圈項目名稱請換成您自己的。

# 1) Read secrets into shell variables (nothing is printed)
HRUM_CM_TOKEN=$(security find-generic-password -s hrum-console-ops -w)
VALUE=$(security find-generic-password -s myapp-STRIPE_SECRET_KEY -w)

# 2) Value goes through stdin, token through a header file: neither shows up in ps or shell history
printf '%s' "$VALUE" | jq -Rs '{value: .}' | curl -s -X PUT \
  -H @<(printf 'Authorization: Bearer %s' "$HRUM_CM_TOKEN") \
  -H 'Content-Type: application/json' --data-binary @- \
  "https://api.hrum.ai/api/v1/partners/v1/console-ai/hosting/apps/$APP_ID/env/STRIPE_SECRET_KEY" \
  | jq '.data.env.names // .'

# 3) Forget the value
unset VALUE

儲存完成後,回應只會顯示名稱清單。請打開應用程式網址,確認應用程式已用新值重新啟動。

用 AI 部署與查看日誌(AI 營運 token)

用同一個 AI 營運 token(hosting_ops),不必進入網站,就能開始部署、查看部署狀態與應用程式輸出的日誌。

從 HRUM MCP 0.3.3 起,也能用 MCP 工具做同樣的事:hrum_hosting_deploy(開始部署)、hrum_hosting_deploys(部署狀態)、hrum_hosting_logs(執行日誌)。先用 hrum_ai_connect 取得具 hosting_ops 權限的 token 再呼叫,應用程式 ID 可在 hrum_hosting_status 查看。不使用 MCP 的工具請用下面的 HTTP 路徑。

作業請求回應
開始部署POST …/hosting/apps/{appId}/deploy,內容 {} 或 {"commit":"40-char sha"}{"deployId","commitSha","retried","status":"queued"}。與主控台的「立即部署」相同,建置所連結分支的最新 commit(首次部署審查與方案規則也相同)。commit 只接受該最新 commit — 舊的 commit 目前還不支援(400 COMMIT_NOT_BRANCH_HEAD)。每分鐘最多 2 次
部署狀態GET …/hosting/apps/{appId}/deploys?limit=20由新到舊:id、commitSha、status、queuedAt、startedAt、finishedAt、liveAt、failReason、scanFindings(僅列出機密值掃描命中的檔案、行數、規則)、logTail(建置日誌的結尾)、startFailReason、startFailLog
請求日誌POST …/hosting/apps/{appId}/logs,內容 {"lines":100}(1–200)202 {"requestId"}
取得日誌GET …/hosting/apps/{appId}/logs/{requestId}status 為 pending 時請在 2–3 秒後重試,為 delivered 時讀取 lines。超過 3 分鐘會變成 expired

日誌與失敗原因在送出前會被遮蔽:該應用程式儲存的環境變數值,以及 sk-…、AKIA…、Bearer …、JWT、…_live_… 這類金鑰形式的字串,都會變成 [redacted]。即便如此,最重要的仍是讓應用程式不要把機密值寫進日誌。所有呼叫(包含被拒絕的)都會連同 token、應用程式、結果一起記錄。

主控台登入工作階段或 HRUM MCP 登入工作階段也有相同的路徑:POST …/console/hosting/apps/{appId}/deploy-now(MCP 僅限透過註冊建立的工作階段)、GET …/console/hosting/apps/{appId}/deploys、POST …/console/hosting/apps/{appId}/logs,內容 {"lines":100}(1–200,MCP 僅限透過註冊建立的工作階段)→ GET …/logs/{requestId}。只能用於自己的應用程式,日誌內容依相同規則遮蔽。取得的日誌內容會在傳送(或請求)後 24 小時刪除(2026-12-01 起改為 7 天,服務條款 第20條第5項)。

HRUM_CM_TOKEN=$(security find-generic-password -s hrum-console-ops -w)
API=https://api.hrum.ai/api/v1/partners/v1/console-ai/hosting/apps/$APP_ID
git push origin main
curl -s -X POST -H @<(printf 'Authorization: Bearer %s' "$HRUM_CM_TOKEN") \
  -H 'Content-Type: application/json' -d '{}' "$API/deploy" | jq '.data // .'
curl -s -H @<(printf 'Authorization: Bearer %s' "$HRUM_CM_TOKEN") \
  "$API/deploys?limit=3" | jq '.data.deploys[] | {id, commitSha, status, liveAt, failReason}'

機密金鑰安全規則(AI 工具須遵守)

實際發生過的例子:一個正在製作銷售管理應用程式的 AI 工具,想把應用程式的主金鑰放進環境變數,但當時沒有可供 AI 使用的營運途徑,於是就停在那裡。現在像 MASTER_KEY 這樣以 _KEY 結尾的名稱,可以用 AI 營運 token 設定,其他名稱則由人在主控台加入。無論哪一種,值都不會經過聊天。

環境變數錯誤

錯誤內容的格式為 {"success":false,"statusCode":…,"message":"…"}。環境變數錯誤沒有 code,請以狀態碼與下列訊息的開頭來區分。API 以韓文回傳這些訊息,因此下表照原樣列出各訊息的開頭,並附上意思。訊息全文請見 llms.txt。

狀態訊息開頭原因 → 解決方式
400이름은 대문자·숫자·밑줄만(名稱只能用英文大寫、數字、底線)名稱不符合規則 → 只用英文大寫、數字、底線,不以數字開頭,最多 64 個字元
400플랫폼이 쓰는 이름이라(平台使用的名稱)PORT、HOSTNAME、NODE_OPTIONS、DATABASE_URL,或以 RIDM_ / PG 開頭的名稱 → 請改用其他名稱
400AI 연결이 자동으로 넣는 이름이라(由 AI 連結自動設定)HRUM_API_KEY → 此應用程式已開啟 AI 連結,由平台設定。若要自行設定,請關閉 AI 連結
400이 계정에서 발급한 API 키만 넣을 수 있어요(只能使用此帳號核發的金鑰)請使用在您自己主控台「API 金鑰」核發的金鑰
400AI 연결이 앱마다 만든 키는 넣을 수 없어요(不能使用 AI 連結為各應用程式建立的金鑰)請使用在主控台「API 金鑰」核發的金鑰
400값을 입력해 주세요(請輸入值)值是空的
400값에 줄바꿈을 넣을 수 없(值不能包含換行)多行的值(PEM 私密金鑰等)→ 轉成單行 base64 放入,在應用程式中解碼使用
400값은 2048바이트까지(值最多 2048 位元組)值超過 2KB → 較大的值請存在資料庫或外部機密儲存區
400실행 환경을 바꾸는 이름이라 AI 경로(會改變執行環境的名稱,AI 途徑不可用)AI 途徑拒絕的名稱 → 由人在主控台加入
400AI 경로(AI 운영 토큰·MCP)로는 _KEY(AI 途徑只能用 _KEY… 等結尾)不是機密名稱的結尾 → 更改名稱,或由人在主控台加入
400Validation failed (uuid is expected)應用程式 ID 不是 UUID → 請使用 GET /console-ai/hosting 的 apps[].id
401MGMT_TOKEN_INVALID沒有 token,或已過期、已撤銷 → 重新核發
403MGMT_SCOPE_DENIED (scope: "hosting_ops")token 沒有 hosting_ops → 勾選後重新核發
404앱을 찾을 수 없(找不到應用程式)其他帳號的應用程式或已刪除的應用程式 → 確認應用程式 ID
404없는 환경변수(不存在的環境變數)要刪除的名稱不存在 → 確認名稱清單
409해지된 앱은 환경변수를 바꿀 수 없(已解約的應用程式)應用程式正在解約中 → 無法變更
409환경변수는 앱당 50개까지(每個應用程式最多 50 個)刪除不用的名稱後再試一次
429—新增與刪除每分鐘最多 30 次 → 稍候再試
503환경변수 저장소가 준비되지 않(環境變數儲存區尚未就緒)伺服器端的問題 → 稍候再試,持續發生請與我們聯絡

AI 連結

這是由平台放入僅供此應用程式使用的 API 金鑰,讓應用程式可以呼叫八字 API 與 AI API 的功能。所有帳號都可以使用。

  1. 開啟 — 在主控台的 應用程式 打開應用程式詳細資料,開啟「使用 AI 連結」。系統會建立應用程式專用金鑰並放入環境變數 HRUM_API_KEY,應用程式會重新啟動。
  2. 呼叫 — 在應用程式的伺服器程式碼中讀取 process.env.HRUM_API_KEY,放進 X-Partner-Api-Key 標頭。金鑰的值在主控台也看不到。請不要放進會送到瀏覽器的程式碼。

開啟期間無法自行設定 HRUM_API_KEY。若已自行設定值,請在開啟前刪除(不刪除的話,會出現要求先刪除既有 HRUM_API_KEY 環境變數的錯誤)。用這個金鑰產生的費用會從您的點數扣除,達到在應用程式詳細資料中設定的每日使用上限後,當天就會停止。關閉後金鑰立即失效,再次開啟會建立新的金鑰。這個金鑰無法呼叫付款 API — 在應用程式中收款 請使用在主控台核發的金鑰。

在應用程式中收款

可以透過 HRUM 付款頁面向應用程式的使用者收款。以賣家(個人、個人事業、法人)身分登記並通過核准後,即可開始銷售。賣家登記請在主控台的 結算 進行。條件由 服務條款 第32–39條(韓文) 規定。免費方案的應用程式也可以銷售。不過,在達到每月傳輸量上限或遭停權而停止公開的期間,開啟新付款會以 409 APP_NOT_SERVING 拒絕。已開啟的付款、訂單查詢與退款仍可照常使用。

  1. 放入 API 金鑰 — 把在主控台 API 金鑰 核發的金鑰放進 環境變數(例如:HRUM_PARTNER_KEY)。「AI 連結」放入的 HRUM_API_KEY 無法呼叫付款 API。金鑰只在伺服器程式碼中使用,絕對不要送到瀏覽器。
  2. 登記商品 — POST /api/v1/partners/v1/storefront/skus,內容 {"appId","name","priceWon"}。付款只會以這裡登記的價格進行。
  3. 開啟付款 — 從伺服器以內容 {"appId","skuId","qty","returnUrl"} 送出 POST /api/v1/partners/v1/storefront/checkouts,並把使用者導向回應中的 checkoutUrl。returnUrl 只能是此應用程式的 https 網址(<name>.ridm.ai 或連結的網域)。
  4. 確認結果 — 付款完成後,使用者會回到 returnUrl?orderId=…。請在伺服器以 GET /api/v1/partners/v1/storefront/orders/{orderId} 確認 status 為 paid 後再提供商品。不要只相信網址上附帶的值。

所有請求都需要 X-Partner-Api-Key 標頭。需要退款時,請附上訂單編號寄信至 [email protected]。退款後,訂單的 status 會變為 canceled 或 partial_canceled。

const res = await fetch("https://api.hrum.ai/api/v1/partners/v1/storefront/checkouts", {
  method: "POST",
  headers: { "Content-Type": "application/json", "X-Partner-Api-Key": process.env.HRUM_PARTNER_KEY },
  body: JSON.stringify({ appId, skuId, qty: 1, returnUrl: "https://myapp.ridm.ai/paid" }),
});
const { checkoutUrl } = (await res.json()).data;

各金鑰權限可呼叫的項目

建立金鑰時可以選擇權限。呼叫所選權限以外的路徑會回傳 403 KEY_SCOPE_MISSING。未選擇權限的既有金鑰仍可呼叫所有路徑。完整路徑請見 OpenAPI 文件。

結算資料 API

可以從伺服器取得與 主控台 → 結算 畫面相同的數字。金鑰只能看到您自己的資料。期間 from / to 以韓國日期(YYYY-MM-DD,含首尾兩天)指定,留空則為本月。一次最多 366 天。

const res = await fetch("https://api.hrum.ai/api/v1/partners/v1/settlement/summary?from=2026-11-01&to=2026-11-30", {
  headers: { "X-Partner-Api-Key": process.env.HRUM_PARTNER_KEY },
});
const { sales, payouts, payoutFee } = (await res.json()).data;

賣家 Webhook

發生付款完成、退款、撥款時,會通知您的伺服器。網址只接受 https://(連接埠 443、8443),無法登記私有或內部位址。

  1. 登記網址 — PUT /api/v1/partners/v1/webhooks/endpoint,內容 {"url":"https://myapp.ridm.ai/hrum/webhook"}。回應中的 secret(whsec_…)只在此時顯示一次。請立即放進伺服器環境變數 HRUM_WEBHOOK_SECRET。要重新核發請送出 {"url": …, "rotateSecret": true}。
  2. 事件 — order.paid(付款完成)、order.refunded(一筆退款)、payout.scheduled(預定撥款)、payout.completed(撥款完成)、webhook.test(POST /webhooks/test)。內容為 {"id","type","created","data"},不含購買者資訊。同一件事只會以相同的 id 建立一次,請以 id 排除重複。
  3. 平台副本 — 以平台金鑰登記網址時,也會收到在該平台開立的賣家訂單之 order.paid、order.refunded 副本。標頭與簽章相同,id 與賣家端不同。data 中另外含有 sellerId、spaceId。
  4. 驗證簽章 — 標頭為 Hrum-Signature: t=<unix seconds>,v1=<hex>。v1 是以機密值計算(t + "." + the raw body as received)的 HMAC-SHA256。請拒絕超過 5 分鐘的 t。
  5. 重新傳送 — 若未在 10 秒內以 2xx 回應,會在 1 分鐘、5 分鐘、30 分鐘、2 小時、12 小時後重新傳送(最多 6 次)。傳送紀錄可用 GET /webhooks/deliveries 查看,重新傳送請用 POST /webhooks/deliveries/{eventId}/redeliver。
const crypto = require("node:crypto");
function verifyHrumWebhook(rawBody, header, secret, toleranceSec = 300) {
  const parts = Object.fromEntries(String(header || "").split(",").map((p) => p.trim().split("=")));
  const t = Number(parts.t);
  if (!Number.isInteger(t) || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
  const want = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest();
  const got = Buffer.from(parts.v1 || "", "hex");
  return got.length === want.length && crypto.timingSafeEqual(got, want);
}
// Express: verify the raw body before parsing it as JSON
app.post("/hrum/webhook", express.raw({ type: "application/json" }), (req, res) => {
  const raw = req.body.toString("utf8");
  if (!verifyHrumWebhook(raw, req.get("Hrum-Signature"), process.env.HRUM_WEBHOOK_SECRET)) return res.sendStatus(400);
  const event = JSON.parse(raw); // if event.id was already handled, just return 200
  res.sendStatus(200);
});

首次部署與自動檢查

第一次建置成功後,會經過自動檢查並自動核准,網址隨即公開。第一次部署公開之前,不會扣除付費方案的費用。儲存庫中含有機密值(金鑰、token、密碼)時,建置會失敗。即使發現新的對外連線對象、新的危險模式,或儲存庫擁有者變更,部署仍會自動反映,相關內容會被記錄。所有自動核准與檢查結果都會記錄,並由營運人員事後確認,若有問題可能會停止公開。停止公開時,會以電子郵件與應用程式畫面通知原因。禁止行為請見 條款 第26條(韓文)。

價格與上限

各方案的價格、記憶體、資料庫、每月傳輸量請見 價格頁面。付費方案的費用每月從儲值的點數中扣除。扣款日餘額不足時應用程式會停止,儲值後會自動恢復。每月傳輸量是傳給訪客的回應與應用程式對外送出的流量(包含呼叫外部 API、上傳、寫入資料庫)的合計。WebSocket 收送的訊框兩個方向都會計入。達到上限時,開啟中的 WebSocket 也會以 1008 關閉。達到上限時,公開與應用程式執行會一起停止(次月 1 日恢復);付費方案可在應用程式畫面購買傳輸量區塊,幾分鐘內就能恢復。達到 80% 與達到上限時,會以電子郵件通知您。

備份與解約

聯絡我們:contact@float.do