Music Bar Street · 音乐酒吧街Demo · UI · GitHub
下载完整资料包联系作者 / 讨论合作

接口约定

以下是一期业务 API 的设计,不是现成的服务地址。统一前缀 /api/v1,JSON 用 camelCase。公开主键为 UUID,金额是整数分,日期时间用带偏移的 RFC 3339,并保留 timezone。

通用规则

需要登录的请求带 Authorization: Bearer <session>,会话在服务端核对。公开浏览接口只返回已公开且审核通过的数据。操作者 ID 从会话取得,不能让请求体替用户指定发起方。

成功结果含 data 与 requestId;失败含 error.code、error.message、error.details 与 requestId。列表使用 cursor、limit,默认 20、最大 100,返回 nextCursor,排序固定并带 ID 作为末级排序。

创建投递、邀约、确认、消息、订单动作和会员购买意向带 Idempotency-Key。服务端按账号、操作、幂等键和请求摘要保存结果;同键同内容返回原结果,同键不同内容返回 409。幂等记录保留时间由实现配置,至少覆盖客户端重试周期;唯一约束仍作为最终防线。

修改资料和需求携带 expectedVersion。修改合作条件创建新版本,不能覆盖旧版本。确认携带 expectedTermsVersion;订单变更携带 expectedOrderVersion。

登录、资料和审核

方法与路径 输入 结果和规则
POST /auth/challenges phone, purpose challengeId, expiresAt;频率限制,不回显验证码
POST /auth/sessions challengeId, code session, expiresAt, account;短信服务商待选
DELETE /auth/session 无 当前会话失效
GET /me 无 自己的身份、账号和资料状态
PUT /me/venue expectedVersion, name, city, address, description, licenseMediaId 自己的酒吧资料;私有证件不回到公开接口
PUT /me/artist expectedVersion, name, city, styles, introduction, rateUnit, rateMinor, mediaIds 自己的艺人资料;媒体用途和所有者核对
POST /me/venue/review expectedVersion 提交酒吧审核
POST /me/artist/review expectedVersion 提交艺人审核
GET /artists city, style, cursor, limit 公开艺人列表;不返回手机号和私有资料
GET /artists/{id} 无 公开艺人主页和已可用作品
GET /venues/{id} 无 公开酒吧主页
GET /me/artist/calendar from, to 本人档期说明与订单占用
POST /me/artist/calendar startsAt, endsAt, kind, note 增加本人档期说明;不覆盖订单占用
DELETE /me/artist/calendar/{id} expectedVersion 仅删除本人手工录入的说明

需求、投递和邀约

方法与路径 输入 结果和规则
GET /demands city, style, from, to, cursor, limit OPEN 且可公开的需求
POST /demands startsAt, endsAt, timezone, budgetMinor, artistType, requirements 本人酒吧的需求;审核、会员额度和时间检查
PATCH /demands/{id} expectedVersion, 可修改字段 本人且仍可修改的需求;不能改已确认订单
POST /demands/{id}/close expectedVersion, reason 关闭本人需求,停止新投递
POST /demands/{id}/applications message 当前艺人的投递;已有记录时返回同一记录
GET /demands/{id}/applications cursor, limit 需求所属酒吧可查看投递
POST /applications/{id}/withdraw reason 当前投递艺人撤回
POST /applications/{id}/select 无 需求所属酒吧建立或返回洽谈
POST /applications/{id}/reject reason 需求所属酒吧拒绝投递
POST /invitations artistId, proposedTerms 本人酒吧发起邀约;邀请不是订单
GET /me/invitations direction, cursor, limit 自己发出或收到的邀约
POST /invitations/{id}/respond decision: ACCEPT / REJECT, message 收件艺人回应;接受时建立洽谈
POST /invitations/{id}/withdraw reason 发件酒吧撤回未完成邀约

条件和订单

方法与路径 输入 结果和规则
GET /negotiations/{id} 无 参与方可读当前条件、确认情况、消息会话
POST /negotiations/{id}/agreement-versions expectedTermsVersion, terms 参与方提新条件;清空当前确认,旧版本保留
POST /negotiations/{id}/confirm expectedTermsVersion 记录本人确认;第二方确认时事务内创建订单并占用档期
POST /negotiations/{id}/cancel reason 订单前终止洽谈并留记录
GET /me/orders status, cursor, limit 自己参与的订单
GET /orders/{id} 无 参与方订单快照、状态和历史事件
POST /orders/{id}/complete expectedOrderVersion 演出结束后记录本人完成;另一方确认后完成
POST /orders/{id}/cancellation-requests expectedOrderVersion, reason 发起取消请求;暂不释放档期
POST /orders/{id}/cancellation-requests/{requestId}/respond decision, reason 另一方回应;同意后取消,分歧进入争议
POST /orders/{id}/change-requests expectedOrderVersion, terms, reason 提出改期或改价,不直接改订单
POST /orders/{id}/change-requests/{requestId}/respond decision 另一方同意后事务内替换当前版本与档期,保留旧记录
POST /orders/{id}/disputes expectedOrderVersion, reason 记录争议,不自动扣款或裁定

取消、变更和争议的子记录可使用 order_events 保存提案和回应,具体表拆分可在实现时确定。每个提案有独立 UUID,只允许回应尚待回应的同一提案;过期订单版本不能覆盖新结果。

一次确认请求:

{"expectedTermsVersion": 3}

一方已确认、另一方还没确认:

{
  "data": {
    "termsVersion": 3,
    "confirmations": {"venue": true, "artist": false},
    "order": null
  },
  "requestId": "example-request-1"
}

双方确认后返回同一份订单 ID。档期冲突返回 409 ARTIST_UNAVAILABLE,整次事务回滚。

一份条件示例:

{
  "startsAt": "2026-11-07T23:00:00+08:00",
  "endsAt": "2026-11-08T01:00:00+08:00",
  "timezone": "Asia/Shanghai",
  "priceUnit": "PER_GIG",
  "quantity": "1",
  "unitPriceMinor": 120000,
  "totalMinor": 120000,
  "currency": "CNY",
  "requirements": "双人演出,场地提供音响;彩排时间另行确认。",
  "cancellationTerms": "取消与改期先协商,结果保存在订单记录中。"
}

quantity 是最多两位小数的正十进制字符串;服务端用十进制计算 unitPriceMinor × quantity,四舍五入到分,核对 totalMinor。PER_GIG 的 quantity 按场数,PER_HOUR 按已约定收费小时数,不能在 UI 里静默切单位。

媒体、消息、会员与运营

方法与路径 输入 结果和规则
POST /media/upload-intents purpose, filename, contentType, sizeBytes mediaId, 短期上传授权;客户端不传目标 Bucket
POST /media/{id}/upload-complete 无 核对对象后更新本人资源上传状态
GET /media/{id}/access 无 根据公开状态或本人/审核权限返回短期地址或播放授权
POST /callbacks/media/{provider} 供应商事件 核对来源与事件 ID,重复处理返回原结果
GET /conversations/{id}/messages cursor, limit 仅参与方,按游标读取
POST /conversations/{id}/messages clientMessageId, body 仅参与方发文字消息,长度 1–2000 字符
PUT /conversations/{id}/read-cursor lastMessageId 只更新自己读到的会话消息
GET /membership/plans 无 套餐、权益及当前购买方式
POST /membership/purchase-intents planId 未接支付时登记意向;不能假装开通会员
GET /me/membership 无 本人酒吧的权益和有效期
POST /membership/orders planId 支付接通后才启用,服务端锁定价格快照
POST /callbacks/payments/{provider} 供应商支付事件 启用后核实支付事实,一次开通
GET /ops/reviews type, cursor, limit 审核权限;不对普通账号开放
POST /ops/reviews/{id}/decisions decision, reason 审核权限,保存审计
POST /ops/resources/{type}/{id}/suspend reason 受控下架,不删除历史订单
GET /ops/dashboard from, to 只读权限,明确统计口径
POST /ops/orders/{id}/dispute-decisions expectedOrderVersion, decision, reason 争议处理权限;保存裁定记录,不代替支付操作

媒体和支付回调不靠普通登录会话授权,要按供应商验证方式核对。运营身份由受控配置或授权记录管理,客户端不能注册成为运营。

HTTP 与业务错误

400 输入不合法;401 未登录或会话失效;403 无权限;404 资源不存在或不可见;409 版本、档期、名额或幂等冲突;422 当前状态不允许操作;429 频率限制;503 外部服务暂不可用。

服务端错误不回传堆栈和凭证。上传授权或支付服务失败要能重新发起同一业务记录,不产生一排重复订单。当前只有接口设计,还没有实现这些 HTTP 接口。