项目矩阵 SaaS · 增长向 Dimage-studio
DDora 主维护 · 设计师向 AI SaaS · 多 vertical

image-studio

基于 Azure OpenAI 的多 vertical 图像生成 SaaS · 主域 design.mvp.restry.cn

面向中国境内设计师 / 推广号 / 个人创作者的专业 AI 出图 SaaS。用户不用为 OpenAI 国际版操心信用卡和网络、不用本地折腾 Stable Diffusion 的算力与模型选型、也不用为 Midjourney 月费犹豫 — 微信扫码登录、微信支付充值、按张扣积分,一站式跑通。后端是 Azure OpenAI gpt-image-2/15(国内可用),按场景拆三个 vertical:/pack 包装设计、/general 通用海报/写真、/generate 自由文生图。登录与支付一律不自建,统一走自家 wx-gateway 多租户网关,省掉公众号和商户号的重复申请。

访问 design.mvp.restry.cn 分支 pack · prod 实跑 Restry/image-studio · private
3
Verticals · pack/general/generate
27
Prisma 表 · Postgres
15%
邀请返佣 · 首充结算
3789
pm2 port · design 域

核心能力 · Five Capabilities

5 件事,用户进来就能扫码出图付款

每个能力先讲"用户/业务上拿到什么",再补一行真实路径与 commit。所有能力共一条边界:登录与支付一律不自建,走 wx-gateway 多租户;模型路由一律走 src/lib/azure.ts,业务代码不直连 Azure。

多 vertical 分包
launcher → 子路由
/ 是品牌中性 launcher,按场景跳 /pack(包装)/ /general(写真)/ /generate(自由)。同库不同入口,各自素材池与卡片样式。
7043613 · 124e779 · subroute split
Azure OpenAI 集中路由
国内可用 · 一份 key 多 vertical
gpt-image-2 / gpt-image-15 走自家 Azure 部署,worker max_global=8 · max_per_user=3。三 vertical 共一份 endpoint 配置,管理后台可改。
lib/azure.ts · AIModel × AIEndpoint
微信扫码登录
走 wx-gateway · 零配置
不自建公众号,接入 wx-gateway 业务方 design-studio-prod,扫码经平台公众号统一回调。Path A 自家 OAuth 已删除(257920b)。
8390d56 · 257920b · /wx/qr/[app]
微信支付 JSAPI
统一收银台 · 商户号托管
充值不接腾讯官方,POST /api/checkout/startcheckoutUrl redirect 到网关付款页。回调 webhook 加积分事务幂等。
62a67ea · c5ef489 · d02f73b
历史图一键编辑
gallery → /generate 预填
画廊卡片悬浮「编辑」按钮,点击跳 /generate 并把原图填入 sourceImage,保留 view-large 单击查看大图行为。
84d0551 · 2539695 · hover-overlay

架构 · User → image-studio → 3 deps

一张图看清:浏览器 / 微信 H5 → image-studio → Azure & 网关 & 支付

应用本体是一份 Next.js + Prisma + Postgres,内部三 vertical 共库共 worker 池;对外依赖压到 3 个:Azure OpenAI(出图)、wx-gateway(登录)、wxpay(付款,也走 wx-gateway)。

End Users
浏览器 / 微信 H5 扫码登录 · 看图 · 充值 · 出图
HTTPS · design.mvp.restry.cn
Application (single Next.js · 3 verticals)
image-studio · pm2 port 3789
design.mvp.restry.cn
Next.js · React · Prisma 6 · Postgres image_studio
/pack
包装设计垂类
/general
海报/写真垂类
/generate
自由文生图
图生 扫码登录 · OAuth 充值 · webhook
External dependencies (3)
AI · Inference
Azure OpenAI
gpt-image-2 / gpt-image-15 部署 · 国内可用 · worker max_global=8 / max_per_user=3
Auth · WeChat MP
wx-gateway
app 名 design-studio-prod · 平台公众号统一回调 · 扫码 + OAuth
Pay · WxPay v3
wxpay (via gateway)
JSAPI · 网关统一收银台页 · webhook → /api/wx/payment-webhook · 加积分幂等
Azure OpenAI 图生 wx-gateway 扫码 / OAuth wxpay 统一收银

关键里程碑 · Timeline

近 30 commits · 4 个结构性里程碑

从首页改造与登录沉浸式开场,中段做完两步支付集成切到网关统一收银,再把素材体系拆 vertical,末段补 gallery 一键编辑 + middleware 双因子放行。⭐ 标记的是结构性里程碑。

2026-04-19 登录加扫码:8390d56 加 wx-gateway 扫码登录与 OAuth 并行;ccf35ddpublicBase() 修代理 host 泄漏 127.0.0.1:3789
2026-04-22 个人中心首版:581c60c 顶栏头像 + /me 页 · cbb12f4 已登录跳 /generate + 扫码主导布局。
2026-04-26 ★ 里程碑Path A 自家 OAuth 删除(257920b)· 微信登录路径统一收敛到平台公众号 + wx-gateway,本项目不再独立备案。
2026-04-29 首页大改:266e9f6 撤水印 + 拆登录/注册 + hero showcase + 统一卡片 + 搜索 + hover info · 1d8f0f7 用 masonic 替换假 CSS columns 瀑布流。
2026-05-02 ★ 里程碑wxpay_jsapi 集成 via wx-gateway(62a67ea)· 充值不接腾讯官方,POST /api/checkout/start/pay/create 走网关,落 Payment 表 + webhook 加积分。
2026-05-05 ★ 里程碑统一收银台页(c5ef489)· 弃 wx.chooseWXPay 客户端 API,直接 window.location.href = checkoutUrl 跳网关付款页 — 修了 iOS H5 内不稳的多端问题。
2026-05-08 ★ 里程碑多 vertical 拆分(7043613)· 根域变 launcher,拆 /pack + /general 子路由,接 design-studio wx 网关;124e779 中性 root brand + general 写真卡片 modal 交互。
2026-05-10 登录沉浸式:dec9ca0 单列 glass card on 全屏品牌海报 · 293b9f9 更浅覆盖让海报透出 · 95ff783 撤 filler copy 留白。
2026-05-13 Gallery 一键编辑:84d0551 历史图悬浮「编辑」按钮跳 /generate 预填 sourceImage · 2539695 修编辑 affordance 不抢 view-large 单击。
2026-05-15 Admin 双因子放行:79df947 middleware 在 /api/images · user/uploads 上同时认 session-tokenadmin-session-token,后台可直查用户素材。
2026-05-17 Hermes 项目记忆落盘:01c08ab hermes-agent skill + 13be9c7 项目 memory.md(修正 SKILL 误写 SQLite,实跑 Postgres)。

名场面 · 1 个最值钱的坑(深度)

微信支付两步走:从 wx.chooseWXPay 到网关统一收银台

这条不是一次性踩坑,是相隔三天的两个 commit。先用客户端 JSAPI 接进来,iOS 微信内置浏览器不稳;改走网关托管的统一收银台页。背后真正想解决的不是 SDK bug,是商户号资质要不要每个 MVP 项目各自申请一份这个根本问题。

HALL OF FAME · WxPay JSAPI Pitfall

充值链路从 wx.chooseWXPay 切到 /pay/checkout/[id] 网关统一收银

症状
62a67ea 上线后,微信内浏览器可拉起付款,但 iOS 微信 H5 / 外部浏览器有概率拉不起 — 用户截图找客服,日志里 WeixinJSBridge is not defined 间歇出现。同时商户号 v3 平台证书 + secret + AppID 散落在每个 MVP 项目各自的 .env,谁泄漏谁背锅。
根因
微信支付有两条调起路径:客户端 JSAPI(wx.chooseWXPay)只在微信内置浏览器 + 公众号 OAuth 拿到 openid 后稳定,在 H5 外部浏览器和部分 webview 必断;JSAPI 走网关统一收银台则由网关侧 redirect 到带签名的付款页、由网关侧调起再 redirect 回业务方 — 这条路把 SDK 调起的环境检查、商户号配置、回调验签全收口到一处。
修法
(1) 62a67ea 集成 wxpay_jsapi via wx-gateway:POST /api/checkout/start → 网关 /pay/create,落 Payment(status=pending){ payOrderId, checkoutUrl }。(2) c5ef489 改用统一收银台页:前端直接 window.location.href = checkoutUrlhttps://wx.mvp.restry.cn/pay/checkout/[id],弃 wx.chooseWXPay。(3) Webhook → /api/wx/payment-webhook 事件 payment.paid 加积分事务幂等(39c9948)。
commit
62a67ea 接入 · d02f73b /topup 加 wxpay 按钮 · c5ef489 切统一收银 · 79df947 middleware 双因子放行后台可查 Payment。
// app/api/checkout/start/route.ts
const r = await fetch(`${WX_GATEWAY_BASE}/pay/create`, {
  method: 'POST',
  headers: hmacHeaders(WX_GATEWAY_APP_NAME, WX_GATEWAY_SECRET, body),
  body: JSON.stringify({ openid, amountFen, returnUrl: '/topup?paid=1' })
})
const { payOrderId, checkoutUrl } = await r.json()
await prisma.payment.create({ data: { payOrderId, userId, status: 'pending', ... } })
// 前端拿到 checkoutUrl 后:window.location.href = checkoutUrl  ← c5ef489 切点
沉淀:微信支付永远走网关统一,业务方代码里不出现商户号 secret。同公司 MVP 矩阵复用同一份 wxpay 商户号(由 wx-gateway 集中托管证书 + 回调 fanout),新 MVP 接入只配 WX_GATEWAY_APP_NAME / SECRET 两个 env;客户端别再用 wx.chooseWXPay,统一 redirect 收银台页,iOS / Android / 外部浏览器一套行为。这条与微信登录走 wx-gateway(257920b 删 Path A)是同一条铁律的两面。

📊 当前现状 · Status

五个维度,逐条带具体数字 / 表名 / commit / 域名

不写"功能正常 / 反馈良好"这种话。下面五个分组每条都对应可 grep 的事实:生产部署 / 数据规模 / 接入依赖 / 最近 7 天主要变动 / 运维状态。

生产部署

  • 主域:design.mvp.restry.cn · pm2 端口 3789 · nginx 反代
  • PM2 进程:image-studio(prod 跑 pack 分支,不是 main)
  • 部署链路:mvp-deployer(deploy.mvp.restry.cn)zip → manifest → 异步 build → Caddy 自动 HTTPS
  • 同主机邻居:packsmith(3792)· image-studio-test(3790)
  • 隐藏后台:/mgmt-7bx3k · middleware 双因子放行,不在任何导航

数据规模

  • 27 张表(schema.prisma):User · Session · WechatAccount · AccessKey · AdminSession
  • 出图域:AIModel · AIEndpoint · Generation · GeneratedImage · Prompt · PromptImage · UserUpload
  • 积分/支付:CreditLedger · TopupCode · TopupHistory · TopupRequest · Payment
  • 增长域:Invite · CheckIn · WelcomeBonusLog · Announcement · Notification · Feedback
  • 独立 Postgres 库:共享 host docker 127.0.0.1:5432 · db / user image_studio

接入依赖(3 个外部)

  • wx-gateway:app 名 design-studio-prod(不是 image-studio!)· 网关 https://wx.mvp.restry.cn · 同时承担扫码登录 + wxpay JSAPI
  • Azure OpenAI:gpt-image-2 / gpt-image-15 部署 · 国内可用 · 凭据在 vault image-studio/AZURE_OPENAI_* · 重试只重 5xx,429 透传(见债务 P0)
  • mvp-deployer:https://deploy.mvp.restry.cn · token 在 vault mvp-deployer/TOKEN · 禁 SSH 走人工,全 HTTP API

最近 7 天主要变动(git log)

  • 13be9c7 docs(hermes): add project memory + fix SKILL stack(PG 不是 SQLite)
  • 79df947 fix(middleware): allow admin token for dual-auth /api routes
  • 2539695 fix(gallery+generate): edit affordance preserves view-large click
  • 84d0551 feat(gallery): 一键编辑 button → /generate 预填 sourceImage
  • 124e779 feat(brand): neutral root brand + /general 写真卡片 modal 交互
  • c5ef489 feat(payment): 切 wx-gateway unified checkout page
  • d02f73b feat(payment): /topup 加 wxpay 按钮
  • 62a67ea feat(payment): 集成 wxpay_jsapi via wx-gateway

运维状态

  • 微信扫码 + wxpay 通:统一收银台后,iOS / 外部浏览器拉起问题不复发,客服无 SDK 相关工单
  • 新人风控三维上线(32c55e0):IP / 设备指纹 / openid 三维去重 + WelcomeBonusLog 全留痕,异常注册可回溯
  • 邀请返佣 + 首充结算(8f3d0fc):邀请人 15% / 被邀人 10% / 单人封顶 1000,事务幂等
  • worker 限流:max_global=8 · max_per_user=3,高峰排队但不雪崩;Azure 429 透传到用户为已知坑
  • 分支策略:prod 跑 pack,main 停在 2539695 · 不直合 main
  • gitnexus 索引:2470 symbols / 3976 relationships / 106 flows 已建

🚧 未结清债务 · Open Debt

8 条具体待办 · 每条带优先级 / 工作量 / 现状

不写"P1 待办 N 条"这种模糊罗列。每条 4 列:优先级(P0 立刻 / P1 本周 / P2 排期) · 工作量(S < 0.5d · M 1-2d · L 3d+) · 待办 · 现状是什么(看了就知道离修好还差什么)。来源:.hermes/memory.md §6 历史踩坑 + README 已知问题 + 近 30 commits 中 fix 标注。

优先级 工作量 待办 现状(还差什么)
P0 M Azure 429 配额耗尽透传到用户 现状:src/lib/azure.ts:78-83 只重试 5xx,429 直接透出 "We are currently servicing too many requests"。修法 A:加 Retry-After 退避 + 队列降级;B:portal 申请扩配额。memory §6.5 标 "等拍板未实施"。
P0 S pack 分支与 main 分叉 prod 实跑 pack,main 停在 2539695 不能直合。当前靠人脑记"别合 main",一旦误操作 prod 回退。需流程化:CI 阻止 PR 到 main / pack 单向 merge / 或把 pack 设默认分支。
P1 M 部署 zip 漏带未提交修改 memory §6.2 铁律:zip 前必 git stash -u 或先 commit/push,否则"功能消失"。当前靠人记,缺 pre-deploy 钩子检查 working tree dirty 即阻止。
P1 M prisma migrate deploy 未进 postDeploy memory §6.3:v2 deployer 不自动跑 migrate,必须放 manifest.postDeploy。漏放就出现 WxFinalizeLog 这类新表 P2021 报错。需把 migrate 步骤固化进项目模板 manifest。
P1 S DATABASE_URL 密码被 mask 成 *** memory §6.4:/api/inventory 拉到的 DATABASE_URL 密码是 ***,重灌就 P1000 鉴权失败。修法:inventory 跳过敏感字段 + 文档要求从 vault 取真值 vault get image-studio/DATABASE_URL
P1 L 部署素材包瘦身常态化 memory §6.1:legacy public/prompts/<legacy>/* 排除后从 125MB → 29MB,只留 xiaofang 120 目录。后续素材增长需常态策略:CDN 托管 / 按 vertical 拆 zip / 增量部署。
P2 M 三 vertical 共用 worker 池 当前 max_global=8 是全 vertical 共池,高峰 /pack 把 /general 挤队。需按 vertical 分配配额或按订阅等级优先级队列。
P2 S inbound webhook 失败无重投兜底 wx-gateway 推 payment.paid 失败,本地无重投。当前靠网关侧重试 + 5 分钟 query cron 兜底,但本项目缺 inbound webhook 失败队列与告警。

🛠 技术栈 · Stack

RuntimeNext.js · React · pnpm · PM2 DBPostgres · Prisma 6 AIAzure OpenAI · gpt-image-2/15 Authwx-gateway 扫码 + OAuth Paywxpay JSAPI · 网关收银 UIlucide-react · recharts · masonic Opsmvp-deployer · Caddy · nginx