feature/IO-3725-RPS-Changes - Add AI context files, fix auto start dev tools in local

This commit is contained in:
Dave
2026-05-28 16:22:54 -04:00
parent 5f860d26e3
commit c7ad369a76
15 changed files with 1236 additions and 3 deletions

103
.ai/architecture.md Normal file
View File

@@ -0,0 +1,103 @@
# 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.

113
.ai/data-graphql-hasura.md Normal file
View File

@@ -0,0 +1,113 @@
# Data, GraphQL, Hasura, and Auth Guide
## GraphQL Client
Apollo setup lives in `src/graphql/GraphQLClient.js`.
Links:
- `HttpLink` uses `import.meta.env.VITE_APP_GRAPHQL_ENDPOINT`.
- `authLink` reads Firebase current user token and attaches `Authorization: Bearer <token>`.
- `RetryLink` retries transient failures.
- `onError` logs GraphQL/network errors.
- `SentryLink` records Apollo operations/errors.
- `apollo-link-logger` is included in development.
Default options:
- `query.fetchPolicy = "network-only"`
- `watchQuery.fetchPolicy = "network-only"`
- `connectToDevTools` enabled outside production
Cache:
- `Query.jobs` uses offset merge policy.
- `Query.search_jobs` uses offset merge policy.
This avoids Apollo "Cache data may be lost when replacing the jobs field" warnings during pagination.
## GraphQL Operation Files
- `src/graphql/jobs.queries.js`: job insert, latest pagination, search pagination, job by id, job by claim number, close date lookup, update/delete, estimate scrubber query.
- `src/graphql/joblines.queries.js`: jobline update.
- `src/graphql/bodyshop.queries.js`: current bodyshop, shop update, notifications.
- `src/graphql/user.queries.js`: user upsert/login association.
- `src/graphql/reporting.queries.js`: report data.
- `src/graphql/notification.queries.js`: accept notification.
- `src/graphql/veh_group.queries.js`: vehicle group lookup.
## Hasura Layout
Hasura project files:
- `hasura/config.yaml`
- `hasura/config.yaml.prod`
- `hasura/metadata/`
- `hasura/migrations/default/`
- `hasura/migrations_backup/`
Important metadata:
- `hasura/metadata/databases/default/tables/`
- `hasura/metadata/databases/default/functions/public_search_jobs.yaml`
Important tables:
- `users`
- `bodyshops`
- `associations`
- `jobs`
- `joblines`
- `targets`
- `veh_groups`
- `groupings`
- `notifications`
Important function:
- `search_jobs`
## Core Relationships
- `users.email` links to `associations.email`.
- `associations.bodyshopid` links users to bodyshops.
- `jobs.bodyshopid` links jobs to bodyshops.
- `joblines.jobid` links joblines to jobs.
- Notifications can target a bodyshop.
## Schema Evolution Notes
The `jobs` and `joblines` schema has grown significantly over time. Do not assume the original create-table migrations show the current shape.
Recent-ish/important fields include:
- `jobs`: `close_date`, `loss_date`, `v_age`, `v_mileage`, `group`, `group_verified`, `requires_reimport`, `ins_rule_set`-related usage through bodyshop settings, owner fields, impact fields, totals/rates JSON, vehicle stage, theft/tlos/insp fields, supplement/betterment amounts, ES fields.
- `joblines`: `line_no`, `db_ref`, `price_diff`, `price_diff_pc`, `ignore`, ADAS/claims clerk/ruleset fields, labor/part flags, tax/cert/glass flags, line refs, modified labor/price fields.
- `bodyshops`: `accepted_ins_co`, `targets`, `groups`, `features`, `channel`, `phone`, `zip_post`, `es_api_key`, `mpi_count_quantity`, `carfax_exclude`, `ins_rule_set`.
Use Hasura metadata and current GraphQL query selections to confirm exact field names before changing queries or migrations.
## Authentication
Firebase auth utilities live in `src/firebase/firebase.utils.js`.
Renderer startup:
1. `src/index.jsx` mounts Redux and App.
2. `src/App/App.jsx` dispatches `checkUserSession`.
3. User sagas validate/load user state.
4. Apollo auth link uses the current Firebase token for GraphQL.
If a user has no shop access, `RoutesPage` renders a "No shop access" error result.
## Data Import Boundary
Electron main decodes local DBF files. Renderer writes decoded results to Hasura. This means import bugs may straddle:
- DBF decoding in `electron/decoder/decoder.js`.
- IPC payloads in `src/ipc/ipc-renderer-handler.js`.
- GraphQL upsert helpers in `src/ipc/ipc-estimate-utils.js`.
- Hasura insert/update permissions and constraints.
When debugging import issues, inspect all four layers.

111
.ai/domain-glossary.md Normal file
View File

@@ -0,0 +1,111 @@
# Domain Glossary
This glossary captures terms that appear in code, database fields, and UI.
## Business Terms
- RPS: Repair Performance System, the desktop app/product.
- Bodyshop: A repair shop/account using the app.
- Association: Link between a user email and a bodyshop.
- Job: A repair claim/estimate record.
- Jobline: A line item within a repair estimate.
- Claim number / `clm_no`: Claim identifier used for lookup/search.
- RO number / `ro_number`: Repair order number.
- Insurer / `ins_co_nm`: Insurance company name on a job.
- Accepted insurers / `accepted_ins_co`: Shop-specific list of insurers to accept/import.
- Close date: Claim close date, used in reporting and ruleset selection.
- Loss date: Date of loss, used by job queries and reporting.
- Vehicle group / `group`: Group assignment based on vehicle make/type/age and configured rules.
- Target: Target percentage used in RPS calculations.
- Grouping: Hasura data that maps vehicle make/type/date ranges to groups.
- Group verified: User/shop-confirmed group assignment.
- Requires reimport: Flag indicating a job should be reimported because decoded data or rules changed.
## Estimate/File Terms
- EMS: Estimate Management Standard file set. The app watches for estimate files in local folders.
- DBF: dBASE file format used by decoded estimate data.
- AD1/AD2: Estimate DBF files decoded by `electron/decoder/decoder.js`.
- LIN: Estimate line DBF file.
- VEH: Vehicle DBF file.
- TTL: Totals DBF file.
- PFH/PFL/PFM/STL: Additional estimate/system DBF files decoded when present.
- Watch path: Local directory watched by chokidar.
- File scan: Manual scan of configured watch paths.
- Import: Decode local estimate files and upsert the resulting job/joblines into Hasura.
## Rules and Programs
- MPI: Manitoba Public Insurance, a ruleset/insurer context used heavily in targets and line rules.
- SGI: Saskatchewan Government Insurance, another ruleset context. Some UI warns SGI eligibility rules may fall back to MPI rules.
- RCC: A reporting/eligibility flag surfaced as `sgi_rcc`/RCC-related UI.
- Ruleset: Date/rule bundle used by decoder logic to mark/interpret joblines.
- V1/V2/V3 rulesets: Decoder-era rulesets selected by close date.
- Claims Clerk: Domain rule engine that flags line-level issues/alerts.
- Estimate Scrubber / ES: External API workflow that validates/scrubs estimate JSON and returns a report.
- ES API key: Shop-specific API key stored on `bodyshops.es_api_key`.
## Common Database Fields
Jobs:
- `id`: UUID primary key.
- `bodyshopid`: Owning bodyshop.
- `clm_no`: Claim number.
- `ro_number`: Repair order number.
- `ins_co_nm`: Insurer name.
- `close_date`: Claim close date.
- `loss_date`: Loss date.
- `v_vin`: Vehicle VIN.
- `v_makedesc` / `v_model`: Vehicle make/model.
- `v_model_yr`: Vehicle model year.
- `v_type`: Vehicle type.
- `v_age`: Vehicle age.
- `v_mileage`: Vehicle mileage.
- `group`: Vehicle group.
- `group_verified`: Whether group was manually verified.
- `rates`, `totals`: JSON estimate rate/total blobs.
- `requires_reimport`: Indicates data should be imported again.
Joblines:
- `id`: UUID primary key.
- `jobid`: Parent job.
- `line_no`: Estimate line number.
- `unq_seq`: Source unique sequence id.
- `line_ind`: Source line indicator.
- `line_desc`: Line description.
- `part_type`: Part type/category.
- `db_price`: Database/reference price.
- `act_price`: Actual price.
- `price_diff`, `price_diff_pc`: Price difference fields.
- `ignore`: Whether line is excluded from calculations.
- `alerts`: Rules/claims-clerk alert payload.
- `line_ref`: Parent/source line reference.
Bodyshops:
- `shopname`: Shop display name.
- `accepted_ins_co`: JSON array of accepted insurers.
- `targets`: JSON target config.
- `groups`: JSON group config.
- `features`: Feature config.
- `channel`: Update/release channel.
- `es_api_key`: Estimate scrubber key.
- `ins_rule_set`: Shop ruleset, such as SGI.
## UI/Code Abbreviations
- `pct`, `pc`: Percent.
- `ppd`: Price/part difference domain abbreviation used in settings/alerts.
- `rps`: Repair performance score/system.
- `asgn`: Assignment.
- `insp`: Inspection.
- `ded`: Deductible.
- `supp`: Supplement.
- `tlos`: Total loss indicator.
- `prt`: Part.
- `lbr`: Labor.
- `amt`: Amount.
- `qty`: Quantity.

152
.ai/electron-main.md Normal file
View File

@@ -0,0 +1,152 @@
# Electron Main, IPC, and Packaging Guide
## Main Files
- `electron/main.js`: Launch shim. Chooses bundled `dist-electron/main.cjs` in packaged mode when present, otherwise source.
- `electron/main-src.js`: Source of truth for main process behavior.
- `electron/preload.js`: Launch shim for preload.
- `electron/preload-src.js`: Source preload bridge.
- `scripts/build-electron.mjs`: Builds `dist-electron/main.cjs` and `dist-electron/preload.cjs`.
## Main Process Responsibilities
`electron/main-src.js` handles:
- App/window lifecycle.
- Application menu.
- Sentry main process setup.
- Auto-updater and update IPC.
- DevTools configuration.
- Third-party notice window.
- Single-instance locking.
- Tray behavior on minimize.
- Initializing `electron-store`.
- Loading IPC handlers.
- Dynamic ESM imports for ESM-only Electron packages.
## Store Initialization
`electron-store` v11 is ESM-only. The app uses `electron/electron-store.js`:
- `initializeStore()` dynamically imports and creates the store.
- `store` is a proxy that throws if accessed before initialization.
`main-src.js` must call:
```js
await initializeStore();
initializeIpcHandlers();
```
before modules such as analytics, watcher, scanner, audit, or decoder read `store`.
Store defaults include:
- `deviceId`
- `showChangeLog`
- `enableNotifications`
- `filePaths`
- `accepted_ins_co`
- `runWatcherOnStartup`
- `polling`
- `ins_rule_set`
## ESM-Only Package Notes
Current major upgrades made these ESM-only:
- `electron-context-menu`
- `electron-store`
- `electron-is-dev`
The app no longer uses `electron-is-dev`; it uses `!app.isPackaged` in main and `process.defaultApp`/`process.execPath` detection in preload.
Use dynamic import for `electron-context-menu`:
```js
const { default: contextMenu } = await import("electron-context-menu");
```
## Sentry Electron
Current dependency: `@sentry/electron@^7.13.0`.
Main process import:
```js
const Sentry = require("@sentry/electron/main");
```
Renderer import:
```js
import * as Sentry from "@sentry/electron/renderer";
```
Main setup uses:
```js
ipcMode: Sentry.IPCMode.Protocol
```
Keep protocol mode unless deliberately changing Sentry IPC behavior. It avoids the deprecated Electron preload path Sentry can otherwise use.
## DevTools
Current behavior:
- Dev mode: DevTools enabled and auto-open unless `ELECTRON_OPEN_DEVTOOLS=0`.
- Packaged mode: DevTools disabled unless `ELECTRON_ENABLE_DEVTOOLS=1`.
- Packaged auto-open: requires `ELECTRON_OPEN_DEVTOOLS=1`.
- React DevTools extension installation: opt-in with `ELECTRON_INSTALL_REACT_DEVTOOLS=1`.
Chrome DevTools can emit Electron backend console noise such as `Autofill.enable` and `Autofill.setAddresses` protocol errors. That noise is tied to DevTools/extension behavior, not app runtime failure.
## IPC Modules
Shared registration:
- `electron/ipc-main-handler.js`
Imported modules:
- `electron/file-watcher/file-watcher-ipc.js`
- `electron/file-scan/file-scan-ipc.js`
- `electron/audit/audit-ipc.js`
Avoid importing `mainWindow` from `main-src.js` in IPC modules. That caused circular dependency warnings. Use:
```js
const parentWindow = BrowserWindow.fromWebContents(event.sender);
```
for dialog parents, or `BrowserWindow.getAllWindows()[0]` for broadcast-style interactions when necessary.
## Packaging
`package.json` contains electron-builder config.
Important scripts:
- `npm run build:electron`: generates `dist-electron/`.
- `npm run pack`: local unpacked package check with `--publish never` and `electron-builder.pack-check.cjs`.
- `npm run dist`: full build/package using package config.
- `npm run distp`: publishes. Use only when explicitly requested.
- `npm run distnopublish`: full build/package with publishing disabled.
`electron-builder.pack-check.cjs` disables Azure Trusted Signing config for pack checks:
```js
azureSignOptions: null
```
The pack check may still locally sign the unpacked executable with signtool. That is not publishing.
Generated artifacts:
- `dist-electron/`: bundled main/preload, ignored.
- `build/`: renderer production build, ignored.
- `dist/`: electron-builder output, ignored.
Do not manually edit generated artifacts.

127
.ai/file-map.md Normal file
View File

@@ -0,0 +1,127 @@
# File Map
Use this as a quick locator before making changes.
## Root
- `package.json`: scripts, dependencies, electron-builder config, product metadata.
- `package-lock.json`: npm dependency lock.
- `vite.config.js`: Vite renderer config.
- `index.html`: Vite app HTML entry.
- `README.md`: old Create React App boilerplate; partially stale.
- `Usage.md`: release usage notes; ignored by git but present.
- `deployment.md`: deployment note; very terse.
- `update-targets.md`: historical GraphQL target load example.
- `SGI.md`: SGI-related domain notes.
- `electron-builder.pack-check.cjs`: no-publish local packaging config for `npm run pack`.
- `.gitignore`: generated artifacts and local secret files.
## Electron
- `electron/main.js`: chooses source or bundled main process.
- `electron/main-src.js`: main process source of truth.
- `electron/preload.js`: chooses source or bundled preload.
- `electron/preload-src.js`: context bridge for IPC/logger.
- `electron/ipc-main-handler.js`: shared IPC registration.
- `electron/electron-store.js`: async ESM-compatible electron-store wrapper.
- `electron/analytics.js`: Amplitude analytics IPC.
- `electron/changelog.json`: versioned release notes.
- `electron/licenses.txt`: third-party notice content shown in the app.
- `electron/file-watcher/`: chokidar watcher and watcher IPC.
- `electron/file-scan/`: manual scan/delete estimate file logic and IPC.
- `electron/decoder/`: DBF estimate decoding and ruleset application.
- `electron/claims-clerk/`: line-level alert rules.
- `electron/audit/`: audit spreadsheet dialog/parsing IPC.
- `electron/estimate-scrubber/`: external estimate scrubber API integration.
- `electron/notification-wrapper/`: native notification helper.
## Renderer Entrypoints
- `src/index.jsx`: React root, Redux Provider, MemoryRouter, PersistGate, Sentry renderer.
- `src/App/App.jsx`: Apollo provider, AntD theme/app provider, auth check, top-level IPC side effects.
- `src/App/App.styles.scss`: app-level styles.
- `src/index.css`: global CSS.
## Renderer Components
- `src/components/pages/routes/routes.page.jsx`: authenticated app shell and routes.
- `src/components/pages/jobs/`: main jobs page.
- `src/components/pages/reporting/`: reporting page.
- `src/components/pages/audit/`: audit page.
- `src/components/pages/scan/`: scan page.
- `src/components/pages/settings/`: settings page.
- `src/components/pages/admin/`: admin page.
- `src/components/pages/sign-in/`: sign-in page.
- `src/components/organisms/jobs-list-latest/`: latest jobs infinite list.
- `src/components/organisms/jobs-list-search/`: search jobs infinite list.
- `src/components/organisms/jobs-detail/`: selected job detail panel.
- `src/components/organisms/watcher-manager/`: file watcher controls.
- `src/components/organisms/shop-settings/`: shop settings workflows.
- `src/components/organisms/update-manager/`: updater UI.
- `src/components/organisms/notification-modal/`: notification UI.
- `src/components/molecules/jobs-lines-table/`: jobline table.
- `src/components/molecules/estimate-scruber-results/`: estimate scrubber results UI. Note the folder name contains `scruber`.
- `src/components/molecules/estimate-scrubber-button/`: estimate scrubber action.
- `src/components/molecules/reporting-dates/`: reporting date range picker.
- `src/components/templates/error-boundary.template.jsx`: app error boundary.
- `src/components/templates/ipc-upsert-job/`: IPC import/upsert template.
## State
- `src/redux/store.js`: store, saga middleware, logger, persist store.
- `src/redux/root.reducer.js`: combines reducers.
- `src/redux/root.saga.js`: combines sagas.
- `src/redux/application/`: watcher/app/update/selection/scrubber state.
- `src/redux/user/`: auth/bodyshop/targets/notifications/dark mode.
- `src/redux/reporting/`: report/audit/scorecard state.
- `src/redux/scan/`: scan state.
## GraphQL and Auth
- `src/graphql/GraphQLClient.js`: Apollo links, auth, retry, Sentry, cache policies.
- `src/graphql/jobs.queries.js`: job queries/mutations.
- `src/graphql/joblines.queries.js`: jobline mutations.
- `src/graphql/bodyshop.queries.js`: shop and notifications.
- `src/graphql/user.queries.js`: user upsert/auth lookup.
- `src/graphql/reporting.queries.js`: reporting queries.
- `src/graphql/notification.queries.js`: notification acceptance.
- `src/graphql/veh_group.queries.js`: vehicle groups.
- `src/firebase/firebase.utils.js`: Firebase auth/app setup.
## IPC
- `src/ipc.types.json`: canonical IPC channel map.
- `src/ipc.types.js`: ESM wrapper.
- `src/ipc.types.commonjs.js`: CommonJS wrapper.
- `src/ipc/ipc-renderer-handler.js`: central renderer IPC listeners.
- `src/ipc/ipc-estimate-utils.js`: estimate upsert and close-date GraphQL helpers.
## Utilities and Assets
- `src/util/antdFeedback.js`: context-safe AntD message/notification bridge.
- `src/util/day.js`: day/date setup.
- `src/util/CalculateJobRps.js`: RPS calculation utility.
- `src/util/GetJobTarget.js`: target calculation utility.
- `src/util/decimalPrecision.js`: numeric precision utility.
- `src/util/sorters.js`: table/list sort helpers.
- `src/assets/`: app logos/images.
- `src/icons/`: app icons by platform/size.
- `public/`: web app static files.
## Hasura and Firebase
- `hasura/config.yaml`: Hasura project config.
- `hasura/config.yaml.prod`: production Hasura config.
- `hasura/metadata/`: tracked Hasura metadata.
- `hasura/migrations/default/`: active SQL migrations.
- `hasura/migrations_backup/`: historical migration backup.
- `firebase/functions/`: Firebase functions project.
- `firebase/firebase.json`: Firebase config.
## Generated/Ignored
- `build/`: renderer production output.
- `dist-electron/`: bundled Electron main/preload output.
- `dist/`: electron-builder output.
- `node_modules/`: dependencies.

95
.ai/frontend.md Normal file
View File

@@ -0,0 +1,95 @@
# 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.

48
.ai/project-overview.md Normal file
View File

@@ -0,0 +1,48 @@
# Project Overview
ImEX RPS is a desktop repair performance system for body shops. It imports estimating-system files, decodes estimates into jobs and joblines, stores and reads them through Hasura GraphQL, and gives users workflows for job review, reporting, audit, scan/import, settings, admin maintenance, updates, and estimate scrubbing.
## Product Concepts
- Bodyshop: The shop/account a signed-in user can access.
- User association: A user is linked to one or more bodyshops through Hasura data.
- Job: A repair estimate/claim. Jobs contain claim number, owner/customer fields, vehicle information, insurer, close/loss dates, totals, rates, group data, flags, and related joblines.
- Jobline: A decoded estimate line. Joblines contain part/labor data, pricing deltas, ignore flags, ruleset-derived booleans, and alert metadata.
- Targets/groupings: Config data used to calculate target percentages and vehicle group eligibility.
- Notifications: Hasura-backed shop/user notifications shown in the app.
- Watch paths: Local folders where Electron watches for estimate files.
- Scan: Manual folder scan for estimate files.
- Audit: Spreadsheet-driven workflow comparing claim data against cached jobs.
- Estimate scrubber: External API workflow that sends estimate JSON and opens/sends scrub reports.
## Main User Workflows
- Sign in with Firebase auth.
- Load user/bodyshop/notifications from Hasura after auth.
- Configure watched folders and shop settings.
- Watch or scan folders for estimate files.
- Decode estimates in Electron main process.
- Upsert jobs/joblines through renderer GraphQL helpers.
- Review jobs and joblines in the Jobs page.
- Search and paginate jobs.
- Generate reporting and scorecards over date ranges.
- Run audits from selected spreadsheets.
- Send eligible estimates to the estimate scrubber service.
- Receive update notices through electron-updater/S3 publishing.
## External Systems
- Hasura GraphQL/Postgres: Primary app data store.
- Firebase: Authentication.
- S3 updater bucket: Electron auto-update publishing target.
- Sentry: Renderer and main-process error telemetry.
- Amplitude: Main-process analytics through IPC.
- Estimate scrubber API: External estimate validation/report flow.
- Local file system: Estimate file watcher, scan, and DBF decoding.
## Legacy Context
The repository started from Create React App but now uses Vite. Some docs and comments are old. Prefer `package.json` scripts and current code over README boilerplate.
The app uses a mixture of older class-era Redux patterns and current library versions. Preserve working conventions unless a task specifically asks for modernization.

105
.ai/recent-changes.md Normal file
View File

@@ -0,0 +1,105 @@
# Recent Changes and Migration Context
This file captures recent cleanup/migration work so future agents do not reverse it.
## AntD 5 Deprecation Cleanup
Warnings addressed:
- `Collapse expandIconPosition` left/right deprecated.
- `rc-collapse children` deprecated.
- `Table rowKey` index parameter deprecated.
- Static `message` cannot consume dynamic theme context.
- `Dropdown overlay` deprecated.
- `RangePicker ranges` deprecated.
Patterns now used:
- `Collapse items`
- `expandIconPosition="end"`
- `Dropdown menu`
- stable table row keys
- `RangePicker presets`
- `src/util/antdFeedback.js` for feedback APIs
- AntD `<App>` wrapper and bridge in `src/App/App.jsx`
## Redux CreateStore Warning
`src/redux/store.js` imports:
```js
import { legacy_createStore as createStore, applyMiddleware, compose } from "redux";
```
This intentionally keeps the current Redux architecture while avoiding the visual deprecation warning. Do not change to plain `createStore`.
## Job Detail Flash Fix
`src/components/organisms/jobs-detail/jobs-detail.organism.jsx` debounces selected job id and shows a skeleton during transitions. This prevents a fraction-of-a-second stale/partial render in the left panel.
When editing this area:
- Preserve stale-data guards.
- Preserve a stable loading state when selected id changes.
- Do not render details for a job whose id does not match current selection.
## Apollo Pagination/Cache Fixes
`src/graphql/GraphQLClient.js` includes offset merge policies:
- `Query.jobs`
- `Query.search_jobs`
List components were hardened against missing previous/incoming arrays.
## Electron Package Upgrades
Packages upgraded together:
- `electron-context-menu` to `^4.1.2`
- `electron-is-dev` to `^3.0.1`
- `electron-store` to `^11.0.2`
- `electron` to `^42.3.0`
- `electron-builder` to `^26.8.1`
- `@sentry/electron` to `^7.13.0`
Important migration consequences:
- `electron-store` is initialized asynchronously via dynamic import.
- `electron-context-menu` is dynamically imported.
- `electron-is-dev` is no longer used in runtime code; use `app.isPackaged`/process checks.
- Sentry uses protocol IPC mode.
- Electron builder pack check uses `electron-builder.pack-check.cjs`.
## Electron Warning Cleanup
Circular dependency warning fixed by removing `mainWindow` export/import patterns. IPC modules use Electron APIs directly:
```js
BrowserWindow.fromWebContents(event.sender)
```
Sentry preload deprecation warnings were addressed by using protocol IPC mode:
```js
ipcMode: Sentry.IPCMode.Protocol
```
DevTools behavior:
- Development opens DevTools by default again.
- Use `ELECTRON_OPEN_DEVTOOLS=0` to suppress.
- React DevTools extension install remains opt-in.
## Pack Check Safety
User specifically requested pack checks without publishing.
`package.json`:
```json
"pack": "electron-builder --dir --publish never --config electron-builder.pack-check.cjs"
```
`electron-builder.pack-check.cjs` disables Azure signing options for this local check. Do not remove `--publish never` from the pack script.

141
.ai/workflows.md Normal file
View File

@@ -0,0 +1,141 @@
# Development, Verification, and Release Workflows
## Local Development
```powershell
npm install
npm run dev
```
This runs:
- Vite renderer dev server on `http://localhost:3006`
- Electron app pointed at that dev server
The app uses `MemoryRouter`, so browser URL routing behavior does not match a normal web app.
## Build Verification
Renderer build:
```powershell
npm run build
```
Electron main/preload bundle:
```powershell
npm run build:electron
```
Run both for most cross-process changes.
Known existing build warnings:
- A warning around `true || j.close_date` in `src/components/pages/admin/admin.page.jsx`.
- Vite chunk-size warnings for large bundles.
Do not treat those as newly introduced unless your change touches them.
## Packaging Check
Use:
```powershell
npm run pack
```
This runs:
```text
electron-builder --dir --publish never --config electron-builder.pack-check.cjs
```
It is the preferred "does it package?" check because it avoids publishing.
## Publishing
Publishing is configured through electron-builder S3 settings in `package.json`. The updater checks periodically.
Do not run publishing scripts unless explicitly requested:
- `npm run distp`
- Any direct `electron-builder --publish always`
If asked to release:
1. Confirm the version in `package.json`.
2. Run `npm run build`.
3. Run `npm run build:electron`.
4. Run a no-publish package check first.
5. Only then run the requested publish command.
## Auto Updates
Main process:
- Uses `electron-updater`.
- `autoUpdater.autoDownload = true`.
- Checks every 30 minutes after app ready.
- Sends update events/progress to renderer through IPC.
- Renderer `UpdateManagerOrganism` handles UI.
Release notes:
- Stored in `electron/changelog.json`.
- Main process reads `require("./changelog.json")[app.getVersion()]`.
- Store key `showChangeLog` controls initial display.
## Hasura
Hasura config and migrations live under `hasura/`.
Be careful with migrations:
- Current migrations are under `hasura/migrations/default/`.
- `hasura/migrations_backup/` is historical backup material.
- Metadata under `hasura/metadata/` should match Hasura's generated layout.
When changing GraphQL queries, verify the Hasura metadata/schema supports selected fields.
## Sentry Source Maps
Script:
```powershell
npm run sentry:sourcemaps
```
Requires a valid `.sentryclirc`/token and should only be run when intentionally uploading source maps.
## Troubleshooting
Electron backend console DevTools noise:
- `Autofill.enable` and `Autofill.setAddresses` errors are Chromium DevTools protocol noise.
- They can appear when Chrome DevTools or React DevTools are open.
Electron circular dependency warning:
- Do not import `mainWindow` from `main-src.js` in other Electron modules.
- Use `BrowserWindow.fromWebContents(event.sender)` for dialogs.
AntD theme/static feedback warning:
- Use `antdMessage`/`antdNotification` from `src/util/antdFeedback.js`.
- Ensure `AntdFeedbackBridge` is mounted inside AntD `<App>`.
Apollo cache replacement warning:
- Confirm field policies in `GraphQLClient.js`.
- Add/adjust merge policies for newly paginated fields.
Search pagination crash:
- Guard `prev?.search_jobs` and `fetchMoreResult?.search_jobs` before spreading.
Git ignore of generated files:
- `.gitignore` includes `/dist-electron/`.
- If generated files still show in status, they are probably already tracked; remove from index with `git rm --cached -r dist-electron` after confirming the local files can stay.

15
.github/copilot-instructions.md vendored Normal file
View File

@@ -0,0 +1,15 @@
# Copilot Instructions for ImEX RPS
Read `AGENTS.md` first. It contains the current project architecture, safety rules, workflows, and migration context.
When proposing or generating code:
- Use npm scripts and current Vite/Electron workflows, not stale Create React App/yarn instructions.
- Keep changes narrow and preserve existing style.
- Do not edit generated `build/`, `dist/`, or `dist-electron/`.
- Do not suggest publish commands unless the user explicitly asks to publish.
- Prefer AntD v5 APIs and avoid deprecated props.
- Preserve Electron security defaults: `contextIsolation: true`, `nodeIntegration: false`, preload bridge for renderer IPC.
- Avoid circular Electron main-process imports; IPC modules should not import `mainWindow` from `main-src.js`.
- Use `.ai/` files for deeper domain and architecture context.

162
AGENTS.md Normal file
View File

@@ -0,0 +1,162 @@
# ImEX RPS Agent Guide
This file is the first stop for coding agents working in this repository. It is intentionally practical: read this before changing code, then use the deeper files in `.ai/` when you need more context.
## Project Snapshot
ImEX RPS is an Electron desktop app with a Vite/React renderer. It is used by body shops to import, inspect, report on, and audit repair estimate data. The app reads estimate files from configured local folders, decodes DBF-based estimate data in the Electron main process, stores jobs/joblines in Hasura/Postgres through GraphQL, and presents workflows for jobs, reporting, scanning, settings, admin work, audits, and estimate scrubbing.
Primary technologies:
- Electron 42, electron-builder 26, Vite 6, React 18
- Ant Design 5
- Redux 5, redux-saga, redux-persist, reselect
- Apollo Client 3 against a Hasura GraphQL endpoint
- Firebase authentication
- Sentry Electron 7
- Hasura metadata and SQL migrations under `hasura/`
## Fast Start
Use npm scripts, not the stale yarn commands in `README.md`.
```powershell
npm install
npm run dev
```
Useful scripts:
- `npm run start` starts Vite on `http://localhost:3006`.
- `npm run electron` starts Electron.
- `npm run dev` runs Vite and Electron together with `concurrently`.
- `npm run build` builds the renderer to `build/`.
- `npm run build:electron` bundles `electron/main-src.js` and `electron/preload-src.js` into `dist-electron/`.
- `npm run pack` performs a local unpacked electron-builder package check with `--publish never`.
- `npm run distp` publishes. Do not run it unless the user explicitly asks to publish.
- `npm run distnopublish` builds a distributable with publish disabled.
Expected local runtime:
- Node must satisfy Electron 42 requirements. At the time of the upgrade, Node 22.22.1 was used successfully.
- `VITE_APP_GRAPHQL_ENDPOINT` must be available in the renderer environment.
- Firebase config lives in `src/firebase/firebase.utils.js`.
- Electron dev mode loads `http://localhost:3006`; packaged mode loads `build/index.html`.
## Important Safety Rules
- Do not publish releases unless the user explicitly says to publish.
- `npm run pack` is safe for local packaging checks because it includes `--publish never` and uses `electron-builder.pack-check.cjs`.
- `dist-electron/`, `build/`, and `dist/` are generated artifacts and are ignored. Do not manually edit them.
- Do not commit local secrets. The repo contains legacy-sensitive assets such as `certificate.p12`, deployment notes, and Sentry/Firebase/AWS-related configuration. Treat them carefully.
- Avoid broad refactors. This project has older patterns and domain-heavy workflows; make narrow changes and preserve behavior.
- Be careful with Electron main/renderer boundaries. Renderer code should use the exposed preload bridge on `window.ipcRenderer`; main-process code should register IPC handlers under `electron/`.
## Architecture Map
Renderer entry:
- `src/index.jsx` wires Redux, redux-persist, `MemoryRouter`, Sentry renderer, and `<App />`.
- `src/App/App.jsx` wires Apollo, AntD `ConfigProvider`, AntD `App`, auth session check, IPC setup, and authorized/unauthorized routing.
- `src/components/pages/routes/routes.page.jsx` defines app pages: jobs, reporting, audit, scan, settings, admin.
Electron entry:
- `electron/main.js` chooses source vs bundled Electron main file.
- `electron/main-src.js` is the source of truth for main-process window creation, Sentry main, auto-updater, app menu, DevTools behavior, and global IPC initialization.
- `electron/preload-src.js` exposes `window.ipcRenderer` and `window.logger`.
- `electron/ipc-main-handler.js` registers shared IPC channels and imports file watcher, file scan, audit, decoder, and estimate scrubber handlers.
- `scripts/build-electron.mjs` produces `dist-electron/main.cjs` and `dist-electron/preload.cjs`.
State/data:
- `src/redux/store.js` still uses Redux core with `legacy_createStore` to avoid Redux's visual createStore deprecation.
- Root reducers: `application`, `user`, `reporting`, `scan`.
- Sagas coordinate auth, user/shop setup, reporting, scanning, and application actions.
- `src/graphql/GraphQLClient.js` sets Apollo auth, retry, Sentry, logger, error links, and cache field policies for `jobs` and `search_jobs`.
- GraphQL operations live in `src/graphql/*.queries.js`.
Domain logic:
- `electron/decoder/decoder.js` decodes estimate files and applies MPI/SGI/ruleset logic.
- `electron/file-watcher/` watches configured estimate folders.
- `electron/file-scan/` scans configured folders for estimates.
- `electron/audit/` reads audit spreadsheets.
- `electron/estimate-scrubber/` sends estimate JSON to the external scrubber API and opens/sends report results.
- `electron/claims-clerk/` computes jobline alerts.
## Current Conventions
Frontend:
- Components are organized by atomic-ish folders: `atoms`, `molecules`, `organisms`, `templates`, `pages`.
- File names generally follow `name.type.jsx` and optional `name.type.styles.scss`.
- Use Ant Design 5 APIs. Avoid deprecated props such as `Dropdown overlay`, `Collapse.Panel` children, `expandIconPosition="left/right"`, `RangePicker ranges`, and `Table rowKey` functions that rely on index.
- Use `src/util/antdFeedback.js` for message/notification calls outside React component context. Static AntD `message`/`notification` calls can miss dynamic theme context.
- Keep UI state stable during data transitions. Job detail selection uses a short debounce/skeleton to avoid flashing stale detail content.
Electron:
- `electron-store` v11 is ESM-only. Use `initializeStore()` before modules that read `store`, then access `store` through the proxy exported from `electron/electron-store.js`.
- `electron-context-menu` v4 is ESM-only. Import dynamically in `app.whenReady()`.
- Do not reintroduce circular imports from `electron/main-src.js` into IPC modules. IPC modules should use `BrowserWindow.fromWebContents(event.sender)` or `BrowserWindow.getAllWindows()` where needed.
- Sentry main uses `ipcMode: Sentry.IPCMode.Protocol`; keep this unless deliberately changing Sentry IPC behavior.
- DevTools are enabled in dev and auto-open by default. Set `ELECTRON_OPEN_DEVTOOLS=0` to suppress auto-open. In packaged builds DevTools are opt-in via `ELECTRON_ENABLE_DEVTOOLS=1` and auto-open via `ELECTRON_OPEN_DEVTOOLS=1`.
- React DevTools extension install is opt-in with `ELECTRON_INSTALL_REACT_DEVTOOLS=1`. It can trigger Chromium DevTools protocol noise.
GraphQL/Apollo:
- Default Apollo query/watchQuery fetch policy is `network-only`; do not assume Apollo cache is the source of truth.
- Apollo cache has custom offset merge functions for `Query.jobs` and `Query.search_jobs` to avoid cache replacement warnings during pagination.
- Firebase current user token is attached as `Authorization: Bearer <token>` through `authLink`.
## Recent Maintenance Context
Recent warning/deprecation cleanup included:
- AntD v5 deprecations fixed for Collapse, Dropdown, RangePicker, Table rowKey, and static message/notification usage.
- Redux `createStore` deprecation warning avoided with `legacy_createStore`.
- Apollo cache warning fixed with field policies for `jobs` and `search_jobs`.
- Job detail left-panel flash reduced by debouncing selected job id and using a skeleton.
- Electron circular dependency warnings removed by avoiding `mainWindow` export/import.
- Electron Sentry preload deprecation path avoided with protocol IPC mode.
- Electron package upgrades completed for `electron`, `electron-builder`, `electron-context-menu`, `electron-is-dev`, `electron-store`, and `@sentry/electron`.
- `dist-electron/` is ignored and should remain generated only.
## Verification Expectations
For most renderer/main changes:
```powershell
npm run build
npm run build:electron
```
For Electron package or builder changes:
```powershell
npm run pack
```
Remember: `npm run pack` is configured to avoid publishing. It may still perform local signing of the unpacked executable.
For AntD deprecation checks, if `antd-style` tooling is available:
```powershell
npx antd-style-cli lint src --only deprecated
```
If a command is unavailable, report that clearly and run the nearest reliable build/check instead.
## More Context
- `.ai/project-overview.md`: product/domain summary.
- `.ai/architecture.md`: process, renderer, state, and data architecture.
- `.ai/electron-main.md`: Electron-specific lifecycle, packaging, IPC, and upgrade notes.
- `.ai/frontend.md`: React/AntD/Redux conventions and common UI pitfalls.
- `.ai/data-graphql-hasura.md`: GraphQL, Hasura, auth, cache, and schema notes.
- `.ai/workflows.md`: development, packaging, release, and troubleshooting workflows.
- `.ai/recent-changes.md`: migration and warning cleanup history.
- `.ai/file-map.md`: important files and directories by responsibility.
- `.ai/domain-glossary.md`: project/domain terms used across code and UI.
- `.github/copilot-instructions.md`, `CLAUDE.md`, and `GEMINI.md` all point agents back to this guide.

26
AI_CONTEXT.md Normal file
View File

@@ -0,0 +1,26 @@
# AI Context Index
This is the root index for AI/code-agent context in ImEX RPS. Start with `AGENTS.md`; use the `.ai/` files for deeper context.
## Read Order
1. `AGENTS.md`
2. `.ai/project-overview.md`
3. `.ai/architecture.md`
4. `.ai/workflows.md`
5. Task-specific files:
- `.ai/frontend.md` for React, AntD, Redux, and UI work.
- `.ai/electron-main.md` for Electron main/preload/IPC/packaging work.
- `.ai/data-graphql-hasura.md` for GraphQL, Apollo, Hasura, Firebase auth, schema, and migrations.
- `.ai/recent-changes.md` for current deprecation cleanup and package migration context.
- `.ai/file-map.md` for locating important code quickly.
- `.ai/domain-glossary.md` for domain terms and abbreviations.
## High-Signal Rules
- Use npm scripts. The old README still mentions yarn/Create React App.
- Do not publish unless explicitly asked. `npm run pack` is the safe local packaging check.
- Do not edit generated `build/`, `dist/`, or `dist-electron/`.
- Keep Electron main/renderer separation clean.
- Use AntD v5 APIs and `src/util/antdFeedback.js` for global message/notification calls.
- Treat local certs, deployment scripts, Sentry DSNs, Firebase config, and AWS notes as sensitive.

17
CLAUDE.md Normal file
View File

@@ -0,0 +1,17 @@
# Claude Instructions
Start with `AGENTS.md`. It is the canonical guide for this repository.
Additional context lives in `.ai/`:
- `.ai/project-overview.md`
- `.ai/architecture.md`
- `.ai/frontend.md`
- `.ai/electron-main.md`
- `.ai/data-graphql-hasura.md`
- `.ai/workflows.md`
- `.ai/recent-changes.md`
- `.ai/file-map.md`
- `.ai/domain-glossary.md`
Do not publish releases unless the user explicitly asks. Use `npm run pack` for local packaging checks.

17
GEMINI.md Normal file
View File

@@ -0,0 +1,17 @@
# Gemini Instructions
Start with `AGENTS.md`. It is the canonical guide for this repository.
Additional context lives in `.ai/`:
- `.ai/project-overview.md`
- `.ai/architecture.md`
- `.ai/frontend.md`
- `.ai/electron-main.md`
- `.ai/data-graphql-hasura.md`
- `.ai/workflows.md`
- `.ai/recent-changes.md`
- `.ai/file-map.md`
- `.ai/domain-glossary.md`
Do not publish releases unless the user explicitly asks. Use `npm run pack` for local packaging checks.

View File

@@ -8,7 +8,8 @@ const Sentry = require("@sentry/electron/main");
const isDev = !app.isPackaged;
const enableDevTools = isDev || process.env.ELECTRON_ENABLE_DEVTOOLS === "1";
const openDevToolsOnStart = enableDevTools && process.env.ELECTRON_OPEN_DEVTOOLS === "1";
const openDevToolsOnStart =
enableDevTools && (isDev ? process.env.ELECTRON_OPEN_DEVTOOLS !== "0" : process.env.ELECTRON_OPEN_DEVTOOLS === "1");
const installReactDevTools = process.env.ELECTRON_INSTALL_REACT_DEVTOOLS === "1";
//const Nucleus = require("nucleus-nodejs");
@@ -209,8 +210,8 @@ function createWindow() {
app.quit();
});
// Open DevTools only when explicitly requested. DevTools itself emits
// Chromium protocol noise such as Autofill.* messages in Electron.
// Auto-open DevTools in dev. DevTools itself can emit Chromium protocol
// noise such as Autofill.* messages in Electron.
if (openDevToolsOnStart) {
mainWindow.webContents.openDevTools({
// mode: "detach"