Skip to content

feat: add setup wizard with CSV import and @wareflow/db package#10

Merged
AliiiBenn merged 13 commits intomainfrom
feature/import-csv-excel
Feb 26, 2026
Merged

feat: add setup wizard with CSV import and @wareflow/db package#10
AliiiBenn merged 13 commits intomainfrom
feature/import-csv-excel

Conversation

@AliiiBenn
Copy link
Member

Summary

  • Update electron-vite to v5.0.0 for vite 7.x compatibility
  • Add tailwindcss support to desktop renderer config
  • Add dev:web, dev:desktop, dev:all scripts at root level
  • Configure both apps to use 127.0.0.1:3000
  • Add PR review GitHub Actions workflow

Test plan

  • Run pnpm dev:all and verify both web and desktop apps start
  • Verify Tailwind CSS works in desktop app
  • Check that PR review workflow is properly configured

🤖 Generated with Claude Code

AliiiBenn and others added 4 commits February 26, 2026 09:52
- Update electron-vite to v5.0.0 for vite 7.x compatibility
- Add tailwindcss support to desktop renderer config
- Add dev:web, dev:desktop, dev:all scripts at root
- Configure both apps to use 127.0.0.1:3000

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create /setup route with 5-step wizard
- Add FileSelection component (drag & drop)
- Add Preview component (data preview table)
- Add ColumnMapping component (column mapping UI)
- Add Validation component (error/warning display)
- Add Complete component (success screen)
- Add types for import process

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@@ -23,13 +25,21 @@ export default defineConfig({
}
},
renderer: {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The root change from ../web/dist to ../web is correct for development mode, but ensure production builds still work correctly since dist is the output directory.

return
}

// Simple CSV parsing for now
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The simple CSV parsing here won't handle quoted values containing commas correctly (e.g., "Doe, John", 25). Consider using a proper CSV parser library like papaparse for robust handling.

import { Button } from '../ui/button'

const MAX_FILE_SIZE = 10 * 1024 * 1024 // 10MB
const ACCEPTED_TYPES = ['.csv', '.xlsx']
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The component accepts .xlsx files in the UI but only performs simple CSV parsing via file.text(). XLSX files will not parse correctly. Either add xlsx parsing library or remove .xlsx from accepted types.

}
}, [step])

const handleImport = useCallback(() => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a stub implementation. The TODO should be addressed before merging - actual database/dexie integration is needed for the import to work.

private-key: ${{ secrets.MARTY_APP_PRIVATE_KEY }}

- name: Run Marty PR Review
uses: nesalia-inc/marty-action@1.0.0
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a third-party action from nesalia-inc/marty-action. Ensure this is a trusted action and consider pinning to a specific version tag (e.g., @v1.0.0) instead of a floating tag to prevent unexpected changes.

},
renderer: {
root: resolve(__dirname, '../web/dist'),
root: resolve(__dirname, '../web'),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a positive change - pointing to the source directory instead of dist allows the desktop app to use the web app's Vite dev server with HMR.

@marty-action
Copy link

marty-action bot commented Feb 26, 2026

@@ -0,0 +1,14 @@

Review Summary

Summary: This PR updates electron-vite to v5.0.0, adds TailwindCSS support to desktop, introduces dev:all scripts, and adds a setup wizard for product imports along with a PR review GitHub Actions workflow.

Critical Issues:

  1. XLSX parsing not implemented (apps/web/src/components/setup/file-selection.tsx:6): The component accepts .xlsx files but only performs CSV parsing - xlsx files will fail to parse correctly
  2. Stub implementation (apps/web/src/routes/setup.tsx:58): The handleImport function is a stub that does not actually save data - marked with TODO comment

Recommendations:

  1. Pin the GitHub Action to a specific version tag (nesalia-inc/marty-action@v1.0.0) instead of floating tag to prevent unexpected changes
  2. Consider using a proper CSV parser library (e.g., papaparse) instead of simple string splitting to handle quoted values with commas
  3. Add the dev:all script to the PR description test plan

Positive Notes:

  • Good separation of concerns with 5 distinct setup wizard components
  • Proper validation with error/warning tracking in the validation step
  • Auto-detection of column mappings is a useful feature
  • Progress indicator provides good UX
  • Dark mode support implemented throughout
  • Both web and desktop now configured to use consistent 127.0.0.1:3000

@@ -1,5 +1,7 @@
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The externalizeDepsPlugin is correctly imported from 'electron-vite' which is the correct import path for version 5.0.0. The configuration looks compatible with electron-vite 5.x.

}
},
server: {
host: '127.0.0.1',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both apps are configured to use port 3000. When running dev:all, both the web app and desktop renderer will try to bind to the same port, causing a conflict. Consider assigning different ports (e.g., web on 3000, desktop renderer on 3001) or using the web app's server for the desktop renderer.

@marty-action
Copy link

marty-action bot commented Feb 26, 2026

Summary

The PR successfully adds the dev:all script and updates electron-vite to v5.0.0 for Vite 7.x compatibility. The implementation is straightforward and follows the existing project patterns.

Critical Issues

Port Conflict (apps/desktop/electron.vite.config.ts:41): Both the web app and desktop renderer are configured to use port 3000. Running pnpm dev:all will cause a port conflict since both apps will try to bind to the same port. Consider:

  • Using different ports (e.g., web: 3000, desktop: 3001)
  • Or configuring the desktop renderer to use the web app's dev server

Recommendations

  1. Test the dev:all script: Verify that both apps start without port conflicts
  2. Update package.json description: The web app's index.html has <title>web</title> - consider a more descriptive title like "Wareflow"

Positive Notes

  • The electron-vite 5.0.0 upgrade is properly configured with compatible dependencies
  • The turbo configuration correctly handles the new dev scripts with `persistent: true"
  • The desktop renderer correctly reuses the web app's source files via the root configuration
  • Tailwind CSS v4 is properly integrated into both apps using @tailwindcss/vite

- Add Geist fonts (sans + mono)
- Add color-scheme and theme-color meta for dark mode
- Improve accessibility: aria-label, focus-visible, keyboard handlers
- Add aria-live for error messages
- Replace input with proper label

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
"dev": "turbo dev",
"dev:web": "turbo dev --filter=web",
"dev:desktop": "turbo dev --filter=desktop",
"dev:all": "turbo run dev --filter=web --filter=desktop",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security Concern: The dev:all script uses turbo run dev but this will run both apps in parallel without waiting for dependencies to be ready. Also, there's no explicit port conflict handling if both apps try to use the same port.

The desktop app renderer is configured to point to the web app (root: resolve(__dirname, '../web')), but the web app runs on port 3000. This could cause issues during parallel development.

@@ -23,13 +25,21 @@ export default defineConfig({
}
},
renderer: {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security Issue: The desktop renderer is sharing the same index.html from the web app. This means the desktop app will load the web app's HTML which includes the same CSP policy. However, the desktop app needs to load the actual desktop renderer entry point (/src/main.tsx), not the web app's entry. This configuration could cause the desktop app to fail to load properly or bypass security policies intended for the web app.

],
build: {
rollupOptions: {
input: {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue: The desktop renderer configuration uses the web app's root and index.html, but the desktop renderer should have its own entry point. Currently, both web and desktop will share the same renderer, which may not be the intended behavior for a desktop application.

Recommendation: Consider creating a separate renderer entry point for the desktop app (e.g., apps/desktop/src/renderer/) or ensure this is intentional for your architecture.

tanstackRouter({ target: 'react', autoCodeSplitting: true }),
viteReact(),
],
server: {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Port Configuration: Both web and desktop apps are configured to use port 3000. When running dev:all, there's no conflict handling. The desktop app renderer is configured to load from the web app's dev server at port 3000, but this requires the web app to start first.

Recommendation: Consider using different ports or adding a startup delay/await mechanism in the dev:all script to ensure the web app starts before the desktop app tries to connect.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@marty-action
Copy link

marty-action bot commented Feb 26, 2026

Summary

This PR updates electron-vite to v5.0.0 for Vite 7.x compatibility, adds Tailwind CSS support to the desktop renderer, and introduces new development scripts (dev:web, dev:desktop, dev:all) at the root level. It also adds a PR review GitHub Actions workflow.

Critical Issues

  1. Port Conflict Risk: Both web and desktop apps are configured to use port 3000. The dev:all script runs both apps in parallel without any coordination, which may cause the desktop app to fail connecting to the web dev server.

  2. Desktop Renderer Configuration: The desktop app's renderer is configured to use the web app's root directory (../web) and index.html. This means the desktop app loads the web app directly rather than having its own renderer entry point. This may cause issues:

    • The desktop app inherits the web app's Content Security Policy which may not be appropriate
    • No clear separation between desktop and web functionality
    • The desktop app may not work offline

Recommendations

  1. Improve dev:all script: Consider adding a startup delay or using a tool like wait-on to ensure the web app starts before the desktop app attempts to connect

  2. Separate Desktop Renderer: Create a dedicated desktop renderer entry point at apps/desktop/src/renderer/ instead of sharing the web app's files

  3. Add Error Handling: The preload script catches errors but only logs them to console. Consider adding proper error handling for production

  4. CSP Policy: Review the Content Security Policy in apps/desktop/src/renderer/index.html - it may need adjustments for the desktop context

Positive Notes

  • Good use of turbo for monorepo management
  • Proper use of electron-vite with externalizeDepsPlugin for main/preload
  • electron-builder configuration is well-structured with proper build targets
  • Added PR review workflow for automated code review
  • Version upgrades are appropriate (electron-vite 5.0.0, Tailwind CSS 4.x)

return
}

const headers = lines[0].split(',').map(h => h.trim().replace(/"/g, ''))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CSV parsing here is simplified and doesn't handle quoted fields containing commas (e.g., "Smith, John",30,New York). Consider using a proper CSV parsing library like papaparse for robust handling.

import { useCallback, useState } from 'react'
import { Upload, FileSpreadsheet, AlertCircle } from 'lucide-react'

const MAX_FILE_SIZE = 10 * 1024 * 1024 // 10MB
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The component accepts .xlsx files (line 5) but the implementation only parses CSV text. There's no actual .xlsx parsing logic - this will cause errors for Excel files. Either remove .xlsx from ACCEPTED_TYPES or implement proper Excel parsing.

private-key: ${{ secrets.MARTY_APP_PRIVATE_KEY }}

- name: Run Marty PR Review
uses: nesalia-inc/marty-action@1.0.0
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For security, third-party actions should be pinned to a specific commit SHA rather than a version tag. This prevents potential supply chain attacks if the version tag is redirected. Consider using nesalia-inc/marty-action@a0b1c2d... (replace with actual commit SHA).

const quantity = row[quantityField]
const numQuantity = parseFloat(quantity)

if (!quantity || quantity.trim() === '') {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a discrepancy: IMPORT_FIELDS in types/setup.ts marks quantity as required: true, but the validation logic here (line 52 comment) treats it as optional. Either update the type definition or the validation logic to be consistent.

}, [step])

const handleImport = useCallback(() => {
// TODO: Connect to Dexie/Backend here
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a placeholder - the actual import to Dexie/backend needs to be implemented. Consider adding a tracking issue or TODO comment to ensure this gets implemented before release.

@marty-action
Copy link

marty-action bot commented Feb 26, 2026

Summary

This PR adds several enhancements: updates electron-vite to v5.0.0 for Vite 7.x compatibility, adds Tailwind CSS support to the desktop renderer, introduces dev scripts (dev:web, dev:desktop, dev:all), configures both apps to use 127.0.0.1:3000, adds a PR review GitHub Actions workflow, and implements a complete 5-step setup wizard for data import.

Critical Issues

  1. Incomplete .xlsx Support (file-selection.tsx:4-5): The component accepts .xlsx files but only implements CSV parsing. Excel files will fail to parse correctly.
  2. Simplified CSV Parsing (file-selection.tsx:37-44): The regex-based CSV parser doesn't handle quoted fields containing commas, which is a standard CSV feature.
  3. Inconsistent Required Field (validation.tsx:51-52): quantity is marked as required in IMPORT_FIELDS but treated as optional in validation logic.

Recommendations

  1. Use a proper CSV parsing library like papaparse for robust CSV handling
  2. Either implement proper .xlsx parsing or remove it from accepted file types
  3. Align the quantity field requirement between type definitions and validation logic
  4. Pin the third-party GitHub action to a specific commit SHA for security (nesalia-inc/marty-action@<sha>)
  5. Consider adding a loading state during file parsing for large files
  6. The handleImport function needs actual backend/Dexie integration before release

Positive Notes

  • Good accessibility implementation with aria-labels, keyboard handlers, and focus states
  • Proper state management with useCallback for event handlers
  • Clean component separation with distinct steps (File → Preview → Mapping → Validate → Complete)
  • Auto-detection of column mappings with fallback matching
  • Comprehensive validation with both errors and warnings
  • Dark mode support throughout the UI
  • Well-structured TypeScript types in types/setup.ts

- Create packages/db with schema and utilities
- Add isSetupRequired, importProducts, resetApp functions
- Update web app to use shared package
- Connect import wizard to Dexie backend

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@marty-action
Copy link

marty-action bot commented Feb 26, 2026

Summary

This PR updates electron-vite to v5.0.0 for Vite 7.x compatibility, adds TailwindCSS support to the desktop renderer, introduces new dev scripts (dev:web, dev:desktop, dev:all), configures both apps to use 127.0.0.1:3000, and adds a PR review GitHub Actions workflow.

Critical Issues

None identified.

Recommendations

  1. Workflow timeout: Consider adding a timeout to the PR review workflow to prevent hanging runs:

    timeout-minutes: 15
  2. Permissions scope: The id-token: write permission (line 10) may be overly broad for this workflow. Consider if it's truly needed.

  3. External action pinning: The workflow uses nesalia-inc/marty-action@1.0.0. Verify this is a trusted action and consider pinning to a specific commit hash instead of a version tag for better security.

  4. Tool permission syntax: The claude_args (line 87-88) uses Bash(gh pr comment:*) which may not be correctly parsed. Consider verifying the exact syntax required by Marty.

Positive Notes

  • The electron-vite upgrade follows proper dependency management practices
  • TailwindCSS integration is correctly configured in the desktop electron-vite config
  • The dev:all script properly uses turbo run dev to run both web and desktop apps concurrently
  • Server configurations are consistent (127.0.0.1:3000) across both apps, ensuring the desktop app can load the web app properly
  • The workflow includes proper triggers (opened, synchronize, ready_for_review, reopened) for comprehensive PR review coverage
  • The workflow follows security best practices by using a GitHub App token instead of a personal access token

@AliiiBenn AliiiBenn changed the title feat: update electron-vite and add dev:all script feat: add setup wizard with CSV import and @wareflow/db package Feb 26, 2026
const errors: ValidationError[] = []
const warnings: ValidationWarning[] = []

const skuField = columnMapping.sku
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue: Missing check for unmapped required fields

The validation runs but doesn't check if required fields (sku, name, quantity) are actually mapped. The component will run validation even if columnMapping.sku is undefined, leading to confusing error messages.

let warehouse = await db.warehouses.toCollection().first()
if (!warehouse) {
const warehouseId = await db.warehouses.add({
name: 'Main Warehouse',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue: Hardcoded warehouse name

"Main Warehouse" is hardcoded. Consider allowing users to configure the warehouse name during setup or at least making it configurable.


export type ParsedData = Record<string, string>

export type ColumnMapping = Partial<Record<ImportField['key'], string>>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue: Type safety - ColumnMapping should not be Partial

ColumnMapping is defined as Partial<Record<...>> but required fields must be mapped. This type doesn't enforce that required fields are actually mapped, leading to potential runtime errors.

updatedAt: new Date()
}))

await db.products.bulkAdd(products)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue: No try-catch around bulkAdd

If bulkAdd throws (e.g., due to duplicate keys or database errors), the error is not caught. Consider wrapping in try-catch for better error handling.

return
}

Papa.parse(file, {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue: PapaParse runs synchronously in browser

For large files, this could block the UI. Consider using PapaParse worker mode or chunking for better performance.

@marty-action
Copy link

marty-action bot commented Feb 26, 2026

Review: This PR looks good overall but has some issues to address.

@marty-action
Copy link

marty-action bot commented Feb 26, 2026

Summary

This PR introduces a setup wizard for CSV product import and creates a new @wareflow/db package using Dexie. The implementation includes file selection, preview, column mapping, validation, and import completion steps.

Critical Issues

  1. Duplicate SKU handling: Validation warns about duplicate SKUs but bulkAdd() will throw on duplicates - the import will fail without clear error message
  2. Missing required field mapping check: Validation runs even when required fields aren't mapped, leading to confusing error messages
  3. No error handling in database operations: bulkAdd() call can throw but isn't wrapped in try-catch

Recommendations

  1. Add a check at the start of validation to verify required fields are mapped before validating data
  2. Use bulkPut() instead of bulkAdd() or handle duplicates explicitly
  3. Add input validation for SKU length and allowed characters
  4. Make warehouse name configurable instead of hardcoding
  5. Consider using PapaParse worker mode for better UI responsiveness with large files
  6. Add TypeScript strict typing - ColumnMapping shouldn't be Partial

Positive Notes

  • Good UX with multi-step wizard flow
  • Proper file type and size validation
  • Good accessibility with ARIA attributes
  • Auto-detection of column mappings works well
  • Clean separation of concerns between components

- Add check for required field mappings before validating data
- Use bulkPut instead of bulkAdd to handle duplicates
- Add try-catch with proper error messages for DB operations
- Show mapping errors in validation step

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
}

// Get or create sector
const sectorName = data[0]?.[mapping.sector] || 'Default'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sector is determined only from the first row of data (data[0]?.[mapping.sector]). All products will be imported into a single sector regardless of their sector field values in the CSV. Consider processing unique sectors from all rows.


try {
// Use bulkPut to handle duplicates (update existing or add new)
await db.products.bulkPut(products)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate SKUs trigger a warning but the import proceeds with bulkPut, which overwrites existing records. Consider either blocking the import when duplicates exist or making this behavior explicit to users.

@@ -0,0 +1,85 @@
import Dexie from 'dexie'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No tests exist for this feature. Consider adding unit tests for CSV parsing, validation logic, and database import functions.

return
}

const ext = file.name.substring(file.name.lastIndexOf('.')).toLowerCase()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good file validation with size and type checks. Consider also validating the file content (magic bytes) in addition to extension to prevent MIME type spoofing attacks.

<ArrowLeft className="w-4 h-4 mr-2" />
Back
</Button>
<Button onClick={onImport} disabled={errorCount > 0 || isImporting}>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider disabling the import button when there are warnings in addition to errors, or make the overwrite behavior explicit to users to prevent unexpected data loss.

@marty-action
Copy link

marty-action bot commented Feb 26, 2026

Summary

Overall, this is a well-implemented feature that adds a setup wizard with CSV import functionality and a new @wareflow/db package using Dexie for IndexedDB storage. The code follows React best practices and provides a good user experience.

Critical Issues

  1. Sector handling limitation (packages/db/src/utils.ts:42): The sector is determined only from the first row of data. All products will be imported into a single sector regardless of their sector field values in the CSV.

  2. Missing SKU uniqueness enforcement: The validation component shows warnings for duplicate SKUs but the import proceeds with bulkPut which overwrites existing records. This could lead to unexpected data loss.

  3. No input sanitization for string fields: String fields like SKU, name, description are directly inserted without sanitization.

Recommendations

  1. Add test coverage: No tests exist for this feature. Consider adding unit tests for CSV parsing, validation logic, and database import functions.

  2. Add error boundary: Consider wrapping the setup wizard in an error boundary to handle unexpected runtime errors.

  3. Add progress for large imports: Database operations don't show progress for large imports. Consider batch processing with progress indicators.

  4. Improve column mapping auto-detection: Could handle more variations like synonyms (e.g., "prod" -> "product").

Positive Notes

  1. Good UX: Multi-step wizard with progress indicator, preview, and validation steps
  2. Accessibility: Proper ARIA attributes, keyboard navigation support
  3. Error handling: Comprehensive validation with clear error/warning messages
  4. Code organization: Clean separation of concerns between components
  5. Type safety: Good use of TypeScript types throughout
  6. Security: No hardcoded secrets, file type validation, size limits
  7. Dexie schema: Properly defined indexes for efficient queries

AliiiBenn and others added 2 commits February 26, 2026 12:56
- Add gradient background
- Improve progress indicator with better visual hierarchy
- Enhance file selection with better icons and animations
- Add help text for expected CSV columns

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@marty-action
Copy link

marty-action bot commented Feb 26, 2026

Summary

This PR introduces several significant features:

  1. New @wareflow/db package: A local-first database layer using Dexie (IndexedDB wrapper) with schemas for warehouses, sectors, zones, and products
  2. Setup Wizard with CSV Import: A multi-step wizard component for importing product data from CSV files, including file selection, column mapping, data preview, validation, and completion
  3. Desktop App Enhancements: Updated electron-vite to v5.0.0, added Tailwind CSS support for desktop renderer
  4. Dev Scripts: Added dev:web, dev:desktop, and dev:all scripts at root level
  5. GitHub Actions Workflow: Added PR review workflow using Marty AI

Critical Issues

1. Missing TypeScript Types for @wareflow/db Package

packages/db/src/db.ts:1-67

The db package exports TypeScript types but lacks proper type definitions. The types field in package.json points to the source file rather than generated types:

"types": "./src/index.ts"

This should be generated from a proper .d.ts file or the package should export interfaces separately.

2. Bulk Import Without Transaction Support

packages/db/src/utils.ts:70-77

The bulk import uses bulkPut but should be wrapped in a Dexie transaction to ensure atomicity:

await db.transaction('rw', db.products, async () => {
  await db.products.bulkPut(products)
})

Currently, if there's a partial failure, data could be in an inconsistent state.

3. Security - No Input Sanitization on CSV Data

apps/web/src/components/setup/file-selection.tsx:30-58

The CSV parsing doesn't sanitize input data before storing. Malicious CSV files could contain scripts or other potentially harmful content. Consider sanitizing string fields.

4. Missing Error Boundary for Setup Wizard

The setup wizard components don't have error boundaries. If parsing fails or an error occurs mid-flow, the entire app could crash.

Recommendations

1. Add Tests

No test files were found in the codebase. Add tests for:

  • CSV parsing and validation logic
  • Database operations (import, reset)
  • Component rendering with React Testing Library

2. Add Loading States

apps/web/src/components/setup/validation.tsx:215-218

The import button shows a loading state, but the actual import function should also handle:

  • Progress indication for large files
  • Cancellation support

3. Improve Column Mapping Auto-Detection

apps/web/src/components/setup/column-mapping.tsx:25-52

The auto-detection logic could be improved:

  • Current implementation only looks at first row
  • Consider using fuzzy matching with more lenient algorithms
  • Add ability to save/load mapping templates

4. File Size Limit Warning

apps/web/src/components/setup/file-selection.tsx:19-22

Current implementation silently rejects files > 10MB. Consider showing a warning before the user selects a file.

5. Missing Database Version Migration Strategy

packages/db/src/db.ts:58-64

The database schema has version 1, but there's no migration strategy for future schema changes. Add migration callbacks for version upgrades.

Positive Notes

  • Excellent user experience in the setup wizard with clear step-by-step flow
  • Good accessibility practices (ARIA labels, keyboard navigation, screen reader support)
  • Proper TypeScript usage throughout
  • Clean component separation and structure
  • Good error messages in validation
  • Auto-detection of column mappings saves user time
  • Proper use of React hooks (useCallback, useMemo) for performance
  • The monorepo structure is well-organized with workspace dependencies
  • Desktop app configuration properly separates main, preload, and renderer processes

"private": true,
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The types field should point to a proper .d.ts file rather than the source. Consider generating types with tsc --declaration or export interfaces separately for better type safety.


try {
// Use bulkPut to handle duplicates (update existing or add new)
await db.products.bulkPut(products)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bulk import should be wrapped in a Dexie transaction (db.transaction('rw', db.products, async () => {...})) to ensure atomicity. If there's a partial failure, data could be left in an inconsistent state.

}

export function Validation({ data, columnMapping, onBack, onImport, isImporting = false, error }: ValidationProps) {
const validation = useMemo((): ValidationResult => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The validation logic runs on every render due to missing data in the dependency array. This could cause performance issues with large datasets. Consider using useMemo with proper memoization or moving validation to a separate function that's called on demand.


constructor() {
super('wareflow')
this.version(1).stores({
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no migration strategy for future schema changes. Add .upgrade() callbacks for version upgrades to handle schema migrations properly when the database version increments.

sector = { id: sectorId, warehouseId: warehouse.id!, name: sectorName, createdAt: new Date(), updatedAt: new Date() }
}

const products: Omit<Product, 'id'>[] = data.map(row => ({
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No tests found in the codebase. Consider adding tests for:

  • CSV parsing and validation logic (Papa.parse results)
  • Database operations (import, reset)
  • Component rendering with React Testing Library

This is especially important for data validation logic which is critical for data integrity.

}: ColumnMappingProps) {
const sampleData = useMemo(() => data.slice(0, 3), [data])

const autoDetectMapping = useMemo(() => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The auto-detection only examines the first row of data. Consider sampling multiple rows (e.g., first 5) to improve detection accuracy, especially if the first row might have empty values or unusual formatting.

updatedAt: new Date()
}))

try {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding error handling for failed bulkPut operations that might fail partially. Currently if some products fail to import, the entire operation may not provide clear feedback about which specific products failed.

const sku = row[skuField]
if (!sku || sku.trim() === '') {
errors.push({ row: rowNum, field: 'sku', message: 'SKU is required' })
} else if (seenSkus.has(sku)) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The duplicate SKU check adds a warning but the import still proceeds with bulkPut. This could lead to duplicate products in the database if the same SKU exists in the CSV. Consider either blocking duplicates or providing a clear option to handle them.

import Dexie from 'dexie'
import { db, type Warehouse, type Sector, type Product } from './db'

export type ParsedData = Record<string, string>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This type definition duplicates ParsedData from apps/web/src/types/setup.ts. Consider exporting the type from the shared @wareflow/db package or using a single source of truth to avoid type duplication.

}

// Get or create sector
const sectorName = data[0]?.[mapping.sector] || 'Default'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, only one sector is created/retrieved based on the first row's sector value. If the CSV contains products from multiple sectors, they'll all be assigned to the same sector. Consider creating multiple sectors or allowing the user to select a default sector during import.

errors?: string[]
}

export const isSetupRequired = async (): Promise<boolean> => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function checks if there are any products, but the setup wizard creates a default warehouse and sector. Consider also checking if warehouses exist to determine if setup is truly required.

@marty-action
Copy link

marty-action bot commented Feb 26, 2026

Summary

This PR introduces a comprehensive setup wizard for CSV product import and creates a new @wareflow/db package using Dexie for IndexedDB persistence. The implementation includes file selection, column mapping with auto-detection, data validation, and a complete import flow. Additionally, it updates electron-vite to v5.0.0, adds Tailwind CSS to the desktop app, and adds a PR review GitHub Actions workflow.

Critical Issues

  1. Duplicate SKU handling (apps/web/src/components/setup/validation.tsx:48-52): The validation detects duplicate SKUs but only issues a warning. The import still proceeds, which could lead to duplicate products in the database since bulkPut will create new entries for duplicates.

  2. Single sector assumption (packages/db/src/utils.ts:42-52): The import logic only creates/retrieves one sector based on the first row. Products from multiple sectors in the CSV will all be assigned to the same sector.

  3. Incomplete import error handling (packages/db/src/utils.ts:70-77): The bulkPut operation doesn't provide granular error feedback - if some products fail to import, users won't know which specific rows had issues.

Recommendations

  1. Type duplication: The ParsedData and ColumnMapping types are duplicated in packages/db/src/utils.ts and apps/web/src/types/setup.ts. Consider exporting these from the shared @wareflow/db package.

  2. Setup detection logic (packages/db/src/utils.ts:12-15): The isSetupRequired function only checks product count. Consider also checking warehouse existence since the setup wizard creates a default warehouse.

  3. Missing zone mapping: The validation component includes a zone field in IMPORT_FIELDS, but the zone is never used in the import logic (packages/db/src/utils.ts:59).

  4. Consider adding transaction support: For large imports, wrapping the bulk operations in a transaction would provide better atomicity and rollback capability.

Positive Notes

  • Excellent user experience: The multi-step wizard with progress indicator, drag-and-drop file upload, and auto-detection of column mappings is well-designed.
  • Comprehensive validation: The validation step catches required field issues, empty values, numeric field validation, and duplicate detection.
  • Good React patterns: Proper use of useCallback, useMemo, and type safety with TypeScript.
  • Accessibility: Good use of ARIA attributes (role, aria-live, sr-only) and keyboard navigation support.
  • Clean component structure: Well-organized setup components with clear separation of concerns.
  • Configuration improvements: The updated electron-vite and unified port configuration (127.0.0.1:3000) for both web and desktop is a good improvement.

Review generated by Claude Code

@AliiiBenn AliiiBenn merged commit e3d9953 into main Feb 26, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant