Files
paygateway/.env.example
T

142 lines
8.0 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PayGateway 配置示例 —— 复制为 .env 后修改
# cp .env.example .env && vim .env
#
# 配置加载顺序:.env 文件(本文件) → 运行时设置(settings 表,可由管理后台改)
# 同名键后者覆盖前者;密钥类一律只从 .env 读取(不进 settings)。
#
# ⚠️ 重要:以下密钥更换会导致数据/会话不可恢复
# - ACCOUNT_MASTER_KEY:accounts.db / upstreams.db 全部密文无法解密
# - LEDGER_PRIVATE_KEY:旧账本条目验签失败
# - QR_TOKEN_SECRET:旧二维码套码 token 失效,需重生成
# - JWT_SECRET:所有登录会话失效(用户被踢下线,重新登录即可,无数据风险)
# ===== 网关监听 =====
# 网关业务端口(易支付 /mq / 套码 /qr 等),对外暴露用
GATEWAY_ADDR=:8080
# 管理后台端口(Vue3 SPA + REST API + WebSocket)
# 生产建议改为 127.0.0.1:8081 配合 nginx 反代,或不暴露
ADMIN_ADDR=:8081
# ===== 对外地址 =====
# 网关公网地址(用于向支付平台回调注册等)
# 同机填 http://127.0.0.1:8080;公网填隧道/域名,留空自动推断为 http://127.0.0.1:8080
EPAY_PUBLIC_BASE_URL=http://127.0.0.1:8080
# 可选设备事件适配器的服务端可达地址。
# PERSONAL_BASE_URL=
# 通道回调地址(一般无需手动设;启动时由隧道动态更新)
# ALIPAY_NOTIFY_URL=http://localhost:8080/alipay/notify
# WECHAT_NOTIFY_URL=http://localhost:8080/wechat/notify
# ===== 上游对接(已废弃 .env 方式!)=====
# 每个上游独立 pid + 密钥,AES-256-GCM 加密存于独立 upstreams.db。
# 网关不再读取 EPAY_PID / EPAY_KEY,未登记的上游一律拒绝下单。
# 配置入口:http://127.0.0.1:8081 → 上游对接 → 新增上游
# ===== 支付账户密钥(已废弃 .env 方式!)=====
# 全部走管理后台 → 账户池 → 新增账户 配置;AES-256-GCM 加密存 accounts.db
# 以下仅为历史字段注释,均不再读取:
# ALIPAY_APP_ID / ALIPAY_PRIVATE_KEY_FILE / ALIPAY_PUBLIC_KEY_FILE
# WECHAT_APP_ID / WECHAT_MCH_ID / WECHAT_API_KEY / WECHAT_IS_PROD
# ===== 订单自动关闭(动态关单窗口,docs/PLAN-DYNAMIC-CLOSE-ALLOC.md)=====
# 【商家通道】未支付订单自动关闭时间(分钟,0=不自动关闭)。
# 商家通道走官方 API、可主动查单、无监听延迟问题 → 固定窗口即可(默认 30min)。
# 关单前必查单:已支付→补账;查单失败→跳过留待调度器/人工池;确认未支付→才关闭。
ORDER_CLOSE_MINUTES=30
# 【个人免签通道】动态窗口由设备负载驱动,clamp 在 [MIN, MAX] 之间(仅影响 personal.* 通道)。
# 窗口 = clamp(设备一轮耗时(活跃账户数×配额×poll成本)×1.5 + 60s, MIN, MAX)
# - 低负载(1~2 活跃账户)→ 逼近 MIN:确认快,尽早释放池配额
# - 高负载(多账户积压)→ 逼近 MAX:给设备更多确认时间,防误关已付款订单
# 0 或 MIN>=MAX → 个人免签退化为 ORDER_CLOSE_MINUTES 静态窗口
# 注意:窗口只影响「未支付订单」何时关,已付款订单始终秒级入账,不受影响
# 动态窗口下限(分钟,默认 5):下限锚点 = 用户扫码→支付操作时间(30s~2min) + 一轮完整确认
ORDER_CLOSE_MIN=5
# 动态窗口上限(分钟,默认 10):上限锚点 = 用户体验红线;超过转人工异常池升级处理,不是无限挂起
ORDER_CLOSE_MAX=10
# 关闭扫描间隔秒数(动态窗口下建议 30s 起,跟随 MAX 窗口粒度)
ORDER_CLOSE_INTERVAL=30
# ===== 设备负载均衡(docs/PLAN-DYNAMIC-CLOSE-ALLOC.md §4.5/§5)=====
# 单设备 WAIT_PAY 订单承载上限(0=按公式自动算:(MAX-60s)/(单次poll 4s)≈135)
# 设备超限 → 均衡分配器跳过该设备,新单路由到其他健康设备
DEVICE_LOAD_CAP=0
# 设备降权阈值(占 DEVICE_LOAD_CAP 比例,默认 0.8):超过后该设备在分配中降权(缓冲带)
DEVICE_OVERLOAD_RATIO=0.8
# 单次 poll 成本估算(ms,动态窗口/设备能力计算用;埋点校准后可留 0)
# DEVICE_POLL_COST_MS=4000
# ===== 存储 / 日志 =====
# 业务库 SQLite 路径(订单/异常池/回调队列/设置)
ORDER_DB=data/paygateway.db
# 日志文件路径(slog JSON + 按天分文件:{date} 自动替换为当天日期,如 paygateway-2026-08-18.log)
# 每文件 50MB 封顶、保留 10 份 × 30 天,超过自动清理;日志同时写入独立日志库 data/logs.db(长期保存)
LOG_FILE=logs/paygateway-{date}.log
# 日志级别:debug / info / warn / error
LOG_LEVEL=info
# ===== 管理后台鉴权 =====
# 管理员凭据已迁移到主数据库(settings 表,bcrypt 哈希),不再使用环境变量。
# 首次启动(DB 无管理员时)访问管理后台自动进入注册页;注册后入口自动关闭。
# 重置管理员:删除 paygateway.db settings 表中 admin_username / admin_password_hash 两行后重启。
# JWT 签名密钥:留空 = 每次重启随机生成(重启后需重新登录)
# 持久化方法:固定为 64 位十六进制(openssl rand -hex 32);更换会踢所有已登录用户下线
# JWT_SECRET=
# ===== 加密 / 签名密钥(前 3 个缺失=服务拒绝启动;后 3 个可空)=====
# 【必备·固定】账户加密主密钥:accounts.db / upstreams.db 全部密文用此加解密
# 首次部署生成:openssl rand -hex 32
# ⚠️ 一旦部署,永不能改 —— 改了等于丢掉所有已配置账户/上游密钥
ACCOUNT_MASTER_KEY=REPLACE_WITH_openssl_rand_hex_32
# 【可选·推荐固定】审计账本签名私钥(ECDSA P-256 PEM 格式)
# 留空 = 首次启动自动生成并持久化到 settings 表(重启复用)
# 显式提供可跨实例迁移账本;更换则旧账本条目验签失败
# LEDGER_PRIVATE_KEY=
# 【可选·推荐固定】个人免签套码 token 签名密钥
# 留空 = 首次启动自动生成并持久化到 settings 表(重启复用)
# 更换则旧"用户扫码 → /mq/{token}"链接全部失效,需在管理后台重新生成套码
# QR_TOKEN_SECRET=
# ===== 个人免签风控(金额单位均为分)=====
# 单笔限额(默认 50000 = 500 元;0 = 不限)
# PERSONAL_MAX_AMOUNT=50000
# 大额告警阈值(默认 20000 = 200 元;超此触发 Bark / Webhook 告警)
# PERSONAL_BIG_AMOUNT=20000
# 单设备每分钟收款推送上限(默认 30;超过则限流,防止监听端异常刷消息)
# PERSONAL_MAX_PER_MIN=30
# ===== 告警(RESILIENCE.md P1-3)=====
# Bark 推送 URL(https://api.day.app/<key>),空=禁用
# ALERT_BARK_URL=
# 通用 Webhook URL(POST JSON:掉线 / 账本异常 / 风控文案检测)
# ALERT_WEBHOOK_URL=
# ===== 公网接口 IP 限流(防刷 / 防 DoS)=====
# 窗口内单 IP 最大请求数(仅作用于 /submit.php /api.php /qr/refresh /mq/:token,不影响 /alipay/notify /wechat/notify /personal/* 签名回调),0=禁用
# PUBLIC_RATE_MAX=60
# 滑动窗口秒数,0=禁用
# PUBLIC_RATE_WINDOW_SEC=60
# ===== 可选二维码适配器 =====
# 具体模式由授权的业务适配器定义。
PERSONAL_QR_MODE=direct
# ===== Cloudflare 命名隧道(固定域名,生产环境推荐)=====
# 非空 = 命名隧道模式(cloudflared tunnel run --config,公网固定域名)
# 空 = 快速隧道(trycloudflare.com 随机域名,仅测试用,重启后域名变化)
CF_TUNNEL_HOSTNAME=your-domain.example.com
# 隧道凭据 JSON 的 base64 编码(含 TunnelID/AccountTag/TunnelSecret)
# 生成方法:base64 -w0 < ~/.cloudflared/paygateway.json
CF_TUNNEL_CREDENTIALS=your_base64_encoded_tunnel_credentials
# Cloudflare 账户邮箱(setup-domain.sh 需要)
CF_EMAIL=your-email@example.com
# Cloudflare Global API Key(setup-domain.sh 自动配置 zone/DNS/SSL)
CF_GLOBAL_KEY=your_global_api_key
# ===== DNSHe API(de5.net 免费子域名需要;setup-domain.sh 全自动处理)=====
# 脚本能力:子域名不存在时自动注册 + 自动把子域 NS 委派给 Cloudflare
DNSHE_API_KEY=your_dnshe_api_key
DNSHE_API_SECRET=your_dnshe_api_secret
DNSHE_API_BASE=https://api005.dnshe.com