# AGENTS.md — Aeroflot.Flights.Web ## Quick Start ```bash # Install dependencies pnpm install # Development servers pnpm dev # Modern.js on :8081 pnpm dev:full # Proxy on :8080 (API forwarding via curl to bypass WAF) # Build targets pnpm build:standalone # SSR server at dist/standalone/ pnpm build:remote # MF remote at dist/remote/ (with mf-manifest.json) pnpm build:both # Both targets # Quality checks (run in order) pnpm typecheck pnpm lint pnpm test pnpm test:coverage pnpm bundle-size # CI gate: total gzip ≤ 2000 kB pnpm check-coverage # CI gate: line coverage ≥ 65% # E2E tests pnpm test:e2e # React app (port 8080) pnpm test:e2e:angular # Angular app (port 4203) ``` ## Architecture **Stack:** Modern.js 2.70.8 (Rspack), React 18.2, Module Federation 2.3.3 **Source structure:** - `src/routes/` — File-based routing (React Router v7) - `src/features/` — Feature modules (online-board, schedule, flights-map, popular-requests) - `src/ui/` — Reusable UI primitives (never import routes/mf from here) - `src/shared/` — Cross-cutting concerns (API client, SignalR, storage, hooks) - `src/observability/` — Logger, metrics (OTel), analytics - `src/i18n/` — Internationalization (9 languages) **Entry points:** - `src/routes/page.tsx` — Root redirect to `/{lang}/onlineboard` - `src/routes/layout.tsx` — Root layout with global providers - `src/routes/[lang]/layout.tsx` — Locale-scoped layout with i18n **Module Federation:** - Remote name: `aeroflot_flights` - Exposes: `./OnlineBoard`, `./Schedule`, `./FlightsMap`, `./PopularRequests` - mf-manifest.json at `https:///mf-manifest.json` ## Critical Constraints 1. **Side-effect-free components** — No `fetch` outside `useEffect`. API calls via `ApiClient` from context. 2. **Dynamic imports** — Use `React.lazy()` for code splitting. Wrap browser-only components (Leaflet) in `ClientOnly`. 3. **SSR safety** — SignalR (`@microsoft/signalr`) is dynamically imported. Never import in SSR bundle (routes/, server/). 4. **Layered architecture** — Enforced by ESLint: - `features/` → cannot import `routes/` or `mf/` - `ui/` → cannot import `features/`, `routes/`, `mf/` - `shared/` → cannot import `features/`, `routes/`, `mf/`, `observability/` - `observability/` → cannot import `features/`, `routes/`, `mf/` 5. **Restricted imports** (ESLint rules): - OTel SDK → use `@/observability/metrics/otel` (getMeter/getTracer) - react-i18next → use `@/i18n/provider` - localStorage/sessionStorage → use `@/shared/storage` 6. **Environment variables** — Read via `getEnv()` from `@/env/index.ts`. SSR injects `window.__ENV__`. ## Dev Server Details - **Port 8081** — Modern.js dev server (SSR + HMR) - **Port 8080** — `pnpm dev:full` proxy with: - `/api/*` and `/flights/*` → `https://flights.test.aeroflot.ru` (via curl to bypass WAF) - `/*` → Modern.js on 8081 ## Testing - **Unit tests** — Vitest (globals enabled, V8 coverage) - **E2E tests** — Playwright (baseURL: `http://localhost:8080`) - **Angular E2E** — Separate config for legacy app (port 4203) **Coverage gates:** - Line coverage ≥ 65% - Bundle size (gzip) ≤ 2000 kB for remote target ## Build Artifacts - `dist/standalone/` — SSR server (Node entrypoint) - `dist/remote/` — MF remote with `mf-manifest.json` - `dist/remote/static/js/` — JS bundles for bundle-size gate ## Deployment - **Standalone** — Dockerfile.react (Node 24-slim, serves SSR) - **Remote** — Dockerfile.remote (nginx serving static files) - CI/CD: `.github/workflows/ci.yml`, `.github/workflows/deploy.yml` ## Known Constraints - Modern.js 3.x blocked by `@module-federation/modern-js` ESM incompatibilities - React Router v7 future flags enabled to suppress deprecation warnings - Legacy Angular 12 SPA in `ClientApp/` (read-only reference) ## Commit Rules - No `Co-Authored-By` lines - English commit messages, focus on "why" not "what" - Commit autonomously when stable; ask before pushing/force-pushing