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:
egg
2026-02-13 17:42:11 +08:00
parent 5b358d71c1
commit 248cbc25e0
119 changed files with 842 additions and 9085 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +0,0 @@
{
"change": "full-modernization-architecture-blueprint",
"records": [],
"rule": "next route cutover is blocked until current route has approved manual sign-off"
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +0,0 @@
{
"source": "data/page_status.json",
"errors": []
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 檢查一致。

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 / Dont
- Do: prefer composable utility classes and shared Vue components.
- Do: keep style changes scoped to one route family per batch.
- Dont: introduce new long inline `<style>` blocks in templates.
- Dont: mix unrelated refactors with migration styling tasks.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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