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
Clone the Repository
Clone the MotorDesk source code to your local machine: git clone < repository-ur l >
cd fleet-pwa
Install Dependencies
Choose your preferred package manager and install all dependencies:
Start Development Server
Launch the development server with hot module replacement: 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:
# 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:
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:
{
"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:
This command:
Runs TypeScript compilation (tsc -b)
Builds the Vite bundle with optimizations
Generates PWA service worker and manifest
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:
This starts a local server at http://localhost:4173 serving the built files.
Deployment
Static Hosting (Recommended)
MotorDesk is a static SPA perfect for modern hosting platforms:
Vercel
Netlify
AWS S3 + CloudFront
Docker
Deploy to Vercel
Install Vercel CLI:
Deploy:
Configure in vercel.json:
{
"buildCommand" : "npm run build" ,
"outputDirectory" : "dist" ,
"rewrites" : [
{ "source" : "/(.*)" , "destination" : "/" }
]
}
Deploy to Netlify
Create netlify.toml:
[ build ]
command = "npm run build"
publish = "dist"
[[ redirects ]]
from = "/*"
to = "/index.html"
status = 200
Deploy via CLI:
npm install -g netlify-cli
netlify deploy --prod
Deploy to AWS
Build the application:
Create S3 bucket and enable static hosting
Upload dist folder:
aws s3 sync dist/ s3://your-bucket-name --delete
Set up CloudFront distribution
Configure error pages (404 → /index.html)
Containerize with Docker Create Dockerfile: FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD [ "nginx" , "-g" , "daemon off;" ]
Create nginx.conf: server {
listen 80 ;
server_name _;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $ uri $ uri / /index.html;
}
}
Build and run: docker build -t motordesk .
docker run -p 80:80 motordesk
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:
Access Settings
Navigate to /settings in your deployed application
Configure Company
Set up company information:
RUC (Tax ID)
Razón Social (Legal name)
Fiscal address
Bank account details
Add Branches
Register all business locations with SUNAT establishment codes
Configure Billing Series
Set up document series for each branch:
FACTURA series (F001, F002, etc.)
BOLETA series (B001, B002, etc.)
Starting correlatives
Create Users
Add user accounts with appropriate roles:
Administrador (Admin)
Vendedor (Sales)
Cajero (Cashier)
SUNAT Integration
Connect to SUNAT electronic billing system:
Obtain API Credentials :
Request API access from SUNAT
Get production and test environment credentials
Store credentials in environment variables
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
Test in Sandbox :
Use SUNAT test environment first
Validate invoice generation
Check XML format compliance
Enable Production :
Switch to production endpoints
Monitor first 50 invoices closely
Set up error notifications
Troubleshooting
Common Issues
Issue : TypeScript cannot resolve module pathsSolution :
Verify path aliases in vite.config.ts
Check tsconfig.json includes the correct paths
Restart the development server
# Clear cache and reinstall
rm -rf node_modules
rm package-lock.json
npm install
Issue : Service worker caches old versionSolution :
Open DevTools → Application → Service Workers
Check “Update on reload”
Click “Unregister” and refresh
Clear site data if needed
Redux state not persisting
Issue : State lost on page refreshSolution :
Check browser IndexedDB support
Verify LocalForage configuration
Check persistConfig whitelist includes required slices
Clear IndexedDB and test fresh:
// In browser console
indexedDB . deleteDatabase ( 'FleetSUNAT_DB' );
Build fails with TypeScript errors
Issue : Type errors during buildSolution :
Run type checking separately:
Fix reported errors
Ensure all dependencies have types:
npm install --save-dev @types/react @types/react-dom
Vite dev server won't start
Issue : Port already in use or permission errorSolution :
Change port in vite.config.ts:
export default defineConfig ({
server: {
port: 3000
}
})
Or kill process on port 5173:
# Linux/Mac
lsof -ti:5173 | xargs kill -9
# Windows
netstat -ano | findstr :5173
taskkill /PID < PI D > /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
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
Images : Use WebP format with fallbacks
Icons : Use SVG sprites or icon fonts
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
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
Weekly
Review error logs
Check sync status for offline transactions
Monitor disk usage for IndexedDB
Monthly
Update dependencies
Review and optimize bundle size
Backup configuration data
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