6 Commits
Author SHA1 Message Date
maxfandClaude d6d034727b feat: 邮箱找回密码 + 日志体系完善 + SMTP 配置补全
## 功能
- 邮箱找回密码:新增 password_resets 表 + POST /api/auth/forgot-password
  (按接收邮箱反查用户 → 生成一次性 30 分钟令牌 → 复用 SMTP 发重置邮件,
   防枚举统一提示、复用登录限流器防刷)+ POST /api/auth/reset
  (校验令牌有效性 → bcrypt 更新密码 → 作废令牌 → 强制该用户全部会话下线);
  H5 新增 /forgot、/reset 页面,登录页加"忘记密码"入口
- SMTP 全局配置补全:新增发件邮箱 smtp_user / 授权码 smtp_pass 字段
  (H5 + 小程序设置页同步展示与保存),GET 脱敏回显,
  修复"脱敏值含 * 被 POST 写回覆盖真实配置"的 bug
- 新增 cmd/sendmail 真实发送工具(配置走环境变量,敏感信息不落库,
  已用 163 SMTP 465 隐式 SSL 实测发送成功)

## 日志体系
- 死配置 OIL_MONITOR_LOG_DIR 替换为 OIL_MONITOR_LOG_LEVEL
  (debug/info/warn/error,LevelVar 动态切换,上线默认 info 收敛日志)
- 自定义 requestLogger 请求日志中间件(Debug 级:method/path/status/耗时/IP)
- 外部交互日志统一:爬虫抓取 / SMTP / Webhook / 高德 regeo / 微信 code2session,
  成功 Debug、失败 Error、均带 dur_ms、URL 去 query 脱敏防 key/token 泄露
- 定时任务统一 runTask 包装:开始 Debug、完成+时长 Info、失败/panic Error
  (panic 被 recover,不连累调度器)

## 测试
- cron/scheduler_test.go:runTask 成功/失败/panic 三路径单测
- push/sender_test.go:本地假 SMTP 服务器完整发送会话链路 + 服务器拒绝失败路径
- db_test.go:表数量断言 11 → 12(新增 password_resets)

## 部署配置与文档
- Dockerfile / docker-compose.yml / .env.example / README:日志配置同步
  (删 /app/logs 目录与挂载,OIL_MONITOR_LOG_LEVEL)
- .gitignore:忽略 internal/pkg 依赖缓存(349M,防误提交)
- docs/10/21/22/23/24:同步 A18/A19 接口、password_resets 表、任务执行日志、SMTP 字段

Co-Authored-By: Claude <noreply@anthropic.com>
2026-09-28 10:26:59 +08:00
maxf 2f13706e54 ## 🎯 项目最终状态
| 维度 | 状态 |
|---|---|
| 三阶段功能(监控/小程序/记账) | ✅ 完整 |
| 代码质量 | ✅ build/vet/test 全绿(12 项单测包) |
| 部署 | ✅ Dockerfile + compose(健康检查/重启/持久化)|
| 安全加固 | ✅ 登录限流 + 采集告警 |
| 文档 | ✅ README + .env.example + 17 份设计 |
| **代码侧交付** | ✅ **已完全可交付** |

**剩余上线事项(需你操作外部资源)**:
1. **HTTPS + 域名**(Nginx/Caddy 反代 + Let's Encrypt)
2. **微信小程序后台**(AppID/合法域名/类目/隐私协议/审核发布)
3. **高德 Key**(admin 设置页配置)
4. **数据源上线监控**(盯日志确认采集正常)

代码侧已就绪,`docker compose up -d --build` 即可跑起来。
2026-09-25 17:18:59 +08:00
maxf 28fcfc6aec ## 1️⃣ 文档与代码一致性 ✅(修复 4 处滞后)
**发现并已修复的文档滞后**(后期代码先于文档,审计时补齐):

| 滞后点 | 修复 |
|---|---|
| `24.附录` users 表缺 `wechat_openid` 列(二期微信登录加的) | ✅ 已补 |
| `24.附录` 缺 `refuel_records` 表(三期记账) | ✅ 已补 |
| `24.附录` 错误码缺 `1012/1013`(三期) | ✅ 已补 |
| `34.附录` 小程序页面目录缺 `calc/refuels`(三期) | ✅ 已补 |

**核对一致项**:
- API 路由 **A1-A23 + `/api/auth/wechat`** 全部注册,与 22/33/43 文档逐项对应
- `schema.sql` 11 表 = 24 附录(10 + refuel)+ 45 附录
- 小程序 8 页文件齐全(js/wxml/wxss/json × 8),`refuels.wxml` 数据绑定与 js 匹配
- H5 8 页面全部可访问

## 2️⃣ 后期变更对前期的影响 ✅ 无破坏

综合回归 **20 项全 PASS**:
- **一期**:账号密码登录 / Cookie 会话 / dashboard / provinces(31省) / history ✅
- **二期**:Bearer token 认证(与 Cookie **双通道共存**,互不冲突)✅
- **三期**:refuel 首条保存 / 区间油耗 8.25 / 统计 / 预填 ✅
- **前端**:9 个资源(8 页 + 静态 JS)全部 200 ✅

关键:二期的 `users` 加列是**幂等增量迁移**(ALTER),未动一期任何表结构;一期 API 与前端全部正常。

## 3️⃣ 整体可行性 ✅ 在可控范围

| 维度 | 状态 |
|---|---|
| 构建/静态检查 | `go build / vet` 全绿 |
| 单元测试 | 6 包 17 单测全过(auth/crawler/cron/db/push/service) |
| 规模 | 11 表 · 23+ 接口 · 8 H5 页面 · 8 小程序页面 · 17 份文档 · ~90 代码文件 |
| 三阶段功能 | 监控预测提醒 → 微信小程序 → 加油记账/真实油耗,全部落地 |

**非阻塞小项**(可后续优化,不影响运行):
1. `refuels.wxml` 第 11 行 `wx:for` 与 `wx:if` 同节点——功能正常,写法可规范
2. api 包 handler 层无独立单测——由端到端回归覆盖(service 层已有单测)

---

**结论:项目整体健康、文档与代码对齐、三阶段功能完整可用。** 4 处文档滞后已修复,无功能性问题。可以进入部署/上线阶段。
2026-09-25 16:56:07 +08:00
maxf 6e4cb0250f 二期微信小程序**全部完成**。交付如下:
## ✅ 二期交付:微信小程序(全量 6 页 + 后端适配)

### 后端改造(API-First 已铺路,小程序零改动复用)

| 改动 | 说明 |
|---|---|
| **Bearer token 认证** | `auth` 中间件同时支持 Cookie(H5)与 `Authorization: Bearer <token>`(小程序) |
| **`POST /api/auth/wechat`** | `wx.login` code → 微信 `jscode2session` 换 openid → 按 `wechat_openid` 查/建用户 → 建会话,**首微信用户自动成为 admin** |
| **`users.wechat_openid` 列** | schema 更新 + **幂等迁移**(旧库自动 `ALTER TABLE`,不丢数据) |
| **全局设置支持微信配置** | `server_settings` 加 `wechat_appid`/`wechat_secret`,H5 与小程序设置页均可配置 |

### 小程序前端 `miniprogram/`(原生,无框架依赖)

```
miniprogram/
├─ app.js / app.json / app.wxss / project.config.json / sitemap.json
├─ utils/
│  ├─ api.js      wx.request 封装(自动带 Bearer,401 跳登录)
│  ├─ auth.js     最近 5 省 LRU + 格式化
│  └─ chart.js    轻量 canvas 折线图(不引 echarts,控制包体)
└─ pages/(6 页,均 4 文件)
   ├─ index      看板:倒计时/预测/当前价/国际油价图/爱车卡片
   ├─ province   最近 5 省 + 31 省分组网格(带 92# 角标)
   ├─ login      微信一键登录
   ├─ vehicles   车辆 CRUD + 调价影响
   ├─ settings   个人偏好 + admin 全局(含微信 AppID/Secret)
   └─ history    年度汇总 + 92# 阶梯图 + 调价记录
```

### 运行方式

```bash
# 1. 启动后端
go run ./cmd/server

# 2. 微信开发者工具
#    - 导入 miniprogram/ 目录
#    - 勾选「不校验合法域名」(本地调试)
#    - app.js 里 baseUrl 指向 http://localhost:8080

# 3. 登录准备
#    先在 H5 或小程序设置页(admin)配置小程序 AppID / AppSecret
```

### 设计对齐
- **定位**:`wx.getLocation` → 后端 `/api/location/regeo`(无需前端高德 Key)
- **登录**:微信一键,与 H5 账号体系共用一张 `users` 表(`wechat_openid` 关联)
- **API**:A1-A17 原样复用,小程序端零后端改动

### 验证状态
- 后端:`go build` / `go vet` / `go test ./...` **全绿**
- 小程序:6 页结构完整,语法经微信开发者工具编译验证(需你本机导入真机预览)
2026-09-24 22:33:52 +08:00
maxf 563052575a 阶段一(MVP 全栈)**全部完成**。最终交付如下:
## ✅ 完整系统已可运行

```
F:\coding\oil-price-monitoring\
├─ cmd/server/main.go           入口(DB + cron + HTTP)
├─ internal/
│  ├─ api/        A1-A17 全部接口 + 路由 + 前端挂载
│  ├─ auth/       bcrypt / 会话 / auth+admin 中间件
│  ├─ crawler/    三路采集器(sina/ndrc/qiyoujiage)+ 测试
│  ├─ cron/       T1-T6 调度 + 预测 + 推送 + 工作日计算
│  ├─ db/         schema.sql(8 表)+ 迁移 + 测试
│  ├─ model/      领域模型
│  ├─ push/       飞书/企微/钉钉/SMTP 发送器 + 测试
│  ├─ service/    共享 impact / province 服务
│  └─ web/        前端 6 页面(embed 进二进制)
├─ Dockerfile + docker-compose.yml + .gitignore
└─ docs/          10.概要设计 + 20-24.详细设计(6 份)
```

## 🚀 运行方式

```bash
# 本地
go run ./cmd/server           # 打开 http://localhost:8080

# 服务器(Docker)
docker compose up -d --build  # 单镜像 ~20MB,数据挂载 ./data
```

## ✅ 真实数据链路验证(本次开发实测)

| 链路 | 结果 |
|---|---|
| 新浪原油 | `Brent=99.45 WTI=93.24`(实时) |
| 发改委今日调控 | 汽 **+395 元/吨(应调+830)** 柴 +385(应调+800),生效 9/25 00:00 |
| 31 省价格 | 北京 92#=8.29 / 95#=8.83 / 98#=10.33 / 0#=8.02 |
| API 端到端 | dashboard/provinces/history/vehicles CRUD/settings/auth 全部通过 |
| 前端页面 | 6 页全部 200,静态资源正常 |

## 📌 系统能力速览

- **匿名访客**:看行情 / 省份切换(最近 5 省 LRU)/ 历史调价 / 浏览器定位(Geolocation→高德逆编码)
- **登录用户**:车辆管理(CRUD + 调价成本测算 + 加油建议)、个人推送渠道配置
- **后台自动**:每日 05:00 原油采集→05:05 预测;调价日 16-18 点高频监测发改委→入库→重算预测→同步 31 省→按用户推送(飞书/企微/钉钉/SMTP)
- **admin**:首用户自动成为管理员,可配高德 Key / SMTP 服务器
2026-09-24 21:13:58 +08:00
maxf 001922327c 文档完善 2026-09-24 14:49:27 +08:00