← 返回运营工作台

体验运营 · 接入与管理指南

协议 v1 · Unity / Godot / 其他引擎共享 · 测试接口与正式环境分开管理

日常管理从这里开始

  1. 确认顶部环境:测试和正式分别使用数据库、资源目录、管理凭据和设备凭据。同一个设备号可以分别配置,两边的场次、票码和收入互不读取。
  2. 在“项目与设备”选择现有项目代码,设置无票/有票规则与币种。若创建新项目,还要到“内容与发布管理”完成资源和版本发布。
  3. 分配设备号、门店、引擎、项目与用途。开发设备强制无票并单独统计;正式部署设备按项目/设备规则验票。已有场次须先结束才能修改设备。创建或轮换凭据时仅返回一次设备密钥。
  4. Unity 打开 ALabNext → 设备运营接入,选择当前场景的 ProjectConfig,启用运营,保存后台返回的设备凭据。它只保存在本机,打包设备可调用 StoreDeviceCredential(config, token);也可由部署进程设置 ALABNEXT_DEVICE_TOKEN。不要写进 AB 包。
  5. 有票测试:在“票务与订单”添加测试平台、创建订单,打开订单详情,登记测试收款,取得票码。在 Unity 运行模式设置本次票码后启动正常体验流程。无票设备无需订单。
  6. 内容准备完成后,原体验启动流程自动预约、确认启动并分发业务消息。体验结束发布 ExperienceCompleted;中断发布 StopExperience,也可显式调用 FinishAsync。后台可附原因人工关闭异常场次。
  7. 运营概览按项目、门店、设备、用途、引擎和收费平台分析;场次、订单及流水可分页与导出。导出最多 5000 行,更多数据请缩小时间范围或按 page 分页调用接口。

统计口径

指标定义
体验启动场次首次由 reserved 变为 running。下载、预约、打开应用和重复请求均不累计;确认后业务启动失败仍属于一次已启动的失败体验。
有票/无票按启动时的设备规则和项目规则快照统计。设备后续修改不改历史。开发设备始终归开发用途,默认为无票。
收入 / 退款 / 净收入按服务端确认的收退款流水发生时间,使用整数分。净收入=收款−退款;多币种分别展示,不换算合计。核销票面值与实收是不同指标。
日期与筛选界面自然日按香港 UTC+8,接口 from 包含、to 不包含,使用带时区 ISO 时间。启动统计按 started_at,流水按 occurred_at,订单列表按 created_at。设备/引擎筛选只影响场次,收入仍按项目/门店/用途/平台筛选,因为订单可能包含多张票、分配到不同设备。
预约/异常预约有效 15 分钟,未开场释放票。概览和设备后续请求会清理过期预约。运行心跳建议 30 秒,90 秒无心跳标记异常,不自动补造完成或退票。
退款规则任何退款使本订单全部未使用票失效。已消费票和已启动场次保留。退款金额不得大于净实收;退款不减少历史启动数。

设备接口

基础 URL:https://webadmin.allinxr.com/environments/test(正式替换为 production)。所有设备接口携带 Authorization: Bearer DEVICE_TOKEN。密钥绑定当前环境和设备。可选头 X-ALabNext-Environment: test 防止 URL 配错。

内容 / 配置准备→ reserve 预约→ start 确认启动→ 心跳 / 业务体验→ finish 结束
方法与路径(/api/runtime/v1)请求
POST /sessions/reservedeviceId, projectCode, requestId, engine(unity/godot/other,与后台一致),可选 ticketCode, appVersion, contentVersion
POST /sessions/{sessionId}/startdeviceId;服务端返回 running 后才触发业务。重复确认不会重复计数。
POST /sessions/{sessionId}/heartbeatdeviceId;读取返回状态,已结束就停止心跳。
POST /sessions/{sessionId}/finishdeviceId, outcome(completed/failed/aborted), reason。未启动的预约不能标记 completed。
GET /sessions/{sessionId}?deviceId=...只能查询自己的场次,返回当前持久化状态。
POST /api/runtime/v1/sessions/reserve
{
  "deviceId": "DEVICE_001", "projectCode": "PROJECT_A",
  "requestId": "每次新场次生成的UUID;重试保持原值",
  "engine": "unity", "appVersion": "1.0", "contentVersion": "v1"
}
HTTP 200
{"code":200,"environment":"test","data":{
  "session_id":"...","status":"reserved","admission_mode":"free"
}}

400 参数不合法;401 凭据无效;403 未分配项目或票码不适用;404 不存在;409 状态冲突。不要因超时换 requestId:原请求可能已经提交。相同 requestId 不允许换项目、票码或版本。设备同一时间最多一个预约/运行场次。

离线时不开始新的统计体验。启动前持久化 requestId 和请求内容,预约后保存 sessionId;崩溃重启先用原 ID 查询、补交结束回执,再开新场。Unity 已实现此回执流程,退出时未能联网会在下次启动补交。回执按服务器/环境/设备分目录,设备密钥不写入回执。

管理接口与订单

前缀 /api/admin/operations,使用当前环境的 OPS_ADMIN_TOKEN(测试对应 TEST_OPS_ADMIN_TOKEN)。未设置时可使用该环境 ADMIN_TOKEN;公网无凭据一律拒绝。仅独立本机测试服务可显式启用 loopback 开发模式。管理凭据与设备凭据不可混用。

接口内容
GET /bootstrap项目、渠道、设备分配与协议版本,不返回密钥。
POST /projectsprojectCode, projectName, admissionMode(free/ticketed), currency(CNY/HKD/USD/EUR), enabled
POST /devicesdeviceId, deviceName, projectCode, storeCode, purpose(development/production), engine, admissionMode(inherit/free/ticketed), enabled, rotateCredential。返回 deviceToken 仅创建/轮换时存在。
POST /channelschannelCode, channelName, enabled
POST /ordersprojectCode, channelCode, externalOrderId, amountMinor(整数分), currency, quantity(默认1,最多100), storeCode, purpose, expiresAt(可选,默认30天), orderId(可选)。返回订单与每张票;平台+外部订单号唯一。
POST /paymentsorderId, kind(payment/refund), amountMinor, currency, eventId, transactionId, reason。付款需整单全额。相同事件/交易重放相同内容不会多记,不允许换金额。仅用于管理端登记测试记录。
GET /dashboardtotals, projects, devices, trend, revenue, channels, ticketValues,均以服务端数据计算。
GET /sessions /orders /ledger分页结果 rows,total,limit,page;公共筛选 projectCode,storeCode,purpose,channelCode,from,to;场次另支持 deviceId,engine。
GET /sessions.csv /orders.csv /ledger.csv相同筛选,防止表格公式注入,导出条数由 X-Export-Total/X-Export-Limit 标记。
GET /orders/{id} /audit订单详情及票/流水;最近200条管理审计。
POST /sessions/{id}/finishoutcome,reason(必填),人工处理异常,有审计记录。

所有管理写操作保留审计;X-Operator 可标注操作者,当前为环境管理密钥授权,不是独立多用户角色权限系统。流水只追加,通过退款冲销,不支持删除收入历史。

通用收款回调(测试契约)

POST /api/integrations/v1/payments/{channelCode},请求体与 payments 相同。服务端配置 OPS_WEBHOOK_KEYS_JSON / TEST_OPS_WEBHOOK_KEYS_JSON,值为渠道代码到独立密钥的 JSON 字典。未配置的渠道拒绝回调。

const raw = JSON.stringify(paymentEvent);
const timestamp = String(Math.floor(Date.now()/1000));
const signature = crypto.createHmac('sha256', channelSecret)
  .update(timestamp + '.' + environment + '.').update(raw).digest('hex');
// Send exact raw bytes with Content-Type: application/json
// X-Ops-Timestamp: timestamp
// X-Ops-Signature: signature

时间窗 ±300 秒,签名绑定环境和原始请求字节;eventId、transactionId 保持稳定。通用回调本身不是任何第三方官方 SDK,后续平台适配器负责官方签名验真、交易状态核对和金额校验。

Godot 4 / 其他引擎

下载 Godot 4 HTTP 接口适配器,添加到场景树后在运行时 configure。适配器只封装协议和同请求重试,宿主项目应实现扫码界面、持久化回执及业务状态恢复。

var ops = ALabNextOperationsClient.new()
add_child(ops)
ops.configure(environment_url, device_id, device_token)
var request_id = ALabNextOperationsClient.new_request_id()
# Save request_id + project/ticket before sending, scoped by environment/device.
var reserved = await ops.reserve(request_id, project_code, ticket_code)
if reserved.ok:
    var session_id = reserved.data.session_id
    # Save session_id; do not generate a new request ID on a timeout.
    var started = await ops.start_session(session_id)
    if started.ok and started.data.status == "running":
        begin_experience_once(session_id)
# Heartbeat every 30s; finish on actual completion; recover receipt after restart.

Android 导出需开启 INTERNET 权限。适配器基于 Godot 官方 HTTPRequest 接口。使用其他语言的项目可直接实现相同 REST 契约,设备用途、票务和收入规则始终由后台决定。

版本:2026-10-03 · 标准接口独立于 image tracking、XR 平台与资产加载实现。