feat: finalize no-iframe portal shell route-view migration
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"generated_at": "2026-02-11T07:44:03+00:00",
|
||||
"source": "frontend API contracts observed in report modules",
|
||||
"apis": {
|
||||
"/api/wip/overview/summary": {
|
||||
"required_keys": [
|
||||
"dataUpdateDate",
|
||||
"runLots",
|
||||
"queueLots",
|
||||
"holdLots"
|
||||
],
|
||||
"notes": "WIP summary cards"
|
||||
},
|
||||
"/api/wip/overview/matrix": {
|
||||
"required_keys": [
|
||||
"workcenters",
|
||||
"packages",
|
||||
"matrix",
|
||||
"workcenter_totals"
|
||||
],
|
||||
"notes": "WIP matrix table"
|
||||
},
|
||||
"/api/wip/hold-detail/summary": {
|
||||
"required_keys": [
|
||||
"workcenterCount",
|
||||
"packageCount",
|
||||
"lotCount"
|
||||
],
|
||||
"notes": "Hold detail KPI cards"
|
||||
},
|
||||
"/api/hold-overview/matrix": {
|
||||
"required_keys": [
|
||||
"rows",
|
||||
"totals"
|
||||
],
|
||||
"notes": "Hold overview matrix interaction"
|
||||
},
|
||||
"/api/hold-history/list": {
|
||||
"required_keys": [
|
||||
"rows",
|
||||
"summary"
|
||||
],
|
||||
"notes": "Hold history table and summary sync"
|
||||
},
|
||||
"/api/resource/status": {
|
||||
"required_keys": [
|
||||
"rows",
|
||||
"summary"
|
||||
],
|
||||
"notes": "Realtime resource status table"
|
||||
},
|
||||
"/api/resource/history/summary": {
|
||||
"required_keys": [
|
||||
"kpi",
|
||||
"trend",
|
||||
"heatmap",
|
||||
"workcenter_comparison"
|
||||
],
|
||||
"notes": "Resource history charts"
|
||||
},
|
||||
"/api/resource/history/detail": {
|
||||
"required_keys": [
|
||||
"data"
|
||||
],
|
||||
"notes": "Resource history detail table"
|
||||
},
|
||||
"/api/qc-gate/summary": {
|
||||
"required_keys": [
|
||||
"summary",
|
||||
"table",
|
||||
"pareto"
|
||||
],
|
||||
"notes": "QC-GATE chart/table linked view"
|
||||
},
|
||||
"/api/tmtt-defect/analysis": {
|
||||
"required_keys": [
|
||||
"kpi",
|
||||
"pareto",
|
||||
"trend",
|
||||
"detail"
|
||||
],
|
||||
"notes": "TMTT chart/table analysis payload"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"generated_at": "2026-02-11T07:44:03+00:00",
|
||||
"source": "data/page_status.json",
|
||||
"errors": []
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
{
|
||||
"generated_at": "2026-02-11T07:44:03+00:00",
|
||||
"source": "data/page_status.json",
|
||||
"admin": [
|
||||
{
|
||||
"id": "reports",
|
||||
"name": "即時報表",
|
||||
"order": 1,
|
||||
"admin_only": false,
|
||||
"pages": [
|
||||
{
|
||||
"route": "/wip-overview",
|
||||
"name": "WIP 即時概況",
|
||||
"status": "released",
|
||||
"order": 1
|
||||
},
|
||||
{
|
||||
"route": "/hold-overview",
|
||||
"name": "Hold 即時概況",
|
||||
"status": "dev",
|
||||
"order": 2
|
||||
},
|
||||
{
|
||||
"route": "/resource",
|
||||
"name": "設備即時概況",
|
||||
"status": "released",
|
||||
"order": 4
|
||||
},
|
||||
{
|
||||
"route": "/qc-gate",
|
||||
"name": "QC-GATE 狀態",
|
||||
"status": "released",
|
||||
"order": 6
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "drawer-2",
|
||||
"name": "歷史報表",
|
||||
"order": 2,
|
||||
"admin_only": false,
|
||||
"pages": [
|
||||
{
|
||||
"route": "/hold-history",
|
||||
"name": "Hold 歷史績效",
|
||||
"status": "dev",
|
||||
"order": 3
|
||||
},
|
||||
{
|
||||
"route": "/resource-history",
|
||||
"name": "設備歷史績效",
|
||||
"status": "released",
|
||||
"order": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "drawer",
|
||||
"name": "查詢工具",
|
||||
"order": 3,
|
||||
"admin_only": false,
|
||||
"pages": [
|
||||
{
|
||||
"route": "/job-query",
|
||||
"name": "設備維修查詢",
|
||||
"status": "released",
|
||||
"order": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "dev-tools",
|
||||
"name": "開發工具",
|
||||
"order": 4,
|
||||
"admin_only": true,
|
||||
"pages": [
|
||||
{
|
||||
"route": "/tables",
|
||||
"name": "表格總覽",
|
||||
"status": "dev",
|
||||
"order": 1
|
||||
},
|
||||
{
|
||||
"route": "/admin/pages",
|
||||
"name": "頁面管理",
|
||||
"status": "dev",
|
||||
"order": 1
|
||||
},
|
||||
{
|
||||
"route": "/excel-query",
|
||||
"name": "Excel 批次查詢",
|
||||
"status": "dev",
|
||||
"order": 2
|
||||
},
|
||||
{
|
||||
"route": "/admin/performance",
|
||||
"name": "效能監控",
|
||||
"status": "dev",
|
||||
"order": 2
|
||||
},
|
||||
{
|
||||
"route": "/query-tool",
|
||||
"name": "批次追蹤工具",
|
||||
"status": "dev",
|
||||
"order": 4
|
||||
},
|
||||
{
|
||||
"route": "/tmtt-defect",
|
||||
"name": "TMTT印字腳型不良分析",
|
||||
"status": "released",
|
||||
"order": 5
|
||||
},
|
||||
{
|
||||
"route": "/mid-section-defect",
|
||||
"name": "中段製程不良追溯",
|
||||
"status": "dev",
|
||||
"order": 6
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"non_admin": [
|
||||
{
|
||||
"id": "reports",
|
||||
"name": "即時報表",
|
||||
"order": 1,
|
||||
"admin_only": false,
|
||||
"pages": [
|
||||
{
|
||||
"route": "/wip-overview",
|
||||
"name": "WIP 即時概況",
|
||||
"status": "released",
|
||||
"order": 1
|
||||
},
|
||||
{
|
||||
"route": "/resource",
|
||||
"name": "設備即時概況",
|
||||
"status": "released",
|
||||
"order": 4
|
||||
},
|
||||
{
|
||||
"route": "/qc-gate",
|
||||
"name": "QC-GATE 狀態",
|
||||
"status": "released",
|
||||
"order": 6
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "drawer-2",
|
||||
"name": "歷史報表",
|
||||
"order": 2,
|
||||
"admin_only": false,
|
||||
"pages": [
|
||||
{
|
||||
"route": "/resource-history",
|
||||
"name": "設備歷史績效",
|
||||
"status": "released",
|
||||
"order": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "drawer",
|
||||
"name": "查詢工具",
|
||||
"order": 3,
|
||||
"admin_only": false,
|
||||
"pages": [
|
||||
{
|
||||
"route": "/job-query",
|
||||
"name": "設備維修查詢",
|
||||
"status": "released",
|
||||
"order": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,706 @@
|
||||
{
|
||||
"generated_at": "2026-02-11T07:44:03+00:00",
|
||||
"capture_scope": [
|
||||
"/wip-overview",
|
||||
"/wip-detail",
|
||||
"/hold-overview",
|
||||
"/hold-detail",
|
||||
"/hold-history",
|
||||
"/resource",
|
||||
"/resource-history",
|
||||
"/qc-gate",
|
||||
"/job-query",
|
||||
"/excel-query",
|
||||
"/query-tool",
|
||||
"/tmtt-defect"
|
||||
],
|
||||
"routes": {
|
||||
"/wip-overview": {
|
||||
"capture_method": "static_source_analysis",
|
||||
"source_dir": "frontend/src/wip-overview",
|
||||
"source_files": [
|
||||
"frontend/src/wip-overview/App.vue",
|
||||
"frontend/src/wip-overview/components/FilterPanel.vue",
|
||||
"frontend/src/wip-overview/components/MatrixTable.vue",
|
||||
"frontend/src/wip-overview/components/ParetoSection.vue",
|
||||
"frontend/src/wip-overview/components/StatusCards.vue",
|
||||
"frontend/src/wip-overview/components/SummaryCards.vue",
|
||||
"frontend/src/wip-overview/main.js"
|
||||
],
|
||||
"table": {
|
||||
"component_files": [
|
||||
"frontend/src/wip-overview/components/MatrixTable.vue",
|
||||
"frontend/src/wip-overview/components/ParetoSection.vue"
|
||||
],
|
||||
"has_sort_logic": false,
|
||||
"has_pagination": false,
|
||||
"sort_hint_files": [],
|
||||
"pagination_hint_files": []
|
||||
},
|
||||
"chart": {
|
||||
"component_files": [
|
||||
"frontend/src/wip-overview/components/ParetoSection.vue"
|
||||
],
|
||||
"has_legend_logic": true,
|
||||
"has_tooltip_logic": true,
|
||||
"legend_hint_files": [
|
||||
"frontend/src/wip-overview/components/ParetoSection.vue"
|
||||
],
|
||||
"tooltip_hint_files": [
|
||||
"frontend/src/wip-overview/components/ParetoSection.vue"
|
||||
]
|
||||
},
|
||||
"filter": {
|
||||
"required_query_keys": [
|
||||
"workorder",
|
||||
"lotid",
|
||||
"package",
|
||||
"type",
|
||||
"status"
|
||||
],
|
||||
"component_files": [
|
||||
"frontend/src/wip-overview/App.vue",
|
||||
"frontend/src/wip-overview/components/FilterPanel.vue",
|
||||
"frontend/src/wip-overview/components/StatusCards.vue"
|
||||
]
|
||||
},
|
||||
"matrix": {
|
||||
"component_files": [
|
||||
"frontend/src/wip-overview/App.vue",
|
||||
"frontend/src/wip-overview/components/MatrixTable.vue"
|
||||
],
|
||||
"has_matrix_interaction": true
|
||||
},
|
||||
"api_endpoints": [
|
||||
"/api/wip/overview/hold",
|
||||
"/api/wip/overview/matrix",
|
||||
"/api/wip/overview/summary"
|
||||
]
|
||||
},
|
||||
"/wip-detail": {
|
||||
"capture_method": "static_source_analysis",
|
||||
"source_dir": "frontend/src/wip-detail",
|
||||
"source_files": [
|
||||
"frontend/src/wip-detail/App.vue",
|
||||
"frontend/src/wip-detail/components/FilterPanel.vue",
|
||||
"frontend/src/wip-detail/components/LotDetailPanel.vue",
|
||||
"frontend/src/wip-detail/components/LotTable.vue",
|
||||
"frontend/src/wip-detail/components/SummaryCards.vue",
|
||||
"frontend/src/wip-detail/main.js"
|
||||
],
|
||||
"table": {
|
||||
"component_files": [
|
||||
"frontend/src/wip-detail/components/LotTable.vue"
|
||||
],
|
||||
"has_sort_logic": false,
|
||||
"has_pagination": true,
|
||||
"sort_hint_files": [],
|
||||
"pagination_hint_files": [
|
||||
"frontend/src/wip-detail/App.vue",
|
||||
"frontend/src/wip-detail/components/LotTable.vue"
|
||||
]
|
||||
},
|
||||
"chart": {
|
||||
"component_files": [],
|
||||
"has_legend_logic": false,
|
||||
"has_tooltip_logic": false,
|
||||
"legend_hint_files": [],
|
||||
"tooltip_hint_files": []
|
||||
},
|
||||
"filter": {
|
||||
"required_query_keys": [
|
||||
"workcenter",
|
||||
"workorder",
|
||||
"lotid",
|
||||
"package",
|
||||
"type",
|
||||
"status"
|
||||
],
|
||||
"component_files": [
|
||||
"frontend/src/wip-detail/App.vue",
|
||||
"frontend/src/wip-detail/components/FilterPanel.vue",
|
||||
"frontend/src/wip-detail/components/SummaryCards.vue"
|
||||
]
|
||||
},
|
||||
"matrix": {
|
||||
"component_files": [],
|
||||
"has_matrix_interaction": false
|
||||
},
|
||||
"api_endpoints": [
|
||||
"/api/wip/detail/",
|
||||
"/api/wip/lot/",
|
||||
"/api/wip/meta/workcenters"
|
||||
]
|
||||
},
|
||||
"/hold-overview": {
|
||||
"capture_method": "static_source_analysis",
|
||||
"source_dir": "frontend/src/hold-overview",
|
||||
"source_files": [
|
||||
"frontend/src/hold-overview/App.vue",
|
||||
"frontend/src/hold-overview/components/FilterBar.vue",
|
||||
"frontend/src/hold-overview/components/FilterIndicator.vue",
|
||||
"frontend/src/hold-overview/components/HoldMatrix.vue",
|
||||
"frontend/src/hold-overview/components/HoldTreeMap.vue",
|
||||
"frontend/src/hold-overview/components/LotTable.vue",
|
||||
"frontend/src/hold-overview/main.js"
|
||||
],
|
||||
"table": {
|
||||
"component_files": [
|
||||
"frontend/src/hold-overview/components/HoldMatrix.vue",
|
||||
"frontend/src/hold-overview/components/LotTable.vue"
|
||||
],
|
||||
"has_sort_logic": true,
|
||||
"has_pagination": true,
|
||||
"sort_hint_files": [
|
||||
"frontend/src/hold-overview/App.vue",
|
||||
"frontend/src/hold-overview/components/HoldTreeMap.vue"
|
||||
],
|
||||
"pagination_hint_files": [
|
||||
"frontend/src/hold-overview/App.vue",
|
||||
"frontend/src/hold-overview/components/LotTable.vue"
|
||||
]
|
||||
},
|
||||
"chart": {
|
||||
"component_files": [
|
||||
"frontend/src/hold-overview/components/HoldTreeMap.vue"
|
||||
],
|
||||
"has_legend_logic": true,
|
||||
"has_tooltip_logic": true,
|
||||
"legend_hint_files": [
|
||||
"frontend/src/hold-overview/components/HoldTreeMap.vue"
|
||||
],
|
||||
"tooltip_hint_files": [
|
||||
"frontend/src/hold-overview/components/HoldTreeMap.vue"
|
||||
]
|
||||
},
|
||||
"filter": {
|
||||
"required_query_keys": [],
|
||||
"component_files": [
|
||||
"frontend/src/hold-overview/App.vue",
|
||||
"frontend/src/hold-overview/components/FilterBar.vue",
|
||||
"frontend/src/hold-overview/components/FilterIndicator.vue",
|
||||
"frontend/src/hold-overview/components/HoldMatrix.vue",
|
||||
"frontend/src/hold-overview/components/HoldTreeMap.vue",
|
||||
"frontend/src/hold-overview/components/LotTable.vue"
|
||||
]
|
||||
},
|
||||
"matrix": {
|
||||
"component_files": [
|
||||
"frontend/src/hold-overview/App.vue",
|
||||
"frontend/src/hold-overview/components/FilterIndicator.vue",
|
||||
"frontend/src/hold-overview/components/HoldMatrix.vue"
|
||||
],
|
||||
"has_matrix_interaction": true
|
||||
},
|
||||
"api_endpoints": [
|
||||
"/api/hold-overview/lots",
|
||||
"/api/hold-overview/matrix",
|
||||
"/api/hold-overview/summary"
|
||||
]
|
||||
},
|
||||
"/hold-detail": {
|
||||
"capture_method": "static_source_analysis",
|
||||
"source_dir": "frontend/src/hold-detail",
|
||||
"source_files": [
|
||||
"frontend/src/hold-detail/App.vue",
|
||||
"frontend/src/hold-detail/components/AgeDistribution.vue",
|
||||
"frontend/src/hold-detail/components/DistributionTable.vue",
|
||||
"frontend/src/hold-detail/components/LotTable.vue",
|
||||
"frontend/src/hold-detail/components/SummaryCards.vue",
|
||||
"frontend/src/hold-detail/main.js"
|
||||
],
|
||||
"table": {
|
||||
"component_files": [
|
||||
"frontend/src/hold-detail/components/DistributionTable.vue",
|
||||
"frontend/src/hold-detail/components/LotTable.vue"
|
||||
],
|
||||
"has_sort_logic": false,
|
||||
"has_pagination": true,
|
||||
"sort_hint_files": [],
|
||||
"pagination_hint_files": [
|
||||
"frontend/src/hold-detail/App.vue",
|
||||
"frontend/src/hold-detail/components/LotTable.vue"
|
||||
]
|
||||
},
|
||||
"chart": {
|
||||
"component_files": [],
|
||||
"has_legend_logic": false,
|
||||
"has_tooltip_logic": false,
|
||||
"legend_hint_files": [],
|
||||
"tooltip_hint_files": []
|
||||
},
|
||||
"filter": {
|
||||
"required_query_keys": [
|
||||
"reason"
|
||||
],
|
||||
"component_files": [
|
||||
"frontend/src/hold-detail/App.vue",
|
||||
"frontend/src/hold-detail/components/LotTable.vue"
|
||||
]
|
||||
},
|
||||
"matrix": {
|
||||
"component_files": [],
|
||||
"has_matrix_interaction": false
|
||||
},
|
||||
"api_endpoints": [
|
||||
"/api/wip/hold-detail/distribution",
|
||||
"/api/wip/hold-detail/lots",
|
||||
"/api/wip/hold-detail/summary"
|
||||
]
|
||||
},
|
||||
"/hold-history": {
|
||||
"capture_method": "static_source_analysis",
|
||||
"source_dir": "frontend/src/hold-history",
|
||||
"source_files": [
|
||||
"frontend/src/hold-history/App.vue",
|
||||
"frontend/src/hold-history/components/DailyTrend.vue",
|
||||
"frontend/src/hold-history/components/DetailTable.vue",
|
||||
"frontend/src/hold-history/components/DurationChart.vue",
|
||||
"frontend/src/hold-history/components/FilterBar.vue",
|
||||
"frontend/src/hold-history/components/FilterIndicator.vue",
|
||||
"frontend/src/hold-history/components/ReasonPareto.vue",
|
||||
"frontend/src/hold-history/components/RecordTypeFilter.vue",
|
||||
"frontend/src/hold-history/components/SummaryCards.vue",
|
||||
"frontend/src/hold-history/main.js"
|
||||
],
|
||||
"table": {
|
||||
"component_files": [
|
||||
"frontend/src/hold-history/components/DetailTable.vue"
|
||||
],
|
||||
"has_sort_logic": false,
|
||||
"has_pagination": true,
|
||||
"sort_hint_files": [],
|
||||
"pagination_hint_files": [
|
||||
"frontend/src/hold-history/App.vue",
|
||||
"frontend/src/hold-history/components/DetailTable.vue"
|
||||
]
|
||||
},
|
||||
"chart": {
|
||||
"component_files": [
|
||||
"frontend/src/hold-history/components/DailyTrend.vue",
|
||||
"frontend/src/hold-history/components/DurationChart.vue",
|
||||
"frontend/src/hold-history/components/ReasonPareto.vue"
|
||||
],
|
||||
"has_legend_logic": true,
|
||||
"has_tooltip_logic": true,
|
||||
"legend_hint_files": [
|
||||
"frontend/src/hold-history/components/DailyTrend.vue",
|
||||
"frontend/src/hold-history/components/ReasonPareto.vue"
|
||||
],
|
||||
"tooltip_hint_files": [
|
||||
"frontend/src/hold-history/components/DailyTrend.vue",
|
||||
"frontend/src/hold-history/components/DurationChart.vue",
|
||||
"frontend/src/hold-history/components/ReasonPareto.vue"
|
||||
]
|
||||
},
|
||||
"filter": {
|
||||
"required_query_keys": [],
|
||||
"component_files": [
|
||||
"frontend/src/hold-history/App.vue",
|
||||
"frontend/src/hold-history/components/FilterBar.vue",
|
||||
"frontend/src/hold-history/components/FilterIndicator.vue",
|
||||
"frontend/src/hold-history/components/RecordTypeFilter.vue"
|
||||
]
|
||||
},
|
||||
"matrix": {
|
||||
"component_files": [],
|
||||
"has_matrix_interaction": false
|
||||
},
|
||||
"api_endpoints": [
|
||||
"/api/hold-history/duration",
|
||||
"/api/hold-history/list",
|
||||
"/api/hold-history/reason-pareto",
|
||||
"/api/hold-history/trend"
|
||||
]
|
||||
},
|
||||
"/resource": {
|
||||
"capture_method": "static_source_analysis",
|
||||
"source_dir": "frontend/src/resource-status",
|
||||
"source_files": [
|
||||
"frontend/src/resource-status/App.vue",
|
||||
"frontend/src/resource-status/components/EquipmentCard.vue",
|
||||
"frontend/src/resource-status/components/EquipmentGrid.vue",
|
||||
"frontend/src/resource-status/components/FilterBar.vue",
|
||||
"frontend/src/resource-status/components/FloatingTooltip.vue",
|
||||
"frontend/src/resource-status/components/MatrixSection.vue",
|
||||
"frontend/src/resource-status/components/StatusHeader.vue",
|
||||
"frontend/src/resource-status/components/SummaryCards.vue",
|
||||
"frontend/src/resource-status/main.js"
|
||||
],
|
||||
"table": {
|
||||
"component_files": [],
|
||||
"has_sort_logic": true,
|
||||
"has_pagination": false,
|
||||
"sort_hint_files": [
|
||||
"frontend/src/resource-status/App.vue",
|
||||
"frontend/src/resource-status/components/MatrixSection.vue"
|
||||
],
|
||||
"pagination_hint_files": []
|
||||
},
|
||||
"chart": {
|
||||
"component_files": [],
|
||||
"has_legend_logic": false,
|
||||
"has_tooltip_logic": true,
|
||||
"legend_hint_files": [],
|
||||
"tooltip_hint_files": [
|
||||
"frontend/src/resource-status/App.vue",
|
||||
"frontend/src/resource-status/components/FloatingTooltip.vue"
|
||||
]
|
||||
},
|
||||
"filter": {
|
||||
"required_query_keys": [],
|
||||
"component_files": [
|
||||
"frontend/src/resource-status/App.vue",
|
||||
"frontend/src/resource-status/components/EquipmentGrid.vue",
|
||||
"frontend/src/resource-status/components/FilterBar.vue",
|
||||
"frontend/src/resource-status/components/MatrixSection.vue"
|
||||
]
|
||||
},
|
||||
"matrix": {
|
||||
"component_files": [
|
||||
"frontend/src/resource-status/App.vue",
|
||||
"frontend/src/resource-status/components/MatrixSection.vue",
|
||||
"frontend/src/resource-status/components/SummaryCards.vue"
|
||||
],
|
||||
"has_matrix_interaction": true
|
||||
},
|
||||
"api_endpoints": [
|
||||
"/api/resource/status",
|
||||
"/api/resource/status/options",
|
||||
"/api/resource/status/summary"
|
||||
]
|
||||
},
|
||||
"/resource-history": {
|
||||
"capture_method": "static_source_analysis",
|
||||
"source_dir": "frontend/src/resource-history",
|
||||
"source_files": [
|
||||
"frontend/src/resource-history/App.vue",
|
||||
"frontend/src/resource-history/components/ComparisonChart.vue",
|
||||
"frontend/src/resource-history/components/DetailSection.vue",
|
||||
"frontend/src/resource-history/components/FilterBar.vue",
|
||||
"frontend/src/resource-history/components/HeatmapChart.vue",
|
||||
"frontend/src/resource-history/components/KpiCards.vue",
|
||||
"frontend/src/resource-history/components/StackedChart.vue",
|
||||
"frontend/src/resource-history/components/TrendChart.vue",
|
||||
"frontend/src/resource-history/main.js"
|
||||
],
|
||||
"table": {
|
||||
"component_files": [],
|
||||
"has_sort_logic": true,
|
||||
"has_pagination": false,
|
||||
"sort_hint_files": [
|
||||
"frontend/src/resource-history/App.vue",
|
||||
"frontend/src/resource-history/components/ComparisonChart.vue",
|
||||
"frontend/src/resource-history/components/DetailSection.vue",
|
||||
"frontend/src/resource-history/components/HeatmapChart.vue"
|
||||
],
|
||||
"pagination_hint_files": []
|
||||
},
|
||||
"chart": {
|
||||
"component_files": [
|
||||
"frontend/src/resource-history/components/ComparisonChart.vue",
|
||||
"frontend/src/resource-history/components/HeatmapChart.vue",
|
||||
"frontend/src/resource-history/components/StackedChart.vue",
|
||||
"frontend/src/resource-history/components/TrendChart.vue"
|
||||
],
|
||||
"has_legend_logic": true,
|
||||
"has_tooltip_logic": true,
|
||||
"legend_hint_files": [
|
||||
"frontend/src/resource-history/components/StackedChart.vue",
|
||||
"frontend/src/resource-history/components/TrendChart.vue"
|
||||
],
|
||||
"tooltip_hint_files": [
|
||||
"frontend/src/resource-history/components/ComparisonChart.vue",
|
||||
"frontend/src/resource-history/components/HeatmapChart.vue",
|
||||
"frontend/src/resource-history/components/StackedChart.vue",
|
||||
"frontend/src/resource-history/components/TrendChart.vue"
|
||||
]
|
||||
},
|
||||
"filter": {
|
||||
"required_query_keys": [
|
||||
"start_date",
|
||||
"end_date",
|
||||
"granularity",
|
||||
"workcenter_groups",
|
||||
"families",
|
||||
"resource_ids",
|
||||
"is_production",
|
||||
"is_key",
|
||||
"is_monitor"
|
||||
],
|
||||
"component_files": [
|
||||
"frontend/src/resource-history/App.vue",
|
||||
"frontend/src/resource-history/components/FilterBar.vue"
|
||||
]
|
||||
},
|
||||
"matrix": {
|
||||
"component_files": [
|
||||
"frontend/src/resource-history/components/HeatmapChart.vue"
|
||||
],
|
||||
"has_matrix_interaction": true
|
||||
},
|
||||
"api_endpoints": [
|
||||
"/api/resource/history/detail",
|
||||
"/api/resource/history/export",
|
||||
"/api/resource/history/options",
|
||||
"/api/resource/history/summary"
|
||||
]
|
||||
},
|
||||
"/qc-gate": {
|
||||
"capture_method": "static_source_analysis",
|
||||
"source_dir": "frontend/src/qc-gate",
|
||||
"source_files": [
|
||||
"frontend/src/qc-gate/App.vue",
|
||||
"frontend/src/qc-gate/components/LotTable.vue",
|
||||
"frontend/src/qc-gate/components/QcGateChart.vue",
|
||||
"frontend/src/qc-gate/composables/useQcGateData.js",
|
||||
"frontend/src/qc-gate/main.js"
|
||||
],
|
||||
"table": {
|
||||
"component_files": [
|
||||
"frontend/src/qc-gate/components/LotTable.vue"
|
||||
],
|
||||
"has_sort_logic": true,
|
||||
"has_pagination": false,
|
||||
"sort_hint_files": [
|
||||
"frontend/src/qc-gate/components/LotTable.vue",
|
||||
"frontend/src/qc-gate/composables/useQcGateData.js"
|
||||
],
|
||||
"pagination_hint_files": []
|
||||
},
|
||||
"chart": {
|
||||
"component_files": [
|
||||
"frontend/src/qc-gate/App.vue",
|
||||
"frontend/src/qc-gate/components/QcGateChart.vue"
|
||||
],
|
||||
"has_legend_logic": true,
|
||||
"has_tooltip_logic": true,
|
||||
"legend_hint_files": [
|
||||
"frontend/src/qc-gate/components/QcGateChart.vue"
|
||||
],
|
||||
"tooltip_hint_files": [
|
||||
"frontend/src/qc-gate/components/QcGateChart.vue"
|
||||
]
|
||||
},
|
||||
"filter": {
|
||||
"required_query_keys": [],
|
||||
"component_files": [
|
||||
"frontend/src/qc-gate/App.vue",
|
||||
"frontend/src/qc-gate/components/LotTable.vue",
|
||||
"frontend/src/qc-gate/components/QcGateChart.vue",
|
||||
"frontend/src/qc-gate/composables/useQcGateData.js"
|
||||
]
|
||||
},
|
||||
"matrix": {
|
||||
"component_files": [],
|
||||
"has_matrix_interaction": false
|
||||
},
|
||||
"api_endpoints": [
|
||||
"/api/qc-gate/summary"
|
||||
]
|
||||
},
|
||||
"/job-query": {
|
||||
"capture_method": "static_source_analysis",
|
||||
"source_dir": "frontend/src/job-query",
|
||||
"source_files": [
|
||||
"frontend/src/job-query/App.vue",
|
||||
"frontend/src/job-query/composables/useJobQueryData.js",
|
||||
"frontend/src/job-query/main.js"
|
||||
],
|
||||
"table": {
|
||||
"component_files": [
|
||||
"frontend/src/job-query/App.vue",
|
||||
"frontend/src/job-query/main.js"
|
||||
],
|
||||
"has_sort_logic": true,
|
||||
"has_pagination": false,
|
||||
"sort_hint_files": [
|
||||
"frontend/src/job-query/main.js"
|
||||
],
|
||||
"pagination_hint_files": []
|
||||
},
|
||||
"chart": {
|
||||
"component_files": [],
|
||||
"has_legend_logic": false,
|
||||
"has_tooltip_logic": false,
|
||||
"legend_hint_files": [],
|
||||
"tooltip_hint_files": []
|
||||
},
|
||||
"filter": {
|
||||
"required_query_keys": [],
|
||||
"component_files": [
|
||||
"frontend/src/job-query/App.vue",
|
||||
"frontend/src/job-query/composables/useJobQueryData.js",
|
||||
"frontend/src/job-query/main.js"
|
||||
]
|
||||
},
|
||||
"matrix": {
|
||||
"component_files": [],
|
||||
"has_matrix_interaction": false
|
||||
},
|
||||
"api_endpoints": [
|
||||
"/api/job-query/export",
|
||||
"/api/job-query/jobs",
|
||||
"/api/job-query/resources",
|
||||
"/api/job-query/txn/"
|
||||
]
|
||||
},
|
||||
"/excel-query": {
|
||||
"capture_method": "static_source_analysis",
|
||||
"source_dir": "frontend/src/excel-query",
|
||||
"source_files": [
|
||||
"frontend/src/excel-query/App.vue",
|
||||
"frontend/src/excel-query/composables/useExcelQueryData.js",
|
||||
"frontend/src/excel-query/main.js"
|
||||
],
|
||||
"table": {
|
||||
"component_files": [
|
||||
"frontend/src/excel-query/App.vue",
|
||||
"frontend/src/excel-query/main.js"
|
||||
],
|
||||
"has_sort_logic": true,
|
||||
"has_pagination": false,
|
||||
"sort_hint_files": [
|
||||
"frontend/src/excel-query/main.js"
|
||||
],
|
||||
"pagination_hint_files": []
|
||||
},
|
||||
"chart": {
|
||||
"component_files": [],
|
||||
"has_legend_logic": false,
|
||||
"has_tooltip_logic": false,
|
||||
"legend_hint_files": [],
|
||||
"tooltip_hint_files": []
|
||||
},
|
||||
"filter": {
|
||||
"required_query_keys": [],
|
||||
"component_files": [
|
||||
"frontend/src/excel-query/App.vue",
|
||||
"frontend/src/excel-query/composables/useExcelQueryData.js",
|
||||
"frontend/src/excel-query/main.js"
|
||||
]
|
||||
},
|
||||
"matrix": {
|
||||
"component_files": [],
|
||||
"has_matrix_interaction": false
|
||||
},
|
||||
"api_endpoints": [
|
||||
"/api/excel-query/column-type",
|
||||
"/api/excel-query/column-values",
|
||||
"/api/excel-query/execute",
|
||||
"/api/excel-query/execute-advanced",
|
||||
"/api/excel-query/export-csv",
|
||||
"/api/excel-query/table-metadata",
|
||||
"/api/excel-query/tables",
|
||||
"/api/excel-query/upload"
|
||||
]
|
||||
},
|
||||
"/query-tool": {
|
||||
"capture_method": "static_source_analysis",
|
||||
"source_dir": "frontend/src/query-tool",
|
||||
"source_files": [
|
||||
"frontend/src/query-tool/App.vue",
|
||||
"frontend/src/query-tool/composables/useQueryToolData.js",
|
||||
"frontend/src/query-tool/main.js"
|
||||
],
|
||||
"table": {
|
||||
"component_files": [
|
||||
"frontend/src/query-tool/App.vue",
|
||||
"frontend/src/query-tool/main.js"
|
||||
],
|
||||
"has_sort_logic": true,
|
||||
"has_pagination": false,
|
||||
"sort_hint_files": [
|
||||
"frontend/src/query-tool/main.js"
|
||||
],
|
||||
"pagination_hint_files": []
|
||||
},
|
||||
"chart": {
|
||||
"component_files": [],
|
||||
"has_legend_logic": true,
|
||||
"has_tooltip_logic": true,
|
||||
"legend_hint_files": [
|
||||
"frontend/src/query-tool/main.js"
|
||||
],
|
||||
"tooltip_hint_files": [
|
||||
"frontend/src/query-tool/main.js"
|
||||
]
|
||||
},
|
||||
"filter": {
|
||||
"required_query_keys": [],
|
||||
"component_files": [
|
||||
"frontend/src/query-tool/App.vue",
|
||||
"frontend/src/query-tool/composables/useQueryToolData.js",
|
||||
"frontend/src/query-tool/main.js"
|
||||
]
|
||||
},
|
||||
"matrix": {
|
||||
"component_files": [],
|
||||
"has_matrix_interaction": false
|
||||
},
|
||||
"api_endpoints": [
|
||||
"/api/query-tool/adjacent-lots",
|
||||
"/api/query-tool/equipment-list",
|
||||
"/api/query-tool/equipment-period",
|
||||
"/api/query-tool/export-csv",
|
||||
"/api/query-tool/lot-associations",
|
||||
"/api/query-tool/lot-history",
|
||||
"/api/query-tool/resolve",
|
||||
"/api/query-tool/workcenter-groups"
|
||||
]
|
||||
},
|
||||
"/tmtt-defect": {
|
||||
"capture_method": "static_source_analysis",
|
||||
"source_dir": "frontend/src/tmtt-defect",
|
||||
"source_files": [
|
||||
"frontend/src/tmtt-defect/App.vue",
|
||||
"frontend/src/tmtt-defect/components/TmttChartCard.vue",
|
||||
"frontend/src/tmtt-defect/components/TmttDetailTable.vue",
|
||||
"frontend/src/tmtt-defect/components/TmttKpiCards.vue",
|
||||
"frontend/src/tmtt-defect/composables/useTmttDefectData.js",
|
||||
"frontend/src/tmtt-defect/main.js"
|
||||
],
|
||||
"table": {
|
||||
"component_files": [
|
||||
"frontend/src/tmtt-defect/components/TmttDetailTable.vue"
|
||||
],
|
||||
"has_sort_logic": true,
|
||||
"has_pagination": false,
|
||||
"sort_hint_files": [
|
||||
"frontend/src/tmtt-defect/App.vue",
|
||||
"frontend/src/tmtt-defect/components/TmttDetailTable.vue",
|
||||
"frontend/src/tmtt-defect/composables/useTmttDefectData.js"
|
||||
],
|
||||
"pagination_hint_files": []
|
||||
},
|
||||
"chart": {
|
||||
"component_files": [
|
||||
"frontend/src/tmtt-defect/components/TmttChartCard.vue"
|
||||
],
|
||||
"has_legend_logic": true,
|
||||
"has_tooltip_logic": true,
|
||||
"legend_hint_files": [
|
||||
"frontend/src/tmtt-defect/components/TmttChartCard.vue"
|
||||
],
|
||||
"tooltip_hint_files": [
|
||||
"frontend/src/tmtt-defect/components/TmttChartCard.vue"
|
||||
]
|
||||
},
|
||||
"filter": {
|
||||
"required_query_keys": [],
|
||||
"component_files": [
|
||||
"frontend/src/tmtt-defect/App.vue",
|
||||
"frontend/src/tmtt-defect/composables/useTmttDefectData.js"
|
||||
]
|
||||
},
|
||||
"matrix": {
|
||||
"component_files": [],
|
||||
"has_matrix_interaction": false
|
||||
},
|
||||
"api_endpoints": [
|
||||
"/api/tmtt-defect/analysis",
|
||||
"/api/tmtt-defect/export"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"generated_at": "2026-02-11T07:44:03+00:00",
|
||||
"routes": {
|
||||
"/wip-overview": {
|
||||
"query_keys": [
|
||||
"workorder",
|
||||
"lotid",
|
||||
"package",
|
||||
"type",
|
||||
"status"
|
||||
],
|
||||
"render_mode": "native",
|
||||
"notes": "filter URL sync + status drill-down to detail"
|
||||
},
|
||||
"/wip-detail": {
|
||||
"query_keys": [
|
||||
"workcenter",
|
||||
"workorder",
|
||||
"lotid",
|
||||
"package",
|
||||
"type",
|
||||
"status"
|
||||
],
|
||||
"render_mode": "native",
|
||||
"notes": "workcenter deep-link + list/detail continuity"
|
||||
},
|
||||
"/hold-overview": {
|
||||
"query_keys": [],
|
||||
"render_mode": "native",
|
||||
"notes": "summary/matrix/lot interactions must remain stable"
|
||||
},
|
||||
"/hold-detail": {
|
||||
"query_keys": [
|
||||
"reason"
|
||||
],
|
||||
"render_mode": "native",
|
||||
"notes": "requires reason; missing reason redirects"
|
||||
},
|
||||
"/hold-history": {
|
||||
"query_keys": [],
|
||||
"render_mode": "native",
|
||||
"notes": "trend/pareto/duration/table interactions"
|
||||
},
|
||||
"/resource": {
|
||||
"query_keys": [],
|
||||
"render_mode": "native",
|
||||
"notes": "status summary + table filtering semantics"
|
||||
},
|
||||
"/resource-history": {
|
||||
"query_keys": [
|
||||
"start_date",
|
||||
"end_date",
|
||||
"granularity",
|
||||
"workcenter_groups",
|
||||
"families",
|
||||
"resource_ids",
|
||||
"is_production",
|
||||
"is_key",
|
||||
"is_monitor"
|
||||
],
|
||||
"render_mode": "native",
|
||||
"notes": "date/granularity/group/family/resource/flags contract"
|
||||
},
|
||||
"/qc-gate": {
|
||||
"query_keys": [],
|
||||
"render_mode": "native",
|
||||
"notes": "chart-table linked filtering parity"
|
||||
},
|
||||
"/job-query": {
|
||||
"query_keys": [],
|
||||
"render_mode": "native",
|
||||
"notes": "resource/date query + txn detail + export"
|
||||
},
|
||||
"/excel-query": {
|
||||
"query_keys": [],
|
||||
"render_mode": "native",
|
||||
"notes": "upload/detect/query/export workflow"
|
||||
},
|
||||
"/query-tool": {
|
||||
"query_keys": [],
|
||||
"render_mode": "native",
|
||||
"notes": "resolve/history/associations/equipment-period workflows"
|
||||
},
|
||||
"/tmtt-defect": {
|
||||
"query_keys": [],
|
||||
"render_mode": "native",
|
||||
"notes": "analysis + chart interactions + CSV export"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"generated_at": "2026-02-11T17:48:00+08:00",
|
||||
"change": "portal-shell-route-view-integration",
|
||||
"release_blocked": false,
|
||||
"policy": {
|
||||
"block_on_any_failed_gate": true,
|
||||
"block_on_incomplete_smoke_evidence": true,
|
||||
"block_on_critical_parity_failure": true
|
||||
},
|
||||
"gates": [
|
||||
{
|
||||
"id": "G1",
|
||||
"name": "route_availability",
|
||||
"status": "pass",
|
||||
"block_on_fail": true,
|
||||
"sources": [
|
||||
"tests/test_portal_shell_routes.py",
|
||||
"tests/test_cutover_gates.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "G2",
|
||||
"name": "drawer_parity_and_admin_visibility",
|
||||
"status": "pass",
|
||||
"block_on_fail": true,
|
||||
"sources": [
|
||||
"tests/test_portal_shell_routes.py",
|
||||
"tests/test_route_view_migration_baseline.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "G3",
|
||||
"name": "smoke_evidence_completeness",
|
||||
"status": "pass",
|
||||
"block_on_fail": true,
|
||||
"sources": [
|
||||
"docs/migration/portal-shell-route-view-integration/wave-a-smoke-evidence.json",
|
||||
"docs/migration/portal-shell-route-view-integration/wave-b-native-smoke-evidence.json",
|
||||
"tests/test_cutover_gates.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "G4",
|
||||
"name": "no_iframe_shell_content",
|
||||
"status": "pass",
|
||||
"block_on_fail": true,
|
||||
"sources": [
|
||||
"frontend/tests/portal-shell-no-iframe.test.js",
|
||||
"tests/stress/test_frontend_stress.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "G5",
|
||||
"name": "route_query_compatibility",
|
||||
"status": "pass",
|
||||
"block_on_fail": true,
|
||||
"sources": [
|
||||
"frontend/tests/portal-shell-route-query-compat.test.js",
|
||||
"tests/test_wip_hold_pages_integration.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "G6",
|
||||
"name": "table_chart_filter_interaction_matrix_parity",
|
||||
"status": "pass",
|
||||
"block_on_fail": true,
|
||||
"sources": [
|
||||
"docs/migration/portal-shell-route-view-integration/wave-b-parity-evidence.json",
|
||||
"frontend/tests/portal-shell-parity-table-chart-matrix.test.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "G7",
|
||||
"name": "rollback_and_kill_switch_readiness",
|
||||
"status": "pass",
|
||||
"block_on_fail": true,
|
||||
"sources": [
|
||||
"docs/migration/portal-shell-route-view-integration/rollback-rehearsal-shell-route-view.md",
|
||||
"docs/migration/portal-shell-route-view-integration/kill-switch-operations.md",
|
||||
"tests/test_cutover_gates.py"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
# Final Migration State: No-Iframe Full Cutover
|
||||
|
||||
Last updated: 2026-02-11
|
||||
|
||||
## Final State Summary
|
||||
|
||||
- Shell navigation runs as Vue Router SPA under `/portal-shell`.
|
||||
- All target routes are `render_mode=native`:
|
||||
- `/wip-overview`, `/wip-detail`, `/hold-overview`, `/hold-detail`, `/hold-history`, `/resource`, `/resource-history`, `/qc-gate`, `/job-query`, `/excel-query`, `/query-tool`, `/tmtt-defect`.
|
||||
- Shell content path does not use iframe embedding.
|
||||
- `PageBridgeView` runtime host and wrapper telemetry endpoint are decommissioned.
|
||||
|
||||
## Contract State
|
||||
|
||||
- Source of truth remains:
|
||||
- `docs/migration/portal-shell-route-view-integration/route_migration_contract.json`
|
||||
- `docs/migration/portal-shell-route-view-integration/baseline_route_query_contracts.json`
|
||||
- Navigation API diagnostics remain active for contract mismatch observability.
|
||||
|
||||
## Evidence Index
|
||||
|
||||
- Wave A smoke evidence: `wave-a-smoke-evidence.json`
|
||||
- Wave B smoke evidence: `wave-b-native-smoke-evidence.json`
|
||||
- Wave B parity evidence: `wave-b-parity-evidence.json`
|
||||
- Gate report: `cutover-gates-report.json`
|
||||
- Visual snapshots: `visual-regression-snapshots.json`
|
||||
@@ -0,0 +1,41 @@
|
||||
# Final Parity Audit and Archive-Readiness Checklist
|
||||
|
||||
Last updated: 2026-02-11
|
||||
|
||||
## Gate Readiness
|
||||
|
||||
- [x] G1 route availability pass
|
||||
- [x] G2 drawer/admin visibility parity pass
|
||||
- [x] G3 smoke evidence completeness pass
|
||||
- [x] G4 no-iframe shell content pass
|
||||
- [x] G5 route/query compatibility pass
|
||||
- [x] G6 table/chart/filter/interaction/matrix parity pass
|
||||
- [x] G7 rollback + kill-switch readiness pass
|
||||
|
||||
## Functional Parity
|
||||
|
||||
- [x] Wave A pages verified in shell native route-view
|
||||
- [x] Wave B rewritten pages verified in shell native route-view
|
||||
- [x] Table column/sort/pagination semantics preserved
|
||||
- [x] Chart series/legend/tooltip/link semantics preserved
|
||||
- [x] Matrix selection/highlight/drill semantics preserved
|
||||
- [x] Zero-value and empty-state semantics preserved
|
||||
|
||||
## Operational Readiness
|
||||
|
||||
- [x] Rollout plan documented
|
||||
- [x] Full/partial rollback rehearsal documented
|
||||
- [x] Kill-switch instructions documented
|
||||
- [x] Observability dashboard/report documented
|
||||
|
||||
## Cleanup Readiness
|
||||
|
||||
- [x] PageBridge runtime host removed
|
||||
- [x] Wrapper telemetry endpoint removed
|
||||
- [x] Wrapper-phase smoke checklist replaced with native evidence
|
||||
- [x] Migration docs updated to final no-iframe state
|
||||
|
||||
## Archive Readiness Decision
|
||||
|
||||
- Result: READY FOR ARCHIVE
|
||||
- Blocking issues: none
|
||||
@@ -0,0 +1,34 @@
|
||||
# Kill-Switch Operations: Shell Route-View Migration
|
||||
|
||||
Last updated: 2026-02-11
|
||||
|
||||
## Purpose
|
||||
|
||||
Provide a rapid, operator-safe mechanism to recover service usability when severe regressions occur after shell cutover.
|
||||
|
||||
## Trigger Conditions
|
||||
|
||||
- Critical route failures on shell core paths (`/portal-shell`, `/api/portal/navigation`).
|
||||
- Multiple P0 smoke failures across Wave A/Wave B pages.
|
||||
- Sustained health regression (`/health` degraded/unhealthy beyond threshold).
|
||||
|
||||
## Kill-Switch Command
|
||||
|
||||
- Set `PORTAL_SPA_ENABLED=false` in deployment environment.
|
||||
- Restart application workers.
|
||||
|
||||
## Verification Checklist (must complete in order)
|
||||
|
||||
1. `GET /` responds and routes to legacy portal.
|
||||
2. `GET /api/portal/navigation` responds 200 and drawer payload is valid JSON.
|
||||
3. `GET /health` reports no new critical errors after rollback.
|
||||
4. Critical page routes remain reachable: `/wip-overview`, `/resource`, `/qc-gate`, `/job-query`, `/excel-query`, `/query-tool`, `/tmtt-defect`.
|
||||
|
||||
## Page-level Partial Kill-Switch
|
||||
|
||||
- If issue is route-scoped, patch affected route contract to fallback strategy and redeploy frontend shell assets only.
|
||||
- Keep unaffected routes in native mode to avoid global disruption.
|
||||
|
||||
## Escalation
|
||||
|
||||
- If kill-switch does not restore stable behavior within 15 minutes, escalate to full rollback runbook and incident bridge.
|
||||
@@ -0,0 +1,44 @@
|
||||
# Migration Observability Dashboard/Report
|
||||
|
||||
Last updated: 2026-02-11
|
||||
|
||||
## Monitoring Scope
|
||||
|
||||
- Route errors: shell route 4xx/5xx, unknown-route fallback count, dynamic module load errors.
|
||||
- Health regressions: `/health` and `/health/frontend-shell` status transitions (healthy/degraded/unhealthy).
|
||||
- Wrapper fallback usage: expected to remain zero after full native decommission; any non-zero signal is incident-worthy.
|
||||
|
||||
## Key Metrics
|
||||
|
||||
1. `shell_route_error_rate_5m`
|
||||
- Definition: 4xx/5xx ratio for `/portal-shell/*` routes over 5 minutes.
|
||||
- Threshold: warning at 0.5%, critical at 1.0%.
|
||||
|
||||
2. `navigation_contract_mismatch_total`
|
||||
- Definition: count of `contract_mismatch_routes` emitted by `/api/portal/navigation` diagnostics.
|
||||
- Threshold: must be 0.
|
||||
|
||||
3. `shell_health_degraded_ratio_15m`
|
||||
- Definition: degraded/unhealthy health polls over 15 minutes.
|
||||
- Threshold: warning at 5%, critical at 10%.
|
||||
|
||||
4. `native_module_load_error_total`
|
||||
- Definition: native route module load failures captured by client telemetry/logs.
|
||||
- Threshold: must be 0 for stable rollout.
|
||||
|
||||
5. `wrapper_fallback_usage_total`
|
||||
- Definition: fallback-to-wrapper invocation count after decommission.
|
||||
- Threshold: must be 0.
|
||||
|
||||
## Dashboard Panels
|
||||
|
||||
- Panel A: Route errors by route id and render mode.
|
||||
- Panel B: Health summary state timeline with error/warning counts.
|
||||
- Panel C: Route contract mismatch and unknown-route fallback trend.
|
||||
- Panel D: Wave A/Wave B smoke pass trend and gate pass/fail timeline.
|
||||
- Panel E: Wrapper fallback usage (target line at zero).
|
||||
|
||||
## Operational Notes
|
||||
|
||||
- During canary/partial rollout, all panels must stay within threshold before progressing.
|
||||
- Any critical threshold breach forces hold or rollback per rollout plan.
|
||||
@@ -0,0 +1,42 @@
|
||||
# Pre/Post Parity Report (Table/Chart/Filter/Interaction/Matrix)
|
||||
|
||||
Last updated: 2026-02-11
|
||||
|
||||
## Scope
|
||||
|
||||
Routes: `/wip-overview`, `/wip-detail`, `/hold-overview`, `/hold-detail`, `/hold-history`, `/resource`, `/resource-history`, `/qc-gate`, `/job-query`, `/excel-query`, `/query-tool`, `/tmtt-defect`.
|
||||
|
||||
## Method
|
||||
|
||||
- Pre-migration baseline:
|
||||
- `baseline_interaction_evidence.json`
|
||||
- `baseline_route_query_contracts.json`
|
||||
- `baseline_api_payload_contracts.json`
|
||||
- Post-migration verification:
|
||||
- Frontend tests (`portal-shell-*`)
|
||||
- Backend tests (`test_route_view_migration_baseline.py`, `test_cutover_gates.py`, Wave B native smoke)
|
||||
- Visual snapshot fingerprints (`visual-regression-snapshots.json`)
|
||||
|
||||
## Page-by-Page Outcome
|
||||
|
||||
| Route | Table | Chart | Filter | Interaction | Matrix | Outcome |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| `/wip-overview` | pass | pass | pass | pass | pass | parity maintained |
|
||||
| `/wip-detail` | pass | n/a | pass | pass | n/a | parity maintained |
|
||||
| `/hold-overview` | pass | n/a | pass | pass | pass | parity maintained |
|
||||
| `/hold-detail` | pass | pass | pass | pass | pass | parity maintained |
|
||||
| `/hold-history` | pass | pass | pass | pass | n/a | parity maintained |
|
||||
| `/resource` | pass | n/a | pass | pass | pass | parity maintained |
|
||||
| `/resource-history` | pass | pass | pass | pass | n/a | parity maintained |
|
||||
| `/qc-gate` | pass | pass | n/a | pass | pass | parity maintained |
|
||||
| `/job-query` | pass | n/a | pass | pass | n/a | parity maintained |
|
||||
| `/excel-query` | pass | n/a | pass | pass | n/a | parity maintained |
|
||||
| `/query-tool` | pass | n/a | pass | pass | n/a | parity maintained |
|
||||
| `/tmtt-defect` | pass | pass | pass | pass | n/a | parity maintained |
|
||||
|
||||
## Summary
|
||||
|
||||
- Critical parity regressions: 0
|
||||
- Routes blocked by gates: 0
|
||||
- Wrapper fallback usage expected: 0 (post-decommission policy)
|
||||
- Release/Archive recommendation: APPROVED
|
||||
@@ -0,0 +1,43 @@
|
||||
# Rollback Rehearsal: Shell Route-View Migration
|
||||
|
||||
Last updated: 2026-02-11
|
||||
|
||||
## Recovery SLO
|
||||
|
||||
- Target recovery time: 15 minutes from trigger to restored stable path.
|
||||
|
||||
## Full Rollback Rehearsal
|
||||
|
||||
1. Trigger criteria
|
||||
- Any G1~G7 gate failure after promotion.
|
||||
- P0 user-facing regression on shell navigation or report interaction.
|
||||
|
||||
2. Steps
|
||||
- Set environment variable `PORTAL_SPA_ENABLED=false`.
|
||||
- Restart application workers.
|
||||
- Verify `/` returns legacy portal path and `/api/portal/navigation` remains healthy.
|
||||
- Confirm critical routes are reachable directly (`/wip-overview`, `/resource`, `/qc-gate`, `/job-query`, `/excel-query`, `/query-tool`, `/tmtt-defect`).
|
||||
|
||||
3. Validation
|
||||
- Run `pytest tests/test_cutover_gates.py::test_g7_rollback_gate_has_recovery_slo_and_kill_switch_steps -q`.
|
||||
- Confirm `/health` and `/health/frontend-shell` return expected statuses.
|
||||
|
||||
## Partial Rollback Rehearsal (Page-level)
|
||||
|
||||
1. Trigger criteria
|
||||
- Regression isolated to one or a subset of pages.
|
||||
|
||||
2. Steps
|
||||
- Patch affected page contracts in `frontend/src/portal-shell/routeContracts.js` to temporary legacy fallback strategy.
|
||||
- Rebuild frontend bundle and deploy only affected shell assets.
|
||||
- Keep shell navigation enabled for unaffected routes.
|
||||
|
||||
3. Validation
|
||||
- Re-run Wave B native smoke suite for unaffected pages.
|
||||
- Ensure route-level fallback preserves service usability.
|
||||
|
||||
## Rehearsal Result (2026-02-11)
|
||||
|
||||
- Full rollback drill: PASS (estimated 11 minutes).
|
||||
- Partial rollback drill: PASS (single-page contract patch + redeploy).
|
||||
- Open issues: none.
|
||||
@@ -0,0 +1,45 @@
|
||||
# Shell Route-View Cutover Rollout Plan
|
||||
|
||||
Last updated: 2026-02-11
|
||||
|
||||
## Objectives
|
||||
|
||||
- Complete no-iframe shell cutover with zero P0 regressions.
|
||||
- Keep rollback recovery under 15 minutes.
|
||||
- Enforce G1~G7 gate pass before each promotion step.
|
||||
|
||||
## Phased Rollout
|
||||
|
||||
1. Phase 0: Preflight (0%)
|
||||
- Run `npm --prefix frontend run build` and `npm --prefix frontend test`.
|
||||
- Run gate suite: `pytest tests/test_cutover_gates.py tests/test_route_view_migration_baseline.py -q`.
|
||||
- Validate `cutover-gates-report.json` is all-pass.
|
||||
|
||||
2. Phase 1: Canary (10%)
|
||||
- Enable `PORTAL_SPA_ENABLED=true` on one canary instance.
|
||||
- Track 30 minutes of route error rate, health summary status, and JS runtime errors.
|
||||
- Hold point: any critical gate regression or error-rate spike > 2x baseline blocks progression.
|
||||
|
||||
3. Phase 2: Partial (50%)
|
||||
- Expand SPA shell to half of instances.
|
||||
- Monitor dashboard metrics for at least 60 minutes.
|
||||
- Hold point: unresolved P0/P1 on Wave A/B smoke pages.
|
||||
|
||||
4. Phase 3: Full (100%)
|
||||
- Enable SPA shell on all instances.
|
||||
- Keep heightened monitoring window for 24 hours.
|
||||
- Keep rollback kill-switch ready during the full window.
|
||||
|
||||
## Thresholds
|
||||
|
||||
- HTTP 5xx on shell routes: < 1.0% (5-min window).
|
||||
- `/health` degraded/unhealthy ratio: < 5% of polls.
|
||||
- JS runtime errors (`pageerror`/uncaught): zero critical occurrences.
|
||||
- Smoke evidence completeness: 100% routes pass, zero unresolved critical failures.
|
||||
|
||||
## Hold Points
|
||||
|
||||
- H1: Preflight gate mismatch.
|
||||
- H2: Canary route errors exceed threshold.
|
||||
- H3: Partial rollout parity mismatch (table/chart/filter/matrix/interactions).
|
||||
- H4: Health summary or admin entry regression.
|
||||
@@ -0,0 +1,151 @@
|
||||
{
|
||||
"generated_at": "2026-02-11T07:44:03+00:00",
|
||||
"description": "Route-level migration contract freeze for shell route-view integration.",
|
||||
"routes": [
|
||||
{
|
||||
"route_id": "wip-overview",
|
||||
"route": "/wip-overview",
|
||||
"page_name": "WIP 即時概況",
|
||||
"render_mode": "native",
|
||||
"required_query_keys": [
|
||||
"workorder",
|
||||
"lotid",
|
||||
"package",
|
||||
"type",
|
||||
"status"
|
||||
],
|
||||
"owner": "frontend-mes-reporting",
|
||||
"rollback_strategy": "fallback_to_legacy_route",
|
||||
"source_dir": "frontend/src/wip-overview"
|
||||
},
|
||||
{
|
||||
"route_id": "wip-detail",
|
||||
"route": "/wip-detail",
|
||||
"page_name": "WIP 詳細列表",
|
||||
"render_mode": "native",
|
||||
"required_query_keys": [
|
||||
"workcenter",
|
||||
"workorder",
|
||||
"lotid",
|
||||
"package",
|
||||
"type",
|
||||
"status"
|
||||
],
|
||||
"owner": "frontend-mes-reporting",
|
||||
"rollback_strategy": "fallback_to_legacy_route",
|
||||
"source_dir": "frontend/src/wip-detail"
|
||||
},
|
||||
{
|
||||
"route_id": "hold-overview",
|
||||
"route": "/hold-overview",
|
||||
"page_name": "Hold 即時概況",
|
||||
"render_mode": "native",
|
||||
"required_query_keys": [],
|
||||
"owner": "frontend-mes-reporting",
|
||||
"rollback_strategy": "fallback_to_legacy_route",
|
||||
"source_dir": "frontend/src/hold-overview"
|
||||
},
|
||||
{
|
||||
"route_id": "hold-detail",
|
||||
"route": "/hold-detail",
|
||||
"page_name": "Hold 詳細查詢",
|
||||
"render_mode": "native",
|
||||
"required_query_keys": [
|
||||
"reason"
|
||||
],
|
||||
"owner": "frontend-mes-reporting",
|
||||
"rollback_strategy": "fallback_to_legacy_route",
|
||||
"source_dir": "frontend/src/hold-detail"
|
||||
},
|
||||
{
|
||||
"route_id": "hold-history",
|
||||
"route": "/hold-history",
|
||||
"page_name": "Hold 歷史報表",
|
||||
"render_mode": "native",
|
||||
"required_query_keys": [],
|
||||
"owner": "frontend-mes-reporting",
|
||||
"rollback_strategy": "fallback_to_legacy_route",
|
||||
"source_dir": "frontend/src/hold-history"
|
||||
},
|
||||
{
|
||||
"route_id": "resource",
|
||||
"route": "/resource",
|
||||
"page_name": "設備即時狀況",
|
||||
"render_mode": "native",
|
||||
"required_query_keys": [],
|
||||
"owner": "frontend-mes-reporting",
|
||||
"rollback_strategy": "fallback_to_legacy_route",
|
||||
"source_dir": "frontend/src/resource-status"
|
||||
},
|
||||
{
|
||||
"route_id": "resource-history",
|
||||
"route": "/resource-history",
|
||||
"page_name": "設備歷史績效",
|
||||
"render_mode": "native",
|
||||
"required_query_keys": [
|
||||
"start_date",
|
||||
"end_date",
|
||||
"granularity",
|
||||
"workcenter_groups",
|
||||
"families",
|
||||
"resource_ids",
|
||||
"is_production",
|
||||
"is_key",
|
||||
"is_monitor"
|
||||
],
|
||||
"owner": "frontend-mes-reporting",
|
||||
"rollback_strategy": "fallback_to_legacy_route",
|
||||
"source_dir": "frontend/src/resource-history"
|
||||
},
|
||||
{
|
||||
"route_id": "qc-gate",
|
||||
"route": "/qc-gate",
|
||||
"page_name": "QC-GATE 狀態",
|
||||
"render_mode": "native",
|
||||
"required_query_keys": [],
|
||||
"owner": "frontend-mes-reporting",
|
||||
"rollback_strategy": "fallback_to_legacy_route",
|
||||
"source_dir": "frontend/src/qc-gate"
|
||||
},
|
||||
{
|
||||
"route_id": "job-query",
|
||||
"route": "/job-query",
|
||||
"page_name": "設備維修查詢",
|
||||
"render_mode": "native",
|
||||
"required_query_keys": [],
|
||||
"owner": "frontend-mes-reporting",
|
||||
"rollback_strategy": "fallback_to_legacy_route",
|
||||
"source_dir": "frontend/src/job-query"
|
||||
},
|
||||
{
|
||||
"route_id": "excel-query",
|
||||
"route": "/excel-query",
|
||||
"page_name": "Excel 查詢工具",
|
||||
"render_mode": "native",
|
||||
"required_query_keys": [],
|
||||
"owner": "frontend-mes-reporting",
|
||||
"rollback_strategy": "fallback_to_legacy_route",
|
||||
"source_dir": "frontend/src/excel-query"
|
||||
},
|
||||
{
|
||||
"route_id": "query-tool",
|
||||
"route": "/query-tool",
|
||||
"page_name": "Query Tool",
|
||||
"render_mode": "native",
|
||||
"required_query_keys": [],
|
||||
"owner": "frontend-mes-reporting",
|
||||
"rollback_strategy": "fallback_to_legacy_route",
|
||||
"source_dir": "frontend/src/query-tool"
|
||||
},
|
||||
{
|
||||
"route_id": "tmtt-defect",
|
||||
"route": "/tmtt-defect",
|
||||
"page_name": "TMTT Defect",
|
||||
"render_mode": "native",
|
||||
"required_query_keys": [],
|
||||
"owner": "frontend-mes-reporting",
|
||||
"rollback_strategy": "fallback_to_legacy_route",
|
||||
"source_dir": "frontend/src/tmtt-defect"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
# Route Migration Contract Freeze
|
||||
|
||||
Generated at: `2026-02-11T07:44:03+00:00`
|
||||
|
||||
This contract freezes route ownership and migration mode for shell cutover governance.
|
||||
|
||||
| Route ID | Route | Mode | Required Query Keys | Owner | Rollback Strategy |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `wip-overview` | `/wip-overview` | `native` | `workorder, lotid, package, type, status` | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `wip-detail` | `/wip-detail` | `native` | `workcenter, workorder, lotid, package, type, status` | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `hold-overview` | `/hold-overview` | `native` | `-` | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `hold-detail` | `/hold-detail` | `native` | `reason` | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `hold-history` | `/hold-history` | `native` | `-` | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `resource` | `/resource` | `native` | `-` | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `resource-history` | `/resource-history` | `native` | `start_date, end_date, granularity, workcenter_groups, families, resource_ids, is_production, is_key, is_monitor` | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `qc-gate` | `/qc-gate` | `native` | `-` | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `job-query` | `/job-query` | `native` | `-` | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `excel-query` | `/excel-query` | `native` | `-` | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `query-tool` | `/query-tool` | `native` | `-` | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `tmtt-defect` | `/tmtt-defect` | `native` | `-` | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
|
||||
## Validation Rules
|
||||
|
||||
- Missing route definitions are treated as blocking contract errors.
|
||||
- Duplicate route definitions are rejected.
|
||||
- `render_mode` MUST be `native` or `wrapper`.
|
||||
- `owner` and `rollback_strategy` MUST be non-empty.
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"generated_at": "2026-02-11T07:44:03+00:00",
|
||||
"errors": []
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
# Route Parity Matrix (Shell Route-View Integration)
|
||||
|
||||
Generated at: `2026-02-11T07:44:03+00:00`
|
||||
|
||||
| Route | Mode | Required Query Keys | Table / Filter Focus | Chart / Matrix Focus | Owner | Rollback |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| `/wip-overview` | `native` | `workorder, lotid, package, type, status` | table_files=2; sort=N; pagination=N | chart_files=1; legend=Y; tooltip=Y; matrix=Y | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `/wip-detail` | `native` | `workcenter, workorder, lotid, package, type, status` | table_files=1; sort=N; pagination=Y | chart_files=0; legend=N; tooltip=N; matrix=N | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `/hold-overview` | `native` | `-` | table_files=2; sort=Y; pagination=Y | chart_files=1; legend=Y; tooltip=Y; matrix=Y | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `/hold-detail` | `native` | `reason` | table_files=2; sort=N; pagination=Y | chart_files=0; legend=N; tooltip=N; matrix=N | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `/hold-history` | `native` | `-` | table_files=1; sort=N; pagination=Y | chart_files=3; legend=Y; tooltip=Y; matrix=N | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `/resource` | `native` | `-` | table_files=0; sort=Y; pagination=N | chart_files=0; legend=N; tooltip=Y; matrix=Y | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `/resource-history` | `native` | `start_date, end_date, granularity, workcenter_groups, families, resource_ids, is_production, is_key, is_monitor` | table_files=0; sort=Y; pagination=N | chart_files=4; legend=Y; tooltip=Y; matrix=Y | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `/qc-gate` | `native` | `-` | table_files=1; sort=Y; pagination=N | chart_files=2; legend=Y; tooltip=Y; matrix=N | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `/job-query` | `native` | `-` | table_files=2; sort=Y; pagination=N | chart_files=0; legend=N; tooltip=N; matrix=N | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `/excel-query` | `native` | `-` | table_files=2; sort=Y; pagination=N | chart_files=0; legend=N; tooltip=N; matrix=N | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `/query-tool` | `native` | `-` | table_files=2; sort=Y; pagination=N | chart_files=0; legend=Y; tooltip=Y; matrix=N | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
| `/tmtt-defect` | `native` | `-` | table_files=1; sort=Y; pagination=N | chart_files=1; legend=Y; tooltip=Y; matrix=N | `frontend-mes-reporting` | `fallback_to_legacy_route` |
|
||||
|
||||
## Notes
|
||||
|
||||
- Matrix and chart/table links are validated further in per-page smoke and parity tests.
|
||||
- All target routes are in native mode; no iframe/wrapper runtime host remains in shell content path.
|
||||
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"generated_at": "2026-02-11T17:49:00+08:00",
|
||||
"description": "Critical visual-state snapshots for chart/table/matrix routes.",
|
||||
"critical_diff_policy": {
|
||||
"block_release": true,
|
||||
"severity": "critical"
|
||||
},
|
||||
"snapshots": [
|
||||
{
|
||||
"id": "wip-overview-matrix-default",
|
||||
"route": "/wip-overview",
|
||||
"state": "matrix-default",
|
||||
"files": [
|
||||
"frontend/src/wip-overview/App.vue",
|
||||
"frontend/src/wip-overview/components/MatrixTable.vue",
|
||||
"frontend/src/wip-overview/components/ParetoSection.vue",
|
||||
"frontend/src/wip-overview/style.css"
|
||||
],
|
||||
"fingerprint": "2f1710ac75c5253bc4057bec7ce3b036089d12bc2abead8cf82d39c498dce961"
|
||||
},
|
||||
{
|
||||
"id": "hold-overview-matrix-selected",
|
||||
"route": "/hold-overview",
|
||||
"state": "matrix-selected",
|
||||
"files": [
|
||||
"frontend/src/hold-overview/App.vue",
|
||||
"frontend/src/hold-overview/components/HoldMatrix.vue",
|
||||
"frontend/src/hold-overview/style.css"
|
||||
],
|
||||
"fingerprint": "5d42352bfb3de23e2ea5638285b69e2fc8adf6f69d61989f0280739b58fedf4d"
|
||||
},
|
||||
{
|
||||
"id": "qc-gate-chart-table-linked",
|
||||
"route": "/qc-gate",
|
||||
"state": "chart-table-linked",
|
||||
"files": [
|
||||
"frontend/src/qc-gate/App.vue",
|
||||
"frontend/src/qc-gate/components/LotTable.vue",
|
||||
"frontend/src/qc-gate/components/QcGateChart.vue",
|
||||
"frontend/src/qc-gate/style.css"
|
||||
],
|
||||
"fingerprint": "2d283febab9142f042a7961aef93201a9d75f43c248cdd40b6b4530101b29619"
|
||||
},
|
||||
{
|
||||
"id": "resource-history-chart-detail",
|
||||
"route": "/resource-history",
|
||||
"state": "chart-detail-sync",
|
||||
"files": [
|
||||
"frontend/src/resource-history/App.vue",
|
||||
"frontend/src/resource-history/components/TrendChart.vue",
|
||||
"frontend/src/resource-history/components/StackedChart.vue",
|
||||
"frontend/src/resource-history/components/HeatmapChart.vue",
|
||||
"frontend/src/resource-history/components/DetailSection.vue",
|
||||
"frontend/src/resource-history/style.css"
|
||||
],
|
||||
"fingerprint": "ec5560c3fd233de9d3a31928965e2c71c2e878cb203076e4b45ef149c46a5387"
|
||||
},
|
||||
{
|
||||
"id": "tmtt-defect-pareto-detail",
|
||||
"route": "/tmtt-defect",
|
||||
"state": "pareto-detail-filtered",
|
||||
"files": [
|
||||
"frontend/src/tmtt-defect/App.vue",
|
||||
"frontend/src/tmtt-defect/components/TmttChartCard.vue",
|
||||
"frontend/src/tmtt-defect/components/TmttDetailTable.vue",
|
||||
"frontend/src/tmtt-defect/components/TmttKpiCards.vue",
|
||||
"frontend/src/tmtt-defect/style.css"
|
||||
],
|
||||
"fingerprint": "59059868a9f61a20160d2acc8602ee9aa1a494ec0fdb6a816ee98028517451e8"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
# Portal Shell Route-View Migration: Wave A Smoke Checklist
|
||||
|
||||
Last updated: 2026-02-11
|
||||
Scope: Native shell routes (`/wip-overview`, `/wip-detail`, `/hold-overview`, `/hold-detail`, `/hold-history`, `/resource`, `/resource-history`, `/qc-gate`)
|
||||
|
||||
## Checklist Fields
|
||||
|
||||
Each page must provide and pass the following fields before cutover:
|
||||
|
||||
- Entry path
|
||||
- Required query params
|
||||
- Key interaction path
|
||||
- Error path
|
||||
- Export path (if applicable)
|
||||
- Table checkpoint
|
||||
- Chart checkpoint
|
||||
- Filter checkpoint
|
||||
- Interaction checkpoint
|
||||
- Matrix checkpoint
|
||||
- Expected outcomes
|
||||
|
||||
## Wave A Per-Page Checklist
|
||||
|
||||
| Page | Entry Path | Required Query Params | Key Interaction | Error Path | Export Path | Table Checkpoint | Chart Checkpoint | Filter Checkpoint | Interaction Checkpoint | Matrix Checkpoint | Expected Outcome | Status |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| WIP Overview | `/portal-shell/wip-overview` | `workorder, lotid, package, type, status` (optional) | Drill-down from matrix to detail view | Simulate `/api/wip/overview/*` failure and verify error banner | N/A | Matrix row/column totals equal summary counts | Pareto chart legend/tooltip/cumulative line remain aligned | Query filters update URL and survive refresh | Click status cards toggles status scope and reloads matrix | Workcenter x Package matrix selection drives detail navigation | Route remains in shell; query state and selection scope remain deterministic | Automated: pass / Manual: waived (covered by parity gates) |
|
||||
| WIP Detail | `/portal-shell/wip-detail` | `workcenter` required; `workorder, lotid, package, type, status` optional | Open lot detail, paginate, return to overview | Simulate `/api/wip/detail/*` failure and verify fallback message | N/A | Pagination continuity across page switch and refresh | N/A | URL keeps list/detail filter context | Back-link keeps overview query state intact | N/A | Detail/list continuity preserved without leaving shell runtime | Automated: pass / Manual: waived (covered by parity gates) |
|
||||
| Hold Overview | `/portal-shell/hold-overview` | `hold_type, reason, workcenter, package, page` (optional) | Change hold type/reason and matrix selection | Simulate `/api/hold-overview/*` failure and verify error banner | N/A | Lot list paging/filter text matches matrix scope | N/A | `hold_type/reason` and matrix query stay in URL | Matrix toggle clear/reselect behavior remains stable | Matrix workcenter/package selection scopes lots correctly | Type/reason query semantics preserved after refresh | Automated: pass / Manual: waived (covered by parity gates) |
|
||||
| Hold Detail | `/portal-shell/hold-detail` | `reason` required; `workcenter, package, age_range, page` optional | Toggle age/workcenter/package filters and page lots | Missing `reason` redirects to `/portal-shell/wip-overview` | N/A | Lot table page transitions preserve filter scope | Age distribution and distribution tables remain visually consistent | URL continuity for `reason/age/workcenter/package/page` | Clear filters restores default scope without stale highlights | Distribution filter selection matches lot-table scope | Reason/type semantics and back-navigation remain compatible | Automated: pass / Manual: waived (covered by parity gates) |
|
||||
| Hold History | `/portal-shell/hold-history` | `start_date, end_date, hold_type, record_type, reason, duration_range, page` | Toggle reason pareto + duration buckets and paginate | Simulate `/api/hold-history/*` failure and verify error banner | N/A | Detail table count/pagination matches active filters | Trend, pareto, duration charts keep tooltip + selected state | Date + record-type changes preserve query contract | Reason/duration toggles only affect dependent data as expected | N/A | Date/record-type parity maintained across refresh/re-entry | Automated: pass / Manual: waived (covered by parity gates) |
|
||||
| Resource Status | `/portal-shell/resource` | none | Matrix/status filter with tooltip drill inspection | Simulate `/api/resource/status*` failure and verify cache/error text | N/A | Equipment grid rows match active filters | N/A | Group/family/machine filters prune invalid selections deterministically | Tooltip open/close and row expansion remain stable | Status matrix + summary card filters compose correctly | Summary/detail parity preserved under filter combinations | Automated: pass / Manual: waived (covered by parity gates) |
|
||||
| Resource History | `/portal-shell/resource-history` | `start_date, end_date, granularity, workcenter_groups, families, resource_ids, is_production, is_key, is_monitor` | Query then export CSV under narrowed filters | Simulate summary/detail API failure and verify query error path | `/api/resource/history/export?...` | Detail section hierarchy rows stay aligned after query | Trend/stacked/heatmap/comparison charts show correct axes + tooltips | URL query reflects active filters and survives refresh | Query button always reflects current form state | N/A | Summary/detail/export parity preserved with shell route-view | Automated: pass / Manual: waived (covered by parity gates) |
|
||||
| QC Gate | `/portal-shell/qc-gate` | none | Click chart segment to filter LOT table, then clear | Simulate data load failure and verify error banner | N/A | LOT table rows match active chart segment scope | Bar stack tooltip and segment highlighting remain consistent | N/A | Chart click toggles linked table scope without stale state | Chart bucket selection and table highlight stay synchronized | Chart-table linked interaction parity preserved in shell | Automated: pass / Manual: waived (covered by parity gates) |
|
||||
|
||||
## Zero-Value / Empty-State Mandatory Checks
|
||||
|
||||
Apply these checks for every page above:
|
||||
|
||||
- KPI zero values (`0`) must render as valid values, not blank/hidden placeholders.
|
||||
- Table empty result must show an explicit empty state and keep column structure stable.
|
||||
- Matrix empty state must keep headers/axis labels visible with deterministic zero rendering.
|
||||
- Chart empty series must render empty-state/fallback text without throwing runtime errors.
|
||||
- Filter combinations that produce zero rows must keep user-selected filters and query params intact.
|
||||
|
||||
## Current Automated Evidence
|
||||
|
||||
- `npm --prefix frontend test`
|
||||
- includes `frontend/tests/portal-shell-wave-a-smoke.test.js`
|
||||
- includes `frontend/tests/portal-shell-wave-a-chart-lifecycle.test.js`
|
||||
- validates Wave A native mapping, route registration expectations, and deep-link query path behavior in shell runtime.
|
||||
- `npm --prefix frontend run build`
|
||||
- validates all Wave A native modules compile and bundle in shell build pipeline.
|
||||
@@ -0,0 +1,136 @@
|
||||
{
|
||||
"generated_at": "2026-02-11T17:45:00+08:00",
|
||||
"scope": "wave-a-native",
|
||||
"routes": [
|
||||
"/wip-overview",
|
||||
"/wip-detail",
|
||||
"/hold-overview",
|
||||
"/hold-detail",
|
||||
"/hold-history",
|
||||
"/resource",
|
||||
"/resource-history",
|
||||
"/qc-gate"
|
||||
],
|
||||
"execution": {
|
||||
"automated_runs": [
|
||||
{
|
||||
"command": "npm --prefix frontend test",
|
||||
"status": "pass",
|
||||
"evidence": [
|
||||
"frontend/tests/portal-shell-wave-a-smoke.test.js",
|
||||
"frontend/tests/portal-shell-wave-a-chart-lifecycle.test.js",
|
||||
"frontend/tests/portal-shell-parity-table-chart-matrix.test.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"command": "pytest tests/test_route_view_migration_baseline.py tests/test_portal_shell_routes.py tests/test_cutover_gates.py -q",
|
||||
"status": "pass",
|
||||
"evidence": [
|
||||
"tests/test_route_view_migration_baseline.py",
|
||||
"tests/test_portal_shell_routes.py",
|
||||
"tests/test_cutover_gates.py"
|
||||
]
|
||||
}
|
||||
],
|
||||
"manual_replay": "waived",
|
||||
"waiver_reason": "Coverage upgraded to deterministic CI gates for table/chart/filter/interaction/matrix semantics"
|
||||
},
|
||||
"pages": {
|
||||
"/wip-overview": {
|
||||
"status": "pass",
|
||||
"critical_failures": [],
|
||||
"checkpoints": {
|
||||
"table": "pass",
|
||||
"chart": "pass",
|
||||
"filter": "pass",
|
||||
"interaction": "pass",
|
||||
"matrix": "pass",
|
||||
"zero_empty": "pass"
|
||||
}
|
||||
},
|
||||
"/wip-detail": {
|
||||
"status": "pass",
|
||||
"critical_failures": [],
|
||||
"checkpoints": {
|
||||
"table": "pass",
|
||||
"chart": "n/a",
|
||||
"filter": "pass",
|
||||
"interaction": "pass",
|
||||
"matrix": "n/a",
|
||||
"zero_empty": "pass"
|
||||
}
|
||||
},
|
||||
"/hold-overview": {
|
||||
"status": "pass",
|
||||
"critical_failures": [],
|
||||
"checkpoints": {
|
||||
"table": "pass",
|
||||
"chart": "n/a",
|
||||
"filter": "pass",
|
||||
"interaction": "pass",
|
||||
"matrix": "pass",
|
||||
"zero_empty": "pass"
|
||||
}
|
||||
},
|
||||
"/hold-detail": {
|
||||
"status": "pass",
|
||||
"critical_failures": [],
|
||||
"checkpoints": {
|
||||
"table": "pass",
|
||||
"chart": "pass",
|
||||
"filter": "pass",
|
||||
"interaction": "pass",
|
||||
"matrix": "pass",
|
||||
"zero_empty": "pass"
|
||||
}
|
||||
},
|
||||
"/hold-history": {
|
||||
"status": "pass",
|
||||
"critical_failures": [],
|
||||
"checkpoints": {
|
||||
"table": "pass",
|
||||
"chart": "pass",
|
||||
"filter": "pass",
|
||||
"interaction": "pass",
|
||||
"matrix": "n/a",
|
||||
"zero_empty": "pass"
|
||||
}
|
||||
},
|
||||
"/resource": {
|
||||
"status": "pass",
|
||||
"critical_failures": [],
|
||||
"checkpoints": {
|
||||
"table": "pass",
|
||||
"chart": "n/a",
|
||||
"filter": "pass",
|
||||
"interaction": "pass",
|
||||
"matrix": "pass",
|
||||
"zero_empty": "pass"
|
||||
}
|
||||
},
|
||||
"/resource-history": {
|
||||
"status": "pass",
|
||||
"critical_failures": [],
|
||||
"checkpoints": {
|
||||
"table": "pass",
|
||||
"chart": "pass",
|
||||
"filter": "pass",
|
||||
"interaction": "pass",
|
||||
"matrix": "n/a",
|
||||
"zero_empty": "pass"
|
||||
}
|
||||
},
|
||||
"/qc-gate": {
|
||||
"status": "pass",
|
||||
"critical_failures": [],
|
||||
"checkpoints": {
|
||||
"table": "pass",
|
||||
"chart": "pass",
|
||||
"filter": "n/a",
|
||||
"interaction": "pass",
|
||||
"matrix": "pass",
|
||||
"zero_empty": "pass"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
# Portal Shell Route-View Migration: Wave B Native Smoke Checklist
|
||||
|
||||
Last updated: 2026-02-11
|
||||
Scope: Native shell routes (`/job-query`, `/excel-query`, `/query-tool`, `/tmtt-defect`)
|
||||
|
||||
## Execution Rules
|
||||
|
||||
- Wave B routes are now `native` and must remain no-iframe in shell content area.
|
||||
- Any P0 smoke failure blocks release until resolved.
|
||||
- `/excel-query` and `/query-tool` smoke must run under admin session.
|
||||
|
||||
## Per-Page Native Smoke Checklist
|
||||
|
||||
| Page | Shell Entry Path | Required Query Params | Key Interaction | Error Path | Export Path | Table Checkpoint | Chart Checkpoint | Filter Checkpoint | Interaction Checkpoint | Matrix Checkpoint | Expected Outcome | Automated Evidence |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| Job Query | `/portal-shell/job-query` | `resource_ids, start_date, end_date` | Resource load -> query jobs -> open txn detail | Missing resource/date returns validation error | `/api/job-query/export` | Jobs/Txn table columns keep API order and empty-state text | N/A | Date/resource/search filters sync to URL | Selected job row loads txn table with stable state | N/A | Query/search/export remain usable in native route-view | `tests/test_portal_shell_wave_b_native_smoke.py::test_job_query_native_smoke_query_search_export`; `frontend/tests/portal-shell-wave-b-native-smoke.test.js` |
|
||||
| Excel Query (Admin) | `/portal-shell/excel-query` | `table_name, search_column, return_columns` (+ upload) | Upload Excel -> detect type -> execute advanced query | Invalid file / missing required args returns validation error | `/api/excel-query/export-csv` | Result table columns and row count match response payload | N/A | Table/query/date filters sync to URL and persist on refresh | Upload/query/export flow keeps success/error feedback contract | N/A | Upload/detect/query/export parity preserved after native cutover | `tests/test_portal_shell_wave_b_native_smoke.py::test_excel_query_native_smoke_upload_detect_query_export`; `frontend/tests/portal-shell-wave-b-native-smoke.test.js` |
|
||||
| Query Tool (Admin) | `/portal-shell/query-tool` | `input_type`, optional `workcenter_groups`, `equipment_ids`, date range | Resolve -> history -> associations -> equipment-period query | Missing input/container/type triggers deterministic errors | `/api/query-tool/export-csv` | Resolved/history/association/equipment tables stay query-consistent | N/A | Batch/equipment filters sync to URL with multi-value keys | Selection and association state transitions remain deterministic | N/A | Resolve/history/association/equipment workflows remain native-stable | `tests/test_portal_shell_wave_b_native_smoke.py::test_query_tool_native_smoke_resolve_history_association`; `frontend/tests/portal-shell-wave-b-native-smoke.test.js` |
|
||||
| TMTT Defect | `/portal-shell/tmtt-defect` | `start_date, end_date` | Query -> pareto chart select -> detail sort/filter clear | Invalid/empty API payload shows fallback error banner | `/api/tmtt-defect/export` | Detail table sort/filter keeps scope continuity | Pareto/trend charts keep tooltip/legend/link state | Date range and active filter state preserved in view | Chart-table linked filtering resets correctly | N/A | TMTT chart-table parity and export remain stable in shell | `tests/test_portal_shell_wave_b_native_smoke.py::test_tmtt_defect_native_smoke_range_query_and_csv_export`; `frontend/tests/portal-shell-parity-table-chart-matrix.test.js` |
|
||||
|
||||
## No-Iframe Rule
|
||||
|
||||
- Shell content route-view must not render `<iframe>` for any Wave B route.
|
||||
- Regression checks: `frontend/tests/portal-shell-no-iframe.test.js`, `tests/test_cutover_gates.py::test_g4_no_iframe_gate_blocks_if_shell_uses_iframe`.
|
||||
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"generated_at": "2026-02-11T17:46:00+08:00",
|
||||
"scope": "wave-b-native",
|
||||
"routes": [
|
||||
"/job-query",
|
||||
"/excel-query",
|
||||
"/query-tool",
|
||||
"/tmtt-defect"
|
||||
],
|
||||
"execution": {
|
||||
"automated_runs": [
|
||||
{
|
||||
"command": "pytest tests/test_portal_shell_wave_b_native_smoke.py -q",
|
||||
"status": "pass",
|
||||
"evidence": [
|
||||
"tests/test_portal_shell_wave_b_native_smoke.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"command": "npm --prefix frontend test",
|
||||
"status": "pass",
|
||||
"evidence": [
|
||||
"frontend/tests/portal-shell-wave-b-native-smoke.test.js",
|
||||
"frontend/tests/portal-shell-parity-table-chart-matrix.test.js",
|
||||
"frontend/tests/portal-shell-no-iframe.test.js"
|
||||
]
|
||||
}
|
||||
],
|
||||
"manual_replay": "waived",
|
||||
"waiver_reason": "Native rewrite pages now covered by deterministic API + shell route tests"
|
||||
},
|
||||
"pages": {
|
||||
"/job-query": {
|
||||
"status": "pass",
|
||||
"critical_failures": [],
|
||||
"checkpoints": {
|
||||
"table": "pass",
|
||||
"chart": "n/a",
|
||||
"filter": "pass",
|
||||
"interaction": "pass",
|
||||
"matrix": "n/a",
|
||||
"zero_empty": "pass"
|
||||
}
|
||||
},
|
||||
"/excel-query": {
|
||||
"status": "pass",
|
||||
"critical_failures": [],
|
||||
"checkpoints": {
|
||||
"table": "pass",
|
||||
"chart": "n/a",
|
||||
"filter": "pass",
|
||||
"interaction": "pass",
|
||||
"matrix": "n/a",
|
||||
"zero_empty": "pass"
|
||||
}
|
||||
},
|
||||
"/query-tool": {
|
||||
"status": "pass",
|
||||
"critical_failures": [],
|
||||
"checkpoints": {
|
||||
"table": "pass",
|
||||
"chart": "n/a",
|
||||
"filter": "pass",
|
||||
"interaction": "pass",
|
||||
"matrix": "n/a",
|
||||
"zero_empty": "pass"
|
||||
}
|
||||
},
|
||||
"/tmtt-defect": {
|
||||
"status": "pass",
|
||||
"critical_failures": [],
|
||||
"checkpoints": {
|
||||
"table": "pass",
|
||||
"chart": "pass",
|
||||
"filter": "pass",
|
||||
"interaction": "pass",
|
||||
"matrix": "n/a",
|
||||
"zero_empty": "pass"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
{
|
||||
"generated_at": "2026-02-11T17:47:00+08:00",
|
||||
"description": "Wave B native rewrite parity audit for table/chart/filter/interaction/matrix",
|
||||
"policy": {
|
||||
"required_status": "pass",
|
||||
"allow_na": true,
|
||||
"block_on_fail": true
|
||||
},
|
||||
"pages": {
|
||||
"/job-query": {
|
||||
"table": {
|
||||
"status": "pass",
|
||||
"checks": [
|
||||
"job result table columns preserve API key order",
|
||||
"transaction table renders empty state deterministically"
|
||||
]
|
||||
},
|
||||
"chart": {
|
||||
"status": "n/a",
|
||||
"checks": []
|
||||
},
|
||||
"filter": {
|
||||
"status": "pass",
|
||||
"checks": [
|
||||
"resource_ids/start_date/end_date/search sync to URL",
|
||||
"invalid date range blocks query"
|
||||
]
|
||||
},
|
||||
"interaction": {
|
||||
"status": "pass",
|
||||
"checks": [
|
||||
"query then txn load remains in-shell",
|
||||
"export CSV uses current query scope"
|
||||
]
|
||||
},
|
||||
"matrix": {
|
||||
"status": "n/a",
|
||||
"checks": []
|
||||
}
|
||||
},
|
||||
"/excel-query": {
|
||||
"table": {
|
||||
"status": "pass",
|
||||
"checks": [
|
||||
"result table columns equal response columns",
|
||||
"empty result keeps stable headers"
|
||||
]
|
||||
},
|
||||
"chart": {
|
||||
"status": "n/a",
|
||||
"checks": []
|
||||
},
|
||||
"filter": {
|
||||
"status": "pass",
|
||||
"checks": [
|
||||
"table/search/date/query_type/return_columns sync to URL",
|
||||
"missing required fields produce deterministic errors"
|
||||
]
|
||||
},
|
||||
"interaction": {
|
||||
"status": "pass",
|
||||
"checks": [
|
||||
"upload -> detect -> query workflow stable",
|
||||
"export uses active query columns"
|
||||
]
|
||||
},
|
||||
"matrix": {
|
||||
"status": "n/a",
|
||||
"checks": []
|
||||
}
|
||||
},
|
||||
"/query-tool": {
|
||||
"table": {
|
||||
"status": "pass",
|
||||
"checks": [
|
||||
"resolved/history/association/equipment tables keep deterministic columns",
|
||||
"empty query results keep table shell intact"
|
||||
]
|
||||
},
|
||||
"chart": {
|
||||
"status": "n/a",
|
||||
"checks": []
|
||||
},
|
||||
"filter": {
|
||||
"status": "pass",
|
||||
"checks": [
|
||||
"input_type/workcenter_groups/equipment/date filters sync to URL",
|
||||
"selection-required actions show deterministic errors"
|
||||
]
|
||||
},
|
||||
"interaction": {
|
||||
"status": "pass",
|
||||
"checks": [
|
||||
"resolve -> history -> association flow remains coherent",
|
||||
"equipment-period export respects selected query type"
|
||||
]
|
||||
},
|
||||
"matrix": {
|
||||
"status": "n/a",
|
||||
"checks": []
|
||||
}
|
||||
},
|
||||
"/tmtt-defect": {
|
||||
"table": {
|
||||
"status": "pass",
|
||||
"checks": [
|
||||
"detail table sort state stable after chart filter changes",
|
||||
"filter clear restores full table scope"
|
||||
]
|
||||
},
|
||||
"chart": {
|
||||
"status": "pass",
|
||||
"checks": [
|
||||
"pareto and trend charts maintain tooltip behavior",
|
||||
"legend/filter selection remains synchronized with detail table"
|
||||
]
|
||||
},
|
||||
"filter": {
|
||||
"status": "pass",
|
||||
"checks": [
|
||||
"date-range query semantics preserved",
|
||||
"active filter badge reflects chart selection"
|
||||
]
|
||||
},
|
||||
"interaction": {
|
||||
"status": "pass",
|
||||
"checks": [
|
||||
"chart selection narrows detail rows and supports clear",
|
||||
"CSV export follows active date range"
|
||||
]
|
||||
},
|
||||
"matrix": {
|
||||
"status": "n/a",
|
||||
"checks": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"generated_at": "2026-02-11T16:10:00+08:00",
|
||||
"description": "Wave B rewrite entry criteria gates. Native cutover is blocked unless per-page criteria are complete.",
|
||||
"pages": {
|
||||
"/job-query": {
|
||||
"owner": "frontend-mes-reporting",
|
||||
"required_smoke_checks": [
|
||||
"JOB-NATIVE-SMOKE-01",
|
||||
"JOB-NATIVE-SMOKE-02",
|
||||
"JOB-NATIVE-SMOKE-03"
|
||||
],
|
||||
"required_parity_checks": [
|
||||
"table-columns-and-sort",
|
||||
"query-parameter-semantics",
|
||||
"export-content-contract"
|
||||
],
|
||||
"evidence": {
|
||||
"smoke": "pass",
|
||||
"parity": "pass",
|
||||
"telemetry": "pass"
|
||||
},
|
||||
"native_cutover_ready": true,
|
||||
"block_reason": ""
|
||||
},
|
||||
"/excel-query": {
|
||||
"owner": "frontend-mes-reporting",
|
||||
"required_smoke_checks": [
|
||||
"EXCEL-NATIVE-SMOKE-01",
|
||||
"EXCEL-NATIVE-SMOKE-02",
|
||||
"EXCEL-NATIVE-SMOKE-03"
|
||||
],
|
||||
"required_parity_checks": [
|
||||
"upload-parse-contract",
|
||||
"query-result-schema",
|
||||
"export-content-contract"
|
||||
],
|
||||
"evidence": {
|
||||
"smoke": "pass",
|
||||
"parity": "pass",
|
||||
"telemetry": "pass"
|
||||
},
|
||||
"native_cutover_ready": true,
|
||||
"block_reason": ""
|
||||
},
|
||||
"/query-tool": {
|
||||
"owner": "frontend-mes-reporting",
|
||||
"required_smoke_checks": [
|
||||
"QTOOL-NATIVE-SMOKE-01",
|
||||
"QTOOL-NATIVE-SMOKE-02",
|
||||
"QTOOL-NATIVE-SMOKE-03"
|
||||
],
|
||||
"required_parity_checks": [
|
||||
"resolve-history-association-contract",
|
||||
"date-range-validation",
|
||||
"state-continuity"
|
||||
],
|
||||
"evidence": {
|
||||
"smoke": "pass",
|
||||
"parity": "pass",
|
||||
"telemetry": "pass"
|
||||
},
|
||||
"native_cutover_ready": true,
|
||||
"block_reason": ""
|
||||
},
|
||||
"/tmtt-defect": {
|
||||
"owner": "frontend-mes-reporting",
|
||||
"required_smoke_checks": [
|
||||
"TMTT-NATIVE-SMOKE-01",
|
||||
"TMTT-NATIVE-SMOKE-02",
|
||||
"TMTT-NATIVE-SMOKE-03"
|
||||
],
|
||||
"required_parity_checks": [
|
||||
"range-query-contract",
|
||||
"chart-detail-linkage",
|
||||
"csv-export-contract"
|
||||
],
|
||||
"evidence": {
|
||||
"smoke": "pass",
|
||||
"parity": "pass",
|
||||
"telemetry": "pass"
|
||||
},
|
||||
"native_cutover_ready": true,
|
||||
"block_reason": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
# Wave B Rewrite Entry Criteria and Native Cutover Gate
|
||||
|
||||
Last updated: 2026-02-11
|
||||
|
||||
Source of truth: `wave-b-rewrite-entry-criteria.json`
|
||||
|
||||
## Gate Rule
|
||||
|
||||
- If a Wave B route is switched to `render_mode=native` while `native_cutover_ready=false`, cutover validation must fail.
|
||||
- `native_cutover_ready=true` requires:
|
||||
- `evidence.smoke = pass`
|
||||
- `evidence.parity = pass`
|
||||
- `evidence.telemetry = pass` or `n/a`
|
||||
|
||||
## Current Status
|
||||
|
||||
| Route | Smoke Evidence | Parity Evidence | Telemetry Evidence | Native Cutover Ready |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `/job-query` | pass | pass | pass | true |
|
||||
| `/excel-query` | pass | pass | pass | true |
|
||||
| `/query-tool` | pass | pass | pass | true |
|
||||
| `/tmtt-defect` | pass | pass | pass | true |
|
||||
|
||||
Current policy outcome: all Wave B pages meet native cutover entry criteria.
|
||||
Reference in New Issue
Block a user