11 KiB
11 KiB
AGENTS.md
一个轻量、精美、移动端优先的个人加油记录与车辆燃油成本分析工具。
中英别名: FuelLog / 加油记
项目目标
10 秒完成一笔加油记录,自动算出实际油价、百公里油耗、每公里成本;移动端 + PWA 优先;架构简单、不堆中间件,后续可扩展到充电、保养、停车、保险等车辆综合成本。
完整产品/技术决策见 FuelLog_PLAN.md,本文件是给 Agent 的工程操作手册。
仓库结构(单仓双工程,推荐)
仓库根 = 整个项目,内含前端与后端两个 Go module 风格的子工程:
FuelLog/
├── fuellog-web/ # Vue 3 + TS + Vite 前端
├── fuellog-api/ # Go + Gin + GORM 后端
├── deploy/ # docker-compose / Nginx / PWA manifest 等
├── docs/ # 设计稿、API 文档、截图
├── data/ # SQLite 文件(开发期;部署期挂 volume)
├── AGENTS.md # 本文件
├── README.md
└── .gitignore
若 Agent 决定使用
frontend/backend/之类的别名,在该子目录里再放一份本地AGENTS.md明确路径即可,根目录命令按本文件执行。
Setup commands
准备环境
- Node.js ≥ 20,pnpm ≥ 9(优先 pnpm,无则 npm)
- Go ≥ 1.22
- Docker / Docker Compose(部署)
git、make(可选,make help查看快捷命令)
后端
cd fuellog-api
go mod tidy
cp .env.example .env # 本地 SQLite 默认 ./data/fuellog.db
go run ./cmd/server # 监听 :8080
go test ./... # 核心计算单测
go vet ./...
前端
cd fuellog-web
pnpm install # 或 npm install
pnpm dev # 启动 Vite,默认 :5173,自动代理 /api -> :8080
pnpm build
pnpm preview # 预览构建产物
pnpm typecheck # vue-tsc
pnpm lint # eslint + prettier
整体(开发期)
docker compose -f deploy/docker-compose.dev.yml up # API + Web + 反代 一把起
部署
docker compose -f deploy/docker-compose.yml up -d
data/ 目录必须挂载 volume,SQLite 不可随容器删除。
技术栈(锁定,不要临时换)
Frontend
- Vue 3 + TypeScript + Vite
- Vue Router / Pinia
- Tailwind CSS(主题通过 CSS Variables / Tailwind Theme,不在组件里写死颜色)
- Naive UI(优先,不适合时退到 Element Plus)
- ECharts(统计图表)
- vite-plugin-pwa(PWA: manifest + service worker + 添加到主屏)
Backend
- Go + Gin
- GORM(默认;若团队更熟 sqlc 允许,需在 PR 写理由)
- SQLite(默认,代码层用 GORM 抽象,后续能切 Postgres)
- 金额:使用
decimal库或按"分"为单位的整数,避免 float 累计误差
Infra
- Docker / Docker Compose
- Nginx / Nginx Proxy Manager 反代
- 单一 SQLite 文件 + volume 持久化
MVP 禁止引入
Kubernetes / 微服务 / Kafka / Redis / RabbitMQ / Elasticsearch / GraphQL / Service Mesh / CQRS / Event Sourcing —— 出现真实需求前不要上。
项目布局
后端 fuellog-api/
fuellog-api/
├── cmd/server/ # main.go
├── internal/
│ ├── handler/ # Gin handler,只做 HTTP
│ ├── service/ # 业务逻辑(油价/油耗/成本/统计)
│ ├── repository/ # 数据库访问
│ ├── model/ # 实体
│ ├── dto/ # 入参/出参
│ ├── middleware/ # 日志/错误/恢复
│ └── router/ # 路由注册
├── migrations/ # GORM AutoMigrate 或 goose 脚本
├── config/
├── pkg/ # 通用工具(decimal 封装、错误码等)
├── go.mod
└── Dockerfile
硬性分层:Handler 不允许写业务逻辑。Service 持有 Repository 抽象,便于单测。
前端 fuellog-web/
fuellog-web/
├── src/
│ ├── api/ # 类型化 API client(基于 openapi 后再生成)
│ ├── assets/
│ ├── components/
│ ├── layouts/ # 移动端 Bottom Nav + 桌面侧栏
│ ├── pages/
│ │ ├── dashboard/
│ │ ├── refuel/ # 列表 + 新增 + 编辑
│ │ ├── statistics/
│ │ └── vehicle/
│ ├── router/
│ ├── stores/ # Pinia
│ ├── types/
│ ├── utils/ # decimal 工具、单位转换
│ ├── App.vue
│ └── main.ts
├── public/ # PWA manifest 图标
├── package.json
└── vite.config.ts
Code style
通用
- 文件名、变量、commit 用英文;用户可见文案、注释、commit message 用简体中文。
- Conventional Commits 强制:
feat:fix:docs:refactor:style:test:chore:perf:。 - 提交前
pnpm lint+go vet必须 0 错 0 警。 - 金额、加油量、里程统一用 decimal 或显式单位,严禁直接
==比较 float。
前端
- TypeScript
strict: true;不写any,能用unknown/ 联合类型收口。 - Vue SFC
<script setup lang="ts">;组合式 API 优先。 - Tailwind + 主题 token,不写死颜色/间距/字号。
- 移动端 360 / 390 / 430 三档断点优先验证,再适配桌面。
- 任何页面必须有 Loading / Empty / Error 三态。
后端
gofmt+goimports必跑。- 错误统一
pkg/apperror,返回{ "code": "INVALID_ARGUMENT", "message": "..." }。 - 参数校验在 Handler 入参后立即完成,失败立即 abort。
- 业务时间统一 UTC 存库,展示按本地时区格式化。
数据库 & Migration
- MVP 使用 SQLite,文件路径从 env 读,默认
./data/fuellog.db。 - 任何表结构变更必须新增 migration 文件,不允许
AutoMigrate覆盖生产数据。 - 核心表:
vehicle、refuel_record,字段定义严格按FuelLog_PLAN.md §7。 - 后续扩展(
charging_record/maintenance_record/fuel_price_history)要预留命名空间,不要把字段塞进refuel_record。
核心计算规则(必须有单测)
公式见 FuelLog_PLAN.md §6,这里只列硬要求:
- 实际油价 =
总金额 / 加油量—— 服务端实时计算并落库,前端输入金额 + 升数后立刻展示。 - 行驶里程 =
本次里程 - 上一次有效里程(同一车辆按时间顺序)。 - 百公里油耗 仅在连续两次
is_full=true的记录之间计算,半箱油记录不能进入标准油耗。 - 每公里燃油成本 =
本次燃油费用 / 行驶里程。 - 单测必须覆盖:
- 油价计算(
176.33 / 23.67 ≈ 7.45) - 油耗计算(
(10500-10000) / 40 * 100 = 8.0) - 半箱油不计入标准油耗
- 删除/编辑记录后 Dashboard / 统计数据正确刷新
- 油价计算(
API 设计
Base path /api,见 FuelLog_PLAN.md §8。最低端点集:
GET/POST/PUT/DELETE /api/vehicles[/...]
GET/POST/PUT/DELETE /api/refuels[?...filters]
GET /api/dashboard
GET /api/statistics/overview
GET /api/statistics/fuel-consumption
GET /api/statistics/fuel-price
GET /api/statistics/monthly-cost
GET /api/statistics/cost-per-km
- 查询参数:
vehicle_id、start_date、end_date、fuel_type、station_name、page、page_size。 - 错误统一格式见上文
apperror。 - 必须在
docs/api.md或 Swagger 同步端点;前端类型与 DTO 保持一致。
UI / UX 硬性要求
- Mobile first,卡片式 Dashboard,大字号主指标(本月花费最大,平均油价/平均油耗次之)。
- 10 秒录入 新增加油:加油时间 → 里程 → 加油量 → 总金额 → 油品 → 加油站 → 是否加满 → 备注,保存按钮固定在移动端底部。
- Light / Dark Mode 必须支持,可跟随系统;通过 CSS Variables 切换,不在组件里堆 if-else。
- 空数据 / 加载中 / 错误 状态统一,不能一片白。
- 删除 任何记录/车辆都要二次确认。
- 移动端文案要短(加油量
23.67 L、金额176.33 元),实际油价¥7.45/L实时显示。
PWA
MVP 必须包含:
manifest.webmanifest、app icon(192 / 512 / maskable)- service worker(由 vite-plugin-pwa 生成)
- 添加到主屏可用
- 离线时能打开基础 UI(空数据也 OK)
- 真正的离线数据同步放后续版本
数据导入导出
Phase 7 必做,放在 MVP 后期,不要拖到最后:
- 导出 JSON:含
vehicles+refuel_records全量 - 导入 JSON:覆盖或合并,UI 给出明确选项
- 导出 CSV:加油记录(给 Excel 看)
- 目的:用户数据任何时候可迁出,不被项目绑死
安全 & 数据完整性
- 金额 ≥ 0,加油量 > 0,里程 ≥ 0,加油时间为合法日期 —— 后端强校验。
vehicle_id必须存在,跨车辆引用全部拒绝。- 删除操作必须显式确认。
.env入.gitignore,不提交密钥;生产敏感配置走环境变量。- 容器内 API 默认只监听内网,由 Nginx 反代对外。
Testing
- 后端:
go test ./...,重点覆盖internal/service(计算 + 统计)。 - 前端:Vitest 覆盖
utils/与关键组件;Playwright 跑核心流程(创建车 → 加油 → 看到 Dashboard 更新)。 - 每完成一个 Phase,跑一次
docker compose up -d,确认整体可起。 - CI 至少跑:
go vet+go test+pnpm typecheck+pnpm build。
Definition of Done
一个功能完成必须同时满足:
- 功能可用(API + 前后端闭环)
- 移动端正常(360 / 390 / 430 三档目视)
- 桌面端正常
- 数据库 migration 同步
- 错误处理完整(统一
apperror格式) - Loading / Empty / Error 状态完整
- 核心逻辑有单测
docker compose up能起- README /
docs/api.md同步更新 - commit message 走 Conventional Commits
Agent 执行顺序(每步先验证,再下一步)
严格按 FuelLog_PLAN.md §27 推进。禁止跳步、禁止一次性生成全部代码:
- 初始化项目骨架(本文件落盘后,创建
fuellog-web/+fuellog-api/+deploy/+docker-compose.dev.yml) - 后端 Model / Repository / Service / Handler + SQLite + migration
- 核心计算单测
- 后端 API(车辆 / 加油 / Dashboard / 统计)
- 前端骨架(Vue Router + Pinia + Tailwind + Naive UI + 主题)
- Dashboard 页面
- 新增加油页面
- 加油记录列表
- 车辆管理
- 统计图表(ECharts)
- UI 精修 / 暗色模式 / Loading / Empty / Error
- PWA
- 导入导出
- Docker 完整部署测试
- README + 截图
每完成一步,回到 Definition of Done 自查,再开下一步。
注意事项
- 不要提前加复杂设施:MVP 不需要 Redis、不需要 K8s、不需要微服务。需要时再讨论。
- 不要堆业务逻辑在 Handler:所有计算走 Service,便于单测。
- 不要写死颜色/间距/字号:统一从 Tailwind theme / CSS Variables 读。
- 不要为"显得高级"加没有实际价值的技术。
- 任何与本文件冲突的需求,先改本文件再改代码,保持文档先行。