2108d432 by 柴进

chore(memory): 同步 Claude auto-memory 到 .claude/memory/

便于在其他机器(公司电脑)拉取后恢复对项目的记忆。
.gitignore 改为 .claude/* + 排除 .claude/memory/,其余 .claude/ 子内容继续忽略。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent f48ebc4d
1 # Memory Index
2
3 - [User: 跨平台 UI 一致性诉求](user_cross_platform_ui.md) — 用户强烈关注 macOS 和 Windows 两端视觉/交互的一致性
4 - [User: 自主交付偏好](user_overnight_autonomy.md) — 大型重构允许"睡前授权 → 醒来 review 分支"模式
5 - [Project: 珠宝壹佰 / 品牌色](project_zb100_brand.md) — 公司"珠宝壹佰",品牌色契合 Apple Blue
6 - [Project: UI 主题系统架构](project_theme_system.md) — (旧 QWidget 路线) theme.py 设计令牌,业务不写 inline setStyleSheet
7 - [Project: UI 迁移到 QML](project_qml_migration.md) — 当前活跃路线,feat/ui-qml-poc 分支,task #11/#12/#20 完成,#13-#19 待办
8 - [Reference: QML PoC 结构](reference_qml_poc_structure.md) — qml_poc/ 文件结构 + Theme token + 组件 API
9 - [Reference: 业务桥层 bridges/](reference_bridges.md) — 5 个 Bridge QObject 的 Property/Signal/Slot 形状(task #13-#17 wiring 查)
10 - [Reference: core/ 业务模块](reference_core_modules.md) — image_generator.py 拆分后的业务核心目录
11 - [Feedback: 拒绝路径盲从 / 第一性原理](feedback_first_principles.md) — 路径非最优时直接建议替代方案,不要按用户当下方案盲做
12 - [Feedback: UI 迭代用 python 跑,别打包](feedback_dev_iter_via_python.md) — 调 UI 用 pythonw.exe 直接跑,PyInstaller 太慢
13 - [Feedback: 旧代码多留几天](feedback_keep_legacy_code.md) — 重构 / 替换实现时默认 .txt 改名保留,不 git rm,等用户主动说删
14 - [Reference: 项目入口和打包](reference_entry_and_build.md) — 主入口、打包脚本、PyInstaller spec 位置
15 - [Reference: 打包当前形状 + 易踩坑](reference_packaging.md) — task #19 ZB100ImageGenerator.spec 现状(QML datas 路径 / pathex / Pillow)
1 ---
2 name: UI 迭代用 python 直接跑,别打包
3 description: 调试 UI 改动时直接 python image_generator.py,不要 pyinstaller 打包
4 type: feedback
5 originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077
6 ---
7 用户原话:"你直接启动py让我看效果好了,不要打包了,打包反而节奏慢了"。
8
9 **Why**:PyInstaller 打包跑一次约 60-90 秒(包括 collect dynamic libs、PYZ、COLLECT),UI 调试每次改一个 padding / 字号都要重打,浪费时间。Python 直接跑只要 1-2 秒到登录页。
10
11 **How to apply**
12 - 当用户想"看效果"或快速验收 UI 改动时,用 `start "" .venv/Scripts/pythonw.exe image_generator.py`(Windows 后台启动,无 console 窗口)
13 - pythonw.exe 而不是 python.exe — 前者不弹黑色 console,跟打包后体验一致
14 - 只在以下场景才打包:
15 - 任务结尾要交付产物(明天上班看 dist)
16 - 验证打包后的资源完整性(如确认 PIL 原生库进了包)
17 - 用户明确要求"打个新包"
18 - 不要在每次改完代码后默认打包
19
20 **配套**:先 `tasklist | grep -i ZB100\|pythonw` 看有没有残留实例,有就 kill,避免端口/文件锁冲突。
1 ---
2 name: 第一性原理 / 拒绝路径盲从
3 description: 用户期望在路径非最优或目标模糊时直接被建议替代方案,而不是被动执行
4 type: feedback
5 originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077
6 ---
7 来自全局 CLAUDE.md(用户的私有规则):
8 > **第一性原理**:从原始需求出发,拒绝路径盲从。目标模糊时停下讨论,路径非最优时直接建议替代方案
9
10 实际验证过的应用场景(2026-05-09):
11 - 用户最初问"UI 有点丑丑的,你有啥建议"——这是个开放问题。我直接给三个方向 + 推荐方案 B(自己写 QSS),用户接受。
12 - 用户在选第三方库 vs 自写 QSS 时也接受了我"先做 B"的推荐。
13 - brainstorming 阶段每个决策都给"我的推荐 + 理由"作为第一项,用户选择速度很快。
14
15 **Why**:用户技术判断力强,希望对话型协作而非"你说一我做一"的脚本式执行。给推荐 + 理由比给清单更省时间。
16
17 **How to apply**
18 - 用户描述任务时如果包含 "你觉得"/"建议"/"看看"等词,**先给推荐**再给替代
19 - 给方案永远是 2-3 个选项 + 我的判断 + 一句话理由,不要列 10 个让他选
20 - 如果发现用户提的实施路径有更好的替代(比如他说"加个 retry"但实际应该改架构),**先建议替代**而不是默默照做
21 - 简单问题直接回答,不要套结构化模板(CLAUDE.md 明确说"仅在架构决策 / 方案评估 / 代码审查时使用结构化模板")
1 ---
2 name: 重构时保留旧实现,多留几天
3 description: 用户偏好在大重构 / 替换实现时保留旧代码作为回退参考,不急着删
4 type: feedback
5 originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077
6 ---
7 重构、替换实现、删除老入口时,**默认先保留旧代码几天到几周**,不要在 PR 里同时删。
8
9 **Why**:用户多次强调(2026-05-09 改 image_generator.py.txt 时、2026-05-11 重申"多留几天")。
10 理由是新实现刚跑通时未必稳定,"万一有问题还能翻翻老代码"。Linus 风格的"不破坏兼容"
11 在这个项目里被延伸成"不要急着断老路"——回退点的存在比代码整洁更重要。
12
13 **How to apply**
14 - 老入口 / 老实现替换为新版后,git mv 改 `.txt` 后缀(Python 不加载 / PyInstaller 不扫)
15 而不是 `git rm`。等用户主动说"删了吧"再删。
16 - 类似 image_generator.py.txt 的情况:要重构的大文件别"一次干净到底",
17 先把核心拆出去,老文件保留两版并存几天。
18 - 在 PR 描述里指明老代码留作 fallback,预计何时清理(让 reviewer 知道"这不是漏删")。
19 - 自己看见老代码躺着别"顺手 cleanup" — 没用户授权不删。
20
21 **判断边界**
22 - 真正过期、已破坏 API、有安全问题的老代码,可以删(这种情况会很明显)。
23 - 普通的"功能重写、行为不变"的老代码,按本规则保留。
1 ---
2 name: UI 迁移到 PySide6 + QML(QtQuick)
3 description: 2026-05-09 用户决定从 QWidget+QSS 转 QtQuick/QML,分支 feat/ui-qml-poc
4 type: project
5 originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077
6 ---
7 **Why**:QWidget+QSS 视觉天花板低(layout 压缩 / sizeHint 不更新 / 字号溢出系列坑)。
8 QML layout 引擎稳定,圆角 / 阴影 / 动效原生支持,跨 Mac+Windows 视觉一致。
9 **Python 业务后端完全不动**,只换 UI 层。
10
11 **分支**`feat/ui-qml-poc`,独立于 master。
12
13 **目录结构**
14 ```
15 core/ 业务核心(task #20 从 image_generator.py 拆出)
16 paths.py / database.py / history.py / generation.py / jewelry.py
17 runtime.py 启动期工具(crash diag / init_logging / cleanup / log_system_info)
18 bridges/ QML 桥层
19 auth.py / imagegen.py / history.py / taskqueue.py / jewelry.py / _icons.py
20 qml_poc/main_qml.py 主入口(8-phase boot + setContextProperty 注入桥)
21 qml_poc/qml/ QML 文件
22 Theme.qml (Singleton tokens)
23 Main.qml / LoginScreen.qml / MainWindow.qml
24 ImageGenTab.qml / StyleDesignerTab.qml / HistoryTab.qml
25 components/ (PrimaryButton / SecondaryButton / ThemedTextField / ThemedComboBox / Card / CaptionLabel)
26 image_generator.py.txt 老 QWidget 代码(git mv 改 .txt 不参与执行,保留扒老逻辑用)
27 task_queue.py / audit_logger.py / preflight.py / config_util.py 保持 master 一致,未改架构
28 ```
29
30 **已完成**(截至 2026-05-10):
31 - ✅ #11 PoC UI 视觉 / #20 image_generator.py 拆 core/
32 - ✅ #12 桥层(5 QObject contextProperty)/ #13 db 登录 + 记住凭据
33 - ✅ #14 图片生成 tab 完整(核心 / 参考图 / 收藏 / 下载 / Ctrl+V / 14 比例 + 自动切模式 /
34 多任务 / 拖拽重排 DragHandler Finder 风格 / 跟手 ghost / 10MB 校验 / 编号 badge)
35 - ✅ #16 历史 tab(ListView + 详情面板 + 右键菜单 / 清空 / 复制 prompt / 在文件管理器中显示选中
36 / 🔁 重做按钮回填到生成 tab 不带生成图)
37 - ✅ #17 任务队列 sidebar(taskQueue.model 增量 / 状态彩色 / 进度条 / 左键回填 loadTask /
38 右键 Menu 取消任务)
39 - ✅ #15 款式设计 tab(8 字段 + 锁定 + 随机 + 字段右键恢复单类别默认 + 顶部全部恢复 +
40 inline ➕/🗑️ 词条 + 实时 Prompt 预览)
41 - ✅ 启动 8-phase boot:crash diag → RotatingFileHandler logs/app.log → 系统信息 →
42 cleanup_clipboard_tempfiles → preflight → 窗口图标 → 桥层 → QML
43 - ✅ 完整 logtrace:bridges/* + core/* 所有 except 用 logger.exception(...)
44 - ✅ 剪贴板三层 fallback + macOS osascript 兜底(避免 Qt clipboard native crash)
45 - ✅ 输入框右键菜单(剪切/复制/粘贴/全选,密码框禁复制剪切)
46 - ✅ #21 修右键粘贴(TextField MouseArea 替代 TapHandler)+ 8px ScrollBar +
47 参考图双击 TapHandler.onDoubleTapped 系统查看器
48 - ✅ #22 日志分级 fsync:TieredFsyncHandler(WARNING+ 同步 fsync / INFO buffered)
49 + 1s 周期 daemon 线程兜底 + macOS DiagnosticReports 提示写入 crash_log.txt
50 - ✅ #19 Windows 打包:ZB100ImageGenerator.spec 切 qml_poc/main_qml.py 入口,
51 pathex=项目根,datas qml_poc/qml→_MEIPASS/qml(不带 qml_poc/ 前缀!
52 PyInstaller 把入口平铺到 _MEIPASS 根,Path(__file__).parent/"qml" 找 _MEIPASS/qml)
53 本地 dist/ZB100ImageGenerator/ZB100ImageGenerator.exe 验证 8 phases 全过
54
55 **剩余待办**
56 - #19 Mac build_mac_universal.sh 真机验证(含 .app + .dmg + Pillow .dylibs)
57 - #19 image_generator.py.txt 真正删除(用户要求暂留作扒老逻辑参考;确认稳定后再删)
58 - #18 系统暗色模式跟随(Theme.qml 加深色 token + Qt.styleHints.colorScheme 监听)
59 - 款式设计批量词库管理对话框(旧版有,新版只有 inline ➕/🗑️)
60 - 双击大图内嵌 viewer(当前 Qt.openUrlExternally 系统查看器替代,等价但 UX 不同)
61
62 **How to apply**
63 - 业务代码改在 core/* + task_queue.py + audit_logger.py
64 - UI 改在 qml_poc/qml/*;桥层 API 形状见 reference_bridges.md
65 - 老逻辑参考 image_generator.py.txt(已重命名不参与执行)
66 - 完整启动序列、logtrace 在 main_qml.py + core/runtime.py
67 - 用户偏好:先做 #19 打包能交付给同事;#18 暗色等留以后单独迭代
1 ---
2 name: UI 主题系统架构
3 description: theme.py 是设计系统单一真相源,业务代码不写 inline setStyleSheet
4 type: project
5 originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077
6 ---
7 2026-05-09 重构上线(分支 `feat/ui-redesign-apple-theme`):
8
9 **架构**
10 - `theme.py` 包含 TOKENS_LIGHT / TOKENS_DARK(24 个语义颜色)/ SIZES(圆角/间距/字号)/ FONT_STACK
11 - `build_qss(mode)` 拼出完整 QSS 字符串
12 - `ThemeManager(QObject)` 监听 `QGuiApplication.styleHints().colorSchemeChanged` 自动切换
13 - `apply_theme(app)``image_generator.py main()` 创建 QApplication 后立即调用
14 - `get_color(token, fallback)` 用于 QSS 命中不到的渲染层 API(如 `setForeground`
15
16 **业务代码规则**
17 - ❌ 不要写 `widget.setStyleSheet(...)` 装饰样式
18 - ✅ 用 `setObjectName("xxx")` 命中 `#xxx` 选择器
19 - ✅ 用 `setProperty("variant", "primary"|"danger"|"ghost"|"link"|"success-flash")` 命中 `[variant="..."]` 按钮变体
20 - ✅ 用 `setProperty("status", "success"|"warning"|"danger"|"info"|"muted")` + `style().polish()` 命中 status label
21 - ✅ 用 `setProperty("role", "title"|"secondary"|"caption"|"muted"|"thumb"|"thumb_index")` 命中通用 label 角色
22 - ✅ 用 `setProperty("drag_state", "idle"|"active")` 命中拖拽态
23 - ✅ 用 `setProperty("has_image", "true"|"false")` 命中预览图占位/已显示
24
25 **仅允许的 inline setStyleSheet**
26 - 平台 hack(macOS 占位符颜色 etc.)— `image_generator.py` 1292/1356
27 - 单点临时高亮反馈(< 3 秒自动恢复)
28
29 **Why**:之前 65 处零散 `setStyleSheet` 让深色模式无法实现,且改一个圆角要找十处。集中后一处改全局。
30
31 **How to apply**:未来加新 widget / 改外观时:
32 1. 优先看 `theme.py` 里有没有合适的现成 token / variant / role
33 2. 如果没有,加到 `theme.py` 里(保持单一真相源),别再开 inline setStyleSheet 的口子
34 3. 状态切换(图标变化、颜色反馈)用 `setProperty + style().polish()`,不要 inline setStyleSheet
1 ---
2 name: 珠宝壹佰品牌信息
3 description: 公司名"珠宝壹佰",应用名"珠宝壹佰图像生成器",品牌色与 Apple Blue 契合
4 type: project
5 originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077
6 ---
7 公司中文名"珠宝壹佰",英文/代码 namespace 用 ZB100(如 `ZB100ImageGenerator``zb100_windows.ico``zb100_mac.icns`、GitLab 域名 `gitlab.zb100.com`)。
8
9 **品牌色**:用户选择 Apple Blue `#0071E3`(Light)/ `#0A84FF`(Dark)作为应用主色,理由是"跟品牌元素的颜色契合"。
10
11 **Why**:避免后续给珠宝业品牌联想(金色 / 祖母绿)—— 这些在 brainstorming 时被讨论过但被用户主动否决,他想要的是工具感而不是行业感。
12
13 **How to apply**
14 - 如果未来需要"品牌色装饰"(市场物料、登录页背景图、欢迎页),用蓝色系而非金/绿
15 - 涉及多色 chart / status indicator 时,主色固定 Apple Blue,状态色(success/warning/danger)用 Apple system colors
16 - 如果有客户提"想加点珠宝业色彩"的需求,先确认是否要打破当前的"工具感专注"原则,不要默默加金色
1 ---
2 name: QML 业务桥层 bridges/* API
3 description: 5 个 Bridge QObject 的 Property/Signal/Slot 形状(截至 2026-05-10)
4 type: reference
5 originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077
6 ---
7 **目录**
8 ```
9 bridges/
10 ├── _icons.py build_placeholder_icon
11 ├── auth.py AuthBridge (db_config, audit_logger, last_user, saved_password_hash, config_path)
12 ├── imagegen.py ImageGenBridge (TaskQueueManager, HistoryManager, AuthBridge, api_key, saved_prompts, config_path)
13 ├── history.py HistoryBridge (HistoryManager)
14 ├── taskqueue.py TaskQueueBridge (TaskQueueManager)
15 └── jewelry.py JewelryBridge (JewelryLibraryManager)
16 ```
17
18 **main_qml.py contextProperty 名字**`auth / imageGen / history / taskQueue / jewelry / appState`
19
20 ---
21
22 **AuthBridge**
23 - Property: `loggedIn` / `currentUser` / `lastUser` (constant) / `hasSavedPassword` (constant)
24 - Slot:
25 - `login(user, pwd) → bool` 明文密码
26 - `loginWithSavedPassword(user) → bool` 用已存 hash("记住密码"路径,跳过 hash)
27 - `saveCredentials(pwd, rememberUser, rememberPwd)` 写回 config.json(pwd="" 时保留旧 hash)
28 - `logout()` / `deviceName() → str`
29 - Signal: `loggedInChanged / currentUserChanged / loginFailed(str)`
30 - 内部:登录成功同步拿 public IP(3 API 兜底 3s timeout)走 audit log_login
31
32 **ImageGenBridge**
33 - Property: `apiKey / busy / savedPrompts (list)`
34 - Slot:
35 - `submitTask(prompt, refs, aspect, size, mode) → task_id` (task_type=IMAGE_GENERATION)
36 - `submitStyleTask(prompt, refs, aspect, size, mode) → task_id` (task_type=STYLE_DESIGN)
37 - `cancelTask(task_id)`
38 - `pasteFromClipboard() → list[str]` 三层 fallback(hasUrls / mime raw bytes / imageData / clipboard.image)
39 + macOS osascript 兜底(避免 Qt clipboard NSPasteboard→NSImage native crash)
40 - `normalizeFileUrls(urls) → list` (内部走 _validate_image_file 校验扩展名 + ≤10MB + QPixmap)
41 - `validateImageFile(path) → {ok, reason}` / `validateImageFiles(paths) → list`
42 - `saveFile(src, dest) → bool` 下载图片
43 - `addSavedPrompt(p) / removeSavedPrompt(p) / toggleSavedPrompt(p) → bool` (返回切换后的"已收藏"状态)
44 - `isSavedPrompt(p) → bool`
45 - Signal: `taskSubmitted(taskId)`, `taskCompleted(taskId, resultPath, prompt, model)`,
46 `taskFailed(taskId, error)`, `taskProgress(taskId, progress, statusText)`,
47 `apiKeyChanged / busyChanged / savedPromptsChanged`
48 - 内部:_on_completed 调 history.save_generation → 写 task.result_path → emit taskCompleted
49
50 **HistoryBridge**
51 - Property: `model` (HistoryListModel QAbstractListModel) / `count`
52 - Slot:
53 - `refresh()` 整体 reset / `addNew(ts)` 增量插顶
54 - `deleteItem(ts)` 增量删 / `clearAll() → bool` rmtree+重建
55 - `getItem(ts) → dict` 详情 / `thumbnailPath(ts) → str` 缩略图路径
56 - `revealInExplorer(path)` Windows explorer /select, / macOS open -R / Linux xdg-open
57 - `copyToClipboard(text) → bool`
58 - `redoToImageGen(ts)` → emit redoRequested 让 ImageGenTab 回填 prompt+参考图+设置
59 - Signal: `itemAdded(ts) / itemRemoved(ts) / countChanged`,
60 `redoRequested(payload)` payload: {timestamp, prompt, referenceImages, aspectRatio, imageSize, mode}
61 - HistoryListModel.roleNames: display / decoration / toolTip / timestamp(=UserRole)
62
63 **TaskQueueBridge**
64 - Property: `model` (_TaskListModel) / `pendingCount` / `runningCount`
65 - Slot: `cancelTask(task_id)`, `loadTask(task_id)` → emit taskLoadRequested 回填到对应 tab
66 - Signal: `pendingCountChanged / runningCountChanged`,
67 `taskLoadRequested(payload)` payload: {taskId, type ("image_gen"|"style_design"),
68 prompt, referenceImages, aspectRatio, imageSize, mode, resultPath (空字符串 if 未完成)}
69 - _TaskListModel.roleNames: `taskId / prompt / status / progress / statusText / elapsed`
70 - status 值: "pending" / "running" / "completed" / "failed"
71
72 **JewelryBridge**
73 - Property: `categories` (list, 8 个类别)
74 - Slot: `getOptions(cat) → list`, `addItem(cat, val)`, `removeItem(cat, val)`,
75 `resetCategory(cat)`, `resetAll()`, `previewPrompt(formData) → str`
76 - Signal: `libraryChanged(category)`
77
78 ---
79
80 **主要 wiring 模式**(QML 端):
81
82 1. ImageGenTab 接 `taskQueue.taskLoadRequested` → type=image_gen 时回填 + 切 tab 0
83 2. ImageGenTab 接 `history.redoRequested` → 回填(不带生成图)+ 切 tab 0
84 3. StyleDesignerTab 接 `taskQueue.taskLoadRequested` → type=style_design 时回填 assembledPrompt + 切 tab 1
85 4. ImageGenTab 接 `imageGen.taskCompleted/Failed/Progress` → 自己 myTaskIds 数组管理多任务
86
87 **重要约束**
88 - bytes 永远不传 QML,写盘 → 传文件路径
89 - Path 对象转 `as_posix()`(防 Windows 反斜杠在 QML "file:///" + path 拼接异常)
90 - HistoryItem 等 dataclass 不直接暴露,用 getItem 转 dict
91 - 异常都用 `logger.exception(msg)` 写完整 stack 到 logs/app.log
1 ---
2 name: core/ 业务核心模块结构
3 description: image_generator.py 5082 行拆解后的业务核心目录布局(task #20 完成)
4 type: reference
5 originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077
6 ---
7 **背景**:image_generator.py 原本 5082 行混了 12 个类(数据库/历史/Worker/词库/UI),
8 QML 迁移期顺手拆出业务核心,UI 类留待 task #19 删除。
9
10 **目录布局**(截至 2026-05-10):
11 ```
12 core/
13 ├── __init__.py
14 ├── paths.py get_app_data_path + save_png_with_validation +
15 _migrate_data_from_app_bundle
16 ├── database.py DatabaseManager + hash_password
17 (加了 authenticate_with_hash 走"记住密码"路径,跳过 hash)
18 ├── history.py HistoryItem + HistoryListModel + HistoryManager
19 HistoryListModel.roleNames 已扩展给 QML:display/decoration/toolTip/timestamp
20 ├── generation.py MODEL_BY_MODE / MODEL_PRO / FLASH_ONLY_ASPECT_RATIOS + ImageGenerationWorker
21 └── jewelry.py DEFAULT_JEWELRY_LIBRARY (8 类) + JewelryLibraryManager + PromptAssembler
22
23 core/runtime.py (新加,2026-05-09 抽出,2026-05-10 加日志兜底)
24 enable_crash_diagnostics(含 macOS DiagnosticReports 提示写入 crash_log.txt)
25 init_logging(用 TieredFsyncHandler 替代 RotatingFileHandler)
26 TieredFsyncHandler — WARNING+ 同步 fsync / INFO buffered
27 start_periodic_fsync — 1s 周期 daemon 线程兜底(INFO 最坏丢 1s)
28 log_system_info / cleanup_clipboard_tempfiles
29 flush_logs(升级为对所有 handlers 走 fsync)
30 get_crash_log_path
31 ```
32
33 **image_generator.py.txt**(2026-05-10 重命名):
34 - git mv .py → .py.txt 保留全部历史;Python 不加载,PyInstaller 不扫
35 - 内容是老 QWidget UI 类(LoginDialog / ImageGeneratorWindow / DraggableThumbnail /
36 DragDropScrollArea / StyleDesignerTab + main())和顶部已搬走的工具函数副本
37 - 用户要求暂不删,留作扒老逻辑参考;task #19 真正"删掉"动作要等用户确认 QML 版稳定后
38
39 **外部消费**
40 - task_queue.py / temp_clean.py: `from core.generation import ImageGenerationWorker`
41 - bridges/*: `from core.history import HistoryManager / HistoryListModel`,
42 `from core.database import DatabaseManager`, `from core.jewelry import PromptAssembler`
43 - image_generator.py 顶部 `from core.* import *` 是 re-export,让 LoginDialog /
44 ImageGeneratorWindow 内部代码无感知(仍按原名字调用,任务 #19 一起删)
1 ---
2 name: 项目入口、打包、远端
3 description: 主入口、PyInstaller spec、打包脚本、Git 远端等关键定位
4 type: reference
5 originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077
6 ---
7 **主入口**
8 - `image_generator.py` `main()` (Phase 1-6 启动序列)
9 - QApplication 创建在 Phase 4,主题应用在 Phase 4 同步
10 - preflight 在 Phase 4.5,登录页在 Phase 6
11
12 **打包**
13 - spec 文件:`ZB100ImageGenerator.spec`(跨平台单一真相源)
14 - Windows 脚本:`build_windows.bat`(自动建 venv + pip install + pyinstaller,最后 pause)
15 - macOS 脚本:`build_mac_universal.sh`
16 - 直接命令:`.venv/Scripts/pyinstaller.exe ZB100ImageGenerator.spec`
17 - 产物:`dist/ZB100ImageGenerator/ZB100ImageGenerator.exe` (~134MB)
18
19 **Git 远端**
20 - `origin: http://gitlab.zb100.com:10080/chaijin/GoogleNanoBananaApp.git`
21 - 默认主分支 `master`
22 - Git 用户 `chaijin`
23
24 **用户管理工具**(管理员):
25 - `python user_util.py [add|list|disable|enable|reset] <username> [<password>]`
26 - 操作 MySQL `nano_banana_users` 表(hash SHA256)
27 - 配置从 `config.json``db_config` 字段读取
1 ---
2 name: PyInstaller 打包配置 (task #19)
3 description: ZB100ImageGenerator.spec 当前形状 + 易踩坑(QML 路径 / Pillow / pathex)
4 type: reference
5 originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077
6 ---
7 **spec 当前形状(2026-05-10)**
8
9 ```python
10 a = Analysis(
11 ['qml_poc/main_qml.py'], # 入口(不是老 image_generator.py)
12 pathex=[str(Path('.').resolve())], # 项目根,让 PyInstaller 找 audit_logger 等顶层模块
13 binaries=pil_native_libs, # Pillow .dylibs/.libs collect_dynamic_libs
14 datas=[
15 ('config.json', '.'),
16 ('qml_poc/qml', 'qml'), # ← 目标路径不带 qml_poc/ 前缀!
17 ('jewelry_library.json', '.'),
18 ] + 平台特定:
19 IS_WIN: ('zb100_windows.ico', '.')
20 IS_MAC: ('zb100_mac.icns', '.')
21 hiddenimports=[
22 'PySide6.QtQml', 'PySide6.QtQuick', 'PySide6.QtQuickControls2',
23 ],
24 )
25 ```
26
27 **关键坑(踩过的)**
28
29 1. **QML datas 目标路径必须是 `qml/` 不是 `qml_poc/qml/`**
30 原因:PyInstaller 把入口脚本 `qml_poc/main_qml.py` 平铺到 `_MEIPASS/main_qml.py`
31 (不是 `_MEIPASS/qml_poc/main_qml.py`),所以 `Path(__file__).parent / "qml"`
32 = `_MEIPASS/qml`。datas 写 `('qml_poc/qml', 'qml')` 才对得上。
33
34 2. **pathex 必须显式给项目根**
35 main_qml.py 顶部 `sys.path.insert(0, ROOT)` PyInstaller 静态分析看不到,
36 不给 pathex → 打包后 `from audit_logger import ...` ModuleNotFoundError。
37
38 3. **Pillow .dylibs 在 macOS 上必须收集**
39 spec 里有完整逻辑(collect_dynamic_libs + 显式枚举),输出量在 console。
40 macOS 验证打包要看 `[spec] 最终 Pillow 原生库数量: > 0`
41
42 **构建命令**
43 - Windows: `build_windows.bat``.venv/Scripts/pyinstaller.exe ZB100ImageGenerator.spec --noconfirm`
44 - macOS: `bash build_mac_universal.sh` (顺便打 .dmg,含 drag-to-install 布局)
45
46 **产物路径**
47 - Windows: `dist/ZB100ImageGenerator/ZB100ImageGenerator.exe` + `_internal/`
48 - macOS: `dist/ZB100ImageGenerator.app` + `dist/ZB100ImageGenerator.dmg`
49
50 **Windows 验证状态(2026-05-10)**
51 打包通过 → 启动 8 phases 全过 → QML 装载成功 → 进入主循环零警告。
52 日志在 `dist/ZB100ImageGenerator/logs/app.log`
53
54 **macOS 验证状态**:未做(开发机是 Windows)。明早起来 `bash build_mac_universal.sh`
55 跑一遍验证,重点看 .dmg 在 NAS / 邮件传输后 PIL/.dylibs symlink 是否完整。
56
57 **仍未删的旧入口**`image_generator.py.txt`(2026-05-10 git mv 改 .txt,不参与打包扫描)
58 用户要求确认 QML 版稳定后再删。
1 ---
2 name: QML PoC 文件结构与设计系统
3 description: feat/ui-qml-poc 分支的 QML 代码组织、Theme 令牌、组件 API
4 type: reference
5 originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077
6 ---
7 **目录结构**
8 ```
9 qml_poc/
10 ├── main_qml.py 入口:装配 5 桥 + audit_logger + history.refresh()
11 │ env 调试:QML_AUTO_LOGIN=1 / QML_DEBUG_TAB=0|1|2
12 └── qml/
13 ├── qmldir 模块声明(singleton Theme 1.0)
14 ├── Theme.qml Singleton 设计令牌
15 ├── Main.qml ApplicationWindow(登录态切换尺寸 + 子页)
16 ├── LoginScreen.qml 登录页(接 auth.login,错误展示 + busy)
17 ├── MainWindow.qml 主窗口(下划线 TabBar + 任务队列 sidebar 接 taskQueue.model)
18 ├── ImageGenTab.qml 图片生成 tab(参考图录入/收藏/下载/预览全接 imageGen)
19 ├── HistoryTab.qml 历史记录 tab(ListView + 详情面板,接 history.model)
20 ├── StyleDesignerTab.qml 款式设计 tab(8 字段 + 实时 Prompt 预览 + 生成)
21 └── components/
22 ├── Card.qml 圆角 + 极淡边框,default property 子元素
23 ├── PrimaryButton.qml pill 圆角 + Apple Blue + 120ms ColorAnimation
24 ├── SecondaryButton.qml 圆角描边,hover 出灰底
25 ├── ThemedTextField.qml 焦点 2px 蓝边动效
26 ├── ThemedComboBox.qml 自定义 chevron + popup 圆角
27 └── CaptionLabel.qml 12pt DemiBold,组上方标签
28 ```
29
30 **Theme.qml 暴露的 token**(singleton,QML import 后 `Theme.accent` 直接用):
31 - 颜色:bgCanvas/bgSurface/bgElevated/bgSubtle/bgHover, textPrimary/Secondary/Tertiary/OnAccent,
32 borderDefault/Strong, divider, accent/Hover/Pressed/Subtle, success/warning/danger
33 - 尺寸:radiusSm/Md/Lg/Pill, space1-6, controlHSm/Md/Lg, fontXs/Sm/Base/Lg/Xl/Xxl
34 - 字体:fontFamily(按 Qt.platform.os 自动选 SF Pro / Segoe UI Variable)
35
36 **关键设计规则**
37 - 所有圆角用 `Theme.radiusXxx`,不要硬编码
38 - 所有颜色用 `Theme.xxx`,不要硬编码 hex
39 - caption + control 用 ColumnLayout spacing 4-6,组之间 spacing 12-16
40 - Card 内 anchors.margins 用 `Theme.space4 (16)` 保证一致
41 - 主按钮(生成 / 登录 / 提交)一律 PrimaryButton(pill 圆角)
42 - 次按钮(添加 / 下载 / 取消)一律 SecondaryButton(描边圆角)
43 - 状态色(成功 / 失败 / 等待)用 `color: Theme.success/danger/warning`
44
45 **AppState QObject**(main_qml.py,作为 contextProperty 暴露):
46 - Property: `loggedIn` (bool), `currentTab` (int)
47 - Slot: `login(username, password) → bool`, `logout()`, `setTab(idx)`
48 - Signal: `loggedInChanged`, `currentTabChanged`
49 - 当前是 PoC 占位(login 接受任意非空),下一步要换成真实 db 认证
50
51 **业务桥层 TODO**(task #12):除 AppState,还需要暴露:
52 - `imageGen`:参考图列表 / 提示词 / 生成方法 / 进度信号
53 - `styleDesigner`:字段列表 / 词库管理 / Prompt 预览
54 - `history`:QAbstractListModel(复用现有 HistoryListModel)
55 - `taskQueue`:QAbstractListModel for 任务列表 + 取消方法
56 - `theme`:跟随系统 colorScheme,触发 QML Theme 切换
1 ---
2 name: 跨平台 UI 一致性诉求
3 description: 用户强烈关注 macOS 和 Windows 两端的视觉与交互一致性,会优先选择能跨平台统一表现的方案
4 type: user
5 originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077
6 ---
7 用户在选 UI 设计方向时明确说:"因为这个也跟我们的品牌元素的颜色契合"以及"可以统一 MacOS 与 Windows 的设计语言"。
8
9 在 dark mode 决策上他强调:"macos 会让软件跟随时间自由转换深浅主题,你可以不做深色主题,但是它变的时候就会巨丑巨难看,这个你应该知道的" — 说明他对系统级 OS 行为有深刻观察,期望应用级响应。
10
11 **应用方式**:未来给这个项目提任何 UI / 视觉建议时:
12 - 优先选 platform-neutral 的设计语言(Apple HIG / Material Design)而不是单平台专属(Fluent UI / iOS-specific)
13 - 涉及 OS 行为(系统主题、字体、缩放、HiDPI)必须双平台都验证
14 - 推荐第三方库前确认 Mac + Windows 都被支持
15 - 字体栈用回退(SF Pro → 苹方 → Segoe UI Variable → 微软雅黑)
1 ---
2 name: 自主交付偏好(overnight 模式)
3 description: 用户接受 "睡前授权 → 醒来在公司 review 分支" 的工作模式,前提是有清晰兜底
4 type: user
5 originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077
6 ---
7 2026-05-09 凌晨用户 brainstorming 完 UI 重设计后说:"我去睡觉了,你搞好把 memory 啥的 save 一下,推送到一个新分支,我明天在公司看新的分支里的内容就行了"。
8
9 明确认可的工作流:
10 1. 新分支隔离(不动 master)
11 2. 分支根目录留 OVERNIGHT_SUMMARY.md 供醒来看进度 + 验收清单
12 3. 多次小颗粒 commit(不是一个大 commit),便于 cherry-pick 或单点 revert
13 4. memory 同步保存
14 5. 推到 origin(GitLab)
15
16 **应用方式**:当他再次给出"你直接搞" / "我去睡了" 类指令,且任务符合"破坏性可控、有明确成功标准"时,可以走 overnight 模式:
17 - 先用 1-2 行确认范围 + 兜底(不动 master / 不破坏功能 / 仅视觉层 etc.)
18 - 不在中途追问澄清;保留为已知问题写在 SUMMARY 里
19 - 全程小步 commit,每个 commit message 精确到"做了什么 / 为什么"
20 - 顺手提交的 untracked 文件要在 SUMMARY 里说明
21 - 任务完成后必须打包/启动验证,让用户醒来直接能跑
22
23 **不适用场景**:涉及数据库变更、生产部署、密钥/凭证、第三方 API 协议变更 — 这些必须等用户在场。
...@@ -16,7 +16,8 @@ dist/ ...@@ -16,7 +16,8 @@ dist/
16 # IDE 16 # IDE
17 .idea/ 17 .idea/
18 .vscode/ 18 .vscode/
19 .claude/ 19 .claude/*
20 !.claude/memory/
20 21
21 # Runtime / user data 22 # Runtime / user data
22 logs/ 23 logs/
......