Files
flights_web/docs/superpowers/phase-1

Phase 1 — Foundation

Phase 1 builds the complete Modern.js + Module Federation 2.0 foundation for the Aeroflot Flights Web rewrite. Nothing in Phase 1 ships to production users — the output is a working dual-build artifact (standalone SSR + MF 2.0 remote) with all observability, security, and CI pipelines live.

What Phase 1 shipped

Phase 1 consists of 14 sub-plans, each with its own implementation plan under docs/superpowers/plans/:

ID Sub-plan Description
1A-1 Project skeleton src/ tree, tsconfig, eslint base, zod-validated env config, package.json
1A-2 MF 2.0 + dual builds Module Federation 2.0 config, standalone + remote build targets, RemoteLoader, MF spike
1A-3 ESLint boundaries Layered dependency rules enforcing shared/ -> features/ -> routes/ direction
1B CI pipeline GitHub Actions workflow: typecheck, lint, test, coverage, build, MF manifest validation, security audit
1C i18n runtime i18next + ICU MessageFormat, 9 locales, locale resolver, serializer
1D API client Fetch-based client with retry, circuit breaker, LRU cache, zod validation
1E SignalR wrapper Reconnecting SignalR connection with useLiveFlights hook for real-time board updates
1F-layout Root layout Root + locale layouts, error routes, smoke route, ErrorBoundary, HTTP error mapper
1F-seo SEO primitives SeoHead component, hreflang builder, JsonLdRenderer for structured data
1G-logger Logger Structured JSON-lines transport + console transport, logger provider
1G-metrics Metrics OpenTelemetry init (server MeterProvider + TracerProvider), custom metric instruments
1G-analytics Analytics Analytics facade with four stub adapters (Yandex.Metrica, CTM, Variocube, Dynatrace)
1H Security CSP with per-request nonce, stream-transform nonce injection, HTTP security headers, secure storage
1I Deploy pipeline Dockerfile pair, health endpoint, graceful shutdown, deploy workflow, runbook

Running locally

Prerequisites

  • Node.js 24.2.0+ (see .nvmrc)
  • pnpm 9+

Commands

# Install dependencies
pnpm install

# Start dev server (standalone SSR mode)
pnpm dev

# Build both targets
pnpm build:both

# Run tests
pnpm test

# Run tests with coverage
pnpm test:coverage

# Lint
pnpm lint

# Typecheck
pnpm typecheck

# Check bundle size
pnpm bundle-size

Build targets

  • Standalone (pnpm build:standalone): Full SSR app with its own server, routes, and HTML shell. Output in dist/standalone/.
  • Remote (pnpm build:remote): MF 2.0 remote component exposing OnlineBoard, Schedule, FlightsMap, PopularRequests. Output in dist/remote/, serves mf-manifest.json at root.

Environment variables

All env vars are validated at startup via zod (see src/env/index.ts). Required variables for local dev are set to defaults. For full configuration, see the env schema.

Key variables:

  • BUILD_TARGETstandalone or remote (set by build scripts)
  • OTEL_EXPORTER_OTLP_ENDPOINT — OpenTelemetry collector endpoint (optional for dev)
  • LOG_LEVELdebug, info, warn, error (default: info)

Debugging common failures

SSR fallback

Symptom: Page renders as empty white screen, then client-side hydration kicks in late.

Cause: An error during SSR caused React to fall back to client-only rendering.

Debug:

  1. Check server logs for SSR errors — they appear as structured JSON lines with "level":"error".
  2. Common culprits: accessing window/document during SSR, missing env vars, API calls outside useEffect.
  3. The ErrorBoundary catches render errors and shows a fallback UI. Check the error boundary's componentDidCatch output in logs.

Missing env vars

Symptom: App crashes at startup with a zod validation error.

Debug:

  1. Read the error message — it lists exactly which env vars failed validation.
  2. Check src/env/index.ts for the full schema and defaults.
  3. For local dev, most vars have sensible defaults. For deployed environments, ensure all required vars are set in the deployment config.

ESLint boundary violations

Symptom: pnpm lint fails with boundaries/element-types or boundaries/entry-point errors.

Debug:

  1. The boundary rules enforce a strict layering: shared/ and observability/ cannot import from features/ or routes/. features/ cannot import from routes/ or mf/. ui/ cannot import from features/.
  2. If you need shared logic, move it to shared/. If you need a feature-specific component, keep it in features/<name>/components/.
  3. Run pnpm lint with --debug for detailed rule information.
  4. See eslint.config.js for the full boundary configuration.

Test flakes

Symptom: Tests pass locally but fail intermittently in CI.

Known flaky patterns:

  1. Timer-based tests (SignalR reconnection, circuit breaker): These use vi.useFakeTimers(). Ensure vi.advanceTimersByTime() is called with exact intervals, not approximate.
  2. ESLint integration tests (tests/eslint/): These spawn real ESLint processes and can be slow (~20s each). They are not flaky but may time out on constrained CI runners. The CI timeout is 20 minutes to accommodate this.
  3. OpenTelemetry tests: The otel.test.ts suite registers global providers. Each test must clean up after itself to avoid state leakage.

General tips:

  • Run pnpm test -- --reporter=verbose to see timing for each test.
  • Use pnpm test -- --bail 1 to stop on first failure for faster feedback.