Huge role refactoring/cleanup. Other commits will propably follow. Because some bugs will exist. Still important for longrun and also for auto docs/help/slideshow generation

This commit is contained in:
2025-07-08 23:43:13 +02:00
parent 6b87a049d4
commit 563d5fd528
1242 changed files with 2301 additions and 1355 deletions

View File

@@ -0,0 +1,39 @@
# EspoCRM
## Description
Enhance your sales and service processes with EspoCRM, an open-source CRM featuring workflow automation, LDAP/OIDC single sign-on, and a sleek, lightweight UI! 🚀💼
## Overview
This Ansible role deploys EspoCRM using Docker. It handles:
- MariaDB database provisioning via the `service-rdbms-central` role
- Nginx domain setup with WebSocket and reverse-proxy configuration
- Environment variable management through Jinja2 templates
- Docker Compose orchestration for **web**, **daemon**, and **websocket** services
- Automatic OIDC scope configuration within the EspoCRM container
With this role, you'll have a production-ready CRM environment that's secure, scalable, and real-time.
## Features
- **Workflow Automation:** Create and manage automated CRM processes with ease 🛠️
- **LDAP/OIDC SSO:** Integrate with corporate identity providers for seamless login 🔐
- **WebSocket Notifications:** Real-time updates via ZeroMQ and WebSockets 🌐
- **Config via Templates:** Fully customizable `.env` and `docker-compose.yml` with Jinja2 ⚙️
- **Health Checks & Logging:** Monitor service health and logs with built-in checks and journald 📈
- **Modular Role Composition:** Leverages central roles for database and Nginx, ensuring consistency across deployments 🔄
## Further Resources
- [EspoCRM Official Website](https://www.espocrm.com/) 🌍
- [EspoCRM Documentation](https://docs.espocrm.com/) 📖
- [CyMaIS Project Repository](https://github.com/kevinveenbirkenbach/cymais) 🔗
## Credits
Developed and maintained by **Kevin Veen-Birkenbach**.
Consulting & Coaching Solutions: [veen.world](https://www.veen.world) 🌟
Part of the [CyMaIS Project](https://github.com/kevinveenbirkenbach/cymais) 📂
License: [CyMaIS NonCommercial License (CNCL)](https://s.veen.world/cncl) ⚖️

View File

@@ -0,0 +1,21 @@
galaxy_info:
author: "Kevin Veen-Birkenbach"
description: "Empower your customer relationship management with EspoCRM. Tailored for businesses of all sizes, EspoCRM enables you to manage your sales, customer interactions, and business processes with ease, fostering productivity and streamlined communication across teams."
license: "CyMaIS NonCommercial License (CNCL)"
license_url: "https://s.veen.world/cncl"
company: |
Kevin Veen-Birkenbach
Consulting & Coaching Solutions
https://www.veen.world
galaxy_tags:
- espocrm
- crm
- sales
repository: "https://s.veen.world/cymais"
issue_tracker_url: "https://s.veen.world/cymaisissues"
documentation: "https://s.veen.world/cymais"
logo:
class: "fa-solid fa-phone"
run_after:
- web-app-keycloak
- web-app-mailu

View File

@@ -0,0 +1,9 @@
credentials:
administrator_password:
description: "Initial password for the EspoCRM administrator user"
algorithm: "sha256"
validation: "^[a-f0-9]{64}$"
database_password:
description: "Password for the EspoCRM database user"
algorithm: "bcrypt"
validation: "^\\$2[aby]\\$.{56}$"

View File

@@ -0,0 +1,8 @@
users:
administrator:
username: "administrator"
contact:
description: "General contact account"
username: "contact"
roles:
- mail-bot

View File

@@ -0,0 +1,29 @@
---
- name: "include service-rdbms-central"
include_role:
name: service-rdbms-central
- name: "Include setup for domain '{{ domain }}'"
include_role:
name: webserver-proxy-domain
vars:
ws_path: "/ws"
ws_port: "{{ ports.localhost.websocket[application_id] }}"
client_max_body_size: "100m"
vhost_flavour: "ws_generic"
domain: "{{ domains | get_domain(application_id) }}"
http_port: "{{ ports.localhost.http[application_id] }}"
- name: Set OIDC scopes in EspoCRM config (inside web container)
ansible.builtin.shell: |
docker compose exec -T web php -r '
require "/var/www/html/bootstrap.php";
$writer = (new \Espo\Core\Application())
->getContainer()
->get("injectableFactory")
->create("\Espo\Core\Utils\Config\ConfigWriter");
$writer->set("oidcScopes", ["openid", "profile", "email"]);
$writer->save();
'
args:
chdir: "{{ docker_compose.directories.instance }}"

View File

@@ -0,0 +1,44 @@
{% include 'roles/docker-compose/templates/base.yml.j2' %}
web:
image: "{{ applications[application_id].images.espocrm }}"
{% include 'roles/docker-container/templates/base.yml.j2' %}
{% include 'roles/docker-container/templates/healthcheck/curl.yml.j2' %}
ports:
- "127.0.0.1:{{ ports.localhost.http[application_id] }}:80"
{% include 'roles/docker-container/templates/depends_on/dmbs_excl.yml.j2' %}
{% include 'roles/docker-container/templates/networks.yml.j2' %}
volumes:
- data:/var/www/html
daemon:
image: "{{ applications[application_id].images.espocrm }}"
restart: {{docker_restart_policy}}
logging:
driver: journald
entrypoint: web-app-daemon.sh
{% include 'roles/docker-container/templates/networks.yml.j2' %}
volumes:
- data:/var/www/html
websocket:
image: "{{ applications[application_id].images.espocrm }}"
restart: {{docker_restart_policy}}
logging:
driver: journald
environment:
- ESPOCRM_CONFIG_USE_WEB_SOCKET=true
- ESPOCRM_CONFIG_WEB_SOCKET_URL=wss://{{ domains | get_domain(application_id) }}/ws
- ESPOCRM_CONFIG_WEB_SOCKET_ZERO_M_Q_SUBSCRIBER_DSN=tcp://*:7777
- ESPOCRM_CONFIG_WEB_SOCKET_ZERO_M_Q_SUBMISSION_DSN=tcp://websocket:7777
entrypoint: web-app-websocket.sh
{% include 'roles/docker-container/templates/depends_on/dmbs_excl.yml.j2' %}
{% include 'roles/docker-container/templates/networks.yml.j2' %}
volumes:
- data:/var/www/html
ports:
- "127.0.0.1:{{ ports.localhost.websocket[application_id] }}:8080"
{% include 'roles/docker-compose/templates/volumes.yml.j2' %}
data:
{% include 'roles/docker-compose/templates/networks.yml.j2' %}

View File

@@ -0,0 +1,105 @@
#############################################
# EspoCRM Docker Environment (.env) ENGLISH
# See: https://hub.docker.com/r/espocrm/espocrm
#############################################
# ------------------------------------------------
# Database connection
# ------------------------------------------------
ESPOCRM_DATABASE_PLATFORM=Mysql
ESPOCRM_DATABASE_HOST={{ database_host }}
ESPOCRM_DATABASE_PORT={{ database_port }}
ESPOCRM_DATABASE_NAME={{ database_name }}
ESPOCRM_DATABASE_USER={{ database_username }}
ESPOCRM_DATABASE_PASSWORD={{ database_password }}
# Disable EspoCRMs built-in cron (handled externally)
CRON_DISABLED=true
# ------------------------------------------------
# Initial admin account
# ------------------------------------------------
ESPOCRM_ADMIN_USERNAME={{ applications[application_id].users.administrator.username }}
ESPOCRM_ADMIN_PASSWORD={{ applications[application_id].credentials.administrator_password }}
# Public base URL of the EspoCRM instance
ESPOCRM_SITE_URL={{ domains | get_url(application_id, web_protocol) }}
# ------------------------------------------------
# General UI & locale settings
# ------------------------------------------------
ESPOCRM_CONFIG_LANGUAGE={{ HOST_LL_CC }}
ESPOCRM_CONFIG_DATE_FORMAT={{ HOST_DATE_FORMAT }}
ESPOCRM_CONFIG_TIME_FORMAT={{ HOST_TIME_FORMAT }}
ESPOCRM_CONFIG_TIME_ZONE={{ HOST_TIMEZONE }}
# ESPOCRM_CONFIG_WEEK_START: 0 = Sunday, 1 = Monday
ESPOCRM_CONFIG_WEEK_START=1
ESPOCRM_CONFIG_DEFAULT_CURRENCY={{ HOST_CURRENCY }}
#ESPOCRM_CONFIG_THOUSAND_SEPARATOR={{ HOST_THOUSAND_SEPARATOR }}
#ESPOCRM_CONFIG_DECIMAL_MARK={{HOST_DECIMAL_MARK}}
# ------------------------------------------------
# Logger
# ------------------------------------------------
ESPOCRM_CONFIG_LOGGER_LEVEL={{ 'DEBUG' if enable_debug | bool else 'INFO' }}
ESPOCRM_CONFIG_LOGGER_PATH=php://stdout
ESPOCRM_CONFIG_LOGGER_ROTATION=false
# ------------------------------------------------
# System SMTP settings
# ------------------------------------------------
ESPOCRM_CONFIG_SMTP_SERVER={{ system_email.host }}
ESPOCRM_CONFIG_SMTP_PORT={{ system_email.port }}
ESPOCRM_CONFIG_SMTP_SECURITY={{ "TLS" if system_email.start_tls else "SSL"}}
ESPOCRM_CONFIG_SMTP_AUTH=true
ESPOCRM_CONFIG_SMTP_USERNAME={{ users['contact'].email }}
ESPOCRM_CONFIG_SMTP_PASSWORD={{ users['contact'].mailu_token }}
ESPOCRM_CONFIG_OUTBOUND_EMAIL_FROM_NAME={{ applications[application_id].email.from_name}}
ESPOCRM_CONFIG_OUTBOUND_EMAIL_FROM_ADDRESS={{ users['contact'].email }}
# ------------------------------------------------
# LDAP settings (optional)
# Applied only if the feature flag is true
# ------------------------------------------------
{% if applications | is_feature_enabled('ldap',application_id) %}
ESPOCRM_CONFIG_AUTHENTICATION_METHOD=Ldap
ESPOCRM_CONFIG_LDAP_HOST={{ ldap.server.domain }}
ESPOCRM_CONFIG_LDAP_PORT={{ ldap.server.port }}
# ESPOCRM_CONFIG_LDAP_SECURITY: "", SSL or TLS
ESPOCRM_CONFIG_LDAP_SECURITY={{ ldap.server.security }}
ESPOCRM_CONFIG_LDAP_USERNAME={{ ldap.dn.administrator.data }}
ESPOCRM_CONFIG_LDAP_PASSWORD={{ ldap.bind_credential }}
ESPOCRM_CONFIG_LDAP_BASE_DN={{ ldap.dn.ou.users }}
ESPOCRM_CONFIG_LDAP_USER_LOGIN_FILTER=(sAMAccountName=%USERNAME%)
{% endif %}
# ------------------------------------------------
# OpenID Connect settings (optional)
# Applied only if the feature flag is true
# ------------------------------------------------
{% if applications | is_feature_enabled('oidc',application_id) %}
# ------------------------------------------------
# OpenID Connect settings
# ------------------------------------------------
ESPOCRM_CONFIG_OIDC_ALLOW_ADMIN_USER=true
ESPOCRM_CONFIG_AUTHENTICATION_METHOD=Oidc
ESPOCRM_CONFIG_OIDC_FALLBACK=false # set true if you want LDAP as fallback
ESPOCRM_CONFIG_OIDC_CLIENT_ID={{ oidc.client.id }}
ESPOCRM_CONFIG_OIDC_CLIENT_SECRET={{ oidc.client.secret }}
ESPOCRM_CONFIG_OIDC_AUTHORIZATION_ENDPOINT={{ oidc.client.authorize_url }}
ESPOCRM_CONFIG_OIDC_TOKEN_ENDPOINT={{ oidc.client.token_url }}
ESPOCRM_CONFIG_OIDC_USER_INFO_ENDPOINT={{ oidc.client.user_info_url }}
ESPOCRM_CONFIG_OIDC_JWKS_ENDPOINT={{ oidc.client.certs }}
ESPOCRM_CONFIG_OIDC_AUTHORIZATION_REDIRECT_URI=https://{{ domains | get_domain(application_id) }}/oidc/callback
#ESPOCRM_CONFIG_OIDC_SCOPES=openid,profile,email # Defined in main.yml
ESPOCRM_CONFIG_OIDC_CREATE_USER=true
ESPOCRM_CONFIG_OIDC_SYNC=true
ESPOCRM_CONFIG_OIDC_USERNAME_CLAIM={{oidc.attributes.username}}
# ESPOCRM_CONFIG_OIDC_SYNC_TEAMS=true
# ESPOCRM_CONFIG_OIDC_GROUP_CLAIM=group
{% endif %}

View File

@@ -0,0 +1,33 @@
images:
espocrm: "espocrm/espocrm:latest"
features:
matomo: true
css: false
portfolio_iframe: true
ldap: false
oidc: true
central_database: true
csp:
flags:
script-src-elem:
unsafe-inline: true
unsafe-eval: true
style-src:
unsafe-inline: true
script-src:
unsafe-eval: true
whitelist:
connect-src:
- wss://espocrm.{{ primary_domain }}
- "data:"
frame-src:
- https://s.espocrm.com/
domains:
aliases:
- "crm.{{ primary_domain }}"
email:
from_name: "Customer Relationship Management ({{ primary_domain }})"
docker:
services:
database:
enabled: true

View File

@@ -0,0 +1,3 @@
application_id: "espocrm"
# EspoCRM uses MySQL/MariaDB
database_type: "mariadb"