Dolibarr: 오픈소스 ERP/CRM 시스템 완전 구축 가이드
⏱️ 예상 읽기 시간: 22분
서론
중소기업의 성장과 함께 고객 관리, 재고 관리, 회계 처리, 프로젝트 관리 등 다양한 비즈니스 프로세스를 통합적으로 관리할 필요성이 증가하고 있습니다. 하지만 상용 ERP/CRM 솔루션은 높은 비용과 복잡한 설정으로 인해 중소기업에서는 접근하기 어려운 경우가 많습니다.
Dolibarr은 이런 문제를 해결하는 오픈소스 ERP/CRM 통합 솔루션입니다. PHP와 MySQL 기반으로 구축되어 설치가 간편하며, 모듈식 구조로 필요한 기능만 선택적으로 활성화할 수 있습니다. 20년 이상의 개발 역사를 가진 성숙한 플랫폼으로, 전 세계 수만 개의 기업에서 사용되고 있습니다.
이번 가이드에서는 Dolibarr의 설치부터 핵심 모듈 설정, 고급 커스터마이징까지 실무에서 바로 활용할 수 있는 완전한 구축 방법을 다루겠습니다.
Dolibarr 핵심 기능
🏢 통합 비즈니스 관리
Dolibarr은 모듈식 아키텍처를 통해 필요한 기능만 선택적으로 활성화할 수 있습니다.
핵심 모듈 구성
// 주요 모듈 카테고리
$core_modules = [
'CRM' => [
'societes', // 고객/공급업체 관리
'contacts', // 연락처 관리
'commercial', // 영업 기회 관리
'propale', // 견적서 관리
'commande', // 주문 관리
'facture' // 송장/청구서 관리
],
'ERP' => [
'produit', // 제품/서비스 관리
'stock', // 재고 관리
'fournisseur', // 구매 관리
'expedition', // 배송 관리
'comptabilite', // 회계 관리
'banque' // 은행/결제 관리
],
'PROJECT' => [
'projet', // 프로젝트 관리
'resource', // 리소스 관리
'timesheet', // 근무시간 관리
'holiday' // 휴가 관리
],
'COLLABORATION' => [
'agenda', // 일정 관리
'adherent', // 회원 관리
'mailing', // 이메일 마케팅
'website' // 웹사이트 빌더
]
];
📊 실시간 대시보드
관리자와 사용자별로 커스터마이징 가능한 대시보드를 제공합니다.
대시보드 위젯 구성
// 대시보드 위젯 설정 예제
class CustomDashboard {
public function getSalesWidgets() {
return [
'monthly_sales' => [
'title' => '월별 매출',
'type' => 'chart',
'data_source' => 'facture',
'period' => 'current_year',
'chart_type' => 'line'
],
'top_customers' => [
'title' => '주요 고객',
'type' => 'table',
'data_source' => 'societe',
'limit' => 10,
'sort_by' => 'total_revenue'
],
'pending_quotes' => [
'title' => '대기 중인 견적',
'type' => 'counter',
'data_source' => 'propale',
'status' => 'validated'
],
'overdue_invoices' => [
'title' => '연체 송장',
'type' => 'alert',
'data_source' => 'facture',
'condition' => 'date_limit < NOW()'
]
];
}
}
🔒 강력한 권한 관리
역할 기반 접근 제어(RBAC)로 세밀한 권한 설정이 가능합니다.
// 권한 그룹 설정 예제
$permission_groups = [
'sales_manager' => [
'read' => ['societe', 'contact', 'propale', 'commande', 'facture'],
'write' => ['societe', 'contact', 'propale', 'commande'],
'delete' => ['propale'],
'admin' => false
],
'accountant' => [
'read' => ['facture', 'comptabilite', 'banque', 'tax'],
'write' => ['comptabilite', 'banque', 'tax'],
'delete' => [],
'admin' => false
],
'warehouse_manager' => [
'read' => ['produit', 'stock', 'expedition', 'reception'],
'write' => ['stock', 'expedition', 'reception'],
'delete' => [],
'admin' => false
]
];
설치 및 환경 구성
1. 시스템 요구사항
서버 환경
# 운영체제: Linux (Ubuntu/CentOS/Debian) 권장
# 웹서버: Apache 2.4+ 또는 Nginx 1.18+
# PHP: 7.4+ (8.1+ 권장)
# 데이터베이스: MySQL 5.7+ 또는 MariaDB 10.3+
# PHP 확장 모듈 (필수)
php -m | grep -E "mysqli|pdo_mysql|gd|curl|zip|xml|json|mbstring"
# PHP 설정 권장값
# memory_limit = 512M
# max_execution_time = 300
# upload_max_filesize = 50M
# post_max_size = 50M
하드웨어 권장사양
- CPU: 2코어 이상
- RAM: 4GB 이상 (사용자 50명 기준)
- 디스크: 20GB 이상 (데이터 성장 고려)
- 네트워크: 안정적인 인터넷 연결
2. LAMP 스택 설치
Ubuntu/Debian 환경
# 시스템 업데이트
sudo apt update && sudo apt upgrade -y
# Apache 웹서버 설치
sudo apt install apache2 -y
sudo systemctl enable apache2
sudo systemctl start apache2
# MySQL 데이터베이스 설치
sudo apt install mysql-server -y
sudo systemctl enable mysql
sudo systemctl start mysql
# 보안 설정
sudo mysql_secure_installation
# PHP 8.1 및 필수 모듈 설치
sudo apt install php8.1 php8.1-mysql php8.1-gd php8.1-curl \
php8.1-zip php8.1-xml php8.1-json php8.1-mbstring \
php8.1-intl php8.1-ldap php8.1-soap php8.1-opcache \
libapache2-mod-php8.1 -y
# Apache PHP 모듈 활성화
sudo a2enmod php8.1
sudo systemctl restart apache2
CentOS/RHEL 환경
# EPEL 저장소 추가
sudo yum install epel-release -y
# Apache 설치
sudo yum install httpd -y
sudo systemctl enable httpd
sudo systemctl start httpd
# MySQL 8.0 설치
sudo yum install mysql-server -y
sudo systemctl enable mysqld
sudo systemctl start mysqld
# PHP 8.1 설치 (Remi 저장소 사용)
sudo yum install yum-utils -y
sudo yum install http://rpms.remirepo.net/enterprise/remi-release-8.rpm -y
sudo yum-config-manager --enable remi-php81
sudo yum install php php-mysql php-gd php-curl php-zip \
php-xml php-json php-mbstring php-intl php-ldap \
php-soap php-opcache -y
sudo systemctl restart httpd
3. 데이터베이스 준비
MySQL 데이터베이스 생성
-- MySQL 로그인
mysql -u root -p
-- 데이터베이스 생성
CREATE DATABASE dolibarr CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 전용 사용자 생성
CREATE USER 'dolibarr_user'@'localhost' IDENTIFIED BY 'strong_password_here';
-- 권한 부여
GRANT ALL PRIVILEGES ON dolibarr.* TO 'dolibarr_user'@'localhost';
-- 권한 적용
FLUSH PRIVILEGES;
-- 데이터베이스 설정 확인
SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';
EXIT;
고급 MySQL 설정
# MySQL 설정 파일 편집
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
# 또는 CentOS의 경우
sudo nano /etc/my.cnf.d/mysql-server.cnf
# MySQL 최적화 설정
[mysqld]
# 문자셋 설정
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
# 성능 최적화
innodb_buffer_pool_size = 1G # RAM의 70% 정도
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2
query_cache_size = 64M
query_cache_type = 1
# 연결 설정
max_connections = 500
max_allowed_packet = 64M
# 보안 설정
bind-address = 127.0.0.1
skip-networking = false
# MySQL 재시작
sudo systemctl restart mysql
4. Dolibarr 다운로드 및 설치
최신 버전 다운로드
# 웹 루트 디렉토리로 이동
cd /var/www/html
# 최신 버전 다운로드 (예: 18.0.0)
sudo wget https://github.com/Dolibarr/dolibarr/releases/download/18.0.0/dolibarr-18.0.0.tgz
# 압축 해제
sudo tar -xzf dolibarr-18.0.0.tgz
# 디렉토리 이름 변경
sudo mv dolibarr-18.0.0 dolibarr
# 소유권 설정
sudo chown -R www-data:www-data dolibarr/
sudo chmod -R 755 dolibarr/
# 설정 디렉토리 쓰기 권한
sudo chmod -R 777 dolibarr/htdocs/install/
sudo chmod -R 777 dolibarr/documents/
Apache 가상 호스트 설정
# 가상 호스트 파일 생성
sudo nano /etc/apache2/sites-available/dolibarr.conf
<VirtualHost *:80>
ServerName your-domain.com
ServerAlias www.your-domain.com
DocumentRoot /var/www/html/dolibarr/htdocs
# 로그 설정
ErrorLog ${APACHE_LOG_DIR}/dolibarr_error.log
CustomLog ${APACHE_LOG_DIR}/dolibarr_access.log combined
# PHP 설정
<Directory "/var/www/html/dolibarr/htdocs">
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
# PHP 메모리 제한
php_admin_value memory_limit 512M
php_admin_value max_execution_time 300
php_admin_value upload_max_filesize 50M
php_admin_value post_max_size 50M
</Directory>
# 보안 설정
<Directory "/var/www/html/dolibarr/documents">
Options -Indexes
AllowOverride None
Require all denied
</Directory>
# .htaccess 파일 보호
<Files ".ht*">
Require all denied
</Files>
</VirtualHost>
# 사이트 활성화
sudo a2ensite dolibarr.conf
sudo a2dissite 000-default.conf
# Apache 모듈 활성화
sudo a2enmod rewrite
sudo a2enmod ssl
# Apache 재시작
sudo systemctl restart apache2
초기 설정 및 구성
1. 웹 기반 설치 마법사
브라우저에서 설치 시작
# 브라우저에서 접속
http://your-domain.com/install/
# 또는 로컬 설치의 경우
http://localhost/dolibarr/install/
설치 단계별 가이드
1단계: 언어 선택
- 인터페이스 언어: 한국어 또는 English
- 국가/지역: South Korea
- 문자셋: UTF-8
2단계: 라이센스 동의
- GPL v3+ 라이센스 확인 및 동의
3단계: 환경 검사
// 필수 요구사항 자동 검사
- PHP 버전: ✅ 8.1.0
- MySQL 지원: ✅ mysqli
- 필수 PHP 모듈: ✅ All required modules found
- 파일 권한: ✅ documents/ writable
- 메모리 제한: ✅ 512M
4단계: 데이터베이스 설정
// 데이터베이스 연결 정보 입력
$db_config = [
'host' => 'localhost',
'port' => '3306',
'database' => 'dolibarr',
'username' => 'dolibarr_user',
'password' => 'strong_password_here',
'prefix' => 'llx_', // 테이블 접두사
'force_utf8' => true // UTF-8 강제 사용
];
5단계: 관리자 계정 생성
// 슈퍼 관리자 계정 설정
$admin_account = [
'login' => 'admin',
'password' => 'secure_admin_password',
'lastname' => '관리자',
'firstname' => '시스템',
'email' => 'admin@your-company.com'
];
2. 기본 회사 정보 설정
회사 프로필 구성
// 관리자 로그인 후 설정 > 회사/조직
$company_profile = [
'name' => '주식회사 예시컴퍼니',
'address' => '서울시 강남구 테헤란로 123',
'zipcode' => '06234',
'town' => '서울',
'country' => 'KR', // ISO 국가 코드
'phone' => '02-1234-5678',
'fax' => '02-1234-5679',
'email' => 'info@example.com',
'url' => 'https://www.example.com',
// 사업자 정보
'idprof1' => '123-45-67890', // 사업자등록번호
'idprof2' => '1234567890123', // 법인등록번호
'tva_intra' => 'KR1234567890', // 부가세번호
// 회계 연도
'fiscal_month_start' => 1, // 1월 시작
// 기본 통화
'currency' => 'KRW',
'currency_symbol' => '₩'
];
사용자 권한 그룹 생성
// 기본 권한 그룹 설정
$user_groups = [
[
'name' => '영업팀',
'note' => '고객 관리 및 영업 활동',
'rights' => [
'societe' => ['read', 'write'],
'contact' => ['read', 'write'],
'propale' => ['read', 'write', 'validate'],
'commande' => ['read', 'write'],
'facture' => ['read']
]
],
[
'name' => '회계팀',
'note' => '재무 및 회계 관리',
'rights' => [
'facture' => ['read', 'write', 'validate'],
'comptabilite' => ['read', 'write'],
'banque' => ['read', 'write'],
'tax' => ['read', 'write']
]
],
[
'name' => '창고팀',
'note' => '재고 및 배송 관리',
'rights' => [
'produit' => ['read', 'write'],
'stock' => ['read', 'write'],
'expedition' => ['read', 'write'],
'reception' => ['read', 'write']
]
]
];
3. 핵심 모듈 활성화
모듈 활성화 스크립트
// 자동 모듈 활성화 스크립트
// /htdocs/custom/scripts/enable_modules.php
require_once '../main.inc.php';
$modules_to_enable = [
// CRM 모듈
'modSociete', // 고객/공급업체
'modContact', // 연락처
'modPropale', // 견적서
'modCommande', // 주문
'modFacture', // 송장
'modContrat', // 계약
// 제품/재고 모듈
'modProduct', // 제품/서비스
'modStock', // 재고 관리
'modExpedition', // 배송
// 회계 모듈
'modComptabilite', // 회계
'modBanque', // 은행/결제
'modTax', // 세금
// 프로젝트 모듈
'modProject', // 프로젝트
'modTimesheet', // 근무시간
// 협업 모듈
'modAgenda', // 일정
'modMailing', // 이메일 마케팅
'modWebsite' // 웹사이트
];
foreach ($modules_to_enable as $module) {
$result = activateModule($module);
if ($result > 0) {
print "✅ $module 모듈 활성화 성공\n";
} else {
print "❌ $module 모듈 활성화 실패\n";
}
}
핵심 모듈 설정
1. 고객 관리 (CRM)
고객 분류 체계 설정
// 고객 카테고리 생성
$customer_categories = [
[
'label' => 'VIP 고객',
'description' => '연 구매액 1억원 이상',
'color' => '#FFD700',
'type' => 0 // 0=고객, 1=공급업체
],
[
'label' => '일반 고객',
'description' => '연 구매액 1천만원 이상',
'color' => '#87CEEB',
'type' => 0
],
[
'label' => '신규 고객',
'description' => '가입 후 6개월 미만',
'color' => '#98FB98',
'type' => 0
],
[
'label' => '휴면 고객',
'description' => '1년 이상 구매 이력 없음',
'color' => '#F0F0F0',
'type' => 0
]
];
영업 기회 파이프라인 구성
// 영업 단계 정의
$opportunity_stages = [
[
'code' => 'PROSPECTING',
'label' => '잠재고객 발굴',
'description' => '초기 관심 표명 단계',
'probability' => 10,
'color' => '#FFA500'
],
[
'code' => 'QUALIFICATION',
'label' => '자격 검증',
'description' => '구매 의사 및 예산 확인',
'probability' => 25,
'color' => '#87CEEB'
],
[
'code' => 'NEEDS_ANALYSIS',
'label' => '니즈 분석',
'description' => '고객 요구사항 상세 파악',
'probability' => 50,
'color' => '#90EE90'
],
[
'code' => 'PROPOSAL',
'label' => '제안서 제출',
'description' => '정식 제안서 발송',
'probability' => 75,
'color' => '#FFD700'
],
[
'code' => 'NEGOTIATION',
'label' => '협상',
'description' => '가격 및 조건 협상',
'probability' => 85,
'color' => '#FFA500'
],
[
'code' => 'CLOSED_WON',
'label' => '수주 성공',
'description' => '계약 체결 완료',
'probability' => 100,
'color' => '#32CD32'
],
[
'code' => 'CLOSED_LOST',
'label' => '수주 실패',
'description' => '계약 무산',
'probability' => 0,
'color' => '#FF6347'
]
];
2. 제품 및 재고 관리
제품 카테고리 구조
// 제품 카테고리 트리 구조
$product_categories = [
[
'label' => '하드웨어',
'description' => '물리적 제품',
'children' => [
['label' => '컴퓨터', 'ref' => 'HW-COMP'],
['label' => '주변기기', 'ref' => 'HW-PERI'],
['label' => '네트워크장비', 'ref' => 'HW-NET']
]
],
[
'label' => '소프트웨어',
'description' => '디지털 제품',
'children' => [
['label' => '운영체제', 'ref' => 'SW-OS'],
['label' => '오피스', 'ref' => 'SW-OFFICE'],
['label' => '개발도구', 'ref' => 'SW-DEV']
]
],
[
'label' => '서비스',
'description' => '무형 서비스',
'children' => [
['label' => '컨설팅', 'ref' => 'SV-CONS'],
['label' => '교육', 'ref' => 'SV-EDU'],
['label' => '유지보수', 'ref' => 'SV-MAINT']
]
]
];
재고 추적 설정
// 창고 관리 설정
$warehouse_config = [
'default_warehouse' => [
'label' => '본사 창고',
'description' => '서울 본사 메인 창고',
'address' => '서울시 강남구 테헤란로 123',
'status' => 1 // 활성 상태
],
'stock_alerts' => [
'enable_low_stock_alert' => true,
'low_stock_threshold' => 10, // 최소 재고량
'enable_overstock_alert' => true,
'overstock_threshold' => 1000, // 과재고 임계값
'alert_recipients' => [
'warehouse@example.com',
'manager@example.com'
]
],
'stock_valuation' => [
'method' => 'FIFO', // FIFO, LIFO, WAC (가중평균)
'include_transport_cost' => true,
'auto_calculate_price' => true
]
];
3. 회계 및 재무 관리
계정 과목 설정
// 한국 표준 계정과목 체계
$chart_of_accounts = [
// 자산
'1' => [
'account' => '100000',
'label' => '자산',
'children' => [
'110000' => '유동자산',
'111000' => '당좌자산',
'111100' => '현금및현금등가물',
'111110' => '현금',
'111120' => '예금',
'112000' => '단기금융상품',
'113000' => '매출채권',
'114000' => '기타채권',
'115000' => '재고자산'
]
],
// 부채
'2' => [
'account' => '200000',
'label' => '부채',
'children' => [
'210000' => '유동부채',
'211000' => '매입채무',
'212000' => '단기차입금',
'213000' => '미지급금',
'214000' => '미지급비용',
'220000' => '비유동부채'
]
],
// 자본
'3' => [
'account' => '300000',
'label' => '자본',
'children' => [
'310000' => '자본금',
'320000' => '자본잉여금',
'330000' => '이익잉여금'
]
],
// 수익
'4' => [
'account' => '400000',
'label' => '수익',
'children' => [
'410000' => '매출액',
'411000' => '상품매출',
'412000' => '제품매출',
'413000' => '용역매출',
'420000' => '영업외수익'
]
],
// 비용
'5' => [
'account' => '500000',
'label' => '비용',
'children' => [
'510000' => '매출원가',
'520000' => '판매비와관리비',
'521000' => '급여',
'522000' => '임차료',
'523000' => '감가상각비',
'524000' => '광고선전비',
'530000' => '영업외비용'
]
]
];
세금 설정 (한국)
// 부가가치세 설정
$tax_configuration = [
'vat_standard' => [
'code' => 'VAT10',
'label' => '부가가치세 10%',
'rate' => 10.0,
'account_collect' => '214100', // 부가세대급금
'account_pay' => '113200', // 부가세선급금
'active' => true
],
'vat_zero' => [
'code' => 'VAT0',
'label' => '영세율 0%',
'rate' => 0.0,
'account_collect' => '214100',
'account_pay' => '113200',
'active' => true
],
'withholding_tax' => [
[
'code' => 'WHT33',
'label' => '소득세 3.3%',
'rate' => 3.3,
'type' => 'withholding',
'account' => '214200'
],
[
'code' => 'WHT88',
'label' => '소득세 8.8%',
'rate' => 8.8,
'type' => 'withholding',
'account' => '214200'
]
]
];
고급 커스터마이징
1. 커스텀 모듈 개발
모듈 구조 생성
// /htdocs/custom/mymodule/core/modules/modMyModule.class.php
class modMyModule extends DolibarrModules
{
public function __construct($db)
{
global $conf;
$this->db = $db;
$this->numero = 500000; // 고유 모듈 번호
$this->rights_class = 'mymodule';
$this->family = "other";
$this->name = preg_replace('/^mod/i', '', get_class($this));
$this->description = "사용자 정의 모듈";
$this->version = '1.0.0';
$this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
// 모듈 의존성
$this->depends = array('modSociete', 'modFacture');
$this->requiredby = array();
// 설정 가능한 상수
$this->const = array(
0 => array(
'MYMODULE_MYPARAM1',
'chaine',
'MyParam1 value',
'Description of parameter 1'
),
1 => array(
'MYMODULE_MYPARAM2',
'chaine',
'MyParam2 value',
'Description of parameter 2'
)
);
// 권한 설정
$this->rights = array(
0 => array(
'id' => 500001,
'label' => 'Read MyModule',
'type' => 'r',
'default' => 1
),
1 => array(
'id' => 500002,
'label' => 'Create/Update MyModule',
'type' => 'w',
'default' => 0
)
);
// 메뉴 구성
$this->menu = array(
0 => array(
'fk_menu' => 'fk_mainmenu=mymodule',
'type' => 'top',
'titre' => 'MyModule',
'url' => '/custom/mymodule/index.php',
'langs' => 'mymodule@mymodule',
'position' => 1000,
'enabled' => 1,
'perms' => '$user->rights->mymodule->read',
'target' => '',
'user' => 2
)
);
}
}
커스텀 비즈니스 객체
// /htdocs/custom/mymodule/class/myobject.class.php
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
class MyObject extends CommonObject
{
public $element = 'myobject';
public $table_element = 'mymodule_myobject';
// 필드 정의
public $fields = array(
'rowid' => array(
'type' => 'integer',
'label' => 'TechnicalID',
'enabled' => 1,
'position' => 1,
'notnull' => 1,
'visible' => 0,
'noteditable' => 1,
'index' => 1,
'comment' => "Id"
),
'ref' => array(
'type' => 'varchar(128)',
'label' => 'Ref',
'enabled' => 1,
'position' => 10,
'notnull' => 1,
'visible' => 4,
'noteditable' => 1,
'default' => '(PROV)',
'index' => 1,
'searchall' => 1,
'showoncombobox' => 1,
'comment' => "Reference of object"
),
'title' => array(
'type' => 'varchar(255)',
'label' => 'Title',
'enabled' => 1,
'position' => 20,
'notnull' => 1,
'visible' => 1,
'searchall' => 1,
'css' => 'minwidth300',
'help' => "Help text for title"
),
'amount' => array(
'type' => 'double(24,8)',
'label' => 'Amount',
'enabled' => 1,
'position' => 30,
'notnull' => 0,
'visible' => 1,
'default' => '0',
'css' => 'right'
)
);
public function __construct($db)
{
global $conf, $langs;
$this->db = $db;
if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) {
$this->fields['rowid']['visible'] = 0;
}
if (empty($conf->multicompany->enabled) && isset($this->fields['entity'])) {
$this->fields['entity']['enabled'] = 0;
}
}
public function create(User $user, $notrigger = false)
{
$resultcreate = $this->createCommon($user, $notrigger);
if ($resultcreate > 0) {
// 참조번호 자동 생성
if ($this->ref == '(PROV)') {
$this->ref = $this->getNextNumRef();
$this->update($user, $notrigger);
}
}
return $resultcreate;
}
private function getNextNumRef()
{
global $conf;
$prefix = 'MO';
$year = date('Y');
$sql = "SELECT MAX(CAST(SUBSTRING(ref, LENGTH('".$prefix.$year."')+1) AS UNSIGNED)) as max";
$sql .= " FROM ".$this->db->prefix().$this->table_element;
$sql .= " WHERE ref LIKE '".$prefix.$year."%'";
$resql = $this->db->query($sql);
if ($resql) {
$obj = $this->db->fetch_object($resql);
$max = (int) $obj->max;
$next = $max + 1;
return $prefix.$year.sprintf('%04d', $next);
}
return $prefix.$year.'0001';
}
}
2. 워크플로우 자동화
이메일 알림 자동화
// /htdocs/custom/workflows/email_automation.php
class EmailWorkflow
{
private $db;
private $conf;
public function __construct($db)
{
global $conf;
$this->db = $db;
$this->conf = $conf;
}
/**
* 견적서 승인 시 자동 이메일 발송
*/
public function sendQuoteApprovalEmail($quoteid)
{
require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
$quote = new Propal($this->db);
$quote->fetch($quoteid);
$quote->fetch_thirdparty();
// 이메일 템플릿 로드
$email_template = $this->loadEmailTemplate('quote_approved');
// 변수 치환
$subject = str_replace(
['__REF__', '__COMPANY__'],
[$quote->ref, $quote->thirdparty->name],
$email_template['subject']
);
$message = str_replace(
['__REF__', '__COMPANY__', '__AMOUNT__', '__VALID_UNTIL__'],
[
$quote->ref,
$quote->thirdparty->name,
price($quote->total_ttc),
dol_print_date($quote->fin_validite, 'day')
],
$email_template['body']
);
// PDF 첨부파일 생성
$pdf_path = $this->generateQuotePDF($quote);
// 이메일 발송
$mail = new CMailFile(
$subject,
$quote->thirdparty->email,
$this->conf->global->MAIN_MAIL_EMAIL_FROM,
$message,
array($pdf_path),
array(),
array(),
'',
'',
0,
-1
);
$result = $mail->sendfile();
if ($result) {
// 로그 기록
$this->logActivity($quoteid, 'EMAIL_SENT', '견적서 승인 이메일 발송 성공');
}
return $result;
}
/**
* 송장 연체 시 알림 이메일 자동 발송
*/
public function sendOverdueInvoiceReminder()
{
require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
$sql = "SELECT f.rowid";
$sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
$sql .= " WHERE f.fk_statut = 1"; // 승인된 송장
$sql .= " AND f.date_lim_reglement < CURDATE()"; // 지불기한 초과
$sql .= " AND f.paye = 0"; // 미지불
$sql .= " AND (f.last_reminder IS NULL OR f.last_reminder < DATE_SUB(CURDATE(), INTERVAL 7 DAY))";
$resql = $this->db->query($sql);
if ($resql) {
while ($obj = $this->db->fetch_object($resql)) {
$invoice = new Facture($this->db);
$invoice->fetch($obj->rowid);
$invoice->fetch_thirdparty();
// 연체 일수 계산
$overdue_days = (strtotime(date('Y-m-d')) - strtotime($invoice->date_lim_reglement)) / 86400;
// 연체 단계별 다른 템플릿 사용
if ($overdue_days <= 7) {
$template = 'overdue_reminder_1';
} elseif ($overdue_days <= 30) {
$template = 'overdue_reminder_2';
} else {
$template = 'overdue_final_notice';
}
$this->sendOverdueNotification($invoice, $template, $overdue_days);
// 마지막 알림 날짜 업데이트
$sql_update = "UPDATE ".MAIN_DB_PREFIX."facture SET last_reminder = CURDATE() WHERE rowid = ".$invoice->id;
$this->db->query($sql_update);
}
}
}
private function loadEmailTemplate($template_name)
{
// 데이터베이스 또는 파일에서 이메일 템플릿 로드
$templates = [
'quote_approved' => [
'subject' => '견적서 승인 알림 - __REF__ (__COMPANY__)',
'body' => '
안녕하세요 __COMPANY__ 담당자님,
견적서 __REF__가 승인되었습니다.
• 견적 금액: __AMOUNT__
• 유효 기간: __VALID_UNTIL__
첨부된 견적서를 확인해 주시기 바랍니다.
감사합니다.
'
],
'overdue_reminder_1' => [
'subject' => '[1차 알림] 송장 지불 기한 경과 - __REF__',
'body' => '
안녕하세요 __COMPANY__ 담당자님,
송장 __REF__의 지불 기한이 __OVERDUE_DAYS__일 경과하였습니다.
빠른 시일 내에 지불해 주시기 바랍니다.
'
]
];
return $templates[$template_name] ?? null;
}
}
// 크론 작업으로 정기 실행
// crontab -e
// 0 9 * * * /usr/bin/php /var/www/html/dolibarr/htdocs/custom/workflows/cron_overdue_reminders.php
3. 리포팅 및 대시보드
커스텀 대시보드 위젯
// /htdocs/custom/dashboard/widgets/sales_performance.php
class SalesPerformanceWidget
{
private $db;
public function __construct($db)
{
$this->db = $db;
}
public function getSalesData($period = 'current_year')
{
$date_conditions = $this->getDateConditions($period);
// 월별 매출 추이
$monthly_sales = $this->getMonthlySales($date_conditions);
// 상위 고객
$top_customers = $this->getTopCustomers($date_conditions);
// 제품별 매출
$product_sales = $this->getProductSales($date_conditions);
// 영업팀 성과
$sales_team_performance = $this->getSalesTeamPerformance($date_conditions);
return [
'monthly_sales' => $monthly_sales,
'top_customers' => $top_customers,
'product_sales' => $product_sales,
'team_performance' => $sales_team_performance,
'kpis' => $this->calculateKPIs($date_conditions)
];
}
private function getMonthlySales($date_conditions)
{
$sql = "SELECT ";
$sql .= " DATE_FORMAT(f.datef, '%Y-%m') as month,";
$sql .= " SUM(f.total_ttc) as amount,";
$sql .= " COUNT(f.rowid) as count";
$sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
$sql .= " WHERE f.fk_statut >= 1"; // 승인된 송장
$sql .= " AND ".$date_conditions;
$sql .= " GROUP BY DATE_FORMAT(f.datef, '%Y-%m')";
$sql .= " ORDER BY month";
$result = [];
$resql = $this->db->query($sql);
if ($resql) {
while ($obj = $this->db->fetch_object($resql)) {
$result[] = [
'month' => $obj->month,
'amount' => (float) $obj->amount,
'count' => (int) $obj->count
];
}
}
return $result;
}
private function getTopCustomers($date_conditions, $limit = 10)
{
$sql = "SELECT ";
$sql .= " s.nom as customer_name,";
$sql .= " s.rowid as customer_id,";
$sql .= " SUM(f.total_ttc) as total_amount,";
$sql .= " COUNT(f.rowid) as invoice_count,";
$sql .= " AVG(f.total_ttc) as avg_amount";
$sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid";
$sql .= " WHERE f.fk_statut >= 1";
$sql .= " AND ".$date_conditions;
$sql .= " GROUP BY s.rowid, s.nom";
$sql .= " ORDER BY total_amount DESC";
$sql .= " LIMIT ".$limit;
$result = [];
$resql = $this->db->query($sql);
if ($resql) {
while ($obj = $this->db->fetch_object($resql)) {
$result[] = [
'customer_name' => $obj->customer_name,
'customer_id' => $obj->customer_id,
'total_amount' => (float) $obj->total_amount,
'invoice_count' => (int) $obj->invoice_count,
'avg_amount' => (float) $obj->avg_amount
];
}
}
return $result;
}
private function calculateKPIs($date_conditions)
{
// 총 매출
$total_revenue = $this->getTotalRevenue($date_conditions);
// 신규 고객 수
$new_customers = $this->getNewCustomersCount($date_conditions);
// 평균 거래 금액
$avg_transaction = $this->getAverageTransaction($date_conditions);
// 송장 수금률
$collection_rate = $this->getCollectionRate($date_conditions);
return [
'total_revenue' => $total_revenue,
'new_customers' => $new_customers,
'avg_transaction' => $avg_transaction,
'collection_rate' => $collection_rate
];
}
public function generateChart($data, $type = 'line')
{
// Chart.js용 데이터 구조 생성
$chart_data = [
'type' => $type,
'data' => [
'labels' => array_column($data, 'month'),
'datasets' => [
[
'label' => '월별 매출',
'data' => array_column($data, 'amount'),
'backgroundColor' => 'rgba(54, 162, 235, 0.2)',
'borderColor' => 'rgba(54, 162, 235, 1)',
'borderWidth' => 2
]
]
],
'options' => [
'responsive' => true,
'scales' => [
'y' => [
'beginAtZero' => true,
'ticks' => [
'callback' => 'function(value) { return "₩" + value.toLocaleString(); }'
]
]
]
]
];
return json_encode($chart_data);
}
}
보안 및 최적화
1. 보안 강화
SSL/TLS 설정
# Let's Encrypt 인증서 설치
sudo apt install certbot python3-certbot-apache -y
# 인증서 발급
sudo certbot --apache -d your-domain.com -d www.your-domain.com
# 자동 갱신 설정
sudo crontab -e
# 0 12 * * * /usr/bin/certbot renew --quiet
보안 헤더 설정
# Apache 보안 설정 추가
<VirtualHost *:443>
# ... 기존 설정 ...
# 보안 헤더
Header always set X-Content-Type-Options nosniff
Header always set X-Frame-Options DENY
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self';"
# HSTS (HTTP Strict Transport Security)
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
# 서버 정보 숨기기
ServerTokens Prod
ServerSignature Off
</VirtualHost>
파일 권한 최적화
# 보안 강화를 위한 파일 권한 설정
sudo find /var/www/html/dolibarr -type d -exec chmod 755 {} \;
sudo find /var/www/html/dolibarr -type f -exec chmod 644 {} \;
# 민감한 디렉토리 보호
sudo chmod 700 /var/www/html/dolibarr/documents/
sudo chmod 600 /var/www/html/dolibarr/htdocs/conf/conf.php
# 웹에서 접근하면 안 되는 파일들
sudo cat > /var/www/html/dolibarr/.htaccess << EOF
# Dolibarr 보안 설정
<Files "*.conf">
Require all denied
</Files>
<Files "*.log">
Require all denied
</Files>
<FilesMatch "\.(inc|conf|config|log)$">
Require all denied
</FilesMatch>
# PHP 실행 방지가 필요한 디렉토리
<Directory "documents">
php_admin_flag engine off
</Directory>
EOF
2. 성능 최적화
MySQL 쿼리 최적화
-- 자주 사용되는 쿼리를 위한 인덱스 추가
ALTER TABLE llx_societe ADD INDEX idx_nom (nom);
ALTER TABLE llx_facture ADD INDEX idx_datef_statut (datef, fk_statut);
ALTER TABLE llx_facturedet ADD INDEX idx_fk_facture_fk_product (fk_facture, fk_product);
-- 파티션 테이블 (대용량 데이터용)
ALTER TABLE llx_facture
PARTITION BY RANGE (YEAR(datef)) (
PARTITION p2020 VALUES LESS THAN (2021),
PARTITION p2021 VALUES LESS THAN (2022),
PARTITION p2022 VALUES LESS THAN (2023),
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p2024 VALUES LESS THAN (2025),
PARTITION p_future VALUES LESS THAN MAXVALUE
);
PHP OPcache 설정
# PHP OPcache 설정 파일 편집
sudo nano /etc/php/8.1/apache2/conf.d/10-opcache.ini
; OPcache 최적화 설정
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=2
opcache.save_comments=1
opcache.fast_shutdown=1
캐싱 시스템 구성
// /htdocs/conf/conf.php 에 추가
// Redis 캐시 설정
$dolibarr_main_cache_driver = 'redis';
$dolibarr_main_cache_host = 'localhost';
$dolibarr_main_cache_port = 6379;
$dolibarr_main_cache_prefix = 'dolibarr_';
// 또는 Memcached 사용
// $dolibarr_main_cache_driver = 'memcached';
// $dolibarr_main_cache_host = 'localhost';
// $dolibarr_main_cache_port = 11211;
백업 및 유지보수
1. 자동 백업 시스템
데이터베이스 백업 스크립트
#!/bin/bash
# /usr/local/bin/dolibarr_backup.sh
# 설정
DB_NAME="dolibarr"
DB_USER="dolibarr_user"
DB_PASS="strong_password_here"
BACKUP_DIR="/var/backups/dolibarr"
FILES_DIR="/var/www/html/dolibarr/documents"
RETENTION_DAYS=30
# 백업 디렉토리 생성
mkdir -p $BACKUP_DIR/{database,files}
# 현재 날짜
DATE=$(date +%Y%m%d_%H%M%S)
echo "=== Dolibarr 백업 시작: $DATE ==="
# 1. 데이터베이스 백업
echo "데이터베이스 백업 중..."
mysqldump -u $DB_USER -p$DB_PASS \
--single-transaction \
--routines \
--triggers \
--events \
--hex-blob \
$DB_NAME | gzip > $BACKUP_DIR/database/dolibarr_db_$DATE.sql.gz
if [ $? -eq 0 ]; then
echo "✅ 데이터베이스 백업 완료"
else
echo "❌ 데이터베이스 백업 실패"
exit 1
fi
# 2. 파일 백업
echo "파일 시스템 백업 중..."
tar -czf $BACKUP_DIR/files/dolibarr_files_$DATE.tar.gz \
-C /var/www/html/dolibarr \
documents/ \
htdocs/conf/conf.php \
htdocs/custom/
if [ $? -eq 0 ]; then
echo "✅ 파일 백업 완료"
else
echo "❌ 파일 백업 실패"
exit 1
fi
# 3. 백업 무결성 검사
echo "백업 무결성 검사 중..."
gzip -t $BACKUP_DIR/database/dolibarr_db_$DATE.sql.gz
tar -tzf $BACKUP_DIR/files/dolibarr_files_$DATE.tar.gz > /dev/null
if [ $? -eq 0 ]; then
echo "✅ 백업 무결성 확인 완료"
else
echo "❌ 백업 파일 손상됨"
exit 1
fi
# 4. 오래된 백업 삭제
echo "오래된 백업 정리 중..."
find $BACKUP_DIR/database -name "*.sql.gz" -type f -mtime +$RETENTION_DAYS -delete
find $BACKUP_DIR/files -name "*.tar.gz" -type f -mtime +$RETENTION_DAYS -delete
# 5. 백업 크기 확인
DB_SIZE=$(du -sh $BACKUP_DIR/database/dolibarr_db_$DATE.sql.gz | cut -f1)
FILES_SIZE=$(du -sh $BACKUP_DIR/files/dolibarr_files_$DATE.tar.gz | cut -f1)
echo "📊 백업 완료:"
echo " - 데이터베이스: $DB_SIZE"
echo " - 파일: $FILES_SIZE"
echo " - 저장 위치: $BACKUP_DIR"
# 6. 백업 결과 이메일 전송 (선택사항)
if command -v mail &> /dev/null; then
echo "백업이 성공적으로 완료되었습니다." | \
mail -s "Dolibarr 백업 완료 - $DATE" admin@your-company.com
fi
echo "=== 백업 완료: $(date +%Y%m%d_%H%M%S) ==="
자동 백업 스케줄링
# crontab 설정
sudo crontab -e
# 매일 새벽 2시에 백업 실행
0 2 * * * /usr/local/bin/dolibarr_backup.sh >> /var/log/dolibarr_backup.log 2>&1
# 실행 권한 부여
sudo chmod +x /usr/local/bin/dolibarr_backup.sh
2. 시스템 모니터링
성능 모니터링 스크립트
#!/bin/bash
# /usr/local/bin/dolibarr_monitor.sh
# 임계값 설정
CPU_THRESHOLD=80
MEMORY_THRESHOLD=85
DISK_THRESHOLD=90
DB_CONNECTION_THRESHOLD=50
# 시스템 상태 체크
check_system_health() {
echo "=== Dolibarr 시스템 상태 체크 ==="
# CPU 사용률
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
echo "CPU 사용률: ${CPU_USAGE}%"
# 메모리 사용률
MEMORY_USAGE=$(free | grep Mem | awk '{printf("%.1f"), $3/$2 * 100.0}')
echo "메모리 사용률: ${MEMORY_USAGE}%"
# 디스크 사용률
DISK_USAGE=$(df /var/www/html/dolibarr | tail -1 | awk '{print $5}' | sed 's/%//')
echo "디스크 사용률: ${DISK_USAGE}%"
# 데이터베이스 연결 수
DB_CONNECTIONS=$(mysql -u dolibarr_user -pstrong_password_here -e "SHOW STATUS LIKE 'Threads_connected';" | tail -1 | awk '{print $2}')
echo "DB 연결 수: ${DB_CONNECTIONS}"
# 웹 서버 상태
if systemctl is-active --quiet apache2; then
echo "웹 서버 상태: ✅ 정상"
else
echo "웹 서버 상태: ❌ 중지됨"
systemctl restart apache2
fi
# 데이터베이스 상태
if systemctl is-active --quiet mysql; then
echo "데이터베이스 상태: ✅ 정상"
else
echo "데이터베이스 상태: ❌ 중지됨"
systemctl restart mysql
fi
# 경고 발송
if (( $(echo "$CPU_USAGE > $CPU_THRESHOLD" | bc -l) )); then
send_alert "CPU 사용률 높음: ${CPU_USAGE}%"
fi
if (( $(echo "$MEMORY_USAGE > $MEMORY_THRESHOLD" | bc -l) )); then
send_alert "메모리 사용률 높음: ${MEMORY_USAGE}%"
fi
if [ "$DISK_USAGE" -gt "$DISK_THRESHOLD" ]; then
send_alert "디스크 사용률 높음: ${DISK_USAGE}%"
fi
}
send_alert() {
local message="$1"
echo "⚠️ 경고: $message"
# 이메일 알림 (선택사항)
if command -v mail &> /dev/null; then
echo "$message" | mail -s "Dolibarr 시스템 경고" admin@your-company.com
fi
# 로그 기록
echo "$(date): $message" >> /var/log/dolibarr_alerts.log
}
# 실행
check_system_health
결론
Dolibarr은 중소기업을 위한 완전한 디지털 트랜스포메이션 솔루션입니다. 오픈소스의 유연성과 상용 솔루션의 기능성을 모두 갖춘 성숙한 플랫폼으로, 비용 효율적이면서도 강력한 비즈니스 관리를 가능하게 합니다.
🎯 핵심 가치
- 비용 절약: 상용 ERP 대비 80% 이상 비용 절감
- 유연성: 모듈식 구조로 필요한 기능만 선택적 도입
- 확장성: 커스텀 모듈과 워크플로우로 무한 확장
- 통합성: CRM부터 ERP까지 하나의 플랫폼에서 관리
🚀 적용 분야
- 제조업: 재고관리, 생산계획, 품질관리
- 유통업: 고객관리, 주문처리, 물류관리
- 서비스업: 프로젝트관리, 시간추적, 고객지원
- 비영리단체: 회원관리, 기부관리, 이벤트관리
💡 성공 요인
- 체계적 도입: 단계별 모듈 활성화로 안정적 전환
- 사용자 교육: 충분한 교육으로 시스템 활용도 극대화
- 데이터 품질: 정확한 초기 데이터 입력과 지속적 관리
- 커스터마이징: 업무 프로세스에 맞는 맞춤형 개발
🔮 미래 발전 방향
- AI 통합: 머신러닝 기반 예측 분석 및 자동화
- 모바일 최적화: 완전한 모바일 ERP 경험
- 클라우드 네이티브: 마이크로서비스 아키텍처 전환
- API 생태계: 다양한 외부 서비스와의 완벽한 연동
Dolibarr을 통해 효율적이고 체계적인 비즈니스 관리 시스템을 구축하고, 디지털 혁신을 통한 경쟁력 강화를 실현해보시기 바랍니다. 오픈소스의 힘으로 엔터프라이즈급 솔루션을 경험하시길 바랍니다! 🏢💼✨
참고 자료