feat: 累积功能变更 — 聊天集成、租户管理、小程序更新、ETL 增强、迁移脚本

包含多个会话的累积代码变更:
- backend: AI 聊天服务、触发器调度、认证增强、WebSocket、调度器最小间隔
- admin-web: ETL 状态页、任务管理、调度配置、登录优化
- miniprogram: 看板页面、聊天集成、UI 组件、导航更新
- etl: DWS 新任务(finance_area_daily/board_cache)、连接器增强
- tenant-admin: 项目初始化
- db: 19 个迁移脚本(etl_feiqiu 11 + zqyy_app 8)
- packages/shared: 枚举和工具函数更新
- tools: 数据库工具、报表生成、健康检查
- docs: PRD/架构/部署/合约文档更新

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Neo
2026-04-06 00:03:48 +08:00
parent 70324d8542
commit 6f8f12314f
515 changed files with 76604 additions and 7456 deletions

View File

@@ -0,0 +1,136 @@
# -*- coding: utf-8 -*-
"""
Dev Trace Log 配置模块
从环境变量读取 trace 相关配置,支持运行时动态修改(内存状态)。
重启后回退到 .env 配置值。使用单例模式,全局唯一实例。
环境变量缺失时使用合理默认值:
- DEV_TRACE_ENABLED: false默认关闭显式开启才采集
- DEV_TRACE_LOG_DIR: export/dev-trace-logs
- DEV_TRACE_LOG_RETENTION_DAYS: 7
- DEV_TRACE_LOG_SQL: true
- DEV_TRACE_LOG_PARAMS: true
"""
from __future__ import annotations
import os
import threading
from typing import Any
def _parse_bool(value: str, default: bool) -> bool:
"""解析布尔型环境变量,支持 true/1/yes不区分大小写"""
if not value:
return default
return value.strip().lower() in ("true", "1", "yes")
class TraceConfig:
"""全链路日志配置(单例)。
属性从环境变量初始化,运行时可通过 update_settings() 动态修改。
重启后自动回退到 .env 值(因为 __init__ 重新读取环境变量)。
"""
_instance: TraceConfig | None = None
_lock: threading.Lock = threading.Lock()
def __new__(cls) -> TraceConfig:
# 双重检查锁定,线程安全的单例
if cls._instance is None:
with cls._lock:
if cls._instance is None:
instance = super().__new__(cls)
instance._init_from_env()
cls._instance = instance
return cls._instance
def _init_from_env(self) -> None:
"""从环境变量读取配置,作为基线值和当前运行时值。"""
# 基线值(.env 原始值reset_to_env 时回退到这里)
self._env_enabled: bool = _parse_bool(
os.environ.get("DEV_TRACE_ENABLED", ""), default=False
)
raw_log_dir: str = os.environ.get(
"DEV_TRACE_LOG_DIR", "export/dev-trace-logs"
)
# CHANGE 2026-03-22 | trace日志路径修复
# 相对路径基于项目根目录解析,避免受后端 cwdapps/backend/)影响
if not os.path.isabs(raw_log_dir):
project_root = os.environ.get("NEOZQYY_ROOT", "")
if project_root:
raw_log_dir = os.path.join(project_root, raw_log_dir)
self._env_log_dir: str = raw_log_dir
self._env_retention_days: int = int(
os.environ.get("DEV_TRACE_LOG_RETENTION_DAYS", "7")
)
self._env_log_sql: bool = _parse_bool(
os.environ.get("DEV_TRACE_LOG_SQL", ""), default=True
)
self._env_log_params: bool = _parse_bool(
os.environ.get("DEV_TRACE_LOG_PARAMS", ""), default=True
)
# 运行时值初始等于基线值API 可动态修改)
self.enabled: bool = self._env_enabled
self.log_dir: str = self._env_log_dir
self.retention_days: int = self._env_retention_days
self.log_sql: bool = self._env_log_sql
self.log_params: bool = self._env_log_params
# ------------------------------------------------------------------
# 运行时开关方法
# ------------------------------------------------------------------
def update_settings(
self,
*,
enabled: bool | None = None,
retention_days: int | None = None,
log_sql: bool | None = None,
log_params: bool | None = None,
) -> None:
"""更新内存中的运行时设置(不写 .env重启后回退"""
if enabled is not None:
self.enabled = enabled
if retention_days is not None:
self.retention_days = retention_days
if log_sql is not None:
self.log_sql = log_sql
if log_params is not None:
self.log_params = log_params
def get_settings(self) -> dict[str, Any]:
"""返回当前运行时设置字典。"""
return {
"enabled": self.enabled,
"log_dir": self.log_dir,
"retention_days": self.retention_days,
"log_sql": self.log_sql,
"log_params": self.log_params,
}
def reset_to_env(self) -> None:
"""重置运行时值为 .env 基线值。"""
self.enabled = self._env_enabled
self.log_dir = self._env_log_dir
self.retention_days = self._env_retention_days
self.log_sql = self._env_log_sql
self.log_params = self._env_log_params
# ------------------------------------------------------------------
# 测试辅助:重置单例(仅测试使用)
# ------------------------------------------------------------------
@classmethod
def _reset_singleton(cls) -> None:
"""销毁单例实例,下次访问时重新从环境变量初始化。仅供测试使用。"""
with cls._lock:
cls._instance = None
def get_trace_config() -> TraceConfig:
"""获取全局 TraceConfig 单例。"""
return TraceConfig()