feat: finalize no-iframe portal shell route-view migration

This commit is contained in:
egg
2026-02-11 17:07:50 +08:00
parent ccab10bee8
commit 1e7f8f4498
100 changed files with 8794 additions and 642 deletions

View File

@@ -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"
}
}
}

View File

@@ -0,0 +1,5 @@
{
"generated_at": "2026-02-11T07:44:03+00:00",
"source": "data/page_status.json",
"errors": []
}

View File

@@ -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
}
]
}
]
}

View File

@@ -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"
]
}
}
}

View File

@@ -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"
}
}
}

View File

@@ -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"
]
}
]
}

View File

@@ -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`

View File

@@ -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

View File

@@ -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.

View File

@@ -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.

View File

@@ -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

View File

@@ -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.

View File

@@ -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.

View File

@@ -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"
}
]
}

View File

@@ -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.

View File

@@ -0,0 +1,4 @@
{
"generated_at": "2026-02-11T07:44:03+00:00",
"errors": []
}

View File

@@ -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.

View File

@@ -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"
}
]
}

View File

@@ -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.

View File

@@ -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"
}
}
}
}

View File

@@ -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`.

View File

@@ -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"
}
}
}
}

View File

@@ -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": []
}
}
}
}

View File

@@ -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": ""
}
}
}

View File

@@ -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.