Backend Guide
This guide covers backend development for IDAH plugins using Ruby.
Overview
IDAH plugins can have backend services that process media files, export data, or integrate with external systems. Backend services are written in Ruby and follow a modular structure.
Technology Stack:
- Language: Ruby 3.4+
- Testing Framework: RSpec
- Schema Validation: Verse Schema
- Dependencies: Bundler
File Structure
<plugin_name>/ └─ backends/ ├─ README.md # Backend quick start guide ├─ spec_helper.rb # Shared RSpec configuration ├─ .rspec # RSpec configuration ├─ media/ # Media service (if enabled) │ └─ <plugin_name_underscore>/ │ └─ .. └─ sync/ # Sync service (if enabled) └─ <plugin_name_underscore>/ └─ ..
Note: <plugin_name_underscore> is your plugin name in snake_case (e.g., my_awesome_plugin for plugin my-awesome-plugin).
Available Backend Services
IDAH plugins can include one, all, or none of these backend services. You can create frontend-only plugins, or add backend services as needed.
Media Service
Handles media file processing (images, videos, audio, etc.). Process original media files and generate thumbnails, previews, or transformations.
Sync Service
Handles data export and synchronization with external systems. Export datasets, entries, annotations, and media to various formats or external APIs.
Testing
Using RSpec
All backend code should have comprehensive tests:
require "spec_helper"
require_relative "processor"
RSpec.describe YourPlugin::Processor do
describe "#process" do
it "processes media correctly" do
options = YourPlugin::Options.new(quality: 90)
processor = described_class.new(options)
context = double("context",
input_file: "input.jpg",
output_file: "output.webp"
)
expect { processor.process(context) }.not_to raise_error
end
end
end Running Tests
bundle exec rspec bundle exec rspec media/processor_spec.rb bundle exec rspec --format documentation Best Practices
1. Module Naming
-
Use nested classes (
YourPlugin::Media,YourPlugin::Sync) to avoid Zeitwerk conflicts - Follow Ruby naming conventions (PascalCase for classes, snake_case for files)
2. Error Handling
def process(context)
raise ArgumentError, "Input file required" unless context.input_file
begin
# Processing logic
rescue StandardError => e
Verse.logger.error("Processing failed: #{e.message}")
raise
end
end 3. Logging
def process(context)
Verse.logger.info("Starting processing for #{context.input_file}")
# ... processing
Verse.logger.info("Processing complete")
end 4. Performance
- Process files in batches when possible
- Use background jobs for long-running tasks
- Clean up temporary files
5. Security
- Validate all input options
- Sanitize file paths
- Use safe file operations
- Don't expose sensitive data in logs
Debugging
Enable Debug Logging
Verse.logger.level = Logger::DEBUG Use Pry for Debugging
require "pry"
def process(context)
binding.pry # Debugger breakpoint
# ... rest of code
end Common Patterns
Media Processing Pipeline
def process(context)
validate_input(context.input_file)
temp_file = create_temp_file
begin
transform(context.input_file, temp_file)
optimize(temp_file, context.output_file)
ensure
cleanup(temp_file)
end
end Batch Export
def export(context)
entries = fetch_entries(context.dataset)
entries.each_slice(100) do |batch|
export_batch(batch)
end
end Next Steps
Learn about specific backend implementations:
- Import & Process Media - Process and transform media files
- Export Datasets - Create custom data exporters
Resources
⚙️ Backend services ready! Explore media processing and data export guides.