# Frontend Guide

## Stack

- React 18
- Vite 6
- Ant Design 5
- React Router DOM 6 with `MemoryRouter`
- Redux 5, redux-saga, redux-persist, reselect
- Apollo Client 3
- SCSS modules/files by component where present

## Component Layout

Components are organized by a loose atomic design convention:

- `src/components/atoms/`
- `src/components/molecules/`
- `src/components/organisms/`
- `src/components/templates/`
- `src/components/pages/`

File naming usually includes the level:

- `jobs-detail.organism.jsx`
- `jobs-list-item.molecule.jsx`
- `loading-spinner.atom.jsx`
- `error-boundary.template.jsx`
- `jobs.page.jsx`

Preserve this style for new code.

## AntD 5 Rules

Use current AntD 5 APIs:

- `Dropdown menu={{ items, onClick }}` instead of `overlay`.
- `Collapse items={[...]}` instead of `Collapse.Panel` children.
- `expandIconPosition="start"` or `"end"`, not `"left"` or `"right"`.
- `DatePicker.RangePicker presets={...}` instead of `ranges`.
- `Table rowKey="stableId"` or a function using a real stable field; do not rely on the deprecated index argument.
- Prefer AntD `App` context-aware feedback APIs.

Global feedback:

- Use `src/util/antdFeedback.js`.
- Import `antdMessage`/`antdNotification` instead of static `message`/`notification` from `antd` in files outside the AntD app context.
- `src/App/App.jsx` configures these through `AntdFeedbackBridge`.

## Theming

`src/App/App.jsx` wraps the app with:

- `ConfigProvider`
- `theme.darkAlgorithm` or `theme.defaultAlgorithm` based on Redux `darkMode`
- AntD locale `en_US`
- AntD `App`

Dark mode is stored in Redux `user.darkMode`.

## Data Loading Notes

Apollo defaults are `network-only` for `query` and `watchQuery`. Components should be resilient to loading states and should not assume cached data is available.

Pagination:

- Latest jobs and search jobs use offset/limit style pagination.
- Apollo cache merge policies exist for `Query.jobs` and `Query.search_jobs`.
- Guard `fetchMoreResult` and previous data as arrays before spreading; an earlier crash came from assuming `prev.search_jobs` was iterable.

Job detail:

- Selection is debounced briefly to prevent a stale left-panel flash.
- Show stable loading/skeleton states during selection/query transitions.
- Guard against stale Apollo data that does not match the currently selected job id.

## Redux Notes

Reducers are old-style switch reducers with action constants. Sagas are used for side effects. When adding logic:

- Add action type constants.
- Add action creators.
- Update reducers immutably.
- Add selectors with `reselect` where state is consumed.
- Add sagas for async or cross-system side effects.

## Common UI Pitfalls

- Avoid static AntD feedback APIs.
- Avoid adding in-component globals/listeners without cleanup.
- Keep table/list row keys stable.
- Keep list pagination state defensive around empty or missing arrays.
- Do not introduce new routing assumptions based on browser history; this is a `MemoryRouter` Electron app.
- Use existing visual density. This is an operational desktop app, not a marketing site.

