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

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

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-02-11

View File

@@ -0,0 +1,131 @@
## Context
`portal-shell` 已建立 Vue Router 導覽骨架與抽屜資料載入,但目前主內容仍以 `PageBridgeView` 導向既有頁面,尚未完成 route-view 內容整合。這代表「不使用 iframe」雖已成為主要技術方向但使用者操作仍處於 shell 與舊頁間切換,抽屜治理、健康資訊呈現與頁面可用性驗收仍分散。
同時,營運中的抽屜設定已由後端 `page_status.json` 管理,且 admin/non-admin 可見性、排序與頁面釋出狀態都依此決定。若 route-view 整合未與抽屜契約同步,就會發生「抽屜有項目但 shell 無法直接承載」或「權限可見性與實際可達性不一致」的風險。
本 change 的定位是「完成遷移」,不只做 shell 外觀而是把導航、內容承載、健康檢查、wrapper 退場與 cutover gate 收斂為單一可驗收遷移路徑。
## Goals / Non-Goals
**Goals:**
- 完成 `portal-shell` route-view 整合,讓已重寫頁面直接在 shell 內容區承載。
- 將 legacy 頁面採「短期 wrapper、最終 rewrite」策略並在本 change 內完成 wrapper 退場。
- 抽屜治理維持後端單一事實來源,並在 shell 端落實 deterministic 顯示與 fallback 行為。
- 健康檢查改為「摘要優先、詳情展開」,避免 header 資訊過載。
- 建立每頁 rewrite smoke 驗收清單與 cutover gate確保遷移可上線且可回滾。
- 對 table/chart/filter/互動/matrix 建立遷移前後對照驗證,未達標不得切換。
**Non-Goals:**
- 不重設 `page_status.json` 的資料模型(`drawers/pages/status/admin_only` 維持)。
- 不改變核心業務 API 的欄位語義與查詢語義。
- 不在本 change 導入新的後端框架或跨服務拆分。
## Decisions
### Decision 1: Shell 採雙模式承載native route-view + temporary wrapper並以能力清單管理
- **選擇**: 在 shell route registry 中明確標註每個頁面的承載模式(`native``wrapper`),由 router 決定掛載元件。
- **理由**:
- 允許先整合既有重寫頁面,再逐步替換 wrapper不阻塞整體切換。
- 能清楚量化「尚未完成遷移」的頁面數量,避免無限期 wrapper。
- **備選方案**:
- 全部先走 wrapper風險低但無法達成完整遷移目標。
- 全部一次性 native 化:風險高、驗收與回滾壓力過大。
### Decision 2: 抽屜契約保持後端治理,前端僅做 route-ready 映射與可達性保護
- **選擇**: `GET /api/portal/navigation` 仍為抽屜來源shell 只加上 route-ready 驗證、可達 fallback、admin 入口一致呈現。
- **理由**:
- 不破壞既有營運調整流程(排序/隱藏/發佈狀態)。
- 避免抽屜資訊在 server/client 出現雙寫與漂移。
- **備選方案**:
- 前端本地抽屜配置:會與管理後台脫鉤,維運成本高。
### Decision 3: 健康資訊採「摘要固定 + 詳情互動展開」
- **選擇**: shell header 僅顯示高層摘要(狀態燈 + 簡短字串);詳細欄位移至點擊展開面板。
- **理由**:
- 解決 header 文案過長與可讀性下降問題。
- 保留診斷深度,不犧牲 ops 能力。
- **備選方案**:
- 全部資訊常駐:視覺噪音高,對導航可用性不利。
- 僅顯示摘要且不提供詳情:故障排查資訊不足。
### Decision 4: 以「每頁 smoke 清單 + Gate」作為切換條件不以主觀完成度判斷
- **選擇**: 每頁 rewrite 需有可執行 smoke 清單G1~G7 gate 不通過不得 final cutover。
- **理由**:
- 遷移規模大,必須機械化驗收標準。
- 可追蹤 regressions 與回滾觸發條件。
- **備選方案**:
- 僅靠人工巡檢:可重複性不足,易漏檢。
### Decision 5: Wrapper 必須在本 change 內歸零,並保留短期 kill-switch
- **選擇**: `job-query``excel-query``query-tool``tmtt-defect` 先保 wrapper 可用,但設里程碑在同一 change 完成 rewrite最後移除 wrapper 路由。
- **理由**:
- 符合「完整遷移」目標,避免技術債延宕。
- 有 kill-switch 可在突發問題時快速退回上一穩定路徑。
- **備選方案**:
- Wrapper 長期保留:短期省工,但不符合完整遷移與長期維護成本控制。
### Decision 6: 互動語義採「基線快照 + 自動驗證 + 發佈門檻」三層保障
- **選擇**: 針對 table/chart/filter/互動/matrix先錄製遷移前基線資料欄位、互動序列、視覺語義遷移後以自動測試和 smoke 清單做逐頁比對,並設 release-block gate。
- **理由**:
- 你的核心風險在「功能看起來可開,但語義已偏移」,必須用可比對證據治理。
- 可量化是否「真的等價」,而不是靠人工主觀判斷。
- **備選方案**:
- 僅做路由可達 smoke不足以驗證 chart/table/matrix 深層語義。
## Risks / Trade-offs
- **[Risk] Route-view 整合後,頁面初次載入時間可能上升** → **Mitigation**: 以 route-level code split、懶載與快取策略控管並建立切頁延遲基線比較。
- **[Risk] 抽屜配置與 route registry 失配造成死連結** → **Mitigation**: 導入 route-ready contract test 與 runtime fallback不可達時導向 shell home + 訊息)。
- **[Risk] Wrapper 退場時漏掉邊緣流程export/進階查詢)** → **Mitigation**: 每頁 smoke 清單納入核心與進階流程;未通過不得切換 native。
- **[Risk] 健康詳情收合後,使用者誤判資訊不足** → **Mitigation**: 摘要保留關鍵狀態詞,並提供單擊展開完整 diagnostics。
- **[Risk] 最後切換期回滾窗口過短** → **Mitigation**: 預演 rollback runbook保留 kill-switch 與既有入口直到所有 gate 連續通過。
- **[Risk] Chart 在 route 切換後容器尺寸或互動狀態異常** → **Mitigation**: 加入 chart resize lifecycle 驗證與互動回放測試(縮放/篩選/聯動)。
- **[Risk] Table/filter/matrix 在重掛載後狀態漂移** → **Mitigation**: 建立 query-state、排序、分頁、選取高亮的前後對照測試。
## Validation Strategy (Pre/Post Migration)
1. **Pre-migration baseline capture**
- 逐頁紀錄table 欄位與排序語義、chart series 與互動行為、filter query contract、matrix 選取/高亮邏輯。
- 產出基線檔與 screenshot/資料快照,作為遷移後對照來源。
2. **Post-migration parity verification**
- 自動化驗證payload key/type、query semantics、table/chart/matrix 行為一致性。
- 互動 smokefilter 套用、chart-table 聯動、matrix drill/select、分頁/返回流程。
- 視覺語義檢查:狀態色、零值顯示、圖例/tooltip、highlight 狀態不漂移。
3. **Gate policy**
- 任一頁面的核心 table/chart/filter/互動/matrix 對照失敗即阻擋 cutover。
- 僅在所有頁面 parity 證據完整且無 critical gap 時,才允許 wrapper 退場與 default cutover。
## Migration Plan
1. **Contract Freeze**
- 鎖定抽屜/路由/權限契約,建立 route-ready 檢查與 mismatch 告警。
2. **Parity Baseline Freeze**
- 完成 table/chart/filter/互動/matrix 基線快照與驗收腳本凍結。
3. **Shell Route-View Host 完成**
- 建立 `native/wrapper` 承載策略、router 動態掛載、fallback 與 breadcrumb/title 一致性。
4. **Health Summary/Detail 改版**
- header 僅顯示摘要,詳細資料改為展開視圖;補齊前後端契約與測試。
5. **Native Integration Wave A已重寫頁**
- 將既有 Vite/Vue 頁面直接整合到 shell route-view移除 PageBridge 導向依賴。
6. **Legacy Rewrite Wave Bwrapper 頁)**
- 完成 `job-query``excel-query``query-tool``tmtt-defect` rewrite逐頁替換 wrapper。
7. **Gate Enforcement & Rollout**
- 每頁 smoke 清單、drawer parity、health/route 穩定性、性能閾值全部通過後切換 default。
8. **Decommission & Cleanup**
- 移除 wrapper 路由與殘留遷移旗標,更新 runbook 與 spec同步封存標準。
## Open Questions
- `native/wrapper` 承載模式是否需回傳於 `navigation` API payload或僅前端 registry 管理即可?
- Wave B 的四頁是否按使用量排序,或以技術風險排序優先重寫?
- cutover 期間是否保留短期雙入口(`/portal``/portal-shell`)觀測窗口?

View File

@@ -0,0 +1,33 @@
## Why
The archived baseline change established a no-iframe SPA shell foundation, but route-view integration is still incomplete for day-to-day use. We need a controlled next phase that keeps drawer navigation stable, preserves page behavior during cutover, and avoids health/status UI overload while retaining diagnosability.
## What Changes
- Integrate rewritten pages directly into `portal-shell` route views and keep selected legacy pages on wrapper mode until rewrite is complete.
- Tighten drawer governance for mixed-mode navigation, including admin entry visibility and route fallback behavior.
- Refine shell health UX to show a compact summary by default and expose detailed diagnostics only on demand (expand/click).
- Add rollout guardrails for route switching with per-page smoke acceptance checklists and explicit rollback points.
- Complete wrapper-page rewrites (`job-query`, `excel-query`, `query-tool`, `tmtt-defect`) and decommission wrapper mode by final cutover.
- Enforce pre/post migration parity validation for table, chart, filter, interaction, and matrix behavior with release-blocking gates.
## Capabilities
### New Capabilities
- `shell-health-summary-detail`: Define summary-vs-detail behavior for shell health diagnostics and user interaction contract.
### Modified Capabilities
- `spa-shell-navigation`: Extend requirements from baseline shell to route-view integration and mixed-mode routing behavior.
- `portal-drawer-navigation`: Update drawer requirements for route readiness, admin entry handling, and fallback semantics.
- `legacy-page-wrapper-strategy`: Clarify temporary wrapper usage boundaries and promotion criteria from wrapper to rewrite.
- `migration-gates-and-rollout`: Add enforcement for smoke checklist completion before enabling direct shell route cutover.
- `report-effects-parity`: Strengthen parity requirements for table/chart/filter/interaction/matrix semantics and evidence capture.
## Impact
- Frontend shell code: `frontend/src/portal-shell/**`, `frontend/src/portal/main.js`, related shared UI/composables.
- Backend contracts and health API: navigation metadata provider and shell health endpoint payload/representation.
- Test suites: portal shell route tests, health endpoint tests, route/drawer integration smoke tests.
- Migration docs and operational runbooks for cutover/rollback and acceptance evidence.
- Legacy module modernization scope: wrapper-first pages must reach native route-view integration before this change is complete.
- Pre/post parity evidence pipeline: baseline snapshots, visual/interaction smoke records, and gate reports for table/chart/filter/matrix parity.

View File

@@ -0,0 +1,45 @@
## MODIFIED Requirements
### Requirement: Selected legacy pages SHALL be integrated via wrapper-first strategy
The migration SHALL integrate `job-query`, `excel-query`, `query-tool`, and `tmtt-defect` through wrapper-based routing before full rewrites, and SHALL keep this mode temporary and explicitly tracked.
#### Scenario: Wrapper route availability for selected pages
- **WHEN** users navigate to each selected legacy page from the new shell
- **THEN** the route SHALL remain reachable and functionally usable through the wrapper layer
#### Scenario: Wrapper inventory is explicit
- **WHEN** migration status is reviewed for shell cutover readiness
- **THEN** the list of pages still in wrapper mode SHALL be explicitly recorded and versioned
### Requirement: Wrapper mode SHALL preserve legacy functional parity
Wrapper integration SHALL preserve current API interactions, core user workflows, and error handling semantics for wrapped pages until rewrite cutover.
#### Scenario: Legacy workflow parity under wrapper
- **WHEN** users execute core operations on a wrapped page (query/filter/export where applicable)
- **THEN** operation results SHALL remain behaviorally equivalent to pre-wrapper baseline
#### Scenario: Wrapper fallback preserves operability
- **WHEN** a native rewrite is temporarily disabled through rollback controls
- **THEN** the corresponding wrapper path SHALL restore usable behavior within the rollback target
### Requirement: Wrapper phase SHALL define rewrite exit criteria
Each wrapped page SHALL have explicit readiness criteria that gate transition from wrapper mode to full Vue module rewrite.
#### Scenario: Rewrite readiness decision
- **WHEN** a wrapped page reaches agreed quality and parity thresholds
- **THEN** the page SHALL be eligible for rewrite scheduling
- **THEN** wrapper decommission SHALL only occur after rewrite parity validation passes
#### Scenario: Exit criteria are enforced before decommission
- **WHEN** a rewrite candidate page has incomplete smoke or parity evidence
- **THEN** wrapper decommission for that page SHALL be blocked
## ADDED Requirements
### Requirement: Wrapper mode SHALL be fully decommissioned at migration completion
The shell migration SHALL reach an end state where selected legacy pages are served through native route-view modules and wrapper mode is removed from runtime navigation.
#### Scenario: Wrapper count reaches zero
- **WHEN** final migration gates are evaluated
- **THEN** `job-query`, `excel-query`, `query-tool`, and `tmtt-defect` SHALL all resolve through native route-view integration
- **THEN** wrapper-only runtime routes for these pages SHALL no longer be active navigation targets

View File

@@ -0,0 +1,41 @@
## MODIFIED Requirements
### Requirement: Migration Gates SHALL Define Cutover Readiness
The system SHALL define explicit migration gates for functional parity, build integrity, drawer visibility parity, route-view readiness, wrapper decommission readiness, and operational health before final cutover.
#### Scenario: Gate evaluation before cutover
- **WHEN** release is prepared for final cutover
- **THEN** all required migration gates MUST pass or cutover SHALL be blocked
#### Scenario: Functional parity gate fails
- **WHEN** any critical route or core workflow parity check fails during gate execution
- **THEN** release governance MUST treat the cutover as failed and prevent promotion
#### Scenario: Rewrite smoke checklist incomplete
- **WHEN** any page in the migration parity matrix has incomplete smoke acceptance evidence
- **THEN** final cutover SHALL be blocked
### Requirement: Rollout and Rollback Procedures MUST be Actionable
The system SHALL document actionable rollout and rollback procedures for SPA-shell migration, route-view integration, and wrapper decommission.
#### Scenario: Rollback execution
- **WHEN** post-cutover validation fails critical checks
- **THEN** operators MUST be able to execute documented rollback steps to restore previous stable behavior
#### Scenario: Kill-switch rollback
- **WHEN** severe production regression is detected after cutover
- **THEN** operators MUST be able to disable the new navigation path through a documented kill-switch mechanism and recover service usability within the defined rollback target time
#### Scenario: Partial rollback for route-view wave
- **WHEN** regressions are isolated to one or more rewritten pages
- **THEN** operators MUST be able to roll back affected pages to controlled fallback mode without breaking shell navigation for unaffected pages
## ADDED Requirements
### Requirement: Migration gates SHALL enforce shell health UX readiness
Cutover readiness SHALL include verification that shell health status is compact by default and detailed diagnostics remain available on demand.
#### Scenario: Health UX gate before release
- **WHEN** release gates are executed
- **THEN** shell header health widget MUST render summary-first behavior
- **THEN** detailed diagnostics MUST remain accessible through explicit user interaction

View File

@@ -0,0 +1,55 @@
## MODIFIED Requirements
### Requirement: Portal Navigation SHALL Group Entries by Functional Drawers
The portal SHALL group navigation entries into functional drawers as defined in the `drawers` configuration of `page_status.json`, rendered by the active portal runtime (server template or SPA shell) without changing drawer assignment semantics and without coupling drawer semantics to iframe/frame metadata.
#### Scenario: Drawer grouping visibility
- **WHEN** users open the portal
- **THEN** the sidebar SHALL display drawers in the order defined by each drawer's `order` field
- **THEN** each drawer SHALL show only the pages assigned to it via `drawer_id`, sorted by each page's `order` field
#### Scenario: Admin-only drawer visibility
- **WHEN** a drawer has `admin_only: true` and the current user is not admin
- **THEN** the drawer and all its pages SHALL NOT be rendered in the sidebar
#### Scenario: Empty drawer visibility
- **WHEN** a drawer has no visible pages (all filtered out by page visibility checks)
- **THEN** the drawer group title SHALL NOT be rendered
### Requirement: Existing Page Behavior SHALL Remain Compatible
The portal navigation refactor SHALL preserve existing target routes while replacing iframe-based page embedding with route-driven navigation and route-view hosting.
#### Scenario: Route continuity
- **WHEN** a user selects an existing page entry from a drawer
- **THEN** the corresponding original route contract SHALL be loaded without changing page business logic behavior
#### Scenario: Direct navigation without iframe
- **WHEN** a sidebar item is clicked
- **THEN** the browser navigation context SHALL remain in the same shell window
- **THEN** the portal SHALL NOT render or activate iframe elements for page content
#### Scenario: Deterministic render mode resolution
- **WHEN** a page is configured for `native` or `wrapper` mode in the shell route registry
- **THEN** the selected mode SHALL resolve deterministically for every request
- **THEN** mode resolution SHALL NOT alter drawer assignment or visibility semantics
### Requirement: Drawer Configuration and Visibility SHALL Remain Deterministic During Migration
Migration to SPA navigation SHALL preserve the effective drawer visibility outcomes defined by current `drawers + pages + status + admin_only` rules and SHALL provide deterministic fallback behavior when route contracts are invalid.
#### Scenario: Non-admin visible drawer pages remain stable
- **WHEN** a non-admin user opens the portal after migration
- **THEN** only pages with released visibility in non-admin drawers SHALL be visible
- **THEN** admin-only drawers SHALL remain hidden
#### Scenario: Admin visible drawer pages remain stable
- **WHEN** an admin user opens the portal after migration
- **THEN** all pages allowed by drawer assignment and page status rules SHALL remain visible
#### Scenario: Duplicate order values resolve deterministically
- **WHEN** multiple pages or drawers share the same `order` value
- **THEN** rendering order SHALL still be deterministic and repeatable across requests
#### Scenario: Invalid route contract fallback
- **WHEN** a drawer entry references a missing or invalid shell route contract
- **THEN** the shell SHALL block direct navigation to that contract
- **THEN** the error SHALL be observable through contract validation or diagnostics

View File

@@ -0,0 +1,51 @@
## MODIFIED Requirements
### Requirement: Report Effect Parity SHALL Be Preserved During Vite Migration
The system SHALL preserve existing report interactions and state transitions when report pages are served through shell route-view migration.
#### Scenario: WIP overview interactions remain equivalent
- **WHEN** users operate WIP overview filters, KPI cards, chart refresh, and drill-down entry
- **THEN** the resulting state transitions and navigation parameters MUST remain behaviorally equivalent to the baseline page logic
#### Scenario: WIP detail interactions remain equivalent
- **WHEN** users operate WIP detail filters, pagination, lot detail popup, and back-to-overview transitions
- **THEN** the resulting data scope and interaction behavior MUST match baseline semantics
#### Scenario: Query/filter semantics remain equivalent across shell transitions
- **WHEN** users apply filter combinations and navigate between list/detail pages in shell route-view
- **THEN** request query parameters and returned data scope MUST remain equivalent to the pre-migration baseline
### Requirement: Report Visual Semantics MUST Remain Consistent
Report pages SHALL keep established status color semantics, KPI display rules, and table/chart/matrix synchronization behavior after migration.
#### Scenario: KPI and matrix state consistency
- **WHEN** metric values are zero or filters target specific matrix levels
- **THEN** KPI values and selected-state highlights MUST render correctly without collapsing valid zero values or losing selection state
#### Scenario: Table and chart linked interaction consistency
- **WHEN** users interact with chart selections, legends, or drill actions that influence table/matrix scope
- **THEN** table rows, matrix selections, and highlight states MUST remain synchronized with chart interaction intent
#### Scenario: Chart container lifecycle consistency after route switch
- **WHEN** a chart page is entered via shell navigation or revisited after route transitions
- **THEN** chart layout, tooltip, and interaction targets MUST render correctly without clipped or stale state
### Requirement: Hold Detail Interaction Semantics SHALL Remain Equivalent After Modularization
Migrating hold-detail to a Vite module and shell route-view integration SHALL preserve existing filter, pagination, and refresh behavior.
#### Scenario: User applies filters and paginates on hold-detail
- **WHEN** users toggle age/workcenter/package filters and navigate pages
- **THEN** returned lots, distribution highlights, and pagination state MUST remain behaviorally equivalent to baseline inline behavior
## ADDED Requirements
### Requirement: Report parity evidence SHALL be captured before and after migration
The migration process SHALL produce verifiable pre/post evidence for table, chart, filter, interaction, and matrix parity on each target page.
#### Scenario: Baseline evidence capture before rewrite
- **WHEN** a page enters migration scope
- **THEN** baseline artifacts SHALL be recorded for key workflows, query contracts, and visual/interaction semantics
#### Scenario: Release gate blocks on missing parity evidence
- **WHEN** cutover readiness is evaluated
- **THEN** any page without complete parity evidence or with unresolved critical deviations SHALL block release

View File

@@ -0,0 +1,34 @@
## ADDED Requirements
### Requirement: Shell health widget SHALL default to compact summary
The shell header SHALL display a compact health summary that communicates overall connection status without rendering full diagnostics inline.
#### Scenario: Compact summary on initial render
- **WHEN** users open `portal-shell`
- **THEN** the header SHALL show health status indicator and short summary text only
- **THEN** detailed subsystem fields SHALL NOT be expanded by default
#### Scenario: Summary reflects aggregated status changes
- **WHEN** backend or shell health status changes between healthy/degraded/unhealthy
- **THEN** the compact summary label and status indicator SHALL update to the new aggregated state
### Requirement: Shell health diagnostics SHALL be disclosed on explicit user interaction
Detailed diagnostics SHALL be available from the shell health widget through explicit user action (click/toggle), while preserving navigation readability.
#### Scenario: Open health detail diagnostics
- **WHEN** a user clicks the health summary widget
- **THEN** the shell SHALL expand or open the diagnostics panel
- **THEN** the panel SHALL include backend and frontend-shell diagnostic items needed for troubleshooting
#### Scenario: Close diagnostics without side effects
- **WHEN** a user clicks outside the diagnostics panel or toggles the widget again
- **THEN** the diagnostics panel SHALL close
- **THEN** current route and page state SHALL remain unchanged
### Requirement: Health diagnostics SHALL remain actionable when health endpoints degrade
The widget SHALL provide a deterministic fallback summary and detail state when one or more health endpoints are unavailable.
#### Scenario: Health endpoint error fallback
- **WHEN** `/health` or `/health/frontend-shell` fails to return a successful response
- **THEN** the summary SHALL indicate degraded or unreachable state
- **THEN** the diagnostics panel SHALL show fallback values or error context instead of empty content

View File

@@ -0,0 +1,43 @@
## MODIFIED Requirements
### Requirement: Portal SHALL provide a SPA shell driven by Vue Router
The portal frontend SHALL use a single SPA shell entry and Vue Router to render page modules without iframe embedding, and SHALL route each page through either native route-view integration or a temporary wrapper component.
#### Scenario: Drawer navigation renders integrated route view
- **WHEN** a user clicks a sidebar page entry whose migration mode is `native`
- **THEN** the active route SHALL be updated through Vue Router
- **THEN** the main content area SHALL render the corresponding page module inside shell route-view without iframe usage
#### Scenario: Wrapper route remains available during migration
- **WHEN** a user clicks a sidebar page entry whose migration mode is `wrapper`
- **THEN** Vue Router SHALL render the wrapper host in shell content area
- **THEN** the wrapper SHALL preserve page reachability until native rewrite is completed
### Requirement: Existing route contracts SHALL remain stable in SPA mode
Migration to SPA shell SHALL preserve existing route paths, deep-link behavior, and query semantics during both native and wrapper phases.
#### Scenario: Direct route entry remains functional
- **WHEN** a user opens an existing route directly (bookmark or refresh)
- **THEN** the route SHALL resolve to the same page functionality as before migration
- **THEN** required query parameters SHALL continue to be interpreted with compatible semantics
#### Scenario: Query continuity across shell navigation
- **WHEN** users navigate from shell list pages to detail pages and back
- **THEN** query-state parameters required by list/detail workflows SHALL remain consistent with pre-migration behavior
### Requirement: SPA shell navigation SHALL enforce page visibility rules
SPA navigation SHALL respect backend-defined drawer and page visibility outcomes, including admin entry visibility and route fallback for hidden routes.
#### Scenario: Non-admin visibility in SPA shell
- **WHEN** a non-admin user opens the shell
- **THEN** routes and drawer items restricted to admin-only visibility SHALL NOT be presented as navigable entries
#### Scenario: Admin visibility in SPA shell
- **WHEN** an admin user opens the shell
- **THEN** pages allowed by drawer and page status rules SHALL be presented as navigable entries
- **THEN** admin entry links exposed by the shell SHALL remain reachable
#### Scenario: Hidden or unknown route fallback
- **WHEN** a user navigates to a route that is not visible or not registered in the current shell navigation set
- **THEN** the shell SHALL redirect to a safe fallback route
- **THEN** the shell SHALL NOT expose iframe-based fallback rendering

View File

@@ -0,0 +1,97 @@
## 1. Migration Baseline and Contract Freeze
- [x] 1.1 Refresh migration baseline snapshots for drawer visibility (admin/non-admin), route availability, and critical query contracts.
- [x] 1.2 Build and commit a route parity matrix for all shell-target pages (`/wip-overview`, `/wip-detail`, `/hold-overview`, `/hold-detail`, `/hold-history`, `/resource`, `/resource-history`, `/qc-gate`, `/job-query`, `/excel-query`, `/query-tool`, `/tmtt-defect`).
- [x] 1.3 Freeze migration contract doc: route id, render mode (`native|wrapper`), required query keys, owner, rollback strategy.
- [x] 1.4 Add contract validation for missing route definitions, duplicated mappings, and invalid render mode declarations.
- [x] 1.5 Capture pre-migration baseline evidence for each target page: table schema/sort/pagination, chart series/legend/tooltip, filter combinations, matrix selection states.
## 2. Shell Route-View Architecture Hardening
- [x] 2.1 Replace `PageBridgeView`-only routing with explicit shell render-mode registry (`native` component host, `wrapper` host).
- [x] 2.2 Implement deterministic dynamic route registration from backend drawer payload + local render-mode registry.
- [x] 2.3 Add unknown/hidden route fallback behavior (safe redirect + non-intrusive user notice).
- [x] 2.4 Ensure breadcrumb/title metadata resolves from route contracts for both native and wrapper modes.
- [x] 2.5 Add integration tests for router registration, fallback routing, and render-mode resolution.
## 3. Drawer Governance and Admin Entry Consistency
- [x] 3.1 Align drawer ordering and page ordering logic between backend navigation payload and shell rendering.
- [x] 3.2 Enforce deterministic filtering for `admin_only` drawers/pages in shell UI and router guards.
- [x] 3.3 Ensure admin entry points (`/admin/pages`, login/logout links) are visible and reachable under expected auth states.
- [x] 3.4 Add contract tests for drawer parity against baseline snapshots (admin and non-admin).
- [x] 3.5 Add diagnostics/logging for drawer-route mismatch events and invalid navigation payloads.
## 4. Health Check Summary/Detail UX Completion
- [x] 4.1 Refactor shell health widget to summary-first header presentation (status dot + concise text only).
- [x] 4.2 Keep detailed health diagnostics behind explicit interaction (click/toggle panel or modal).
- [x] 4.3 Ensure detail panel supports close-on-outside-click, keyboard escape, and stable focus behavior.
- [x] 4.4 Refine `/health/frontend-shell` contract to separate summary fields from detailed diagnostics payload.
- [x] 4.5 Add tests for healthy/degraded/unhealthy summary transitions and endpoint failure fallback behavior.
## 5. Native Route-View Integration Wave A (Already-Rewritten Pages)
- [x] 5.1 Integrate `/wip-overview` as native shell route-view and verify filter/query URL sync behavior.
- [x] 5.2 Integrate `/wip-detail` as native shell route-view and verify detail/list back-navigation query continuity.
- [x] 5.3 Integrate `/hold-overview` and `/hold-detail` as native shell route-views with reason/type query parity.
- [x] 5.4 Integrate `/hold-history` as native shell route-view with date/record-type filter parity.
- [x] 5.5 Integrate `/resource` and `/resource-history` as native shell route-views with summary/detail/export parity.
- [x] 5.6 Integrate `/qc-gate` as native shell route-view with chart-table linked interactions preserved.
- [x] 5.7 Add route-level smoke tests for Wave A pages in shell context (render, query, refresh, navigation).
- [x] 5.8 Add chart lifecycle checks for Wave A (route enter/re-enter, resize, tooltip, linked-highlight stability).
## 6. Wrapper Stabilization Wave B (Before Rewrite)
- [x] 6.1 Keep wrapper-mode operability for `/job-query` with query/search/export smoke coverage.
- [x] 6.2 Keep wrapper-mode operability for `/excel-query` with upload/detect/query/export smoke coverage.
- [x] 6.3 Keep wrapper-mode operability for `/query-tool` with resolve/history/association workflows.
- [x] 6.4 Keep wrapper-mode operability for `/tmtt-defect` with range query and CSV export workflow.
- [x] 6.5 Instrument wrapper telemetry for load success/error/latency and fallback usage count.
- [x] 6.6 Define per-page rewrite entry criteria and block native cutover when criteria are incomplete.
## 7. Wrapper-to-Native Rewrite Completion (Full Migration Target)
- [x] 7.1 Rewrite `/tmtt-defect` as canonical native shell route-view module using shared UI/composables.
- [x] 7.2 Rewrite `/job-query` as native shell route-view module with workflow parity and no wrapper dependency.
- [x] 7.3 Rewrite `/excel-query` as native shell route-view module with upload-query-export parity.
- [x] 7.4 Rewrite `/query-tool` as native shell route-view module with full workflow parity.
- [x] 7.5 Replace wrapper mapping with native mapping in shell route registry for all Wave B pages.
- [x] 7.6 Decommission wrapper runtime paths and remove wrapper-only fallback code once parity gates pass.
- [x] 7.7 Validate table/chart/filter/matrix parity for each rewritten Wave B page before marking rewrite complete.
## 8. Per-Page Rewrite Smoke Acceptance (Mandatory)
- [x] 8.1 Build a smoke checklist artifact per rewritten page (entry path, required query params, key interaction, error path, export path).
- [x] 8.2 Execute and record smoke evidence for Wave A native pages under shell route-view.
- [x] 8.3 Execute and record smoke evidence for Wave B rewritten pages before wrapper decommission.
- [x] 8.4 Block release when any page lacks complete smoke evidence or has unresolved critical failures.
- [x] 8.5 Extend smoke checklist fields to include mandatory table/chart/filter/interaction/matrix checkpoints and expected outcomes.
- [x] 8.6 Add explicit zero-value and empty-state checks for KPI/table/matrix rendering parity.
## 9. Test and Quality Gate Enforcement
- [x] 9.1 Extend backend tests for `/api/portal/navigation` contract parity (drawer/page ordering, visibility, admin metadata).
- [x] 9.2 Extend shell frontend tests for route-mode rendering, health summary/detail behavior, and admin entry visibility.
- [x] 9.3 Add regression tests ensuring no iframe elements are used for shell page content paths.
- [x] 9.4 Add contract tests for route/query compatibility across list-detail workflows.
- [x] 9.5 Add cutover gate tests validating G1-G7 readiness signals and failure-block semantics.
- [x] 9.6 Add table parity tests (column keys/types/order, sorting semantics, pagination continuity).
- [x] 9.7 Add chart parity tests (series key/type, legend toggles, tooltip behavior, chart-table linked scope).
- [x] 9.8 Add matrix interaction tests (selection/highlight persistence, drill behavior, filter-linked state transitions).
- [x] 9.9 Add visual regression snapshots for critical chart/table/matrix states and block on critical diffs.
## 10. Rollout, Rollback, and Operations
- [x] 10.1 Define phased rollout plan for shell route-view cutover (canary scope, thresholds, hold points).
- [x] 10.2 Rehearse rollback playbook for both full rollback and page-level partial rollback.
- [x] 10.3 Define kill-switch operation for quickly reverting affected pages while keeping shell accessible.
- [x] 10.4 Capture migration observability dashboard/report for route errors, health regressions, and wrapper fallback usage.
## 11. Cleanup and Closure
- [x] 11.1 Remove obsolete `PageBridgeView` redirect-only logic after all pages are native-integrated.
- [x] 11.2 Remove wrapper-specific code, flags, and stale docs after verified decommission.
- [x] 11.3 Update migration docs/spec references to reflect completed no-iframe full migration state.
- [x] 11.4 Run final parity audit and archive-readiness checklist before change closure.
- [x] 11.5 Produce final pre/post parity report summarizing page-by-page outcomes for table/chart/filter/interaction/matrix.

View File

@@ -1,22 +1,28 @@
## Purpose
Define stable requirements for legacy-page-wrapper-strategy.
## Requirements
### Requirement: Selected legacy pages SHALL be integrated via wrapper-first strategy
The migration SHALL integrate `job-query`, `excel-query`, `query-tool`, and `tmtt-defect` through wrapper-based routing before full rewrites.
The migration SHALL integrate `job-query`, `excel-query`, `query-tool`, and `tmtt-defect` through wrapper-based routing before full rewrites, and SHALL keep this mode temporary and explicitly tracked.
#### Scenario: Wrapper route availability for selected pages
- **WHEN** users navigate to each selected legacy page from the new shell
- **THEN** the route SHALL remain reachable and functionally usable through the wrapper layer
#### Scenario: Wrapper inventory is explicit
- **WHEN** migration status is reviewed for shell cutover readiness
- **THEN** the list of pages still in wrapper mode SHALL be explicitly recorded and versioned
### Requirement: Wrapper mode SHALL preserve legacy functional parity
Wrapper integration SHALL preserve current API interactions, core user workflows, and error handling semantics for wrapped pages.
Wrapper integration SHALL preserve current API interactions, core user workflows, and error handling semantics for wrapped pages until rewrite cutover.
#### Scenario: Legacy workflow parity under wrapper
- **WHEN** users execute core operations on a wrapped page (query/filter/export where applicable)
- **THEN** operation results SHALL remain behaviorally equivalent to pre-wrapper baseline
#### Scenario: Wrapper fallback preserves operability
- **WHEN** a native rewrite is temporarily disabled through rollback controls
- **THEN** the corresponding wrapper path SHALL restore usable behavior within the rollback target
### Requirement: Wrapper phase SHALL define rewrite exit criteria
Each wrapped page SHALL have explicit readiness criteria that gate transition from wrapper mode to full Vue module rewrite.
@@ -24,3 +30,16 @@ Each wrapped page SHALL have explicit readiness criteria that gate transition fr
- **WHEN** a wrapped page reaches agreed quality and parity thresholds
- **THEN** the page SHALL be eligible for rewrite scheduling
- **THEN** wrapper decommission SHALL only occur after rewrite parity validation passes
#### Scenario: Exit criteria are enforced before decommission
- **WHEN** a rewrite candidate page has incomplete smoke or parity evidence
- **THEN** wrapper decommission for that page SHALL be blocked
### Requirement: Wrapper mode SHALL be fully decommissioned at migration completion
The shell migration SHALL reach an end state where selected legacy pages are served through native route-view modules and wrapper mode is removed from runtime navigation.
#### Scenario: Wrapper count reaches zero
- **WHEN** final migration gates are evaluated
- **THEN** `job-query`, `excel-query`, `query-tool`, and `tmtt-defect` SHALL all resolve through native route-view integration
- **THEN** wrapper-only runtime routes for these pages SHALL no longer be active navigation targets

View File

@@ -2,7 +2,7 @@
Define stable requirements for migration-gates-and-rollout.
## Requirements
### Requirement: Migration Gates SHALL Define Cutover Readiness
The system SHALL define explicit migration gates for functional parity, build integrity, drawer visibility parity, and operational health before final cutover.
The system SHALL define explicit migration gates for functional parity, build integrity, drawer visibility parity, route-view readiness, wrapper decommission readiness, and operational health before final cutover.
#### Scenario: Gate evaluation before cutover
- **WHEN** release is prepared for final cutover
@@ -12,8 +12,12 @@ The system SHALL define explicit migration gates for functional parity, build in
- **WHEN** any critical route or core workflow parity check fails during gate execution
- **THEN** release governance MUST treat the cutover as failed and prevent promotion
#### Scenario: Rewrite smoke checklist incomplete
- **WHEN** any page in the migration parity matrix has incomplete smoke acceptance evidence
- **THEN** final cutover SHALL be blocked
### Requirement: Rollout and Rollback Procedures MUST be Actionable
The system SHALL document actionable rollout and rollback procedures for SPA-shell migration and iframe decommission.
The system SHALL document actionable rollout and rollback procedures for SPA-shell migration, route-view integration, and wrapper decommission.
#### Scenario: Rollback execution
- **WHEN** post-cutover validation fails critical checks
@@ -23,6 +27,10 @@ The system SHALL document actionable rollout and rollback procedures for SPA-she
- **WHEN** severe production regression is detected after cutover
- **THEN** operators MUST be able to disable the new navigation path through a documented kill-switch mechanism and recover service usability within the defined rollback target time
#### Scenario: Partial rollback for route-view wave
- **WHEN** regressions are isolated to one or more rewritten pages
- **THEN** operators MUST be able to roll back affected pages to controlled fallback mode without breaking shell navigation for unaffected pages
### Requirement: Migration Gates SHALL Include Runtime Resilience Validation
Cutover readiness gates MUST include resilience checks for pool exhaustion handling, circuit-breaker fail-fast behavior, and recovery flow.
@@ -54,3 +62,12 @@ Cutover governance MUST include verification that runtime architecture contracts
#### Scenario: Gate fails on stale architecture contract
- **WHEN** implementation introduces resilience or module-governance changes but README architecture section remains outdated
- **THEN** release governance MUST treat the gate as failed until documentation is aligned
### Requirement: Migration gates SHALL enforce shell health UX readiness
Cutover readiness SHALL include verification that shell health status is compact by default and detailed diagnostics remain available on demand.
#### Scenario: Health UX gate before release
- **WHEN** release gates are executed
- **THEN** shell header health widget MUST render summary-first behavior
- **THEN** detailed diagnostics MUST remain accessible through explicit user interaction

View File

@@ -1,10 +1,8 @@
## Purpose
Define stable requirements for portal-drawer-navigation.
## Requirements
### Requirement: Portal Navigation SHALL Group Entries by Functional Drawers
The portal SHALL group navigation entries into functional drawers as defined in the `drawers` configuration of `page_status.json`, rendered by the active portal runtime (server template or SPA shell) without changing drawer assignment semantics.
The portal SHALL group navigation entries into functional drawers as defined in the `drawers` configuration of `page_status.json`, rendered by the active portal runtime (server template or SPA shell) without changing drawer assignment semantics and without coupling drawer semantics to iframe/frame metadata.
#### Scenario: Drawer grouping visibility
- **WHEN** users open the portal
@@ -20,19 +18,24 @@ The portal SHALL group navigation entries into functional drawers as defined in
- **THEN** the drawer group title SHALL NOT be rendered
### Requirement: Existing Page Behavior SHALL Remain Compatible
The portal navigation refactor SHALL preserve existing target routes while replacing iframe-based page embedding with route-driven navigation.
The portal navigation refactor SHALL preserve existing target routes while replacing iframe-based page embedding with route-driven navigation and route-view hosting.
#### Scenario: Route continuity
- **WHEN** a user selects an existing page entry from a drawer
- **THEN** the corresponding original route SHALL be loaded without changing page business logic behavior
- **THEN** the corresponding original route contract SHALL be loaded without changing page business logic behavior
#### Scenario: Direct navigation without iframe
- **WHEN** a sidebar item is clicked
- **THEN** the browser SHALL navigate to the page's route in the same window
- **THEN** the browser navigation context SHALL remain in the same shell window
- **THEN** the portal SHALL NOT render or activate iframe elements for page content
#### Scenario: Deterministic render mode resolution
- **WHEN** a page is configured for `native` or `wrapper` mode in the shell route registry
- **THEN** the selected mode SHALL resolve deterministically for every request
- **THEN** mode resolution SHALL NOT alter drawer assignment or visibility semantics
### Requirement: Drawer Configuration and Visibility SHALL Remain Deterministic During Migration
Migration to SPA navigation SHALL preserve the effective drawer visibility outcomes defined by current `drawers + pages + status + admin_only` rules.
Migration to SPA navigation SHALL preserve the effective drawer visibility outcomes defined by current `drawers + pages + status + admin_only` rules and SHALL provide deterministic fallback behavior when route contracts are invalid.
#### Scenario: Non-admin visible drawer pages remain stable
- **WHEN** a non-admin user opens the portal after migration
@@ -46,3 +49,9 @@ Migration to SPA navigation SHALL preserve the effective drawer visibility outco
#### Scenario: Duplicate order values resolve deterministically
- **WHEN** multiple pages or drawers share the same `order` value
- **THEN** rendering order SHALL still be deterministic and repeatable across requests
#### Scenario: Invalid route contract fallback
- **WHEN** a drawer entry references a missing or invalid shell route contract
- **THEN** the shell SHALL block direct navigation to that contract
- **THEN** the error SHALL be observable through contract validation or diagnostics

View File

@@ -4,7 +4,7 @@
TBD - created by archiving change vite-jinja-report-parity-hardening. Update Purpose after archive.
## Requirements
### Requirement: Report Effect Parity SHALL Be Preserved During Vite Migration
The system SHALL preserve existing Jinja-era report interactions when report pages are served by Vite modules.
The system SHALL preserve existing report interactions and state transitions when report pages are served through shell route-view migration.
#### Scenario: WIP overview interactions remain equivalent
- **WHEN** users operate WIP overview filters, KPI cards, chart refresh, and drill-down entry
@@ -14,17 +14,40 @@ The system SHALL preserve existing Jinja-era report interactions when report pag
- **WHEN** users operate WIP detail filters, pagination, lot detail popup, and back-to-overview transitions
- **THEN** the resulting data scope and interaction behavior MUST match baseline semantics
#### Scenario: Query/filter semantics remain equivalent across shell transitions
- **WHEN** users apply filter combinations and navigate between list/detail pages in shell route-view
- **THEN** request query parameters and returned data scope MUST remain equivalent to the pre-migration baseline
### Requirement: Report Visual Semantics MUST Remain Consistent
Report pages SHALL keep established status color semantics, KPI display rules, and table/chart synchronization behavior after migration.
Report pages SHALL keep established status color semantics, KPI display rules, and table/chart/matrix synchronization behavior after migration.
#### Scenario: KPI and matrix state consistency
- **WHEN** metric values are zero or filters target specific matrix levels
- **THEN** KPI values and selected-state highlights MUST render correctly without collapsing valid zero values or losing selection state
#### Scenario: Table and chart linked interaction consistency
- **WHEN** users interact with chart selections, legends, or drill actions that influence table/matrix scope
- **THEN** table rows, matrix selections, and highlight states MUST remain synchronized with chart interaction intent
#### Scenario: Chart container lifecycle consistency after route switch
- **WHEN** a chart page is entered via shell navigation or revisited after route transitions
- **THEN** chart layout, tooltip, and interaction targets MUST render correctly without clipped or stale state
### Requirement: Hold Detail Interaction Semantics SHALL Remain Equivalent After Modularization
Migrating hold-detail to a Vite module SHALL preserve existing filter, pagination, and refresh behavior.
Migrating hold-detail to a Vite module and shell route-view integration SHALL preserve existing filter, pagination, and refresh behavior.
#### Scenario: User applies filters and paginates on hold-detail
- **WHEN** users toggle age/workcenter/package filters and navigate pages
- **THEN** returned lots, distribution highlights, and pagination state MUST remain behaviorally equivalent to baseline inline behavior
### Requirement: Report parity evidence SHALL be captured before and after migration
The migration process SHALL produce verifiable pre/post evidence for table, chart, filter, interaction, and matrix parity on each target page.
#### Scenario: Baseline evidence capture before rewrite
- **WHEN** a page enters migration scope
- **THEN** baseline artifacts SHALL be recorded for key workflows, query contracts, and visual/interaction semantics
#### Scenario: Release gate blocks on missing parity evidence
- **WHEN** cutover readiness is evaluated
- **THEN** any page without complete parity evidence or with unresolved critical deviations SHALL block release

View File

@@ -0,0 +1,38 @@
# shell-health-summary-detail Specification
## Purpose
TBD - created by archiving change portal-shell-route-view-integration. Update Purpose after archive.
## Requirements
### Requirement: Shell health widget SHALL default to compact summary
The shell header SHALL display a compact health summary that communicates overall connection status without rendering full diagnostics inline.
#### Scenario: Compact summary on initial render
- **WHEN** users open `portal-shell`
- **THEN** the header SHALL show health status indicator and short summary text only
- **THEN** detailed subsystem fields SHALL NOT be expanded by default
#### Scenario: Summary reflects aggregated status changes
- **WHEN** backend or shell health status changes between healthy/degraded/unhealthy
- **THEN** the compact summary label and status indicator SHALL update to the new aggregated state
### Requirement: Shell health diagnostics SHALL be disclosed on explicit user interaction
Detailed diagnostics SHALL be available from the shell health widget through explicit user action (click/toggle), while preserving navigation readability.
#### Scenario: Open health detail diagnostics
- **WHEN** a user clicks the health summary widget
- **THEN** the shell SHALL expand or open the diagnostics panel
- **THEN** the panel SHALL include backend and frontend-shell diagnostic items needed for troubleshooting
#### Scenario: Close diagnostics without side effects
- **WHEN** a user clicks outside the diagnostics panel or toggles the widget again
- **THEN** the diagnostics panel SHALL close
- **THEN** current route and page state SHALL remain unchanged
### Requirement: Health diagnostics SHALL remain actionable when health endpoints degrade
The widget SHALL provide a deterministic fallback summary and detail state when one or more health endpoints are unavailable.
#### Scenario: Health endpoint error fallback
- **WHEN** `/health` or `/health/frontend-shell` fails to return a successful response
- **THEN** the summary SHALL indicate degraded or unreachable state
- **THEN** the diagnostics panel SHALL show fallback values or error context instead of empty content

View File

@@ -1,26 +1,33 @@
## Purpose
Define stable requirements for spa-shell-navigation.
## Requirements
### Requirement: Portal SHALL provide a SPA shell driven by Vue Router
The portal frontend SHALL use a single SPA shell entry and Vue Router to render page modules without iframe embedding.
The portal frontend SHALL use a single SPA shell entry and Vue Router to render page modules without iframe embedding, and SHALL route each page through either native route-view integration or a temporary wrapper component.
#### Scenario: Drawer navigation renders router view
- **WHEN** a user clicks a sidebar page entry
#### Scenario: Drawer navigation renders integrated route view
- **WHEN** a user clicks a sidebar page entry whose migration mode is `native`
- **THEN** the active route SHALL be updated through Vue Router
- **THEN** the main content area SHALL render the corresponding route view without iframe usage
- **THEN** the main content area SHALL render the corresponding page module inside shell route-view without iframe usage
#### Scenario: Wrapper route remains available during migration
- **WHEN** a user clicks a sidebar page entry whose migration mode is `wrapper`
- **THEN** Vue Router SHALL render the wrapper host in shell content area
- **THEN** the wrapper SHALL preserve page reachability until native rewrite is completed
### Requirement: Existing route contracts SHALL remain stable in SPA mode
Migration to SPA shell SHALL preserve existing route paths and deep-link behavior.
Migration to SPA shell SHALL preserve existing route paths, deep-link behavior, and query semantics during both native and wrapper phases.
#### Scenario: Direct route entry remains functional
- **WHEN** a user opens an existing route directly (bookmark or refresh)
- **THEN** the route SHALL resolve to the same page functionality as before migration
- **THEN** required query parameters SHALL continue to be interpreted with compatible semantics
#### Scenario: Query continuity across shell navigation
- **WHEN** users navigate from shell list pages to detail pages and back
- **THEN** query-state parameters required by list/detail workflows SHALL remain consistent with pre-migration behavior
### Requirement: SPA shell navigation SHALL enforce page visibility rules
SPA navigation SHALL respect backend-defined drawer and page visibility outcomes.
SPA navigation SHALL respect backend-defined drawer and page visibility outcomes, including admin entry visibility and route fallback for hidden routes.
#### Scenario: Non-admin visibility in SPA shell
- **WHEN** a non-admin user opens the shell
@@ -29,3 +36,10 @@ SPA navigation SHALL respect backend-defined drawer and page visibility outcomes
#### Scenario: Admin visibility in SPA shell
- **WHEN** an admin user opens the shell
- **THEN** pages allowed by drawer and page status rules SHALL be presented as navigable entries
- **THEN** admin entry links exposed by the shell SHALL remain reachable
#### Scenario: Hidden or unknown route fallback
- **WHEN** a user navigates to a route that is not visible or not registered in the current shell navigation set
- **THEN** the shell SHALL redirect to a safe fallback route
- **THEN** the shell SHALL NOT expose iframe-based fallback rendering