architecture.md 21 KB

Glacier 公司管理系统 — 技术架构设计(草案 v0.3)

状态:设计阶段(已确认关键技术决策,见 §0),仅设计,不写代码。 适用范围:Glacier 公司内部管理系统(首页 + 业务功能子空间 + 数据采集)。


0. 已确认决策(v0.2 落实)

# 决策点 结论 对架构的影响
1 模板引擎 Twig(composer 引入) §3.3:模板/脚本分离由 Twig 承担,自带转义
2 依赖策略 尽可能减少依赖;无法绕过的才用 composer 第三方 核心(路由/DB/会话/中间件)全部自研;唯一默认第三方 = Twig
3 子空间管理 同一仓库(glacier 单仓多模块) §2:模块收拢在 app/modules/ 下
4 数据库 单库多表(库名 glacier) §3.5:统一表前缀约定,避免表名冲突
5 上传文件 本地磁盘,但规避直接访问 §3.9:存 storage/uploads/(Web 根之外),经控制器鉴权下发
6 语言 / 时区 中文界面,UTC+8 §3.4:全链路统一时区与字符集
7 数据来源 Python 爬虫为可能的数据来源 §3.8:独立 Python 采集管道,入库供系统展示

1. 总体架构

                 ┌──────────────────────────────────────────────────┐
  浏览器 (HTTP)  │                                                  │
      │          │  生产: Debian   Caddy(自动HTTPS) → PHP-FPM       │
      ▼          │  开发: Windows  WAMP Apache      → mod_php       │
 ┌──────────┐    │                                                  │
 │  public/ │    │          ┌──────────────────────┐                │
 │ index.php│───▶│          │  应用核心 (app/core)  │                │
 └──────────┘    │          │  Router · Twig       │                │
      │          │          │  Database · Session  │                │
      │          │          └──────────┬───────────┘                │
      │          │                     │                            │
      │          │        ┌────────────┼────────────┐               │
      │          │        ▼            ▼            ▼               │
      │          │  modules/      controllers/   models/            │
      │          │  (业务子空间)   (业务逻辑)     (数据层)           │
      │          │        │                                          │
      │          │        ▼                                          │
      │          │  Go 服务 (独立进程, 按需引入)                      │
      │          └───────────────┬──────────────────────────────────┘
      │                          ▼
      │                  MariaDB (生产) / MySQL (开发)
      │                  库: glacier, 单库多表, 统一前缀
      ▼                          ▲
   静态资源: /assets              │ 写入 (只写库+私有存储, 不碰 Web 层)
   上传: storage/uploads (私有)    │
                                  │
                     ┌────────────┴────────────┐
                     │  Python 爬虫管道 (crawlers/) │
                     │  调度 → 采集 → 清洗/去重 → 入库 │
                     └─────────────────────────┘

1.1 分层职责

层 职责 不许做的事
Web 服务器 TLS、静态资源、URL rewrite 到入口 不执行业务逻辑
入口 (public/index.php) 引导、加载配置、调用 Router 不包含业务逻辑
Router(URL 模式引擎) 将 URL 映射到控制器/模块 不解析物理路径
Controller 接收请求、调模型、产出数据 不直接输出 HTML(交给 Twig)
Model 数据访问(PDO 预处理)、业务规则 不处理 URL
View(Twig 模板) 只渲染控制器给的数据 不写业务逻辑、不做数据库访问
Go 服务 复杂/长任务/高并发能力(按需) 不处理 Web 会话
Python 爬虫 外部数据采集、清洗、入库 不直接提供 Web 页面、不碰会话

1.2 技术选型速查

项 选型 理由 / 备注
PHP 8.1+(生产 PHP-FPM,开发 mod_php) 生态成熟,WAMP 开箱即用
模板引擎 Twig(composer,唯一默认第三方) 自带转义、布局继承;稳定成熟
路由 自研 URL Pattern Engine 需求明确、可控、零依赖
DB PDO + prepared statement 防注入、跨 MySQL/MariaDB 一致
会话 原生 Session 封装(可选 DB 存储) 后期扩展权限体系
复杂后端 Go 独立二进制(按需) 编译型、并发强、部署简单
数据采集 Python 3.10+(requests + BeautifulSoup/lxml 等轻量库) 生态适合爬虫;不引重框架(无 Scrapy 起步)
前端 原生 HTML/CSS + 少量 JS;无前端框架 管理系统以表单/表格为主
生产反代 Caddy 自动 HTTPS、配置简单
开发 Web WAMP Apache 本机开发一致预览

2. 目录结构设计(仓库蓝图)

glacier/
├── public/                  # ★ 唯一对外 Web 根目录
│   ├── index.php            # 单一入口(前端控制器)
│   ├── .htaccess            # 开发环境 rewrite(Apache/WAMP)
│   └── assets/              # css / js / img(前端静态资源,可直接访问)
├── app/
│   ├── core/                # 核心基础设施(自研,零依赖)
│   │   ├── Router.php       # URL 模式引擎
│   │   ├── Database.php     # PDO 封装 + 迁移
│   │   ├── Session.php      # 会话管理封装
│   │   ├── Middleware.php   # 中间件管道(本期预留 auth/权限/CSRF)
│   │   ├── Response.php     # 统一响应(HTML/JSON/重定向)
│   │   ├── File.php         # 上传/下载控制器支撑(私有存储鉴权下发)
│   │   └── helpers.php      # 转义等公共函数
│   ├── config/              # 配置(环境分层)
│   │   ├── env.dev.php      # 开发环境配置(含 DB、时区、BASE_URL)
│   │   ├── env.prod.php     # 生产环境配置
│   │   └── routes.php       # ★ URL 模式路由表(集中声明)
│   ├── controllers/         # 各页面控制器
│   ├── models/              # 数据模型
│   ├── views/               # Twig 模板(与脚本分离)
│   │   ├── layouts/         # 布局模板(页头/页脚/导航)
│   │   └── partials/        # 可复用片段
│   ├── middleware/          # 中间件实现(后期)
│   └── modules/             # ★ 业务子空间(见 §4)
│       └── <name>/          # 每个 /<name> 一个模块
│           ├── routes.php   # 模块内路由(前缀自动挂载)
│           ├── controllers/
│           ├── models/
│           └── views/
├── storage/                 # ★ 私有存储(Web 根之外,禁止直接访问)
│   ├── uploads/             # 上传文件(本地磁盘,经控制器鉴权下发)
│   ├── cache/               # 模板/路由缓存
│   └── logs/                # 应用日志
├── crawlers/                # ★ Python 数据采集管道(见 §3.8)
│   ├── requirements.txt     # 依赖清单(轻量)
│   ├── common/              # 公共:DB 连接、去重、日志、调度
│   └── tasks/               # 各采集任务(按数据源划分)
├── go/                      # Go 复杂后端服务(独立 module,按需)
│   └── services/
├── database/                # SQL 迁移脚本(版本化,单库多表)
├── docs/                    # 文档(本文件)
├── deploy/                  # 部署资产
│   ├── Caddyfile            # 生产 rewrite + TLS 配置
│   ├── systemd/             # PHP-FPM / Go / Python 任务单元
│   └── deploy.sh            # 发布脚本
├── vendor/                  # composer 第三方(Twig 等)— .gitignore
├── .gitignore               # 需重写:PHP + Python + 上传/密钥/缓存
├── composer.json            # 仅声明 Twig(+ 后续按需评估)
├── README.md                # 项目说明(指向本文档)
└── LICENSE

关键原则:

  1. 只暴露 public/;上传在 storage/,物理路径不可能出现在 URL,也不可能被直接访问。
  2. 所有动态请求进 index.php,由路由表声明式分发;assets/ 是唯一直接服务的静态目录。
  3. 依赖最小化:核心全自研,composer 只装 Twig;Python 侧只装采集所需轻量库。

3. 核心机制设计

3.1 URL 模式引擎(Router)— 自研,不依赖物理路径

  • 单一入口:public/index.php 接收所有请求(rewrite 见 §3.2),把 URL 路径交给 Router。
  • 路由表(声明式):app/config/routes.php,形如 模式 → [处理器, 中间件]。
  • 模式语法(极简):静态段 /、/about;参数段 /user/:id;可选段 /news[/:page];模块前缀 /<module> 自动挂载到 app/modules/<module>/routes.php。
  • 匹配规则:按注册顺序;区分 GET/POST;未命中 → 渲染 404 模板页。
  • 物理路径隔离:Router 只消费 URL 模式与模块名,从不把 URL 段拼进文件系统路径;模块名白名单([a-z0-9_-] + 目录存在性校验),杜绝路径穿越。

示例映射(概念,非代码):

URL 处理器
/ Home 控制器(本期 → "开发中"占位页)
/assets/* Web 服务器直接服务(不经过 PHP)
/file/download/:id 私有文件鉴权下发(§3.9)
/project 模块 project 入口(子空间)
/project/xxx 模块 project 内部路由

3.2 URL rewrite:开发 / 生产语义对齐

  • 开发(WAMP/Apache):public/.htaccess — 非静态文件请求 rewrite 到 index.php。
  • 生产(Caddy):deploy/Caddyfile — 真实文件(assets)直接服务,否则交 PHP-FPM 入口。
  • 两份规则同一语义:真实文件 → 直接返回;否则 → 入口。上传目录不在 Web 根,天然不参与。

3.3 模板与脚本分离 — Twig

  • 分工:Controller 产出数据;Twig 只渲染。
  • Twig 使用约定:
    • 模板目录:app/views/(布局/片段),模块模板在 app/modules/<name>/views/;
    • 布局继承:{% extends 'layouts/base.html.twig' %} + {% block %};
    • 默认自动转义(Twig 原生);富文本用 |raw 时先经净化器(后期统一白名单净化);
    • 模板编译缓存写入 storage/cache/(开发可关,生产开)。
  • 依赖策略:Twig 是唯一默认 composer 依赖;后续如需第三方,先评估能否自研或替代,无法绕过才引入(§9 持续跟踪)。

3.4 配置与环境隔离

  • APP_ENV 切换 env.dev.php / env.prod.php。
  • 统一配置项:DB 连接、时区 Asia/Shanghai(UTC+8)、语言 zh-CN、字符集 utf8mb4、BASE_URL(模板生成链接用,杜绝物理路径)、Session 名/有效期、上传/存储目录、爬虫调度开关等。
  • 密钥不落库不入库:生产经环境变量/独立文件注入(.gitignore 排除)。
  • 时区在 PHP(date_default_timezone_set)、DB 连接(time_zone)、Python(Asia/Shanghai) 三层统一为 UTC+8。

3.5 数据库 — 单库多表

  • 库名:glacier(开发 MySQL / 生产 MariaDB 同名)。
  • 表前缀约定(避免模块间冲突、便于迁移与权限):
    • 系统核心表:g_(如 g_users、g_sessions、g_settings);
    • 模块表:<module>_(如 news_articles、project_tasks);
    • 采集表:crawl_(如 crawl_sources、crawl_items)。
  • 统一 Database.php(PDO):DSN、utf8mb4、异常模式;一律 prepared statement。
  • 迁移:database/ 下 0001_xxx.sql 顺序编号(up/down),开发/生产共用同一套。
  • 时间字段统一 TIMESTAMP/DATETIME + UTC+8 语义;ID 统一约定(自增或雪花,按模块需要)。

3.6 Session 与访问控制(本期只预留接口)

  • Session.php 封装:HttpOnly、SameSite=Lax、Secure(生产开)、session 名唯一化、CSRF Token(表单统一中间件校验)。
  • 中间件管道:本期实现 CSRF、请求日志;预留 auth / permission 空实现。
  • 后期权限模型(设计预留):用户 + 角色 + 权限(RBAC 简化版);Session 在域名根共享,跨子空间统一登录;权限判断集中在中间件。

3.7 Go 复杂后端集成(设计预留)

  • 适用场景(出现才引入):定时任务、队列/异步、报表聚合、外部 API 网关、并发同步、性能敏感接口。
  • 形态:独立二进制 + systemd,监听内部端口/unix socket;PHP 经 cURL 调用(JSON、错误码、超时重试统一)。

3.8 Python 爬虫数据管道(新增,数据来源)

定位:外部数据来源(如行业新闻、政策、竞品信息等)→ 采集 → 清洗/去重 → 入库 → 系统各模块展示。爬虫只写数据库与私有存储,不提供 Web 页面、不碰会话。

管道结构:

调度 (cron / systemd timer / 手动)
   │
   ▼
采集任务 (crawlers/tasks/<source>.py, requests + 解析)
   │   · 遵守 robots.txt / 限速 / 超时 / 重试
   ▼
清洗与去重 (crawlers/common)
   │   · 字段规范化 · 内容哈希去重 · 编码统一 utf8
   ▼
入库 (写入 glacier 库 crawl_* 表, PDO/MySQL 驱动)
   │   · 只写库 + 私有存储 · 失败可重跑(幂等)
   ▼
系统展示 (PHP 模块读 crawl_* 表渲染, 或经二次加工)

设计约定:

  • 目录:crawlers/(独立于 PHP 树);依赖 requirements.txt(轻量:requests、beautifulsoup4、lxml 起步,不引 Scrapy 等重框架,复杂再评估);
  • 运行环境:开发 Windows(venv + Python 3.10+)/ 生产 Debian(python3-venv + systemd timer 或 cron);
  • 单写者原则:写库统一走 crawlers/common/db.py,表结构以 database/ 迁移为准(schema 唯一来源);
  • 采集表归属 crawl_ 前缀;字段含 source_url(唯一约束去重)、content_hash、fetched_at、status(new/processed/ignored);
  • 安全:抓取内容入库前净化(防存储型 XSS,展示层 Twig 转义兜底);凭据(若需登录抓取)不入库不入仓库,.gitignore 排除;遵守目标站点 robots 与频率限制,避免法律与封禁风险;
  • 触发方式:初期手动 + cron 定时;需要动态调度/复杂编排时再考虑 Go 服务或系统自带调度表。

3.9 上传与私有文件(本地磁盘,规避直接访问)

  • 上传落盘:storage/uploads/(Web 根之外)→ 任何 URL 都访问不到物理文件。
  • 下发:/file/download/:id 控制器 → 校验(登录/权限/归属,后期)→ 流式输出(Content-Disposition 可控)。
  • 存储命名:随机文件名 + 扩展名白名单 + MIME 校验 + 大小限制;元数据入库(g_files 或模块表)。
  • 前端静态资源(css/js/img)仍走 public/assets/ 直接访问,两者严格区分。

4. 子空间(/project)体系设计

  • domain.com/<name> 每个 <name> 是独立业务子空间(模块),收拢在 app/modules/<name>/:
    • routes.php(模块内路由,前缀自动挂载)、controllers/、models/、views/(Twig)、module.php(声明:名称、访问要求、导航注册)。
  • 单库多表:模块表用 <module>_ 前缀,无独立数据库。
  • 开源程序改造接入:放入模块内,不直接暴露其入口文件;URL 经模块路由收口;Session 统一;登录/权限由系统中间件决定。
  • 访问控制(后期):系统级认证 + 模块级角色/权限声明,集中在中间件。

5. 首页

  • 本期:/ → Home 控制器 → Twig 渲染"开发中"占位页(品牌 + 占位说明,中文)。
  • 后期:公司新闻(news 模块,可消费爬虫采集的 crawl_*_items 数据)+ 功能导航(从 module.php 聚合菜单)。

6. 安全基线(贯穿全程)

项 措施
SQL 注入 PDO prepared statement 唯一路径(PHP);Python 写库同样参数化
XSS Twig 默认转义;富文本显式净化
CSRF 表单统一 token 校验(中间件)
路径穿越 模块名白名单 + 不拼接物理路径
文件上传/下载 私有目录存储 + 控制器鉴权下发(§3.9)
会话 HttpOnly + SameSite;登录后重置 session id
采集安全 robots/限速;内容净化;凭据不落库不入库
敏感信息 密钥不落库不入库;生产注入
错误处理 开发显示详情,生产只记日志

7. 开发 / 生产一致性对照

维度 开发(WAMP/Windows) 生产(Debian) 处理
Web 服务器 Apache Caddy rewrite 语义对齐;以 Caddy 为准
PHP mod_php PHP-FPM 版本一致(8.1+);php.ini 关键项对齐
数据库 MySQL MariaDB 兼容语法;迁移两端验证
Python Windows venv (3.10+) python3-venv + systemd timer/cron 版本一致;requirements 固定版本
路径 反斜杠 斜杠 代码内一律相对路径/配置基址
大小写 不敏感 敏感 一律小写命名
时区/字符集 Asia/Shanghai + utf8mb4 同左 三层统一(PHP/DB/Python)

8. 实施步骤(分阶段)

阶段 内容 验收点
P0 环境 WAMP(PHP 8.1+)与 Python 3.10+ venv 就绪;初始化目录骨架;重写 .gitignore(PHP+Python+上传/密钥/缓存);composer 引入 Twig 环境可跑;仓库结构就位
P1 骨架 单一入口 + Router(URL 模式引擎)+ 错误处理 + 日志 任意 URL 进入口,不出现物理路径
P2 模板 Twig 接入 + 布局 + 首页"开发中"占位页 + assets 首页渲染正常;模板/脚本分离生效
P3 数据层 Database 封装 + 迁移机制 + 配置分层(dev/prod,UTC+8) 迁移可在开发库执行;配置切换生效
P4 模块机制 modules/ 约定 + 模块路由挂载 + 模块声明 示例模块经 /<name> 可访问
P5 会话与中间件 Session 封装 + CSRF + auth/permission 空实现 中间件可挂载
P6 爬虫管道 crawlers/ 骨架 + common(DB/去重/日志)+ 采集任务框架 + 入库表迁移(采集目标待定,留空) 采集数据入库;重复抓取幂等
P7 首个真实功能 选一个业务模块(如公司新闻,可消费采集数据)全链路 数据展示、模板渲染、权限挂载
P8 部署 Caddyfile + systemd(PHP-FPM/Go/Python 任务)+ 部署脚本;生产试部署 生产 https 访问;rewrite 一致
P9 Go 集成(按需) 出现复杂需求再引入 Go 内部接口连通

建议 P0→P8 顺序执行,P9 按需触发;每阶段一次 git 提交。


9. 决策状态与待确认事项

已确认(v0.2)

  • ✅ 模板:Twig(composer)
  • ✅ 依赖:最小化;核心自研;无法绕过的第三方按需引入(当前仅 Twig)
  • ✅ 子空间:同一仓库单仓多模块
  • ✅ 数据库:单库多表(g_ / <module>_ / crawl_ 前缀)
  • ✅ 上传:本地磁盘 + 私有存储 + 控制器鉴权下发
  • ✅ 语言/时区:中文 + UTC+8(三层统一)
  • ✅ 数据来源:Python 爬虫管道(轻量库起步)

待确认事项处理(v0.3 更新)

  1. 采集目标:留空(待定) — 第一个爬虫的数据源与频率在 P6 实施前再定,不影响前期阶段。
  2. 调度方式:✅ 确认 — 初期 cron / 手动触发够用;不做调度 UI。
  3. Go 引入时机:占位留空(挂起) — P9 保持按需触发,无明确需求不启动。
  4. 登录体系范围:占位留空 — P5 只做接口预留,登录 UI 归属在 P7 前后再定。
  5. 开源程序改造清单:留空(待定) — 后续确定接入哪些开源 PHP 程序时再补充。
  6. composer 第三方补充:✅ 否 — 除 Twig 外无其他必装库;维持最小依赖(核心自研),后续按需评估。

10. 附录:核心概念速记

  • 单一入口:所有动态请求进 public/index.php。
  • URL ≠ 物理路径:路由表是 URL 的唯一解释者;上传文件在 Web 根之外。
  • 模块 = 子空间:/<name> 即一个模块,收拢在 app/modules/<name>/。
  • 模板只做展示:Twig 渲染,默认转义。
  • 单库多表:glacier 库 + 统一前缀(系统 g_ / 模块 <module>_ / 采集 crawl_)。
  • Python 爬虫只写数据:采集 → 清洗 → 入库,不提供页面。
  • Go 按需引入:不提前造复杂后端。
  • Session/权限后期做:本期只留中间件接口。