体验运营 · 接入与管理指南
协议 v1 · Unity / Godot / 其他引擎共享 · 测试接口与正式环境分开管理
日常管理从这里开始
- 确认顶部环境:测试和正式分别使用数据库、资源目录、管理凭据和设备凭据。同一个设备号可以分别配置,两边的场次、票码和收入互不读取。
- 在“项目与设备”选择现有项目代码,设置无票/有票规则与币种。若创建新项目,还要到“内容与发布管理”完成资源和版本发布。
- 分配设备号、门店、引擎、项目与用途。开发设备强制无票并单独统计;正式部署设备按项目/设备规则验票。已有场次须先结束才能修改设备。创建或轮换凭据时仅返回一次设备密钥。
- Unity 打开 ALabNext → 设备运营接入,选择当前场景的 ProjectConfig,启用运营,保存后台返回的设备凭据。它只保存在本机,打包设备可调用
StoreDeviceCredential(config, token);也可由部署进程设置ALABNEXT_DEVICE_TOKEN。不要写进 AB 包。 - 有票测试:在“票务与订单”添加测试平台、创建订单,打开订单详情,登记测试收款,取得票码。在 Unity 运行模式设置本次票码后启动正常体验流程。无票设备无需订单。
- 内容准备完成后,原体验启动流程自动预约、确认启动并分发业务消息。体验结束发布
ExperienceCompleted;中断发布StopExperience,也可显式调用FinishAsync。后台可附原因人工关闭异常场次。 - 运营概览按项目、门店、设备、用途、引擎和收费平台分析;场次、订单及流水可分页与导出。导出最多 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 配错。
| 方法与路径(/api/runtime/v1) | 请求 |
|---|---|
| POST /sessions/reserve | deviceId, projectCode, requestId, engine(unity/godot/other,与后台一致),可选 ticketCode, appVersion, contentVersion |
| POST /sessions/{sessionId}/start | deviceId;服务端返回 running 后才触发业务。重复确认不会重复计数。 |
| POST /sessions/{sessionId}/heartbeat | deviceId;读取返回状态,已结束就停止心跳。 |
| POST /sessions/{sessionId}/finish | deviceId, 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 /projects | projectCode, projectName, admissionMode(free/ticketed), currency(CNY/HKD/USD/EUR), enabled |
| POST /devices | deviceId, deviceName, projectCode, storeCode, purpose(development/production), engine, admissionMode(inherit/free/ticketed), enabled, rotateCredential。返回 deviceToken 仅创建/轮换时存在。 |
| POST /channels | channelCode, channelName, enabled |
| POST /orders | projectCode, channelCode, externalOrderId, amountMinor(整数分), currency, quantity(默认1,最多100), storeCode, purpose, expiresAt(可选,默认30天), orderId(可选)。返回订单与每张票;平台+外部订单号唯一。 |
| POST /payments | orderId, kind(payment/refund), amountMinor, currency, eventId, transactionId, reason。付款需整单全额。相同事件/交易重放相同内容不会多记,不允许换金额。仅用于管理端登记测试记录。 |
| GET /dashboard | totals, 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}/finish | outcome,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 平台与资产加载实现。