Backend Plugins
Extend Rasepi's .NET 8 API with custom services, action guards, event handlers, translation providers, and import/export processors.
Overview
Backend plugins run inside the Rasepi API process as loadable .NET assemblies. They have full access to the plugin SDK and can hook into the entry lifecycle, guard actions before they happen, provide translation engines, and more.
dotnet new classlib -n MyPlugin
dotnet add reference path/to/Rasepi.Plugins.SDK.csproj
Plugin SDK
The SDK provides interfaces and base types for building plugins.
IRasepiPlugin
The root interface every plugin must implement.
public class MyPlugin : IRasepiPlugin
{
public PluginManifest Manifest => new()
{
Id = "my-plugin",
Name = "My Plugin",
Version = "1.0.0",
Author = "Your Name"
};
public void ConfigureServices(IServiceCollection services)
{
// Register your services
}
}Plugin Interfaces
IRasepiPluginRoot plugin interface. Every plugin implements this.
IPluginModuleRegister services and middleware in the DI container.
IActionGuardIntercept and allow/deny operations before they happen.
IPluginEventHandlerReact to events after operations complete.
ITranslationProviderPluginProvide custom translation engines.
IImportPluginImport entries from external formats.
IExportPluginExport entries to external formats.
Action Guards
Action guards intercept operations before they happen. Return ActionGuardResult.Allow() or ActionGuardResult.Deny("reason").
public class ComplianceGuard : IActionGuard
{
public Task<ActionGuardResult> EvaluateAsync(
ActionGuardContext context)
{
if (context.ActionName == ActionNames.DeleteEntry
&& context.Entity is Entry entry
&& entry.IsPublished)
{
return Task.FromResult(
ActionGuardResult.Deny(
"Cannot delete published entries"));
}
return Task.FromResult(ActionGuardResult.Allow());
}
}Available Actions
CreateHubUpdateHubDeleteHubCreateEntryUpdateEntryDeleteEntryPublishEntryCreateTranslationUpdateTranslationRenewEntryUpdateExpiryEvent Handlers
Event handlers react after operations complete. Use them for notifications, audit logging, cache warming, and integrations.
public class SlackNotifier : IPluginEventHandler
{
public async Task HandleEventAsync(
string eventName,
IPluginContext context,
object? payload)
{
if (eventName == "entry.published")
{
await _slack.PostAsync(
$"New entry published: {payload}");
}
}
}Translation Providers
Implement ITranslationProviderPlugin to add custom translation engines (DeepL, Google Translate, AI-based, etc.).
public class DeepLProvider : ITranslationProviderPlugin
{
public string ProviderId => "deepl";
public string DisplayName => "DeepL";
public Task<IReadOnlyList<string>>
GetSupportedLanguagesAsync()
=> Task.FromResult<IReadOnlyList<string>>(
new[] { "en", "de", "fr", "es", "ja" });
public async Task<TranslationBatchResult>
TranslateAsync(
IReadOnlyList<string> blocks,
string sourceLanguage,
string targetLanguage,
TranslationOptions? options = null)
{
// Call DeepL API for each block
}
}Import / Export
Implement IImportPlugin and IExportPlugin for custom format support (Word, Notion, Markdown, etc.).
public class MarkdownExporter : IExportPlugin
{
public string FormatId => "markdown";
public string DisplayName => "Markdown";
public string FileExtension => ".md";
public Task<byte[]> ExportAsync(
Entry entry,
IPluginContext context)
{
// Convert TipTap JSON blocks to Markdown
}
}Deployment
Build your plugin as a .NET class library and place the DLL in the Plugins/ directory. Rasepi loads plugins automatically on startup.
dotnet build -c Release
cp bin/Release/net8.0/MyPlugin.dll ../backend/Rasepi.Api/Plugins/
Configure in appsettings.json:
{
"Plugins": {
"AutoLoadDirectory": "Plugins",
"Enabled": ["my-plugin"]
}
}