Skip to main content

第二篇:可运行的 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 写的,但你需要:

  1. 人工验证第一轮匹配结果:挑 5 条手动对一遍
  2. 差异行标记清楚——宁可把「不确定」标出来,也不要把错的标成对的

其他的——变量命名、代码复用、错误处理——先放一放。它们重要,但不是现在。


什么时候进入下一阶段?

你已经验证了:

  • ✅ 技术方案可行:L 的真实数据跑通了
  • ✅ 核心价值成立:3 小时 → 3 秒的降幅是真实数字
  • ✅ 发现了真实的新需求:分次付款、部分退款等复杂场景

但你也在想:

  • 分次付款怎么处理?要不要支持退款匹配?
  • L 说「特别好用」,但这是不是只是因为她是你的朋友?
  • 还有没有完全不同的解法?比如不做手动上传,直接对接银行 API?

进入下一阶段的信号:你不确定哪种解法最好。

现在你对问题有了更深的认知,但你不知道应该沿着当前方向深化,还是换一个思路。这时候,做多原型发散——同时探索三个不同的方向,让真实的客户反馈帮你选。

这是第三篇的内容。


本篇总结

做了什么技术栈花了多久月费
Next.js + Prisma + Supabase 搭建Next.js, Prisma, PostgreSQL4 小时Supabase 免费
文件上传 + CSV 解析 APIPapaParse1 小时-
金额+日期匹配引擎TypeScript1 小时-
结果展示 + 差异标记 UIReact + Tailwind2 小时-
真实数据测试-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 天
2MVP能不能跑通核心流程?1-4 周
3Alpha 内测核心功能在真实用户手里用得住吗?2-6 周
4Beta 公测规模大一点会不会崩?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 周根据反馈修最痛的点,准备 AlphaMVP V2

MVP 最该避免的坑

不要在 MVP 阶段追求代码质量。 MVP 是用完就可能扔掉的东西。它的价值不在于代码能维护多久——在于「它让多少个客户说了『这就是我要的!』」。


阶段三:Alpha 内测(2-6 周)

做什么?

从 2-3 个客户扩展到 10-30 个。在真实使用场景里看产品能不能「用得住」。这时候你会遇到三类问题:

第一类:Bug(修了就好)

  • 上传某种格式的 CSV 报错 → 修解析器
  • 对账结果偶尔出现重复的匹配 → 加去重逻辑

第二类:交互问题(每个人都卡在同一个地方)

  • 第一次用的人有 60% 找不到「开始对账」按钮 → 需要改交互,不能靠培训
  • 差异确认后没有反馈,用户不知道自己操作成功了 → 改设计

第三类:需求偏差(你以为重要的东西,用户根本不用)

  • 你花了两天做的「对账报告导出」功能,没有一个人点开过
  • 你随便放的一个「通知销售」的按钮,点击率远高于你精心设计的「对账总结」页面

这个阶段最该避免的坑

不要试图通过「给用户录教程」来解决产品问题。 如果一个功能需要教程才能用,这个功能的设计本身就有问题。改设计,别录视频。


阶段四:Beta 公测(4-10 周)

做什么?

从 30 个客户扩展到 100-500 个。验证三件事:

  1. 性能撑得住吗? —— 100 个客户同时跑对账,数据库 CPU 会不会飙到 100%
  2. 多租户能正常工作吗? —— 客户 A 看不到客户 B 的数据吗?发生过吗?
  3. 你一个人能服务这么多人吗? —— 以前 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 + Deploy3 分钟
客户刷新页面,bug 修好了
从报告到修复的总时间7 分钟

同样的 bug,如果是硬件(比如固件 bug),你需要:改代码 → 编译 → 拿烧录器刷固件 → 测试 → 如果客户已经收到货了,还要远程 OTA 或召回 → 从报告到修复的总时间可能是 1-7 天。

这种迭代速度的差异,决定了软件创业可以用「快速试错、小步快跑」的方式验证方向。硬件创业必须在「试错窗口」关闭(开模)之前,想清楚大部分关键设计。