${label}
+ ${formatNumber(value)} + ${hint} +diff --git a/.env.example b/.env.example index 54abb0a..99aca20 100644 --- a/.env.example +++ b/.env.example @@ -28,6 +28,17 @@ FIELD_ENCRYPTION_KEY=replace-with-exactly-32-random-bytes-as-base64 IDENTITY_HMAC_KEY=replace-with-a-distinct-32-random-bytes-as-base64 IDENTITY_TOMBSTONE_RETENTION_DAYS=365 +# Admin console. Enable bootstrap for the first successful startup only, then +# set it back to false and remove all four ADMIN_BOOTSTRAP_* credential values. +ADMIN_ENABLED=false +ADMIN_BOOTSTRAP_ENABLED=false +ADMIN_BOOTSTRAP_OPERATOR_ID=replace-with-random-uuid +ADMIN_BOOTSTRAP_USERNAME=owner +ADMIN_BOOTSTRAP_PASSWORD_HASH=replace-with-argon2id-phc-hash +ADMIN_BOOTSTRAP_TOTP_SECRET_BASE32=replace-with-random-base32-secret +ADMIN_SESSION_HOURS=8 +ADMIN_MAXIMUM_MANUAL_GRANT=100000 + # Apple identifiers are not secrets, but use the values from your own developer account. APPLE_TEAM_ID=replace-with-apple-team-id APPLE_KEY_ID=replace-with-apple-key-id diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8068399..670fb25 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,11 @@ jobs: steps: - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: "22" + cache: npm + cache-dependency-path: admin-web/package-lock.json - uses: actions/setup-java@v4 with: distribution: temurin diff --git a/admin-web/.gitignore b/admin-web/.gitignore new file mode 100644 index 0000000..3bdd52e --- /dev/null +++ b/admin-web/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +dist/ +.DS_Store diff --git a/admin-web/index.html b/admin-web/index.html new file mode 100644 index 0000000..59999fd --- /dev/null +++ b/admin-web/index.html @@ -0,0 +1,14 @@ + + +
+ + + + +| UTC 日期 | 新增用户 | 消耗积分 |
|---|---|---|
| ${escapeHtml(point.date)} | ${formatNumber(point.registrations)} | ${formatNumber(point.creditsUsed)} |
${escapeHtml(label)}…
+${escapeHtml(message)}
+ ${retry ? '' : ""} +${escapeHtml(message)}
追踪管理员操作、目标和执行结果。
+| 时间 | 操作员 | 操作 | 目标 | 请求 ID | 结果 |
|---|
${escapeHtml(entry.action)}安全、克制、可追溯的运营管理
+使用管理员凭据和认证器动态验证码登录。凭据不会保存到浏览器。
+ + `); + + const form = root.querySelector按内部用户 ID 查询不可变积分流水。
+| 时间 | 流水号 | 类型 | 变动 | 结余 | 原因 |
|---|---|---|---|---|---|
| ${formatDateTime(entry.createdAt)} | +${escapeHtml(entry.entryId)} | +${statusLabel(entry.type)} | +${formatSignedCredits(entry.amount)} | +${formatNumber(entry.balanceAfter)} | +${escapeHtml(entry.reasonCode)} | +
快速掌握增长与积分消耗情况。
+按 UTC 日期统计注册数
按类型统计,不包含用户内容
当前周期暂无使用记录
' + : ` +| 类型 | 请求 | 消耗积分 | 语音毫秒 | 输入 Token | 输出 Token |
|---|---|---|---|---|---|
${escapeHtml(item.kind)} |
+ ${formatNumber(item.requests)} | +${formatNumber(item.chargedCredits)} | +${formatNumber(item.asrMillis)} | +${formatNumber(item.inputTokens)} | +${formatNumber(item.outputTokens)} | +
${label}
+ ${formatNumber(value)} + ${hint} +奖励以有效使用为前提,不以注册量代替真实转化。
+待资格确认
+ ${formatNumber(data.pendingBindings)} + 等待有效使用 +不符合奖励条件
+ ${formatNumber(data.ineligibleBindings)} + 未发放积分 +从分享至有效使用
按有效邀请数排序
| 名次 | 用户 ID | 邀请 | 有效 | 奖励积分 |
|---|---|---|---|---|
| ${index + 1} | +${escapeHtml(item.userId)} | +${formatNumber(item.invited)} | +${formatNumber(item.qualified)} | +${formatNumber(item.creditsEarned)} | +
管理运营人员、角色、登录锁定、会话与双重认证。
+已加载 ${operators.length} 个账户
| 管理员 | 角色 | 状态 | 最近登录 | 操作 |
|---|
请立即把 TOTP 密钥交给对应管理员,并确认已添加到认证器。
+${escapeHtml(provisioning.totpSecret)}
+
+ 按内部用户 ID 精确查询,不展示 Apple 身份标识。
+| 用户 | 状态 | 积分余额 | 注册时间 | 操作 |
|---|
${escapeHtml(user.userId)}
+不可变账本记录
| 时间 | 类型 | 变动 | 结余 | 原因 |
|---|
按使用类型汇总,不包含用户内容
| 类型 | 请求 | 消耗积分 | 语音时长(毫秒) | 输入 Token | 输出 Token |
|---|---|---|---|---|---|
${escapeHtml(item.kind)} |
+ ${formatNumber(item.requests)} | +${formatNumber(item.chargedCredits)} | +${formatNumber(item.asrMillis)} | +${formatNumber(item.inputTokens)} | +${formatNumber(item.outputTokens)} | +