diff --git a/.ai/architecture.md b/.ai/architecture.md new file mode 100644 index 0000000..64edcb8 --- /dev/null +++ b/.ai/architecture.md @@ -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 ``. +- `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. + diff --git a/.ai/data-graphql-hasura.md b/.ai/data-graphql-hasura.md new file mode 100644 index 0000000..b9b3e84 --- /dev/null +++ b/.ai/data-graphql-hasura.md @@ -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 `. +- `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. + diff --git a/.ai/domain-glossary.md b/.ai/domain-glossary.md new file mode 100644 index 0000000..49528c2 --- /dev/null +++ b/.ai/domain-glossary.md @@ -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. + diff --git a/.ai/electron-main.md b/.ai/electron-main.md new file mode 100644 index 0000000..8caafd7 --- /dev/null +++ b/.ai/electron-main.md @@ -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. + diff --git a/.ai/file-map.md b/.ai/file-map.md new file mode 100644 index 0000000..f48ed4a --- /dev/null +++ b/.ai/file-map.md @@ -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. + diff --git a/.ai/frontend.md b/.ai/frontend.md new file mode 100644 index 0000000..5f74ac5 --- /dev/null +++ b/.ai/frontend.md @@ -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. + diff --git a/.ai/project-overview.md b/.ai/project-overview.md new file mode 100644 index 0000000..bd24901 --- /dev/null +++ b/.ai/project-overview.md @@ -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. + diff --git a/.ai/recent-changes.md b/.ai/recent-changes.md new file mode 100644 index 0000000..21c0d06 --- /dev/null +++ b/.ai/recent-changes.md @@ -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 `` 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. + diff --git a/.ai/workflows.md b/.ai/workflows.md new file mode 100644 index 0000000..d874d45 --- /dev/null +++ b/.ai/workflows.md @@ -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 ``. + +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. + diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..f06750c --- /dev/null +++ b/.github/copilot-instructions.md @@ -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. + diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..799ce53 --- /dev/null +++ b/AGENTS.md @@ -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 ``. +- `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 ` 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. diff --git a/AI_CONTEXT.md b/AI_CONTEXT.md new file mode 100644 index 0000000..6418e8f --- /dev/null +++ b/AI_CONTEXT.md @@ -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. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..d699c10 --- /dev/null +++ b/CLAUDE.md @@ -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. diff --git a/GEMINI.md b/GEMINI.md new file mode 100644 index 0000000..daf7007 --- /dev/null +++ b/GEMINI.md @@ -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. diff --git a/electron/main-src.js b/electron/main-src.js index 06adaa0..edcb88d 100644 --- a/electron/main-src.js +++ b/electron/main-src.js @@ -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"