# chip-eqs **Repository Path**: vbsoft2018_admin/chip-eqs ## Basic Information - **Project Name**: chip-eqs - **Description**: Chip|得芯应手 芯片询价平台(模块化单体:Vue3 前台/后台 + Express API + MySQL + Redis) - **Primary Language**: NodeJS - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-18 - **Last Updated**: 2026-09-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Chip|得芯应手 · 芯片询价交易平台 > 网站标语:**想芯事成,手到芯来**。 > 面向中型/新创/成长型企业的芯片与电子元件询价、报价、交易与 BOM 采购平台。 > 它**不是公开竞价市场,也不是固定标价商城**:采购维护价格,系统执行规则,业务负责沟通,财务核实资金,客户确认收货。 需求基线:[`产品设计与需求分析/芯片询价平台需求分析报告.md`](产品设计与需求分析/芯片询价平台需求分析报告.md)(v2.0)。 低保真 47 屏:[`产品设计与需求分析/低保真原型/index.html`](产品设计与需求分析/低保真原型/index.html);架构图:[`产品设计与需求分析/架构图/index.html`](产品设计与需求分析/架构图/index.html)。 ## 技术栈 - **前端** `frontend/`:Vue 3 + Vite + TypeScript、Element Plus、Pinia、Vue Router(hash)、Axios、dayjs、xlsx。单 SPA 含客户门户与内部后台两套布局,dev 端口 **7301**。 - **后端** `backend/`:Node.js + Express + TypeScript(ESM,tsx 运行)、MySQL(mysql2,手写 SQL,无 ORM)、Redis(ioredis)、JWT、bcrypt、zod、multer、xlsx。分层 `routes → services → db/pool`,端口 **7300**。 - npm workspaces 管理前后端;金额内部用万分之一元 bigint,API/DB 用十进制字符串/`DECIMAL(18,4)`,**禁用浮点**。 ## 目录 ``` backend/ sql/schema.sql # 约 60 张表 DDL src/ config/ db/ redis/ middleware/ utils/ jobs/ services/ # 业务逻辑(auth/company/product/supply/rfq/quote/order/finance/points/matching/bom/channel/...) routes/ # Express 路由(/api/*) tests/ # Vitest(globalSetup 自动 reseed) scripts/seed.ts # 种子数据;smoke.mjs 为 HTTP 端到端冒烟 frontend/ src/{api,router,stores,utils,layouts,views,components} src/views/portal # 客户门户 C1–C17 src/views/internal # 采购 P / 业务 S / 财务 F / 管理员 A docs/ # 决策、数据模型、API、测试映射、渠道能力 ``` ## 快速开始 前置:Node.js ≥ 20、可访问的 MySQL 8 与 Redis。 ```powershell # 1) 安装依赖(仓库根,workspaces 同时安装前后端) npm install --registry=https://registry.npmmirror.com # 2) 配置后端环境变量 Copy-Item backend/.env.example backend/.env # 编辑 backend/.env,填入 DB_HOST/DB_PORT/DB_USER/DB_PASSWORD/DB_NAME、REDIS_*、JWT_SECRET # 3) 初始化数据库表结构 + 种子数据 npm run db:init --workspace backend npm run db:seed --workspace backend # 4) 启动后端(7300)与前端(7301) npm run dev:api # 终端 1 npm run dev:web # 终端 2 → http://127.0.0.1:7301/ (/api 已配置代理到 7300) ``` > 前端 Vite proxy 把 `/api` 转发到 `http://127.0.0.1:7300`,无需额外跨域配置。 ## 种子账号(密码均为 `Test1234`,仅限本地/测试) | 角色 | 邮箱 | 说明 | |---|---|---| | 管理员 | admin@chip.com | 全局/系统治理 | | 业务 | sales@chip.com | RFQ 处理、客户、跟进 | | 采购 | procurement@chip.com | 供应商/价格/供货判断 | | 财务 | finance@chip.com | 收款核对、付款核销、对账 | | 客户(已认证企业 owner) | buyer@chipdemo.com | 南京芯创电子 | | 客户(同企业成员) | buyer2@chipdemo.com | 用于换员工不绕过计数 | | 客户(待审核企业) | newbuyer@chipdemo.com | 用于 AT-01 未认证拦截 | ## 测试与质量检查 ```powershell npm run test --workspace backend # Vitest 全量(自动 reseed) node backend/scripts/smoke.mjs # HTTP 端到端冒烟(先 seed 并启动 API) node node_modules/typescript/bin/tsc --noEmit -p backend/tsconfig.json # 后端类型 node node_modules/vue-tsc/bin/vue-tsc.js --noEmit -p frontend/tsconfig.json # 前端类型 npm run build:web # 前端生产构建 ``` 当前基线:后端 Vitest 60/60 通过、后端 tsc 0、前端 vue-tsc 0、vite build 通过、HTTP 冒烟 28/28。 验收项 AT-01~AT-35 与测试的映射见 [`docs/test-cases.md`](docs/test-cases.md)。 ## 生产/交付打包(dist 运行包) `npm run build:dist`(`node scripts/build-dist.cjs`)产出可直接运行的 `dist/`: ``` dist/ package.json # 独立运行包,npm start = node api/main.so api/main.so # 后端唯一文件:加载器 + 内嵌 V8 字节码(无 .js/.cjs 源码) api/.env # 由 backend/.env 复制,运行时读取(也可用环境变量覆盖) www/ # 前端 vite build 产物,由后端一并托管 uploads/ # 上传目录(npm start 的工作目录为 dist) node_modules/ # 运行期依赖闭包(含 bytenode),离线可直接启动 ``` ### 两种后端保护方式(`--mode`) | | `bytecode`(默认) | `obf`(新增) | |---|---|---| | 命令 | `npm run build:dist` | `npm run build:dist:obf` | | 链路 | esbuild 单文件 → 混淆 → **bytenode 编译 V8 字节码** → 内嵌 | esbuild 单文件 → **最高强度混淆** → 脚本对流加密 → 内嵌 | | 产物体积 | `main.so` ≈ 380 KB | `main.so` ≈ 5.3 MB | | Node 依赖 | **强绑定 V8**,换 Node 必须重打包 | 不绑定 V8,任意 Node 24+ 均可运行(实测 node 22 也能跑) | | 强度 | 无可读 JS(字节码) | 纯文本 JS,但处于"加密 + 全选项混淆 + 反调试"状态 | 两种模式的产物布局完全一致,且 `dist/api` 内**没有任何 `.js/.cjs` 文件**(后端唯一文件 `api/main.so`,`.so` 仅为扩展名,node 对未知扩展名按 CommonJS 执行),`npm start` 命令也一致。 #### `obf` 模式的四层防护(重点:反混淆、防泄露) 1. **javascript-obfuscator 全选项拉满**:控制流扁平化(threshold 1、5 轮变换)、死代码注入(0.4)、字符串提取为 `rc4` 加密数组 + 索引偏移 + 数组旋转/打乱 + 5 层链式包装函数、字符串再二次拆分(8 字符/片)、数值表达式化、标识符十六进制重命名(含全局)、Unicode 转义。 两个已明确关闭的例外:`renameProperties` / `transformObjectKeys` —— 它们会重命名对象属性,导致数据库行字段、接口载荷键读不到(这是服务端代码的硬约束)。 2. **反调试 / 自防御**:`selfDefending`(产物被格式化/beautify 后立即失效并卡死)、`debugProtection`(附加调试器时自扰)。 3. **载荷加密**:混淆结果再由构建脚本用 **salt 派生的 keystream(sha512 分块)做流加密 → base64** 后内嵌。直接打开文件只能看到加载器 + 4 行超长密文,**看不到任何语句结构**。 4. **双层完整性校验**:启动先算文件本体哈希(自引用哈希,先把哈希位写成占位符再回填,且已做 CRLF 归一化),再算解密后载荷哈希。任一层不匹配就打印 `产物完整性校验失败` 并 **exit 1 拒绝执行**。 若确需绕过文件层校验(例如某些部署管线会改写文件),可设 `EQS_DISABLE_INTEGRITY_CHECK=1`,此时载荷层校验仍会生效。 效果实测:`main.so` 中 grep `supplier_confirmed`、`/api/rfqs`、`OFFER_MAX_ATTEMPTS`、`pointsDeductCapBps`、`mysql2`、`SELECT`、`createApp` 等关键字均为 **0 命中**。 > 诚实提示:JS 属于"下发到运行端的明文执行"语言,任何混淆最终都能被足够投入的逆向突破;这几层的作用是**把成本抬高到不划算**,同时在被篡改时**明确拒绝运行**而不是带着后门默默起来。真正的机密(密钥、令牌)不要放在代码里,应放在 `api/.env` 或环境变量中。 - 启动后后端即站点:`http://127.0.0.1:/` 直接是前端页面,`/api/*` 为接口,`/uploads/*` 为上传物,非 `/api`、`/uploads` 的 GET 回退到 SPA `index.html`。 - **V8 字节码与 Node/V8 版本绑定**:仅 `bytecode` 模式受限,打包机与运行机必须同版本,换 Node 版本必须重新打包;`main.so` 启动时会校验 V8 版本并给出明确报错(实测用 node 22 启动 node 24 的字节码包会直接拒绝)。 当前交付目标为 **Node 24.0.0(V8 13.6.233.8-node.10)**: ```powershell # 打包(bytecode 模式必须用与目标机相同的 Node,本机系统 Node 为 v24.0.0) & "C:\Program Files\nodejs\node.exe" scripts/build-dist.cjs # obf 模式(强混淆,不绑定 V8):可用任意 Node 打包 & "C:\Program Files\nodejs\node.exe" scripts/build-dist.cjs --mode=obf # 可加 EQS_NODE_VERSION=24.0.0 强制校验打包机版本,不一致直接中止 # 运行(dist 目录内) cd dist; npm start # = node api/main.so ``` - 常用参数:`--mode=bytecode|obf`、`--skip-web`(复用已有 `frontend/dist` 不重构建)、`--keep-tmp`(保留中间产物 `.dist-build/`)。 - 说明:本环境的批量删除保护会拦截构建脚本对 `dist` 的清理,打包时如遇 `safe-delete` 报错,需要在命令前加 `CODEBUDDY_SAFE_DELETE_ENABLED=0`(仅作用于构建脚本对自己产物目录的清理)。 - **端口排他(单实例,跨 Windows/Linux)**:启动前检测 `PORT`。若被**旧 Node 实例**占用,先结束它再启动: `[port] 端口 7300 被旧实例占用(PID 39416(node.exe)),正在结束…` → `[port] 旧实例已结束,端口 7300 已释放`; 若占用者是**其他程序**(python/nginx/数据库等)则**拒绝启动并明确报错**,不擅自杀不明进程 (例:`端口 7398 被非 Node 进程占用:PID 454(python3)。请手动处理,或用 PORT 环境变量换端口`)。 可用 `AUTO_FREE_PORT=false` 关闭自动结束(只报错)。实现见 `backend/src/utils/port.ts`,随打包进入字节码。 平台差异由同一份代码内部分流: | | Windows | Linux(Ubuntu)/ macOS | |---|---|---| | 定位占用进程 | `netstat -ano` | 扫描 `/proc/net/tcp(6)` + `/proc//fd`(**不依赖 lsof/ss**,最小化镜像可用),取不到再降级 `lsof` → `ss` | | 读进程名 | `tasklist` | `/proc//comm` + `/proc//cmdline`,降级 `ps` | | 结束进程 | `taskkill /F /T` | Node 内建 `process.kill`:先 **SIGTERM** 优雅退出(最长等 1.5s),未释放再升级 **SIGKILL** | Linux 下若占用进程属于其他用户/容器外部,普通用户无法定位,会提示改用 sudo 或换端口。 已在 Ubuntu 24.04(WSL)实测 7 个场景:IPv4/IPv6 旧实例接管、SIGTERM→SIGKILL 升级、非 Node 进程拒绝且不误杀、空闲放行、`AUTO_FREE_PORT=false` 只报错。 - 前端 `www/assets/*.js` 是浏览器必需的静态资源(浏览器无法执行 `.so`/字节码,且前端代码本就下发到客户浏览器),不属于后端代码泄露范畴。 ## 必须遵守的业务红线(详见 AGENTS.md / docs/decisions.md) 1. **五类价格分离**:市场参考价 / 采购成本 / 内部最低可成交价 / 对外咨询参考价 / 正式报价。客户、机器人、业务不见成本与底价;BOM 客户报告/导出只见对外咨询参考价。 2. **职责分离**:采购定价、业务沟通、财务核款、客户收货,后端强制校验;AI/机器人不承诺成交供货积分、不付款、不改价。 3. **唯一积分引擎**:三方确认(客户全收 + 业务交付 + 财务全额到账)后一次性、幂等发放;90 天无完成交易到期。 4. **五次出价与暂停**:企业+产品+轮次跨渠道合并计数,重建 RFQ/换员工不绕过。 5. **版本化与有效期**:价格/报价/BOM/积分规则版本化;过期报价签回不生订单。 6. **渠道白名单与人工降级**:未验证能力不模拟成功,“任务创建”不等于“已送达”。 7. 金额禁浮点;BOM/聊天/备注为不可信输入,防公式注入与提示词注入。 8. 当前所有积分比例、折抵、时效参数均为**测试草案·未批准**,不得作为对外商业承诺。 ## 文档索引 - [docs/decisions.md](docs/decisions.md):架构与业务决策、未决参数清单 - [docs/data-model.md](docs/data-model.md):数据模型(按业务域) - [docs/api-spec.yaml](docs/api-spec.yaml):HTTP API(OpenAPI 3) - [docs/test-cases.md](docs/test-cases.md):AT ↔ 自动化测试映射 - [docs/channel-capabilities.md](docs/channel-capabilities.md):渠道能力白名单与治理 ## 已知边界(POC/占位) - 微信各能力、对象存储、供应商正式系统为显式 mock/占位,正式环境禁止伪造成功响应。 - 前端暂无浏览器自动化测试;价格自动监测、AI 大模型为“待后台任务/未接入”占位。 - 多币种未开放(当前仅 CNY)。