refactor(ECR-004): Synastry 再拆、Scale 测、Membership 守卫、OpenAPI 与 CI
ci / h5 (push) Canceled after 0s
ci / api (push) Canceled after 0s
ci / ess-docs (push) Canceled after 0s

压合盘贴线文件;补选答单测与 nil 守卫;对齐关键 OpenAPI schemas;加 GitHub Actions 门禁。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jackyu66git
2026-08-05 21:06:14 +08:00
co-authored by Cursor
parent 67701d1f7b
commit 7034c92de7
22 changed files with 1317 additions and 543 deletions
+191 -1
View File
@@ -50,7 +50,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/Envelope'
$ref: '#/components/schemas/EnvelopeProfileList'
post:
tags: [profile]
summary: 创建个人档案
@@ -372,6 +372,10 @@ paths:
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/EnvelopeScaleList'
/api/v1/scales/{slug}:
get:
@@ -416,6 +420,10 @@ paths:
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/EnvelopeAskQuota'
/api/v1/ask/threads:
post:
@@ -505,6 +513,10 @@ paths:
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/EnvelopeMembershipMe'
/api/v1/orders:
post:
@@ -566,3 +578,181 @@ components:
kind: { type: string, enum: [membership, deep_access] }
plan: { type: string, description: month|quarter|year when membership }
report_id: { type: string, format: uuid, description: when deep_access }
# --- Aligned with packages/types (ECR-004) ---
Profile:
type: object
required: [id, user_id, relation, display_name, birth_date, created_at]
properties:
id: { type: string, format: uuid }
user_id: { type: string, format: uuid }
relation: { type: string, enum: [self, other] }
display_name: { type: string }
birth_date: { type: string, format: date }
birth_time: { type: string, nullable: true }
birth_place: { type: string, nullable: true }
relation_type: { type: string, nullable: true }
geo_lat: { type: number, nullable: true }
geo_lng: { type: number, nullable: true }
geo_visible: { type: boolean }
created_at: { type: string, format: date-time }
GrowthReport:
type: object
required: [id, user_id, profile_id, type, summary, has_deep_access, created_at]
properties:
id: { type: string, format: uuid }
user_id: { type: string, format: uuid }
profile_id: { type: string, format: uuid }
type: { type: string }
summary: { type: object, additionalProperties: true }
detail: { type: object, nullable: true, additionalProperties: true }
has_deep_access: { type: boolean }
created_at: { type: string, format: date-time }
MembershipMe:
type: object
required: [active, status]
properties:
active: { type: boolean }
plan: { type: string }
status: { type: string }
expires_at: { type: string, format: date-time, nullable: true }
ask_quota_left: { type: integer }
ScaleSummary:
type: object
required: [slug, title, description]
properties:
slug: { type: string }
title: { type: string }
description: { type: string }
ScaleQuestionOption:
type: object
required: [key, text]
properties:
key: { type: string }
text: { type: string }
ScaleQuestion:
type: object
required: [id, sort, body]
properties:
id: { type: string, format: uuid }
sort: { type: integer }
body:
type: object
required: [prompt, options]
properties:
prompt: { type: string }
options:
type: array
items: { $ref: '#/components/schemas/ScaleQuestionOption' }
ScaleDetail:
type: object
required: [slug, title, description, questions]
properties:
slug: { type: string }
title: { type: string }
description: { type: string }
questions:
type: array
items: { $ref: '#/components/schemas/ScaleQuestion' }
ScaleSubmitResult:
type: object
required: [id, result]
properties:
id: { type: string, format: uuid }
result: { type: object, additionalProperties: true }
AskQuota:
type: object
required: [active_membership, remaining, free_limit, source]
properties:
active_membership: { type: boolean }
remaining: { type: integer }
free_limit: { type: integer }
source: { type: string }
AskThread:
type: object
required: [id, user_id, profile_id, created_at]
properties:
id: { type: string, format: uuid }
user_id: { type: string, format: uuid }
profile_id: { type: string, format: uuid }
scene: { type: string, nullable: true }
created_at: { type: string, format: date-time }
AskMessage:
type: object
required: [id, thread_id, role, content, created_at]
properties:
id: { type: string, format: uuid }
thread_id: { type: string, format: uuid }
role: { type: string, enum: [user, assistant] }
content: { type: string }
created_at: { type: string, format: date-time }
ImageCardScene:
type: object
required: [key, label]
properties:
key: { type: string }
label: { type: string }
ImageCardQuota:
type: object
required: [remaining, daily_free, unlimited]
properties:
remaining: { type: integer }
daily_free: { type: integer }
unlimited: { type: boolean }
EnvelopeProfileList:
allOf:
- $ref: '#/components/schemas/Envelope'
- type: object
properties:
data:
type: object
properties:
items:
type: array
items: { $ref: '#/components/schemas/Profile' }
EnvelopeGrowthReport:
allOf:
- $ref: '#/components/schemas/Envelope'
- type: object
properties:
data: { $ref: '#/components/schemas/GrowthReport' }
EnvelopeMembershipMe:
allOf:
- $ref: '#/components/schemas/Envelope'
- type: object
properties:
data: { $ref: '#/components/schemas/MembershipMe' }
EnvelopeScaleList:
allOf:
- $ref: '#/components/schemas/Envelope'
- type: object
properties:
data:
type: object
properties:
items:
type: array
items: { $ref: '#/components/schemas/ScaleSummary' }
EnvelopeAskQuota:
allOf:
- $ref: '#/components/schemas/Envelope'
- type: object
properties:
data: { $ref: '#/components/schemas/AskQuota' }