diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md deleted file mode 100644 index a1da51d..0000000 --- a/docs/ARCHITECTURE.md +++ /dev/null @@ -1,140 +0,0 @@ -# eSIM-Tools 架构说明 - -## 当前架构 - -### 概述 - -eSIM-Tools 是一个 Web 应用,用于管理 Giffgaff 和 Simyo 运营商的 eSIM 激活。采用无服务器架构,Netlify Functions 作为后端 API,静态托管作为前端。 - -### 技术栈 - -- **前端**: 原生 JavaScript, Bootstrap, PWA -- **后端**: Node.js/Express (本地开发), Netlify Functions (生产环境) -- **构建工具**: Webpack, Babel, PostCSS -- **优化工具**: Sharp (图片), Terser (JS), Workbox (Service Worker) - -### 部署架构 - -``` -用户请求 → Netlify CDN (静态资源) → Netlify Functions (API) → 运营商 API - ↓ - Edge Functions (BFF 代理层,注入 ACCESS_KEY) -``` - -### 模块依赖关系 - -``` -┌─────────────────────────────────────────────────────────┐ -│ 前端层 (Browser) │ -├─────────────────────────────────────────────────────────┤ -│ index.html → src/giffgaff/ → src/js/modules/ │ -│ src/simyo/ → (通用工具模块) │ -└─────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────┐ -│ Edge Functions (BFF) │ -│ netlify/edge-functions/bff-proxy.js │ -│ (ACCESS_KEY 注入 + 请求转发) │ -└─────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────┐ -│ Netlify Functions (Serverless) │ -├─────────────────────────────────────────────────────────┤ -│ giffgaff-token-exchange.js giffgaff-graphql.js │ -│ giffgaff-mfa-challenge.js giffgaff-sms-activate.js │ -│ giffgaff-mfa-validation.js auto-activate-esim.js │ -│ verify-cookie.js health.js │ -│ public-config.js notifications.js │ -│ notifications-internal.js │ -│ _shared/middleware.js _shared/internal-headers.js │ -└─────────────────────────────────────────────────────────┘ -``` - -### 关键设计决策 - -1. **无框架设计**: 使用原生 JavaScript 避免框架依赖,保持最小打包体积 -2. **BFF 模式**: Edge Functions 作为 Backend-For-Frontend 代理层,注入 ACCESS_KEY 并转发请求 -3. **中间件统一**: 通过 `withAuth` 中间件统一处理鉴权、CORS、验证 -4. **原生 ES6 模块**: 业务页面不经 Webpack 打包,按需加载 - ---- - -## 构建优化 - -### 1. 图片处理速度提升 2.4 倍 (`scripts/optimize-images.js`) - -**问题**: 旧脚本串行处理图片,10 张图片需要 60 秒。 - -**方案**: 改为并行处理(可配置并发数),加入智能缓存跳过已优化文件,支持 mozjpeg 和 adaptive filtering 压缩。 - -**效果**: 处理时间从 60 秒降至 25 秒,压缩率提升 30-40%。 - -### 2. 压缩率提升 15-20% (`scripts/compress.js`) - -**问题**: 旧压缩脚本仅使用 Gzip,且每次都全量压缩。 - -**方案**: 同时生成 Brotli + Gzip 双版本,加入基于缓存的跳过逻辑避免重复压缩。 - -**效果**: 压缩率提升 15-20%,后续构建只需压缩变更文件。 - -### 3. 滚动性能提升,内存泄漏消除 (`src/js/performance.js`) - -**问题**: Intersection Observer 未清理导致内存泄漏,图片在进入视口后才开始加载。 - -**方案**: 统一 Observer 生命周期管理,视口前预加载图片,加入错误处理。 - -**效果**: 内存使用减少 10-15%,滚动更流畅。 - -### 4. 打包体积减少 25%,长期缓存更优 (`webpack.config.js`) - -**问题**: 打包体积 ~450KB (gzip),第三方库未分离,缓存命中率低。 - -**方案**: 拆分第三方 chunk,提取 runtime,使用确定性模块 ID,加入 Brotli 插件和 500KB 性能预算。 - -**效果**: 打包体积降至 ~340KB (gzip) / ~280KB (brotli)。 - -### 5. 通用工具函数库 (`src/js/modules/utils.js`) - -提供 debounce (leading/trailing)、throttle (RAF)、记忆化、指数退避重试、bytes/JSON 格式化等常用工具。 - -### 6. 请求验证与安全防护 (`src/js/middleware/validation.js`) - -提供请求体大小验证、Header 校验、XSS 清理、内存级速率限制、请求计时日志和异步错误边界。 - ---- - -## 性能基准 - -以下数据基于 Lighthouse 测量(Chrome DevTools,模拟 4G 网络): - -### 优化前 -- 打包体积: ~450KB (gzip) -- 图片优化: 10 张图片 60 秒 -- First Contentful Paint: 1.8s -- Time to Interactive: 3.2s - -### 优化后 -- 打包体积: ~340KB (gzip), ~280KB (brotli) -- 图片优化: 10 张图片 25 秒 (2.4x 提升) -- First Contentful Paint: 1.2s (提升 33%) -- Time to Interactive: 2.1s (提升 34%) - ---- - -## 实施路线 - -### 阶段 1: 代码质量 (已完成) -- 优化构建工具 -- 添加工具库 -- 改进错误处理 -- 添加验证中间件 - -### 阶段 2: 基础设施 (进行中) -- ✅ Sentry 监控 (前后端) -- ✅ 内存级速率限制 (`_shared/rate-limiter.js`) -- 添加 Redis 缓存 -- 添加端到端测试 - -> 更多未来架构规划请参考 [FUTURE_ARCHITECTURE.md](./FUTURE_ARCHITECTURE.md) diff --git a/docs/FUTURE_ARCHITECTURE.md b/docs/FUTURE_ARCHITECTURE.md deleted file mode 100644 index 0ed8933..0000000 --- a/docs/FUTURE_ARCHITECTURE.md +++ /dev/null @@ -1,249 +0,0 @@ -# eSIM-Tools 未来架构规划 - -> 本文档记录当前尚未实施的架构规划,仅供未来参考。 - -## 微服务架构迁移 - -### 当前状态 -- 单体 Netlify Functions -- 业务逻辑与 API 处理器紧耦合 -- 复用性有限 - -### 目标架构 - -``` -┌─────────────────────────────────────────────────┐ -│ API Gateway / BFF Layer │ -│ (Netlify Edge Functions / Cloudflare Workers) │ -└─────────────────────────────────────────────────┘ - │ - ┌──────────────┼──────────────┐ - │ │ │ -┌───────▼──────┐ ┌─────▼──────┐ ┌────▼────────┐ -│ Auth Service │ │ Provider │ │ Activation │ -│ (OAuth) │ │ Adapters │ │ Service │ -└───────────────┘ └────────────┘ └─────────────┘ - │ │ │ - └──────────────┼──────────────┘ - │ - ┌──────────────▼──────────────┐ - │ Shared Middleware │ - │ (Rate Limit, Auth, Log) │ - └─────────────────────────────┘ -``` - -**优势:** -- 独立部署和扩展 -- 更好的关注点分离 -- 更容易测试和维护 -- 新运营商的插件架构 - -**实施计划:** -1. 将共享逻辑提取到 `src/services/core/` -2. 在 `src/services/adapters/` 中创建运营商适配器 -3. 在 `src/services/middleware/` 中实现中间件链 -4. 添加服务注册表用于动态运营商加载 - -**代码示例:** -```javascript -// src/services/adapters/BaseProvider.js -/** - * 运营商适配器基类 - * @abstract - */ -class BaseProvider { - constructor(config) { - this.config = config; - } - - /** - * 认证方法(子类必须实现) - * @param {Object} credentials - 认证凭据 - * @returns {Promise} 认证结果 - */ - async authenticate(credentials) { - throw new Error('Must implement authenticate()'); - } - - /** - * eSIM 激活方法(子类必须实现) - * @param {Object} data - 激活数据 - * @returns {Promise} 激活结果 - */ - async activateESIM(data) { - throw new Error('Must implement activateESIM()'); - } -} -``` - -## 可扩展性策略 - -### 当前限制 -- 无状态函数(无会话持久化) -- 有限的并发请求处理 -- 无长时间运行任务的作业队列 -- 直接 API 调用,无熔断器 - -### 目标方案 - -#### A. 添加数据库层 - -``` -┌──────────────────────────────────────┐ -│ Application Layer │ -└──────────────────────────────────────┘ - │ - ┌─────────────┼─────────────┐ - │ │ -┌───▼──────┐ ┌──────────▼────┐ -│ Redis │ │ PostgreSQL │ -│ (Cache) │ │ (Sessions) │ -└──────────┘ └───────────────┘ -``` - -**使用场景:** -- 多步骤 OAuth 流程的会话管理 -- 跨 Serverless 实例的速率限制 -- API 请求去重 -- 用户偏好和设置 - -**技术建议:** -- **Redis**: Upstash Redis (Serverless 友好) -- **PostgreSQL**: Neon 或 Supabase (Serverless Postgres) - -#### B. CDN 优先架构 - -``` -用户请求 - │ - ▼ -┌─────────────────┐ -│ CDN Edge │ ← 静态资源 (HTML, CSS, JS, Images) -│ (Cloudflare) │ ← Service Worker precache -└────────┬────────┘ - │ (Cache Miss) - ▼ -┌─────────────────┐ -│ Origin Server │ ← 仅动态 API 请求 -│ (Netlify) │ -└─────────────────┘ -``` - -**优化:** -- 对哈希资源设置长缓存时间 (1 年) -- HTML 使用 stale-while-revalidate -- 实现边缘渲染个性化内容 -- 预获取关键 API 响应 - -#### C. 后台处理作业队列 - -``` -API Request → Enqueue Job → Return Job ID - │ - ▼ - ┌──────────────┐ - │ Job Queue │ - │ (BullMQ) │ - └──────┬───────┘ - │ - ┌───────┴────────┐ - │ │ - ┌────▼────┐ ┌─────▼────┐ - │ Worker 1│ │ Worker 2 │ - └─────────┘ └──────────┘ -``` - -**使用场景:** -- 图片优化 -- 批量 eSIM 激活 -- 报告生成 -- 邮件通知 - -**技术:** BullMQ + Redis 后端 - -## 未来功能规划 - -### A. 多运营商插件系统 - -**接口定义:** -```javascript -/** - * 运营商插件接口 - * @interface ProviderPlugin - */ -// 所有方法由具体运营商适配器实现: -// - authenticate(credentials) → Promise -// - activateESIM(data) → Promise -// - getStatus(id) → Promise -// - validate(data) → ValidationResult -``` - -**插件注册表:** -```javascript -class PluginRegistry { - constructor() { - this.plugins = new Map(); - } - - async loadPlugin(name) { - const plugin = await import(`./plugins/${name}`); - this.plugins.set(name, plugin); - } - - getProvider(name) { - return this.plugins.get(name); - } -} -``` - -**优势:** -- 轻松添加新运营商 -- 社区贡献 -- A/B 测试不同实现 -- 运营商 API 渐进迁移 - -### B. 实时状态追踪 - -**WebSocket 架构:** -``` -Client → WebSocket → Server → Provider API - │ │ - └──────── Status Updates ──────┘ -``` - -**Server-Sent Events 实现 (更简单):** -```javascript -// 客户端 -const eventSource = new EventSource('/api/esim-status?id=123'); -eventSource.onmessage = (event) => { - const status = JSON.parse(event.data); - updateUI(status); -}; -``` - -### C. 离线优先 PWA 与后台同步 - -**增强的 Service Worker 策略:** -```javascript -// 后台同步失败的请求 -self.addEventListener('sync', (event) => { - if (event.tag === 'esim-activation') { - event.waitUntil(retryActivation()); - } -}); -``` - -**功能:** -- 离线时队列 eSIM 激活请求 -- 连接恢复后自动重试 -- 使用 IndexedDB 进行本地状态管理 -- 并发编辑的冲突解决 - -### D. 分析仪表板 - -**追踪指标:** -- 按运营商统计激活成功率 -- 平均激活时间 -- 错误率和类型 -- 用户旅程分析 -- 性能指标 (Core Web Vitals) diff --git a/src/giffgaff/giffgaff_modular.html b/src/giffgaff/giffgaff_modular.html index 447a0fe..004d926 100644 --- a/src/giffgaff/giffgaff_modular.html +++ b/src/giffgaff/giffgaff_modular.html @@ -875,18 +875,10 @@ - + - + diff --git a/src/giffgaff/js/init-i18n.js b/src/giffgaff/js/init-i18n.js new file mode 100644 index 0000000..7c6a027 --- /dev/null +++ b/src/giffgaff/js/init-i18n.js @@ -0,0 +1,4 @@ +// Giffgaff 页面国际化初始化 +import { initI18n } from '/src/js/modules/i18n.js'; + +initI18n('giffgaff'); diff --git a/src/giffgaff/js/init-notification.js b/src/giffgaff/js/init-notification.js new file mode 100644 index 0000000..3fdc195 --- /dev/null +++ b/src/giffgaff/js/init-notification.js @@ -0,0 +1,6 @@ +// Giffgaff 页面通知系统初始化 +import NotificationService from '/src/js/modules/notification-service.js'; + +document.addEventListener('DOMContentLoaded', () => { + NotificationService.init(); +}); diff --git a/src/simyo/js/init-i18n.js b/src/simyo/js/init-i18n.js new file mode 100644 index 0000000..f42c05d --- /dev/null +++ b/src/simyo/js/init-i18n.js @@ -0,0 +1,4 @@ +// Simyo 页面国际化初始化 +import { initI18n } from '/src/js/modules/i18n.js'; + +initI18n('simyo'); diff --git a/src/simyo/js/init-notification.js b/src/simyo/js/init-notification.js new file mode 100644 index 0000000..b2aa6a8 --- /dev/null +++ b/src/simyo/js/init-notification.js @@ -0,0 +1,6 @@ +// Simyo 页面通知系统初始化 +import NotificationService from '/src/js/modules/notification-service.js'; + +document.addEventListener('DOMContentLoaded', () => { + NotificationService.init(); +}); diff --git a/src/simyo/simyo_modular.html b/src/simyo/simyo_modular.html index bf98098..5b16268 100644 --- a/src/simyo/simyo_modular.html +++ b/src/simyo/simyo_modular.html @@ -555,18 +555,10 @@ - + - +