A comprehensive Customer Relationship Management (CRM) and project management system designed specifically for San Clemente Woodworking. This application helps manage the entire workflow from initial customer contact through project completion, including job tracking, scheduling, customer management, and payroll.
- Overview
- Architecture
- Use Cases
- Features
- Tech Stack
- Installation
- Configuration
- Running the Application
- Project Structure
- API Documentation
- Database Schema
- Google Calendar Integration
- Payroll System
- Authentication & Security
- Troubleshooting
Paarth is a full-stack CRM solution built to streamline operations for a custom woodworking business. It provides end-to-end management of:
- Customer Relationships: Centralized customer database with multiple contact methods and addresses
- Sales Pipeline: Visual kanban board tracking jobs through 13 distinct stages from appointment to final payment
- Project Management: Detailed job tracking with estimates, contracts, scheduling, and file management
- Calendar Integration: Google Calendar sync for seamless scheduling with recurrence support
- Task Management: General todos and job-specific tasks with priority and due dates
- Payroll: Timesheet tracking with hours, travel miles, receipts, and overtime calculations
- Activity Logging: Comprehensive audit trail of all customer and job interactions
The system is designed with a modern, responsive UI built on Material-UI and a robust REST API backend using Express and MongoDB.
Paarth follows a client-server architecture with clear separation between frontend and backend:
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β React Frontend β βββββββΊ β Express Backend β βββββββΊ β MongoDB β
β (Port 5173) β REST β (Port 4000) β ODM β Database β
βββββββββββββββββββ API βββββββββββββββββββ βββββββββββββββββββ
β β
β β
βΌ βΌ
βββββββββββββββββββ βββββββββββββββββββ
β Material-UI β β Google Calendarβ
β Components β β API (OAuth 2.0)β
βββββββββββββββββββ βββββββββββββββββββ
Technology Stack:
- React 19: Modern UI framework with hooks and functional components
- Material-UI (MUI) v7: Component library for consistent design
- React Router v7: Client-side routing
- Axios: HTTP client for API communication
- @dnd-kit: Drag-and-drop functionality for pipeline board
- date-fns: Date manipulation and formatting
- react-hot-toast: User notifications
- Vite: Fast build tool and dev server
Structure:
frontend/src/
βββ components/ # Reusable UI components
β βββ appointments/ # Appointment-related components
β βββ customers/ # Customer management components
β βββ jobs/ # Job detail modals and forms
β βββ layout/ # MainLayout, Sidebar, TopBar
β βββ pipeline/ # Pipeline board and job cards
β βββ tasks/ # Task management components
β βββ todos/ # Todo list components
βββ pages/ # Route-level page components
βββ context/ # React Context providers (if any)
βββ hooks/ # Custom React hooks
βββ services/ # API service layer
βββ theme/ # MUI theme configuration
βββ utils/ # Utility functions
Key Design Patterns:
- Component Composition: Modular, reusable components
- Container/Presentational: Separation of data logic and presentation
- Context API: Global state management (if needed)
- Custom Hooks: Reusable stateful logic
Technology Stack:
- Node.js: JavaScript runtime
- Express 5: Web framework with middleware support
- MongoDB: NoSQL database for flexible schema
- Mongoose: ODM (Object Document Mapper) for MongoDB
- JWT: Token-based authentication
- Multer: File upload handling
- Google APIs: Calendar integration via OAuth 2.0
- bcryptjs: Password hashing
Structure:
backend/src/
βββ controllers/ # Business logic layer
β βββ authController.js
β βββ customerController.js
β βββ jobController.js
β βββ taskController.js
β βββ appointmentController.js
β βββ calendarController.js
β βββ fileController.js
β βββ activityController.js
βββ models/ # Mongoose schemas
β βββ User.js
β βββ Customer.js
β βββ Job.js
β βββ Task.js
β βββ Appointment.js
β βββ Activity.js
β βββ File.js
βββ routes/ # API route definitions
β βββ auth.js
β βββ customers.js
β βββ jobs.js
β βββ tasks.js
β βββ appointments.js
β βββ calendar.js
β βββ files.js
βββ middleware/ # Express middleware
β βββ auth.js # JWT authentication
β βββ upload.js # File upload handling
βββ utils/ # Helper functions
β βββ generateToken.js
β βββ stageConfig.js
βββ server.js # Express app setup and MongoDB connection
Key Design Patterns:
- MVC (Model-View-Controller): Clear separation of concerns
- RESTful API: Standard HTTP methods and status codes
- Middleware Chain: Authentication, validation, error handling
- Repository Pattern: Data access abstraction through Mongoose models
- User Interaction: User interacts with React component
- API Call: Component calls API service function (Axios)
- HTTP Request: Request sent to Express backend
- Middleware: Authentication, validation, file upload processing
- Controller: Business logic execution
- Model: Database operations via Mongoose
- Response: JSON response sent back to frontend
- State Update: React component updates UI based on response
MongoDB Collections:
users: User accounts and authenticationcustomers: Customer information with multiple addresses/contactsjobs: Job details, stages, estimates, contracts, schedulingtasks: General tasks and todosappointments: Scheduled appointmentsactivities: Activity log for audit trailfiles: File metadata and references
Relationships:
- Jobs β Customers (many-to-one)
- Jobs β Users (assignedTo, createdBy)
- Tasks β Jobs (optional, many-to-one)
- Tasks β Customers (optional, many-to-one)
- Activities β Jobs (optional, many-to-one)
- Activities β Customers (required, many-to-one)
- Files β Jobs (optional, many-to-one)
Indexing Strategy:
- Jobs:
stage,isArchived,customerId,assignedTo - Customers: Text search on
nameandprimaryEmail - Activities:
jobId,customerIdwith timestamps - Tasks:
jobId,assignedTo,dueDatefor efficient querying
Scenario: A potential customer calls or emails about a custom woodworking project.
Workflow:
-
Create Customer Record
- Navigate to Customers page
- Click "Add Customer"
- Enter name, phone, email, address
- Select source (referral, Yelp, Instagram, etc.)
- Save customer
-
Schedule Appointment
- From customer detail or Pipeline page
- Create new job with title (e.g., "Kitchen Cabinets - John Smith")
- Job automatically starts in "Appointment Scheduled" stage
- Add appointment date/time and location
- Optionally sync to Google Calendar
-
Track Follow-up
- Create task to "Follow up on appointment"
- Set due date and priority
- System logs activity automatically
System Actions:
- Customer record created in database
- Job created with
APPOINTMENT_SCHEDULEDstage - Activity log entry:
customer_created,job_created - If calendar sync enabled, Google Calendar event created
Scenario: After appointment, create and send estimate to customer.
Workflow:
-
Move Job to Estimate Stage
- Drag job card from "Appointment Scheduled" to "Estimate Current, first 5 days"
- Or use job detail modal to change stage
-
Add Estimate Details
- Open job detail modal
- Enter estimated value
- Add line items (description, quantity, unit price)
- Upload estimate PDF if available
-
Send Estimate
- Move job to "Estimate Sent" stage
- System records
estimate.sentAttimestamp - Activity log:
estimate_sent
-
Track Response
- If no response after 7 days, job automatically moves to "Dead Estimates" archive
- If customer responds, move to "Design Review" or "Contract Out"
System Actions:
- Job stage updated in database
- Estimate data saved (amount, line items, sent date)
- Activity log:
stage_change,estimate_sent - File upload stored in
backend/uploads/and metadata in database
Scenario: Customer approves estimate and signs contract.
Workflow:
-
Contract Preparation
- Move job to "Contract Out" stage
- Upload contract PDF
- Add notes about contract terms
-
Contract Signed
- Move job to "Signed / Deposit Pending" stage
- Record contract signed date
- Enter deposit required amount
-
Deposit Received
- Update deposit received amount and date
- Job moves to "Job Prep" stage
- Activity log:
contract_signed,deposit_received
System Actions:
- Contract details saved (signed date, deposit amounts)
- Job stage progression tracked
- Activity log entries created
- Payment information recorded for financial tracking
Scenario: Prepare job for production and schedule installation.
Workflow:
-
Job Prep
- Job in "Job Prep" stage
- Add notes about materials, measurements, special requirements
-
Takeoff Complete
- Move to "Takeoff Complete" stage
- Record takeoff completion date and person
- Add takeoff notes
-
Ready to Schedule
- Move to "Ready to Schedule" stage
- All prep work complete
-
Schedule Installation
- Navigate to Calendar page
- Select job and set start/end dates
- Configure recurrence if needed (daily, weekly, monthly, yearly)
- Add crew notes
- Sync to Google Calendar
- Job moves to "Scheduled" stage
System Actions:
- Schedule data saved (start date, end date, recurrence)
- Google Calendar event created/updated via API
- Job stage updated to
SCHEDULED - Activity log:
job_scheduled,calendar_sync
Scenario: Track job through production and installation phases.
Workflow:
-
In Production
- Move job to "In Production" stage
- Add progress notes
- Upload photos of work in progress
-
Installation
- Move to "Installed" stage
- Record installation date
- Add installation notes and photos
-
Final Payment
- Move to "Final Payment Closed" stage
- Record final payment amount and method
- Job completion date recorded
System Actions:
- Job stage progression tracked
- Files uploaded and linked to job
- Activity log entries for each stage change
- Payment information recorded
Scenario: Create and track tasks for follow-ups and job-related activities.
Workflow:
-
Create Task
- Navigate to Tasks page
- Click "Add Task"
- Enter title, description, due date
- Set priority (low, medium, high, urgent)
- Optionally link to job or customer
- Assign to team member
-
Complete Task
- Mark task as complete
- System records completion date and user
- Task moves to "Completed Tasks" page
System Actions:
- Task created in database
- Activity log:
task_created - On completion:
task_completedactivity logged - Task filtered from active list
Scenario: Track employee hours, travel, and expenses for payroll.
Workflow:
-
Daily Time Entry
- Navigate to Payroll page
- Enter date
- Record clock in/out times
- Add break duration
- System calculates total hours
-
Travel Miles
- Add daily travel miles
- System calculates travel cost (configurable rate)
-
Receipts
- Add multiple receipts with descriptions
- Upload receipt images/PDFs
-
Overtime Calculation
- System automatically calculates weighted hours
- Hours over 40/week = 1.5x rate
-
Print Timesheet
- Use print functionality for clean formatted output
System Actions:
- Hours calculated from in/out times and breaks
- Overtime calculated based on weekly totals
- Travel costs calculated
- All data stored for payroll processing
Scenario: Manage customer information and track interactions.
Workflow:
-
View Customer
- Navigate to Customers page
- Search by name or email
- View customer detail with all jobs
-
Update Customer
- Add additional phone numbers or emails
- Add multiple addresses
- Add tags for categorization
- Update notes
-
View Customer History
- See all jobs associated with customer
- View activity log for all interactions
- See all files uploaded for customer's jobs
System Actions:
- Customer data updated in database
- Activity log:
customer_updated - All related jobs remain linked
- Search functionality uses MongoDB text indexes
Scenario: Archive completed jobs and dead estimates.
Workflow:
-
Archive Completed Job
- From job detail modal, click "Archive"
- Job moves to archive (not deleted)
- Archived timestamp and user recorded
-
View Dead Estimates
- Navigate to "Dead Estimates" page
- View estimates sent but no response after 7 days
- Can reactivate if customer responds later
-
View Job Archive
- Navigate to "Job Archive" page
- View all archived jobs
- Filter and search archived jobs
System Actions:
- Job
isArchivedflag set to true - Archived timestamp and user recorded
- Job removed from active pipeline
- All data preserved for historical reference
Scenario: Sync job schedules with Google Calendar.
Workflow:
-
Initial Setup
- Follow
GOOGLE_CALENDAR_SETUP.mdguide - Configure OAuth 2.0 credentials
- Get refresh token
- Follow
-
Schedule Job
- Set job schedule dates on Calendar page
- Configure recurrence if needed
- Click "Sync to Calendar"
- System creates Google Calendar event
-
Automatic Updates
- When job details change, calendar event updates
- When job deleted/archived, calendar event removed
System Actions:
- OAuth 2.0 authentication with Google
- Google Calendar API calls to create/update/delete events
- Event ID stored in job
calendar.googleEventId - Sync status tracked in
calendar.calendarStatus
- Visual Kanban Board: Drag-and-drop interface for managing jobs through stages
- 13 Job Stages: From appointment scheduling to final payment
- Stage Grouping: Organized into Appointments, Sales, Readiness, and Execution phases
- Value Tracking: Estimated and contracted values for revenue forecasting
- Source Tracking: Track where leads come from (referral, Yelp, Instagram, etc.)
- Comprehensive Database: Store customer information with multiple contact methods
- Multiple Addresses: Support for multiple addresses per customer
- Multiple Contacts: Multiple phone numbers and email addresses
- Tags: Categorize customers with custom tags
- Search Functionality: Full-text search by name or email
- Customer History: View all jobs and activities for each customer
- Detailed Job Records: Complete job information with stages, estimates, contracts
- File Management: Upload and manage job-related files (PDFs, images, documents)
- Notes Timeline: Chronological notes with user attribution
- Stage History: Track all stage changes with timestamps
- Assignment: Assign jobs to team members
- Archive System: Archive instead of delete for historical reference
- Google Calendar Sync: Two-way sync with Google Calendar
- Recurrence Support: Daily, weekly, monthly, yearly recurrence patterns
- Automatic Updates: Calendar events update when job details change
- Crew Notes: Add notes visible in calendar events
- General Tasks: Create tasks independent of jobs
- Job-Linked Tasks: Link tasks to specific jobs or customers
- Priority Levels: Low, medium, high, urgent priorities
- Due Dates: Set and track due dates
- Assignment: Assign tasks to team members
- Completion Tracking: Mark tasks complete with timestamp
- Appointment Creation: Schedule customer appointments
- Location Tracking: Record appointment locations
- Notes: Add appointment-specific notes
- Completion Tracking: Mark appointments as complete
- Upload Support: Upload files (PDFs, images, documents)
- Job Linking: Link files to specific jobs
- Metadata Storage: Store file metadata in database
- Static Serving: Files served via Express static middleware
- Comprehensive Tracking: Log all customer and job interactions
- Activity Types: 20+ activity types (created, updated, stage_change, etc.)
- User Attribution: Track who performed each action
- Timestamps: All activities timestamped
- Change Tracking: Record what changed in updates
- Timesheet Management: Daily hours tracking with in/out times
- Break Tracking: Record break durations
- Overtime Calculation: Automatic weighted hours (1.5x for hours over 40)
- Travel Miles: Track daily travel with automatic cost calculation
- Receipts: Add multiple receipts with descriptions
- Print Functionality: Clean formatted print output
- Separate Task System: Task management for development work
- JSON Storage: Stored in
developer-tasks.jsonfile - Independent from Main Tasks: Separate from customer/job tasks
- React 19: UI framework
- Material-UI (MUI) v7: Component library
- React Router v7: Routing
- Axios: HTTP client
- @dnd-kit: Drag-and-drop
- date-fns: Date manipulation
- react-hot-toast: Notifications
- Vite: Build tool
- Node.js: Runtime environment
- Express 5: Web framework
- MongoDB: Database
- Mongoose: ODM
- JWT: Authentication
- Multer: File uploads
- Google APIs: Calendar integration
- bcryptjs: Password hashing
- Node.js (v18 or higher)
- MongoDB (local installation or MongoDB Atlas account)
- npm or yarn
- Google Cloud account (optional, for Calendar integration)
git clone <repository-url>
cd Paarthcd backend
npm installcd ../frontend
npm installCreate a .env file in the backend directory:
# MongoDB Connection
MONGODB_URI=mongodb://localhost:27017/paarth
# or for MongoDB Atlas:
# MONGODB_URI=mongodb+srv://username:password@cluster.mongodb.net/paarth
# JWT Secret (use a strong random string)
JWT_SECRET=your_jwt_secret_here
# Server Port
PORT=4000
# Google Calendar API (Optional - see GOOGLE_CALENDAR_SETUP.md)
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
GOOGLE_REDIRECT_URI=http://localhost:4000/calendar/auth/callback
GOOGLE_REFRESH_TOKEN=your_refresh_token
# File Upload
MAX_FILE_SIZE=10485760 # 10MB in bytesCreate a .env file in the frontend directory:
VITE_API_URL=http://localhost:4000For production, update to your production API URL.
-
Start MongoDB (if running locally):
mongod
-
Start Backend Server:
cd backend npm run devBackend will run on
http://localhost:4000 -
Start Frontend Development Server:
cd frontend npm run devFrontend will run on
http://localhost:5173
-
Build Frontend:
cd frontend npm run buildThis creates a
distfolder with optimized production files. -
Start Backend:
cd backend npm start -
Serve Frontend (optional): You can serve the frontend
distfolder using a web server like Nginx, or configure Express to serve static files.
Paarth/
βββ backend/
β βββ src/
β β βββ controllers/ # Business logic
β β β βββ authController.js
β β β βββ customerController.js
β β β βββ jobController.js
β β β βββ taskController.js
β β β βββ appointmentController.js
β β β βββ calendarController.js
β β β βββ fileController.js
β β β βββ activityController.js
β β βββ models/ # Mongoose schemas
β β β βββ User.js
β β β βββ Customer.js
β β β βββ Job.js
β β β βββ Task.js
β β β βββ Appointment.js
β β β βββ Activity.js
β β β βββ File.js
β β βββ routes/ # API routes
β β β βββ auth.js
β β β βββ customers.js
β β β βββ jobs.js
β β β βββ tasks.js
β β β βββ appointments.js
β β β βββ calendar.js
β β β βββ files.js
β β β βββ activities.js
β β βββ middleware/ # Express middleware
β β β βββ auth.js # JWT authentication
β β β βββ upload.js # File upload handling
β β βββ utils/ # Helper functions
β β β βββ generateToken.js
β β β βββ stageConfig.js
β β βββ server.js # Express server setup
β βββ uploads/ # Uploaded files storage
β βββ package.json
β βββ .env # Environment variables (create this)
βββ frontend/
β βββ src/
β β βββ components/ # Reusable components
β β β βββ appointments/
β β β βββ customers/
β β β βββ jobs/
β β β βββ layout/
β β β βββ pipeline/
β β β βββ tasks/
β β β βββ todos/
β β βββ pages/ # Page components
β β β βββ PipelinePage.jsx
β β β βββ CustomersPage.jsx
β β β βββ CalendarPage.jsx
β β β βββ TasksPage.jsx
β β β βββ PayrollPage.jsx
β β β βββ ...
β β βββ services/ # API services
β β βββ theme/ # MUI theme
β β βββ utils/ # Utility functions
β β βββ App.jsx # Main app component
β β βββ main.jsx # Entry point
β βββ public/ # Static assets
β βββ package.json
β βββ .env # Environment variables (create this)
βββ GOOGLE_CALENDAR_SETUP.md # Calendar setup guide
βββ README.md # This file
All protected routes require a JWT token in the Authorization header:
Authorization: Bearer <token>
Register a new user.
Request Body:
{
"name": "John Doe",
"email": "john@example.com",
"password": "password123"
}Response:
{
"token": "jwt_token_here",
"user": {
"id": "user_id",
"name": "John Doe",
"email": "john@example.com"
}
}Login user.
Request Body:
{
"email": "john@example.com",
"password": "password123"
}Response:
{
"token": "jwt_token_here",
"user": {
"id": "user_id",
"name": "John Doe",
"email": "john@example.com"
}
}Get current authenticated user.
Headers: Authorization: Bearer <token>
Response:
{
"id": "user_id",
"name": "John Doe",
"email": "john@example.com"
}Get all jobs (optionally filtered by stage, archived status).
Query Parameters:
stage: Filter by stageisArchived: Filter archived jobs (true/false)customerId: Filter by customer
Response:
[
{
"id": "job_id",
"customerId": "customer_id",
"title": "Kitchen Cabinets",
"stage": "SCHEDULED",
"valueEstimated": 15000,
"valueContracted": 15000,
"source": "referral",
"schedule": {
"startDate": "2024-01-15T00:00:00.000Z",
"endDate": "2024-01-20T00:00:00.000Z"
},
"createdAt": "2024-01-01T00:00:00.000Z"
}
]Create a new job.
Request Body:
{
"customerId": "customer_id",
"title": "Kitchen Cabinets",
"stage": "APPOINTMENT_SCHEDULED",
"valueEstimated": 15000,
"source": "referral"
}Get job by ID.
Update job.
Request Body: (partial update, include only fields to update)
{
"stage": "ESTIMATE_IN_PROGRESS",
"valueEstimated": 16000
}Delete job (soft delete - sets isArchived flag).
Move job to different stage.
Request Body:
{
"stage": "ESTIMATE_SENT",
"note": "Estimate sent to customer"
}Archive job.
Get all customers.
Query Parameters:
search: Search by name or email
Create customer.
Request Body:
{
"name": "John Smith",
"primaryPhone": "555-1234",
"primaryEmail": "john@example.com",
"address": {
"street": "123 Main St",
"city": "San Clemente",
"state": "CA",
"zip": "92672"
},
"source": "referral"
}Get customer by ID.
Update customer.
Delete customer.
Upload customers from CSV file.
Get all tasks.
Query Parameters:
jobId: Filter by jobcustomerId: Filter by customercompleted: Filter completed tasks (true/false)
Create task.
Request Body:
{
"title": "Follow up on estimate",
"description": "Call customer about estimate",
"dueDate": "2024-01-15T00:00:00.000Z",
"priority": "high",
"jobId": "job_id"
}Mark task as complete.
Delete task.
Get all appointments.
Query Parameters:
completed: Filter completed appointments (true/false)
Create appointment.
Mark appointment as complete.
Delete appointment.
Get Google Calendar OAuth authorization URL.
Response:
{
"authUrl": "https://accounts.google.com/..."
}OAuth callback endpoint (handles code exchange for refresh token).
Sync job to Google Calendar.
Request Body:
{
"startDate": "2024-01-15T00:00:00.000Z",
"endDate": "2024-01-20T00:00:00.000Z",
"recurrence": {
"type": "none",
"interval": 1,
"count": 10
}
}Remove job from Google Calendar.
Upload file.
Request: Multipart form data
file: File to uploadjobId: (optional) Link to jobdescription: (optional) File description
Response:
{
"id": "file_id",
"filename": "contract.pdf",
"path": "/uploads/contract-1234567890.pdf",
"mimetype": "application/pdf",
"size": 102400,
"jobId": "job_id"
}Get file metadata.
Delete file.
Get all developer tasks.
Create developer task.
Update developer task.
Delete developer task.
{
name: String (required),
email: String (required, unique, lowercase),
password: String (required, hashed),
isActive: Boolean (default: true),
role: String (enum: ['admin', 'user']),
createdAt: Date,
updatedAt: Date
}{
name: String (required),
primaryPhone: String,
primaryEmail: String (lowercase),
phones: [String],
emails: [String],
address: {
street: String,
city: String,
state: String,
zip: String
},
addresses: [{
street: String,
city: String,
state: String,
zip: String,
fullAddress: String
}],
tags: [String],
notes: String,
source: String (enum: ['referral', 'yelp', 'instagram', 'facebook', 'website', 'repeat', 'other']),
createdBy: ObjectId (ref: 'User'),
createdAt: Date,
updatedAt: Date
}{
customerId: ObjectId (ref: 'Customer', required),
title: String (required),
stage: String (enum: [
'APPOINTMENT_SCHEDULED',
'ESTIMATE_IN_PROGRESS',
'ESTIMATE_SENT',
'ENGAGED_DESIGN_REVIEW',
'CONTRACT_OUT',
'CONTRACT_SIGNED',
'DEPOSIT_PENDING',
'JOB_PREP',
'TAKEOFF_COMPLETE',
'READY_TO_SCHEDULE',
'SCHEDULED',
'IN_PRODUCTION',
'INSTALLED',
'FINAL_PAYMENT_CLOSED'
]),
valueEstimated: Number,
valueContracted: Number,
source: String (enum: ['referral', 'yelp', 'instagram', 'facebook', 'website', 'repeat', 'other']),
assignedTo: ObjectId (ref: 'User'),
appointment: {
dateTime: Date,
location: String,
notes: String
},
estimate: {
amount: Number,
sentAt: Date,
lineItems: [{
description: String,
quantity: Number,
unitPrice: Number,
total: Number
}]
},
contract: {
signedAt: Date,
depositRequired: Number,
depositReceived: Number,
depositReceivedAt: Date
},
takeoff: {
completedAt: Date,
completedBy: ObjectId (ref: 'User'),
notes: String
},
schedule: {
startDate: Date,
endDate: Date,
crewNotes: String,
recurrence: {
type: String (enum: ['none', 'daily', 'weekly', 'monthly', 'yearly']),
interval: Number,
count: Number
}
},
calendar: {
googleEventId: String,
calendarStatus: String (enum: ['created', 'updated', 'error', 'none']),
lastSyncedAt: Date
},
finalPayment: {
amountDue: Number,
amountPaid: Number,
paidAt: Date,
paymentMethod: String (enum: ['cash', 'check', 'bank_transfer', 'credit_card', 'other'])
},
notes: [{
content: String,
createdBy: ObjectId (ref: 'User'),
createdAt: Date,
isStageChange: Boolean,
isAppointment: Boolean
}],
isArchived: Boolean (default: false),
archivedAt: Date,
archivedBy: ObjectId (ref: 'User'),
isDeadEstimate: Boolean (default: false),
movedToDeadEstimateAt: Date,
createdBy: ObjectId (ref: 'User', required),
createdAt: Date,
updatedAt: Date
}{
jobId: ObjectId (ref: 'Job', optional),
customerId: ObjectId (ref: 'Customer', optional),
title: String (required),
description: String,
dueDate: Date,
priority: String (enum: ['low', 'medium', 'high', 'urgent']),
type: String (enum: ['follow_up', 'send_estimate', 'review_design', 'collect_deposit', 'schedule_install', 'site_visit', 'quality_check', 'collect_payment', 'other']),
assignedTo: ObjectId (ref: 'User'),
completedAt: Date,
completedBy: ObjectId (ref: 'User'),
createdBy: ObjectId (ref: 'User', required),
createdAt: Date,
updatedAt: Date
}{
type: String (enum: [
'customer_created', 'customer_updated',
'job_created', 'job_updated', 'job_archived',
'stage_change', 'value_update', 'note',
'call', 'email', 'sms', 'meeting',
'file_uploaded', 'file_deleted',
'estimate_sent', 'estimate_updated',
'contract_signed', 'deposit_received', 'payment_received',
'job_scheduled', 'calendar_sync',
'task_created', 'task_completed',
'takeoff_complete'
]),
jobId: ObjectId (ref: 'Job', optional),
customerId: ObjectId (ref: 'Customer', required),
fromStage: String,
toStage: String,
changes: Map,
note: String,
fileId: ObjectId (ref: 'File'),
fileName: String,
amount: Number,
paymentType: String,
paymentMethod: String,
duration: String,
location: String,
subject: String,
googleEventId: String,
createdBy: ObjectId (ref: 'User', required),
createdAt: Date,
updatedAt: Date
}The application supports syncing jobs to Google Calendar for seamless scheduling. See GOOGLE_CALENDAR_SETUP.md for detailed setup instructions.
- Automatic Event Creation: When jobs are scheduled, events are created in Google Calendar
- Recurrence Support: Daily, weekly, monthly, yearly recurrence patterns
- Event Updates: Calendar events update when job details change
- Event Deletion: Calendar events are removed when jobs are archived or deleted
- OAuth 2.0: Secure authentication with Google APIs
- Create Google Cloud Project
- Enable Google Calendar API
- Create OAuth 2.0 credentials
- Configure redirect URI
- Get refresh token
- Add credentials to
.envfile
See GOOGLE_CALENDAR_SETUP.md for step-by-step instructions.
The payroll page provides comprehensive timesheet management:
- Work Hours Tracking: Daily hours with in/out times and breaks
- Overtime Calculation: Automatic weighted hours (1.5x for hours over 40 per week)
- Travel Miles: Track daily travel with automatic cost calculation
- Receipts: Add multiple receipts with descriptions
- Print Functionality: Clean formatted print output for payroll processing
- Navigate to Payroll page
- Select date
- Enter clock in/out times
- Add break duration
- Add travel miles (if applicable)
- Add receipts (if applicable)
- System calculates total hours and overtime
- Print timesheet for payroll processing
- User registers/logs in via
/auth/registeror/auth/login - Backend validates credentials and generates JWT token
- Token returned to frontend
- Frontend stores token (typically in localStorage)
- Frontend includes token in
Authorization: Bearer <token>header for protected routes - Backend middleware (
requireAuth) validates token on each request - User object attached to request for use in controllers
- Password Hashing: Passwords hashed using bcryptjs
- JWT Tokens: Secure token-based authentication
- Protected Routes: Middleware protects sensitive endpoints
- CORS: Configured for secure cross-origin requests
- File Upload Validation: File type and size validation
- Input Validation: Mongoose schema validation
- Use strong JWT secrets in production
- Store sensitive environment variables securely
- Use HTTPS in production
- Regularly update dependencies
- Implement rate limiting for production
- Use MongoDB authentication in production
Symptoms:
- Backend starts but shows "MongoDB connection error"
- API requests return 503 "Database connection unavailable"
Solutions:
-
Ensure MongoDB is running:
# Check if MongoDB is running mongosh -
Verify
MONGODB_URIin.env:MONGODB_URI=mongodb://localhost:27017/paarth
-
For MongoDB Atlas:
- Check IP whitelist in Atlas dashboard
- Verify connection string format
- Check network connectivity
-
Check MongoDB logs for errors
Symptoms:
- "Google Calendar not configured" error
- Events not syncing to Google Calendar
Solutions:
-
Verify all environment variables are set:
GOOGLE_CLIENT_ID=... GOOGLE_CLIENT_SECRET=... GOOGLE_REDIRECT_URI=... GOOGLE_REFRESH_TOKEN=...
-
Check that Calendar API is enabled in Google Cloud Console
-
Verify refresh token is valid (may need to re-authenticate):
- Visit
/calendar/auth-urlendpoint - Complete OAuth flow
- Update refresh token in
.env
- Visit
-
Check backend logs for API errors
Symptoms:
- Files not uploading
- "File too large" errors
- Files not accessible
Solutions:
-
Check
MAX_FILE_SIZEin.env:MAX_FILE_SIZE=10485760 # 10MB
-
Ensure
uploads/directory exists and is writable:mkdir -p backend/uploads chmod 755 backend/uploads
-
Verify file types are allowed (check
upload.jsmiddleware) -
Check disk space on server
Symptoms:
- API calls failing
- CORS errors in browser console
Solutions:
-
Verify
VITE_API_URLin frontend.env:VITE_API_URL=http://localhost:4000
-
Ensure backend is running on correct port
-
Check CORS configuration in
server.js -
Verify backend is accessible:
curl http://localhost:4000/health
Symptoms:
- Frontend build fails
- TypeScript errors
Solutions:
-
Clear node_modules and reinstall:
rm -rf node_modules package-lock.json npm install
-
Check Node.js version (should be v18+):
node --version
-
Verify all dependencies are installed:
npm install
- The application uses MongoDB for data persistence
- File uploads are stored in
backend/uploads/ - Developer tasks are stored in
backend/developer-tasks.json - The frontend communicates with the backend via REST API
- All dates are handled in local timezone
- Jobs are archived (soft deleted) rather than permanently deleted
- Dead estimates are automatically moved after 7 days of no response
[Add your license here]
[Add contributors here]
For issues or questions, please create an issue or contact the development team.
- v1.0.0: Initial release with core CRM functionality
- Sales pipeline management
- Customer management
- Job tracking
- Calendar integration
- Task management
- Payroll system
Potential features for future releases:
- Email integration for sending estimates/contracts
- SMS notifications
- Advanced reporting and analytics
- Mobile app (React Native)
- Multi-tenant support
- Advanced search and filtering
- Export functionality (PDF, CSV)
- Integration with accounting software
- Customer portal for viewing job status
Last updated: [Current Date]