// docs / architecture
系统架构
基于 Next.js 16 App Router 的全栈 AI 流水线。无需独立后端 — API Routes、AI 编排和前端全部在同一个仓库中。
系统概览
Open-OX Studio 由三个主要层次构成:Next.js 前端(SSR + 客户端状态)、 AI 流水线(服务端编排)、以及外部服务(Supabase、E2B、LLM API)。
浏览器
└── /studio/[projectId] ← React 客户端,SSE 消费者
│
├── POST /api/projects → 创建 DB 记录,返回 projectId
├── POST /api/ai → 启动生成流(SSE)
├── POST /api/.../modify → 启动修改流(SSE)
└── POST /api/.../preview → 启动/刷新预览(后端随 OPEN_OX_PREVIEW_BACKEND 分支)
服务端(Next.js API Routes)
├── AI 流水线(generate_project / modify_project)
├── Supabase(projects 表 + project-files / site-previews Storage)
└── 预览:OPEN_OX_PREVIEW_BACKEND env → local | storage | e2bprojectId 在 AI 流水线启动之前就已创建。用户可以在生成过程中关闭浏览器, 重新进入时通过 DB 中的增量 buildSteps 恢复进度。技术栈
| 层次 | 技术 | 选型理由 |
|---|---|---|
| 框架 | Next.js 16 App Router | SSR + API Routes 合一,无需独立后端 |
| 语言 | TypeScript 严格模式 | AI 生成代码的类型安全保障 |
| 样式 | Tailwind CSS v4 + shadcn/ui | CSS 变量驱动主题,AI 可直接操作 |
| 数据库 | Supabase (PostgreSQL) | 托管 Postgres + Storage + 实时订阅 |
| 沙箱 / 预览 | local · Storage · E2B | 预览后端可选:本地 dev、静态导出+代理、或云端沙箱 |
| LLM | OpenAI-compatible API | 可切换 Gemini / GPT / 任意提供商 |
为什么用原生 fetch 而非 OpenAI SDK
OpenAI SDK 内部使用 agentkeepalive,默认 socket timeout 为 8 秒。 单次 section 生成调用可达 60 秒,SDK 会强制断连。 原生 fetch 配合 AbortSignal.timeout(300_000) 覆盖所有场景。
const res = await fetch(`${baseURL}/chat/completions`, {
method: "POST",
body: JSON.stringify({ model, messages, tools }),
signal: AbortSignal.timeout(300_000), // 5 min
});请求流程
从用户输入到上线预览的完整生命周期:
1. 用户输入 prompt → 点击 Build
2. POST /api/projects → 创建 DB 记录(status=generating)
3. 服务端立即返回 projectId(< 100ms)
4. 浏览器跳转到 /studio/{projectId}
5. 页面检测 status=generating 且 buildSteps 为空
6. 自动触发 POST /api/ai,传入 projectId
7. 服务端运行 AI 流水线,每个步骤完成后:
a. SSE 事件推送到浏览器(实时显示)
b. 写入 Supabase(支持断线恢复)
8. status → ready / failed/studio/[id] 会启动 3 秒轮询循环,并显示 DB 中已完成的步骤。API 路由
/api/projects创建项目记录,返回 projectId/api/projects项目列表(需登录)。默认返回全员项目;?mine=1 或 folder=uncategorized|… 时仅当前用户并按文件夹筛选/api/projects/[id]按 ID 获取项目(用于轮询)/api/projects/[id]重命名、移动文件夹等(仅所有者)/api/projects/[id]删除项目及文件(仅所有者)/api/ai启动生成流水线(SSE 流)/api/projects/[id]/modify启动修改 Agent(SSE 流)/api/projects/[id]/preview启动或刷新预览(local/storage/e2b 由环境决定;storage 模式下访客可取得静态 URL)/api/projects/[id]/preview修改后重建预览/api/models获取可用 LLM 模型列表/api/skills获取可用风格技能列表SELECT 全部 projects 行(便于项目广场按成员浏览);INSERT / UPDATE / DELETE 仍限制为资源所有者。输入触发器系统
HeroPrompt 输入框支持多种触发器,在文本任意位置通过特殊字符激活。 选中后以彩色 chip 形式注入,提交时各 chip 的 payload 合并到请求体。
| 触发符 | 功能 | 提交字段 |
|---|---|---|
| / | 风格模板选择(如 /glassmorphism) | styleGuide |
| @ | 引用已有项目作为设计参考 | referenceProjectId |
| # | 约束标签(#暗色主题 #极简 #中文) | prompt 追加 |
| URL | 粘贴 URL 自动提取为参考 | referenceUrl |
| 图片 | 粘贴截图作为视觉参考 | imageBase64 |
架构
app/hooks/usePromptTriggers.ts — 统一触发器 hook(检测 / @ # + 光标位置) app/components/ui/TriggerMenu.tsx — 浮层下拉菜单(按类型显示不同颜色前缀) app/components/ui/PromptChips.tsx — 注入的标签展示(含图片缩略图) app/components/ui/QuickTemplates.tsx — 快捷模板 pills
触发检测基于光标位置:从光标往前搜索最近的触发字符, 触发字符必须在行首或空格后,且到光标之间不含空格。 这允许用户在文本中间任意位置触发菜单。
Modify Agent
生成后的迭代修改由 Modify Agent 处理 — 一个受 Claude Code 启发的开放式 Agent 循环。 Agent 在单次循环中完成搜索、阅读、编辑和验证。
工具列表
read_filesearch_codelist_diredit_filewrite_filerun_buildexec_shellthinkrevert_file4-Phase 工作流
Phase 1: ORIENT — search_code + list_dir,建立全局理解 Phase 2: READ — 只读 1-2 个最相关文件,形成修改计划 Phase 3: EDIT — edit_file 精确替换,最小改动 Phase 4: VERIFY — run_build 验证编译
安全机制
Must read before edit — edit_file 前必须先 read_file,防止盲改。Loop Detection — 连续 4 次操作同一文件时注入策略转换提示。Tool Result Budget — 单条结果上限 30K 字符。Context 压缩 — 基于相关性,热文件保留完整,冷文件压缩。
数据持久化
projects 表
| 字段 | 类型 | 说明 |
|---|---|---|
| id | text PK | {timestamp}_{slug} — URL 可读,全局唯一 |
| user_id | uuid FK | 所属用户(auth.users) |
| owner_username | text | 创建时写入的展示名,用于全员列表按成员分组 |
| folder_id | uuid FK? | 单层文件夹(project_folders),可空 |
| status | enum | generating / ready / failed |
| blueprint | jsonb | analyze 步骤输出的完整 ProjectBlueprint |
| build_steps | jsonb[] | 增量写入 — 每步完成后立即持久化 |
| modification_history | jsonb[] | 每次修改的完整记录(含 diff) |
| sandbox_id | text | E2B 沙箱 ID(用于重连) |
| verification_status | enum | passed / failed(next build 结果) |
源码持久化在 Storage 桶 project-files;静态预览产物在 site-previews(由 /site-previews/… 代理访问)。 本地丢失时从 project-files 恢复到 sites/ 后再构建预览。
关键工程决策
projectId 在 AI 启动前创建
支持断线恢复、可分享 URL、以及无需重新输入 prompt 的重试。
buildSteps 增量持久化
每个步骤完成后立即写入 DB。用户中途关闭页面后重新进入,看到的是真实进度而非空白。
Blueprint normalize 层
asProjectBlueprint() 对每个字段做 normalize 并提供 fallback。LLM 输出不一致时不会导致流水线崩溃。
静态预览默认走 Storage(本地开发)
配置 Service Role 与 NEXT_PUBLIC_SITE_URL 且未指定 OPEN_OX_PREVIEW_BACKEND 时,本地默认与生产一致使用静态导出 + 代理,避免 Dev Server 与 CSP 差异。