Add architecture documentation and retail system workshop PPT

This commit is contained in:
Guangfei.Zhao
2026-08-12 17:49:57 +08:00
commit 54c001a793
26 changed files with 9618 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
# agents
.agents
.codegrapg
.omo
# python
.venv
*/__pycache__/
# drawio temp files
.$*.drawio.bkp
@@ -0,0 +1,899 @@
# 202606 Conti Retail APP Component data source
## Continental Retail APP
### 1 用户登录
**功能**
用户登录功能,支持用户通过合法账号凭证进入APP系统,是APP所有功能的入口权限校验模块。
#### 1.1 手机验证码登录
**功能**
基于手机号的验证码登录方式,用户输入手机号后获取短信验证码,通过验证码校验完成登录;
**数据集**
- 1. 第三方验证码;
- 2. 登录成功结果集;
**来源**
APP Backend
**安全**
HTTPS
**备注**
短信调用第三方短信网关
#### 1.2 账号密码登录
**功能**
传统的账号+密码登录方式,用户输入已注册的账号和对应密码,通过系统校验后完成登录,;
**数据集**
1. 登录成功结果集;
**来源**
APP Backend
**安全**
HTTPS
#### 1.3 用户协议 / 隐私政策
**功能**
用户注册/登录前需查看并确认的用户服务协议与隐私政策,明确用户与平台的权利义务、个人信息使用规则等合规内容。
**数据集**
1. 用户协议与隐私政策完整内容;
**来源**
APP Backend
**安全**
HTTPS
### 2 APP首页及功能
**功能**
APP的核心主页面,是用户登录后进入的首个页面,整合了核心功能入口、包括扫码、待办事项、动态预警、施工队列等核心数据展示;底部菜单会包含入库,采购,延保,个人中心等核心导航菜单。其所有展示信息均调用O2O后台相关接口;
**前置任务**
3.1
#### 2.1 首页展示
**功能**
展示用户登录成功能的页面
**数据集**
- 1.获取切换后的店铺信息集
- 2.获取店铺列表结果集,用于店铺切换
- 3.当前用户的菜单数据集
**来源**
APP Backend
**安全**
HTTPS
#### 2.2 首页展示
**功能**
展示用户登录成功能的页面
**数据集**
- 1.动态预警
- 2.促销信息
**来源**
Mini Program Backend
**安全**
HTTPS
#### 2.3 店铺切换
**功能**
点击左上角的店铺名称可以切换到另一个店铺
**数据集**
1.获取切换后的店铺信息集
**来源**
APP Backend
**安全**
HTTPS
#### 2.4 扫一扫
**功能**
基于F6的扫码功能,支持扫描VIN, 车牌,二维码/条形码,在弹窗选择不同功能后,实现快速跳转对应功能流程的快捷操作,页面直接嵌入F6的扫码页面;合并扫码接车,扫码核销,扫码入库,延保扫车牌等功能;
**数据集**
- 嵌入F6扫码页:
- 1. 验证可正常调用扫码功能;
- 2. 验证可正常识别VIN, 车牌,有效二维码/条形码,快速跳转对应功能/展示对应信息;
**来源**
Involve F6 Page
**安全**
HTTPS
#### 2.5 公告/通知
**功能**
平台向用户发布的官方公告、活动通知、系统通知、业务提醒等消息内容,支持用户查看、标记已读、删除等操作,是平台与用户的信息触达渠道,且促销活动通知需要在首页顶部滚动提示,数据接口来自于O2O后台;
**数据集**
1. 公告/通知列表,按发布时间倒序排列;
**来源**
Mini Program Backend
**安全**
HTTPS
#### 2.6 待办事项
**功能**
集中展示用户需要处理的各类待办任务,包含订单待处理/待安装,活动报名问卷、待完善门店基本资料/渠道资料、待确认/待上传视频保单等业务待办,待办事项数据接口来自于O2O后台和延保后台;
**数据集**
1. 当前用户的所有待办事项,按优先级/截止时间排序;
**来源**
Mini Program Backend
**安全**
HTTPS
#### 2.7 动态预警
**功能**
针对门店进货和O2O等业务场景的异常情况进行实时预警提醒,包含月度签约量达成预警,O2O补货率达成预警,O2O 时效订单预警等,帮助用户及时发现并处理业务风险;预警数据接口来自于ROOS和O2O后台;
**数据集**
1.当前用户的所有预警信息,按预警等级/时间排序;
**来源**
Mini Program Backend
**安全**
HTTPS
#### 2.8 店铺管理
**功能**
门店相关信息的全生命周期管理模块,是门店运营的基础管理模块,以“马上下单”中的店铺管理为蓝板,数据接口调用“马上下单”后台店铺管理接口;
**前置任务**
3.1, 3.2
##### 2.8.1 基础信息
**功能**
- 管理门店的基础信息,包含门店名称,门店住编码,负责人姓名,联系方式,门店地址,门店评分,门头照片等;支持查看,编辑,保存功能;
- 维护功能调用“马上下单”后台接口;
**数据集**
1.门店基础数据结果集;
**来源**
Mini Program Backend
**安全**
HTTPS
##### 2.8.2 店铺服务信息
**功能**
- 管理门店服务信息,包含门店基础信息,门店合作的线上线下渠道、分销渠道、合作平台信息,以及服务项目信息等;支持查看,编辑,保存功能;
- 维护功能调用“马上下单”后台接口;
**数据集**
1.门店服务信息数据结果集
**来源**
Mini Program Backend
**安全**
HTTPS
##### 2.8.3 营业执照信息
**功能**
维护门店营业执照,企业名称,统一社会信用代码等信息,调用“马上下单”后台接口
**数据集**
1.营业执照信息结果集
**来源**
Mini Program Backend
**安全**
HTTPS
##### 2.8.4 渠道信息
**功能**
渠道信息,调用“马上下单”后台接口
**数据集**
1.渠道信息结果集;
**来源**
Mini Program Backend
**安全**
HTTPS
##### 2.8.5 经营范围
**功能**
维护会员体系门店开通申请,认证轮胎技术检测中心开通申请,单独服务项目管理,以及开票方式等,调用“O2O”后台接口
**数据集**
1.经营范围信息结果集;
**来源**
Mini Program Backend
**安全**
HTTPS
##### 2.8.6 收款信息
**功能**
O2O的平安账号模块,维护企业的银行账号信息,支持修改绑定的手机号及解绑银行卡功能;调用“O2O”后台接口
**数据集**
1. 收款信息结果集
**来源**
Mini Program Backend
**安全**
HTTPS
##### 2.8.7 人员管理
**功能**
门店员工账号、角色权限全生命周期管理功能,支持员工账号的创建、编辑、权限分配、启停、删除的配置管理, 主要数据来源于马上下单后台接口
**数据集**
- 1. 门店员工列表结果集;
- 2. 员工详细信息;
**来源**
Mini Program Backend
**安全**
HTTPS
### 3 销售流程
**功能**
门店线上线下销售、O2O运营、订单管理、库存管理、营销推广的全流程管理模块,包含O2O接单、库存查询、核销记录等核心功能,是门店销售运营的核心管理模块,所有销售运营数据接口来源于O2O后台。
**前置任务**
3.1, 3.2
#### 3.1 准备
**功能**
首页待办事项,消息公告
#### 3.2 客户查询
##### 3.2.1 首页扫码
**功能**
首页扫车牌入口(要考虑未接F6的车辆如何处理?)
**数据集**
嵌入F6扫码页:F6扫码页面
**来源**
Involve F6 Page
**安全**
HTTPS
##### 3.2.2 历史工单记录
**功能**
查看历史工单记录
**数据集**
- 1.历史工单记录结果集
- 2.单条工单详细信息
**来源**
Mini Program Backend
**安全**
HTTPS
##### 3.2.3 新建工单
**功能**
新建工单
**数据集**
工单数据集(保存到O2O后台)
**来源**
Mini Program Backend
**安全**
HTTPS
##### 3.2.4 销售商机
**功能**
销售商机
**数据集**
- 1.服务提醒记录集
- 2.意向池
**来源**
F6 Backend
**安全**
HTTPS
##### 3.2.5 延保历史记录
**功能**
延保历史记录
**数据集**
- 1.延保历史记录集
- 2. 单条延保详细信息集
**来源**
Mini Program Backend
**安全**
HTTPS
#### 3.3 报价开单
**功能**
显示到店记录页(与3.2.1或3.2.2可能有冲突)
**数据集**
- 嵌入F6到店记录页:
- 1.到店记录页
- 2.新车辆,完善信息
- 3.车辆详情
- 4.开单
**来源**
Involve F6 Page
**安全**
HTTPS
#### 3.4 施工查车
**功能**
接上一步,开单后相关操作
**数据集**
- 嵌入F6开单记录页:
- 5.施工查车,选择查车检测模板,记录查车异常结果,批量更新查车正常结果,查车报告发送车主(SMS短信,微信)
- 6.查车结果转工单, 查车结果转商机
**来源**
Involve F6 Page
**安全**
HTTPS
#### 3.5 结算
**功能**
接上一步,工单完成后结算
**数据集**
- 嵌入F6结算收银页:
- 7.添加其它项目
- 8.结算收款
**来源**
Involve F6 Page
**安全**
HTTPS
### 结算
**功能**
进入延保流程
**数据集**
- 1.延保数据集
- 2.延保出库,总数量减1
**来源**
Mini Program Backend
**安全**
HTTPS
#### 3.6 提醒
**功能**
后台直接触发提醒
**数据集**
F6后台自动按规则生成提醒单,生成提醒作业
#### 3.7 售后
##### 3.7.1 延保服务
**功能**
延保服务
**数据集**
- 1.延保服务信息集(保存到延保后台)
- 2.延保出库
**来源**
Mini Program Backend
**安全**
HTTPS
##### 3.7.2 延保注册
**功能**
延保注册
**数据集**
延保注册数据集(保存到延保后台)
**来源**
User Input
**安全**
HTTPS
### 4 采购流程
**功能**
- 1.所有采购(马牌相关/其它非马牌配件)都应该能在App内完成。可以直接区分马牌/非马牌的入口
- 2.针对非轮产品,需要有清晰的树状分类,方便出库与后续统计(可以参考开思/途虎)
- 3.下单前,同一个SKU下,可以显示不同DOT,不同仓库,不同价格
- 4.打造供应链平台,引进三方询价整合(如开思)
**前置任务**
3.1, 3.2
#### 4.1 触发采购
**功能**
平台可采购商品的全维度信息展示模块,包含商品名称、规格、型号、价格、库存、详情介绍、参数等信息,支持商品搜索、筛选、分类查看,是进货采购的基础商品信息模块。数据接口来源于ROOS后台接口。
**数据集**
1. 当前用户购物车信息数据集
**来源**
Mini Program Backend
**安全**
HTTPS
#### 4.2 产品查询
**功能**
展示门店订货促销/O2O售出平台促销/运营活动等的日历视图,按时间维度展示活动的开始/结束时间、活动类型、活动内容,支持用户快速查看活动详情、报名参与活动;活动数据接口待确定(待确定);
**数据集**
1. 促销日历数据集;
**来源**
Mini Program Backend
**安全**
HTTPS
#### 4.3 添加购物车
**功能**
用户采购商品的临时存放与结算管理模块,支持商品加入购物车、数量修改、规格选择、商品删除、批量选择、结算下单等功能,是采购流程的核心中间环节。后台数据调用ROOS接口。
**数据集**
1.购物车数据集(保存至ROOS后台)
**来源**
Mini Program Backend
**安全**
HTTPS
#### 4.4 结算
**功能**
采购订单的结算确认模块,支持用户确认收货地址、商品信息、订单金额、优惠信息、支付方式,提交订单生成采购单,是采购流程的订单生成环节,后台接口调用O2O结算接口和F6接口。
**数据集**
1.结算信息结果集
**来源**
APP Backend
**安全**
证书令牌
**备注**
需要调用三方接口,银行接口可能需要令牌或证书
#### 4.5 收货
**功能**
门店商品的入库、出库、库存盘点、库存明细管理的功能模块,包含入库单、出库单的创建、审核、查看,库存明细查询,库存盘点,库存预警等功能,是门店库存管理的核心模块。数据会调用O2O的出入库接口。
**数据集**
嵌入F6扫码入库页面
**来源**
Involve F6 Page
**安全**
HTTPS
#### 4.6 其它
**功能**
采购订单列表和采购订单详情
**数据集**
- 1.采购订单列表
- 2.采购订单详情
**来源**
Mini Program Backend
**安全**
HTTPS
### 5 经营分析
**功能**
门店全业务线的经营数据统计与分析模块,包含采购数据、销售数据、O2O订单数据、核销收入、返利数据、库存数据、延保业务数据等全维度经营指标,支持多维度筛选、数据趋势分析、报表导出等功能,为门店经营决策提供数据支撑。
**前置任务**
3.1, 3.2
#### 5.1 采购及返利对账单(马牌)
**功能**
针对马牌品牌的商品采购、返利金额的对账管理模块,包含采购明细、返利规则、返利金额计算、对账单生成、对账状态跟踪、差异处理等功能,是门店与品牌方采购返利对账的核心模块。它的数据来源于ROOS接口和F6接口。
**数据集**
对账单
**来源**
Mini Program Backend
**安全**
HTTPS
#### 5.2 门店核销收入(马牌)
**功能**
针对马牌品牌相关商品、服务的门店核销收入的统计与管理模块,包含核销明细、收入金额、结算规则、结算周期、到账状态、收入明细查询、对账管理等功能,是门店马牌相关业务收入的核心管理模块,它的数据来源于ROOS接口。
**数据集**
核销结果集
**来源**
Mini Program Backend
**安全**
HTTPS
#### 5.3 返利中心
**功能**
门店所有品牌、所有业务线的返利金额、返利规则、返利进度、返利提现的集中管理模块,包含返利余额展示、返利明细查询、返利规则查看、返利提现申请、提现进度跟踪等功能,是门店返利权益的核心管理模块,它的数据来源于ROOS接口。
**数据集**
返利结果集
**来源**
Mini Program Backend
**安全**
HTTPS
### 6 个人中心
**功能**
APP用户的个人信息、账号设置、功能入口的集中管理模块,包含个人信息维护、账号安全设置、收货地址管理、客服入口、消息通知、系统设置、退出登录等核心功能,是用户个人账号与系统设置的核心管理模块
**前置任务**
3.1, 3.2
#### 6.1 收货地址
**功能**
用户采购商品、O2O服务的收货/服务地址的管理模块,支持地址的新增、编辑、删除、设为默认地址、地址搜索等功能,是订单结算、服务下单的基础地址配置模块,它的数据来源于马上下单接口(待确认)。
**数据集**
- 1. 验证可正常加载展示用户已保存的收货地址列表,按使用时间/默认状态排序;
- 2. 验证支持新增收货地址,可正常填写收货人、联系电话、所在地区、详细地址等信息,提交后可正常保存;
- 3. 验证支持对已有地址进行编辑、删除、设为默认地址操作,操作后状态可正常更新;
- 4. 验证订单结算、服务下单时可正常选择已保存的收货地址,默认地址可自动选中;
- 5. 验证地址信息可正常同步至订单、物流模块,地址数据准确无错误
**来源**
APP Backend
**安全**
HTTPS
#### 6.2 服务热线
**功能**
平台官方服务热线、客服电话的展示与快速拨打功能模块,展示不同业务线的服务热线、服务时间、服务范围,支持一键拨打热线电话,是用户快速联系官方客服的渠道。
**数据集**
- 1. 验证可正常加载展示所有业务线的服务热线列表,包含热线号码、服务时间、服务范围、服务类型;?
- 2. 验证点击热线号码可正常调起手机拨号界面,一键拨打对应热线电话;
- 3. 验证服务热线的服务时间、状态可实时更新,非服务时间有明确的提示;
- 4. 验证支持按业务类型搜索筛选服务热线,可快速定位目标热线;
- 5. 验证热线相关的常见问题、服务说明可正常展示,内容清晰准确
**来源**
APP Backend
**安全**
HTTPS
#### 6.3 经销商客服
**功能**
对应经销商的专属客服联系、咨询、服务功能模块,展示经销商客服的联系方式、服务时间、服务范围,支持在线咨询、留言反馈、问题提交等功能,是用户对接经销商专属服务的渠道。
**数据集**
- 1. 验证可正常加载展示对应经销商的客服信息,包含客服名称、联系方式、服务时间、服务范围;
- 2. 验证支持在线咨询功能,可正常发送文字、图片、文件等咨询内容,客服回复可实时接收;
- 3. 验证支持问题反馈、留言提交功能,可正常填写问题描述、上传相关材料,提交后可正常查看处理进度;
- 4. 验证客服服务时间、状态可实时更新,非服务时间有明确的提示;
- 5. 验证历史咨询、反馈记录可正常查询、查看,数据准确无遗漏
**来源**
APP Backend
**安全**
HTTPS
#### 6.4 O2O /延保客服 (企微)
**功能**
O2O业务、延保业务的专属企业微信客服功能模块,支持一键添加企业微信客服、在线咨询、问题反馈、服务跟进等功能,是用户对接O2O与延保业务专属服务的渠道,它的数据来源于企业微信接口(待确认)。
**数据集**
- 1. 验证可正常加载展示O2O/延保业务的企业微信客服信息,包含客服名称、企业微信二维码、服务时间、服务范围;
- 2. 验证可正常扫码/一键添加对应企业微信客服,添加后可正常发起在线咨询;
- 3. 验证支持在线咨询功能,可正常发送文字、图片、文件、订单等内容,客服回复可实时接收;
- 4. 验证支持问题反馈、服务单提交功能,可正常填写问题描述、上传相关材料,提交后可正常查看处理进度;
- 5. 验证历史咨询、服务记录可正常查询、查看,客服服务状态可实时更新
**来源**
APP Backend
**安全**
HTTPS
#### 6.5 退出登录
**功能**
用户账号的安全退出功能,支持用户主动退出当前登录的账号,清除当前设备的登录状态,退出后需重新登录才可访问需登录的功能,保障用户账号安全。
**数据集**
- 1. 验证在个人中心可正常点击退出登录按钮,弹出确认退出的提示框;
- 2. 验证确认退出后,可正常清除当前设备的登录状态,自动跳转至登录页面;
- 3. 验证退出登录后,无法访问需登录的功能页面,点击相关功能会自动跳转至登录页面;
- 4. 验证退出登录后,重新打开APP不会自动登录,需手动输入账号凭证登录;
- 5. 验证多设备登录时,单设备退出登录不影响其他设备的登录状态
**来源**
APP Backend
**安全**
HTTPS
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,300 @@
<?xml version='1.0' encoding='utf-8'?>
<mxfile host="Electron" agent="Codex" compressed="false" pages="2">
<diagram id="app-overview" name="App Architecture Overview">
<mxGraphModel dx="2513" dy="1405" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="2200" pageHeight="1400" background="#FFFFFF" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="ov-title" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=30;fontStyle=1;fontColor=#0f172a;" value="Continental Retail APP Architecture Overview" vertex="1">
<mxGeometry height="40" width="860" x="48" y="28" as="geometry" />
</mxCell>
<mxCell id="ov-subtitle" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=14;fontColor=#475569;" value="App-only view: Flutter is the host shell; migrated mini-program modules and native pages render directly, while Local H5 (static pages) and F6 remote H5 stay as WebView hybrid branches, and platform adapters stay behind the native plugin layer." vertex="1">
<mxGeometry height="24" width="1260" x="48" y="72" as="geometry" />
</mxCell>
<mxCell id="ov-meta-bg" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#d1d5db;strokeWidth=1.3;" value="" vertex="1">
<mxGeometry height="84" width="280" x="1860" y="24" as="geometry" />
</mxCell>
<mxCell id="ov-meta" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=top;fontSize=12;fontColor=#374151;spacingTop=8;spacingLeft=10;" value="Version: v1.0&lt;br&gt;Date: 2026-06-26&lt;div&gt;Page: App Architecture Overview&lt;/div&gt;" vertex="1">
<mxGeometry height="64" width="250" x="1870" y="32" as="geometry" />
</mxCell>
<mxCell id="ov-boundary" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8fafc;strokeColor=#cbd5e1;strokeWidth=1.4;" value="" vertex="1">
<mxGeometry height="1160" width="2090" x="48" y="132" as="geometry" />
</mxCell>
<mxCell id="ov-host-zone" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#eff6ff;strokeColor=#93c5fd;strokeWidth=1.6;" value="" vertex="1">
<mxGeometry height="980" width="560" x="88" y="188" as="geometry" />
</mxCell>
<mxCell id="ov-host-title" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=24;fontStyle=1;fontColor=#1d4ed8;" value="Flutter App Runtime" vertex="1">
<mxGeometry height="30" width="280" x="116" y="212" as="geometry" />
</mxCell>
<mxCell id="ov-bridge-zone" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#eef6ff;strokeColor=#60a5fa;strokeWidth=1.6;" value="" vertex="1">
<mxGeometry height="980" width="640" x="700" y="188" as="geometry" />
</mxCell>
<mxCell id="ov-bridge-title" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=24;fontStyle=1;fontColor=#2563eb;" value="Bridge and Plugin Layers" vertex="1">
<mxGeometry height="30" width="340" x="728" y="212" as="geometry" />
</mxCell>
<mxCell id="ov-platform-zone" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8fafc;strokeColor=#d1d5db;strokeWidth=1.6;" value="" vertex="1">
<mxGeometry height="980" width="700" x="1392" y="188" as="geometry" />
</mxCell>
<mxCell id="ov-platform-title" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=24;fontStyle=1;fontColor=#475569;" value="Platform Adapters" vertex="1">
<mxGeometry height="30" width="260" x="1420" y="212" as="geometry" />
</mxCell>
<mxCell id="ov-shell" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#bfdbfe;strokeColor=#1d4ed8;strokeWidth=1.6;fontSize=18;fontStyle=1;fontColor=#1e293b;" value="Flutter Host Shell&#10;App entry, navigation host, lifecycle owner" vertex="1">
<mxGeometry height="92" width="440" x="150" y="286" as="geometry" />
</mxCell>
<mxCell id="ov-native" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#1d4ed8;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Flutter Native Pages&#10;App-owned screens and interactions" vertex="1">
<mxGeometry height="92" width="145" x="150" y="602" as="geometry" />
</mxCell>
<mxCell id="ov-migrated" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#1d4ed8;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Migrated Mini-Program Modules&#10;Native Flutter screens rebuilt from former mini-programs" vertex="1">
<mxGeometry height="92" width="145" x="307" y="602" as="geometry" />
</mxCell>
<mxCell id="ov-local" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#2563eb;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Local H5 in WebView&#10;Bundled static HTML5 content" vertex="1">
<mxGeometry height="92" width="146" x="464" y="602" as="geometry" />
</mxCell>
<mxCell id="ov-f6" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#ea580c;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="F6 Remote H5 in WebView&#10;Embedded supplier pages inside the app" vertex="1">
<mxGeometry height="92" width="440" x="150" y="870" as="geometry" />
</mxCell>
<mxCell id="ov-bridge" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#0ea5e9;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="JSBridge Contract&#10;Allowlisted JS &lt;-&gt; Flutter messages" vertex="1">
<mxGeometry height="92" width="500" x="772" y="304" as="geometry" />
</mxCell>
<mxCell id="ov-plugin" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#1d4ed8;strokeWidth=1.6;fontSize=16;fontStyle=1;fontColor=#1e293b;" value="Flutter Native Plugin Layer&#10;Plugin routing and platform channel boundary" vertex="1">
<mxGeometry height="92" width="500" x="772" y="450" as="geometry" />
</mxCell>
<mxCell id="ov-cap" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#dbeafe;strokeColor=#2563eb;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="App-Owned Native Capabilities&#10;Scan / Camera / Upload / Bluetooth / Notification / Storage / Share / Payment" vertex="1">
<mxGeometry height="100" width="500" x="772" y="598" as="geometry" />
</mxCell>
<mxCell id="ov-webview" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#38bdf8;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="WebView Container&#10;Hosts Local H5 and F6 H5 with unified runtime control" vertex="1">
<mxGeometry height="92" width="500" x="772" y="748" as="geometry" />
</mxCell>
<mxCell id="ov-ios" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#2563eb;strokeWidth=1.6;fontSize=16;fontStyle=1;fontColor=#1e293b;" value="iOS Native Adapter&#10;WKWebView and iOS native implementations" vertex="1">
<mxGeometry height="92" width="250" x="1460" y="304" as="geometry" />
</mxCell>
<mxCell id="ov-android" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#2563eb;strokeWidth=1.6;fontSize=16;fontStyle=1;fontColor=#1e293b;" value="Android Native Adapter&#10;Android WebView and native Android implementations" vertex="1">
<mxGeometry height="92" width="250" x="1770" y="304" as="geometry" />
</mxCell>
<mxCell id="ov-harmony" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#94a3b8;strokeWidth=1.5;dashed=1;dashPattern=6 4;fontSize=16;fontColor=#475569;" value="Harmony Adapter (Later)&#10;Future platform adaptation after Phase 1" vertex="1">
<mxGeometry height="92" width="250" x="1615" y="462" as="geometry" />
</mxCell>
<mxCell id="ov-phase-note" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#f8fafc;strokeColor=#cbd5e1;strokeWidth=1.4;fontSize=15;fontColor=#334155;" value="Platform principle&#10;iOS / Android first. Harmony adapts only the platform layer later." vertex="1">
<mxGeometry height="84" width="500" x="1490" y="620" as="geometry" />
</mxCell>
<mxCell id="ov-legend-bg" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#d1d5db;strokeWidth=1.3;" value="" vertex="1">
<mxGeometry height="72" width="980" x="88" y="1200" as="geometry" />
</mxCell>
<mxCell id="ov-legend-title" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=18;fontStyle=1;fontColor=#111827;" value="Legend" vertex="1">
<mxGeometry height="24" width="100" x="114" y="1220" as="geometry" />
</mxCell>
<mxCell id="ov-leg-blue" parent="1" style="shape=line;html=1;strokeColor=#2563eb;strokeWidth=2;" value="" vertex="1">
<mxGeometry height="10" width="80" x="114" y="1252" as="geometry" />
</mxCell>
<mxCell id="ov-leg-blue-t" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#111827;" value="Primary App path" vertex="1">
<mxGeometry height="24" width="150" x="206" y="1242" as="geometry" />
</mxCell>
<mxCell id="ov-leg-orange" parent="1" style="shape=line;html=1;strokeColor=#ea580c;strokeWidth=2;dashed=1;dashPattern=8 6;" value="" vertex="1">
<mxGeometry height="10" width="80" x="394" y="1252" as="geometry" />
</mxCell>
<mxCell id="ov-leg-orange-t" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#111827;" value="F6 WebView branch" vertex="1">
<mxGeometry height="24" width="170" x="486" y="1242" as="geometry" />
</mxCell>
<mxCell id="ov-leg-gray" parent="1" style="shape=line;html=1;strokeColor=#94a3b8;strokeWidth=2;dashed=1;dashPattern=6 4;" value="" vertex="1">
<mxGeometry height="10" width="80" x="700" y="1252" as="geometry" />
</mxCell>
<mxCell id="ov-leg-gray-t" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#111827;" value="Future platform path" vertex="1">
<mxGeometry height="24" width="180" x="792" y="1242" as="geometry" />
</mxCell>
<mxCell id="ov-e1" edge="1" parent="1" source="ov-shell" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;endArrow=diamond;endFill=1;;exitX=0.165;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="ov-native" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ov-e-mig" edge="1" parent="1" source="ov-shell" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;endArrow=diamond;endFill=1;;exitX=0.522;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="ov-migrated" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ov-e2" edge="1" parent="1" source="ov-shell" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;endArrow=diamond;endFill=1;;exitX=0.879;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="ov-local" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ov-e3" edge="1" parent="1" source="ov-shell" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;endArrow=diamond;endFill=1;;exitX=0.488;exitY=1;exitDx=0;exitDy=0;entryX=0.488;entryY=0;entryDx=0;entryDy=0;" target="ov-f6" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ov-e4" edge="1" parent="1" source="ov-local" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#2563eb;strokeWidth=1.4;endArrow=block;endFill=1;;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;" target="ov-bridge" value="JS -&gt; Flutter bridge">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="650" y="625" /><mxPoint x="650" y="373" /></Array>
</mxGeometry>
</mxCell>
<mxCell id="ov-e5" edge="1" parent="1" source="ov-f6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#ea580c;strokeWidth=1.4;dashed=1;dashPattern=8 6;endArrow=block;endFill=1;;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0;entryY=0.85;entryDx=0;entryDy=0;" target="ov-bridge" value="JS -&gt; Flutter bridge">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="690" y="893" /><mxPoint x="690" y="382" /></Array>
</mxGeometry>
</mxCell>
<mxCell id="ov-e6" edge="1" parent="1" source="ov-native" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;endArrow=block;endFill=1;;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="ov-plugin" value="native interactions">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="330" y="625" /><mxPoint x="330" y="496" /></Array>
</mxGeometry>
</mxCell>
<mxCell id="ov-e-mig-plugin" edge="1" parent="1" source="ov-migrated" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;endArrow=block;endFill=1;;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;" target="ov-plugin" value="native interactions">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="500" y="625" /><mxPoint x="500" y="519" /></Array>
</mxGeometry>
</mxCell>
<mxCell id="ov-e7" edge="1" parent="1" source="ov-bridge" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#0ea5e9;strokeWidth=1.4;endArrow=block;endFill=1;;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="ov-plugin" value="message routing">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ov-e8" edge="1" parent="1" source="ov-plugin" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1d4ed8;strokeWidth=1.5;endArrow=block;endFill=1;;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="ov-cap" value="Flutter -&gt; native plugin">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ov-e9" edge="1" parent="1" source="ov-local" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#2563eb;strokeWidth=1.2;endArrow=block;endFill=1;;exitX=1;exitY=0.75;exitDx=0;exitDy=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;" target="ov-webview" value="local container">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="650" y="671" /><mxPoint x="650" y="771" /></Array>
</mxGeometry>
</mxCell>
<mxCell id="ov-e10" edge="1" parent="1" source="ov-f6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#ea580c;strokeWidth=1.2;dashed=1;dashPattern=8 6;endArrow=block;endFill=1;;exitX=1;exitY=0.75;exitDx=0;exitDy=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;" target="ov-webview" value="remote container">
<mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="730" y="939" /><mxPoint x="730" y="817" /></Array></mxGeometry>
</mxCell>
<mxCell id="ov-e11" edge="1" parent="1" source="ov-cap" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#2563eb;strokeWidth=1.5;endArrow=block;endFill=1;;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="ov-ios" value="current adapter">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1350" y="623" /><mxPoint x="1350" y="350" /></Array>
</mxGeometry>
</mxCell>
<mxCell id="ov-e12" edge="1" parent="1" source="ov-cap" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#2563eb;strokeWidth=1.5;endArrow=block;endFill=1;;exitX=1;exitY=0.75;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" target="ov-android" value="current adapter">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1420" y="673" /><mxPoint x="1420" y="429" /><mxPoint x="1895" y="429" /></Array>
</mxGeometry>
</mxCell>
<mxCell id="ov-e13" edge="1" parent="1" source="ov-cap" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#94a3b8;strokeWidth=1.5;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="ov-harmony" value="later adapter">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1380" y="648" /><mxPoint x="1380" y="508" /></Array>
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
<diagram id="app-detailed-layers" name="App Detailed Layering">
<mxGraphModel dx="2871" dy="1606" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="2200" pageHeight="1400" background="#FFFFFF" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="dt-title" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=30;fontStyle=1;fontColor=#0f172a;" value="Continental Retail APP Detailed Layering" vertex="1">
<mxGeometry height="40" width="780" x="48" y="28" as="geometry" />
</mxCell>
<mxCell id="dt-subtitle" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=14;fontColor=#475569;" value="Pure App-internal layering: runtime shell, native pages plus migrated mini-program modules render directly, Local H5 and F6 remote H5 stay as WebView hybrid branches through the bridge contract, then native plugin boundary, capabilities, and platform adapters." vertex="1">
<mxGeometry height="24" width="1280" x="48" y="72" as="geometry" />
</mxCell>
<mxCell id="dt-meta-bg" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#d1d5db;strokeWidth=1.3;" value="" vertex="1">
<mxGeometry height="84" width="280" x="1860" y="24" as="geometry" />
</mxCell>
<mxCell id="dt-meta" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=top;fontSize=12;fontColor=#374151;spacingTop=8;spacingLeft=10;" value="Version: v1.0&lt;br&gt;Date: 2026-06-26&lt;div&gt;Page: App Detailed Layering&lt;/div&gt;" vertex="1">
<mxGeometry height="64" width="250" x="1870" y="32" as="geometry" />
</mxCell>
<mxCell id="dt-boundary" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8fafc;strokeColor=#cbd5e1;strokeWidth=1.4;" value="" vertex="1">
<mxGeometry height="1180" width="2090" x="48" y="136" as="geometry" />
</mxCell>
<mxCell id="dt-l1" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#bfdbfe;strokeColor=#1d4ed8;strokeWidth=1.8;fontSize=18;fontStyle=1;fontColor=#1e293b;" value="Layer 1 - Flutter Host Shell&#10;Entry point, navigation container, lifecycle owner" vertex="1">
<mxGeometry height="88" width="1680" x="250" y="220" as="geometry" />
</mxCell>
<mxCell id="dt-l2a" parent="1" style="rounded=1;arcSize=18;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#1d4ed8;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Layer 2A - Flutter Native Pages&#10;App-owned flows and UI interactions" vertex="1">
<mxGeometry height="92" width="400" x="210" y="374" as="geometry" />
</mxCell>
<mxCell id="dt-l2m" parent="1" style="rounded=1;arcSize=18;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#1d4ed8;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Layer 2B - Migrated Mini-Program Modules&#10;Native Flutter screens rebuilt from former mini-programs" vertex="1">
<mxGeometry height="92" width="400" x="646" y="374" as="geometry" />
</mxCell>
<mxCell id="dt-l2b" parent="1" style="rounded=1;arcSize=18;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#2563eb;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Layer 2C - Local H5 WebView&#10;Bundled static HTML5 content" vertex="1">
<mxGeometry height="92" width="400" x="1082" y="374" as="geometry" />
</mxCell>
<mxCell id="dt-l2c" parent="1" style="rounded=1;arcSize=18;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#ea580c;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Layer 2D - F6 Remote H5 WebView&#10;Embedded remote H5 pages inside the app" vertex="1">
<mxGeometry height="92" width="400" x="1518" y="374" as="geometry" />
</mxCell>
<mxCell id="dt-l3" parent="1" style="rounded=1;arcSize=18;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#0ea5e9;strokeWidth=1.6;fontSize=16;fontColor=#1e293b;" value="Layer 3 - JSBridge Contract&#10;Allowlisted commands, request / response messages, runtime trace propagation" vertex="1">
<mxGeometry height="92" width="1680" x="250" y="544" as="geometry" />
</mxCell>
<mxCell id="dt-l4" parent="1" style="rounded=1;arcSize=18;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#1d4ed8;strokeWidth=1.6;fontSize=16;fontStyle=1;fontColor=#1e293b;" value="Layer 4 - Flutter Native Plugin Layer&#10;Platform channels, plugin routing, and capability abstraction boundary" vertex="1">
<mxGeometry height="92" width="1680" x="250" y="714" as="geometry" />
</mxCell>
<mxCell id="dt-l5" parent="1" style="rounded=1;arcSize=18;html=1;whiteSpace=wrap;fillColor=#dbeafe;strokeColor=#2563eb;strokeWidth=1.6;fontSize=16;fontColor=#1e293b;" value="Layer 5 - App-Owned Native Capabilities&#10;Scan / Camera / Upload / Bluetooth / Notification / Storage / Share / Payment" vertex="1">
<mxGeometry height="92" width="1680" x="250" y="884" as="geometry" />
</mxCell>
<mxCell id="dt-l6a" parent="1" style="rounded=1;arcSize=18;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#2563eb;strokeWidth=1.5;fontSize=16;fontStyle=1;fontColor=#1e293b;" value="Layer 6A - iOS Adapter&#10;WKWebView + native iOS implementations" vertex="1">
<mxGeometry height="92" width="500" x="250" y="1054" as="geometry" />
</mxCell>
<mxCell id="dt-l6b" parent="1" style="rounded=1;arcSize=18;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#2563eb;strokeWidth=1.5;fontSize=16;fontStyle=1;fontColor=#1e293b;" value="Layer 6B - Android Adapter&#10;Android WebView + native Android implementations" vertex="1">
<mxGeometry height="92" width="500" x="870" y="1054" as="geometry" />
</mxCell>
<mxCell id="dt-l6c" parent="1" style="rounded=1;arcSize=18;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#94a3b8;strokeWidth=1.5;dashed=1;dashPattern=6 4;fontSize=16;fontColor=#475569;" value="Layer 6C - Harmony Adapter (Later)&#10;Future platform adaptation after iOS / Android" vertex="1">
<mxGeometry height="92" width="440" x="1490" y="1054" as="geometry" />
</mxCell>
<mxCell id="dt-note" parent="1" style="rounded=1;arcSize=18;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#cbd5e1;strokeWidth=1.4;fontSize=15;fontColor=#334155;" value="App-only principle&#10;This diagram describes only the internal App runtime and platform adaptation structure." vertex="1">
<mxGeometry height="70" width="980" x="610" y="1186" as="geometry" />
</mxCell>
<mxCell id="dt-leg-bg" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#d1d5db;strokeWidth=1.3;" value="" vertex="1">
<mxGeometry height="64" width="920" x="180" y="1268" as="geometry" />
</mxCell>
<mxCell id="dt-leg-title" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=16;fontStyle=1;fontColor=#111827;" value="Legend" vertex="1">
<mxGeometry height="24" width="90" x="204" y="1288" as="geometry" />
</mxCell>
<mxCell id="dt-leg-blue" parent="1" style="shape=line;html=1;strokeColor=#2563eb;strokeWidth=2;" value="" vertex="1">
<mxGeometry height="10" width="80" x="294" y="1300" as="geometry" />
</mxCell>
<mxCell id="dt-leg-blue-t" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#111827;" value="Current platform path" vertex="1">
<mxGeometry height="24" width="180" x="386" y="1290" as="geometry" />
</mxCell>
<mxCell id="dt-leg-orange" parent="1" style="shape=line;html=1;strokeColor=#ea580c;strokeWidth=2;dashed=1;dashPattern=8 6;" value="" vertex="1">
<mxGeometry height="10" width="80" x="620" y="1300" as="geometry" />
</mxCell>
<mxCell id="dt-leg-orange-t" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#111827;" value="F6 WebView branch" vertex="1">
<mxGeometry height="24" width="170" x="712" y="1290" as="geometry" />
</mxCell>
<mxCell id="dt-leg-gray" parent="1" style="shape=line;html=1;strokeColor=#94a3b8;strokeWidth=2;dashed=1;dashPattern=6 4;" value="" vertex="1">
<mxGeometry height="10" width="80" x="920" y="1300" as="geometry" />
</mxCell>
<mxCell id="dt-leg-gray-t" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#111827;" value="Future Harmony path" vertex="1">
<mxGeometry height="24" width="180" x="1012" y="1290" as="geometry" />
</mxCell>
<mxCell id="dt-e1" edge="1" parent="1" source="dt-l1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;endArrow=diamond;endFill=1;;exitX=0.0952;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="dt-l2a" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="dt-e-mig" edge="1" parent="1" source="dt-l1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;endArrow=diamond;endFill=1;;exitX=0.3548;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="dt-l2m" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="dt-e2" edge="1" parent="1" source="dt-l1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;endArrow=diamond;endFill=1;;exitX=0.6143;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="dt-l2b" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="dt-e3" edge="1" parent="1" source="dt-l1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;endArrow=diamond;endFill=1;;exitX=0.8738;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="dt-l2c" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="dt-e4" edge="1" parent="1" source="dt-l2b" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#2563eb;strokeWidth=1.5;endArrow=block;endFill=1;;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.6143;entryY=0;entryDx=0;entryDy=0;" target="dt-l3" value="JS -&gt; Flutter bridge">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="dt-e5" edge="1" parent="1" source="dt-l2c" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#ea580c;strokeWidth=1.5;dashed=1;dashPattern=8 6;endArrow=block;endFill=1;;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.8738;entryY=0;entryDx=0;entryDy=0;" target="dt-l3" value="JS -&gt; Flutter bridge">
<mxGeometry relative="1" as="geometry">
</mxGeometry>
</mxCell>
<mxCell id="dt-e6" edge="1" parent="1" source="dt-l2a" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;endArrow=block;endFill=1;;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.0952;entryY=0;entryDx=0;entryDy=0;" target="dt-l4" value="native interactions">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="dt-e-mig-l4" edge="1" parent="1" source="dt-l2m" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;endArrow=block;endFill=1;;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.3548;entryY=0;entryDx=0;entryDy=0;" target="dt-l4" value="native interactions">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="dt-e7" edge="1" parent="1" source="dt-l3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#0ea5e9;strokeWidth=1.4;endArrow=block;endFill=1;;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="dt-l4" value="message dispatch">
<mxGeometry relative="1" as="geometry">
</mxGeometry>
</mxCell>
<mxCell id="dt-e8" edge="1" parent="1" source="dt-l4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1d4ed8;strokeWidth=1.5;endArrow=block;endFill=1;;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="dt-l5" value="Flutter -&gt; native plugin">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="dt-e9" edge="1" parent="1" source="dt-l5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#2563eb;strokeWidth=1.5;endArrow=block;endFill=1;;exitX=0.149;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="dt-l6a" value="current adapter">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="dt-e10" edge="1" parent="1" source="dt-l5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#2563eb;strokeWidth=1.5;endArrow=block;endFill=1;;exitX=0.518;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="dt-l6b" value="current adapter">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="dt-e11" edge="1" parent="1" source="dt-l5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#94a3b8;strokeWidth=1.5;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;;exitX=0.869;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="dt-l6c" value="later adapter">
<mxGeometry relative="1" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>
@@ -0,0 +1,801 @@
# Continental Retail APP Architecture Diagram 详细说明
本文用于解释 `architecture-diagram.drawio` 中的 3 张系统架构图,帮助产品、研发、架构、移动端、后端、集成、测试和评审人员快速理解这套系统为什么这样设计、每一页分别在说明什么、不同域之间的关系如何划分,以及关键访问链路和治理规则如何落地。
这 3 张图不是数据库设计图,也不是接口字段定义图,更不是某台服务器部署细节图。它们的定位是:
- 用于统一架构认知。
- 用于评审系统边界和责任归属。
- 用于说明主访问链路和例外链路。
- 用于帮助研发和测试理解关键业务运行方式。
---
## 1. 这 3 张图整体在表达什么
这套图表达的是一套“统一移动入口、主后台统一编排、历史后台保留独立边界、供应商能力受控接入”的系统架构。
它的核心目标不是把所有历史系统都并进一个后台,而是在保留实际业务边界的前提下,把移动端访问链路重新组织成一个清晰、可治理、可演进的体系。
3 张图分别承担不同职责:
- `System Overview`
说明系统能力分别归谁拥有,重点是“谁负责什么”。
- `System Architecture`
说明系统按层分布后的结构关系,重点是“系统怎么连接、怎么治理”。
- `Key Flows and Context Governance`
说明关键业务链路在运行时如何流转,重点是“具体流程怎么走、异常和上下文怎么管”。
这 3 张图共同强调以下架构原则:
- `Mobile App -> App Backend` 是唯一主访问链路。
- `App Backend` 是 APP 的主后台和统一业务编排中心。
- `Mini Program Backend` 继续保持独立后台域,不直接并入主后台。
- `F6 Supplier Domain` 是供应商能力域,不被定义为 APP 主后台。
- `Mobile App -> F6` 只允许发生在嵌入式 `WebView` 场景。
- `App Backend -> F6 APIs` 必须经过 `F6 Integration Adapter`
- 历史 Mini 直连链路只保留为兼容路径,不作为推荐默认方案。
---
## 2. 图例和颜色到底在表达什么
为了让读图的人在 3 页之间建立统一认知,这套图对颜色和线条语义做了固定约定。
### 2.1 颜色语义
- 蓝色区域和蓝色节点
表示 APP 本身和 `App Backend` 主域相关能力。
- 绿色区域和绿色节点
表示保留的 `Mini Program Backend` 历史业务域。
- 橙色区域和橙色节点
表示 `F6 Supplier Domain`、WebView 入口、供应商接入和集成适配层。
- 灰色区域和灰色说明
表示通用治理、跨域聚合、外部服务或非主业务实体说明。
- 红色点线
表示历史兼容链路,只是过渡保留,不是推荐设计。
### 2.2 连线语义
- 蓝色实线
表示主访问链路,也就是 APP 面向主后台的标准访问方式。
- 橙色虚线
表示 F6 相关的例外链路,包括嵌入式 WebView、换票和供应商访问路径。
- 灰色虚线
表示聚合访问、外部服务访问或跨域读取。
- 红色点线
表示历史兼容直连,不建议在新功能中继续复制。
这组语义在 3 页中都保持一致。第三页底部的 `Route Semantics` 也用线段样例再次标注这些规则,避免读图时只靠颜色文字理解链路含义。因此这套图并不是 3 张孤立页面,而是一套统一的架构表达。
---
## 3. 第一页:System Overview 详细说明
`System Overview` 是能力归属图。它的重点不是展示某个接口先调谁、后调谁,而是回答一个更基础的问题:
“整套系统里,不同能力到底归哪个域负责?”
这一页把系统划分成 4 个主域和 1 个底部治理带:
- `Mobile App`
- `App Backend`
- `Mini Program Backend Domain`
- `F6 Supplier Domain`
- `External Services + Governance Rules`
### 3.1 Mobile App:统一移动入口
左侧第一列是 `Mobile App`,代表用户真正使用的移动端容器。
这部分说明的是,APP 在架构中的职责主要是“承载、呈现、调用原生能力、维持当前会话”,而不是直接承担复杂跨系统编排。
它包含几个关键块:
- `Login / Agreement / App Shell`
表示 APP 是唯一统一入口,用户从这里进入整个系统。
- `WebView + JSBridge`
表示 APP 具备嵌入式 WebView 承载能力,但这里特别强调“只用于 F6 portal pages”,不是泛化的任意外部浏览器。
- `Native Capabilities`
表示扫码、相机、上传、蓝牙、通知等设备能力由 APP 容器掌控。
- `Store-Aware Session Holder`
表示 APP 本地会持有当前门店和角色上下文,但上下文本身的权威归属仍然在主后台。
换句话说,APP 主要负责:
- 提供统一入口。
- 承担页面容器。
- 调度设备能力。
- 保存当前会话状态。
但 APP 不负责:
- 多系统聚合编排。
- 供应商 API 直接调用。
- 业务权限主判断。
- 门店上下文主定义。
### 3.2 App Backend:主业务域和控制中心
中间第二列是 `App Backend`,这是整页最核心的部分。
这一列强调的是:APP 主后台不只是一个普通 API 服务,而是整个移动平台的控制面和编排中心。
它包含以下能力:
- `Auth and Token Center`
负责登录、令牌签发、刷新、退出和身份可信控制。
- `Store Context + Menu + Permission + Config`
负责当前门店、角色范围、菜单权限和配置下发。
- `Workbench Aggregation`
负责首页工作台、提醒、摘要和多个系统结果的统一返回。
- `Business Orchestration`
负责订单、采购、流程上下文和字段标准化。
- `WebView Ticket and Signing Entry`
负责 F6 WebView 场景的换票、上下文准备和 trace handoff。
这一列的含义非常明确:
- APP 所有主流程都应先到这里。
- 这里决定用户是谁、当前在哪个门店、可以看什么菜单、有什么权限。
- 这里负责把复杂的后端异构系统整合成移动端可用结果。
- 这里也是所有供应商接入和链路治理的统一出口。
如果没有这一层,移动端就会变成一个多后台直连客户端,导致:
- 门店和角色上下文不统一。
- 权限边界难以收口。
- 多系统异常无法统一处理。
- 供应商接入逻辑扩散到多个模块。
### 3.3 Mini Program Backend Domain:保留独立边界的历史系统域
第三列是 `Mini Program Backend Domain`
这部分要表达的不是“历史系统不重要”,而是:
“这些系统仍然重要,但它们不是 APP 的统一主后台。”
图中列出了典型保留系统:
- `O2O`
- `Warranty`
- `Retail Store`
- `ROOS`
其中 `Retail Store` 对应“马上下单”体系中的门店注册、门店信息修改、店员管理等门店基础资料能力,不再使用容易被误解为交易订单的旧英文表述。
并通过说明卡强调:
- 它们仍然拥有历史业务数据和流程。
- 它们仍然可以是某些能力的 `Source of Truth`
- 但面向 APP 的访问,原则上应通过 `App Backend` 聚合和标准化后暴露。
这部分架构表达非常重要,因为它避免了两个极端:
- 一个极端是误以为历史系统可以被立刻彻底替换。
- 另一个极端是继续把移动端做成多个小程序后台的直连入口。
正确做法是:
- 保留历史系统边界。
- 承认它们的业务归属。
- 但将移动端访问统一收束到主后台。
### 3.4 F6 Supplier Domain:供应商能力域
第四列是 `F6 Supplier Domain`
这部分专门用来说明 F6 的定位:
- 它是供应商域。
- 它提供能力,但不是 APP 的主系统。
- 它既包含页面能力,也包含接口能力。
图中分成两类:
- `F6 WebView Pages`
- `F6 Capability APIs`
并给出代表性示例:
- WebView 例子:`Sales, scan, settlement, inbound`
- API 例子:`Procurement, activity, inventory sync`
这里的核心意思是:
- 页面可以在受控情况下嵌入到 APP WebView 中。
- API 不允许 APP 前端直接调用。
- 所有 API 级访问应通过 `App Backend` 内部适配层完成。
### 3.5 底部:External Services 和 Governance Rules
最底部是一条横向带,补充说明两件事:
- 系统还会依赖外部服务。
- 整套系统必须遵守统一治理规则。
外部服务示例包括:
- `SMS`
- `Marketing / CRM`
- `WeCom`
治理规则则明确写出 4 条核心边界:
- `App -> App Backend is primary`
- `App -> F6 only in Embedded WebView`
- `F6 APIs go through Adapter`
- `Mini direct access is legacy-only`
这 4 条规则可以理解为第一页的结论。整张图不只是介绍组件,而是在告诉所有参与方:
“系统边界和默认访问方式已经定了,新需求不要再随意绕开它。”
---
## 4. 第二页:System Architecture 详细说明
`System Architecture` 是分层架构图。它建立在第一页能力归属基础上,进一步解释系统按层组织后的技术结构。
如果第一页回答的是“谁负责什么”,那么第二页回答的是:
“这些能力在逻辑架构上如何分层组织,链路如何穿过这些层?”
这一页分成以下层次:
- `Client Tier`
- `Access & Security`
- `App Backend`
- `Integration Layer`
- `Mini Program Backend`
- `F6 Supplier Domain`
- `External Services`
- `Cross-Cutting`
### 4.1 Client Tier:客户端层
最上层是 `Client Tier`
这里包含:
- `Store User Persona`
- `Mobile App`
- `Native Capabilities`
- `WebView + JSBridge`
这层说明的是:
- 用户并不是直接面对多个后端系统,而是面对一个统一 APP。
- 原生能力和 WebView 容器都属于客户端能力域。
- 客户端负责发起请求、展示页面、承载设备能力和 WebView 容器。
这里再次强调:`WebView + JSBridge` 是一种容器能力,不等于前端可以直接把供应商接口当成主链路使用。
### 4.2 Access & Security:接入与安全层
第二层是 `Access & Security`
它包含:
- `API Gateway`
- `JWT / Auth`
- `WebView Allowlist`
这层表达的是系统接入不能裸奔,所有访问必须经过入口控制和安全校验。
#### API Gateway
`API Gateway` 代表统一 API 接入入口,负责:
- HTTPS / TLS 接入。
- 路由分发。
- 基础限流和治理。
- 将移动端和后端实现细节隔离。
#### JWT / Auth
`JWT / Auth` 代表统一身份凭证体系,负责:
- 令牌签发。
- 令牌刷新。
- 请求身份识别。
- 为后续权限和上下文建立可信基础。
#### WebView Allowlist
`WebView Allowlist` 是这一层里很关键的一个治理点。
它表达的是:
- 并不是任何外部 WebView 页面都可以被 APP 打开。
- 嵌入式 WebView 域名必须是受控、登记和允许的。
- 这既是安全规则,也是架构边界规则。
### 4.3 App Backend:主后台层
第三层是 `App Backend`,也是架构主域。
这里包含:
- `Identity & Store Center`
- `BFF Orchestration`
- `Workbench Aggregation`
- `WebView Ticket Center`
#### Identity & Store Center
这个模块负责:
- 用户身份。
- 门店主数据。
- 角色范围。
- 菜单权限。
它的意义是让系统具备统一上下文中心,否则每个后端域都按自己的方式解释用户和门店,会导致移动端体验严重割裂。
#### BFF Orchestration
这是面向移动端的统一 BFF 编排层,负责:
- 统一接口形态。
- 聚合和标准化多个后端返回。
- 减少前端直接理解多个后端协议的复杂度。
在架构里它是非常重要的一层,因为 APP 实际看到的“后端世界”,应该优先由它统一封装,而不是暴露历史系统差异。
#### Workbench Aggregation
这个模块更聚焦首页和工作台聚合能力,典型包括:
- 待办。
- 提醒。
- 门店经营摘要。
- 多来源业务 tile 数据。
它说明首页不是由单一系统直接返回,而是由主后台整合多个来源后下发。
#### WebView Ticket Center
这个模块专门解决 F6 WebView 场景下的入口控制问题,负责:
- 生成或换取 WebView 票据。
- 绑定当前用户和门店上下文。
- 传递 trace 信息。
- 为嵌入式 WebView 提供受控启动入口。
这意味着 APP 打开 F6 WebView 时,并不是裸跳 URL,而是先由主后台准备好上下文和票据条件。
### 4.4 Integration Layer:集成适配层
第四层是 `Integration Layer`
这一层存在的意义,是把供应商接入复杂性控制在一个专门层里,而不是扩散进整个业务系统。
包含两个关键组件:
- `F6 Integration Adapter`
- `Timeout / Retry`
#### F6 Integration Adapter
它负责:
- 换票。
- 供应商访问上下文准备。
- 将主后台调用收口到统一适配出口。
本质上它是主后台访问 F6 的统一适配出口。
#### Timeout / Retry
这部分表达的是供应商链路治理能力,包括:
- 超时控制。
- 重试策略。
因为 F6 是外部能力域,不稳定性和响应波动风险都比内部模块更高,所以这里保留最关键的超时和重试治理。
### 4.5 Mini Program Backend:历史后台层
第五层是 `Mini Program Backend`
这一层包含:
- `O2O Backend`
- `Warranty Backend`
- `Retail Store Backend`
- `ROOS Backend`
其中 `Retail Store Backend` 对应原“马上下单”相关的门店、人员、地址和资料维护能力,命名上按业务域表达为门店基础资料后台。
这层的架构含义不是“这些服务很次要”,而是:
- 它们继续承担原有业务责任。
- 它们可以是数据主来源。
- 但移动端调用它们时,优先通过主后台聚合。
这页里灰色虚线从 `BFF Orchestration` 向下扇出,就是在表达:
- 主后台聚合多个 Mini 域。
- 主后台对外统一返回。
- APP 不应把它们当多个主后台直接使用。
### 4.6 F6 Supplier Domain:供应商能力层
右侧是 `F6 Supplier Domain`
这里分成两个主要能力:
- `F6 WebView Pages`
- `F6 Capability APIs`
它们分别对应两种不同访问模式:
#### F6 WebView Pages
用于页面嵌入场景,例如:
- 销售开单。
- 扫码。
- 结算。
- 入库。
访问特点是:
- 页面最终可能由移动端 WebView 直接打开。
- 但打开前需要经过主后台准备票据和上下文。
- 域名必须在 Allowlist 中。
#### F6 Capability APIs
用于系统间能力调用,例如:
- 采购。
- 促销。
- ERP 补充能力。
访问特点是:
- 前端不能直接调用。
- 只能从 `App Backend -> Integration Adapter -> F6 APIs` 发起。
### 4.7 External Services:外部服务层
底部右侧是 `External Services`,包括:
- `SMS`
- `Marketing / CRM`
- `WeCom`
这说明 APP 主后台除了对接历史内部域和供应商域外,也会调用一些外部平台服务。
这些服务通常承担:
- 短信验证码。
- 营销或客户关系数据。
- 企业协同消息。
它们本质上也是外部依赖,因此在架构里被单独表达,而不是混在主后台内部。
### 4.8 Cross-Cutting:横切关注点
右上方还有一组 `Cross-Cutting` 模块:
- `Observability`
- `Audit / Security`
- `Config Center`
这些不是某个独立业务流程,而是所有流程都必须共享的治理能力。
#### Observability
负责:
- Trace ID
- 日志
- 指标
确保跨域链路可追踪。
#### Audit / Security
负责:
- 敏感信息控制。
- 关键行为留痕。
- 审计证据保留。
#### Config Center
负责:
- 菜单配置。
- 开关配置。
- WebView 入口策略。
这部分说明 APP 平台不是硬编码系统,而是需要较强配置化能力支撑运营和演进。
### 4.9 第二页想强调的核心结论
第二页最终想让读图人形成以下认知:
- 客户端只有一个统一入口。
- 安全和接入必须前置。
- 主后台必须承担统一 BFF 和统一上下文职责。
- 供应商接入必须通过适配层治理。
- 历史 Mini 域继续存在,但面向 APP 的输出需要经由主后台整合。
- 所有跨域链路都要可观测、可审计、可配置、可降级。
---
## 5. 第三页:Key Flows and Context Governance 详细说明
第三页是运行时流程图。它不是在重新画系统结构,而是在解释:
“当业务真实运行起来时,这套架构的关键行为是怎么发生的?”
这一页选了 4 条最关键的流程:
- `Flow 1 Login and Store Context Bootstrap`
- `Flow 2 F6 WebView Launch and Session Rules`
- `Flow 3 Home Aggregation and Mini Compatibility`
- `Flow 4 Hybrid Procurement and Inbound Flow`
同时底部补充统一治理规则。
### 5.1 Flow 1Login and Store Context Bootstrap
这条流程解释登录后的上下文建立过程。
流程步骤是:
1. `App Login`
2. `Token Issue`
3. `Store List + Default Store`
4. `Menu / Permission / Config Baseline`
5. `Context Established`
这个流程在架构上的真正含义不是“登录成功返回 token”这么简单,而是:
- 用户身份只是第一步。
- 系统真正可运行还需要建立当前门店上下文。
- 菜单、权限和配置要跟门店和角色一起确定。
- APP 登录后不是只有一个用户态,而是一个“用户 + 门店 + 角色 + 菜单 + 配置”的完整工作上下文。
所以这条流程强调的是:
- `Store Context` 是核心控制对象。
- 登录完成不代表业务上下文完成。
- APP 中很多行为都依赖这一步建立出的当前门店语义。
### 5.2 Flow 2F6 WebView Launch and Session Rules
这条流程解释 F6 WebView 嵌入为什么是“例外链路但仍然受控”。
流程步骤是:
1. `App asks for WebView entry`
2. `Backend exchanges / prepares ticket`
3. `Embedded open in WebView`
并补充 3 条强规则:
- `Store switch invalidates WebView`
- `Expired ticket needs refresh`
- `Failure fallback shows safe message + trace ID`
这条流程表达的重点有 4 个:
#### 第一,WebView 入口必须由主后台签发
APP 不是拿到一个 URL 就直接打开,而是要先通过主后台获取受控入口。
#### 第二,WebView 会话受当前门店上下文约束
如果用户切换门店,当前 WebView 会话不能继续沿用旧上下文,否则会造成门店数据串用和权限风险。
#### 第三,票据是时效性的
过期票据需要刷新,而不是无限复用。
#### 第四,失败时必须可支持排障
如果 F6 打不开,不能只给用户一个空白页或技术错误,而是要给出安全提示并带 trace 信息,方便客服、研发和集成排查。
### 5.3 Flow 3Home Aggregation and Mini Compatibility
这条流程解释首页工作台为什么一定是聚合页,而不是某个单体后端直接吐数据。
流程步骤是:
1. `Workbench request`
2. `Backend aggregates O2O / Warranty / ROOS / Config`
3. `Partial failure returns degradable tiles`
4. `Legacy Mini direct access is compatibility only`
这条流程的重点非常明确:
#### 第一,首页是聚合结果
首页的数据来源天然分散,不可能全部只来自一个系统。
#### 第二,主后台要负责标准化
不同 Mini 域返回结构、状态和错误处理方式可能不同,需要统一加工后再交给 APP。
#### 第三,降级方式必须是“局部降级”
如果其中一个来源失败,不应该让整个首页白屏,而应该:
- 哪个 tile 有问题就降级哪个 tile。
- 其他可用部分继续返回。
#### 第四,历史直连不是默认解法
即使某些 Mini 场景短期仍保留兼容直连,也应明确标记为历史兼容路径,而不是继续作为新功能访问方式。
### 5.4 Flow 4Hybrid Procurement and Inbound Flow
这条流程解释采购和入库为什么是“混合模式”。
流程步骤是:
1. `Retail store context + permission + normalization`
2. `F6 owns procurement / promotion / ERP`
3. `Inbound execution uses WebView or API path`
4. `Historical data may still come from Mini aggregation`
这条流程在业务上很关键,因为它说明采购和入库类能力并不是纯内部能力,也不是纯供应商能力,而是一个混合场景。
它的架构含义是:
- 主后台负责上下文、权限和统一口径。
- F6 负责其擅长和实际拥有的供应商能力。
- 页面型操作可能通过 WebView 完成。
- 接口型能力通过适配层访问。
- 部分历史辅助数据可能仍来自 Mini 域聚合。
这也解释了为什么:
- 不能把 F6 当主后台。
- 也不能假装采购和入库完全脱离 F6。
- 更不能让前端自己到处直连多个系统完成业务。
正确解法是由主后台掌控主流程,由供应商承接其能力边界内的部分。
---
## 6. 底部治理规则和线段语义在告诉我们什么
第三页底部的 `Shared Governance Rules``Route Semantics``Review checks` 不是补充装饰,而是整套架构落地的检查清单和读图规则。
### 6.1 Shared Governance Rules
这里明确了 4 条总规则:
- `Store context is owned by App Backend`
- `F6 WebView is an embedded exception`
- `Mini systems remain independent`
- `Every degraded or supplier-facing failure returns a user-safe message and a trace ID`
它们分别约束:
- 上下文归属。
- 例外链路边界。
- 历史系统独立性。
- 失败处理方式。
### 6.2 Route Semantics
这里用线段样例说明第三页所有关键链路的读法:
- `Primary App route`
对应蓝色实线,表示 APP 到主后台的标准主链路。
- `F6 embedded / exception`
对应橙色虚线,表示 F6 WebView 嵌入、票据换取或供应商例外链路。
- `Aggregation / external`
对应灰色虚线,表示主后台向 Mini 域、外部服务或聚合来源发起的访问。
- `Legacy compatibility`
对应红色点线,表示历史兼容路径,只能作为过渡保留,不能作为新功能默认链路。
这部分和第二页的图例保持一致,目的是让评审人员在看流程图时能直接区分“主链路、例外链路、聚合链路、历史链路”,避免把 F6 WebView 或 Mini 直连误解成默认访问方式。
### 6.3 Review Checks
这里的检查项可以直接作为评审问题来问:
1. 门店切换是否会关闭当前供应商 WebView 会话。
2. 首页失败是否按 tile 降级而不是整页失败。
3. 采购和入库是否保持 F6-first 的供应商能力归属。
4. Mini 直连是否被严格控制为过渡链路。
如果某个新需求或技术方案违反了这里的检查项,通常意味着它已经偏离当前架构原则。
---
## 7. 为什么必须这样设计
这套架构不是为了“画得好看”,而是为了解决当前业务现实中的几个核心问题。
### 7.1 解决多入口和多后台混乱
历史上不同能力分散在多个小程序和后台里,APP 如果继续直接对接多个后端,移动端复杂度会越来越高。
统一 `App Backend` 作为主后台后,可以:
- 收敛前端访问入口。
- 统一账号和门店上下文。
- 统一权限和配置。
### 7.2 保留历史资产而不是强行推倒重来
Mini Program Backend 仍然保留业务边界,避免为了“统一”而做不现实的大拆大建。
这使系统具备:
- 现实可落地性。
- 渐进式演进能力。
- 更低迁移风险。
### 7.3 把 F6 当成供应商能力,而不是主系统
这是整个架构中最重要的认知之一。
因为 F6
- 不是自有主后台。
- 协议和稳定性不完全可控。
- 同时提供页面和接口两类能力。
所以必须:
- 页面入口受控。
- API 接口后端统一适配。
- 供应商异常和主系统隔离。
### 7.4 支持真实业务运行中的上下文治理
系统不是“登录就结束”,而是多门店、多角色、多链路环境下持续运行。
因此必须把以下能力做成架构级规则:
- 当前门店上下文。
- WebView 会话绑定和失效控制。
- 跨域链路可追踪。
- 失败时可降级、可审计、可支持排障。
---
## 8. 读完这 3 页后应该形成的统一认知
如果要用一句话总结这 3 页图,它表达的是:
“Continental Retail APP 是一个以 `App Backend` 为统一主后台、以 `Mobile App` 为统一入口、以 `Mini Program Backend` 为保留独立历史域、以 `F6` 为受控供应商能力域的混合架构系统。”
更具体地说,所有参与方应形成以下共识:
- APP 不是多个后台的并列客户端,而是统一入口。
- `App Backend` 不是普通接口层,而是控制面和编排中心。
- Mini 后台继续存在,但面向 APP 时应优先通过主后台聚合。
- F6 是供应商域,页面和接口都要按受控方式接入。
- 门店上下文是系统运行的核心治理对象。
- 首页聚合必须支持局部降级。
- WebView 是例外链路,不是默认业务通路。
- 所有跨域链路都必须可治理、可观测、可审计。
---
## 9. 这份说明适合怎么使用
这份文档适合以下用途:
- 架构评审时作为讲解稿。
- 产品、研发、测试 onboarding 时作为系统认知材料。
- 需求讨论时用于确认是否违反既定架构原则。
- 接口联调前用于统一系统边界和责任分工。
如果后续需要,我还可以继续补两类配套文档:
- 一份“面向评审汇报”的精简版讲稿。
- 一份“按模块拆解”的实现说明,把图里的每个块映射到实际研发任务和接口边界。
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,322 @@
<mxfile host="Electron" agent="Codex" compressed="false">
<diagram id="deployment-architecture" name="Deployment Architecture">
<mxGraphModel dx="2357" dy="1402" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="2400" pageHeight="1500" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="d-title" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=28;fontStyle=1;fontColor=#1f2937;" value="Continental Retail APP Azure Deployment Architecture" vertex="1">
<mxGeometry height="40" width="760" x="50" y="24" as="geometry" />
</mxCell>
<mxCell id="d-subtitle" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#4b5563;" value="Standalone deployment topology aligned to the AKS reference style: secure ingress, private workloads, peered backend networks, private endpoints, and platform dependencies." vertex="1">
<mxGeometry height="24" width="1080" x="50" y="62" as="geometry" />
</mxCell>
<mxCell id="d-meta-bg" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#d1d5db;strokeWidth=1.5;" value="" vertex="1">
<mxGeometry height="78" width="260" x="2050" y="22" as="geometry" />
</mxCell>
<mxCell id="d-meta" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=top;fontSize=12;fontColor=#374151;spacingTop=8;spacingLeft=10;" value="Version: v1.0&lt;br&gt;Date: 2026-06-26&lt;div&gt;Page: Deployment Architecture&lt;/div&gt;" vertex="1">
<mxGeometry height="60" width="230" x="2060" y="30" as="geometry" />
</mxCell>
<mxCell id="d-legend-bg" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#d1d5db;strokeWidth=1.5;" value="" vertex="1">
<mxGeometry height="230" width="330" x="20" y="1230" as="geometry" />
</mxCell>
<mxCell id="d-legend-title" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=18;fontStyle=1;fontColor=#111827;" value="Legend" vertex="1">
<mxGeometry height="24" width="100" x="50" y="1248" as="geometry" />
</mxCell>
<mxCell id="d-legend-line-ssh" parent="1" style="shape=line;html=1;strokeColor=#0f766e;strokeWidth=2;dashed=1;dashPattern=8 6;" value="" vertex="1">
<mxGeometry height="10" width="92" x="50" y="1288" as="geometry" />
</mxCell>
<mxCell id="d-legend-text-ssh" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#111827;" value="SSH traffic" vertex="1">
<mxGeometry height="24" width="160" x="165" y="1280" as="geometry" />
</mxCell>
<mxCell id="d-legend-line-https" parent="1" style="shape=line;html=1;strokeColor=#64748b;strokeWidth=2;dashed=1;dashPattern=10 6;" value="" vertex="1">
<mxGeometry height="10" width="92" x="50" y="1316" as="geometry" />
</mxCell>
<mxCell id="d-legend-text-https" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#111827;" value="HTTPS traffic" vertex="1">
<mxGeometry height="24" width="160" x="165" y="1308" as="geometry" />
</mxCell>
<mxCell id="d-legend-line-monitor" parent="1" style="shape=line;html=1;strokeColor=#ea580c;strokeWidth=2;" value="" vertex="1">
<mxGeometry height="10" width="92" x="50" y="1344" as="geometry" />
</mxCell>
<mxCell id="d-legend-text-monitor" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#111827;" value="Monitoring" vertex="1">
<mxGeometry height="24" width="160" x="165" y="1336" as="geometry" />
</mxCell>
<mxCell id="d-legend-line-private" parent="1" style="shape=line;html=1;strokeColor=#2563eb;strokeWidth=2;" value="" vertex="1">
<mxGeometry height="10" width="92" x="50" y="1372" as="geometry" />
</mxCell>
<mxCell id="d-legend-text-private" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#111827;" value="Private Connection" vertex="1">
<mxGeometry height="24" width="180" x="165" y="1364" as="geometry" />
</mxCell>
<mxCell id="d-legend-line-vnetlink" parent="1" style="shape=line;html=1;strokeColor=#eab308;strokeWidth=2;dashed=1;dashPattern=3 3;" value="" vertex="1">
<mxGeometry height="10" width="92" x="50" y="1400" as="geometry" />
</mxCell>
<mxCell id="d-legend-text-vnetlink" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#111827;" value="Virtual Network Link" vertex="1">
<mxGeometry height="24" width="190" x="165" y="1392" as="geometry" />
</mxCell>
<mxCell id="d-legend-line-peering" parent="1" style="shape=line;html=1;strokeColor=#9ca3af;strokeWidth=2;dashed=1;dashPattern=2 4;" value="" vertex="1">
<mxGeometry height="10" width="92" x="50" y="1428" as="geometry" />
</mxCell>
<mxCell id="d-legend-text-peering" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#111827;" value="Virtual Network Peering" vertex="1">
<mxGeometry height="24" width="210" x="165" y="1420" as="geometry" />
</mxCell>
<mxCell id="d-internet" parent="1" style="shape=cloud;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#6b7280;strokeWidth=1.8;fontSize=16;fontStyle=1;fontColor=#111827;" value="Internet" vertex="1">
<mxGeometry height="70" width="140" x="720" y="110" as="geometry" />
</mxCell>
<mxCell id="d-fw-pip" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#0284c7;strokeWidth=1.8;fontSize=14;fontStyle=1;fontColor=#111827;" value="Azure Firewall Public IP" vertex="1">
<mxGeometry height="54" width="170" x="440" y="200" as="geometry" />
</mxCell>
<mxCell id="d-bastion-pip" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#06b6d4;strokeWidth=1.8;fontSize=14;fontStyle=1;fontColor=#111827;" value="Azure Bastion Public IP" vertex="1">
<mxGeometry height="54" width="170" x="940" y="200" as="geometry" />
</mxCell>
<mxCell id="d-vnet" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8fbff;strokeColor=#60a5fa;strokeWidth=1.8;dashed=1;dashPattern=2 4;" value="" vertex="1">
<mxGeometry height="920" width="2000" x="110" y="260" as="geometry" />
</mxCell>
<mxCell id="d-vnet-label" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=22;fontStyle=1;fontColor=#1d4ed8;" value="Azure China VNet / Deployment Boundary" vertex="1">
<mxGeometry height="28" width="470" x="136" y="272" as="geometry" />
</mxCell>
<mxCell id="d-security-zone" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#d1d5db;strokeWidth=1.2;dashed=1;dashPattern=4 4;" value="" vertex="1">
<mxGeometry height="170" width="1240" x="180" y="330" as="geometry" />
</mxCell>
<mxCell id="d-fw-subnet" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff7ed;strokeColor=#f59e0b;strokeWidth=1.4;fontStyle=1;verticalAlign=top;align=left;spacingTop=8;spacingLeft=10;fontColor=#111827;" value="AzureFirewallSubnet" vertex="1">
<mxGeometry height="110" width="440" x="220" y="360" as="geometry" />
</mxCell>
<mxCell id="d-bastion-subnet" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ecfeff;strokeColor=#06b6d4;strokeWidth=1.4;fontStyle=1;verticalAlign=top;align=left;spacingTop=8;spacingLeft=10;fontColor=#111827;" value="AzureBastionSubnet" vertex="1">
<mxGeometry height="110" width="440" x="760" y="360" as="geometry" />
</mxCell>
<mxCell id="d-firewall" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#f97316;strokeWidth=1.6;fontSize=14;fontStyle=1;fontColor=#111827;" value="Azure Firewall" vertex="1">
<mxGeometry height="46" width="150" x="365" y="394" as="geometry" />
</mxCell>
<mxCell id="d-bastion" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#06b6d4;strokeWidth=1.6;fontSize=14;fontStyle=1;fontColor=#111827;" value="Azure Bastion" vertex="1">
<mxGeometry height="46" width="150" x="905" y="394" as="geometry" />
</mxCell>
<mxCell id="d-peered-networks" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8fafc;strokeColor=#94a3b8;strokeWidth=1.4;fontStyle=1;verticalAlign=top;align=left;spacingTop=8;spacingLeft=10;fontColor=#111827;" value="Peered Backend Networks" vertex="1">
<mxGeometry height="220" width="150" x="20" y="560" as="geometry" />
</mxCell>
<mxCell id="d-peered-text" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;fontSize=13;fontColor=#334155;" value="Mini Program Backend&lt;br&gt;F6 Backend APIs&lt;br&gt;Enterprise Services" vertex="1">
<mxGeometry height="90" width="120" x="35" y="625" as="geometry" />
</mxCell>
<mxCell id="d-network-zone" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#d1d5db;strokeWidth=1.2;dashed=1;dashPattern=4 4;" value="" vertex="1">
<mxGeometry height="200" width="1060" x="192" y="560" as="geometry" />
</mxCell>
<mxCell id="d-dnat-public" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fffbeb;strokeColor=#fcd34d;strokeWidth=1;fontSize=12;fontColor=#111827;" value="DNAT Rule" vertex="1">
<mxGeometry height="34" width="104" x="270" y="576" as="geometry" />
</mxCell>
<mxCell id="d-dnat-internal" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fffbeb;strokeColor=#fcd34d;strokeWidth=1;fontSize=12;fontColor=#111827;" value="DNAT Rule" vertex="1">
<mxGeometry height="34" width="104" x="670" y="576" as="geometry" />
</mxCell>
<mxCell id="d-udr" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f3f4f6;strokeColor=#d1d5db;strokeWidth=1;fontSize=12;fontColor=#111827;" value="UDRs" vertex="1">
<mxGeometry height="32" width="90" x="504" y="580" as="geometry" />
</mxCell>
<mxCell id="d-public-slb" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#22c55e;strokeWidth=1.6;fontSize=13;fontStyle=1;fontColor=#111827;" value="AKS Cluster Public Standard&lt;br&gt;Load Balancer" vertex="1">
<mxGeometry height="62" width="210" x="240" y="670" as="geometry" />
</mxCell>
<mxCell id="d-route-table" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#38bdf8;strokeWidth=1.6;fontSize=13;fontStyle=1;fontColor=#111827;" value="Route Table" vertex="1">
<mxGeometry height="46" width="120" x="520" y="678" as="geometry" />
</mxCell>
<mxCell id="d-internal-slb" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#22c55e;strokeWidth=1.6;fontSize=13;fontStyle=1;fontColor=#111827;" value="AKS Cluster Internal Standard&lt;br&gt;Load Balancer" vertex="1">
<mxGeometry height="62" width="220" x="720" y="670" as="geometry" />
</mxCell>
<mxCell id="d-dns-stack" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#d1d5db;strokeWidth=1.2;dashed=1;dashPattern=4 4;" value="" vertex="1">
<mxGeometry height="380" width="450" x="1525" y="310" as="geometry" />
</mxCell>
<mxCell id="d-dns-1" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#60a5fa;strokeWidth=1.4;fontSize=12;fontColor=#111827;" value="Private DNS Zone&lt;br&gt;privatelink.blob.core.windows.net" vertex="1">
<mxGeometry height="52" width="340" x="1570" y="342" as="geometry" />
</mxCell>
<mxCell id="d-dns-2" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#60a5fa;strokeWidth=1.4;fontSize=12;fontColor=#111827;" value="Private DNS Zone&lt;br&gt;privatelink.vaultcore.azure.net" vertex="1">
<mxGeometry height="52" width="340" x="1570" y="418" as="geometry" />
</mxCell>
<mxCell id="d-dns-3" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#60a5fa;strokeWidth=1.4;fontSize=12;fontColor=#111827;" value="Private DNS Zone&lt;br&gt;privatelink.azurecr.io" vertex="1">
<mxGeometry height="52" width="340" x="1570" y="500" as="geometry" />
</mxCell>
<mxCell id="d-dns-4" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#60a5fa;strokeWidth=1.4;fontSize=12;fontColor=#111827;" value="Private DNS Zone&lt;br&gt;privatelink.region.azmk8s.io" vertex="1">
<mxGeometry height="52" width="340" x="1570" y="580" as="geometry" />
</mxCell>
<mxCell id="d-app-zone" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#60a5fa;strokeWidth=1.8;dashed=1;dashPattern=2 4;" value="" vertex="1">
<mxGeometry height="260" width="1800" x="180" y="800" as="geometry" />
</mxCell>
<mxCell id="d-aks-cluster" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f3ff;strokeColor=#8b5cf6;strokeWidth=1.6;fontStyle=1;verticalAlign=top;align=left;spacingTop=8;spacingLeft=10;fontColor=#111827;" value="Private AKS Cluster" vertex="1">
<mxGeometry height="160" width="520" x="260" y="850" as="geometry" />
</mxCell>
<mxCell id="d-admin-workload" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#8b5cf6;strokeWidth=1.3;fontSize=13;fontStyle=1;fontColor=#111827;" value="Admin Frontend" vertex="1">
<mxGeometry height="44" width="126" x="300" y="900" as="geometry" />
</mxCell>
<mxCell id="d-backend-workload" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#8b5cf6;strokeWidth=1.3;fontSize=13;fontStyle=1;fontColor=#111827;" value="App Backend APIs" vertex="1">
<mxGeometry height="44" width="146" x="448" y="900" as="geometry" />
</mxCell>
<mxCell id="d-adapter-workload" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#8b5cf6;strokeWidth=1.3;fontSize=13;fontStyle=1;fontColor=#111827;" value="Adapter / Jobs" vertex="1">
<mxGeometry height="44" width="114" x="616" y="900" as="geometry" />
</mxCell>
<mxCell id="d-aks-note" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#c4b5fd;strokeWidth=1;fontSize=12;fontColor=#4c1d95;" value="Ingress + workloads stay private behind the AKS load balancers and route table controls." vertex="1">
<mxGeometry height="40" width="430" x="300" y="958" as="geometry" />
</mxCell>
<mxCell id="d-vm" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#38bdf8;strokeWidth=1.6;fontSize=13;fontStyle=1;fontColor=#111827;" value="Virtual Machine&lt;br&gt;Ops / Maintenance" vertex="1">
<mxGeometry height="90" width="180" x="920" y="890" as="geometry" />
</mxCell>
<mxCell id="d-ssh-tag" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f0fdfa;strokeColor=#99f6e4;strokeWidth=1;fontSize=12;fontColor=#134e4a;" value="SSH" vertex="1">
<mxGeometry height="26" width="60" x="980" y="822" as="geometry" />
</mxCell>
<mxCell id="d-pe-storage" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#38bdf8;strokeWidth=1.5;fontSize=12;fontStyle=1;fontColor=#111827;" value="Private Endpoint" vertex="1">
<mxGeometry height="38" width="130" x="1280" y="900" as="geometry" />
</mxCell>
<mxCell id="d-pe-keyvault" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#38bdf8;strokeWidth=1.5;fontSize=12;fontStyle=1;fontColor=#111827;" value="Private Endpoint" vertex="1">
<mxGeometry height="38" width="130" x="1460" y="900" as="geometry" />
</mxCell>
<mxCell id="d-pe-acr" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#38bdf8;strokeWidth=1.5;fontSize=12;fontStyle=1;fontColor=#111827;" value="Private Endpoint" vertex="1">
<mxGeometry height="38" width="130" x="1640" y="900" as="geometry" />
</mxCell>
<mxCell id="d-pe-api" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#38bdf8;strokeWidth=1.5;fontSize=12;fontStyle=1;fontColor=#111827;" value="Private Endpoint" vertex="1">
<mxGeometry height="38" width="130" x="1820" y="900" as="geometry" />
</mxCell>
<mxCell id="d-loganalytics" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#2563eb;strokeWidth=1.6;fontSize=13;fontStyle=1;fontColor=#111827;" value="Azure Log Analytics" vertex="1">
<mxGeometry height="64" width="180" x="360" y="1252" as="geometry" />
</mxCell>
<mxCell id="d-k8s-api" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#60a5fa;strokeWidth=1.6;fontSize=13;fontStyle=1;fontColor=#111827;" value="Kubernetes API Server" vertex="1">
<mxGeometry height="64" width="190" x="560" y="1250" as="geometry" />
</mxCell>
<mxCell id="d-storage" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#60a5fa;strokeWidth=1.6;fontSize=13;fontStyle=1;fontColor=#111827;" value="Azure Storage Account" vertex="1">
<mxGeometry height="64" width="190" x="1180" y="1250" as="geometry" />
</mxCell>
<mxCell id="ejoeoSuEdeszuMshxJfI-1" edge="1" parent="1" source="d-keyvault" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" target="d-acr" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="d-keyvault" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#f59e0b;strokeWidth=1.6;fontSize=13;fontStyle=1;fontColor=#111827;" value="Azure Key Vault" vertex="1">
<mxGeometry height="64" width="190" x="1460" y="1250" as="geometry" />
</mxCell>
<mxCell id="d-acr" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#3b82f6;strokeWidth=1.6;fontSize=13;fontStyle=1;fontColor=#111827;" value="Azure Container Registry" vertex="1">
<mxGeometry height="64" width="220" x="1740" y="1250" as="geometry" />
</mxCell>
<mxCell id="d-edge-internet-fw" edge="1" parent="1" source="d-internet" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#64748b;strokeWidth=1.5;dashed=1;dashPattern=10 6;" target="d-fw-pip">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="520" y="144" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="d-edge-internet-bastion" edge="1" parent="1" source="d-internet" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#0f766e;strokeWidth=1.5;dashed=1;dashPattern=8 6;" target="d-bastion-pip">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1026" y="144" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="d-edge-fw-pip-firewall" edge="1" parent="1" source="d-fw-pip" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#64748b;strokeWidth=1.5;dashed=1;dashPattern=10 6;" target="d-firewall">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="d-edge-bastion-pip-bastion" edge="1" parent="1" source="d-bastion-pip" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#0f766e;strokeWidth=1.5;dashed=1;dashPattern=8 6;" target="d-bastion">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="d-edge-firewall-publicslb" edge="1" parent="1" source="d-firewall" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#64748b;strokeWidth=1.4;dashed=1;dashPattern=10 6;" target="d-public-slb">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="440" y="600" />
<mxPoint x="345" y="600" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="d-edge-firewall-internalslb" edge="1" parent="1" source="d-firewall" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#64748b;strokeWidth=1.4;dashed=1;dashPattern=10 6;" target="d-internal-slb">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="440" y="620" />
<mxPoint x="830" y="620" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="d-edge-udr-route" edge="1" parent="1" source="d-udr" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#64748b;strokeWidth=1.2;dashed=1;dashPattern=10 6;" target="d-route-table">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="d-edge-publicslb-aks" edge="1" parent="1" source="d-public-slb" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#2563eb;strokeWidth=1.6;" target="d-aks-cluster">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="345" y="790" />
<mxPoint x="430" y="790" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="d-edge-internalslb-aks" edge="1" parent="1" source="d-internal-slb" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#2563eb;strokeWidth=1.6;" target="d-aks-cluster">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="830" y="790" />
<mxPoint x="700" y="790" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="d-edge-bastion-vm" edge="1" parent="1" source="d-bastion" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#0f766e;strokeWidth=1.5;dashed=1;dashPattern=8 6;" target="d-vm">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="995" y="560" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="d-edge-peering" edge="1" parent="1" source="d-peered-networks" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#9ca3af;strokeWidth=1.4;dashed=1;dashPattern=2 4;" target="d-route-table">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="580" y="750" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="d-edge-dns-storage" edge="1" parent="1" source="d-dns-1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#eab308;strokeWidth=1.6;dashed=1;dashPattern=3 3;" target="d-pe-storage">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1450" y="368" />
<mxPoint x="1450" y="920" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="d-edge-dns-keyvault" edge="1" parent="1" source="d-dns-2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#eab308;strokeWidth=1.6;dashed=1;dashPattern=3 3;" target="d-pe-keyvault">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1520" y="444" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="d-edge-dns-acr" edge="1" parent="1" source="d-dns-3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#eab308;strokeWidth=1.6;dashed=1;dashPattern=3 3;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" target="d-pe-acr">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1550" y="526" />
<mxPoint x="1550" y="742" />
<mxPoint x="1705" y="742" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="d-edge-dns-api" edge="1" parent="1" source="d-dns-4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#eab308;strokeWidth=1.6;dashed=1;dashPattern=3 3;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" target="d-pe-api">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1950" y="606" />
<mxPoint x="1950" y="820" />
<mxPoint x="1885" y="820" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="d-edge-storage-service" edge="1" parent="1" source="d-pe-storage" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#2563eb;strokeWidth=1.6;" target="d-storage">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="d-edge-keyvault-service" edge="1" parent="1" source="d-pe-keyvault" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#2563eb;strokeWidth=1.6;" target="d-keyvault">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="d-edge-acr-service" edge="1" parent="1" source="d-pe-acr" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#2563eb;strokeWidth=1.6;" target="d-acr">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="d-edge-api-service" edge="1" parent="1" source="d-pe-api" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#2563eb;strokeWidth=1.6;" target="d-k8s-api">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1885" y="1110" />
<mxPoint x="2110" y="1110" />
<mxPoint x="2110" y="1380" />
<mxPoint x="655" y="1380" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="d-edge-aks-loganalytics" edge="1" parent="1" source="d-aks-cluster" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#ea580c;strokeWidth=1.6;" target="d-loganalytics">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="d-edge-aks-k8sapi" edge="1" parent="1" source="d-aks-cluster" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#2563eb;strokeWidth=1.6;" target="d-k8s-api">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="700" y="1130" />
<mxPoint x="655" y="1130" />
</Array>
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>
@@ -0,0 +1,101 @@
# pyright: reportMissingImports=false
from __future__ import annotations
from pathlib import Path
import re
from openpyxl import load_workbook
ROOT = Path(__file__).resolve().parent
SOURCE_FILE = ROOT.parent / "202606 Conti Retail APP Component data source.xlsx"
OUTPUT_FILE = ROOT / f"{SOURCE_FILE.stem}.md"
FIELDS = [
("编号", 2),
("模块", 3),
("功能", 4),
("负责人", 5),
("前置任务", 6),
("数据集", 7),
("来源", 8),
("安全", 9),
("备注", 10),
]
def normalize_cell(value: object) -> str:
if value is None:
return ""
if isinstance(value, float) and value.is_integer():
value = int(value)
text = str(value).replace("\r\n", "\n").replace("\r", "\n")
lines = [re.sub(r"\s+", " ", line).strip() for line in text.split("\n")]
return "\n".join(line for line in lines if line)
def add_field(parts: list[str], name: str, value: str) -> None:
if not value:
return
parts.append(f"**{name}**")
parts.append("")
lines = [line.strip() for line in value.splitlines() if line.strip()]
if len(lines) > 1:
parts.extend(f"- {line}" for line in lines)
else:
parts.extend(lines)
parts.append("")
def extract_workbook_to_md() -> None:
workbook = load_workbook(SOURCE_FILE, data_only=True)
parts: list[str] = [f"# {SOURCE_FILE.stem}", ""]
for worksheet in workbook.worksheets:
rows: list[dict[str, str]] = []
for row_index in range(2, worksheet.max_row + 1):
row = {
field: normalize_cell(worksheet.cell(row=row_index, column=column).value)
for field, column in FIELDS
}
if not any(row.values()):
continue
if not any(row[key] for key in ("编号", "模块", "功能")):
continue
rows.append(row)
if not rows:
continue
parts.append(f"## {worksheet.title}")
parts.append("")
for row in rows:
number = row["编号"]
module = row["模块"]
title = " ".join(part for part in (number, module) if part).strip()
level = min(6, 3 + number.count(".")) if number else 3
parts.append(f"{'#' * level} {title or 'Untitled'}")
parts.append("")
add_field(parts, "功能", row["功能"])
add_field(parts, "负责人", row["负责人"])
add_field(parts, "前置任务", row["前置任务"])
add_field(parts, "数据集", row["数据集"])
add_field(parts, "来源", row["来源"])
add_field(parts, "安全", row["安全"])
add_field(parts, "备注", row["备注"])
OUTPUT_FILE.write_text("\n".join(parts).strip() + "\n", encoding="utf-8")
print("Wrote workbook markdown output")
if __name__ == "__main__":
extract_workbook_to_md()
@@ -0,0 +1,128 @@
# pyright: reportMissingImports=false
from __future__ import annotations
from pathlib import Path
import re
import fitz
import numpy as np
from pptx import Presentation
from pptx.enum.shapes import MSO_SHAPE_TYPE
from rapidocr_onnxruntime import RapidOCR
ROOT = Path(__file__).resolve().parent
SOURCE_DIR = ROOT.parent
PDF_PATH = SOURCE_DIR / "User Journeys.pdf"
PPTX_PATH = SOURCE_DIR / "零售商系统方案研讨会PPT.retro.pptx"
PDF_OUTPUT = ROOT / "User Journeys.md"
PPTX_OUTPUT = ROOT / "零售商系统方案研讨会PPT.retro.md"
OCR = RapidOCR()
def normalize_text(text: str) -> str:
text = text.replace("\r\n", "\n").replace("\r", "\n")
lines = [re.sub(r"\s+", " ", line).strip() for line in text.split("\n")]
return "\n".join(line for line in lines if line)
def extract_page_ocr_text(page: fitz.Page) -> str:
pix = page.get_pixmap(matrix=fitz.Matrix(4, 4), alpha=False)
image = np.frombuffer(pix.samples, dtype=np.uint8).reshape(pix.height, pix.width, pix.n)
result, _ = OCR(image)
if not result:
return ""
return normalize_text("\n".join(str(item[1]) for item in result))
def extract_pdf_to_md(pdf_path: Path, output_path: Path) -> None:
doc = fitz.open(pdf_path)
parts: list[str] = [f"# {pdf_path.stem}", ""]
try:
for index in range(doc.page_count):
page = doc.load_page(index)
text = normalize_text(str(page.get_text("text") or ""))
if not text:
text = extract_page_ocr_text(page)
parts.append(f"## Page {index + 1}")
parts.append("")
parts.append(text or "[No extractable text]")
parts.append("")
finally:
doc.close()
output_path.write_text("\n".join(parts).strip() + "\n", encoding="utf-8")
def iter_shape_text(shape) -> list[str]:
chunks: list[str] = []
if hasattr(shape, "has_text_frame") and shape.has_text_frame:
text = normalize_text(shape.text_frame.text)
if text:
chunks.append(text)
if hasattr(shape, "has_table") and shape.has_table:
for row in shape.table.rows:
cells = [normalize_text(cell.text) for cell in row.cells]
cells = [cell for cell in cells if cell]
if cells:
chunks.append(" | ".join(cells))
if shape.shape_type == MSO_SHAPE_TYPE.GROUP:
for subshape in shape.shapes:
chunks.extend(iter_shape_text(subshape))
return chunks
def extract_pptx_to_md(pptx_path: Path, output_path: Path) -> None:
prs = Presentation(str(pptx_path))
parts: list[str] = [f"# {pptx_path.stem}", ""]
for index, slide in enumerate(prs.slides, start=1):
title = ""
parts.append(f"## Slide {index}")
parts.append("")
if slide.shapes.title and slide.shapes.title.text:
title = normalize_text(slide.shapes.title.text)
if title:
parts.append(f"### {title}")
parts.append("")
seen: set[str] = set()
collected = []
for shape in slide.shapes:
for chunk in iter_shape_text(shape):
if title and chunk == title:
continue
if chunk and chunk not in seen:
seen.add(chunk)
collected.append(chunk)
if collected:
parts.extend(f"- {chunk}" for chunk in collected)
else:
parts.append("[No extractable text]")
parts.append("")
output_path.write_text("\n".join(parts).strip() + "\n", encoding="utf-8")
def main() -> None:
extract_pdf_to_md(PDF_PATH, PDF_OUTPUT)
extract_pptx_to_md(PPTX_PATH, PPTX_OUTPUT)
print("Wrote PDF markdown output")
print("Wrote PPTX markdown output")
if __name__ == "__main__":
main()
@@ -0,0 +1,265 @@
<mxfile host="Electron" agent="Codex" compressed="false">
<diagram id="gitlab-cicd-azure-deployment" name="GitLab CI-CD to Azure Deployment">
<mxGraphModel dx="1182" dy="661" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="2200" pageHeight="1400" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="g-title" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=28;fontStyle=1;fontColor=#1f2937;" value="Continental Retail APP GitLab CI/CD to Azure Deployment" vertex="1">
<mxGeometry height="40" width="900" x="50" y="24" as="geometry" />
</mxCell>
<mxCell id="g-subtitle" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#4b5563;" value="Delivery pipeline view: source trigger, CI validation, artifact control, Azure deployment promotion, and environment rollout." vertex="1">
<mxGeometry height="24" width="1100" x="50" y="62" as="geometry" />
</mxCell>
<mxCell id="g-meta-bg" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#d1d5db;strokeWidth=1.5;" value="" vertex="1">
<mxGeometry height="86" width="300" x="1830" y="22" as="geometry" />
</mxCell>
<mxCell id="g-meta" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=top;fontSize=12;fontColor=#374151;spacingTop=8;spacingLeft=10;" value="Version: v1.0&lt;br&gt;Date: 2026-06-26&lt;div&gt;Page: GitLab CI-CD to Azure Deployment&lt;/div&gt;" vertex="1">
<mxGeometry height="66" width="276" x="1842" y="30" as="geometry" />
</mxCell>
<mxCell id="g-zone-source" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8fafc;strokeColor=#cbd5e1;strokeWidth=1.6;" value="" vertex="1">
<mxGeometry height="1120" width="350" x="40" y="130" as="geometry" />
</mxCell>
<mxCell id="g-zone-source-title" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=20;fontStyle=1;fontColor=#0f172a;" value="1. Source &amp; Triggers" vertex="1">
<mxGeometry height="28" width="240" x="66" y="152" as="geometry" />
</mxCell>
<mxCell id="g-zone-ci" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#eff6ff;strokeColor=#93c5fd;strokeWidth=1.6;" value="" vertex="1">
<mxGeometry height="1120" width="520" x="420" y="130" as="geometry" />
</mxCell>
<mxCell id="g-zone-ci-title" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=20;fontStyle=1;fontColor=#1d4ed8;" value="2. CI Validation" vertex="1">
<mxGeometry height="28" width="220" x="446" y="152" as="geometry" />
</mxCell>
<mxCell id="g-zone-release" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f3ff;strokeColor=#c4b5fd;strokeWidth=1.6;" value="" vertex="1">
<mxGeometry height="1120" width="380" x="970" y="130" as="geometry" />
</mxCell>
<mxCell id="g-zone-release-title" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=20;fontStyle=1;fontColor=#6d28d9;" value="3. Artifact &amp; Release Controls" vertex="1">
<mxGeometry height="28" width="320" x="996" y="152" as="geometry" />
</mxCell>
<mxCell id="g-zone-cd" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff7ed;strokeColor=#fdba74;strokeWidth=1.6;" value="" vertex="1">
<mxGeometry height="1120" width="330" x="1380" y="130" as="geometry" />
</mxCell>
<mxCell id="g-zone-cd-title" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=20;fontStyle=1;fontColor=#c2410c;" value="4. CD to Azure" vertex="1">
<mxGeometry height="28" width="200" x="1406" y="152" as="geometry" />
</mxCell>
<mxCell id="g-zone-azure" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ecfdf5;strokeColor=#86efac;strokeWidth=1.6;" value="" vertex="1">
<mxGeometry height="1120" width="420" x="1740" y="130" as="geometry" />
</mxCell>
<mxCell id="g-zone-azure-title" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=20;fontStyle=1;fontColor=#15803d;" value="5. Azure Environments" vertex="1">
<mxGeometry height="28" width="260" x="1766" y="152" as="geometry" />
</mxCell>
<mxCell id="g-dev" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#94a3b8;strokeWidth=1.5;fontSize=14;fontStyle=1;fontColor=#111827;" value="Developer" vertex="1">
<mxGeometry height="50" width="160" x="120" y="220" as="geometry" />
</mxCell>
<mxCell id="g-repo" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#334155;strokeWidth=1.6;fontSize=14;fontStyle=1;fontColor=#111827;" value="GitLab Repository" vertex="1">
<mxGeometry height="60" width="200" x="100" y="320" as="geometry" />
</mxCell>
<mxCell id="g-trigger-validation" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#64748b;strokeWidth=1.4;fontSize=13;fontColor=#111827;" value="Push / Merge Request&#xa;CI Validation Trigger" vertex="1">
<mxGeometry height="58" width="240" x="80" y="410" as="geometry" />
</mxCell>
<mxCell id="g-trigger-release" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#334155;strokeWidth=1.5;fontSize=13;fontStyle=1;fontColor=#111827;" value="Protected Tag / Release Trigger&#xa;Select Version to Deploy" vertex="1">
<mxGeometry height="58" width="240" x="80" y="500" as="geometry" />
</mxCell>
<mxCell id="g-branch-policy" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8fafc;strokeColor=#cbd5e1;strokeWidth=1.2;fontSize=12;fontColor=#334155;" value="Validation runs on code change. Release promotion selects an already validated immutable version." vertex="1">
<mxGeometry height="44" width="240" x="80" y="592" as="geometry" />
</mxCell>
<mxCell id="g-ci-lint" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#60a5fa;strokeWidth=1.5;fontSize=14;fontStyle=1;fontColor=#111827;" value="Lint / Static Checks" vertex="1">
<mxGeometry height="56" width="180" x="510" y="230" as="geometry" />
</mxCell>
<mxCell id="g-ci-test" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#60a5fa;strokeWidth=1.5;fontSize=14;fontStyle=1;fontColor=#111827;" value="Unit / Integration Tests" vertex="1">
<mxGeometry height="56" width="190" x="710" y="230" as="geometry" />
</mxCell>
<mxCell id="g-ci-build" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#2563eb;strokeWidth=1.5;fontSize=14;fontStyle=1;fontColor=#111827;" value="Build / Package" vertex="1">
<mxGeometry height="56" width="180" x="560" y="360" as="geometry" />
</mxCell>
<mxCell id="g-ci-scan" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#2563eb;strokeWidth=1.5;fontSize=14;fontStyle=1;fontColor=#111827;" value="Security / Quality Scan" vertex="1">
<mxGeometry height="56" width="220" x="560" y="470" as="geometry" />
</mxCell>
<mxCell id="g-ci-runner" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dbeafe;strokeColor=#3b82f6;strokeWidth=1.6;fontSize=14;fontStyle=1;fontColor=#1e3a8a;" value="GitLab Runners" vertex="1">
<mxGeometry height="60" width="210" x="540" y="610" as="geometry" />
</mxCell>
<mxCell id="g-ci-runner-note" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#bfdbfe;strokeWidth=1.1;fontSize=12;fontColor=#1e40af;" value="Shared or dedicated executors run validation and deployment jobs." vertex="1">
<mxGeometry height="40" width="290" x="500" y="692" as="geometry" />
</mxCell>
<mxCell id="g-registry" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#8b5cf6;strokeWidth=1.6;fontSize=14;fontStyle=1;fontColor=#111827;" value="Published Build Artifact / Image" vertex="1">
<mxGeometry height="60" width="200" x="1060" y="250" as="geometry" />
</mxCell>
<mxCell id="g-acr" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#8b5cf6;strokeWidth=1.6;fontSize=14;fontStyle=1;fontColor=#111827;" value="Azure Container Registry (ACR)" vertex="1">
<mxGeometry height="60" width="260" x="1030" y="360" as="geometry" />
</mxCell>
<mxCell id="g-release-tag" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#a78bfa;strokeWidth=1.4;fontSize=13;fontColor=#111827;" value="Selected Immutable Release Version" vertex="1">
<mxGeometry height="46" width="250" x="1035" y="460" as="geometry" />
</mxCell>
<mxCell id="g-approval" parent="1" style="shape=rhombus;html=1;whiteSpace=wrap;fillColor=#faf5ff;strokeColor=#9333ea;strokeWidth=1.5;fontSize=13;fontStyle=1;fontColor=#111827;" value="Promotion Gate&#xa;Beyond Dev" vertex="1">
<mxGeometry height="96" width="180" x="1070" y="590" as="geometry" />
</mxCell>
<mxCell id="g-rollback" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff7ed;strokeColor=#fb923c;strokeWidth=1.3;fontSize=12;fontColor=#9a3412;" value="Rollback redeploys the last approved image tag or artifact version." vertex="1">
<mxGeometry height="48" width="280" x="1020" y="730" as="geometry" />
</mxCell>
<mxCell id="g-cd-auth" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#f97316;strokeWidth=1.6;fontSize=14;fontStyle=1;fontColor=#111827;" value="Runner Auth to Azure" vertex="1">
<mxGeometry height="56" width="180" x="1450" y="240" as="geometry" />
</mxCell>
<mxCell id="g-cd-secrets" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#f97316;strokeWidth=1.6;fontSize=14;fontStyle=1;fontColor=#111827;" value="Key Vault / Config Retrieval" vertex="1">
<mxGeometry height="56" width="220" x="1430" y="350" as="geometry" />
</mxCell>
<mxCell id="g-cd-deploy-dev" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#ea580c;strokeWidth=1.6;fontSize=14;fontStyle=1;fontColor=#111827;" value="Deploy selected version to Dev" vertex="1">
<mxGeometry height="52" width="140" x="1470" y="470" as="geometry" />
</mxCell>
<mxCell id="g-cd-deploy-uat" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#ea580c;strokeWidth=1.6;fontSize=14;fontStyle=1;fontColor=#111827;" value="Promote approved version to UAT" vertex="1">
<mxGeometry height="52" width="140" x="1470" y="580" as="geometry" />
</mxCell>
<mxCell id="g-cd-deploy-prod" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#ea580c;strokeWidth=1.6;fontSize=14;fontStyle=1;fontColor=#111827;" value="Promote approved version to Prod" vertex="1">
<mxGeometry height="52" width="140" x="1470" y="690" as="geometry" />
</mxCell>
<mxCell id="g-cd-smoke" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff7ed;strokeColor=#fdba74;strokeWidth=1.2;fontSize=12;fontColor=#9a3412;" value="Post-deploy smoke check / health verification" vertex="1">
<mxGeometry height="44" width="270" x="1405" y="810" as="geometry" />
</mxCell>
<mxCell id="g-env-dev" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#22c55e;strokeWidth=1.6;fontSize=14;fontStyle=1;fontColor=#111827;" value="Dev Environment&lt;br&gt;Azure Application Hosting Target" vertex="1">
<mxGeometry height="76" width="260" x="1820" y="240" as="geometry" />
</mxCell>
<mxCell id="g-env-uat" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#22c55e;strokeWidth=1.6;fontSize=14;fontStyle=1;fontColor=#111827;" value="UAT Environment&lt;br&gt;Azure Application Hosting Target" vertex="1">
<mxGeometry height="76" width="260" x="1820" y="400" as="geometry" />
</mxCell>
<mxCell id="g-env-prod" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#16a34a;strokeWidth=1.8;fontSize=14;fontStyle=1;fontColor=#111827;" value="Production Environment&lt;br&gt;Azure Application Hosting Target" vertex="1">
<mxGeometry height="76" width="260" x="1820" y="560" as="geometry" />
</mxCell>
<mxCell id="g-env-note" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f0fdf4;strokeColor=#86efac;strokeWidth=1.2;fontSize=12;fontColor=#166534;" value="Build once, promote across environments with versioned artifacts and gated approvals." vertex="1">
<mxGeometry height="46" width="320" x="1790" y="700" as="geometry" />
</mxCell>
<mxCell id="g-bottom-principles-bg" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#d1d5db;strokeWidth=1.3;" value="" vertex="1">
<mxGeometry height="90" width="2080" x="60" y="1280" as="geometry" />
</mxCell>
<mxCell id="g-bottom-principles" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=top;fontSize=13;fontColor=#374151;spacingTop=6;" value="Key handoff points: source change triggers pipeline → CI validates quality → immutable artifact or image is published → approval promotes release → deployment job targets Azure environment → smoke check confirms release or triggers rollback." vertex="1">
<mxGeometry height="50" width="1980" x="84" y="1300" as="geometry" />
</mxCell>
<mxCell id="g-edge-dev-repo" edge="1" parent="1" source="g-dev" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#475569;strokeWidth=1.4;" target="g-repo">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="g-edge-repo-trigger" edge="1" parent="1" source="g-repo" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#475569;strokeWidth=1.4;" target="g-trigger-validation">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="g-edge-trigger-ci" edge="1" parent="1" source="g-trigger-validation" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#2563eb;strokeWidth=1.6;" target="g-ci-lint">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="380" y="445" />
<mxPoint x="380" y="258" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="g-edge-trigger-release-artifact" edge="1" parent="1" source="g-trigger-release" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#7c3aed;strokeWidth=1.6;fontSize=12;fontColor=#6d28d9;labelBackgroundColor=#ffffff;" target="g-release-tag" value="select validated version">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="360" y="530" />
<mxPoint x="920" y="530" />
<mxPoint x="920" y="483" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="g-edge-lint-test" edge="1" parent="1" source="g-ci-lint" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#2563eb;strokeWidth=1.5;" target="g-ci-test">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="g-edge-test-build" edge="1" parent="1" source="g-ci-test" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#2563eb;strokeWidth=1.5;" target="g-ci-build">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="806" y="320" />
<mxPoint x="650" y="320" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="g-edge-build-scan" edge="1" parent="1" source="g-ci-build" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#2563eb;strokeWidth=1.5;" target="g-ci-scan">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="g-edge-scan-runner" edge="1" parent="1" source="g-ci-scan" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#2563eb;strokeWidth=1.5;" target="g-ci-runner">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="g-edge-runner-artifact" edge="1" parent="1" source="g-ci-runner" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#7c3aed;strokeWidth=1.6;" target="g-registry">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="855" y="640" />
<mxPoint x="855" y="280" />
<mxPoint x="1030" y="280" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="g-edge-artifact-acr" edge="1" parent="1" source="g-registry" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#7c3aed;strokeWidth=1.6;" target="g-acr">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="g-edge-acr-tag" edge="1" parent="1" source="g-acr" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#7c3aed;strokeWidth=1.4;" target="g-release-tag">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="g-edge-approved-version-dev" edge="1" parent="1" source="g-release-tag" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#7c3aed;strokeWidth=1.4;dashed=1;dashPattern=5 4;" target="g-cd-deploy-dev" value="deploy selected version">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1320" y="484" />
<mxPoint x="1320" y="496" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="g-edge-approval-auth" edge="1" parent="1" source="g-trigger-release" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#ea580c;strokeWidth=1.6;fontSize=12;fontColor=#c2410c;labelBackgroundColor=#ffffff;" target="g-cd-auth" value="start release pipeline">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="360" y="530" />
<mxPoint x="1360" y="530" />
<mxPoint x="1360" y="268" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="g-edge-auth-secrets" edge="1" parent="1" source="g-cd-auth" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#ea580c;strokeWidth=1.4;" target="g-cd-secrets">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="g-edge-secrets-dev" edge="1" parent="1" source="g-cd-secrets" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#ea580c;strokeWidth=1.4;" target="g-cd-deploy-dev">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="g-edge-dev-uat" edge="1" parent="1" source="g-cd-deploy-dev" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#9333ea;strokeWidth=1.4;fontSize=12;fontColor=#6d28d9;labelBackgroundColor=#ffffff;" target="g-approval" value="successful Dev release">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="g-edge-uat-prod" edge="1" parent="1" source="g-approval" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#ea580c;strokeWidth=1.4;fontSize=12;fontColor=#c2410c;labelBackgroundColor=#ffffff;" target="g-cd-deploy-uat" value="approved promotion">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="g-edge-uat-prod-step" edge="1" parent="1" source="g-cd-deploy-uat" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#ea580c;strokeWidth=1.4;" target="g-cd-deploy-prod">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="g-edge-deploy-dev-env" edge="1" parent="1" source="g-cd-deploy-dev" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#16a34a;strokeWidth=1.6;" target="g-env-dev">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1780" y="496" />
<mxPoint x="1780" y="278" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="g-edge-deploy-uat-env" edge="1" parent="1" source="g-cd-deploy-uat" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#16a34a;strokeWidth=1.6;" target="g-env-uat">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1800" y="606" />
<mxPoint x="1800" y="438" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="g-edge-deploy-prod-env" edge="1" parent="1" source="g-cd-deploy-prod" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#16a34a;strokeWidth=1.6;" target="g-env-prod">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1760" y="716" />
<mxPoint x="1760" y="620" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="g-edge-prod-smoke" edge="1" parent="1" source="g-env-prod" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#16a34a;strokeWidth=1.4;dashed=1;dashPattern=6 4;exitX=0.25;exitY=1;exitDx=0;exitDy=0;" target="g-cd-smoke">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1885" y="670" />
<mxPoint x="1780" y="670" />
<mxPoint x="1780" y="760" />
<mxPoint x="1540" y="760" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="g-edge-smoke-rollback" edge="1" parent="1" source="g-cd-smoke" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#f97316;strokeWidth=1.4;dashed=1;dashPattern=6 4;" target="g-rollback">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1360" y="832" />
<mxPoint x="1360" y="754" />
</Array>
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>
@@ -0,0 +1,455 @@
<mxfile host="Electron" agent="Codex" compressed="false" pages="2">
<diagram id="network-architecture" name="Network Architecture">
<mxGraphModel dx="1182" dy="661" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1800" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="2" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=28;fontStyle=1;fontColor=#1f2937;" value="Continental Retail APP Network Architecture" vertex="1">
<mxGeometry height="40" width="620" x="60" y="28" as="geometry" />
</mxCell>
<mxCell id="3" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#4b5563;" value="Primary route: Mobile App -&gt; App Backend. F6 API access is backend-only, F6 H5 is embedded-only, and Mini direct access is retained only for limited legacy compatibility." vertex="1">
<mxGeometry height="24" width="980" x="60" y="68" as="geometry" />
</mxCell>
<mxCell id="4" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#d1d5db;strokeWidth=1.5;" value="" vertex="1">
<mxGeometry height="74" width="240" x="1490" y="26" as="geometry" />
</mxCell>
<mxCell id="5" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=top;fontSize=12;fontColor=#374151;spacingTop=8;spacingLeft=10;" value="Version: v0.9&lt;br&gt;Date: 2026-06-16&lt;div&gt;Page: Network Architecture&lt;/div&gt;" vertex="1">
<mxGeometry height="56" width="220" x="1500" y="34" as="geometry" />
</mxCell>
<mxCell id="6" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dbeafe;strokeColor=#2563eb;strokeWidth=2;fontSize=18;fontStyle=1;fontColor=#1e3a8a;" value="Mobile App" vertex="1">
<mxGeometry height="70" width="250" x="770" y="120" as="geometry" />
</mxCell>
<mxCell id="7" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#eff6ff;strokeColor=#93c5fd;fontSize=13;fontColor=#1f2937;" value="Native Shell + WebView&lt;br&gt;Scan / Camera / Upload / JSBridge" vertex="1">
<mxGeometry height="62" width="300" x="1060" y="124" as="geometry" />
</mxCell>
<mxCell id="8" parent="1" style="shape=cloud;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#94a3b8;strokeWidth=1.8;fontSize=16;fontStyle=1;fontColor=#1f2937;" value="Internet" vertex="1">
<mxGeometry height="80" width="150" x="820" y="220" as="geometry" />
</mxCell>
<mxCell id="9" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#eef6ff;strokeColor=#2563eb;strokeWidth=2;" value="" vertex="1">
<mxGeometry height="530" width="580" x="610" y="340" as="geometry" />
</mxCell>
<mxCell id="10" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;fontSize=22;fontStyle=1;fontColor=#1e3a8a;" value="Primary App Backend Domain (Azure China)" vertex="1">
<mxGeometry height="30" width="460" x="670" y="360" as="geometry" />
</mxCell>
<mxCell id="11" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff7ed;strokeColor=#f59e0b;strokeWidth=1.4;fontStyle=1;verticalAlign=top;align=left;spacingTop=8;spacingLeft=10;fontColor=#1f2937;" value="Public Ingress Zone" vertex="1">
<mxGeometry height="130" width="520" x="640" y="410" as="geometry" />
</mxCell>
<mxCell id="12" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#fb923c;strokeWidth=1.5;fontSize=14;fontStyle=1;fontColor=#1f2937;" value="WAF / Application Gateway" vertex="1">
<mxGeometry height="58" width="190" x="680" y="460" as="geometry" />
</mxCell>
<mxCell id="13" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#fb923c;strokeWidth=1.5;fontSize=14;fontStyle=1;fontColor=#1f2937;" value="Public Load Balancer" vertex="1">
<mxGeometry height="58" width="180" x="930" y="460" as="geometry" />
</mxCell>
<mxCell id="14" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e0f2fe;strokeColor=#38bdf8;strokeWidth=1.4;fontStyle=1;verticalAlign=top;align=left;spacingTop=8;spacingLeft=10;fontColor=#1f2937;" value="Private Application Zone" vertex="1">
<mxGeometry height="270" width="520" x="640" y="570" as="geometry" />
</mxCell>
<mxCell id="15" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f3ff;strokeColor=#a78bfa;strokeWidth=1.4;fontSize=14;fontStyle=1;fontColor=#1f2937;" value="NSG / Access Control" vertex="1">
<mxGeometry height="42" width="420" x="690" y="610" as="geometry" />
</mxCell>
<mxCell id="16" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#60a5fa;strokeWidth=1.5;fontSize=14;fontStyle=1;fontColor=#1f2937;" value="App Backend BFF / Unified APIs" vertex="1">
<mxGeometry height="80" width="180" x="680" y="700" as="geometry" />
</mxCell>
<mxCell id="17" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#60a5fa;strokeWidth=1.5;fontSize=14;fontStyle=1;fontColor=#1f2937;" value="Business Aggregation / Orchestration" vertex="1">
<mxGeometry height="80" width="200" x="900" y="700" as="geometry" />
</mxCell>
<mxCell id="18" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#60a5fa;strokeWidth=1.5;fontSize=14;fontStyle=1;fontColor=#1f2937;" value="F6 Integration Adapter" vertex="1">
<mxGeometry height="38" width="200" x="790" y="790" as="geometry" />
</mxCell>
<mxCell id="19" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8fafc;strokeColor=#cbd5e1;strokeWidth=1;fontSize=12;fontColor=#374151;" value="Identity / Store Context&lt;br&gt;Menu / Config / WebView Ticket" vertex="1">
<mxGeometry height="40" width="180" x="680" y="660" as="geometry" />
</mxCell>
<mxCell id="20" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8fafc;strokeColor=#cbd5e1;strokeWidth=1;fontSize=12;fontColor=#374151;" value="Unified Error / Audit&#xa;Logging / Security / Trace ID" vertex="1">
<mxGeometry height="40" width="200" x="900" y="660" as="geometry" />
</mxCell>
<mxCell id="21" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f0fdf4;strokeColor=#16a34a;strokeWidth=2;" value="" vertex="1">
<mxGeometry height="530" width="460" x="60" y="340" as="geometry" />
</mxCell>
<mxCell id="22" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;fontSize=22;fontStyle=1;fontColor=#166534;" value="Mini Program Backend VPC" vertex="1">
<mxGeometry height="30" width="380" x="100" y="360" as="geometry" />
</mxCell>
<mxCell id="78" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dcfce7;strokeColor=#86efac;strokeWidth=1;fontSize=12;fontColor=#166534;" value="Independent VPC / network boundary" vertex="1">
<mxGeometry height="28" width="250" x="165" y="390" as="geometry" />
</mxCell>
<mxCell id="23" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ecfdf5;strokeColor=#4ade80;strokeWidth=1.4;fontStyle=1;verticalAlign=top;align=left;spacingTop=8;spacingLeft=10;fontColor=#1f2937;" value="Public Ingress Zone" vertex="1">
<mxGeometry height="120" width="400" x="90" y="410" as="geometry" />
</mxCell>
<mxCell id="24" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#4ade80;strokeWidth=1.5;fontSize=14;fontStyle=1;fontColor=#1f2937;" value="Mini Gateway / Firewall" vertex="1">
<mxGeometry height="56" width="180" x="200" y="458" as="geometry" />
</mxCell>
<mxCell id="26" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ecfdf5;strokeColor=#4ade80;strokeWidth=1.4;fontStyle=1;verticalAlign=top;align=left;spacingTop=8;spacingLeft=10;fontColor=#1f2937;" value="Independent Mini Services" vertex="1">
<mxGeometry height="188" width="400" x="90" y="585" as="geometry" />
</mxCell>
<mxCell id="33" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#4ade80;strokeWidth=1.4;fontSize=14;fontStyle=1;fontColor=#1f2937;" value="O2O / Warranty / 马上下单 / ROOS&lt;br&gt;Shared Capabilities" vertex="1">
<mxGeometry height="80" width="270" x="155" y="655" as="geometry" />
</mxCell>
<mxCell id="77" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f0fdf4;strokeColor=#86efac;fontSize=13;fontColor=#166534;" value="Independent domain retained. App-facing flows should converge through App Backend. Only selected legacy modules may still direct-connect." vertex="1">
<mxGeometry height="42" width="370" x="105" y="792" as="geometry" />
</mxCell>
<mxCell id="34" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff7ed;strokeColor=#ea580c;strokeWidth=2;" value="" vertex="1">
<mxGeometry height="530" width="450" x="1280" y="340" as="geometry" />
</mxCell>
<mxCell id="35" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;fontSize=21;fontStyle=1;fontColor=#c2410c;" value="F6 Supplier VPC (Alibaba Cloud)" vertex="1">
<mxGeometry height="30" width="390" x="1310" y="360" as="geometry" />
</mxCell>
<mxCell id="79" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffedd5;strokeColor=#fdba74;strokeWidth=1;fontSize=12;fontColor=#9a3412;" value="Supplier-managed VPC / network boundary" vertex="1">
<mxGeometry height="28" width="285" x="1362" y="390" as="geometry" />
</mxCell>
<mxCell id="36" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff7ed;strokeColor=#fb923c;strokeWidth=1.4;fontStyle=1;verticalAlign=top;align=left;spacingTop=8;spacingLeft=10;fontColor=#1f2937;" value="Public Access Zone" vertex="1">
<mxGeometry height="130" width="390" x="1310" y="410" as="geometry" />
</mxCell>
<mxCell id="37" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#fb923c;strokeWidth=1.5;fontSize=14;fontStyle=1;fontColor=#1f2937;" value="Access Gateway / WAF" vertex="1">
<mxGeometry height="58" width="160" x="1340" y="460" as="geometry" />
</mxCell>
<mxCell id="38" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#fb923c;strokeWidth=1.5;fontSize=14;fontStyle=1;fontColor=#1f2937;" value="Load Balancer" vertex="1">
<mxGeometry height="58" width="140" x="1530" y="460" as="geometry" />
</mxCell>
<mxCell id="39" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#fb923c;strokeWidth=1.5;fontSize=13;fontStyle=1;fontColor=#1f2937;" value="Allowlisted B2B API Gateway" vertex="1">
<mxGeometry height="34" width="210" x="1400" y="418" as="geometry" />
</mxCell>
<mxCell id="40" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff7ed;strokeColor=#fb923c;strokeWidth=1.4;fontStyle=1;verticalAlign=top;align=left;spacingTop=8;spacingLeft=10;fontColor=#1f2937;" value="Private Service Zone" vertex="1">
<mxGeometry height="240" width="390" x="1310" y="565" as="geometry" />
</mxCell>
<mxCell id="41" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f3ff;strokeColor=#a78bfa;strokeWidth=1.4;fontSize=14;fontStyle=1;fontColor=#1f2937;" value="Security Group / Access Policy" vertex="1">
<mxGeometry height="42" width="330" x="1340" y="603" as="geometry" />
</mxCell>
<mxCell id="42" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#fdba74;strokeWidth=1.4;fontSize=14;fontStyle=1;fontColor=#1f2937;" value="F6 WebView Pages" vertex="1">
<mxGeometry height="78" width="150" x="1340" y="690" as="geometry" />
</mxCell>
<mxCell id="43" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#fdba74;strokeWidth=1.4;fontSize=14;fontStyle=1;fontColor=#1f2937;" value="F6 Capability APIs&#xa;(Backend Only)" vertex="1">
<mxGeometry height="78" width="150" x="1520" y="690" as="geometry" />
</mxCell>
<mxCell id="44" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff7ed;strokeColor=#fdba74;fontSize=13;fontColor=#92400e;" value="Procurement / Promotion / ERP capabilities are consumed through backend integration. App direct access is allowed only for embedded F6 H5 pages." vertex="1">
<mxGeometry height="48" width="330" x="1340" y="792" as="geometry" />
</mxCell>
<mxCell id="45" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8fafc;strokeColor=#d1d5db;strokeWidth=1.2;" value="" vertex="1">
<mxGeometry height="150" width="1670" x="60" y="910" as="geometry" />
</mxCell>
<mxCell id="46" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=18;fontStyle=1;fontColor=#111827;" value="Architecture Principles" vertex="1">
<mxGeometry height="24" width="220" x="86" y="930" as="geometry" />
</mxCell>
<mxCell id="47" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=top;fontSize=14;fontColor=#374151;spacingTop=4;" value="1. `Mobile App -&amp;gt; App Backend` is the only primary route.&lt;br&gt;2. `App -&amp;gt; F6` appears only in the Embedded H5 scenario.&lt;br&gt;3. `App Backend -&amp;gt; F6 API` must pass through `F6 Integration Adapter`.&lt;br&gt;4. `Mini Program Backend` remains an independent domain.&lt;br&gt;5. Unified controls include HTTPS/TLS, Trace ID, audit logging, config switches, and normalized error handling." vertex="1">
<mxGeometry height="84" width="980" x="86" y="966" as="geometry" />
</mxCell>
<mxCell id="48" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=18;fontStyle=1;fontColor=#111827;" value="Legend" vertex="1">
<mxGeometry height="24" width="80" x="1160" y="930" as="geometry" />
</mxCell>
<mxCell id="49" parent="1" style="shape=line;html=1;strokeColor=#2563eb;strokeWidth=2;" value="" vertex="1">
<mxGeometry height="10" width="72" x="1168" y="974" as="geometry" />
</mxCell>
<mxCell id="50" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#1f2937;" value="Primary route" vertex="1">
<mxGeometry height="24" width="120" x="1250" y="965" as="geometry" />
</mxCell>
<mxCell id="51" parent="1" style="shape=line;html=1;strokeColor=#16a34a;strokeWidth=2;" value="" vertex="1">
<mxGeometry height="10" width="72" x="1168" y="1008" as="geometry" />
</mxCell>
<mxCell id="52" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#1f2937;" value="VPC backend integration" vertex="1">
<mxGeometry height="24" width="140" x="1250" y="999" as="geometry" />
</mxCell>
<mxCell id="53" parent="1" style="shape=line;html=1;strokeColor=#f97316;strokeWidth=2;" value="" vertex="1">
<mxGeometry height="10" width="72" x="1420" y="974" as="geometry" />
</mxCell>
<mxCell id="54" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#1f2937;" value="F6 H5 route" vertex="1">
<mxGeometry height="24" width="110" x="1502" y="965" as="geometry" />
</mxCell>
<mxCell id="55" parent="1" style="shape=line;html=1;strokeColor=#6b7280;strokeWidth=2;dashed=1;dashPattern=8 8;" value="" vertex="1">
<mxGeometry height="10" width="72" x="1420" y="1008" as="geometry" />
</mxCell>
<mxCell id="56" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#1f2937;" value="Legacy compatibility" vertex="1">
<mxGeometry height="24" width="150" x="1502" y="999" as="geometry" />
</mxCell>
<mxCell id="57" edge="1" parent="1" source="6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#2563eb;strokeWidth=1.2;fontSize=12;fontColor=#1e3a8a;" target="7" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="58" edge="1" parent="1" source="6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#2563eb;strokeWidth=1.4;" target="8">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="59" edge="1" parent="1" source="8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#2563eb;strokeWidth=1.5;fontSize=12;fontColor=#1e3a8a;" target="12" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="900" y="350" />
<mxPoint x="775" y="350" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="60" edge="1" parent="1" source="8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#f97316;strokeWidth=1.5;fontSize=12;fontColor=#c2410c;" target="37" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1420" y="260" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="61" edge="1" parent="1" source="12" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#2563eb;strokeWidth=1.2;" target="13">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="62" edge="1" parent="1" source="13" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#2563eb;strokeWidth=1.2;" target="16">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1020" y="600" />
<mxPoint x="770" y="600" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="63" edge="1" parent="1" source="16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#2563eb;strokeWidth=1.4;" target="17">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="64" edge="1" parent="1" source="17" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#16a34a;strokeWidth=1.4;fontSize=12;fontColor=#166534;exitX=0;exitY=0.75;exitDx=0;exitDy=0;" target="18" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="880" y="760" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="65" edge="1" parent="1" source="18" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#16a34a;strokeWidth=1.4;fontSize=12;fontColor=#166534;" target="39" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1240" y="810" />
<mxPoint x="1240" y="435" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="66" edge="1" parent="1" source="39" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#16a34a;strokeWidth=1.4;" target="43">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1505" y="571" />
<mxPoint x="1595" y="571" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="67" edge="1" parent="1" source="17" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#16a34a;strokeWidth=1.4;fontSize=12;fontColor=#166534;startSize=6;" target="24" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1060" y="850" />
<mxPoint x="580" y="850" />
<mxPoint x="580" y="610" />
<mxPoint x="290" y="610" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="74" edge="1" parent="1" source="37" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#f97316;strokeWidth=1.2;" target="38">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="75" edge="1" parent="1" source="38" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#f97316;strokeWidth=1.2;" target="42">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1690" y="489" />
<mxPoint x="1690" y="660" />
<mxPoint x="1415" y="660" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="76" edge="1" parent="1" source="8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;dashed=1;dashPattern=8 8;strokeColor=#6b7280;strokeWidth=1.2;fontSize=12;fontColor=#4b5563;labelBackgroundColor=#ffffff;" target="24" value="Legacy only">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="320" y="300" />
<mxPoint x="290" y="300" />
<mxPoint x="290" y="486" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="cXHFUXgN8kNcZhofBCdT-80" edge="1" parent="1" source="33" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.63;entryY=1.012;entryDx=0;entryDy=0;entryPerimeter=0;" target="33">
<mxGeometry relative="1" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
<diagram id="network-topology" name="Network Topology">
<mxGraphModel dx="1436" dy="803" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1800" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="nt-title" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=28;fontStyle=1;fontColor=#1f2937;" value="Continental Retail APP Network Topology" vertex="1">
<mxGeometry height="40" width="700" x="60" y="28" as="geometry" />
</mxCell>
<mxCell id="nt-subtitle" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#4b5563;" value="Topology view focused on network boundaries, public ingress points, and allowed cross-domain connectivity." vertex="1">
<mxGeometry height="24" width="940" x="60" y="68" as="geometry" />
</mxCell>
<mxCell id="nt-version-box" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#9ca3af;strokeWidth=1.5;" value="" vertex="1">
<mxGeometry height="74" width="240" x="1490" y="26" as="geometry" />
</mxCell>
<mxCell id="nt-version-text" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=top;fontSize=12;fontColor=#374151;spacingTop=8;spacingLeft=10;" value="Version: v0.9&lt;br&gt;Date: 2026-06-16&lt;br&gt;Page: Network Topology" vertex="1">
<mxGeometry height="62" width="220" x="1500" y="32" as="geometry" />
</mxCell>
<mxCell id="nt-public-zone" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f9fafb;strokeColor=#9ca3af;strokeWidth=1.5;dashed=1;dashPattern=8 8;" value="" vertex="1">
<mxGeometry height="650" width="440" x="680" y="145" as="geometry" />
</mxCell>
<mxCell id="nt-public-zone-title" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;fontSize=18;fontStyle=1;fontColor=#111827;" value="Public Network" vertex="1">
<mxGeometry height="28" width="180" x="810" y="165" as="geometry" />
</mxCell>
<mxCell id="nt-mobile" parent="1" style="shape=mxgraph.aws4.mobile_client;html=1;fillColor=#f3f4f6;strokeColor=#111827;strokeWidth=2;fontSize=16;fontStyle=1;fontColor=#111827;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;spacingTop=8;" value="Mobile App" vertex="1">
<mxGeometry height="95" width="72" x="864" y="215" as="geometry" />
</mxCell>
<mxCell id="nt-internet" parent="1" style="shape=cloud;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#374151;strokeWidth=2;fontSize=18;fontStyle=1;fontColor=#1f2937;" value="Internet" vertex="1">
<mxGeometry height="110" width="210" x="795" y="365" as="geometry" />
</mxCell>
<mxCell id="nt-dns" parent="1" style="shape=hexagon;perimeter=hexagonPerimeter2;whiteSpace=wrap;html=1;fixedSize=1;fillColor=#ffffff;strokeColor=#6b7280;strokeWidth=1.4;fontSize=13;fontStyle=1;fontColor=#111827;" value="Public DNS / Domain" vertex="1">
<mxGeometry height="74" width="150" x="825" y="535" as="geometry" />
</mxCell>
<mxCell id="nt-azure" parent="1" style="shape=mxgraph.azure.cloud;html=1;fillColor=#ffffff;strokeColor=#111827;strokeWidth=2;fontSize=18;fontStyle=1;fontColor=#111827;verticalAlign=top;spacingTop=18;" value="Azure China&lt;br&gt;Primary App Backend VNet" vertex="1">
<mxGeometry height="470" width="520" x="80" y="255" as="geometry" />
</mxCell>
<mxCell id="nt-azure-boundary" parent="1" style="shape=rect;rounded=0;whiteSpace=wrap;html=1;fillColor=none;strokeColor=#111827;strokeWidth=1.8;dashed=1;dashPattern=6 6;fontSize=13;fontColor=#111827;verticalAlign=top;align=left;spacingTop=8;spacingLeft=10;" value="VNet boundary" vertex="1">
<mxGeometry height="330" width="430" x="125" y="345" as="geometry" />
</mxCell>
<mxCell id="nt-azure-dmz" parent="1" style="shape=rect;rounded=0;whiteSpace=wrap;html=1;fillColor=#f9fafb;strokeColor=#374151;strokeWidth=1.4;fontStyle=1;verticalAlign=top;align=left;spacingTop=8;spacingLeft=10;fontColor=#1f2937;" value="Public DMZ Subnet" vertex="1">
<mxGeometry height="98" width="360" x="160" y="380" as="geometry" />
</mxCell>
<mxCell id="nt-azure-ingress" parent="1" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fillColor=#ffffff;strokeColor=#374151;strokeWidth=1.5;fontSize=13;fontStyle=1;fontColor=#1f2937;" value="WAF / App Gateway&lt;br&gt;+ Public LB" vertex="1">
<mxGeometry height="58" width="210" x="235" y="412" as="geometry" />
</mxCell>
<mxCell id="nt-azure-private" parent="1" style="shape=rect;rounded=0;whiteSpace=wrap;html=1;fillColor=#f3f4f6;strokeColor=#6b7280;strokeWidth=1.4;fontStyle=1;verticalAlign=top;align=left;spacingTop=8;spacingLeft=10;fontColor=#1f2937;" value="Private Application Subnet" vertex="1">
<mxGeometry height="150" width="360" x="160" y="505" as="geometry" />
</mxCell>
<mxCell id="nt-app-backend" parent="1" style="shape=mxgraph.azure.app_services;html=1;fillColor=#ffffff;strokeColor=#374151;strokeWidth=1.5;fontSize=13;fontStyle=1;fontColor=#1f2937;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;spacingTop=6;" value="" vertex="1">
<mxGeometry height="74" width="110" x="230" y="556" as="geometry" />
</mxCell>
<mxCell id="nt-f6-adapter" parent="1" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fillColor=#ffffff;strokeColor=#374151;strokeWidth=1.5;fontSize=13;fontStyle=1;fontColor=#1f2937;" value="F6 Integration&lt;br&gt;Adapter" vertex="1">
<mxGeometry height="58" width="130" x="370" y="556" as="geometry" />
</mxCell>
<mxCell id="nt-nsg" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f3f4f6;strokeColor=#6b7280;strokeWidth=1.3;fontSize=12;fontStyle=1;fontColor=#111827;" value="NSG / Access Rules" vertex="1">
<mxGeometry height="32" width="220" x="230" y="505" as="geometry" />
</mxCell>
<mxCell id="nt-mini" parent="1" style="shape=mxgraph.azure.cloud;html=1;fillColor=#ffffff;strokeColor=#111827;strokeWidth=2;fontSize=18;fontStyle=1;fontColor=#111827;verticalAlign=top;spacingTop=18;" value="Mini Program Backend&lt;br&gt;Independent VPC" vertex="1">
<mxGeometry height="360" width="430" x="80" y="720" as="geometry" />
</mxCell>
<mxCell id="nt-mini-boundary" parent="1" style="shape=rect;rounded=0;whiteSpace=wrap;html=1;fillColor=none;strokeColor=#111827;strokeWidth=1.8;dashed=1;dashPattern=6 6;fontSize=13;fontColor=#111827;verticalAlign=top;align=left;spacingTop=8;spacingLeft=10;" value="VPC boundary" vertex="1">
<mxGeometry height="225" width="340" x="125" y="820" as="geometry" />
</mxCell>
<mxCell id="nt-mini-gw" parent="1" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fillColor=#ffffff;strokeColor=#374151;strokeWidth=1.5;fontSize=13;fontStyle=1;fontColor=#1f2937;" value="Mini Gateway&lt;br&gt;/ Firewall" vertex="1">
<mxGeometry height="58" width="150" x="160" y="875" as="geometry" />
</mxCell>
<mxCell id="nt-mini-svc" parent="1" style="shape=datastore;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;fillColor=#ffffff;strokeColor=#374151;strokeWidth=1.5;fontSize=13;fontStyle=1;fontColor=#1f2937;" value="Mini Services&lt;br&gt;O2O / Warranty&lt;br&gt;马上下单 / ROOS" vertex="1">
<mxGeometry height="92" width="150" x="285" y="935" as="geometry" />
</mxCell>
<mxCell id="nt-f6" parent="1" style="shape=mxgraph.azure.cloud;html=1;fillColor=#f9fafb;strokeColor=#111827;strokeWidth=2;fontSize=18;fontStyle=1;fontColor=#111827;verticalAlign=top;spacingTop=18;" value="F6 Supplier VPC&lt;br&gt;Alibaba Cloud" vertex="1">
<mxGeometry height="540" width="520" x="1200" y="255" as="geometry" />
</mxCell>
<mxCell id="nt-f6-boundary" parent="1" style="shape=rect;rounded=0;whiteSpace=wrap;html=1;fillColor=none;strokeColor=#111827;strokeWidth=1.8;dashed=1;dashPattern=6 6;fontSize=13;fontColor=#111827;verticalAlign=top;align=left;spacingTop=8;spacingLeft=10;" value="Supplier-managed VPC boundary" vertex="1">
<mxGeometry height="390" width="430" x="1245" y="345" as="geometry" />
</mxCell>
<mxCell id="nt-f6-public" parent="1" style="shape=rect;rounded=0;whiteSpace=wrap;html=1;fillColor=#f9fafb;strokeColor=#374151;strokeWidth=1.4;fontStyle=1;verticalAlign=top;align=left;spacingTop=8;spacingLeft=10;fontColor=#1f2937;" value="Public Access Subnet" vertex="1">
<mxGeometry height="130" width="360" x="1280" y="380" as="geometry" />
</mxCell>
<mxCell id="nt-f6-h5-ingress" parent="1" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fillColor=#ffffff;strokeColor=#374151;strokeWidth=1.5;fontSize=13;fontStyle=1;fontColor=#1f2937;" value="Access Gateway / WAF&lt;br&gt;+ Load Balancer" vertex="1">
<mxGeometry height="58" width="190" x="1305" y="425" as="geometry" />
</mxCell>
<mxCell id="nt-f6-api-gw" parent="1" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fillColor=#ffffff;strokeColor=#374151;strokeWidth=1.5;fontSize=13;fontStyle=1;fontColor=#1f2937;" value="Allowlisted&lt;br&gt;B2B API Gateway" vertex="1">
<mxGeometry height="58" width="150" x="1510" y="425" as="geometry" />
</mxCell>
<mxCell id="nt-f6-private" parent="1" style="shape=rect;rounded=0;whiteSpace=wrap;html=1;fillColor=#f3f4f6;strokeColor=#6b7280;strokeWidth=1.4;fontStyle=1;verticalAlign=top;align=left;spacingTop=8;spacingLeft=10;fontColor=#1f2937;" value="Private Service Subnet" vertex="1">
<mxGeometry height="165" width="360" x="1280" y="540" as="geometry" />
</mxCell>
<mxCell id="nt-f6-h5" parent="1" style="shape=mxgraph.aws4.client;html=1;fillColor=#ffffff;strokeColor=#6b7280;strokeWidth=1.5;fontSize=13;fontStyle=1;fontColor=#1f2937;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;spacingTop=6;" value="F6 WebView&lt;br&gt;Pages" vertex="1">
<mxGeometry height="74" width="92" x="1325" y="595" as="geometry" />
</mxCell>
<mxCell id="nt-f6-api" parent="1" style="shape=datastore;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;fillColor=#ffffff;strokeColor=#6b7280;strokeWidth=1.5;fontSize=13;fontStyle=1;fontColor=#1f2937;" value="F6 Capability APIs&lt;br&gt;Backend Only" vertex="1">
<mxGeometry height="74" width="150" x="1490" y="595" as="geometry" />
</mxCell>
<mxCell id="nt-notes-box" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f9fafb;strokeColor=#9ca3af;strokeWidth=1.2;" value="" vertex="1">
<mxGeometry height="155" width="720" x="1000" y="875" as="geometry" />
</mxCell>
<mxCell id="nt-notes-title" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=18;fontStyle=1;fontColor=#111827;" value="Topology Reading" vertex="1">
<mxGeometry height="24" width="180" x="1030" y="895" as="geometry" />
</mxCell>
<mxCell id="nt-notes-text" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=top;fontSize=14;fontColor=#374151;spacingTop=4;" value="1. This page is network-centric: VNet/VPC boundaries are the main objects.&lt;br&gt;2. Public traffic enters only through exposed ingress nodes.&lt;br&gt;3. Backend integration crosses network boundaries through controlled gateways.&lt;br&gt;4. Mini direct access is shown as a legacy exception, not a target route." vertex="1">
<mxGeometry height="88" width="650" x="1030" y="930" as="geometry" />
</mxCell>
<mxCell id="nt-legend-box" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#9ca3af;strokeWidth=1.2;" value="" vertex="1">
<mxGeometry height="180" width="320" x="640" y="877" as="geometry" />
</mxCell>
<mxCell id="nt-legend-title" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=18;fontStyle=1;fontColor=#111827;" value="Legend" vertex="1">
<mxGeometry height="24" width="90" x="670" y="885" as="geometry" />
</mxCell>
<mxCell id="nt-legend-primary-line" parent="1" style="shape=line;html=1;strokeColor=#111827;strokeWidth=2;" value="" vertex="1">
<mxGeometry height="10" width="70" x="675" y="928" as="geometry" />
</mxCell>
<mxCell id="nt-legend-primary-text" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#1f2937;" value="Primary App route" vertex="1">
<mxGeometry height="24" width="150" x="760" y="919" as="geometry" />
</mxCell>
<mxCell id="nt-legend-backend-line" parent="1" style="shape=line;html=1;strokeColor=#111827;strokeWidth=2;" value="" vertex="1">
<mxGeometry height="10" width="70" x="675" y="962" as="geometry" />
</mxCell>
<mxCell id="nt-legend-backend-text" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#1f2937;" value="Backend integration" vertex="1">
<mxGeometry height="24" width="160" x="760" y="953" as="geometry" />
</mxCell>
<mxCell id="nt-legend-h5-line" parent="1" style="shape=line;html=1;strokeColor=#111827;strokeWidth=2;dashed=1;dashPattern=2 4;" value="" vertex="1">
<mxGeometry height="10" width="70" x="675" y="996" as="geometry" />
</mxCell>
<mxCell id="nt-legend-h5-text" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#1f2937;" value="F6 WebView route" vertex="1">
<mxGeometry height="24" width="160" x="760" y="987" as="geometry" />
</mxCell>
<mxCell id="nt-legend-legacy-line" parent="1" style="shape=line;html=1;strokeColor=#6b7280;strokeWidth=2;dashed=1;dashPattern=8 8;" value="" vertex="1">
<mxGeometry height="10" width="70" x="675" y="1030" as="geometry" />
</mxCell>
<mxCell id="nt-legend-legacy-text" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=13;fontColor=#1f2937;" value="Legacy compatibility" vertex="1">
<mxGeometry height="24" width="170" x="760" y="1021" as="geometry" />
</mxCell>
<mxCell id="nt-e-mobile-internet" edge="1" parent="1" source="nt-mobile" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#111827;strokeWidth=1.5;" target="nt-internet">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="nt-e-internet-dns" edge="1" parent="1" source="nt-internet" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#111827;strokeWidth=1.2;" target="nt-dns">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="nt-e-dns-azure" edge="1" parent="1" source="nt-dns" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#111827;strokeWidth=1.5;fontSize=12;fontColor=#111827;labelBackgroundColor=#ffffff;" target="nt-azure-ingress" value="primary HTTPS">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="600" y="572" />
<mxPoint x="600" y="441" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="nt-e-azure-ingress-app" edge="1" parent="1" source="nt-azure-ingress" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#111827;strokeWidth=1.3;" target="nt-app-backend">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="nt-e-app-adapter" edge="1" parent="1" source="nt-app-backend" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#111827;strokeWidth=1.4;" target="nt-f6-adapter">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="nt-e-adapter-f6-api-gw" edge="1" parent="1" source="nt-f6-adapter" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#111827;strokeWidth=1;fontSize=12;fontColor=#111827;labelBackgroundColor=#ffffff;" target="nt-f6-api-gw" value="allowlisted B2B API">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="435" y="640" />
<mxPoint x="1160" y="640" />
<mxPoint x="1160" y="500" />
<mxPoint x="1585" y="500" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="nt-e-f6-api-gw-api" edge="1" parent="1" source="nt-f6-api-gw" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#111827;strokeWidth=1.3;" target="nt-f6-api">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="nt-e-app-mini" edge="1" parent="1" source="nt-app-backend" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#111827;strokeWidth=1.8;fontSize=12;fontColor=#111827;labelBackgroundColor=#ffffff;" target="nt-mini-gw" value="backend aggregation">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="285" y="690" />
<mxPoint x="235" y="690" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="nt-e-mini-gw-svc" edge="1" parent="1" source="nt-mini-gw" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#111827;strokeWidth=1.3;" target="nt-mini-svc">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="nt-e-dns-f6-h5" edge="1" parent="1" source="nt-dns" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#111827;strokeWidth=1.4;fontSize=12;fontColor=#111827;labelBackgroundColor=#ffffff;dashed=1;dashPattern=2 4;" target="nt-f6-h5-ingress" value="embedded WebView">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1080" y="572" />
<mxPoint x="1080" y="454" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="nt-e-f6-h5-ingress-h5" edge="1" parent="1" source="nt-f6-h5-ingress" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;strokeColor=#111827;strokeWidth=1.2;dashed=1;dashPattern=2 4;" target="nt-f6-h5">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="nt-e-legacy-mini" edge="1" parent="1" source="nt-dns" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=block;endFill=1;dashed=1;dashPattern=8 8;strokeColor=#6b7280;strokeWidth=1.3;fontSize=12;fontColor=#4b5563;labelBackgroundColor=#ffffff;" target="nt-mini-gw" value="legacy only">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="640" y="572" />
<mxPoint x="640" y="904" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="OBjgTYgMnUBFrRI9yGty-1" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;fontSize=10;" value="&lt;span style=&quot;color: rgb(31, 41, 55); font-weight: 700; white-space: nowrap;&quot;&gt;App Backend&lt;/span&gt;&lt;br style=&quot;color: rgb(31, 41, 55); font-weight: 700; white-space: nowrap;&quot;&gt;&lt;span style=&quot;color: rgb(31, 41, 55); font-weight: 700; white-space: nowrap;&quot;&gt;BFF + Orchestration&lt;/span&gt;" vertex="1">
<mxGeometry height="73" width="110" x="230" y="557" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>
@@ -0,0 +1,691 @@
# Multicloud Network Architecture 详细说明
本文用于解释 `network-architecture-diagram.drawio` 中的两个页面,帮助产品、研发、集成和评审人员快速理解这套架构为什么这样设计、每个区域代表什么、各条访问链路分别承担什么职责,以及从网络拓扑角度如何理解各 VNet / VPC 之间的连通关系。
这个 draw.io 文件现在包含两个视图:
- `Network Architecture`:架构评审视图,重点说明业务域边界、主访问链路、供应商接入方式和历史系统兼容策略。
- `Network Topology`:网络拓扑视图,重点说明 VNet / VPC 边界、公网入口、私有服务区、跨网络访问路径和允许 / 例外链路。
两张图表达的是同一套系统,但侧重点不同:第一张回答“为什么这样分域、谁应该访问谁”,第二张回答“网络上从哪里进、跨哪些边界、通过哪些受控入口连通”。
## 1. 这张图整体在表达什么
这张图表达的是一套“三域分离、主链路统一、供应商隔离、历史系统兼容”的多云网络架构。
它的核心目标不是展示某个具体服务器怎么部署,而是说明以下几个关键架构原则:
- `Mobile App -> App Backend` 是唯一主访问链路。
- `App Backend` 是 APP 的统一主后台和业务编排中心。
- `F6` 是供应商能力域,不是 APP 的主后台。
- `Mobile App -> F6` 只允许发生在嵌入式 `WebView` 场景。
- `App Backend -> F6 API` 必须通过 `F6 Integration Adapter` 访问。
- `Mini Program Backend` 保持独立后台域,但面向 APP 的能力应优先通过 `App Backend` 聚合。
- `App Backend -> Mini Program Backend``App Backend -> F6` 都是跨独立 VPC / VNet 边界的受控后端访问,不是主域内部本地调用。
- 历史上少量 APP 直连 Mini 后台的场景可以兼容保留,但不能继续扩散。
从架构表达上看,这张图并不是一张“部署拓扑详图”,而是一张“面向架构评审的网络边界与主访问链路图”。
## 2. 顶部:Mobile App 和 Internet
图最上方是 `Mobile App`,下面是 `Internet`
这部分表示:
- 用户所有访问都从移动端发起。
- APP 访问不同后端域时,需要通过公网链路进入各自对外暴露的入口层。
- 移动端不是直接连内部服务,而是只访问被允许暴露的受控入口。
这张图中,APP 主要存在两类访问路径:
- 主访问路径:`Mobile App -> App Backend`
- 特殊访问路径:`Mobile App -> F6 WebView Pages`
其中第一条是主链路,第二条是例外链路,而且这个例外只允许发生在 F6 的嵌入式 WebView 场景。
## 3. 中间 Azure 域:Primary App Backend Domain
中间区域是 `Azure China (Beijing) VNet`,它代表 APP 主业务域,也是整张图最核心的部分。
这一块承担的是:
- APP 的统一主后台。
- 身份、门店、权限、菜单、配置等基础能力中心。
- 多系统数据聚合和业务编排中心。
- F6 和 Mini Program Backend 的统一接入和治理出口。
### 3.1 为什么这块是核心
整张图最重要的一条架构原则就是:
`Mobile App -> App Backend`
这意味着 APP 不应该把多个后台都当成自己的“直接主后台”。真正的主后台只有一个,就是这里的 `App Backend`
这样做的好处是:
- APP 不需要分别理解多个后端的认证和权限模型。
- 门店上下文、角色上下文、菜单权限可以统一收口。
- F6 和历史 Mini 服务的复杂性可以被隔离在后端。
- 前端链路更稳定,后端也更方便统一治理。
### 3.2 DMZ / Public Ingress Zone
Azure 域上半部分是 `DMZ / Public Ingress Zone`
这部分是公网入口区,作用是先接住来自 APP 的外部请求,不让外部流量直接打进私有服务区。
里面包括:
- `WAF / Application Gateway`
- `Public Load Balancer`
这两个组件组合表达的是标准公网入口模式:
- 先经过网关和安全过滤。
- 再经过负载均衡。
- 最后把请求转发到私有区中的后端服务。
这里的 `WAF / Application Gateway` 主要表示:
- Web 应用防护。
- 统一入口控制。
- 基础七层流量治理。
- 对异常流量、非法请求做第一层拦截。
`Public Load Balancer` 则表示:
- 对后面的 APP 后端服务实例进行流量分发。
- 屏蔽单实例细节。
- 让后面服务集群保持弹性扩缩能力。
### 3.3 Private Application Zone
Azure 域下半部分是 `Private Application Zone`,也就是私有业务服务区。
这里才是真正承载 APP 业务能力的地方。
它包含以下几个关键组件:
#### App Backend BFF / Unified APIs
这是 APP 的统一接口层,可以理解成 APP 面向移动端的统一后端入口。
它负责的事情包括:
- 登录认证。
- 用户信息返回。
- 门店上下文建立和切换。
- 菜单与权限返回。
- 系统配置下发。
- F6 WebView 启动参数准备。
- 为移动端提供统一接口风格。
图中旁边的说明框:
`Identity / Store Context / Menu / Config / WebView Ticket`
就是为了强调这件事:APP 依赖的核心控制面能力必须由主后台统一掌握。
#### Business Aggregation / Orchestration
这是业务聚合与编排层。
它和 `App Backend BFF / Unified APIs` 的区别在于:
- `BFF / Unified APIs` 更偏向“给移动端一个统一的接口入口”。
- `Business Aggregation / Orchestration` 更偏向“把多个后端系统的数据和流程编排成一个完整业务结果”。
比如:
- 首页工作台聚合多个系统数据。
- 采购、库存、延保、返利等场景的跨系统整合。
- 对 Mini 后台返回结果做标准化。
- 把 F6 能力、Mini 后台能力和 APP 自身基础能力组合起来。
这个层次存在的意义是:
- 把复杂的多系统业务放在后端做,而不是让 APP 自己拼装。
- 让 APP 更像一个统一入口,而不是一个多系统直连终端。
#### F6 Integration Adapter
这是 F6 供应商接入适配层。
它的职责是:
- 发起对 F6 的 allowlisted B2B 访问。
- 处理 F6 鉴权、签名、票据换取。
- 组装调用 F6 所需的 Header 或上下文。
- 做字段映射和错误码转换。
- 做超时、重试、熔断、异常隔离。
- 把供应商侧不稳定性隔离在适配层内。
它存在的意义非常重要:
- APP 主后台不应该让每个业务模块都自己直接调 F6。
- F6 是外部供应商域,协议、鉴权、返回结构都可能与主系统不同。
- 所有访问 F6 API 的逻辑都集中在这里,才能实现统一治理。
#### NSG / Access Control
这个框表示私有区里的访问控制层。
`NSG` 一般可以理解为 `Network Security Group`,也就是网络安全组。
它在图里的意思不是某个独立业务服务,而是一层安全控制能力,用来表达:
- 私有业务区不是公网可直接访问的。
- 即使请求已经通过前面的 `WAF / Application Gateway``Public Load Balancer`,进入私有区后仍要受访问控制规则约束。
- 私有区内部组件之间也不应该默认全部互通,而应按来源、目标、协议、端口进行规则控制。
用更直白的话说,这一层是在强调:
“后端服务即使在一个私有网络里,也不是谁都能访问谁,必须按规则放行。”
#### Unified Error / Audit / Logging / Security
这个说明框不是单独服务,而是架构责任说明。
它表达的是:
- 错误处理要统一。
- 安全能力要统一。
- 审计记录要统一。
- 日志追踪要统一。
这也是为什么 `App Backend` 被定义为主业务域,而不是单纯一个 API 容器。
## 4. 右侧 F6 Supplier VPCF6 供应商域
右侧区域是 `F6 Supplier VPC (Alibaba Cloud)`,它表示供应商 F6 所在的独立云网络域。图中同时标注 `Supplier-managed VPC / network boundary`,用来强调 F6 不只是一个业务系统框,而是供应商侧独立管理的 VPC 网络边界。
这块的标题是:
`F6 Supplier VPC (Alibaba Cloud)`
这句话非常关键,它强调:
- F6 由供应商管理。
- F6 是外部能力域。
- F6 不是 APP 主后台的一部分。
- APP 需要接入 F6,但不能把 F6 当成自己的主系统。
### 4.1 F6 域的两类能力
F6 域中被分成两类对外能力:
- `F6 WebView Pages`
- `F6 Capability APIs (Backend Only)`
这两者是整张图中最重要的区别之一。
#### F6 WebView Pages
这是给用户页面使用的能力,也就是嵌入到 APP WebView 里的页面。
适用于:
- 扫码开单页。
- 到店记录页。
- 报价开单页。
- 施工查车页。
- 结算收银页。
- 扫码收货页。
- 部分采购和促销页面。
访问链路是:
`Mobile App -> Internet -> Access Gateway / WAF -> Load Balancer -> F6 WebView Pages`
这条链路的含义是:
- APP 可以直接访问 F6,但仅限于嵌入式 WebView 页面。
- 这里的“直接访问”不是绕过主后台做业务控制,而是在进入 WebView 之前,由 `App Backend` 先完成票据、上下文和权限准备。
#### F6 Capability APIs (Backend Only)
这是系统间调用的接口能力。
图上明确标注了:
`Backend Only`
这表示:
- 移动端不能直接调这些接口。
- 这些接口只能由 `App Backend` 经由 `F6 Integration Adapter` 发起访问。
典型用途包括:
- 获取 WebView 免登票据。
- 获取采购、促销、ERP补充能力。
- 发起供应商相关查询或写入。
- 执行需要后端协同的业务流程。
### 4.2 F6 域的入口层
F6 域上部也分为公网入口区:
- `Access Gateway / WAF`
- `Load Balancer`
- `Allowlisted B2B API Gateway`
这三者分别表达不同入口:
- WebView 页面流量走 Access Gateway / WAF 和 Load Balancer。
- 后端 API 调用走专门的 allowlisted B2B API Gateway。
这正是图中为什么要同时区分页面链路和 API 链路,因为它们不是一回事。
### 4.3 App Backend 到 F6 的受控后端集成链路是什么意思
图中从 `F6 Integration Adapter` 指向 `Allowlisted B2B API Gateway` 的绿色后端集成链路,表示:
- 这是系统间受控访问。
- 不是终端用户流量。
- 需要白名单放通。
- 这是从 App Backend 所在 Azure VNet 到 F6 Supplier VPC 的跨网络边界访问。
- 访问入口必须落在 F6 VPC 对外暴露的受控 B2B API Gateway 上,而不是直接访问 F6 私有服务节点。
- 同时承担获取 WebView 票据、签名、免登参数等职责。
- 图上不再在线路上写长标签,而是通过颜色和图例表达其语义。
这也是为什么 PRD 里强调:
- F6 API 必须通过 App Backend 调用。
- APP 对 F6 的直接访问只保留 WebView 场景。
## 5. 左侧 Mini Program Backend VPC:历史小程序后台域
左侧区域表示历史小程序后台域。图中外层标注为 `Mini Program Backend VPC`,用来说明 Mini 后台不是 App Backend 私有区里的内部模块,而是保留在独立 VPC / 网络域中的历史后台集合。
这一域在图中的定位是:
- 它仍然存在。
- 它仍然是独立后台边界。
- 它不会被简单视为 APP 的主后台。
- 面向 APP 的能力应逐步被 `App Backend` 聚合。
### 5.1 为什么这里采用聚合表示而不是展开拓扑
图中把它写成:
`Independent Mini Services`
并列出:
- `O2O`
- `Warranty`
- `Retail Store`
- `ROOS`
- `Shared Capabilities`
这样写是为了强调:
- Mini Program Backend 不是一个单体后台。
- 它是多个历史业务后台的集合。
- 它们仍然可能各自承担不同的数据主来源和业务责任。
- 其中 `Retail Store` 对应“马上下单”体系中的门店注册、门店信息修改、店员管理等门店基础资料能力,不再使用容易误解为交易订单的 `Order` 表述。
- 这张图是评审视图,因此只保留“入口层 + 独立服务集合”的表达,不再展开每个历史服务之间的内部转发关系。
图这样画,更符合 PRD 对历史系统边界的定义,也能避免内部箭头过多影响主链路可读性。
### 5.2 主推荐链路:通过 App Backend 聚合
`Business Aggregation / Orchestration` 指向 Mini 域入口的是绿色后端集成链路。
这条线表达的是推荐架构:
- 新能力优先通过 `App Backend` 聚合后暴露给 APP。
- 历史 Mini 后台继续作为独立服务存在。
- 但它们不再被 APP 当成第一入口直接大量访问。
- 从网络角度看,这条链路是 App Backend 所在 Azure VNet 到 Mini Program Backend VPC 的受控后端调用。
- App Backend 应访问 Mini VPC 暴露的网关、防火墙或受控入口,不应把 Mini 私有服务当作同一 VNet 内的本地服务直接访问。
这是“统一主后台”原则的重要一部分。
### 5.3 兼容链路:少量保留直连
图中从 `Internet` 指向 Mini 域入口的灰色虚线标注为:
`Legacy only`
这条线表达的是:
- 某些历史模块短期还保留 APP 直连 Mini 后台的方式。
- 但这种方式只是兼容,不是推荐方案。
- 这不是未来架构方向。
- 新模块不应该继续沿用这种方式。
这条线的存在是为了如实表达现状,同时避免评审误解为:
“APP 会长期平行直连所有历史后台。”
## 6. 这张图里的主要链路怎么理解
### 6.1 主链路:APP 到主后台
链路为:
`Mobile App -> Internet -> WAF / Application Gateway -> Public Load Balancer -> App Backend BFF / Unified APIs`
这条链路表示:
- 用户所有主业务请求先进入主后台域。
- 主后台对移动端暴露统一接口。
- APP 的身份、权限、门店上下文和主流程控制都从这里进入。
这是整个系统最重要的访问路径。
### 6.2 F6 H5 页面链路
链路为:
`Mobile App -> Internet -> Access Gateway / WAF -> Load Balancer -> F6 WebView Pages`
这条链路表示:
- APP 可直接以 WebView 方式打开 F6 页面。
- 但这里的“直接打开”是页面访问级别,而不是随意直接调用供应商 API。
- 页面进入前的上下文准备、票据获取、权限判断仍由 `App Backend` 完成。
### 6.3 F6 API 链路
链路为:
`Mobile App -> App Backend -> Business Aggregation / Orchestration -> F6 Integration Adapter -> F6 Supplier VPC / Allowlisted B2B API Gateway -> F6 Capability APIs`
这条链路表示:
- 所有后端级 F6 能力都应该由主后台发起调用。
- 供应商集成逻辑不直接暴露给移动端。
- 主后台统一承担安全、审计、错误处理和链路治理。
- 网络上这是跨 VPC / VNet 的后端集成链路,需要通过 F6 VPC 暴露的 allowlisted API 入口进入。
### 6.4 Mini 聚合链路
链路为:
`Mobile App -> App Backend -> Business Aggregation / Orchestration -> Mini Program Backend VPC -> Mini Gateway / Firewall -> Independent Mini Services`
这条链路表示:
- 历史后台能力仍被使用。
- 但 APP 访问时优先走主后台聚合。
- 这有利于统一接口、统一权限和统一数据口径。
- 网络上这不是 App Backend 内部进程调用,而是从主后台 VNet 到 Mini 后台 VPC 的受控后端访问。
- Mini VPC 的外层入口承担网络隔离、访问控制和历史服务保护职责。
### 6.5 Mini 兼容直连链路
链路为:
`Mobile App -> Internet -> Mini Program Backend Domain`
但图中明确标注这是:
`Legacy compatibility direct access only`
它表示:
- 当前还有少量历史兼容模块未完成收敛。
- 架构上允许暂时存在。
- 但这不是目标态。
## 7. 为什么说这是多云架构
这张图之所以叫 `Multicloud`,是因为主系统不是部署在单一云环境里,而是跨越了多个云网络边界:
- 移动端经公网访问。
- 主业务域在 `Azure China`
- F6 供应商域在 `Alibaba Cloud`
- 历史 Mini Program Backend 在独立 VPC / 云网络域中。
这意味着:
- 不同域之间不是天然内网互通。
- 跨域访问必须经过明确入口。
- 供应商域和主域的边界要清晰。
- 历史系统不能被简单视为主域内部服务。
这也是为什么图中如此强调:
- VPC / VNet 边界。
- DMZ 与私有区分层。
- 受控 API 链路。
- 兼容直连和推荐主链路的区别。
## 8. 这张图的价值是什么
这张图的价值不在于说明某台机器部署在哪,而在于回答下面这些评审问题:
- APP 到底应该先访问谁。
- F6 是主后台还是供应商域。
- 为什么 F6 页面能直开,但 F6 API 不能让 APP 直接调。
- 历史 Mini 后台还保不保留。
- App Backend 到底是不是只是一个 API 网关,还是主编排中心。
- 多个系统的数据、权限和上下文由谁统一控制。
如果用一句话总结整张图:
“APP 只有一个主后台入口,供应商能力通过受控方式接入,历史小程序后台继续存在但逐步被主后台聚合,整个系统通过多云边界和访问控制实现职责分离与链路治理。”
## 9. 如何理解图中的关键标签
### Primary App Backend Domain
表示 APP 的统一主业务域,是控制面和编排面的中心。
### F6 Supplier VPC
表示 F6 是位于 Alibaba Cloud 的供应商管理独立 VPC,不属于 App Backend 主后台域。
### Independent Mini Services
表示历史小程序后台不是一个单系统,而是一组位于独立 VPC / 网络域内的后台服务。
### DMZ / Public Ingress Zone
表示对外暴露入口区,用于承接公网流量,隔离内网服务。
### Private Application Zone / Private Service Zone
表示真正承载业务服务的私有区域,不直接向公网开放。
### NSG / Access Control
表示私有区域内的访问控制和安全规则层,强调后端服务是受控访问而非默认互通。
### F6 Integration Adapter
表示对 F6 的统一适配与治理出口。
### Backend integration path
表示推荐路径,即主后台通过受控 VPC 网络入口优先聚合历史系统能力。
### Legacy only
表示兼容性保留链路,不是目标架构,不应扩散到新模块。
## 10. 第二页 Network Topology 怎么理解
`Network Topology` 是对第一张 `Network Architecture` 的补充,不是重复画一张架构图。
第一张图更偏“架构职责和访问原则”,所以使用了较多业务组件、说明框和颜色区分;第二张图更偏“网络连通和边界关系”,所以采用黑白灰拓扑表达,避免让颜色承担业务语义。
这张拓扑图重点表达四件事:
- 三个核心网络边界:`Primary App Backend VNet``Mini Program Backend VPC``F6 Supplier VPC`
- 公网访问统一从 `Mobile App -> Internet -> Public DNS / Domain` 进入。
- 每个网络域只通过自己的受控入口暴露能力,而不是暴露内部服务。
- 跨 VNet / VPC 的访问必须经过网关、防火墙、API Gateway 或适配层。
### 10.1 为什么拓扑图是黑白灰
网络拓扑图的目标不是强调业务域颜色,而是强调:
- 网络边界在哪里。
- 公网入口在哪里。
- 私有服务在哪里。
- 哪些链路是允许的。
- 哪些链路只是兼容例外。
因此第二页没有继续沿用第一张图里的蓝色、绿色、橙色业务域配色,而是使用黑白灰表达。
这样更符合网络拓扑图的阅读习惯:读者主要通过形状、边界框、线型和线条粗细理解网络关系,而不是通过颜色理解业务语义。
### 10.2 拓扑图里的主要区域
#### Public Network
中间的 `Public Network` 表示公网访问区。
里面包括:
- `Mobile App`
- `Internet`
- `Public DNS / Domain`
它表达的是:移动端访问后端系统时,首先进入公网和域名解析层,然后再被路由到不同网络域暴露出来的公网入口。
这里不是一个业务系统,而是网络访问路径的公共部分。
#### Azure China / Primary App Backend VNet
左上区域表示 APP 主后台所在的 Azure China VNet。
它内部用虚线框标出 `VNet boundary`,并分成两层:
- `Public DMZ Subnet`
- `Private Application Subnet`
`Public DMZ Subnet` 中放的是 `WAF / App Gateway + Public LB`,表示 APP 主链路必须先经过公网入口、防护和负载均衡。
`Private Application Subnet` 中放的是:
- `NSG / Access Rules`
- `App Backend BFF + Orchestration`
- `F6 Integration Adapter`
这表示真正的 APP 后台服务不直接暴露公网,而是在私有子网中运行,并受到 NSG / Access Rules 约束。
#### Mini Program Backend Independent VPC
左下区域表示历史小程序后台所在的独立 VPC。
它内部包括:
- `Mini Gateway / Firewall`
- `Mini Services`
这里强调的是:Mini 后台不是 Azure App Backend VNet 里的内部模块,而是另一个独立网络边界中的历史服务集合。
APP 面向 Mini 能力的目标链路应当是:
`App Backend -> Mini Gateway / Firewall -> Mini Services`
而不是让 APP 长期绕过主后台直接访问 Mini 服务。
#### F6 Supplier VPC / Alibaba Cloud
右侧区域表示供应商 F6 所在的 Alibaba Cloud VPC。
它内部用 `Supplier-managed VPC boundary` 表示这是供应商管理的独立网络边界,不属于 APP 主后台网络。
F6 侧有两个不同入口:
- `Access Gateway / WAF + Load Balancer`
- `Allowlisted B2B API Gateway`
前者服务于 F6 WebView 页面访问,后者服务于主后台到 F6 API 的后端集成。
这两个入口不能混在一起理解,因为它们的访问来源、访问目的和安全要求都不同。
### 10.3 拓扑图里的线型含义
第二页不用颜色区分链路,而是用线型和粗细表达语义。
#### Primary App route
主访问链路是:
`Mobile App -> Internet -> Public DNS / Domain -> WAF / App Gateway + Public LB -> App Backend`
这条链路表示 APP 的主业务请求进入 Azure App Backend VNet,由主后台统一承接。
#### Backend integration
后端集成链路有两类:
- `App Backend -> Mini Gateway / Firewall -> Mini Services`
- `App Backend -> F6 Integration Adapter -> Allowlisted B2B API Gateway -> F6 Capability APIs`
这两类链路都表示受控的跨网络边界访问。
它们不是同一 VNet 内部的本地调用,也不是移动端直接访问第三方或历史后台。
#### F6 WebView route
F6 WebView 链路是:
`Mobile App -> Internet -> Public DNS / Domain -> F6 Access Gateway / WAF + Load Balancer -> F6 WebView Pages`
这条链路表示 APP 可以打开供应商 F6 的嵌入式页面。
但它仍然只是 WebView 页面访问例外,不代表 APP 可以直接访问 F6 API。
#### Legacy compatibility
Mini legacy 兼容链路是:
`Mobile App -> Internet -> Public DNS / Domain -> Mini Gateway / Firewall`
这条线用虚线表达,含义是:
- 这是历史兼容链路。
- 不是目标态主链路。
- 不应继续扩散到新功能。
- 后续应尽量收敛到 `App Backend -> Mini` 的后端聚合路径。
### 10.4 Network Architecture 和 Network Topology 的区别
两张图的区别可以这样理解:
| 页面 | 主要回答的问题 | 适合谁看 | 重点 |
| --- | --- | --- | --- |
| `Network Architecture` | 为什么这样分域、主链路是谁、F6 和 Mini 怎么定位 | 产品、研发、架构评审 | 架构原则、职责边界、访问治理 |
| `Network Topology` | 网络上怎么连、从哪里进、跨哪些 VNet / VPC | 网络、安全、运维、集成 | 网络边界、入口节点、连通路径、线型语义 |
因此,第二张图看起来应该比第一张更“网络化”:
- 更少业务说明。
- 更强调 VNet / VPC boundary。
- 更强调 ingress / gateway / firewall。
- 更强调公网和私网分层。
- 更强调跨网络访问不是默认互通,而是通过受控入口连接。
## 11. 结论
这两张图合起来已经把系统最关键的几件事表达清楚了:
- APP 的统一主入口是 `App Backend`
- F6 API 由主后台统一接入。
- 历史 Mini 后台独立保留在自己的 VPC / 网络域中,但应逐步收敛到主后台聚合。
- 各域通过公网入口区、私有服务区和访问控制层进行隔离。
因此,`Network Architecture` 本质上是一张“面向架构评审的网络边界与访问链路图”,重点在于:
- 说明系统边界。
- 说明主访问链路。
- 说明供应商接入方式。
- 说明历史系统兼容策略。
- 说明为什么要把 APP 主后台定义为统一编排中心。
`Network Topology` 则是一张“面向网络、安全和集成理解的拓扑图”,重点在于:
- 说明公网入口。
- 说明 VNet / VPC 边界。
- 说明私有服务区不直接暴露公网。
- 说明跨网络边界访问必须通过受控网关。
- 说明 legacy direct access 只是兼容例外,不是目标态。
@@ -0,0 +1,807 @@
<mxfile host="Electron" agent="Codex" compressed="false" pages="3">
<diagram id="system-overview" name="System Overview">
<mxGraphModel dx="2513" dy="1405" grid="1" gridSize="8" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="2384" pageHeight="1504" background="#FFFFFF" math="1" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="100" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=32;fontStyle=1;fontColor=#0f172a;" value="Continental Retail APP System Overview" vertex="1">
<mxGeometry height="40" width="760" x="80" y="36" as="geometry" />
</mxCell>
<mxCell id="101" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=16;fontColor=#475569;" value="Capability ownership view: the app uses one main backend domain, while Mini backends and F6 stay independent." vertex="1">
<mxGeometry height="24" width="980" x="80" y="80" as="geometry" />
</mxCell>
<mxCell id="102" parent="1" style="rounded=1;arcSize=12;html=1;whiteSpace=wrap;fillColor=#f8fafc;strokeColor=#cbd5e1;strokeWidth=1.2;" value="" vertex="1">
<mxGeometry height="1248" width="2256" x="64" y="128" as="geometry" />
</mxCell>
<mxCell id="103" parent="1" style="rounded=1;arcSize=12;html=1;whiteSpace=wrap;fillColor=#e0f2fe;strokeColor=#7dd3fc;strokeWidth=1.5;" value="" vertex="1">
<mxGeometry height="928" width="416" x="112" y="184" as="geometry" />
</mxCell>
<mxCell id="104" parent="1" style="rounded=1;arcSize=12;html=1;whiteSpace=wrap;fillColor=#dbeafe;strokeColor=#2563eb;strokeWidth=1.5;" value="" vertex="1">
<mxGeometry height="928" width="520" x="560" y="184" as="geometry" />
</mxCell>
<mxCell id="105" parent="1" style="rounded=1;arcSize=12;html=1;whiteSpace=wrap;fillColor=#dcfce7;strokeColor=#22c55e;strokeWidth=1.5;" value="" vertex="1">
<mxGeometry height="928" width="520" x="1112" y="184" as="geometry" />
</mxCell>
<mxCell id="106" parent="1" style="rounded=1;arcSize=12;html=1;whiteSpace=wrap;fillColor=#ffedd5;strokeColor=#f97316;strokeWidth=1.5;" value="" vertex="1">
<mxGeometry height="928" width="608" x="1664" y="184" as="geometry" />
</mxCell>
<mxCell id="107" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;fontSize=26;fontStyle=1;fontColor=#0f172a;" value="Mobile App" vertex="1">
<mxGeometry height="28" width="192" x="224" y="206" as="geometry" />
</mxCell>
<mxCell id="108" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;fontSize=28;fontStyle=1;fontColor=#1d4ed8;" value="App Backend" vertex="1">
<mxGeometry height="28" width="176" x="732" y="206" as="geometry" />
</mxCell>
<mxCell id="109" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;fontSize=24;fontStyle=1;fontColor=#15803d;" value="Mini Program Backend Domain" vertex="1">
<mxGeometry height="28" width="360" x="1192" y="206" as="geometry" />
</mxCell>
<mxCell id="110" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;fontSize=26;fontStyle=1;fontColor=#c2410c;" value="F6 Supplier Domain" vertex="1">
<mxGeometry height="28" width="200" x="1868" y="206" as="geometry" />
</mxCell>
<mxCell id="111" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=18;fontStyle=1;fontColor=#0f172a;" value="App Shell and Entry" vertex="1">
<mxGeometry height="24" width="220" x="144" y="258" as="geometry" />
</mxCell>
<mxCell id="112" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=18;fontStyle=1;fontColor=#1d4ed8;" value="Context and Control" vertex="1">
<mxGeometry height="24" width="220" x="592" y="258" as="geometry" />
</mxCell>
<mxCell id="113" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=18;fontStyle=1;fontColor=#15803d;" value="Retained Business Systems" vertex="1">
<mxGeometry height="24" width="240" x="1144" y="258" as="geometry" />
</mxCell>
<mxCell id="114" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=18;fontStyle=1;fontColor=#c2410c;" value="Supplier Pages and APIs" vertex="1">
<mxGeometry height="24" width="240" x="1696" y="258" as="geometry" />
</mxCell>
<mxCell id="115" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#38bdf8;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Login / Agreement / App Shell&#xa;Single mobile entry for store users" vertex="1">
<mxGeometry height="96" width="352" x="144" y="296" as="geometry" />
</mxCell>
<mxCell id="116" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#38bdf8;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="WebView + JSBridge&#xa;Embedded WebView only for F6 pages" vertex="1">
<mxGeometry height="88" width="352" x="144" y="424" as="geometry" />
</mxCell>
<mxCell id="117" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#38bdf8;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Native Capabilities&#xa;Scan, camera, upload, Bluetooth, notifications" vertex="1">
<mxGeometry height="88" width="352" x="144" y="544" as="geometry" />
</mxCell>
<mxCell id="118" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#38bdf8;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Store-Aware Session Holder&#xa;Keeps current store and role locally" vertex="1">
<mxGeometry height="88" width="352" x="144" y="664" as="geometry" />
</mxCell>
<mxCell id="119" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#2563eb;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Auth and Token Center&#xa;Login, refresh, logout, identity trust" vertex="1">
<mxGeometry height="96" width="456" x="592" y="296" as="geometry" />
</mxCell>
<mxCell id="120" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#2563eb;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Store Context + Menu + Permission + Config&#xa;Owns current store, role scope, menu baseline" vertex="1">
<mxGeometry height="96" width="456" x="592" y="424" as="geometry" />
</mxCell>
<mxCell id="121" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#2563eb;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Workbench Aggregation&#xa;Builds home tiles, reminders, and summary views" vertex="1">
<mxGeometry height="88" width="456" x="592" y="552" as="geometry" />
</mxCell>
<mxCell id="122" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#2563eb;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Business Orchestration&#xa;Normalizes order, procurement, and workflow context" vertex="1">
<mxGeometry height="88" width="456" x="592" y="672" as="geometry" />
</mxCell>
<mxCell id="123" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#ea580c;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="WebView Ticket and Signing Entry&#xa;Prepares supplier session and trace context" vertex="1">
<mxGeometry height="88" width="456" x="592" y="792" as="geometry" />
</mxCell>
<mxCell id="124" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#22c55e;strokeWidth=1.5;fontSize=20;fontStyle=1;fontColor=#1e293b;" value="O2O" vertex="1">
<mxGeometry height="72" width="168" x="1160" y="316" as="geometry" />
</mxCell>
<mxCell id="125" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#22c55e;strokeWidth=1.5;fontSize=20;fontStyle=1;fontColor=#1e293b;" value="Warranty" vertex="1">
<mxGeometry height="72" width="168" x="1392" y="316" as="geometry" />
</mxCell>
<mxCell id="126" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#22c55e;strokeWidth=1.5;fontSize=20;fontStyle=1;fontColor=#1e293b;" value="马上下单" vertex="1">
<mxGeometry height="72" width="168" x="1160" y="420" as="geometry" />
</mxCell>
<mxCell id="127" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#22c55e;strokeWidth=1.5;fontSize=20;fontStyle=1;fontColor=#1e293b;" value="ROOS" vertex="1">
<mxGeometry height="72" width="168" x="1392" y="420" as="geometry" />
</mxCell>
<mxCell id="128" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#f0fdf4;strokeColor=#86efac;strokeWidth=1.4;fontSize=16;fontColor=#166534;" value="Retained source systems&#xa;Still own historical business data and workflows" vertex="1">
<mxGeometry height="96" width="400" x="1160" y="548" as="geometry" />
</mxCell>
<mxCell id="129" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#22c55e;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Representative examples&#xa;Home data, warranty lookup, order support, rebate data" vertex="1">
<mxGeometry height="88" width="400" x="1160" y="676" as="geometry" />
</mxCell>
<mxCell id="130" parent="1" style="shape=document;boundedLbl=1;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#f97316;strokeWidth=1.5;fontSize=20;fontStyle=1;fontColor=#1e293b;" value="F6 WebView Pages" vertex="1">
<mxGeometry height="88" width="224" x="1712" y="308" as="geometry" />
</mxCell>
<mxCell id="131" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#f97316;strokeWidth=1.5;fontSize=20;fontStyle=1;fontColor=#1e293b;" value="F6 Capability APIs" vertex="1">
<mxGeometry height="88" width="224" x="1984" y="308" as="geometry" />
</mxCell>
<mxCell id="132" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffedd5;strokeColor=#fdba74;strokeWidth=1.4;fontSize=16;fontColor=#9a3412;" value="Procurement / Promotion / ERP&#xa;Supplier-owned capabilities stay outside the main backend" vertex="1">
<mxGeometry height="96" width="496" x="1712" y="436" as="geometry" />
</mxCell>
<mxCell id="133" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#f97316;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="WebView examples&#xa;Sales, scan, settlement, inbound" vertex="1">
<mxGeometry height="88" width="224" x="1712" y="564" as="geometry" />
</mxCell>
<mxCell id="134" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#f97316;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="API examples&#xa;Procurement, activity, inventory sync" vertex="1">
<mxGeometry height="88" width="224" x="1984" y="564" as="geometry" />
</mxCell>
<mxCell id="135" parent="1" style="rounded=1;arcSize=12;html=1;whiteSpace=wrap;fillColor=#f8fafc;strokeColor=#cbd5e1;strokeWidth=1.2;" value="" vertex="1">
<mxGeometry height="184" width="2096" x="112" y="1144" as="geometry" />
</mxCell>
<mxCell id="136" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=20;fontStyle=1;fontColor=#334155;" value="External Services" vertex="1">
<mxGeometry height="24" width="180" x="144" y="1168" as="geometry" />
</mxCell>
<mxCell id="137" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=20;fontStyle=1;fontColor=#334155;" value="Governance Rules" vertex="1">
<mxGeometry height="24" width="180" x="1160" y="1168" as="geometry" />
</mxCell>
<mxCell id="138" parent="1" style="ellipse;shape=cloud;html=1;whiteSpace=wrap;fillColor=#dbeafe;strokeColor=#2563eb;strokeWidth=1.4;fontSize=16;fontColor=#1e293b;" value="SMS" vertex="1">
<mxGeometry height="72" width="176" x="152" y="1212" as="geometry" />
</mxCell>
<mxCell id="139" parent="1" style="ellipse;shape=cloud;html=1;whiteSpace=wrap;fillColor=#dbeafe;strokeColor=#2563eb;strokeWidth=1.4;fontSize=16;fontColor=#1e293b;" value="Marketing / CRM" vertex="1">
<mxGeometry height="72" width="224" x="368" y="1212" as="geometry" />
</mxCell>
<mxCell id="140" parent="1" style="ellipse;shape=cloud;html=1;whiteSpace=wrap;fillColor=#dbeafe;strokeColor=#2563eb;strokeWidth=1.4;fontSize=16;fontColor=#1e293b;" value="WeCom" vertex="1">
<mxGeometry height="72" width="176" x="632" y="1212" as="geometry" />
</mxCell>
<mxCell id="141" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#2563eb;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="App -&gt; App Backend is primary" vertex="1">
<mxGeometry height="72" width="224" x="1160" y="1212" as="geometry" />
</mxCell>
<mxCell id="142" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#f97316;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="App -&gt; F6 only in Embedded WebView" vertex="1">
<mxGeometry height="72" width="224" x="1416" y="1212" as="geometry" />
</mxCell>
<mxCell id="143" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#f97316;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="F6 APIs go through Adapter" vertex="1">
<mxGeometry height="72" width="224" x="1672" y="1212" as="geometry" />
</mxCell>
<mxCell id="144" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#dc2626;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Mini direct access is legacy-only" vertex="1">
<mxGeometry height="72" width="248" x="1928" y="1212" as="geometry" />
</mxCell>
<mxCell id="145" edge="1" parent="1" source="115" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#2563eb;strokeWidth=1;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="119" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="154" connectable="0" parent="145" style="edgeLabel;html=1;align=center;verticalAlign=middle;fontSize=13;fontColor=#1d4ed8;" value="primary route" vertex="1">
<mxGeometry relative="1" x="0.5" as="geometry">
<mxPoint y="-14" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="146" edge="1" parent="1" source="118" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#2563eb;strokeWidth=1;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="120" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="552" y="708" />
<mxPoint x="552" y="472" />
</Array>
<mxPoint x="528" y="691.0000000000002" as="sourcePoint" />
<mxPoint x="852" y="525" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="155" connectable="0" parent="146" style="edgeLabel;html=1;align=center;verticalAlign=middle;fontSize=13;fontColor=#1d4ed8;" value="primary route" vertex="1">
<mxGeometry relative="1" x="0.5" as="geometry">
<mxPoint y="-14" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="147" edge="1" parent="1" source="121" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#64748b;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="124" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="820" y="536" />
<mxPoint x="1352" y="536" />
<mxPoint x="1352" y="352" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="156" connectable="0" parent="147" style="edgeLabel;html=1;align=center;verticalAlign=middle;fontSize=13;fontColor=#64748b;" value="aggregated call" vertex="1">
<mxGeometry relative="1" x="0.5" as="geometry">
<mxPoint y="-14" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="148" edge="1" parent="1" source="121" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#64748b;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="125" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="820" y="536" />
<mxPoint x="1376" y="536" />
<mxPoint x="1376" y="352" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="149" edge="1" parent="1" source="122" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#64748b;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="126" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1120" y="716" />
<mxPoint x="1120" y="456" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="150" edge="1" parent="1" source="122" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#64748b;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="127" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1616" y="716" />
<mxPoint x="1616" y="456" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="151" edge="1" parent="1" source="123" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#ea580c;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="130" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="157" connectable="0" parent="151" style="edgeLabel;html=1;align=center;verticalAlign=middle;fontSize=13;fontColor=#ea580c;" value="embedded WebView" vertex="1">
<mxGeometry relative="1" x="0.5" as="geometry">
<mxPoint y="-14" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="152" edge="1" parent="1" source="122" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#c2410c;strokeWidth=1;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="131" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="820" y="784" />
<mxPoint x="2240" y="784" />
<mxPoint x="2240" y="352" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="158" connectable="0" parent="152" style="edgeLabel;html=1;align=center;verticalAlign=middle;fontSize=13;fontColor=#c2410c;" value="adapter call" vertex="1">
<mxGeometry relative="1" x="0.5" as="geometry">
<mxPoint y="-14" as="offset" />
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
<diagram id="system-architecture" name="System Architecture">
<mxGraphModel dx="2233" dy="1249" grid="1" gridSize="8" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="3700" pageHeight="1800" background="#FFFFFF" math="1" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="200" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=36;fontStyle=1;fontColor=#0f172a;" value="Continental Retail APP System Architecture" vertex="1">
<mxGeometry height="48" width="1100" x="96" y="40" as="geometry" />
</mxCell>
<mxCell id="201" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=18;fontColor=#475569;" value="Reference review page: layered architecture, route semantics, and domain boundaries for implementation and integration." vertex="1">
<mxGeometry height="28" width="1800" x="96" y="92" as="geometry" />
</mxCell>
<mxCell id="202" parent="1" style="rounded=1;arcSize=12;html=1;whiteSpace=wrap;fillColor=#f8fafc;strokeColor=#e2e8f0;strokeWidth=1;" value="" vertex="1">
<mxGeometry height="560" width="560" x="96" y="160" as="geometry" />
</mxCell>
<mxCell id="203" parent="1" style="rounded=1;arcSize=12;html=1;whiteSpace=wrap;fillColor=#f8fafc;strokeColor=#e2e8f0;strokeWidth=1;" value="" vertex="1">
<mxGeometry height="560" width="540" x="736" y="160" as="geometry" />
</mxCell>
<mxCell id="204" parent="1" style="rounded=1;arcSize=12;html=1;whiteSpace=wrap;fillColor=#f8fafc;strokeColor=#e2e8f0;strokeWidth=1;" value="" vertex="1">
<mxGeometry height="560" width="980" x="1356" y="160" as="geometry" />
</mxCell>
<mxCell id="205" parent="1" style="rounded=1;arcSize=12;html=1;whiteSpace=wrap;fillColor=#f8fafc;strokeColor=#e2e8f0;strokeWidth=1;" value="" vertex="1">
<mxGeometry height="560" width="440" x="2416" y="160" as="geometry" />
</mxCell>
<mxCell id="206" parent="1" style="rounded=1;arcSize=12;html=1;whiteSpace=wrap;fillColor=#f8fafc;strokeColor=#e2e8f0;strokeWidth=1;" value="" vertex="1">
<mxGeometry height="320" width="1212" x="1356" y="780" as="geometry" />
</mxCell>
<mxCell id="207" parent="1" style="rounded=1;arcSize=12;html=1;whiteSpace=wrap;fillColor=#f8fafc;strokeColor=#e2e8f0;strokeWidth=1;" value="" vertex="1">
<mxGeometry height="560" width="560" x="2936" y="160" as="geometry" />
</mxCell>
<mxCell id="208" parent="1" style="rounded=1;arcSize=12;html=1;whiteSpace=wrap;fillColor=#f8fafc;strokeColor=#e2e8f0;strokeWidth=1;" value="" vertex="1">
<mxGeometry height="360" width="560" x="2936" y="780" as="geometry" />
</mxCell>
<mxCell id="209" parent="1" style="rounded=1;arcSize=12;html=1;whiteSpace=wrap;fillColor=#f8fafc;strokeColor=#e2e8f0;strokeWidth=1;" value="" vertex="1">
<mxGeometry height="472" width="560" x="2936" y="1200" as="geometry" />
</mxCell>
<mxCell id="210" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=24;fontStyle=1;fontColor=#1e293b;" value="Client Tier" vertex="1">
<mxGeometry height="30" width="260" x="128" y="188" as="geometry" />
</mxCell>
<mxCell id="211" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=24;fontStyle=1;fontColor=#1e293b;" value="Access &amp; Security" vertex="1">
<mxGeometry height="30" width="260" x="768" y="188" as="geometry" />
</mxCell>
<mxCell id="212" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=24;fontStyle=1;fontColor=#1e293b;" value="App Backend" vertex="1">
<mxGeometry height="30" width="260" x="1388" y="188" as="geometry" />
</mxCell>
<mxCell id="213" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=24;fontStyle=1;fontColor=#1e293b;" value="Integration Layer" vertex="1">
<mxGeometry height="30" width="260" x="2448" y="188" as="geometry" />
</mxCell>
<mxCell id="214" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=24;fontStyle=1;fontColor=#1e293b;" value="Mini Program Backend" vertex="1">
<mxGeometry height="30" width="320" x="1388" y="808" as="geometry" />
</mxCell>
<mxCell id="215" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=24;fontStyle=1;fontColor=#1e293b;" value="F6 Supplier Domain" vertex="1">
<mxGeometry height="30" width="280" x="2968" y="188" as="geometry" />
</mxCell>
<mxCell id="216" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=24;fontStyle=1;fontColor=#1e293b;" value="External Services" vertex="1">
<mxGeometry height="30" width="260" x="2968" y="808" as="geometry" />
</mxCell>
<mxCell id="217" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=24;fontStyle=1;fontColor=#1e293b;" value="Cross-Cutting" vertex="1">
<mxGeometry height="30" width="260" x="2968" y="1228" as="geometry" />
</mxCell>
<mxCell id="218" parent="1" style="ellipse;html=1;whiteSpace=wrap;fillColor=#e0f2fe;strokeColor=#0284c7;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="Store User Persona" vertex="1">
<mxGeometry height="100" width="220" x="128" y="260" as="geometry" />
</mxCell>
<mxCell id="219" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#bfdbfe;strokeColor=#1d4ed8;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="Mobile App&lt;br&gt;Native entry" vertex="1">
<mxGeometry height="100" width="220" x="384" y="260" as="geometry" />
</mxCell>
<mxCell id="220" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#dbeafe;strokeColor=#2563eb;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="Native Capabilities&#xa;Scan / camera / upload / Bluetooth" vertex="1">
<mxGeometry height="100" width="220" x="128" y="460" as="geometry" />
</mxCell>
<mxCell id="221" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#fed7aa;strokeColor=#ea580c;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="WebView + JSBridge&#xa;Embedded WebView container" vertex="1">
<mxGeometry height="100" width="220" x="384" y="460" as="geometry" />
</mxCell>
<mxCell id="222" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#e0e7ff;strokeColor=#4338ca;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="API Gateway&#xa;HTTPS / TLS / routing" vertex="1">
<mxGeometry height="100" width="220" x="768" y="260" as="geometry" />
</mxCell>
<mxCell id="223" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#e0e7ff;strokeColor=#4338ca;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="JWT / Auth&#xa;Token issue and refresh" vertex="1">
<mxGeometry height="100" width="220" x="1024" y="260" as="geometry" />
</mxCell>
<mxCell id="224" parent="1" style="rhombus;html=1;whiteSpace=wrap;fillColor=#fef3c7;strokeColor=#d97706;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="WebView Allowlist&#xa;Supplier domain control" vertex="1">
<mxGeometry height="120" width="220" x="896" y="460" as="geometry" />
</mxCell>
<mxCell id="225" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#dbeafe;strokeColor=#2563eb;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="Identity &amp; Store Center&#xa;IAM, store, role, menu" vertex="1">
<mxGeometry height="110" width="260" x="1400" y="460" as="geometry" />
</mxCell>
<mxCell id="226" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#bfdbfe;strokeColor=#1d4ed8;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="BFF Orchestration&#xa;Unified response and normalization" vertex="1">
<mxGeometry height="110" width="260" x="1728" y="260" as="geometry" />
</mxCell>
<mxCell id="227" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#dbeafe;strokeColor=#2563eb;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="Workbench Aggregation" vertex="1">
<mxGeometry height="110" width="260" x="1728" y="460" as="geometry" />
</mxCell>
<mxCell id="228" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#fed7aa;strokeColor=#ea580c;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="WebView Ticket Center&#xa;Signed entry and trace handoff" vertex="1">
<mxGeometry height="110" width="260" x="2056" y="460" as="geometry" />
</mxCell>
<mxCell id="229" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#fdba74;strokeColor=#c2410c;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="F6 Integration Adapter&lt;br&gt;Ticket exchange" vertex="1">
<mxGeometry height="110" width="260" x="2460" y="260" as="geometry" />
</mxCell>
<mxCell id="230" parent="1" style="shape=parallelogram;perimeter=parallelogramPerimeter;fixedSize=1;html=1;whiteSpace=wrap;fillColor=#fed7aa;strokeColor=#ea580c;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="Timeout / Retry" vertex="1">
<mxGeometry height="110" width="260" x="2460" y="480" as="geometry" />
</mxCell>
<mxCell id="231" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#d1fae5;strokeColor=#059669;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="O2O Backend" vertex="1">
<mxGeometry height="100" width="220" x="1400" y="900" as="geometry" />
</mxCell>
<mxCell id="232" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#d1fae5;strokeColor=#059669;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="Warranty Backend" vertex="1">
<mxGeometry height="100" width="220" x="1680" y="900" as="geometry" />
</mxCell>
<mxCell id="233" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#d1fae5;strokeColor=#059669;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="马上下单 Backend" vertex="1">
<mxGeometry height="100" width="220" x="1960" y="900" as="geometry" />
</mxCell>
<mxCell id="234" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#d1fae5;strokeColor=#059669;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="ROOS Backend" vertex="1">
<mxGeometry height="100" width="220" x="2240" y="900" as="geometry" />
</mxCell>
<mxCell id="235" parent="1" style="shape=document;boundedLbl=1;html=1;whiteSpace=wrap;fillColor=#fef3c7;strokeColor=#d97706;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="F6 WebView Pages&#xa;Sales, scan, settlement, inbound" vertex="1">
<mxGeometry height="110" width="220" x="2992" y="260" as="geometry" />
</mxCell>
<mxCell id="236" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#fef3c7;strokeColor=#d97706;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="F6 Capability APIs&#xa;Procurement / promotion / ERP" vertex="1">
<mxGeometry height="110" width="220" x="2992" y="480" as="geometry" />
</mxCell>
<mxCell id="237" parent="1" style="ellipse;shape=cloud;html=1;whiteSpace=wrap;fillColor=#dbeafe;strokeColor=#2563eb;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="SMS" vertex="1">
<mxGeometry height="100" width="180" x="2992" y="860" as="geometry" />
</mxCell>
<mxCell id="238" parent="1" style="ellipse;shape=cloud;html=1;whiteSpace=wrap;fillColor=#dbeafe;strokeColor=#2563eb;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="Marketing / CRM" vertex="1">
<mxGeometry height="100" width="220" x="3224" y="860" as="geometry" />
</mxCell>
<mxCell id="239" parent="1" style="ellipse;shape=cloud;html=1;whiteSpace=wrap;fillColor=#dbeafe;strokeColor=#2563eb;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="WeCom" vertex="1">
<mxGeometry height="100" width="180" x="2992" y="1000" as="geometry" />
</mxCell>
<mxCell id="240" parent="1" style="shape=document;boundedLbl=1;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#cbd5e1;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="Observability&#xa;Trace ID / logs / metrics" vertex="1">
<mxGeometry height="100" width="220" x="2992" y="1280" as="geometry" />
</mxCell>
<mxCell id="241" parent="1" style="shape=document;boundedLbl=1;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#cbd5e1;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="Audit / Security&#xa;Masking and evidence" vertex="1">
<mxGeometry height="100" width="220" x="2992" y="1410" as="geometry" />
</mxCell>
<mxCell id="242" parent="1" style="shape=document;boundedLbl=1;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#cbd5e1;strokeWidth=1.5;fontSize=18;fontColor=#1e293b;" value="Config Center&#xa;Menu, switches, WebView entry" vertex="1">
<mxGeometry height="100" width="220" x="2992" y="1540" as="geometry" />
</mxCell>
<mxCell id="243" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=18;fontStyle=1;fontColor=#0f172a;" value="Legend" vertex="1">
<mxGeometry height="28" width="140" x="96" y="1670" as="geometry" />
</mxCell>
<mxCell id="244" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=16;fontColor=#1f2937;" value="Primary App -&gt; App Backend route" vertex="1">
<mxGeometry height="26" width="420" x="200" y="1704" as="geometry" />
</mxCell>
<mxCell id="245" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=16;fontColor=#1f2937;" value="Embedded WebView or F6 exception path" vertex="1">
<mxGeometry height="26" width="420" x="200" y="1734" as="geometry" />
</mxCell>
<mxCell id="246" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=16;fontColor=#1f2937;" value="Aggregation or external calls" vertex="1">
<mxGeometry height="26" width="360" x="760" y="1704" as="geometry" />
</mxCell>
<mxCell id="247" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=16;fontColor=#1f2937;" value="Legacy compatibility only" vertex="1">
<mxGeometry height="26" width="360" x="760" y="1734" as="geometry" />
</mxCell>
<mxCell id="248a" parent="1" style="shape=line;html=1;strokeColor=#2563eb;strokeWidth=1.5;" value="" vertex="1">
<mxGeometry height="10" width="80" x="96" y="1712" as="geometry" />
</mxCell>
<mxCell id="248b" parent="1" style="shape=line;html=1;strokeColor=#ea580c;strokeWidth=1.5;dashed=1;dashPattern=6 4;" value="" vertex="1">
<mxGeometry height="10" width="80" x="96" y="1742" as="geometry" />
</mxCell>
<mxCell id="248c" parent="1" style="shape=line;html=1;strokeColor=#64748b;strokeWidth=1.5;dashed=1;dashPattern=6 4;" value="" vertex="1">
<mxGeometry height="10" width="80" x="650" y="1712" as="geometry" />
</mxCell>
<mxCell id="248d" parent="1" style="shape=line;html=1;strokeColor=#dc2626;strokeWidth=1.5;dashed=1;dashPattern=2 2;" value="" vertex="1">
<mxGeometry height="10" width="80" x="650" y="1742" as="geometry" />
</mxCell>
<mxCell id="248" edge="1" parent="1" source="218" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#94a3b8;strokeWidth=1;endArrow=diamond;endFill=1;jumpStyle=arc;jumpSize=8;" target="219" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="249" edge="1" parent="1" source="219" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;endArrow=diamond;endFill=1;jumpStyle=arc;jumpSize=8;" target="220" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="494" y="410" />
<mxPoint x="238" y="410" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="250" edge="1" parent="1" source="219" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;endArrow=diamond;endFill=1;jumpStyle=arc;jumpSize=8;" target="221" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="494" y="410" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="251" edge="1" parent="1" source="219" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#2563eb;strokeWidth=1;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="222" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="700" y="310" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="252" edge="1" parent="1" source="222" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;endArrow=diamond;endFill=1;jumpStyle=arc;jumpSize=8;" target="223" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="253" edge="1" parent="1" source="222" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#2563eb;strokeWidth=1;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="226" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="878" y="224" />
<mxPoint x="1320" y="224" />
<mxPoint x="1320" y="288" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="254" edge="1" parent="1" source="223" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#2563eb;strokeWidth=1;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="225" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1134" y="420" />
<mxPoint x="1530" y="420" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="255" edge="1" parent="1" source="225" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;endArrow=diamond;endFill=1;exitX=1;exitY=0.32;exitDx=0;exitDy=0;entryX=0;entryY=0.32;entryDx=0;entryDy=0;jumpStyle=arc;jumpSize=8;" target="226" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1695" y="515" />
<mxPoint x="1695" y="315" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="256" edge="1" parent="1" source="227" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;endArrow=diamond;endFill=1;exitX=0;exitY=0.68;exitDx=0;exitDy=0;entryX=0.381;entryY=1.028;entryDx=0;entryDy=0;jumpStyle=arc;jumpSize=8;entryPerimeter=0;" target="226" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1712" y="535" />
<mxPoint x="1712" y="420" />
<mxPoint x="1827" y="420" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="257" edge="1" parent="1" source="226" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;endArrow=diamond;endFill=1;exitX=1;exitY=0.32;exitDx=0;exitDy=0;entryX=0;entryY=0.32;entryDx=0;entryDy=0;jumpStyle=arc;jumpSize=8;" target="228" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="2020" y="315" />
<mxPoint x="2186" y="420" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="258" edge="1" parent="1" source="228" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#ea580c;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="221" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="2186" y="130" />
<mxPoint x="648" y="130" />
<mxPoint x="648" y="510" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="259" edge="1" parent="1" source="221" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#ea580c;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="224" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="700" y="520" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="260" edge="1" parent="1" source="224" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#ea580c;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="235" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1280" y="640" />
<mxPoint x="2860" y="640" />
<mxPoint x="2860" y="315" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="261" edge="1" parent="1" source="226" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#c2410c;strokeWidth=1;endArrow=block;endFill=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;jumpStyle=arc;jumpSize=8;" target="229" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="262" edge="1" parent="1" source="229" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;endArrow=diamond;endFill=1;jumpStyle=arc;jumpSize=8;" target="230" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="263" edge="1" parent="1" source="230" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#ea580c;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="236" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="2860" y="535" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="264" edge="1" parent="1" source="226" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;exitDx=0;exitDy=0;entryDx=0;entryDy=0;jumpStyle=arc;jumpSize=8;" target="231" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1320" y="315" />
<mxPoint x="1320" y="850" />
<mxPoint x="1510" y="850" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="265" edge="1" parent="1" source="226" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;exitDx=0;exitDy=0;entryDx=0;entryDy=0;jumpStyle=arc;jumpSize=8;" target="232" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1290" y="335" />
<mxPoint x="1290" y="870" />
<mxPoint x="1790" y="870" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="266" edge="1" parent="1" source="226" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;exitDx=0;exitDy=0;entryDx=0;entryDy=0;jumpStyle=arc;jumpSize=8;" target="233" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="2350" y="315" />
<mxPoint x="2350" y="850" />
<mxPoint x="2070" y="850" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="267" edge="1" parent="1" source="226" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;exitDx=0;exitDy=0;entryDx=0;entryDy=0;jumpStyle=arc;jumpSize=8;" target="234" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="2380" y="335" />
<mxPoint x="2380" y="870" />
<mxPoint x="2350" y="870" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="268" edge="1" parent="1" source="219" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#dc2626;strokeWidth=1;dashed=1;dashPattern=2 2;endArrow=open;endFill=0;jumpStyle=arc;jumpSize=8;" target="231" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="64" y="310" />
<mxPoint x="64" y="950" />
<mxPoint x="1400" y="950" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="269" edge="1" parent="1" source="223" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="237" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1134" y="112" />
<mxPoint x="2880" y="112" />
<mxPoint x="2880" y="910" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="270" edge="1" parent="1" source="226" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="238" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1858" y="120" />
<mxPoint x="2860" y="120" />
<mxPoint x="2860" y="976" />
<mxPoint x="3334" y="976" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="271" edge="1" parent="1" source="226" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1e293b;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="239" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1888" y="100" />
<mxPoint x="2890" y="100" />
<mxPoint x="2890" y="1050" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="272" edge="1" parent="1" source="226" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#94a3b8;strokeWidth=1;dashed=1;dashPattern=2 2;endArrow=open;endFill=0;exitDx=0;exitDy=0;entryDx=0;entryDy=0;jumpStyle=arc;jumpSize=8;" target="240" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1920" y="140" />
<mxPoint x="2860" y="140" />
<mxPoint x="2860" y="1330" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="273" edge="1" parent="1" source="225" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#94a3b8;strokeWidth=1;dashed=1;dashPattern=2 2;endArrow=open;endFill=0;exitDx=0;exitDy=0;entryDx=0;entryDy=0;jumpStyle=arc;jumpSize=8;" target="241" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1320" y="515" />
<mxPoint x="1320" y="1150" />
<mxPoint x="2860" y="1150" />
<mxPoint x="2860" y="1460" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="274" edge="1" parent="1" source="225" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#94a3b8;strokeWidth=1;dashed=1;dashPattern=2 2;endArrow=open;endFill=0;exitDx=0;exitDy=0;entryDx=0;entryDy=0;jumpStyle=arc;jumpSize=8;" target="242" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1300" y="535" />
<mxPoint x="1300" y="1180" />
<mxPoint x="2860" y="1180" />
<mxPoint x="2860" y="1590" />
</Array>
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
<diagram id="key-flows" name="Key Flows and Context Governance">
<mxGraphModel dx="1436" dy="803" grid="1" gridSize="8" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="2384" pageHeight="1504" background="#FFFFFF" math="1" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="300" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=32;fontStyle=1;fontColor=#0f172a;" value="Key Flows and Context Governance" vertex="1">
<mxGeometry height="40" width="720" x="80" y="36" as="geometry" />
</mxCell>
<mxCell id="301" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=16;fontColor=#475569;" value="Runtime behaviors map directly to the architecture page: primary backend route, F6 embedded exception, and legacy Mini compatibility." vertex="1">
<mxGeometry height="24" width="1180" x="80" y="80" as="geometry" />
</mxCell>
<mxCell id="302" parent="1" style="rounded=1;arcSize=12;html=1;whiteSpace=wrap;fillColor=#eff6ff;strokeColor=#93c5fd;strokeWidth=1.4;" value="" vertex="1">
<mxGeometry height="296" width="1088" x="80" y="144" as="geometry" />
</mxCell>
<mxCell id="303" parent="1" style="rounded=1;arcSize=12;html=1;whiteSpace=wrap;fillColor=#fff7ed;strokeColor=#fdba74;strokeWidth=1.4;" value="" vertex="1">
<mxGeometry height="296" width="1088" x="1216" y="144" as="geometry" />
</mxCell>
<mxCell id="304" parent="1" style="rounded=1;arcSize=12;html=1;whiteSpace=wrap;fillColor=#f8fafc;strokeColor=#cbd5e1;strokeWidth=1.4;" value="" vertex="1">
<mxGeometry height="344" width="1088" x="80" y="488" as="geometry" />
</mxCell>
<mxCell id="305" parent="1" style="rounded=1;arcSize=12;html=1;whiteSpace=wrap;fillColor=#fff7ed;strokeColor=#fdba74;strokeWidth=1.4;" value="" vertex="1">
<mxGeometry height="344" width="1088" x="1216" y="488" as="geometry" />
</mxCell>
<mxCell id="306" parent="1" style="rounded=1;arcSize=12;html=1;whiteSpace=wrap;fillColor=#f8fafc;strokeColor=#cbd5e1;strokeWidth=1.2;" value="" vertex="1">
<mxGeometry height="504" width="2224" x="96" y="880" as="geometry" />
</mxCell>
<mxCell id="307" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=24;fontStyle=1;fontColor=#1d4ed8;" value="Flow 1&#xa;Login and Store Context Bootstrap" vertex="1">
<mxGeometry height="52" width="360" x="112" y="168" as="geometry" />
</mxCell>
<mxCell id="308" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=24;fontStyle=1;fontColor=#c2410c;" value="Flow 2&#xa;F6 WebView Launch and Session Rules" vertex="1">
<mxGeometry height="52" width="360" x="1248" y="168" as="geometry" />
</mxCell>
<mxCell id="309" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=24;fontStyle=1;fontColor=#334155;" value="Flow 3&#xa;Home Aggregation and Mini Compatibility" vertex="1">
<mxGeometry height="52" width="420" x="112" y="512" as="geometry" />
</mxCell>
<mxCell id="310" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=24;fontStyle=1;fontColor=#c2410c;" value="Flow 4&#xa;Hybrid Procurement and Inbound Flow" vertex="1">
<mxGeometry height="52" width="420" x="1248" y="512" as="geometry" />
</mxCell>
<mxCell id="311" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#bfdbfe;strokeColor=#1d4ed8;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="App Login" vertex="1">
<mxGeometry height="72" width="168" x="136" y="252" as="geometry" />
</mxCell>
<mxCell id="312" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#dbeafe;strokeColor=#2563eb;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Token Issue" vertex="1">
<mxGeometry height="72" width="168" x="344" y="252" as="geometry" />
</mxCell>
<mxCell id="313" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#dbeafe;strokeColor=#2563eb;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Store List + Default Store" vertex="1">
<mxGeometry height="72" width="208" x="552" y="252" as="geometry" />
</mxCell>
<mxCell id="314" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#dbeafe;strokeColor=#2563eb;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Menu / Permission / Config Baseline" vertex="1">
<mxGeometry height="72" width="224" x="800" y="252" as="geometry" />
</mxCell>
<mxCell id="315" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#bfdbfe;strokeColor=#1d4ed8;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Context Established" vertex="1">
<mxGeometry height="64" width="888" x="136" y="360" as="geometry" />
</mxCell>
<mxCell id="316" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#bfdbfe;strokeColor=#1d4ed8;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="App asks for WebView entry" vertex="1">
<mxGeometry height="72" width="176" x="1248" y="252" as="geometry" />
</mxCell>
<mxCell id="317" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#fed7aa;strokeColor=#ea580c;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Backend exchanges / prepares ticket" vertex="1">
<mxGeometry height="72" width="208" x="1464" y="252" as="geometry" />
</mxCell>
<mxCell id="318" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#fef3c7;strokeColor=#d97706;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Embedded open in WebView" vertex="1">
<mxGeometry height="72" width="192" x="1712" y="252" as="geometry" />
</mxCell>
<mxCell id="319" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#ea580c;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Store switch invalidates WebView" vertex="1">
<mxGeometry height="52" width="176" x="1944" y="230" as="geometry" />
</mxCell>
<mxCell id="320" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#ea580c;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Expired ticket needs refresh" vertex="1">
<mxGeometry height="52" width="176" x="1944" y="294" as="geometry" />
</mxCell>
<mxCell id="321" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#94a3b8;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Failure fallback shows safe message + trace ID" vertex="1">
<mxGeometry height="52" width="280" x="1944" y="358" as="geometry" />
</mxCell>
<mxCell id="322" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#bfdbfe;strokeColor=#1d4ed8;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Workbench request" vertex="1">
<mxGeometry height="72" width="176" x="136" y="612" as="geometry" />
</mxCell>
<mxCell id="323" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#dbeafe;strokeColor=#2563eb;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Backend aggregates O2O / Warranty / ROOS / Config" vertex="1">
<mxGeometry height="72" width="336" x="352" y="612" as="geometry" />
</mxCell>
<mxCell id="324" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#64748b;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Partial failure returns degradable tiles" vertex="1">
<mxGeometry height="72" width="272" x="728" y="612" as="geometry" />
</mxCell>
<mxCell id="325" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#dc2626;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Legacy Mini direct access is compatibility only" vertex="1">
<mxGeometry height="72" width="864" x="128" y="728" as="geometry" />
</mxCell>
<mxCell id="326" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#dbeafe;strokeColor=#2563eb;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="ROOS context + permission + normalization" vertex="1">
<mxGeometry height="72" width="272" x="1248" y="612" as="geometry" />
</mxCell>
<mxCell id="327" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#fef3c7;strokeColor=#d97706;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="F6 owns procurement / promotion / ERP" vertex="1">
<mxGeometry height="72" width="256" x="1560" y="612" as="geometry" />
</mxCell>
<mxCell id="328" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#fed7aa;strokeColor=#ea580c;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Inbound execution uses WebView or API path" vertex="1">
<mxGeometry height="72" width="232" x="1856" y="612" as="geometry" />
</mxCell>
<mxCell id="329" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#64748b;strokeWidth=1.5;fontSize=16;fontColor=#1e293b;" value="Historical data may still come from Mini aggregation" vertex="1">
<mxGeometry height="72" width="840" x="1248" y="728" as="geometry" />
</mxCell>
<mxCell id="330" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=24;fontStyle=1;fontColor=#0f172a;" value="Shared Governance Rules" vertex="1">
<mxGeometry height="28" width="320" x="112" y="912" as="geometry" />
</mxCell>
<mxCell id="331" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#2563eb;strokeWidth=1.5;fontSize=20;fontColor=#1e293b;spacing=14;" value="Store context is owned by App Backend and every app request carries the current store scope." vertex="1">
<mxGeometry height="112" width="512" x="112" y="968" as="geometry" />
</mxCell>
<mxCell id="332" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#ea580c;strokeWidth=1.5;fontSize=20;fontColor=#1e293b;spacing=14;" value="F6 WebView is an embedded exception, not a replacement for the primary App -&gt; App Backend route." vertex="1">
<mxGeometry height="112" width="512" x="664" y="968" as="geometry" />
</mxCell>
<mxCell id="333" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#22c55e;strokeWidth=1.5;fontSize=20;fontColor=#1e293b;spacing=14;" value="Mini systems remain independent and can be source-of-truth, but the app should consume them through aggregation whenever possible." vertex="1">
<mxGeometry height="112" width="552" x="1216" y="968" as="geometry" />
</mxCell>
<mxCell id="334" parent="1" style="rounded=1;arcSize=20;html=1;whiteSpace=wrap;fillColor=#ffffff;strokeColor=#94a3b8;strokeWidth=1.5;fontSize=20;fontColor=#1e293b;spacing=14;" value="Every degraded or supplier-facing failure returns a user-safe message and a trace ID for support and audit." vertex="1">
<mxGeometry height="112" width="512" x="1800" y="968" as="geometry" />
</mxCell>
<mxCell id="335" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=26;fontStyle=1;fontColor=#0f172a;" value="Route Semantics" vertex="1">
<mxGeometry height="32" width="260" x="112" y="1124" as="geometry" />
</mxCell>
<mxCell id="336a" parent="1" style="shape=line;html=1;strokeColor=#2563eb;strokeWidth=1.5;" value="" vertex="1">
<mxGeometry height="10" width="84" x="136" y="1180" as="geometry" />
</mxCell>
<mxCell id="336" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=18;fontColor=#1f2937;" value="Primary App route" vertex="1">
<mxGeometry height="28" width="220" x="236" y="1170" as="geometry" />
</mxCell>
<mxCell id="337a" parent="1" style="shape=line;html=1;strokeColor=#ea580c;strokeWidth=1.5;dashed=1;dashPattern=6 4;" value="" vertex="1">
<mxGeometry height="10" width="84" x="496" y="1180" as="geometry" />
</mxCell>
<mxCell id="337" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=18;fontColor=#1f2937;" value="F6 embedded / exception" vertex="1">
<mxGeometry height="28" width="300" x="596" y="1170" as="geometry" />
</mxCell>
<mxCell id="338a" parent="1" style="shape=line;html=1;strokeColor=#64748b;strokeWidth=1.5;dashed=1;dashPattern=6 4;" value="" vertex="1">
<mxGeometry height="10" width="84" x="936" y="1180" as="geometry" />
</mxCell>
<mxCell id="338" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=18;fontColor=#1f2937;" value="Aggregation / external" vertex="1">
<mxGeometry height="28" width="280" x="1036" y="1170" as="geometry" />
</mxCell>
<mxCell id="339a" parent="1" style="shape=line;html=1;strokeColor=#dc2626;strokeWidth=1.5;dashed=1;dashPattern=2 2;" value="" vertex="1">
<mxGeometry height="10" width="84" x="1376" y="1180" as="geometry" />
</mxCell>
<mxCell id="339" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=18;fontColor=#1f2937;" value="Legacy compatibility" vertex="1">
<mxGeometry height="28" width="260" x="1476" y="1170" as="geometry" />
</mxCell>
<mxCell id="340" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=26;fontStyle=1;fontColor=#0f172a;" value="Review checks" vertex="1">
<mxGeometry height="32" width="240" x="112" y="1244" as="geometry" />
</mxCell>
<mxCell id="341" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=20;fontColor=#334155;" value="1. Store switch closes active supplier WebView session." vertex="1">
<mxGeometry height="30" width="720" x="136" y="1296" as="geometry" />
</mxCell>
<mxCell id="342" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=20;fontColor=#334155;" value="2. Home page degrades by tile, not by blank screen." vertex="1">
<mxGeometry height="30" width="720" x="136" y="1338" as="geometry" />
</mxCell>
<mxCell id="343" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=20;fontColor=#334155;" value="3. Procurement and inbound remain hybrid with F6-first supplier ownership." vertex="1">
<mxGeometry height="30" width="960" x="936" y="1296" as="geometry" />
</mxCell>
<mxCell id="344" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontSize=20;fontColor=#334155;" value="4. Mini direct links are transitional and not the default route." vertex="1">
<mxGeometry height="30" width="960" x="936" y="1338" as="geometry" />
</mxCell>
<mxCell id="345" edge="1" parent="1" source="311" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#2563eb;strokeWidth=1;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="312" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="346" edge="1" parent="1" source="312" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#2563eb;strokeWidth=1;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="313" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="347" edge="1" parent="1" source="313" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#2563eb;strokeWidth=1;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="314" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="348" edge="1" parent="1" source="314" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#2563eb;strokeWidth=1;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="315" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="912" y="336" />
<mxPoint x="568" y="336" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="349" edge="1" parent="1" source="316" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#2563eb;strokeWidth=1;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="317" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="350" edge="1" parent="1" source="317" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#ea580c;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="318" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="351" edge="1" parent="1" source="318" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#64748b;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="321" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="352" edge="1" parent="1" source="322" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1d4ed8;strokeWidth=1;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="323" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="353" edge="1" parent="1" source="323" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#64748b;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="324" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="354" edge="1" parent="1" source="323" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#dc2626;strokeWidth=1;dashed=1;dashPattern=2 2;endArrow=open;endFill=0;jumpStyle=arc;jumpSize=8;" target="325" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="520" y="696" />
<mxPoint x="568" y="696" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="355" edge="1" parent="1" source="326" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#1d4ed8;strokeWidth=1;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="327" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="356" edge="1" parent="1" source="327" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#ea580c;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="328" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="357" edge="1" parent="1" source="326" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#64748b;strokeWidth=1;dashed=1;dashPattern=6 4;endArrow=block;endFill=1;jumpStyle=arc;jumpSize=8;" target="329" value="">
<mxGeometry relative="1" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>
@@ -0,0 +1,640 @@
# 零售商系统方案研讨会PPT.retro
## Slide 1
### 零售商系统方案研讨会(复盘)
- 6/12
- China
## Slide 2
### 零售流程
[No extractable text]
## Slide 3
### 首页功能简介
- 登录
门店切换(针对总分店)
维护员工信息(App Web 同步)
店长
前台客服
收银
维修技师
美容技师
市场专员
维护门店基本信息
- 基本功能
## Slide 4
### 首页功能简介
- 登录
门店切换(针对总分店)
维护员工信息(App Web 同步)
店长
前台客服
收银
维修技师
美容技师
市场专员
维护门店基本信息
- 基本功能
## Slide 5
### 销售流程 – 准备(任务提醒)
- 报价开单
- 施工查车
- 结算
- 提醒
- 售后
- 待办事项:
O2O订单接单提醒
CDMS采购单支付提醒
延保视频上传提醒
问卷提醒
过期门店信息更新提醒
消息公告(站内信/促销)
产品库存预警
- 客户查询
- 准备
## Slide 6
### 销售流程 客户查询
- 首页扫车牌入口
OCR(文本识别)功能
显示车牌历史交易记录,包含:
历史工单(数据ERP提供)
展示历史工单内容
新建工单
延保历史记录
延保注册
- 销售商机
- 报价开单
- 施工查车
- 结算
- 提醒
- 售后
- 客户查询
- 准备
## Slide 7
### 销售流程 客户查询
- 销售商机
服务提醒
意向池
- 施工查车
- 结算
- 提醒
- 售后
- 准备
- 报价开单
- 客户查询
## Slide 8
### 销售流程 报价开工单
- 提醒
- 售后
- 准备
- 施工查车
- 结算
- 报价开单
- 客户查询
- 完善VIN码及车主信息
- 维护车辆信息
VIN码匹配车型
## Slide 9
### 销售流程 施工查车
- 提醒
- 售后
- 准备
- 施工查车
- 结算
- 报价开单
- 客户查询
- 检测开单
- 选择检测项目
- 查车
选择查车检测模板
## Slide 10
### 销售流程 施工查车
- 提醒
- 售后
- 准备
- 施工查车
- 结算
- 报价开单
- 客户查询
- 异常项拍照,正常项批量通过
- 检测项目
- 记录查车异常结果
批量更新查车正常结果
## Slide 11
### 销售流程 施工查车
- 提醒
- 售后
- 准备
- 施工查车
- 结算
- 报价开单
- 客户查询
- 生成检测报告发送车主
- 微信/企业微信/公众号/短信
- 查车报告发送车主
SMS短信
微信
## Slide 12
### 销售流程 施工查车
- 提醒
- 售后
- 准备
- 施工查车
- 结算
- 报价开单
- 客户查询
- 检测单转工单/商机
- 查车结果转工单
查车结果转商机
## Slide 13
### 销售流程 施工查车
- 提醒
- 售后
- 准备
- 施工查车
- 结算
- 报价开单
- 客户查询
- 转工单
- 完工
- 查车结果转工单
叉车结果转商机
## Slide 14
### 销售流程 结算
- 添加其它项目
结算收款
- 报价开单
- 施工查车
- 结算
- 提醒
- 售后
- 客户查询
- 准备
## Slide 15
### 销售流程 结算
- 当前延保流程
- 报价开单
- 施工查车
- 结算
- 提醒
- 售后
- 客户查询
- 准备
## Slide 16
### 销售流程 提醒
- 1
- 设置提醒规则
- 2
- 生成提醒单
- 3
- 跟进提醒单
- 设置提醒规则
生成提醒单
跟进提醒单
- 报价开单
- 施工查车
- 结算
- 提醒
- 售后
- 客户查询
- 准备
## Slide 17
### 销售流程 提醒
- 1
- 设置提醒规则
- 2
- 生成提醒单
- 3
- 跟进提醒单
- 设置提醒规则
生成提醒单
跟进提醒单
- 报价开单
- 施工查车
- 结算
- 提醒
- 售后
- 客户查询
- 准备
## Slide 18
### 销售流程 提醒
- 1
- 设置提醒规则
- 2
- 生成提醒单
- 3
- 跟进提醒单
- SA发券
SA电话跟进
SA主动发短信提醒
临近服务期系统自动发送短信提醒
- 设置提醒规则
生成提醒单
跟进提醒单
- 报价开单
- 施工查车
- 结算
- 提醒
- 售后
- 客户查询
- 准备
## Slide 19
### 销售流程 提醒
- 报价开单
- 施工查车
- 结算
- 提醒
- 售后
- 客户查询
- 准备
- 消费者收到短信
## Slide 20
### 销售流程 售后
- 质量理赔
延保理赔
- 报价开单
- 施工查车
- 结算
- 提醒
- 售后
- 客户查询
- 准备
- 销售商机
## Slide 21
### 请分组讨论 有哪些功能,与门店期望有差异? 有哪些重要的功能,但没有提及? 其他建议和意见?
[No extractable text]
## Slide 22
### 采购流程(线上采购马牌轮胎/非轮产品) – 触发采购/产品查询
- 触发采购
- 产品查询
- 添加购物车
- 结算
- 收货
- Feature demo:
进入采购首页,选择/搜索产品
先选择品类(轮胎,机油
,雨刮)
再选择品牌(马牌,维京)
直接搜索产品
加入购物车
- 其它
## Slide 23
### 采购流程(线上采购马牌轮胎/非轮产品) – 购物车
- 触发采购
- 产品查询
- 添加购物车
- 结算
- 收货
- 其它
## Slide 24
### 采购流程(线上采购马牌轮胎/非轮产品) – 结算
- 触发采购
- 产品查询
- 添加购物车
- 结算
- 收货
- 其它
- 提交订单后同步ERP的采购模块
## Slide 25
### 采购流程(线上采购马牌轮胎/非轮产品) – 收货
- 触发采购
- 产品查询
- 添加购物车
- 结算
- 收货
- 扫码入库(条码和门店的关系绑定)
- 其它
## Slide 26
### 采购流程(线上采购马牌轮胎/非轮产品) – 其它
- 触发采购
- 产品查询
- 添加购物车
- 结算
- 收货
- 采购订单列表
采购订单详情
- 其它
## Slide 27
### 采购流程(线下)
- 安全库存设置
方式一:此模式将根据您设置的【日均销量】及【备货天数上、下限】自动计算出安全库存上、下限【设置成功后材料的安全库存将会进行每日动态更新】
方式二:按固定值,安全库存上限/下限
- 支持表格导入
- 缺货提醒
- 转采购单
- 快速采购
- 一键入库
## Slide 28
### 采购流程(线下)
- 根据安全库存下限采购入库
- 手动选择批量采购入库
- 供应商销售单拍照识别入库
- EXCEL批量导入入库
- 缺货提醒
- 转采购单
- 快速采购
- 一键入库
## Slide 29
### 采购流程(线下)
- 缺货提醒
- 转采购单
- 快速采购
- 一键入库
- 马牌一键入库
## Slide 30
### 请分组讨论
[No extractable text]
## Slide 31
### 库存管理亮点
- 快速库存调整
- 安全库存
- 定期盘点
全盘点
品类盘点
动销盘点
自定义盘点
临时盘点
## Slide 32
### 库存管理亮点
- 快速库存调整
- 安全库存
- 定期盘点
全盘点
品类盘点
动销盘点
自定义盘点
临时盘点
## Slide 33
### 库存管理亮点
- 快速库存调整
- 安全库存
- 定期盘点
全盘点
品类盘点
动销盘点
自定义盘点
临时盘点
## Slide 34
### 库存管理亮点
- DOT管理
- 安全库存
- 安全库存设置
方式一:此模式将根据您设置的【日均销量】及【备货天数上、下限】自动计算出安全库存上、下限【设置成功后材料的安全库存将会进行每日动态更新】
方式二:按固定值,安全库存上限/下限
- 支持表格导入
## Slide 35
### 库存管理亮点
- DOT管理
- 安全库存
- 缺货提醒—一键跳转采购页面
- 滞销库存提醒—一键跳转退货页面
## Slide 36
### 请分组讨论
[No extractable text]
## Slide 37
### CRM客户管理
- 创建营销任务
- 选择发送用户
- 设置发送内容
## Slide 38
### CRM客户管理
- 创建营销任务
- 选择发送用户
- 设置发送内容
## Slide 39
### CRM客户管理
- 创建营销任务
- 选择发送用户
- 设置发送内容
## Slide 40
### CRM客户管理
- 创建营销任务
- 选择发送用户
- 设置发送内容
## Slide 41
### 请分组讨论
[No extractable text]
## Slide 42
### 员工绩效
- 设置业绩规则
- 业绩规则列表
- 业绩明细列表
- 计件业绩:按完成具体工作量来计算业绩提成,结清后实时产生;
阶梯业绩:按配置金额范围来判断所属阶梯,直接使用阶梯上的规则计算提成,按自然月生成,每天凌晨1点更新;
叠加业绩:使用不同阶梯上对应提成比例,将多个阶梯的提成累加,按自然月生成,每天凌晨1点更新;
## Slide 43
### 员工绩效
- 设置业绩规则
- 业绩规则列表
- 业绩明细列表
## Slide 44
### 员工绩效
- 设置业绩规则
- 业绩规则列表
- 业绩明细列表
## Slide 45
### 员工绩效
- 对应员工姓名
对应工单号
对应提成金额
- 设置业绩规则
- 业绩规则列表
- 业绩明细列表
## Slide 46
### 请分组讨论
[No extractable text]
## Slide 47
### 报表和其它
- 报表
门店经营报表
马牌相关报表
公告与提醒
马牌公告(announcement for all retailers)
提醒(notification for specific retailers)
马牌相关的提醒
来自ERP的相关提醒(库存预警由ERP提供)
车型轮胎/非轮产品匹配查询
需要F6确认是否能够加入这次的workshop内容
## Slide 48
### 财务
- Feature demo:
财务看板
营业收入
营业支出
其他收支
预收处理
定金管理
预付管理
应收账款
应付账款
开票管理
收支明细
企业钱包
- 财务看板
营业收入
营业支出
其他收支
预收处理
定金管理
预付管理
应收账款
应付账款
开票管理
收支明细
企业钱包
## Slide 49
### 请分组讨论
[No extractable text]
## Slide 50
### 其它建议
- 接入店内摄像头,实现信息自动录入及客户提醒
探讨门店自有系统与 APP 的融合方案。
不同类型门店是否能兼容一套系统体系。
销售相关数据是否能对马牌开放(权限问题)。