PostHog 前端 QA 实战指南:开发堆栈就绪检查(Stack Readiness)与登录(Login)流程
【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog
本篇技术指南以 PostHog 仓库内qa-frontend技能链的核心参考文档 stack-and-login.md 为骨架,系统讲解在进行浏览器前端 QA(Browser QA)前,如何判断本地 PostHog 开发堆栈是否可用、何时以及如何启动堆栈,以及如何安全地登录测试账号与准备隔离测试工作区。读完本篇,你将掌握一整套可复制的"堆栈复用 → 健康检查 → 审批启动 → 登录鉴权"流程,并理解其背后的仓库源码与安全边界,可直接应用于 PR 模式与本地模式的 PostHog 前端回归验证。
背景:stack-and-login 在 QA 流程中的角色
PostHog 仓库在 .agents/skills/qa-frontend/SKILL.md 中定义了一套完整的仓库内前端 QA 技能(/qa-frontend),它运行在一个有界的前端 QA 循环里,支持两种模式:
- PR 模式:用户提供 PR 引用(URL、编号或分支),技能检出 PR 后执行 QA,经批准后上传证据并发布 PR 评论,要求工作树干净。
- 本地模式:针对当前检出内容与未提交改动进行 QA,报告只写本地,不上传、不评论、不推送,允许脏工作树。
无论哪种模式,进入 Checkout、Diff 分析、浏览器执行之前,都必须先通过堆栈就绪与登录这道门。这正是 stack-and-login.md 的职责:它全权负责BASE_URL、STACK_STARTED_BY_AGENT、对仓库内run-posthog技能的委托、phrocs 进程检查、启动审批规则,以及登录/测试工作区的处理。SKILL.md 明确要求:"Do not checkout, edit, upload, comment, or push until it confirms the local PostHog stack is reachable enough for the planned QA target"——未通过就绪检查前,一切后续动作都被禁止。
一、堆栈就绪(Stack Readiness)
1.1 环境变量基线:BASE_URL 与 STACK_STARTED_BY_AGENT
在开始任何检查之前,先设置两个关键环境变量:
BASE_URL="${BASE_URL:-http://localhost:8010}" STACK_STARTED_BY_AGENT=0BASE_URL是浏览器 QA 实际访问的入口。默认值http://localhost:8010是 PostHog 开发堆栈的 Envoy 风格代理地址:它把/static/*反代到 Vite(开发服务器实际运行在:8234),其余流量反代给 Django,因此浏览器始终浏览 8010 端口,直接访问 Vite 的 8234 端口会因无索引路由而 404(详见 .agents/skills/run-posthog/SKILL.md 的 Gotchas 一节)。STACK_STARTED_BY_AGENT是一个归属标记:只有当你(Agent)获得用户批准并实际启动了堆栈时才置为1,其核心约束是只允许停止自己启动的那个堆栈,且只能在清理阶段或获得用户批准后进行。
1.2 核心原则:复用用户现有堆栈
文档强调的第一条原则是:默认复用用户已有的环境,不要因为你要跑 QA 就去启动、重启或替换开发堆栈。动作顺序是:
- 先检查
BASE_URL处 PostHog 是否已经可达; - 若可达,直接继续,不要启动、重启、替换或等待另一个堆栈;
- 若不可达,再考虑启动流程(见 1.5 启动审批)。
这一原则与 .agents/skills/qa-frontend/references/safety-rules.md 中的"Local Stack Control"章节一致:BASE_URL已可达时禁止另起炉灶,且"启动、停止、重启本地 PostHog 开发堆栈"本身属于必须获得当前会话内明确批准(explicit approval)的动作。
1.3 模式差异:PR 模式与本地模式的堆栈要求
堆栈选择还取决于运行模式:
- PR 模式:优先让 PR 的代码在开发者机器之外执行——例如通过远程 devbox 提供
BASE_URL转发端口(仓库的setting-up-devbox技能覆盖了如何配置一个 devbox)。因为 PR 模式会在本地堆栈上执行 PR 作者的代码(Python 与 JavaScript),等于以运行者权限运行他人的代码;若要在开发者自己机器上跑 PR 代码,必须取得 safety-rules.md 中描述的显式批准,并明确告知"这将在你的机器上执行 <作者> 的代码"。 - 本地模式:测试的是开发者自己的代码,没有上述门槛。
另外,仓库内还存在 git hook 风险:PostHog 跟踪.husky/post-checkout、pre-commit、pre-push,且core.hooksPath指向它们。因此 PR 模式检出时必须导出GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=core.hooksPath GIT_CONFIG_VALUE_0=/dev/null,防止检出时执行 PR 控制的 hook(见 SKILL.md 的 Checkout 章节)。
当仓库内存在 .agents/skills/run-posthog/SKILL.md 时,以它的当前就绪检查、phrocs 进程指引和setup_test/登录配方为唯一事实来源(source of truth);stack-and-login 参考文档只额外附加 QA 专属约束:用户堆栈可用就复用、启动/重启 PostHog 前先询问、只停止自己启动的堆栈。
1.4 可达性检查:curl 探测与 phrocs MCP 进程检查
对BASE_URL执行两条最小健康检查命令:
curl -sf --max-time 5 "$BASE_URL/_health" curl -sf --max-time 10 -o /dev/null -w '%{http_code}' "$BASE_URL/"- 第一条探测
/_health端点,-f让 HTTP 错误直接表现为命令失败,--max-time 5限制超时为 5 秒; - 第二条对根路径发起请求,只输出 HTTP 状态码(期望 200 或 302)。
若两条检查显示应用可达,就直接继续,不再折腾其他堆栈。若失败,则使用可用的本地健康检查手段,例如当 phrocs 已在运行时调用其 MCP 工具:
mcp__phrocs__get_process_status(process="backend")mcp__phrocs__get_process_status(process="frontend")
在 .agents/skills/run-posthog/SKILL.md 中还有更完整的就绪条(readiness bars):backend与frontend是 UI QA 的硬性门槛(hard gates),只有目标路由还需要mcp、feature-flags、nodejs、capture或ingestion等单元时才追加检查。对于 HogQL 支撑的场景(insights、dashboards、web analytics)以及POST /api/setup_test/...,还额外要求migrate-clickhouse进程显示status:"done" exit_code:0。
1.5 目标路由就绪比全栈健康更重要
文档给出了一个关键判断:"可达"不等于"在服务你的检出内容"。BASE_URL可能是转发到远程堆栈(如 Coder devbox)的地址,而转发堆栈可能滞后于或偏离本地工作树。因此,在开始针对 diff 的验证或变更状态(登录、主题切换、种子数据)之前,必须确认堆栈确实在运行被测代码:打开一个被改动过的界面、确认改动已呈现,若堆栈同步有延迟则短暂重试。
数据播种(seeding)也必须对准浏览器实际对话的那个堆栈——本地执行manage.py shell写的是本地数据库,当BASE_URL转发到远程堆栈时这显然是错误的目标。播种应在提供BASE_URL的堆栈上进行,否则就记录一个 coverage gap。
对浏览器 QA 而言,目标路由就绪是比"本地全栈绿灯"更强的证据:改动后的 UI 能加载、分支/SHA 或其他 diff 内标记与在测代码一致、路由关键 API 可用。无关的降级单元记入run-notes.md即可,不必为了一个可用目标路由去追逐全栈健康。
1.6 启动流程与审批门槛
当 PostHog 不可达时,顺序如下:
- 先查用户记忆/设置与本地偏好,再查仓库指引及
AGENTS.md等邻近文档中推荐的启动方式; - 在启动 PostHog 之前询问用户希望如何处理;
- 若目录与命令都很明确,可以提出具体的启动路径建议(包括是交互式还是后台运行),但要明确标注这是待确认的推断;若目录、命令、
BASE_URL或启动方式不明确,则直接询问用户希望在哪里、以何种方式运行堆栈,或是否改用其他BASE_URL; - 在聊天中提问并停止等待用户回答。沙箱升级提示、命令批准对话框或已被批准的指令前缀都不等于工作流批准——它们只在你选定 agent 托管启动后才授权某条命令执行。
若用户批准 agent 托管启动,则:
- 优先使用仓库常规的后台堆栈:对新/已停止的 devbox 用
hogli devbox:start --start-app;对服务BASE_URL的检出目录用hogli up -d -y。hogli dev:*系列仅用于理解不清晰的路由依赖。 - 运行已批准的启动路径,并设置
STACK_STARTED_BY_AGENT=1。 - 若命令因 shell 缺少仓库依赖或全局命令不在
PATH上而失败,遵循仓库对同一启动意图的指引(例如仓库本地包装脚本或flox这类环境包装器),并宣告这一回退。 - 在切换检出、目录、启动模式、删除锁文件或启动不同堆栈之前,再次询问。
- 无头(headless)Agent 会话中避免交互式终端 UI,除非用户明确要求。
- 只停止自己启动的堆栈,且仅在清理阶段或用户批准后进行。
启动之后,重复run-posthog的应用可达性检查(若该技能不可用,则用 1.4 的最小检查),并查询相关进程状态:backend、frontend,以及与改动表面直接相关的进程(例如测试 MCP 改动时的mcp)。只有应用可达且所需进程集就绪,才允许继续;backend 或 frontend 未就绪时,必须在检出、编辑、上传、评论或推送之前停止。
日志获取的优先级:优先使用 phrocs MCP 日志——mcp__phrocs__get_process_logs(process="backend")与mcp__phrocs__get_process_logs(process="frontend");仅当 phrocs MCP 不可用时,回退到仓库本地日志目录.posthog/.generated/logs/。
二、登录(Login)
2.1 两条登录路径:setup_test 隔离工作区 vs 种子默认账号
文档给出两条登录路径,按需选择:
路径 A:需要真实数据或隔离工作区时,使用run-posthog的POST /api/setup_test/organization_with_team/配方。在浏览器页面上下文中调用它,然后用返回的user_email与固定密码12345678从页面上下文登录;构造路由时使用返回的team_id:/project/{team_id}/...。文档强调这是前端 QA 的准备工作,不是独立的后端/API 测试。
路径 B:不需要专用工作区时,默认使用公开的 PostHog 本地开发种子账号:test@posthog.com/12345678。这两个凭据记录在 docs/published/handbook/engineering/manual-dev-setup.md("The first time you run the app, you can log in with a test account: usertest@posthog.compwd12345678"),由bin/start播种。它们只存在于以该方式播种的开发堆栈上(笔记本堆栈或个人 devbox),因此回退到它们是安全的。
2.2 源码佐证:setup_test 端点的实现与门槛
setup_test端点的实现位于 posthog/api/playwright_setup.py:它是一个仅接受POST的 DRF 视图,permission_classes([AllowAny]),通过test_name路由参数从posthog.test.playwright_setup_functions中注册的PLAYWRIGHT_SETUP_FUNCTIONS字典里选取对应的 setup 函数。关键安全门槛在第 20-28 行:
test_modes = ( getattr(settings, "TEST", False), getattr(settings, "DEBUG", False), getattr(settings, "CI", False), getattr(settings, "E2E_TESTING", False), ) if not any(test_modes): raise Http404()即该端点仅在 TEST / DEBUG / CI / E2E_TESTING 任一模式下可用,本地开发默认满足DEBUG=True,因此可用;生产式配置下会直接 404。请求体经 pydanticinput_model校验后调用 setup 函数,成功返回{"success": True, "test_name": ..., "result": ...},异常则返回 500 与错误描述。这与 .agents/skills/run-posthog/SKILL.md 中"Gated onDEBUG=True | E2E_TESTING | CI | TEST"的描述完全对应。
run-posthog技能给出了完整的浏览器 MCP 配方(.agents/skills/run-posthog/SKILL.md 的 Drive the UI for /verify 一节),此处摘要关键步骤:
// 1. 在页面上下文中创建隔离工作区(每次调用使用随机邮箱,密码固定 12345678) const r = await fetch('/api/setup_test/organization_with_team/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ data: { skip_onboarding: true } }), }) const { result } = await r.json() // result: { user_email, team_id, personal_api_key, organization_id, ... } // 2. 仍在页面上下文中执行登录(保证 Django 的 CSRF 中间件拿到正确 cookie) const r = await fetch('/api/login/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: workspace.user_email, password: '12345678' }), }) // 200 = 已登录;403 = 不在页面上下文;400 = 工作区并未真正创建该用户其中第二步必须在页面上下文中运行——直接curl -X POST /api/login/会因 CSRF 返回 403(run-posthog的 Gotchas 明确记录:会话登录必须在页面内执行,使 cookie 与 CSRF token 正常流转);非浏览器 API 调用则应改用setup_test返回的personal_api_key作为Authorization: Bearer <key>,token 认证无 CSRF 问题。
2.3 凭据来源与优先级
qa-frontend技能在 Preconditions 阶段(.agents/skills/qa-frontend/SKILL.md)从$ARGUMENTS解析--login-username/--username与--login-password/--password到LOGIN_USERNAME/LOGIN_PASSWORD。解析之后若仍未设置,再应用种子默认值:
LOGIN_USERNAME="${LOGIN_USERNAME:-test@posthog.com}" LOGIN_PASSWORD="${LOGIN_PASSWORD:-12345678}"由此形成三种凭据来源,按优先级排列:
- chat 参数:调用时显式传入的
--login-username/--login-password; - 环境变量:shell 中已导出的
LOGIN_USERNAME/LOGIN_PASSWORD; - 种子默认值:
test@posthog.com/12345678。
文档特别说明,不需要_OVERRIDE/_EFFECTIVE这类间接层;而fork 规则(fork-rule)的运行完全忽略上述优先级,一律只使用一次性(throwaway)凭据,详见 safety-rules.md 的 Fork PRs 章节——因为 fork 的代码可能窃取密码、浏览器会话、CSRF token 或本地数据,任何 fork PR 的浏览器 QA 都应假设"密码与会话可能泄露"。
2.4 密码安全与用户可见输出
两条铁律:
- 绝不打印密码;对 chat 提供的凭据,在面向用户的输出中只称"login override provided"(已提供登录覆盖)。
LOGIN_PASSWORD不得打印、记录或包含进证据与评论(SKILL.md Preconditions 同样重申:"Do not print, log, or includeLOGIN_PASSWORDin evidence or comments")。
2.5 浏览器 MCP 登录的五个步骤
使用浏览器 MCP/工具时,按如下顺序完成登录:
- 导航到
$BASE_URL/login; - 若使用
setup_test:先在页面内执行 run-posthog 的 setup 与登录 fetch,再导航到返回team_id对应的路由; - 否则,用生效的登录值填写邮箱与密码;
- 提交表单;
- 等待登录后的 URL 匹配
**/project/**——这是登录成功的关键信号,因为 PostHog 登录成功后会跳转到项目作用域路由。
2.6 登录失败的处理
若登录失败,或两个生效登录值任一缺失:中止整个流程、恢复原分支、不发布 PR 评论——因为 QA 实际上没有运行,发布评论会给出误导性结论。这与 SKILL.md 中"Never print passwords or include credentials in evidence. If login fails, abort before posting a PR comment because QA did not run"一致。
三、常见故障与排查线索(结合实际堆栈经验)
虽然 stack-and-login 文档本身聚焦就绪与登录,仓库内 .agents/skills/run-posthog/SKILL.md 沉淀了与之直接相关的常见故障,可作为登录/就绪失败时的排查地图:
migrate-clickhouse冷启动崩溃:hogli up -d时与migrate-postgres并行启动存在竞态,Postgres 未就绪时崩溃。这是POST /api/setup_test/...与 HogQL 场景的硬前置,但不是/run的前置。修复序列:等migrate-postgres显示status:"done"后重启崩溃的迁移单元(mcp__phrocs__toggle_process是外科手术式工具,但在共享堆栈上被 auto-mode 拦截时,回退到phrocs stop && hogli up -d全量重启,或直接python manage.py migrate_clickhouse——需先set -a; source .env.services; set +a使CLICKHOUSE_DATABASE=posthog)。POST /api/login/返回 400invalid_credentials:你登录的用户并非setup_test工作区真正创建的用户(通常是 ClickHouse 崩溃导致)。检查 setup_test 调用的响应,若其 500,先修 ClickHouse。POST /api/setup_test/organization_with_team/返回 404:DEBUG、E2E_TESTING、CI、TEST全部为假。本地开发默认DEBUG=True;若未设置,通常是.env.local缺失或DJANGO_SETTINGS_MODULE指向了类生产配置。POST /api/setup_test/organization_with_team/返回 500Table posthog.person does not exist:migrate-clickhouse启动时崩溃,见第一条。- 页面内
fetch('/api/login/')返回 403:调用未发生在页面上下文(例如用了page.request.post而非page.evaluate)。必须用evaluate_script/browser_evaluate使调用源于页面内。 hogli up -d报Another instance of bin/start is already running:上一次运行未清理;用 phrocs 状态确认无残留后,删除bin/start.lock重试。- 浏览器控制台的 CSP 警告与 401:登录前的正常现象——preflight/login 页面会尝试拉取
/api/projects/@current、/api/users/@me/与 PostHog.js 远程配置,在注册前均返回 401。
四、流程总结:一张就绪-登录决策表
| 阶段 | 判定条件 | 动作 |
|---|---|---|
| 设置基线 | 无 | BASE_URL=${BASE_URL:-http://localhost:8010};STACK_STARTED_BY_AGENT=0 |
| 复用检查 | curl/_health与/均成功 | 直接继续,不启动/重启/替换堆栈 |
| 复用失败 | curl 失败 | 用 phrocsget_process_status(backend/frontend)补充判断 |
| 仍不可达 | 进程检查未就绪 | 查用户偏好 → 查仓库指引/AGENTS.md → 询问用户启动方式并等待答复 |
| 获批启动 | 用户批准 | 运行hogli devbox:start --start-app或hogli up -d -y;STACK_STARTED_BY_AGENT=1 |
| 启动后复检 | 重跑可达性 + 进程检查 | 仅当应用可达且所需进程集就绪才继续;否则在 checkout/编辑/评论/推送前停止 |
| 登录路径 A | 需要隔离数据 | 页面上下文调POST /api/setup_test/organization_with_team/,用返回邮箱 +12345678登录,team_id构造路由 |
| 登录路径 B | 无需隔离数据 | test@posthog.com/12345678(种子默认) |
| 登录验证 | 地址匹配**/project/** | 视为成功;失败则中止、恢复分支、不发 PR 评论 |
这套流程的核心设计思想可以概括为三点:最小干预(能复用就不新建)、显式批准(启动/重启/推送等高影响动作必须对话内确认)、证据优先(目标路由可用的局部证据优于全栈绿灯的粗粒度判断)。对于任何需要在 PostHog 仓库上执行浏览器前端 QA 的开发者或 Agent,先跑通"堆栈就绪 → 登录"这两步,是后续所有测试用例设计、证据采集与报告产出的可靠前提。
【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考