本页注释仓库各目录的职责(以 lib/ 为主,并覆盖 backend/ 与其它顶层目录),并标注几个大文件的当前行数。Agent 要改动代码前应该先看这里。所有行数为 2026-06-21 wc -l 实测值——线条会漂移,重新计算请勿信旧值。
顶层目录:
lib/(Flutter 客户端,下面详述)、backend/(账户系统 + CM4 云端)、android/ios/web/(平台 target)、assets/、l10n.yaml生成的lib/l10n/、test/、tools/、protocol-docs/、docs/。
此外,lib/features/onboarding/ 是当前真实存在且重要的功能子系统,承载首启权限说明页 PermissionsIntroPage、Android 后台权限引导页 BackgroundPermissionPage,以及首页首启提示 home_onboarding_overlay.dart。
其中 home_onboarding_overlay.dart 当前不是单条静态提示,而是由 HomeOnboardingController 驱动、只展示一次的两步 coach-mark:首页第 1 步显示 Welcome 提示,第 2 步显示 Add Device 提示,二者都锚定 dashboard 右上角的 "+" 按钮;是否已看过通过 SharedPreferences 键 home_onboarding_seen_v1 持久化。main.dart 会在冷启动后的引导链中先后调用这些入口,而不是仅零散引用几个独立页面。
补充:app.dart 现还在应用最顶层常驻 cookSessionRecorderProvider 与 authControllerProvider,并在 MaterialApp.builder 每次重建时调用 NotificationService.updateLocalizations(...);也就是说它不仅管路由和 alarm 页面跳转,还承担了全局烹饪记录、登录态恢复和通知文案语言同步。
另外,builder 现在最外层还会包一层 ConnectionAlertHost,使 WiFi 模式下的连接丢失提醒可以跨页面弹出;AlarmBannerHost 只是其内部的一层。
补充:main.dart 当前除基础启动顺序外,还实际承载了若干关键首启/冷启动流程。
另外,文件还处理真实的后台→前台账号同步补偿:当 App 从 paused/hidden 恢复到前台时,会调用 _onForegroundedAccountSync(),先 stop() 再重启 deviceBindingRealtimeProvider 的订阅,然后主动执行 syncAccountBoundDevices(ref) 与 cookLogProvider.notifier.syncNow()。也就是说,其他手机在本机后台期间发生的绑定设备变更与 cook log 变化,不只依赖冷启动或 realtime 重连,还会在一次真实的前台恢复时补拉补齐。
另外,main.dart 现在还负责账号会话治理:启动时与运行中登录态切换时都会先调用 _ensureAccountSession() 做“≤4 台手机登录位”准入;若超限,会弹 _showSessionLimitPicker(...) 让用户移除一台旧手机后再继续。通过准入后,文件会启动 _startSessionRealtime() 与 _startLivenessMonitor():前者在本机登录位被其他手机移除时触发 _handleSessionKicked(),清理本地账号/设备相关数据并签退;后者每 60 秒执行 _checkAccountLiveness() / _checkSessionPresence(),连续两次账号存活探测均返回 deleted 后,才会走 _handleRemoteAccountDeletion(),调用 wipeAllLocalData(ref) 做全量本地清空并弹出远端删号提示;首次 deleted 会在 10 秒后复探,避免单次误判触发清空。此外,runApp() 之后它还会在根 ProviderContainer 外挂常驻报警评估:监听 connectedBoostersProvider 并刷新 alarmStateProvider,Timer.periodic(const Duration(seconds: 5), ...) 会在 Dart 事件循环仍运行时每 5 秒强制重评一次;Android 暂停时事件循环可能被冻结,因此不能保证后台/暂停期间持续推进。此外它还在 runApp() 前安装了两条全局崩溃日志入口:FlutterError.onError 会把框架层未捕获异常写入 DevLogService.logCrash(...),PlatformDispatcher.instance.onError 会记录根区异步异常,并对 supabase_flutter 抛出的未捕获 AuthException 以及 broker TLS 半开 socket 的 SocketException: Reading from a closed socket(经 CloudConnectionRegistry.reportClosedSocketPumpError() 处理)返回 true,避免登录深链失败或 MQTT pump 风暴直接把 App 杀掉。首次启动时,会先进入 PermissionsIntroPage 说明页,再触发延后的系统权限申请,而不是一上来直接弹系统权限。进入主界面后的启动检查链还会依次处理缺失权限提示、系统蓝牙关闭提醒、通知/铃声音量过低提醒,以及 Android 的后台权限 / OEM 自启动引导页。另一个重要流程是账号态同步:main.dart 不会在 _initKnownDevices() 完成后无条件直接同步,而是先通过 _ensureAccountSession() 做账号会话准入;只有其返回 true 时,才会调用 reconcileAccountRegion(ref) 与 syncAccountBoundDevices(ref),并启动相关订阅/监测。运行中从未登录切到已登录时,同样先经过这道 gate,再执行后续同步逻辑。当账号下其他手机新增绑定设备时,会通过 onSync 再次调用 syncAccountBoundDevices(ref) 同步本机设备列表;删除绑定设备时则走 onDelete,调用 forgetDevice(ref, name, unbind: false) 做完整本机清理:断开 BLE、停止连接管理、清除重连队列并归档活跃烹饪。退出登录时会调用 stop() 取消订阅。此外,这条冷启动链在后台权限引导之后还会调用 _maybeReNudgeAfterKill(),当 Android 后台监测期间曾被系统杀死且满足条件时再次弹出 OEM 自启动引导;最后还会调用 homeOnboardingProvider.notifier 的 maybeShow() 触发首页首启提示。
| 文件 | 行数 | 作用 |
|---|---|---|
main.dart |
1033 | 入口:初始化顺序严格——WidgetsFlutterBinding → 屏幕方向锁竖屏 → DevLogService.init()(必须 first awaited) → APP_START 锚点 + 元数据 → PushSyncService.instance.init()(在 runApp() 前注册后台 device-sync push 入口) → 非首次启动时 AppPermissions.requestAllUpfront()(首次启动推迟到权限介绍页) → 显式 ProviderContainer → runApp() → _AppExitObserver(lifecycle)+ MethodChannel culinatech.app/lifecycle(native onDestroy)。_AppExit.run() 双触发幂等(dart-detached / native-onDestroy 谁先到谁赢);清理顺序上还会先同步调用 cookingSessionsProvider.notifier.finalizeActiveForAppExit() 收尾活跃烹饪,并在 BLE/MQTT shutdown 后 best-effort 调用 CookingLiveActivityService.endAll() 结束 iOS 实时活动。 |
app.dart |
234 | MaterialApp、onGenerateRoute 实际还额外处理了 WifiNetworkSelectPage.reconfigureRouteName 这一强制重配网入口,因此不止文中列出的 10 个带参路由。(ConnectionModePage / WifiNetworkSelectPage / WifiSetupPage / BoosterConfigurationsPage / FirmwareUpgradePage / SignInLandingPage / EmailAuthPage / EmailCodePage / ForgotPasswordPage / CookingPage)+ 12 个静态路由表、rootNavigatorKey + rootRouteObserver、safety alarm 全屏推送监听(internalOverTemp / ambientOverTemp → WarningPage,其它类型走 AlarmBannerHost banner)、Live Activity sync provider 订阅 |
lib/core/ — 跨业务共享层补充:lib/core/config/ 存放客户端编译期配置:supabase_config.dart(Supabase URL/anon key,USE_SUPABASE dart-define 开关)与 firebase_push_config.dart(FCM 后台 device-sync push 的 FirebaseOptions,未配置时 PushSyncService 保持 dormant)。
core/models/补充:probe.dart 当前还新增了 cookTimer 字段,表示 booster 上报的该探针烹饪已运行时长;null 表示本次报文未携带计时器,Duration.zero 则表示 booster 明确上报“已停止”。这使探针模型本身也承载了多手机同步与远端结束烹饪所需的权威计时信息。
补充:cooking_session.dart 现在除了 CookingSession 与 CookSessionStatus 外,还定义了 TemperatureReading,并把到达目标后的拖尾记录流程显式建模到 targetReachedTime、acknowledgedTime、markTargetReached()、finalizeComplete()、ackWindowEnd() 等字段/方法里;这部分是当前烹饪完成判定与时间线恢复的核心。另一个当前重要字段是 presetName,并通过 displayMeatName 优先回显用户在目标页选择的预设标签;它用于保留 Mutton、Goose、Lobster、Ostrich、Ham 及 Custom N 这类不会被 MeatType 精确表达的名称,且已进入会话 JSON 序列化/反序列化。
| 文件 | 行数 | 内容 |
|---|---|---|
booster.dart |
377 | Booster(设备快照) + DeviceStatus 枚举(connected / lostConnection / boosterShuttingDown / boosterOff / allDocked) + WifiStatus / ServerRegion + devicePrefix() / deviceTypeLabel() / getProbeCount() 工具方法;export BoosterFamily 自 transport |
补充:Booster 当前还承载了多项关键运行态字段,包括 espFirmwareVersion、ringCount、wifiMac、wifiRssiDbm、mqttConnected,以及按 CM4 屏显顺序重排探针列表的 probesInDisplayOrder;这些字段已直接服务于 OTA 版本判断、铃声设置回读、设备信息展示、WiFi/MQTT 连通性展示和多探针 UI 排序。
| probe.dart | 399 | Probe(探针快照) + ProbeNumber 枚举(含 colorName / firmwareIndex / labelFor()) + ProbeAddress 常量(pen1=0x0A 等) + MeatType / Doneness 枚举;2026-04 重构后 ProbeAlarmConfig / ProbeSensorFlags 等烹饪/报警/范围标志已迁出,详见 状态模型 §探针级 |
补充:该文件当前还定义了 ProbeNumber.cm4LcdOrder,用于把 CM4 探针按蓝 / 白 / 黑 / 黄的屏显顺序排序;并提供 ProbeNumber.fromIdentifierByte(...)、ProbeNumber.isNewProtocol(...) 统一兼容新协议 0x01..0x04 与 legacy 0x0A/0x0B/0x0D/0x0E/0x0F 的探针标识解析。此外,MeatTypeFwTable.validDoneness 还显式约束了各肉类可发送的熟度集合,供 UI 与指令下发层复用。
| cooking_session.dart | 515 | CookingSession + CookSessionStatus(active / completed / cancelled / disconnected) + 序列化逻辑 |
补充:CookingSession 当前还包含 remoteStarted 字段,用于标记“该会话其实是由另一台手机发起、当前手机只是根据 booster 权威计时接管显示/报警的镜像会话”。该字段已进入 JSON 序列化/反序列化,并直接参与多手机 cook log 去重:镜像会话在完成时不会再由本机额外写一条日志。
| connection_display_state.dart | 243 | UI 连接展示层:除 ConnectionDisplayState 外还定义 BtLinkDisplayState;其派生不只依赖 Booster + Probe,还依赖 graceActive、manualReconnectInProgress、cloudLive 等状态 |
补充:该文件当前还提供了三个关键派生函数:btLinkDisplayState(...) 统一将 BLE RSSI 映射为 1~4 格或断连态;boosterConnectionDisplayState(...) 负责 booster 级而非 probe 级的连接展示;shouldHideLostBannerForCloud(...) 则在“所有当前展示设备都已 cloud-live”时抑制 dashboard 顶部的 Lost connection banner。
core/protocol/补充:booster_message.dart 当前不只承载 CM4SettingsResponse。其中 CM4VersionInfo 对应 VER 查询回复;其 firmwareVersion 是 ESP(乐鑫 WiFi 芯片)的十进制版本,和遥测中的 JieLi BLE 芯片 Booster.firmwareVersion 不同。它还定义了 CM4WifiStatus、CM4MqttStatus、CM4CredAck、CM4RingCount、CM4DisplayMode、CM4VersionInfo、CM4SettingsAscii 等统一解析消息类型,分别覆盖 WiFi/MQTT 状态、配网凭证写入 ACK、铃声时长、屏显模式、VER 版本+WiFi MAC,以及 SETT== 设置推送等上行消息。
2026-05 前 cm4_data_parser.dart 是 1061 行的 "多协议巨型解析器";现已拆成 6 个文件,按职责切分:
另:cm4_protocol.dart 现在不只提供下行命令常量/构造器。它还定义了 HOST=? 未写入时的默认返回哨兵 Default mqtt broker!,以及 ProbeConfigCommand.tryParse(...) 这一反解析器,用于把 SET_BL/WH/BU/YE=ABCDEF 这类探针配置命令重新解成 probeSlot、alarmEnabled、单位、目标温度、meatWireE、donenessWireF,供多手机同步等上层逻辑复用。
另外,该文件当前还定义了 Cm4WorkState,使 SET_<probe>=ABCDEF 可按需扩展为 7 字符的 SET_<probe>=ABCDEFG:G=0 停止烹饪、G=1 开始烹饪、G=2 保持当前 work-state;ProbeConfigCommand.tryParse(...) 也已同步接受 6 字符与 7 字符两种载荷并回填 workState。同一文件还定义了 RI_CNT= / RI_CNT=?,其中 4 表示 Mute。
| 文件 | 行数 | 作用 |
|---|---|---|
cm4_protocol.dart |
301 | CM4 ASCII 命令构造器(SET_RD、SET_F/SET_C、CNT_0、SET_BL/WH/BU/YE=ABCDEF、BL_LVL=、RI_LVL=、SSID=/PSWD=、HOST=/HOST=?、OTA 等) |
补充:该文件当前还定义了 booster 屏显模式命令 TEMP_INT / TEMP_EXT / TEMP_ALL 及查询 TEMP=?,并包含 WIFI=0/1、M_ID=、M_PD= 等配网与云端登录路径实际使用的命令。另外,报警相关还区分了两条不同命令:RING_OFF 只用于静音当前正在响的 buzzer;若要清除单探针在 booster 侧的报警状态,则使用 disarmProbe(...),其 wire 形式为 SET_{COLOR}=000000<G>。
| legacy_protocol.dart | 164 | CM1/CM2/CM3 传统字节命令(0x55AB、0x55AE、0x55B1、0x55AD、0x55AF/B0/B2 SET_TARGET) + commandByteFromAddress() 地址→命令字节映射 + reconstructMacFromCompressed() |
| cm4_data_parser.dart | 478 | CM4 ASCII 解析(D=、PENON/PENOFF、SETT==、VER 查询回复、WIFI_STS=、MQTT_STS=、M_ID OK/M_PD OK、RI_CNT=、<deviceId> online 等消息) |
补充:该解析器当前还会识别 OTA=N% 形式的 ESP OTA 进度上行消息,并产出 CM4OtaProgress(percent);百分号可省略,结果会被夹到 0..100。
补充:该解析器当前还会解析 booster 屏显模式查询回读 TEMP_INT / TEMP_EXT / TEMP_ALL,并容错接受 TEMP=INT/EXT/ALL 形式,产出 CM4DisplayMode。
补充:该解析器还会把 SSID=? 扫描回复(每条 BLE 通知一个 AP)解析为 CM4WifiScanEntry,供 WifiNetworkSelectPage / box_wifi_scan_service.dart 汇总附近网络列表。
| legacy_data_parser.dart | 429 | legacy 二进制解析(12B 设置响应、15B 探针温度、2B 心跳、0x55AA 入仓) |
补充:该解析器还处理 8 字节 0x55B0 探针状态通知(尾部携带 6 字节探针 MAC),并产出 CM4ProbeAddressNotification。
| booster_message.dart | 481 | 解析输出的统一消息类型层(CM4Message 家族 + CM4SettingsResponse) |
| temperature_lookup.dart | 199 | ADC→°C 查表 LUT(tempIntArray 内温 / tempExtArray 外温)——抽出公共 LUT,CM4 / legacy 解析共享 |
补充:该文件还放着跨协议公共工具:BoosterBatteryReading / decodeBoosterBattery()(中继盒电量与充电态解码)、tempCtoF() / tempCtoFNullable()、hexToBytes(),以及 ADC 反查核心 reverseLookup()。
core/transport/ — 传输层抽象(2026-05-01 拆分落地)补充:BoosterTransport 当前除 connect / disconnect / setProbeTarget / setUnit / muteAlarm / queryStatus 与三条流外,还定义了 deviceId / family / probeCount 三个只读属性、dispose() 释放接口、disarmProbeAlarm(ProbeNumber) 按探针清除 booster 侧报警,以及 sendSetting(String) 这一通用设置下发入口。
补充:Cm4BoosterTransport 不仅封装 CM4 的 ASCII 命令;当前发送策略已不是“仅 BLE 断开才走云端”。当设备处于 cloud-primary 时,它会优先把命令通过 _cloudSend 发布到 /CM4/<id>/apps;只有在非 cloud-primary 场景下,才先走 BLE、再在 BLE 不可用时回退到云端。因此 booster 级设置既支持 BLE,也支持 MQTT-first 的路径。
| 文件 | 内容 |
|---|---|
booster_transport.dart |
abstract class BoosterTransport:connect / disconnect / setProbeTarget / setUnit / muteAlarm / queryStatus + dataStream / connectionStateStream / rssiStream |
booster_family.dart |
enum BoosterFamily { legacy, cm4 } + BoosterFamilyExt(心跳 bytes/cadence、MTU 决策) + BoosterFamilyDeviceId 扩展('CM4_xxx'.boosterFamily) |
补充:BoosterFamilyExt.heartbeatIntervalSeconds 当前对 legacy 与 cm4 都固定为 45 秒;heartbeatBytes 分别映射为 legacy 的 LegacyCommand.lockRefresh(0x55B1)与 CM4 的 CM4Command.heartbeat(CNT_0);requestsLargeMtu 仅对 CM4 为 true。
| legacy_booster_transport.dart | legacy 实现(45s 0x55B1 心跳、0x55AB 单位、0x55AD mute、0x55AF/B0/B2 SET_TARGET) |
| cm4_booster_transport.dart | CM4 实现(45s CNT_0 独占锁刷新——per Liang 2026-06-06 / c613148 起与 legacy 对齐;ASCII 命令、512 MTU 协商) |
BleDeviceService._transportFor(deviceId) 按 deviceId.boosterFamily 懒创建并缓存到 _transports[deviceId]。详见 04-规划与跟进/02-传输层重构。
core/providers/另:connection_alert_provider.dart 现在不只是“有一个 WiFi 模式断连提示 provider”。它实际定义了 ConnectionAlertKind.usingBluetooth / disconnected 两类告警语义,并以固定 _sweepInterval = 5s 轮询、在云端上行连续中断 _alertAfter = 60s 后才出提示;也就是说该子系统显式建模了“云断但 BLE 顶上”与“云断且 BLE 也不可用”这两种不同用户提示。另外,当前实现还有两个关键抑制条件:当前代码只要求该设备仍属 cloud-primary,且本机会话里至少一次见过它 cloud-live;随后只要 booster 自身经 BLE 上报 mqttConnected == false / wifiStatus == WifiStatus.disconnected,或在“本机会话曾见过 cloud-live 且当前不聋”的前提下云端遥测继续静默,代码才会开始/继续跟踪断连。若只是本机 broker 会话事件变为 disconnected,当前实现会把这视为“本机听不见了”,暂停并重置这段 outage 的成熟计时,而不是把它本身当作断连触发条件。,避免“本机其实听不见”或“这台手机这次会话里从未见过它在线”时误报。并且同一次 outage 一旦被用户 dismiss,就会写入 _dismissed,直到该设备云链路恢复前都不会重复弹出。
| 文件 | 行数 | 内容 |
|---|---|---|
device_providers.dart |
3645 | 主要的 Riverpod 状态聚合文件,但并非所有 StateNotifier 都集中在这里;lib/core/providers/connection_alert_provider.dart 还单独定义了 connectionAlertProvider / ConnectionAlertNotifier,用于 WiFi 模式断连提示:boosterProvider.family / connectedBoostersProvider / cookingSessionsProvider / cookLogProvider(持久化,capped 50 条) / alarmStateProvider(threshold 评估,main.dart 的 listen+Timer 驱动重评) / temperatureUnitProvider / appLanguageProvider / lastBoosterNameProvider。文件大,建议按功能拆:booster / cooking / alarm / settings |
core/services/补充:当前该目录还包含 cloud_connection_registry.dart,它不是单一 MQTT 连接,而是按 deviceId 维护独立的 MqttService,用于让多台 CM4 在 WiFi 模式下同时保持各自云连接并合并遥测流。
另外,core/services/ 现还包含几项被 main.dart 冷启动链直接依赖的重要服务:account_session_service.dart(账号登录位注册 / 移除 / presence 检查)、background_kill_watchdog.dart(记录“后台监测期间是否被系统杀死”,供下次冷启动决定是否再次弹 OEM 自启动引导)、push_sync_service.dart(在 runApp() 前初始化 device-sync push,并在运行中注册 / 注销 token)。这些文件虽未在本页表格中列出,但已属于当前仓库结构里需要单独知道的核心服务。
补充:同目录还有 process_exit_diagnostics.dart(main.dart 在 runApp() 前 fire-and-forget 调用 ProcessExitDiagnostics.logPreviousExits(),读取 Android 上一次进程死亡原因写入 dev log)与 background_permissions_service.dart(main.dart 的 OEM 后台权限 / 自启动引导页 _maybeShowBgPermsDialog() / _maybeReNudgeAfterKill() 直接依赖)。账号会话踢下线/放弃登录路径还会用到 account_mqtt_cred_service.dart(清理本机缓存的账号 MQTT 凭证)。
| 文件 | 行数 | 作用 |
|---|---|---|
ble_service.dart |
2208 | BLE 底层 I/O:连接、特征发现、读/订阅;连接单飞门 _connectGate 串行化 connect()/directConnect();锁刷新写按 deviceId.hashCode 相位错峰(ble_service.dart:1354);buffer 策略(Strategy A 逐探针节流、Strategy B 缓冲刷新) |
ble_device_service.dart |
4880 | 复杂度热点:多设备状态追踪、_transportFor 路由、重连节奏(前台 + 后台 <4h 始终 15s 不衰减;后台 ≥4h _bgTieredCadenceArmDuration 触发 15/60s/5m 分级)、90s 宽限期(gracePeriod)、入仓关机分类(_dockShutoffWindow=1s + _dockShutoffUiDelay=10s + _dockShutoffReconnectDelay=8s)、packet dispatch、staleness 检查(60s 全沉默 → lostConnection、20s 15B 沉默 → 探针置灰)、_QueryTracker 跟踪 0x55AE↔12B 响应(3s window)、readRssi() 每 10s 采样 Booster.rssi |
device_connection_manager.dart |
626 | BLE vs MQTT 优先级编排,统一遥测流 |
device_service.dart |
75 | 抽象接口(DeviceService) |
mock_device_service.dart |
354 | Mock 实现(dev/test 用) |
alarm_service.dart |
1312 | 每设备报警栈(_active[(deviceId, ProbeNumber?, AlarmType)])、优先级轮换、声音 + 震动派发;AlarmType 13 类(per Liang 2026-04-30 #18 从 7 类扩到 12,2026-05 再加 ambientUnderTemp 共 13);AlarmThresholds(internalOverTempF=212 / internalHiClampC=101 / ambientOverTempF=527 / lowBatteryTrigger=2 等);末尾托管 ProbeSensorFlags + probeSensorFlagsProvider、ProbeAlarmConfig + probeAlarmConfigProvider(5 字段,固定代码);critical battery(≤10%)每 10 min 重复(TAPD #1003012) |
mqtt_service.dart |
1110 | MQTT 云端 fallback,仅 WiFi-enabled CM4 使用;区域由 region_service.dart 决定 broker |
notification_service.dart |
589 | Android 前台服务桥 + 本地通知调度;updateLocalizations() 在 app.dart builder 每次 rebuild 同步当前 locale(per Liang TAPD i18n bug);_alarmContent / startBackgroundMonitoring 走 AppLocalizations 的 notify* / bgMon* 路径 |
foreground_service.dart |
65 | Android 前台服务通道(小封装) |
permissions_service.dart |
278 | 权限请求:requestAllUpfront() 启动时统一请求 + BLE 路径 lazy 重试;currentStatuses() + isEffectivelyGranted() 给 main.dart 的 "missing perms" 弹窗用 |
dev_log_service.dart |
852 | 结构化日志(APP / BLE / PARSER / TRACE / PERMISSION / CORE 事件),含 packet seq #<seq> 关联 |
dev_log_decoder.dart |
279 | 开发者日志导出与解码(base64 / 人类可读 / JSON 三种格式) |
region_service.dart |
211 | MQTT 区域自动检测(IP 地理定位 → China/US/EU,失败默认 China);与 booster 的 USUS= 命令独立——App 选自己的 broker,不写回 booster |
known_devices_service.dart |
159 | SharedPreferences 持久化已配对设备(deviceId、connectionMode、名字);main.dart 启动后 _initKnownDevices() seed reconnect queue |
cooking_live_activity_service.dart |
241 | iOS Live Activities(实时活动)—— 锁屏 / 灵动岛烹饪温度卡,详见 实时活动 |
core/theme/ 与 core/utils/theme/app_theme.dart:深色主题、颜色常量、kAmbientMaxLabelC/F(外温 LUT 上限标签)等utils/anonymous_id.dart:匿名 ID(日志去识别化)utils/log_timestamp.dart:日志时间戳格式化utils/meat_localization.dart:肉种/熟度的本地化字符串映射utils/navigation_utils.dart:Navigator helper(safe pop / 路由判断)lib/features/thermometer/ — 业务层除 thermometer/ 外,lib/features/ 当前还包含独立的 auth/ 子系统:application/ 下有账户状态 provider,presentation/ 下有 AccountPage、SignInLandingPage、EmailAuthPage、EmailCodePage、ForgotPasswordPage 等账户相关页面,并且这些路由已由 app.dart 直接接入应用主路由层。
补充:presentation/ 里还实际存在 account_credential_page.dart,提供 AccountCredentialPage,用于“修改密码 / 为第三方账号注册邮箱”这两类需要邮件二次验证的凭证管理流程;它由 AccountPage 直接 push,而不是挂在 app.dart 的主路由表里。
data/| 子目录 | 文件 |
|---|---|
datasources/ |
ble_thermometer_datasource.dart / cloud_thermometer_datasource.dart / mock_thermometer_service.dart |
repositories/ |
thermometer_repository_impl.dart(对 BLE 数据源的薄封装) |
domain/| 子目录 | 文件 |
|---|---|
entities/ |
device_type.dart / probe_reading.dart / thermometer_device.dart / thermometer_snapshot.dart |
repositories/ |
thermometer_repository.dart(接口,依赖反转) |
presentation/补充:帮助中心当前不是单页直出。HelpCenterPage 先按设备型号进入 HelpTopicsPage 主题列表,再由主题列表 push HelpDetailPage 展示具体帮助内容;因此 help_topics_page.dart 与 help_detail_page.dart 也是当前真实存在且重要的页面文件。
完整路径:lib/features/thermometer/presentation/
补充:pages/cook_log_detail_page.dart 提供 CookLogDetailPage,由 CookLogPage push 打开,用于查看单条烹饪日志详情、编辑备注并展示温度曲线(依赖 cook_graph_axis.dart 等控件)。
补充:presentation/data/ 当前也有真实代码,不只有 pages/、widgets/、providers/、controllers/ 四类文件;其中 meat_doneness_tables.dart 为目标温度页提供按肉类划分的熟度区间数据,并通过 family 处理 CM4 与 legacy 的差异。
pages/(20 个页面文件(不含同目录的 help_models.dart 数据文件),每屏一个;详见界面解析 起的逐屏文档)—— 最大的两个:
dashboard_page.dart(2449 行)—— 多设备卡片网格、连接状态 banner、长按忘记设备cooking_page.dart(2095 行)—— 实时温度图、计时器、目标选择、报警评估、连接 overlaywidgets/ —— 共享控件:
probe_gauge.dart —— 圆形温度表magnifying_ruler.dart —— 目标温度滚动尺temperature_gradient_bar.dart —— 渐变温度条quick_target_sheet.dart —— 快选目标 bottom sheetdev_overlay.dart —— 开发者悬浮调试层glassmorphic_card.dart —— 玻璃拟态卡片样式alarm_banner.dart —— 顶部 alarm banner host(非 safety alarm 用)connection_alert_host.dart —— WiFi 模式云断连合并弹窗宿主(app.dart 的 MaterialApp.builder 最外层包裹,内部再包 AlarmBannerHost)alarm_visual_card.dart —— alarm 视觉卡片help_previews.dart —— 帮助中心的预览控件providers/thermometer_providers.dart —— 业务层 Riverpod Providercontrollers/connection_manager.dart —— 业务层连接控制器lib/l10n/ — 国际化app_en.arb / app_de.arb / app_es.arb / app_fr.arb / app_it.arb / app_zh.arbapp_localizations_*.dart + 基类 app_localizations.dartl10n.yaml + pubspec.yaml 的 flutter: generate: trueandroid/ 与 ios/ — 平台特化android/app/src/main/kotlin/com/example/culinatech_app/MainActivity.kt —— 重写 onDestroy 通过 MethodChannel culinatech.app/lifecycle 通知 Dart 层做 BLE+MQTT 清理。未重写 onTaskRemoved(需要 Service 子类,见 待解决问题 TAPD #9)。同目录下 BleMonitoringService.kt 是 Android 前台服务通道ios/Podfile —— platform :ios, '16.0';Live Activities 需要 iOS 16.1+ 单独 Widget Extension target(见 ios/CulinaTechLiveActivity/SETUP.md)backend/ — 账户系统 + CM4 云端(服务端脚手架)CM4 账户系统与云端 onboarding 的服务端部分。权威设计见 docs/planning/PLAN_ACCOUNT_SYSTEM.md(先读它)。技术栈(PLAN §3,2026-06-05 锁定):Supabase(Auth + Postgres + RLS) + 自建 Mosquitto(mosquitto-go-auth 插件直接对 Supabase Postgres 鉴权)。无 AWS、无 EMQX。
| 子目录 / 文件 | 作用 |
|---|---|
CM4_BROKER_CONNECTION.md |
固件连接规范(host、TLS、鉴权、topic) |
fleet/ |
多区域 CM4 云 broker 集群(见下) |
mosquitto/ |
broker 栈:docker-compose.yml + mosquitto.conf + mosquitto-go-auth,对 supabase/migrations/0002_mqtt_authz.sql 实时鉴权 |
supabase/migrations/ |
0001_app_schema.sql(账户/设备表) / 0002_mqtt_authz.sql(broker 鉴权) / 0003_account_delete.sql(账户注销) |
tls/ |
gen-ca.sh——自建 CA + broker 证书;CA root 嵌入固件并打包进 App(assets/certs/culinatech_ca.crt),全集群共用一个 CA,加区域无需重刷固件 |
backend/fleet/ — 多区域 broker 集群(2026-06-17 上线)每个 box 跑与新加坡 dev broker 相同的自建栈,由同一个 CA 签发。拓扑:Test cm4-hk(阿里云 HK)/ Americas cm4-us(弗吉尼亚)/ EMEA cm4-eu(伦敦)/ APAC cm4-sg(新加坡,原始);均 SWAS 2vCPU/2GiB、Ubuntu 24.04、TLS :8883。脚本读 ~/.culinatech/.env 的阿里云 key。
| 脚本 | 作用 |
|---|---|
provision_one.py <region> |
新建一台 SWAS box + 设密码 + 开 8883 + 重启 |
configure_keepers.py |
给 keeper box 设 root 密码、开 8883、重启 |
list_fleet.py |
跨区域清点所有 SWAS 实例 |
deploy_box.py <hk\|us\|eu> |
从 SG 拉栈 bundle、推到 box、装 Docker、起栈 |
replicate_accounts.py |
把 mqtt_accounts 表 SG → 新 box 复制 |
verify_brokers.py |
TLS + 鉴权 + pub/sub 往返健康检查 |
na_broker_geo.py |
按 Shopify 订单分布分析北美 broker 选址(弗吉尼亚依据) |
| 目录 | 内容 |
|---|---|
assets/ |
图片资源(含 6 语 probe_*_<lang>.png 设备指南图)、assets/certs/culinatech_ca.crt(CM4 云 CA root) |
test/ |
Flutter 单元 / widget 测试 |
tools/ |
开发期工具:HTML 预览页(设备指南 / 帮助 / 图标 / 目标设定)+ Dart 构建脚本(build_apk.dart、bump_version.dart)+ cm4_connect_probe.py 等 |
web/ |
Flutter web target 脚手架(favicon / icons / index.html / manifest),非主要交付 |
protocol-docs/ |
协议原始稿(CM1/CM2/CM3 v4/v5、CM4 的 .docx/.md)——固件团队来源文档 |
docs/ |
仓库内文档,含 docs/claude-memory/ 知识库 |
| 文件 | 行数 | 建议拆分方向 |
|---|---|---|
ble_device_service.dart |
4880 | 已通过 transport-split 卸下了 family-specific 写命令;剩余主体仍可拆:重连循环 / 入仓关机处理器 / packet dispatch 路由 / staleness+RSSI 监控 |
device_providers.dart |
3645 | 按功能拆:booster / cooking / alarm / settings |
ble_service.dart |
2208 | 抽 buffer 策略 + 锁相位错峰 |
dashboard_page.dart |
2449 | 抽出卡片渲染为独立 widget 文件 |
cooking_page.dart |
2095 | 抽出目标选择器 + 温度图为子 widget |
alarm_service.dart |
1312 | 13 类 AlarmType 评估器可按 Tier S/A/B/C/D 拆 |