Open Scouts:打造你的专属AI网络侦察兵,24/7监控你关注的一切
摘要
Open Scouts是一款AI驱动的监控平台,能创建自动任务(scouts)持续搜索网络,通过Next.js、Supabase等技术实现,支持邮件通知与语义搜索,本文详解其功能、技术栈、使用步骤及设计与分析体系。
什么是Open Scouts?
想象一下,如果你有一群不知疲倦的侦察兵,每天24小时帮你盯着网络上的各种信息——新开业的餐厅、行业最新动态、甚至是特定产品的价格变动,一旦发现你关心的内容,就立刻向你汇报。这就是Open Scouts能为你做的。
Open Scouts是一个基于AI的监控平台,你可以在上面创建“scouts”——这些其实是自动化的任务,它们会按照你设定的时间间隔运行,持续搜索网络上的信息。不管你是想关注附近新开的咖啡馆、跟踪人工智能领域的最新资讯,还是监控任何其他类型的更新,这些“侦察兵”都会全天候工作,找到你需要的内容后就及时通知你。
Open Scouts的技术栈:背后的“硬实力”
要支撑这样一个能持续监控、智能分析并及时通知的平台,背后需要一整套强大的技术体系。Open Scouts用到的技术栈包括:
-
Next.js 16:采用App Router和Turbopack,负责构建前端应用和处理服务器端逻辑,让整个平台运行更高效。 -
React 19:用于构建用户界面,让交互更流畅,用户体验更好。 -
TypeScript:提供类型检查,减少代码错误,让开发更稳健。 -
Tailwind CSS v4:用于样式设计,能快速构建出美观且一致的界面。 -
Supabase:集数据库、认证和边缘函数于一体,简化后端开发。 -
pgvector:处理向量嵌入,支持语义搜索,让搜索更智能,能理解内容的含义。 -
Firecrawl SDK(@mendable/firecrawl-js):负责网页抓取和搜索,帮“侦察兵”获取网络信息。 -
OpenAI API:提供AI代理和嵌入功能,让“侦察兵”具备智能分析能力。 -
Resend:处理邮件通知,确保你能及时收到“侦察兵”的汇报。
如何开始使用Open Scouts?
如果你想亲自试试Open Scouts,按照下面的步骤操作就能快速上手:
准备工作:你需要这些东西
在开始之前,确保你已经准备好了这些:
-
Node.js 18或更高版本 -
包管理工具(bun、npm或pnpm,默认推荐bun) -
Supabase账号(可以去supabase.com注册) -
OpenAI API密钥(从platform.openai.com获取) -
Firecrawl API密钥(来自firecrawl.dev) -
Resend API密钥(从resend.com获取,用于邮件通知) -
Google Cloud Console账号(可选,用于Google OAuth登录)
步骤1:克隆代码并安装依赖
首先,把代码克隆到你的本地,然后安装需要的依赖。打开终端,运行这些命令:
git clone https://github.com/leonardogrig/open-scout
cd open-scout
bun install # 如果你用npm或pnpm,就换成npm install或pnpm install
步骤2:创建Supabase项目
Supabase是整个平台的后端核心,所以需要先创建一个Supabase项目:
-
打开supabase.com的控制台(supabase.com/dashboard) -
创建一个新项目 -
等待项目完成配置(这可能需要一点时间)
步骤3:启用必要的扩展
在Supabase项目里,有些扩展是必须启用的,它们能让平台的各种功能正常工作:
-
进入Supabase控制台的“Database → Extensions” -
搜索并启用这些扩展: -
pg_cron:用于定时任务,让“侦察兵”能按计划运行 -
pg_net:支持从数据库发送HTTP请求 -
vector:用于AI驱动的语义搜索,分析执行摘要 -
supabase_vault:安全存储凭证,通常默认已启用
-
步骤4:设置环境变量
环境变量里存储了各种API密钥和配置信息,需要正确设置:
-
在项目根目录创建一个 .env文件,可以通过复制示例文件来做:cp .env.example .env -
然后在 .env文件里填写你的实际信息。.env.example文件里有详细说明,还附带了获取每个API密钥的链接,照着做就行。
步骤5:运行数据库设置
这一步会配置数据库表、权限等关键内容,让平台能正常工作:
-
首先关联你的Supabase项目(这是同步密钥必须的): bunx supabase login # 登录Supabase CLI,只需要做一次 bunx supabase link --project-ref <your-project-ref> # 项目ID在Supabase控制台的URL里能找到 -
然后运行设置脚本: bun run setup:db # 用npm或pnpm的话,就换成npm run setup:db或pnpm run setup:db
这个脚本会做很多重要的事情:
-
创建所有需要的表(比如 scouts、scout_executions、scout_execution_steps等) -
添加用户认证支持(用户ID列、行级安全策略) -
启用实时订阅功能 -
为AI生成的执行摘要设置向量嵌入 -
配置可扩展的调度器架构(pg_cron + pg_net + vault) -
自动把Supabase URL和服务角色密钥存储到vault里 -
设置用于“侦察兵”调度和清理的定时任务 -
从 .env文件同步边缘函数的密钥(OPENAI_API_KEY、FIRECRAWL_API_KEY、RESEND_API_KEY)
注意:这个脚本会检查是否启用了必要的扩展(vector、pg_cron、pg_net)。如果没启用,会显示提示,你按照提示在Supabase控制台启用后,再重新运行脚本就行。
步骤6:设置身份认证
Open Scouts用Supabase Auth来处理用户认证,支持邮箱/密码和Google OAuth两种方式。
启用邮箱/密码认证(默认已启用)
-
进入Supabase控制台的“Authentication → Providers → Email” -
确保“Enable Email Provider”是开启的 -
可以根据需要在“Authentication → Email Templates”里配置邮件模板
启用Google OAuth(可选但推荐)
如果你想让用户能用Google账号登录,按下面的步骤做:
-
创建Google OAuth凭证:
-
打开Google Cloud Console(console.cloud.google.com) -
创建一个新项目或者选择已有的项目 -
进入“APIs & Services → Credentials” -
点击“Create Credentials → OAuth client ID” -
应用类型选择“Web application” -
添加授权的JavaScript来源: -
开发环境: http://localhost:3000 -
生产环境: https://your-domain.com(换成你的域名)
-
-
添加授权的重定向URI: -
https://<your-project-ref>.supabase.co/auth/v1/callback
-
-
复制“Client ID”和“Client Secret”
-
-
在Supabase里配置:
-
进入Supabase控制台的“Authentication → Providers → Google” -
开启“Enable Google Provider” -
粘贴刚才复制的Client ID和Client Secret -
保存设置
-
步骤7:部署边缘函数
边缘函数负责处理“侦察兵”的执行和邮件发送,需要部署到Supabase Cloud:
bunx supabase functions deploy scout-cron
bunx supabase functions deploy send-test-email
注意:运行setup:db时,密钥(OPENAI_API_KEY、FIRECRAWL_API_KEY、RESEND_API_KEY)会自动同步。如果需要手动更新,可以运行:
bunx supabase secrets set OPENAI_API_KEY=sk-proj-... # 换成你的实际密钥
步骤8:设置Resend(邮件通知)
当“侦察兵”找到结果时,会通过邮件通知你,这需要配置Resend:
-
在resend.com创建一个账号 -
从Resend控制台获取API密钥 -
把密钥添加到 .env文件,然后重新运行setup:db同步,或者手动设置:bunx supabase secrets set RESEND_API_KEY=re_... # 换成你的实际密钥 -
在resend.com/domains验证一个自定义域名,这样就能发送邮件到任何邮箱了
重要 – 免费套餐限制:
-
没有验证域名的话,Resend只能发送邮件到你的Resend账号邮箱 -
免费套餐每月包含3000封邮件(每天限100封)
测试邮件设置:
-
进入应用的“Settings” -
点击“Send Test Email”验证配置是否正确 -
查看你的收件箱,看看有没有收到测试邮件
步骤9:配置Firecrawl
Open Scouts用Firecrawl来进行网页抓取和搜索,有两种配置方式:
选项A:标准API密钥(推荐给贡献者)
这种方式最简单,所有用户共享一个API密钥:
-
在firecrawl.dev注册账号 -
从dashboard(www.firecrawl.dev/app/api-keys)获取API密钥 -
添加到 .env文件:FIRECRAWL_API_KEY=fc-your-key-here # 换成你的密钥 -
设置边缘函数的密钥: npx supabase secrets set FIRECRAWL_API_KEY=fc-your-key-here
选项B:合作伙伴集成(用于生产环境部署)
如果你要部署Open Scouts供多个用户使用,想管理每个用户的API密钥,就用这种方式:
-
联系Firecrawl获取合作伙伴密钥 -
在 .env文件里设置合作伙伴密钥:FIRECRAWL_API_KEY=your-partner-key # 换成你的合作伙伴密钥 -
设置边缘函数的密钥: npx supabase secrets set FIRECRAWL_API_KEY=your-partner-key
合作伙伴集成的工作原理:
-
用户注册时,会自动为他们创建一个唯一的Firecrawl API密钥 -
每个用户的使用情况会单独跟踪 -
密钥安全地存储在 user_preferences表中 -
如果用户的密钥失效,系统会自动切换到共享的合作伙伴密钥 -
用户可以在“Settings → Firecrawl Integration”查看他们的连接状态
优势:
-
能更好地跟踪每个用户的使用情况 -
可以单独撤销某个用户的密钥 -
自动为新用户分配密钥 -
自我修复:检测到无效密钥时自动切换到备用方案
注意:合作伙伴集成完全向后兼容。如果没有合作伙伴密钥,系统会像选项A那样用共享密钥工作。
步骤10:运行开发服务器
一切设置好后,就可以启动开发服务器,看看Open Scouts的样子了:
bun run dev # 用npm或pnpm的话,就换成npm run dev或pnpm run dev
然后打开http://localhost:3000,就能访问应用了。
Open Scouts是如何工作的?
了解了如何搭建,再来看看它具体是怎么运作的,从用户登录到“侦察兵”工作,每个环节都有其逻辑。
用户认证流程
-
公共首页:用户不用登录就能浏览 landing 页 -
创建侦察兵:当用户输入查询并按回车时,会提示他们登录 -
登录/注册:用户可以通过邮箱/密码或Google OAuth认证 -
继续流程:认证后,会自动继续创建“侦察兵”的流程 -
用户隔离:每个用户只能看到和管理自己的“侦察兵”
“侦察兵”系统
-
创建侦察兵:定义你想监控的内容(比如“侦察最近我附近的印度餐厅”或“侦察AI新闻”) -
AI代理设置:系统会自动配置搜索查询和策略 -
设置频率:选择运行频率(每小时、每3天、每周等) -
配置通知:在设置里添加你的邮箱,当“侦察兵”找到结果时就会收到提醒 -
持续监控:调度器每分钟检查一次,触发到期的“侦察兵” -
AI摘要:每次成功执行都会生成一个简洁的一句话摘要,并带有语义嵌入 -
收到通知:如果配置了邮箱,当“侦察兵”找到新结果时会收到邮件提醒 -
查看结果:在“侦察兵”页面实时查看所有发现,包括AI生成的摘要
手动执行
在任何“侦察兵”页面点击“Run Now”按钮,就能立即触发执行,不用等定时任务。
邮件通知
当“侦察兵”找到结果时,会自动向你的账号邮箱发送邮件提醒:
-
自动发送:只有当“侦察兵”成功找到结果时才会发邮件 -
内容丰富:美观的HTML邮件,包含“侦察兵”的结果和链接 -
测试:可以用设置里的“Send Test Email”按钮验证设置是否正确
邮件服务:由Resend提供(免费套餐每月3000封邮件)
注意:在Resend的免费套餐中,如果没有验证域名,邮件只能发送到你的Resend账号邮箱。要发送到任何邮箱,需要在resend.com/domains验证一个自定义域名。
架构设计
Open Scouts的架构各个部分分工明确,共同支撑整个平台的运行:
-
前端:Next.js应用,通过Supabase Realtime实现实时更新 -
数据库:PostgreSQL(Supabase),用pg_cron做调度,pgvector支持语义搜索 -
认证:Supabase Auth(邮箱/密码 + Google OAuth) -
AI代理:OpenAI GPT-4,带函数调用(搜索和抓取工具) -
AI摘要:自动生成一句话摘要,每个成功执行都带有向量嵌入 -
边缘函数:基于Deno的无服务器函数,协调代理执行 -
网页抓取:Firecrawl API,用于搜索和内容提取(通过合作伙伴集成支持每个用户的API密钥)
可扩展的调度器架构
Open Scouts采用的调度器模式能支持成千上万的“侦察兵”:
每分钟:
pg_cron → dispatch_due_scouts() → 找到到期的侦察兵 → pg_net HTTP POST
↓
┌──────────────────────┼──────────────────────┐
↓ ↓ ↓
边缘函数 边缘函数 边缘函数
(侦察兵A) (侦察兵B) (侦察兵C)
[独立运行] [独立运行] [独立运行]
-
调度器(SQL):通过pg_cron每分钟运行一次,查询到期的“侦察兵”,并发送单独的HTTP请求 -
独立执行:每个“侦察兵”在自己的边缘函数实例中运行,有独立的资源(256MB内存,400秒超时) -
自动清理:另一个定时任务每5分钟清理一次卡住的执行 -
Vault集成:Supabase凭证安全地存储在vault中,供调度器读取
安全保障
使用任何平台,安全都是重中之重,Open Scouts在安全方面做了这些工作:
-
行级安全(RLS):所有数据库表都有RLS策略,确保用户只能访问自己的数据 -
用户隔离:“侦察兵”、消息和执行都与认证用户绑定 -
安全认证流程:OAuth令牌和会话由Supabase Auth管理 -
服务角色:服务器端操作(定时任务、边缘函数)使用服务角色获取特权访问 -
API密钥存储:Firecrawl API密钥(使用合作伙伴集成时)存储在服务器端的 user_preferences中,从不会暴露给客户端
Firecrawl设计系统:让界面既美观又易用
Open Scouts的界面是基于Firecrawl设计系统构建的,这个系统让整个应用的视觉风格保持一致,同时也方便开发人员快速构建界面。
设计系统概述
Firecrawl设计系统围绕模块化组件架构构建,位于components-new/目录下。它整合了多个UI库,为应用提供一致的视觉语言。
核心技术
-
Tailwind CSS:带自定义配置的实用优先CSS框架 -
shadcn/ui:基于Radix UI的高质量React组件 -
自定义组件:应用特定的共享组件
目录结构
components-new/
├── ui/ # 核心UI组件
│ ├── shadcn/ # shadcn/ui组件
│ ├── magic/ # Magic UI动画组件
│ ├── tremor/ # Tremor数据可视化组件
│ └── motion/ # 运动和动画工具
├── shared/ # 共享应用组件
│ ├── icons/ # 图标组件和品牌资产
│ ├── buttons/ # 自定义按钮组件
│ ├── cards/ # 卡片组件
│ ├── effects/ # 视觉效果和动画
│ ├── layout/ # 布局工具
│ └── ui/ # 共享UI工具
├── app/ # 应用特定组件
│ ├── brand/ # 品牌相关组件
│ ├── pricing/ # 定价页面组件
│ └── (home)/ # 首页组件
└── providers/ # 上下文提供者和主题管理
颜色系统
设计系统使用在colors.json和styles/colors.json中定义的全面调色板,支持明暗模式下的一致主题。
颜色分类
热力色(Heat Colors)
主要品牌色,有不同的透明度级别:
-
heat-4到heat-100:橙红色品牌色(#fa5d19),透明度从4%到100%
强调色(Accent Colors)
用于不同UI状态和上下文的语义颜色:
-
accent-black:深中性色(#262626) -
accent-white:纯白色(#ffffff) -
accent-amethyst:紫色强调(#9061ff) -
accent-bluetron:蓝色强调(#2a6dfb) -
accent-crimson:红色强调(#eb3424) -
accent-forest:绿色强调(#42c366) -
accent-honey:黄色强调(#ecb730)
透明度变体(Alpha Variants)
用于分层和深度的透明叠加:
-
black-alpha-1到black-alpha-88:黑色,透明度1%到88% -
white-alpha-56和white-alpha-72:白色,透明度56%和72%
UI颜色
界面元素的特定颜色:
-
border-faint、border-muted、border-loud:边框颜色变体 -
illustrations-faint、illustrations-muted、illustrations-default:插图颜色 -
background-lighter、background-base:背景颜色变体
颜色使用
颜色通过CSS自定义属性集成到Tailwind CSS中:
const colors = Object.keys(colorsJson).reduce(
(acc, key) => {
acc[key] = `var(--${key})`;
return acc;
},
{} as Record<string, string>
);
这使得动态主题和一致的颜色使用成为可能:
<div className="bg-heat-100 text-accent-white">
主要品牌样式
</div>
<div className="border border-border-muted bg-background-base">
微妙的界面元素
</div>
Tailwind配置
Tailwind配置(tailwind.config.ts)扩展了默认主题,包含专门为Firecrawl设计系统设计的自定义排版、间距和工具类。
排版比例
设计系统包含全面的排版比例,带有语义命名:
标题
-
title-h1:60px,行高64px,字间距-0.3px -
title-h2:52px,行高56px,字间距-0.52px -
title-h3:40px,行高44px,字间距-0.4px -
title-h4:32px,行高36px,字间距-0.32px -
title-h5:24px,行高32px,字间距-0.24px
正文
-
body-x-large:20px,行高28px,字间距-0.1px -
body-large:16px,行高24px -
body-medium:14px,行高20px,字间距0.14px -
body-small:13px,行高20px -
body-input:15px,行高24px
标签
-
label-x-large:20px,行高28px,字重450 -
label-large:16px,行高24px,字重450 -
label-medium:14px,行高20px,字重450 -
label-small:13px,行高20px,字重450 -
label-x-small:12px,行高20px,字重450
等宽字体
-
mono-medium:14px,行高22px -
mono-small:13px,行高20px,字重500 -
mono-x-small:12px,行高16px
字体家族
-
无衬线(Sans):SuisseIntl(主要),系统 fallback -
等宽(Mono):Geist Mono,系统 fallback -
ASCII:Roboto Mono,系统 fallback
自定义工具类
配置包含几个自定义工具类:
边框工具
-
.inside-border:绝对定位的边框叠加 -
.inside-border-x:水平边框叠加 -
.inside-border-y:垂直边框叠加 -
.mask-border:用于边框效果的CSS遮罩
定位工具
-
.center-x:水平居中 -
.center-y:垂直居中 -
.center:完全居中 -
.flex-center:Flexbox居中
布局工具
-
.overlay:全屏叠加定位 -
.text-gradient:文本渐变效果
自定义尺寸工具
-
cw-{size}:居中宽度定位 -
ch-{size}:居中高度定位 -
cs-{size}:居中正方形尺寸 -
cmw-{maxWidth},{padding}:带内边距的居中最大宽度 -
mw-{maxWidth},{padding}:带内边距的最大宽度
重要:自定义尺寸系统
Firecrawl设计系统使用自定义尺寸系统,其中数值等于实际像素,而不是像标准Tailwind那样的rem单位。
这意味着什么
在tailwind.config.ts中,定义了一个自定义的sizes对象(第16-37行),它将数字映射到像素值:
const sizes = Array.from({ length: 1000 }, (_, i) => i).reduce(
(acc, curr) => {
acc[curr] = `${curr}px`; // 3 = "3px",8 = "8px",100 = "100px"
return acc;
},
{ /* 分数百分比 */ }
);
这个sizes对象然后应用于多个CSS属性(第337-344行):
-
spacing– 影响内边距(p-*)、外边距(m-*)、间距(gap-*) -
width– 影响宽度(w-*) -
height– 影响高度(h-*) -
size– 影响size-*工具(宽度+高度简写) -
inset– 影响定位(top-*、left-*等)
与标准Tailwind的比较
| 类名 | 标准Tailwind | Firecrawl系统 |
|---|---|---|
w-3 |
0.75rem(12px) | 3px |
h-8 |
2rem(32px) | 8px |
size-4 |
1rem(16px) | 4px |
p-12 |
3rem(48px) | 12px |
gap-24 |
6rem(96px) | 24px |
应该怎么用
✅ 对于间距(内边距、外边距、间距):
<div className="p-24 gap-16 mb-8"> {/* 24px内边距,16px间距,8px底边距 */}
✅ 对于边框半径(基于像素):
<div className="rounded-8"> {/* 8px边框半径 */}
<div className="rounded-6"> {/* 6px边框半径 */}
<div className="rounded-4"> {/* 4px边框半径 */}
✅ 对于边框宽度(明确的像素):
<div className="border-1"> {/* 1px边框 */}
❌ 避免用于组件高度/宽度:
{/* 错误 - 按钮会只有9px高! */}
<Button className="h-9" />
{/* 错误 - 图标会只有4px × 4px! */}
<Icon className="size-4" />
与组件一起使用
问题:许多UI组件(按钮、图标、输入框等)使用h-*和size-*工具类,它们期望的是rem-based值,但得到的是像素值。
解决方案:对于应该更大的高度/宽度,使用明确的像素值:
{/* 不要用size-4(4px),用明确的值 */}
<Icon className="w-16 h-16" /> {/* 16px × 16px图标 */}
{/* 或者对非间距尺寸使用style属性 */}
<Icon style={{ width: '1rem', height: '1rem' }} /> {/* 16px × 16px */}
常见组件修复
输入组件:
// 错误 - 创建9px高的输入框
<Input className="h-9 px-3 py-1 rounded-md border text-sm" />
// 正确 - 合适的40px高输入框
<Input className="h-40 px-12 py-8 rounded-6 border-1 text-body-input" />
按钮组件:
// 错误 - 创建9px高的按钮
<Button className="h-9 px-4 gap-2">点击我</Button>
// 正确 - 合适的36px高按钮
<Button className="h-36 px-16 gap-8">点击我</Button>
文本区域组件:
// 错误 - 创建10px的内边距
<Textarea className="py-10 px-12" />
// 正确 - 合适的内边距
<Textarea className="py-16 px-16" />
图标组件:
// 错误 - 创建4px × 4px的图标
<Icon className="size-4" />
// 正确 - 合适的16px × 16px图标
<Icon className="w-16 h-16" />
迁移指南
从标准Tailwind或其他项目移植组件时:
-
间距保持不变 – p-24= 24px内边距 ✓ -
高度需要转换 – h-9(36px)→h-144(144px)或使用style -
尺寸需要转换 – size-4(16px)→size-64(64px)或使用style -
边框半径 – 使用像素数: rounded-8而不是rounded-lg -
边框宽度 – 明确指定: border-1而不是border
排版例外
排版使用语义尺寸(不受此系统影响):
<h1 className="text-title-h3"> {/* 使用排版配置中的40px */}
<p className="text-body-medium"> {/* 使用排版配置中的14px */}
边框半径系统
边框半径使用基于像素的数值(不是标准Tailwind名称):
// 可用:rounded-{0-32},1px递增
rounded-0 // 0px
rounded-4 // 4px(小按钮、输入框)
rounded-6 // 6px(卡片、模态框)
rounded-8 // 8px(大卡片、容器)
rounded-16 // 16px(非常圆)
rounded-32 // 32px(最大圆角)
rounded-full // 999px(正圆)
常见用法:
-
小UI元素(按钮、徽章): rounded-4 -
中型组件(输入框、小卡片): rounded-6 -
大型组件(卡片、模态框): rounded-8 -
圆形/药丸形: rounded-full
❌ 不要使用标准Tailwind名称:
{/* 错误 - 这些在配置中不存在 */}
<div className="rounded-sm rounded-md rounded-lg rounded-xl" />
{/* 正确 - 使用像素数 */}
<div className="rounded-4 rounded-6 rounded-8 rounded-16" />
透明度系统
自定义透明度范围0-99(基于百分比):
// 可用:opacity-{0-99}
opacity-0 // 0%(不可见)
opacity-10 // 10%
opacity-50 // 50%(半透明)
opacity-80 // 80%
opacity-100 // 100%(完全不透明)- 尽量少用,优先用opacity-99
示例:
<div className="opacity-50 hover:opacity-100">悬停时淡入</div>
<div className="bg-black opacity-20">微妙的叠加层</div>
过渡系统
自定义过渡时间和持续时间:
时间函数(默认)
transition-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1)
所有transition类默认使用这种缓动。
过渡持续时间
可用:duration-{0-59},每个数字 = n × 50ms
duration-0 // 0ms(即时)
duration-4 // 200ms(默认,快速)
duration-10 // 500ms(中等)
duration-20 // 1000ms(慢)
duration-40 // 2000ms(很慢)
示例:
<div className="transition-all duration-4">快速过渡(200ms)</div>
<div className="transition-opacity duration-10">中等淡出(500ms)</div>
动画
可用的自定义关键帧动画:
// 手风琴动画
animate-accordion-down // 平滑的手风琴展开
animate-accordion-up // 平滑的手风琴收起
// 淡入动画
animate-fade-in // 从0到100%不透明度的淡入
animate-fade-up // 淡入 + 上移10px
// 特殊效果
animate-screenshot-scroll // 15秒无限滚动动画
animate-selection-pulse-green // 绿色选择脉冲
animate-button-press // 按钮按下效果(缩小/放大)
用法:
<div className="animate-fade-in">挂载时淡入</div>
<button className="animate-button-press">按我</button>
常见间距值
为保持一致性,推荐使用这些间距值:
微间距(紧凑布局)
-
gap-4、p-4、m-4= 4px -
gap-8、p-8、m-8= 8px
标准间距(最常用)
-
gap-12、p-12、m-12= 12px -
gap-16、p-16、m-16= 16px -
gap-24、p-24、m-24= 24px
大间距(区块、容器)
-
gap-32、p-32、m-32= 32px -
gap-48、p-48、m-48= 48px -
gap-64、p-64、m-64= 64px
超大间距(页面布局)
-
gap-80、p-80、m-80= 80px -
gap-96、p-96、m-96= 96px -
gap-128、p-128、m-128= 128px
分数百分比(也可用):
w-1/2 // 50%
w-1/3 // 33.3%
w-2/3 // 66.6%
w-1/4 // 25%
w-1/6 // 16.6%
w-5/6 // 83.3%
响应式断点
screens: {
xs: { min: "390px" },
"xs-max": { max: "389px" },
sm: { min: "576px" },
"sm-max": { max: "575px" },
md: { min: "768px" },
"md-max": { max: "767px" },
lg: { min: "996px" },
"lg-max": { max: "995px" },
xl: { min: "1200px" },
"xl-max": { max: "1199px" }
}
组件架构
UI组件(components-new/ui/)
UI层由三个主要组件库组成:
shadcn/ui组件
高质量、可访问的React组件:
-
表单控件: Button、Input、Select、Checkbox、Switch -
布局: Card、Sheet、Dialog、Tabs、Accordion -
导航: NavigationMenu、DropdownMenu、ContextMenu -
反馈: Toast、Alert、Progress、Badge -
数据: Table、DataTable、Calendar
Magic UI组件
带动画和交互的组件:
-
animated-shiny-text:闪光文本效果 -
animated-list:列表动画 -
dot-pattern:背景图案 -
dock:macOS风格的 dock 组件 -
ripple:波纹效果 -
gradual-spacing:文本间距动画
Tremor组件
数据可视化和仪表板组件:
-
图表: LineChart、BarChart、AreaChart -
控件: Button、Badge、Dropdown -
布局: Card、Calendar、DatePicker -
进度: ProgressBar
共享组件(components-new/shared/)
图标(shared/icons/)
品牌和工具图标,有组织的导出:
// 品牌图标
export { default as SymbolWhite } from './symbol-white';
export { default as SymbolColored } from './symbol-colored';
export { default as WordmarkWhite } from './wordmark-white';
export { default as WordmarkColored } from './wordmark-colored';
// 工具图标
export { default as AnimatedLogo } from './animated-logo';
export { default as Check } from './check';
export { default as GitHub } from './github';
按钮(shared/buttons/)
带品牌样式的自定义按钮组件:
export { SlateButton } from './slate-button';
export { HeatButton } from './heat-button';
export { FireActionLink } from './fire-action-link';
布局组件
-
curvy-rect:曲线矩形形状 -
animated-height:高度动画 -
animated-width:宽度动画 -
unified-blur-overlay:背景模糊效果
效果和动画
-
flame/:火焰动画效果 -
animated-beam:连接光束动画 -
data-sources-beam:数据流可视化
应用组件(components-new/app/)
品牌组件(app/brand/)
特定于品牌展示的组件:
-
brand-hero.tsx:品牌页面hero区域 -
brand-assets-copy.tsx:资产复制功能 -
brand-assets-download.tsx:资产下载功能 -
brand-group.tsx:品牌资产分组 -
firecrawl-logo.tsx:Logo组件变体 -
firecrawl-wordmark.tsx:文字标志组件
品牌hero组件示例:
export default function BrandHero() {
return (
<section className='max-w-[1112px] mx-auto -mt-1'>
<SectionHead
action={(
<a className="contents" href="/brand/brand-assets.zip" download>
<Button className='mx-auto' size='large' variant='primary'>
下载品牌资产
</Button>
</a>
)}
description="欢迎来到Firecrawl品牌中心..."
title={<><span className="text-heat-100">Firecrawl </span>品牌资产</>}
titleClassName='text-title-h3'
>
<DeveloperFlame />
</SectionHead>
</section>
);
}
品牌资产
资产组织(public/brand/)
品牌资产组织在public/brand/目录中,包含全面的logo和营销材料:
Logo变体
-
firecrawl-logo.svg/png:主要logo -
firecrawl-light-logo.svg/png:浅色主题变体 -
firecrawl-wordmark.svg/png:纯文字标志 -
firecrawl-light-wordmark.svg/png:浅色文字标志变体 -
firecrawl-icon.png:应用图标 -
firecrawl-app-icon.png:应用图标变体
特殊资产
-
firecrawl-logo-transparent.png:透明背景logo -
firecrawl-logo-with-fire.png:带火焰元素的logo -
logo_fire.png:独立火焰元素
营销材料
-
scrape-data-from-any-site--firecrawl.jpg -
turn-websites-into-llm-ready-data--firecrawl.jpg -
we-handle-all-the-hard-stuff--firecrawl.jpg -
trusted-by-devs-at-top-companies--firecrawl.jpg
资产分发
-
brand-assets.zip:完整的品牌资产包,可供下载
品牌使用指南
Logo使用
-
使用 firecrawl-logo.svg作为主要品牌展示 -
在深色背景上使用 firecrawl-light-logo.svg -
空间有限时使用 firecrawl-wordmark.svg -
保持适当的间距和尺寸比例
颜色使用
-
主要品牌色: heat-100(#fa5d19) -
强调色用于突出显示和CTA时要适度 -
保持足够的对比度以确保可访问性
PostHog集成:了解用户如何使用Open Scouts
为了知道用户是如何使用Open Scouts的,以及平台的运行状况,Open Scouts集成了PostHog进行产品分析。
我们跟踪什么
用户旅程
我们跟踪从注册到成为活跃用户的完整用户旅程:
-
认证 – 注册、登录和OAuth流程 -
侦察兵创建 – 用户创建新的监控侦察兵时 -
配置 – 侦察兵设置的进度(目标、查询、位置、频率) -
激活 – 侦察兵启用自动监控时 -
参与度 – 手动运行、查看结果、管理侦察兵
执行指标
服务器端跟踪侦察兵执行性能:
-
执行成功/失败率 -
持续时间和步骤数 -
重复检测(结果与之前的运行匹配时) -
邮件通知送达情况
关键漏斗
激活漏斗
衡量用户从注册到拥有活跃侦察兵的效率:
注册 → 创建侦察兵 → 完成配置 → 激活侦察兵
参与漏斗
衡量用户的持续参与度:
查看结果 → 手动触发 → 查看邮件通知
产品健康指标
| 指标 | 描述 |
|---|---|
| 执行成功率 | 成功完成的侦察兵运行百分比 |
| 重复检测率 | 发现已报告信息的运行百分比 |
| 配置完成率 | 已创建的侦察兵中完全配置的百分比 |
| 激活率 | 已配置的侦察兵中用户实际开启的百分比 |
| 邮件送达率 | 成功发送的通知百分比 |
设置
环境变量
NEXT_PUBLIC_POSTHOG_KEY=your_project_api_key
NEXT_PUBLIC_POSTHOG_HOST=https://us.posthog.com # 可选
PostHog密钥还必须提供给Supabase边缘函数,用于服务器端跟踪。
架构
┌─────────────────────────────────────────────────────────────┐
│ 浏览器 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ posthog-js(instrumentation-client.ts) │ │
│ │ - 用户识别 │ │
│ │ - 页面浏览和UI交互 │ │
│ │ - 客户端事件 │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Next.js服务器 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ posthog-node(lib/posthog-server.ts) │ │
│ │ - 服务器端事件捕获 │ │
│ │ - API路由跟踪 │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Supabase边缘函数 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ HTTP捕获API(supabase/functions/.../posthog.ts)│ │
│ │ - 执行生命周期事件 │ │
│ │ - 邮件通知跟踪 │ │
│ │ - 性能指标 │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
事件参考
认证
| 事件 | 触发时机 |
|---|---|
user_signed_up |
新账户创建时 |
user_logged_in |
现有用户登录时 |
google_auth_initiated |
用户点击Google OAuth时 |
侦察兵管理
| 事件 | 触发时机 |
|---|---|
scout_created |
新侦察兵创建时 |
scout_configuration_completed |
所有必填字段填写完成时 |
scout_activated |
侦察兵启用自动监控时 |
scout_deactivated |
侦察兵禁用时 |
scout_deleted |
侦察兵永久删除时 |
执行(服务器端)
| 事件 | 触发时机 |
|---|---|
scout_execution_started |
执行开始时 |
scout_execution_completed |
执行成功完成时 |
scout_execution_failed |
执行出错时 |
scout_duplicate_detected |
结果与之前的运行匹配时 |
scout_email_notification_sent |
尝试发送邮件通知时 |
用户参与
| 事件 | 触发时机 |
|---|---|
scout_execution_triggered |
用户手动运行侦察兵时 |
scout_results_viewed |
用户查看执行结果时 |
execution_history_cleared |
用户清除执行历史时 |
设置
| 事件 | 触发时机 |
|---|---|
test_email_sent |
用户发送测试通知时 |
firecrawl_key_regenerated |
用户重新生成API密钥时 |
location_updated |
用户更改默认位置时 |
添加新事件
客户端
import posthog from "posthog-js";
posthog.capture("event_name", {
relevant_property: "value",
});
服务器端(API路由)
import { getPostHogClient } from "@/lib/posthog-server";
const posthog = getPostHogClient();
posthog.capture({
distinctId: user.id,
event: "event_name",
properties: { ... },
});
边缘函数
import { captureEvent } from "./posthog.ts";
captureEvent({
event: "event_name",
distinctId: userId,
properties: { ... },
});
隐私考虑
-
用户识别使用Supabase user.id(不是邮箱)作为主要标识符 -
邮箱仅作为用户属性存储,用于支持目的 -
事件属性中不包含任何个人身份信息(PII) -
使用PostHog的代理路径( /ingest)提高数据收集的可靠性
常见问题(FAQ)
关于Open Scouts的基本问题
-
Open Scouts适合什么场景使用?
只要你需要持续监控网络上的特定信息,都可以用它。比如跟踪行业新闻、关注新开业的店铺、监控产品价格变化等。 -
使用Open Scouts需要编程基础吗?
按照步骤设置的话,不需要深入的编程知识,但需要能操作终端和配置一些文件。
技术与设置相关
-
必须使用所有提到的技术吗?
是的,这些技术是平台正常运行的基础,比如Supabase提供数据库和认证,Firecrawl负责网页抓取等。 -
免费套餐够用吗?
Resend的免费套餐每月有3000封邮件,适合个人试用。如果是企业使用,可能需要升级套餐。 -
如何知道我的“侦察兵”是否在正常工作?
可以在应用中查看“侦察兵”的执行历史,也可以通过邮件通知来确认。如果有问题,执行历史中会显示错误信息。
设计系统相关
-
为什么设计系统要用自定义尺寸,而不是标准Tailwind?
这是为了更精确地控制界面元素的大小,确保设计的一致性,尤其是在需要像素级精确的场景下。 -
可以修改设计系统的颜色吗?
可以通过修改colors.json和Tailwind配置来调整颜色,但建议保持品牌色的一致性。
PostHog分析相关
-
跟踪的用户数据安全吗?
安全,跟踪时使用的是用户的ID而非个人信息,且不包含PII在事件属性中。 -
可以关闭PostHog分析吗?
目前没有直接的开关,但可以通过不设置PostHog的环境变量来禁用。
总结
Open Scouts是一个功能强大的AI监控平台,它能帮你24小时盯着网络上的信息,让你不会错过任何重要内容。通过合理设置,你可以创建各种“侦察兵”来满足自己的需求。
它的技术栈涵盖了前端、后端、AI、数据库等多个领域,确保了平台的稳定性和扩展性。设计系统则让界面既美观又易用,而PostHog集成则能帮助开发者了解用户使用情况,持续改进产品。
如果你想拥有一个自己的AI网络侦察兵团队,不妨按照文中的步骤试试Open Scouts,相信它会给你带来不少便利。

