Skip to main content

Installation Guide

MotorDesk is a modern Progressive Web App built with React, TypeScript, and Vite. This guide will walk you through the complete setup process from development to production deployment.

Prerequisites

Before installing MotorDesk, ensure you have the following installed on your system:

Node.js

Version 18.x or higher recommended

Package Manager

npm, yarn, or pnpm

Git

For cloning the repository

Modern Browser

Chrome, Firefox, Safari, or Edge (latest versions)

System Requirements

  • RAM: Minimum 4GB (8GB recommended)
  • Disk Space: 500MB for dependencies
  • OS: Windows 10+, macOS 10.15+, or Linux (Ubuntu 20.04+)

Quick Start

1

Clone the Repository

Clone the MotorDesk source code to your local machine:
git clone <repository-url>
cd fleet-pwa
2

Install Dependencies

Choose your preferred package manager and install all dependencies:
npm install
3

Start Development Server

Launch the development server with hot module replacement:
npm run dev
The application will be available at http://localhost:5173
The development server includes Hot Module Replacement (HMR) for instant updates without full page reloads.

Project Structure

Understanding the project structure helps with configuration and customization:
fleet-pwa/
├── src/
│   ├── components/      # Reusable UI components
│   │   ├── auth/        # Authentication components
│   │   ├── customers/   # Customer management
│   │   ├── products/    # Product components
│   │   ├── sales/       # Sales/billing components
│   │   ├── vehicles/    # Fleet management
│   │   ├── layout/      # Layout components
│   │   └── ui/          # Base UI components
│   ├── pages/           # Route pages
│   │   ├── Home.tsx
│   │   ├── Vehicles.tsx
│   │   ├── Customers.tsx
│   │   ├── Products.tsx
│   │   ├── Sales.tsx
│   │   ├── Reports.tsx
│   │   ├── Settings.tsx
│   │   └── Login.tsx
│   ├── store/           # Redux state management
│   │   ├── index.ts     # Store configuration
│   │   ├── slices/      # Redux slices
│   │   └── rootSaga.ts  # Redux Saga
│   ├── hooks/           # Custom React hooks
│   ├── routes/          # Route configuration
│   ├── services/        # API services
│   ├── constants/       # App constants
│   ├── data/            # Mock/seed data
│   ├── styles/          # CSS modules
│   └── main.tsx         # Application entry point
├── public/              # Static assets
├── package.json         # Dependencies
├── vite.config.ts       # Vite configuration
├── tsconfig.json        # TypeScript config
└── index.html           # HTML template

Dependencies

Core Dependencies

The application relies on these key packages (from package.json): Framework & UI:
{
  "react": "^18.2.0",
  "react-dom": "^18.2.0",
  "react-router-dom": "^7.13.1",
  "lucide-react": "^0.575.0"
}
State Management:
{
  "@reduxjs/toolkit": "^2.11.2",
  "react-redux": "^9.2.0",
  "redux-persist": "^6.0.0",
  "redux-saga": "^1.4.2",
  "localforage": "^1.10.0"
}
PWA Support:
{
  "vite-plugin-pwa": "^1.2.0"
}

Development Dependencies

Build Tools:
{
  "vite": "^7.3.1",
  "@vitejs/plugin-react": "^5.1.1",
  "typescript": "^5.3.3"
}
Styling:
{
  "tailwindcss": "^4.2.1",
  "@tailwindcss/vite": "^4.2.1"
}
Code Quality:
{
  "eslint": "^9.39.1",
  "typescript-eslint": "^8.48.0",
  "eslint-plugin-react-hooks": "^7.0.1",
  "eslint-plugin-react-refresh": "^0.4.24"
}

Configuration

Environment Variables

Create a .env file in the project root for environment-specific configuration:
.env
# API Configuration
VITE_API_BASE_URL=https://api.yourcompany.com
VITE_SUNAT_API_URL=https://sunat-api.yourcompany.com

# External Services
VITE_DECOLECTA_API_KEY=your_api_key_here

# Application Settings
VITE_APP_NAME="MotorDesk Fleet Management"
VITE_DEFAULT_LOCALE=es-PE
VITE_DEFAULT_CURRENCY=PEN

# Feature Flags
VITE_ENABLE_OFFLINE_MODE=true
VITE_ENABLE_PWA=true
Never commit .env files to version control. Add them to .gitignore to protect sensitive credentials.

Vite Configuration

The application uses Vite for blazing-fast builds. Key configuration from vite.config.ts:
vite.config.ts
import { defineConfig } from "vite"
import react from "@vitejs/plugin-react"
import { VitePWA } from "vite-plugin-pwa"
import tailwindcss from "@tailwindcss/vite"
import path from "path"

export default defineConfig({
  plugins: [
    react(),
    tailwindcss(),
    VitePWA({
      registerType: "autoUpdate",
      includeAssets: ["favicon.ico", "apple-touch-icon.png", "mask-icon.svg"],
      manifest: {
        name: "Sistema de Gestión de Flotas SUNAT 2026",
        short_name: "FleetSUNAT",
        description: "Gestión logística y facturación electrónica offline-first",
        theme_color: "#ffffff",
        background_color: "#ffffff",
        display: "standalone",
        icons: [
          { src: "pwa-192x192.png", sizes: "192x192", type: "image/png" },
          { src: "pwa-512x512.png", sizes: "512x512", type: "image/png" }
        ]
      }
    })
  ],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
      "@components": path.resolve(__dirname, "./src/components"),
      "@pages": path.resolve(__dirname, "./src/pages"),
      "@routes": path.resolve(__dirname, "./src/routes"),
      "@hooks": path.resolve(__dirname, "./src/hooks"),
      "@store": path.resolve(__dirname, "./src/store"),
      "@services": path.resolve(__dirname, "./src/services"),
      "@constants": path.resolve(__dirname, "./src/constants"),
      "@data": path.resolve(__dirname, "./src/data"),
      "@styles": path.resolve(__dirname, "./src/styles")
    }
  }
})

TypeScript Configuration

The project uses strict TypeScript settings for type safety:
tsconfig.json
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src"]
}

Redux Store Setup

MotorDesk uses Redux with persistence for offline-first capabilities. The store configuration (src/store/index.ts):
import { configureStore } from '@reduxjs/toolkit';
import createSagaMiddleware from 'redux-saga';
import { persistStore, persistReducer } from 'redux-persist';
import localforage from 'localforage';
import { combineReducers } from 'redux';
import authReducer from './slices/authSlice';
import salesReducer from './slices/salesSlice';
import rootSaga from './rootSaga';

// Configure LocalForage for IndexedDB storage
localforage.config({
  name: 'FleetSUNAT_DB',
  storeName: 'redux_state'
});

// Persist configuration
const persistConfig = {
  key: 'sunat-root',
  storage: localforage,
  whitelist: ['auth', 'sales'], // Only persist these slices
};

const rootReducer = combineReducers({
  auth: authReducer,
  sales: salesReducer,
});

const persistedReducer = persistReducer(persistConfig, rootReducer);
const sagaMiddleware = createSagaMiddleware();

export const store = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      thunk: false,
      serializableCheck: {
        ignoredActions: ['persist/PERSIST', 'persist/REHYDRATE', 'persist/REGISTER'],
      },
    }).concat(sagaMiddleware),
});

sagaMiddleware.run(rootSaga);

export const persistor = persistStore(store);

Integrating the Store

The store is integrated in src/main.tsx:
import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import { store, persistor } from './store';
import App from './App';
import './index.css';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <App />
      </PersistGate>
    </Provider>
  </React.StrictMode>,
)
PersistGate delays rendering until the persisted state is retrieved from IndexedDB, ensuring consistent state on app load.

Building for Production

Production Build

Create an optimized production build:
npm run build
This command:
  1. Runs TypeScript compilation (tsc -b)
  2. Builds the Vite bundle with optimizations
  3. Generates PWA service worker and manifest
  4. Outputs to the dist/ directory

Build Output

The build process generates:
dist/
├── assets/
│   ├── index-[hash].js      # Main application bundle
│   ├── index-[hash].css     # Compiled styles
│   └── [chunk]-[hash].js    # Code-split chunks
├── manifest.webmanifest      # PWA manifest
├── sw.js                     # Service worker
├── workbox-[hash].js         # Workbox runtime
├── pwa-192x192.png          # PWA icons
├── pwa-512x512.png
└── index.html               # Entry HTML

Preview Production Build

Test the production build locally:
npm run preview
This starts a local server at http://localhost:4173 serving the built files.

Deployment

MotorDesk is a static SPA perfect for modern hosting platforms:
Deploy to Vercel
  1. Install Vercel CLI:
npm i -g vercel
  1. Deploy:
vercel
  1. Configure in vercel.json:
{
  "buildCommand": "npm run build",
  "outputDirectory": "dist",
  "rewrites": [
    { "source": "/(.*)", "destination": "/" }
  ]
}

Required Headers for PWA

Ensure your hosting platform serves these headers:
# Service Worker
Location: /sw.js
Cache-Control: no-cache, no-store, must-revalidate

# Manifest
Location: /manifest.webmanifest
Content-Type: application/manifest+json

# General assets
Cache-Control: public, max-age=31536000, immutable

Post-Deployment Configuration

Initial Setup

After deployment, configure the application:
1

Access Settings

Navigate to /settings in your deployed application
2

Configure Company

Set up company information:
  • RUC (Tax ID)
  • Razón Social (Legal name)
  • Fiscal address
  • Bank account details
3

Add Branches

Register all business locations with SUNAT establishment codes
4

Configure Billing Series

Set up document series for each branch:
  • FACTURA series (F001, F002, etc.)
  • BOLETA series (B001, B002, etc.)
  • Starting correlatives
5

Create Users

Add user accounts with appropriate roles:
  • Administrador (Admin)
  • Vendedor (Sales)
  • Cajero (Cashier)

SUNAT Integration

Connect to SUNAT electronic billing system:
  1. Obtain API Credentials:
    • Request API access from SUNAT
    • Get production and test environment credentials
    • Store credentials in environment variables
  2. Configure Endpoints:
    VITE_SUNAT_API_URL=https://api-cpe.sunat.gob.pe
    VITE_SUNAT_USERNAME=your_ruc
    VITE_SUNAT_PASSWORD=your_password
    VITE_SUNAT_CERT_PATH=/path/to/certificate.pfx
    
  3. Test in Sandbox:
    • Use SUNAT test environment first
    • Validate invoice generation
    • Check XML format compliance
  4. Enable Production:
    • Switch to production endpoints
    • Monitor first 50 invoices closely
    • Set up error notifications

Troubleshooting

Common Issues

Issue: TypeScript cannot resolve module pathsSolution:
  1. Verify path aliases in vite.config.ts
  2. Check tsconfig.json includes the correct paths
  3. Restart the development server
# Clear cache and reinstall
rm -rf node_modules
rm package-lock.json
npm install
Issue: Service worker caches old versionSolution:
  1. Open DevTools → Application → Service Workers
  2. Check “Update on reload”
  3. Click “Unregister” and refresh
  4. Clear site data if needed
Issue: State lost on page refreshSolution:
  1. Check browser IndexedDB support
  2. Verify LocalForage configuration
  3. Check persistConfig whitelist includes required slices
  4. Clear IndexedDB and test fresh:
// In browser console
indexedDB.deleteDatabase('FleetSUNAT_DB');
Issue: Type errors during buildSolution:
  1. Run type checking separately:
npx tsc --noEmit
  1. Fix reported errors
  2. Ensure all dependencies have types:
npm install --save-dev @types/react @types/react-dom
Issue: Port already in use or permission errorSolution:
  1. Change port in vite.config.ts:
export default defineConfig({
  server: {
    port: 3000
  }
})
  1. Or kill process on port 5173:
# Linux/Mac
lsof -ti:5173 | xargs kill -9

# Windows
netstat -ano | findstr :5173
taskkill /PID <PID> /F

Getting Help

If you encounter issues not covered here:

Check Logs

Review browser console and build output for errors

Verify Dependencies

Ensure all packages are at compatible versions

Test in Isolation

Create minimal reproduction of the issue

Community Support

Reach out to the development team or community forums

Performance Optimization

Code Splitting

Vite automatically code-splits routes. Optimize further with dynamic imports:
// Lazy load heavy components
import { lazy, Suspense } from 'react';

const Reports = lazy(() => import('@pages/Reports'));

function App() {
  return (
    <Suspense fallback={<LoadingSpinner />}>
      <Reports />
    </Suspense>
  );
}

Asset Optimization

  1. Images: Use WebP format with fallbacks
  2. Icons: Use SVG sprites or icon fonts
  3. Fonts: Subset fonts to include only needed characters

Caching Strategy

The PWA uses Workbox with these strategies:
  • App Shell: Cache-first
  • API Responses: Network-first with 5-minute cache
  • Static Assets: Cache-first with versioning

Security Considerations

Always follow security best practices when deploying to production.

Checklist

  • Use HTTPS for all production deployments
  • Enable CORS only for trusted domains
  • Store sensitive data in environment variables
  • Implement Content Security Policy (CSP) headers
  • Enable HSTS (HTTP Strict Transport Security)
  • Sanitize all user inputs
  • Keep dependencies updated for security patches
  • Use authentication tokens with expiration
  • Encrypt sensitive data in IndexedDB
  • Implement rate limiting on API calls

CSP Header Example

Content-Security-Policy: default-src 'self'; 
  script-src 'self' 'unsafe-inline'; 
  style-src 'self' 'unsafe-inline'; 
  img-src 'self' data: https:; 
  connect-src 'self' https://api.yourcompany.com;

Monitoring & Maintenance

Application Monitoring

Set up monitoring for:
  • Error Tracking: Use Sentry or similar for runtime errors
  • Analytics: Track user behavior and feature usage
  • Performance: Monitor Core Web Vitals
  • Uptime: Set up health checks for API endpoints

Regular Maintenance

1

Weekly

  • Review error logs
  • Check sync status for offline transactions
  • Monitor disk usage for IndexedDB
2

Monthly

  • Update dependencies
  • Review and optimize bundle size
  • Backup configuration data
3

Quarterly

  • Security audit
  • Performance review
  • User feedback analysis

Next Steps

Features Guide

Explore all MotorDesk features

API Documentation

Learn about the API endpoints

User Guide

End-user documentation

SUNAT Integration

Configure electronic billing

Build docs developers (and LLMs) love