# 服务端规范(两类云函数与 api/ 模块) > 定位:FmodeStudio 项目中"后端"由平台能力承担:Parse Server 托管数据与鉴权,特殊逻辑走两类云函数(概念与用法不同,务必区分)或 api/ 自定义路由模块。 ## 负面清单(Do Not) - [禁止] 动态云函数代码中不定义 handler(request, response) 函数 - [禁止] 云函数/api 路由中硬编码密钥、远程地址、魔法数值 - [禁止] 未校验入参直接使用(前端校验只是体验,服务端必须二次校验) - [禁止] 向客户端返回原始错误堆栈(生产环境) - [禁止] 吞错误(裸 catch 无处理)或让异步异常静默 - [禁止] 字符串拼接查询条件(SQL 注入;Parse 查询 API 天然参数化) - [禁止] 把 masterKey/数据库密码写入前端或 api/ 代码(仅 config.json 与服务端) ## 两类云函数区别(速览) - **Parse Cloud Code**:项目文件 apps/server/cloud/main.js,Parse.Cloud.define('name', handler) 定义,随项目代码一起部署,前端 Parse.Cloud.run('name', params) 调用,运行于 Parse Server 进程,全局注入 Parse/globalThis.Psql;模式 A 自动支持,模式 B 需手动加载 cloud/main.js。 - **动态云函数(fmode-functions-api)**:代码存 Parse DB Function 表 code 字段(必须含 handler),写入即即时生效,同名 Parse.Cloud.run 调用或 POST /api/functions,沙箱 new Function() 动态执行,注入 Parse/Psql/request.user/company/account;模式 A 内置支持,模式 B 需手动引入 fmode-functions-api 模块。 ## 必须规则(Parse Cloud Code) 1. **[必须] 定义与组织**:云函数用 Parse.Cloud.define('name', async (req) => {...});数据钩子用 Parse.Cloud.beforeSave/afterSave;入口 apps/server/cloud/main.js(config.json 的 cloud 字段指定),拆分模块放 cloud/providers/ 由 main.js 统一加载。 2. **[必须] 入参与权限**:入参从 req.params 读取并校验;权限用 requireUser/requireMaster/requireAnyUserRoles 或显式 useMasterKey;业务错误 throw new Parse.Error(code, message);超时约 15 秒,长任务用 Job 或 Express 路由。 3. **[必须] 适用场景**:数据校验钩子(beforeSave/afterSave)、简单聚合查询、需随项目代码版本管理的服务端逻辑;纯数据强校验业务(订单提交/考核提交等)走云函数。 ## 必须规则(动态云函数) 4. **[必须] Function 表结构**:函数存 Parse DB Function 表——name(函数名)/desc/type(standalone 独立/trigger 触发器/job 后台/schedule 定时)/code(函数源码,必须包含 handler)/respType(json/stream 等)/path(配合 pid 调用)/pid(Pointer→Project 所属项目)。 5. **[必须] 编写规范**:代码必须定义 async function handler(request, response)——前端参数从 request.body.params 读取;自动注入 Parse(SDK 数据库操作)/Psql(PostgreSQL 直连)/request.user(当前登录用户,需传 token)/request.company(当前用户关联公司)/request.account(当前账户);无 request.user 时 return response.status(401).json({ error: '需要登录' });输出统一 response.json({ success: true, data }),禁止手拼不规范 JSON。 6. **[必须] 调用方式**:前端与 Parse Cloud Code 同名调用 Parse.Cloud.run('functionName', params);HTTP 直调 POST /api/functions(body: token + id(云函数 objectId)+ params,或 pid + path + params)。 7. **[必须] 适用场景**:需即时生效、不重启服务器的接口;用户自定义业务逻辑;复杂事务、第三方对接;多项目共享的通用接口。选择指南——数据钩子/简单聚合 → Parse Cloud Code;即时生效/自定义业务 → 动态云函数;多项目复用/独立服务 → api/ 模块。 ## 必须规则(api/ 自定义路由模块) 8. **[必须] 目录约定与自动发现**:apps/server/api/module//routes.ts → /api/,routes-.ts → /api//;桶文件 apps/server/api/routes.ts import 所有子模块并 router.use() 挂载,新增子模块必须同步登记。 9. **[必须] 路由写法**:子模块 export default express.Router();路由内取 const Parse = (globalThis as any).Parse 做数据操作;服务端操作默认 useMasterKey: true(避免 CLP/ACL 权限问题);入参必须校验;XSS 入参 sanitize、输出编码;禁止 SQL 拼接(Parse 查询 API 天然参数化)。 10. **[必须] 统一错误处理**:api 路由错误统一 try-catch → res.status(语义码).json({ success: false, message });生产环境隐藏堆栈、开发保留;日志脱敏(密码/token/手机号/身份证一律掩码)。 11. **[必须] 适用场景**:第三方对接(飞书/企业微信等)、SSE/WS 长连接、AI 流式、独立服务接口。 ## 必须规则(认证与全局) 12. **[必须] 会话传递**:前端登录后获取 sessionToken,请求经 Authorization: Bearer 传递;云函数/路由凭 token 识别 request.user。 13. **[必须] 多租户约束**:业务表必须含 company: Pointer;查询默认按当前 company 过滤;仅管理员操作可用 useMasterKey: true 绕过租户限制。 14. **[必须] 全局注入认知**:globalThis.Parse(Parse JS SDK,增删改查)/globalThis.Psql(pg-promise,直接 SQL)/globalThis.appConfig(config.json 完整配置)/globalThis.loadModule(url)/loadCdnModule(url)(fmode-server 动态加载 CDN/NPM/本地 modules/ 模块,模式 B 需手动实现或跳过)。 15. **[必须] parse-server 8 集成注意**:构造签名只在默认导出(`import ParseServer from 'parse-server'`);parse@7 服务端 `Parse._initialize(appId, '', masterKey)` 仅 2 参,且服务端禁用 Parse.User.become(内存安全,改 Parse.User.me);`parse/node` 子路径无类型声明,需项目内 d.ts 环境桥接(如 types/parse-node.d.ts);Parse Server 8 必须 `await parseServer.start()`——不 await 则状态停留 initialized、所有 /parse 请求 500 且 cloud/main.js 不加载。