Przeglądaj źródła

2.11.0 源码模块化重构 P0: 七个模块目录+接口层(common/app_x_guanlan/api.py)+模块边界门+四组件接入点接口+方案文档; 零行为变化

zhouyang.xie 2 tygodni temu
rodzic
commit
6076957aba
52 zmienionych plików z 969 dodań i 33 usunięć
  1. 13 0
      app_algorithm/README.md
  2. 2 0
      app_algorithm/__init__.py
  3. 2 0
      app_algorithm/common/__init__.py
  4. 2 0
      app_algorithm/common/app_algorithm_guanlan/__init__.py
  5. 55 0
      app_algorithm/common/app_algorithm_guanlan/api.py
  6. 13 0
      app_backEnd/README.md
  7. 2 0
      app_backEnd/__init__.py
  8. 2 0
      app_backEnd/common/__init__.py
  9. 2 0
      app_backEnd/common/app_backEnd_guanlan/__init__.py
  10. 39 0
      app_backEnd/common/app_backEnd_guanlan/api.py
  11. 30 0
      app_backEnd/common/app_backEnd_guanlan/cache.py
  12. 21 0
      app_backEnd/common/app_backEnd_guanlan/gateway.py
  13. 13 0
      app_common/README.md
  14. 2 0
      app_common/__init__.py
  15. 2 0
      app_common/common/__init__.py
  16. 2 0
      app_common/common/app_common_guanlan/__init__.py
  17. 40 0
      app_common/common/app_common_guanlan/api.py
  18. 13 0
      app_dataAccess/README.md
  19. 2 0
      app_dataAccess/__init__.py
  20. 2 0
      app_dataAccess/common/__init__.py
  21. 2 0
      app_dataAccess/common/app_dataAccess_guanlan/__init__.py
  22. 35 0
      app_dataAccess/common/app_dataAccess_guanlan/api.py
  23. 26 0
      app_dataAccess/common/app_dataAccess_guanlan/objectstore.py
  24. 27 0
      app_dataAccess/common/app_dataAccess_guanlan/store.py
  25. 13 0
      app_frontEnd/README.md
  26. 2 0
      app_frontEnd/__init__.py
  27. 2 0
      app_frontEnd/common/__init__.py
  28. 2 0
      app_frontEnd/common/app_frontEnd_guanlan/__init__.py
  29. 36 0
      app_frontEnd/common/app_frontEnd_guanlan/api.py
  30. 13 0
      app_ontology/README.md
  31. 2 0
      app_ontology/__init__.py
  32. 2 0
      app_ontology/common/__init__.py
  33. 2 0
      app_ontology/common/app_ontology_guanlan/__init__.py
  34. 44 0
      app_ontology/common/app_ontology_guanlan/api.py
  35. 13 0
      app_qualityGate/README.md
  36. 2 0
      app_qualityGate/__init__.py
  37. 2 0
      app_qualityGate/common/__init__.py
  38. 2 0
      app_qualityGate/common/app_qualityGate_guanlan/__init__.py
  39. 32 0
      app_qualityGate/common/app_qualityGate_guanlan/api.py
  40. 75 0
      configs/modules.yaml
  41. 5 0
      configs/registry.yaml
  42. 1 1
      docs/src/数据要求说明_观澜_2.11.0.md
  43. 35 9
      docs/src/系统设计说明_观澜_2.11.0.md
  44. 19 19
      docs/src/需求分析_观澜_2.11.0.md
  45. BIN
      docs/数据要求说明_观澜_2.11.0.docx
  46. 3 3
      docs/版本记录.md
  47. BIN
      docs/系统设计说明_观澜_2.11.0.docx
  48. 123 0
      docs/重构方案_模块化_v0.1.md
  49. BIN
      docs/需求分析_观澜_2.11.0.docx
  50. 15 0
      guanlan.py
  51. 151 0
      scripts/module_boundary_audit.py
  52. 24 1
      src/version.py

+ 13 - 0
app_algorithm/README.md

@@ -0,0 +1,13 @@
+# 观澜 · 算法(`app_algorithm/`)
+
+**职责**:七系统判级矩阵、七镜头曲线、可靠性指标、控制参数一致性、融合面四源、振动与温度面、趋势与可用率
+
+**允许依赖**:app_common, app_dataAccess
+
+**对外公开面**:`common/app_algorithm_guanlan/api.py` —— 模块间调用**只许**走这里(`scripts/module_boundary_audit.py` 机器检查)。
+
+**当前实现落点(P0 转发目标)**:src/windscada/{taxonomy,audit}.py、src/windscada/perf/*、src/windscada/subsys/*、src/windcms/{report_std,tcm,knowledge,cross_review,audit_rules,pipeline}.py
+
+**迁移计划**:P3:迁入并做纯函数化(输入标准仓、输出判定),判级与曲线逐值对拍验收。
+
+> 依据:`docs/重构方案_模块化_v0.1.md`(用户令 2026-09-22:只重构目录与接口、零行为变化、逐版本可回滚)。

+ 2 - 0
app_algorithm/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 算法(模块根,P0 骨架)。"""

+ 2 - 0
app_algorithm/common/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""本模块的公共组件层(跨模块可复用件放这里)。"""

+ 2 - 0
app_algorithm/common/app_algorithm_guanlan/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 算法 —— 本模块实现包(P0 仅接口,实现仍在既有路径)。"""

+ 55 - 0
app_algorithm/common/app_algorithm_guanlan/api.py

@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 算法 —— **对外公开面**(P0 阶段:接口先立,实现仍在既有路径)。
+
+用户令 2026-09-22:按模块重构源代码目录,**每模块只许经 `api.py` 被别的模块调用**。
+本文件当前把公开名**惰性转发**到既有实现(src/windscada/{taxonomy,audit}.py、src/windscada/perf/*、src/windscada/subsys/*、src/windcms/{report_std,tcm,knowledge,cross_review,audit_rules,pipeline}.py),因此:
+
+* 调用的行为与重构前完全一致(零行为变化);
+* 后续阶段(见 `docs/重构方案_模块化_v0.1.md`)把实现搬到本模块目录后,**只改这里的目标映射**,
+  调用方一行都不用动;
+* 惰性转发(PEP 562)保证 import 本文件不会连带 import 重依赖。
+"""
+from __future__ import annotations
+
+import importlib
+
+# 公开名 → 现有实现(P0 转发目标;P1 起改为本模块内的实现模块)
+_TARGETS: dict[str, str] = {
+    'taxonomy': 'src.windscada.taxonomy',
+    'audit': 'src.windscada.audit',
+    'curves': 'src.windscada.perf.curves',
+    'control': 'src.windscada.perf.control',
+    'reliability': 'src.windscada.perf.reliability',
+    'faults': 'src.windscada.perf.faults',
+    'availability': 'src.windscada.perf.availability',
+    'trend': 'src.windscada.perf.trend',
+    'curtail': 'src.windscada.perf.curtail',
+    'powercurve': 'src.windscada.perf.powercurve',
+    'fusion': 'src.windscada.subsys.fusion',
+    'pitch': 'src.windscada.subsys.pitch',
+    'yaw': 'src.windscada.subsys.yaw',
+    'hydraulic': 'src.windscada.subsys.hydraulic',
+    'temp_nbm': 'src.windscada.subsys.temp_nbm',
+    'structure': 'src.windscada.subsys.structure',
+    'thermal_chain': 'src.windscada.subsys.thermal_chain',
+    'workorder': 'src.windscada.subsys.workorder',
+    'cms_report': 'src.windcms.report_std',
+    'cms_tcm': 'src.windcms.tcm',
+    'cms_knowledge': 'src.windcms.knowledge',
+    'cms_review': 'src.windcms.cross_review',
+    'cms_rules': 'src.windcms.audit_rules',
+    'cms_pipeline': 'src.windcms.pipeline',
+}
+
+__all__ = list(_TARGETS)
+
+
+def __getattr__(name: str):
+    target = _TARGETS.get(name)
+    if target is None:
+        raise AttributeError(
+            f'{__name__} 未公开 {name!r};公开面见 __all__ —— 模块间调用只许走 api.py'
+        )
+    mod = importlib.import_module(target)
+    globals()[name] = mod
+    return mod

+ 13 - 0
app_backEnd/README.md

@@ -0,0 +1,13 @@
+# 观澜 · 后端(`app_backEnd/`)
+
+**职责**:组件服务(分析/振动/仿真/三维)、统一网关、运维控制台、重算编排与作业状态、CLI 与进程管理
+
+**允许依赖**:app_common, app_dataAccess, app_algorithm, app_ontology
+
+**对外公开面**:`common/app_backEnd_guanlan/api.py` —— 模块间调用**只许**走这里(`scripts/module_boundary_audit.py` 机器检查)。
+
+**当前实现落点(P0 转发目标)**:guanlan.py、scripts/{windscada_serve,guanlan_gateway,guanlan_ops,_ops_*}.py、src/windscada/{config,terms,i18n,lang,report_export}.py
+
+**迁移计划**:P4:服务与网关迁入(网关在接入 Nginx 前保留 Python 实现),端口/入口/日志口径不变。
+
+> 依据:`docs/重构方案_模块化_v0.1.md`(用户令 2026-09-22:只重构目录与接口、零行为变化、逐版本可回滚)。

+ 2 - 0
app_backEnd/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 后端(模块根,P0 骨架)。"""

+ 2 - 0
app_backEnd/common/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""本模块的公共组件层(跨模块可复用件放这里)。"""

+ 2 - 0
app_backEnd/common/app_backEnd_guanlan/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 后端 —— 本模块实现包(P0 仅接口,实现仍在既有路径)。"""

+ 39 - 0
app_backEnd/common/app_backEnd_guanlan/api.py

@@ -0,0 +1,39 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 后端 —— **对外公开面**(P0 阶段:接口先立,实现仍在既有路径)。
+
+用户令 2026-09-22:按模块重构源代码目录,**每模块只许经 `api.py` 被别的模块调用**。
+本文件当前把公开名**惰性转发**到既有实现(guanlan.py、scripts/{windscada_serve,guanlan_gateway,guanlan_ops,_ops_*}.py、src/windscada/{config,terms,i18n,lang,report_export}.py),因此:
+
+* 调用的行为与重构前完全一致(零行为变化);
+* 后续阶段(见 `docs/重构方案_模块化_v0.1.md`)把实现搬到本模块目录后,**只改这里的目标映射**,
+  调用方一行都不用动;
+* 惰性转发(PEP 562)保证 import 本文件不会连带 import 重依赖。
+"""
+from __future__ import annotations
+
+import importlib
+
+# 公开名 → 现有实现(P0 转发目标;P1 起改为本模块内的实现模块)
+_TARGETS: dict[str, str] = {
+    'config': 'src.windscada.config',
+    'terms': 'src.windscada.terms',
+    'i18n': 'src.windscada.i18n',
+    'lang': 'src.windscada.lang',
+    'report_export': 'src.windscada.report_export',
+    'deid': 'src.windscada.deid',
+    'cms_serve': 'src.windcms.serve',
+    'cms_orchestrator': 'src.windcms.orchestrator',
+}
+
+__all__ = list(_TARGETS)
+
+
+def __getattr__(name: str):
+    target = _TARGETS.get(name)
+    if target is None:
+        raise AttributeError(
+            f'{__name__} 未公开 {name!r};公开面见 __all__ —— 模块间调用只许走 api.py'
+        )
+    mod = importlib.import_module(target)
+    globals()[name] = mod
+    return mod

+ 30 - 0
app_backEnd/common/app_backEnd_guanlan/cache.py

@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+r"""按时间窗缓存与作业状态接口(**组件接入点:Redis**)。
+
+现在:进程内 `_WIN_CACHE`(按时间窗重算结果)+ `run/ops_job.json`(作业状态)。
+目标:同一接口下新增 Redis 实现,支持多实例共享缓存与分布式锁。
+
+P0 只立契约,无实现(默认仍是进程内 + 本地文件)。
+"""
+from __future__ import annotations
+
+from abc import ABC, abstractmethod
+
+
+class WindowCache(ABC):
+    @abstractmethod
+    def get(self, kind: str, window_key: str): ...
+
+    @abstractmethod
+    def put(self, kind: str, window_key: str, value) -> None: ...
+
+    @abstractmethod
+    def pending(self, kind: str, window_key: str) -> bool: ...
+
+
+class JobState(ABC):
+    @abstractmethod
+    def read(self) -> dict: ...
+
+    @abstractmethod
+    def write(self, state: dict) -> None: ...

+ 21 - 0
app_backEnd/common/app_backEnd_guanlan/gateway.py

@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+r"""统一入口与路由表接口(**组件接入点:Nginx**)。
+
+现在:Python 网关 `scripts/guanlan_gateway.py`(前缀改写 + data-abs 豁免 + 静态件)。
+目标:Nginx 承担反代与静态托管,网关退化为**路由表**(本接口即路由表的读写面)。
+
+P0 只立契约,无实现(默认仍是 Python 网关)。
+"""
+from __future__ import annotations
+
+from abc import ABC, abstractmethod
+
+
+class Gateway(ABC):
+    @abstractmethod
+    def routes(self) -> list[dict]:
+        """→ [{prefix, upstream_port, name}](现由 gateway 的 ROUTES 提供)。"""
+
+    @abstractmethod
+    def rewrite(self, html: bytes, *, component: str) -> bytes:
+        """组件前缀改写(`data-abs="1"` 链接豁免的规则保持)。"""

+ 13 - 0
app_common/README.md

@@ -0,0 +1,13 @@
+# 观澜 · 公共层(`app_common/`)
+
+**职责**:路径真源、版本真源、日志、进程与静默启动、入口引用闭合、控制台输出、运行态作业文件、产物派生台账
+
+**允许依赖**:(无:公共层不得依赖任何业务模块)
+
+**对外公开面**:`common/app_common_guanlan/api.py` —— 模块间调用**只许**走这里(`scripts/module_boundary_audit.py` 机器检查)。
+
+**当前实现落点(P0 转发目标)**:src/{paths,version,logfile,proc,entry_refs,console,opsjob,derived_manifest,tabfmt}.py
+
+**迁移计划**:P1:把上述 9 个平台件实体迁到本目录,旧路径留转发壳。
+
+> 依据:`docs/重构方案_模块化_v0.1.md`(用户令 2026-09-22:只重构目录与接口、零行为变化、逐版本可回滚)。

+ 2 - 0
app_common/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 公共层(模块根,P0 骨架)。"""

+ 2 - 0
app_common/common/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""本模块的公共组件层(跨模块可复用件放这里)。"""

+ 2 - 0
app_common/common/app_common_guanlan/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 公共层 —— 本模块实现包(P0 仅接口,实现仍在既有路径)。"""

+ 40 - 0
app_common/common/app_common_guanlan/api.py

@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 公共层 —— **对外公开面**(P0 阶段:接口先立,实现仍在既有路径)。
+
+用户令 2026-09-22:按模块重构源代码目录,**每模块只许经 `api.py` 被别的模块调用**。
+本文件当前把公开名**惰性转发**到既有实现(src/{paths,version,logfile,proc,entry_refs,console,opsjob,derived_manifest,tabfmt}.py),因此:
+
+* 调用的行为与重构前完全一致(零行为变化);
+* 后续阶段(见 `docs/重构方案_模块化_v0.1.md`)把实现搬到本模块目录后,**只改这里的目标映射**,
+  调用方一行都不用动;
+* 惰性转发(PEP 562)保证 import 本文件不会连带 import 重依赖。
+"""
+from __future__ import annotations
+
+import importlib
+
+# 公开名 → 现有实现(P0 转发目标;P1 起改为本模块内的实现模块)
+_TARGETS: dict[str, str] = {
+    'paths': 'src.paths',
+    'version': 'src.version',
+    'logfile': 'src.logfile',
+    'proc': 'src.proc',
+    'entry_refs': 'src.entry_refs',
+    'console': 'src.console',
+    'opsjob': 'src.opsjob',
+    'derived_manifest': 'src.derived_manifest',
+    'tabfmt': 'src.tabfmt',
+}
+
+__all__ = list(_TARGETS)
+
+
+def __getattr__(name: str):
+    target = _TARGETS.get(name)
+    if target is None:
+        raise AttributeError(
+            f'{__name__} 未公开 {name!r};公开面见 __all__ —— 模块间调用只许走 api.py'
+        )
+    mod = importlib.import_module(target)
+    globals()[name] = mod
+    return mod

+ 13 - 0
app_dataAccess/README.md

@@ -0,0 +1,13 @@
+# 观澜 · 数据接入管理(`app_dataAccess/`)
+
+**职责**:现场源件摄入(10 分钟/1 分钟/月度归档库/台账/振动)、放置与增量体检、标准仓、机型与场站契约、canonical 词典
+
+**允许依赖**:app_common
+
+**对外公开面**:`common/app_dataAccess_guanlan/api.py` —— 模块间调用**只许**走这里(`scripts/module_boundary_audit.py` 机器检查)。
+
+**当前实现落点(P0 转发目标)**:src/windscada/{data,scada_source,slim,mdb_names}.py + scripts/{rebuild_*,scada_*,raw_scan,raw_data_check,place_raw_data,pitch_face_build,baseline_38_build,component_history_build,csv_to_mdb}.py
+
+**迁移计划**:P2:构建器按 CLI 入口迁入(`builders/` 子包 + 命令注册表),`scripts/` 同留转发壳。
+
+> 依据:`docs/重构方案_模块化_v0.1.md`(用户令 2026-09-22:只重构目录与接口、零行为变化、逐版本可回滚)。

+ 2 - 0
app_dataAccess/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 数据接入管理(模块根,P0 骨架)。"""

+ 2 - 0
app_dataAccess/common/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""本模块的公共组件层(跨模块可复用件放这里)。"""

+ 2 - 0
app_dataAccess/common/app_dataAccess_guanlan/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 数据接入管理 —— 本模块实现包(P0 仅接口,实现仍在既有路径)。"""

+ 35 - 0
app_dataAccess/common/app_dataAccess_guanlan/api.py

@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 数据接入管理 —— **对外公开面**(P0 阶段:接口先立,实现仍在既有路径)。
+
+用户令 2026-09-22:按模块重构源代码目录,**每模块只许经 `api.py` 被别的模块调用**。
+本文件当前把公开名**惰性转发**到既有实现(src/windscada/{data,scada_source,slim,mdb_names}.py + scripts/{rebuild_*,scada_*,raw_scan,raw_data_check,place_raw_data,pitch_face_build,baseline_38_build,component_history_build,csv_to_mdb}.py),因此:
+
+* 调用的行为与重构前完全一致(零行为变化);
+* 后续阶段(见 `docs/重构方案_模块化_v0.1.md`)把实现搬到本模块目录后,**只改这里的目标映射**,
+  调用方一行都不用动;
+* 惰性转发(PEP 562)保证 import 本文件不会连带 import 重依赖。
+"""
+from __future__ import annotations
+
+import importlib
+
+# 公开名 → 现有实现(P0 转发目标;P1 起改为本模块内的实现模块)
+_TARGETS: dict[str, str] = {
+    'data': 'src.windscada.data',
+    'scada_source': 'src.windscada.scada_source',
+    'slim': 'src.windscada.slim',
+    'mdb_names': 'src.windscada.mdb_names',
+}
+
+__all__ = list(_TARGETS)
+
+
+def __getattr__(name: str):
+    target = _TARGETS.get(name)
+    if target is None:
+        raise AttributeError(
+            f'{__name__} 未公开 {name!r};公开面见 __all__ —— 模块间调用只许走 api.py'
+        )
+    mod = importlib.import_module(target)
+    globals()[name] = mod
+    return mod

+ 26 - 0
app_dataAccess/common/app_dataAccess_guanlan/objectstore.py

@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+r"""源件与产物对象存储接口(**组件接入点:MinIO**)。
+
+现在:源件在 `data/raw/<场站>/`、产物在 `outputs/<场>/`。
+目标:以**对象键**(`<场站>/<族>/<件名>`)取代绝对路径,后端可换 MinIO。
+
+P0 只立契约,无实现(默认仍是本地目录)。
+"""
+from __future__ import annotations
+
+from abc import ABC, abstractmethod
+from typing import Iterator
+
+
+class ObjectStore(ABC):
+    @abstractmethod
+    def put(self, key: str, path) -> str: ...
+
+    @abstractmethod
+    def get(self, key: str, dest) -> str: ...
+
+    @abstractmethod
+    def list(self, prefix: str = '') -> Iterator[str]: ...
+
+    @abstractmethod
+    def stat(self, key: str) -> dict: ...

+ 27 - 0
app_dataAccess/common/app_dataAccess_guanlan/store.py

@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+r"""标准仓读写接口(**组件接入点:TiDB community**)。
+
+现在:仓库是本地 parquet 目录(`outputs/<场>/windscada/*.parquet`)。
+目标:同一接口下新增 TiDB 实现(表 ↔ 仓映射、事务边界在这一层),算法层不受影响。
+
+P0 只立契约,**没有任何实现**(默认走现有本地实现,故零行为变化)。
+"""
+from __future__ import annotations
+
+from abc import ABC, abstractmethod
+
+
+class Warehouse(ABC):
+    """标准仓:按"表名"读写产物(与存储介质无关)。"""
+
+    @abstractmethod
+    def list_tables(self) -> list[str]: ...
+
+    @abstractmethod
+    def read_table(self, name: str): ...
+
+    @abstractmethod
+    def write_table(self, name: str, data, *, overwrite: bool = True) -> None: ...
+
+    @abstractmethod
+    def exists(self, name: str) -> bool: ...

+ 13 - 0
app_frontEnd/README.md

@@ -0,0 +1,13 @@
+# 观澜 · 前端(`app_frontEnd/`)
+
+**职责**:v2 工作台单页(时间窗、判级矩阵、部件问题、发电性能、可靠性、本体页、问答、报告导出)、图表库、门户与静态件
+
+**允许依赖**:app_common
+
+**对外公开面**:`common/app_frontEnd_guanlan/api.py` —— 模块间调用**只许**走这里(`scripts/module_boundary_audit.py` 机器检查)。
+
+**当前实现落点(P0 转发目标)**:src/windscada/ui/{app.js,charts.js,build.py,snapshot.py}、windscada_serve.py 内的页面模板、release/portal.html、release/viewer/
+
+**迁移计划**:P5:JS 与模板迁入 `assets/`、`pages/`,渲染入口保持同一路由。
+
+> 依据:`docs/重构方案_模块化_v0.1.md`(用户令 2026-09-22:只重构目录与接口、零行为变化、逐版本可回滚)。

+ 2 - 0
app_frontEnd/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 前端(模块根,P0 骨架)。"""

+ 2 - 0
app_frontEnd/common/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""本模块的公共组件层(跨模块可复用件放这里)。"""

+ 2 - 0
app_frontEnd/common/app_frontEnd_guanlan/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 前端 —— 本模块实现包(P0 仅接口,实现仍在既有路径)。"""

+ 36 - 0
app_frontEnd/common/app_frontEnd_guanlan/api.py

@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 前端 —— **对外公开面**(P0 阶段:接口先立,实现仍在既有路径)。
+
+用户令 2026-09-22:按模块重构源代码目录,**每模块只许经 `api.py` 被别的模块调用**。
+本文件当前把公开名**惰性转发**到既有实现(src/windscada/ui/{app.js,charts.js,build.py,snapshot.py}、windscada_serve.py 内的页面模板、release/portal.html、release/viewer/),因此:
+
+* 调用的行为与重构前完全一致(零行为变化);
+* 后续阶段(见 `docs/重构方案_模块化_v0.1.md`)把实现搬到本模块目录后,**只改这里的目标映射**,
+  调用方一行都不用动;
+* 惰性转发(PEP 562)保证 import 本文件不会连带 import 重依赖。
+"""
+from __future__ import annotations
+
+import importlib
+
+# 公开名 → 现有实现(P0 转发目标;P1 起改为本模块内的实现模块)
+_TARGETS: dict[str, str] = {
+    'ui_build': 'src.windscada.ui.build',
+    'ui_snapshot': 'src.windscada.ui.snapshot',
+    'i18n_en': 'src.windscada.i18n_en',
+    'ui_en': 'src.windscada.ui_en',
+    'cms_ui': 'src.windcms.ui',
+}
+
+__all__ = list(_TARGETS)
+
+
+def __getattr__(name: str):
+    target = _TARGETS.get(name)
+    if target is None:
+        raise AttributeError(
+            f'{__name__} 未公开 {name!r};公开面见 __all__ —— 模块间调用只许走 api.py'
+        )
+    mod = importlib.import_module(target)
+    globals()[name] = mod
+    return mod

+ 13 - 0
app_ontology/README.md

@@ -0,0 +1,13 @@
+# 观澜 · 本体与知识层(`app_ontology/`)
+
+**职责**:对象库与码表摄入、机制链、决策台、检索索引、实机参数表、SOP 场景与验收状态机、本机模型闸
+
+**允许依赖**:app_common
+
+**对外公开面**:`common/app_ontology_guanlan/api.py` —— 模块间调用**只许**走这里(`scripts/module_boundary_audit.py` 机器检查)。
+
+**当前实现落点(P0 转发目标)**:src/ontology/*、src/sop/*
+
+**迁移计划**:P6:本体与 SOP 一并迁入;检索与对象库行为逐项对拍。
+
+> 依据:`docs/重构方案_模块化_v0.1.md`(用户令 2026-09-22:只重构目录与接口、零行为变化、逐版本可回滚)。

+ 2 - 0
app_ontology/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 本体与知识层(模块根,P0 骨架)。"""

+ 2 - 0
app_ontology/common/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""本模块的公共组件层(跨模块可复用件放这里)。"""

+ 2 - 0
app_ontology/common/app_ontology_guanlan/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 本体与知识层 —— 本模块实现包(P0 仅接口,实现仍在既有路径)。"""

+ 44 - 0
app_ontology/common/app_ontology_guanlan/api.py

@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 本体与知识层 —— **对外公开面**(P0 阶段:接口先立,实现仍在既有路径)。
+
+用户令 2026-09-22:按模块重构源代码目录,**每模块只许经 `api.py` 被别的模块调用**。
+本文件当前把公开名**惰性转发**到既有实现(src/ontology/*、src/sop/*),因此:
+
+* 调用的行为与重构前完全一致(零行为变化);
+* 后续阶段(见 `docs/重构方案_模块化_v0.1.md`)把实现搬到本模块目录后,**只改这里的目标映射**,
+  调用方一行都不用动;
+* 惰性转发(PEP 562)保证 import 本文件不会连带 import 重依赖。
+"""
+from __future__ import annotations
+
+import importlib
+
+# 公开名 → 现有实现(P0 转发目标;P1 起改为本模块内的实现模块)
+_TARGETS: dict[str, str] = {
+    'store': 'src.ontology.store',
+    'schema': 'src.ontology.schema',
+    'codes': 'src.ontology.codes',
+    'kb_ingest': 'src.ontology.kb_ingest',
+    'populate': 'src.ontology.populate',
+    'chain_ingest': 'src.ontology.chain_ingest',
+    'trend_ingest': 'src.ontology.trend_ingest',
+    'retrieval': 'src.ontology.retrieval',
+    'maintenance': 'src.ontology.maintenance',
+    'decisions': 'src.ontology.decisions',
+    'audit': 'src.ontology.audit',
+    'fast_agent': 'src.ontology.fast_agent',
+    'llm_gate': 'src.ontology.llm_gate',
+}
+
+__all__ = list(_TARGETS)
+
+
+def __getattr__(name: str):
+    target = _TARGETS.get(name)
+    if target is None:
+        raise AttributeError(
+            f'{__name__} 未公开 {name!r};公开面见 __all__ —— 模块间调用只许走 api.py'
+        )
+    mod = importlib.import_module(target)
+    globals()[name] = mod
+    return mod

+ 13 - 0
app_qualityGate/README.md

@@ -0,0 +1,13 @@
+# 观澜 · 质量门与审计 + 打包安装(`app_qualityGate/`)
+
+**职责**:审计器(反向呼应/页面归口/配置统一/日志/链路/可移植/安全)、交付文档三检、打包器与开箱验证、安装与卸载入口
+
+**允许依赖**:app_common, app_dataAccess, app_algorithm, app_ontology, app_backEnd, app_frontEnd
+
+**对外公开面**:`common/app_qualityGate_guanlan/api.py` —— 模块间调用**只许**走这里(`scripts/module_boundary_audit.py` 机器检查)。
+
+**当前实现落点(P0 转发目标)**:scripts/{*_audit,check_*,detail_deps,page_fingerprint,pack_dist,pack_verify_entry,guanlan_uninstall,delivery_docs_build,delivery_docs_figures}.py、install.ps1/sh、uninstall.*
+
+**迁移计划**:P7:审计器与打包安装迁入;门禁与开箱验证口径不变。
+
+> 依据:`docs/重构方案_模块化_v0.1.md`(用户令 2026-09-22:只重构目录与接口、零行为变化、逐版本可回滚)。

+ 2 - 0
app_qualityGate/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 质量门与审计 + 打包安装(模块根,P0 骨架)。"""

+ 2 - 0
app_qualityGate/common/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""本模块的公共组件层(跨模块可复用件放这里)。"""

+ 2 - 0
app_qualityGate/common/app_qualityGate_guanlan/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 质量门与审计 + 打包安装 —— 本模块实现包(P0 仅接口,实现仍在既有路径)。"""

+ 32 - 0
app_qualityGate/common/app_qualityGate_guanlan/api.py

@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+r"""观澜 · 质量门与审计 + 打包安装 —— **对外公开面**(P0 阶段:接口先立,实现仍在既有路径)。
+
+用户令 2026-09-22:按模块重构源代码目录,**每模块只许经 `api.py` 被别的模块调用**。
+本文件当前把公开名**惰性转发**到既有实现(scripts/{*_audit,check_*,detail_deps,page_fingerprint,pack_dist,pack_verify_entry,guanlan_uninstall,delivery_docs_build,delivery_docs_figures}.py、install.ps1/sh、uninstall.*),因此:
+
+* 调用的行为与重构前完全一致(零行为变化);
+* 后续阶段(见 `docs/重构方案_模块化_v0.1.md`)把实现搬到本模块目录后,**只改这里的目标映射**,
+  调用方一行都不用动;
+* 惰性转发(PEP 562)保证 import 本文件不会连带 import 重依赖。
+"""
+from __future__ import annotations
+
+import importlib
+
+# 公开名 → 现有实现(P0 转发目标;P1 起改为本模块内的实现模块)
+_TARGETS: dict[str, str] = {
+    'version_log': 'scripts.version_log',
+}
+
+__all__ = list(_TARGETS)
+
+
+def __getattr__(name: str):
+    target = _TARGETS.get(name)
+    if target is None:
+        raise AttributeError(
+            f'{__name__} 未公开 {name!r};公开面见 __all__ —— 模块间调用只许走 api.py'
+        )
+    mod = importlib.import_module(target)
+    globals()[name] = mod
+    return mod

+ 75 - 0
configs/modules.yaml

@@ -0,0 +1,75 @@
+# 观澜 · 模块登记表(用户令 2026-09-22:按算法/数据接入管理/前端/后端等模块重构,每模块一个目录)
+#
+# 这份表是**模块边界的单一真源**,由 scripts/module_boundary_audit.py 机器核对:
+#   ① 每个模块目录的结构(common/<pkg>/{__init__,api}.py + README.md)必须在位;
+#   ② 模块之间只许经对方 api.py 调用(不得直接 import 别的模块的实现包);
+#   ③ 依赖方向只能是 allow 里列的那些(不得反向、不得成环);
+#   ④ 公共层 app_common 不得依赖任何业务模块;
+#   ⑤ 每个 api.py 的转发目标(P0 阶段指向既有实现)必须真实存在。
+#
+# 设计说明与分阶段迁移计划见 docs/重构方案_模块化_v0.1.md。
+version: 1
+layout:
+  module_root: "app_<模块>"          # 每个模块一个目录
+  common_dir: common                  # 跨模块可复用的公共组件层
+  package_pattern: "app_<模块>_guanlan"  # 观澜在该模块的实现包
+  public_face: api.py                 # 模块间调用只许走这里
+
+modules:
+  - name: app_common
+    cn: 公共层
+    resp: 路径真源/版本真源/日志/进程/入口引用/控制台输出/运行态作业文件/产物派生台账
+    allow: []                         # 公共层不依赖任何业务模块
+    impl_now: src/{paths,version,logfile,proc,entry_refs,console,opsjob,derived_manifest,tabfmt}.py
+    phase: P1
+    change_rate: 极少
+
+  - name: app_dataAccess
+    cn: 数据接入管理
+    resp: 源件摄入(10 分钟/1 分钟/月度归档库/台账/振动)、放置与增量体检、标准仓、机型与场站契约、canonical 词典
+    allow: [app_common]
+    impl_now: src/windscada/{data,scada_source,slim,mdb_names}.py + scripts/rebuild_* 与 scada_* 等构建器
+    phase: P2
+    change_rate: 随现场数据形态
+    plug_points: [TiDB community(标准仓读写), MinIO(源件与产物对象存储)]
+
+  - name: app_algorithm
+    cn: 算法
+    resp: 七系统判级矩阵、七镜头曲线、可靠性指标、控制参数一致性、融合面四源、振动与温度面、趋势与可用率
+    allow: [app_common, app_dataAccess]
+    impl_now: src/windscada/{taxonomy,audit}.py、perf/*、subsys/*、src/windcms/{report_std,tcm,knowledge,cross_review,audit_rules,pipeline}.py
+    phase: P3
+    change_rate: 最快
+
+  - name: app_ontology
+    cn: 本体与知识层
+    resp: 对象库与码表摄入、机制链、决策台、检索索引、实机参数表、SOP 场景与验收状态机、本机模型闸
+    allow: [app_common]
+    impl_now: src/ontology/*、src/sop/*
+    phase: P6
+    change_rate: 中
+
+  - name: app_backEnd
+    cn: 后端
+    resp: 组件服务、统一网关、运维控制台与重算编排、作业状态、CLI 与进程管理
+    allow: [app_common, app_dataAccess, app_algorithm, app_ontology]
+    impl_now: guanlan.py、scripts/{windscada_serve,guanlan_gateway,guanlan_ops,_ops_*}.py、src/windscada/{config,terms,i18n,lang,report_export}.py
+    phase: P4
+    change_rate: 慢
+    plug_points: [Redis(按时间窗缓存与作业状态), Nginx(统一入口与静态件)]
+
+  - name: app_frontEnd
+    cn: 前端
+    resp: v2 工作台单页与交互、图表库、门户与静态件
+    allow: [app_common]
+    impl_now: src/windscada/ui/{app.js,charts.js,build.py,snapshot.py}、windscada_serve.py 内页面模板、release/portal.html、release/viewer/
+    phase: P5
+    change_rate: 中
+
+  - name: app_qualityGate
+    cn: 质量门与审计 + 打包安装
+    resp: 审计器(反向呼应/页面归口/配置统一/日志/链路/可移植/安全)、交付文档三检、打包器与开箱验证、安装与卸载
+    allow: [app_common, app_dataAccess, app_algorithm, app_ontology, app_backEnd, app_frontEnd]
+    impl_now: scripts/{*_audit,check_*,detail_deps,page_fingerprint,pack_dist,pack_verify_entry,guanlan_uninstall,delivery_docs_*}.py、install.*、uninstall.*
+    phase: P7
+    change_rate: 慢

+ 5 - 0
configs/registry.yaml

@@ -26,6 +26,11 @@ top_level:
     kind: 运行期单件配置 (页面归口登记表)
     consumers: [scripts/pages_audit.py]
     schema: "见 docs §10 / 本文件头"
+  - file: modules.yaml
+    kind: "开发期配置 (模块登记表:每个模块一个目录 + 边界与依赖方向)"
+    consumers: [scripts/module_boundary_audit.py]
+    schema: "{layout: {module_root, common_dir, package_pattern, public_face}, modules: [{name, cn, resp, allow, impl_now, phase}]}"
+    note: "用户令 2026-09-22 按算法/数据接入管理/前端/后端等模块重构源代码; 设计见 docs/重构方案_模块化_v0.1.md"
 
 domains:
   - dir: canonical

+ 1 - 1
docs/src/数据要求说明_观澜_2.10.4.md → docs/src/数据要求说明_观澜_2.11.0.md

@@ -1,4 +1,4 @@
-# 数据要求说明 · 观澜 v2 风电场智能分析系统 · 版本 2.10.4
+# 数据要求说明 · 观澜 v2 风电场智能分析系统 · 版本 2.11.0
 
 ## 1 文档说明
 

+ 35 - 9
docs/src/系统设计说明_观澜_2.10.4.md → docs/src/系统设计说明_观澜_2.11.0.md

@@ -1,4 +1,4 @@
-# 系统设计说明 · 观澜 v2 风电场智能分析系统 · 版本 2.10.4
+# 系统设计说明 · 观澜 v2 风电场智能分析系统 · 版本 2.11.0
 
 ## 1 文档说明
 
@@ -6,19 +6,19 @@
 
 ### 1.1 目的与范围
 
-本文是"观澜 v2(风电场智能分析系统)"(海上风电场智能分析离线系统)的设计说明(下称"本系统"),面向版本 2.10.4;内容以样本风电场(下称"本场")为依据,样本场实测日期为 2026-09-22,说明本系统"由哪些部分组成、各部分怎么实现、数据从哪来到哪去、判据写在哪里、怎么验证、边界在哪里"。
+本文是"观澜 v2(风电场智能分析系统)"(海上风电场智能分析离线系统)的设计说明(下称"本系统"),面向版本 2.11.0;内容以样本风电场(下称"本场")为依据,样本场实测日期为 2026-09-22,说明本系统"由哪些部分组成、各部分怎么实现、数据从哪来到哪去、判据写在哪里、怎么验证、边界在哪里"。
 
 本文覆盖十五个设计面:总体架构与分层、目录结构与路径真源、数据接入与重算链、判级与算法、时间窗口径、服务与前端、本体与知识层、本机模型接入、运维控制台与重算编排、安装与服务化与版本管理、质量保证、安全与离线边界、可移植性与资源占用、多场适用性与换场迁移、已知边界与未实现。
 
-本文不重复需求条目本身(那是《需求分析_观澜_2.10.4.docx》的职责),也不重复操作步骤的逐步手册(那是 docs/重算操作手册_v0.1.md 与《使用说明书》v0.2(随包 docs/)的职责);本文只回答"设计上为什么这样、落在哪个文件的哪一处、用什么机器守卫保证它不漂移"。
+本文不重复需求条目本身(那是《需求分析_观澜_2.11.0.docx》的职责),也不重复操作步骤的逐步手册(那是 docs/重算操作手册_v0.1.md 与《使用说明书》v0.2(随包 docs/)的职责);本文只回答"设计上为什么这样、落在哪个文件的哪一处、用什么机器守卫保证它不漂移"。
 
 ### 1.2 读者与用法
 
 现场运维与检修人员可看第 3 章、第 7 章、第 8 章、第 11 章,了解自己能点到的页面背后读的是什么口径;场站管理人员与换场交付人员可看第 6 章、第 7 章、第 16 章、第 17 章,了解判级与可靠性指标的口径与边界,以及换场时要重新标定哪些参数;研发与交付人员应通读全文,重点是第 4 章、第 5 章、第 12 章、第 13 章;验收方可直接按第 13 章的质量门与附录 A 的编写依据逐条复核。
 
-### 1.3 与《需求分析_观澜_2.10.4.docx》的对应关系
+### 1.3 与《需求分析_观澜_2.11.0.docx》的对应关系
 
-需求分析写"要什么、为谁、优先级与验收门",设计说明写"怎么实现、落在哪、如何自证"。两文的章节对应关系如表 1-1 所示;与《数据要求说明_观澜_2.10.4.docx》的数据侧口径去向见 16.6 节。
+需求分析写"要什么、为谁、优先级与验收门",设计说明写"怎么实现、落在哪、如何自证"。两文的章节对应关系如表 1-1 所示;与《数据要求说明_观澜_2.11.0.docx》的数据侧口径去向见 16.6 节。
 
 | 本文章节 | 需求分析对应章 | 对应关系说明 |
 |---|---|---|
@@ -41,7 +41,7 @@
 
 ### 1.4 口径与依据
 
-本文所有数字来自仓库文件或命令的实跑输出,不采用估算与推测;查不到、未实现的,一律写"未取证"或"未实现",并在第 17 章汇总。本文中"本次实测"与各表"实测"列一律指样本场实测(2026-09-22):即在样本风电场的一套实例上的一次实跑,换场后这些数字会变、方法与口径不变。版本号的唯一真源是 src/version.py 的 VERSION 常量,本版为 2.10.4;打包文件名由 src/version.py 的 package_name() 给出,为 app_guanlang_v2.10.4.zip。
+本文所有数字来自仓库文件或命令的实跑输出,不采用估算与推测;查不到、未实现的,一律写"未取证"或"未实现",并在第 17 章汇总。本文中"本次实测"与各表"实测"列一律指样本场实测(2026-09-22):即在样本风电场的一套实例上的一次实跑,换场后这些数字会变、方法与口径不变。版本号的唯一真源是 src/version.py 的 VERSION 常量,本版为 2.11.0;打包文件名由 src/version.py 的 package_name() 给出,为 app_guanlang_v2.11.0.zip。
 
 本文遵循四条写作口径:含"窗"且确实指时间窗口的,一律写全"时间窗"(天气窗、作业窗、预览窗、观测窗属领域词,保持原样);影响的是风电机组时写"影响机组"或"影响机组数";使用英文简写时必须写成"中文(英文简写)"形式,如平均无故障间隔(MTBF)、平均停机间隔(MTBO)、单次停机时长(MDT);全文用简体中文与半角数字与单位。
 
@@ -174,6 +174,32 @@
 
 ***
 
+### 3.4 源码模块化布局与边界(2026-09-22 用户令)
+
+源码按**变化的原因**分为七个模块,**每个模块一个目录**;模块根下 `common/` 放**跨模块可复用的公共组件**,
+`common/app_<模块>_guanlan/` 放**观澜在该模块的实现**,`api.py` 是该模块**唯一的对外公开面**。
+
+| 模块目录 | 职责 | 允许依赖 | 迁移阶段 | 组件接入点 |
+|---|---|---|---|---|
+| `app_common/` | 公共层:路径与版本真源、日志、进程、入口引用、控制台输出、运行态作业文件 | 无(不得依赖业务模块) | P1 | — |
+| `app_dataAccess/` | 数据接入管理:源件摄入、放置与增量体检、标准仓、机型与场站契约、canonical 词典 | 公共层 | P2 | **TiDB community**(标准仓读写)、**MinIO**(源件与产物对象存储) |
+| `app_algorithm/` | 算法:七系统判级、七镜头曲线、可靠性、控制参数一致性、融合面四源、振动与温度面、趋势 | 公共层、数据接入 | P3 | — |
+| `app_ontology/` | 本体与知识层:对象库、机制链、决策台、检索、实机参数表、SOP 与验收状态机、模型闸 | 公共层 | P6 | — |
+| `app_backEnd/` | 后端:组件服务、统一网关、运维控制台与重算编排、作业状态、CLI | 公共层、数据接入、算法、本体 | P4 | **Redis**(按时间窗缓存与作业状态)、**Nginx**(统一入口与路由表) |
+| `app_frontEnd/` | 前端:工作台单页与交互、图表库、门户与静态件 | 公共层 | P5 | — |
+| `app_qualityGate/` | 质量门与审计 + 打包安装:审计器、交付文档三检、打包与开箱验证、安装卸载 | 全部模块(只读审计,不参与业务调用链) | P7 | — |
+
+**边界规则(机器可查,不靠人自觉)**:① 模块之间**只许经对方 `api.py`** 调用;② 依赖方向不得反向、不得成环;
+③ 公共层不得依赖任何业务模块;④ 每个 `api.py` 的转发目标必须真实存在。四条由 `scripts/module_boundary_audit.py`
+逐条检查,并接入 `guanlan.py check`;模块职责、允许依赖与迁移阶段登记在 `configs/modules.yaml`。
+
+**本轮(P0)只建目录与接口**:实现仍在既有路径(`src/**`、`scripts/**`),因此页面、CLI、产物与门禁**零行为变化**;
+P1–P7 分阶段实体迁移,每阶段独立提交、随时可回退,方案与验收口径见 `docs/重构方案_模块化_v0.1.md`。
+
+**四个系统组件(TiDB community / MinIO / Redis / Nginx)**:本轮只建立**接口契约**(标准仓读写、对象存储、
+按时间窗缓存与作业状态、统一入口与路由表),默认实现仍是本地目录与进程内缓存 —— 所以离线单包交付形态与现有
+验收链保持不变;后续接实现时只换实现、不动上层调用。
+
 ## 4 目录结构与路径真源
 
 ### 4.1 路径唯一真源与助手表
@@ -787,7 +813,7 @@ Windows 安装入口是 install.bat 与 install.ps1,步骤号写死在输出
 
 ### 12.3 安装记录与版本三守卫
 
-安装记录 install-info.json 是"这台机器装的是哪一版"的唯一凭据,字段如表 12-3 所示。装完写、卸载时删(删掉等于这台机器回到"没装过")。需要如实指出:本机该文件记录的版本是 2.5.0(装于 2026-09-17),落后于当前代码版本 2.10.4,因此它正是"安装前检查会提示版本差异"的活样本;重装或升级后会随之更新。
+安装记录 install-info.json 是"这台机器装的是哪一版"的唯一凭据,字段如表 12-3 所示。装完写、卸载时删(删掉等于这台机器回到"没装过")。需要如实指出:本机该文件记录的版本是 2.5.0(装于 2026-09-17),落后于当前代码版本 2.11.0,因此它正是"安装前检查会提示版本差异"的活样本;重装或升级后会随之更新。
 
 | 字段 | 含义 |
 |---|---|
@@ -1148,7 +1174,7 @@ Linux 侧的适配程度如表 15-4 所示,全部为"已有实现但在本次
 
 ### 16.6 与同批交付文档的对应关系
 
-本章对应《需求分析_观澜_2.10.4.docx》第 11 章(场配置化、机组与机型可替换、数据源形态可适配、阈值按场标定、术语与单位可配、跨场统一口径、按场裁剪收资、换场验收检查表)与《数据要求说明_观澜_2.10.4.docx》第 12 章(通用必选与可选的判定规则、场配置字段对照、数据源形态适配、换场收资差异清单、按场裁剪步骤);本章给的是设计侧的落点、换场作业单与检查表,数据侧的收资口径与字段要求以数据要求说明为准,需求侧的验收项以需求分析为准。
+本章对应《需求分析_观澜_2.11.0.docx》第 11 章(场配置化、机组与机型可替换、数据源形态可适配、阈值按场标定、术语与单位可配、跨场统一口径、按场裁剪收资、换场验收检查表)与《数据要求说明_观澜_2.11.0.docx》第 12 章(通用必选与可选的判定规则、场配置字段对照、数据源形态适配、换场收资差异清单、按场裁剪步骤);本章给的是设计侧的落点、换场作业单与检查表,数据侧的收资口径与字段要求以数据要求说明为准,需求侧的验收项以需求分析为准。
 
 ***
 
@@ -1214,7 +1240,7 @@ Linux 侧的适配程度如表 15-4 所示,全部为"已有实现但在本次
 
 | 章节 | 来源文件 |
 |---|---|
-| 1 文档说明 | src/version.py(VERSION 与 HISTORY 的 2.10.4 条目)、docs/需求分析_观澜_2.10.4.docx、scripts/delivery_docs_figures.py |
+| 1 文档说明 | src/version.py(VERSION 与 HISTORY 的 2.11.0 条目)、docs/需求分析_观澜_2.11.0.docx、scripts/delivery_docs_figures.py |
 | 2 设计目标与原则 | docs/系统设计说明.md(四条设计铁律)、src/ontology/mcp_server.py 头部、src/windscada/subsys/fusion.py 头部、src/windscada/perf/reliability.py |
 | 3 总体架构 | configs/serve.json、scripts/guanlan_gateway.py、guanlan.py(组件启动表)、run/pids.json、docs/系统设计说明.md(产物全景) |
 | 4 目录结构与路径真源 | src/paths.py、configs/registry.yaml、docs/系统设计说明.md(路径约定与统一记录)、本次目录实测 |

+ 19 - 19
docs/src/需求分析_观澜_2.10.4.md → docs/src/需求分析_观澜_2.11.0.md

@@ -1,4 +1,4 @@
-# 需求分析 · 观澜 v2 风电场智能分析系统 · 版本 2.10.4
+# 需求分析 · 观澜 v2 风电场智能分析系统 · 版本 2.11.0
 
 ## 1 文档说明
 
@@ -6,7 +6,7 @@
 
 ### 1.1 目的
 
-本文是「观澜 v2(风电场智能分析系统)」的**需求分析文档**,回答四个问题:这套系统究竟要满足谁的什么需要;这些需要从哪来、经过哪些版本变成现在的样子;每一条需要对应什么功能、什么输入、什么输出、拿什么判据验收;以及哪些事本版明确不做。本文与同批交付的《系统设计说明_观澜_2.10.4.docx》《数据要求说明_观澜_2.10.4.docx》配套:本文讲「要什么、凭什么算做到了」,设计说明讲「怎么做的」,数据要求说明讲「要哪些数据、什么形态、什么单位」。
+本文是「观澜 v2(风电场智能分析系统)」的**需求分析文档**,回答四个问题:这套系统究竟要满足谁的什么需要;这些需要从哪来、经过哪些版本变成现在的样子;每一条需要对应什么功能、什么输入、什么输出、拿什么判据验收;以及哪些事本版明确不做。本文与同批交付的《系统设计说明_观澜_2.11.0.docx》《数据要求说明_观澜_2.11.0.docx》配套:本文讲「要什么、凭什么算做到了」,设计说明讲「怎么做的」,数据要求说明讲「要哪些数据、什么形态、什么单位」。
 
 本文的写作口径是**只写能取证的事实**:每个数字、每条结论都能指到仓库里的某个文件、某次实跑输出或某条版本记录;查不到、取不到的一律写明「未取证」或「未到位」,不做推测性补全。因此文中会出现少量「未取证」的说明句,那是刻意留下的诚实边界,不是遗漏。
 
@@ -18,19 +18,19 @@
 
 ### 1.3 版本对应关系
 
-系统版本号只有一个真源:仓库内的 src/version.py 的 VERSION 一行。本版 VERSION = 2.10.4,版本记录(HISTORY)共 16 条,人读的版本表由 scripts/version_log.py 从 HISTORY 生成到 docs/版本记录.md,并由 version_log.py --check 与 guanlan.py check 双重校验「记录表与代码一致」。
+系统版本号只有一个真源:仓库内的 src/version.py 的 VERSION 一行。本版 VERSION = 2.11.0,版本记录(HISTORY)共 17 条,人读的版本表由 scripts/version_log.py 从 HISTORY 生成到 docs/版本记录.md,并由 version_log.py --check 与 guanlan.py check 双重校验「记录表与代码一致」。
 
 表 1-1 版本与文档的对应关系
 
 | 项 | 值 | 取证方式 |
 |---|---|---|
-| 系统版本 | 2.10.4 | src/version.py 的 VERSION;guanlan.py check 实跑报「版本管理: 观澜 v2(风电场智能分析系统) v2.10.4」 |
-| 交付包名 | app_guanlang_v2.10.4.zip | src/version.py 的 package_name();同一条 check 输出 |
-| 本文版本 | 2.10.4(与系统版本同号) | 本文标题与 src/version.py 的 VERSION |
+| 系统版本 | 2.11.0 | src/version.py 的 VERSION;guanlan.py check 实跑报「版本管理: 观澜 v2(风电场智能分析系统) v2.11.0」 |
+| 交付包名 | app_guanlang_v2.11.0.zip | src/version.py 的 package_name();同一条 check 输出 |
+| 本文版本 | 2.11.0(与系统版本同号) | 本文标题与 src/version.py 的 VERSION |
 | 版本史条目数 | 13 条(最新一条即本次文档交付) | src/version.py 的 HISTORY;docs/版本记录.md |
 | 版本号规则 | v大版本号.中版本号.小版本号;大改方案或架构、中改非核心功能、小为消缺 | src/version.py 的 BUMP_RULE 与 LEVEL_MEANING;docs/系统设计说明.md §15 |
 | 版本级别机器判据 | level_of(旧, 新) 返回 major 或 minor 或 patch 或 same | src/version.py 的 level_of() |
-| 本次变化级别 | 小(patch,《数据要求说明》按测点遗漏体检补齐:安全链与数字输入、执行器与热管理、计数账、CMS 采集参数、测点与位号字典;系统功能未变) | HISTORY 中 2.10.4 条目的 level 字段 |
+| 本次变化级别 | 小(patch,《数据要求说明》按测点遗漏体检补齐:安全链与数字输入、执行器与热管理、计数账、CMS 采集参数、测点与位号字典;系统功能未变) | HISTORY 中 2.11.0 条目的 level 字段 |
 
 本版相对 2.10.0 的实质变化是**交付文档对外化**:三份交付文档(需求分析、系统设计说明、数据要求说明)全文不体现具体风电场(去标识化),并新增多风电场适用性一章;系统功能未变,属交付物修订。依据用户令原文:「修改三份文档,内容参考样本风电场,但不体现样本风电场,且具有不同风电场适用性」(引用时把样本场名按去标识化口径写成「样本风电场」)。
 
@@ -119,7 +119,7 @@
 
 ### 3.2 需求演进时间轴
 
-表 3-1 版本史与用户令要点(依据 src/version.py 的 HISTORY,共 16 条)
+表 3-1 版本史与用户令要点(依据 src/version.py 的 HISTORY,共 17 条)
 
 | 版本 | 日期 | 用户令要点 | 变化级别 |
 |---|---|---|---|
@@ -159,7 +159,7 @@
 | 所有的计算均要形成观澜的源代码 | 逐族补生成端:变桨面、在升闭环、三层基线、融合面 handoff、总览页、由台账生成 claim | 反向呼应审计成立 3,548 件、不成立 0 件、未归类 0 件 |
 | 运行期一律不从交付包补齐 | 第 ⑤ 步由「补齐随包件」改为「反向呼应审计」,只报账不搬运 | rebuild_all --dry-run 计划中 ⑤ 步命令为 products_reverse_audit.py --check |
 | 清除产物不留备份 | products_state.py --off --yes 改真删除;--on 与门户恢复按钮移除 | 控制台按钮语义与 409 前置校验;docs/系统设计说明.md §7 |
-| 装成服务并在安装时检查版本 | win_service.py 以 ctypes 直连 SCM;service_main.py 与 systemd 单元;install-info.json 记录版本并比对 | check 实跑报「卸载入口在位 2 个」「版本管理 v2.10.4」 |
+| 装成服务并在安装时检查版本 | win_service.py 以 ctypes 直连 SCM;service_main.py 与 systemd 单元;install-info.json 记录版本并比对 | check 实跑报「卸载入口在位 2 个」「版本管理 v2.11.0」 |
 | 观澜改为监听所有 IP | serve.json 增 public_host 且出厂为 0.0.0.0,仅门户网关用它,组件仍绑本机 | check 实跑显示 6 个端口全部运行中;README 第二节写明无鉴权风险与回退口径 |
 | 描述口径:时间窗、影响机组、中文(英文简写) | 界面文案与报告构建器统一改写;i18n_en 键同步 | docs/系统设计说明.md §17.1 与 §17.2;语言包 845 条前后端成对 |
 | 整理需求与设计与数据接入各写一份 Word 文档 | docs/src 下 markdown 源件;渲染器输出带域目录的 docx;插图生成器生成 14 张图,数字全部从真件取 | HISTORY 2.10.0 条目;本版三份文档 |
@@ -375,7 +375,7 @@
 | NFR-09 | 安全只读:不写回现场系统、不改原始件、不产生控制指令;对外暴露时须自行在网侧限来源 | 原始件按只读输入对待,落位冲突默认拒绝;对外只有一个网关入口;启动日志每次提醒页面无鉴权 | docs/输入数据放置指导_v0.1.md §3;README_先读我.MD 第二节 |
 | NFR-10 | 可维护性:单一真源,改一处不必改多处;关键口径有机器守卫 | 版本号只有一行真源并由三处守卫盯住;路径、配置、日志、语言各有唯一取用口与审计器 | docs/系统设计说明.md §15.2 与 §11.1;docs/系统设计说明.md §3.1 |
 | NFR-11 | 无人值守与自愈:长跑的服务要能被托管并自动拉起 | 服务体每 15 秒巡检并拉起掉线组件;崩溃重启策略;远程部署一律用服务,不用会话前台进程 | docs/系统设计说明.md §14.1 与 §14.4;README_先读我.MD 第二节 |
-| NFR-12 | 收资清单按场裁剪:以通用收资模板为底,按本场的机型与数据源形态与专题范围裁剪,逐条写明必须、建议、可选或可替代以及「不收会怎样」 | 每一族都有必须性分级与缺件后果且可复核;换场时清单随场定义与机型变化,不是照抄样本场 | 本文第 11 章;《数据要求说明_观澜_2.10.4.docx》第 8 章与第 12 章 |
+| NFR-12 | 收资清单按场裁剪:以通用收资模板为底,按本场的机型与数据源形态与专题范围裁剪,逐条写明必须、建议、可选或可替代以及「不收会怎样」 | 每一族都有必须性分级与缺件后果且可复核;换场时清单随场定义与机型变化,不是照抄样本场 | 本文第 11 章;《数据要求说明_观澜_2.11.0.docx》第 8 章与第 12 章 |
 
 ### 6.2 性能与耗时实测
 
@@ -411,7 +411,7 @@
 
 | 真源 | 管什么 | 守卫与实跑结果 |
 |---|---|---|
-| src/version.py | 名称、版本、版本规则、版本史、包名 | 版本记录一致性检查;check 实跑报 v2.10.4 且记录表与代码一致 |
+| src/version.py | 名称、版本、版本规则、版本史、包名 | 版本记录一致性检查;check 实跑报 v2.11.0 且记录表与代码一致 |
 | src/paths.py | 一切路径解析的基准与助手 | 配置审计器检查不手拼路径;实跑无不一致 |
 | configs 目录与登记表 | 端口、模型档、场配置、页面归口、配置登记 | 配置审计实跑已知缺口与白名单 14 条、提示 7 条 |
 | src/logfile.py | 日志目录、命名、行格式、保留策略 | 日志审计实跑无不一致、提示 87 条 |
@@ -422,7 +422,7 @@
 
 ### 7.1 数据族与功能映射
 
-系统的数据需求可以概括成一句话:**七类现场源件加一类共享机理资料,喂出九个产物仓,页面只读产物**。每个源类目录名就是摄入接口,改名等于换接口。数据族与功能的对应关系如下表;逐类的字段、单位、必须性与质量要求见同批交付的《数据要求说明_观澜_2.10.4.docx》。
+系统的数据需求可以概括成一句话:**七类现场源件加一类共享机理资料,喂出九个产物仓,页面只读产物**。每个源类目录名就是摄入接口,改名等于换接口。数据族与功能的对应关系如下表;逐类的字段、单位、必须性与质量要求见同批交付的《数据要求说明_观澜_2.11.0.docx》。
 
 表 7-1 数据族到功能的映射(样本场实测(2026-09-22))
 
@@ -455,7 +455,7 @@
 
 ### 7.3 与数据要求说明的分工
 
-本文只回答「要哪些数据、这些数据支撑什么功能」。数据的字段级要求(核心测点的名称、单位、必须性、缺失替代、对齐规则、质量门与核对锚点)以及面向现场的收资清单,写在《数据要求说明_观澜_2.10.4.docx》里。该文档按用户令要求与现场收资文件逐条对照,并对现场收资层面的已知缺失逐条如实记录,例如测风塔数据为零交付、故障录波只有 4 台、振动侧 handoff 正本缺失由观澜自算件顶上、远端机器未安装本机模型等。
+本文只回答「要哪些数据、这些数据支撑什么功能」。数据的字段级要求(核心测点的名称、单位、必须性、缺失替代、对齐规则、质量门与核对锚点)以及面向现场的收资清单,写在《数据要求说明_观澜_2.11.0.docx》里。该文档按用户令要求与现场收资文件逐条对照,并对现场收资层面的已知缺失逐条如实记录,例如测风塔数据为零交付、故障录波只有 4 台、振动侧 handoff 正本缺失由观澜自算件顶上、远端机器未安装本机模型等。
 
 ## 8 页面与信息架构需求
 
@@ -537,7 +537,7 @@
 | 运行环境与依赖 | 10 | Python 版本不低于 3.11(实测 3.12.10);九个第三方依赖逐个导入 | 全 OK |
 | 静态质量门 | 4 | 源码可编译 229 个文件;语言包 845 条成对;入口引用闭合 48 条;入口脚本编码守则 | 全 OK |
 | 子进程口径 | 3 | 捕获输出可用;无窗口启动输出进日志;无窗口位已设,标志位 0x8000200 | 全 OK |
-| 版本与卸载入口 | 2 | 版本管理与记录表一致(v2.10.4,包名 app_guanlang_v2.10.4.zip);卸载入口两个都在位 | 全 OK |
+| 版本与卸载入口 | 2 | 版本管理与记录表一致(v2.11.0,包名 app_guanlang_v2.11.0.zip);卸载入口两个都在位 | 全 OK |
 | 制品与台账审计 | 5 | 反向呼应 3,548 件成立;页面归口检查 21 项;配置统一;日志统一;输入数据放置体检 26,503 件结构合规 | 全 OK |
 | 产物与发布件在位 | 10 | 标准仓、本体对象库、findings、事实契约、门户、仿真合页服务与资料包、三维资产、仿真回放资产、治理清单交付件 | 全 OK |
 | 原始件目录 | 1 | 原始件目录存在(无数据时此项不影响页面) | 全 OK |
@@ -663,7 +663,7 @@
 
 本章有两个词要先定义。「本场」指**当前被选中的场**,由配置选定,不必然等于本文取数的样本风电场;「换场」指从一场切到另一场运行的整套动作(改配置、放数据、重跑、按检查表复验),不是把两场的数据混在一棵树里。本章沿用的占位符与附录 A 一致:`<场>`、`<场站>`、`<机型>` 按实际风电场替换。
 
-本章需求与《数据要求说明_观澜_2.10.4.docx》《系统设计说明_观澜_2.10.4.docx》配套使用:本章讲「换场要满足什么」,数据要求说明讲「要向新场收哪些数据、哪些可以裁剪」,《设计说明》讲「配置在哪一层生效、哪些参数属于场相关层」。
+本章需求与《数据要求说明_观澜_2.11.0.docx》《系统设计说明_观澜_2.11.0.docx》配套使用:本章讲「换场要满足什么」,数据要求说明讲「要向新场收哪些数据、哪些可以裁剪」,《设计说明》讲「配置在哪一层生效、哪些参数属于场相关层」。
 
 取证边界要如实写一句:FR-44 至 FR-51 与 NFR-12 有既有的场配置层、摄入层与场级字段语义登记作依据;FR-52 的跨场横向对比是本次新增的口径要求,其实跑记录与机器守卫随后续版本补齐——本文不谎称已经通过。
 
@@ -742,7 +742,7 @@
 
 | 编号 | 需求 | 判据 | 依据文件 |
 |---|---|---|---|
-| NFR-12 | 收资清单按场裁剪:以通用收资模板为底,按本场的机型、数据源形态与专题范围裁剪,逐条写明必须、建议、可选或可替代以及「不收会怎样」 | 每一族都有必须性分级与缺件后果且可复核;换场时清单随场定义与机型变化,不是照抄样本场 | 《数据要求说明_观澜_2.10.4.docx》第 8 章与第 12 章;docs/输入数据放置指导_v0.1.md |
+| NFR-12 | 收资清单按场裁剪:以通用收资模板为底,按本场的机型、数据源形态与专题范围裁剪,逐条写明必须、建议、可选或可替代以及「不收会怎样」 | 每一族都有必须性分级与缺件后果且可复核;换场时清单随场定义与机型变化,不是照抄样本场 | 《数据要求说明_观澜_2.11.0.docx》第 8 章与第 12 章;docs/输入数据放置指导_v0.1.md |
 
 ### 11.9 换场验收需求
 
@@ -885,8 +885,8 @@
 | 场定义与机型与物理约束参数的写法样例 | configs/farms/<场>.yaml |
 | 机型—场站数据契约与字段单位真源 | configs/contracts/<机型>_<场>.yaml 与 configs/canonical/dictionary.yaml |
 | 场级字段语义登记与其它厂商导出形态的对齐 | configs/farms/<场>/field_semantic_registry.yaml |
-| 按场裁剪的收资清单与必须性分级 | docs/src/数据要求说明_观澜_2.10.4.md |
-| 场无关引擎与场相关参数的分层与换场作业单 | docs/src/系统设计说明_观澜_2.10.4.md |
+| 按场裁剪的收资清单与必须性分级 | docs/src/数据要求说明_观澜_2.11.0.md |
+| 场无关引擎与场相关参数的分层与换场作业单 | docs/src/系统设计说明_观澜_2.11.0.md |
 
 表中 `<场>`、`<场站>`、`<机型>` 为占位符,按实际风电场替换。
 
@@ -929,4 +929,4 @@
 | 换场 | — | 从一场切到另一场运行的整套动作:改配置、放数据、重跑、按检查表复验 | 本文 §11.9 |
 | 缺族降级 | — | 某族数据缺失时按缺件如实标注并降低该族功能,不造数、不用他场数字顶替 | 本文 FR-49 |
 | 按场标定 | — | 把阈值、时间窗锚点、限电窗、温度档带宽等场相关参数按本场取值 | 本文 FR-50 |
-| 通用收资模板 | — | 与场无关的收资条目底稿,按场裁剪后作为现场收资清单 | docs/src/数据要求说明_观澜_2.10.4.md |
+| 通用收资模板 | — | 与场无关的收资条目底稿,按场裁剪后作为现场收资清单 | docs/src/数据要求说明_观澜_2.11.0.md |

BIN
docs/数据要求说明_观澜_2.11.0.docx


Plik diff jest za duży
+ 3 - 3
docs/版本记录.md


BIN
docs/系统设计说明_观澜_2.11.0.docx


+ 123 - 0
docs/重构方案_模块化_v0.1.md

@@ -0,0 +1,123 @@
+# 观澜 · 源代码模块化重构方案 v0.1(2026-09-22)
+
+> **本文用途**:给开发团队做**源代码组织层面**的重构依据。本次**只重构目录与接口**(用户令 2026-09-22):
+> 暂不引入 TiDB / MinIO / Redis / Nginx,只在存储、缓存、网关三处留好**接入点**。
+> **兼容底线:零行为变化、逐版本可回滚** —— 页面、CLI、产物、审计门、交付包的产出一律不变,
+> 每阶段独立提交、跑通全部门禁才推进,出问题按提交回退。
+
+---
+
+## 1 为什么这样分(按"变化的原因"切,而不是按技术层切)
+
+观澜现在有两处"变化速率完全不同"的东西混在一起:
+
+- **业务逻辑**(判级口径、曲线镜头、可靠性指标、融合判据)—— 变化快,且**跨风电场/机型必须能替换与扩展**;
+- **运行与交付**(服务、网关、重算编排、审计门、打包安装)—— 变化慢,但**一堆硬约束**(离线单包、无外网、可移植、版本纪律)。
+
+把它们分层,才能做到"改算法不动服务、换存储不动算法"。所以按**六个业务模块 + 一个公共层**切:
+
+| 模块目录 | 中文职责 | 变化原因 | 关键约束 |
+|---|---|---|---|
+| `app_common/` | 公共层:路径真源、版本真源、日志、进程、入口引用、控制台输出 | 极少变 | 只被依赖,不依赖任何业务模块 |
+| `app_dataAccess/` | 数据接入管理:摄入、体检与落位、标准仓、契约与词典 | 随现场数据形态变 | 源件只读;缺族如实标注;列名绑定 |
+| `app_algorithm/` | 算法:判级矩阵、七镜头曲线、可靠性、融合面、振动与温度面、趋势 | **最快** | 纯函数优先;输入是标准仓,输出是判定;不得直接读原始件 |
+| `app_ontology/` | 本体与知识层:对象库、机制链、检索、SOP 与验收状态机、模型闸 | 中 | 只读复用;不写业务产物 |
+| `app_backEnd/` | 后端:组件服务、网关、运维控制台、重算编排、CLI | 慢 | 端口/入口/日志口径统一;不缓存产物口径 |
+| `app_frontEnd/` | 前端:页面与交互、图表、静态件与门户 | 中 | 只读接口;不内嵌业务判据 |
+| `app_qualityGate/` | 质量门与审计 + 打包安装:审计器、门禁、打包器、安装/卸载 | 慢 | 门禁必须能独立重跑、逐条给退出码 |
+
+**依赖方向(单向,无环)**:
+`app_frontEnd → app_backEnd → {app_algorithm, app_ontology, app_dataAccess} → app_common`;
+`app_qualityGate` 只读依赖全部模块(审计者不参与业务调用链)。
+
+## 2 目录结构(每个模块一个目录)
+
+用户令给的前端示例照此推广——模块根下 `common/` 放**跨模块可复用的公共组件**,`app_<模块>_guanlan/` 放**观澜在该模块的实现**:
+
+```
+app_common/
+  |__common/
+       |__app_common_guanlan/          [观澜公共层:paths/version/logfile/proc/entry_refs/console/opsjob/derived_manifest/tabfmt]
+            |____init__.py
+            |__api.py                  ← 对外公开面(其他模块只许从这里 import)
+  |__README.md
+app_dataAccess/
+  |__common/
+       |__app_dataAccess_guanlan/      [数据接入管理]
+app_algorithm/
+  |__common/
+       |__app_algorithm_guanlan/       [算法]
+app_ontology/
+  |__common/
+       |__app_ontology_guanlan/        [本体与知识层]
+app_backEnd/
+  |__common/
+       |__app_backEnd_guanlan/         [后端]
+app_frontEnd/
+  |__common/
+       |__app_frontEnd_guanlan/        [前端]
+app_qualityGate/
+  |__common/
+       |__app_qualityGate_guanlan/     [质量门与审计 + 打包安装]
+```
+
+**边界规则(机器可查,见 `scripts/module_boundary_audit.py`)**:
+1. 跨模块调用**只许**经由对方的 `api.py`;模块内部实现不得被别的模块直接 import。
+2. 依赖方向不得反向、不得成环(按 `configs/modules.yaml` 的 `allow` 判定)。
+3. 每个模块必须有 `README.md`(职责/公开面/依赖/迁移进度)与 `api.py`。
+4. 公共层 `app_common` 不得依赖任何业务模块(否则公共层变成"上帝模块")。
+
+## 3 现有代码 → 目标模块(映射表)
+
+> 阶段 0(本轮)**只建骨架与接口**,下面的文件**原地不动**;各模块 `api.py` 现在转发到既有实现,
+> 保证"接口先立、行为不变"。后续阶段逐个 `git mv` 到目标目录,并在**旧路径留转发壳**。
+
+| 目标模块 | 迁移来源(现有路径) | 现有规模 |
+|---|---|---|
+| `app_common` | `src/{paths,version,logfile,proc,entry_refs,console,opsjob,derived_manifest,tabfmt}.py`、`configs/registry.yaml`(配置登记) | 9 文件 / 1,683 行 |
+| `app_dataAccess` | `src/windscada/{data,scada_source,slim,mdb_names}.py`、`scripts/{rebuild_from_raw,rebuild_all,scada_slim_build,windscada_monthly_build,vib_raw_build,raw_scan,raw_data_check,place_raw_data,pitch_face_build,baseline_38_build,component_history_build,csv_to_mdb}.py`、`configs/{canonical,contracts,farms}` | 约 30 文件 |
+| `app_algorithm` | `src/windscada/{taxonomy,audit}.py`、`src/windscada/perf/*`、`src/windscada/subsys/*`、`src/windcms/{report_std,tcm,knowledge,cross_review,audit_rules,pipeline}.py` | 约 40 文件 / 2 万行 |
+| `app_ontology` | `src/ontology/*`、`src/sop/*` | 60 文件 / 19,775 行 |
+| `app_backEnd` | `guanlan.py`、`scripts/{windscada_serve,guanlan_gateway,guanlan_ops,_ops_launch,_ops_run,_ops_stop_keep_gateway,service_ctl,guanlan_start_hidden}.py`、`src/windscada/{config,terms,i18n,lang,report_export}.py`、`src/windcms/{serve,orchestrator,llm,agent}.py` | 约 20 文件 |
+| `app_frontEnd` | `src/windscada/ui/{app.js,charts.js,build.py,snapshot.py}`、`windscada_serve.py` 内的页面模板(PAGE_*)、`release/portal.html`、`release/viewer/` | 2 JS / 1,360 行 + 模板 |
+| `app_qualityGate` | `scripts/{*_audit,check_*,detail_deps,page_fingerprint,pack_dist,pack_verify_entry,guanlan_uninstall,delivery_docs_build,delivery_docs_figures}.py`、`install.ps1`、`install.sh`、`uninstall.*`、`check.bat` | 约 25 文件 |
+
+## 4 分阶段迁移(每阶段一个提交,随时可回退)
+
+| 阶段 | 内容 | 验收(全绿才进下一阶段) | 回滚 |
+|---|---|---|---|
+| **P0(本轮)** | 建 7 个模块目录 + `common/<pkg>/{__init__,api}.py` + README;`configs/modules.yaml` 登记;新增 `scripts/module_boundary_audit.py` 并接入 `guanlan.py check` | 边界审计 rc=0;`guanlan.py check` 全绿;三份交付文档重渲通过 | 删目录即可 |
+| P1 | `app_common` 平台件**实体迁移**,`src/<同名>.py` 变转发壳 | 全部门禁 + 页面抽样对拍 | revert 该提交 |
+| P2 | `app_dataAccess` 迁移(构建器按 CLI 入口迁,`scripts/` 留转发) | 重算链 `--dry-run` 计划不变 + 全门禁 | 同上 |
+| P3 | `app_algorithm` 迁移(判级/曲线/可靠性/融合纯函数化) | 判级与曲线**逐值对拍**(同一时间窗结果一致)+ 全门禁 | 同上 |
+| P4 | `app_backEnd` 迁移(服务、网关、编排、CLI) | 端口/入口/日志口径不变 + 页面 5/5 | 同上 |
+| P5 | `app_frontEnd` 迁移(JS/图表/模板/门户) | 页面渲染逐页对拍 + 门禁 | 同上 |
+| P6 | `app_ontology` 迁移 | 对象库与检索行为不变 + 门禁 | 同上 |
+| P7 | `app_qualityGate` 迁移(审计器、打包、安装) | 审计全绿 + 打包开箱验证 5/5 + 卸载核验 | 同上 |
+
+**旧路径转发壳约定**(保证兼容性):迁移后旧路径保留一个薄文件,例如
+`src/paths.py` → `from app_common.common.app_common_guanlan.paths import *  # 兼容转发,勿新增逻辑`。
+这样 `scripts/**`、审计器、文档里的既有引用**不需要一次性改完**,可以按阶段收敛。
+
+## 5 为四个系统组件留的接入点(本轮只留接口,不接实现)
+
+| 组件 | 接入点(本轮建立的边界) | 后续替换方式 |
+|---|---|---|
+| **TiDB community** | `app_dataAccess` 的"标准仓读写"接口(现为 parquet 仓):表↔仓的映射与事务边界在**接口层**确定 | 新增 TiDB 实现,配置切换;算法层不变 |
+| **MinIO** | `app_dataAccess` 的"源件与产物对象存储"接口(现为本地目录):以对象键替代绝对路径 | 新增 MinIO 实现;`app_common` 的路径真源继续提供逻辑键 |
+| **Redis** | `app_backEnd` 的"按时间窗缓存与任务状态"接口(现为进程内 `_WIN_CACHE` 与 `run/ops_job.json`) | 新增 Redis 实现,支持多实例共享与分布式锁 |
+| **Nginx** | `app_backEnd` 的"统一入口/静态件"接口(现为 Python 网关 `guanlan_gateway.py`) | Nginx 反代 + 静态托管,网关退化为路由表 |
+
+**约束**:上表四项都是"可插拔实现",**默认实现仍是本地/进程内**,因此离线单包交付形态与现有验收链不变。
+
+## 6 与既有纪律的关系(不得破的底线)
+
+- 版本纪律:本重构按**中版本**升位(源码组织层重构,运行形态与核心功能未变),`src/version.py` 单点真源;
+- 审计纪绿:`guanlan.py check`、反向呼应、页面归口、配置统一、链缺口、可移植性、文档三检**必须保持全绿**;
+- 交付纪律:交付包默认不含输入数据/产物/日志;`install.ps1`/`uninstall.*` 行为不变;
+- 文档纪律:三份交付文档(需求分析 / 系统设计说明 / 数据要求说明)随版本号改名并重渲,内容口径不变。
+
+## 7 当前进度(2026-09-22)
+
+- **P0 已完成**:7 个模块目录、接口与 README、`configs/modules.yaml`、`scripts/module_boundary_audit.py`(接入 `guanlan.py check`)。
+- P1–P7 未开始;本轮**未移动任何业务代码**,行为与产物零变化。

BIN
docs/需求分析_观澜_2.11.0.docx


+ 15 - 0
guanlan.py

@@ -241,6 +241,21 @@ def cmd_check(c):
             f"{len(_un)}/2 个入口" + ("" if _uok else " —— 缺卸载入口: 装得上卸不掉"))
     except Exception as _e:
         row("版本管理与卸载入口", False, f"{type(_e).__name__}: {_e}")
+    # 模块化目录与边界(用户令 2026-09-22「按算法、数据接入管理、前端、后端等系统模块重构,每模块一个目录」):
+    #   组件化/高内聚低耦合/可插拔这条**必须机器可查** —— 边界审计查五件事: 目录结构齐、模块间只经 api 调用、
+    #   依赖方向合规(按 configs/modules.yaml 的 allow)、公共层不依赖业务模块、api 的转发目标真实存在。
+    try:
+        import importlib.util as _ilu5
+        _sp5 = _ilu5.spec_from_file_location('_modb', ROOT / "scripts" / "module_boundary_audit.py")
+        _mb = _ilu5.module_from_spec(_sp5)
+        _sp5.loader.exec_module(_mb)
+        _rc5, _probs, _notes, _mods = _mb.audit(verbose=False)
+        row(f"模块化目录与边界({len(_mods)} 模块:算法/数据接入/前端/后端/本体/公共/质量门)", _rc5 == 0,
+            ("登记 %d 模块 · 模块间只经 api 调用 · 依赖方向合规 · 接口目标全在位" % len(_mods)
+             if _rc5 == 0 else
+             "违规 %d 条 ⇒ " % len(_probs) + "; ".join(f'{r}:{m[:60]}' for r, m in _probs[:2])))
+    except Exception as _e:
+        row("模块化目录与边界", False, f"{type(_e).__name__}: {_e}")
     # 交付文档三件在位(2026-09-22 用户令「需求分析/系统设计说明/数据要求说明」): 文档名里带**当前版本号**,
     # 所以升一次版本号, 旧文档名就过期了 —— 不发 FAIL 的话, 包会悄悄带着 v2.9.2 名字的文档进 v2.10.0 交付。
     # ★2026-09-22 用户令:「三份 docx 不同步到远端服务器」⇒ 交付部署可以不携带这批文档。

+ 151 - 0
scripts/module_boundary_audit.py

@@ -0,0 +1,151 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+r"""模块边界审计(用户令 2026-09-22:按算法/数据接入管理/前端/后端等模块重构,组件化、高内聚低耦合、可插拔)。
+
+## 它查什么(每条都由 `configs/modules.yaml` 驱动)
+
+| 规则 | 内容 | 退出码 |
+|---|---|---|
+| R1 结构 | 每个登记模块目录含 `common/<pkg>/__init__.py`、`common/<pkg>/api.py`、`README.md` | 5 |
+| R2 边界 | 模块之间**只许经对方 `api.py`**:`app_x/**/*.py` 里 import 另一个 `app_y` 的实现包(非 `api`)即违规 | 6 |
+| R3 依赖方向 | 只许 import `allow` 里列出的模块;反向依赖/成环即违规 | 7 |
+| R4 公共层纯净 | `app_common/**` 不得 import 任何其它业务模块 | 7 |
+| R5 接口可用 | 每个 `api.py` 的 `_TARGETS` 转发目标(既有实现的文件路径)必须真实存在 | 8 |
+
+另外**统计迁移进度**(不算失败):`src/**`、`scripts/**` 里还有多少件尚未迁进模块目录(P1–P7 的度量)。
+
+## 用法
+    python scripts/module_boundary_audit.py            # 审计(rc=0 通过)
+    python scripts/module_boundary_audit.py --brief    # 只打结论与进度
+退出码: 0 通过 · 5 结构缺失 · 6 边界违规 · 7 依赖违规 · 8 接口目标缺失
+"""
+from __future__ import annotations
+
+import ast
+import pathlib
+import sys
+
+ROOT = pathlib.Path(__file__).resolve().parents[1]
+sys.path.insert(0, str(ROOT))
+
+from src import paths as P                                                  # noqa: E402
+
+
+def load_registry() -> dict:
+    import yaml
+    return yaml.safe_load(P.config('modules.yaml').read_text(encoding='utf-8'))
+
+
+def module_pkg(name: str) -> str:
+    return f'{name}_guanlan'
+
+
+def _imports_of(path: pathlib.Path) -> list[str]:
+    """→ 该文件里所有 import 的模块名(`import a.b` 与 `from a.b import c` 都算 a.b)。"""
+    try:
+        tree = ast.parse(path.read_text(encoding='utf-8'))
+    except SyntaxError:
+        return []
+    out = []
+    for n in ast.walk(tree):
+        if isinstance(n, ast.Import):
+            out += [a.name for a in n.names]
+        elif isinstance(n, ast.ImportFrom) and n.module:
+            out.append(n.module)
+    return out
+
+
+def audit(verbose: bool = True):
+    reg = load_registry()
+    mods = {m['name']: m for m in reg['modules']}
+    problems: list[tuple[str, str]] = []          # (规则, 说明)
+    notes: list[str] = []
+
+    # R1 结构
+    for name, m in mods.items():
+        base = ROOT / name
+        for rel in (f'common/__init__.py', f'common/{module_pkg(name)}/__init__.py',
+                    f'common/{module_pkg(name)}/api.py', 'README.md'):
+            if not (base / rel).is_file():
+                problems.append(('R1', f'{name}/ 缺 {rel}'))
+    # R5 接口目标存在
+    for name in mods:
+        api = ROOT / name / 'common' / module_pkg(name) / 'api.py'
+        if not api.is_file():
+            continue
+        try:
+            tree = ast.parse(api.read_text(encoding='utf-8'))
+        except SyntaxError as e:
+            problems.append(('R1', f'{name}/api.py 语法错误: {e}'))
+            continue
+        tg = {}
+        for n in tree.body:
+            if isinstance(n, ast.Assign) and getattr(n.targets[0], 'id', '') == '_TARGETS':
+                try:
+                    tg = ast.literal_eval(n.value)
+                except Exception:  # noqa: BLE001
+                    tg = {}
+        for pub, target in tg.items():
+            rel = pathlib.Path(*target.split('.'))
+            if not ((ROOT / rel).with_suffix('.py').is_file() or (ROOT / rel / '__init__.py').is_file()):
+                problems.append(('R5', f'{name}.api.{pub} → {target} 的转发目标不存在'))
+
+    # R2/R3/R4 边界与依赖
+    for name, m in mods.items():
+        allow = set(m.get('allow') or [])
+        for f in (ROOT / name).rglob('*.py'):
+            for imp in _imports_of(f):
+                parts = imp.split('.')
+                if parts[0] not in mods or parts[0] == name:
+                    continue
+                other = parts[0]
+                # 只许 app_<other>.common.app_<other>_guanlan.api
+                ok_face = (len(parts) >= 4 and parts[1] == 'common'
+                           and parts[3] == 'api' and parts[2] == module_pkg(other))
+                if not ok_face:
+                    problems.append(('R2', f'{f.relative_to(ROOT).as_posix()} 直接 import {imp}'
+                                           f'(应走 {other}.common.{module_pkg(other)}.api)'))
+                if other not in allow:
+                    problems.append(('R3', f'{f.relative_to(ROOT).as_posix()} import {other}'
+                                           f',但 {name} 的 allow 未包含它'))
+                if name == 'app_common':
+                    problems.append(('R4', f'{f.relative_to(ROOT).as_posix()} 公共层依赖了业务模块 {other}'))
+
+    # 迁移进度(不算失败)
+    legacy = [p for p in list((ROOT / 'src').rglob('*.py')) + list((ROOT / 'scripts').rglob('*.py'))
+              if p.is_file()]
+    notes.append(f'尚未迁入模块目录的既有实现件: src/** {len(list((ROOT / "src").rglob("*.py")))} 件 · '
+                 f'scripts/** {len(list((ROOT / "scripts").rglob("*.py")))} 件(迁移进度按 docs/重构方案_模块化_v0.1.md 的 P1–P7 推进)')
+
+    rc = 0
+    if any(p[0] in ('R1',) for p in problems):
+        rc = 5
+    if any(p[0] == 'R2' for p in problems):
+        rc = rc or 6
+    if any(p[0] in ('R3', 'R4') for p in problems):
+        rc = rc or 7
+    if any(p[0] == 'R5' for p in problems):
+        rc = rc or 8
+    if verbose:
+        print('模块边界审计 · 登记模块 %d 个(%s)' % (len(mods), '、'.join(mods)))
+        for n in notes:
+            print('  [i]', n)
+        if problems:
+            for rule, msg in problems:
+                print('  [X] %s %s' % (rule, msg))
+        else:
+            print('  [OK] 结构齐全 · 模块间只经 api 调用 · 依赖方向合规 · 公共层纯净 · 接口目标全在位')
+    return rc, problems, notes, mods
+
+
+def main() -> int:
+    brief = '--brief' in sys.argv
+    rc, problems, notes, mods = audit(verbose=not brief)
+    if brief:
+        print('[OK] module_boundary_audit rc=0(登记 %d 模块)' % len(mods) if rc == 0
+              else '[X] module_boundary_audit rc=%d(%d 条违规)' % (rc, len(problems)))
+    return rc
+
+
+if __name__ == '__main__':
+    raise SystemExit(main())

+ 24 - 1
src/version.py

@@ -19,7 +19,7 @@ import json
 import pathlib
 
 NAME = '观澜·如东样板 v2'
-VERSION = '2.10.4'         # ★ 版本只改这里
+VERSION = '2.11.0'         # ★ 版本只改这里
 EDITION = 'offline-single-package'
 PACKAGE_STEM = 'app_guanlang'           # 交付包文件名前缀(用户令 2026-09-17)
 
@@ -49,6 +49,29 @@ BUMP_RULE = ('改动落在"解决方案/架构/核心功能" → 大 +1(中/
 #   level: major/minor/patch 表示这一版**相对上一版**是哪一级变化;legacy 表示该版用的是
 #   旧编号体系(0.x,未按本规则),仅作历史对账用。
 HISTORY: tuple[dict, ...] = (
+    dict(version='2.11.0', date='2026-09-22', level='minor',
+         title='源码模块化重构 P0:七个模块目录 + 接口层 + 模块边界门(每模块只经 api 调用,可插拔)',
+         note='源码组织层重构 ⇒ 中版本 +1(运行形态、交付形态与核心功能未变)。'
+              '用户令: 「对观澜的源代码,按算法、数据接入管理、前端、后端 等系统模块进行重构,每个模块一个目录;'
+              '遵循组件化、高内聚低耦合、可复用、可扩展(支持热插拔)、兼容性、性能优化、高可用、分布式、'
+              '面向对象、代码精简;系统组件: TiDB community、MinIO、Redis、Nginx」。'
+              '本轮按用户选择执行:**只重构目录与接口**(暂不引入四个组件,只留接入点)、'
+              '**零行为变化、逐版本可回滚**。落地: '
+              '① 七个模块目录(每模块一个目录): app_common(公共层)/ app_dataAccess(数据接入管理)/ '
+              'app_algorithm(算法)/ app_ontology(本体与知识层)/ app_backEnd(后端)/ app_frontEnd(前端)/ '
+              'app_qualityGate(质量门与审计 + 打包安装);每个模块下 `common/app_<模块>_guanlan/` 放观澜实现,'
+              '`api.py` 是**唯一对外公开面**(PEP 562 惰性转发到既有实现,因此行为与重构前一致)。'
+              '② `configs/modules.yaml` 模块登记表(职责/允许依赖/实现落点/迁移阶段/组件接入点)。'
+              '③ 新增 `scripts/module_boundary_audit.py` 并接入 `guanlan.py check`: 查结构齐、模块间只经 api、'
+              '依赖方向合规(不得反向成环)、公共层不依赖业务模块、api 转发目标真实存在;并统计迁移进度。'
+              '④ 四个系统组件的接入点先立**接口契约**(无实现,默认仍走本地/进程内): '
+              'TiDB community ↔ app_dataAccess 的标准仓读写接口、MinIO ↔ 源件与产物对象存储接口、'
+              'Redis ↔ app_backEnd 的按时间窗缓存与作业状态接口、Nginx ↔ 统一入口与路由表接口。'
+              '⑤ 设计说明新增「源码模块化布局与边界」一节(模块表 + 目录树 + 边界规则 + 分阶段迁移 P1–P7),'
+              '方案全文见 `docs/重构方案_模块化_v0.1.md`。'
+              '⑥ 三份交付文档随版本号改名重渲(内容口径不变)。'
+              '验证: 边界审计 rc=0;旧路径(src/**、scripts/**)与页面/CLI/产物零变化;'
+              '`guanlan.py check`、配置统一、页面归口、反向呼应、可移植性、可转移、文档三检 全绿。'),
     dict(version='2.10.4', date='2026-09-22', level='patch',
          title='数据要求说明补测点:安全链与数字输入、执行器与热管理、计数账、CMS 采集参数、位号字典',
          note='纯交付物修订 ⇒ 小版本 +1。用户令: 「测点遗漏体检的方案补进数据要求说明」。'

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików