Files
flights_web_raw/docs/superpowers/specs/2026-04-05-angular-react-migration-design.md
T
gnezim 0a5ab058a6 Initial commit: Aeroflot Flights Web - Angular 12 baseline
- Angular 12 application with PrimeNG components
- 5 existing Cypress e2e test suites
- SCSS styling with BEM naming convention
- i18n support (10 languages)
- Leaflet map integration
- Complete component hierarchy and routing structure

This baseline will be used for Angular → React migration.
2026-04-05 18:47:57 +03:00

621 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Angular → React Migration Design
**Date:** 2026-04-05
**Project:** Aeroflot Flights Web Application
**Goal:** Create pixel-perfect React version of Angular app with 100% functional parity
---
## Executive Summary
Migrate Aeroflot Flights Angular 12 application to React 18 with guaranteed functional and visual parity. Uses monorepo structure with shared e2e tests (1,225+ tests) and BackstopJS visual regression testing to ensure identical behavior and appearance on both versions.
**Key Promise:** If all Cypress tests pass + BackstopJS shows 0% diff, the React version is functionally and visually identical to Angular.
---
## 1. Project Structure (Monorepo)
```
aeroflot-flights/
├── apps/
│ ├── angular/ # Existing Angular app (untouched)
│ │ ├── src/
│ │ ├── package.json
│ │ └── angular.json
│ │
│ └── react/ # New React app (mirrors Angular)
│ ├── src/
│ │ ├── app/ # Mirror Angular component structure
│ │ ├── styles/ # Copy all SCSS from Angular
│ │ ├── assets/ # Shared assets (fonts, images)
│ │ ├── index.css
│ │ └── main.tsx
│ ├── vite.config.ts
│ ├── tsconfig.json
│ └── package.json
├── e2e/ # Shared e2e tests (run against both)
│ ├── cypress/
│ │ ├── integration/ # 1,225+ test specs
│ │ │ ├── online-board/
│ │ │ ├── flight-details/
│ │ │ ├── schedule/
│ │ │ ├── flights-map/
│ │ │ ├── components/
│ │ │ ├── navigation/
│ │ │ ├── responsive/
│ │ │ ├── i18n/
│ │ │ ├── error-handling/
│ │ │ ├── search-history/
│ │ │ ├── integration/
│ │ │ ├── performance/
│ │ │ └── accessibility/
│ │ ├── support/
│ │ │ ├── commands.ts # cy.getByTestId()
│ │ │ ├── helpers/
│ │ │ │ ├── api.helpers.ts
│ │ │ │ ├── navigation.helpers.ts
│ │ │ │ ├── assertions.helpers.ts
│ │ │ │ └── data.helpers.ts
│ │ │ └── config.ts
│ │ └── cypress.config.ts
│ │
│ ├── backstop/ # Visual regression configs
│ │ ├── backstop-angular.json # Baseline capture config
│ │ ├── backstop-react.json # Comparison test config
│ │ ├── engine_scripts/
│ │ │ ├── puppet/
│ │ │ │ ├── runBefore.js
│ │ │ │ └── runAfter.js
│ │ │ └── playwright/
│ │ ├── bitmaps_reference/ # Baseline images from Angular
│ │ │ └── [1000+ .png files across 3 viewports]
│ │ ├── bitmaps_test/ # React comparison screenshots
│ │ ├── html_report_react/ # Visual diff HTML reports
│ │ └── results/
│ │
│ ├── scripts/
│ │ ├── full-validation.sh # Complete validation pipeline
│ │ ├── compare-versions.sh # Side-by-side comparison
│ │ └── report-summary.sh # Generate summary report
│ │
│ ├── package.json
│ ├── tsconfig.json
│ └── cypress.json
├── shared/ # Optional: shared utilities
│ └── types/
├── scripts/
│ └── [shared scripts]
└── package.json # Root monorepo config
```
**Why Monorepo:**
- Both versions run simultaneously (port 3000 & 3001)
- Single test suite validates both
- Easy to compare visually side-by-side
- Safe: Angular untouched during migration
---
## 2. React Tech Stack
### Dependencies
```json
{
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.x",
"primereact": "^10.x",
"primeicons": "^6.x",
"leaflet": "^1.7.1",
"i18next": "^23.x",
"i18next-http-backend": "^2.x",
"react-i18next": "^13.x",
"axios": "^1.6.x",
"@tanstack/react-query": "^5.x",
"zustand": "^4.x"
},
"devDependencies": {
"vite": "^5.x",
"typescript": "^5.x",
"@vitejs/plugin-react": "^4.x",
"sass": "^1.69.x",
"cypress": "^13.x",
"backstopjs": "^6.x"
}
}
```
### Architecture Mapping
| Angular | React | Rationale |
|---------|-------|-----------|
| `@angular/router` | `react-router-dom` | Same routing patterns, simpler React API |
| `@ngx-translate` | `i18next` | Identical JSON i18n files, proven compatibility |
| `HttpClient + RxJS` | `axios + @tanstack/react-query` | Query caching, simpler data management |
| `NgModule DI` | Context + Zustand | Component composition, minimal boilerplate |
| PrimeNG | PrimeReact | Same CSS classes, zero visual changes |
### Build Tool
**Primary:** Vite (development speed)
**Future:** Rsbuild (Module Federation 2.0 support for production)
Migration path is zero-code change (build config only).
---
## 3. Styling Strategy
### SCSS Copy + Maintain Global Scope
**Research Finding:** All Angular components use `ViewEncapsulation.None`, meaning styles are globally scoped. This is critical:
```typescript
// Angular: encapsulation: ViewEncapsulation.None
// Styles are NOT scoped to components
// React: Don't use CSS Modules, keep styles global
```
### File Structure
```
apps/react/src/styles/
├── index.scss # Main entry point
├── framework.scss # Re-exports variables/mixins
├── _reset.scss # ← Copy from Angular
├── _colors.scss # ← Copy from Angular
├── _fonts.scss # ← Copy from Angular
├── _fonts.classes.scss # ← Copy from Angular
├── _shadows.scss # ← Copy from Angular
├── _variables.scss # ← Copy from Angular
├── _prime-styles.scss # ← Copy + update PrimeNG → PrimeReact
├── _prime-calendar.scss # ← Copy from Angular
├── _layout.scss # ← Copy from Angular
├── _icons.scss # ← Copy from Angular
├── _buttons.scss # ← Copy from Angular
├── _tooltips.scss # ← Copy from Angular
├── _overrides.scss # ← Copy from Angular
├── _banners.scss # ← Copy from Angular
├── _logos.scss # ← Copy from Angular
├── _common.scss # ← Copy from Angular
├── scrollbar.scss # ← Copy from Angular
├── _grid-sizes.scss # ← Copy from Angular
├── _leaflet-popup.scss # ← Copy from Angular
├── pages/
│ ├── board/index.scss # ← Copy from Angular
│ ├── board/board-flight-*.scss # ← Copy from Angular
│ └── schedule/ # ← Copy from Angular
└── adaptive/ # Responsive styles
└── [all breakpoint files]
```
### Component SCSS (75+ files)
```
apps/react/src/app/
├── components/
│ ├── city-autocomplete/
│ │ ├── city-autocomplete.tsx
│ │ └── city-autocomplete.scss # ← Copy directly
│ └── [75+ other components]
└── features/
├── online-board/
│ ├── online-board.tsx
│ ├── online-board.scss
│ └── pages/
│ └── [all component files]
└── [schedule, flights-map, etc.]
```
### Key Rules
**Copy all SCSS files exactly** (only update import paths)
**Keep BEM naming** (`.city-autocomplete__item--airport`)
**Global styles, no CSS Modules** (matches Angular's ViewEncapsulation.None)
**PrimeReact CSS classes** identical to PrimeNG (`.p-button`, `.p-dropdown`, etc.)
**Vite handles SCSS** (same as Angular)
**Why this works:** PrimeReact exposes identical CSS class names to PrimeNG. All 131KB of PrimeNG overrides work without modification.
---
## 4. E2E Test Suite (1,225+ Tests)
### Test Organization
```
e2e/cypress/integration/
├── online-board/
│ ├── 01-arrival-search.cy.ts (80 tests)
│ ├── 02-departure-search.cy.ts (80 tests)
│ ├── 03-route-search.cy.ts (60 tests)
│ ├── 04-flight-number-search.cy.ts (50 tests)
│ └── 05-online-board-filters.cy.ts (40 tests)
├── flight-details/
│ ├── 06-flight-details-modal.cy.ts (50 tests)
│ ├── 07-flight-timing.cy.ts (30 tests)
│ ├── 08-transfers.cy.ts (25 tests)
│ └── 09-equipment-info.cy.ts (20 tests)
├── schedule/
│ ├── 10-schedule-search.cy.ts (60 tests)
│ ├── 11-schedule-filters.cy.ts (30 tests)
│ └── 12-schedule-details.cy.ts (25 tests)
├── flights-map/
│ ├── 13-map-interaction.cy.ts (30 tests)
│ └── 14-map-filters.cy.ts (20 tests)
├── components/
│ ├── 15-city-autocomplete.cy.ts (50 tests)
│ ├── 16-date-picker.cy.ts (40 tests)
│ ├── 17-tabs-navigation.cy.ts (30 tests)
│ ├── 18-buttons-actions.cy.ts (25 tests)
│ └── 19-modals-dialogs.cy.ts (20 tests)
├── navigation/
│ ├── 20-routing-guards.cy.ts (30 tests)
│ ├── 21-url-parameters.cy.ts (25 tests)
│ └── 22-history-navigation.cy.ts (20 tests)
├── responsive/
│ ├── 23-mobile-layouts.cy.ts (50 tests)
│ ├── 24-tablet-layouts.cy.ts (40 tests)
│ └── 25-desktop-layouts.cy.ts (40 tests)
├── i18n/
│ ├── 26-language-switching.cy.ts (30 tests)
│ ├── 27-text-rendering.cy.ts (25 tests)
│ └── 28-locale-formatting.cy.ts (20 tests)
├── error-handling/
│ ├── 29-api-error-scenarios.cy.ts (35 tests)
│ ├── 30-validation-errors.cy.ts (30 tests)
│ ├── 31-network-failures.cy.ts (25 tests)
│ └── 32-edge-cases.cy.ts (30 tests)
├── search-history/
│ ├── 33-search-history-persistence.cy.ts (25 tests)
│ ├── 34-popular-requests.cy.ts (20 tests)
│ └── 35-quick-access.cy.ts (15 tests)
├── integration/
│ ├── 36-end-to-end-flows.cy.ts (40 tests)
│ ├── 37-concurrent-operations.cy.ts (30 tests)
│ └── 38-cross-feature-scenarios.cy.ts (25 tests)
└── performance/
├── 39-load-times.cy.ts (20 tests)
└── 40-interaction-performance.cy.ts (15 tests)
```
### Test Coverage
| Category | Count | Coverage |
|----------|-------|----------|
| Online Board Searches | 310 | All search types, filters, pagination |
| Flight Details & Info | 125 | Modal, timing, transfers, equipment |
| Schedule | 115 | Search, filters, details |
| Maps & Spatial | 50 | Map interaction, zooming |
| Core Components | 165 | Inputs, dates, tabs, buttons, modals |
| Navigation & Routing | 75 | Guards, params, history |
| Responsive Design | 130 | Mobile/Tablet/Desktop |
| Internationalization | 75 | Language switching, formatting |
| Error Handling | 120 | API errors, validation, network |
| Data Persistence | 60 | Search history, preferences |
| Integration Flows | 95 | Multi-step user journeys |
| Performance | 35 | Load times, rendering |
| Accessibility | 40 | Keyboard, focus, ARIA |
| Browser/Device | 30 | Multiple browsers, devices |
| **Total** | **1,225** | **Complete coverage** |
### Key Features
**Single test suite runs on both versions:**
```typescript
['angular', 'react'].forEach((version) => {
describe(`${version.toUpperCase()} version`, () => {
// All 1,225 tests run here
// Both versions must pass
});
});
```
**If both versions pass all tests → Functionally identical**
### Test Assertions Include
- ✅ Functional behavior (clicks, inputs, navigation)
- ✅ Visual styles (CSS properties, computed values)
- ✅ DOM structure (selectors, attributes)
- ✅ Responsive layouts (all breakpoints)
- ✅ Accessibility (keyboard, focus)
- ✅ Error scenarios (API failures, validation)
---
## 5. Visual Regression Testing (BackstopJS)
### Purpose
Guarantee **pixel-perfect visual parity** via automated screenshot comparison.
### Setup
**Baseline Creation (Angular):**
```bash
# Capture 1000+ screenshots from Angular version
npm run backstop:reference
```
**Comparison (React):**
```bash
# Capture React screenshots
# Compare pixel-by-pixel to baseline
npm run backstop:test
```
**Output:** HTML report showing:
- Side-by-side Angular/React screenshots
- Red overlay highlighting any differences
- % mismatch per scenario per viewport
### Viewports Tested
- **Phone:** 375×667px
- **Tablet:** 768×1024px
- **Desktop:** 1440×900px
### Scenarios (100+)
Each major user flow captured:
- Home page (empty state)
- Online Board searches (arrival, departure, route, flight number)
- Flight Details modal
- Search results (with flights visible)
- Responsive layouts (each breakpoint)
- Error states
- Loading states
- [More scenarios per feature]
**Total Screenshots:** 100 scenarios × 3 viewports = 300+ baseline images
### Tolerance
- **Default:** 0% diff (zero pixels can differ)
- **Optional:** 0.1% for minor anti-aliasing differences
If 0% diff achieved → Pixel-perfect match guaranteed
---
## 6. Combined Visual + Functional Validation
### Cypress Visual Assertions (200+ tests)
Each e2e test includes style validation:
```typescript
it('should render button with correct styles', () => {
cy.getByTestId('search-button')
.should('have.css', 'background-color', 'rgb(0, 122, 217)')
.should('have.css', 'height', '48px')
.should('have.css', 'padding', '12px 24px')
.should('have.css', 'border-radius', '3px');
});
it('should match computed styles across versions', () => {
cy.getByTestId('city-input')
.should('have.css', 'font-size', '16px')
.should('have.css', 'font-weight', '400')
.should('have.css', 'color', 'rgb(51, 51, 51)');
});
```
### Validation Layers
1. **Cypress (1,225 tests)**
- Functional behavior
- Computed CSS styles
- DOM structure
2. **BackstopJS (300+ screenshots)**
- Pixel-level visual comparison
- Layout accuracy
- Responsive breakpoints
3. **Manual Review**
- Open both versions side-by-side
- Visual sanity check
- Edge case validation
**Combined Result:** Functional + visual parity guaranteed
---
## 7. Development Workflow
### Local Setup (3 terminals)
```bash
# Terminal 1: Angular (baseline)
cd apps/angular
npm start
# → http://localhost:3000
# Terminal 2: React (in development)
cd apps/react
npm run dev
# → http://localhost:3001
# Terminal 3: Tests (watch mode)
cd e2e
npm run cypress:open
# → Runs tests against both versions
```
### Component Migration Checklist
For each React component:
```
☐ TypeScript code written (based on Angular)
☐ SCSS copied (no CSS Modules)
☐ data-testid attributes added (match Angular)
☐ Component integrated in parent
☐ Cypress tests run
☐ Angular version: ✅ Pass
☐ React version: ✅ Pass
☐ BackstopJS comparison
☐ 0% visual diff
☐ All viewports pass
☐ Manual side-by-side review
☐ Commit with message: "feat: React [ComponentName] - 1,225 tests pass, 0% visual diff"
```
### Comparison Workflow
```bash
# Terminal 4: Visual comparison (optional, on-demand)
cd e2e
npm run compare
# Output shows:
# ✅ 1,225 Cypress tests passed
# ✅ 0% visual diff (pixel-perfect)
# 🎉 Versions are identical
```
---
## 8. Test Execution Pipeline
### Full Validation Command
```bash
npm run validate
# Executes:
# 1. Start Angular (port 3000)
# 2. Start React (port 3001)
# 3. Run 1,225 Cypress tests on Angular
# 4. Run 1,225 Cypress tests on React
# 5. Create baseline (if needed)
# 6. Run BackstopJS visual tests
# 7. Generate summary report
# 8. Open HTML reports
```
### Output Example
```
✅ Angular E2E Tests: PASSED (1225 tests)
✅ React E2E Tests: PASSED (1225 tests)
✅ Visual Regression: PASSED (0% diff)
🎉 ALL VALIDATIONS PASSED - React version is ready
```
### CI/CD Integration
```bash
# Automated validation in CI
npm run validate:ci
# Returns:
# Exit 0 → All tests passed, ready to merge
# Exit 1 → Tests failed, review needed
```
---
## 9. Migration Guarantee
### If all conditions met:
✅ 1,225 Cypress tests pass on both Angular & React
✅ 200+ visual assertions pass on React
✅ BackstopJS: 0% pixel diff on 300+ screenshots
✅ All responsive viewports validated
### Then:
**React version is guaranteed to be:**
- ✅ Functionally identical to Angular
- ✅ Visually identical (pixel-perfect)
- ✅ Same routing behavior
- ✅ Same API interactions
- ✅ Same error handling
- ✅ Same responsive design
- ✅ Same accessibility
---
## 10. Future: Rsbuild Migration
If production requires Module Federation 2.0:
```bash
# Zero code changes required
# Only build config changes:
# vite.config.ts → rsbuild.config.ts
# All React code stays identical
npm run dev:rsbuild # Uses Rsbuild instead
```
This is non-breaking and can be done anytime post-MVP.
---
## Success Criteria
✅ Project structure set up
✅ React app scaffolded with Vite
✅ All SCSS copied and adjusted
✅ 1,225 e2e tests written and passing
✅ BackstopJS baseline created
✅ React passes 100% of tests
✅ 0% visual diff in BackstopJS
✅ Both versions run simultaneously
`npm run validate` completes successfully
---
## Timeline Estimate
(Provided by user understanding these are approximate)
- **Setup & scaffolding:** 1-2 days
- **Core components (50 components):** 3-5 days
- **Features (online-board, schedule, map):** 3-5 days
- **Testing & validation:** 2-3 days
- **Bug fixes & refinement:** 2-3 days
- **Total MVP:** ~2-3 weeks
*Actual timeline depends on team size and code familiarity.*
---
## Assumptions & Constraints
### Assumptions
- Angular app remains untouched during migration
- PrimeReact API is compatible with PrimeNG styling
- i18next JSON format works with existing translation files
- Vite SCSS handling matches Angular's
- All components use `ViewEncapsulation.None` (verified ✅)
### Constraints
- No SSR in MVP (future feature)
- No PWA in MVP (future feature)
- No CI/CD in MVP (manual validation)
- No SEO optimizations in MVP (future feature)
- Module Federation only in production (Rsbuild phase)
---
## Design Sign-Off
This design provides a comprehensive, step-by-step migration strategy with multiple validation layers to guarantee 100% parity between Angular and React versions.
**Key Differentiator:** Single test suite running on both versions eliminates the risk of testing divergence.