第二篇:可运行的 Demo — 加上真后端和数据库
进入信号:客户看过静态原型后说「什么时候能用?」
本篇解决的问题:怎么把一个只能看的前端壳,变成真正能跑起来的应用?选什么技术栈、怎么设计第一版数据模型、怎么让客户用自己的真实数据验证?
从「能看」到「能用」
上一次你给 L 看了静态原型,她说「对,就是这个感觉,什么时候能真正用起来?」
现在你有了明确的信号:方向对,该让这个原型跑真实数据了。
但注意——这个阶段的目标仍然不是「做一个产品」。目标是:让 L 用她的真实数据跑一次完整流程,看她卡在哪里。
你的技术决策应该服务这个目标,而不是服务「未来可能的扩展」。
技术栈选型:做给一个客户的 Demo 选什么?
后端方案对比
在做决定之前,你有三个选择:
| 方案 | 适合场景 | 不适合场景 |
|---|---|---|
| Next.js API Routes | 前端为主,后端逻辑简单 | 复杂的后端计算、WebSocket |
| 独立后端(FastAPI/Express) | 后端逻辑复杂、需要 Python 生态 | 团队只有前端、部署麻烦 |
| Supabase 直接用 | 纯 CRUD,零后端逻辑 | 需要复杂业务逻辑 |
对于对账工具,你需要:
- 文件上传和解析(CSV/Excel 格式处理)
- 匹配算法(金额、日期、单号的多字段匹配)
- 差异标记和状态管理
这里有一些逻辑,不是纯 CRUD。但你也不想为了一个客户拆成前后端两个服务。
你的选择:Next.js API Routes + Prisma ORM + Supabase PostgreSQL。
理由:
- Next.js API Routes 写业务逻辑够用,不需要额外部署一个后端服务
- Prisma 自动生成 TypeScript 类型,和前端共享类型定义——这在原型阶段价值巨大
- Supabase PostgreSQL 免费层有 500MB 空间,一个客户的几个对账 CSV 数据绰绰有余
- 以后要迁移到独立后端?把 API Routes 里的逻辑抽成 Service 层就行,不伤筋动骨
开始搭建
# 在原型项目基础上,或者新建一个 Next.js 项目
npx create-next-app@latest reconciler --typescript --tailwind --app
cd reconciler
npm install prisma @prisma/client
npm install @supabase/supabase-js
npm install papaparse xlsx # CSV/Excel 解析
npx prisma init
Vibe Coding 提示词示例: "帮我用 Prisma schema 设计一个对账系统的数据模型。需要:银行流水表(bank_transactions)、订单表(orders)、匹配结果表(reconciliation_results)。bank_transactions 字段包括 date、amount、description、bank_ref。orders 字段包括 order_date、amount、order_no、customer_name。reconciliation_results 记录哪条银行流水匹配了哪条订单,以及匹配状态(matched/unmatched/partial)。用 PostgreSQL。"
第一版数据模型:克制是美德
AI 可能会吐给你 20 张表、50 个字段的设计。删。原型阶段只留必要的。
model BankTransaction {
id String @id @default(cuid())
date DateTime
amount Float
description String?
bankRef String?
matched Boolean @default(false)
createdAt DateTime @default(now())
}
model Order {
id String @id @default(cuid())
orderDate DateTime
orderNo String
amount Float
customerName String?
matched Boolean @default(false)
createdAt DateTime @default(now())
}
model Reconciliation {
id String @id @default(cuid())
bankTransactionId String
orderId String
status String @default("matched") // matched | unmatched | partial
difference Float?
note String?
confirmed Boolean @default(false)
confirmedBy String?
createdAt DateTime @default(now())
bankTransaction BankTransaction @relation(fields: [bankTransactionId], references: [id])
order Order @relation(fields: [orderId], references: [id])
}
3 张表,总计不到 30 个字段。 够用吗?对于第一个 Demo,完全够。
补充一点:注意到没有 User 表、没有多租户字段。因为现在只有一个客户 L,这些等需要的时候再加。过度设计是原型阶段最大的时间杀手。
数据库在哪跑?
Supabase 免费层。去 supabase.com 注册 → 建项目 → 拿到连接字符串 → 贴到 .env:
DATABASE_URL="postgresql://postgres:[PASSWORD]@db.xxx.supabase.co:5432/postgres"
然后:
npx prisma db push # 不需要 migration,直接推 Schema
不需要 Docker、不需要本地装 Postgres、不需要配 pg_hba.conf。Supabase 把运维复杂度吃掉了,让原型阶段专注于写功能。
核心功能实现
1. 文件上传 + 解析
一个 API Route 处理两件事:接收 CSV/Excel,解析成结构化数据,写入数据库。
// app/api/upload/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { PrismaClient } from '@prisma/client';
import Papa from 'papaparse';
const prisma = new PrismaClient();
export async function POST(req: NextRequest) {
const formData = await req.formData();
const file = formData.get('file') as File;
const type = formData.get('type') as string; // 'bank' | 'order'
const content = await file.text();
const { data } = Papa.parse(content, { header: true });
if (type === 'bank') {
await prisma.bankTransaction.createMany({
data: data.map((row: any) => ({
date: new Date(row.date),
amount: parseFloat(row.amount),
description: row.description,
bankRef: row.ref,
})),
});
}
// order 处理类似
return NextResponse.json({ success: true, count: data.length });
}
这个代码粗糙吗? 粗糙。没有校验、没有错误处理、没有文件大小限制。但对于一个客户来说,它能跑。这就是原型阶段的代码质量标准。
2. 匹配引擎
这是对账的核心——怎么匹配银行流水和订单?
// lib/matching.ts
export async function runReconciliation() {
const bankTxns = await prisma.bankTransaction.findMany({ where: { matched: false } });
const orders = await prisma.order.findMany({ where: { matched: false } });
for (const txn of bankTxns) {
// 策略 1:金额 + 日期完全匹配
const match = orders.find(
o => o.amount === txn.amount &&
o.orderDate.toDateString() === txn.date.toDateString()
);
if (match) {
await prisma.reconciliation.create({
data: {
bankTransactionId: txn.id,
orderId: match.id,
status: 'matched',
difference: 0,
},
});
await prisma.bankTransaction.update({ where: { id: txn.id }, data: { matched: true } });
await prisma.order.update({ where: { id: match.id }, data: { matched: true } });
}
// 策略 2:金额匹配,日期 ±1 天(处理跨行到账延迟)
// 策略 3:金额匹配,银行 description 包含订单号
// ... 后续迭代再加
}
}
这里只需要最简单的一层匹配——金额 + 日期。因为 L 说过,她的业务里 80% 的情况都是同一天同金额的付款。剩下 20% 的复杂情况,后面再迭代。
3. 差异展示
匹配失败的交易,在页面上标红展示:
// components/MatchResult.tsx
export function MatchResult({ reconciliations }: { reconciliations: Reconciliation[] }) {
// 已匹配的:绿色,展开看详情
// 未匹配的:红色,带「通知负责人」按钮
// 已确认的:灰色,归档
}
差异行旁边加一个按钮——「通知负责人」。点击后暂不真实发送(L 还没定通知谁),先弹出输入框让她填「要通知谁、说什么」。这个占位设计本身也会给她反馈信号,让她知道「对,我需要这个功能」。
第一次真实数据测试
周五,你带着笔记本去 L 的公司。她导出了这周的银行流水和订单报表。
上传。点击「开始对账」。3 秒后:
- 35 笔匹配成功 ✅
- 3 笔差异 ⚠️
L 盯着屏幕看了 10 秒,然后指着差异行说:
「这笔我知道,客户分两次付的,所以金额对不上。这个你们能处理吗?」
第一个真实需求出现了:分次付款匹配。
她又说:
「但是比我之前快了 100 倍。我以前要 3 个小时才能找出这 3 笔差异,现在 3 秒就找到了。」
这就是 Demo 的价值——不是交付一个完美的产品,而是让客户在真实场景里用,告诉你什么是对的、什么是错的、什么还缺。
Demo 阶段的代码质量底线
Demo 阶段不需要代码质量。但有一个例外:
数据绝对不能丢。
如果你的代码里有一个 bug 导致匹配错误,L 可能做错财务决策。所以对于匹配引擎,虽然是 AI 写的,但你需要:
- 人工验证第一轮匹配结果:挑 5 条手动对一遍
- 差异行标记清楚——宁可把「不确定」标出来,也不要把错的标成对的
其他的——变量命名、代码复用、错误处理——先放一放。它们重要,但不是现在。
什么时候进入下一阶段?
你已经验证了:
- ✅ 技术方案可行:L 的真实数据跑通了
- ✅ 核心价值成立:3 小时 → 3 秒的降幅是真实数字
- ✅ 发现了真实的新需求:分次付款、部分退款等复杂场景
但你也在想:
- 分次付款怎么处理?要不要支持退款匹配?
- L 说「特别好用」,但这是不是只是因为她是你的朋友?
- 还有没有完全不同的解法?比如不做手动上传,直接对接银行 API?
进入下一阶段的信号:你不确定哪种解法最好。
现在你对问题有了更深的认知,但你不知道应该沿着当前方向深化,还是换一个思路。这时候,做多原型发散——同时探索三个不同的方向,让真实的客户反馈帮你选。
这是第三篇的内容。
本篇总结
| 做了什么 | 技术栈 | 花了多久 | 月费 |
|---|---|---|---|
| Next.js + Prisma + Supabase 搭建 | Next.js, Prisma, PostgreSQL | 4 小时 | Supabase 免费 |
| 文件上传 + CSV 解析 API | PapaParse | 1 小时 | - |
| 金额+日期匹配引擎 | TypeScript | 1 小时 | - |
| 结果展示 + 差异标记 UI | React + Tailwind | 2 小时 | - |
| 真实数据测试 | - | 1 小时 | - |
当前系统形态: Next.js 单体应用,前端 + API Routes + Prisma + Supabase PostgreSQL。3 张表,一个能跑通的完整对账流程。服务 1 个客户。
本月账单:$0(Supabase 免费层 + Vercel Hobby)
AI 在这个阶段的角色: AI 写 Prisma Schema、API Route、React 组件,你负责验证数据正确性和交互逻辑。AI 能搭起框架,但「匹配算法该用什么策略」仍然是你基于客户反馈判断的。
下一步
当你不确定最好的解法——进入第三篇:多原型并行,用一个客户问题做三个方向的原型。
软件和硬件最大的区别:软件可以在上线当天就收到用户反馈,在当天晚上就修复 bug 并发布更新。 这种迭代速度是软件创业最大的优势——但它也带来了一个最大的陷阱:因为改起来太容易,很多人还没想清楚就开写了。
本篇把软件从 idea 到规模化产品的完整周期拆开。和硬件开发周期对照着看,你会更清楚两种创业的区别。
软件开发的五个阶段
| 阶段 | 名称 | 核心问题 | 典型耗时 |
|---|---|---|---|
| 1 | 概念验证 | 这个 idea 用户真的需要吗? | 1-7 天 |
| 2 | MVP | 能不能跑通核心流程? | 1-4 周 |
| 3 | Alpha 内测 | 核心功能在真实用户手里用得住吗? | 2-6 周 |
| 4 | Beta 公测 | 规模大一点会不会崩? | 4-10 周 |
| 5 | 规模化 | 怎么从 100 个用户到 10000? | 持续 |
总计:从 idea 到稳定的付费产品,软件通常需要 2-6 个月。
阶段一:概念验证(1-7 天)
做什么?
用最轻的方式验证「这个方向对不对」。核心原则:在写代码之前,先拿到「这个 idea 值得做」的证据。
验证方式(按成本从低到高)
| 方式 | 做什么 | 耗时 | 成本 |
|---|---|---|---|
| 纸面原型 | 在白板上画界面流程图 | 2 小时 | ¥0 |
| 静态页面 | React + 假数据,一个能点但不能用的页面 | 3-6 小时 | ¥0 |
| Landing Page | 一个描述你产品的单页 + 邮箱收集 | 半天 | ¥0 |
| 在竞品的差评里找需求 | 搜「XX 不好用」→ 你的产品差异化定位 | 1 小时 | ¥0 |
进入下一阶段的信号
至少有 3 个陌生人(不是你朋友)看了你的静态原型后,问了「什么时候能用?」而不是「挺好的」。
阶段二:MVP(1-4 周)
做什么?
做一个真正能跑的版本。只做最核心的一条链路,其他的都不要。
MVP 的铁律:砍到只剩一条主线。 对账工具?只做「上传 → 匹配 → 显示差异」。设置页面?不要。用户头像?不要。忘记密码?不要。只做让用户感受到核心价值的那一条链路。
时间线和关键动作
| 周次 | 动作 | 交付物 |
|---|---|---|
| 第 1 周 | 搭框架(Next.js + Prisma + Supabase),设计第一版数据模型 | 能跑的骨架 |
| 第 1-2 周 | 开发核心链路(前端 + API + 数据库 + 假数据或小规模真数据) | 能演示的 MVP |
| 第 2-3 周 | 给 2-3 个目标客户试用,坐在他们旁边看 | 真实的反馈 |
| 第 3-4 周 | 根据反馈修最痛的点,准备 Alpha | MVP V2 |
MVP 最该避免的坑
不要在 MVP 阶段追求代码质量。 MVP 是用完就可能扔掉的东西。它的价值不在于代码能维护多久——在于「它让多少个客户说了『这就是我要的!』」。
阶段三:Alpha 内测(2-6 周)
做什么?
从 2-3 个客户扩展到 10-30 个。在真实使用场景里看产品能不能「用得住」。这时候你会遇到三类问题:
第一类:Bug(修了就好)
- 上传某种格式的 CSV 报错 → 修解析器
- 对账结果偶尔出现重复的匹配 → 加去重逻辑
第二类:交互问题(每个人都卡在同一个地方)
- 第一次用的人有 60% 找不到「开始对账」按钮 → 需要改交互,不能靠培训
- 差异确认后没有反馈,用户不知道自己操作成功了 → 改设计
第三类:需求偏差(你以为重要的东西,用户根本不用)
- 你花了两天做的「对账报告导出」功能,没有一个人点开过
- 你随便放的一个「通知销售」的按钮,点击率远高于你精心设计的「对账总结」页面
这个阶段最该避免的坑
不要试图通过「给用户录教程」来解决产品问题。 如果一个功能需要教程才能用,这个功能的设计本身就有问题。改设计,别录视频。
阶段四:Beta 公测(4-10 周)
做什么?
从 30 个客户扩展到 100-500 个。验证三件事:
- 性能撑得住吗? —— 100 个客户同时跑对账,数据库 CPU 会不会飙到 100%
- 多租户能正常工作吗? —— 客户 A 看不到客户 B 的数据吗?发生过吗?
- 你一个人能服务这么多人吗? —— 以前 30 个客户你微信能回,100 个客户之后你的微信一天响 200 次
时间线和关键动作
| 周次 | 动作 | 交付物 |
|---|---|---|
| 第 1-2 周 | 加多租户隔离、权限系统 | 客户数据不会互相泄漏 |
| 第 3-4 周 | 加性能优化(索引、缓存) | 数据库 CPU < 50% |
| 第 5-6 周 | 加监控(Sentry + 日志) | 你比客户先知道系统出了问题 |
| 第 7-8 周 | 接通 Stripe / 支付宝,开始试探性收费 | 有人真的愿意付钱 |
| 第 9-10 周 | 根据付费客户反馈,修付费后暴露的新问题 | Beta 完成,进入 GA |
这个阶段最该避免的坑
不要等到 Beta 才想商业模式。 Beta 用户里有 10 个说「我会付钱」——在 Beta 结束前让其中 3 个真的付了钱。「我会付钱」和「我付了钱」中间隔着的不是一句话,是决策链条。
阶段五:规模化(持续)
做什么?
从 500 个付费客户到 5000、50000。重点从「功能开发」转移到「稳定性、可扩展性、标准化」。
| 里程碑 | 核心动作 |
|---|---|
| 500 付费客户 | CI/CD 自动化、监控告警体系 |
| 2000 付费客户 | 服务拆分(把对账引擎拆成独立服务) |
| 5000 付费客户 | 数据库读写分离、缓存体系 |
| 20000 付费客户 | 多区域部署、SLA 承诺、7×24 on-call |
总时间线全景图
Week 1: 概念验证(纸面原型 / 静态页面)
Week 2-5: MVP 开发 + 第一个客户试用
Week 6-11: Alpha 内测(10-30 个客户,陪跑 + 改设计)
Week 12-21: Beta 公测(100-500 个客户,性能 + 多租户 + 收费)
Week 22+: 规模化(持续优化和扩展)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
总计:约 5-6 个月从 idea 到付费产品
软件的迭代速度到底有多快?
一个具体数据:
| 你的动作 | 耗时 |
|---|---|
| 客户报告一个 bug | — |
| 你在 IDE 里找到问题 | 3 分钟 |
| 改 3 行代码 | 1 分钟 |
git push → GitHub Actions 自动 Build + Deploy | 3 分钟 |
| 客户刷新页面,bug 修好了 | — |
| 从报告到修复的总时间 | 7 分钟 |
同样的 bug,如果是硬件(比如固件 bug),你需要:改代码 → 编译 → 拿烧录器刷固件 → 测试 → 如果客户已经收到货了,还要远程 OTA 或召回 → 从报告到修复的总时间可能是 1-7 天。
这种迭代速度的差异,决定了软件创业可以用「快速试错、小步快跑」的方式验证方向。硬件创业必须在「试错窗口」关闭(开模)之前,想清楚大部分关键设计。