Apps (plugin system)

The Apps module provides a plugin/integration ecosystem for your SaaS. Apps are integrations or capabilities that users and organizations can enable — payment gateways, messaging platforms, storage services, email providers, and any custom capability your domain requires.

Concepts

Concept Description
App A registered integration (e.g. Stripe, Telegram, Dropbox).
Scope Where an app can be installed: user, organization, or resource.
Installation An app enabled for a specific user, org, or resource with config.
Capability An interface an app can implement (e.g. payment, storage).
Catalog override YAML configuration to adjust app metadata.

Defining an app

Create a service implementing AppDefinitionInterface (extend AbstractApp for convenience):

use Derafu\PlatformBundle\Apps\Abstract\AbstractApp;
use Derafu\PlatformBundle\Apps\Enum\AppScope;

final class StripeApp extends AbstractApp
{
    protected string $code = 'stripe';
    protected string $name = 'Stripe';
    protected string $description = 'Accept payments via Stripe.';
    protected string $icon = 'stripe';
    protected string $category = 'payments';

    protected array $scopes = [AppScope::Organization];

    // Keys to encrypt in the installation config
    protected array $sensitiveConfigKeys = ['secret_key', 'webhook_secret'];

    // Optional: a form key for the configuration form
    protected ?string $configFormKey = 'stripe_config';
}

The service is auto-discovered via the AppDefinitionInterface AutoconfigureTag. No manual service registration needed.

Scopes

An app can support one or more scopes:

Scope Entity Use case
AppScope::User BaseUserAppInstallation Personal integration (e.g. Telegram notifications)
AppScope::Organization BaseOrganizationAppInstallation Shared integration for the whole org
AppScope::Resource BaseResourceAppInstallation Integration for a specific resource

A multi-scope app (e.g. a storage app) can be installed at the user, organization, and/or resource level simultaneously.

Installing and managing apps

use Derafu\PlatformBundle\Apps\Contract\Service\AppInstallationManagerInterface;

// Install for a user
$installation = $appInstallationManager->installForUser(
    appCode: 'stripe',
    user: $currentUser,
    config: ['public_key' => 'pk_live_...', 'secret_key' => 'sk_live_...']
);

// Install for an organization
$installation = $appInstallationManager->installForOrganization(
    appCode: 'stripe',
    organization: $org,
    config: ['public_key' => 'pk_live_...', 'secret_key' => 'sk_live_...']
);

// Check if installed
$installed = $appInstallationManager->isInstalledForOrganization('stripe', $org);

// Get installation
$installation = $appInstallationManager->getForOrganization('stripe', $org);

// Uninstall
$appInstallationManager->uninstallForOrganization('stripe', $org);

Sensitive config keys declared in $sensitiveConfigKeys are transparently encrypted at rest by AppConfigEncryptor. Retrieval also decrypts transparently.

The app registry

The AppRegistryInterface collects all registered apps. It applies catalog overrides from configuration (scopes, flags, tags, supported resources):

use Derafu\PlatformBundle\Apps\Contract\Service\AppRegistryInterface;

$app = $appRegistry->get('stripe');       // AppDefinitionInterface
$apps = $appRegistry->all();              // all registered apps
$apps = $appRegistry->byScope(AppScope::User); // filtered by scope
$apps = $appRegistry->byCategory('payments'); // filtered by category

Catalog configuration

The YAML catalog section adjusts metadata of registered apps without modifying the app class. Useful for overriding defaults per-deployment:

derafu_platform:
    apps:
        catalog:
            stripe:
                scopes: [user, organization]
                flags: [featured]
            telegram:
                scopes: [user]
                flags: [featured]
            dropbox:
                scopes: [user, organization, resource]
                resources:
                    - App\Entity\Resource\Project

flags controls UI presentation (e.g. featured items appear prominently). resources lists which FQCN resource classes the app supports when installed at the resource scope.

Capabilities

Apps can implement capability interfaces to advertise features. The CapabilityRegistryInterface answers “which installed apps for this organization support X?”:

use Derafu\PlatformBundle\Apps\Contract\Capability\PaymentGatewayInterface;

// Define a capability interface (app side)
interface PaymentGatewayInterface
{
    public function processPayment(int $amountCents, string $currency): string;
}

// An app implements it
final class StripeApp extends AbstractApp implements PaymentGatewayInterface
{
    public function processPayment(int $amountCents, string $currency): string
    {
        // Stripe API call...
    }
}

// Query at runtime
use Derafu\PlatformBundle\Apps\Contract\Service\CapabilityRegistryInterface;

$gateways = $capabilityRegistry->forOrganization(PaymentGatewayInterface::class, $org);
// Returns all installed apps for $org that implement PaymentGatewayInterface

Resource apps

For apps that target a specific resource (e.g. “email provider for this Project”), create a resource installation entity:

use Derafu\PlatformBundle\Apps\Entity\BaseResourceAppInstallation;

#[ORM\Entity]
#[ORM\Table(name: 'project_app_installations')]
class ProjectAppInstallation extends BaseResourceAppInstallation
{
    #[ORM\ManyToOne(targetEntity: Project::class)]
    #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
    private Project $project;

    public function getProject(): Project { return $this->project; }
    public function setProject(Project $project): static { $this->project = $project; return $this; }
}

Settings UI

The Apps module registers a settings section automatically. Users and org admins can browse, install, configure, and uninstall apps from a dedicated settings page — no custom controllers needed.

On this page

Last updated on 15/05/2026 by Anonymous