这是过去半年(2025年底 - 2026年中)所有付出代价才学到的教训,按主题分类。新人入职先扫一遍标题,遇到对应场景再回来读细节,能省一周。
不是运行时读 process.env。改完必须重启 dev server / 重新构建。
Why:Webpack 会在 build 阶段把 process.env.NEXT_PUBLIC_FOO 静态替换成字面量。
How:需要运行时动态读取(极少场景)用 process.env[key] 字符串索引绕过 webpack。
NEXT_PUBLIC_* 在 fly.toml 的 [build.args] 写了不够 —— GHA 用 docker/build-push-action 独立构建,fly.toml 不生效。
Why:fly.toml 只对本地 flyctl deploy 生效;CI 走的是独立 docker build。
How:每次新增 NEXT_PUBLIC_* 必须改两处。换 token 同理:本地 + GHA secrets + fly.toml + workflow build-args 四处全改。
workflow 里写 ${{ secrets.FOO }} 不代表 FOO 存在。会静默用空值。
How:必须 gh secret list 确认存在再触发;不要相信 workflow 文件。
Better Auth 的 session.user.id 是 text,业务表的 userId 是 UUID,混用 postgres 直接拒绝并 500 + 泄露 SQL 到浏览器。
How:查 orders / messagesV2 / subscriptions 等任何 UUID 列前,先翻译成 businessUser.id。已加 Branded Types 编译期防御。
Better Auth 的 session_data 手工构造必失败。只设 session_token,让框架自己处理。
Why:Android Google 登录修了三轮(clientId 字段名 → cookie 前缀 → session_data 格式),根因就是手动模拟内部 cookie。
同功能修 2 轮以上,停下读 node_modules 源码。逐层猜会无限循环。
Fly 部署仅启动新容器。新 migration 必须在 fly.toml release_command 或 GHA workflow 显式调 pnpm db:migrate。
Why:PR 合并后线上 schema 静默落后,下次访问 42703 直接崩。
How:schema drift 时查 information_schema 定位缺失列;手工补 DDL + INSERT __drizzle_migrations 后再跑 db:migrate。
其他表 snake_case,messagesV2 是历史遗留 camelCase。原生 SQL 必须对齐实际列名。
sql\`... \${date}\` 透传 Date 给 postgres driver 会 ERR_INVALID_ARG_TYPE。
How:用 gt / lt helper,或显式 date.toISOString()。
TypeScript non-nullable 声明不保证运行时安全。hotVideo 等可空字段必须加 || '' guard。
Capacitor 6+ 依赖 Java 21 source。默认 macOS 是 JDK 17,gradle 报 invalid source release。
Capacitor Google Auth 插件只读 clientId,不是 serverClientId。配错返回 DEVELOPER_ERROR / 账号选择器立即 cancel。
原生 flags 未就绪时 React 已经渲染。需延迟重试 + React 二次确认。
upload-keystore.jks + keystore.properties,alias upload。丢了无法更新应用。备份位置见记忆库。
禁止覆盖 latest.apk。Cloudflare 缓存 7+ 天,覆盖会让用户拿不到新版。
Airwallex SDK 加载失败 → URL 直跳;整体不可用 → Stripe 兜底。三级降级是硬要求。
所有折扣 / 价格 / 优惠必须从 src/config/ 动态读取,不能 hardcode「70% OFF」之类字面量。2026-03-29 已全部清理。
payment_success / payment_failed 必须在 webhook 用 posthog-node 打,不能只靠前端 redirect 时打。
付费弹窗历史 bug。改 drawer 时确认 snapPoints[index] 不越界。
角色为空 → 推送选不出对象 → 用户收不到。空角色 + 在线用户 + 角色数都需要降级路径。
不要全部走 OneSignal,在线用户 SSE 直接推到 /new-chat,体验更好。
2026-04-09 上线,日推送量降 60%。频率按用户活跃度分层 + 视频问句 + 首条文字优化。
generate.message.ts 必须包 Langfuse trace(含 flushAsync)。否则成本归因不准。
正常结束和 catch 块都要 await langfuse.flushAsync(),否则数据丢失。
US 区账号 fallback URL 必须是 us.cloud.langfuse.com,欧区地址返回 401。
Opus 等模型返回 JSON 时可能带 \`\`\`json 包裹,直接 parse 抛异常。先剥 fence 再 parse。
inputTokens / outputTokens / totalTokens 替代旧的 promptTokens / completionTokens;useChat onFinish 用 message 不是 responseMessage。
降级模型不能比主模型贵。轻量任务用最便宜的模型(如 x-ai/grok-4-fast)。
2026-04-13 Google 以 ToS 违反封了。降级 / 轻量模型全部切到 x-ai/grok-4-fast。
不做就数据永远匿名 + 跨用户污染。
payment_success 等转化事件必须在 webhook 用 posthog-node 打,前端只是兜底。
{event:String} 报错时改用白名单校验 + inline。
浏览器端 / Node 端 / Worker 端三套。混淆会导致事件归错项目。
2026-04-07 删 dev 项目(9129 噪音 errors)。生产用 javascript-nextjs。注意 org slug 是 softieai 有 typo。
sentry.client.config.ts + withSentryConfig 包装,DSN 走 build args。少一步浏览器错误就监控不到。
null guard / Android 守卫 / DB try-catch / 噪音过滤。否则 Issues by Frequency 全是噪音。
Depot 会让 internal 网络失败。
命令可能不持久;事后 fly status 确认。
同 app 可有不同规格 machine。统计必须逐台求和,禁止 machines[0] × count。
BuildKit mount cache 在 CI 无效。用 cache-from/cache-to: type=gha。
256MB 会 OOM 崩溃。
禁止纯文本 / post 格式。颜色按类型:indigo(技术)/ red(告警)/ green(成功)/ orange(注意)/ blue(信息)。
Lark 不渲染。结构化数据用 column_set 多列布局。
用 --dry-run 验证;调通后只发一次。反复发会骚扰群成员。
不要猜 Webhook 归属。先查记忆库 reference_lark_webhooks.md。
tsgkcplyz3ky.sg.larksuite.com,禁止 feishu.cn。
CDN 缓存必须在 Cloudflare 侧 override。
子页改无效,要从根布局改。
用原生 <script> 替代。
Fly.io 1GB RAM + PostHog autocapture off + DB pool 10 + 根布局去 headers()。
www.softie.ai 开橙云 + Cache Rule,匿名用户 TTFB 从 ~200ms 降到 ~30ms。
搜 GitHub 同类项目了解行业标准(Character Card V2、SillyTavern 等)再动手。
viewport 360×640 + scaleFactor 3,别直接 1080×1920 会走桌面布局。
否则 CI 静默失败阻塞部署。
新增 helper / service 合并前必须 grep 至少一处 import,否则成 24h 死代码。extractMemoryAnchors 就是从定义到接入隔了 24h。
不假设功能正常,先 curl / 浏览器确认现状再下手。
DB / Redis / API probe 几乎与 Sentry 冗余。先识别真正盲区再动手。
独立脚本 + 只读 + continue-on-error,不动生产代码路径。
create node 会创建空文档,不会引用已有的。
四模块并行审查 + 6 种高频 bug 模式清单(详见记忆库 feedback_bug_hunting_methodology.md)。
Route A 决策 2026-04-11:API 忽略前端 isPrivate,UGC 角色一律 private;移除编辑 5 Sparks 费用;Profile 加 My Characters 入口。
仓库配置 + 控制台 GitHub 连接 + 旧平台独有功能替代,缺一会留影子部署。Vercel 那次就是没卸 GitHub App,2026-04 又意外部署了一份。
目标美国市场。UI 不能有中文残留,包括占位文本、错误提示、空状态等。
这页不是用来一次读完的。建议:
~/.claude/projects/-Users-gloom-softieweb/memory/,下一个新人就少踩一个