Skip to content

Performance: App takes 2 minutes to launch and crashes #166

@codewizdave

Description

@codewizdave

Problem Summary

The WEMS v2 Electron application suffers from severe performance issues at startup, crashes, memory leaks, security vulnerabilities, and numerous code quality problems. This is not production-ready.


🚨 CRITICAL ISSUES (Must Fix)

1. Startup Performance & Crashes

Issue #166 - App takes 2 minutes to launch and crashes

2. SECURITY: postMessage Wildcard Origin

File: src/preload/index.ts:76, 100

window.postMessage({ type: "main-ready" }, "*");
window.postMessage({ type: "orpc-port-ready" }, "*", [port]);

Problem: Using "*" as target origin allows ANY website to capture these messages.

3. CRITICAL Memory Leaks

Location Issue
src/core/ipc/manager.ts:41-49 window.addEventListener never removed
src/core/ipc/manager.ts:68-96 Polling setTimeout never stops
src/renderer/src/app.tsx:22-38 window.addEventListener never removed
src/main/index.ts:224-226 Lock watcher cleanup never called

4. DATABASE: Column Name Mismatch (CRITICAL)

File: src/core/db/schema/notes.ts:13

isCompleted: integer("isCompleted", { mode: "boolean" })

But migration 0004_notes.sql creates is_completed (snake_case).

5. DATABASE: N+1 Query Problem (CRITICAL)

File: src/core/ipc/database/handlers.ts:1692-1862

getAllDrivingAuthorizationStatuses() makes 1 + (N × 5) queries.
With 100 employees = 501 queries.


🔒 SECURITY ISSUES

Severity File Issue
CRITICAL src/preload/index.ts:76,100 postMessage with "*" origin
MODERATE src/preload/index.ts:58-77 ipcRenderer.on listeners never removed
HIGH src/main/index.ts:121-127 serverPort never closed on shutdown
MODERATE src/main/index.ts:255-258 Uncaught exception doesn't graceful shutdown

🗄️ DATABASE ISSUES

Severity Issue Location
CRITICAL Column mismatch isCompleted vs is_completed notes.ts:13 vs 0004_notes.sql
HIGH trainingProvider nullable mismatch online-trainings.ts:16 vs migration
HIGH N+1 queries (501 queries for 100 employees) handlers.ts:1692-1862
HIGH createEmployee manual rollback (not atomic) handlers.ts:367-379
MEDIUM Missing indexes on employee_id FKs Multiple schema files
MEDIUM Missing indexes on deleted_at Most soft-delete tables

⚡ OPTIMISTIC UPDATES ANALYSIS

Summary Table

Hook Optimistic Rollback Invalidation Temp ID Status
use-employees.ts
useCreateEmployee ⚠️ Partial Date.now() ⚠️
useUpdateEmployee ⚠️ Partial N/A ⚠️
useDeleteEmployee N/A
use-contracts.ts
useCreateContract BUG ⚠️ Partial Date.now()
useUpdateContract ⚠️ Partial N/A ⚠️
useDeleteContract ⚠️ Partial N/A ⚠️
use-caces.ts
useCreateCaces Date.now()
useUpdateCaces N/A
useDeleteCaces N/A
use-medical-visits.ts
useCreateMedicalVisit Date.now()
useUpdateMedicalVisit ⚠️ Partial N/A ⚠️
useDeleteMedicalVisit N/A
use-driving-authorizations.ts
useCreateDrivingAuthorization MISSING N/A N/A N/A
useUpdateDrivingAuthorization MISSING N/A N/A N/A
useDeleteDrivingAuthorization ⚠️ Partial N/A ⚠️
use-online-trainings.ts
useCreateOnlineTraining MISSING N/A N/A N/A
useUpdateOnlineTraining MISSING N/A N/A N/A
useDeleteOnlineTraining ⚠️ Partial N/A ⚠️
use-positions-worklocations.ts
useCreateDepartment ⚠️ Partial Date.now() ⚠️
useUpdateDepartment MISSING N/A N/A N/A
useDeleteDepartment ⚠️ Partial N/A ⚠️
useCreateContractType ⚠️ Partial Date.now() ⚠️
useUpdateContractType MISSING N/A N/A N/A
useDeleteContractType ⚠️ Partial N/A ⚠️
useCreatePosition ⚠️ Partial Date.now() ⚠️
useUpdatePosition MISSING N/A N/A N/A
useDeletePosition ⚠️ ⚠️ Partial N/A ⚠️
useCreateWorkLocation ⚠️ Partial Date.now() ⚠️
useUpdateWorkLocation MISSING N/A N/A N/A
useDeleteWorkLocation ⚠️ Partial N/A ⚠️
use-notes.ts
useCreateNote ⚠️ Partial Date.now() ⚠️
useUpdateNote ⚠️ Partial N/A ⚠️
useDeleteNote ⚠️ Partial N/A ⚠️
use-agencies.ts
useCreateAgency ⚠️ Partial Date.now() ⚠️
useUpdateAgency ⚠️ Partial N/A ⚠️
useDeleteAgency ⚠️ Partial N/A ⚠️
use-documents.ts
useCreateDocument ⚠️ Partial temp-${Date.now()} ⚠️
useUpdateDocument ⚠️ Partial N/A ⚠️
useDeleteDocument ⚠️ Partial N/A ⚠️

❌ CRITICAL BUG: useCreateContract Broken Rollback

File: src/renderer/src/hooks/use-contracts.ts:89-104

// onMutate saves BOTH queries:
const previousContracts = queryClient.getQueryData(queryKeys.contracts.lists());
const previousByEmployee = queryClient.getQueryData(
  queryKeys.contracts.byEmployee(newContract.employeeId)
);

// But onError ONLY restores the first:
if (context?.previousContracts) {
  queryClient.setQueryData(queryKeys.contracts.lists(), context.previousContracts);
}
// previousByEmployee is NEVER restored!

Impact: If contract creation fails, contracts.byEmployee cache is left in inconsistent state.

❌ MISSING Optimistic Updates (9 mutations)

Hook File Lines
useCreateDrivingAuthorization use-driving-authorizations.ts 29-56
useUpdateDrivingAuthorization use-driving-authorizations.ts 59-87
useCreateOnlineTraining use-online-trainings.ts 28-58
useUpdateOnlineTraining use-online-trainings.ts 60-90
useUpdateDepartment use-positions-worklocations.ts 72-89
useUpdateContractType use-positions-worklocations.ts 199-216
useUpdatePosition use-positions-worklocations.ts 333-349
useUpdateWorkLocation use-positions-worklocations.ts 490-508

⚠️ Partial Issues

Temp ID Collision Risk

Most create mutations use Date.now() which can collide on rapid creation:

id: Date.now(), // Can collide!

Better: crypto.randomUUID() or temp-${Date.now()}-${Math.random()}.

Missing Toast on Error

  • useUpdateContract:155 - No error toast
  • useDeleteContract:203 - No error toast
  • useDeleteDrivingAuthorization:113 - No description toast
  • useDeleteOnlineTraining:116 - No description toast

useDeletePosition Uses Wrong Pattern

File: use-positions-worklocations.ts:367-373

Instead of filtering out deleted items, it sets deletedAt:

// WRONG - shows "deleted" items in UI
old.map((p) => p.id === data.id ? { ...p, deletedAt: ... } : p)

Pattern Inconsistency

  • Pattern A (Single): Used in contracts, notes, onlineTrainings, drivingAuthorizations
  • Pattern B (Map): Used in employees, caces, medicalVisits, agencies, documents, positions

Pattern B is superior - captures ALL matching queries.

Missing Employee-Scoped Invalidation

Create/Delete for employee-tied entities don't invalidate byEmployee queries:

  • useCreateContract → should invalidate contracts.byEmployee(employeeId)
  • useCreateCaces → should invalidate caces.byEmployee(employeeId)
  • useCreateMedicalVisit → should invalidate medicalVisits.byEmployee(employeeId)
  • useCreateDrivingAuthorization → should invalidate drivingAuthorizations.byEmployee(employeeId)
  • useCreateOnlineTraining → should invalidate onlineTrainings.byEmployee(employeeId)

📝 CODE QUALITY ISSUES

TypeScript: 80+ Uses of any

File Lines Issue
actions/database.ts 221, 229, 270, 278 data: any parameters
pages/employees-page.tsx 37, 108, 112, 238 useState<any>, handleEditClick(employee: any)
pages/employee-detail-page.tsx 135, 140, 335, 438+ Multiple any in callbacks

React Anti-patterns: 12+ useEffect Missing Dependencies

File Line Issue
contracts-page.tsx 167-169 Empty deps array
EditEmployeeDialog.tsx 135-156 Missing contract in deps
app-sidebar.tsx 97-100 getAppVersion not in deps

useMemo Used as Side Effect (WRONG)

File: src/renderer/src/pages/caces-page.tsx:178-180

// WRONG - useMemo is for computed values, not side effects
useMemo(() => {
  setCurrentPage(1);
}, []);

State Management Bug: toggleNoteComplete

File: src/renderer/src/stores/notes-store.ts:37-42

toggleNoteComplete: (id) =>
  set((state) => ({
    notes: state.notes.map((note) =>
      note.id === id ? { ...note, badges: note.badges } : note  // BUG: doesn't change isCompleted!
    ),
  })),

🏗️ ARCHITECTURE ISSUES

File Size Issue
handlers.ts 108KB 60+ handlers in one file
database.ts (actions) 1046 lines 100+ functions
Page components 1500-2000+ lines Should be split
All mutation hooks Duplicated Should extract useOptimisticMutation
  • Double migration on startup
  • Hardcoded window dimensions (800x600)
  • No error boundary at app level

📊 TOTAL SUMMARY

Category Count Critical
Memory Leaks 4 🚨
Security Issues 4 🚨
Database Issues 6 🚨
Optimistic Update Bugs 1 🚨
Missing Optimistic Updates 9
TypeScript any 80+ ⚠️
useEffect Missing Deps 12+ ⚠️
Rollback/Invalidation Issues 20+ ⚠️

Total Issues: 140+


Environment

  • Electron: 40
  • Node: 25+
  • Platform: Windows 11 Enterprise
  • Build: electron-builder 26.7 with NSIS installer

Labels: bug, priority:critical, performance, tech-debt, security, database

Metadata

Metadata

Assignees

No one assigned

    Labels

    databaseIssues related to database configurationsecuritySecurity issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions