Customization

Learn how to brand, extend, and customize Automation Hub — from simple logo changes to building your own custom modules with the Module SDK.

Branding

Customize the look and feel of your Automation Hub instance to match your organization's brand identity.

Logo & Favicon

Navigate to Settings > General to upload:

Landing Page Branding

Navigate to Settings > Landing Page for additional branding options specific to the public-facing page:

Landing Page Editor

The landing page admin editor at Settings > Landing Page provides full control over all public-facing sections:

Each section supports:

Adding Translations

Automation Hub uses i18next for frontend internationalization. Translation files are JSON files located at:

File Structure
resources/js/locales/
├── en/
│   └── common.json       # English translations
├── es/
│   └── common.json       # Spanish translations
├── fr/
│   └── common.json       # French translations
└── ar/
    └── common.json       # Arabic translations

Translation File Format

Each common.json file is a flat or nested JSON object with translation keys:

resources/js/locales/en/common.json
{
  "dashboard": {
    "title": "Dashboard",
    "welcome": "Welcome back, {{name}}",
    "totalWorkflows": "Total Workflows",
    "totalExecutions": "Total Executions"
  },
  "workflows": {
    "title": "Workflows",
    "create": "Create Workflow",
    "edit": "Edit Workflow",
    "delete": "Delete Workflow",
    "confirmDelete": "Are you sure you want to delete this workflow?"
  },
  "common": {
    "save": "Save",
    "cancel": "Cancel",
    "delete": "Delete",
    "loading": "Loading..."
  }
}

How to Add a New Key

  1. Add the key to all 4 locale files (en, es, fr, ar)
  2. Use the useTranslation hook in your React component:
React Component Example
import { useTranslation } from 'react-i18next';

export function MyComponent() {
  const { t } = useTranslation();

  return (
    <div>
      <h1>{t('myModule.title')}</h1>
      <p>{t('myModule.description', { count: 5 })}</p>
    </div>
  );
}

Adding a New Language

  1. Create a new folder: resources/js/locales/{locale}/common.json
  2. Copy the English file as a base and translate all keys
  3. Register the locale in the i18n configuration file
  4. Add RTL support if needed (set dir: 'rtl' in the locale config)

Creating a Custom Module

Automation Hub provides a Module SDK that allows you to create custom modules with their own node types, routes, and business logic.

Step 1: Create the Module Folder

bash
mkdir -p app/Modules/YourModule

Step 2: Create module.json Manifest

app/Modules/YourModule/module.json
{
  "name": "YourModule",
  "slug": "your-module",
  "version": "1.0.0",
  "description": "A custom module for Automation Hub",
  "author": "Your Name",
  "enabled": true,
  "provider": "App\\Modules\\YourModule\\YourModuleProvider",
  "nodes": [
    "your_custom_action"
  ],
  "settings": {
    "api_key": {
      "type": "encrypted",
      "label": "API Key",
      "required": true
    }
  }
}

Step 3: Create the Module Service Provider

app/Modules/YourModule/YourModuleProvider.php
<?php

namespace App\Modules\YourModule;

use App\Core\Modules\ModuleSDK;

class YourModuleProvider extends ModuleSDK
{
    /**
     * Register node executors provided by this module.
     */
    public function registerNodeExecutors(): array
    {
        return [
            'your_custom_action' => \App\Modules\YourModule\Nodes\YourCustomActionExecutor::class,
        ];
    }

    /**
     * Register module-specific routes.
     */
    public function registerRoutes(): void
    {
        // Register API routes, webhook endpoints, etc.
    }

    /**
     * Boot the module (run after all providers are registered).
     */
    public function boot(): void
    {
        // Publish config, migrations, views, etc.
    }
}

Step 4: Create a Node Executor

app/Modules/YourModule/Nodes/YourCustomActionExecutor.php
<?php

namespace App\Modules\YourModule\Nodes;

use App\Core\Contracts\NodeExecutorInterface;
use App\Core\DTOs\NodeExecutionContext;
use App\Core\DTOs\NodeExecutionResult;

class YourCustomActionExecutor implements NodeExecutorInterface
{
    /**
     * Execute the node logic.
     *
     * @param NodeExecutionContext $context Contains input data, config, and credentials
     * @return NodeExecutionResult The output to pass to downstream nodes
     */
    public function execute(NodeExecutionContext $context): NodeExecutionResult
    {
        // Access input from previous nodes
        $inputData = $context->getInputData();
        $name = $inputData['name'] ?? 'World';

        // Access module settings (decrypted automatically)
        $apiKey = $context->getModuleSetting('api_key');

        // Perform your custom logic
        $result = [
            'greeting' => "Hello, {$name}!",
            'timestamp' => now()->toISOString(),
        ];

        return NodeExecutionResult::success($result);
    }

    /**
     * Describe the node for the visual canvas (inputs, outputs, config fields).
     */
    public static function describe(): array
    {
        return [
            'type' => 'your_custom_action',
            'label' => 'Your Custom Action',
            'description' => 'Performs a custom action with your external service',
            'category' => 'your-module',
            'icon' => 'zap',
            'inputs' => [
                [
                    'key' => 'name',
                    'label' => 'Name',
                    'type' => 'string',
                    'required' => true,
                    'description' => 'The name to greet',
                ],
            ],
            'outputs' => [
                ['key' => 'greeting', 'type' => 'string'],
                ['key' => 'timestamp', 'type' => 'string'],
            ],
            'config' => [],
        ];
    }
}

Step 5: Register the Module

Register your module using the artisan command:

bash
php artisan module:discover

Alternatively, register it manually in the module configuration file.

Project Folder Structure

Folder Structure Overview
automation-hub/
├── app/
│   ├── Core/                    # Core platform logic
│   │   ├── Contracts/           # Interfaces (NodeExecutorInterface, etc.)
│   │   ├── DTOs/                # Data Transfer Objects
│   │   ├── Engine/              # Workflow execution engine
│   │   ├── Events/              # Domain events & event bus
│   │   ├── Models/              # Eloquent models (Workflow, Execution, etc.)
│   │   ├── Modules/             # Module SDK base classes
│   │   └── Services/            # Core services (audit, auth, etc.)
│   ├── Modules/                 # Feature modules (self-contained)
│   │   ├── Email/               # Email module (SMTP, Resend)
│   │   ├── WhatsApp/            # WhatsApp module (Meta, Twilio)
│   │   ├── AI/                  # AI module (Claude, OpenAI)
│   │   ├── Courier/             # Courier module (Deprixa Plus)
│   │   └── Notifications/       # Notifications module
│   ├── Shared/                  # Shared utilities, traits, helpers
│   └── Http/                    # Controllers, Middleware, Requests
├── resources/
│   └── js/
│       ├── Pages/               # Inertia.js React pages
│       ├── Components/          # Reusable React components
│       ├── Hooks/               # Custom React hooks
│       ├── Layouts/             # Page layouts
│       └── locales/             # i18n translation files (en/es/fr/ar)
├── routes/                      # Web and API route definitions
├── database/
│   ├── migrations/              # Database migrations
│   └── seeders/                 # Data seeders (templates, etc.)
├── config/                      # Configuration files
├── tests/                       # Automated tests (274 tests)
└── public/                      # Web root (compiled assets)

Modular Architecture

Each module in app/Modules/ is self-contained with its own providers, node executors, models, and configuration. This makes it easy to add, remove, or replace modules without affecting the core platform.