← Documentation Home

Drupal Module Development Guide

Comprehensive guide for developing custom Drupal modules in the LLM Platform ecosystem.

Table of Contents

Overview

The LLM Platform uses custom Drupal modules to provide AI-powered functionality, agent orchestration, and enterprise integrations. All modules follow Drupal coding standards and OSSA compliance requirements.

Key Principles

  1. OSSA Compliance: All AI agent modules must follow the Open Standard for Swarm Architecture
  2. Drupal Standards: Follow PHPCS and PHPStan standards (Drupal, DrupalPractice)
  3. Test Coverage: PHPUnit tests for all critical functionality
  4. API-First: REST, GraphQL, and JSON:API support
  5. Security: Input validation, access control, audit logging

Module Structure

Standard Drupal module structure with OSSA enhancements:

module_name/
├── .agents/                      # OSSA agent manifests
│   └── agent-name/
│       ├── manifest.json         # OSSA manifest
│       ├── README.md
│       └── tools/
├── .claude/                      # Claude Code configuration
│   └── CLAUDE.md                 # Employment protection
├── config/
│   ├── install/                  # Default config
│   └── schema/                   # Config schema
├── src/
│   ├── Controller/               # Route controllers
│   ├── Entity/                   # Entity definitions
│   ├── Form/                     # Form classes
│   ├── Plugin/                   # Plugin definitions
│   └── Service/                  # Services
├── tests/
│   ├── src/
│   │   ├── Unit/                 # Unit tests
│   │   ├── Kernel/               # Kernel tests
│   │   └── Functional/           # Functional tests
├── module_name.info.yml          # Module metadata
├── module_name.module            # Hooks
├── module_name.routing.yml       # Routes
├── module_name.services.yml      # Service definitions
├── module_name.permissions.yml   # Permissions
├── composer.json                 # Composer dependencies
└── README.md                     # Documentation

Development Workflow

1. Module Location

Source Location (edit here):

/Users/flux423/Sites/LLM/all_drupal_custom/modules/MODULE_NAME/

Deployment Location (Composer-managed, DO NOT EDIT):

/Users/flux423/Sites/LLM/llm-platform/web/modules/custom/MODULE_NAME/

2. Sync Modules

After making changes, sync to deployment:

buildkit drupal sync --modules

Or with dry-run to preview:

buildkit drupal sync --modules --dry-run

3. Module Creation

Create a new module:

buildkit drupal module:create my_module_name

This scaffolds: - Basic module structure - .info.yml with dependencies - Service definitions - OSSA compliance files - CLAUDE.md employment protection

4. Development Commands

# Clear cache
buildkit drupal cache:clear

# Export config
buildkit drupal config:export

# Run database updates
buildkit drupal database:update

# PHPCS validation
buildkit drupal phpcs MODULE_PATH --fix

# Design taste validation
buildkit drupal taste MODULE_PATH

OSSA Compliance

All AI agent modules must be OSSA-compliant.

Manifest Structure

Every agent requires .agents/agent-name/manifest.json:

{
  "name": "agent-name",
  "version": "1.0.0",
  "type": "worker",
  "description": "Agent description",
  "capabilities": [
    "capability1",
    "capability2"
  ],
  "tools": [
    {
      "name": "tool_name",
      "type": "function",
      "description": "Tool description",
      "parameters": {
        "type": "object",
        "properties": {},
        "required": []
      }
    }
  ],
  "dependencies": [],
  "security": {
    "isolation_level": "container",
    "permissions": []
  }
}

Validation

# Validate OSSA manifest
ossa validate .agents/agent-name/manifest.json

# Migrate old manifests
ossa migrate .agents/old-agent/ --output .agents/new-agent/

Best Practices

1. Module Info File

name: 'Module Name'
type: module
description: 'Clear, concise description including OSSA compliance note'
package: 'Package Name'
core_version_requirement: ^10.3 || ^11
version: 0.1.1

dependencies:
  # Core dependencies only
  - drupal:system (>=10.3)
  - drupal:user

suggests:
  # Optional enhancements
  - admin_toolbar:admin_toolbar

configure: module_name.settings
lifecycle: stable

2. Service Definitions

Use dependency injection:

# module_name.services.yml
services:
  module_name.service_name:
    class: Drupal\module_name\Service\ServiceName
    arguments:
      - '@entity_type.manager'
      - '@logger.factory'
      - '@config.factory'

3. Entity Definitions

Use ECK (Entity Construction Kit) or custom entities:

<?php

namespace Drupal\module_name\Entity;

use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;

/**
 * Defines the Example entity.
 *
 * @ContentEntityType(
 *   id = "example_entity",
 *   label = @Translation("Example Entity"),
 *   base_table = "example_entity",
 *   entity_keys = {
 *     "id" = "id",
 *     "uuid" = "uuid",
 *     "label" = "name",
 *   },
 * )
 */
class ExampleEntity extends ContentEntityBase {

  public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
    $fields = parent::baseFieldDefinitions($entity_type);

    $fields['name'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Name'))
      ->setRequired(TRUE);

    return $fields;
  }

}

4. Plugin System

Use plugins for extensibility:

<?php

namespace Drupal\module_name\Plugin\ActionType;

use Drupal\Core\Plugin\PluginBase;

/**
 * @ActionType(
 *   id = "example_action",
 *   label = @Translation("Example Action"),
 *   description = @Translation("Description of action"),
 * )
 */
class ExampleAction extends PluginBase {

  public function execute(array $context): array {
    // Implementation
    return ['success' => TRUE];
  }

}

5. API Endpoints

Provide REST/GraphQL endpoints:

# module_name.routing.yml
module_name.api.endpoint:
  path: '/api/v1/module-name/{id}'
  defaults:
    _controller: '\Drupal\module_name\Controller\ApiController::getData'
    _format: 'json'
  requirements:
    _permission: 'access module name api'
    _method: 'GET'

6. Configuration Schema

Define configuration schema:

# config/schema/module_name.schema.yml
module_name.settings:
  type: config_object
  label: 'Module Name settings'
  mapping:
    api_key:
      type: string
      label: 'API Key'
    timeout:
      type: integer
      label: 'Timeout (seconds)'

Testing

PHPUnit Setup

# Run all tests
vendor/bin/phpunit modules/custom/module_name/tests

# Run specific test suite
vendor/bin/phpunit --testsuite Unit modules/custom/module_name

Unit Test Example

<?php

namespace Drupal\Tests\module_name\Unit;

use Drupal\Tests\UnitTestCase;
use Drupal\module_name\Service\ExampleService;

/**
 * @coversDefaultClass \Drupal\module_name\Service\ExampleService
 * @group module_name
 */
class ExampleServiceTest extends UnitTestCase {

  /**
   * @covers ::processData
   */
  public function testProcessData() {
    $service = new ExampleService();
    $result = $service->processData(['input' => 'test']);

    $this->assertEquals('expected', $result['output']);
  }

}

Kernel Test Example

<?php

namespace Drupal\Tests\module_name\Kernel;

use Drupal\KernelTests\KernelTestBase;

/**
 * Tests the Example entity.
 *
 * @group module_name
 */
class ExampleEntityTest extends KernelTestBase {

  protected static $modules = ['module_name', 'user', 'system'];

  protected function setUp(): void {
    parent::setUp();
    $this->installEntitySchema('example_entity');
  }

  public function testEntityCreation() {
    $entity = ExampleEntity::create(['name' => 'Test']);
    $entity->save();

    $this->assertNotNull($entity->id());
    $this->assertEquals('Test', $entity->label());
  }

}

Deployment

1. Pre-Deployment Checks

# Run tests
buildkit golden test

# Validate code
buildkit drupal phpcs modules/custom/module_name --fix

# Check design taste
buildkit drupal taste modules/custom/module_name

# Security audit
buildkit golden audit

2. Sync and Deploy

# Sync to deployment location
buildkit drupal sync --modules

# Export configuration
buildkit drupal config:export

# Deploy to environment
buildkit golden deploy --env dev

3. Post-Deployment

# Run database updates
buildkit drupal database:update

# Import configuration
buildkit drupal config:import

# Clear caches
buildkit drupal cache:clear

# Verify module status
drush pm:list --type=module --status=enabled | grep module_name

Employment Protection

All modules include .claude/CLAUDE.md with employment protection:

# CLAUDE.md - module_name

## 🚨 EMPLOYMENT PROTECTION ACTIVE
- Claude Code BLOCKED from development branch
- AI attribution BLOCKED in commits
- Feature branch workflow ENFORCED

## 💰 TOKEN OPTIMIZATION MANDATORY
Before writing ANY code > 500 tokens:
- Check: buildkit agents list
- Use: buildkit agents spawn --type worker

Protected by Agent BuildKit v0.1.9

Common Patterns

AI Integration

// Use AI service
$ai = \Drupal::service('ai.provider.manager');
$provider = $ai->createInstance('openai');
$result = $provider->chat($messages);

ECA Integration

# Workflow automation
langcode: en
status: true
dependencies:
  module:
    - module_name
id: example_workflow
label: 'Example Workflow'
modeller: bpmn
events:
  - id: event_1
    plugin: 'content:entity:save'
conditions: []
actions:
  - id: action_1
    plugin: 'module_name:custom_action'

Queue Processing

// Queue worker
$queue = \Drupal::queue('module_name_tasks');
$queue->createItem(['data' => $data]);

// Process in QueueWorker plugin

Resources

See Also