Files
cmbuyer/admin

采购服务

启动前必须显式设置下列环境变量;服务不提供默认管理员账号、密码或会话密钥。

变量 要求
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 内部原始截图的绝对私有目录;不得指向仓库或公开静态目录。

示例仅展示变量名,不提供可运行凭据:

$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 = '<内部截图绝对目录>'
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 被读取之前。