fix(query-tool): batch detail loading, UX polish, and docs cleanup
- Fix multi-WO display: auto-select all tree roots after resolve so detail panel loads data for every work order, not just the first seed CID - Disable scroll-wheel zoom on lineage tree (roam: 'move') to prevent accidental layout jumps while preserving drag-pan - Add batch API endpoints (get_lot_history_batch, get_lot_associations_batch) to avoid N parallel requests hitting rate limits - Remove redundant Split sub-tab from LOT detail (tree already shows splits) - Rename 退貨 → 報廢 to match actual reject/scrap data semantics - Hide internal ID columns (CONTAINERID, EQUIPMENTID, RESOURCEID) from history table display - Add timeline scroll container and time range header for long timelines - Remove obsolete migration and architecture docs no longer needed Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,27 +0,0 @@
|
||||
# Deferred Route Modernization Follow-up Artifacts
|
||||
|
||||
This directory stores execution artifacts for `deferred-route-modernization-follow-up`.
|
||||
|
||||
## Upstream Reference
|
||||
|
||||
- Phase 1: `docs/migration/full-modernization-architecture-blueprint/`
|
||||
- Handoff: `docs/migration/full-modernization-architecture-blueprint/deferred_route_handoff.md`
|
||||
|
||||
## Core Governance
|
||||
|
||||
- `route_scope_matrix.json`: frozen in-scope deferred route matrix (promoted from phase 1 deferred).
|
||||
- `governance_milestones.md`: completion and deprecation milestones for deferred-route phase.
|
||||
- `exception_registry.json`: approved temporary exceptions with owner and milestone.
|
||||
- `upstream_linkage.json`: explicit linkage to phase 1 handoff artifacts.
|
||||
- `scope_boundary_note.md`: clarification that dev routes are eligible for modernization.
|
||||
|
||||
## Pre-Change Confirmation
|
||||
|
||||
- `pre_change_confirmation_template.md`: required fields and template.
|
||||
- `pre_change_confirmations.json`: recorded per-route confirmations.
|
||||
|
||||
## Rollout Operations
|
||||
|
||||
- `rollout_runbook.md`: phase steps and hold points for deferred-route cutover.
|
||||
- `rollback_controls.md`: per-route rollback and false-positive gate handling.
|
||||
- `observability_checkpoints.md`: route/gate/rollback observability contract.
|
||||
@@ -1,42 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"change": "deferred-route-modernization-follow-up",
|
||||
"fields": [
|
||||
"id",
|
||||
"type",
|
||||
"scope",
|
||||
"owner",
|
||||
"introduced_by",
|
||||
"reason",
|
||||
"mitigation",
|
||||
"status",
|
||||
"milestone",
|
||||
"tracking_issue"
|
||||
],
|
||||
"entries": [
|
||||
{
|
||||
"id": "style-excel-query-shell-tokens-no-fallback",
|
||||
"type": "style",
|
||||
"scope": "/excel-query",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"introduced_by": "legacy-template",
|
||||
"reason": "excel-query uses shell tokens (--portal-brand-start, --portal-brand-end, --portal-shadow-panel) without CSS fallback values; inherited from legacy era before shell token governance",
|
||||
"mitigation": "add fallback values during content modernization cutover for /excel-query",
|
||||
"status": "approved-temporary",
|
||||
"milestone": "2026-03-19",
|
||||
"tracking_issue": "deferred-route-modernization-follow-up/excel-query-style-hardening"
|
||||
},
|
||||
{
|
||||
"id": "style-query-tool-shell-tokens-no-fallback",
|
||||
"type": "style",
|
||||
"scope": "/query-tool",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"introduced_by": "legacy-template",
|
||||
"reason": "query-tool uses shell tokens (--portal-brand-start, --portal-brand-end, --portal-shadow-panel) without CSS fallback values; inherited from legacy era before shell token governance",
|
||||
"mitigation": "add fallback values during content modernization cutover for /query-tool",
|
||||
"status": "approved-temporary",
|
||||
"milestone": "2026-03-19",
|
||||
"tracking_issue": "deferred-route-modernization-follow-up/query-tool-style-hardening"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
# Deferred Route Modernization Governance Milestones
|
||||
|
||||
## Upstream Reference
|
||||
|
||||
- Phase 1: `full-modernization-architecture-blueprint`
|
||||
- Handoff: `docs/migration/full-modernization-architecture-blueprint/deferred_route_handoff.md`
|
||||
|
||||
## Phase Completion Criteria
|
||||
|
||||
A phase is complete only when all criteria below are true:
|
||||
|
||||
1. Route governance: 100% of in-scope deferred routes in `route_scope_matrix.json` have valid shell contract metadata and ownership with scope promoted to `in-scope`.
|
||||
2. Style governance: deferred route-local styles do not introduce page-global selectors (`:root`, `body`) unless recorded in exception registry.
|
||||
3. Quality governance: functional parity, visual checkpoints, accessibility checks, and performance budgets pass at configured gate severity.
|
||||
4. Content safety governance: page-content parity evidence + manual acceptance sign-off exist for each migrated deferred route.
|
||||
5. Bug carry-over governance: known-bug replay checks for migrated scope do not reproduce legacy defects.
|
||||
6. Pre-change confirmation: each deferred route has an approved pre-change confirmation record before implementation begins.
|
||||
|
||||
## Legacy Deprecation Milestones
|
||||
|
||||
- 2026-02-19: deferred route contract CI completeness gate enabled in `warn` mode.
|
||||
- 2026-02-26: deferred route contract CI completeness gate promoted to `block` mode.
|
||||
- 2026-03-05: deferred route asset readiness gate promoted to `block` mode.
|
||||
- 2026-03-12: runtime fallback posture retired for deferred routes in production policy.
|
||||
- 2026-03-19: unresolved style exceptions past milestone fail modernization review.
|
||||
|
||||
## Route Cutover Sequence
|
||||
|
||||
Routes are cut over one at a time in the following planned order:
|
||||
|
||||
1. `/tables`
|
||||
2. `/excel-query`
|
||||
3. `/query-tool`
|
||||
4. `/mid-section-defect`
|
||||
|
||||
Next route cutover is blocked until current route has:
|
||||
- Parity pass (golden fixtures + interaction checks)
|
||||
- Manual acceptance sign-off
|
||||
- Known-bug replay pass
|
||||
@@ -1,44 +0,0 @@
|
||||
# Deferred Route Modernization Observability Checkpoints
|
||||
|
||||
## Route Governance Signals
|
||||
|
||||
1. `navigation_contract_mismatch_total`
|
||||
- Source: `/api/portal/navigation` diagnostics.
|
||||
- Alert condition: non-zero for deferred-promoted routes.
|
||||
|
||||
2. `route_contract_missing_metadata_total`
|
||||
- Source: route governance CI script.
|
||||
- Alert condition: >0 in block mode for `/tables`, `/excel-query`, `/query-tool`, `/mid-section-defect`.
|
||||
|
||||
## Quality Gate Signals
|
||||
|
||||
1. `quality_gate_failed_total{gate_id}`
|
||||
- Source: quality gate report.
|
||||
- Alert condition: any mandatory gate failed for deferred-promoted routes.
|
||||
|
||||
2. `manual_acceptance_pending_routes`
|
||||
- Source: manual acceptance records.
|
||||
- Alert condition: cutover attempted with pending sign-off for deferred routes.
|
||||
|
||||
3. `pre_change_confirmation_missing`
|
||||
- Source: pre-change confirmation records.
|
||||
- Alert condition: implementation started without recorded confirmation.
|
||||
|
||||
## Fallback and Rollback Signals
|
||||
|
||||
1. `deferred_route_runtime_fallback_served_total`
|
||||
- Should remain zero after fallback retirement milestone for each route.
|
||||
|
||||
2. `content_cutover_flag_rollbacks_total{route}`
|
||||
- Track frequency per deferred route.
|
||||
|
||||
3. `legacy_bug_replay_failures_total{route}`
|
||||
- Any non-zero indicates carry-over risk and blocks sign-off.
|
||||
|
||||
## Cutover Sequence Signals
|
||||
|
||||
1. `deferred_route_cutover_sequence_violation`
|
||||
- Alert condition: route cutover attempted out of planned sequence.
|
||||
|
||||
2. `deferred_route_signoff_blocked_by_bug_replay`
|
||||
- Alert condition: sign-off blocked due to reproduced legacy bug.
|
||||
@@ -1,35 +0,0 @@
|
||||
# Pre-Change Confirmation Template (Deferred Route)
|
||||
|
||||
## Rule
|
||||
|
||||
Before any implementation work begins on a deferred route, a route-scoped pre-change confirmation MUST be recorded and approved. Implementation is BLOCKED until confirmation exists.
|
||||
|
||||
## Required Fields
|
||||
|
||||
1. **Route**: The deferred route path (e.g., `/tables`).
|
||||
2. **Status Snapshot**: Current route status in page registry (e.g., `dev`, `released`).
|
||||
3. **Scope Boundary Check**: Confirmation that the route is listed in `route_scope_matrix.json` as in-scope for this change.
|
||||
4. **Contract Baseline Refs**: References to existing route contracts and content contracts that define expected behavior.
|
||||
5. **Known-Bug Baseline Ref**: Reference to `known_bug_baseline.json` entry for this route (or confirmation that baseline is initialized).
|
||||
6. **Rollback Flag Plan**: Planned feature flag key and rollback strategy for this route's cutover.
|
||||
7. **Owner**: The person/team responsible for this route's modernization.
|
||||
8. **Date**: Date of confirmation.
|
||||
9. **Approved By**: Reviewer who approved the pre-change confirmation.
|
||||
|
||||
## Template
|
||||
|
||||
```
|
||||
Route: /<route-name>
|
||||
Status Snapshot: <dev|released>
|
||||
Scope Boundary Check: confirmed in route_scope_matrix.json as in-scope
|
||||
Contract Baseline Refs:
|
||||
- Route contract: route_contracts.json#/<route-name>
|
||||
- Content contract: route_content_contracts.json#/<route-name>
|
||||
Known-Bug Baseline Ref: known_bug_baseline.json#/<route-name>
|
||||
Rollback Flag Plan:
|
||||
- Feature flag: modernization_feature_flags.json#/<route-name>.content_cutover_enabled
|
||||
- Rollback strategy: fallback_to_legacy_route
|
||||
Owner: <owner>
|
||||
Date: <YYYY-MM-DD>
|
||||
Approved By: <reviewer>
|
||||
```
|
||||
@@ -1,85 +0,0 @@
|
||||
{
|
||||
"change": "deferred-route-modernization-follow-up",
|
||||
"rule": "implementation is blocked for a route until its pre-change confirmation is recorded and approved",
|
||||
"required_fields": [
|
||||
"route",
|
||||
"status_snapshot",
|
||||
"scope_boundary_check",
|
||||
"contract_baseline_refs",
|
||||
"known_bug_baseline_ref",
|
||||
"rollback_flag_plan",
|
||||
"owner",
|
||||
"date",
|
||||
"approved_by"
|
||||
],
|
||||
"records": [
|
||||
{
|
||||
"route": "/tables",
|
||||
"status_snapshot": "dev",
|
||||
"scope_boundary_check": "confirmed in route_scope_matrix.json as in-scope (promoted from deferred)",
|
||||
"contract_baseline_refs": {
|
||||
"route_contract": "route_contracts.json#/tables",
|
||||
"content_contract": "route_content_contracts.json#/tables"
|
||||
},
|
||||
"known_bug_baseline_ref": "known_bug_baseline.json#/tables",
|
||||
"rollback_flag_plan": {
|
||||
"feature_flag": "modernization_feature_flags.json#/tables.content_cutover_enabled",
|
||||
"rollback_strategy": "fallback_to_legacy_route"
|
||||
},
|
||||
"owner": "frontend-mes-reporting",
|
||||
"date": "2026-02-12",
|
||||
"approved_by": "deferred-route-modernization-follow-up"
|
||||
},
|
||||
{
|
||||
"route": "/excel-query",
|
||||
"status_snapshot": "dev",
|
||||
"scope_boundary_check": "confirmed in route_scope_matrix.json as in-scope (promoted from deferred)",
|
||||
"contract_baseline_refs": {
|
||||
"route_contract": "route_contracts.json#/excel-query",
|
||||
"content_contract": "route_content_contracts.json#/excel-query"
|
||||
},
|
||||
"known_bug_baseline_ref": "known_bug_baseline.json#/excel-query",
|
||||
"rollback_flag_plan": {
|
||||
"feature_flag": "modernization_feature_flags.json#/excel-query.content_cutover_enabled",
|
||||
"rollback_strategy": "fallback_to_legacy_route"
|
||||
},
|
||||
"owner": "frontend-mes-reporting",
|
||||
"date": "2026-02-12",
|
||||
"approved_by": "deferred-route-modernization-follow-up"
|
||||
},
|
||||
{
|
||||
"route": "/query-tool",
|
||||
"status_snapshot": "dev",
|
||||
"scope_boundary_check": "confirmed in route_scope_matrix.json as in-scope (promoted from deferred)",
|
||||
"contract_baseline_refs": {
|
||||
"route_contract": "route_contracts.json#/query-tool",
|
||||
"content_contract": "route_content_contracts.json#/query-tool"
|
||||
},
|
||||
"known_bug_baseline_ref": "known_bug_baseline.json#/query-tool",
|
||||
"rollback_flag_plan": {
|
||||
"feature_flag": "modernization_feature_flags.json#/query-tool.content_cutover_enabled",
|
||||
"rollback_strategy": "fallback_to_legacy_route"
|
||||
},
|
||||
"owner": "frontend-mes-reporting",
|
||||
"date": "2026-02-12",
|
||||
"approved_by": "deferred-route-modernization-follow-up"
|
||||
},
|
||||
{
|
||||
"route": "/mid-section-defect",
|
||||
"status_snapshot": "dev",
|
||||
"scope_boundary_check": "confirmed in route_scope_matrix.json as in-scope (promoted from deferred)",
|
||||
"contract_baseline_refs": {
|
||||
"route_contract": "route_contracts.json#/mid-section-defect",
|
||||
"content_contract": "route_content_contracts.json#/mid-section-defect"
|
||||
},
|
||||
"known_bug_baseline_ref": "known_bug_baseline.json#/mid-section-defect",
|
||||
"rollback_flag_plan": {
|
||||
"feature_flag": "modernization_feature_flags.json#/mid-section-defect.content_cutover_enabled",
|
||||
"rollback_strategy": "fallback_to_legacy_route"
|
||||
},
|
||||
"owner": "frontend-mes-reporting",
|
||||
"date": "2026-02-12",
|
||||
"approved_by": "deferred-route-modernization-follow-up"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
# Deferred Route Modernization Rollback Controls
|
||||
|
||||
## Route-Level Reversion Controls
|
||||
|
||||
- **Content cutover feature flag**: Set `content_cutover_enabled: false` in `data/modernization_feature_flags.json` for the affected route to immediately revert to legacy content path.
|
||||
- **PORTAL_SPA_ENABLED=false**: Disable shell-first navigation runtime globally (affects all routes).
|
||||
- **Route-scoped contract fallback**: Mark route contract with fallback strategy and redeploy shell assets.
|
||||
|
||||
## Per-Route Rollback Procedure
|
||||
|
||||
1. Set `content_cutover_enabled: false` for the affected route in `modernization_feature_flags.json`.
|
||||
2. Restart workers to pick up the flag change.
|
||||
3. Verify legacy content path is serving correctly.
|
||||
4. Record rollback in manual acceptance records with reason and timestamp.
|
||||
5. Investigate root cause before re-enabling cutover.
|
||||
|
||||
## False-Positive Gate Handling
|
||||
|
||||
1. Capture failing gate output and route impact.
|
||||
2. Confirm whether failure is test flake or product defect.
|
||||
3. If false-positive and production risk is high:
|
||||
- Temporarily switch gate severity from `block` to `warn`.
|
||||
- Record waiver with owner, reason, expiry.
|
||||
4. Restore `block` mode after corrective action.
|
||||
|
||||
## Required Rollback Evidence
|
||||
|
||||
- Incident timestamp and impacted route.
|
||||
- Gate IDs that triggered rollback.
|
||||
- Feature flag state before/after rollback.
|
||||
- Manual acceptance and known-bug replay references.
|
||||
@@ -1,47 +0,0 @@
|
||||
# Deferred Route Modernization Rollout Runbook
|
||||
|
||||
## Upstream Reference
|
||||
|
||||
- Phase 1 runbook: `docs/migration/full-modernization-architecture-blueprint/rollout_runbook.md`
|
||||
|
||||
## Phase Sequence
|
||||
|
||||
1. Governance freeze
|
||||
- Confirm `route_scope_matrix.json` has deferred routes promoted to in-scope.
|
||||
- Confirm pre-change confirmations recorded for all 4 routes.
|
||||
- Confirm exception registry has no unresolved blocking entries.
|
||||
|
||||
2. Route governance enforcement
|
||||
- Run route contract completeness checks in warn mode.
|
||||
- Fix all deferred-route metadata gaps.
|
||||
- Promote route governance checks to block mode.
|
||||
|
||||
3. Per-route content modernization (sequential)
|
||||
- Enable content cutover flag for first route (`/tables`).
|
||||
- Execute parity checks and manual acceptance.
|
||||
- Run known-bug replay checks.
|
||||
- On pass: sign off and proceed to next route.
|
||||
- On fail: rollback flag and investigate.
|
||||
|
||||
4. Cutover sequence
|
||||
- `/tables` -> `/excel-query` -> `/query-tool` -> `/mid-section-defect`
|
||||
- Next route blocked until current route has approved sign-off.
|
||||
|
||||
5. Asset/gate enforcement
|
||||
- Validate deferred route asset readiness.
|
||||
- Run quality gate suite (functional, visual, accessibility, performance).
|
||||
- Promote gate severity from warn to block per milestones.
|
||||
|
||||
6. Fallback retirement
|
||||
- Retire runtime fallback for deferred routes after all acceptance gates pass.
|
||||
|
||||
## Hold Points
|
||||
|
||||
- Hold-1: Any deferred route missing contract metadata or pre-change confirmation.
|
||||
- Hold-2: Any parity failure or known-bug replay failure.
|
||||
- Hold-3: Any mandatory quality gate failure in block mode.
|
||||
- Hold-4: Cutover attempted before previous route sign-off complete.
|
||||
|
||||
## Promotion Rule
|
||||
|
||||
Promotion is allowed only when all hold points are clear for the current route in sequence.
|
||||
@@ -1,100 +0,0 @@
|
||||
{
|
||||
"change": "deferred-route-modernization-follow-up",
|
||||
"upstream_change": "full-modernization-architecture-blueprint",
|
||||
"generated_at": "2026-02-12T00:00:00Z",
|
||||
"phase": "phase-2-deferred-route-modernization",
|
||||
"policy": {
|
||||
"scope_is_frozen": true,
|
||||
"out_of_scope_tasks_must_be_rejected": true,
|
||||
"dev_routes_are_eligible": true,
|
||||
"released_only_restriction_does_not_apply": true
|
||||
},
|
||||
"in_scope": [
|
||||
{
|
||||
"route": "/tables",
|
||||
"category": "report",
|
||||
"canonical_shell_path": "/portal-shell/tables",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"prior_scope": "deferred",
|
||||
"prior_change": "full-modernization-architecture-blueprint"
|
||||
},
|
||||
{
|
||||
"route": "/excel-query",
|
||||
"category": "report",
|
||||
"canonical_shell_path": "/portal-shell/excel-query",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"prior_scope": "deferred",
|
||||
"prior_change": "full-modernization-architecture-blueprint"
|
||||
},
|
||||
{
|
||||
"route": "/query-tool",
|
||||
"category": "report",
|
||||
"canonical_shell_path": "/portal-shell/query-tool",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"prior_scope": "deferred",
|
||||
"prior_change": "full-modernization-architecture-blueprint"
|
||||
},
|
||||
{
|
||||
"route": "/mid-section-defect",
|
||||
"category": "report",
|
||||
"canonical_shell_path": "/portal-shell/mid-section-defect",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"prior_scope": "deferred",
|
||||
"prior_change": "full-modernization-architecture-blueprint"
|
||||
}
|
||||
],
|
||||
"out_of_scope": [
|
||||
{
|
||||
"route": "/wip-overview",
|
||||
"reason": "completed-in-phase-1"
|
||||
},
|
||||
{
|
||||
"route": "/wip-detail",
|
||||
"reason": "completed-in-phase-1"
|
||||
},
|
||||
{
|
||||
"route": "/hold-overview",
|
||||
"reason": "completed-in-phase-1"
|
||||
},
|
||||
{
|
||||
"route": "/hold-detail",
|
||||
"reason": "completed-in-phase-1"
|
||||
},
|
||||
{
|
||||
"route": "/hold-history",
|
||||
"reason": "completed-in-phase-1"
|
||||
},
|
||||
{
|
||||
"route": "/resource",
|
||||
"reason": "completed-in-phase-1"
|
||||
},
|
||||
{
|
||||
"route": "/resource-history",
|
||||
"reason": "completed-in-phase-1"
|
||||
},
|
||||
{
|
||||
"route": "/qc-gate",
|
||||
"reason": "completed-in-phase-1"
|
||||
},
|
||||
{
|
||||
"route": "/job-query",
|
||||
"reason": "completed-in-phase-1"
|
||||
},
|
||||
{
|
||||
"route": "/tmtt-defect",
|
||||
"reason": "completed-in-phase-1"
|
||||
},
|
||||
{
|
||||
"route": "/admin/pages",
|
||||
"reason": "completed-in-phase-1"
|
||||
},
|
||||
{
|
||||
"route": "/admin/performance",
|
||||
"reason": "completed-in-phase-1"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
# Scope Boundary Note
|
||||
|
||||
## Change
|
||||
|
||||
`deferred-route-modernization-follow-up`
|
||||
|
||||
## Scope Clarification
|
||||
|
||||
Deferred routes (`/tables`, `/excel-query`, `/query-tool`, `/mid-section-defect`) are **in-scope** for this follow-up change regardless of their current page status (`dev` or `released`).
|
||||
|
||||
The **released-only restriction does not apply** to this change. These routes were intentionally deferred from phase 1 to control blast radius and are now the explicit modernization target.
|
||||
|
||||
## What Is In-Scope
|
||||
|
||||
- `/tables` — currently `dev` in page registry
|
||||
- `/excel-query` — currently `dev` in page registry
|
||||
- `/query-tool` — currently `dev` in page registry
|
||||
- `/mid-section-defect` — currently `dev` in page registry
|
||||
|
||||
## What Is NOT In-Scope
|
||||
|
||||
- Phase-1 routes that are already modernized and governed (10 report + 2 admin routes)
|
||||
- Routes outside the deferred matrix
|
||||
- Backend business data semantics beyond compatibility safeguards
|
||||
- Unrelated admin/report features not in the deferred matrix
|
||||
|
||||
## Policy
|
||||
|
||||
- Phase-1 in-scope routes SHALL NOT be reopened by this change unless explicitly required for shared governance wiring.
|
||||
- Deferred routes adopt identical governance rigor (contracts, parity, manual acceptance, bug replay) as phase-1 routes.
|
||||
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"change": "deferred-route-modernization-follow-up",
|
||||
"upstream_change": "full-modernization-architecture-blueprint",
|
||||
"handoff_artifact": "docs/migration/full-modernization-architecture-blueprint/deferred_route_handoff.md",
|
||||
"consumed_artifacts": {
|
||||
"scope_boundary": "docs/migration/full-modernization-architecture-blueprint/route_scope_matrix.json",
|
||||
"parity_fixtures": "docs/migration/full-modernization-architecture-blueprint/parity_golden_fixtures.json",
|
||||
"interaction_parity_checks": "docs/migration/full-modernization-architecture-blueprint/interaction_parity_checks.json",
|
||||
"manual_acceptance_checklist": "docs/migration/full-modernization-architecture-blueprint/page_content_manual_acceptance_checklist.md",
|
||||
"known_bug_baseline": "docs/migration/full-modernization-architecture-blueprint/known_bug_baseline.json",
|
||||
"bug_revalidation_records": "docs/migration/full-modernization-architecture-blueprint/bug_revalidation_records.json",
|
||||
"quality_gate_policy": "docs/migration/full-modernization-architecture-blueprint/quality_gate_policy.json",
|
||||
"governance_milestones": "docs/migration/full-modernization-architecture-blueprint/governance_milestones.md",
|
||||
"asset_readiness_manifest": "docs/migration/full-modernization-architecture-blueprint/asset_readiness_manifest.json"
|
||||
},
|
||||
"transfer_rules": [
|
||||
"Deferred routes remain excluded from phase-1 blocking criteria",
|
||||
"Follow-up change MUST promote these routes to in-scope before legacy retirement",
|
||||
"Equivalent parity/manual-acceptance/bug-revalidation gates must be applied"
|
||||
],
|
||||
"deferred_routes": [
|
||||
"/tables",
|
||||
"/excel-query",
|
||||
"/query-tool",
|
||||
"/mid-section-defect"
|
||||
]
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
# Full Modernization Architecture Blueprint Artifacts
|
||||
|
||||
This directory stores execution artifacts for `full-modernization-architecture-blueprint`.
|
||||
|
||||
## Core Governance
|
||||
|
||||
- `route_scope_matrix.json`: frozen in-scope/deferred route contract matrix.
|
||||
- `governance_milestones.md`: completion and deprecation milestones.
|
||||
- `exception_registry.json`: approved temporary exceptions with owner and milestone.
|
||||
- Policy artifact runtime cache model:
|
||||
- `src/mes_dashboard/core/modernization_policy.py` caches `route_scope_matrix.json` and
|
||||
`asset_readiness_manifest.json` in-process with `lru_cache`.
|
||||
- Runtime behavior is restart-refresh by default: JSON edits take effect after worker restart.
|
||||
- Controlled refresh is available through `clear_modernization_policy_cache()` for tests or
|
||||
explicit maintenance hooks; no automatic file watcher/hot reload is active in production.
|
||||
|
||||
## Content Modernization Safety
|
||||
|
||||
- `page_content_manual_acceptance_checklist.md`: mandatory manual sign-off checklist.
|
||||
- `known_bug_baseline.json`: route-level known bug baseline and replay blocking policy.
|
||||
|
||||
## Rollout Operations
|
||||
|
||||
- `rollout_runbook.md`: phase steps and hold points.
|
||||
- `rollback_controls.md`: rollback and false-positive gate handling.
|
||||
- `observability_checkpoints.md`: route/gate/rollback observability contract.
|
||||
- `deferred_route_handoff.md`: explicit handoff package to deferred-route follow-up change.
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"change": "full-modernization-architecture-blueprint",
|
||||
"in_scope_required_assets": {
|
||||
"/portal-shell": ["portal-shell.html", "portal-shell.js", "portal-shell.css", "tailwind.css"],
|
||||
"/wip-overview": ["wip-overview.html", "wip-overview.js"],
|
||||
"/wip-detail": ["wip-detail.html", "wip-detail.js"],
|
||||
"/hold-overview": ["hold-overview.html", "hold-overview.js"],
|
||||
"/hold-detail": ["hold-detail.html", "hold-detail.js"],
|
||||
"/hold-history": ["hold-history.html", "hold-history.js"],
|
||||
"/resource": ["resource-status.html", "resource-status.js"],
|
||||
"/resource-history": ["resource-history.html", "resource-history.js"],
|
||||
"/qc-gate": ["qc-gate.html", "qc-gate.js"],
|
||||
"/job-query": ["job-query.js"],
|
||||
"/tmtt-defect": ["tmtt-defect.js"],
|
||||
"/tables": ["tables.html", "tables.js"],
|
||||
"/excel-query": ["excel-query.js"],
|
||||
"/query-tool": ["query-tool.js"],
|
||||
"/mid-section-defect": ["mid-section-defect.html", "mid-section-defect.js"]
|
||||
},
|
||||
"deferred_routes": []
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"change": "full-modernization-architecture-blueprint",
|
||||
"records": [],
|
||||
"schema": {
|
||||
"route": "string",
|
||||
"known_bug_id": "string",
|
||||
"replay_date": "YYYY-MM-DD",
|
||||
"result": "pass|fail",
|
||||
"notes": "string",
|
||||
"signoff_owner": "string"
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"change": "full-modernization-architecture-blueprint",
|
||||
"canonical_policy": {
|
||||
"applies_when": "PORTAL_SPA_ENABLED=true",
|
||||
"report_routes": "redirect direct route entry to /portal-shell/<route>",
|
||||
"admin_routes": "shell target redirects to backend /admin/* while backend keeps auth authority"
|
||||
},
|
||||
"direct_entry_compatibility": {
|
||||
"query_semantics_must_be_preserved": true,
|
||||
"redirect_status_code": 302
|
||||
},
|
||||
"in_scope_report_routes": [
|
||||
"/wip-overview",
|
||||
"/wip-detail",
|
||||
"/hold-overview",
|
||||
"/hold-detail",
|
||||
"/hold-history",
|
||||
"/resource",
|
||||
"/resource-history",
|
||||
"/qc-gate",
|
||||
"/job-query",
|
||||
"/tmtt-defect",
|
||||
"/tables",
|
||||
"/excel-query",
|
||||
"/query-tool",
|
||||
"/mid-section-defect"
|
||||
]
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
# Deferred Route Handoff (Phase 1 -> Follow-up)
|
||||
|
||||
## Source Change
|
||||
|
||||
- `openspec/changes/full-modernization-architecture-blueprint/`
|
||||
|
||||
## Deferred Routes (Not in Phase 1 Blocking Scope)
|
||||
|
||||
- `/tables`
|
||||
- `/excel-query`
|
||||
- `/query-tool`
|
||||
- `/mid-section-defect`
|
||||
|
||||
## Follow-up Change
|
||||
|
||||
- `openspec/changes/deferred-route-modernization-follow-up/`
|
||||
|
||||
## Handoff Content
|
||||
|
||||
1. Scope boundary contract:
|
||||
- Source: `docs/migration/full-modernization-architecture-blueprint/route_scope_matrix.json`
|
||||
|
||||
2. Required acceptance model to carry forward:
|
||||
- Parity fixtures/checks:
|
||||
- `docs/migration/full-modernization-architecture-blueprint/parity_golden_fixtures.json`
|
||||
- `docs/migration/full-modernization-architecture-blueprint/interaction_parity_checks.json`
|
||||
- Manual acceptance + bug replay:
|
||||
- `docs/migration/full-modernization-architecture-blueprint/page_content_manual_acceptance_checklist.md`
|
||||
- `docs/migration/full-modernization-architecture-blueprint/known_bug_baseline.json`
|
||||
- `docs/migration/full-modernization-architecture-blueprint/bug_revalidation_records.json`
|
||||
|
||||
3. Governance policy to carry forward:
|
||||
- `docs/migration/full-modernization-architecture-blueprint/quality_gate_policy.json`
|
||||
- `docs/migration/full-modernization-architecture-blueprint/governance_milestones.md`
|
||||
- `docs/migration/full-modernization-architecture-blueprint/asset_readiness_manifest.json`
|
||||
|
||||
## Transfer Rule
|
||||
|
||||
- Deferred routes remain excluded from phase-1 blocking criteria.
|
||||
- Follow-up change MUST promote these routes to in-scope and apply equivalent parity/manual-acceptance/bug-revalidation gates before legacy retirement.
|
||||
@@ -1,66 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"change": "full-modernization-architecture-blueprint",
|
||||
"fields": [
|
||||
"id",
|
||||
"type",
|
||||
"scope",
|
||||
"owner",
|
||||
"introduced_by",
|
||||
"reason",
|
||||
"mitigation",
|
||||
"status",
|
||||
"milestone",
|
||||
"tracking_issue"
|
||||
],
|
||||
"entries": [
|
||||
{
|
||||
"id": "style-admin-pages-inline-css",
|
||||
"type": "style",
|
||||
"scope": "/admin/pages",
|
||||
"owner": "frontend-platform-admin",
|
||||
"introduced_by": "legacy-template",
|
||||
"reason": "admin pages remain backend-rendered in this phase",
|
||||
"mitigation": "enforce shell contract governance while retaining backend auth authority",
|
||||
"status": "approved-temporary",
|
||||
"milestone": "2026-03-19",
|
||||
"tracking_issue": "deferred-route-modernization-follow-up/admin-template-modernization"
|
||||
},
|
||||
{
|
||||
"id": "style-admin-performance-inline-css",
|
||||
"type": "style",
|
||||
"scope": "/admin/performance",
|
||||
"owner": "frontend-platform-admin",
|
||||
"introduced_by": "legacy-template",
|
||||
"reason": "admin performance remains backend-rendered in this phase",
|
||||
"mitigation": "governed navigation + route-level fallback controls",
|
||||
"status": "approved-temporary",
|
||||
"milestone": "2026-03-19",
|
||||
"tracking_issue": "deferred-route-modernization-follow-up/admin-template-modernization"
|
||||
},
|
||||
{
|
||||
"id": "style-excel-query-shell-tokens-no-fallback",
|
||||
"type": "style",
|
||||
"scope": "/excel-query",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"introduced_by": "legacy-template",
|
||||
"reason": "shell tokens without CSS fallback values; inherited from legacy era",
|
||||
"mitigation": "add fallback values during content modernization cutover",
|
||||
"status": "approved-temporary",
|
||||
"milestone": "2026-03-19",
|
||||
"tracking_issue": "deferred-route-modernization-follow-up/excel-query-style-hardening"
|
||||
},
|
||||
{
|
||||
"id": "style-query-tool-shell-tokens-no-fallback",
|
||||
"type": "style",
|
||||
"scope": "/query-tool",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"introduced_by": "legacy-template",
|
||||
"reason": "shell tokens without CSS fallback values; inherited from legacy era",
|
||||
"mitigation": "add fallback values during content modernization cutover",
|
||||
"status": "approved-temporary",
|
||||
"milestone": "2026-03-19",
|
||||
"tracking_issue": "deferred-route-modernization-follow-up/query-tool-style-hardening"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
# Full Modernization Governance Milestones
|
||||
|
||||
## Phase Completion Criteria
|
||||
|
||||
A phase is complete only when all criteria below are true:
|
||||
|
||||
1. Route governance: 100% of in-scope routes in `route_scope_matrix.json` have valid shell contract metadata and ownership.
|
||||
2. Style governance: in-scope route-local styles do not introduce page-global selectors (`:root`, `body`) unless recorded in exception registry.
|
||||
3. Quality governance: functional parity, visual checkpoints, accessibility checks, and performance budgets pass at configured gate severity.
|
||||
4. Content safety governance: page-content parity evidence + manual acceptance sign-off exist for each migrated in-scope route.
|
||||
5. Bug carry-over governance: known-bug replay checks for migrated scope do not reproduce legacy defects.
|
||||
|
||||
## Legacy Deprecation Milestones
|
||||
|
||||
- 2026-02-20: route contract CI completeness gate enabled in `warn` mode.
|
||||
- 2026-02-27: route contract CI completeness gate promoted to `block` mode.
|
||||
- 2026-03-05: in-scope asset readiness gate promoted to `block` mode.
|
||||
- 2026-03-12: runtime fallback posture retired for in-scope routes in production policy.
|
||||
- 2026-03-19: unresolved style exceptions past milestone fail modernization review.
|
||||
|
||||
## Deferred Route Linkage
|
||||
|
||||
Deferred routes are not pass/fail criteria in this phase and are handed over to a follow-up change:
|
||||
|
||||
- `/tables`
|
||||
- `/excel-query`
|
||||
- `/query-tool`
|
||||
- `/mid-section-defect`
|
||||
|
||||
Follow-up change handoff is recorded in `openspec/changes/deferred-route-modernization-follow-up/`.
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"change": "full-modernization-architecture-blueprint",
|
||||
"required_flows": {
|
||||
"/wip-overview": ["filter_apply", "filter_reset", "status_card_drill"],
|
||||
"/wip-detail": ["list_detail_continuity", "pagination", "filter_reset"],
|
||||
"/hold-overview": ["reason_toggle", "matrix_selection", "lot_scope_sync"],
|
||||
"/hold-detail": ["reason_required_redirect", "distribution_toggle", "lot_scope_sync"],
|
||||
"/hold-history": ["date_range_query", "pareto_selection", "duration_bucket_selection"],
|
||||
"/resource": ["status_filter", "workcenter_family_filter", "tooltip_open_close"],
|
||||
"/resource-history": ["query_submit", "export_csv", "chart_detail_sync"],
|
||||
"/qc-gate": ["chart_bucket_selection", "table_filter_sync", "filter_clear"],
|
||||
"/job-query": ["resource_select", "query_submit", "export_csv"],
|
||||
"/tmtt-defect": ["date_range_query", "chart_filter_link", "detail_sort"],
|
||||
"/admin/pages": ["drawer_crud", "page_status_update", "admin_visibility"],
|
||||
"/admin/performance": ["admin_auth_access", "performance_view_load"],
|
||||
"/tables": ["table_select", "column_filter_apply", "query_submit"],
|
||||
"/excel-query": ["file_upload", "column_select", "query_execute", "export_csv"],
|
||||
"/query-tool": ["lot_resolve", "history_load", "association_query", "equipment_period_query", "export_csv"],
|
||||
"/mid-section-defect": ["date_range_query", "loss_reason_filter", "pareto_chart_drill", "detail_pagination", "export_csv"]
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
{
|
||||
"change": "full-modernization-architecture-blueprint",
|
||||
"scope": "all-governed-routes",
|
||||
"routes": {
|
||||
"/wip-overview": {
|
||||
"baseline_status": "initialized",
|
||||
"known_bugs": []
|
||||
},
|
||||
"/wip-detail": {
|
||||
"baseline_status": "initialized",
|
||||
"known_bugs": []
|
||||
},
|
||||
"/hold-overview": {
|
||||
"baseline_status": "initialized",
|
||||
"known_bugs": []
|
||||
},
|
||||
"/hold-detail": {
|
||||
"baseline_status": "initialized",
|
||||
"known_bugs": []
|
||||
},
|
||||
"/hold-history": {
|
||||
"baseline_status": "initialized",
|
||||
"known_bugs": []
|
||||
},
|
||||
"/resource": {
|
||||
"baseline_status": "initialized",
|
||||
"known_bugs": []
|
||||
},
|
||||
"/resource-history": {
|
||||
"baseline_status": "initialized",
|
||||
"known_bugs": []
|
||||
},
|
||||
"/qc-gate": {
|
||||
"baseline_status": "initialized",
|
||||
"known_bugs": []
|
||||
},
|
||||
"/job-query": {
|
||||
"baseline_status": "initialized",
|
||||
"known_bugs": []
|
||||
},
|
||||
"/tmtt-defect": {
|
||||
"baseline_status": "initialized",
|
||||
"known_bugs": []
|
||||
},
|
||||
"/admin/pages": {
|
||||
"baseline_status": "initialized",
|
||||
"known_bugs": []
|
||||
},
|
||||
"/admin/performance": {
|
||||
"baseline_status": "initialized",
|
||||
"known_bugs": []
|
||||
},
|
||||
"/tables": {
|
||||
"baseline_status": "initialized",
|
||||
"known_bugs": []
|
||||
},
|
||||
"/excel-query": {
|
||||
"baseline_status": "initialized",
|
||||
"known_bugs": []
|
||||
},
|
||||
"/query-tool": {
|
||||
"baseline_status": "initialized",
|
||||
"known_bugs": []
|
||||
},
|
||||
"/mid-section-defect": {
|
||||
"baseline_status": "initialized",
|
||||
"known_bugs": []
|
||||
}
|
||||
},
|
||||
"revalidation_rule": {
|
||||
"reproduced_legacy_bug_blocks_signoff": true,
|
||||
"reproduced_legacy_bug_blocks_legacy_retirement": true
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"change": "full-modernization-architecture-blueprint",
|
||||
"records": [],
|
||||
"rule": "next route cutover is blocked until current route has approved manual sign-off"
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
# Modernization Observability Checkpoints
|
||||
|
||||
## Route Governance Signals
|
||||
|
||||
1. `navigation_contract_mismatch_total`
|
||||
- Source: `/api/portal/navigation` diagnostics.
|
||||
- Alert condition: non-zero for in-scope routes.
|
||||
|
||||
2. `route_contract_missing_metadata_total`
|
||||
- Source: route governance CI script.
|
||||
- Alert condition: >0 in block mode.
|
||||
|
||||
## Quality Gate Signals
|
||||
|
||||
1. `quality_gate_failed_total{gate_id}`
|
||||
- Source: quality gate report.
|
||||
- Alert condition: any mandatory gate failed.
|
||||
|
||||
2. `manual_acceptance_pending_routes`
|
||||
- Source: manual acceptance records.
|
||||
- Alert condition: cutover attempted with pending sign-off.
|
||||
|
||||
## Fallback and Rollback Signals
|
||||
|
||||
1. `in_scope_runtime_fallback_served_total`
|
||||
- Should remain zero after fallback retirement milestone.
|
||||
|
||||
2. `content_cutover_flag_rollbacks_total`
|
||||
- Track frequency and route impact.
|
||||
|
||||
3. `legacy_bug_replay_failures_total`
|
||||
- Any non-zero indicates carry-over risk and blocks sign-off.
|
||||
@@ -1,28 +0,0 @@
|
||||
# Page Content Manual Acceptance Checklist
|
||||
|
||||
## Rule
|
||||
|
||||
- Route cutover proceeds one route at a time.
|
||||
- Next route cutover is blocked until current route is manually signed off.
|
||||
- Legacy code retirement is blocked until parity checks and manual sign-off are both complete.
|
||||
|
||||
## Mandatory Checks Per Route
|
||||
|
||||
1. Filter semantics match baseline (apply, reset, URL/query continuity).
|
||||
2. Chart interactions match baseline (drill/selection/clear behavior).
|
||||
3. Empty/loading/error/success states are correct and non-overlapping.
|
||||
4. Table/chart linked interactions remain deterministic.
|
||||
5. Accessibility: keyboard flow, focus visibility, `aria-*` semantics, reduced-motion behavior.
|
||||
6. Known-bug replay checks completed (see `known_bug_baseline.json`).
|
||||
7. No reproduced legacy bug in migrated scope.
|
||||
|
||||
## Sign-Off Template
|
||||
|
||||
- Route:
|
||||
- Owner:
|
||||
- Reviewer:
|
||||
- Date:
|
||||
- Parity evidence links:
|
||||
- Known-bug replay result:
|
||||
- Blocking defects:
|
||||
- Decision: `approved` | `rework-required`
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"change": "full-modernization-architecture-blueprint",
|
||||
"fixtures": {
|
||||
"/wip-overview": ["tests/fixtures/frontend_compute_parity.json"],
|
||||
"/wip-detail": ["docs/migration/portal-shell-route-view-integration/wave-b-parity-evidence.json"],
|
||||
"/hold-overview": ["docs/migration/portal-shell-route-view-integration/baseline_interaction_evidence.json"],
|
||||
"/hold-detail": ["docs/migration/portal-shell-route-view-integration/baseline_interaction_evidence.json"],
|
||||
"/hold-history": ["docs/migration/portal-shell-route-view-integration/baseline_interaction_evidence.json"],
|
||||
"/resource": ["docs/migration/portal-shell-route-view-integration/baseline_api_payload_contracts.json"],
|
||||
"/resource-history": ["docs/migration/portal-shell-route-view-integration/baseline_api_payload_contracts.json"],
|
||||
"/qc-gate": ["docs/migration/portal-shell-route-view-integration/visual-regression-snapshots.json"],
|
||||
"/job-query": ["docs/migration/portal-shell-route-view-integration/wave-b-parity-evidence.json"],
|
||||
"/tmtt-defect": ["docs/migration/portal-shell-route-view-integration/wave-b-parity-evidence.json"],
|
||||
"/admin/pages": ["tests/test_portal_shell_routes.py"],
|
||||
"/admin/performance": ["tests/test_performance_integration.py"],
|
||||
"/tables": ["tests/test_portal_shell_routes.py"],
|
||||
"/excel-query": ["tests/test_portal_shell_routes.py"],
|
||||
"/query-tool": ["tests/test_portal_shell_routes.py"],
|
||||
"/mid-section-defect": ["tests/test_portal_shell_routes.py"]
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"change": "full-modernization-architecture-blueprint",
|
||||
"targets": {
|
||||
"shell_navigation_api_avg_ms": 150,
|
||||
"shell_navigation_api_p95_ms": 350,
|
||||
"portal_shell_entry_avg_ms": 200,
|
||||
"portal_shell_entry_p95_ms": 450
|
||||
},
|
||||
"source_baselines": [
|
||||
"docs/migration/portal-no-iframe/performance_baseline_spa.json",
|
||||
"docs/migration/portal-no-iframe/performance_baseline_legacy.json"
|
||||
]
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"change": "full-modernization-architecture-blueprint",
|
||||
"severity_mode": {
|
||||
"current": "warn",
|
||||
"promotion_target": "block",
|
||||
"promotion_milestone": "2026-02-27"
|
||||
},
|
||||
"gates": [
|
||||
{"id": "Q1", "name": "functional-parity", "required": true},
|
||||
{"id": "Q2", "name": "visual-regression", "required": true},
|
||||
{"id": "Q3", "name": "accessibility-keyboard-aria-motion", "required": true},
|
||||
{"id": "Q4", "name": "performance-budget", "required": true},
|
||||
{"id": "Q5", "name": "manual-acceptance-and-bug-revalidation", "required": true}
|
||||
],
|
||||
"deferred_routes_excluded": []
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"mode": "block",
|
||||
"errors": [],
|
||||
"warnings": [
|
||||
"/excel-query uses shell tokens without fallback ['--portal-shadow-panel'] in frontend/src/excel-query/style.css with approved exception"
|
||||
],
|
||||
"info": [],
|
||||
"passed": true
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
# Full Modernization Rollback Controls
|
||||
|
||||
## Route-Level Reversion Controls
|
||||
|
||||
- `PORTAL_SPA_ENABLED=false`:
|
||||
Disable shell-first navigation runtime globally.
|
||||
- Route-scoped contract fallback:
|
||||
Mark route contract with fallback strategy and redeploy shell assets.
|
||||
- Content cutover feature flag:
|
||||
Disable route-level modernized content path while keeping shell runtime up.
|
||||
|
||||
## False-Positive Gate Handling
|
||||
|
||||
1. Capture failing gate output and route impact.
|
||||
2. Confirm whether failure is test flake or product defect.
|
||||
3. If false-positive and production risk is high:
|
||||
- Temporarily switch gate severity from `block` to `warn`.
|
||||
- Record waiver with owner, reason, expiry.
|
||||
4. Restore `block` mode after corrective action.
|
||||
|
||||
## Required Rollback Evidence
|
||||
|
||||
- Incident timestamp and impacted routes.
|
||||
- Gate IDs that triggered rollback.
|
||||
- Route contract state before/after rollback.
|
||||
- Manual acceptance and known-bug replay references.
|
||||
@@ -1,33 +0,0 @@
|
||||
# Full Modernization Rollout Runbook
|
||||
|
||||
## Phase Sequence
|
||||
|
||||
1. Governance freeze
|
||||
- Confirm `route_scope_matrix.json` has no pending route-scope changes.
|
||||
- Confirm exception registry entries include owner + milestone.
|
||||
|
||||
2. Route governance enforcement
|
||||
- Run route contract completeness checks in warn mode.
|
||||
- Fix all in-scope metadata gaps.
|
||||
- Promote route governance checks to block mode.
|
||||
|
||||
3. Style/content hardening
|
||||
- Apply style isolation checks for in-scope routes.
|
||||
- Execute parity checks and manual acceptance route-by-route.
|
||||
- Run known-bug replay checks per route.
|
||||
|
||||
4. Asset/gate enforcement
|
||||
- Validate in-scope asset readiness.
|
||||
- Run quality gate suite (functional, visual, accessibility, performance).
|
||||
- Promote gate severity from warn to block according to policy.
|
||||
|
||||
## Hold Points
|
||||
|
||||
- Hold-1: Any in-scope route missing contract metadata.
|
||||
- Hold-2: Any unresolved style exception past milestone.
|
||||
- Hold-3: Any parity failure or known-bug replay failure.
|
||||
- Hold-4: Any mandatory quality gate failure in block mode.
|
||||
|
||||
## Promotion Rule
|
||||
|
||||
Promotion is allowed only when all hold points are clear and no deferred-route checks were incorrectly included as blockers.
|
||||
@@ -1,101 +0,0 @@
|
||||
{
|
||||
"change": "full-modernization-architecture-blueprint",
|
||||
"in_scope_routes": {
|
||||
"/wip-overview": {
|
||||
"filter_input_semantics": ["workorder", "lotid", "package", "type", "status"],
|
||||
"query_payload_contract": ["workorder", "lotid", "package", "type", "status"],
|
||||
"chart_data_shape": ["status_cards", "matrix", "pareto"],
|
||||
"state_contract": ["loading", "empty", "error", "success"]
|
||||
},
|
||||
"/wip-detail": {
|
||||
"filter_input_semantics": ["workcenter", "workorder", "lotid", "package", "type", "status", "page"],
|
||||
"query_payload_contract": ["workcenter", "workorder", "lotid", "package", "type", "status", "page"],
|
||||
"chart_data_shape": ["summary_cards", "lot_table"],
|
||||
"state_contract": ["loading", "empty", "error", "success"]
|
||||
},
|
||||
"/hold-overview": {
|
||||
"filter_input_semantics": ["hold_type", "reason", "workcenter", "package", "age_range", "page"],
|
||||
"query_payload_contract": ["hold_type", "reason", "workcenter", "package", "age_range", "page"],
|
||||
"chart_data_shape": ["summary_cards", "matrix", "treemap", "lot_table"],
|
||||
"state_contract": ["loading", "empty", "error", "success"]
|
||||
},
|
||||
"/hold-detail": {
|
||||
"filter_input_semantics": ["reason", "workcenter", "package", "age_range", "page"],
|
||||
"query_payload_contract": ["reason", "workcenter", "package", "age_range", "page"],
|
||||
"chart_data_shape": ["summary_cards", "distribution", "lot_table"],
|
||||
"state_contract": ["loading", "empty", "error", "success"]
|
||||
},
|
||||
"/hold-history": {
|
||||
"filter_input_semantics": ["start_date", "end_date", "hold_type", "record_type", "reason", "duration_range", "page"],
|
||||
"query_payload_contract": ["start_date", "end_date", "hold_type", "record_type", "reason", "duration_range", "page"],
|
||||
"chart_data_shape": ["trend", "reason_pareto", "duration", "detail_table"],
|
||||
"state_contract": ["loading", "empty", "error", "success"]
|
||||
},
|
||||
"/resource": {
|
||||
"filter_input_semantics": ["workcenter_groups", "families", "resource_ids", "statuses"],
|
||||
"query_payload_contract": ["workcenter_groups", "families", "resource_ids", "statuses"],
|
||||
"chart_data_shape": ["summary_cards", "status_matrix", "equipment_grid"],
|
||||
"state_contract": ["loading", "empty", "error", "success"]
|
||||
},
|
||||
"/resource-history": {
|
||||
"filter_input_semantics": ["start_date", "end_date", "granularity", "workcenter_groups", "families", "resource_ids", "is_production", "is_key", "is_monitor"],
|
||||
"query_payload_contract": ["start_date", "end_date", "granularity", "workcenter_groups", "families", "resource_ids", "is_production", "is_key", "is_monitor"],
|
||||
"chart_data_shape": ["kpi", "trend", "heatmap", "workcenter_comparison", "detail"],
|
||||
"state_contract": ["loading", "empty", "error", "success"]
|
||||
},
|
||||
"/qc-gate": {
|
||||
"filter_input_semantics": ["chart_bucket_selection", "table_sort"],
|
||||
"query_payload_contract": ["summary", "table", "pareto"],
|
||||
"chart_data_shape": ["station_stack_chart", "linked_lot_table"],
|
||||
"state_contract": ["loading", "empty", "error", "success"]
|
||||
},
|
||||
"/job-query": {
|
||||
"filter_input_semantics": ["resource_ids", "start_date", "end_date"],
|
||||
"query_payload_contract": ["resource_ids", "start_date", "end_date"],
|
||||
"chart_data_shape": ["job_table", "txn_table"],
|
||||
"state_contract": ["loading", "empty", "error", "success"]
|
||||
},
|
||||
"/tmtt-defect": {
|
||||
"filter_input_semantics": ["start_date", "end_date", "sort", "page"],
|
||||
"query_payload_contract": ["start_date", "end_date"],
|
||||
"chart_data_shape": ["kpi", "pareto", "trend", "detail_table"],
|
||||
"state_contract": ["loading", "empty", "error", "success"]
|
||||
},
|
||||
"/admin/pages": {
|
||||
"filter_input_semantics": ["drawer_crud", "page_status_edit", "order_updates"],
|
||||
"query_payload_contract": ["drawers", "pages", "status"],
|
||||
"chart_data_shape": ["n/a"],
|
||||
"state_contract": ["loading", "empty", "error", "success"]
|
||||
},
|
||||
"/admin/performance": {
|
||||
"filter_input_semantics": ["date_range", "severity", "search"],
|
||||
"query_payload_contract": ["performance_summary", "log_stream"],
|
||||
"chart_data_shape": ["timeline", "status_summary"],
|
||||
"state_contract": ["loading", "empty", "error", "success"]
|
||||
},
|
||||
"/tables": {
|
||||
"filter_input_semantics": ["table_category", "table_name", "dynamic_column_filters"],
|
||||
"query_payload_contract": ["table_name", "limit", "time_field", "filters"],
|
||||
"chart_data_shape": ["dynamic_data_table"],
|
||||
"state_contract": ["loading", "empty", "error", "success"]
|
||||
},
|
||||
"/excel-query": {
|
||||
"filter_input_semantics": ["file_upload", "excel_column", "table_name", "search_column", "query_type", "return_columns", "date_range"],
|
||||
"query_payload_contract": ["table_name", "search_column", "return_columns", "search_values", "query_type", "date_column", "date_from", "date_to"],
|
||||
"chart_data_shape": ["result_table", "csv_export"],
|
||||
"state_contract": ["loading", "empty", "error", "success"]
|
||||
},
|
||||
"/query-tool": {
|
||||
"filter_input_semantics": ["input_type", "workcenter_groups", "input_values", "association_type", "equipment_ids", "equipment_query_type", "start_date", "end_date"],
|
||||
"query_payload_contract": ["input_type", "values", "container_id", "workcenter_groups", "type", "equipment_ids", "equipment_names", "start_date", "end_date", "query_type"],
|
||||
"chart_data_shape": ["resolved_lots_table", "lot_history_table", "association_table", "equipment_table"],
|
||||
"state_contract": ["loading", "empty", "error", "success"]
|
||||
},
|
||||
"/mid-section-defect": {
|
||||
"filter_input_semantics": ["start_date", "end_date", "loss_reasons"],
|
||||
"query_payload_contract": ["start_date", "end_date", "loss_reasons", "page", "page_size"],
|
||||
"chart_data_shape": ["kpi_cards", "pareto_by_station", "pareto_by_loss_reason", "pareto_by_machine", "pareto_by_tmtt_machine", "pareto_by_workflow", "pareto_by_package", "daily_trend", "detail_table"],
|
||||
"state_contract": ["loading", "empty", "error", "success"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
{
|
||||
"change": "full-modernization-architecture-blueprint",
|
||||
"generated_at": "2026-02-12T00:00:00Z",
|
||||
"routes": [
|
||||
{
|
||||
"route": "/wip-overview",
|
||||
"route_id": "wip-overview",
|
||||
"scope": "in-scope",
|
||||
"render_mode": "native",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"canonical_shell_path": "/portal-shell/wip-overview",
|
||||
"rollback_strategy": "fallback_to_legacy_route"
|
||||
},
|
||||
{
|
||||
"route": "/wip-detail",
|
||||
"route_id": "wip-detail",
|
||||
"scope": "in-scope",
|
||||
"render_mode": "native",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"canonical_shell_path": "/portal-shell/wip-detail",
|
||||
"rollback_strategy": "fallback_to_legacy_route"
|
||||
},
|
||||
{
|
||||
"route": "/hold-overview",
|
||||
"route_id": "hold-overview",
|
||||
"scope": "in-scope",
|
||||
"render_mode": "native",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"canonical_shell_path": "/portal-shell/hold-overview",
|
||||
"rollback_strategy": "fallback_to_legacy_route"
|
||||
},
|
||||
{
|
||||
"route": "/hold-detail",
|
||||
"route_id": "hold-detail",
|
||||
"scope": "in-scope",
|
||||
"render_mode": "native",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"canonical_shell_path": "/portal-shell/hold-detail",
|
||||
"rollback_strategy": "fallback_to_legacy_route"
|
||||
},
|
||||
{
|
||||
"route": "/hold-history",
|
||||
"route_id": "hold-history",
|
||||
"scope": "in-scope",
|
||||
"render_mode": "native",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"canonical_shell_path": "/portal-shell/hold-history",
|
||||
"rollback_strategy": "fallback_to_legacy_route"
|
||||
},
|
||||
{
|
||||
"route": "/resource",
|
||||
"route_id": "resource",
|
||||
"scope": "in-scope",
|
||||
"render_mode": "native",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"canonical_shell_path": "/portal-shell/resource",
|
||||
"rollback_strategy": "fallback_to_legacy_route"
|
||||
},
|
||||
{
|
||||
"route": "/resource-history",
|
||||
"route_id": "resource-history",
|
||||
"scope": "in-scope",
|
||||
"render_mode": "native",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"canonical_shell_path": "/portal-shell/resource-history",
|
||||
"rollback_strategy": "fallback_to_legacy_route"
|
||||
},
|
||||
{
|
||||
"route": "/qc-gate",
|
||||
"route_id": "qc-gate",
|
||||
"scope": "in-scope",
|
||||
"render_mode": "native",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"canonical_shell_path": "/portal-shell/qc-gate",
|
||||
"rollback_strategy": "fallback_to_legacy_route"
|
||||
},
|
||||
{
|
||||
"route": "/job-query",
|
||||
"route_id": "job-query",
|
||||
"scope": "in-scope",
|
||||
"render_mode": "native",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"canonical_shell_path": "/portal-shell/job-query",
|
||||
"rollback_strategy": "fallback_to_legacy_route"
|
||||
},
|
||||
{
|
||||
"route": "/tmtt-defect",
|
||||
"route_id": "tmtt-defect",
|
||||
"scope": "in-scope",
|
||||
"render_mode": "native",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"canonical_shell_path": "/portal-shell/tmtt-defect",
|
||||
"rollback_strategy": "fallback_to_legacy_route"
|
||||
},
|
||||
{
|
||||
"route": "/admin/pages",
|
||||
"route_id": "admin-pages",
|
||||
"scope": "in-scope",
|
||||
"render_mode": "external",
|
||||
"owner": "frontend-platform-admin",
|
||||
"visibility_policy": "admin_only",
|
||||
"canonical_shell_path": "/portal-shell/admin/pages",
|
||||
"rollback_strategy": "external_route_reversion"
|
||||
},
|
||||
{
|
||||
"route": "/admin/performance",
|
||||
"route_id": "admin-performance",
|
||||
"scope": "in-scope",
|
||||
"render_mode": "external",
|
||||
"owner": "frontend-platform-admin",
|
||||
"visibility_policy": "admin_only",
|
||||
"canonical_shell_path": "/portal-shell/admin/performance",
|
||||
"rollback_strategy": "external_route_reversion"
|
||||
},
|
||||
{
|
||||
"route": "/tables",
|
||||
"route_id": "tables",
|
||||
"scope": "in-scope",
|
||||
"render_mode": "native",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"canonical_shell_path": "/portal-shell/tables",
|
||||
"rollback_strategy": "fallback_to_legacy_route"
|
||||
},
|
||||
{
|
||||
"route": "/excel-query",
|
||||
"route_id": "excel-query",
|
||||
"scope": "in-scope",
|
||||
"render_mode": "native",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"canonical_shell_path": "/portal-shell/excel-query",
|
||||
"rollback_strategy": "fallback_to_legacy_route"
|
||||
},
|
||||
{
|
||||
"route": "/query-tool",
|
||||
"route_id": "query-tool",
|
||||
"scope": "in-scope",
|
||||
"render_mode": "native",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"canonical_shell_path": "/portal-shell/query-tool",
|
||||
"rollback_strategy": "fallback_to_legacy_route"
|
||||
},
|
||||
{
|
||||
"route": "/mid-section-defect",
|
||||
"route_id": "mid-section-defect",
|
||||
"scope": "in-scope",
|
||||
"render_mode": "native",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"canonical_shell_path": "/portal-shell/mid-section-defect",
|
||||
"rollback_strategy": "fallback_to_legacy_route"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
{
|
||||
"change": "full-modernization-architecture-blueprint",
|
||||
"generated_at": "2026-02-12T00:00:00Z",
|
||||
"phase": "phase-1-shell-and-content-modernization",
|
||||
"policy": {
|
||||
"scope_is_frozen": true,
|
||||
"out_of_scope_tasks_must_be_rejected": true
|
||||
},
|
||||
"in_scope": [
|
||||
{
|
||||
"route": "/wip-overview",
|
||||
"category": "report",
|
||||
"canonical_shell_path": "/portal-shell/wip-overview",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin"
|
||||
},
|
||||
{
|
||||
"route": "/wip-detail",
|
||||
"category": "report",
|
||||
"canonical_shell_path": "/portal-shell/wip-detail",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin"
|
||||
},
|
||||
{
|
||||
"route": "/hold-overview",
|
||||
"category": "report",
|
||||
"canonical_shell_path": "/portal-shell/hold-overview",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin"
|
||||
},
|
||||
{
|
||||
"route": "/hold-detail",
|
||||
"category": "report",
|
||||
"canonical_shell_path": "/portal-shell/hold-detail",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin"
|
||||
},
|
||||
{
|
||||
"route": "/hold-history",
|
||||
"category": "report",
|
||||
"canonical_shell_path": "/portal-shell/hold-history",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin"
|
||||
},
|
||||
{
|
||||
"route": "/resource",
|
||||
"category": "report",
|
||||
"canonical_shell_path": "/portal-shell/resource",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin"
|
||||
},
|
||||
{
|
||||
"route": "/resource-history",
|
||||
"category": "report",
|
||||
"canonical_shell_path": "/portal-shell/resource-history",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin"
|
||||
},
|
||||
{
|
||||
"route": "/qc-gate",
|
||||
"category": "report",
|
||||
"canonical_shell_path": "/portal-shell/qc-gate",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin"
|
||||
},
|
||||
{
|
||||
"route": "/job-query",
|
||||
"category": "report",
|
||||
"canonical_shell_path": "/portal-shell/job-query",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin"
|
||||
},
|
||||
{
|
||||
"route": "/tmtt-defect",
|
||||
"category": "report",
|
||||
"canonical_shell_path": "/portal-shell/tmtt-defect",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin"
|
||||
},
|
||||
{
|
||||
"route": "/admin/pages",
|
||||
"category": "admin",
|
||||
"canonical_shell_path": "/portal-shell/admin/pages",
|
||||
"owner": "frontend-platform-admin",
|
||||
"visibility_policy": "admin_only"
|
||||
},
|
||||
{
|
||||
"route": "/admin/performance",
|
||||
"category": "admin",
|
||||
"canonical_shell_path": "/portal-shell/admin/performance",
|
||||
"owner": "frontend-platform-admin",
|
||||
"visibility_policy": "admin_only"
|
||||
},
|
||||
{
|
||||
"route": "/tables",
|
||||
"category": "report",
|
||||
"canonical_shell_path": "/portal-shell/tables",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"promoted_from": "deferred",
|
||||
"promoted_by": "deferred-route-modernization-follow-up"
|
||||
},
|
||||
{
|
||||
"route": "/excel-query",
|
||||
"category": "report",
|
||||
"canonical_shell_path": "/portal-shell/excel-query",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"promoted_from": "deferred",
|
||||
"promoted_by": "deferred-route-modernization-follow-up"
|
||||
},
|
||||
{
|
||||
"route": "/query-tool",
|
||||
"category": "report",
|
||||
"canonical_shell_path": "/portal-shell/query-tool",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"promoted_from": "deferred",
|
||||
"promoted_by": "deferred-route-modernization-follow-up"
|
||||
},
|
||||
{
|
||||
"route": "/mid-section-defect",
|
||||
"category": "report",
|
||||
"canonical_shell_path": "/portal-shell/mid-section-defect",
|
||||
"owner": "frontend-mes-reporting",
|
||||
"visibility_policy": "released_or_admin",
|
||||
"promoted_from": "deferred",
|
||||
"promoted_by": "deferred-route-modernization-follow-up"
|
||||
}
|
||||
],
|
||||
"deferred": []
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"change": "full-modernization-architecture-blueprint",
|
||||
"generated_at": "2026-02-12T00:00:00Z",
|
||||
"in_scope_routes": {
|
||||
"/wip-overview": {"global_selectors": [], "status": "clean"},
|
||||
"/wip-detail": {"global_selectors": [], "status": "clean"},
|
||||
"/hold-overview": {"global_selectors": [], "status": "clean"},
|
||||
"/hold-detail": {"global_selectors": [], "status": "clean"},
|
||||
"/hold-history": {"global_selectors": [], "status": "clean"},
|
||||
"/resource": {"global_selectors": [], "status": "clean"},
|
||||
"/resource-history": {"global_selectors": [], "status": "clean"},
|
||||
"/qc-gate": {"global_selectors": [], "status": "clean-after-refactor"},
|
||||
"/job-query": {"global_selectors": [], "status": "clean"},
|
||||
"/tmtt-defect": {"global_selectors": [], "status": "clean"},
|
||||
"/admin/pages": {
|
||||
"global_selectors": ["body"],
|
||||
"status": "exception-registered",
|
||||
"exception_id": "style-admin-pages-inline-css"
|
||||
},
|
||||
"/admin/performance": {
|
||||
"global_selectors": ["body"],
|
||||
"status": "exception-registered",
|
||||
"exception_id": "style-admin-performance-inline-css"
|
||||
},
|
||||
"/tables": {"global_selectors": [], "status": "pending-audit"},
|
||||
"/excel-query": {"global_selectors": [], "status": "pending-audit"},
|
||||
"/query-tool": {"global_selectors": [], "status": "pending-audit"},
|
||||
"/mid-section-defect": {"global_selectors": [], "status": "pending-audit"}
|
||||
},
|
||||
"shared_layers": {
|
||||
"frontend/src/styles/tailwind.css": [":root", "body"],
|
||||
"frontend/src/portal-shell/style.css": [":root", "body"]
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
# OpenSpec Archive Readiness (`portal-no-iframe-navigation`)
|
||||
|
||||
## Spec Sync Scope
|
||||
|
||||
Main specs synchronized/updated for this change:
|
||||
|
||||
- `openspec/specs/full-vite-page-modularization/spec.md`
|
||||
- `openspec/specs/portal-drawer-navigation/spec.md`
|
||||
- `openspec/specs/vue-vite-page-architecture/spec.md`
|
||||
- `openspec/specs/migration-gates-and-rollout/spec.md`
|
||||
- `openspec/specs/spa-shell-navigation/spec.md` (new)
|
||||
- `openspec/specs/tailwind-design-system/spec.md` (new)
|
||||
- `openspec/specs/frontend-motion-system/spec.md` (new)
|
||||
- `openspec/specs/legacy-page-wrapper-strategy/spec.md` (new)
|
||||
|
||||
## Migration Closure Artifacts
|
||||
|
||||
- Rewrite smoke checklist:
|
||||
- `docs/migration/portal-no-iframe/legacy_rewrite_smoke_checklists.md`
|
||||
- Rewrite exemplar:
|
||||
- `docs/migration/portal-no-iframe/tmtt_rewrite_exemplar.md`
|
||||
- Rewrite playbook:
|
||||
- `docs/migration/portal-no-iframe/legacy_rewrite_playbook.md`
|
||||
- Wrapper decommission record:
|
||||
- `docs/migration/portal-no-iframe/wrapper_decommission_report.md`
|
||||
- Frame field retirement record:
|
||||
- `docs/migration/portal-no-iframe/frame_id_tool_src_deprecation_plan.md`
|
||||
|
||||
## Pre-Archive Checklist
|
||||
|
||||
- [x] `openspec validate portal-no-iframe-navigation --strict` passes.
|
||||
- [x] Build and core migration tests pass on latest branch.
|
||||
- [x] Task list in `openspec/changes/portal-no-iframe-navigation/tasks.md` is fully checked.
|
||||
@@ -1,46 +0,0 @@
|
||||
{
|
||||
"source": "current frontend API consumption contracts",
|
||||
"apis": {
|
||||
"/api/wip/overview/summary": {
|
||||
"required_keys": [
|
||||
"dataUpdateDate",
|
||||
"runLots",
|
||||
"queueLots",
|
||||
"holdLots"
|
||||
],
|
||||
"notes": "summary header and cards depend on these fields"
|
||||
},
|
||||
"/api/wip/overview/matrix": {
|
||||
"required_keys": [
|
||||
"workcenters",
|
||||
"packages",
|
||||
"matrix",
|
||||
"workcenter_totals"
|
||||
],
|
||||
"notes": "matrix table rendering contract"
|
||||
},
|
||||
"/api/wip/hold-detail/summary": {
|
||||
"required_keys": [
|
||||
"workcenterCount",
|
||||
"packageCount",
|
||||
"lotCount"
|
||||
],
|
||||
"notes": "hold detail summary cards contract"
|
||||
},
|
||||
"/api/resource/history/summary": {
|
||||
"required_keys": [
|
||||
"kpi",
|
||||
"trend",
|
||||
"heatmap",
|
||||
"workcenter_comparison"
|
||||
],
|
||||
"notes": "resource history chart summary contract"
|
||||
},
|
||||
"/api/resource/history/detail": {
|
||||
"required_keys": [
|
||||
"data"
|
||||
],
|
||||
"notes": "detail table contract (plus truncated/max_records metadata when present)"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"source": "data/page_status.json",
|
||||
"errors": []
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
{
|
||||
"generated_at": "2026-02-12T02:26:36.887797+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": "released",
|
||||
"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": "released",
|
||||
"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": "dev",
|
||||
"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": "/hold-overview",
|
||||
"name": "Hold 即時概況",
|
||||
"status": "released",
|
||||
"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": "released",
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
{
|
||||
"source": "frontend route parsing and current parity matrix",
|
||||
"routes": {
|
||||
"/wip-overview": {
|
||||
"query_keys": [
|
||||
"workorder",
|
||||
"lotid",
|
||||
"package",
|
||||
"type",
|
||||
"status"
|
||||
],
|
||||
"notes": "filters + status URL state must remain compatible"
|
||||
},
|
||||
"/wip-detail": {
|
||||
"query_keys": [
|
||||
"workcenter",
|
||||
"workorder",
|
||||
"lotid",
|
||||
"package",
|
||||
"type",
|
||||
"status"
|
||||
],
|
||||
"notes": "workcenter deep-link and back-link query continuity"
|
||||
},
|
||||
"/hold-detail": {
|
||||
"query_keys": [
|
||||
"reason"
|
||||
],
|
||||
"notes": "reason required for normal access flow"
|
||||
},
|
||||
"/resource-history": {
|
||||
"query_keys": [
|
||||
"start_date",
|
||||
"end_date",
|
||||
"granularity",
|
||||
"workcenter_groups",
|
||||
"families",
|
||||
"resource_ids",
|
||||
"is_production",
|
||||
"is_key",
|
||||
"is_monitor"
|
||||
],
|
||||
"notes": "query/export params must remain compatible"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
# Drawer Governance Contract (Portal No-Iframe Migration)
|
||||
|
||||
## Scope
|
||||
|
||||
This contract defines drawer behavior that must remain stable during migration.
|
||||
|
||||
## Canonical Responsibilities
|
||||
|
||||
Drawer metadata is responsible for:
|
||||
|
||||
- Information architecture grouping.
|
||||
- Display order.
|
||||
- Access visibility (`admin_only`).
|
||||
|
||||
Drawer metadata is not responsible for:
|
||||
|
||||
- Content embedding mode (`iframe`, `toolFrame`).
|
||||
- Rendering technology selection (Jinja vs SPA route view).
|
||||
|
||||
## Contract Rules
|
||||
|
||||
1. Drawer IDs must be unique and non-empty.
|
||||
2. Page routes must be unique and non-empty.
|
||||
3. `page.drawer_id` (when present) must reference an existing drawer.
|
||||
4. `order` values (when present) must be positive integers.
|
||||
5. Page status must be one of `released` or `dev`.
|
||||
6. Visibility outcomes must be deterministic for admin/non-admin users.
|
||||
|
||||
## Deterministic Rendering Order
|
||||
|
||||
Drawers:
|
||||
|
||||
- Primary sort by `order` ascending.
|
||||
- Secondary sort by `name` ascending.
|
||||
|
||||
Pages in each drawer:
|
||||
|
||||
- Primary sort by `order` ascending.
|
||||
- Secondary sort by `(name or route)` ascending.
|
||||
|
||||
## Visibility Semantics
|
||||
|
||||
- Non-admin users can view only `released` pages in non-admin-only drawers.
|
||||
- Admin users can view all drawer-assigned pages according to current page status policy.
|
||||
- Drawers with zero visible pages are hidden.
|
||||
|
||||
## Validation Artifacts
|
||||
|
||||
- `baseline_drawer_contract_validation.json`
|
||||
- `baseline_drawer_visibility.json`
|
||||
@@ -1,44 +0,0 @@
|
||||
# `frame_id` / `tool_src` Deprecation Plan
|
||||
|
||||
## Status
|
||||
|
||||
- Retirement completed in this change.
|
||||
- Runtime navigation payload generation no longer emits:
|
||||
- `frame_id`
|
||||
- `tool_src`
|
||||
|
||||
## Context
|
||||
|
||||
Frame-era fields were used for iframe loading compatibility:
|
||||
|
||||
- `frame_id`
|
||||
- `tool_src`
|
||||
|
||||
## Policy
|
||||
|
||||
Deprecation is phased and must not break active routes.
|
||||
|
||||
## Phases
|
||||
|
||||
1. **Compatibility phase**:
|
||||
- Keep fields in payload.
|
||||
- Ensure new router navigation logic does not rely on these fields.
|
||||
2. **Dual-run phase**:
|
||||
- Validate all navigation paths without frame fields.
|
||||
3. **Retirement readiness**:
|
||||
- Wrapper-first pages are stable in shell.
|
||||
- Cutover gates G1~G7 are green in rehearsal.
|
||||
4. **Removal phase**:
|
||||
- Remove generation and downstream usage of `frame_id/tool_src`.
|
||||
- Update related tests and docs.
|
||||
|
||||
## Removal Checkpoints
|
||||
|
||||
- Checkpoint A: drawer parity stable in canary.
|
||||
- Checkpoint B: legacy wrappers stable with no frame-field dependency.
|
||||
- Checkpoint C: rollback mechanism verified independent of frame fields. ✓
|
||||
|
||||
## Risk Controls
|
||||
|
||||
- Keep rollback-safe path via route-level navigation and kill-switch.
|
||||
- Keep gate coverage for route/drawer/workflow parity after field removal.
|
||||
@@ -1,40 +0,0 @@
|
||||
# Legacy Rewrite Playbook (Batch-2)
|
||||
|
||||
## Target Pages
|
||||
|
||||
This playbook governs rewrite execution for the remaining three legacy pages:
|
||||
|
||||
- `/job-query`
|
||||
- `/excel-query`
|
||||
- `/query-tool`
|
||||
|
||||
Rewrite order follows `legacy_rewrite_priority_matrix.md`.
|
||||
|
||||
## Canonical Steps
|
||||
|
||||
1. Preserve route and API contracts first.
|
||||
2. Move page state and API calls into composables (`use<Page>Data`).
|
||||
3. Replace page-local repeated blocks with shared UI components where possible.
|
||||
4. Keep Tailwind token alignment for new/changed UI.
|
||||
5. Validate with per-page smoke checklist before/after switch.
|
||||
|
||||
## Required Acceptance (Per Page)
|
||||
|
||||
- Route reachable and functional without shell wrapper.
|
||||
- Core query workflow succeeds and returns expected result sections.
|
||||
- Export path remains usable (where applicable).
|
||||
- No new unhandled runtime error on the primary path.
|
||||
- Checklist IDs pass:
|
||||
- `/job-query`: `JOB-SMOKE-01`~`JOB-SMOKE-06`
|
||||
- `/excel-query`: `EXCEL-SMOKE-01`~`EXCEL-SMOKE-06`
|
||||
- `/query-tool`: `QTOOL-SMOKE-01`~`QTOOL-SMOKE-06`
|
||||
|
||||
Checklist source:
|
||||
|
||||
- `docs/migration/portal-no-iframe/legacy_rewrite_smoke_checklists.md`
|
||||
|
||||
## Shared Guardrails
|
||||
|
||||
- Do not change backend API signatures in rewrite phase.
|
||||
- Keep direct-link behavior and query semantics stable.
|
||||
- If parity fails, rollback to previous stable page artifact before continuing.
|
||||
@@ -1,40 +0,0 @@
|
||||
# Legacy Rewrite Priority Matrix
|
||||
|
||||
## Scoring model
|
||||
|
||||
`priority_score = usage(0-5)*0.3 + complexity(0-5)*0.4 + risk(0-5)*0.3`
|
||||
|
||||
- Usage: current observed operational usage + business criticality.
|
||||
- Complexity: route/API count, frontend LOC, workflow branches.
|
||||
- Risk: data mutation/export/upload sensitivity and regression blast radius.
|
||||
|
||||
## Measured technical baseline
|
||||
|
||||
| Page | Backend route LOC | Template LOC | Frontend LOC | API surface |
|
||||
| --- | ---: | ---: | ---: | --- |
|
||||
| `query-tool` | 509 | 1267 | 3139 | resolve/history/adjacent/associations/equipment/export |
|
||||
| `excel-query` | 355 | 1181 | 624 | upload/schema/query/export |
|
||||
| `job-query` | 195 | 995 | 520 | resources/jobs/txn/export |
|
||||
| `tmtt-defect` | 82 | 271 | 363 | analysis/query + CSV export |
|
||||
|
||||
## Priority scoring
|
||||
|
||||
| Page | Usage | Complexity | Risk | Score |
|
||||
| --- | ---: | ---: | ---: | ---: |
|
||||
| `tmtt-defect` | 2 | 1 | 2 | 1.6 |
|
||||
| `job-query` | 3 | 2 | 3 | 2.6 |
|
||||
| `excel-query` | 3 | 4 | 4 | 3.7 |
|
||||
| `query-tool` | 4 | 5 | 5 | 4.7 |
|
||||
|
||||
## Rewrite order decision
|
||||
|
||||
1. `tmtt-defect` (canonical exemplar)
|
||||
2. `job-query`
|
||||
3. `excel-query`
|
||||
4. `query-tool`
|
||||
|
||||
## Rationale
|
||||
|
||||
- Start with lowest-complexity page to establish shared migration playbook.
|
||||
- Keep high-complexity/high-risk `query-tool` last to maximize reuse from prior rewrites.
|
||||
- Defer upload-heavy `excel-query` until shared error/retry/upload patterns are stabilized.
|
||||
@@ -1,77 +0,0 @@
|
||||
# Legacy Rewrite Smoke Checklists (Per-Page)
|
||||
|
||||
本文件是 `7.2 ~ 7.4` 的執行前置與驗收基準。
|
||||
每一頁在「重寫前(wrapper baseline)」與「重寫後(rewrite candidate)」都必須執行同一組 smoke。
|
||||
|
||||
## 0. 執行規則
|
||||
|
||||
- 必須記錄:執行日期、分支/commit、執行人、環境(DEV/UAT)。
|
||||
- 每頁 smoke 通過率要求:`100%`。
|
||||
- 任何 P0 smoke 失敗即視為 `No-Go`,不得進入 wrapper 移除。
|
||||
- `excel-query`、`query-tool` 為 admin/dev 可見頁,需使用 admin 身份執行。
|
||||
|
||||
## 1. `tmtt-defect`(Rewrite Exemplar)
|
||||
|
||||
### 前置條件
|
||||
- 可取得有效 `start_date/end_date` 測試區間。
|
||||
- `/api/tmtt-defect/analysis` 與 `/api/tmtt-defect/export` 可連線。
|
||||
|
||||
### Smoke Cases
|
||||
- [ ] `TMTT-SMOKE-01` Route reachable: `/tmtt-defect` 可直接開啟,無白屏/JS error。
|
||||
- [ ] `TMTT-SMOKE-02` Required params guard: 缺少日期時,顯示明確錯誤且不崩潰。
|
||||
- [ ] `TMTT-SMOKE-03` Query success: 送出合法日期後,KPI/Charts/Detail 皆成功渲染。
|
||||
- [ ] `TMTT-SMOKE-04` Drill-down: 點擊 Pareto 圖欄位可套用/清除篩選,明細同步。
|
||||
- [ ] `TMTT-SMOKE-05` Table behavior: 明細表格可排序,排序方向切換正確。
|
||||
- [ ] `TMTT-SMOKE-06` Export CSV: 匯出成功,response 為 CSV 且檔名包含日期區間。
|
||||
|
||||
## 2. `job-query`
|
||||
|
||||
### 前置條件
|
||||
- `resource` 清單可取得。
|
||||
- 至少有一組可查詢日期區間。
|
||||
|
||||
### Smoke Cases
|
||||
- [ ] `JOB-SMOKE-01` Route reachable: `/job-query` 可直接開啟。
|
||||
- [ ] `JOB-SMOKE-02` Resource loading: `/api/job-query/resources` 回傳清單,UI 可選取。
|
||||
- [ ] `JOB-SMOKE-03` Query jobs: 選設備+日期後可查詢成功並顯示結果。
|
||||
- [ ] `JOB-SMOKE-04` Txn detail: 由查詢結果可開啟某筆 job 的 txn history。
|
||||
- [ ] `JOB-SMOKE-05` Export CSV: 匯出成功且檔案可下載。
|
||||
- [ ] `JOB-SMOKE-06` Validation: 缺日期/無設備/超過上限時回傳明確錯誤訊息。
|
||||
|
||||
## 3. `excel-query`(Admin)
|
||||
|
||||
### 前置條件
|
||||
- 準備一份有效 `.xlsx` 測試檔。
|
||||
- Admin session 已登入。
|
||||
|
||||
### Smoke Cases
|
||||
- [ ] `EXCEL-SMOKE-01` Route/auth: `/excel-query` admin 可進入,非 admin 受保護。
|
||||
- [ ] `EXCEL-SMOKE-02` Upload: 上傳有效 Excel 後可解析欄位與預覽。
|
||||
- [ ] `EXCEL-SMOKE-03` Column detect: 欄位唯一值與型別偵測可正常運作。
|
||||
- [ ] `EXCEL-SMOKE-04` Execute query: 標準查詢與進階查詢都可回傳資料。
|
||||
- [ ] `EXCEL-SMOKE-05` Export CSV: 查詢結果可匯出 CSV。
|
||||
- [ ] `EXCEL-SMOKE-06` Invalid file guard: 非 `.xls/.xlsx` 檔案被拒絕且回傳可讀錯誤。
|
||||
|
||||
## 4. `query-tool`(Admin)
|
||||
|
||||
### 前置條件
|
||||
- Admin session 已登入。
|
||||
- 可用測試 lot/equipment/date range。
|
||||
|
||||
### Smoke Cases
|
||||
- [ ] `QTOOL-SMOKE-01` Route reachable: `/query-tool` 可開啟。
|
||||
- [ ] `QTOOL-SMOKE-02` Resolve flow: lot_id/serial/work_order 至少一種解析成功。
|
||||
- [ ] `QTOOL-SMOKE-03` History flow: lot history 可查詢並顯示。
|
||||
- [ ] `QTOOL-SMOKE-04` Adjacent flow: adjacent lots 查詢可回傳。
|
||||
- [ ] `QTOOL-SMOKE-05` Associations: materials/rejects/holds/splits/jobs 查詢可用。
|
||||
- [ ] `QTOOL-SMOKE-06` Equipment period: status_hours/lots/materials/rejects/jobs 至少各成功一次。
|
||||
- [ ] `QTOOL-SMOKE-07` Export CSV: 匯出可下載且欄位合理。
|
||||
- [ ] `QTOOL-SMOKE-08` Validation: 缺參數、非法日期範圍會回傳可讀錯誤。
|
||||
|
||||
## 5. Exit Rule(與 7.4 連動)
|
||||
|
||||
只有在下列條件全成立,才可移除 wrapper:
|
||||
|
||||
- [ ] 四頁 rewrite smoke 全部通過。
|
||||
- [ ] 與 `legacy_wrapper_telemetry_contract.md` 對照,error 率在門檻內。
|
||||
- [ ] 與 `parity_checklist.md` 的 Route/Workflow/API contract 檢查一致。
|
||||
@@ -1,21 +0,0 @@
|
||||
# Legacy Wrapper Exit Criteria (Rewrite-ready)
|
||||
|
||||
A wrapped page is rewrite-ready only when all criteria are met.
|
||||
|
||||
## Functional readiness
|
||||
|
||||
1. Core workflows are documented with at least one deterministic smoke script per workflow.
|
||||
2. Route/query contract is frozen and covered by contract tests.
|
||||
3. Export/upload side effects (if any) are reproducible in test or staging.
|
||||
|
||||
## Technical readiness
|
||||
|
||||
1. Shared UI and composables can cover at least 70% of page scaffolding (filters, cards, table shell, pagination).
|
||||
2. Required API payload key/type contract is stable for two consecutive releases.
|
||||
3. Wrapper telemetry shows no unresolved high-severity navigation failures in the last release cycle.
|
||||
|
||||
## Operational readiness
|
||||
|
||||
1. Rollback path for rewritten page is documented and rehearsed.
|
||||
2. Error budget and success threshold for canary are defined before rewrite starts.
|
||||
3. Product owner confirms parity acceptance checklist for the target page.
|
||||
@@ -1,40 +0,0 @@
|
||||
# Legacy Wrapper Telemetry Contract
|
||||
|
||||
## Status
|
||||
|
||||
- Retired after wrapper decommission.
|
||||
- `POST /api/portal/wrapper-telemetry` has been removed.
|
||||
- Reference only for historical migration traceability.
|
||||
|
||||
## Wrapper scope
|
||||
|
||||
- `/job-query`
|
||||
- `/excel-query`
|
||||
- `/query-tool`
|
||||
- `/tmtt-defect`
|
||||
|
||||
## Client events
|
||||
|
||||
- `wrapper_loaded`: wrapper route rendered in shell.
|
||||
- `launch`: user clicked "進入既有頁面" and navigation handoff started.
|
||||
|
||||
## API endpoint
|
||||
|
||||
- `POST /api/portal/wrapper-telemetry`
|
||||
- Payload:
|
||||
- `event_type: string`
|
||||
- `route: string` (must be one of wrapper scope routes)
|
||||
- `page_name?: string`
|
||||
- `drawer_name?: string`
|
||||
- `duration_ms?: number`
|
||||
- `ts?: string`
|
||||
|
||||
## Validation
|
||||
|
||||
- Reject unknown routes with `400`.
|
||||
- Reject missing `event_type` with `400`.
|
||||
|
||||
## Fallback behavior
|
||||
|
||||
- Wrapper UI always provides direct anchor navigation to the legacy route.
|
||||
- Telemetry failure must not block navigation.
|
||||
@@ -1,20 +0,0 @@
|
||||
# Motion Baseline Guidelines (Vue Transition First)
|
||||
|
||||
## Baseline principles
|
||||
|
||||
1. Motion clarifies state change, not decoration.
|
||||
2. Default to short transitions (180ms - 240ms) with easing.
|
||||
3. Keep animation on container level (route/panel/filter-chip), avoid animating large table row sets.
|
||||
|
||||
## Standard transitions
|
||||
|
||||
- Route change: `route-fade` (`opacity + translateY`) in portal shell.
|
||||
- Drawer navigation: hover/active transition on sidebar links.
|
||||
- Filter apply/remove: `TransitionGroup` chip enter/leave motion.
|
||||
- Data refresh pulse: panel-level pulse when chart/table refresh is running.
|
||||
|
||||
## Accessibility
|
||||
|
||||
- Respect `prefers-reduced-motion: reduce`.
|
||||
- All key transitions must have non-animated fallback styles.
|
||||
- Motion must not block interaction or delay data rendering.
|
||||
@@ -1,19 +0,0 @@
|
||||
# GSAP Escalation Rule
|
||||
|
||||
## Default
|
||||
|
||||
Use Vue native transitions and CSS transitions for portal migration work.
|
||||
|
||||
## GSAP allowed only when all conditions are true
|
||||
|
||||
1. Interaction cannot be expressed with native Vue/CSS transitions without major maintainability cost.
|
||||
2. Animation is business-critical (e.g., complex timeline playback or synchronized multi-chart storytelling).
|
||||
3. Reduced-motion fallback is explicitly implemented.
|
||||
4. Performance impact is measured on target hardware and meets baseline thresholds.
|
||||
5. A rollback switch exists to disable advanced animation without breaking functionality.
|
||||
|
||||
## Approval checklist
|
||||
|
||||
- Document the exact scenario and why Vue/CSS is insufficient.
|
||||
- Add test coverage for degraded/non-animated path.
|
||||
- Confirm bundle-size impact is acceptable for the target route.
|
||||
@@ -1,27 +0,0 @@
|
||||
# Shared Pagination Migration Batch 1
|
||||
|
||||
## Scope
|
||||
|
||||
Migrated pages/components:
|
||||
|
||||
- `wip-detail/components/LotTable.vue`
|
||||
- `hold-detail/components/LotTable.vue`
|
||||
- `hold-overview/components/LotTable.vue`
|
||||
- `hold-history/components/DetailTable.vue`
|
||||
- `mid-section-defect/components/DetailTable.vue`
|
||||
|
||||
## Change
|
||||
|
||||
- Replaced direct/inline pagination rendering with shared `PaginationControl`.
|
||||
- Preserved existing page event contracts (`prev-page`, `next-page`).
|
||||
|
||||
## Visual parity checks
|
||||
|
||||
- Pagination visibility still depends on `totalPages > 1`.
|
||||
- Prev/Next button enablement remains bounded by page range.
|
||||
- Page info text format remains unchanged on migrated views.
|
||||
|
||||
## Removed duplicated artifacts
|
||||
|
||||
- Removed local Prev/Next markup and boundary logic from `hold-history/components/DetailTable.vue`.
|
||||
- Consolidated pagination behavior into shared wrapper for this batch.
|
||||
@@ -1,46 +0,0 @@
|
||||
# Portal No-Iframe Migration Parity Checklist
|
||||
|
||||
This checklist is the execution companion for `portal-no-iframe-navigation` migration.
|
||||
|
||||
## A. Drawer Visibility Parity
|
||||
|
||||
- [ ] Non-admin visible drawers/routes match `baseline_drawer_visibility.json` exactly.
|
||||
- [ ] Admin visible drawers/routes match `baseline_drawer_visibility.json` exactly.
|
||||
- [ ] Empty drawers remain hidden.
|
||||
- [ ] `admin_only` drawer behavior remains unchanged.
|
||||
|
||||
## B. Route and Query Contract Parity
|
||||
|
||||
- [ ] `/wip-overview` preserves `workorder|lotid|package|type|status` URL semantics.
|
||||
- [ ] `/wip-detail` preserves `workcenter|workorder|lotid|package|type|status` URL semantics.
|
||||
- [ ] `/hold-detail` preserves required `reason` semantics and fallback behavior.
|
||||
- [ ] `/resource-history` preserves date/granularity/group/family/resource/flag query semantics.
|
||||
|
||||
## C. Core Workflow Smoke Paths
|
||||
|
||||
- [ ] Legacy rewrite per-page smoke checklist passes (`legacy_rewrite_smoke_checklists.md`).
|
||||
- [ ] `/` open portal and switch via drawer navigation.
|
||||
- [ ] `/wip-overview` apply filters and drill down to `/wip-detail`.
|
||||
- [ ] `/wip-overview` reason drill-down to `/hold-detail`.
|
||||
- [ ] `/resource-history` execute query and export path.
|
||||
- [ ] Legacy rewrite pages (`/job-query`, `/excel-query`, `/query-tool`, `/tmtt-defect`) remain reachable and usable.
|
||||
|
||||
## D. API Payload Contract Parity
|
||||
|
||||
- [ ] `/api/wip/overview/summary` required keys present.
|
||||
- [ ] `/api/wip/overview/matrix` required keys present.
|
||||
- [ ] `/api/wip/hold-detail/summary` required keys present.
|
||||
- [ ] `/api/resource/history/summary` required keys present.
|
||||
- [ ] `/api/resource/history/detail` required keys present.
|
||||
|
||||
## E. Stability and Performance
|
||||
|
||||
- [ ] No unhandled JS runtime errors on critical E2E paths.
|
||||
- [ ] Route switch latency remains within agreed threshold.
|
||||
- [ ] Memory footprint does not regress beyond agreed threshold.
|
||||
|
||||
## F. Cutover Decision
|
||||
|
||||
- [ ] All G1~G7 gates are green.
|
||||
- [ ] Rollback rehearsal result is recent and valid.
|
||||
- [ ] Cutover owner and rollback owner are explicitly assigned.
|
||||
@@ -1,21 +0,0 @@
|
||||
# Performance Baseline Comparison
|
||||
|
||||
Measured via Flask test client (route latency in ms).
|
||||
|
||||
## Key Entry Routes
|
||||
|
||||
| Surface | Avg (ms) | P95 (ms) |
|
||||
| --- | ---: | ---: |
|
||||
| Legacy portal `/` | 1.557 | 0.891 |
|
||||
| SPA shell `/portal-shell` | 0.239 | 0.263 |
|
||||
|
||||
## Shared API Route
|
||||
|
||||
| Route | Legacy Avg (ms) | SPA Avg (ms) | Delta (ms) |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| `/api/portal/navigation` | 0.341 | 0.313 | -0.028 |
|
||||
|
||||
## Notes
|
||||
|
||||
- This baseline is synthetic (test client), used for migration regression gate trend tracking.
|
||||
- Production browser/network RUM should be captured separately during canary rollout.
|
||||
@@ -1,61 +0,0 @@
|
||||
{
|
||||
"portal_spa_enabled": false,
|
||||
"samples_per_route": 15,
|
||||
"metrics": [
|
||||
{
|
||||
"route": "/",
|
||||
"samples": 15,
|
||||
"avg_ms": 1.557,
|
||||
"p95_ms": 0.891,
|
||||
"min_ms": 0.536,
|
||||
"max_ms": 14.997,
|
||||
"status_codes": [
|
||||
200
|
||||
]
|
||||
},
|
||||
{
|
||||
"route": "/api/portal/navigation",
|
||||
"samples": 15,
|
||||
"avg_ms": 0.341,
|
||||
"p95_ms": 0.396,
|
||||
"min_ms": 0.284,
|
||||
"max_ms": 0.404,
|
||||
"status_codes": [
|
||||
200
|
||||
]
|
||||
},
|
||||
{
|
||||
"route": "/wip-overview",
|
||||
"samples": 15,
|
||||
"avg_ms": 0.683,
|
||||
"p95_ms": 0.925,
|
||||
"min_ms": 0.422,
|
||||
"max_ms": 2.633,
|
||||
"status_codes": [
|
||||
200
|
||||
]
|
||||
},
|
||||
{
|
||||
"route": "/resource",
|
||||
"samples": 15,
|
||||
"avg_ms": 0.413,
|
||||
"p95_ms": 0.506,
|
||||
"min_ms": 0.337,
|
||||
"max_ms": 0.699,
|
||||
"status_codes": [
|
||||
200
|
||||
]
|
||||
},
|
||||
{
|
||||
"route": "/qc-gate",
|
||||
"samples": 15,
|
||||
"avg_ms": 0.422,
|
||||
"p95_ms": 0.453,
|
||||
"min_ms": 0.371,
|
||||
"max_ms": 0.615,
|
||||
"status_codes": [
|
||||
200
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
{
|
||||
"portal_spa_enabled": true,
|
||||
"samples_per_route": 15,
|
||||
"metrics": [
|
||||
{
|
||||
"route": "/portal-shell",
|
||||
"samples": 15,
|
||||
"avg_ms": 0.239,
|
||||
"p95_ms": 0.263,
|
||||
"min_ms": 0.169,
|
||||
"max_ms": 0.708,
|
||||
"status_codes": [
|
||||
200
|
||||
]
|
||||
},
|
||||
{
|
||||
"route": "/api/portal/navigation",
|
||||
"samples": 15,
|
||||
"avg_ms": 0.313,
|
||||
"p95_ms": 0.412,
|
||||
"min_ms": 0.257,
|
||||
"max_ms": 0.437,
|
||||
"status_codes": [
|
||||
200
|
||||
]
|
||||
},
|
||||
{
|
||||
"route": "/job-query",
|
||||
"samples": 15,
|
||||
"avg_ms": 0.904,
|
||||
"p95_ms": 0.786,
|
||||
"min_ms": 0.33,
|
||||
"max_ms": 7.345,
|
||||
"status_codes": [
|
||||
200
|
||||
]
|
||||
},
|
||||
{
|
||||
"route": "/excel-query",
|
||||
"samples": 15,
|
||||
"avg_ms": 0.47,
|
||||
"p95_ms": 0.448,
|
||||
"min_ms": 0.324,
|
||||
"max_ms": 1.951,
|
||||
"status_codes": [
|
||||
403
|
||||
]
|
||||
},
|
||||
{
|
||||
"route": "/query-tool",
|
||||
"samples": 15,
|
||||
"avg_ms": 0.448,
|
||||
"p95_ms": 0.802,
|
||||
"min_ms": 0.32,
|
||||
"max_ms": 0.849,
|
||||
"status_codes": [
|
||||
403
|
||||
]
|
||||
},
|
||||
{
|
||||
"route": "/tmtt-defect",
|
||||
"samples": 15,
|
||||
"avg_ms": 0.583,
|
||||
"p95_ms": 0.585,
|
||||
"min_ms": 0.323,
|
||||
"max_ms": 3.455,
|
||||
"status_codes": [
|
||||
200
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
# Portal No-Iframe Migration Rollback Rehearsal Runbook
|
||||
|
||||
## Objective
|
||||
|
||||
Validate that navigation can be restored to pre-cutover stable behavior within target SLO.
|
||||
|
||||
- Target recovery SLO: <= 15 minutes
|
||||
|
||||
## Trigger Conditions
|
||||
|
||||
Execute rollback when any of the following occur after cutover:
|
||||
|
||||
- P0 route unavailable or broken workflow.
|
||||
- Drawer visibility parity mismatch.
|
||||
- Critical API payload contract mismatch causing page failure.
|
||||
- Severe runtime JS errors on critical user paths.
|
||||
|
||||
## Preconditions
|
||||
|
||||
- Feature-flag/env toggle path for shell cutover is in place.
|
||||
- Latest baseline snapshots are available under `docs/migration/portal-no-iframe/`.
|
||||
- On-call owner and rollback owner are assigned.
|
||||
|
||||
## Rehearsal Steps
|
||||
|
||||
1. Enable new navigation mode in staging/canary.
|
||||
2. Execute parity checklist (`parity_checklist.md`) on critical routes.
|
||||
3. Force simulated rollback trigger (toggle off new mode).
|
||||
4. Re-run critical smoke checks:
|
||||
- portal load
|
||||
- drawer visibility
|
||||
- wip overview/detail flow
|
||||
- resource history query path
|
||||
5. Record elapsed recovery time and failures.
|
||||
|
||||
## Verification Criteria
|
||||
|
||||
- Toggle change takes effect without manual code rollback.
|
||||
- Critical routes recover to expected behavior.
|
||||
- Recovery time is within SLO.
|
||||
- No residual hard-failure state remains.
|
||||
|
||||
## Post-Rehearsal Record
|
||||
|
||||
- Date:
|
||||
- Environment:
|
||||
- Operator:
|
||||
- Trigger reason:
|
||||
- Recovery duration:
|
||||
- Issues found:
|
||||
- Follow-up actions:
|
||||
@@ -1,28 +0,0 @@
|
||||
# Rollback Strategy (Shell / Router / Wrapper)
|
||||
|
||||
## Scope
|
||||
|
||||
- Shell entry failures (`/portal-shell`, route guards, navigation API)
|
||||
- Legacy route integration failures (`job-query`, `excel-query`, `query-tool`, `tmtt-defect`)
|
||||
|
||||
## Immediate actions
|
||||
|
||||
1. Flip `PORTAL_SPA_ENABLED=false`.
|
||||
2. Confirm `/` portal route responds and sidebar route links render.
|
||||
3. Verify core routes (`/wip-overview`, `/resource`, `/qc-gate`) return 2xx.
|
||||
4. Verify legacy routes (`/job-query`, `/excel-query`, `/query-tool`, `/tmtt-defect`) return 2xx.
|
||||
|
||||
## Validation checkpoints (<=15 minutes)
|
||||
|
||||
- `GET /api/portal/navigation` returns deterministic drawer/page list.
|
||||
- No spike in 5xx for portal and legacy routes.
|
||||
- Smoke flows for one P0 page and one legacy page pass.
|
||||
|
||||
## Legacy route fallback
|
||||
|
||||
- If a legacy route fails hard, temporarily hide it from drawer config (`page_status.json`) and announce maintenance route.
|
||||
|
||||
## Post-rollback follow-up
|
||||
|
||||
- Capture failed gate(s), timestamp, and impacted routes.
|
||||
- Generate incident summary with fix candidate and rehearsal re-entry criteria.
|
||||
@@ -1,27 +0,0 @@
|
||||
# Phased Rollout Plan (Canary)
|
||||
|
||||
## Feature switch
|
||||
|
||||
- Primary switch: `PORTAL_SPA_ENABLED`
|
||||
- Canary enabled users/groups are routed to `/portal-shell`; others remain on `/` route-based portal.
|
||||
|
||||
## Phases
|
||||
|
||||
1. Phase A (Internal): dev/admin users only, 1 day.
|
||||
2. Phase B (Canary): 10-20% target users, 2-3 days.
|
||||
3. Phase C (Broad): 50% users if gates are green for 24h.
|
||||
4. Phase D (Full): 100% after cutover gates pass.
|
||||
|
||||
## Success thresholds
|
||||
|
||||
- Route availability (P0): >= 99.9% 2xx/3xx.
|
||||
- Client runtime error rate on critical paths: 0 unhandled exceptions.
|
||||
- Drawer parity drift: 0 mismatches (admin/non-admin route sets).
|
||||
- Wrapper launch success (`launch` telemetry): >= 99%.
|
||||
|
||||
## Error thresholds (rollback trigger)
|
||||
|
||||
- P0 route availability < 99.5% in any 30-minute window.
|
||||
- Any critical workflow smoke failure.
|
||||
- Drawer parity mismatch count > 0 after deployment.
|
||||
- Wrapper telemetry error rate >= 2% sustained 30 minutes.
|
||||
@@ -1,50 +0,0 @@
|
||||
# Shared UI Component Contracts
|
||||
|
||||
## `PaginationControl`
|
||||
|
||||
File: `frontend/src/shared-ui/components/PaginationControl.vue`
|
||||
|
||||
- Props:
|
||||
- `page?: number` (legacy compatibility)
|
||||
- `modelValue?: number`
|
||||
- `totalPages: number`
|
||||
- `infoText?: string`
|
||||
- `visible?: boolean`
|
||||
- Emits:
|
||||
- `update:modelValue(number)`
|
||||
- `change(number)`
|
||||
- `prev(number)`
|
||||
- `next(number)`
|
||||
- Compatibility:
|
||||
- Supports legacy usage (`:page`, `@prev`, `@next`) for migration-safe replacement.
|
||||
|
||||
## `SectionCard`
|
||||
|
||||
File: `frontend/src/shared-ui/components/SectionCard.vue`
|
||||
|
||||
- Slots:
|
||||
- `header`
|
||||
- default body
|
||||
- `footer`
|
||||
- Purpose:
|
||||
- Normalize page section container structure and spacing.
|
||||
|
||||
## `FilterToolbar`
|
||||
|
||||
File: `frontend/src/shared-ui/components/FilterToolbar.vue`
|
||||
|
||||
- Slots:
|
||||
- default filter controls
|
||||
- `actions`
|
||||
- Purpose:
|
||||
- Shared filter layout shell with consistent spacing and action alignment.
|
||||
|
||||
## `StatusBadge`
|
||||
|
||||
File: `frontend/src/shared-ui/components/StatusBadge.vue`
|
||||
|
||||
- Props:
|
||||
- `tone: neutral | success | warning | danger`
|
||||
- `text: string`
|
||||
- Purpose:
|
||||
- Replace repeated local badge/status color snippets.
|
||||
@@ -1,31 +0,0 @@
|
||||
# Shared Composables Contracts
|
||||
|
||||
## `useAutoRefresh`
|
||||
|
||||
File: `frontend/src/shared-composables/useAutoRefresh.js`
|
||||
|
||||
- Current behavior wraps existing `wip-shared` implementation.
|
||||
- Purpose: single import path for all page modules before deeper implementation merge.
|
||||
|
||||
## `useAutocomplete`
|
||||
|
||||
File: `frontend/src/shared-composables/useAutocomplete.js`
|
||||
|
||||
- Current behavior wraps existing `wip-shared` implementation.
|
||||
- Purpose: single import path to normalize field/autocomplete interactions.
|
||||
|
||||
## `usePaginationState`
|
||||
|
||||
File: `frontend/src/shared-composables/usePaginationState.js`
|
||||
|
||||
- State: `page`, `perPage`, `total`, `totalPages`
|
||||
- Derived: `hasPrev`, `hasNext`
|
||||
- Methods: `setFromPayload`, `reset`
|
||||
|
||||
## `useQueryState`
|
||||
|
||||
File: `frontend/src/shared-composables/useQueryState.js`
|
||||
|
||||
- `readQueryState(keys)`
|
||||
- `writeQueryState(nextState)`
|
||||
- Purpose: unify URL query read/write semantics across pages.
|
||||
@@ -1,40 +0,0 @@
|
||||
# Tailwind Design Tokens Mapping
|
||||
|
||||
## Goal
|
||||
|
||||
Map existing portal visual language into a stable token set for phased migration.
|
||||
|
||||
## Color tokens
|
||||
|
||||
- `brand.500` / `brand.600` / `brand.700`: primary brand actions and active navigation states.
|
||||
- `accent.500`: gradient accent endpoint for shell headers.
|
||||
- `surface.app` / `surface.card` / `surface.muted`: app background, card surfaces, muted blocks.
|
||||
- `stroke.soft` / `stroke.panel`: border hierarchy.
|
||||
- `state.success` / `state.warning` / `state.danger` / `state.neutral`: status dots and health states.
|
||||
|
||||
## Typography tokens
|
||||
|
||||
- `fontFamily.sans`: `Noto Sans TC`, `Microsoft JhengHei`, system fallback.
|
||||
|
||||
## Layout tokens
|
||||
|
||||
- `spacing.shell`: outer shell padding.
|
||||
- `spacing.panel`: panel interior spacing.
|
||||
- `spacing.nav`: sidebar item horizontal spacing.
|
||||
- `spacing.block`: vertical rhythm baseline.
|
||||
|
||||
## Radius and elevation tokens
|
||||
|
||||
- `borderRadius.shell`: shell and main card radius.
|
||||
- `borderRadius.card`: smaller control/card radius.
|
||||
- `boxShadow.soft`: light containers (sidebar).
|
||||
- `boxShadow.panel`: content panel container.
|
||||
- `boxShadow.shell`: header gradient card emphasis.
|
||||
|
||||
## Z-index token
|
||||
|
||||
- `zIndex.popup`: status popup / overlay layer.
|
||||
|
||||
## Migration note
|
||||
|
||||
Tokens are intentionally aligned with current portal values to minimize visual drift during iframe decommission.
|
||||
@@ -1,33 +0,0 @@
|
||||
# Tailwind Migration Guide (Portal No-iframe)
|
||||
|
||||
## Purpose
|
||||
|
||||
Move distributed page CSS toward a token-driven Tailwind system without breaking existing portal behavior.
|
||||
|
||||
## Step-by-step
|
||||
|
||||
1. Keep existing route/page behavior unchanged.
|
||||
2. Replace repeated layout wrappers with Tailwind utilities first (`grid`, `flex`, spacing, radius, shadows).
|
||||
3. Replace repeated visual primitives with shared component classes from `@layer components`.
|
||||
4. Move hard-coded colors/spacing to tokens in `tailwind.config.js` and `tailwind.css`.
|
||||
5. Remove obsolete page-local CSS only after visual parity is verified.
|
||||
|
||||
## Recommended migration order
|
||||
|
||||
1. Shell and shared navigation blocks
|
||||
2. Filter bars and KPI card rows
|
||||
3. Shared table containers and pagination controls
|
||||
4. Page-specific edge states and empty/error banners
|
||||
|
||||
## Parity checks per batch
|
||||
|
||||
- Drawer visibility and route links stay unchanged.
|
||||
- Existing URL/query semantics remain compatible.
|
||||
- No new runtime style conflicts in non-admin/admin views.
|
||||
|
||||
## Do / Don’t
|
||||
|
||||
- Do: prefer composable utility classes and shared Vue components.
|
||||
- Do: keep style changes scoped to one route family per batch.
|
||||
- Don’t: introduce new long inline `<style>` blocks in templates.
|
||||
- Don’t: mix unrelated refactors with migration styling tasks.
|
||||
@@ -1,26 +0,0 @@
|
||||
# Tailwind Style Governance (Migration Phase)
|
||||
|
||||
## Scope
|
||||
|
||||
- Applies to all new frontend work under `frontend/src/**` during iframe removal migration.
|
||||
- Existing page-local CSS can remain temporarily, but new large page-local blocks are disallowed.
|
||||
|
||||
## Rules
|
||||
|
||||
1. New shared UI styles must be authored in Tailwind layers (`base`, `components`, `utilities`) under `frontend/src/styles/tailwind.css`.
|
||||
2. Reusable patterns (cards, filter bars, badge groups, table shells) must use component classes or Vue components, not copy-pasted CSS.
|
||||
3. Page-specific CSS additions over 40 lines require an explicit migration note in the PR and an issue to move them into shared layers.
|
||||
4. Token values must come from `tailwind.config.js` or CSS variables in `tailwind.css`; hard-coded new color scales are disallowed.
|
||||
5. Motion/accessibility styles must support reduced-motion fallback and avoid forced animation on critical data refresh paths.
|
||||
|
||||
## Review Checklist
|
||||
|
||||
- New files import `frontend/src/styles/tailwind.css` through the entry module.
|
||||
- No new iframe-targeting selectors are introduced.
|
||||
- Shared classes/components are reused before adding page-local CSS.
|
||||
- Token naming remains stable (`brand`, `surface`, `stroke`, `state`, spacing/radius/shadow/z-index).
|
||||
|
||||
## Exceptions
|
||||
|
||||
- Bugfix hotfixes may temporarily bypass these rules only if release risk is high.
|
||||
- Every exception must include an expiry task in `openspec/changes/portal-no-iframe-navigation/tasks.md`.
|
||||
@@ -1,44 +0,0 @@
|
||||
# `tmtt-defect` Rewrite Exemplar
|
||||
|
||||
## Scope
|
||||
|
||||
- Route: `/tmtt-defect`
|
||||
- Goal: establish the first canonical legacy rewrite pattern with:
|
||||
- Vue SFC composition
|
||||
- shared UI layer reuse
|
||||
- Tailwind token layer coexistence
|
||||
- no iframe / no wrapper dependency
|
||||
|
||||
## Implemented Structure
|
||||
|
||||
- Entry: `frontend/src/tmtt-defect/main.js`
|
||||
- Page container: `frontend/src/tmtt-defect/App.vue`
|
||||
- Data state/composable: `frontend/src/tmtt-defect/composables/useTmttDefectData.js`
|
||||
- Reusable page components:
|
||||
- `frontend/src/tmtt-defect/components/TmttKpiCards.vue`
|
||||
- `frontend/src/tmtt-defect/components/TmttChartCard.vue`
|
||||
- `frontend/src/tmtt-defect/components/TmttDetailTable.vue`
|
||||
- Shared UI usage:
|
||||
- `frontend/src/shared-ui/components/FilterToolbar.vue`
|
||||
- `frontend/src/shared-ui/components/SectionCard.vue`
|
||||
- `frontend/src/shared-ui/components/StatusBadge.vue`
|
||||
- Backend template mount shell: `src/mes_dashboard/templates/tmtt_defect.html`
|
||||
|
||||
## Behavioral Parity
|
||||
|
||||
The rewrite keeps current route and API contracts:
|
||||
|
||||
- Query API: `GET /api/tmtt-defect/analysis`
|
||||
- Export API: `GET /api/tmtt-defect/export`
|
||||
- Sort/filter/detail behavior preserved on result table
|
||||
|
||||
Smoke coverage references:
|
||||
|
||||
- `TMTT-SMOKE-01` ~ `TMTT-SMOKE-06` in `legacy_rewrite_smoke_checklists.md`
|
||||
|
||||
## Verification Snapshot
|
||||
|
||||
- `npm --prefix frontend run build` passed
|
||||
- `pytest -q tests/test_template_integration.py tests/test_portal_shell_routes.py tests/test_cutover_gates.py tests/test_app_factory.py` passed
|
||||
|
||||
This page is the baseline implementation that remaining legacy rewrites follow.
|
||||
@@ -1,41 +0,0 @@
|
||||
# UI Pattern Inventory (WIP / Resource / Hold / QC)
|
||||
|
||||
## Duplicated patterns observed
|
||||
|
||||
1. Filter bars:
|
||||
- `hold-overview/components/FilterBar.vue`
|
||||
- `hold-history/components/FilterBar.vue`
|
||||
- `resource-status/components/FilterBar.vue`
|
||||
- `resource-history/components/FilterBar.vue`
|
||||
- `mid-section-defect/components/FilterBar.vue`
|
||||
2. KPI/Summary cards:
|
||||
- `wip-overview/components/SummaryCards.vue`
|
||||
- `wip-detail/components/SummaryCards.vue`
|
||||
- `hold-detail/components/SummaryCards.vue`
|
||||
- `hold-history/components/SummaryCards.vue`
|
||||
- `resource-status/components/SummaryCards.vue`
|
||||
- `resource-history/components/KpiCards.vue`
|
||||
- `mid-section-defect/components/KpiCards.vue`
|
||||
3. Table + pagination shells:
|
||||
- `wip-detail/components/LotTable.vue`
|
||||
- `hold-detail/components/LotTable.vue`
|
||||
- `hold-overview/components/LotTable.vue`
|
||||
- `hold-history/components/DetailTable.vue`
|
||||
- `mid-section-defect/components/DetailTable.vue`
|
||||
- `qc-gate/components/LotTable.vue`
|
||||
4. Multi-select and query controls:
|
||||
- `resource-shared/components/MultiSelect.vue`
|
||||
- `mid-section-defect/components/MultiSelect.vue`
|
||||
5. Repeated status/badge presentation logic:
|
||||
- WIP/Hold status class mapping and local badge styles in multiple tables/cards.
|
||||
|
||||
## Consolidation targets
|
||||
|
||||
- Shared UI layer (`frontend/src/shared-ui/components`)
|
||||
- Shared composables layer (`frontend/src/shared-composables`)
|
||||
- Tailwind tokenized styles (`frontend/src/styles/tailwind.css`)
|
||||
|
||||
## First migration batch completed
|
||||
|
||||
- Unified pagination rendering for WIP/Hold/Mid-section detail tables through `PaginationControl` wrapper.
|
||||
- Auto-refresh and autocomplete imports migrated to `shared-composables` entry points.
|
||||
@@ -1,27 +0,0 @@
|
||||
# Wrapper Decommission Report
|
||||
|
||||
## Decision
|
||||
|
||||
Legacy shell wrapper mode has been decommissioned after rewrite milestone validation.
|
||||
|
||||
## Changes Applied
|
||||
|
||||
- Removed shell wrapper route branch:
|
||||
- `frontend/src/portal-shell/router.js`
|
||||
- `frontend/src/portal-shell/App.vue`
|
||||
- Removed wrapper-specific frontend artifacts:
|
||||
- deleted `frontend/src/portal-shell/constants.js`
|
||||
- deleted `frontend/src/portal-shell/views/LegacyWrapperView.vue`
|
||||
- Removed backend wrapper telemetry endpoint:
|
||||
- deleted `/api/portal/wrapper-telemetry` in `src/mes_dashboard/app.py`
|
||||
|
||||
## Operational Outcome
|
||||
|
||||
- Portal shell navigation now uses direct page-bridge behavior only.
|
||||
- Legacy page access remains available via direct routes.
|
||||
- Wrapper telemetry contract is retired.
|
||||
|
||||
## Validation
|
||||
|
||||
- Route and template integration tests updated and passing.
|
||||
- Cutover gate tests remain green after wrapper removal.
|
||||
@@ -1,85 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"generated_at": "2026-02-11T07:44:03+00:00",
|
||||
"source": "data/page_status.json",
|
||||
"errors": []
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
{
|
||||
"generated_at": "2026-02-12T02:26:36.887797+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": "released",
|
||||
"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": "released",
|
||||
"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": "dev",
|
||||
"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": "/hold-overview",
|
||||
"name": "Hold 即時概況",
|
||||
"status": "released",
|
||||
"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": "released",
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,706 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
# 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`
|
||||
@@ -1,41 +0,0 @@
|
||||
# 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
|
||||
@@ -1,34 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,44 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,42 +0,0 @@
|
||||
# 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
|
||||
@@ -1,43 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,45 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,151 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"generated_at": "2026-02-11T07:44:03+00:00",
|
||||
"errors": []
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,72 +0,0 @@
|
||||
{
|
||||
"generated_at": "2026-02-12T12:40: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": "f2ca1666f50afb4f922b522cdf739685ce068911a17d6e6c285244770f451f2c"
|
||||
},
|
||||
{
|
||||
"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": "13e000938f5fc398a9abf2c62b3e64dd0c4742ba87b20d144c18befd57e2e1f4"
|
||||
},
|
||||
{
|
||||
"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": "385910e89f10f016f7973e97be30a697a396a71ea470c1bcfe028a2c6daa4cc9"
|
||||
},
|
||||
{
|
||||
"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": "141d712008d33887a103a5a5133543d527be208c2a5700d16f4c045ce13bb166"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,136 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
# 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`.
|
||||
@@ -1,82 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
{
|
||||
"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": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
{
|
||||
"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": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
# 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