采购服务
启动前必须显式设置下列环境变量;服务不提供默认管理员账号、密码或会话密钥。
| 变量 | 要求 |
|---|---|
CMBUYER_ADMIN_USERNAME |
非空管理员账号。 |
CMBUYER_ADMIN_PASSWORD_BCRYPT |
非空 bcrypt 密码哈希,不接受明文密码。 |
CMBUYER_SESSION_SECRET |
至少 32 字节的会话签名密钥。 |
CMBUYER_COOKIE_SECURE |
可选;存在时只能精确为 true 或 false。HTTPS 部署应设为 true。 |
CMBUYER_DATABASE_SOURCE |
已迁移 SQLite 的显式 data source。 |
CMBUYER_AUTHORIZATION_TTL |
一次性授权的正 Go duration,例如 10m。 |
CMBUYER_MAX_TASK_QUANTITY |
每条任务允许的正整数数量上限。 |
CMBUYER_MAX_TOTAL_PRICE |
每条任务允许的规范正数总价上限,例如 999.99。 |
CMBUYER_EVIDENCE_DIR |
内部原始截图的绝对私有目录;不得指向仓库或公开静态目录。 |
CMBUYER_CLAIM_TOKEN_SECRET |
claim token 专用 32 字节密钥的 64 位小写十六进制;不得复用 session 或设备 token。 |
CMBUYER_CLAIM_LEASE_TTL |
正 Go duration,且必须严格短于 CMBUYER_AUTHORIZATION_TTL。 |
示例仅展示变量名,不提供可运行凭据:
$env:CMBUYER_ADMIN_USERNAME = '<管理员账号>'
$env:CMBUYER_ADMIN_PASSWORD_BCRYPT = '<bcrypt 密码哈希>'
$env:CMBUYER_SESSION_SECRET = '<至少 32 字节的随机密钥>'
$env:CMBUYER_COOKIE_SECURE = 'true'
$env:CMBUYER_DATABASE_SOURCE = '<SQLite data source>'
$env:CMBUYER_AUTHORIZATION_TTL = '10m'
$env:CMBUYER_MAX_TASK_QUANTITY = '99'
$env:CMBUYER_MAX_TOTAL_PRICE = '999.99'
$env:CMBUYER_EVIDENCE_DIR = '<内部截图绝对目录>'
$env:CMBUYER_CLAIM_TOKEN_SECRET = '<64 位小写十六进制随机值>'
$env:CMBUYER_CLAIM_LEASE_TTL = '1m'
go run ./cmd/migrate -database $env:CMBUYER_DATABASE_SOURCE up
go run ./cmd/server
MVP 服务固定绑定 IPv4 回环 127.0.0.1:8080,只供同一运营电脑上的采购服务和采购工具使用。不要把监听地址
改成 0.0.0.0 或局域网地址;未来若需要非回环访问,必须先单独建立并验收 HTTPS/TLS 终止与代理
信任边界,设备 Bearer 不得经过明文局域网。
数据库迁移完成后,用同一个显式 SQLite data source 管理设备凭据:
# 签发:token 只在本次成功输出中显示一次,请立即放入采购工具的受控本机配置。
go run ./cmd/device-credentials -database $env:CMBUYER_DATABASE_SOURCE issue -name '<非秘密设备名称>'
# 仅显示设备 id、名称、状态和时间,不显示 token/hash。
go run ./cmd/device-credentials -database $env:CMBUYER_DATABASE_SOURCE list
# 撤销立即影响之后开始的每次设备请求;重复执行保持 REVOKED,不恢复旧 token。
go run ./cmd/device-credentials -database $env:CMBUYER_DATABASE_SOURCE revoke -device-id '<签发时的设备UUID>'
该 CLI 只接受已存在、已迁移的文件型 SQLite 普通路径或 file: URI,并强制以 mode=rw 打开;
路径拼错或文件缺失时 SQLite 原子拒绝且不会留下空数据库,也不接受内存、只读或可创建模式。CLI
不自动迁移。签发 token 是 32 字节加密随机值的 64 位小写十六进制表示;
SQLite 只保存原始 token 的 32 字节 SHA-256 BLOB。签发输出以外的 list/revoke、日志、错误和 HTTP
响应都不会显示 token 或 hash。
采购服务会话仅保存在当前进程内;进程重启后既有登录会话会安全失效。 管理员的“开始采购(只创建待付款订单)”只签发一次性授权并创建待付款订单的资格;服务不会自动付款,也不包含任何支付操作。
GET /tasks/{id} 直接访问时渲染完整详情页,任务列表以同一 URL 加载详情抽屉。内部截图只通过
GET /evidence/{asset_id} 向有效管理员会话提供,并始终返回 no-store;文件不在静态目录中。
POST /api/v1/tasks/{id}/evidence 使用 Authorization: Bearer <token> 和
X-CMBuyer-Device-ID: <小写UUIDv4> 逐请求查库认证;管理员会话不能代替设备身份。凭据错误统一空
401,SQLite 认证故障为空 503,且两者都发生在上传 body 被读取之前。