Files
imexrps/.ai/architecture.md

3.8 KiB

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.