我在 4 周内独自构建了全栈 F1 Fantasy 平台 — 使用 AI Agents

发布: (2026年2月8日 GMT+8 10:27)
17 分钟阅读
原文: Dev.to

Source: Dev.to

介绍

本文最初发表于 binaryroute.com

在2025年12月下旬的短假期间,我打开笔记本电脑,心中只有一个简单的想法——打造我作为粉丝一直想要的 F1 幻想联盟平台

四周后,Formula1.Plus 正式上线:

  • 70 + 个数据库表
  • 30 + 个 API 模块
  • 赛道预测、实时排行榜、私人联盟、遥测仪表盘、新闻聚合、社区功能以及完整的管理后台

全部由 一名开发者 独立构建并发布。

本文将技术性地回顾我是如何实现这一切的——先搭建的框架、选用的技术栈、使其成为可能的 AI 工作流,以及我以后会做哪些不同的选择。

独自全栈开发的问题

如果你曾经尝试独自构建一个全栈产品,你一定体会过其中的痛苦。你会同时成为:

  • Architect
  • Front‑end developer
  • Back‑end developer
  • DBA
  • DevOps engineer
  • QA tester

一次性全部兼顾。

每一次上下文切换都会消耗你的时间。你花在“管道”上的时间多于产品本身。项目进展停滞、范围缩小,或者在进行到一半时就精疲力竭。

这样一个项目——包括预测引擎、评分系统、排行榜、联赛、带语义搜索的新闻聚合、遥测仪表盘、后台任务处理、Passkey 认证——原本需要 6 个月的艰苦开发。很可能在第 3 个月就被放弃。

有两件事改变了这个算式:

  1. 我构建的一个用于消除样板代码的框架。
  2. 充当配对程序员的 AI 代理。

ProjectX – 打破模板的框架

在写下任何一行 F1 代码之前,我已经构建了 ProjectX —— 一个带有 CLI 的主观化全栈 TypeScript 框架。

Idea: 只需定义一次数据库模式,运行一个命令,即可生成所有代码。

projectx crud --models drivers,races,predictions

这条命令会生成:

  • 使用 Hono 的 API 路由,包含通过 Zod 进行的输入校验
  • 包含业务逻辑和授权钩子的 Service 层
  • 使用 Drizzle ORM 查询的 Repository 层
  • 为前端提供带有正确缓存键的 TanStack Query 钩子
  • 为 Service 层生成的单元测试脚手架

全部 类型安全,全部通过 依赖注入 连接。无需手动编写 API 类型定义 —— 前端可以通过 Hono 的 typed client 从后端直接导入路由类型。

Architecture Diagram (simplified)

HTTP Layer (Hono Routes)

Middleware (Auth, Rate Limiting, Logging, Caching)

DI Container

Service Layer (Business Logic + Authorization)

Repository Layer (Drizzle ORM)

PostgreSQL

每个功能都遵循此模式。每个功能都有自己的文件夹。后期使用的 AI 代理能够立即在该结构中导航,因为它在整个项目中保持了一致性。

仓库结构

f1plus/
├── apps/
│   ├── api/          # Hono backend
│   └── web/          # TanStack Start frontend
├── packages/
│   ├── db/           # Drizzle schemas + migrations
│   ├── db-sync/      # F1 data synchronization
│   ├── types/        # Shared TypeScript types
│   ├── ui/           # shadcn/ui component library
│   ├── emails/       # React Email templates
│   ├── env/          # Zod‑based env validation
│   └── tsconfig/     # Shared TS configs

七个共享包、两个应用、一个 pnpm 工作区。所有内容共享类型,毫不偏离。

这个结构是唯一最重要的决定。原因并非它新颖——而是它让我和 AI 代理从第一天起就拥有了可预测的代码库。

Source:

Stack 选择与理由

TanStack Start

  • SSR‑ready(服务器端渲染就绪)
  • 通过 TanStack Router 实现基于文件的路由
  • 内置 TanStack Query 用于数据获取

路由实现了完整的类型安全——路由参数、搜索参数、loader 都都有类型。再配合后端 Hono 的类型化客户端,我可以实现 从数据库到组件的端到端类型安全,且无需手动编写任何类型。

// 前端 Hook —— 由 ProjectX CLI 生成
export function useDriverStandings(seasonId: string) {
  return useQuery({
    queryKey: ['driver-standings', seasonId],
    queryFn: () => api.standings.drivers.$get({ query: { seasonId } }),
  })
}

查询函数的类型来源于 Hono 路由定义。只要更改 API 响应结构,TypeScript 就会立刻在前端报错。

Tailwind v4 + CSS 自定义属性

我定义了一套设计令牌:

--f1-bg-card;
--f1-bg-secondary;
--f1-border;
--f1-text;
--f1-text-muted;
--f1-red;

这些令牌在浅色模式和暗色模式下会解析为不同的值。所有组件都使用这些令牌而不是硬编码颜色,从而实现 零组件级别覆盖 的完整 UI 主题化。

shadcn/ui

提供可访问、未样式化的基础组件,你可以自行定制。没有依赖锁定。我对每个组件都做了定制,以匹配 F1 的美学风格。

Hono

一个 15 KB 的 Web 框架,可运行在 Node、Cloudflare Workers、Deno、Bun 等环境。选择它的三大理由:

  1. 类型化路由 —— hono/client 零运行时开销的类型推断。
  2. 中间件组合 —— 限流、鉴权、日志、请求体大小限制、CORS 等都可以组合使用。
  3. 性能 —— 速度快,性能可观。
// 限流层级
const rateLimits = {
  global:   { max: 200, window: '1m' },
  mutations:{ max: 30,  window: '1m' },
  expensive:{ max: 20, window: '1m' },
}

Drizzle ORM

在原始 SQL 与重量级 ORM 之间的最佳平衡。类型安全的查询、零运行时开销,且模式定义就是普通的 TypeScript。

export const drivers = pgTable('drivers', {
  id:          text('id').primaryKey(),
  name:        text('name').notNull(),
  abbreviation:varchar('abbreviation', { length: 3 }),
  nationality: text('nationality'),
  dateOfBirth: date('date_of_birth'),
  // …
})

pgvector + HuggingFace Transformers

用于 语义搜索 新闻文章——使用 Transformers 为文章生成向量嵌入,并通过相似度进行查询。这让用户能够按意义而非仅关键词搜索 F1 新闻。

后台任务工作者

Worker负责的任务
Scoring计算比赛得分并更新排行榜
News Sync抓取并处理 F1 新闻文章
Email通过 React Email + Resend 发送事务性邮件
F1DB Sync自动同步来自 F1DB(GitHub 上社区维护的开源 F1 数据集)的历史数据
Task通用异步任务

AI 配对编程工作流

  1. 提示生成 – 我用自然语言描述了所需的功能。
  2. 代码框架 – AI 生成了骨架(CLI 命令、文件布局)。
  3. 迭代细化 – 我请求具体细节(验证、认证钩子、测试)。
  4. 审查与合并 – 我检查了差异,运行测试并完成合并。

由于 ProjectX 强制执行了一致且可预测的结构,AI 能够可靠地定位正确的文件,导入正确的类型,并遵循现有约定。

我会做的不同之处

区域原始做法修订后做法
Testing生成了单元测试脚手架,但后续大多数测试都是手动编写的。从第 0 天起在服务层采用 property‑based testing(fast‑check)。
CI/CD简单的 GitHub Actions 工作流。为每个 PR 添加 preview deployments,使用 Vercel/Cloudflare Pages 及早捕获 UI 回归。
Observability基础的控制台日志。集成 OpenTelemetry + Loki/Grafana,实现 API 调用和后台任务的分布式追踪。
Feature Flags硬编码的开关。使用 LaunchDarkly‑风格的标记库,实现新评分算法的渐进式发布。
DocumentationREADME + 行内注释。使用 typedoc + swagger-ui 自动从 Hono 路由类型生成 API docs

结束语

独自构建一个生产级、全栈的幻想联盟平台是件艰巨的任务,但只要有:

  • 一个 有主见、自动生成代码的框架(ProjectX),它可以消除样板代码,
  • AI 代理 充当配对程序员,
  • 一个 精挑细选、类型安全的技术栈(TanStack Start、Hono、Drizzle、shadcn/ui),

工作量就能从数月压缩到数周。

如果你正准备单枪匹马进行全栈开发,首先要 标准化你的架构利用 AI 完成重复的脚手架搭建。其余的工作将会顺畅得多。

祝编码愉快!

通用异步任务

Bull Board 提供用于监控所有队列的管理员仪表盘。

BetterAuth 处理 OAuth(Google、Discord、X)以及 Passkey/WebAuthn 支持。
Passkey 是认证的未来——无需密码,抗钓鱼,支持生物识别。
只用了一个下午就完成了设置。

让四周开发成为可能的关键环节

在整个构建过程中,我使用了 Claude CodeOpenAI CodexGemini——不是作为自动补全,而是作为能够在上下文中保持完整代码库的协作者。

  • Claude Code 是核心开发者——直接在仓库中编写、重构和调试代码。
  • Claude、Codex 和 Gemini 充当架构师:每个非平凡功能都会经过详尽的设计过程,我会在确定最终实现方案前收集多个模型的观点。不同模型会捕捉到不同的边缘情况,交叉覆盖提升了信心。

功能脚手架

我会描述一个功能(例如 “添加一个预测系统,让用户为每场比赛挑选车手,并使用每周锁定机制获取额外积分”),然后代理会生成:

  • 数据模型
  • 服务层
  • 路由
  • 验证规则
  • 前端 Hook

第一次生成并不完美,但大约达到 80 %。我会审查、调整并迭代。

并行代码审查

当我需要将 50+ 个组件文件 中硬编码的 bg-white/10 不透明度模式迁移到用于浅色模式的 CSS 自定义属性时,我同时启动了三个 AI 代理——每个代理处理一批文件,并遵循相同的映射指南。原本需要整整一天的繁琐查找‑替换工作,几分钟内就完成,且结果保持一致。

调试

示例: 赛道‑电路 SVG 组件出现模糊效果,原因是 8 层堆叠的 CSS drop-shadow 滤镜 产生了指数级叠加。代理定位到根本原因(每个滤镜都作用于前面所有滤镜的累计结果),删除了轮廓系统,并调整了描边宽度——这本可能让我花费一小时的修复工作。

一致性

随着代码库增长到 50+ 个组件,AI 仍保持模式一致:

  • 相同的命名约定
  • 相同的文件结构
  • 相同的验证方式

这正是单独开发者往往会开始偷工减料的地方。

关键洞见: AI 代理的表现取决于你提供的模式。

ProjectX 的强制性架构为 AI 提供了护栏:

  • 服务位于 features/<name>/<name>.service.ts
  • 验证使用 Zod 模式,放在 features/<name>/validations.ts
  • 路由保持轻量——将业务委托给服务层
  • 前端 Hook 遵循 TanStack Query 约定

如果没有这种一致性,你只会更快地生成“意大利面”代码。该框架不仅为我服务,也为 AI 提供了指导。

Source:

部署故事

TanStack Start 通过 Vite 插件构建为 Cloudflare Workers。前端在边缘运行,全球分布,几乎没有冷启动。

  • 成本: 在此规模下几乎免费;Cloudflare 的免费层非常慷慨。

Railway 运行 Hono API、PostgreSQL 和 Redis。Docker 多阶段构建保持镜像精简。健康检查、自动重启和部署预览都是内置的。

railway.toml

[deploy]
healthcheckPath = "/health/ready"
healthcheckTimeout = 30
restartPolicyType = "on_failure"
restartPolicyMaxRetries = 5

两个工作流

  1. CI – 对每个 PR 进行 lint、类型检查、构建、测试
  2. 部署 – 手动触发,先运行迁移,然后将 API 部署到 Railway,前端部署到 Cloudflare
Push to main → CI passes → Trigger deploy →
  Run migrations → Deploy API (Railway) → Deploy Web (Cloudflare)

整个生产基础设施 —— API 服务器、PostgreSQL、Redis、边缘部署的前端、CI/CD —— 费用约为 $20 / 月(使用无服务器数据库和 Redis 选项约为 $10 / 月)。无需 Kubernetes。无需 Terraform。无需 DevOps 工程师。

4 周内的发布内容

预测与计分

  • 赛道预测,包含车手和车队选择
  • 本周锁定(Lock‑of‑the‑week)机制,用于大胆预测(额外积分)
  • 最后名次选择、车队前 3 名、额外选择
  • 通过后台工作者实现的自动计分引擎

排行榜与联赛

  • 实时排行榜,包含全时段和单赛季排名
  • 使用邀请码的私有联赛
  • 联赛专属排行榜和积分榜

遥测与数据

  • 车手 DNA 细分及表现分析
  • 自动同步自 F1DB(社区维护的开源数据集)的历史数据
  • 赛道概况,包含往期成绩和统计数据
  • 基于 Recharts 的可视化

社区

  • Grand Stand — 投票、讨论、社区互动
  • 使用语义搜索 (pgvector) 的新闻聚合
  • 活动动态流和社交功能

管理后台

  • 赛事管理与预测配置
  • 通过 Bull Board 进行队列监控
  • 审计日志、联系人管理、投票模板

认证与基础设施

  • OAuth(Google、Discord、X)+ Passkey/WebAuthn
  • 限流(分层:全局、变更、耗时查询)
  • 使用 OpenTelemetry 的分布式追踪
  • 使用 Pino 的结构化日志

F1 赛季即将到来,我正在在第 1 轮之前获取早期用户。

ProjectX – 开源

ProjectX——使这一切成为可能的框架——即将开源。它是一个单一 monorepo 的 CLI,能够开箱即用地脚手架 Web、移动端和浏览器扩展,并提供完整的架构。

功能包括:

  • 插件系统
0 浏览
Back to Blog

相关文章

阅读更多 »