Selaa lähdekoodia

docs: 公司管理系统技术架构设计 v0.3

caesar 1 kuukausi sitten
vanhempi
sitoutus
d8c284a783
1 muutettua tiedostoa jossa 350 lisäystä ja 0 poistoa
  1. 350 0
      docs/architecture.md

+ 350 - 0
docs/architecture.md

@@ -0,0 +1,350 @@
+# 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/权限后期做**:本期只留中间件接口。