一个农场季节从"已播种"走到"生长期",中间不需要任何人点一下按钮。当积温(GDD,生长度日)累计跨过作物阈值,季节状态自己就往前走了。

这是 Mecropolis 的核心逻辑。它把 Open-Meteo 的气温从播种那天起逐日累加,用真实发生过的天气,算出每块地里的作物现在处在什么阶段。农场经理和农艺师不用手动维护时间表,季节的进度由天气自己讲。

打开网易新闻 查看精彩图片

它到底在算什么

积温这个概念不复杂:作物生长需要热量,把每天的温度折算成一个累积值,累到某个数,作物就进入下一个阶段。Mecropolis 把这个累积过程接上了实时天气接口,所以阶段推进的依据不是日历,是这块地实际经历过的天气。

应用面向的是想把一个季节的完整故事放在一处的人——从驱动它的降雨和高温,到什么时候喷了什么药。数据模型里没有任何东西绑死在某个地区:农场、地块和坐标都是 Sanity 文档,Open-Meteo 能给地球上任何一个点返回天气。

开发者做这个应用时心里想的是南非西开普省的农场,因为他从小在那里长大,现在的工作也围绕那里。演示农场放在斯瓦特兰小麦带。

不用登录就能看到的东西

落地页不需要登录。上面是一张基于 MapLibre 的区域天气地图,每个网格单元按本季累计的度日数着色。旁边并排着演示站点的实时天气状况、土壤、虫害压力和区域产量统计。

登录之后进入仪表盘,能看到农场、地块、季节看板、季节对比、CSV 导出、活动流,以及一个推荐队列——可以批准、拒绝或标记完成。

单个季节页面里的东西更密:

  • 阶段步进器,直观显示作物走到哪一步
  • 积温图表
  • 降雨和温度的假设情景模拟
  • 地块照片和土壤检测 PDF
  • 带修订历史的日期笔记,可以逐条恢复
  • 对地块日志的语义搜索
  • 对季节已存记录的 AI 摘要

所有数据都是真的。天气和土壤来自实时接口,施药和产量由操作者录入。区域基准数据单独展示,绝不会拿来填补某块地的产量。作物模型参数是开发者自己手写的估算值,没有引用来源,应用里也如实说明了这一点。

从 Next.js 推倒重来

Mecropolis 最终跑在的架构,不是它一开始用的那套。第一版是 Next.js 16,内嵌 Sanity Studio,用 Auth.js 做凭据登录,部署在 Vercel 上。本地能跑,但 Studio 渲染又慢又脆,Next 构建在 Vercel 上卡住。后来 Vercel 因为提交作者邮箱的问题拒绝了一次部署。

开发者发现自己跟托管平台和渲染引擎搏斗的时间,比做应用本身还多。9月22日,他停下来重开:要的是一个 Web 应用,不是桌面应用,规格书里其他内容不变。技术栈换成 React + Vite + TypeScript + React Router,Sanity 作为后端内容湖,不依赖 Sanity 的渲染引擎。

重建后是一个跑在 Cloudflare Pages 上的 Vite + React 单页应用。浏览器直接读取一个公开可读的 Sanity 数据集,而每一次写入都经过一个持有写入令牌的 Pages Function。这个拆分后来被证明是整个项目里最好的决定——它给了一个统一的地方去执行会话校验、来源检查、Zod 验证和写入上限,也给 Sanity Functions 留了一个干净的调用端点。

又过了一天,范围进一步收窄:不实现 Sanity Studio,因为渲染问题会额外花时间调试,干脆自己写 Web 应用。

整个构建过程用的是 Claude Code,从第一次规格评审到最终部署。开发者先在终端里用 Claude Code CLI,后来转到 Claude 桌面应用,两个并排用:桌面应用跑长会话,带内置浏览器预览,CLI 就在旁边的终端里。工作从9月20日持续到26日,跨了很多个会话。

他先写了一份完整的项目规格(仓库里的 planning.txt),然后让 Claude 检查其中的不一致之处,并按阶段规划构建。之后基本是短提示词推进:"开始第一阶段"、"继续重设计"、"还有什么没做完"。