Skip to content

Deploying Ever Gauzy

Introduction

Ever Gauzy is a comprehensive, open-source business management platform designed for collaborative, on-demand, and sharing economies. Combining enterprise resource planning (ERP), customer relationship management (CRM), human resource management (HRM), applicant tracking (ATS), and project management (PM) capabilities, Ever Gauzy provides organizations with a unified platform for managing every aspect of their operations.

Built with TypeScript, Node.js, NestJS, and Angular, Ever Gauzy offers a modern, scalable architecture that can grow with your business. Whether you’re managing employees, tracking time and activities, handling invoices and expenses, or coordinating projects and tasks, Ever Gauzy delivers the tools you need in a single, integrated platform.

Core Capabilities:

Human Resources Management: Manage your workforce with comprehensive employee profiles, onboarding workflows, contract management, and performance tracking. Monitor employee activities, track attendance, manage time off requests, and evaluate performance metrics to build a productive, engaged team.

Time Management and Tracking: Track work hours with precision using built-in timers, activity monitoring, and automated timesheets. Monitor employee productivity with screenshots and activity levels. Generate detailed time reports for payroll processing, project billing, and compliance requirements.

Project and Task Management: Organize work with projects, tasks, milestones, and sprints. Assign tasks to team members, track progress, set deadlines, and monitor project health. Integrate time tracking directly with tasks for accurate project costing and resource allocation.

Customer Relationship Management: Manage customer relationships throughout the entire lifecycle. Track leads, contacts, deals, and proposals. Monitor sales pipelines, schedule appointments, and maintain detailed communication histories. Build stronger customer relationships and close more deals.

Financial Management: Handle invoicing, expenses, estimates, and payments in one place. Generate professional invoices with customizable templates. Track expenses by project, employee, or category. Manage vendor relationships and monitor financial health with comprehensive reporting and analytics.

Applicant Tracking System: Streamline hiring with candidate management, interview scheduling, and evaluation workflows. Post job openings, track applications, schedule interviews, and collaborate with hiring teams. Make better hiring decisions with structured evaluation criteria and candidate comparisons.

Goals and KPIs: Set organizational and individual goals aligned with business objectives. Track key performance indicators, monitor progress toward targets, and measure success across teams and departments. Drive accountability and continuous improvement with transparent goal tracking.

Organization Management: Support multiple organizations, departments, teams, and roles within a single deployment. Manage organizational hierarchies, define team structures, and coordinate across business units. Perfect for agencies, multi-location businesses, and enterprise organizations.

Integration Ecosystem: Connect with external tools like Upwork, HubStaff, and other productivity platforms. Leverage REST APIs for custom integrations. Automate workflows with webhooks and external triggers.

Customization and Extensibility: Adapt the platform to your specific needs with custom fields, workflows, and business logic. Configure permissions and access controls. Brand the platform with your organization’s identity. Extend functionality through the open-source codebase.

Deploying Ever Gauzy on Klutch.sh provides automatic Docker detection, persistent storage for business-critical data, seamless scaling as your organization grows, automated SSL certificates for secure access, and managed infrastructure so you can focus on running your business.

This comprehensive guide covers every step of deploying Ever Gauzy on Klutch.sh, from initial repository setup to production optimization. You’ll learn how to configure databases, manage persistent storage, set up environment variables, optimize performance, and implement production-ready security practices.


Prerequisites

Before deploying Ever Gauzy to Klutch.sh, ensure you have:

  • A Klutch.sh account with dashboard access
  • A GitHub account for repository hosting
  • A PostgreSQL database deployed on Klutch.sh or external provider (16.x recommended)
  • Optional: Redis instance for caching and sessions (recommended for production)
  • Docker installed locally for testing (optional)
  • Basic understanding of business management systems and ERP/CRM concepts
  • Familiarity with Node.js and TypeScript (for customizations)
  • At least 4GB RAM and 20GB storage for production deployment

Understanding Ever Gauzy Architecture

Technology Stack

Ever Gauzy is built on a modern, enterprise-grade technology stack:

Backend:

  • Node.js 18+: JavaScript runtime for server-side execution
  • NestJS: Progressive Node.js framework for scalable server applications
  • TypeScript: Type-safe development for maintainability
  • TypeORM/MikroORM: Multi-database ORM support
  • GraphQL + REST: Flexible API options for integrations

Frontend:

  • Angular: Powerful framework for building dynamic web applications
  • RxJS: Reactive programming for real-time updates
  • Ngx-admin: Feature-rich admin dashboard template
  • Nebular: UI components optimized for business applications

Database Options:

  • PostgreSQL: Recommended for production (primary support)
  • MySQL/MariaDB: Alternative relational database option
  • SQLite: Development and testing (not recommended for production)

Infrastructure Dependencies:

  • Redis: Caching, session management, and job queues (recommended)
  • MinIO/S3: Object storage for file uploads and documents (optional)
  • OpenSearch: Full-text search capabilities (optional)
  • Cube.js: Analytics and reporting engine (optional)

Core Components

API Server: NestJS-based API handling all business logic, data operations, and external integrations

Web Application: Angular-based user interface for administrators, managers, and employees

Database Layer: PostgreSQL storing all business data with ACID compliance

Cache Layer: Redis for fast data access, session storage, and background job queues

File Storage: Local filesystem or S3-compatible object storage for uploads, documents, and media

Background Workers: Asynchronous job processing for emails, reports, and data synchronization

Authentication: JWT-based authentication with role-based access control

Time Tracker: Electron-based desktop application for employee time tracking and activity monitoring


Installation and Setup

Step 1: Create Your Project Directory

First, create a new directory for your Ever Gauzy deployment:

Terminal window
mkdir ever-gauzy-klutch
cd ever-gauzy-klutch
git init

Your project structure will look like:

ever-gauzy-klutch/
├── Dockerfile
├── .env.example
├── .dockerignore
├── .gitignore
├── docker-entrypoint.sh
├── config/
│ └── (configuration files)
├── uploads/
│ └── (file uploads - persistent)
└── README.md

Step 2: Create the Dockerfile

Create a production-ready Dockerfile for Ever Gauzy:

# Multi-stage build for optimized production image
FROM node:18-alpine AS builder
# Install build dependencies
RUN apk add --no-cache \
python3 \
make \
g++ \
git \
curl \
bash
# Set working directory
WORKDIR /app
# Clone Ever Gauzy repository
RUN git clone --depth 1 --branch master https://github.com/ever-co/ever-gauzy.git .
# Install dependencies with Yarn
RUN yarn install --frozen-lockfile --network-timeout 1000000
# Build the application
RUN yarn build:prod
# Production stage
FROM node:18-alpine
# Install runtime dependencies
RUN apk add --no-cache \
curl \
bash \
postgresql-client \
ca-certificates \
dumb-init
# Create app user for security
RUN addgroup -g 1000 gauzy && \
adduser -u 1000 -G gauzy -s /bin/bash -D gauzy
# Set working directory
WORKDIR /app
# Copy built application from builder stage
COPY --from=builder --chown=gauzy:gauzy /app/dist /app/dist
COPY --from=builder --chown=gauzy:gauzy /app/node_modules /app/node_modules
COPY --from=builder --chown=gauzy:gauzy /app/package.json /app/package.json
COPY --from=builder --chown=gauzy:gauzy /app/.env.sample /app/.env.sample
# Create directories for persistent data
RUN mkdir -p /app/uploads /app/logs /app/public && \
chown -R gauzy:gauzy /app/uploads /app/logs /app/public
# Switch to non-root user
USER gauzy
# Expose application ports
# 3000 - API server
# 4200 - Web application
EXPOSE 3000 4200
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:3000/api/health || exit 1
# Use dumb-init for proper signal handling
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
# Start the application
CMD ["node", "dist/apps/api/main.js"]

Key Features:

  • Multi-stage build reduces final image size
  • Non-root user for enhanced security
  • Health checks for container orchestration
  • Persistent volume directories pre-created
  • Production build optimization

Step 3: Create Environment Configuration

Create a comprehensive .env.example file:

Terminal window
# Application Configuration
APP_NAME="Ever Gauzy"
APP_LOGO="https://example-app.klutch.sh/assets/images/logo.png"
APP_SIGNATURE="Ever Gauzy Platform"
APP_LINK="https://example-app.klutch.sh"
NODE_ENV=production
# Server Configuration
API_HOST=0.0.0.0
API_PORT=3000
API_BASE_URL=https://example-app.klutch.sh/api
CLIENT_BASE_URL=https://example-app.klutch.sh
# Platform URLs
PLATFORM_WEBSITE_URL=https://gauzy.co
PLATFORM_WEBSITE_DOWNLOAD_URL=https://gauzy.co/downloads
# Database Configuration (PostgreSQL recommended)
DB_ORM=typeorm
DB_TYPE=postgres
DB_HOST=postgres.internal.example-app.klutch.sh
DB_PORT=5432
DB_NAME=gauzy
DB_USER=gauzy_user
DB_PASS=secure_database_password_here
DB_LOGGING=error
DB_POOL_SIZE=40
DB_CONNECTION_TIMEOUT=30000
DB_SSL_MODE=false
# Redis Configuration (recommended for production)
REDIS_ENABLED=true
REDIS_HOST=redis.internal.example-app.klutch.sh
REDIS_PORT=6379
REDIS_PASSWORD=secure_redis_password_here
REDIS_TLS=false
REDIS_URL=redis://:secure_redis_password_here@redis.internal.example-app.klutch.sh:6379
# Session Configuration
EXPRESS_SESSION_SECRET=secure_session_secret_minimum_32_characters
# JWT Configuration
JWT_SECRET=secure_jwt_secret_minimum_32_characters
JWT_TOKEN_EXPIRATION_TIME=86400
JWT_REFRESH_TOKEN_SECRET=secure_refresh_token_secret_32_chars
JWT_REFRESH_TOKEN_EXPIRATION_TIME=2592000
# Email Verification
JWT_VERIFICATION_TOKEN_SECRET=secure_verification_secret_32_chars
JWT_VERIFICATION_TOKEN_EXPIRATION_TIME=86400
# Magic Link Authentication
MAGIC_CODE_EXPIRATION_TIME=600
# Rate Limiting
THROTTLE_ENABLED=true
THROTTLE_TTL=60000
THROTTLE_LIMIT=300
# File Upload Configuration
FILE_STORAGE_PROVIDER=local
# For local storage
UPLOAD_PATH=/app/uploads
MAX_FILE_SIZE=10485760
# Email Configuration (SMTP)
MAIL_FROM_ADDRESS=noreply@yourdomain.com
MAIL_FROM_NAME="Ever Gauzy"
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=your-email@gmail.com
MAIL_PASSWORD=your-app-password
MAIL_SECURE=false
# SMS Configuration (optional - Twilio)
TWILIO_ACCOUNT_SID=
TWILIO_AUTH_TOKEN=
TWILIO_FROM_NUMBER=
# Integration Configuration (optional)
# Upwork Integration
UPWORK_CLIENT_ID=
UPWORK_CLIENT_SECRET=
UPWORK_CALLBACK_URL=https://example-app.klutch.sh/api/integrations/upwork/callback
# HubStaff Integration
HUBSTAFF_CLIENT_ID=
HUBSTAFF_CLIENT_SECRET=
HUBSTAFF_CALLBACK_URL=https://example-app.klutch.sh/api/integrations/hubstaff/callback
# GitHub Integration
GAUZY_GITHUB_CLIENT_ID=
GAUZY_GITHUB_CLIENT_SECRET=
GAUZY_GITHUB_WEBHOOK_URL=https://example-app.klutch.sh/api/integrations/github/webhook
GAUZY_GITHUB_WEBHOOK_SECRET=
# OAuth Configuration (optional)
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GOOGLE_CALLBACK_URL=https://example-app.klutch.sh/api/auth/google/callback
FACEBOOK_CLIENT_ID=
FACEBOOK_CLIENT_SECRET=
FACEBOOK_CALLBACK_URL=https://example-app.klutch.sh/api/auth/facebook/callback
# Logging Configuration
LOG_LEVEL=info
SENTRY_DSN=
# Feature Flags
ALLOW_SUPER_ADMIN_ROLE=true
DEMO=false

Step 4: Create Docker Ignore File

Create a .dockerignore file to optimize build times:

# Git files
.git
.gitignore
.gitattributes
# Environment files
.env
.env.local
.env.*.local
# Node modules (will be installed during build)
node_modules
*/*/node_modules
# Build artifacts
dist
build
.next
out
# IDE files
.vscode
.idea
*.swp
*.swo
*~
# OS files
.DS_Store
Thumbs.db
# Documentation
*.md
docs
# Test files
**/*.spec.ts
**/*.test.ts
coverage
.nyc_output
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Temporary files
tmp
temp
*.tmp

Step 5: Create Initialization Script (Optional)

Create a docker-entrypoint.sh script for automated database migrations:

#!/bin/bash
set -e
echo "Starting Ever Gauzy..."
# Wait for database to be ready
echo "Waiting for database connection..."
until PGPASSWORD=$DB_PASS psql -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME" -c '\q' 2>/dev/null; do
echo "PostgreSQL is unavailable - sleeping"
sleep 2
done
echo "PostgreSQL is up - proceeding with startup"
# Run database migrations (if needed)
if [ "$RUN_MIGRATIONS" = "true" ]; then
echo "Running database migrations..."
node dist/apps/api/main.js migrate
fi
# Seed initial data (only for first deployment)
if [ "$SEED_DATA" = "true" ]; then
echo "Seeding database with initial data..."
node dist/apps/api/main.js seed
fi
# Start the application
echo "Starting Ever Gauzy API server..."
exec node dist/apps/api/main.js

Make it executable:

Terminal window
chmod +x docker-entrypoint.sh

Step 6: Test Locally (Optional)

Test your Docker setup locally before deploying:

Terminal window
# Build the Docker image
docker build -t ever-gauzy-klutch .
# Run with environment variables
docker run -d \
--name gauzy-test \
-p 3000:3000 \
-p 4200:4200 \
-e NODE_ENV=production \
-e DB_TYPE=postgres \
-e DB_HOST=your-db-host \
-e DB_PORT=5432 \
-e DB_NAME=gauzy \
-e DB_USER=gauzy_user \
-e DB_PASS=your-password \
-e JWT_SECRET=test-secret-32-characters-min \
-v gauzy-uploads:/app/uploads \
ever-gauzy-klutch
# Check logs
docker logs -f gauzy-test
# Access the application at http://localhost:3000
# Stop and remove when done
docker stop gauzy-test
docker rm gauzy-test

Step 7: Push to GitHub

Commit and push your configuration to GitHub:

Terminal window
git add Dockerfile .env.example .dockerignore docker-entrypoint.sh
git commit -m "Initial Ever Gauzy deployment configuration"
git remote add origin https://github.com/yourusername/ever-gauzy-klutch.git
git push -u origin main

Deploying to Klutch.sh

Now deploy Ever Gauzy on Klutch.sh with persistent storage and database integration:

  1. Set Up PostgreSQL Database

    Before deploying Ever Gauzy, you need a PostgreSQL database. Follow our PostgreSQL deployment guide to set up a database on Klutch.sh, or use an external managed PostgreSQL service.

    Note your database connection details:

    • Host: your-postgres-app.klutch.sh (if using TCP traffic on Klutch.sh)
    • Port: 8000 (external port for TCP traffic on Klutch.sh)
    • Database name: gauzy
    • Username: gauzy_user
    • Password: (secure password you set)
  2. Optional: Set Up Redis Cache

    For production deployments, deploy Redis for caching and session management. Follow our Redis deployment guide.

    Redis connection details:

    • Host: your-redis-app.klutch.sh
    • Port: 8000
    • Password: (secure password you set)
  3. Log in to Klutch.sh

    Navigate to klutch.sh/app and sign in to your account.

  4. Create a New Project

    Click “New Project” and give it a descriptive name like “Ever Gauzy Platform”.

  5. Create a New App

    Within your project:

    • Click “New App”
    • Select “GitHub” as your git source
    • Choose your Ever Gauzy repository
    • Select the main or master branch
    • Klutch.sh will automatically detect the Dockerfile
  6. Configure Network Settings

    Set up networking for HTTP traffic:

    • Traffic Type: Select HTTP
    • Internal Port: Enter 3000 (API server port)
    • Ever Gauzy serves the web application and API on the same port in this configuration
  7. Configure Environment Variables

    Add all required environment variables in the Klutch.sh dashboard. At minimum, configure:

    Database Configuration:

    DB_TYPE=postgres
    DB_HOST=your-postgres-app.klutch.sh
    DB_PORT=8000
    DB_NAME=gauzy
    DB_USER=gauzy_user
    DB_PASS=your-secure-database-password

    Application URLs:

    API_BASE_URL=https://example-app.klutch.sh/api
    CLIENT_BASE_URL=https://example-app.klutch.sh
    NODE_ENV=production

    Security Secrets (generate secure random strings):

    JWT_SECRET=minimum-32-character-secure-random-string
    JWT_REFRESH_TOKEN_SECRET=minimum-32-character-secure-random-string
    JWT_VERIFICATION_TOKEN_SECRET=minimum-32-character-secure-random-string
    EXPRESS_SESSION_SECRET=minimum-32-character-secure-random-string

    Redis Configuration (if using):

    REDIS_ENABLED=true
    REDIS_HOST=your-redis-app.klutch.sh
    REDIS_PORT=8000
    REDIS_PASSWORD=your-redis-password

    Replace example-app.klutch.sh with your actual Klutch.sh domain.

  8. Attach Persistent Volumes

    Ever Gauzy requires persistent storage for uploaded files and documents:

    Volume 1 - File Uploads:

    • Mount Path: /app/uploads
    • Size: 10GB-50GB (depending on expected usage)
    • Stores user uploads, documents, avatars, and media files

    Volume 2 - Application Logs:

    • Mount Path: /app/logs
    • Size: 5GB-10GB
    • Stores application logs for debugging and monitoring

    Persistent volumes ensure your data survives deployments and container restarts.

  9. Configure Resources

    Set appropriate compute resources:

    • CPU: 2-4 vCPUs minimum (4+ for production)
    • Memory: 4GB minimum (8GB+ recommended for production)
    • Instances: Start with 1, scale horizontally as needed
  10. Deploy Your Application

    Click “Deploy” to start the deployment process. Klutch.sh will:

    • Build your Docker image from the Dockerfile
    • Configure networking and persistent storage
    • Set up environment variables
    • Deploy the container
    • Assign a domain like example-app.klutch.sh

    Initial deployment may take 10-15 minutes as Ever Gauzy builds and initializes the database.

  11. Initialize Database

    On first deployment, Ever Gauzy will automatically:

    • Run database migrations to create tables and schemas
    • Seed initial data (admin user, organizations, roles)

    Monitor the deployment logs to ensure initialization completes successfully.

  12. Access Ever Gauzy

    Once deployed, access Ever Gauzy at your Klutch.sh domain:

    • URL: https://example-app.klutch.sh
    • Default Admin Email: admin@ever.co
    • Default Admin Password: admin

    Important: Change the admin password immediately after first login!


Initial Configuration

First Login and Setup

After deploying Ever Gauzy, complete the initial configuration:

  1. Change Admin Credentials

    Navigate to SettingsProfile and update:

    • Admin email address
    • Strong password (minimum 12 characters)
    • Profile information
  2. Configure Your Organization

    Set up your organization details:

    • Navigate to SettingsOrganizations
    • Update organization name, logo, and branding
    • Configure contact information and address
    • Set default currency and timezone
    • Configure working hours and holidays
  3. Set Up Employees

    Add your team members:

    • Navigate to EmployeesAdd Employee
    • Enter employee details (name, email, role)
    • Set employment type (full-time, contractor, etc.)
    • Configure pay rates and billing rates
    • Invite employees via email
  4. Configure Teams and Departments

    Organize your workforce:

    • Create departments (Engineering, Sales, Marketing, etc.)
    • Set up teams within departments
    • Assign team managers and members
    • Define team goals and KPIs
  5. Set Up Projects

    Create projects for work tracking:

    • Navigate to ProjectsAdd Project
    • Define project details, budget, and timeline
    • Assign team members to projects
    • Configure task lists and milestones
    • Set up project billing and cost tracking
  6. Configure Roles and Permissions

    Define access controls:

    • Navigate to SettingsRoles & Permissions
    • Create custom roles for different user types
    • Set granular permissions for each role
    • Assign roles to employees

Email Configuration

Configure SMTP for sending notifications and invitations:

Add these environment variables in Klutch.sh:

MAIL_FROM_ADDRESS=noreply@yourdomain.com
MAIL_FROM_NAME="Ever Gauzy"
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=your-email@gmail.com
MAIL_PASSWORD=your-app-password
MAIL_SECURE=false

For Gmail:

  1. Enable 2-factor authentication
  2. Generate an app-specific password
  3. Use the app password in MAIL_PASSWORD

Custom Domain Setup

Configure a custom domain for your Ever Gauzy instance:

  1. In Klutch.sh dashboard, navigate to your app settings

  2. Go to DomainsAdd Custom Domain

  3. Enter your domain: gauzy.yourdomain.com

  4. Add the CNAME record to your DNS:

    • Name: gauzy
    • Value: example-app.klutch.sh
    • TTL: 3600
  5. Update environment variables:

    API_BASE_URL=https://gauzy.yourdomain.com/api
    CLIENT_BASE_URL=https://gauzy.yourdomain.com
  6. Redeploy to apply changes

Klutch.sh automatically provisions SSL certificates via Let’s Encrypt.


Using Ever Gauzy

Time Tracking

Manual Time Entry:

  1. Navigate to Timesheet
  2. Click Add Time Log
  3. Select date, project, and task
  4. Enter start/end time or duration
  5. Add description and submit

Timer-Based Tracking:

  1. Click the timer icon in the navigation
  2. Select project and task
  3. Click Start Timer
  4. Work on your task
  5. Click Stop when finished
  6. Review and submit time log

Desktop Time Tracker (optional):

  • Download the Ever Gauzy Desktop Timer app
  • Configure connection to your Klutch.sh instance
  • Enable activity monitoring and screenshots
  • Track time automatically while working

Project Management

Create Projects:

1. Navigate to Projects → Add Project
2. Enter project details:
- Name and description
- Client/customer
- Start and end dates
- Budget and currency
3. Assign team members
4. Set up task lists
5. Configure billing settings

Manage Tasks:

  • Create tasks with titles, descriptions, priorities
  • Assign tasks to team members
  • Set due dates and estimates
  • Track progress and completion
  • Link tasks to time tracking

Invoicing and Billing

Generate Invoices:

  1. Navigate to InvoicingAdd Invoice
  2. Select client and project
  3. Add invoice items:
    • Billable time logs
    • Expenses
    • Fixed-price items
  4. Review totals and tax calculations
  5. Send invoice to client via email

Track Expenses:

  • Record expenses by project or category
  • Upload receipt images
  • Mark expenses as billable
  • Include in client invoices
  • Generate expense reports

Employee Management

Onboarding Workflow:

  1. Create employee profile
  2. Send invitation email
  3. Employee completes profile
  4. Assign to departments and teams
  5. Set up goals and KPIs
  6. Configure permissions and access

Performance Tracking:

  • Set individual and team goals
  • Define KPIs and metrics
  • Track progress toward targets
  • Conduct performance reviews
  • Generate performance reports

Production Best Practices

Security Hardening

Secure Secrets Management:

  • Use strong, unique passwords (minimum 32 characters for JWT secrets)
  • Rotate JWT secrets periodically
  • Store secrets securely (never commit to repository)
  • Use different secrets for development and production
  • Enable Redis password protection
  • Configure database SSL connections

Access Control:

  • Implement role-based access control (RBAC)
  • Follow principle of least privilege
  • Regularly audit user permissions
  • Disable default admin account after creating new admin
  • Enforce strong password policies
  • Enable two-factor authentication for admin accounts

Network Security:

  • Use HTTPS only (automatic on Klutch.sh)
  • Configure CORS properly
  • Implement rate limiting (already configured)
  • Monitor for suspicious activity
  • Regularly review access logs

Performance Optimization

Database Optimization:

-- Create indexes for frequently queried columns
CREATE INDEX idx_employee_user_id ON employee(user_id);
CREATE INDEX idx_timesheet_employee_id ON timesheet(employee_id);
CREATE INDEX idx_task_project_id ON task(project_id);
-- Analyze query performance
EXPLAIN ANALYZE SELECT * FROM timesheet WHERE employee_id = '...';
-- Monitor slow queries
SELECT query, mean_exec_time, calls
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 10;

Redis Caching: Enable Redis for significant performance improvements:

  • Session management (reduces database load)
  • Query result caching
  • Background job queues
  • Real-time features

Application Tuning: Configure optimal settings in environment variables:

DB_POOL_SIZE=40
THROTTLE_LIMIT=300
MAX_FILE_SIZE=10485760

Backup Strategy

Database Backups:

# Automated backup script
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backups"
# Create backup directory
mkdir -p $BACKUP_DIR
# Backup PostgreSQL database
PGPASSWORD=$DB_PASS pg_dump \
-h $DB_HOST \
-p $DB_PORT \
-U $DB_USER \
-d $DB_NAME \
-F c \
-f $BACKUP_DIR/gauzy_backup_$DATE.dump
# Compress backup
gzip $BACKUP_DIR/gauzy_backup_$DATE.dump
# Upload to S3 or cloud storage (optional)
aws s3 cp $BACKUP_DIR/gauzy_backup_$DATE.dump.gz \
s3://your-bucket/gauzy-backups/
# Keep only last 30 days of backups
find $BACKUP_DIR -name "gauzy_backup_*.dump.gz" -mtime +30 -delete
echo "Backup completed: gauzy_backup_$DATE.dump.gz"

File Storage Backups:

  • Persistent volumes on Klutch.sh are automatically backed up
  • Consider additional backups to S3-compatible storage
  • Test backup restoration procedures regularly

Restore Procedure:

Terminal window
# Restore from PostgreSQL dump
PGPASSWORD=$DB_PASS pg_restore \
-h $DB_HOST \
-p $DB_PORT \
-U $DB_USER \
-d $DB_NAME \
-c \
gauzy_backup_20240101_120000.dump

Monitoring and Logging

Application Monitoring:

  • Monitor API response times
  • Track error rates and exceptions
  • Set up alerts for critical issues
  • Monitor database connection pool usage
  • Track memory and CPU utilization

Health Checks: Ever Gauzy includes a health endpoint:

Terminal window
# Check API health
curl https://example-app.klutch.sh/api/health
# Expected response
{
"status": "ok",
"info": {
"database": { "status": "up" },
"redis": { "status": "up" }
}
}

Log Management:

  • Configure appropriate log levels for production
  • Centralize logs for analysis
  • Set up log rotation to manage disk space
  • Monitor logs for errors and warnings

Sentry Integration (optional):

SENTRY_DSN=https://your-sentry-dsn@sentry.io/project-id
SENTRY_HTTP_TRACING_ENABLED=true
SENTRY_POSTGRES_TRACKING_ENABLED=false

Scaling Strategies

Horizontal Scaling:

  • Increase instance count in Klutch.sh dashboard
  • Configure load balancing (automatic on Klutch.sh)
  • Ensure Redis is enabled for session sharing
  • Use external PostgreSQL for centralized data

Vertical Scaling:

  • Increase CPU allocation for compute-intensive operations
  • Add memory for handling more concurrent users
  • Scale database resources separately

Database Scaling:

  • Implement read replicas for reporting queries
  • Consider connection pooling (PgBouncer)
  • Optimize queries and add indexes
  • Partition large tables by date or organization

Troubleshooting

Application Won’t Start

Symptom: Container restarts repeatedly or fails to start

Solutions:

  1. Check deployment logs in Klutch.sh dashboard

  2. Verify database connection:

    Terminal window
    # Test database connectivity
    PGPASSWORD=$DB_PASS psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -c "SELECT version();"
  3. Ensure all required environment variables are set

  4. Verify JWT secrets are at least 32 characters

  5. Check database credentials are correct

  6. Ensure database is accessible from your app

Cannot Login

Symptom: Admin credentials not working

Solutions:

  1. Verify database was seeded with initial data

  2. Reset admin password via database:

    -- Connect to database
    UPDATE "user"
    SET password = '$2a$10$example_hashed_password'
    WHERE email = 'admin@ever.co';
  3. Check JWT_SECRET is configured correctly

  4. Verify Redis connection if session issues persist

  5. Clear browser cache and cookies

Time Tracking Not Working

Symptom: Timer doesn’t start or time logs not saved

Solutions:

  1. Check employee is assigned to project
  2. Verify project has active status
  3. Ensure employee has time tracking permissions
  4. Check database connectivity
  5. Review application logs for errors
  6. Verify task exists and is active

File Uploads Failing

Symptom: Cannot upload documents or images

Solutions:

  1. Verify persistent volume is attached at /app/uploads

  2. Check volume has sufficient space

  3. Ensure MAX_FILE_SIZE environment variable is set appropriately

  4. Verify file type is allowed

  5. Check disk space on persistent volume:

    Terminal window
    df -h /app/uploads
  6. Review permissions on upload directory

Database Connection Errors

Symptom: “Connection refused” or “Connection timeout” errors

Solutions:

  1. Verify PostgreSQL is running and accessible

  2. Check database host and port configuration

  3. Verify network connectivity:

    Terminal window
    nc -zv $DB_HOST $DB_PORT
  4. Check PostgreSQL allows connections from application

  5. Verify credentials are correct

  6. Review PostgreSQL logs for connection issues

  7. Ensure database connection pool size is appropriate

Performance Issues

Symptom: Slow response times or timeout errors

Solutions:

  1. Enable Redis caching for improved performance
  2. Optimize database queries and add indexes
  3. Increase database connection pool size
  4. Scale application resources (CPU/memory)
  5. Monitor slow query logs
  6. Implement query result caching
  7. Consider read replicas for reporting queries
  8. Optimize file upload sizes

Integration Issues

Symptom: OAuth or external integrations not working

Solutions:

  1. Verify callback URLs match exactly (including https)
  2. Check OAuth client IDs and secrets are correct
  3. Ensure callback URLs are whitelisted in external service
  4. Verify external service credentials
  5. Check firewall rules allow outbound connections
  6. Review integration logs for specific errors

Sample Code

REST API Integration

Node.js Example (using Axios):

const axios = require('axios');
// Configuration
const API_BASE_URL = 'https://example-app.klutch.sh/api';
const API_TOKEN = 'your-jwt-token-here';
// Create API client
const gauzyAPI = axios.create({
baseURL: API_BASE_URL,
headers: {
'Authorization': `Bearer ${API_TOKEN}`,
'Content-Type': 'application/json'
}
});
// Get all employees
async function getEmployees() {
try {
const response = await gauzyAPI.get('/employee');
console.log('Employees:', response.data);
return response.data;
} catch (error) {
console.error('Error fetching employees:', error.response?.data || error.message);
throw error;
}
}
// Create a time log
async function createTimeLog(data) {
try {
const response = await gauzyAPI.post('/timesheet/time-log', {
employeeId: data.employeeId,
projectId: data.projectId,
taskId: data.taskId,
logType: 'TRACKED',
startedAt: data.startedAt,
stoppedAt: data.stoppedAt,
description: data.description
});
console.log('Time log created:', response.data);
return response.data;
} catch (error) {
console.error('Error creating time log:', error.response?.data || error.message);
throw error;
}
}
// Get projects
async function getProjects(organizationId) {
try {
const response = await gauzyAPI.get('/organization-projects', {
params: { organizationId }
});
console.log('Projects:', response.data);
return response.data;
} catch (error) {
console.error('Error fetching projects:', error.response?.data || error.message);
throw error;
}
}
// Create an invoice
async function createInvoice(data) {
try {
const response = await gauzyAPI.post('/invoices', {
invoiceDate: data.invoiceDate,
invoiceNumber: data.invoiceNumber,
dueDate: data.dueDate,
organizationContactId: data.clientId,
organizationId: data.organizationId,
invoiceItems: data.items,
totalValue: data.totalValue,
currency: data.currency
});
console.log('Invoice created:', response.data);
return response.data;
} catch (error) {
console.error('Error creating invoice:', error.response?.data || error.message);
throw error;
}
}
// Usage example
(async () => {
try {
// Get all employees
const employees = await getEmployees();
// Create a time log
if (employees.items && employees.items.length > 0) {
const timeLog = await createTimeLog({
employeeId: employees.items[0].id,
projectId: 'project-uuid-here',
startedAt: new Date('2024-01-15T09:00:00Z'),
stoppedAt: new Date('2024-01-15T17:00:00Z'),
description: 'Working on feature development'
});
}
} catch (error) {
console.error('API Error:', error);
}
})();

Python Example (using Requests):

import requests
from datetime import datetime, timedelta
from typing import Dict, List, Optional
class GauzyAPI:
def __init__(self, base_url: str, token: str):
self.base_url = base_url.rstrip('/')
self.session = requests.Session()
self.session.headers.update({
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
})
def get_employees(self) -> List[Dict]:
"""Fetch all employees"""
response = self.session.get(f'{self.base_url}/employee')
response.raise_for_status()
return response.json()
def create_time_log(self, employee_id: str, project_id: str,
started_at: datetime, stopped_at: datetime,
description: str = '', task_id: Optional[str] = None) -> Dict:
"""Create a new time log entry"""
data = {
'employeeId': employee_id,
'projectId': project_id,
'logType': 'TRACKED',
'startedAt': started_at.isoformat(),
'stoppedAt': stopped_at.isoformat(),
'description': description
}
if task_id:
data['taskId'] = task_id
response = self.session.post(f'{self.base_url}/timesheet/time-log', json=data)
response.raise_for_status()
return response.json()
def get_projects(self, organization_id: str) -> List[Dict]:
"""Get all projects for an organization"""
params = {'organizationId': organization_id}
response = self.session.get(f'{self.base_url}/organization-projects', params=params)
response.raise_for_status()
return response.json()
def create_invoice(self, organization_id: str, client_id: str,
invoice_date: datetime, due_date: datetime,
items: List[Dict], currency: str = 'USD') -> Dict:
"""Create a new invoice"""
total_value = sum(item['price'] * item['quantity'] for item in items)
data = {
'invoiceDate': invoice_date.isoformat(),
'dueDate': due_date.isoformat(),
'organizationContactId': client_id,
'organizationId': organization_id,
'invoiceItems': items,
'totalValue': total_value,
'currency': currency
}
response = self.session.post(f'{self.base_url}/invoices', json=data)
response.raise_for_status()
return response.json()
def get_time_logs(self, employee_id: str, start_date: datetime,
end_date: datetime) -> List[Dict]:
"""Get time logs for an employee within date range"""
params = {
'employeeId': employee_id,
'startDate': start_date.isoformat(),
'endDate': end_date.isoformat()
}
response = self.session.get(f'{self.base_url}/timesheet/time-log', params=params)
response.raise_for_status()
return response.json()
# Usage example
if __name__ == '__main__':
# Initialize API client
api = GauzyAPI(
base_url='https://example-app.klutch.sh/api',
token='your-jwt-token-here'
)
try:
# Get employees
employees = api.get_employees()
print(f"Found {len(employees['items'])} employees")
# Create time log
if employees['items']:
employee_id = employees['items'][0]['id']
time_log = api.create_time_log(
employee_id=employee_id,
project_id='project-uuid-here',
started_at=datetime.now() - timedelta(hours=8),
stopped_at=datetime.now(),
description='Development work on new features'
)
print(f"Time log created: {time_log['id']}")
# Get projects
projects = api.get_projects(organization_id='org-uuid-here')
print(f"Found {len(projects)} projects")
except requests.exceptions.HTTPError as e:
print(f"API Error: {e.response.status_code} - {e.response.text}")
except Exception as e:
print(f"Error: {str(e)}")

Go Example:

package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
const (
APIBaseURL = "https://example-app.klutch.sh/api"
APIToken = "your-jwt-token-here"
)
type GauzyClient struct {
BaseURL string
HTTPClient *http.Client
Token string
}
type Employee struct {
ID string `json:"id"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
Email string `json:"email"`
Organization string `json:"organizationId"`
}
type TimeLog struct {
ID string `json:"id,omitempty"`
EmployeeID string `json:"employeeId"`
ProjectID string `json:"projectId"`
TaskID string `json:"taskId,omitempty"`
LogType string `json:"logType"`
StartedAt time.Time `json:"startedAt"`
StoppedAt time.Time `json:"stoppedAt"`
Description string `json:"description"`
}
func NewGauzyClient(baseURL, token string) *GauzyClient {
return &GauzyClient{
BaseURL: baseURL,
Token: token,
HTTPClient: &http.Client{
Timeout: time.Second * 30,
},
}
}
func (c *GauzyClient) doRequest(method, path string, body interface{}) ([]byte, error) {
var reqBody io.Reader
if body != nil {
jsonData, err := json.Marshal(body)
if err != nil {
return nil, fmt.Errorf("marshal request body: %w", err)
}
reqBody = bytes.NewBuffer(jsonData)
}
req, err := http.NewRequest(method, c.BaseURL+path, reqBody)
if err != nil {
return nil, fmt.Errorf("create request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+c.Token)
req.Header.Set("Content-Type", "application/json")
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("execute request: %w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("read response: %w", err)
}
if resp.StatusCode >= 400 {
return nil, fmt.Errorf("API error %d: %s", resp.StatusCode, string(respBody))
}
return respBody, nil
}
func (c *GauzyClient) GetEmployees() ([]Employee, error) {
respBody, err := c.doRequest("GET", "/employee", nil)
if err != nil {
return nil, err
}
var result struct {
Items []Employee `json:"items"`
}
if err := json.Unmarshal(respBody, &result); err != nil {
return nil, fmt.Errorf("unmarshal response: %w", err)
}
return result.Items, nil
}
func (c *GauzyClient) CreateTimeLog(timeLog TimeLog) (*TimeLog, error) {
timeLog.LogType = "TRACKED"
respBody, err := c.doRequest("POST", "/timesheet/time-log", timeLog)
if err != nil {
return nil, err
}
var result TimeLog
if err := json.Unmarshal(respBody, &result); err != nil {
return nil, fmt.Errorf("unmarshal response: %w", err)
}
return &result, nil
}
func main() {
client := NewGauzyClient(APIBaseURL, APIToken)
// Get employees
employees, err := client.GetEmployees()
if err != nil {
fmt.Printf("Error fetching employees: %v\n", err)
return
}
fmt.Printf("Found %d employees\n", len(employees))
// Create time log
if len(employees) > 0 {
timeLog := TimeLog{
EmployeeID: employees[0].ID,
ProjectID: "project-uuid-here",
StartedAt: time.Now().Add(-8 * time.Hour),
StoppedAt: time.Now(),
Description: "Working on API integration",
}
created, err := client.CreateTimeLog(timeLog)
if err != nil {
fmt.Printf("Error creating time log: %v\n", err)
return
}
fmt.Printf("Time log created: %s\n", created.ID)
}
}

Additional Resources


Conclusion

Deploying Ever Gauzy on Klutch.sh provides your organization with a powerful, self-hosted business management platform that puts you in complete control of your data and workflows. With comprehensive ERP, CRM, HRM, and project management capabilities, Ever Gauzy enables teams of all sizes to streamline operations, track time and productivity, manage customer relationships, and grow their business efficiently.

By leveraging Klutch.sh’s managed infrastructure, you get automatic Docker deployments, persistent storage for business-critical data, seamless scaling as your organization grows, and enterprise-grade reliability without the operational complexity. Focus on running your business while Klutch.sh handles the infrastructure.

Start managing your entire business operation from a single, unified platform. Deploy Ever Gauzy on Klutch.sh today and transform how your organization works.