开发规范文档
智能家庭饮食管家 App - 开发规范文档
最后更新: 2026-05-20
一、文档修订记录
| 版本 | 日期 | 作者 | 修改说明 |
|---|---|---|---|
| v1.0 | 2026-05-20 | 初始版本:Git 规范、C++/QML 代码规范、文档维护规范、CMake 规范、单人开发自律清单 |
第一部分:Git 规范
1.1 分支策略
本项目采用 简化 Git Flow 模型(单人适配版):
main ← 始终可编译、可运行
│
├── develop ← 日常开发集成分支(主力分支)
│ │
│ ├── feature/xxx ← 每个功能模块一条分支
│ ├── fix/xxx ← Bug 修复分支
│ └── refactor/xxx ← 重构分支
│
└── release/vX.Y ← 发布分支(阶段里程碑)
| 分支类型 | 命名格式 | 从哪分出 | 合并到哪 | 生命周期 |
|---|---|---|---|---|
main | 固定 | — | — | 永久 |
develop | 固定 | main | main (发版时) | 永久 |
feature/* | feature/1.2-arch-skeleton | develop | develop | 功能完成后删除 |
fix/* | fix/fifo-underflow | develop | develop | 修复后删除 |
refactor/* | refactor/repo-template | develop | develop | 重构后删除 |
release/* | release/v0.1-alpha | develop | main + develop | 发布后打 Tag 删除 |
单人简化规则:
- 日常开发直接在
develop上做,每完成一个子任务提交一次 - 涉及较大重构(跨层修改 ≥3 个文件)时,切
feature/或refactor/分支 - 阶段里程碑达到后,从
develop合入main并打 Tag
1.2 Commit Message 规范
采用 Conventional Commits 精简版:
<type>(<scope>): <subject>
[optional body — 一行一个要点]
[optional footer — 关联 issue / breaking change]
type 取值
| type | 含义 | 示例 |
|---|---|---|
feat | 新功能 | feat(core): 实现 TDEE 计算服务 |
fix | Bug 修复 | fix(repo): FIFO 扣减负数问题 |
refactor | 重构(无功能改动) | refactor(data): Repository 模板化 |
docs | 文档变更 | docs: 新增开发规范文档 009 |
style | 格式调整(空格、缩进) | style(qml): 统一 QML 缩进为 4 空格 |
test | 测试增改 | test(auth): 补充 Argon2id 单元测试 |
chore | 构建/工具/配置 | chore(cmake): 引入 QuickControls2 模块 |
perf | 性能优化 | perf(db): 索引优化查询耗时 |
scope 取值
| scope | 对应层/模块 | 对应目录 |
|---|---|---|
app | 入口、应用级 | src/app/ |
ui | QML 视图与组件 | src/ui/qml/, src/ui/components/ |
core | Service 层 | src/core/ |
data | Repository 层 | src/data/ |
network | 通信/同步 | src/network/ |
utils | 工具类 | src/utils/ |
cmake | CMake 构建 | CMakeLists.txt, cmake/ |
docs | 文档 | docs/ |
test | 测试 | tests/ |
resource | 资源文件 | resources/ |
规则
- subject 强制中文(项目文档体系统一中文),不超过 50 字
- body 选填,多行时每行一个要点,行宽 ≤72 字符
- 一个 commit 只做一件事:禁止”修了 A 又加了 B 顺便改了 C”的混合提交
示例
feat(core): 实现 Mifflin-St Jeor BMR/TDEE 计算公式
- 支持男/女性别分支(男性公式 +5,女性公式 -161)
- 输入:身高(cm)、体重(kg)、年龄(岁)
- 返回:BMR(千卡)、TDEE(千卡,基于活动系数 1.2-1.9)
- TDEE 默认活动系数 1.55(中等活动量)
fix(data): 修复 updateWithVersion 乐观锁版本号误判
WHERE version = :expected AND id = :uuid 传入参数顺序错误,
导致 version 字段未被正确校验,并发更新时可能产生脏写。
chore(cmake): 新增 Quick Sql Network 模块,移除 Widget 源文件
BREAKING CHANGE: mainwindow.h/.cpp/.ui 已删除,UI 入口改为
src/ui/qml/main.qml。旧分支代码需同步此变更。
1.3 Tag 规范
采用 Semantic Versioning 2.0.0,格式 v<MAJOR>.<MINOR>.<PATCH>[-<pre-release>]。
| 阶段 | Tag 示例 | 说明 |
|---|---|---|
| 阶段里程碑 | v0.1-alpha | M1:基础框架可运行 |
| 内部测试版 | v0.2-beta | M5:菜单管理可用 |
| 正式候选 | v0.9-rc1 | M9:测试通过 |
| 正式发布 | v1.0.0 | M10:发布 |
Tag 分支来源: 仅从 main 分支打 Tag(在 release/* 合入后)。
1.4 .gitignore 维护
已存在的 .gitignore 规则覆盖了 Qt、编译产物、OS 文件、数据库文件、依赖目录。新增以下规则(如有需要直接在 .gitignore 末追加):
# IDE 临时文件(补充)
*.swp
*.swo
*~
# CMake 生成文件(补充)
CMakeCache.txt
CMakeFiles/
cmake_install.cmake
Makefile
*.cmake
# Qt Creator(补充)
*.autosave
# QML 编译缓存
*.qmlc
*.jsc
qmlcache/
# 打包产物
*.dmg
*.app
*.deb
*.rpm
*.apk
第二部分:代码规范
2.1 C++ 规范
命名
| 元素 | 风格 | 示例 |
|---|---|---|
| 类名 | PascalCase | InventoryRepository, AuthService |
| 公开方法 | camelCase | getUserProfile(), calculateTDEE() |
| 私有方法 | camelCase + 前缀 _ 或 p_ | _validateToken(), p_executeSql() |
| 成员变量 | camelCase + 尾缀 _ | dbConnection_, currentFamilyId_ |
| 常量 | kPascalCase 或 UPPER_SNAKE_CASE | kDefaultPageSize / MAX_RETRY_COUNT |
| 枚举值 | UPPER_SNAKE_CASE | DietGoal::WEIGHT_LOSS |
| 文件名 | snake_case(全小写下划线) | base_repository.h, auth_service.cpp |
| 命名空间 | snake_case(全小写) | namespace smart_diet |
头文件保护
// 使用 #pragma once(Qt 官方推荐,简洁且所有现代编译器支持)
#pragma once
// 不使用传统的 #ifndef / #define / #endif 三件套
Include 顺序
// 1. 本类对应的头文件
#include "auth_service.h"
// 2. Qt 库头文件(按模块字母序)
#include <QDateTime>
#include <QObject>
#include <QString>
#include <QtSql/QSqlDatabase>
// 3. 本项目内其他头文件(按目录层级)
#include "data/user_repository.h"
#include "utils/constants.h"
// 4. 标准库头文件
#include <memory>
#include <optional>
类结构模板
#pragma once
#include <QObject>
class AuthService : public QObject {
Q_OBJECT
public:
explicit AuthService(QObject *parent = nullptr);
~AuthService() override = default;
// --- 公开接口 ---
Q_INVOKABLE bool login(const QString &loginId, const QString &password);
Q_INVOKABLE bool registerUser(const QVariantMap &profile);
signals:
// --- 信号(遵循 动词-ed / 动词-过去式)---
void loggedIn(const QString &userId);
void errorOccurred(const QString &message, int errorCode);
private:
// --- 私有方法 ---
QString hashPassword(const QString &plainText) const;
bool verifyPassword(const QString &plainText, const QString &hash) const;
// --- 成员变量 ---
class UserRepository *userRepo_ = nullptr; // 依赖注入,不 new
};
其他约定
- 禁止裸指针拥有所有权:Repository/Service 持有依赖时用
std::unique_ptr或构造注入,不手动new/delete - 优先
std::optional而非返回哨兵值:std::optional<User> getById(const QString& uuid)优于返回空对象或nullptr - C++17 特性可用:
if constexpr、结构化绑定、std::string_view、std::optional、std::variant - 禁止
using namespace std:头文件中绝对禁止,.cpp 中不鼓励
2.2 QML 规范
文件命名
| 元素 | 风格 | 示例 |
|---|---|---|
| 页面/视图 | PascalCase + Page 后缀 | HomePage.qml, LoginPage.qml |
| 可复用组件 | PascalCase | NutritionRing.qml, BatchCard.qml |
| 对话框/弹窗 | PascalCase + Dialog 后缀 | CookingDialog.qml |
| 基础样式文件 | snake_case | theme_colors.js, font_sizes.js |
QML 文件结构(从上到下)
// 1. import 语句(Qt 模块 → 第三方 → 项目内部)
import QtQuick
import QtQuick.Controls
import "../components" as C // 项目组件
// 2. 根元素的 id 必须在最前
ApplicationWindow {
id: root // 根节点 id 统一用 "root"
// 3. 属性声明(property → 公开接口 → 内部状态)
property int currentStep: 0
readonly property bool isReady: currentStep > 0
// 4. 信号声明
signal stepCompleted(int stepIndex)
// 5. 函数(公开 → 私有)
function resetStep() { ... }
// 6. 子元素(视觉树),嵌套缩进 4 空格
Rectangle {
id: header
anchors { ... }
}
}
命名约定
| 元素 | 风格 | 示例 |
|---|---|---|
| id | camelCase | loginButton, calorieRing, headerNav |
| property | camelCase | currentMeal, isOffline |
| signal | PascalCase 动词过去式 | loggedIn, menuConfirmed |
| function | camelCase 动词 | refreshData(), navigateTo() |
布局约定
- 使用
anchors优先于硬编码坐标,保证跨分辨率适配 - 颜色统一引用自
Theme单例(阶段 1.4 定义),禁止在 QML 中硬编码色值 - 间距单位:小间距
8,中间距16,大间距24
严格禁止
- ❌ 在 QML 中编写 SQL 语句
- ❌ 在 QML 中调用网络 API(
XMLHttpRequest/fetch) - ❌ 在 QML 中包含 TDEE 计算、采购清单生成等业务逻辑
- ❌ 使用
Qt.resolvedUrl()进行跨模块硬路径引用
上述操作必须通过 C++ Service 层的 Q_INVOKABLE 方法或在 Connections 中监听信号完成。
2.3 目录与文件组织
src/
├── app/
│ └── main.cpp # 应用入口,仅此一个 .cpp
│
├── core/ # Service 层
│ ├── base_service.h # Service 抽象基类
│ ├── auth_service.h / .cpp # 认证服务
│ ├── family_service.h / .cpp # 家庭管理服务
│ ├── menu_service.h / .cpp # 菜单服务
│ └── inventory_service.h / .cpp # 库存服务
│
├── data/ # Repository 层
│ ├── base_repository.h # Repository 模板基类
│ ├── database_manager.h / .cpp # 数据库连接管理(单例)
│ ├── user_repository.h / .cpp
│ ├── family_repository.h / .cpp
│ └── ...
│
├── network/ # 网络通信层
│ ├── sync_manager.h / .cpp # 同步队列与策略
│ ├── ws_client.h / .cpp # WebSocket 客户端
│ └── http_client.h / .cpp # HTTP REST 客户端
│
├── ui/
│ ├── qml/ # 页面级 QML(每个页面一个文件)
│ │ ├── main.qml # QML 入口
│ │ ├── HomePage.qml
│ │ ├── LoginPage.qml
│ │ └── ...
│ ├── components/ # 可复用 QML 组件
│ │ ├── NutritionRing.qml # 营养环形图
│ │ ├── BatchCard.qml # 批次卡片
│ │ └── ...
│ ├── styles/ # 样式常量
│ │ ├── Theme.qml # 颜色、字体单例
│ │ └── Sizes.qml # 间距、圆角常量
│ └── views/ # [留空] C++ ViewModel 宿主(如有需要)
│
├── utils/ # 工具类
│ ├── constants.h # 全局常量、枚举
│ ├── uuid_generator.h / .cpp # UUID 工具
│ └── time_utils.h / .cpp # ISO 8601 转换工具
│
tests/
├── unit/ # 单元测试(文件名 = 被测类 + _test)
│ ├── tdee_calculator_test.cpp
│ └── user_repository_test.cpp
└── integration/ # 集成测试
└── ws_sync_test.cpp
铁律:
- 每个
.h必须有且仅有一个对应.cpp(除非是纯模板类) - 头文件放声明,
.cpp放实现。禁止在头文件中写函数体(简单的 getter/setter 除外) - 新模块必须在对应目录下,不得跨层放置
第三部分:文档维护规范
3.1 文档更新触发时机
| 触发条件 | 应更新的文档 | 说明 |
|---|---|---|
| 新增/修改 API | 005.接口设计文档.md | 同步更新接口定义、请求/响应示例 |
| 新增/修改表结构 | 004.数据库设计文档.md | 同步更新 DDL、ER 图说明 |
| 架构层级调整 | 001.概要设计文档.md | 同步更新分层图与职责描述 |
| UI 页面新增/大改 | 003.详细设计(原型设计).md | 保持原型与实装一致 |
| 新增安全机制 | 007.安全设计文档.md | 记录新的安全措施 |
| 测试策略变化 | 006.测试策略文档.md | 更新测试覆盖范围 |
| 开发计划调整 | 008.项目开发计划.md | 更新阶段状态、工时、里程碑 |
| 每次工作结束 | docs/dev-log/YYYY年M月D日.md | 每日开发日志 |
| 任何规范变更 | 009.开发规范文档.md(本文档) | 保持规范最新 |
3.2 文档修订记录规则
每个文档顶部的修订记录表必须更新:
- 版本号:每次修改递增 minor(v1.0 → v1.1,实质性变更才跳 v2.0)
- 日期:修改当天的日期
- 修改说明:一句话说清改了什么,不要写”优化了部分内容”这种模糊描述
3.3 开发日志规范
日志文件路径:docs/dev-log/YYYY年M月D日.md
每日必写(结束工作前最后一步):
# 开发日志 - YYYY-MM-DD
## 今日完成
- [x] [任务名称 1] - [简要说明]
- [x] [任务名称 2] - [简要说明]
## 遇到的问题
1. [问题描述]
→ [解决方式 / 所需帮助]
## 明日计划
1. [任务名称] - [预估工时]
2. [任务名称] - [预估工时]
## 实际工时
__h / 计划 __h
## 备注
[可选:技术决策记录、踩坑备忘、灵感想法]
3.4 README 维护
- 新增核心模块后,更新
readme.md中「技术架构」或「项目结构」章节 - 发布新版本后,更新 README 中的「最后更新」日期
第四部分:CMake 构建规范
4.1 目录级 CMakeLists.txt 模板
当 src/core/、src/data/ 等目录出现 ≥2 个源文件时,应创建子目录 CMakeLists.txt:
# src/core/CMakeLists.txt
# 收集本目录所有源文件
file(GLOB CORE_SOURCES
"*.cpp"
"*.h"
)
# 导出变量供父级 CMakeLists.txt 使用
set(CORE_SOURCES ${CORE_SOURCES} PARENT_SCOPE)
顶层 CMakeLists.txt 使用 add_subdirectory 引入:
add_subdirectory(src/core)
add_subdirectory(src/data)
# ...
set(PROJECT_SOURCES
src/app/main.cpp
${CORE_SOURCES}
${DATA_SOURCES}
...
)
4.2 源文件添加规则
- 新
.cpp/.h文件:自动通过file(GLOB)收集,无需手动在 CMakeLists.txt 中逐条添加 - 新 QML 文件:必须同时添加到
resources.qrc中,否则运行时无法加载 - 新资源(图片/字体):放入
resources/对应子目录,并加入resources.qrc
4.3 平台兼容要求
- 不允许使用平台特定 API(
#ifdef _WIN32等)在业务层代码中出现 - 如需平台差异,封装在
utils/下的独立工具类中 - CMake 中 Qt5 兼容路径保留,但不新增 Qt5 特有逻辑
第五部分:单人开发自律规范
5.1 每日检查清单
每天开始工作前,回答三个问题:
- ☐ 今天做哪个阶段的任务?(对照
008.项目开发计划.md) - ☐ 是否依赖昨天未完成的工作?如果是,先收尾还是绕过去?
- ☐ 这个任务做完后,需要更新哪些文档?
每天结束工作前,执行以下动作:
- ☐ 写开发日志(
docs/dev-log/) - ☐ 更新
008.项目开发计划.md中的阶段进度表(实际工时、完成度) - ☐
git add+git commit(即使不 push 也要本地提交) - ☐ 如果今日有跨模块修改,运行一次编译确认无错误
5.2 代码提交前自检
每次 git commit 前必须逐条确认:
| # | 检查项 | 通过条件 |
|---|---|---|
| 1 | 无注释掉的死代码 | 删除,不注释。Git 历史可以恢复 |
| 2 | 无调试打印 | 移除所有 qDebug() / console.log() 调试输出 |
| 3 | Include 无冗余 | 没有用了但忘删的头文件 |
| 4 | 硬编码常量已提取 | 色值、数字阈值、API URL 全部在 constants.h 或 Theme.qml 中 |
| 5 | 编译通过 | cmake --build 零 error,warnings ≤ 0(警告全部视为 error 处理) |
| 6 | 新功能无跨层调用 | UI 不直接调 Repository、Repository 不直接调网络 |
| 7 | 文档已同步 | 若修改了 API/DB/架构,对应设计文档已更新 |
5.3 阶段验收自检
每个阶段结束(里程碑 M1-M10),对照 008.项目开发计划.md 第七条验收标准逐条确认,并填写:
====================================
阶段 N 验收记录
日期:YYYY-MM-DD
====================================
验收项 通过/不通过 备注
────────────────────────────────────────────────
✅ 代码可编译运行 通过
✅ 分层架构符合设计 通过
✅ 单元测试可运行 通过
────────────────────────────────────────────────
遗留问题:
(无 / 列出)
────────────────────────────────────────────────
是否准出下一阶段:是 / 否
签字:___________ 日期:___________
(签字行可选,但建议养成习惯)
5.4 “遇到困难”处理流程
当某个子任务实际耗时超过计划的 150% 时,强制执行:
- 暂停编码,在当天的开发日志中写明阻塞原因
- 判断原因类型:
- 技术未知(没用过的新库/API)→ 先花 ≤2h 专项学习,再继续
- 设计缺陷(前面的设计不支持此功能)→ 更新设计文档后再编码
- 完美主义(反复调 UI 细节)→ 标记为 P2,先保功能完整
- 更新
008.项目开发计划.md中的「调整记录」表
第六部分:其他约定
6.1 语言标准
| 场景 | 语言 |
|---|---|
| 代码注释 | 中文(简短提示可用英文,复杂逻辑必须中文) |
| Commit message | 中文 subject,body 中英均可 |
| 文档 | 全部中文 |
| 代码符号(变量/函数/类) | 英文 |
| UI 文案 | 中文(通过 .ts 翻译文件管理) |
6.2 版本号管理
CMakeLists.txt 中的 VERSION 与 Tag 同步更新。规则:
| 变更类型 | 版本号变化 | 示例 |
|---|---|---|
| 阶段里程碑 | MINOR +1 | 0.1 → 0.2 |
| Bug 修复 | PATCH +1 | 0.1.0 → 0.1.1 |
| 正式发布 | 直接跳 1.0.0 | — |
6.3 第三方库引入原则
- 优先 Qt 内置模块:能用 Qt 自带的(
QtSql、QtNetwork)绝不多引第三方 - 必须引入第三方库时:记录在
docs/dev-log/当天的日志中,说明用途、版本、许可证 - 第三方库放在
third_party/目录下,或通过 CMakeFetchContent引入
附录 A:快速查阅清单
| 我想知道… | 去看… |
|---|---|
| 项目要做什么 | readme.md |
| 产品需求细节 | 002.产品需求文档PRD.md |
| UI 长什么样 | 003.详细设计(原型设计).md |
| 技术架构怎么搭的 | 001.概要设计文档.md |
| 数据库表结构 | 004.数据库设计文档.md |
| API 怎么调 | 005.接口设计文档.md |
| 怎么测试 | 006.测试策略文档.md |
| 安全怎么做 | 007.安全设计文档.md |
| 现在做到哪了/下一步做什么 | 008.项目开发计划.md |
| 代码/提交/Git 怎么规范 | 009.开发规范文档.md(本文档) |
| 今天做了什么 | docs/dev-log/YYYY年M月D日.md |