feat(modernization): full architecture blueprint with hardening follow-up
Implement phased modernization infrastructure for transitioning from multi-page legacy routing to SPA portal-shell architecture, plus post-delivery hardening fixes for policy loading, fallback consistency, and governance drift detection. Key changes: - Add route contract enrichment with scope/visibility/compatibility policies - Canonical 302 redirects from legacy direct-entry to /portal-shell/ routes - Asset readiness enforcement and runtime fallback retirement for in-scope routes - Shared feature-flag helpers (env > config > default) replacing duplicated _to_bool - Defensive copy for lru_cached policy payloads preventing mutation corruption - Unified retired-fallback response helper across app and blueprint routes - Frontend/backend route-contract cross-validation in governance gates - Shell CSS token fallback values for routes rendered outside shell scope - Local-safe .env.example defaults with production recommendation comments - Legacy contract fallback warning logging and single-hop redirect optimization Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
# asset-readiness-and-fallback-retirement Specification
|
||||
|
||||
## Purpose
|
||||
TBD - created by archiving change full-modernization-architecture-blueprint. Update Purpose after archive.
|
||||
## Requirements
|
||||
### Requirement: In-scope frontend assets SHALL be release-ready before deployment
|
||||
In-scope routes SHALL rely on build/deploy readiness guarantees instead of runtime fallback behavior as the primary resilience mechanism.
|
||||
|
||||
#### Scenario: Build-readiness enforcement
|
||||
- **WHEN** release artifacts are prepared for deployment
|
||||
- **THEN** in-scope route assets SHALL be validated for presence and loadability
|
||||
- **THEN** missing required in-scope assets SHALL fail the release gate
|
||||
|
||||
### Requirement: Runtime fallback retirement SHALL follow a governed phase policy
|
||||
Runtime fallback behavior for in-scope modernization routes SHALL be retired under explicit governance milestones.
|
||||
|
||||
#### Scenario: Fallback retirement in phase scope
|
||||
- **WHEN** a route is marked in-scope for fallback retirement
|
||||
- **THEN** runtime fallback behavior for that route SHALL be removed or disabled by policy
|
||||
- **THEN** reliability for that route SHALL be guaranteed by release-time readiness gates
|
||||
|
||||
### Requirement: Deferred routes SHALL keep existing fallback posture in this phase
|
||||
Routes deferred from this modernization phase SHALL retain their existing fallback posture until handled by a follow-up change.
|
||||
|
||||
#### Scenario: Deferred fallback continuity
|
||||
- **WHEN** `/tables`, `/excel-query`, `/query-tool`, or `/mid-section-defect` is evaluated in this phase
|
||||
- **THEN** fallback retirement SHALL NOT be required for phase completion
|
||||
- **THEN** fallback retirement decisions for those routes SHALL be addressed in a follow-up modernization change
|
||||
|
||||
### Requirement: Fallback-retirement failure response SHALL be consistent across route hosts
|
||||
When in-scope runtime fallback retirement is enabled and route assets are unavailable, app-level and blueprint-level route handlers SHALL return a consistent retired-fallback response surface.
|
||||
|
||||
#### Scenario: App-level in-scope route enters retired fallback state
|
||||
- **WHEN** an in-scope app-level route cannot serve required dist assets and fallback retirement is enabled
|
||||
- **THEN** the route SHALL return the standardized retired-fallback response contract
|
||||
|
||||
#### Scenario: Blueprint-level in-scope route enters retired fallback state
|
||||
- **WHEN** an in-scope blueprint-level route cannot serve required dist assets and fallback retirement is enabled
|
||||
- **THEN** the route SHALL return the same standardized retired-fallback response contract used by app-level routes
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# frontend-platform-modernization-governance Specification
|
||||
|
||||
## Purpose
|
||||
TBD - created by archiving change full-modernization-architecture-blueprint. Update Purpose after archive.
|
||||
## Requirements
|
||||
### Requirement: Frontend modernization scope SHALL be explicitly governed
|
||||
The modernization program SHALL define an explicit in-scope and out-of-scope route matrix for each phase, and SHALL treat that matrix as a release-governed contract artifact.
|
||||
|
||||
#### Scenario: Scope matrix publication
|
||||
- **WHEN** a modernization phase is created
|
||||
- **THEN** the phase SHALL publish an explicit in-scope route list and out-of-scope route list
|
||||
- **THEN** the matrix SHALL include `/admin/pages` and `/admin/performance` in scope for this phase
|
||||
- **THEN** the matrix SHALL mark `/tables`, `/excel-query`, `/query-tool`, and `/mid-section-defect` as deferred routes for a follow-up phase
|
||||
|
||||
#### Scenario: Scope drift prevention
|
||||
- **WHEN** implementation tasks are derived from the phase specs
|
||||
- **THEN** tasks targeting routes outside the in-scope matrix SHALL be rejected for this phase
|
||||
|
||||
### Requirement: Modernization phases SHALL define completion and deprecation milestones
|
||||
Each modernization phase SHALL define measurable completion criteria and deprecation milestones for legacy-era patterns.
|
||||
|
||||
#### Scenario: Phase completion criteria
|
||||
- **WHEN** a phase reaches release review
|
||||
- **THEN** it SHALL provide objective completion criteria for route governance, style governance, and quality gates
|
||||
- **THEN** it SHALL identify any remaining deferred routes and their next-phase linkage
|
||||
|
||||
#### Scenario: Legacy deprecation milestones
|
||||
- **WHEN** legacy fallback or legacy style exceptions remain in phase scope
|
||||
- **THEN** the phase SHALL define a dated milestone or release gate to remove those exceptions
|
||||
|
||||
### Requirement: Operator-facing environment defaults SHALL be onboarding-safe
|
||||
`.env.example` SHALL prioritize local onboarding safety while clearly documenting production hardening recommendations for modernization controls.
|
||||
|
||||
#### Scenario: Local bootstrap from `.env.example`
|
||||
- **WHEN** a developer initializes `.env` from `.env.example` in a local non-production environment
|
||||
- **THEN** startup-critical modernization flags SHALL default to onboarding-safe values that do not fail boot solely because dist readiness gates are strict by default
|
||||
|
||||
#### Scenario: Production recommendation visibility
|
||||
- **WHEN** operators review `.env.example` for deployment configuration
|
||||
- **THEN** production-recommended values for shell-first and modernization-hardening flags SHALL be explicitly documented in adjacent comments
|
||||
|
||||
### Requirement: Policy cache refresh model SHALL be explicit in governance docs
|
||||
Governance-owned policy artifacts that are loaded with in-process caching SHALL document runtime refresh behavior and operator expectations.
|
||||
|
||||
#### Scenario: Cached policy artifact behavior documentation
|
||||
- **WHEN** maintainers read modernization governance artifacts
|
||||
- **THEN** they SHALL find explicit guidance on whether policy JSON updates require process restart, cache clear, or automatic reload
|
||||
|
||||
29
openspec/specs/frontend-quality-gate-modernization/spec.md
Normal file
29
openspec/specs/frontend-quality-gate-modernization/spec.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# frontend-quality-gate-modernization Specification
|
||||
|
||||
## Purpose
|
||||
TBD - created by archiving change full-modernization-architecture-blueprint. Update Purpose after archive.
|
||||
## Requirements
|
||||
### Requirement: Modernization releases SHALL pass multi-dimensional frontend quality gates
|
||||
In-scope modernization releases SHALL pass functional, visual, accessibility, and performance gates before promotion.
|
||||
|
||||
#### Scenario: Gate bundle at release candidate
|
||||
- **WHEN** a release candidate includes in-scope modernization changes
|
||||
- **THEN** it SHALL execute functional behavior parity checks for affected routes
|
||||
- **THEN** it SHALL execute critical-state visual regression checks for affected routes
|
||||
- **THEN** it SHALL execute accessibility checks for keyboard and reduced-motion behavior
|
||||
- **THEN** it SHALL execute performance budget checks for defined shell/route thresholds
|
||||
|
||||
### Requirement: Gate failures SHALL block release promotion
|
||||
Blocking quality gates SHALL prevent release promotion for in-scope modernization changes.
|
||||
|
||||
#### Scenario: Blocking gate failure
|
||||
- **WHEN** any mandatory modernization quality gate fails
|
||||
- **THEN** release promotion SHALL be blocked until the failure is resolved or explicitly waived per governance policy
|
||||
|
||||
### Requirement: Deferred routes SHALL be excluded from this phase gate baseline
|
||||
The route baseline for this modernization phase SHALL exclude deferred routes.
|
||||
|
||||
#### Scenario: Deferred route baseline exclusion
|
||||
- **WHEN** gate baseline is computed for this phase
|
||||
- **THEN** `/tables`, `/excel-query`, `/query-tool`, and `/mid-section-defect` SHALL be excluded from mandatory modernization gate coverage
|
||||
|
||||
@@ -2,22 +2,27 @@
|
||||
Define stable requirements for full-vite-page-modularization.
|
||||
## Requirements
|
||||
### Requirement: Major Pages SHALL be Managed by Vite Modules
|
||||
The system SHALL provide Vite-managed module entries for major portal pages under a phased SPA-shell migration while keeping direct route access compatible.
|
||||
The system SHALL provide Vite-managed module entries for all in-scope modernization routes under shell-first governance, including admin surfaces `/admin/pages` and `/admin/performance` as governed targets. Deferred routes (`/tables`, `/excel-query`, `/query-tool`, `/mid-section-defect`) are excluded from this phase's required module-governance completeness.
|
||||
|
||||
#### Scenario: Portal shell module loading
|
||||
- **WHEN** the portal experience is rendered
|
||||
- **THEN** it MUST load its behavior from a Vite-built module asset when available
|
||||
#### Scenario: In-scope module governance completeness
|
||||
- **WHEN** modernization route coverage is validated for this phase
|
||||
- **THEN** every in-scope route SHALL have deterministic module-governance metadata and ownership mapping
|
||||
|
||||
#### Scenario: Module fallback continuity
|
||||
- **WHEN** a required Vite asset is unavailable
|
||||
- **THEN** the system MUST keep affected page behavior functional through explicit fallback logic
|
||||
#### Scenario: Deferred route exclusion in this phase
|
||||
- **WHEN** completeness validation executes for this phase
|
||||
- **THEN** deferred routes SHALL be excluded from mandatory pass criteria
|
||||
|
||||
### Requirement: Build Pipeline SHALL Produce Backend-Served Assets
|
||||
Vite build output MUST be emitted into backend static paths and served by Flask/Gunicorn on the same origin.
|
||||
Vite build output for in-scope modernization routes MUST be emitted into backend static paths and validated at release time. Missing required in-scope assets SHALL fail release gates instead of relying on runtime fallback behavior.
|
||||
|
||||
#### Scenario: Build artifact placement
|
||||
- **WHEN** frontend build is executed
|
||||
- **THEN** generated JS/CSS files SHALL be written to the configured backend static dist directory
|
||||
#### Scenario: Build artifact readiness for in-scope routes
|
||||
- **WHEN** frontend build is executed for release
|
||||
- **THEN** required in-scope route artifacts SHALL be present in configured backend static dist paths
|
||||
- **THEN** missing required artifacts SHALL fail readiness checks
|
||||
|
||||
#### Scenario: Deferred route fallback posture unchanged in this phase
|
||||
- **WHEN** deferred routes are evaluated in this phase
|
||||
- **THEN** existing fallback posture SHALL not block this phase's completion
|
||||
|
||||
### Requirement: Vite Page Modules SHALL Reuse Shared Chart and Query Building Blocks
|
||||
Page entry modules MUST consume shared chart/query/drawer utilities for common behaviors.
|
||||
@@ -83,3 +88,4 @@ WIP overview and WIP detail Vite entry modules SHALL use shared frontend core ut
|
||||
#### Scenario: Shared utility change propagates across both pages
|
||||
- **WHEN** autocomplete mapping rules are updated in the shared core module
|
||||
- **THEN** both WIP overview and WIP detail modules MUST consume the updated behavior without duplicated page-local logic edits
|
||||
|
||||
|
||||
@@ -17,3 +17,21 @@ Cache, throttling, and index-related numeric literals that control behavior MUST
|
||||
- **WHEN** operators need to tune cache/index thresholds
|
||||
- **THEN** they MUST find values in named constants or environment variables rather than scattered inline literals
|
||||
|
||||
### Requirement: Feature-flag resolution SHALL use shared helper semantics
|
||||
Environment/config/default feature-flag resolution logic SHALL be implemented through shared helper utilities instead of duplicated per-module parsing.
|
||||
|
||||
#### Scenario: Feature-flag evaluation in app and policy modules
|
||||
- **WHEN** modules resolve boolean feature flags from environment variables and Flask config
|
||||
- **THEN** they SHALL use a shared helper that enforces consistent precedence and truthy/falsey parsing behavior
|
||||
|
||||
### Requirement: Cached policy payloads SHALL protect against shared mutable-state corruption
|
||||
Policy loader functions that cache JSON payloads in-process SHALL prevent downstream callers from mutating the shared cached object reference.
|
||||
|
||||
#### Scenario: Cached policy payload consumed by multiple callers
|
||||
- **WHEN** multiple callers read cached policy payloads during process lifetime
|
||||
- **THEN** one caller's accidental mutation SHALL NOT alter another caller's observed policy state through shared reference side effects
|
||||
|
||||
#### Scenario: Policy cache behavior documentation
|
||||
- **WHEN** maintainers inspect cached policy loader code
|
||||
- **THEN** they SHALL find explicit comments describing refresh/invalidation behavior expectations
|
||||
|
||||
|
||||
58
openspec/specs/page-content-modernization-safety/spec.md
Normal file
58
openspec/specs/page-content-modernization-safety/spec.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# page-content-modernization-safety Specification
|
||||
|
||||
## Purpose
|
||||
TBD - created by archiving change full-modernization-architecture-blueprint. Update Purpose after archive.
|
||||
## Requirements
|
||||
### Requirement: In-scope page-content modernization SHALL be contract-first
|
||||
Before chart/filter/page interaction refactors are cut over, each in-scope route SHALL define a contract baseline that captures data and interaction semantics.
|
||||
|
||||
#### Scenario: Route contract baseline defined
|
||||
- **WHEN** an in-scope route is selected for chart/filter modernization
|
||||
- **THEN** the route SHALL define filter input semantics, query payload expectations, and chart data-shape contracts
|
||||
- **THEN** the route SHALL define critical state expectations for loading, empty, error, and success interactions
|
||||
|
||||
### Requirement: Cutover SHALL require parity evidence against baseline behavior
|
||||
In-scope chart/filter modernization cutover SHALL require parity evidence against baseline fixtures and critical interaction flows.
|
||||
|
||||
#### Scenario: Parity gate before default switch
|
||||
- **WHEN** a route is proposed for defaulting to a modernized chart/filter implementation
|
||||
- **THEN** golden fixture parity checks SHALL pass for defined critical states
|
||||
- **THEN** interaction parity checks SHALL pass for filter apply/reset and chart selection/drill behaviors
|
||||
|
||||
### Requirement: Route-level content cutover SHALL be reversible
|
||||
Modernized chart/filter content rollouts SHALL use reversible controls that allow immediate rollback without reverting unrelated shell architecture work.
|
||||
|
||||
#### Scenario: Controlled rollout and rollback
|
||||
- **WHEN** a modernized route is enabled for users
|
||||
- **THEN** the route SHALL be controlled by route-scoped feature flag or equivalent switch
|
||||
- **THEN** rollback procedure SHALL be documented and executable within one release cycle
|
||||
|
||||
### Requirement: Page-content modernization progression SHALL require manual route acceptance
|
||||
In-scope chart/filter/page-content migration SHALL progress one route at a time with explicit manual acceptance records.
|
||||
|
||||
#### Scenario: Route-by-route manual acceptance gate
|
||||
- **WHEN** an in-scope route completes modernization implementation and parity checks
|
||||
- **THEN** that route SHALL be manually accepted using a defined checklist covering filter flows, chart interactions, empty/error behavior, and visual correctness
|
||||
- **THEN** the next route SHALL NOT begin cutover until manual acceptance for the current route is signed off
|
||||
|
||||
### Requirement: Known legacy bugs in migrated scope SHALL NOT be carried into modernized routes
|
||||
Modernized route acceptance SHALL include explicit revalidation of known legacy defects in migrated scope, and reproduced defects SHALL block sign-off.
|
||||
|
||||
#### Scenario: Route-level legacy bug baseline and replay
|
||||
- **WHEN** an in-scope route enters chart/filter/page-content modernization
|
||||
- **THEN** a route-level known-bug baseline (within migrated scope) SHALL be recorded before implementation
|
||||
- **THEN** manual acceptance SHALL replay those known-bug checks on the modernized route
|
||||
|
||||
#### Scenario: Legacy bug carry-over is blocked
|
||||
- **WHEN** manual acceptance finds that a known legacy bug is still reproducible in the modernized route
|
||||
- **THEN** route sign-off SHALL fail
|
||||
- **THEN** route cutover completion and legacy code retirement SHALL be blocked until the bug is fixed
|
||||
|
||||
### Requirement: Legacy content path retirement SHALL require parity and manual acceptance
|
||||
Legacy chart/filter implementations SHALL be removed only after parity checks and manual acceptance criteria are satisfied.
|
||||
|
||||
#### Scenario: Legacy removal approval
|
||||
- **WHEN** legacy chart/filter code is planned for removal on an in-scope route
|
||||
- **THEN** the route SHALL provide parity pass evidence and manual acceptance sign-off records
|
||||
- **THEN** unresolved parity failures or manual acceptance defects SHALL block legacy removal
|
||||
|
||||
@@ -2,46 +2,31 @@
|
||||
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, and SHALL route each page through native route-view integration. The shell layout SHALL use a full-viewport fluid layout with flexbox, removing all max-width constraints and block-centered styling. The main content area (`.shell-content`) SHALL fill available space as a flex child, and the sidebar SHALL be a collapsible flex child that pushes content when expanded on desktop. The content area class SHALL be `.shell-content` (not `.content`) to avoid CSS collision with page-level `.content` classes.
|
||||
The portal frontend SHALL use a single SPA shell entry and Vue Router to render in-scope page modules without iframe embedding. In-scope routes for this phase SHALL include the governed report routes and admin surfaces `/admin/pages` and `/admin/performance`, while deferred routes (`/tables`, `/excel-query`, `/query-tool`, `/mid-section-defect`) are explicitly excluded from this phase contract.
|
||||
|
||||
#### 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
|
||||
- **THEN** the content area SHALL fill the available viewport width minus the sidebar width (if sidebar is expanded)
|
||||
#### Scenario: In-scope route renders through shell governance
|
||||
- **WHEN** a user navigates to an in-scope shell-governed route
|
||||
- **THEN** the route SHALL resolve through Vue Router with shell contract metadata
|
||||
- **THEN** the shell SHALL render the corresponding module/target without iframe fallback
|
||||
|
||||
#### Scenario: Shell layout fills full viewport
|
||||
- **WHEN** the portal shell renders
|
||||
- **THEN** the shell SHALL span the full viewport width with no max-width constraint
|
||||
- **THEN** the header SHALL span edge-to-edge with no border-radius
|
||||
- **THEN** the sidebar and content area SHALL have no outer borders or border-radius
|
||||
#### Scenario: Admin route appears as governed target
|
||||
- **WHEN** an admin user opens shell navigation
|
||||
- **THEN** `/admin/pages` and `/admin/performance` SHALL be exposed as governed navigation targets per access policy
|
||||
|
||||
#### Scenario: Page-level max-width constraints are removed when embedded
|
||||
- **WHEN** a page module registered in the shell route contracts renders inside `.shell-content`
|
||||
- **THEN** page-level max-width constraints SHALL be overridden to allow full-width rendering
|
||||
- **THEN** page-level duplicate padding SHALL be removed to avoid double spacing
|
||||
- **THEN** standalone page rendering (outside the shell) SHALL remain unaffected
|
||||
|
||||
#### Scenario: Shell content class avoids collision with page-level classes
|
||||
- **WHEN** a page module that uses its own `.content` class renders inside the shell
|
||||
- **THEN** the shell's content wrapper (`.shell-content`) SHALL NOT interfere with the page's `.content` styling
|
||||
|
||||
#### 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
|
||||
#### Scenario: Deferred route is excluded from this phase route-governance requirement
|
||||
- **WHEN** phase-level shell-governance compliance is evaluated
|
||||
- **THEN** `/tables`, `/excel-query`, `/query-tool`, and `/mid-section-defect` SHALL be treated as deferred and excluded from pass/fail criteria for this phase
|
||||
|
||||
### 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.
|
||||
Migration to the shell-first SPA model SHALL preserve route/query compatibility for in-scope routes while introducing canonical shell routing policy and explicit compatibility handling.
|
||||
|
||||
#### 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: Canonical shell path behavior for in-scope routes
|
||||
- **WHEN** a user opens an in-scope report route via canonical shell path
|
||||
- **THEN** route behavior and query semantics SHALL remain compatible with established baseline behavior
|
||||
|
||||
#### 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
|
||||
#### Scenario: Compatibility policy for direct route entry
|
||||
- **WHEN** a user opens an in-scope report route via direct non-canonical entry
|
||||
- **THEN** the system SHALL apply explicit compatibility policy (preserve behavior or compatibility redirect) without breaking route semantics
|
||||
|
||||
### 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.
|
||||
@@ -60,3 +45,22 @@ SPA navigation SHALL respect backend-defined drawer and page visibility outcomes
|
||||
- **THEN** the shell SHALL redirect to a safe fallback route
|
||||
- **THEN** the shell SHALL NOT expose iframe-based fallback rendering
|
||||
|
||||
### Requirement: Canonical redirect scope boundaries SHALL be explicit and intentional
|
||||
Canonical shell direct-entry redirects SHALL apply only to governed in-scope report routes and SHALL explicitly exclude admin external targets with documented rationale.
|
||||
|
||||
#### Scenario: In-scope report route direct entry
|
||||
- **WHEN** SPA shell mode is enabled and a user enters an in-scope report route directly
|
||||
- **THEN** the system SHALL redirect to the canonical `/portal-shell/...` route while preserving query semantics
|
||||
|
||||
#### Scenario: Admin external target direct entry
|
||||
- **WHEN** SPA shell mode is enabled and a user enters `/admin/pages` or `/admin/performance` directly
|
||||
- **THEN** the system SHALL NOT apply report-route canonical redirect policy
|
||||
- **THEN** the exclusion rationale SHALL be documented in code-level comments or governance docs
|
||||
|
||||
### Requirement: Missing-required-parameter redirects SHALL avoid avoidable multi-hop chains
|
||||
Routes with server-side required query parameters SHALL minimize redirect hops under SPA shell mode.
|
||||
|
||||
#### Scenario: Hold detail missing reason in SPA shell mode
|
||||
- **WHEN** a user opens `/hold-detail` without `reason` while SPA shell mode is enabled
|
||||
- **THEN** the route SHALL resolve via a single-hop redirect to the canonical overview shell path
|
||||
|
||||
|
||||
40
openspec/specs/style-isolation-and-token-enforcement/spec.md
Normal file
40
openspec/specs/style-isolation-and-token-enforcement/spec.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# style-isolation-and-token-enforcement Specification
|
||||
|
||||
## Purpose
|
||||
TBD - created by archiving change full-modernization-architecture-blueprint. Update Purpose after archive.
|
||||
## Requirements
|
||||
### Requirement: In-scope pages SHALL enforce style isolation boundaries
|
||||
In-scope modernization pages SHALL avoid page-global selectors for page-local concerns and SHALL keep style concerns scoped to route-level containers or shared design-system layers.
|
||||
|
||||
#### Scenario: Global selector control
|
||||
- **WHEN** style governance checks analyze in-scope page styles
|
||||
- **THEN** page-local style changes SHALL NOT introduce new `:root` or `body` rules for route-local presentation concerns
|
||||
- **THEN** shared cross-route concerns SHALL be authored in designated shared style layers
|
||||
|
||||
### Requirement: In-scope shared semantics SHALL be token-first
|
||||
Shared UI semantics in in-scope routes SHALL be implemented with token-backed Tailwind/shared-style primitives before page-local overrides are allowed.
|
||||
|
||||
#### Scenario: Token-first UI pattern adoption
|
||||
- **WHEN** an in-scope route introduces or updates shared UI semantics (layout shell, card, filter, action, status)
|
||||
- **THEN** the route SHALL consume token-backed shared primitives
|
||||
- **THEN** page-local hard-coded visual values SHALL require explicit exception justification
|
||||
|
||||
### Requirement: Legacy style exceptions SHALL be tracked and sunset
|
||||
Legacy CSS exceptions for in-scope routes SHALL be tracked with ownership and removal milestones.
|
||||
|
||||
#### Scenario: Exception registry requirement
|
||||
- **WHEN** an in-scope route cannot yet remove legacy style behavior
|
||||
- **THEN** the route SHALL be registered with an exception owner and planned removal milestone
|
||||
- **THEN** unresolved exceptions past milestone SHALL fail modernization governance review
|
||||
|
||||
### Requirement: Route-local token usage SHALL include fallback values outside shell scope
|
||||
Route-level styles that reference shell-provided token variables SHALL define fallback values to preserve rendering correctness when rendered outside shell variable scope.
|
||||
|
||||
#### Scenario: Route rendered outside portal shell variable scope
|
||||
- **WHEN** a route-local stylesheet references shell token variables and the page is rendered without shell-level CSS variables
|
||||
- **THEN** visual-critical properties (for example header gradients) SHALL still resolve through explicit fallback token values
|
||||
|
||||
#### Scenario: Style governance check for unresolved shell variables
|
||||
- **WHEN** style-governance validation inspects in-scope route styles
|
||||
- **THEN** unresolved shell-variable references without fallback SHALL be flagged as governance failures or approved exceptions
|
||||
|
||||
@@ -1,29 +1,28 @@
|
||||
## Purpose
|
||||
Define stable requirements for tailwind-design-system.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: Frontend styles SHALL be governed by Tailwind design tokens
|
||||
The frontend SHALL define a Tailwind-based design token system for color, spacing, typography, radius, and elevation to ensure consistent styling across modules. The `--portal-shell-max-width` CSS variable SHALL be set to `none` to support the fluid layout. A `--portal-sidebar-width` variable SHALL be added for sidebar width reference. The `.u-content-shell` utility class SHALL use `width: 100%` instead of `max-width` constraint.
|
||||
The frontend SHALL enforce a token-governed style system for in-scope routes. Shared visual semantics SHALL be expressed through token-backed Tailwind/shared layers, and ad-hoc page-local hard-coded values for shared semantics SHALL require explicit exception governance.
|
||||
|
||||
#### Scenario: Shared token usage across modules
|
||||
- **WHEN** two report modules render equivalent UI elements (e.g., card, filter chip, primary button)
|
||||
#### Scenario: Shared token usage across in-scope modules
|
||||
- **WHEN** two in-scope modules render equivalent UI semantics (e.g., card, filter chip, primary action, status indicator)
|
||||
- **THEN** they SHALL use the same token-backed style semantics
|
||||
- **THEN** visual output SHALL remain consistent across modules
|
||||
- **THEN** visual output SHALL remain consistent across those modules
|
||||
|
||||
#### Scenario: Fluid layout tokens
|
||||
- **WHEN** the portal shell renders
|
||||
- **THEN** `--portal-shell-max-width` SHALL resolve to `none`
|
||||
- **THEN** `--portal-sidebar-width` SHALL resolve to `240px`
|
||||
- **THEN** `.u-content-shell` SHALL apply `width: 100%` without max-width constraint
|
||||
#### Scenario: Token governance review
|
||||
- **WHEN** an in-scope route introduces new shared UI styling
|
||||
- **THEN** the styling SHALL map to shared tokens/layers or be recorded in an approved exception registry
|
||||
|
||||
### Requirement: Tailwind migration SHALL support coexistence with legacy CSS
|
||||
The migration SHALL allow Tailwind and existing page CSS to coexist during phased rollout without breaking existing pages.
|
||||
Tailwind migration SHALL support controlled coexistence only as a transition state for this phase. In-scope routes SHALL move toward isolation-first style ownership and SHALL NOT introduce new page-global CSS side effects for route-local concerns.
|
||||
|
||||
#### Scenario: Legacy page remains functional during coexistence
|
||||
- **WHEN** a not-yet-migrated page is rendered
|
||||
- **THEN** existing CSS behavior SHALL remain intact
|
||||
- **THEN** Tailwind introduction SHALL NOT cause blocking style regressions
|
||||
#### Scenario: In-scope global selector control
|
||||
- **WHEN** in-scope route styles are reviewed
|
||||
- **THEN** new route-local styling SHALL NOT introduce page-global selectors (`:root`, `body`) for local presentation behavior
|
||||
|
||||
#### Scenario: Deferred route coexistence allowance
|
||||
- **WHEN** deferred routes (`/tables`, `/excel-query`, `/query-tool`, `/mid-section-defect`) are evaluated during this phase
|
||||
- **THEN** existing coexistence posture SHALL be allowed and handled by a follow-up modernization change
|
||||
|
||||
### Requirement: New shared UI components SHALL prefer Tailwind-first styling
|
||||
Newly introduced shared components SHALL be implemented with Tailwind-first conventions to avoid expanding duplicated page-local CSS.
|
||||
@@ -32,3 +31,4 @@ Newly introduced shared components SHALL be implemented with Tailwind-first conv
|
||||
- **WHEN** a new shared component is introduced in migration scope
|
||||
- **THEN** its primary style contract SHALL be expressed through Tailwind utilities/components
|
||||
- **THEN** page-local CSS additions SHALL be minimized and justified
|
||||
|
||||
|
||||
51
openspec/specs/unified-shell-route-coverage/spec.md
Normal file
51
openspec/specs/unified-shell-route-coverage/spec.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# unified-shell-route-coverage Specification
|
||||
|
||||
## Purpose
|
||||
TBD - created by archiving change full-modernization-architecture-blueprint. Update Purpose after archive.
|
||||
## Requirements
|
||||
### Requirement: In-scope routes SHALL be shell-contract governed
|
||||
All in-scope modernization routes SHALL be represented in shell route contracts, loader registration policy, and navigation visibility governance.
|
||||
|
||||
#### Scenario: In-scope coverage validation
|
||||
- **WHEN** shell route contract validation is executed
|
||||
- **THEN** every in-scope route SHALL have route metadata, ownership metadata, and visibility policy metadata
|
||||
- **THEN** missing in-scope route contracts SHALL fail validation
|
||||
|
||||
#### Scenario: Admin route inclusion
|
||||
- **WHEN** shell navigation is built for admin users
|
||||
- **THEN** `/admin/pages` and `/admin/performance` SHALL be represented as governed navigation targets according to visibility/access policy
|
||||
|
||||
### Requirement: Out-of-scope routes SHALL not block this phase
|
||||
Routes explicitly marked as out-of-scope for this modernization phase SHALL be excluded from required shell-coverage gates in this phase.
|
||||
|
||||
#### Scenario: Deferred route exclusion
|
||||
- **WHEN** modernization gates execute for this phase
|
||||
- **THEN** `/tables`, `/excel-query`, `/query-tool`, and `/mid-section-defect` SHALL be treated as deferred routes
|
||||
- **THEN** deferred route absence from new shell-governance gates SHALL NOT fail this phase
|
||||
|
||||
### Requirement: Route coverage governance SHALL be CI-enforced
|
||||
Route coverage and contract completeness checks for in-scope routes SHALL run as CI gates.
|
||||
|
||||
#### Scenario: CI gate failure on in-scope gap
|
||||
- **WHEN** CI detects an in-scope route without required contract metadata
|
||||
- **THEN** the modernization gate SHALL fail
|
||||
- **THEN** release promotion SHALL be blocked until resolved
|
||||
|
||||
### Requirement: Frontend and backend route-contract inventories SHALL be cross-validated
|
||||
Route-governance checks SHALL verify that frontend shell route contracts and backend route contract artifacts describe the same governed route set and scope classes.
|
||||
|
||||
#### Scenario: Cross-source contract parity gate
|
||||
- **WHEN** modernization governance checks run in CI
|
||||
- **THEN** mismatches between backend route contract JSON and frontend `routeContracts.js` route inventory SHALL fail the gate
|
||||
|
||||
#### Scenario: Scope classification drift detection
|
||||
- **WHEN** a route has inconsistent scope classification between frontend and backend contract sources
|
||||
- **THEN** governance checks SHALL report the specific route and conflicting scope values
|
||||
|
||||
### Requirement: Legacy contract-source fallback SHALL emit operational warning
|
||||
When contract loading falls back from the primary modernization contract artifact to a legacy artifact path, the service SHALL emit explicit warning telemetry.
|
||||
|
||||
#### Scenario: Legacy contract fallback path selected
|
||||
- **WHEN** the primary contract artifact is unavailable and a legacy contract file is loaded
|
||||
- **THEN** the system SHALL log a warning that includes the selected legacy source path
|
||||
|
||||
@@ -1,135 +1,139 @@
|
||||
## Purpose
|
||||
Define stable requirements for vue-vite-page-architecture.
|
||||
|
||||
## Requirements
|
||||
|
||||
|
||||
### Requirement: Pure Vite pages SHALL be served as static HTML
|
||||
The system SHALL support serving Vite-built HTML pages directly via Flask without Jinja2 rendering.
|
||||
|
||||
#### Scenario: Serve pure Vite page
|
||||
- **WHEN** user navigates to a pure Vite page route (e.g., `/qc-gate`)
|
||||
- **THEN** Flask SHALL serve the pre-built HTML file from `static/dist/` via `send_from_directory`
|
||||
- **THEN** the HTML SHALL NOT pass through Jinja2 template rendering
|
||||
|
||||
#### Scenario: Page works as top-level navigation target
|
||||
- **WHEN** a pure Vite page is opened from portal direct navigation
|
||||
- **THEN** the page SHALL render correctly as a top-level route without iframe embedding dependency
|
||||
- **THEN** page functionality SHALL NOT rely on portal-managed frame lifecycle
|
||||
|
||||
### Requirement: Vite config SHALL support Vue SFC and HTML entry points
|
||||
The Vite build configuration SHALL support Vue Single File Components alongside existing vanilla JS entries.
|
||||
|
||||
#### Scenario: Vue plugin coexistence
|
||||
- **WHEN** `vite build` is executed
|
||||
- **THEN** Vue SFC (`.vue` files) SHALL be compiled by `@vitejs/plugin-vue`
|
||||
- **THEN** existing vanilla JS entry points SHALL continue to build without modification
|
||||
|
||||
#### Scenario: HTML entry point
|
||||
- **WHEN** a page uses an HTML file as its Vite entry point
|
||||
- **THEN** Vite SHALL process the HTML and its referenced JS/CSS into `static/dist/`
|
||||
- **THEN** the output SHALL include `<page-name>.html`, `<page-name>.js`, and `<page-name>.css`
|
||||
|
||||
#### Scenario: Chunk splitting
|
||||
- **WHEN** Vite builds the project
|
||||
- **THEN** Vue runtime SHALL be split into a `vendor-vue` chunk
|
||||
- **THEN** ECharts modules (including TreemapChart, BarChart, LineChart) SHALL be split into the existing `vendor-echarts` chunk
|
||||
- **THEN** chunk splitting SHALL NOT affect existing page bundles
|
||||
|
||||
#### Scenario: Migrated page entry replacement
|
||||
- **WHEN** a vanilla JS page is migrated to Vue 3
|
||||
- **THEN** its Vite entry SHALL change from JS file to HTML file (e.g., `src/wip-overview/main.js` → `src/wip-overview/index.html`)
|
||||
- **THEN** the original JS entry SHALL be replaced, not kept alongside
|
||||
|
||||
#### Scenario: Hold Overview entry point
|
||||
- **WHEN** the hold-overview page is added
|
||||
- **THEN** `vite.config.js` input SHALL include `'hold-overview': resolve(__dirname, 'src/hold-overview/index.html')`
|
||||
- **THEN** the build SHALL produce `hold-overview.html`, `hold-overview.js`, and `hold-overview.css` in `static/dist/`
|
||||
|
||||
#### Scenario: Hold History entry point
|
||||
- **WHEN** the hold-history page is added
|
||||
- **THEN** `vite.config.js` input SHALL include `'hold-history': resolve(__dirname, 'src/hold-history/index.html')`
|
||||
- **THEN** the build SHALL produce `hold-history.html`, `hold-history.js`, and `hold-history.css` in `static/dist/`
|
||||
|
||||
#### Scenario: Shared CSS import across migrated pages
|
||||
- **WHEN** multiple migrated pages import a shared CSS module (e.g., `wip-shared/styles.css`)
|
||||
- **THEN** Vite SHALL bundle the shared CSS into each page's output CSS
|
||||
- **THEN** shared CSS SHALL NOT create a separate shared chunk that requires additional HTTP requests
|
||||
|
||||
#### Scenario: Shared composable import across module boundaries
|
||||
- **WHEN** a migrated page imports a composable from another shared module (e.g., `hold-history` imports `useAutoRefresh` from `wip-shared/`)
|
||||
- **THEN** the composable SHALL be bundled into the importing page's JS output
|
||||
- **THEN** cross-module imports SHALL NOT create unexpected shared chunks
|
||||
|
||||
### Requirement: Pure Vite pages SHALL handle API calls without legacy MesApi
|
||||
Pure Vite pages SHALL use the existing `frontend/src/core/api.js` module for API communication without depending on the global `window.MesApi` object from `_base.html`.
|
||||
|
||||
#### Scenario: API GET request from pure Vite page
|
||||
- **WHEN** a pure Vite page makes a GET API call
|
||||
- **THEN** the call SHALL use the `apiGet` function from `core/api.js`
|
||||
- **THEN** the call SHALL work without `window.MesApi` being present
|
||||
|
||||
### Requirement: Pure Vite pages SHALL handle POST API calls without legacy MesApi
|
||||
Pure Vite pages SHALL use the `apiPost` function from `core/api.js` for POST requests without depending on `window.MesApi`.
|
||||
|
||||
#### Scenario: API POST request from pure Vite page
|
||||
- **WHEN** a pure Vite page makes a POST API call
|
||||
- **THEN** the call SHALL use the `apiPost` function from `core/api.js`
|
||||
- **THEN** the call SHALL include `Content-Type: application/json` header
|
||||
- **THEN** the call SHALL work without `window.MesApi` being present
|
||||
|
||||
#### Scenario: CSRF token handling in POST requests
|
||||
- **WHEN** a pure Vite page calls `apiPost`
|
||||
- **THEN** `apiPost` SHALL attempt to read CSRF token from `<meta name="csrf-token">`
|
||||
- **THEN** if no meta tag exists, the request SHALL still proceed (non-admin APIs do not enforce CSRF)
|
||||
|
||||
### Requirement: Pure Vite pages with server-side route validation SHALL use send_from_directory with pre-validation
|
||||
Pages that require server-side parameter validation before serving SHALL validate parameters in the Flask route and then serve the static HTML.
|
||||
|
||||
#### Scenario: Hold Detail reason validation
|
||||
- **WHEN** user navigates to `/hold-detail` without a `reason` parameter
|
||||
- **THEN** Flask SHALL redirect to `/wip-overview`
|
||||
- **WHEN** user navigates to `/hold-detail?reason={value}`
|
||||
- **THEN** Flask SHALL serve the pre-built HTML file from `static/dist/` via `send_from_directory`
|
||||
- **THEN** the HTML SHALL NOT pass through Jinja2 template rendering
|
||||
|
||||
#### Scenario: Frontend fallback validation
|
||||
- **WHEN** the pure Vite hold-detail page loads
|
||||
- **THEN** the page SHALL read `reason` from URL parameters
|
||||
- **THEN** if `reason` is empty or missing, the page SHALL redirect to `/wip-overview`
|
||||
|
||||
### Requirement: Mid-section defect page SHALL separate filter state from query state
|
||||
The mid-section defect page SHALL maintain separate reactive state for UI input (`filters`) and committed query parameters (`committedFilters`).
|
||||
|
||||
#### Scenario: User changes date without clicking query
|
||||
- **WHEN** user modifies the date range in the filter bar but does not click "查詢"
|
||||
- **THEN** auto-refresh, pagination, and CSV export SHALL continue using the previously committed filter values
|
||||
- **THEN** the new date range SHALL NOT affect any API calls until "查詢" is clicked
|
||||
|
||||
#### Scenario: User clicks query button
|
||||
- **WHEN** user clicks "查詢"
|
||||
- **THEN** the current `filters` state SHALL be snapshotted into `committedFilters`
|
||||
- **THEN** all subsequent API calls SHALL use the committed values
|
||||
|
||||
#### Scenario: CSV export uses committed filters
|
||||
- **WHEN** user clicks "匯出 CSV" after modifying filters without re-querying
|
||||
- **THEN** the export SHALL use the committed filter values from the last query
|
||||
- **THEN** the export SHALL NOT use the current UI filter values
|
||||
|
||||
### Requirement: Mid-section defect page SHALL cancel in-flight requests on new query
|
||||
The mid-section defect page SHALL use `AbortController` to cancel in-flight API requests when a new query is initiated.
|
||||
|
||||
#### Scenario: New query cancels previous query
|
||||
- **WHEN** user clicks "查詢" while a previous query is still in-flight
|
||||
- **THEN** the previous query's summary and detail requests SHALL be aborted
|
||||
- **THEN** the AbortError SHALL be handled silently (no error banner shown)
|
||||
|
||||
#### Scenario: Page navigation cancels previous detail request
|
||||
- **WHEN** user clicks next page while a previous page request is still in-flight
|
||||
- **THEN** the previous page request SHALL be aborted
|
||||
- **THEN** the new page request SHALL proceed independently
|
||||
|
||||
#### Scenario: Query and pagination use independent abort keys
|
||||
- **WHEN** a query is in-flight and user triggers pagination
|
||||
- **THEN** the query SHALL NOT be cancelled by the pagination request
|
||||
- **THEN** the pagination SHALL use a separate abort key from the query
|
||||
## Purpose
|
||||
Define stable requirements for vue-vite-page-architecture.
|
||||
## Requirements
|
||||
### Requirement: Pure Vite pages SHALL be served as static HTML
|
||||
The system SHALL serve in-scope pure Vite pages through backend static HTML delivery under a shell-first canonical routing policy. Direct-entry compatibility for in-scope routes SHALL be explicit and governed. Admin targets `/admin/pages` and `/admin/performance` SHALL be represented as governed shell navigation targets, while maintaining backend auth/session authority.
|
||||
|
||||
#### Scenario: In-scope canonical shell entry
|
||||
- **WHEN** a user navigates to an in-scope canonical shell route
|
||||
- **THEN** the shell SHALL render the target route via governed route contracts and static asset delivery
|
||||
|
||||
#### Scenario: Direct-entry compatibility policy for in-scope routes
|
||||
- **WHEN** a user opens an in-scope route through direct non-canonical entry
|
||||
- **THEN** the system SHALL apply explicit compatibility behavior without breaking established query semantics
|
||||
|
||||
#### Scenario: Admin targets in shell governance
|
||||
- **WHEN** shell navigation is rendered for an authorized admin user
|
||||
- **THEN** `/admin/pages` and `/admin/performance` SHALL be reachable through governed admin navigation targets
|
||||
|
||||
#### Scenario: Deferred routes excluded from this phase architecture criteria
|
||||
- **WHEN** this phase architecture compliance is evaluated
|
||||
- **THEN** `/tables`, `/excel-query`, `/query-tool`, and `/mid-section-defect` SHALL be excluded and handled in a follow-up change
|
||||
|
||||
### Requirement: Vite config SHALL support Vue SFC and HTML entry points
|
||||
The Vite build configuration SHALL support Vue Single File Components alongside existing vanilla JS entries.
|
||||
|
||||
#### Scenario: Vue plugin coexistence
|
||||
- **WHEN** `vite build` is executed
|
||||
- **THEN** Vue SFC (`.vue` files) SHALL be compiled by `@vitejs/plugin-vue`
|
||||
- **THEN** existing vanilla JS entry points SHALL continue to build without modification
|
||||
|
||||
#### Scenario: HTML entry point
|
||||
- **WHEN** a page uses an HTML file as its Vite entry point
|
||||
- **THEN** Vite SHALL process the HTML and its referenced JS/CSS into `static/dist/`
|
||||
- **THEN** the output SHALL include `<page-name>.html`, `<page-name>.js`, and `<page-name>.css`
|
||||
|
||||
#### Scenario: Chunk splitting
|
||||
- **WHEN** Vite builds the project
|
||||
- **THEN** Vue runtime SHALL be split into a `vendor-vue` chunk
|
||||
- **THEN** ECharts modules (including TreemapChart, BarChart, LineChart) SHALL be split into the existing `vendor-echarts` chunk
|
||||
- **THEN** chunk splitting SHALL NOT affect existing page bundles
|
||||
|
||||
#### Scenario: Migrated page entry replacement
|
||||
- **WHEN** a vanilla JS page is migrated to Vue 3
|
||||
- **THEN** its Vite entry SHALL change from JS file to HTML file (e.g., `src/wip-overview/main.js` → `src/wip-overview/index.html`)
|
||||
- **THEN** the original JS entry SHALL be replaced, not kept alongside
|
||||
|
||||
#### Scenario: Hold Overview entry point
|
||||
- **WHEN** the hold-overview page is added
|
||||
- **THEN** `vite.config.js` input SHALL include `'hold-overview': resolve(__dirname, 'src/hold-overview/index.html')`
|
||||
- **THEN** the build SHALL produce `hold-overview.html`, `hold-overview.js`, and `hold-overview.css` in `static/dist/`
|
||||
|
||||
#### Scenario: Hold History entry point
|
||||
- **WHEN** the hold-history page is added
|
||||
- **THEN** `vite.config.js` input SHALL include `'hold-history': resolve(__dirname, 'src/hold-history/index.html')`
|
||||
- **THEN** the build SHALL produce `hold-history.html`, `hold-history.js`, and `hold-history.css` in `static/dist/`
|
||||
|
||||
#### Scenario: Shared CSS import across migrated pages
|
||||
- **WHEN** multiple migrated pages import a shared CSS module (e.g., `wip-shared/styles.css`)
|
||||
- **THEN** Vite SHALL bundle the shared CSS into each page's output CSS
|
||||
- **THEN** shared CSS SHALL NOT create a separate shared chunk that requires additional HTTP requests
|
||||
|
||||
#### Scenario: Shared composable import across module boundaries
|
||||
- **WHEN** a migrated page imports a composable from another shared module (e.g., `hold-history` imports `useAutoRefresh` from `wip-shared/`)
|
||||
- **THEN** the composable SHALL be bundled into the importing page's JS output
|
||||
- **THEN** cross-module imports SHALL NOT create unexpected shared chunks
|
||||
|
||||
### Requirement: Pure Vite pages SHALL handle API calls without legacy MesApi
|
||||
Pure Vite pages SHALL use the existing `frontend/src/core/api.js` module for API communication without depending on the global `window.MesApi` object from `_base.html`.
|
||||
|
||||
#### Scenario: API GET request from pure Vite page
|
||||
- **WHEN** a pure Vite page makes a GET API call
|
||||
- **THEN** the call SHALL use the `apiGet` function from `core/api.js`
|
||||
- **THEN** the call SHALL work without `window.MesApi` being present
|
||||
|
||||
### Requirement: Pure Vite pages SHALL handle POST API calls without legacy MesApi
|
||||
Pure Vite pages SHALL use the `apiPost` function from `core/api.js` for POST requests without depending on `window.MesApi`.
|
||||
|
||||
#### Scenario: API POST request from pure Vite page
|
||||
- **WHEN** a pure Vite page makes a POST API call
|
||||
- **THEN** the call SHALL use the `apiPost` function from `core/api.js`
|
||||
- **THEN** the call SHALL include `Content-Type: application/json` header
|
||||
- **THEN** the call SHALL work without `window.MesApi` being present
|
||||
|
||||
#### Scenario: CSRF token handling in POST requests
|
||||
- **WHEN** a pure Vite page calls `apiPost`
|
||||
- **THEN** `apiPost` SHALL attempt to read CSRF token from `<meta name="csrf-token">`
|
||||
- **THEN** if no meta tag exists, the request SHALL still proceed (non-admin APIs do not enforce CSRF)
|
||||
|
||||
### Requirement: Pure Vite pages with server-side route validation SHALL use send_from_directory with pre-validation
|
||||
Pages that require server-side parameter validation before serving SHALL validate parameters in the Flask route and then serve the static HTML.
|
||||
|
||||
#### Scenario: Hold Detail reason validation
|
||||
- **WHEN** user navigates to `/hold-detail` without a `reason` parameter
|
||||
- **THEN** Flask SHALL redirect to `/wip-overview`
|
||||
- **WHEN** user navigates to `/hold-detail?reason={value}`
|
||||
- **THEN** Flask SHALL serve the pre-built HTML file from `static/dist/` via `send_from_directory`
|
||||
- **THEN** the HTML SHALL NOT pass through Jinja2 template rendering
|
||||
|
||||
#### Scenario: Frontend fallback validation
|
||||
- **WHEN** the pure Vite hold-detail page loads
|
||||
- **THEN** the page SHALL read `reason` from URL parameters
|
||||
- **THEN** if `reason` is empty or missing, the page SHALL redirect to `/wip-overview`
|
||||
|
||||
### Requirement: Mid-section defect page SHALL separate filter state from query state
|
||||
The mid-section defect page SHALL maintain separate reactive state for UI input (`filters`) and committed query parameters (`committedFilters`).
|
||||
|
||||
#### Scenario: User changes date without clicking query
|
||||
- **WHEN** user modifies the date range in the filter bar but does not click "查詢"
|
||||
- **THEN** auto-refresh, pagination, and CSV export SHALL continue using the previously committed filter values
|
||||
- **THEN** the new date range SHALL NOT affect any API calls until "查詢" is clicked
|
||||
|
||||
#### Scenario: User clicks query button
|
||||
- **WHEN** user clicks "查詢"
|
||||
- **THEN** the current `filters` state SHALL be snapshotted into `committedFilters`
|
||||
- **THEN** all subsequent API calls SHALL use the committed values
|
||||
|
||||
#### Scenario: CSV export uses committed filters
|
||||
- **WHEN** user clicks "匯出 CSV" after modifying filters without re-querying
|
||||
- **THEN** the export SHALL use the committed filter values from the last query
|
||||
- **THEN** the export SHALL NOT use the current UI filter values
|
||||
|
||||
### Requirement: Mid-section defect page SHALL cancel in-flight requests on new query
|
||||
The mid-section defect page SHALL use `AbortController` to cancel in-flight API requests when a new query is initiated.
|
||||
|
||||
#### Scenario: New query cancels previous query
|
||||
- **WHEN** user clicks "查詢" while a previous query is still in-flight
|
||||
- **THEN** the previous query's summary and detail requests SHALL be aborted
|
||||
- **THEN** the AbortError SHALL be handled silently (no error banner shown)
|
||||
|
||||
#### Scenario: Page navigation cancels previous detail request
|
||||
- **WHEN** user clicks next page while a previous page request is still in-flight
|
||||
- **THEN** the previous page request SHALL be aborted
|
||||
- **THEN** the new page request SHALL proceed independently
|
||||
|
||||
#### Scenario: Query and pagination use independent abort keys
|
||||
- **WHEN** a query is in-flight and user triggers pagination
|
||||
- **THEN** the query SHALL NOT be cancelled by the pagination request
|
||||
- **THEN** the pagination SHALL use a separate abort key from the query
|
||||
|
||||
|
||||
Reference in New Issue
Block a user