Quickstart

Get CRM running locally and build your first custom module in under 10 minutes.

STEP 1

Prerequisites

Before you begin, make sure you have the following installed on your machine:

Requirement Version Notes
Docker Desktop 4.x+ Docker Compose v2 included
Git Any recent For cloning the repo
curl Any recent For testing API endpoints
PHP 7.4 (in Docker) Provided by the Docker image

You'll also need access to the platform/ directory from the CRM-PHP repository, specifically:

  • platform/Deployments/deploy-package/CRM-PHP-Docker/ — Docker stack
  • platform/Deployments/deploy-package/CRM-PHP-Docker/crm/httpdocs/ — The web root
STEP 2

Install CRM via Docker

The entire CRM stack — nginx, PHP/Apache, MySQL 8.0, LangChain — runs in Docker Compose. Start it with one command.

bash
# Navigate to the Docker stack directory
cd platform/Deployments/deploy-package/CRM-PHP-Docker/

# Copy the example environment file and fill in your credentials
cp .env.example .env

# Start the full stack (nginx, PHP app, MySQL, LangChain)
docker compose up -d

# Wait ~30 seconds for MySQL to initialize, then check status
docker compose ps

Once all containers are running:

Service URL
CRM Web App http://localhost:8090
phpMyAdmin http://localhost:8081
Default credentials: Login at http://localhost:8090 with admin / 111. API base URL: http://localhost:8090/api/v1.

Useful Docker Commands

bash
# View app container logs
docker compose logs -f crm-app

# Execute a command inside the PHP container
docker exec -it crm-app bash

# Restart only the app container (after code changes)
docker compose restart crm-app

# Clear Smarty compiled template cache
docker exec crm-app rm -rf /var/www/html/httpdocs/files/themes/default/*

# Stop the entire stack
docker compose down
STEP 3

Create Your First Module

A module consists of two files: a PHP controller and a Smarty template. No registration is needed for a public-facing module — just create the files and visit the URL.

Controller: modules/hello.php

php
<?php
// httpdocs/modules/hello.php

pb_on_action('view', function () {
    pb_title('Hello World');
    pb_template('hello');
    pb_set_tpl_var('message', 'Welcome to CRM!');
    pb_set_tpl_var('items', ['Contacts', 'Organizations', 'Support Tickets']);
});

Create this file at:

bash
platform/Deployments/deploy-package/CRM-PHP-Docker/crm/httpdocs/modules/hello.php

Template: themes/default/hello.tpl

smarty
{* httpdocs/themes/default/hello.tpl *}

{if $m.action eq 'view'}
    {include file="block_begin.tpl"}

    <h1>{$m.message}</h1>
    <p>This module is working. Here are the main CRM sections:</p>

    <ul>
    {foreach from=$m.items item=item}
        <li>{$item}</li>
    {/foreach}
    </ul>

    {include file="block_end.tpl"}
{/if}

Create this file at:

bash
platform/Deployments/deploy-package/CRM-PHP-Docker/crm/httpdocs/themes/default/hello.tpl
STEP 4

Access Your Module via URL

No restart or build step needed — PHP files are served directly. Open your browser and visit:

text
http://localhost:8090/index.php?m=hello&d=view

You should see the CRM dashboard layout with your "Hello World" heading and the list of CRM sections.

URL Pattern: ?m= is the module name (filename without .php), and ?d= is the action name (passed to pb_on_action()). The URL ?m=hello&d=view loads modules/hello.php and calls the 'view' action handler.

Test the API Endpoint Too

bash
# Get an access token
curl -X POST http://localhost:8090/api/v1/login \
  -H "Content-Type: application/json" \
  -d '{"login":"webmaster@local.dev","password":"111","device_name":"quickstart"}'

# Use the token to call app-state
curl http://localhost:8090/api/v1/common/app-state \
  -H "access_token: YOUR_TOKEN_HERE"
STEP 5

Create an Admin Module

Admin modules are registered in the Module Management UI and support install/uninstall lifecycle hooks. They require a /* * Module Name: ... */ comment so the UI can discover them.

Create: modules/hello-admin.php

php
<?php
/* * Module Name: Hello Admin */

use PB\Access\PBAccess;
use PB\Common\Redirect;
use PB\Core\PBURL;
use PB\UI\UI;

// Main admin page
pb_on_action('admin', function () {
    PBAccess::AdminRequired();
    pb_title('Hello Admin');
    pb_template('hello-admin');

    $ui = new UI();
    PB::BreadCrumbs()->Add('Hello Admin', PBURL::CurrentModule('admin'));
    $ui->NotificationInfo('Hello from the admin module!');
    $ui->Output(true);
});

// Install — creates DB tables and registers the module
pb_on_action('install', function () {
    PBAccess::AdminRequired();

    pb_register_module('hello-admin', 'Hello Admin');

    // Create your tables here:
    execsql("CREATE TABLE IF NOT EXISTS hello_items (
        id         INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
        id_company INT UNSIGNED NOT NULL DEFAULT 0,
        title      VARCHAR(255) NOT NULL DEFAULT '',
        timeadded  INT UNSIGNED NOT NULL DEFAULT 0
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    Redirect::Now(PBURL::AdminModulesManagement());
});

// Uninstall — drops DB tables and unregisters the module
pb_on_action('uninstall', function () {
    PBAccess::AdminRequired();

    pb_unregister_module('hello-admin');
    execsql("DROP TABLE IF EXISTS hello_items");

    Redirect::Now(PBURL::AdminModulesManagement());
});

Create: themes/default/hello-admin.tpl

smarty
{* themes/default/hello-admin.tpl *}
{if $m.action eq 'admin'}
    {include file="block_begin.tpl"}
    {* The UI component system renders the content here automatically *}
    {include file="block_end.tpl"}
{/if}

Install the Module

  1. Log in as admin at http://localhost:8090
  2. Go to Admin → Modules → Manage Modules
  3. Find Hello Admin in the list
  4. Click Install
  5. The module is now active and the hello_items table is created

Visit the admin page at:

text
http://localhost:8090/index.php?m=hello-admin&d=admin
STEP 6

Next Steps

You have a working module! Here's what to explore next:

📱

Mobile API Reference

Explore all REST endpoints: contacts, activities, support tickets, push notifications, and more.

View Reference →
🛠

Module Dev Guide

Deep dive into the ORM, UI components, Smarty templates, URL helpers, and the complete polls example.

Read Guide →

Swagger UI Explorer

Try API calls directly in the browser with the interactive Swagger UI connected to the live API.

Open Explorer →

Key Things to Remember

  • Always use execsql(), getsqlfield(), getsqlarray(), insertsql() — never dbquery()
  • Never use {literal} in Smarty templates — put JS in external .js files loaded via pb_add_jsfile()
  • Call PBAccess::AdminRequired() at the top of every admin action
  • Use PB::POST($key)->AsString() / AsAbsInt() — never read $_POST directly
  • Admin modules need 3 actions: admin, install, and uninstall
  • The URL pattern is always ?m=module-name&d=action-name
  • DB date columns use Unix timestamps (timeadded, created_time) — never created_at

Deploy to Production

When you're ready to deploy your module to the production server:

bash
# From the repo root, commit your module files
git add platform/Deployments/deploy-package/CRM-PHP-Docker/crm/httpdocs/modules/hello.php
git add platform/Deployments/deploy-package/CRM-PHP-Docker/crm/httpdocs/themes/default/hello.tpl
git commit -m "feat: add hello module"

# Deploy to the your production server
./platform/deploy-client.sh [clientname] "add hello module"
Template cache: After deploying, Smarty's compiled template cache may serve stale HTML. Clear it with: docker exec crm-app rm -rf /var/www/html/httpdocs/files/themes/default/* on the production server.