# AllApp 团队技术提升方案 > 由 Senior Developer (高级开发工程师) 基于全量代码审查制定 | 2026-07-04 --- ## 一、现状评估总览 基于对 `app-go/`(Go 后端)和 `app-rn/`(React Native 前端)的全面代码审查,以下是当前技术水平的综合评估: | 维度 | 评分 | 说明 | |------|------|------| | 项目架构设计 | ★★★★☆ | 通用数据 API + 文件路由 + 三层布局,设计思路清晰 | | 代码规范一致性 | ★★★☆☆ | 有 CODE_STYLE.md 但部分规则未严格执行 | | 类型安全 | ★★★☆☆ | strict 模式开启但 `any` 泛滥 | | 测试覆盖 | ★☆☆☆☆ | **零测试**,前后端均无测试文件 | | 工程化工具链 | ★★☆☆☆ | Go 无 linter;前端有 oxlint+oxfmt | | 错误处理 | ★★★☆☆ | Handler 层一致,DB 层缺失 | | 代码复用 | ★★☆☆☆ | 存在大量重复代码(sotre 16个相似方法、Layout 60% 重复) | | 安全性 | ★★☆☆☆ | SQL 注入风险、用户存在性泄漏、测试代码泄漏到生产 | --- ## 二、优先修复清单(按紧急程度) ### 🔴 P0 — 本周必须修复 #### P0-1: SQL 注入风险 — `LoadData`/`LoadDataPage` 参数直接拼接 **问题定位**:`app-go/pkg/db/select.go:37-43,75-99` ```go // 当前代码(有风险) sql := fmt.Sprintf( "SELECT %s FROM %s%s%s LIMIT %d OFFSET %d", selectCols, viewName, where, order, pageSize, offset, ) ``` **修复方案**:对 `viewName` 强制校验,对 `orderBy` 做白名单,LIMIT/OFFSET 参数化: ```go func (c *Client) LoadData(req LoadDataReq) (*LoadDataResp, error) { // 1. 表名白名单校验 safeViewName, err := quoteTable(req.ViewName) if err != nil { return nil, fmt.Errorf("invalid view name: %w", err) } // 2. 排序字段白名单校验 safeOrderBy, safeOrderDir, err := validateOrderBy(req.OrderBy, req.SearchColumns) if err != nil { return nil, fmt.Errorf("invalid order by: %w", err) } // 3. LIMIT/OFFSET 使用参数化 sql := fmt.Sprintf( "SELECT %s FROM %s%s%s LIMIT $%d OFFSET $%d", selectCols, safeViewName, where, safeOrderBy, paramIdx, paramIdx+1, ) args = append(args, pageSize, offset) // ... } ``` #### P0-2: 生产代码中的测试登录入口 **问题定位**:`app-rn/src/app/(main)/auth/login.tsx:196-238` ```tsx // 当前代码 — 测试按钮暴露在生产构建中 handleTestLogin("test1")}> 测试用户1 handleTestLogin("test2")}> 测试用户2 ``` **修复方案**:使用 `__DEV__` 条件编译: ```tsx {__DEV__ && ( [DEV ONLY] 测试登录 )} ``` #### P0-3: `validate.go` 用 panic 替代 error 返回 **问题定位**:`app-go/pkg/db/validate.go:22,32` ```go // 当前代码 — panic 会导致整个请求崩溃 func quoteTable(table string) string { if !validTableName.MatchString(table) { panic(fmt.Sprintf("invalid table: %s", table)) // 危险! } return fmt.Sprintf(`"%s"`, table) } ``` **修复方案**:改为返回 error,让调用方决策: ```go func quoteTable(table string) (string, error) { if !validTableName.MatchString(table) { return "", fmt.Errorf("invalid table name: %s", table) } return fmt.Sprintf(`"%s"`, table), nil } ``` --- ### 🟡 P1 — 本月必须推进 #### P1-1: 零测试 → 建立测试基础设施 **Go 后端**: ```go // pkg/db/validate_test.go — 先测试纯函数 func TestQuoteTable(t *testing.T) { tests := []struct { name string input string want string wantErr bool }{ {"valid simple", "users", `"users"`, false}, {"valid with underscore", "b_user", `"b_user"`, false}, {"sql injection attempt", "users; DROP TABLE", "", true}, {"empty", "", "", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := quoteTable(tt.input) if tt.wantErr { require.Error(t, err) return } require.NoError(t, err) assert.Equal(t, tt.want, got) }) } } ``` **前端**:配置 jest + @testing-library/react-native ```bash cd app-rn pnpm add -D jest @testing-library/react-native @testing-library/jest-native ``` 第一个测试:`src/hooks/__tests__/useLoading.test.ts` #### P1-2: Go 后端 Linter 配置 创建 `app-go/.golangci.yml`: ```yaml linters: enable: - errcheck - gosimple - govet - ineffassign - staticcheck - unused - bodyclose - gofmt - goimports - revive - gocritic linters-settings: revive: rules: - name: exported severity: warning run: timeout: 3m issues: exclude-use-default: false ``` #### P1-3: 消除巨型文件 | 文件 | 当前行数 | 目标行数 | 拆分方案 | |------|----------|----------|----------| | `chat/index.tsx` | 718 | ≤300 | 提取 `useChatScroll`、`useChatSend`、`ChatMessageBubble` 组件 | | `store/clothing.ts` | 473 | ≤200 | 拆为 `useClothingData` + `useClothingMutations` | | `store/meal.ts` | 477 | ≤200 | 同上 | | `handle/auth.go` | 524 | ≤300 | 拆出 `bind.go`、`user_helper.go` | #### P1-4: 消除代码重复 **1) Store 保存方法工厂化**(消除 16 个重复方法): ```typescript // src/store/helpers.ts — 通用工厂 export function createSaveChanges>( tableName: string ) { return async ( changes: { inserts?: Partial[]; updates?: Partial[]; deletes?: Pick[] } ): Promise => { const res = await saveDataApi([{ table_name: tableName, key_field: "id", ...normalizeChanges(changes), }]); return res.isSuccess; }; } // 使用 const saveClothesChanges = createSaveChanges("b_clothing"); const saveOutfitChanges = createSaveChanges("b_clothing_outfit"); ``` **2) Layout 公共逻辑抽取**(消除 AppLayout/ModuleLayout 60% 重复): ```typescript // src/hooks/useActiveTab.ts export function useActiveTab( tabs: TabbarItem[], pathname: string ): TabbarItem | undefined { const lastValidRef = useRef(); return useMemo(() => { const found = tabs.find((t) => t.id === pathname); if (found?.isCenter) return lastValidRef.current; const valid = found ?? lastValidRef.current; if (found) lastValidRef.current = found; return valid; }, [pathname, tabs]); } ``` #### P1-5: `any` 类型专项清理 **优先级**:先清 API 层,再清 Store 层,最后清页面层 ```typescript // src/request/api.ts — 添泛型约束 export async function loadDataApi>( params: LoadDataParams ): Promise> { ... } export async function loadDataPageApi>( params: LoadDataPageParams ): Promise> { ... } ``` --- ### 🟢 P2 — 本季度持续优化 #### P2-1: 一致性改进 - 统一版本号策略(全部用 `^` 或 exact version) - 统一 className 拼接方式(全部用 `cn()`,禁模板字符串拼接) - 统一颜色引用(使用 Tailwind 主题变量,禁硬编码 `#FFFFFF`) - DB 层统一使用 `c.Exec/c.Query` 而非直接访问 `c.pool` #### P2-2: 工程化增强 - `package.json` 添加 `"type-check": "tsc --noEmit"` 脚本 - 添加 pre-commit hook(lint-staged + oxfmt + oxlint) - S3 依赖瘦身(评估 `minio-go` 替代 aws-sdk-go-v2) - 添加 `noUncheckedIndexedAccess` 到 tsconfig #### P2-3: 架构清理 - 评估 `@gorhom/bottom-sheet` vs 自建 BottomSheet,二选一 - `request/index.ts` 中第二个 alova 实例独立抽取 - 清理 tsconfig 中的无效路径引用 --- ## 三、团队工作流改进 ### 3.1 Code Review 制度 ``` 提交前自检清单(每位开发者): □ TypeScript 无 any(除特殊场景加注释说明) □ 异步操作使用 useLoading + LoadingOverlay □ 新页面使用 PageLayout/ModuleLayout 包裹 □ 无硬编码颜色值 □ 无 console.log/print 残留 □ 文件不超过 300 行(超过需拆分) ``` ### 3.2 Git 提交规范 ``` feat: 新功能 fix: 修复 bug refactor: 重构(不改变功能) style: 格式调整 test: 添加测试 chore: 构建/工具链变更 ``` ### 3.3 CI 流水线建议 ```yaml # .github/workflows/ci.yml jobs: backend: - golangci-lint run - go test ./... - go build ./cmd/app frontend: - pnpm lint - pnpm exec tsc --noEmit - pnpm test -- --passWithNoTests # 过渡期 ``` ### 3.4 技术债看板 建议在 TAPD/飞书多维表格中维护技术债看板: | 状态 | 内容 | |------|------| | 待处理 | 状态列为"Known Issues"中提到但未修复的项目 | | 处理中 | 当前 Sprint 在修的技术债 | | 已修复 | 已验证修复合入主分支 | --- ## 四、团队能力建设路线图 ### 第一阶段(1-2 周):止血 - [x] 修复 P0-1 SQL 注入 - [x] 修复 P0-2 测试代码泄漏 - [x] 修复 P0-3 panic → error - [ ] 搭建 Go linter + 修复现有警告 - [ ] 搭建前端测试基础设施(jest 配置 + 第一个测试用例) ### 第二阶段(3-4 周):夯实 - [ ] 完成 P1-3 巨型文件拆分 - [ ] 完成 P1-4 代码重复消除 - [ ] 完成 P1-5 `any` 类型第一阶段清理(API 层 + Store 层) - [ ] 添加 `type-check` 到 CI - [ ] 建立 Code Review checklist ### 第三阶段(2-3 月):精进 - [ ] 测试覆盖率达到 30%+ - [ ] 完成 P2 各项一致性改进 - [ ] 引入性能监控(前端 FPS 监控、后端 p99 延迟) - [ ] 技术分享制度(每两周一次,轮流分享) ### 第四阶段(3-6 月):卓越 - [ ] 测试覆盖率达到 60%+ - [ ] 暗黑模式完整支持 - [ ] 无障碍(a11y)合规 - [ ] 性能基准测试 + 回归监控 - [ ] 建立内部组件库文档 --- ## 五、推荐学习资源 ### Go 后端 - **测试**:[Learn Go with Tests](https://quii.gitbook.io/learn-go-with-tests/) - **项目结构**:[Standard Go Project Layout](https://github.com/golang-standards/project-layout) - **错误处理**:`pkg/errors` 最佳实践 - **SQL 安全**:OWASP SQL Injection Prevention Cheat Sheet ### React Native 前端 - **TypeScript 深入**:[TypeScript Deep Dive](https://basarat.gitbook.io/typescript/) - **Zustand 最佳实践**:[Zustand Guide](https://docs.pmnd.rs/zustand/guides/practice-with-no-store-actions) - **React Native 性能**:[React Native Performance Guide](https://reactnative.dev/docs/performance) - **测试**:[Testing Library Recipes](https://callstack.github.io/react-native-testing-library/) --- ## 六、关键指标跟踪 | 指标 | 当前值 | 1月目标 | 3月目标 | |------|--------|---------|---------| | Go 测试覆盖率 | 0% | 15% | 30% | | 前端测试文件数 | 0 | 5 | 15 | | `any` 类型数量 | 100+ | 减少 50% | 减少 80% | | 文件超过 300 行 | 5 | 2 | 0 | | Golangci-lint 警告 | 未统计 | 0 | 0 | | CI 通过时间 | 无 CI | < 3min | < 2min | --- > **总结**:项目架构设计思路清晰,规范文档也写得不错,当前主要短板在于 **工程化工具链缺失**(无 linter/无测试/无 CI)和 **代码纪律不足**(any 滥用、巨型文件、重复代码)。前两周集中"止血",之后两个月持续推进,三个月内可以达到较为成熟的中等偏上水平。 有任何具体项需要我深入协助实施的,随时告诉我!