๐Ÿ›๏ธ Architectural Revolution in Dolibarr ERP

A radical transformation that converts Dolibarr from a traditional PHP system into a pure client/server model where PostgreSQL is the brain that handles all business logic through automatic triggers and advanced functions.

๐Ÿš€

Pure Client/Server

PostgreSQL as intelligent server, PHP as presentation client

โšก

Centralized Logic

All business rules executing automatically in the database

๐ŸŽฏ

Guaranteed Consistency

Impossible to skip validations or calculations, automatic and transparent execution

๐ŸŽฏ Project Objectives

Main Objective

Completely transform Dolibarr ERP architecture from a traditional PHP system to a pure client/server model where all business logic resides in PostgreSQL through triggers and functions.

๐Ÿ—๏ธ Client/Server Architecture

Implement a model where PostgreSQL is the intelligent server that handles ALL business logic, and PHP acts only as a presentation client.

โšก Total Elimination of PHP Logic

Completely remove validations, calculations and business rules from PHP code, transferring them to automatic PostgreSQL triggers.

๐ŸŽฏ PostgreSQL Exclusive

Abandon MySQL/MariaDB compatibility to take full advantage of PostgreSQL's advanced capabilities.

โœ… Consistency Guarantee

Ensure that business rules are always executed, regardless of which client accesses the database.

๐Ÿ›๏ธ Architectural Comparison

โŒ Dolibarr Original

PHP (Fat Client)

  • Field validations
  • Total calculations
  • Code generation
  • Business rules
  • Flow control

MySQL/PostgreSQL (Dumb Storage)

  • Data storage
  • Basic constraints
  • Simple relationships

โŒ Identified Problems:

  • Scattered and duplicated logic
  • Inconsistencies between accesses
  • Easy to skip validations
  • Complex maintenance
  • Fragmented testing

โœ… Client/Server Model

PHP (Thin Client)

  • Data presentation
  • User interface
  • Simple SQL commands
  • No business logic

PostgreSQL (Smart Server)

  • ๐Ÿ”ง Automatic triggers
  • ๐Ÿ“ Validation functions
  • ๐Ÿงฎ Guaranteed calculations
  • ๐Ÿท๏ธ Code generation
  • ๐Ÿ”’ Business rules
  • ๐Ÿ“Š Automatic auditing

โœ… Benefits Achieved:

  • Centralized and consistent logic
  • Always automatic validations
  • Improved performance
  • Simplified maintenance
  • Unified testing

๐Ÿ—„๏ธ Three Database Architecture

To ensure maximum precision in migration, we implement a testing architecture with three specialized databases:

dolibarrdev

Development

Main development database

  • Contains ALL PostgreSQL logic
  • Triggers and functions implemented
  • Real test data
  • Main working environment

dolibarr_test_php

Test PHP

Replica of original PHP behavior

  • Table structure only
  • No triggers or functions
  • Simulates pure PHP behavior
  • Comparison base for tests

dolibarr_test_postgresql

Test PostgreSQL

Exact copy of dolibarrdev

  • Complete triggers and functions
  • Pure PostgreSQL behavior
  • Implementation validation
  • Automated comparative tests

๐Ÿ”„ Comparative Testing Flow

1

Capture PHP Behavior

Execute operations in dolibarr_test_php and record results

โ†’
2

Execute in PostgreSQL

Perform the same operations in dolibarr_test_postgresql

โ†’
3

Compare Results

Validate that both behaviors are identical

โ†’
4

Certify Migration

Guarantee 100% functional parity

๐Ÿ“Š Project Metrics

17
Modules Completed
of 81 identified (61.7%)
1,215
Unit Tests
100% passing
269
PostgreSQL Functions
105 triggers created
68
Comparative Tests
Rigorous validation

Progress by Category

100%
100%
95%
61.7%

๐Ÿ“… Project Timeline

2025-07-05

Project Start

Initial analysis of Dolibarr, definition of objectives and establishment of client/server model as target architecture.

2025-07-05

Societe Module (First Success)

Complete implementation of the first module, establishing patterns and methodology for the rest of the project.

2025-07-05

Testing Infrastructure

Development of pgTAP testing and 3-database architecture for rigorous comparative tests.

2025-07-06

Reached 17 Modules

Completed Societe, Product, User, Banque, Tax, Propale, Categories, Don, Contact, Commande, Facture, Stock, Bookkeeping, ExpenseReport, FournisseurCommande, Expeditions and Contracts with 100% tests passing.

2025-07-06

Comprehensive Documentation

Creation of this interactive HTML book documenting the entire architectural transformation process.

Future

Advanced Modules

Completion of the 4 remaining modules: Fichinter, Expedition, Contrat, and other specific modules.

๐Ÿ’ก Technical Justification

๐Ÿ—๏ธ Traditional Model Problems

  • Scattered Logic: Validations and rules spread across multiple PHP files
  • Inconsistency: Different behaviors depending on access point
  • Complex Maintenance: Changes require modifying multiple files
  • Fragmented Testing: Difficult to test all combinations
  • Performance: Multiple roundtrips to the database

โœ… Client/Server Model Advantages

  • Centralization: All logic in one controlled place
  • Guarantees: Triggers always execute, without exceptions
  • Performance: Optimized calculations in the database
  • Consistency: Same behavior for all clients
  • Auditability: Total control over operations

๐Ÿ“ Technical Transformation Example

โŒ Code PHP Original

public function verify() {
    // Validate that name is not empty
    if (empty($this->nom)) {
        $this->errors[] = "Name is required";
        return -1;
    }
    
    // Validate email if present
    if (!empty($this->email)) {
        if (!filter_var($this->email, FILTER_VALIDATE_EMAIL)) {
            $this->errors[] = "Invalid email";
            return -1;
        }
    }
    
    // Verify that code doesn't exist
    $sql = "SELECT COUNT(*) as nb FROM llx_societe WHERE code_client = '".$this->code_client."'";
    $resql = $this->db->query($sql);
    if ($resql) {
        $obj = $this->db->fetch_object($resql);
        if ($obj->nb > 0) {
            $this->errors[] = "Customer code already in use";
            return -1;
        }
    }
    
    return 0;
}

โœ… Trigger PostgreSQL

CREATE OR REPLACE FUNCTION llx_societe_before_insert()
RETURNS trigger AS $$
BEGIN
    -- Validate required name
    IF NEW.nom IS NULL OR trim(NEW.nom) = '' THEN
        RAISE EXCEPTION 'Name is required';
    END IF;
    
    -- Validate email
    IF NEW.email IS NOT NULL AND NEW.email != '' THEN
        IF NOT (NEW.email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$') THEN
            RAISE EXCEPTION 'Invalid email: %', NEW.email;
        END IF;
    END IF;
    
    -- Generate code automatically if empty
    IF NEW.code_client IS NULL OR trim(NEW.code_client) = '' THEN
        NEW.code_client := llx_societe_get_next_code('C');
    ELSE
        -- Verify uniqueness
        IF EXISTS (SELECT 1 FROM llx_societe WHERE code_client = NEW.code_client) THEN
            RAISE EXCEPTION 'Customer code already in use: %', NEW.code_client;
        END IF;
    END IF;
    
    -- Set defaults
    NEW.entity := COALESCE(NEW.entity, 1);
    NEW.status := COALESCE(NEW.status, 1);
    NEW.datec := COALESCE(NEW.datec, NOW());
    
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

๐ŸŽฏ Transformation Result

Simplified PHP:
public function verify() {
    return 0; // Triggers handle EVERYTHING automatically!
}