bluefly / dita_ccms
DITA authoring and publishing framework for Drupal 10/11 with API-first approach and test-driven development.
Requires
- php: >=8.1
- drupal/core: ^10.3 || ^11.0
- drupal/eck: ^2.0
- drupal/feeds: ^3.0
- drupal/field_group: ^3.4 || ^4.0
- drupal/views_data_export: ^1.4
Requires (Dev)
- drupal/core-dev: ^10.3 || ^11.0
Suggests
- drupal/advancedqueue: Advanced queue processing for DITA publishing jobs (^1.0)
- drupal/feeds: Import DITA content from external sources (^3.0)
- drupal/graphql: GraphQL API support for DITA content (^4.0)
- drupal/metatag: Meta tag management for DITA content (^2.0)
- drupal/pathauto: Automatic URL alias generation for DITA topics (^1.0)
- drupal/redis: Redis caching for improved performance (^1.0)
Conflicts
- drupal/dita_ccms: *
This package is auto-updated.
Last update: 2025-08-25 12:21:46 UTC
README
DITA-Compliant Enterprise Content Management
Built for technical documentation teams and enterprise knowledge management
๐๏ธ Architecture Overview
The DITA CCMS module provides comprehensive DITA (Darwin Information Typing Architecture) content management capabilities for Drupal, enabling technical documentation teams to author, manage, and publish structured content using industry-standard DITA XML format.
System Architecture
graph TB
subgraph "Frontend Layer"
UI[Authoring Interface]
API[REST/GraphQL API]
Admin[Admin Dashboard]
end
subgraph "Content Layer"
DITA[DITA Topics & Maps]
ECK[ECK Entities]
Fields[Custom Fields]
Workflow[Content Workflow]
end
subgraph "Processing Layer"
Import[DITA Import]
Export[DITA Export]
Transform[DITA-OT Integration]
Queue[Batch Processing]
end
subgraph "Storage Layer"
DB[(Database)]
Files[File Storage]
Cache[Cache Layer]
Search[Search Index]
end
UI --> DITA
API --> DITA
Admin --> Workflow
DITA --> Import
DITA --> Export
Import --> DB
Export --> Files
Workflow --> Queue
Queue --> Cache
DITA Content Types
graph LR
subgraph "DITA Topic Types"
Topic[Topic]
Concept[Concept]
Task[Task]
Reference[Reference]
Troubleshooting[Troubleshooting]
end
subgraph "Content Structure"
Map[DITA Map]
Bookmap[Bookmap]
SubjectScheme[Subject Scheme]
end
subgraph "Relationships"
RelTable[Relationship Table]
CrossRef[Cross References]
Links[External Links]
end
Map --> Topic
Map --> Concept
Map --> Task
Topic --> RelTable
Concept --> CrossRef
Task --> Links
๐ Quick Start
Prerequisites
- Drupal 10.3 or 11
- PHP 8.1+
- Required modules:
- Entity Construction Kit (ECK) ^2.0
- Content Moderation
- Workflows
- Feeds ^3.0
- REST
- Serialization
- Views
- Views Data Export
- Field Group
Installation
# Using Composer (Recommended)
composer require drupal/dita_ccms
drush en dita_ccms -y
# Manual Installation
cd web/modules/custom/
git clone [repository-url] dita_ccms
drush en dita_ccms -y
Initial Configuration
Configure DITA Topic Types
# Navigate to admin interface drush uli # Go to: /admin/structure/dita-topic-types
Set Up Workflows
# Configure editorial workflow drush config:import:single --file=config/install/workflows.workflow.dita_editorial.yml
Configure Import/Export
# Set up DITA-OT integration drush config:set dita_ccms.settings dita_ot_path /opt/dita-ot
๐ DITA Content Management
Topic Creation Workflow
graph TD
A[Create Topic] --> B[Select Topic Type]
B --> C[Fill Required Fields]
C --> D[Add Content]
D --> E[Set Metadata]
E --> F[Submit for Review]
F --> G{Review Passed?}
G -->|Yes| H[Publish]
G -->|No| I[Return for Revision]
I --> D
H --> J[Archive]
Content Structure
# Example DITA Topic Structure
topic:
title: "LLM Platform Integration Guide"
type: "concept"
metadata:
audience: "developers"
keywords: ["llm", "integration", "api"]
status: "published"
version: "1.0"
content:
- section: "Overview"
content: "Integration guide for LLM Platform..."
- section: "Prerequisites"
content: "Required components and setup..."
- section: "Implementation"
content: "Step-by-step integration process..."
๐ API Integration
REST Endpoints
# OpenAPI Specification
openapi: 3.1.0
info:
title: DITA CCMS API
version: 1.0.0
paths:
/api/dita/topics:
get:
summary: List DITA topics
parameters:
- name: type
in: query
schema:
type: string
enum: [topic, concept, task, reference]
post:
summary: Create DITA topic
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/DitaTopic'
GraphQL Schema
# DITA Content Queries
type DitaTopic {
id: ID!
title: String!
type: TopicType!
content: String
metadata: TopicMetadata
workflow: WorkflowState
created: DateTime!
updated: DateTime!
}
type TopicMetadata {
audience: String
keywords: [String]
status: String
version: String
}
enum TopicType {
TOPIC
CONCEPT
TASK
REFERENCE
TROUBLESHOOTING
}
๐งช Testing Strategy
Test-Driven Development
// tests/dita-content.spec.ts
import { test, expect } from '@playwright/test';
test.describe('DITA Content Management', () => {
test('should create DITA topic', async ({ page }) => {
await page.goto('/admin/content/dita-topics/add');
// Fill required fields
await page.fill('[name="title"]', 'Test DITA Topic');
await page.selectOption('[name="topic_type"]', 'concept');
await page.fill('[name="content"]', 'Test content for DITA topic');
// Submit form
await page.click('[type="submit"]');
// Verify creation
await expect(page.locator('.messages--status')).toContainText('Topic created');
});
test('should validate DITA XML export', async ({ page }) => {
await page.goto('/admin/content/dita-topics');
// Select topic for export
await page.check('[name="topics[1]"]');
await page.selectOption('[name="export_format"]', 'dita_xml');
// Export
await page.click('[name="export"]');
// Verify XML output
const content = await page.locator('pre').textContent();
expect(content).toContain('<?xml version="1.0" encoding="UTF-8"?>');
expect(content).toContain('<topic id="test-topic">');
});
});
Quality Gates
# Run comprehensive tests
npx tddai test --module dita_ccms
# Validate OpenAPI specifications
npx tddai validate:openapi openapi/dita_ccms.openapi.yml
# Check coding standards
npx tddai standards-enforce --module dita_ccms
# Performance testing
npx tddai performance:test --module dita_ccms
๐ Workflow Management
Editorial Workflow
stateDiagram-v2
[*] --> Draft
Draft --> InReview
InReview --> NeedsRevision
InReview --> Approved
NeedsRevision --> Draft
Approved --> Published
Published --> Archived
Archived --> Draft
Workflow Configuration
# config/install/workflows.workflow.dita_editorial.yml
langcode: en
status: true
dependencies:
module:
- content_moderation
id: dita_editorial
label: 'DITA Editorial Workflow'
type: content_moderation
type_settings:
states:
draft:
label: 'Draft'
weight: 0
published: false
default_revision: false
in_review:
label: 'In Review'
weight: 1
published: false
default_revision: false
approved:
label: 'Approved'
weight: 2
published: false
default_revision: false
published:
label: 'Published'
weight: 3
published: true
default_revision: true
archived:
label: 'Archived'
weight: 4
published: false
default_revision: false
transitions:
to_in_review:
label: 'Submit for Review'
from: [draft]
to: in_review
weight: 0
approve:
label: 'Approve'
from: [in_review]
to: approved
weight: 0
publish:
label: 'Publish'
from: [approved]
to: published
weight: 0
archive:
label: 'Archive'
from: [published]
to: archived
weight: 0
return_for_revision:
label: 'Return for Revision'
from: [in_review]
to: draft
weight: 0
๐ Performance & Scalability
Caching Strategy
graph LR
subgraph "Cache Layers"
L1[L1: Memory Cache]
L2[L2: Redis Cache]
L3[L3: Database Cache]
end
subgraph "Cache Types"
Content[Content Cache]
Metadata[Metadata Cache]
Search[Search Cache]
Export[Export Cache]
end
L1 --> Content
L2 --> Metadata
L3 --> Search
L2 --> Export
Batch Processing
<?php
namespace Drupal\dita_ccms\Plugin\QueueWorker;
use Drupal\Core\Queue\QueueWorkerBase;
use Drupal\Core\Queue\RequeueException;
/**
* Processes DITA export queue items.
*
* @QueueWorker(
* id = "dita_export",
* title = @Translation("DITA Export Processor"),
* cron = {"time" = 60}
* )
*/
class DitaExportQueueWorker extends QueueWorkerBase {
/**
* {@inheritdoc}
*/
public function processItem($data) {
try {
$this->exportDitaContent($data);
}
catch (\Exception $e) {
// Requeue on failure
throw new RequeueException($e->getMessage());
}
}
}
๐ Security & Compliance
Access Control
# config/install/dita_ccms.permissions.yml
dita_ccms:
# Content creation
create dita_topic: true
create dita_map: true
# Content editing
edit own dita_topic: true
edit any dita_topic: false
# Workflow management
use dita_editorial workflow: true
moderate dita_editorial workflow: false
# Export permissions
export dita_content: true
export dita_xml: false # Restricted to admins
Audit Logging
<?php
namespace Drupal\dita_ccms\EventSubscriber;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Logs DITA content operations for compliance.
*/
class DitaAuditSubscriber implements EventSubscriberInterface {
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
return [
'dita_ccms.topic.created' => 'logTopicCreation',
'dita_ccms.topic.updated' => 'logTopicUpdate',
'dita_ccms.topic.deleted' => 'logTopicDeletion',
'dita_ccms.content.exported' => 'logContentExport',
];
}
/**
* Logs topic creation events.
*/
public function logTopicCreation($event) {
$this->logger->info('DITA topic created: @title by @user', [
'@title' => $event->getTopic()->getTitle(),
'@user' => $event->getUser()->getAccountName(),
]);
}
}
๐ Integration Examples
LLM Platform Integration
<?php
namespace Drupal\dita_ccms\Service;
use Drupal\llm\Service\LlmServiceInterface;
/**
* Integrates DITA CCMS with LLM Platform.
*/
class LlmIntegrationService {
/**
* Generates DITA content using AI.
*/
public function generateDitaContent($prompt, $topicType) {
$llmService = \Drupal::service('llm.service');
$response = $llmService->generate([
'prompt' => "Generate DITA $topicType content: $prompt",
'model' => 'gpt-4',
'format' => 'dita_xml'
]);
return $this->parseDitaResponse($response);
}
}
MCP Server Integration
<?php
namespace Drupal\dita_ccms\Mcp;
use Drupal\mcp_registry\McpServerInterface;
/**
* MCP Server for DITA CCMS operations.
*/
class DitaMcpServer implements McpServerInterface {
/**
* Lists available DITA topics.
*/
public function listTopics($params) {
$topics = $this->entityTypeManager
->getStorage('dita_topic')
->loadMultiple();
return array_map(function($topic) {
return [
'id' => $topic->id(),
'title' => $topic->getTitle(),
'type' => $topic->getTopicType(),
'status' => $topic->getWorkflowStatus(),
];
}, $topics);
}
}
๐ Monitoring & Analytics
Performance Metrics
# config/install/dita_ccms.monitoring.yml
monitoring:
metrics:
content_creation_rate:
type: counter
description: "DITA topics created per hour"
threshold: 100
export_processing_time:
type: histogram
description: "Time to process export requests"
buckets: [0.1, 0.5, 1.0, 2.0, 5.0]
workflow_transition_rate:
type: counter
description: "Workflow state transitions per hour"
threshold: 50
Health Checks
<?php
namespace Drupal\dita_ccms\Health;
use Drupal\Core\Health\HealthCheckInterface;
/**
* Health check for DITA CCMS module.
*/
class DitaHealthCheck implements HealthCheckInterface {
/**
* {@inheritdoc}
*/
public function run() {
$issues = [];
// Check DITA-OT availability
if (!$this->isDitaOtAvailable()) {
$issues[] = 'DITA Open Toolkit not available';
}
// Check workflow configuration
if (!$this->isWorkflowConfigured()) {
$issues[] = 'Editorial workflow not configured';
}
// Check permissions
if (!$this->arePermissionsCorrect()) {
$issues[] = 'Permission configuration issues detected';
}
return [
'status' => empty($issues) ? 'healthy' : 'unhealthy',
'issues' => $issues,
];
}
}
๐ง Development & Customization
Custom Topic Types
<?php
namespace Drupal\custom_module\Plugin\DitaTopicType;
use Drupal\dita_ccms\Plugin\DitaTopicType\DitaTopicTypeBase;
/**
* Custom DITA topic type for API documentation.
*
* @DitaTopicType(
* id = "api_doc",
* label = @Translation("API Documentation"),
* description = @Translation("Documentation for API endpoints and usage")
* )
*/
class ApiDocTopicType extends DitaTopicTypeBase {
/**
* {@inheritdoc}
*/
public function getFields() {
return [
'endpoint_url' => [
'type' => 'string',
'label' => 'API Endpoint URL',
'required' => TRUE,
],
'http_method' => [
'type' => 'list',
'label' => 'HTTP Method',
'options' => ['GET', 'POST', 'PUT', 'DELETE'],
'required' => TRUE,
],
'request_schema' => [
'type' => 'text_long',
'label' => 'Request Schema (JSON)',
],
'response_schema' => [
'type' => 'text_long',
'label' => 'Response Schema (JSON)',
],
];
}
}
Custom Export Formats
<?php
namespace Drupal\custom_module\Plugin\DitaExportFormat;
use Drupal\dita_ccms\Plugin\DitaExportFormat\DitaExportFormatBase;
/**
* Exports DITA content to Confluence format.
*
* @DitaExportFormat(
* id = "confluence",
* label = @Translation("Confluence"),
* description = @Translation("Export to Confluence wiki format")
* )
*/
class ConfluenceExportFormat extends DitaExportFormatBase {
/**
* {@inheritdoc}
*/
public function export($content, $options = []) {
// Convert DITA to Confluence markup
$confluenceMarkup = $this->convertDitaToConfluence($content);
return [
'content' => $confluenceMarkup,
'mime_type' => 'text/plain',
'filename' => $options['filename'] ?? 'export.txt',
];
}
}
๐ Related Documentation
๐ค Contributing
- Follow DITA Authoring Guidelines
- Use Development Templates
- Include Mermaid Diagrams for complex workflows
- Validate OpenAPI specifications before committing
- Run comprehensive tests:
npx tddai test --module dita_ccms
๐ Support
- Documentation Issues: Create issues in this repository
- Technical Support: Use the TDD Workflow
- Architecture Questions: Review System Architecture
This module follows DITA 1.3 standards and integrates seamlessly with the LLM Platform ecosystem.