先更新1版记录下

This commit is contained in:
2026-04-16 11:30:30 +08:00
parent ead8e2edd5
commit 2f2d796e30
40 changed files with 393714 additions and 4071 deletions

View File

@@ -1,77 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<mxfile host="app.diagrams.net" modified="2026-04-14T10:41:00.000Z" agent="Oz" version="24.7.17">
<diagram id="ctx-er" name="ER图">
<mxGraphModel dx="1800" dy="1200" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1800" pageHeight="1200" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="2" value="00 组织与权限上下文 - ER图" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=22;fontStyle=1;" parent="1" vertex="1">
<mxGeometry x="20" y="20" width="450" height="30" as="geometry"/>
</mxCell>
<mxCell id="3" value="统一隔离键adcode / tenant_id / tenant_path / dept_id / dept_path" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#666666;" parent="1" vertex="1">
<mxGeometry x="20" y="52" width="720" height="24" as="geometry"/>
</mxCell>
<mxCell id="10" value="tb_sys_tenant&lt;br&gt;PK tenant_id&lt;br&gt;FK parent_tenant_id -&gt; tb_sys_tenant.tenant_id&lt;br&gt;tenant_name, tenant_type, status&lt;br&gt;adcode, tenant_path, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=12;" parent="1" vertex="1">
<mxGeometry x="40" y="120" width="280" height="140" as="geometry"/>
</mxCell>
<mxCell id="11" value="tb_sys_dept&lt;br&gt;PK dept_id&lt;br&gt;FK parent_dept_id -&gt; tb_sys_dept.dept_id&lt;br&gt;FK tenant_id -&gt; tb_sys_tenant.tenant_id&lt;br&gt;dept_name, dept_type&lt;br&gt;adcode, tenant_path, dept_path, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=12;" parent="1" vertex="1">
<mxGeometry x="360" y="120" width="300" height="150" as="geometry"/>
</mxCell>
<mxCell id="12" value="tb_sys_user&lt;br&gt;PK user_id, UK username&lt;br&gt;FK tenant_id -&gt; tb_sys_tenant.tenant_id&lt;br&gt;FK dept_id -&gt; tb_sys_dept.dept_id&lt;br&gt;display_name, password_hash, status&lt;br&gt;adcode, tenant_path, dept_path, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=12;" parent="1" vertex="1">
<mxGeometry x="700" y="120" width="320" height="150" as="geometry"/>
</mxCell>
<mxCell id="13" value="tb_sys_role&lt;br&gt;PK role_id, UK role_code&lt;br&gt;FK tenant_id -&gt; tb_sys_tenant.tenant_id&lt;br&gt;role_name&lt;br&gt;dept_id, dept_path, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;fontSize=12;" parent="1" vertex="1">
<mxGeometry x="700" y="320" width="290" height="130" as="geometry"/>
</mxCell>
<mxCell id="14" value="tb_sys_permission&lt;br&gt;PK permission_id, UK permission_code&lt;br&gt;FK tenant_id -&gt; tb_sys_tenant.tenant_id&lt;br&gt;permission_name&lt;br&gt;dept_id, dept_path, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;fontSize=12;" parent="1" vertex="1">
<mxGeometry x="1030" y="320" width="320" height="130" as="geometry"/>
</mxCell>
<mxCell id="15" value="rel_user_role&lt;br&gt;PK (user_id, role_id)&lt;br&gt;FK user_id -&gt; tb_sys_user.user_id&lt;br&gt;FK role_id -&gt; tb_sys_role.role_id&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" parent="1" vertex="1">
<mxGeometry x="1030" y="120" width="290" height="130" as="geometry"/>
</mxCell>
<mxCell id="16" value="rel_role_permission&lt;br&gt;PK (role_id, permission_id)&lt;br&gt;FK role_id -&gt; tb_sys_role.role_id&lt;br&gt;FK permission_id -&gt; tb_sys_permission.permission_id&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" parent="1" vertex="1">
<mxGeometry x="1360" y="120" width="320" height="130" as="geometry"/>
</mxCell>
<mxCell id="17" value="tb_auth_refresh_token&lt;br&gt;PK token_id&lt;br&gt;FK user_id -&gt; tb_sys_user.user_id&lt;br&gt;refresh_token, expire_at, revoked&lt;br&gt;tenant_id, dept_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=12;" parent="1" vertex="1">
<mxGeometry x="40" y="330" width="300" height="130" as="geometry"/>
</mxCell>
<mxCell id="18" value="tb_auth_login_audit&lt;br&gt;PK audit_id&lt;br&gt;FK user_id -&gt; tb_sys_user.user_id&lt;br&gt;username, login_ip, login_status&lt;br&gt;tenant_id, dept_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=12;" parent="1" vertex="1">
<mxGeometry x="360" y="330" width="300" height="130" as="geometry"/>
</mxCell>
<mxCell id="19" value="设计方法与原因&lt;br&gt;1) DDD上下文先行权限域作为业务域前置依赖&lt;br&gt;2) RBAC最小闭环用户-角色-权限拆分降低耦合&lt;br&gt;3) 多租户统一隔离键:保证后续业务表可水平扩展&lt;br&gt;4) 认证审计分离:令牌高频写与审计查询分流" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" parent="1" vertex="1">
<mxGeometry x="1360" y="320" width="320" height="170" as="geometry"/>
</mxCell>
<mxCell id="100" value="N:1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#6c8ebf;" parent="1" source="11" target="10" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="101" value="N:1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#6c8ebf;" parent="1" source="12" target="10" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="102" value="N:1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#6c8ebf;" parent="1" source="12" target="11" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="103" value="N:1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#9673a6;" parent="1" source="13" target="10" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="104" value="M:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#d6b656;" parent="1" source="15" target="12" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="105" value="M:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#d6b656;" parent="1" source="15" target="13" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="106" value="M:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#d6b656;" parent="1" source="16" target="13" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="107" value="M:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#d6b656;" parent="1" source="16" target="14" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="108" value="N:1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#b85450;" parent="1" source="17" target="12" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="109" value="N:1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#b85450;" parent="1" source="18" target="12" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
</diagram>
<mxfile host="65bd71144e">
<diagram id="ctx-er-v2" name="ER图">
<mxGraphModel dx="1312" dy="773" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1800" pageHeight="1200" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="2" value="00 组织与权限上下文 - ER图含班级模型" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=22;fontStyle=1;" parent="1" vertex="1">
<mxGeometry x="20" y="20" width="620" height="30" as="geometry"/>
</mxCell>
<mxCell id="3" value="全局技术栈对齐:业务主数据落 PostgreSQLAI知识检索能力由 Milvus + NebulaGraph/Neo4j 承担;同步调度统一采用 REST/JAR本模块仅维护组织权限" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=12;fontColor=#666666;" parent="1" vertex="1">
<mxGeometry x="20" y="52" width="1400" height="24" as="geometry"/>
</mxCell>
<mxCell id="10" value="upms.tb_sys_tenant&lt;br&gt;PK tenant_id&lt;br&gt;parent_tenant_id, tenant_name, tenant_type&lt;br&gt;adcode, tenant_path, status" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="40" y="90" width="280" height="120" as="geometry"/>
</mxCell>
<mxCell id="11" value="upms.tb_sys_dept&lt;br&gt;PK dept_id&lt;br&gt;FK tenant_id -&gt; tb_sys_tenant.tenant_id&lt;br&gt;parent_dept_id, dept_name, dept_type&lt;br&gt;adcode, tenant_path, dept_path" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="360" y="90" width="320" height="140" as="geometry"/>
</mxCell>
<mxCell id="12" value="upms.tb_sys_user&lt;br&gt;PK user_id, UK username&lt;br&gt;FK tenant_id -&gt; tb_sys_tenant.tenant_id&lt;br&gt;FK dept_id -&gt; tb_sys_dept.dept_id&lt;br&gt;display_name, status, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="730" y="90" width="340" height="140" as="geometry"/>
</mxCell>
<mxCell id="13" value="upms.tb_sys_role&lt;br&gt;PK role_id, UK role_code&lt;br&gt;tenant_id, role_name, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1">
<mxGeometry x="1110" y="90" width="280" height="110" as="geometry"/>
</mxCell>
<mxCell id="14" value="upms.tb_sys_menu&lt;br&gt;PK route_id&lt;br&gt;parent_route_id, route_path, component_key&lt;br&gt;permission_code, hidden, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1">
<mxGeometry x="1430" y="90" width="320" height="130" as="geometry"/>
</mxCell>
<mxCell id="15" value="upms.tb_sys_role_menu&lt;br&gt;PK (role_id, route_id)&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="1430" y="260" width="300" height="100" as="geometry"/>
</mxCell>
<mxCell id="16" value="auth.tb_auth_refresh_token&lt;br&gt;PK token_id&lt;br&gt;FK user_id -&gt; tb_sys_user.user_id&lt;br&gt;refresh_token, expire_at, revoked" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1">
<mxGeometry x="40" y="290" width="320" height="120" as="geometry"/>
</mxCell>
<mxCell id="17" value="auth.tb_auth_login_audit&lt;br&gt;PK audit_id&lt;br&gt;FK user_id -&gt; tb_sys_user.user_id&lt;br&gt;username, login_ip, login_status" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1">
<mxGeometry x="400" y="290" width="320" height="120" as="geometry"/>
</mxCell>
<mxCell id="18" value="upms.tb_school_class&lt;br&gt;PK class_id&lt;br&gt;FK dept_id -&gt; tb_sys_dept.dept_id&lt;br&gt;class_name, grade_code, status&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="760" y="290" width="340" height="140" as="geometry"/>
</mxCell>
<mxCell id="19" value="upms.tb_school_class_member&lt;br&gt;PK (class_id, user_id)&lt;br&gt;FK class_id -&gt; tb_school_class.class_id&lt;br&gt;FK user_id -&gt; tb_sys_user.user_id&lt;br&gt;member_role, member_status, joined_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="1140" y="450" width="350" height="150" as="geometry"/>
</mxCell>
<mxCell id="20" value="upms.tb_school_class_course_rel&lt;br&gt;PK (class_id, course_id)&lt;br&gt;FK class_id -&gt; tb_school_class.class_id&lt;br&gt;relation_status, tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="1530" y="390" width="320" height="120" as="geometry"/>
</mxCell>
<mxCell id="30" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;exitX=1;exitY=0.35;entryX=0;entryY=0.35;" parent="1" source="10" target="11" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="31" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;exitX=1;exitY=0;entryX=0;entryY=0;" parent="1" source="10" target="12" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="700" y="70"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="32" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;exitX=0.6;exitY=1;entryX=0.4;entryY=0;" parent="1" source="13" target="15" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="33" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;exitX=0.4;exitY=1;entryX=0.6;entryY=0;" parent="1" source="14" target="15" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="34" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;exitX=0;exitY=0.7;entryX=1;entryY=0.35;" parent="1" source="12" target="16" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="35" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;exitX=0;exitY=0.85;entryX=1;entryY=0.45;" parent="1" source="12" target="17" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="36" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;exitX=1;exitY=0.8;entryX=0;entryY=0.4;" parent="1" source="11" target="18" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="37" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;exitX=1;exitY=0.6;entryX=0;entryY=0.4;" parent="1" source="18" target="19" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="38" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;exitX=1;exitY=0.85;entryX=0;entryY=0.2;" parent="1" source="18" target="20" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

View File

@@ -8,6 +8,9 @@
<mxCell id="2" value="00 组织与权限上下文 - 对象类数据流图" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=22;fontStyle=1;" parent="1" vertex="1">
<mxGeometry x="20" y="20" width="520" height="30" as="geometry"/>
</mxCell>
<mxCell id="3" value="本模块边界说明:仅承载组织/权限与认证AI 图谱与向量同步任务由 ai 模块统一调度REST/JAR目标存储为 Milvus + NebulaGraph/Neo4j" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=12;fontColor=#666666;" parent="1" vertex="1">
<mxGeometry x="20" y="52" width="1200" height="24" as="geometry"/>
</mxCell>
<mxCell id="10" value="Actor&lt;br&gt;学生" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="40" y="120" width="120" height="70" as="geometry"/>
</mxCell>
@@ -38,7 +41,7 @@
<mxCell id="41" value="Entity&lt;br&gt;TenantDeptAggregate" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1">
<mxGeometry x="820" y="210" width="200" height="70" as="geometry"/>
</mxCell>
<mxCell id="42" value="Entity&lt;br&gt;RolePermissionAggregate" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1">
<mxCell id="42" value="Entity&lt;br&gt;RoleMenuAggregate" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1">
<mxGeometry x="820" y="310" width="200" height="70" as="geometry"/>
</mxCell>
<mxCell id="43" value="Entity&lt;br&gt;AuthTokenStore" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1">
@@ -50,7 +53,7 @@
<mxCell id="51" value="Redis(Session/Token)" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="1090" y="320" width="220" height="80" as="geometry"/>
</mxCell>
<mxCell id="60" value="设计方法与原因&lt;br&gt;1) BCE分层明确交互职责&lt;br&gt;2) 鉴权与查询控制器分离,便于独立扩展&lt;br&gt;3) 权判定集中到Policy服务降低重复逻辑&lt;br&gt;4) Token热数据落Redis用户组织主数据落PG" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" parent="1" vertex="1">
<mxCell id="60" value="设计方法与原因&lt;br&gt;1) BCE分层明确交互职责&lt;br&gt;2) 鉴权与查询控制器分离,便于独立扩展&lt;br&gt;3) 菜单授权判定集中到Policy服务降低重复逻辑&lt;br&gt;4) Token热数据落Redis用户组织主数据落PG&lt;br&gt;5) AI同步调度配置通过权限体系统一管控" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" parent="1" vertex="1">
<mxGeometry x="1360" y="190" width="360" height="180" as="geometry"/>
</mxCell>
<mxCell id="100" value="登录/路由请求" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="10" target="20" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
@@ -61,7 +64,7 @@
<mxCell id="105" value="权限判定" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="31" target="32" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="106" value="用户读取" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="30" target="40" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="107" value="组织读取" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="31" target="41" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="108" value="角色权限读取" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="32" target="42" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="108" value="角色菜单读取" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="32" target="42" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="109" value="Token签发/撤销" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="30" target="43" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="110" value="持久化" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="40" target="50" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="111" value="持久化" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="41" target="50" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>

View File

@@ -1,64 +1,112 @@
<?xml version="1.0" encoding="UTF-8"?>
<mxfile host="app.diagrams.net" modified="2026-04-14T10:42:00.000Z" agent="Oz" version="24.7.17">
<diagram id="course-er" name="ER图">
<mxGraphModel dx="1800" dy="1200" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1800" pageHeight="1200" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="2" value="01 课程学习 - ER图" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=22;fontStyle=1;" parent="1" vertex="1">
<mxGeometry x="20" y="20" width="360" height="30" as="geometry"/>
</mxCell>
<mxCell id="3" value="课程主数据 + 学习过程数据分层;所有业务主表均携带 tenant_id/adcode/dept_path" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#666666;" parent="1" vertex="1">
<mxGeometry x="20" y="52" width="860" height="24" as="geometry"/>
</mxCell>
<mxCell id="10" value="cl_course&lt;br&gt;PK course_id&lt;br&gt;title, subject_code, grade_code&lt;br&gt;difficulty_level, status&lt;br&gt;tenant_id, adcode, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="40" y="120" width="250" height="130" as="geometry"/>
</mxCell>
<mxCell id="11" value="cl_course_chapter&lt;br&gt;PK chapter_id&lt;br&gt;FK course_id -&gt; cl_course.course_id&lt;br&gt;chapter_no, chapter_title&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="330" y="120" width="250" height="130" as="geometry"/>
</mxCell>
<mxCell id="12" value="cl_course_lesson&lt;br&gt;PK lesson_id&lt;br&gt;FK chapter_id -&gt; cl_course_chapter.chapter_id&lt;br&gt;lesson_no, lesson_title, duration_sec&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="620" y="120" width="270" height="130" as="geometry"/>
</mxCell>
<mxCell id="13" value="cl_knowledge_point&lt;br&gt;PK kp_id&lt;br&gt;kp_code, kp_name, subject_code, grade_code&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1">
<mxGeometry x="930" y="120" width="260" height="120" as="geometry"/>
</mxCell>
<mxCell id="14" value="cl_course_knowledge_rel&lt;br&gt;PK (course_id, kp_id)&lt;br&gt;FK course_id -&gt; cl_course.course_id&lt;br&gt;FK kp_id -&gt; cl_knowledge_point.kp_id&lt;br&gt;weight, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="1230" y="120" width="280" height="130" as="geometry"/>
</mxCell>
<mxCell id="15" value="cl_course_resource&lt;br&gt;PK resource_id&lt;br&gt;FK lesson_id -&gt; cl_course_lesson.lesson_id&lt;br&gt;resource_type(pdf/video/doc), resource_url&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="620" y="290" width="290" height="130" as="geometry"/>
</mxCell>
<mxCell id="16" value="cl_course_tag&lt;br&gt;PK tag_id&lt;br&gt;tag_name, tag_type&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1">
<mxGeometry x="40" y="300" width="230" height="110" as="geometry"/>
</mxCell>
<mxCell id="17" value="cl_course_tag_rel&lt;br&gt;PK (course_id, tag_id)&lt;br&gt;FK course_id -&gt; cl_course.course_id&lt;br&gt;FK tag_id -&gt; cl_course_tag.tag_id&lt;br&gt;tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="300" y="300" width="270" height="120" as="geometry"/>
</mxCell>
<mxCell id="18" value="cl_learning_session&lt;br&gt;PK session_id&lt;br&gt;FK user_id -&gt; tb_sys_user.user_id&lt;br&gt;FK course_id -&gt; cl_course.course_id&lt;br&gt;status(STARTED/PAUSED/COMPLETED)&lt;br&gt;started_at, ended_at, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="930" y="290" width="300" height="140" as="geometry"/>
</mxCell>
<mxCell id="19" value="cl_learning_progress&lt;br&gt;PK progress_id&lt;br&gt;FK session_id -&gt; cl_learning_session.session_id&lt;br&gt;FK lesson_id -&gt; cl_course_lesson.lesson_id&lt;br&gt;progress_pct, last_position_sec&lt;br&gt;mastery_level, tenant_id, updated_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="1260" y="300" width="320" height="140" as="geometry"/>
</mxCell>
<mxCell id="20" value="cl_learning_event&lt;br&gt;PK event_id&lt;br&gt;FK session_id -&gt; cl_learning_session.session_id&lt;br&gt;event_type(start/pause/seek/finish)&lt;br&gt;event_time, payload_json, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="930" y="460" width="300" height="130" as="geometry"/>
</mxCell>
<mxCell id="21" value="设计方法与原因&lt;br&gt;1) 聚合根Course / LearningSession&lt;br&gt;2) 状态机Session状态驱动进度写入&lt;br&gt;3) 标签与知识点解耦,支持多维检索&lt;br&gt;4) 事件明细单表追加,兼顾审计与回放" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1">
<mxGeometry x="40" y="470" width="840" height="120" as="geometry"/>
</mxCell>
<mxCell id="100" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="11" target="10" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="101" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="12" target="11" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="102" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="15" target="12" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="103" value="M:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="14" target="10" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="104" value="M:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="14" target="13" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="105" value="M:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="17" target="10" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="106" value="M:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="17" target="16" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="107" value="N:1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="18" target="10" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="108" value="N:1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="19" target="18" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="109" value="N:1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="19" target="12" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="110" value="N:1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="20" target="18" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
</root>
</mxGraphModel>
</diagram>
<mxfile host="65bd71144e">
<diagram id="course-er" name="ER图">
<mxGraphModel dx="1312" dy="773" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1800" pageHeight="1200" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="2" value="01 课程学习 - ER图含知识点掌握与图谱/向量同步关联)" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=22;fontStyle=1;" parent="1" vertex="1">
<mxGeometry x="20" y="20" width="360" height="30" as="geometry"/>
</mxCell>
<mxCell id="3" value="课程主数据 + 学习过程数据分层;业务主库为 PostgreSQL知识检索能力由 Milvus + NebulaGraph/Neo4j 承担" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#666666;" parent="1" vertex="1">
<mxGeometry x="20" y="52" width="1100" height="24" as="geometry"/>
</mxCell>
<mxCell id="10" value="cl_course&lt;br&gt;PK course_id&lt;br&gt;title, subject_code, grade_code&lt;br&gt;difficulty_level, status&lt;br&gt;tenant_id, adcode, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="50" y="130" width="250" height="130" as="geometry"/>
</mxCell>
<mxCell id="12" value="cl_course_lesson&lt;br&gt;PK lesson_id&lt;br&gt;FK chapter_id -&gt; cl_course_chapter.chapter_id&lt;br&gt;lesson_no, lesson_title, duration_sec&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="650" y="300" width="270" height="130" as="geometry"/>
</mxCell>
<mxCell id="13" value="cl_knowledge_point&lt;br&gt;PK kp_id&lt;br&gt;kp_code, kp_name, subject_code, grade_code&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1">
<mxGeometry x="1030" y="10" width="260" height="120" as="geometry"/>
</mxCell>
<mxCell id="14" value="cl_course_knowledge_rel&lt;br&gt;PK (course_id, kp_id)&lt;br&gt;FK course_id -&gt; cl_course.course_id&lt;br&gt;FK kp_id -&gt; cl_knowledge_point.kp_id&lt;br&gt;weight, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="1680" y="190" width="280" height="130" as="geometry"/>
</mxCell>
<mxCell id="15" value="cl_course_resource&lt;br&gt;PK resource_id&lt;br&gt;FK lesson_id -&gt; cl_course_lesson.lesson_id&lt;br&gt;resource_type(pdf/video/doc), resource_url&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="640" y="560" width="290" height="130" as="geometry"/>
</mxCell>
<mxCell id="16" value="cl_course_tag&lt;br&gt;PK tag_id&lt;br&gt;tag_name, tag_type&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1">
<mxGeometry x="50" y="420" width="230" height="110" as="geometry"/>
</mxCell>
<mxCell id="17" value="cl_course_tag_rel&lt;br&gt;PK (course_id, tag_id)&lt;br&gt;FK course_id -&gt; cl_course.course_id&lt;br&gt;FK tag_id -&gt; cl_course_tag.tag_id&lt;br&gt;tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="330" y="410" width="270" height="120" as="geometry"/>
</mxCell>
<mxCell id="18" value="cl_learning_session&lt;br&gt;PK session_id&lt;br&gt;FK user_id -&gt; tb_sys_user.user_id&lt;br&gt;FK course_id -&gt; cl_course.course_id&lt;br&gt;status(STARTED/PAUSED/COMPLETED)&lt;br&gt;started_at, ended_at, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="950" y="450" width="300" height="140" as="geometry"/>
</mxCell>
<mxCell id="19" value="cl_learning_progress&lt;br&gt;PK progress_id&lt;br&gt;FK session_id -&gt; cl_learning_session.session_id&lt;br&gt;FK lesson_id -&gt; cl_course_lesson.lesson_id&lt;br&gt;progress_pct, last_position_sec&lt;br&gt;mastery_level, tenant_id, updated_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="1880" y="295" width="320" height="140" as="geometry"/>
</mxCell>
<mxCell id="20" value="cl_learning_event&lt;br&gt;PK event_id&lt;br&gt;FK session_id -&gt; cl_learning_session.session_id&lt;br&gt;event_type(start/pause/seek/finish)&lt;br&gt;event_time, payload_json, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="950" y="750" width="300" height="130" as="geometry"/>
</mxCell>
<mxCell id="21" value="设计方法与原因&lt;br&gt;1) 聚合根Course / LearningSession&lt;br&gt;2) 状态机Session状态驱动进度写入&lt;br&gt;3) 标签与知识点解耦,支持多维检索&lt;br&gt;4) 事件明细单表追加,兼顾审计与回放&lt;br&gt;5) 知识点/学习画像变化可通过 ai.tb_ai_knowledge_sync_task 异步同步" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1">
<mxGeometry x="10" y="850" width="840" height="120" as="geometry"/>
</mxCell>
<mxCell id="22" value="外部同步依赖ai&lt;br&gt;ai.tb_ai_knowledge_file&lt;br&gt;ai.tb_ai_knowledge_sync_task&lt;br&gt;ai.tb_ai_graph_entity / ai.tb_ai_graph_relation" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" parent="1" vertex="1">
<mxGeometry x="1320" y="760" width="330" height="150" as="geometry"/>
</mxCell>
<mxCell id="23" value="cl_kp_prerequisite_rel&lt;br&gt;PK (kp_id, pre_kp_id)&lt;br&gt;FK kp_id -&gt; cl_knowledge_point.kp_id&lt;br&gt;FK pre_kp_id -&gt; cl_knowledge_point.kp_id&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="1320" y="150" width="340" height="120" as="geometry"/>
</mxCell>
<mxCell id="24" value="cl_kp_material_rel&lt;br&gt;PK (kp_id, resource_id)&lt;br&gt;FK kp_id -&gt; cl_knowledge_point.kp_id&lt;br&gt;FK resource_id -&gt; cl_course_resource.resource_id&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="1350" y="565" width="360" height="120" as="geometry"/>
</mxCell>
<mxCell id="25" value="cl_student_kp_mastery&lt;br&gt;PK mastery_id&lt;br&gt;FK kp_id -&gt; cl_knowledge_point.kp_id&lt;br&gt;student_id, mastery_level, mastery_score&lt;br&gt;last_practiced_at, tenant_id, updated_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="1320" y="420" width="360" height="120" as="geometry"/>
</mxCell>
<mxCell id="100" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="10" target="11" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="101" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="11" target="12" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="102" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="12" target="15" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="103" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="10" target="14" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="104" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="13" target="14" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="105" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="11" target="17" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="106" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="16" target="17" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="107" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="10" target="18" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="108" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="18" target="19" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="109" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="12" target="19" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="110" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="18" target="20" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="112" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="13" target="23" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="113" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="13" target="24" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="114" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="15" target="24" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="115" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="13" target="25" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="116" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="19" target="25" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="11" value="cl_course_chapter&lt;br&gt;PK chapter_id&lt;br&gt;FK course_id -&gt; cl_course.course_id&lt;br&gt;chapter_no, chapter_title&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="340" y="240" width="250" height="130" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

View File

@@ -8,6 +8,9 @@
<mxCell id="2" value="01 课程学习 - 对象类数据流图" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=22;fontStyle=1;" parent="1" vertex="1">
<mxGeometry x="20" y="20" width="460" height="30" as="geometry"/>
</mxCell>
<mxCell id="3" value="知识点/学习进度相关事件可入 ai 同步任务表,由调度器以 REST/JAR 模式驱动向 Milvus + NebulaGraph/Neo4j 同步" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=12;fontColor=#666666;" parent="1" vertex="1">
<mxGeometry x="20" y="52" width="1300" height="24" as="geometry"/>
</mxCell>
<mxCell id="10" value="Actor&lt;br&gt;学生" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1"><mxGeometry x="40" y="130" width="120" height="70" as="geometry"/></mxCell>
<mxCell id="11" value="Actor&lt;br&gt;教师" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1"><mxGeometry x="40" y="240" width="120" height="70" as="geometry"/></mxCell>
<mxCell id="12" value="Actor&lt;br&gt;机构管理员" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1"><mxGeometry x="40" y="350" width="120" height="70" as="geometry"/></mxCell>
@@ -20,9 +23,12 @@
<mxCell id="41" value="Entity&lt;br&gt;KnowledgeIndexAggregate" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1"><mxGeometry x="800" y="210" width="220" height="70" as="geometry"/></mxCell>
<mxCell id="42" value="Entity&lt;br&gt;LearningSessionAggregate" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1"><mxGeometry x="800" y="310" width="230" height="70" as="geometry"/></mxCell>
<mxCell id="43" value="Entity&lt;br&gt;LearningProgressAggregate" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1"><mxGeometry x="800" y="410" width="240" height="70" as="geometry"/></mxCell>
<mxCell id="44" value="Entity&lt;br&gt;AiSyncTaskAggregate" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1"><mxGeometry x="800" y="510" width="240" height="70" as="geometry"/></mxCell>
<mxCell id="50" value="PostgreSQL(course/learning)" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="1080" y="170" width="240" height="90" as="geometry"/></mxCell>
<mxCell id="51" value="Redis(学习进度热点缓存)" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="1080" y="320" width="240" height="90" as="geometry"/></mxCell>
<mxCell id="60" value="设计方法与原因&lt;br&gt;1) CQRS课程目录读取与学习进度写入分离&lt;br&gt;2) 会话聚合驱动事件化进度更新&lt;br&gt;3) 热点进度走Redis减轻主库读压&lt;br&gt;4) 课程实体与知识点索引分离,支持后续多策略检索" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" parent="1" vertex="1">
<mxCell id="52" value="PostgreSQL(ai sync task/config)" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="1080" y="470" width="260" height="90" as="geometry"/></mxCell>
<mxCell id="53" value="Milvus + NebulaGraph/Neo4j" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="1080" y="620" width="260" height="90" as="geometry"/></mxCell>
<mxCell id="60" value="设计方法与原因&lt;br&gt;1) CQRS课程目录读取与学习进度写入分离&lt;br&gt;2) 会话聚合驱动事件化进度更新&lt;br&gt;3) 热点进度走Redis减轻主库读压&lt;br&gt;4) 课程实体与知识点索引分离,支持后续多策略检索&lt;br&gt;5) 同步调度支持 JAR 本地执行与 REST 远程触发" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" parent="1" vertex="1">
<mxGeometry x="1360" y="170" width="360" height="190" as="geometry"/>
</mxCell>
<mxCell id="100" value="浏览课程/课时" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="10" target="20" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
@@ -40,6 +46,9 @@
<mxCell id="112" value="持久化" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="42" target="50" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="113" value="持久化/缓存" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="43" target="50" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="114" value="热点缓存" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="43" target="51" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="115" value="同步任务入队" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;dashed=1;endArrow=block;endFill=1;" parent="1" source="32" target="44" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="116" value="落库" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="44" target="52" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="117" value="REST/JAR调度执行" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;dashed=1;endArrow=block;endFill=1;" parent="1" source="44" target="53" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
</root>
</mxGraphModel>
</diagram>

View File

@@ -1,38 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<mxfile host="app.diagrams.net" modified="2026-04-14T10:43:00.000Z" agent="Oz" version="24.7.17">
<diagram id="homework-er" name="ER图">
<mxfile host="app.diagrams.net" modified="2026-04-15T07:43:00.000Z" agent="Oz" version="24.7.17">
<diagram id="homework-er-v2" name="ER图">
<mxGraphModel dx="1800" dy="1200" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1800" pageHeight="1200" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="2" value="02 习题与作业 - ER图" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=22;fontStyle=1;" parent="1" vertex="1">
<mxGeometry x="20" y="20" width="400" height="30" as="geometry"/>
<mxCell id="2" value="02 习题与作业 - ER图question单schema10_create + 20_init" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=22;fontStyle=1;" parent="1" vertex="1">
<mxGeometry x="20" y="20" width="520" height="30" as="geometry"/>
</mxCell>
<mxCell id="10" value="hw_question_bank&lt;br&gt;PK bank_id&lt;br&gt;bank_name, subject_code, grade_code&lt;br&gt;status, tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1"><mxGeometry x="40" y="110" width="240" height="120" as="geometry"/></mxCell>
<mxCell id="11" value="hw_question_item&lt;br&gt;PK question_id&lt;br&gt;FK bank_id -&gt; hw_question_bank.bank_id&lt;br&gt;question_type, stem, difficulty&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1"><mxGeometry x="310" y="110" width="270" height="130" as="geometry"/></mxCell>
<mxCell id="12" value="hw_question_version&lt;br&gt;PK version_id&lt;br&gt;FK question_id -&gt; hw_question_item.question_id&lt;br&gt;version_no, answer_key, analysis&lt;br&gt;is_current, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1"><mxGeometry x="610" y="110" width="280" height="130" as="geometry"/></mxCell>
<mxCell id="13" value="hw_question_kp_rel&lt;br&gt;PK (question_id, kp_id)&lt;br&gt;FK question_id -&gt; hw_question_item.question_id&lt;br&gt;FK kp_id -&gt; cl_knowledge_point.kp_id&lt;br&gt;weight, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="920" y="110" width="280" height="130" as="geometry"/></mxCell>
<mxCell id="14" value="hw_paper&lt;br&gt;PK paper_id&lt;br&gt;paper_name, subject_code, total_score&lt;br&gt;tenant_id, created_by, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1"><mxGeometry x="40" y="290" width="240" height="120" as="geometry"/></mxCell>
<mxCell id="15" value="hw_paper_question&lt;br&gt;PK (paper_id, question_id)&lt;br&gt;FK paper_id -&gt; hw_paper.paper_id&lt;br&gt;FK question_id -&gt; hw_question_item.question_id&lt;br&gt;question_order, score, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="310" y="290" width="300" height="130" as="geometry"/></mxCell>
<mxCell id="16" value="hw_assignment&lt;br&gt;PK assignment_id&lt;br&gt;FK paper_id -&gt; hw_paper.paper_id&lt;br&gt;title, publish_time, deadline&lt;br&gt;status(DRAFT/PUBLISHED/CLOSED)&lt;br&gt;tenant_id, created_by" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1"><mxGeometry x="640" y="290" width="300" height="150" as="geometry"/></mxCell>
<mxCell id="17" value="hw_assignment_target&lt;br&gt;PK target_id&lt;br&gt;FK assignment_id -&gt; hw_assignment.assignment_id&lt;br&gt;target_type(class/student)&lt;br&gt;target_ref_id, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1"><mxGeometry x="970" y="290" width="280" height="130" as="geometry"/></mxCell>
<mxCell id="18" value="hw_submission&lt;br&gt;PK submission_id&lt;br&gt;FK assignment_id -&gt; hw_assignment.assignment_id&lt;br&gt;FK student_id -&gt; tb_sys_user.user_id&lt;br&gt;submit_time, used_seconds&lt;br&gt;status(SUBMITTED/RESUBMITTED)&lt;br&gt;tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1"><mxGeometry x="1280" y="290" width="330" height="150" as="geometry"/></mxCell>
<mxCell id="19" value="hw_submission_answer&lt;br&gt;PK answer_id&lt;br&gt;FK submission_id -&gt; hw_submission.submission_id&lt;br&gt;FK question_id -&gt; hw_question_item.question_id&lt;br&gt;answer_content, answer_type, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1"><mxGeometry x="1280" y="470" width="330" height="130" as="geometry"/></mxCell>
<mxCell id="20" value="hw_submission_attachment&lt;br&gt;PK attachment_id&lt;br&gt;FK submission_id -&gt; hw_submission.submission_id&lt;br&gt;file_type, object_key, file_hash&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1"><mxGeometry x="920" y="470" width="330" height="130" as="geometry"/></mxCell>
<mxCell id="21" value="设计方法与原因&lt;br&gt;1) 题目版本化:保障历史作业可追溯&lt;br&gt;2) 试卷与作业分离:一份试卷可多次发布&lt;br&gt;3) 发布对象独立表:支持按班级/学员精细投放&lt;br&gt;4) 提交主表+答案明细:便于后续批改并行处理" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1">
<mxGeometry x="40" y="470" width="840" height="130" as="geometry"/>
<mxCell id="3" value="说明:question 目录仅保留 2 个 SQL 文件10_create_question_tables.sql / 20_init_question_seed.sql" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=12;fontColor=#666666;" parent="1" vertex="1">
<mxGeometry x="20" y="52" width="1100" height="24" as="geometry"/>
</mxCell>
<mxCell id="100" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="11" target="10" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="101" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="12" target="11" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="102" value="M:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="13" target="11" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="103" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="15" target="14" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="104" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="15" target="11" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="105" value="N:1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="16" target="14" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="106" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="17" target="16" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="107" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="18" target="16" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="108" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="19" target="18" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="109" value="N:1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="19" target="11" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="110" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="20" target="18" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="10" value="question.hw_question_bank&lt;br&gt;PK bank_id&lt;br&gt;bank_name, subject_code, grade_code, status&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="40" y="90" width="270" height="120" as="geometry"/>
</mxCell>
<mxCell id="11" value="question.hw_question_item&lt;br&gt;PK question_id&lt;br&gt;FK bank_id -&gt; hw_question_bank.bank_id&lt;br&gt;question_type, stem, stem_json, difficulty&lt;br&gt;answer_payload, analysis, scoring_rule_json&lt;br&gt;question_status, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="350" y="80" width="380" height="170" as="geometry"/>
</mxCell>
<mxCell id="12" value="question.hw_question_kp_rel&lt;br&gt;PK (question_id, kp_id)&lt;br&gt;FK question_id -&gt; hw_question_item.question_id&lt;br&gt;FK kp_id -&gt; cl_knowledge_point.kp_id&lt;br&gt;relation_type, confidence, graph_relation_id, source_table/source_pk&lt;br&gt;tenant_id, updated_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="780" y="90" width="320" height="130" as="geometry"/>
</mxCell>
<mxCell id="21" value="外部同步依赖ai&lt;br&gt;ai.tb_ai_knowledge_file&lt;br&gt;ai.tb_ai_knowledge_sync_task&lt;br&gt;ai.tb_ai_graph_entity / ai.tb_ai_graph_relation&lt;br&gt;Target: Milvus + NebulaGraph/Neo4j" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" parent="1" vertex="1">
<mxGeometry x="40" y="890" width="370" height="150" as="geometry"/>
</mxCell>
<mxCell id="13" value="question.hw_paper&lt;br&gt;PK paper_id&lt;br&gt;paper_name, subject_code, total_score&lt;br&gt;grading_policy_json&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1">
<mxGeometry x="40" y="300" width="290" height="130" as="geometry"/>
</mxCell>
<mxCell id="14" value="question.hw_paper_question&lt;br&gt;PK (paper_id, question_id)&lt;br&gt;question_order, score, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="380" y="320" width="310" height="120" as="geometry"/>
</mxCell>
<mxCell id="15" value="question.hw_assignment&lt;br&gt;PK assignment_id&lt;br&gt;FK paper_id -&gt; hw_paper.paper_id&lt;br&gt;title, publish_time, deadline, status&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="740" y="300" width="340" height="140" as="geometry"/>
</mxCell>
<mxCell id="16" value="question.hw_assignment_target&lt;br&gt;PK target_id&lt;br&gt;FK assignment_id -&gt; hw_assignment.assignment_id&lt;br&gt;target_type, target_ref_id, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="1130" y="300" width="320" height="130" as="geometry"/>
</mxCell>
<mxCell id="17" value="question.hw_submission&lt;br&gt;PK submission_id&lt;br&gt;FK assignment_id -&gt; hw_assignment.assignment_id&lt;br&gt;FK student_id -&gt; tb_sys_user.user_id&lt;br&gt;submit_time, used_seconds, status, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1">
<mxGeometry x="740" y="500" width="360" height="150" as="geometry"/>
</mxCell>
<mxCell id="18" value="question.hw_submission_answer&lt;br&gt;PK answer_id&lt;br&gt;FK submission_id -&gt; hw_submission.submission_id&lt;br&gt;FK question_id -&gt; hw_question_item.question_id&lt;br&gt;answer_type, answer_payload&lt;br&gt;file_id, file_type, tenant_id&lt;br&gt;UK (submission_id, question_id)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1">
<mxGeometry x="1140" y="500" width="390" height="170" as="geometry"/>
</mxCell>
<mxCell id="19" value="upms.tb_sys_file&lt;br&gt;PK file_id&lt;br&gt;media_type, object_key, file_hash&lt;br&gt;uploaded_by, tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="1140" y="730" width="320" height="120" as="geometry"/>
</mxCell>
<mxCell id="30" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="10" target="11" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="31" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="11" target="12" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="32" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="13" target="14" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="33" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="11" target="14" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="34" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="13" target="15" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="35" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="15" target="16" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="36" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="15" target="17" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="37" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="17" target="18" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="38" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="19" target="18" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
</root>
</mxGraphModel>
</diagram>

View File

@@ -5,24 +5,30 @@
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="2" value="02 习题与作业 - 对象类数据流图" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=22;fontStyle=1;" parent="1" vertex="1">
<mxCell id="2" value="02 习题与作业 - 对象类数据流图question单schema" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=22;fontStyle=1;" parent="1" vertex="1">
<mxGeometry x="20" y="20" width="500" height="30" as="geometry"/>
</mxCell>
<mxCell id="3" value="question 仅 10/20 两个 SQL提交成功后除 MQ 事件外,同步写入 ai 任务表,通过 REST/JAR 调度同步到 Milvus + NebulaGraph/Neo4j" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=12;fontColor=#666666;" parent="1" vertex="1">
<mxGeometry x="20" y="52" width="1400" height="24" as="geometry"/>
</mxCell>
<mxCell id="10" value="Actor&lt;br&gt;教师" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1"><mxGeometry x="40" y="150" width="120" height="70" as="geometry"/></mxCell>
<mxCell id="11" value="Actor&lt;br&gt;学生" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1"><mxGeometry x="40" y="300" width="120" height="70" as="geometry"/></mxCell>
<mxCell id="20" value="Boundary&lt;br&gt;TeacherHomeworkBoundary" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="230" y="130" width="220" height="90" as="geometry"/></mxCell>
<mxCell id="21" value="Boundary&lt;br&gt;StudentHomeworkBoundary" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="230" y="280" width="220" height="90" as="geometry"/></mxCell>
<mxCell id="20" value="Boundary&lt;br&gt;TeacherQuestionBoundary" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="230" y="130" width="220" height="90" as="geometry"/></mxCell>
<mxCell id="21" value="Boundary&lt;br&gt;StudentQuestionBoundary" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="230" y="280" width="220" height="90" as="geometry"/></mxCell>
<mxCell id="30" value="Control&lt;br&gt;QuestionBankService" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1"><mxGeometry x="520" y="90" width="220" height="80" as="geometry"/></mxCell>
<mxCell id="31" value="Control&lt;br&gt;AssignmentPublishService" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1"><mxGeometry x="520" y="200" width="220" height="80" as="geometry"/></mxCell>
<mxCell id="32" value="Control&lt;br&gt;HomeworkQueryService" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1"><mxGeometry x="520" y="310" width="220" height="80" as="geometry"/></mxCell>
<mxCell id="32" value="Control&lt;br&gt;QuestionQueryService" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1"><mxGeometry x="520" y="310" width="220" height="80" as="geometry"/></mxCell>
<mxCell id="33" value="Control&lt;br&gt;SubmissionService" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1"><mxGeometry x="520" y="420" width="220" height="80" as="geometry"/></mxCell>
<mxCell id="40" value="Entity&lt;br&gt;QuestionBankAggregate" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1"><mxGeometry x="810" y="90" width="220" height="70" as="geometry"/></mxCell>
<mxCell id="41" value="Entity&lt;br&gt;AssignmentAggregate" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1"><mxGeometry x="810" y="200" width="220" height="70" as="geometry"/></mxCell>
<mxCell id="42" value="Entity&lt;br&gt;AssignmentTargetAggregate" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1"><mxGeometry x="810" y="300" width="240" height="70" as="geometry"/></mxCell>
<mxCell id="43" value="Entity&lt;br&gt;SubmissionAggregate" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1"><mxGeometry x="810" y="410" width="220" height="70" as="geometry"/></mxCell>
<mxCell id="50" value="PostgreSQL(question/homework)" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="1080" y="170" width="250" height="90" as="geometry"/></mxCell>
<mxCell id="44" value="Entity&lt;br&gt;AiSyncTaskAggregate" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1"><mxGeometry x="810" y="520" width="240" height="70" as="geometry"/></mxCell>
<mxCell id="50" value="PostgreSQL(question)" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="1080" y="170" width="250" height="90" as="geometry"/></mxCell>
<mxCell id="51" value="ObjectStorage(附件/图片/PDF)" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="1080" y="320" width="250" height="90" as="geometry"/></mxCell>
<mxCell id="52" value="MQ(SubmissionCreatedEvent)" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="1080" y="450" width="250" height="90" as="geometry"/></mxCell>
<mxCell id="53" value="PostgreSQL(ai sync task/config)" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="1080" y="580" width="250" height="90" as="geometry"/></mxCell>
<mxCell id="54" value="Milvus + NebulaGraph/Neo4j" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="1080" y="710" width="250" height="90" as="geometry"/></mxCell>
<mxCell id="60" value="设计方法与原因&lt;br&gt;1) 发布链路与作答链路拆分,降低接口复杂度&lt;br&gt;2) 提交成功后发事件,解耦后续批改流程&lt;br&gt;3) 附件文件与答案结构分存,便于扩展多题型&lt;br&gt;4) 题库聚合与作业聚合分离,支持独立演进" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" parent="1" vertex="1">
<mxGeometry x="1380" y="200" width="330" height="190" as="geometry"/>
</mxCell>
@@ -41,6 +47,9 @@
<mxCell id="112" value="持久化" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="43" target="50" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="113" value="附件存储" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="43" target="51" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="114" value="异步事件" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="43" target="52" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="115" value="同步任务入队" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;dashed=1;endArrow=block;endFill=1;" parent="1" source="33" target="44" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="116" value="落库" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="44" target="53" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="117" value="REST/JAR调度执行" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;dashed=1;endArrow=block;endFill=1;" parent="1" source="44" target="54" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
</root>
</mxGraphModel>
</diagram>

View File

@@ -1,35 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<mxfile host="app.diagrams.net" modified="2026-04-14T10:44:00.000Z" agent="Oz" version="24.7.17">
<diagram id="grading-er" name="ER图">
<mxGraphModel dx="1800" dy="1200" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1800" pageHeight="1200" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="2" value="03 批改与反馈 - ER图不含AI实现细节" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=22;fontStyle=1;" parent="1" vertex="1">
<mxGeometry x="20" y="20" width="560" height="30" as="geometry"/>
</mxCell>
<mxCell id="10" value="gd_grading_task&lt;br&gt;PK grading_task_id&lt;br&gt;FK submission_id -&gt; hw_submission.submission_id&lt;br&gt;status(PENDING/RUNNING/WAIT_REVIEW/DONE)&lt;br&gt;trigger_source, tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1"><mxGeometry x="40" y="120" width="330" height="140" as="geometry"/></mxCell>
<mxCell id="11" value="gd_grading_rule_set&lt;br&gt;PK rule_set_id&lt;br&gt;rule_version, subject_code, objective_policy&lt;br&gt;subjective_policy(manual_first)&lt;br&gt;tenant_id, enabled" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1"><mxGeometry x="400" y="120" width="320" height="130" as="geometry"/></mxCell>
<mxCell id="12" value="gd_objective_score&lt;br&gt;PK objective_score_id&lt;br&gt;FK grading_task_id -&gt; gd_grading_task.grading_task_id&lt;br&gt;FK answer_id -&gt; hw_submission_answer.answer_id&lt;br&gt;score, matched_rule, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1"><mxGeometry x="750" y="120" width="340" height="140" as="geometry"/></mxCell>
<mxCell id="13" value="gd_subjective_review&lt;br&gt;PK review_id&lt;br&gt;FK grading_task_id -&gt; gd_grading_task.grading_task_id&lt;br&gt;FK answer_id -&gt; hw_submission_answer.answer_id&lt;br&gt;reviewer_id, review_score, status, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1"><mxGeometry x="1120" y="120" width="350" height="140" as="geometry"/></mxCell>
<mxCell id="14" value="gd_score_summary&lt;br&gt;PK summary_id&lt;br&gt;FK grading_task_id -&gt; gd_grading_task.grading_task_id&lt;br&gt;total_score, grade_level(A/B/C)&lt;br&gt;surpass_ratio, used_seconds, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1"><mxGeometry x="40" y="300" width="330" height="140" as="geometry"/></mxCell>
<mxCell id="15" value="gd_error_tag&lt;br&gt;PK error_tag_id&lt;br&gt;tag_code, tag_name&lt;br&gt;category(审题/计算/概念)&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1"><mxGeometry x="400" y="300" width="300" height="130" as="geometry"/></mxCell>
<mxCell id="16" value="gd_answer_error_rel&lt;br&gt;PK (answer_id, error_tag_id)&lt;br&gt;FK answer_id -&gt; hw_submission_answer.answer_id&lt;br&gt;FK error_tag_id -&gt; gd_error_tag.error_tag_id&lt;br&gt;confidence, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="730" y="300" width="330" height="130" as="geometry"/></mxCell>
<mxCell id="17" value="gd_wrong_question&lt;br&gt;PK wrong_question_id&lt;br&gt;FK student_id -&gt; tb_sys_user.user_id&lt;br&gt;FK question_id -&gt; hw_question_item.question_id&lt;br&gt;source_submission_id, mastery_status&lt;br&gt;review_count, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1"><mxGeometry x="1090" y="300" width="350" height="150" as="geometry"/></mxCell>
<mxCell id="18" value="gd_review_plan&lt;br&gt;PK review_plan_id&lt;br&gt;FK wrong_question_id -&gt; gd_wrong_question.wrong_question_id&lt;br&gt;plan_date, plan_stage(E1/E2/E3)&lt;br&gt;status, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1"><mxGeometry x="40" y="490" width="330" height="130" as="geometry"/></mxCell>
<mxCell id="19" value="gd_teacher_comment&lt;br&gt;PK comment_id&lt;br&gt;FK review_id -&gt; gd_subjective_review.review_id&lt;br&gt;comment_type(text/voice), content_ref&lt;br&gt;reviewer_id, tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1"><mxGeometry x="400" y="490" width="340" height="130" as="geometry"/></mxCell>
<mxCell id="20" value="设计方法与原因&lt;br&gt;1) 批改任务聚合承接状态机,保证流程一致性&lt;br&gt;2) 客观分与主观复核拆表,支持并行与补录&lt;br&gt;3) 错因标签与错题沉淀解耦,便于策略演进&lt;br&gt;4) 仅保留 GradingEnginePort 抽象不绑定AI实现" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1">
<mxGeometry x="780" y="500" width="660" height="130" as="geometry"/>
</mxCell>
<mxCell id="100" value="N:1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="10" target="11" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="101" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="12" target="10" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="102" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="13" target="10" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="103" value="1:1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="14" target="10" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="104" value="M:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="16" target="15" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="105" value="衍生" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="17" target="14" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="106" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="18" target="17" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="107" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="19" target="13" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>
<mxfile host="65bd71144e">
<diagram id="grading-er-v2" name="ER图">
<mxGraphModel dx="1312" dy="773" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1800" pageHeight="1200" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="2" value="03 批改与反馈 - ER图question单schema含知识点分析与AI同步" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=22;fontStyle=1;" parent="1" vertex="1">
<mxGeometry x="20" y="20" width="560" height="30" as="geometry"/>
</mxCell>
<mxCell id="3" value="说明:批改与反馈表统一在 question/10_create_question_tables.sql 中定义" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=12;fontColor=#666666;" parent="1" vertex="1">
<mxGeometry x="20" y="52" width="900" height="24" as="geometry"/>
</mxCell>
<mxCell id="10" value="question.gd_grading_task&lt;br&gt;PK grading_task_id&lt;br&gt;FK submission_id -&gt; hw_submission.submission_id&lt;br&gt;paper_id, task_status, trigger_source&lt;br&gt;tenant_id, created_at, updated_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="25" y="110" width="330" height="140" as="geometry"/>
</mxCell>
<mxCell id="11" value="question.gd_answer_grade&lt;br&gt;PK answer_grade_id&lt;br&gt;FK grading_task_id -&gt; gd_grading_task.grading_task_id&lt;br&gt;FK answer_id -&gt; hw_submission_answer.answer_id&lt;br&gt;grade_mode, grade_status, score, grader_id&lt;br&gt;evidence_json, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="420" y="90" width="360" height="150" as="geometry"/>
</mxCell>
<mxCell id="12" value="question.gd_score_summary&lt;br&gt;PK summary_id&lt;br&gt;UK grading_task_id -&gt; gd_grading_task.grading_task_id&lt;br&gt;total_score, grade_level, surpass_ratio, used_seconds&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1">
<mxGeometry x="830" y="90" width="340" height="140" as="geometry"/>
</mxCell>
<mxCell id="13" value="question.gd_error_tag&lt;br&gt;PK error_tag_id&lt;br&gt;tag_code, tag_name, category&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1">
<mxGeometry x="40" y="300" width="300" height="120" as="geometry"/>
</mxCell>
<mxCell id="14" value="question.gd_answer_error_rel&lt;br&gt;PK (answer_id, error_tag_id)&lt;br&gt;FK answer_id -&gt; hw_submission_answer.answer_id&lt;br&gt;FK error_tag_id -&gt; gd_error_tag.error_tag_id&lt;br&gt;confidence, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="390" y="300" width="350" height="130" as="geometry"/>
</mxCell>
<mxCell id="15" value="question.gd_wrong_question&lt;br&gt;PK wrong_question_id&lt;br&gt;student_id, question_id, source_submission_id&lt;br&gt;mastery_status, review_count&lt;br&gt;tenant_id, created_at, updated_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="790" y="290" width="350" height="140" as="geometry"/>
</mxCell>
<mxCell id="16" value="question.gd_review_plan&lt;br&gt;PK review_plan_id&lt;br&gt;FK wrong_question_id -&gt; gd_wrong_question.wrong_question_id&lt;br&gt;plan_date, plan_stage, plan_status&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="1190" y="290" width="340" height="130" as="geometry"/>
</mxCell>
<mxCell id="17" value="question.gd_teacher_comment&lt;br&gt;PK comment_id&lt;br&gt;FK answer_grade_id -&gt; gd_answer_grade.answer_grade_id&lt;br&gt;reviewer_id, comment_type, content_ref&lt;br&gt;tenant_id, created_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1">
<mxGeometry x="420" y="480" width="350" height="130" as="geometry"/>
</mxCell>
<mxCell id="18" value="question.gd_explanation_submission&lt;br&gt;PK explanation_id&lt;br&gt;student_id, wrong_question_id, source_answer_id&lt;br&gt;audio_file_id, transcript_text, submission_status&lt;br&gt;tenant_id, created_at, updated_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="40" y="500" width="340" height="150" as="geometry"/>
</mxCell>
<mxCell id="19" value="question.gd_explanation_assessment&lt;br&gt;PK assessment_id&lt;br&gt;UK explanation_id -&gt; gd_explanation_submission.explanation_id&lt;br&gt;evaluator_type, total_score, pass_status&lt;br&gt;improvement_suggestion, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="830" y="500" width="360" height="140" as="geometry"/>
</mxCell>
<mxCell id="20" value="question.gd_explanation_dimension_score&lt;br&gt;PK dimension_score_id&lt;br&gt;FK assessment_id -&gt; gd_explanation_assessment.assessment_id&lt;br&gt;dimension_code, dimension_name&lt;br&gt;score, weight, tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="1240" y="500" width="340" height="140" as="geometry"/>
</mxCell>
<mxCell id="23" value="question.gd_answer_kp_analysis&lt;br&gt;PK analysis_id&lt;br&gt;FK answer_id -&gt; hw_submission_answer.answer_id&lt;br&gt;FK kp_id -&gt; cl_knowledge_point.kp_id&lt;br&gt;correctness, mastery_score, confidence&lt;br&gt;evidence_json, tenant_id, updated_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="1240" y="90" width="360" height="160" as="geometry"/>
</mxCell>
<mxCell id="21" value="upms.tb_sys_message&lt;br&gt;PK message_id&lt;br&gt;message_type, biz_type, content_object_id&lt;br&gt;web_jump_url, tenant_id, send_at" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="40" y="710" width="330" height="120" as="geometry"/>
</mxCell>
<mxCell id="22" value="upms.tb_sys_message_recipient&lt;br&gt;PK (message_id, recipient_user_id)&lt;br&gt;FK message_id -&gt; tb_sys_message.message_id&lt;br&gt;read_status, read_at, clicked_at&lt;br&gt;tenant_id" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="430" y="710" width="360" height="120" as="geometry"/>
</mxCell>
<mxCell id="24" value="外部同步依赖ai&lt;br&gt;ai.tb_ai_knowledge_file&lt;br&gt;ai.tb_ai_knowledge_sync_task&lt;br&gt;ai.tb_ai_graph_entity / ai.tb_ai_graph_relation&lt;br&gt;Target: Milvus + NebulaGraph/Neo4j" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" parent="1" vertex="1">
<mxGeometry x="820" y="710" width="360" height="150" as="geometry"/>
</mxCell>
<mxCell id="30" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="10" target="11" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="31" value="1:1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="10" target="12" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="32" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="13" target="14" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="33" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="12" target="15" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="34" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="15" target="16" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="35" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="11" target="17" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="36" value="1:1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="18" target="19" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="37" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="19" target="20" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="38" value="触发通知" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="11" target="21" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="39" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="21" target="22" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="40" value="1:N" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;exitPerimeter=1;entryPerimeter=1;" parent="1" source="11" target="23" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

View File

@@ -5,27 +5,36 @@
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="2" value="03 批改与反馈 - 对象类数据流图(规则批改 + 教师复核" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=22;fontStyle=1;" parent="1" vertex="1">
<mxCell id="2" value="03 批改与反馈 - 对象类数据流图(question单schema" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=22;fontStyle=1;" parent="1" vertex="1">
<mxGeometry x="20" y="20" width="700" height="30" as="geometry"/>
</mxCell>
<mxCell id="3" value="批改结果会触发知识点分析同步任务;调度器支持 REST/JAR 两种模式JAR 本地执行 + REST 远程触发),目标为 Milvus + NebulaGraph/Neo4j" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=12;fontColor=#666666;" parent="1" vertex="1">
<mxGeometry x="20" y="52" width="1400" height="24" as="geometry"/>
</mxCell>
<mxCell id="10" value="Actor&lt;br&gt;学生" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1"><mxGeometry x="40" y="150" width="120" height="70" as="geometry"/></mxCell>
<mxCell id="11" value="Actor&lt;br&gt;教师" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1"><mxGeometry x="40" y="300" width="120" height="70" as="geometry"/></mxCell>
<mxCell id="20" value="Boundary&lt;br&gt;StudentResultBoundary" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="230" y="140" width="220" height="90" as="geometry"/></mxCell>
<mxCell id="21" value="Boundary&lt;br&gt;TeacherReviewBoundary" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="230" y="290" width="220" height="90" as="geometry"/></mxCell>
<mxCell id="22" value="Boundary&lt;br&gt;MessageInboxBoundary" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="230" y="640" width="220" height="90" as="geometry"/></mxCell>
<mxCell id="30" value="Control&lt;br&gt;GradingDispatcher" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1"><mxGeometry x="520" y="80" width="220" height="80" as="geometry"/></mxCell>
<mxCell id="31" value="Control&lt;br&gt;ObjectiveScoringService" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1"><mxGeometry x="520" y="190" width="220" height="80" as="geometry"/></mxCell>
<mxCell id="32" value="Control&lt;br&gt;ReviewWorkflowService" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1"><mxGeometry x="520" y="300" width="220" height="80" as="geometry"/></mxCell>
<mxCell id="33" value="Control&lt;br&gt;WrongBookService" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1"><mxGeometry x="520" y="410" width="220" height="80" as="geometry"/></mxCell>
<mxCell id="34" value="Control&lt;br&gt;ReviewPlannerService" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1"><mxGeometry x="520" y="520" width="220" height="80" as="geometry"/></mxCell>
<mxCell id="36" value="Control&lt;br&gt;SiteMessageService" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" parent="1" vertex="1"><mxGeometry x="520" y="640" width="220" height="80" as="geometry"/></mxCell>
<mxCell id="35" value="Port&lt;br&gt;GradingEnginePort&lt;br&gt;(当前规则实现 RuleBasedEngine)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1"><mxGeometry x="780" y="80" width="250" height="90" as="geometry"/></mxCell>
<mxCell id="40" value="Entity&lt;br&gt;GradingTaskAggregate" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1"><mxGeometry x="780" y="210" width="230" height="70" as="geometry"/></mxCell>
<mxCell id="41" value="Entity&lt;br&gt;ObjectiveScoreAggregate" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1"><mxGeometry x="780" y="310" width="230" height="70" as="geometry"/></mxCell>
<mxCell id="42" value="Entity&lt;br&gt;SubjectiveReviewAggregate" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1"><mxGeometry x="780" y="410" width="250" height="70" as="geometry"/></mxCell>
<mxCell id="43" value="Entity&lt;br&gt;WrongQuestionAggregate" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1"><mxGeometry x="780" y="510" width="240" height="70" as="geometry"/></mxCell>
<mxCell id="50" value="PostgreSQL(grading/wrongbook)" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="1080" y="230" width="250" height="90" as="geometry"/></mxCell>
<mxCell id="44" value="Entity&lt;br&gt;SiteMessageAggregate&lt;br&gt;message_id, biz_type&lt;br&gt;content_object_id, web_jump_url" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" parent="1" vertex="1"><mxGeometry x="780" y="640" width="270" height="90" as="geometry"/></mxCell>
<mxCell id="50" value="PostgreSQL(question + ai sync task)" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="1080" y="230" width="250" height="90" as="geometry"/></mxCell>
<mxCell id="51" value="Redis(结果缓存/待复核队列)" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="1080" y="370" width="250" height="90" as="geometry"/></mxCell>
<mxCell id="52" value="MQ(GradingCompletedEvent)" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="1080" y="510" width="250" height="90" as="geometry"/></mxCell>
<mxCell id="60" value="设计方法与原因&lt;br&gt;1) 批改调度、判分、复核、错题沉淀分控制器,职责清晰&lt;br&gt;2) 通过 Port 抽象引擎实现后续可无缝接入AI或外部服务&lt;br&gt;3) 结果完成后事件化通知,支撑复习计划与消息触达&lt;br&gt;4) 主流程先保障规则可用,再逐步增强智能能力" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" parent="1" vertex="1">
<mxCell id="53" value="PostgreSQL(upms.site_message / recipient)" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="1080" y="650" width="250" height="90" as="geometry"/></mxCell>
<mxCell id="54" value="Redis(未读计数缓存)" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="1080" y="770" width="250" height="90" as="geometry"/></mxCell>
<mxCell id="55" value="Milvus + NebulaGraph/Neo4j" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1"><mxGeometry x="1080" y="890" width="250" height="90" as="geometry"/></mxCell>
<mxCell id="60" value="设计方法与原因&lt;br&gt;1) 批改调度、判分、复核、错题沉淀分控制器,职责清晰&lt;br&gt;2) 通过 Port 抽象引擎实现后续可无缝接入AI或外部服务&lt;br&gt;3) 主观题待审阅由站内信服务落库含content_object_id和web_jump_url&lt;br&gt;4) 教师通过收件箱点击跳转到对应审阅页,链路可追踪可回执" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" parent="1" vertex="1">
<mxGeometry x="1380" y="230" width="330" height="220" as="geometry"/>
</mxCell>
<mxCell id="100" value="查看批改结果" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="10" target="20" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
@@ -46,6 +55,16 @@
<mxCell id="115" value="持久化" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="43" target="50" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="116" value="待复核缓存" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="42" target="51" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="117" value="完成事件" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="34" target="52" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="118" value="查看站内信" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="11" target="22" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="119" value="待审阅通知触发" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="32" target="36" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="120" value="复习提醒通知触发" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="34" target="36" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="121" value="生成站内信" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="36" target="44" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="122" value="消息落库" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="44" target="53" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="123" value="未读计数缓存" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="44" target="54" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="124" value="已读/点击回执" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="22" target="36" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="125" value="点击消息跳转审阅页" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="22" target="21" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="126" value="返回跳转参数(messageId/objectId/url)" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;endArrow=block;endFill=1;" parent="1" source="36" target="22" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
<mxCell id="127" value="同步任务执行" style="edgeStyle=orthogonalEdgeStyle;rounded=0;jettySize=auto;html=1;dashed=1;endArrow=block;endFill=1;" parent="1" source="34" target="55" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell>
</root>
</mxGraphModel>
</diagram>