Initial commit: Happy Up monorepo through Sprint 5.
Document-driven MVP with FastAPI backend, Vue H5, WeChat mini shell, product demo, and Docker dev stack. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,922 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>儿童 AI 体态管理平台 · 系统架构与建设规划 V1.0</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #f4f7fb;
|
||||
--surface: #ffffff;
|
||||
--primary: #1a6fb5;
|
||||
--primary-dark: #0f4f86;
|
||||
--accent: #2bb673;
|
||||
--accent-soft: #e8f7ef;
|
||||
--warn: #e6a23c;
|
||||
--danger: #d9534f;
|
||||
--text: #1f2937;
|
||||
--text-muted: #6b7280;
|
||||
--border: #e5e7eb;
|
||||
--shadow: 0 4px 24px rgba(15, 79, 134, 0.08);
|
||||
--radius: 14px;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
line-height: 1.65;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
/* Hero */
|
||||
.hero {
|
||||
background: linear-gradient(135deg, #0f4f86 0%, #1a6fb5 45%, #2bb673 100%);
|
||||
color: #fff;
|
||||
padding: 56px 24px 48px;
|
||||
text-align: center;
|
||||
}
|
||||
.hero-badge {
|
||||
display: inline-block;
|
||||
background: rgba(255,255,255,0.18);
|
||||
border: 1px solid rgba(255,255,255,0.3);
|
||||
border-radius: 999px;
|
||||
padding: 6px 16px;
|
||||
font-size: 13px;
|
||||
margin-bottom: 20px;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
.hero h1 {
|
||||
font-size: clamp(26px, 4vw, 40px);
|
||||
font-weight: 700;
|
||||
margin-bottom: 12px;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
.hero p {
|
||||
font-size: 17px;
|
||||
opacity: 0.92;
|
||||
max-width: 680px;
|
||||
margin: 0 auto 28px;
|
||||
}
|
||||
.hero-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
justify-content: center;
|
||||
font-size: 13px;
|
||||
opacity: 0.85;
|
||||
}
|
||||
.hero-meta span {
|
||||
background: rgba(255,255,255,0.12);
|
||||
padding: 4px 12px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.hero-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
justify-content: center;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.hero-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px 28px;
|
||||
border-radius: 999px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
transition: transform 0.15s, box-shadow 0.15s;
|
||||
}
|
||||
.hero-btn-primary {
|
||||
background: #fff;
|
||||
color: var(--primary-dark);
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
|
||||
}
|
||||
.hero-btn-primary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 28px rgba(0,0,0,0.2);
|
||||
}
|
||||
.hero-btn-outline {
|
||||
background: rgba(255,255,255,0.12);
|
||||
color: #fff;
|
||||
border: 1.5px solid rgba(255,255,255,0.45);
|
||||
}
|
||||
.hero-btn-outline:hover { background: rgba(255,255,255,0.22); }
|
||||
|
||||
/* Floating demo entry */
|
||||
.fab-demo {
|
||||
position: fixed;
|
||||
right: 24px;
|
||||
bottom: 24px;
|
||||
z-index: 200;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 14px 22px;
|
||||
background: linear-gradient(135deg, var(--accent), #1e9e5a);
|
||||
color: #fff;
|
||||
border-radius: 999px;
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
box-shadow: 0 8px 32px rgba(43,182,115,0.45);
|
||||
transition: transform 0.15s;
|
||||
}
|
||||
.fab-demo:hover { transform: scale(1.04); }
|
||||
.fab-demo .icon { font-size: 18px; }
|
||||
|
||||
/* Layout */
|
||||
.container {
|
||||
max-width: 1100px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px 80px;
|
||||
}
|
||||
|
||||
/* Nav */
|
||||
.toc-bar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
background: rgba(255,255,255,0.95);
|
||||
backdrop-filter: blur(8px);
|
||||
border-bottom: 1px solid var(--border);
|
||||
padding: 10px 20px;
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.toc-bar a {
|
||||
display: inline-block;
|
||||
color: var(--text-muted);
|
||||
text-decoration: none;
|
||||
font-size: 13px;
|
||||
padding: 6px 14px;
|
||||
border-radius: 999px;
|
||||
margin-right: 4px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.toc-bar a:hover, .toc-bar a.active {
|
||||
background: var(--primary);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Sections */
|
||||
section {
|
||||
margin-top: 48px;
|
||||
}
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.section-num {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background: var(--primary);
|
||||
color: #fff;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.section-header h2 {
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
color: var(--primary-dark);
|
||||
}
|
||||
|
||||
/* Cards */
|
||||
.card {
|
||||
background: var(--surface);
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--shadow);
|
||||
border: 1px solid var(--border);
|
||||
padding: 28px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.card h3 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--primary-dark);
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 2px solid var(--accent-soft);
|
||||
}
|
||||
|
||||
/* KPI Grid */
|
||||
.kpi-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
gap: 16px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.kpi {
|
||||
background: linear-gradient(145deg, #fff, #f0f7ff);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
.kpi .value {
|
||||
font-size: 28px;
|
||||
font-weight: 800;
|
||||
color: var(--primary);
|
||||
line-height: 1.2;
|
||||
}
|
||||
.kpi .label {
|
||||
font-size: 13px;
|
||||
color: var(--text-muted);
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 14px;
|
||||
}
|
||||
th {
|
||||
background: #f0f6fc;
|
||||
color: var(--primary-dark);
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
padding: 11px 14px;
|
||||
border-bottom: 2px solid var(--border);
|
||||
}
|
||||
td {
|
||||
padding: 10px 14px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
vertical-align: top;
|
||||
}
|
||||
tr:last-child td { border-bottom: none; }
|
||||
tr:hover td { background: #fafbfc; }
|
||||
|
||||
/* Tags */
|
||||
.tag {
|
||||
display: inline-block;
|
||||
padding: 2px 10px;
|
||||
border-radius: 999px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.tag-must { background: #fde8e8; color: #c0392b; }
|
||||
.tag-should { background: #fef3cd; color: #856404; }
|
||||
.tag-could { background: #e8f4fd; color: #1a6fb5; }
|
||||
.tag-p0 { background: #fde8e8; color: #c0392b; }
|
||||
.tag-p1 { background: #e8f4fd; color: #1a6fb5; }
|
||||
.tag-p2 { background: #e8f7ef; color: #1e7e4a; }
|
||||
.tag-p3 { background: #f3e8ff; color: #6b21a8; }
|
||||
|
||||
/* Timeline */
|
||||
.timeline {
|
||||
position: relative;
|
||||
padding-left: 32px;
|
||||
}
|
||||
.timeline::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 8px;
|
||||
bottom: 8px;
|
||||
width: 3px;
|
||||
background: linear-gradient(to bottom, var(--primary), var(--accent));
|
||||
border-radius: 3px;
|
||||
}
|
||||
.timeline-item {
|
||||
position: relative;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
.timeline-item::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -26px;
|
||||
top: 6px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background: var(--surface);
|
||||
border: 3px solid var(--primary);
|
||||
border-radius: 50%;
|
||||
}
|
||||
.timeline-item h4 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--primary-dark);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.timeline-item .period {
|
||||
font-size: 13px;
|
||||
color: var(--accent);
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.timeline-item p {
|
||||
color: var(--text-muted);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* Mermaid */
|
||||
.mermaid-wrap {
|
||||
background: #fafbfc;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
overflow-x: auto;
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
|
||||
/* Alert boxes */
|
||||
.alert {
|
||||
border-radius: 10px;
|
||||
padding: 14px 18px;
|
||||
font-size: 14px;
|
||||
margin: 16px 0;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.alert-info { background: #e8f4fd; border-left: 4px solid var(--primary); }
|
||||
.alert-warn { background: #fef3cd; border-left: 4px solid var(--warn); }
|
||||
.alert-danger { background: #fde8e8; border-left: 4px solid var(--danger); }
|
||||
|
||||
/* Action checklist */
|
||||
.checklist { list-style: none; }
|
||||
.checklist li {
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px dashed var(--border);
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
font-size: 14px;
|
||||
}
|
||||
.checklist li::before {
|
||||
content: '☐';
|
||||
color: var(--primary);
|
||||
font-size: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.checklist li.done { color: var(--accent); font-weight: 600; }
|
||||
.checklist li.done::before { content: '✓'; color: var(--accent); }
|
||||
|
||||
/* Two column */
|
||||
.grid-2 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
footer {
|
||||
text-align: center;
|
||||
padding: 32px 20px;
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
border-top: 1px solid var(--border);
|
||||
margin-top: 60px;
|
||||
}
|
||||
|
||||
/* Print */
|
||||
@media print {
|
||||
.toc-bar { display: none; }
|
||||
.hero { padding: 24px; }
|
||||
section { page-break-inside: avoid; }
|
||||
.card { box-shadow: none; }
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.card { padding: 18px; }
|
||||
.kpi .value { font-size: 22px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Hero -->
|
||||
<div class="hero">
|
||||
<div class="hero-badge">商业交付包 V1.0 · 合伙人讨论稿</div>
|
||||
<h1>儿童 AI 体态管理平台</h1>
|
||||
<p>系统架构与建设规划 — 从 MVP 到商业试点的完整技术路线与落地节奏</p>
|
||||
<div class="hero-meta">
|
||||
<span>版本 V1.0</span>
|
||||
<span>2026-07-23</span>
|
||||
<span>目标用户 3–16 岁</span>
|
||||
<span>非医疗诊断 · 健康管理</span>
|
||||
</div>
|
||||
<div class="hero-actions">
|
||||
<a href="产品交互Demo.html" class="hero-btn hero-btn-primary">📱 进入产品交互 Demo</a>
|
||||
<a href="产品交互Demo.html#page-live-prep" class="hero-btn hero-btn-outline">🎥 AI 跟练 Demo</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TOC -->
|
||||
<nav class="toc-bar">
|
||||
<a href="#overview">项目定位</a>
|
||||
<a href="#architecture">系统架构</a>
|
||||
<a href="#modules">模块划分</a>
|
||||
<a href="#flow">核心流程</a>
|
||||
<a href="#tech">技术选型</a>
|
||||
<a href="#roadmap">建设规划</a>
|
||||
<a href="#team">团队分工</a>
|
||||
<a href="#security">安全合规</a>
|
||||
<a href="#risk">风险应对</a>
|
||||
<a href="#action">行动清单</a>
|
||||
<a href="产品交互Demo.html" style="background:var(--accent);color:#fff;margin-left:8px">📱 产品 Demo</a>
|
||||
</nav>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<!-- 1. Overview -->
|
||||
<section id="overview">
|
||||
<div class="section-header">
|
||||
<div class="section-num">1</div>
|
||||
<h2>项目定位与建设目标</h2>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>我们在做什么</h3>
|
||||
<p>面向 <strong>3–16 岁儿童青少年</strong> 的 AI 体态管理与运动康复平台,围绕含胸驼背、头前伸、高低肩、骨盆姿态、膝内扣、足弓与运动协调等常见问题,提供 AI 筛查、结构化报告、训练计划、打卡复测与机构 SaaS 运营闭环。</p>
|
||||
<div class="alert alert-danger" style="margin-top:16px">
|
||||
<span>⚠️</span>
|
||||
<span><strong>合规边界</strong>:平台输出用于健康管理与运动训练,<strong>不替代医院诊断</strong>。涉及疼痛、明显畸形、外伤或医生已明确限制运动的情况,必须提示线下专业评估。</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>试点阶段核心指标</h3>
|
||||
<div class="kpi-grid">
|
||||
<div class="kpi"><div class="value">≥90%</div><div class="label">分析任务达成率</div></div>
|
||||
<div class="kpi"><div class="value">≥80%</div><div class="label">报告 30 分钟内查看率</div></div>
|
||||
<div class="kpi"><div class="value">≥60%</div><div class="label">14 天训练完成率</div></div>
|
||||
<div class="kpi"><div class="value">≥50%</div><div class="label">60 天复测率</div></div>
|
||||
<div class="kpi"><div class="value">≥20%</div><div class="label">报告→课程转化率</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 2. Architecture -->
|
||||
<section id="architecture">
|
||||
<div class="section-header">
|
||||
<div class="section-num">2</div>
|
||||
<h2>总体系统架构</h2>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>分层架构</h3>
|
||||
<div class="mermaid-wrap">
|
||||
<pre class="mermaid">
|
||||
flowchart TB
|
||||
subgraph CLIENT["客户端层"]
|
||||
MP["微信小程序 / H5 家长端"]
|
||||
TR["儿童训练端"]
|
||||
AD["Web 管理后台"]
|
||||
end
|
||||
|
||||
subgraph GATEWAY["网关层"]
|
||||
GW["鉴权 JWT · 限流 · 审计 · requestId"]
|
||||
end
|
||||
|
||||
subgraph BIZ["业务服务层"]
|
||||
AUTH["Auth / User"]
|
||||
CHILD["Child Profile"]
|
||||
VIDEO["Video / Analysis"]
|
||||
TRAIN["Training"]
|
||||
COMM["Commerce"]
|
||||
OPS["Admin / Ops"]
|
||||
end
|
||||
|
||||
subgraph AI["AI 服务层(异步)"]
|
||||
VW["Video Worker"]
|
||||
POSE["Pose 服务"]
|
||||
SCORE["评分服务"]
|
||||
AGENT["Agent 解释"]
|
||||
end
|
||||
|
||||
subgraph DATA["数据设施层"]
|
||||
MYSQL[("MySQL 8.x")]
|
||||
REDIS[("Redis")]
|
||||
OSS[("对象存储 OSS")]
|
||||
LOG["日志 / 监控"]
|
||||
end
|
||||
|
||||
CLIENT --> GATEWAY --> BIZ
|
||||
BIZ --> AI
|
||||
BIZ --> DATA
|
||||
AI --> DATA
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>五大设计原则</h3>
|
||||
<div class="grid-2">
|
||||
<div>
|
||||
<p><strong>① 业务与 AI 解耦</strong><br>长任务异步化,HTTP 不阻塞,前端轮询/WebSocket 查状态。</p>
|
||||
</div>
|
||||
<div>
|
||||
<p><strong>② 全链路可追溯</strong><br>保留关键点、指标、模型版本、Agent 提示词版本。</p>
|
||||
</div>
|
||||
<div>
|
||||
<p><strong>③ 多租户隔离</strong><br>机构数据按 tenant_id 隔离,教练仅访问授权儿童。</p>
|
||||
</div>
|
||||
<div>
|
||||
<p><strong>④ 接口契约优先</strong><br>以 openapi.yaml 为单一事实来源,向后兼容扩展。</p>
|
||||
</div>
|
||||
<div>
|
||||
<p><strong>⑤ 幂等与审计</strong><br>写接口 Idempotency-Key;复核/退款/权限变更全量审计。</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 3. Modules -->
|
||||
<section id="modules">
|
||||
<div class="section-header">
|
||||
<div class="section-num">3</div>
|
||||
<h2>模块划分与职责</h2>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>业务服务模块</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>模块</th><th>职责</th><th>核心数据</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td><strong>Auth/User</strong></td><td>手机/微信登录、角色、租户</td><td>users, tenants</td></tr>
|
||||
<tr><td><strong>Child Profile</strong></td><td>儿童档案、成长指标、授权</td><td>children, child_measurements</td></tr>
|
||||
<tr><td><strong>Video/Analysis</strong></td><td>直传签名、任务、报告</td><td>videos, analysis_tasks, reports</td></tr>
|
||||
<tr><td><strong>Training</strong></td><td>动作库、计划、打卡、复测</td><td>exercises, training_plans</td></tr>
|
||||
<tr><td><strong>Commerce</strong></td><td>套餐、订单、会员权益</td><td>products, orders</td></tr>
|
||||
<tr><td><strong>Admin/Ops</strong></td><td>线索、看板、审计</td><td>operation_leads, audit_logs</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="grid-2">
|
||||
<div class="card">
|
||||
<h3>AI 服务组件</h3>
|
||||
<table>
|
||||
<thead><tr><th>组件</th><th>技术</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Video Worker</td><td>FFmpeg + 队列</td></tr>
|
||||
<tr><td>Pose 服务</td><td>MediaPipe Pose(33 关键点)</td></tr>
|
||||
<tr><td>评分服务</td><td>规则引擎 + 加权算法</td></tr>
|
||||
<tr><td>Agent 服务</td><td>LLM + 模板约束</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>Agent 角色分工</h3>
|
||||
<table>
|
||||
<thead><tr><th>Agent</th><th>输出</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Assessment</td><td>风险摘要、复核建议</td></tr>
|
||||
<tr><td>Coach</td><td>周期计划、每日动作</td></tr>
|
||||
<tr><td>Parent</td><td>家长可读报告文案</td></tr>
|
||||
<tr><td>Operation</td><td>线索分层、触达话术</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 4. Flow -->
|
||||
<section id="flow">
|
||||
<div class="section-header">
|
||||
<div class="section-num">4</div>
|
||||
<h2>核心业务流程</h2>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>家长端主流程</h3>
|
||||
<div class="mermaid-wrap">
|
||||
<pre class="mermaid">
|
||||
flowchart LR
|
||||
A["授权登录"] --> B["创建档案"]
|
||||
B --> C["拍摄上传"]
|
||||
C --> D["创建分析任务"]
|
||||
D --> E["AI 异步处理"]
|
||||
E --> F["生成报告"]
|
||||
F --> G["查看建议"]
|
||||
G --> H["训练打卡"]
|
||||
H --> I["复测对比"]
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>AI 分析异步链路</h3>
|
||||
<div class="mermaid-wrap">
|
||||
<pre class="mermaid">
|
||||
sequenceDiagram
|
||||
participant P as 家长端
|
||||
participant API as 后端 API
|
||||
participant Q as 消息队列
|
||||
participant W as AI Worker
|
||||
participant A as Agent
|
||||
|
||||
P->>API: POST /api/analysis/tasks
|
||||
API->>Q: 入队 QUEUED
|
||||
API-->>P: 返回 taskId
|
||||
|
||||
W->>Q: 拉取任务
|
||||
W->>W: 抽帧 + Pose + 指标计算
|
||||
alt 置信度不足
|
||||
W->>API: FAILED + 建议重拍
|
||||
else 置信度合格
|
||||
W->>A: 生成报告文案
|
||||
A->>API: 写入 report
|
||||
API-->>P: 推送/轮询 SUCCEEDED
|
||||
end
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<span>💡</span>
|
||||
<span><strong>MVP 最小闭环</strong>:家长 2 分钟内完成建档 + 视频上传 → 5 分钟内收到 AI 报告 → 报告含风险等级、指标解释、建议动作、免责声明。</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 5. Tech -->
|
||||
<section id="tech">
|
||||
<div class="section-header">
|
||||
<div class="section-num">5</div>
|
||||
<h2>技术选型建议</h2>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>MVP 推荐技术栈</h3>
|
||||
<table>
|
||||
<thead><tr><th>层级</th><th>推荐方案</th><th>说明</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>后端 API</td><td>Python FastAPI / Node.js NestJS</td><td>与 OpenAPI 契约对齐</td></tr>
|
||||
<tr><td>任务队列</td><td>Redis + Celery / BullMQ</td><td>分析任务削峰、重试</td></tr>
|
||||
<tr><td>数据库</td><td>MySQL 8.x</td><td>已有完整 schema</td></tr>
|
||||
<tr><td>对象存储</td><td>阿里云 OSS / MinIO</td><td>视频直传、生命周期归档</td></tr>
|
||||
<tr><td>AI 推理</td><td>MediaPipe Pose + Python Worker</td><td>一期快速落地</td></tr>
|
||||
<tr><td>Agent</td><td>大模型 API + Prompt 模板</td><td>输出受控、版本化</td></tr>
|
||||
<tr><td>家长端</td><td>微信小程序(Taro/uni-app)</td><td>覆盖微信生态</td></tr>
|
||||
<tr><td>管理后台</td><td>Vue 3 + Element Plus</td><td>高密度信息布局</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>环境规划</h3>
|
||||
<table>
|
||||
<thead><tr><th>环境</th><th>用途</th><th>要求</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>dev</td><td>日常开发联调</td><td>模拟支付、测试 OSS</td></tr>
|
||||
<tr><td>test</td><td>测试验收回归</td><td>数据可重置</td></tr>
|
||||
<tr><td>staging</td><td>预发布/客户演示</td><td>与生产同拓扑</td></tr>
|
||||
<tr><td>prod</td><td>正式服务</td><td>备份、监控、告警</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 6. Roadmap -->
|
||||
<section id="roadmap">
|
||||
<div class="section-header">
|
||||
<div class="section-num">6</div>
|
||||
<h2>分阶段建设规划</h2>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="timeline">
|
||||
<div class="timeline-item">
|
||||
<h4><span class="tag tag-p0">P0</span> 方案确认</h4>
|
||||
<div class="period">1 周</div>
|
||||
<p>范围、架构、数据、合规边界对齐。交付:PRD 签字、架构文档、接口/DB 契约、Git 工程初始化。</p>
|
||||
</div>
|
||||
<div class="timeline-item">
|
||||
<h4><span class="tag tag-p1">P1</span> MVP 研发</h4>
|
||||
<div class="period">4–6 周</div>
|
||||
<p>家长端 + 视频分析 + 报告 + 基础后台。交付:可演示版本、测试报告、staging 部署。</p>
|
||||
</div>
|
||||
<div class="timeline-item">
|
||||
<h4><span class="tag tag-p2">P2</span> 试点交付</h4>
|
||||
<div class="period">4 周</div>
|
||||
<p>接入 1–3 家机构,跑通筛查→课程闭环。交付:试点数据、运营 SOP、教练培训。</p>
|
||||
</div>
|
||||
<div class="timeline-item">
|
||||
<h4><span class="tag tag-p3">P3</span> 商业化增强</h4>
|
||||
<div class="period">6–8 周</div>
|
||||
<p>支付、权限、模型评估、生产运维。交付:商业版 V1.0、监控告警、备份演练。</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>P1 MVP 六周排期</h3>
|
||||
<table>
|
||||
<thead><tr><th>周次</th><th>模块</th><th>交付标准</th><th>优先级</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>W1</td><td>工程初始化 + Auth + 儿童档案</td><td>登录、建档 CRUD、DB 迁移</td><td><span class="tag tag-must">Must</span></td></tr>
|
||||
<tr><td>W2</td><td>视频上传链路</td><td>OSS 直传、视频登记、拍摄引导 UI</td><td><span class="tag tag-must">Must</span></td></tr>
|
||||
<tr><td>W3</td><td>AI Worker 骨架</td><td>抽帧 + MediaPipe + 基础指标</td><td><span class="tag tag-must">Must</span></td></tr>
|
||||
<tr><td>W4</td><td>报告生成 + Agent</td><td>结构化 report + 家长文案</td><td><span class="tag tag-must">Must</span></td></tr>
|
||||
<tr><td>W5</td><td>家长端小程序</td><td>建档→上传→看报告完整流程</td><td><span class="tag tag-must">Must</span></td></tr>
|
||||
<tr><td>W6</td><td>基础管理后台 + 联调</td><td>报告列表、任务监控、冒烟测试</td><td><span class="tag tag-should">Should</span></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="alert alert-warn" style="margin-top:16px">
|
||||
<span>📌</span>
|
||||
<span><strong>MVP 可后置</strong>:支付与会员、完整训练打卡、运营线索漏斗、多机构租户管理 → 放入 P2/P3。</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 7. Team -->
|
||||
<section id="team">
|
||||
<div class="section-header">
|
||||
<div class="section-num">7</div>
|
||||
<h2>团队分工建议</h2>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<table>
|
||||
<thead><tr><th>角色</th><th>人数</th><th>核心职责</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>产品负责人</td><td>1</td><td>需求拆解、验收标准、试点反馈闭环</td></tr>
|
||||
<tr><td>前端工程师</td><td>1</td><td>小程序/H5、儿童训练页、Web 后台</td></tr>
|
||||
<tr><td>后端工程师</td><td>1</td><td>API、任务队列、权限、数据模型</td></tr>
|
||||
<tr><td>算法工程师</td><td>1</td><td>关键点、评分规则、质量检测、Agent 约束</td></tr>
|
||||
<tr><td>测试/交付</td><td>0.5–1</td><td>场景测试、部署验证、SOP 落地</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 8. Security -->
|
||||
<section id="security">
|
||||
<div class="section-header">
|
||||
<div class="section-num">8</div>
|
||||
<h2>安全与合规架构</h2>
|
||||
</div>
|
||||
|
||||
<div class="grid-2">
|
||||
<div class="card">
|
||||
<h3>数据分级</h3>
|
||||
<table>
|
||||
<thead><tr><th>等级</th><th>类型</th><th>策略</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>L1 敏感</td><td>手机号、姓名、视频</td><td>加密/哈希、脱敏</td></tr>
|
||||
<tr><td>L2 业务</td><td>报告、训练、订单</td><td>MySQL + 租户隔离</td></tr>
|
||||
<tr><td>L3 衍生</td><td>关键点、指标 JSON</td><td>绑定任务、保留版本</td></tr>
|
||||
<tr><td>L4 运营</td><td>线索、看板聚合</td><td>脱敏聚合</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>合规硬性约束</h3>
|
||||
<ul class="checklist">
|
||||
<li>报告不得出现确诊、治疗、治愈等医疗表述</li>
|
||||
<li>Agent 输出引用输入字段,保留提示词版本</li>
|
||||
<li>低置信度 → 仅「建议重拍/教练复核」</li>
|
||||
<li>审计日志保留 ≥ 180 天</li>
|
||||
<li>写接口幂等保护(Idempotency-Key)</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 9. Risk -->
|
||||
<section id="risk">
|
||||
<div class="section-header">
|
||||
<div class="section-num">9</div>
|
||||
<h2>风险与应对</h2>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<table>
|
||||
<thead><tr><th>风险</th><th>影响</th><th>应对策略</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>AI 置信度不足</td><td>报告不可用、信任低</td><td>拍摄质量前置检测 + 降级文案</td></tr>
|
||||
<tr><td>医疗合规边界模糊</td><td>法律风险</td><td>PRD 约束 + Agent 过滤 + 人工复核</td></tr>
|
||||
<tr><td>MVP 范围膨胀</td><td>延期交付</td><td>严格 MoSCoW,支付/运营后置</td></tr>
|
||||
<tr><td>机构数据隔离</td><td>合作受阻</td><td>一期引入 tenant_id</td></tr>
|
||||
<tr><td>儿童个体差异大</td><td>误报/漏报</td><td>保留教练复核,不做全自动闭环</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 10. Engineering -->
|
||||
<section id="engineering">
|
||||
<div class="section-header">
|
||||
<div class="section-num">10</div>
|
||||
<h2>工程化进展(P3)</h2>
|
||||
</div>
|
||||
|
||||
<div class="grid-2">
|
||||
<div class="card">
|
||||
<h3>Monorepo 结构</h3>
|
||||
<pre style="background:#f8fafc;padding:14px;border-radius:10px;font-size:12px;line-height:1.6;overflow:auto">happy-up/
|
||||
├── contracts/ openapi + database.sql
|
||||
├── apps/api/ FastAPI Starter
|
||||
├── doc/ 商业交付文档包
|
||||
├── docker-compose.yml
|
||||
└── Makefile</pre>
|
||||
<p style="margin-top:12px;font-size:13px;color:var(--muted)">
|
||||
<code>make up</code> 启动 MySQL/Redis · <code>make api-dev</code> 启动 API · Swagger <code>/docs</code>
|
||||
</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>产品 Demo(P2 能力)</h3>
|
||||
<ul class="checklist">
|
||||
<li class="done">AI 实时跟练 · Ghost · 五维评分</li>
|
||||
<li class="done">WebRTC 摄像头预览(校准/跟练/拍摄)</li>
|
||||
<li class="done">真实 PDF 导出(4 类报告)</li>
|
||||
<li class="done">28 天趋势 · 三报告对比 · 儿童端</li>
|
||||
</ul>
|
||||
<a href="产品交互Demo.html" class="hero-btn hero-btn-primary" style="margin-top:14px;display:inline-block">进入 Demo</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="margin-top:16px">
|
||||
<h3>Sprint 1 下一步</h3>
|
||||
<table>
|
||||
<thead><tr><th>序号</th><th>任务</th><th>交付标准</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>1</td><td>Alembic 迁移</td><td>对接 database.sql 核心表</td></tr>
|
||||
<tr><td>2</td><td>Auth JWT</td><td>登录签发 + 鉴权中间件</td></tr>
|
||||
<tr><td>3</td><td>儿童档案 CRUD</td><td>落库 + 单元测试</td></tr>
|
||||
<tr><td>4</td><td>分析任务队列</td><td>Redis 入队 + Worker 骨架</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 11. Action -->
|
||||
<section id="action">
|
||||
<div class="section-header">
|
||||
<div class="section-num">11</div>
|
||||
<h2>近期行动清单(合伙人讨论)</h2>
|
||||
</div>
|
||||
|
||||
<div class="grid-2">
|
||||
<div class="card">
|
||||
<h3>本周 P0 — 需要合伙人拍板</h3>
|
||||
<ul class="checklist">
|
||||
<li>确认 MVP 范围与 6 周交付目标</li>
|
||||
<li>确认技术选型(FastAPI vs NestJS、云厂商)</li>
|
||||
<li>确认团队配置与外包边界</li>
|
||||
<li class="done">Git 初始化 + monorepo 目录结构</li>
|
||||
<li class="done">从 openapi.yaml / database.sql 生成工程骨架</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>下周起 P1 — 研发启动</h3>
|
||||
<ul class="checklist">
|
||||
<li>Sprint 1:Auth + 儿童档案 + DB 迁移</li>
|
||||
<li>确定 1 家种子机构作为试点需求来源</li>
|
||||
<li>算法完成 MediaPipe 本地验证(正/侧面站姿)</li>
|
||||
<li>staging 环境搭建与 CI 流水线</li>
|
||||
<li>每周需求评审 + 风险评审机制启动</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<a href="产品交互Demo.html" class="fab-demo" title="体验产品交互 Demo">
|
||||
<span class="icon">📱</span> 产品 Demo
|
||||
</a>
|
||||
|
||||
<footer>
|
||||
儿童 AI 体态管理与运动康复平台 · 商业交付包 V1.0 · 系统架构与建设规划<br>
|
||||
配套 Markdown 文档:<code>03_技术架构/系统架构与建设规划.md</code> · 生成日期 2026-07-23
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
mermaid.initialize({
|
||||
startOnLoad: true,
|
||||
theme: 'neutral',
|
||||
flowchart: { curve: 'basis', padding: 16 },
|
||||
sequence: { actorMargin: 50 }
|
||||
});
|
||||
|
||||
// Highlight active TOC on scroll
|
||||
const sections = document.querySelectorAll('section[id]');
|
||||
const tocLinks = document.querySelectorAll('.toc-bar a');
|
||||
window.addEventListener('scroll', () => {
|
||||
let current = '';
|
||||
sections.forEach(s => {
|
||||
if (window.scrollY >= s.offsetTop - 120) current = s.id;
|
||||
});
|
||||
tocLinks.forEach(a => {
|
||||
a.classList.toggle('active', a.getAttribute('href') === '#' + current);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,424 @@
|
||||
# 儿童 AI 体态管理平台 · 系统架构与建设规划
|
||||
|
||||
> **版本**:V1.0 · **日期**:2026-07-23
|
||||
> **适用阶段**:MVP → 商业试点 → 商业交付 V1.0
|
||||
> **主要读者**:创始团队、合伙人、产品、研发、运营、机构合作方
|
||||
|
||||
---
|
||||
|
||||
## 1. 项目定位与建设目标
|
||||
|
||||
### 1.1 产品定位
|
||||
|
||||
面向 **3–16 岁儿童青少年** 的 AI 体态管理与运动康复平台,围绕含胸驼背、头前伸、高低肩、骨盆姿态、膝内扣、足弓与运动协调等常见问题,提供:
|
||||
|
||||
- **AI 筛查**(非医疗诊断)
|
||||
- **结构化报告**与可解释建议
|
||||
- **训练计划**与打卡复测
|
||||
- **机构 SaaS** 运营与转化闭环
|
||||
|
||||
> **合规边界**:平台输出用于健康管理与运动训练,不替代医院诊断;涉及疼痛、明显畸形、外伤或医生已明确限制运动的情况,必须提示线下专业评估。
|
||||
|
||||
### 1.2 本期建设目标
|
||||
|
||||
| 维度 | 目标 |
|
||||
|------|------|
|
||||
| 业务闭环 | 建档 → 视频采集 → AI 分析 → 报告 → 训练 → 复测 → 机构转化 |
|
||||
| 技术目标 | 业务与 AI 解耦、多租户隔离、全链路可追溯、异步分析 ≤ 5 分钟 |
|
||||
| 商业目标 | 4–6 周可演示 MVP,8–10 周接入 1–3 家机构试点 |
|
||||
|
||||
### 1.3 核心成功指标(试点阶段)
|
||||
|
||||
| 指标 | 定义 | 目标 |
|
||||
|------|------|------|
|
||||
| 分析任务达成率 | 任务进入 PROCESSING 并生成报告或可解释失败 | ≥ 90% |
|
||||
| 报告查看率 | 报告产生后 30 分钟内家长首次查看 | ≥ 80% |
|
||||
| 训练任务完成率 | 14 天内计划任务完成比例 | ≥ 60% |
|
||||
| 训练后复测率 | 60 天内完成复测的儿童比例 | ≥ 50% |
|
||||
| 课程转化率 | 看完报告后进入课程/会员 | ≥ 20% |
|
||||
|
||||
---
|
||||
|
||||
## 2. 总体系统架构
|
||||
|
||||
### 2.1 分层架构概览
|
||||
|
||||
系统采用 **云原生分层架构**:客户端层 → 网关层 → 业务服务层 → AI 服务层 → 数据设施层。
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 客户端层 (Client) │
|
||||
│ 微信小程序/H5 家长端 │ 儿童训练端 │ Web 管理后台 │
|
||||
└───────────────────────────────┬─────────────────────────────────┘
|
||||
│ HTTPS
|
||||
┌───────────────────────────────▼─────────────────────────────────┐
|
||||
│ 网关层 (API Gateway) │
|
||||
│ 鉴权 JWT · 限流 · 审计 · 请求追踪 (requestId) │
|
||||
└───────────────────────────────┬─────────────────────────────────┘
|
||||
│
|
||||
┌───────────────────────────────▼─────────────────────────────────┐
|
||||
│ 业务服务层 (Business Services) │
|
||||
│ Auth/User │ Child Profile │ Video/Analysis │ Training │ Commerce │
|
||||
│ Admin/Ops │
|
||||
└───────────────┬─────────────────────────────┬───────────────────┘
|
||||
│ REST + 任务创建 │ 异步回调
|
||||
┌───────────────▼───────────────┐ ┌───────────▼───────────────────┐
|
||||
│ AI 服务层 (AI Layer) │ │ 消息队列 (Queue) │
|
||||
│ Video Worker │ Pose │ Score │◄──│ Redis/RabbitMQ │
|
||||
│ Agent 解释服务 │ └───────────────────────────────┘
|
||||
└───────────────┬───────────────┘
|
||||
│
|
||||
┌───────────────▼─────────────────────────────────────────────────┐
|
||||
│ 数据设施层 (Data Layer) │
|
||||
│ MySQL 8.x │ Redis │ 对象存储 OSS │ 向量记忆 │ 日志/监控平台 │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 关键设计原则
|
||||
|
||||
1. **业务与 AI 解耦**:长任务异步化,前端只创建任务并轮询/WebSocket 查状态,不阻塞 HTTP 链路。
|
||||
2. **全链路可追溯**:保留原始关键点、计算指标、模型版本、Agent 提示词版本与审核状态。
|
||||
3. **多租户隔离**:机构数据按 `tenant_id` 隔离,教练仅访问授权儿童。
|
||||
4. **接口契约优先**:以 `openapi.yaml` 为单一事实来源,向后兼容扩展。
|
||||
5. **幂等与审计**:写接口支持 `Idempotency-Key`;报告复核、退款、权限变更全量审计。
|
||||
|
||||
---
|
||||
|
||||
## 3. 模块划分与职责
|
||||
|
||||
### 3.1 业务服务模块
|
||||
|
||||
| 模块 | 职责 | 核心数据表 |
|
||||
|------|------|-----------|
|
||||
| **Auth/User** | 手机/微信登录、角色、租户、隐私协议 | `users`, `tenants`, `users_passwords` |
|
||||
| **Child Profile** | 儿童档案、成长指标、授权关系 | `children`, `child_measurements` |
|
||||
| **Video/Analysis** | 直传签名、视频登记、分析任务、报告 | `videos`, `analysis_tasks`, `reports` |
|
||||
| **Training** | 动作库、训练计划、打卡、复测 | `exercises`, `training_plans`, `training_records` |
|
||||
| **Commerce** | 套餐、订单、会员权益 | `products`, `orders` |
|
||||
| **Admin/Ops** | 运营线索、看板、审计、配置 | `operation_leads`, `audit_logs`, `data_retention_rules` |
|
||||
|
||||
### 3.2 AI 服务模块
|
||||
|
||||
| 组件 | 输入 | 输出 | 技术选型 |
|
||||
|------|------|------|----------|
|
||||
| **Video Worker** | 对象存储视频 | 帧序列、质量检测结果 | FFmpeg + 队列消费 |
|
||||
| **Pose 服务** | 图片/视频帧 | 33 关键点坐标 + 置信度 | MediaPipe Pose(一期) |
|
||||
| **评分服务** | 关键点序列 | 体态指标、动作评分、风险等级 | 规则引擎 + 加权算法 |
|
||||
| **Agent 服务** | 结构化指标 | 报告文案、训练建议、家长话术 | LLM + 模板约束 |
|
||||
|
||||
#### Agent 角色分工
|
||||
|
||||
| Agent | 职责 | 输出 |
|
||||
|-------|------|------|
|
||||
| Assessment Agent | 解读视觉指标与置信度 | 风险摘要、重点指标、复核建议 |
|
||||
| Coach Agent | 结合年龄与目标生成计划 | 周期计划、每日动作、进阶规则 |
|
||||
| Parent Agent | 专业内容家长化翻译 | 报告文案、提醒、复测建议 |
|
||||
| Operation Agent | 机构线索分层与触达 | 人群标签、话术、任务建议 |
|
||||
|
||||
### 3.3 客户端模块
|
||||
|
||||
| 端 | 用户 | 核心页面/流程 |
|
||||
|----|------|--------------|
|
||||
| **小程序/H5 家长端** | 家长 | 登录 → 建档 → 拍摄引导上传 → 报告 → 训练计划 → 订单 |
|
||||
| **儿童训练端** | 儿童/家长陪同 | 今日训练 → 动作演示 → 跟练计时 → 打卡反馈 |
|
||||
| **Web 管理后台** | 教练/运营/管理员 | 线索 → 档案 → 报告复核 → 课程 → 数据看板 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 核心业务流程
|
||||
|
||||
### 4.1 家长端主流程
|
||||
|
||||
```
|
||||
授权登录 → 隐私协议确认 → 创建儿童档案
|
||||
→ 按引导拍摄/upload-token 直传 OSS
|
||||
→ 登记视频 → 创建 analysis_task
|
||||
→ 异步 AI 处理(Pose + 评分 + Agent)
|
||||
→ 生成 report → 家长查看
|
||||
→ 购买/领取 training_plan → 每日打卡 → 复测
|
||||
```
|
||||
|
||||
### 4.2 AI 分析异步链路
|
||||
|
||||
```
|
||||
POST /api/analysis/tasks (返回 taskId)
|
||||
│
|
||||
▼
|
||||
队列 QUEUED → Worker 拉取
|
||||
│
|
||||
▼
|
||||
PROCESSING: 抽帧 → Pose → 指标计算 → 质量校验
|
||||
│
|
||||
├── 置信度不足 → FAILED + 建议重拍
|
||||
│
|
||||
▼
|
||||
Agent 生成报告文案 → 写入 reports
|
||||
│
|
||||
▼
|
||||
Webhook 回调后端 → status=SUCCEEDED + reportId
|
||||
│
|
||||
▼
|
||||
家长端轮询/推送 → 展示报告
|
||||
```
|
||||
|
||||
### 4.3 教练复核流程(试点阶段)
|
||||
|
||||
```
|
||||
AI 报告 (draft) → 教练后台复核 → 调整建议/关联课程
|
||||
→ 报告 published → 下发家长端 → 跟踪训练与复测
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 技术选型建议
|
||||
|
||||
### 5.1 推荐技术栈(MVP 阶段)
|
||||
|
||||
| 层级 | 推荐方案 | 说明 |
|
||||
|------|----------|------|
|
||||
| **后端 API** | Python FastAPI 或 Node.js NestJS | 与 OpenAPI 契约对齐,异步友好 |
|
||||
| **任务队列** | Redis + Celery / BullMQ | 分析任务削峰、重试 |
|
||||
| **数据库** | MySQL 8.x | 已有完整 schema(`database.sql`) |
|
||||
| **缓存** | Redis | Session、限流、队列、热点数据 |
|
||||
| **对象存储** | 阿里云 OSS / MinIO(dev) | 视频直传、生命周期归档 |
|
||||
| **AI 推理** | MediaPipe Pose + Python Worker | 一期快速落地,后续可替换模型 |
|
||||
| **Agent** | OpenAI API / 国产大模型 + Prompt 模板 | 输出受控,版本化管理 |
|
||||
| **家长端** | 微信小程序(Taro/uni-app) | 覆盖微信生态 |
|
||||
| **管理后台** | Vue 3 + Element Plus | 高密度信息布局 |
|
||||
| **网关** | Nginx / Kong | 鉴权、限流、TLS 终结 |
|
||||
| **监控** | Prometheus + Grafana / 云监控 | 业务 + AI 任务双维度 |
|
||||
|
||||
### 5.2 环境规划
|
||||
|
||||
| 环境 | 用途 | 要求 |
|
||||
|------|------|------|
|
||||
| dev | 日常开发联调 | 模拟支付、测试 OSS |
|
||||
| test | 测试验收回归 | 数据可重置,配置接近生产 |
|
||||
| staging | 预发布/客户演示 | 与生产同版本、同拓扑 |
|
||||
| prod | 正式服务 | 备份、监控、告警、权限收敛 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 分阶段建设规划
|
||||
|
||||
### 6.1 阶段总览
|
||||
|
||||
| 阶段 | 周期 | 目标 | 关键交付物 |
|
||||
|------|------|------|-----------|
|
||||
| **P0 方案确认** | 1 周 | 范围、架构、数据、合规边界对齐 | PRD 签字、架构文档、接口/DB 契约、Git 工程初始化 |
|
||||
| **P1 MVP 研发** | 4–6 周 | 家长端 + 视频分析 + 报告 + 基础后台 | 可演示版本、测试报告、staging 部署 |
|
||||
| **P2 试点交付** | 4 周 | 接入 1–3 家机构,跑通筛查→课程闭环 | 试点数据、运营 SOP、教练培训材料 |
|
||||
| **P3 商业化增强** | 6–8 周 | 支付、权限、模型评估、生产运维 | 商业版 V1.0、监控告警、备份演练 |
|
||||
|
||||
### 6.2 P1 MVP 详细排期(建议)
|
||||
|
||||
| 周次 | 模块 | 交付标准 |
|
||||
|------|------|----------|
|
||||
| W1 | 工程初始化 + Auth + 儿童档案 | 登录、建档 CRUD、DB 迁移跑通 |
|
||||
| W2 | 视频上传链路 | OSS 直传、视频登记、质量预检 UI |
|
||||
| W3 | AI Worker 骨架 | 抽帧 + MediaPipe + 基础指标输出 |
|
||||
| W4 | 报告生成 + Agent | 结构化 report + 家长可读文案 |
|
||||
| W5 | 家长端小程序 | 建档→上传→看报告完整流程 |
|
||||
| W6 | 基础管理后台 + 联调 | 报告列表、任务监控、冒烟测试 |
|
||||
|
||||
**MVP 最小闭环(Must Have):**
|
||||
|
||||
> 家长 2 分钟内完成建档 + 视频上传 → 5 分钟内收到 AI 报告 → 报告含风险等级、指标解释、建议动作、免责声明
|
||||
|
||||
**MVP 可后置(Should/Could):**
|
||||
|
||||
- 支付与会员
|
||||
- 完整训练打卡
|
||||
- 运营线索漏斗
|
||||
- 多机构租户管理
|
||||
|
||||
### 6.3 团队分工建议
|
||||
|
||||
| 角色 | 人数 | 职责 |
|
||||
|------|------|------|
|
||||
| 产品负责人 | 1 | 需求拆解、验收标准、试点反馈闭环 |
|
||||
| 前端工程师 | 1 | 小程序/H5、儿童训练页、Web 后台 |
|
||||
| 后端工程师 | 1 | API、任务队列、权限、数据模型 |
|
||||
| 算法工程师 | 1 | 关键点、评分规则、质量检测、Agent 约束 |
|
||||
| 测试/交付 | 0.5–1 | 场景测试、部署验证、SOP 落地 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 数据与安全架构
|
||||
|
||||
### 7.1 数据分层
|
||||
|
||||
| 等级 | 数据类型 | 存储策略 |
|
||||
|------|----------|----------|
|
||||
| L1 敏感 | 手机号、儿童姓名、视频原片 | 加密/哈希、脱敏展示、访问审计 |
|
||||
| L2 业务 | 报告、训练记录、订单 | MySQL + 租户隔离 |
|
||||
| L3 衍生 | 关键点、指标 JSON、Agent 输出 | 与任务绑定,保留模型版本 |
|
||||
| L4 运营 | 线索、看板聚合 | 脱敏聚合,按租户隔离 |
|
||||
|
||||
### 7.2 安全与合规要点
|
||||
|
||||
- 报告 **不得** 出现确诊、治疗、治愈等医疗表述
|
||||
- Agent 输出引用输入字段,保留提示词版本
|
||||
- 低置信度 → 仅输出「建议重拍/教练复核」,不给强结论
|
||||
- 审计日志保留 ≥ 180 天;视频/报告按 `retention_days` 归档
|
||||
- 写接口幂等保护(`api_idempotency_keys` 表)
|
||||
|
||||
---
|
||||
|
||||
## 8. 部署拓扑
|
||||
|
||||
### 8.1 MVP 单区域部署
|
||||
|
||||
```
|
||||
┌─────────────┐
|
||||
用户 ──────────► │ Nginx │
|
||||
│ API Gateway│
|
||||
└──────┬──────┘
|
||||
│
|
||||
┌────────────┼────────────┐
|
||||
▼ ▼ ▼
|
||||
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||
│ API 服务 │ │AI Worker │ │ 后台服务 │
|
||||
└────┬─────┘ └────┬─────┘ └────┬─────┘
|
||||
│ │ │
|
||||
┌────┴────────────┴────────────┴────┐
|
||||
│ MySQL │ Redis │ OSS │ 日志 │
|
||||
└───────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 8.2 商业化阶段演进
|
||||
|
||||
- AI Worker、视频转码、报告生成 **拆分为独立队列消费者**
|
||||
- 引入灰度发布、多环境配置、自动扩缩容
|
||||
- 模型/评分规则/报告模板 **版本化独立发布**
|
||||
|
||||
---
|
||||
|
||||
## 9. 风险与应对
|
||||
|
||||
| 风险 | 影响 | 应对策略 |
|
||||
|------|------|----------|
|
||||
| AI 置信度不足导致报告不可用 | 用户体验差、机构信任低 | 拍摄质量前置检测 + 低置信度降级文案 |
|
||||
| 医疗合规边界模糊 | 法律风险 | PRD 硬性约束 + Agent 过滤 + 人工复核 |
|
||||
| MVP 范围膨胀 | 延期交付 | 严格 MoSCoW,支付/运营后置 |
|
||||
| 机构试点数据隔离 | 合作受阻 | 一期即引入 tenant_id,权限最小化 |
|
||||
| 算法儿童个体差异 | 误报/漏报 | 保留教练复核环节,不做全自动闭环 |
|
||||
|
||||
---
|
||||
|
||||
## 10. 工程化 Monorepo(P3)
|
||||
|
||||
### 10.1 仓库结构
|
||||
|
||||
```
|
||||
happy-up/
|
||||
├── contracts/ # openapi.yaml + database.sql(从 doc/ 同步)
|
||||
├── apps/api/ # FastAPI 后端 Starter
|
||||
├── doc/ # 商业交付文档包 V1.0
|
||||
├── docker-compose.yml # MySQL 8 + Redis 7
|
||||
└── Makefile
|
||||
```
|
||||
|
||||
### 10.2 产品 Demo 能力(P1/P2)
|
||||
|
||||
| 能力 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| AI 实时跟练打卡 | ✅ | Ghost 叠加 · Coach Agent cue · 五维评分 |
|
||||
| WebRTC 摄像头预览 | ✅ | 机位校准/跟练/拍摄引导页 |
|
||||
| 真实 PDF 导出 | ✅ | 筛查/跟练/趋势/三报告对比 |
|
||||
| 28 天趋势 + 三报告对比 | ✅ | 商业闭环可视化 |
|
||||
| 儿童训练端 | ✅ | 大按钮 + 儿童版 cue |
|
||||
|
||||
入口:`doc/.../03_技术架构/产品交互Demo.html`
|
||||
|
||||
### 10.3 API Starter
|
||||
|
||||
- **框架**:FastAPI + Pydantic v2 + SQLAlchemy 2
|
||||
- **契约对齐**:路由覆盖 `openapi.yaml` 全部 path(当前 Mock 数据,与 Demo 一致)
|
||||
- **统一响应**:`StandardResponse` + `requestId` 中间件
|
||||
- **本地依赖**:`make up` 启动 MySQL/Redis,`make api-dev` 启动 API
|
||||
|
||||
详见仓库根目录 `README.md` 与 `apps/api/README.md`。
|
||||
|
||||
### 10.4 Sprint 1 已完成
|
||||
|
||||
- JWT 登录(验证码 682139)+ Bearer 鉴权
|
||||
- 儿童档案 CRUD 落库(MySQL)
|
||||
- Alembic baseline + `make api-seed`
|
||||
- 产品 Demo **API 联调模式**(登录 + 首页档案)
|
||||
|
||||
### 10.5 Sprint 2 已完成
|
||||
|
||||
- 视频直传凭证 + 登记落库(`videos` 表)
|
||||
- 分析任务 Redis 队列 + Worker 骨架 + 内联处理(开发模式)
|
||||
- 报告生成落库(`reports` 表 · 对齐 Demo 指标)
|
||||
- Demo **筛查全流程 API 联调**(上传 → 分析 → 报告)
|
||||
|
||||
### 10.6 Sprint 3 已完成
|
||||
|
||||
- 训练计划 CRUD + 打卡记录落库(`training_plans` / `training_records`)
|
||||
- Admin 运营看板真实 DB 聚合
|
||||
- Demo 全链路 API 联调(含训练计划页 + 打卡写入 + 后台 KPI)
|
||||
- `apps/web/` 前端工程占位
|
||||
|
||||
### 10.7 Sprint 4 已完成
|
||||
|
||||
- 本地直传 + MinIO 预签名 URL(`OSS_ENABLED=true` + `docker compose` MinIO)
|
||||
- `PUT /api/videos/direct-upload` 本地上传回退
|
||||
- MediaPipe 分析骨架(`pip install -e ".[ai]"` 可选)
|
||||
- `apps/web` Vue 3 H5(登录 / 档案 / 筛查联调)
|
||||
- Admin 看板按 `tenant_id` 隔离聚合
|
||||
|
||||
### 10.8 Sprint 5 已完成
|
||||
|
||||
- MediaPipe 帧级评分(`pose_metrics.py` 纯函数 + OpenCV 抽帧)
|
||||
- 服务端 PDF 导出 `GET /api/reports/{id}/pdf`
|
||||
- OSS 生产配置:`OSS_PROVIDER=aliyun` + `OSS_CDN_BASE_URL`
|
||||
- H5 四 Tab UI(首页/筛查/报告/训练)对齐 Demo 配色
|
||||
- 微信小程序壳 `apps/mini`
|
||||
|
||||
### 10.9 Sprint 6 下一步
|
||||
|
||||
1. 真实视频数据集标定与模型精度调优
|
||||
2. 小程序完整 Tab + 跟练页
|
||||
3. 报告复核工作流 + 消息通知
|
||||
4. 生产部署(K8s / CI-CD)
|
||||
|
||||
---
|
||||
|
||||
## 11. 近期行动清单(合伙人讨论用)
|
||||
|
||||
### 本周(P0)
|
||||
|
||||
- [ ] 合伙人确认 MVP 范围与 6 周交付目标
|
||||
- [ ] 确认技术选型(FastAPI vs NestJS、云厂商)
|
||||
- [ ] 确认团队配置与外包边界
|
||||
- [x] Git 初始化 + monorepo 目录结构
|
||||
- [x] 从 `openapi.yaml` / `database.sql` 生成工程骨架
|
||||
|
||||
### 下周起(P1 启动)
|
||||
|
||||
- [ ] Sprint 1:Auth + 儿童档案 + DB 迁移
|
||||
- [ ] 确定 1 家种子机构作为试点需求来源
|
||||
- [ ] 算法同学完成 MediaPipe 本地验证(正面/侧面站姿)
|
||||
|
||||
---
|
||||
|
||||
## 附录:文档索引
|
||||
|
||||
| 文档 | 路径 |
|
||||
|------|------|
|
||||
| 产品 PRD | `02_企业级PRD/PRD完整版.docx` |
|
||||
| 企业级架构 | `03_技术架构/企业级系统架构.docx` |
|
||||
| **本架构与建设规划** | `03_技术架构/系统架构与建设规划.md` |
|
||||
| **合伙人讨论 HTML** | `03_技术架构/系统架构与建设规划.html` |
|
||||
| 数据库设计 | `06_数据库设计/database.sql` |
|
||||
| API 契约 | `07_API接口/openapi.yaml` |
|
||||
| AI 算法设计 | `04_AI视觉算法/AI视觉算法详细设计.docx` |
|
||||
| Agent 规范 | `08_Agent智能系统/Agent设计规范.docx` |
|
||||
| 研发计划 | `12_研发计划/研发计划与项目管理.docx` |
|
||||
| 部署运维 | `14_部署运维/生产部署运维.docx` |
|
||||
|
||||
---
|
||||
|
||||
*本文档基于商业交付包 V1.0 现有材料整理,用于创始团队与合伙人架构讨论及研发启动对齐。*
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,316 @@
|
||||
-- Kids AI Posture Platform V1.0 database schema
|
||||
-- MySQL 8.x
|
||||
-- 目标:满足审计、幂等、治理、隐私与可追溯性要求
|
||||
|
||||
CREATE TABLE tenants (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
type VARCHAR(32) NOT NULL DEFAULT 'organization',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'active',
|
||||
retention_days INT NOT NULL DEFAULT 1095,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
CHECK (type IN ('organization','school','clinic','mall','other')),
|
||||
CHECK (status IN ('active','inactive','frozen','closed')),
|
||||
CHECK (retention_days BETWEEN 30 AND 3650)
|
||||
);
|
||||
|
||||
CREATE TABLE users (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
tenant_id BIGINT NULL,
|
||||
phone VARCHAR(32),
|
||||
phone_hash VARCHAR(128),
|
||||
wechat_openid VARCHAR(128),
|
||||
role VARCHAR(32) NOT NULL DEFAULT 'parent',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'active',
|
||||
consent_signed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
privacy_version VARCHAR(16) DEFAULT 'v1',
|
||||
last_login_at TIMESTAMP NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
KEY idx_users_tenant_role (tenant_id, role),
|
||||
UNIQUE KEY uk_users_phone_hash (phone_hash),
|
||||
UNIQUE KEY uk_users_wechat_openid (wechat_openid),
|
||||
CHECK (role IN ('parent','coach','org_admin','platform_admin')),
|
||||
CHECK (status IN ('active','inactive','blocked'))
|
||||
);
|
||||
|
||||
CREATE TABLE users_passwords (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
user_id BIGINT NOT NULL,
|
||||
password_hash VARCHAR(256) NOT NULL,
|
||||
salt VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
KEY idx_user_password (user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE children (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
tenant_id BIGINT NULL,
|
||||
parent_user_id BIGINT NOT NULL,
|
||||
coach_user_id BIGINT NULL,
|
||||
name VARCHAR(64) NOT NULL,
|
||||
gender VARCHAR(16) NOT NULL DEFAULT 'unknown',
|
||||
birthday DATE NOT NULL,
|
||||
height DECIMAL(5,2),
|
||||
weight DECIMAL(5,2),
|
||||
contraindications TEXT,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'active',
|
||||
deleted_at TIMESTAMP NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
KEY idx_children_parent (parent_user_id),
|
||||
KEY idx_children_tenant_coach (tenant_id, coach_user_id),
|
||||
KEY idx_children_status (status),
|
||||
CHECK (gender IN ('male','female','unknown')),
|
||||
CHECK (status IN ('active','inactive','archived')),
|
||||
CHECK (height IS NULL OR (height > 20 AND height < 240)),
|
||||
CHECK (weight IS NULL OR (weight > 5 AND weight < 250))
|
||||
);
|
||||
|
||||
CREATE TABLE child_measurements (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
child_id BIGINT NOT NULL,
|
||||
height DECIMAL(5,2),
|
||||
weight DECIMAL(5,2),
|
||||
source VARCHAR(32) NOT NULL DEFAULT 'manual',
|
||||
measured_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_measurements_child_time (child_id, measured_at),
|
||||
CHECK (source IN ('manual','device','coach','report')),
|
||||
CHECK (height IS NULL OR (height > 20 AND height < 240)),
|
||||
CHECK (weight IS NULL OR (weight > 5 AND weight < 250))
|
||||
);
|
||||
|
||||
CREATE TABLE videos (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
child_id BIGINT NOT NULL,
|
||||
uploaded_by BIGINT NOT NULL,
|
||||
scene VARCHAR(64) NOT NULL,
|
||||
object_key VARCHAR(512) NOT NULL,
|
||||
duration_seconds INT,
|
||||
width INT,
|
||||
height INT,
|
||||
size_bytes BIGINT,
|
||||
codec VARCHAR(32),
|
||||
quality_result JSON,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'uploaded',
|
||||
archive_until_date DATE NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
KEY idx_videos_child_scene (child_id, scene),
|
||||
KEY idx_videos_status (status),
|
||||
UNIQUE KEY uk_videos_object_key (object_key),
|
||||
CHECK (scene IN ('front_posture','side_posture','squat','balance','gait','custom')),
|
||||
CHECK (status IN ('uploaded','transcoding','failed','ready','archived')),
|
||||
CHECK (duration_seconds IS NULL OR duration_seconds BETWEEN 1 AND 1800),
|
||||
CHECK (size_bytes IS NULL OR size_bytes BETWEEN 1 AND 10737418240)
|
||||
);
|
||||
|
||||
CREATE TABLE analysis_tasks (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
child_id BIGINT NOT NULL,
|
||||
video_id BIGINT NOT NULL,
|
||||
task_type VARCHAR(64) NOT NULL,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'CREATED',
|
||||
progress INT NOT NULL DEFAULT 0,
|
||||
model_version VARCHAR(64),
|
||||
error_code VARCHAR(64),
|
||||
error_message VARCHAR(512),
|
||||
result JSON,
|
||||
idempotency_key VARCHAR(128),
|
||||
retry_count INT NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
started_at TIMESTAMP NULL,
|
||||
finished_at TIMESTAMP NULL,
|
||||
UNIQUE KEY uk_analysis_idempotency (child_id, video_id, task_type, idempotency_key),
|
||||
KEY idx_analysis_child_status (child_id, status),
|
||||
KEY idx_analysis_video (video_id),
|
||||
KEY idx_analysis_created (created_at),
|
||||
CHECK (status IN ('CREATED','QUEUED','PROCESSING','SUCCEEDED','FAILED','CANCELLED')),
|
||||
CHECK (task_type IN ('posture_screening','movement_scoring','reassessment')),
|
||||
CHECK (progress BETWEEN 0 AND 100),
|
||||
CHECK (retry_count BETWEEN 0 AND 20)
|
||||
);
|
||||
|
||||
CREATE TABLE reports (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
child_id BIGINT NOT NULL,
|
||||
task_id BIGINT NOT NULL,
|
||||
report_type VARCHAR(64) NOT NULL DEFAULT 'posture_screening',
|
||||
risk_level VARCHAR(32) NOT NULL,
|
||||
summary TEXT NOT NULL,
|
||||
metrics JSON NOT NULL,
|
||||
recommendations JSON NOT NULL,
|
||||
disclaimer TEXT NOT NULL,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'draft',
|
||||
reviewed_by BIGINT NULL,
|
||||
reviewed_at TIMESTAMP NULL,
|
||||
published_at TIMESTAMP NULL,
|
||||
expires_at DATE NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_reports_task (task_id),
|
||||
KEY idx_reports_child_status (child_id, status),
|
||||
CHECK (risk_level IN ('low','medium','high','review_required')),
|
||||
CHECK (status IN ('draft','published','retracted','archived'))
|
||||
);
|
||||
|
||||
CREATE TABLE exercises (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
category VARCHAR(64) NOT NULL,
|
||||
target_issue VARCHAR(128),
|
||||
difficulty VARCHAR(32) NOT NULL DEFAULT 'basic',
|
||||
duration_seconds INT NOT NULL DEFAULT 60,
|
||||
media_url VARCHAR(512),
|
||||
thumbnail_url VARCHAR(512),
|
||||
rules JSON,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'active',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
KEY idx_exercises_category (category, status),
|
||||
CHECK (difficulty IN ('basic','intermediate','advanced')),
|
||||
CHECK (status IN ('active','offline','deprecated')),
|
||||
CHECK (duration_seconds BETWEEN 20 AND 1800)
|
||||
);
|
||||
|
||||
CREATE TABLE training_plans (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
child_id BIGINT NOT NULL,
|
||||
report_id BIGINT NULL,
|
||||
coach_user_id BIGINT NULL,
|
||||
goal VARCHAR(256) NOT NULL,
|
||||
cycle_days INT NOT NULL DEFAULT 28,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'draft',
|
||||
plan_detail JSON NOT NULL,
|
||||
started_at TIMESTAMP NULL,
|
||||
ended_at TIMESTAMP NULL,
|
||||
deleted_at TIMESTAMP NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
KEY idx_training_plans_child_status (child_id, status),
|
||||
CHECK (cycle_days BETWEEN 7 AND 180),
|
||||
CHECK (status IN ('draft','active','completed','paused','cancelled'))
|
||||
);
|
||||
|
||||
CREATE TABLE training_records (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
plan_id BIGINT NOT NULL,
|
||||
child_id BIGINT NOT NULL,
|
||||
exercise_id BIGINT NOT NULL,
|
||||
completed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
score INT,
|
||||
duration_seconds INT,
|
||||
feedback JSON,
|
||||
note VARCHAR(512),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
KEY idx_training_records_plan (plan_id),
|
||||
KEY idx_training_records_child_time (child_id, created_at),
|
||||
CHECK (score IS NULL OR score BETWEEN 0 AND 100),
|
||||
CHECK (duration_seconds IS NULL OR duration_seconds BETWEEN 1 AND 7200)
|
||||
);
|
||||
|
||||
CREATE TABLE products (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
tenant_id BIGINT NULL,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
product_type VARCHAR(32) NOT NULL,
|
||||
price_cents INT NOT NULL,
|
||||
duration_days INT NULL,
|
||||
benefits JSON NOT NULL,
|
||||
limit_child INTEGER NOT NULL DEFAULT 1,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'active',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CHECK (product_type IN ('video_pack','training_plan','membership','assessment_bundle','course_package')),
|
||||
CHECK (status IN ('active','inactive','discontinued')),
|
||||
CHECK (price_cents >= 0),
|
||||
CHECK (duration_days IS NULL OR duration_days BETWEEN 1 AND 3650)
|
||||
);
|
||||
|
||||
CREATE TABLE orders (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
user_id BIGINT NOT NULL,
|
||||
child_id BIGINT NULL,
|
||||
product_id BIGINT NOT NULL,
|
||||
amount_cents INT NOT NULL,
|
||||
pay_status VARCHAR(32) NOT NULL DEFAULT 'pending',
|
||||
payment_channel VARCHAR(32),
|
||||
paid_at TIMESTAMP NULL,
|
||||
canceled_at TIMESTAMP NULL,
|
||||
refund_status VARCHAR(32) DEFAULT 'none',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
KEY idx_orders_user_status (user_id, pay_status),
|
||||
KEY idx_orders_child (child_id),
|
||||
CHECK (pay_status IN ('pending','paid','failed','closed','refunding','refunded')),
|
||||
CHECK (refund_status IN ('none','requested','processing','completed','rejected')),
|
||||
CHECK (amount_cents >= 0)
|
||||
);
|
||||
|
||||
CREATE TABLE operation_leads (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
tenant_id BIGINT NOT NULL,
|
||||
child_id BIGINT NULL,
|
||||
source VARCHAR(64) NOT NULL,
|
||||
stage VARCHAR(32) NOT NULL DEFAULT 'new',
|
||||
owner_user_id BIGINT NULL,
|
||||
score INT DEFAULT 0,
|
||||
priority TINYINT DEFAULT 3,
|
||||
next_follow_at TIMESTAMP NULL,
|
||||
note TEXT,
|
||||
touched_at TIMESTAMP NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
KEY idx_leads_tenant_stage (tenant_id, stage),
|
||||
KEY idx_leads_owner_next (owner_user_id, next_follow_at),
|
||||
CHECK (source IN ('wechat','h5','miniapp','partner','referral','offline_campaign')),
|
||||
CHECK (stage IN ('new','contacted','qualified','closed','lost','churned')),
|
||||
CHECK (priority BETWEEN 1 AND 5),
|
||||
CHECK (score BETWEEN 0 AND 100)
|
||||
);
|
||||
|
||||
CREATE TABLE audit_logs (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
tenant_id BIGINT NULL,
|
||||
actor_user_id BIGINT NOT NULL,
|
||||
action VARCHAR(128) NOT NULL,
|
||||
resource_type VARCHAR(64) NOT NULL,
|
||||
resource_id BIGINT NULL,
|
||||
request_id VARCHAR(64),
|
||||
ip VARCHAR(64),
|
||||
user_agent VARCHAR(256),
|
||||
payload JSON,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
KEY idx_audit_actor_time (actor_user_id, created_at),
|
||||
KEY idx_audit_resource (resource_type, resource_id)
|
||||
);
|
||||
|
||||
CREATE TABLE data_retention_rules (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
tenant_id BIGINT NULL,
|
||||
resource_type VARCHAR(64) NOT NULL,
|
||||
archive_after_days INT NOT NULL,
|
||||
delete_after_days INT NOT NULL,
|
||||
legal_basis VARCHAR(128),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_retention (tenant_id, resource_type),
|
||||
CHECK (delete_after_days >= archive_after_days),
|
||||
CHECK (archive_after_days >= 30)
|
||||
);
|
||||
|
||||
CREATE TABLE api_idempotency_keys (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
scope VARCHAR(32) NOT NULL,
|
||||
idempotency_key VARCHAR(128) NOT NULL,
|
||||
request_path VARCHAR(255) NOT NULL,
|
||||
request_hash CHAR(64) NOT NULL,
|
||||
response_status INT,
|
||||
response_body JSON,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_idempotency_scope_key (scope, idempotency_key),
|
||||
KEY idx_idempotency_created (created_at)
|
||||
);
|
||||
|
||||
-- 运行时可选索引补充说明(按需执行)
|
||||
-- CREATE INDEX idx_analysis_status_updated ON analysis_tasks(status, updated_at);
|
||||
-- CREATE INDEX idx_reports_risk_level ON reports(risk_level, created_at);
|
||||
-- CREATE INDEX idx_orders_pay_status_updated ON orders(pay_status, updated_at);
|
||||
@@ -0,0 +1,670 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: Kids AI Posture Platform API
|
||||
version: 1.0.0
|
||||
description: |
|
||||
儿童AI体态管理与运动康复平台 V1.0 API 契约。
|
||||
所有报告用于健康管理建议,不构成医疗诊断。接口返回统一包含 requestId 以便追踪。
|
||||
servers:
|
||||
- url: https://api.example.com
|
||||
description: production
|
||||
- url: https://staging-api.example.com
|
||||
description: staging
|
||||
security:
|
||||
- bearerAuth: []
|
||||
|
||||
x-error-model: &error-model
|
||||
code: integer
|
||||
message: string
|
||||
details:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
requestId: string
|
||||
|
||||
tags:
|
||||
- name: Auth
|
||||
- name: Children
|
||||
- name: Videos
|
||||
- name: Analysis
|
||||
- name: Reports
|
||||
- name: Training
|
||||
- name: Admin
|
||||
|
||||
paths:
|
||||
/api/auth/login:
|
||||
post:
|
||||
tags: [Auth]
|
||||
summary: 手机号或微信授权登录
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/LoginRequest'
|
||||
examples:
|
||||
phone:
|
||||
summary: 手机验证码
|
||||
value:
|
||||
loginType: phone_code
|
||||
credential: "186xxxx0000"
|
||||
code: "682139"
|
||||
wechat:
|
||||
summary: 微信授权码
|
||||
value:
|
||||
loginType: wechat
|
||||
credential: "wx_auth_code"
|
||||
responses:
|
||||
'200':
|
||||
description: 登录成功
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/LoginResponse'
|
||||
'401':
|
||||
description: 登录失败
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
/api/children:
|
||||
get:
|
||||
tags: [Children]
|
||||
summary: 获取当前用户可访问的儿童档案
|
||||
parameters:
|
||||
- name: page
|
||||
in: query
|
||||
schema: { type: integer, minimum: 1, default: 1 }
|
||||
- name: pageSize
|
||||
in: query
|
||||
schema: { type: integer, minimum: 1, maximum: 100, default: 20 }
|
||||
responses:
|
||||
'200':
|
||||
description: 儿童档案分页列表
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ChildrenPagedResponse'
|
||||
post:
|
||||
tags: [Children]
|
||||
summary: 创建儿童档案
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ChildCreateRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: 创建成功
|
||||
headers:
|
||||
Idempotency-Key:
|
||||
description: 冪等键回显,用于重试去重核对
|
||||
schema: { type: string }
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ChildResponse'
|
||||
'400':
|
||||
description: 请求参数错误
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
/api/children/{childId}:
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/ChildId'
|
||||
get:
|
||||
tags: [Children]
|
||||
summary: 获取儿童档案详情
|
||||
responses:
|
||||
'200':
|
||||
description: 档案详情
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ChildResponse'
|
||||
'404':
|
||||
description: 资源不存在
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
patch:
|
||||
tags: [Children]
|
||||
summary: 更新儿童档案
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ChildUpdateRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: 更新成功
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ChildResponse'
|
||||
'409':
|
||||
description: 更新冲突(数据并发)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
delete:
|
||||
tags: [Children]
|
||||
summary: 注销/归档儿童档案
|
||||
responses:
|
||||
'204':
|
||||
description: 归档成功
|
||||
|
||||
/api/videos/upload-token:
|
||||
post:
|
||||
tags: [Videos]
|
||||
summary: 获取视频直传凭证
|
||||
description: 建议请求头携带 Idempotency-Key,避免重试产生重复录像对象。
|
||||
parameters:
|
||||
- name: Idempotency-Key
|
||||
in: header
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UploadTokenRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: 上传凭证
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UploadTokenResponse'
|
||||
'429':
|
||||
description: 请求过于频繁
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
/api/videos:
|
||||
post:
|
||||
tags: [Videos]
|
||||
summary: 登记已上传视频
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/VideoCreateRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: 视频登记成功
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/VideoResponse'
|
||||
'409':
|
||||
description: 去重/重复提交
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
/api/analysis/tasks:
|
||||
post:
|
||||
tags: [Analysis]
|
||||
summary: 创建AI分析任务
|
||||
description: 同一 childId+videoId+taskType 可复用幂等键创建。
|
||||
parameters:
|
||||
- name: Idempotency-Key
|
||||
in: header
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/AnalysisTaskCreateRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: 任务创建成功
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/AnalysisTaskResponse'
|
||||
'409':
|
||||
description: 重复任务,返回已有任务
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/AnalysisTaskResponse'
|
||||
|
||||
/api/analysis/tasks/{taskId}:
|
||||
get:
|
||||
tags: [Analysis]
|
||||
summary: 查询分析任务状态
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/TaskId'
|
||||
responses:
|
||||
'200':
|
||||
description: 任务状态
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/AnalysisTaskResponse'
|
||||
'404':
|
||||
description: 任务不存在
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
/api/analysis/tasks/{taskId}/cancel:
|
||||
post:
|
||||
tags: [Analysis]
|
||||
summary: 取消分析任务
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/TaskId'
|
||||
responses:
|
||||
'200':
|
||||
description: 取消成功
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/StandardResponse'
|
||||
|
||||
/api/analysis/webhook:
|
||||
post:
|
||||
tags: [Analysis]
|
||||
summary: 分析结果回调(异步)
|
||||
description: 系统内部回调给后端事件网关,需使用 HMAC 签名。
|
||||
security: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/AnalysisTaskWebhook'
|
||||
responses:
|
||||
'204':
|
||||
description: 接收成功
|
||||
|
||||
/api/reports/{reportId}:
|
||||
get:
|
||||
tags: [Reports]
|
||||
summary: 获取体态分析报告
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/ReportId'
|
||||
responses:
|
||||
'200':
|
||||
description: 报告详情
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ReportResponse'
|
||||
|
||||
/api/training/plans:
|
||||
post:
|
||||
tags: [Training]
|
||||
summary: 创建训练计划
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TrainingPlanCreateRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: 训练计划创建成功
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TrainingPlanResponse'
|
||||
|
||||
/api/training/plans/{planId}:
|
||||
parameters:
|
||||
- name: planId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
get:
|
||||
tags: [Training]
|
||||
summary: 获取训练计划
|
||||
responses:
|
||||
'200':
|
||||
description: 训练计划详情
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TrainingPlanResponse'
|
||||
|
||||
/api/training/plans/{planId}/records:
|
||||
post:
|
||||
tags: [Training]
|
||||
summary: 提交训练打卡记录
|
||||
parameters:
|
||||
- name: planId
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: integer }
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TrainingRecordCreateRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: 打卡成功
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TrainingRecordResponse'
|
||||
|
||||
/api/admin/dashboard:
|
||||
get:
|
||||
tags: [Admin]
|
||||
summary: 获取机构运营看板
|
||||
responses:
|
||||
'200':
|
||||
description: 看板指标
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/AdminDashboardResponse'
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
parameters:
|
||||
ChildId:
|
||||
name: childId
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: integer }
|
||||
TaskId:
|
||||
name: taskId
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: integer }
|
||||
ReportId:
|
||||
name: reportId
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: integer }
|
||||
schemas:
|
||||
ApiMeta:
|
||||
type: object
|
||||
properties:
|
||||
requestId: { type: string }
|
||||
timestamp: { type: string, format: date-time }
|
||||
traceId: { type: string }
|
||||
StandardResponse:
|
||||
type: object
|
||||
properties:
|
||||
code: { type: integer }
|
||||
message: { type: string }
|
||||
data: { type: object, nullable: true }
|
||||
meta: { $ref: '#/components/schemas/ApiMeta' }
|
||||
ErrorResponse:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/StandardResponse'
|
||||
- type: object
|
||||
properties:
|
||||
code: { type: integer, example: 10003 }
|
||||
message: { type: string, example: parameter_validation_failed }
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
errorCode: { type: string }
|
||||
path: { type: string }
|
||||
PagedMeta:
|
||||
type: object
|
||||
properties:
|
||||
page: { type: integer }
|
||||
pageSize: { type: integer }
|
||||
total: { type: integer }
|
||||
hasMore: { type: boolean }
|
||||
LoginRequest:
|
||||
type: object
|
||||
required: [loginType, credential]
|
||||
properties:
|
||||
loginType: { type: string, enum: [phone_code, wechat] }
|
||||
credential: { type: string }
|
||||
code: { type: string }
|
||||
LoginResponse:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/StandardResponse'
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
token: { type: string }
|
||||
user: { $ref: '#/components/schemas/User' }
|
||||
User:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: integer }
|
||||
phoneMasked: { type: string }
|
||||
role: { type: string, enum: [parent, coach, org_admin, platform_admin] }
|
||||
ChildCreateRequest:
|
||||
type: object
|
||||
required: [name, birthday]
|
||||
properties:
|
||||
name: { type: string }
|
||||
birthday: { type: string, format: date }
|
||||
gender: { type: string, enum: [male, female, unknown] }
|
||||
height: { type: number }
|
||||
weight: { type: number }
|
||||
contraindications: { type: string }
|
||||
ChildUpdateRequest:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/ChildCreateRequest'
|
||||
Child:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: integer }
|
||||
name: { type: string }
|
||||
birthday: { type: string, format: date }
|
||||
age: { type: integer }
|
||||
height: { type: number }
|
||||
weight: { type: number }
|
||||
status: { type: string }
|
||||
ChildResponse:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/StandardResponse'
|
||||
- type: object
|
||||
properties:
|
||||
data: { $ref: '#/components/schemas/Child' }
|
||||
ChildrenPagedResponse:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/StandardResponse'
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
list:
|
||||
type: array
|
||||
items: { $ref: '#/components/schemas/Child' }
|
||||
page: { $ref: '#/components/schemas/PagedMeta' }
|
||||
UploadTokenRequest:
|
||||
type: object
|
||||
required: [childId, fileName, contentType, size]
|
||||
properties:
|
||||
childId: { type: integer }
|
||||
fileName: { type: string }
|
||||
contentType: { type: string, example: video/mp4 }
|
||||
size: { type: integer }
|
||||
UploadTokenResponse:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/StandardResponse'
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
uploadUrl: { type: string }
|
||||
objectKey: { type: string }
|
||||
expireAt: { type: string, format: date-time }
|
||||
VideoCreateRequest:
|
||||
type: object
|
||||
required: [childId, objectKey, scene]
|
||||
properties:
|
||||
childId: { type: integer }
|
||||
objectKey: { type: string }
|
||||
scene:
|
||||
type: string
|
||||
enum: [front_posture, side_posture, squat, balance, gait]
|
||||
captureHint: { type: string }
|
||||
VideoResponse:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/StandardResponse'
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: integer }
|
||||
status: { type: string, enum: [uploaded, rejected, archived] }
|
||||
AnalysisTaskCreateRequest:
|
||||
type: object
|
||||
required: [childId, videoId, taskType]
|
||||
properties:
|
||||
childId: { type: integer }
|
||||
videoId: { type: integer }
|
||||
taskType: { type: string, enum: [posture_screening, movement_scoring, reassessment] }
|
||||
AnalysisTaskResponse:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/StandardResponse'
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: integer }
|
||||
status:
|
||||
type: string
|
||||
enum: [CREATED, QUEUED, PROCESSING, SUCCEEDED, FAILED, CANCELLED]
|
||||
progress: { type: integer, minimum: 0, maximum: 100 }
|
||||
errorCode: { type: string }
|
||||
reportId: { type: integer }
|
||||
retryCount: { type: integer }
|
||||
AnalysisTaskWebhook:
|
||||
type: object
|
||||
required: [taskId, status]
|
||||
properties:
|
||||
taskId: { type: integer }
|
||||
status:
|
||||
type: string
|
||||
enum: [SUCCEEDED, FAILED, CANCELLED]
|
||||
progress: { type: integer }
|
||||
errorCode: { type: string }
|
||||
result: { type: object }
|
||||
signature: { type: string }
|
||||
ReportResponse:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/StandardResponse'
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: integer }
|
||||
childId: { type: integer }
|
||||
taskId: { type: integer }
|
||||
riskLevel: { type: string, enum: [low, medium, high, review_required] }
|
||||
summary: { type: string }
|
||||
metrics:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
name: { type: string }
|
||||
value: { type: number }
|
||||
level: { type: string }
|
||||
confidence: { type: number }
|
||||
recommendations:
|
||||
type: array
|
||||
items: { type: string }
|
||||
disclaimer: { type: string }
|
||||
reviewedBy: { type: integer, nullable: true }
|
||||
TrainingPlanCreateRequest:
|
||||
type: object
|
||||
required: [childId, goal, cycleDays]
|
||||
properties:
|
||||
childId: { type: integer }
|
||||
reportId: { type: integer }
|
||||
goal: { type: string }
|
||||
cycleDays: { type: integer, minimum: 7 }
|
||||
exerciseIds:
|
||||
type: array
|
||||
items: { type: integer }
|
||||
constraints:
|
||||
type: object
|
||||
properties:
|
||||
maxDailyMinutes: { type: integer }
|
||||
coachNotes: { type: string }
|
||||
TrainingPlanResponse:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/StandardResponse'
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: integer }
|
||||
status: { type: string, enum: [draft, active, completed, paused] }
|
||||
detail: { type: object }
|
||||
startedAt: { type: string, format: date-time }
|
||||
endedAt: { type: string, format: date-time, nullable: true }
|
||||
TrainingRecordCreateRequest:
|
||||
type: object
|
||||
required: [exerciseId, completed]
|
||||
properties:
|
||||
exerciseId: { type: integer }
|
||||
completed: { type: boolean }
|
||||
score: { type: integer, minimum: 0, maximum: 100 }
|
||||
durationSeconds: { type: integer }
|
||||
note: { type: string }
|
||||
media:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
TrainingRecordResponse:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/StandardResponse'
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: integer }
|
||||
planId: { type: integer }
|
||||
createdAt: { type: string, format: date-time }
|
||||
AdminDashboardResponse:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/StandardResponse'
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
newChildren: { type: integer }
|
||||
uploadedVideos: { type: integer }
|
||||
completedReports: { type: integer }
|
||||
activePlans: { type: integer }
|
||||
conversionRate: { type: number }
|
||||
reassessmentCompletionRate: { type: number }
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,61 @@
|
||||
# 儿童 AI 体态管理与运动康复平台 · 商业交付版本 V1.0
|
||||
|
||||
> 面向 3–16 岁儿童青少年的 AI 体态管理与运动康复平台(非医疗诊断)
|
||||
|
||||
---
|
||||
|
||||
## 文档目录
|
||||
|
||||
| 序号 | 模块 | 文档 | 说明 |
|
||||
|:----:|------|------|------|
|
||||
| 01 | 商业计划书 | [儿童AI体态管理商业计划书.docx](../01_商业计划书/儿童AI体态管理商业计划书.docx) | 商业模式与市场分析 |
|
||||
| 02 | 企业级 PRD | [PRD完整版.docx](../02_企业级PRD/PRD完整版.docx) | 产品需求、指标、用户故事 |
|
||||
| 03 | 技术架构 | [企业级系统架构.docx](./03_技术架构/企业级系统架构.docx) | 云原生分层架构设计 |
|
||||
| 03 | **架构与建设规划** | **[系统架构与建设规划.md](./03_技术架构/系统架构与建设规划.md)** | **合伙人讨论用 · 架构 + 排期 + 行动清单** |
|
||||
| 03 | **架构 HTML 演示** | **[系统架构与建设规划.html](./03_技术架构/系统架构与建设规划.html)** | **浏览器打开 · 可视化架构图与路线图** |
|
||||
| 03 | **产品交互 Demo** | **[产品交互Demo.html](./03_技术架构/产品交互Demo.html)** | **P2:摄像头 + PDF · 跟练/趋势/儿童端** |
|
||||
| — | **工程 Starter** | **[apps/api/README.md](../../apps/api/README.md)** | **P3:FastAPI 骨架 · 对齐 OpenAPI** |
|
||||
| 04 | AI 视觉算法 | [AI视觉算法详细设计.docx](../04_AI视觉算法/AI视觉算法详细设计.docx) | Pose、指标、评分、质量控制 |
|
||||
| 05 | 视频处理 | [视频处理工程设计.docx](../05_视频处理系统/视频处理工程设计.docx) | 上传、转码、质量检测 |
|
||||
| 06 | 数据库设计 | [database.sql](../06_数据库设计/database.sql) | MySQL 8.x 完整表结构 |
|
||||
| 07 | API 接口 | [openapi.yaml](../07_API接口/openapi.yaml) | REST API 契约(OpenAPI 3.0) |
|
||||
| 08 | Agent 智能系统 | [Agent设计规范.docx](../08_Agent智能系统/Agent设计规范.docx) | 评估/教练/家长/运营 Agent |
|
||||
| 09 | 前端产品设计 | [前端产品详细设计.docx](../09_前端产品设计/前端产品详细设计.docx) | 小程序、训练端、后台 |
|
||||
| 10 | 后端工程设计 | [后端工程详细设计.docx](../10_后端工程设计/后端工程详细设计.docx) | 服务模块、权限、安全 |
|
||||
| 11 | 管理后台 | [管理后台详细设计.docx](../11_管理后台/管理后台详细设计.docx) | 运营、复核、看板 |
|
||||
| 12 | 研发计划 | [研发计划与项目管理.docx](../12_研发计划/研发计划与项目管理.docx) | P0–P3 里程碑与团队分工 |
|
||||
| 13 | 测试验收 | [测试验收标准.docx](../13_测试验收/测试验收标准.docx) | 场景测试与验收清单 |
|
||||
| 14 | 部署运维 | [生产部署运维.docx](../14_部署运维/生产部署运维.docx) | 环境、发布、监控、备份 |
|
||||
| 15 | 运营 SOP | [商业运营与课程SOP.docx](../15_运营SOP/商业运营与课程SOP.docx) | 机构运营与课程流程 |
|
||||
|
||||
---
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 合伙人 / 投资人讨论
|
||||
|
||||
1. 用浏览器打开 **[系统架构与建设规划.html](./03_技术架构/系统架构与建设规划.html)**
|
||||
2. 点击 **「进入产品交互 Demo」** 体验完整产品流程(无需开发,纯演示)
|
||||
3. 配合阅读 **[系统架构与建设规划.md](./03_技术架构/系统架构与建设规划.md)** 获取完整文字版
|
||||
|
||||
### 研发启动
|
||||
|
||||
1. 阅读 [PRD完整版.docx](../02_企业级PRD/PRD完整版.docx) 确认 MVP 范围
|
||||
2. 以 [openapi.yaml](../07_API接口/openapi.yaml) 为 API 契约单一来源(工程副本:`../../contracts/`)
|
||||
3. 以 [database.sql](../06_数据库设计/database.sql) 初始化数据库(`make up`)
|
||||
4. 启动 API Starter:见仓库根 [README.md](../../README.md)
|
||||
5. 按 [系统架构与建设规划.md](./03_技术架构/系统架构与建设规划.md) Sprint 1 排期
|
||||
|
||||
---
|
||||
|
||||
## 版本信息
|
||||
|
||||
| 字段 | 值 |
|
||||
|------|-----|
|
||||
| 版本 | V1.0 |
|
||||
| 更新日期 | 2026-07-23 |
|
||||
| 适用阶段 | MVP → 商业试点 → 商业交付 |
|
||||
|
||||
---
|
||||
|
||||
*本交付包所有 AI 报告输出用于健康管理建议,不构成医疗诊断。*
|
||||
Binary file not shown.
Reference in New Issue
Block a user