Files
imexrps/.ai/architecture.md

104 lines
3.8 KiB
Markdown

# Architecture
## Process Model
ImEX RPS has two main runtimes:
- Electron main process: window lifecycle, native menus, file system access, estimate decoding, file watching/scanning, audit file dialogs, updater, app-level settings, analytics, and IPC.
- React renderer process: UI, routing, Redux state, Apollo GraphQL operations, Firebase auth, and renderer-side IPC listeners.
The renderer does not get Node integration. The preload script exposes a controlled bridge:
- `window.ipcRenderer.send(channel, data)`
- `window.ipcRenderer.on(channel, handler)`
- `window.ipcRenderer.invoke(channel, data)`
- `window.ipcRenderer.removeAllListeners(...)`
- `window.logger.*`
## Entrypoints
Electron:
- `electron/main.js` decides whether to run the source main file or bundled `dist-electron/main.cjs`.
- `electron/main-src.js` is the main source file.
- `electron/preload.js` decides whether to run the source preload or bundled `dist-electron/preload.cjs`.
- `electron/preload-src.js` exposes IPC/logger bridges.
- `scripts/build-electron.mjs` bundles main/preload outputs.
Renderer:
- `src/index.jsx` initializes Sentry renderer, Redux Provider, `MemoryRouter`, `PersistGate`, and `<App />`.
- `src/App/App.jsx` initializes Apollo, AntD context/theme, auth session check, IPC side effects, and authorized/unauthorized routing.
- `src/components/pages/routes/routes.page.jsx` renders the main app shell and routes.
## Routing
Routes are memory-router routes because this is an Electron app:
- `/` Jobs
- `/settings` Settings
- `/reporting` Reporting
- `/audit` Audit
- `/scan` Scan
- `/admin` Admin
The app shell includes the side menu, notifications modal, release notes, and update manager.
## Redux Shape
Store setup:
- `src/redux/store.js`
- Redux core `legacy_createStore`
- Saga middleware
- Redux logger in development
- Redux DevTools compose if present
- redux-persist wrapper with all active reducers currently blacklisted
Reducers:
- `application`: watcher status, watched paths, selected job id, selected target percent, settings, update state, release notes, estimate scrubber results.
- `user`: current user, bodyshop, targets, fingerprint, auth errors, notifications, dark mode.
- `reporting`: report date range, report rows, scorecard, audit data/errors/loading, excluded ids, cached jobs.
- `scan`: scan loading state, last scanned, estimate list.
Sagas:
- `applicationSagas`
- `userSagas`
- `reportingSagas`
- `scanSagas`
## Data Flow for Estimate Import
1. User configures `filePaths` in settings.
2. Electron store persists those paths.
3. `electron/file-watcher/file-watcher.js` watches paths with chokidar.
4. New/changed estimate files are decoded by `electron/decoder/decoder.js`.
5. Main process sends decoded payloads over IPC.
6. Renderer `src/ipc/ipc-renderer-handler.js` receives decoded estimates.
7. Renderer GraphQL helper `UpsertEstimate` writes jobs/joblines to Hasura.
8. Jobs UI queries data back through Apollo.
## Data Flow for Job Details
1. A list item dispatches selected job id to Redux `application`.
2. `jobs-detail.organism.jsx` debounces selected id briefly to avoid rendering a stale/partial left panel.
3. Apollo queries `QUERY_JOB_BY_PK`.
4. Detail subcomponents render job metadata, joblines, targets, group controls, claims clerk, estimate scrubber, and other actions.
## IPC Contract
IPC channel names live in `src/ipc.types.json`, imported by:
- `src/ipc.types.js` for ESM renderer code.
- `src/ipc.types.commonjs.js` for CommonJS Electron code.
When adding IPC:
- Add channel names to `src/ipc.types.json`.
- Register main handlers in the relevant Electron module.
- Register renderer listeners in `src/ipc/ipc-renderer-handler.js` or a local component effect.
- Keep handlers idempotent when possible; repeated imports/listeners can create duplicate events.