Skip to main content

Configuration and Customization Guide

This comprehensive guide covers all configuration and customization options for OmniCRM, including backend settings, frontend branding, visual customization, and deployment best practices.

Overview

OmniCRM uses two main configuration systems:

Backend Configuration:

  • File: OmniCRM-API/crm_config.yaml
  • Format: YAML
  • Requires: API restart after changes
  • Used for: Database, integrations, security, provisioning

Frontend Configuration:

  • File: OmniCRM-UI/.env
  • Format: Environment variables
  • Requires: UI rebuild after changes
  • Used for: Branding, features, external services

Backend Configuration (crm_config.yaml)

The crm_config.yaml file contains all backend system settings.

Location: /OmniCRM/OmniCRM-API/crm_config.yaml

Database Configuration

database:
username: omnitouch
password: omnitouch2024
server: localhost

Fields:

  • username - MySQL database username
  • password - MySQL database password
  • server - Database server hostname or IP (default: localhost)

Database Connection:

  • Database name is hardcoded as omnicrm
  • Default port: 3306 (MySQL default)
  • Connection string: mysql+pymysql://username:password@server/omnicrm

Security Note: Never commit this file with real credentials to version control. Use environment-specific configuration or secrets management.

Note: This should match your .env database credentials. In containerized deployments, the server is typically db (Docker service name).

Service Types

service_types:
- omnicharge
- mobile
- fixed
- fixed-voice
- hotspot
- dongle

Purpose: Defines valid service types for your deployment.

These are used throughout the system for:

  • Product categorization
  • Addon filtering (addons match service types)
  • Provisioning workflows
  • Reporting and analytics

Add custom service types here for your specific use cases.

HSS Integration (Home Subscriber Server)

For mobile network operators with HSS integration:

hss:
hss_peers:
- 'http://10.179.2.140:8080'
apn_list: "1,2,3,4,5,6"

Configuration:

  • hss_peers - List of HSS endpoints for subscriber provisioning
  • apn_list - Comma-separated list of APN IDs available for provisioning

Used for: Mobile network provisioning and subscriber authentication.

Mailjet Email Template Configuration

OmniCRM uses Mailjet for transactional emails. Each email type has its own template configuration:

mailjet:
api_key: your_mailjet_api_key
api_secret: your_mailjet_api_secret

# Customer Welcome Email
api_crmCommunicationCustomerWelcome:
from_email: "support@yourcompany.com"
from_name: "Your Company Support"
template_id: 5977509
subject: "Welcome to YourCompany"

# Customer Invoice Email
api_crmCommunicationCustomerInvoice:
from_email: "billing@yourcompany.com"
from_name: "Your Company Billing"
template_id: 6759851
subject: "Your Invoice - "

# Invoice Reminder
api_crmCommunicationCustomerInvoiceReminder:
from_email: "billing@yourcompany.com"
from_name: "Your Company Billing"
template_id: 5977570
subject: "Invoice Payment Reminder"

# User Welcome Email (Staff/Admin)
api_crmCommunicationUserWelcome:
from_email: "admin@yourcompany.com"
from_name: "Your Company Admin"
template_id: 6118112
subject: "Welcome to the Team"

# Password Reset Request
api_crmCommunicationUserPasswordReset:
from_email: "security@yourcompany.com"
from_name: "Your Company Security"
template_id: 6735666
subject: "Password Reset Request"

# Password Reset Success Confirmation
api_crmCommunicationUserPasswordResetSuccess:
from_email: "security@yourcompany.com"
from_name: "Your Company Security"
template_id: 6118378
subject: "Password Reset Successful"

# Password Change Notification
api_crmCommunicationUserPasswordChange:
from_email: "security@yourcompany.com"
from_name: "Your Company Security"
template_id: 6118423
subject: "Password Changed"

# Email Verification
api_crmCommunicationEmailVerification:
from_email: "verify@yourcompany.com"
from_name: "Your Company Verification"
template_id: 6267350
subject: "Verify Your Email Address"

# Balance Expired Notification
api_crmCommunicationsBalanceExpired:
from_email: "alerts@yourcompany.com"
from_name: "Your Company Alerts"
template_id: 7238252
subject: "Service Balance Expired"

# Low Balance Warning
api_crmCommunicationsBalanceLow:
from_email: "alerts@yourcompany.com"
from_name: "Your Company Alerts"
template_id: 7238263
subject: "Low Balance Warning"

Creating Mailjet Templates:

  1. Log in to Mailjet dashboard (<https://app.mailjet.com>)
  2. Navigate to TransactionalTemplates
  3. Create a new template or clone an existing one
  4. Note the Template ID (numeric value)
  5. Add template variables matching the OmniCRM data structure
  6. Update crm_config.yaml with the template ID

Available Template Variables:

Each email type receives specific variables. Common examples:

  • {{customer_name}} - Customer or user name
  • {{service_name}} - Service or product name
  • {{invoice_id}} - Invoice number
  • {{invoice_amount}} - Total invoice amount
  • {{due_date}} - Payment due date
  • {{reset_link}} - Password reset URL
  • {{verification_link}} - Email verification URL
  • {{balance}} - Current account balance
  • {{expiry_date}} - Balance or service expiry date

Provisioning Configuration

provisioning:
failure_list: ['admin@yourcompany.com', 'ops@yourcompany.com']

Purpose:

  • failure_list - Email addresses notified when Ansible provisioning fails
  • Notifications include playbook name, error details, and customer information
  • Allows ops team to quickly respond to provisioning issues

Invoice Configuration

invoice:
template_filename: 'yourcompany_invoice_template.html'

Purpose:

Specifies which Jinja2 HTML template to use for PDF invoice generation.

Template Location: /OmniCRM-API/invoice_templates/

See Invoice PDF Generation section below for details on creating custom templates.

CRM Base URL

crm:
base_url: 'http://localhost:5000'

Purpose:

  • Used by Ansible playbooks to make API callbacks
  • Used in email templates for generating links to the CRM
  • Should be the publicly accessible URL of your API (not internal container names)

Examples:

  • Development: http://localhost:5000
  • Production: https://api.yourcompany.com
  • Docker: http://omnicrm-api:5000 (internal container communication)

Important:

  • Do NOT include trailing slash
  • Use publicly accessible URL if playbooks run on different servers
  • Update when deploying to production

OCS and CGRates Configuration

ocs:
ocsApi: 'http://10.179.2.142:8080/api'
ocsTenant: 'mnc380.mcc313.3gppnetwork.org'
cgrates: 'localhost:2080'

Configuration:

  • ocsApi - OCS API endpoint for subscriber management
  • ocsTenant - Tenant identifier for multi-tenant OCS deployments
  • cgrates - CGRates JSON-RPC API endpoint (host:port)

Used for: Real-time charging, balance management, usage tracking.

SMSC Configuration (SMS Gateway)

smsc:
source_msisdn: 'YourCompany'
smsc_url: 'http://10.179.2.216/SMSc/'
api_key: 'your_smsc_api_key'

Purpose:

  • Send SMS notifications to customers (low balance, service alerts, 2FA codes)
  • source_msisdn - Sender ID displayed to recipients (alphanumeric or phone number)
  • smsc_url - SMSC gateway API endpoint
  • api_key - Authentication for SMSC API

Cell Broadcast Configuration

cbc_url: 'http://10.179.1.113:8080'

Purpose: Cell Broadcast Center (CBC) API endpoint for emergency alerts.

See features_cell_broadcast for usage details.

JWT Secret Key

jwt_secret: 'CHANGE_ME_ON_DEPLOYMENT'  # Auto-generated by Ansible

Security:

  • Used to sign and verify authentication tokens (JWT)
  • Critical for authentication security - treat like a password
  • Each deployment/environment MUST have a unique secret
  • Never share or commit to version control

Automated Secret Management (Ansible Deployment):

When deploying with Ansible, the JWT secret is automatically managed:

  1. First deployment: Ansible generates a random 64-character hex string (256 bits of entropy)
  2. Subsequent deployments: Ansible preserves the existing secret from the server
  3. Each server gets its own unique secret - sessions don't work across environments

This ensures:

  • No hardcoded secrets in git repositories
  • Each environment is cryptographically isolated
  • Secrets persist across deployments (sessions aren't invalidated on redeploy)
  • Rebuilding a server generates a new secret (sessions are correctly invalidated)

Manual Secret Generation (Non-Ansible Deployments):

If deploying without Ansible, you MUST manually generate a unique secret:

# Generate a cryptographically secure random key
python3 -c "import secrets; print(secrets.token_hex(32))"
# or
openssl rand -hex 32

Then update crm_config.yaml:

jwt_secret: 'your_generated_secret_here'

Important:

  • Never use the default placeholder value CHANGE_ME_ON_DEPLOYMENT in production
  • Never share publicly - anyone with the secret can forge authentication tokens
  • Changing this invalidates all existing user sessions (users must re-login)
  • Each environment (dev, staging, prod) MUST have different secrets

Stripe Payment Configuration

stripe:
secret_key: 'sk_live_xxxxxxxxxx'
publishable_key: 'pk_live_xxxxxxxxxx'
currency: 'aud'
statement_descriptor_suffix: 'YOURCOMPANY'

Configuration:

  • secret_key - Stripe secret API key (server-side, keep confidential)
  • publishable_key - Stripe publishable key (client-side, safe to expose)
  • currency - ISO 4217 currency code (aud, usd, gbp, eur, etc.)
  • statement_descriptor_suffix - Appears on customer credit card statements

Key Types:

  • Test keys: sk_test_... and pk_test_... (for development)
  • Live keys: sk_live_... and pk_live_... (for production)

Statement Descriptor Usage:

  • Shown on customer bank statements as "YOURCOMPANY"
  • Maximum 22 characters
  • Helps customers identify charges
  • Also used in invoice PDF filenames (e.g., YOURCOMPANY_12345.pdf)

See Payment Vendor Integrations <integrations_payment_vendors> for setup details.

API Keys and IP Whitelisting

Define API keys with role-based access and IP restrictions:

api_keys:
"YOUR_API_KEY_1":
roles: ["admin"]
ips: ["127.0.0.1", "::1"]
"YOUR_API_KEY_2":
roles: ["customer_service_agent_1"]
ips: ["127.0.0.1", "::1", "10.0.1.0/24"]

# IP Whitelist (standalone, without API key)
ip_whitelist:
"10.179.2.142":
roles: ["admin"]

Purpose:

  • Allow external systems to authenticate via API key
  • Restrict access by IP address
  • Grant specific roles to API consumers
  • Useful for integrations (billing systems, monitoring, automation)

Generating API Keys:

openssl rand -base64 48

Roles:

  • admin - Full access to all endpoints
  • Custom roles defined in RBAC system

Security Best Practices:

  • Use long, random API keys (minimum 32 characters)
  • Restrict IPs to known sources only
  • Grant minimum necessary roles
  • Rotate API keys regularly
  • Monitor API key usage in logs

Security Warning:

  • Only use IP whitelist for trusted internal networks
  • Must NOT use localhost IPs (127.0.0.1, ::1)
  • Use API keys instead for external access
  • Consider firewall rules as additional protection

See administration_api_keys and concepts_api for details.


Frontend Configuration (.env)

The React UI is configured via environment variables in OmniCRM-UI/.env.

Location: /OmniCRM/OmniCRM-UI/.env

API Keys and External Services

# Google Maps API (for address autocomplete and geocoding)
VITE_GOOGLE_API_KEY=your_google_api_key

# Stripe Payment Gateway
VITE_STRIPE_PUBLISHABLE_KEY=pk_test_xxxxx

# Disable browser auto-launch on npm start
BROWSER=none

Must Match:

VITE_STRIPE_PUBLISHABLE_KEY must match stripe.publishable_key in crm_config.yaml.

Branding and Company Information

# Company Branding
VITE_COMPANY_NAME="ShellFone"
VITE_PORTAL_NAME="ShellManager"
VITE_SELF_CARE_NAME="ShellCare"
VITE_COMPANY_TAGLINE="Phones with Shells"

These values appear throughout the UI:

  • COMPANY_NAME - Displayed in page titles, emails, and customer communications
  • PORTAL_NAME - Name of the admin/staff portal (e.g., "ShellManager")
  • SELF_CARE_NAME - Name of the customer self-service portal (e.g., "ShellCare")
  • COMPANY_TAGLINE - Appears in login screens and marketing materials

Localization and Regional Settings

# Language and Locale
# Supported languages: ar, ch, en, fr, gr, it, ru, sp
VITE_DEFAULT_LANGUAGE=en
VITE_LOCALE="en-GB"

# Default Location (for address autocomplete)
VITE_DEFAULT_LOCATION="Sydney, Australia"
VITE_DEFAULT_COUNTRY="Australia"

# Currency Settings
VITE_CURRENCY_CODE="GBP"
VITE_CURRENCY_SYMBOL="£"

Supported Languages:

  • ar - Arabic
  • ch - Chinese
  • en - English (default)
  • fr - French
  • gr - Greek
  • it - Italian
  • ru - Russian
  • sp - Spanish

Common Currencies:

  • USD - $ (US Dollar)
  • GBP - £ (British Pound)
  • EUR - € (Euro)
  • AUD - $ (Australian Dollar)
  • CAD - $ (Canadian Dollar)

Note: Must match stripe.currency in crm_config.yaml.

Color Theme Configuration

# Primary Color (main brand color)
VITE_PRIMARY_COLOR=#405189

# Additional Color Options (commented examples)
# VITE_SECONDARY_COLOR=#2bFFcf
# VITE_TERTIARY_COLOR=#1a9fbf
# VITE_SUCCESS_COLOR=#28a745
# VITE_INFO_COLOR=#17a2b8
# VITE_WARNING_COLOR=#ffc107
# VITE_DANGER_COLOR=#dc3545

Available Colors:

  • VITE_PRIMARY_COLOR - Main brand color (buttons, links, highlights)
  • VITE_SECONDARY_COLOR - Accent color
  • VITE_TERTIARY_COLOR - Additional accent
  • VITE_SUCCESS_COLOR - Success messages (#28a745)
  • VITE_INFO_COLOR - Info messages (#17a2b8)
  • VITE_WARNING_COLOR - Warnings (#ffc107)
  • VITE_DANGER_COLOR - Errors (#dc3545)
  • VITE_LIGHT_COLOR - Light backgrounds (#f8f9fa)
  • VITE_DARK_COLOR - Dark text (#343a40)
  • VITE_PRIMARY_DARK_COLOR - Dark variant of primary color

Format: Hexadecimal color codes (#RRGGBB)

The primary color is applied to:

  • Navigation headers
  • Action buttons
  • Links and highlights
  • Active states
  • Brand elements

Font Configuration

# Font Family Configuration
# Sans-Serif: Inter, Roboto, Open Sans, Lato, Quicksand, Poppins, Nunito, Montserrat, Work Sans, Source Sans Pro, Raleway, Ubuntu, Josefin Sans, HKGrotesk
# Serif: Merriweather, Lora, Playfair Display
# System: System (native device fonts)
# Default: Quicksand
VITE_FONT_FAMILY=Quicksand

Important: All fonts are self-hosted locally within the OmniCRM-UI application. This means:

  • No external font loading - Fonts are bundled with the application
  • Walled garden compatible - No internet access required for fonts to work
  • Offline operation - Full functionality in air-gapped or restricted network environments
  • Privacy - No external requests to Google Fonts, Adobe Fonts, or other CDNs
  • Performance - Faster loading without external dependencies
  • Security - No third-party tracking or data leakage through font requests

Available Options:

Sans-Serif Fonts:

  • Inter, Roboto, Open Sans, Lato, Quicksand (default), Poppins, Nunito, Montserrat, Work Sans, Source Sans Pro, Raleway, Ubuntu, Josefin Sans, HKGrotesk

Serif Fonts:

  • Merriweather, Lora, Playfair Display

System Fonts:

  • System - Uses native device fonts for best performance and smallest bundle size

Adding Custom Fonts:

Yes, you can add additional fonts! All fonts are stored locally in the application.

To add a new custom font:

  1. Add font files to OmniCRM-UI/src/assets/fonts/your-font-name/

    • Use WOFF2 format for best compression and browser support
    • Include multiple weights (300, 400, 500, 600, 700) for proper rendering
    • Name files: your-font-name-300.woff2, your-font-name-400.woff2, etc.
  2. Define @font-face rules in OmniCRM-UI/src/assets/scss/fonts/_google-fonts.scss

    //
    // Your Custom Font - Description
    //

    @font-face {
    font-family: 'Your Font Name';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("../../fonts/your-font-name/your-font-name-400.woff2") format('woff2');
    }

    @font-face {
    font-family: 'Your Font Name';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("../../fonts/your-font-name/your-font-name-700.woff2") format('woff2');
    }
  3. Set in .env file:

    VITE_FONT_FAMILY=Your Font Name

Font Weight Guidelines:

  • 300 - Light (optional, for subtle headings)
  • 400 - Regular (required, default text)
  • 500 - Medium (optional, emphasis)
  • 600 - Semi-Bold (optional, subheadings)
  • 700 - Bold (required, headings and strong text)

Configure up to 6 quick-access web applications that appear in the admin dashboard:

# Web App 1: GitHub
VITE_WEB_APP_1_NAME="GitHub"
VITE_WEB_APP_1_URL="https://github.com"
VITE_WEB_APP_1_ICON_PATH="resources/webapp_icons/github.png"

# Web App 2: Xero
VITE_WEB_APP_2_NAME="Xero"
VITE_WEB_APP_2_URL="https://go.xero.com/"
VITE_WEB_APP_2_ICON_PATH="resources/webapp_icons/xero.png"

# Web App 3-6: Additional integrations
# (Configure similarly with NAME, URL, and ICON_PATH)

Pattern:

  • VITE_WEB_APP_N_NAME - Display name
  • VITE_WEB_APP_N_URL - Target URL
  • VITE_WEB_APP_N_ICON_PATH - Icon file path (relative to public/)

Example Icons: GitHub, Xero, Monday.com, Gmail, MailJet, Slack

Grafana Dashboard Integration

OmniCRM integrates with Grafana to provide analytics dashboards. Users with the grafana_access permission can access Grafana at /grafana to create custom dashboards, and those dashboards can be embedded in the OmniCRM interface.

# Grafana Dashboard Integration
# Dashboard IDs (comma-separated) - get these from /grafana/d/ID/name URLs
VITE_GRAFANA_DASHBOARD_IDS=abc123,def456,ghi789

# Dashboard Labels (comma-separated, must match order of IDs)
VITE_GRAFANA_DASHBOARD_LABELS=System Metrics,User Analytics,Network Performance

Fields:

  • VITE_GRAFANA_DASHBOARD_IDS - Comma-separated list of Grafana dashboard IDs from the URL path
  • VITE_GRAFANA_DASHBOARD_LABELS - Comma-separated list of dashboard display names (must match the order of IDs)

How to Find Dashboard IDs:

When viewing a dashboard in Grafana, the URL will look like /grafana/d/abc123/dashboard-name. The dashboard ID is the part after /d/ and before the name (in this example, abc123).

Usage:

Once configured, dashboards automatically appear in the OmniCRM sidebar under the "Dashboards" menu. Users can click to view embedded dashboards while keeping the OmniCRM navigation visible.

Example:

If your dashboard URL is http://your-server/grafana/d/system-overview-123/system-metrics, then:

  • Dashboard ID: system-overview-123
  • Dashboard Label: Choose any friendly name like "System Overview"

Important:

  • The number of IDs must match the number of labels
  • Dashboards appear in the sidebar in the order they are defined
  • Only users with the grafana_access permission can view dashboards
  • Changes require rebuilding the frontend UI

Support and Documentation URLs

# FAQs and Support URLs
VITE_FAQS_URL=https://support.yourcompany.com/faqs
VITE_SUPPORT_URL=https://support.yourcompany.com

Purpose: Links to external support resources shown in the UI.

Social Logins

# Allow Social Logins (yes|no)
VITE_ALLOW_SOCIAL_LOGINS=yes

Options:

  • yes - Enable social login buttons (Google, Facebook, etc.)
  • no - Disable social logins

Note: Social login providers must be configured separately.

Analytics and Tracking

# Google Analytics 4 or Google Tag Manager (optional)
# For GA4, use format: G-XXXXXXXXXX
# For GTM, use format: GTM-XXXXXXX
VITE_GOOGLE_TAG_ID=G-XXXXXXXXXX

Purpose: Enable Google Analytics 4 (GA4) or Google Tag Manager (GTM) tracking to monitor user behavior and application usage.

Supported Formats:

  • GA4 Measurement ID: G-XXXXXXXXXX - For Google Analytics 4 tracking
  • GTM Container ID: GTM-XXXXXXX - For Google Tag Manager
  • Disabled: Leave empty or omit to disable tracking

How It Works:

The system automatically detects the tracking service based on the ID format:

  • IDs starting with G- initialize Google Analytics 4
  • IDs starting with GTM- initialize Google Tag Manager
  • Empty or missing value disables all tracking

Features:

  • Automatic Page Tracking - Every route change is tracked as a page view
  • Custom Event Tracking - Track user interactions, button clicks, form submissions
  • No Code Changes Required - Just set the environment variable and rebuild the UI

Setup Instructions:

  1. Obtain Your Tracking ID:

    For Google Analytics 4:

    • Log in to Google Analytics
    • Create or select a GA4 property
    • Go to AdminData Streams
    • Select your web stream
    • Copy the Measurement ID (format: G-XXXXXXXXXX)

    For Google Tag Manager:

    • Log in to Google Tag Manager
    • Create or select a container
    • Copy the Container ID (format: GTM-XXXXXXX)
  2. Add to .env File:

    VITE_GOOGLE_TAG_ID=G-XXXXXXXXXX
  3. Rebuild the UI:

    cd OmniCRM-UI
    npm run build
  4. Verify Tracking:

    • Open your application in a browser
    • Check browser console for initialization messages
    • Use Google Analytics Real-Time reports to see active users

Advanced Usage - Custom Event Tracking:

The integration provides utility functions for tracking custom events throughout your application.

Example - Track Button Clicks:

import { trackEvent } from './utils/googleAnalytics';

// In your component
const handleCheckout = () => {
trackEvent('checkout_initiated', {
cart_value: 99.99,
item_count: 3,
page: '/cart'
});
// Continue with checkout logic
};

Example - Track Form Submissions:

import { trackEvent } from './utils/googleAnalytics';

const handleFormSubmit = (formType) => {
trackEvent('form_submission', {
form_type: formType,
timestamp: new Date().toISOString()
});
};

Example - Track Custom Page Views:

import { trackPageView } from './utils/googleAnalytics';

// Manually track a page view (useful for modal dialogs, tabs, etc.)
trackPageView('/virtual/page-path', 'Page Title');

Available Tracking Functions:

FunctionPurposeParameters
initializeGoogleTracking()Initialize tracking on app startNone (called automatically)
trackEvent(eventName, eventParams)Track custom eventsEvent name (string), parameters (object)
trackPageView(path, title)Track page views manuallyPath (string), title (string)

Privacy and Compliance:

Google Analytics tracking collects user behavior data. Ensure compliance with data protection regulations:

  • GDPR (Europe) - Obtain user consent before tracking, provide opt-out mechanism
  • CCPA (California) - Allow users to opt-out of data collection
  • Privacy Policy - Disclose use of Google Analytics in your privacy policy
  • Cookie Consent - Implement cookie consent banner if required by local laws
  • Data Retention - Configure appropriate data retention periods in Google Analytics settings

Troubleshooting:

IssuePossible CauseSolution
No data in GA dashboardTracking ID incorrectVerify ID format matches G-XXXXXXXXXX or GTM-XXXXXXX
Console errors on page loadInvalid tracking IDCheck for typos in .env file
Page views not trackingUI not rebuilt after .env changeRun npm run build and restart UI
Events not appearingAd blocker enabledTest with ad blocker disabled
Delayed dataNormal GA behaviorUse Real-Time reports for immediate verification

Performance Considerations:

  • Tracking scripts load asynchronously and do not block page rendering
  • Minimal performance impact (< 50KB additional payload)
  • Scripts are cached by browsers after first load
  • No tracking occurs if VITE_GOOGLE_TAG_ID is empty

Implementation Details:

  • Tracking code: OmniCRM-UI/src/utils/googleAnalytics.js
  • Page tracking hook: OmniCRM-UI/src/utils/usePageTracking.js
  • Initialization: Automatic on app startup in App.js or index.js

Top-Up and Recharge Configuration

VITE_TOPUP_PRICE_PER_DAY=10

Purpose: Sets the price per day for top-up/recharge services in the self-care portal.

Fields:

  • VITE_TOPUP_PRICE_PER_DAY - Daily price for recharge services (numeric value)

Example: If set to 10 and currency is USD, customers pay $10 per day of service.

Note: This value must match the backend pricing configuration. See features_topup_recharge for complete setup details.


Branding and Visual Customization

OmniCRM allows you to replace default branding images with your company's logo and splash screens without modifying code.

Logo Files and Fallback System

Logos are stored in /OmniCRM-UI/src/assets/images/omnitouch/ and use a fallback system:

Default Logos (always present):

  • DefaultLogoDark.png - Dark theme logo (used on light backgrounds)
  • DefaultLogoLight.png - Light theme logo (used on dark backgrounds)

Custom Logos (optional, take precedence when present):

  • logoSm.png - Small logo for collapsed sidebar (recommended: 100x100px)
  • logoDark.png - Full-size dark logo for headers (recommended: 200x50px)
  • logoLight.png - Full-size light logo for authentication screens (recommended: 200x50px)

How Logo Fallback Works:

The system attempts to load custom logos first. If a custom logo file doesn't exist, it falls back to the default:

// From Header.js
const tryImport = (filename) => {
try {
return require(`../assets/images/omnitouch/${filename}`);
} catch (err) {
return null; // Falls back to default
}
};

const userLogoSm = tryImport("logoSm.png");
const userLogoDark = tryImport("logoDark.png");
const userLogoLight = tryImport("logoLight.png");

Where Logos Appear:

  • logoSm.png - Collapsed sidebar, mobile navigation, small header displays
  • logoDark.png - Main header bar (light mode), admin dashboard header
  • logoLight.png - Login/registration screens, dark backgrounds, authentication carousel

Replacing Logos:

  1. Create Your Logo Files:

    • Use PNG format for transparency support
    • Match the recommended dimensions above
    • Ensure logos are clear at both regular and retina resolutions
  2. Add to OmniCRM:

    # Copy your logo files to the omnitouch images directory
    cp /path/to/your/logoSm.png OmniCRM-UI/src/assets/images/omnitouch/
    cp /path/to/your/logoDark.png OmniCRM-UI/src/assets/images/omnitouch/
    cp /path/to/your/logoLight.png OmniCRM-UI/src/assets/images/omnitouch/
  3. Rebuild the UI:

    cd OmniCRM-UI
    npm run build
  4. Verify Changes:

    • Check light mode header (should show logoDark.png)
    • Check dark mode header (should show logoLight.png)
    • Check collapsed sidebar (should show logoSm.png)
    • Check login screen (should show logoLight.png)

Logo Design Best Practices:

  • Contrast - Ensure logos are visible on both light and dark backgrounds
  • Simplicity - Logos should be recognizable at small sizes
  • Format - Use PNG with transparent backgrounds
  • Retina - Provide 2x resolution for high-DPI displays
  • Consistency - Use the same brand colors across all logo variants

Splash Screens and Authentication Backgrounds

The authentication screens (login, registration, password reset) use a carousel background with customizable images.

Location: /OmniCRM-UI/src/pages/AuthenticationInner/authCarousel.js

Default Configuration:

import logoLight from "../../assets/images/logo-light.png";

// Logo displayed on authentication screens
<!-- ![Company Logo](../absolute/path/to/your-logo.png) -->
<h1>INVOICE</h1>
</div>

<div class="invoice-details">
<p><strong>Invoice Number:</strong> {{ invoice_number }}</p>
<p><strong>Date:</strong> {{ date }}</p>
<p><strong>Due Date:</strong> {{ due_date }}</p>
<p><strong>Billing Period:</strong> {{ start_date }} to {{ end_date }}</p>
</div>

<div class="customer-details">
<h3>Bill To:</h3>
<p>{{ client.name }}</p>
<p>{{ client.address.address_line_1 }}</p>
<p>{{ client.address.city }}, {{ client.address.state }} {{ client.address.zip_code }}</p>
<p>{{ client.address.country }}</p>
</div>

<table>
<thead>
<tr>
<th>Description</th>
<th>Date</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
{% for transaction in transaction_list[0] %}
<tr>
<td>{{ transaction.title }}</td>
<td>{{ transaction.created }}</td>
<td>${{ "%.2f"|format(transaction.retail_cost) }}</td>
</tr>
{% endfor %}
</tbody>
</table>

<div class="total">
<p>Total Amount Due: ${{ "%.2f"|format(total_amount) }}</p>
</div>

{% if paid %}
<div style="text-align: center; color: green; font-weight: bold;">
PAID
</div>
{% endif %}

{% if void %}
<div style="text-align: center; color: red; font-weight: bold;">
VOID
</div>
{% endif %}
</body>
</html>

Template Best Practices:

  • Use absolute paths for images - file:///absolute/path/to/image.png
  • Inline CSS - WeasyPrint doesn't load external stylesheets reliably
  • Test with sample data - Use invoice_templates/rendered/ to inspect HTML
  • Page breaks - Use <div style="page-break-after: always;"></div> for multi-page invoices
  • Headers and footers - Use @page CSS rules for repeating elements
  • Currency formatting - Use Jinja2 filters: {{ "%.2f"|format(amount) }}

Creating a Custom Invoice Template

  1. Copy Example Template:

    cd /OmniCRM/OmniCRM-API/invoice_templates
    cp norfone_invoice_template.html yourcompany_invoice_template.html
  2. Edit Template:

    • Replace company name, logo, contact information
    • Adjust styling (colors, fonts, layout) to match brand
    • Add or remove sections as needed (tax breakdowns, payment instructions, etc.)
  3. Update Configuration:

    Edit crm_config.yaml:

    invoice:
    template_filename: 'yourcompany_invoice_template.html'
  4. Test Invoice Generation:

    • Create a test invoice in the CRM
    • Download the PDF and verify formatting
    • Check invoice_templates/rendered/{invoice_id}.html for debugging
  5. Invalidate Old Caches (if needed):

    If you've changed the template and want to regenerate existing invoices:

    -- Clear all cached PDFs (forces regeneration)
    DELETE FROM Invoice_PDF_Cache;

PDF Caching System

To improve performance, OmniCRM caches generated PDFs:

Cache Behavior:

  • First Request - PDF is generated, cached, and returned
  • Subsequent Requests - Cached PDF is returned immediately (no regeneration)
  • Cache Invalidation - Occurs when invoice is modified, voided, or refunded
  • Cache Cleanup - Old caches are automatically purged after 30 days of inactivity

Cache Storage:

  • Base64-encoded PDF stored in Invoice_PDF_Cache table
  • SHA256 content hash for integrity verification
  • Includes filename, creation timestamp, last accessed timestamp

Manual Cache Management:

# In OmniCRM API or Python shell
from services.invoice_service import cleanup_old_pdf_cache, invalidate_invoice_cache
from utils.db_helpers import get_db_session

session = get_db_session()

# Clean up caches older than 30 days
result = cleanup_old_pdf_cache(session, days_old=30)
print(result) # {'status': 'success', 'deleted_count': 15}

# Invalidate specific invoice cache
invalidate_invoice_cache(session, invoice_id='12345')

API Endpoints:

Generate/download invoice PDF:

GET /invoice/pdf/{invoice_id}

Response: PDF file download with filename from Stripe statement descriptor

Cache Headers:

  • First request: Slower response (generation time)
  • Cached requests: Instant response
  • Cache hit/miss is transparent to the user

Applying Configuration Changes

Backend (crm_config.yaml)

  1. Edit OmniCRM-API/crm_config.yaml
  2. Save changes
  3. Restart the API service:
cd OmniCRM-API
sudo systemctl restart omnicrm-api
# or
./restart_api.sh

Changes take effect immediately after restart.

Frontend (.env)

  1. Edit OmniCRM-UI/.env
  2. Save changes
  3. Rebuild the UI:
cd OmniCRM-UI
npm run build
  1. Restart the UI service or web server

Development Mode:

During development with npm start, restart the dev server to apply changes.


Configuration Best Practices

Security

  • Never commit secrets - Use .gitignore for config files with credentials
  • Use strong passwords - Minimum 16 characters with mixed case, numbers, and symbols
  • Rotate credentials regularly - Especially for production deployments
  • Restrict database access - Use IP whitelisting and firewall rules
  • Use environment-specific configs - Separate dev/staging/production configs
  • Limit API key permissions - Assign minimal necessary roles
  • Use IP whitelisting sparingly - Prefer API keys for better security

Maintenance

  • Document changes - Keep changelog of configuration modifications
  • Backup configs - Store copies before major changes
  • Test in staging - Verify config changes before production deployment
  • Version control - Track config templates (without secrets) in git

Performance

  • Use local database - Avoid remote database for better performance
  • Configure caching - Enable OCS caching if available
  • Optimize Grafana - Limit number of embedded dashboards

Branding

  • Match colors - Ensure UI colors complement your logo
  • Test contrast - Verify text readability on colored backgrounds
  • Mobile testing - Check branding on mobile devices
  • Logo placement - Use appropriate logo sizes for different contexts

Troubleshooting

Common Issues

Changes not applied

  • Cause: Service not restarted or UI not rebuilt
  • Fix: Restart API/UI services after config changes

YAML syntax errors

  • Cause: Invalid YAML formatting (indentation, quotes, etc.)
  • Fix: Validate YAML online or use yamllint crm_config.yaml

Database connection failed

  • Cause: Wrong credentials or server unreachable
  • Fix: Verify database is running, credentials are correct

Stripe payments not working

  • Cause: Mismatched keys between backend and frontend
  • Fix: Ensure publishable_key matches in both files

Emails not sending

  • Cause: Invalid Mailjet credentials or template IDs
  • Fix: Verify Mailjet API key/secret, check template IDs exist

PDF Generation Fails:

  • Check that WeasyPrint is installed: pip install weasyprint
  • Verify template filename matches crm_config.yaml
  • Check invoice_templates/rendered/ for HTML rendering errors
  • Review API logs for Jinja2 template errors

Images Not Appearing in PDF:

  • Use absolute file paths: file:///full/path/to/image.png
  • Ensure image files exist and are readable
  • Check image format (PNG and JPEG work best)
  • Verify image paths don't contain special characters

Styling Issues:

  • Inline all CSS (external stylesheets not supported)
  • Avoid complex CSS features (flexbox, grid may not render correctly)
  • Test with simple layouts first, add complexity gradually
  • Use tables for layout instead of divs where possible

Cache Not Invalidating:

  • Verify invalidate_invoice_cache() is called when invoice is modified
  • Check that transaction updates trigger cache invalidation
  • Manually delete from Invoice_PDF_Cache table if needed

Configuration Checklist

Use this checklist when deploying OmniCRM:

Backend Configuration

  • Copy .env.example to .env
  • Set strong database passwords
  • Configure CGRates credentials
  • Update crm_config.yaml with your settings:
    • Database connection
    • Service types
    • Mailjet API keys and template IDs
    • Provisioning failure notification emails
    • Invoice template filename
    • CRM base URL (publicly accessible)
    • OCS/CGRates endpoints
    • SMSC configuration
    • Generate new JWT secret key
    • Stripe keys (live, not test)
    • API keys and IP whitelisting

Frontend Configuration

  • Copy OmniCRM-UI/.env.example to OmniCRM-UI/.env
  • Set Google Maps API key
  • Set Stripe publishable key
  • Update company branding:
    • Company name
    • Portal name
    • Self-care name
    • Company tagline
  • Configure localization:
    • Default language
    • Locale
    • Default location and country
    • Currency code and symbol
  • Set primary brand color
  • Configure web app integrations (optional)
  • Add support and FAQ URLs (optional)
  • Set Google Analytics/Tag Manager tracking ID (optional)

Branding Assets

  • Create logo files (logoSm.png, logoDark.png, logoLight.png)
  • Upload logos to OmniCRM-UI/src/assets/images/omnitouch/
  • Create custom invoice template HTML
  • Upload invoice template to OmniCRM-API/invoice_templates/
  • Update crm_config.yaml with invoice template filename
  • Test invoice PDF generation
  • Rebuild UI: npm run build

Security

  • Change all default passwords
  • Generate unique JWT secret
  • Use production Stripe keys (not test keys)
  • Rotate Mailjet API keys
  • Enable firewall rules
  • Configure IP whitelisting for API access
  • Set up SSL/TLS certificates
  • Enable HTTPS for all endpoints
  • Review CORS settings
  • Implement rate limiting
  • Configure backup and recovery procedures

Testing

  • Test customer registration flow
  • Test service provisioning end-to-end
  • Verify email notifications are sent correctly
  • Test invoice generation and PDF download
  • Verify payment processing (Stripe)
  • Check user authentication and 2FA
  • Test impersonation and audit logging
  • Verify usage data syncs from OCS
  • Test ActionPlan creation and renewal
  • Confirm inventory allocation works correctly

Deployment

  • Build Docker images or deploy to servers
  • Start database containers (MySQL, PostgreSQL)
  • Start CGRates
  • Start OmniCRM API
  • Start OmniCRM UI
  • Configure reverse proxy (nginx, traefik)
  • Set up monitoring (Grafana, Prometheus)
  • Configure log aggregation
  • Set up automated backups
  • Document deployment architecture
  • Train staff on system usage

  • RBAC and User Management </rbac>
  • Products and Services </concepts_products_and_services>
  • Ansible Provisioning </concepts_ansible>
  • Inventory Management </administration_inventory>
  • Customer Invoices </payments_invoices>
  • Two-Factor Authentication </2fa>
  • Customer Care and Impersonation </customer_care>
  • Payment Vendor Integrations <integrations_payment_vendors>
  • administration_api_keys - API key management
  • integrations_mailjet - Email integration
  • concepts_api - API authentication