diff --git a/AGENTS.md b/AGENTS.md index 5cb3f6fa..ce355e4c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,182 +1,123 @@ -# AGENTS.md — Aeroflot.Flights.Web +# AGENTS.md - Aeroflot.Flights.Web -## Quick Start +## Read First + +React 18 SSR app on Modern.js 2.70.8 with Rspack and Module Federation 2.3.3. It is deployed both as a standalone SSR app and as a remote frontend component for customer Web/PWA hosts. + +Work in `src/`. Treat `ClientApp/` as legacy Angular 12 reference only unless the user explicitly asks otherwise. + +Prefer small, local changes that match the existing architecture. Do not widen dependencies across layers, and do not introduce browser-only imports into SSR paths. + +## Commands ```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) +pnpm dev:full # Proxy on :8080; forwards API via curl -# 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% +pnpm bundle-size # remote gzip budget: <= 2000 kB +pnpm check-coverage # line coverage gate: >= 65% -# E2E tests -pnpm test:e2e # React app (port 8080) -pnpm test:e2e:angular # Angular app (port 4203) +pnpm build:standalone # dist/standalone/ +pnpm build:remote # dist/remote/ with mf-manifest.json +pnpm build:both + +pnpm test:e2e # React app, baseURL http://localhost:8080 +pnpm test:e2e:angular # Legacy Angular app, port 4203 ``` -## Current State +## Critical Rules -React 18 SSR application built with **Modern.js 2.70.8** (Rspack bundler) and **Module Federation 2.3.3**. The app is a remote frontend component embeddable in the customer's channel apps (Web, PWA). - -**Stack:** Modern.js 2.70.8, React 18.2, Rspack, Module Federation 2.3.3, i18next (9 languages), PrimeReact, Leaflet, SignalR, OpenTelemetry, Vitest, Playwright. - -**Source:** `src/` (file-based routing under `src/routes/`). Legacy Angular 12 SPA in `ClientApp/` (read-only reference, not deployed). - -**Builds:** `pnpm build:standalone` (SSR server at `dist/standalone/`), `pnpm build:remote` (MF remote at `dist/remote/` with `mf-manifest.json`). - -**Dev:** `pnpm dev` (Modern.js on :8081), `pnpm dev:full` (proxy on :8080 with API forwarding via curl to bypass WAF). - -**Known constraint:** Modern.js 3.x upgrade is blocked by `@module-federation/modern-js` ESM incompatibilities (broken `__filename`/`require` in ESM bundles, missing `api.modifyWebpackConfig` in Rsbuild 2.0). React Router v7 future flags are enabled to suppress deprecation warnings. - -## Contractual Requirements - -The following are contractual hard constraints for the remote frontend component. - -### 1. Tech Stack - -- **ModernJS (SSR)** for the frontend framework. -- **Module Federation 2.0**. Any bundler with MF 2.0 support is acceptable: Webpack 5, Rsbuild, Rspack, or Vite. -- Must emit `mf-manifest.json` at `https:///mf-manifest.json` exposing components and logic. Reference: https://module-federation.io/guide/basic/webpack.html. -- **React 18+**, Concurrent Mode compatible. -- `` support required when async loading is used. -- Component bodies must be side-effect free — **no `fetch` outside `useEffect`**. -- Dynamic imports must use `React.lazy()`. - -### 2. Data & Integrations - -- Consumes customer REST APIs, JSON payloads only. -- Rendered data must stay consistent with API responses (no stale state leaking into the UI). - -### 3. Performance - -- Must sustain **100 RPS**. - -### 4. Availability & Fault Tolerance - -- VMs hosting the component must be geographically distributed. -- 24/7/365 availability; recovery time ≤ 6 hours after infra is restored. - -### 5. Security - -- Component must be isolated — no attack surface exposed to other components of the host site. - -### 6. SEO & Accessibility - -- SEO optimization required. -- Render microdata: **JSON-LD** and **OpenGraph**. -- Web analytics integrations: **Yandex.Metrica, CTM, Variocube, Key-Astrom (Dynatrace)**. - -### 7. Cross-Platform - -- Embeddable in multiple channel apps (Web, PWA). -- Fully responsive ("fluid") layout across all screen sizes. - -### 8. Logging & Monitoring - -- Frontend log collection in a customer-specified format, shipped to the customer's log aggregation system. -- System event monitoring with export to a metrics aggregator. - -### 9. Module Structure - -- Must conform to the customer's standard remote frontend module structure for uniform deployment. - -### 10. Design - -- Implement against customer-provided mockups using the customer's design system. -- Must embed other customer remote components when available. +- Components must be side-effect free: no `fetch` outside `useEffect`; use the API client from context. +- Use `React.lazy()` for dynamic imports. Wrap browser-only UI such as Leaflet in `ClientOnly`. +- SignalR must stay out of SSR bundles; import `@microsoft/signalr` dynamically only. +- Read env through `getEnv()` from `@/env/index.ts`; SSR injects `window.__ENV__`. +- Keep rendered state consistent with API responses; avoid stale state leaking into UI. +- Preserve SEO/accessibility requirements, including JSON-LD and OpenGraph where relevant. +- Keep layouts fluid and responsive across screen sizes. ## Architecture -**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) +Top-level source areas: -**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 +- `src/routes/` - file-based routing and layouts. +- `src/features/` - feature modules: online board, schedule, flights map, popular requests. +- `src/ui/` - shared UI primitives only. +- `src/shared/` - API client, storage, hooks, SignalR helpers. +- `src/observability/` - logging, metrics, analytics. +- `src/i18n/` - i18n provider and translations. -**Module Federation:** -- Remote name: `aeroflot_flights` -- Exposes: `./OnlineBoard`, `./Schedule`, `./FlightsMap`, `./PopularRequests` -- mf-manifest.json at `https:///mf-manifest.json` +Entry points: -## Critical Constraints +- `src/routes/page.tsx` redirects to `/{lang}/onlineboard`. +- `src/routes/layout.tsx` owns global providers. +- `src/routes/[lang]/layout.tsx` owns locale-scoped i18n. -1. **Side-effect-free components** — No `fetch` outside `useEffect`. API calls via `ApiClient` from context. +Module Federation: -2. **Dynamic imports** — Use `React.lazy()` for code splitting. Wrap browser-only components (Leaflet) in `ClientOnly`. +- Remote name: `aeroflot_flights`. +- Exposes: `./OnlineBoard`, `./Schedule`, `./FlightsMap`, `./PopularRequests`. +- Remote build must emit `dist/remote/mf-manifest.json`, served as `/mf-manifest.json`. -3. **SSR safety** — SignalR (`@microsoft/signalr`) is dynamically imported. Never import in SSR bundle (routes/, server/). +## Layer Boundaries -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/` +ESLint enforces these boundaries: -5. **Restricted imports** (ESLint rules): - - OTel SDK → use `@/observability/metrics/otel` (getMeter/getTracer) - - react-i18next → use `@/i18n/provider` - - localStorage/sessionStorage → use `@/shared/storage` +- `features/` must not import `routes/` or `mf/`. +- `ui/` must not import `features/`, `routes/`, or `mf/`. +- `shared/` must not import `features/`, `routes/`, `mf/`, or `observability/`. +- `observability/` must not import `features/`, `routes/`, or `mf/`. -6. **Environment variables** — Read via `getEnv()` from `@/env/index.ts`. SSR injects `window.__ENV__`. +Restricted imports: -## Dev Server Details +- Use `@/observability/metrics/otel` instead of importing OTel SDKs directly. +- Use `@/i18n/provider` instead of importing `react-i18next` directly. +- Use `@/shared/storage` instead of direct `localStorage` or `sessionStorage`. -- **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 +## Progressive Detail -## Testing +Reach for the sections below only when the task needs them. -- **Unit tests** — Vitest (globals enabled, V8 coverage) -- **E2E tests** — Playwright (baseURL: `http://localhost:8080`) -- **Angular E2E** — Separate config for legacy app (port 4203) +### Contractual Requirements -**Coverage gates:** -- Line coverage ≥ 65% -- Bundle size (gzip) ≤ 2000 kB for remote target +- Modern.js SSR, React 18+, Module Federation 2.0 compatible output. +- `mf-manifest.json` must expose components and logic at `https:///mf-manifest.json`. +- Customer REST APIs use JSON payloads only. +- Target capacity: 100 RPS. +- Remote component must remain isolated from host components. +- Required analytics/monitoring integrations include Yandex.Metrica, CTM, Variocube, and Key-Astrom/Dynatrace. +- Frontend logs and system events must be exportable to customer aggregators. +- Implementation must follow customer mockups, design system, and standard remote module structure. -## Build Artifacts +### Dev Server -- `dist/standalone/` — SSR server (Node entrypoint) -- `dist/remote/` — MF remote with `mf-manifest.json` -- `dist/remote/static/js/` — JS bundles for bundle-size gate +- `pnpm dev` serves Modern.js SSR/HMR on port 8081. +- `pnpm dev:full` serves port 8080 and proxies: + - `/api/*` and `/flights/*` to `https://flights.test.aeroflot.ru` via curl. + - all other paths to Modern.js on 8081. -## Deployment +### Build And Deploy -- **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` +- `dist/standalone/` is the Node SSR server, deployed with `Dockerfile.react`. +- `dist/remote/` is the static MF remote, deployed with `Dockerfile.remote`. +- CI/CD lives in `.github/workflows/ci.yml` and `.github/workflows/deploy.yml`. -## Commit Rules +### Current Constraints -- Never add `Co-Authored-By` lines to commit messages. -- Commit messages in English, concise, focused on "why" not "what". -- Commit autonomously when changes are complete and stable — no need to ask for permission. Group related edits into logical commits. Still ask before pushing, force-pushing, or any destructive git operation. +- Modern.js 3.x upgrade is currently blocked by `@module-federation/modern-js` ESM incompatibilities. +- React Router v7 future flags are enabled to suppress deprecation warnings. -## Gitea / Tea Command Rules +## Git And CI -- Use `tea` command to check Gitea workflow runs: `tea run list --limit 5` to see last 5 runs -- Use `tea run view ` to inspect a specific run -- Use `tea run rerun ` to re-run a failed workflow +- Do not add `Co-Authored-By` lines. +- Commit messages must be English, concise, and focused on why. +- Commit completed stable work autonomously. Ask before pushing, force-pushing, or destructive git operations. +- Use Gitea `tea` for workflow runs: + - `tea run list --limit 5` + - `tea run view ` + - `tea run rerun `