Phoenix uses a modular plugin system that allows features to be developed, tested, and deployed independently while sharing a common platform infrastructure.
A PluginBase abstract class provides sensible defaults for optional members, so most plugins only need to override the methods they actually use.
Defines the C# project, NuGet dependencies, and references to Phoenix.Core. Each plugin is a standalone .NET class library.
The backend implementation: IPlugin interface, database entities, pipelines, hooks, API endpoints, and service registrations.
Declares frontend routes, components, extension points, and assets that the Remix UI should load for this plugin.
Each plugin specifies its own database entities, API endpoints, pipelines, and frontend code. This isolation means plugins can be developed, tested, and deployed independently without modifying core platform code.
Called during application build. Each plugin registers its DI services, repositories, pipeline handlers, and configuration options into the shared service collection.
Called when Entity Framework builds the database model. Each plugin configures its own entity mappings, indexes, relationships, and schema isolation.
Called after the application is built. Plugins can map endpoints, register middleware, seed data, or perform any startup initialization.
Connector plugins use WorkflowVendor and WorkflowProduct properties to categorize their pipelines within the workflow engine. This taxonomy enables the platform to route workflows to the correct connector implementation.
Creating a branch simply adds a new pointer to the current commit. You can then switch to it and start making independent changes without affecting the original branch.
When commits are made on different branches, the branches diverge. Each branch has its own line of history, and they can later be merged back together.
A Git submodule is a reference to another Git repository embedded within your project. Rather than copying code, the parent repository stores a pointer to a specific commit in the submodule's repository. This means the submodule's code lives in its own repository with its own history, branches, and pull requests—but it appears as a folder in your project.
When a submodule has changes or is pointing to a different commit than what the parent expects, git status will show the submodule as modified. The status shows the submodule folder with a special notation indicating the commit reference has changed.
git submodule update --init
git submodule foreach git pull origin develop
Detached HEAD State
When you enter a submodule directory, you are typically in a detached HEAD state. This means HEAD points directly to a commit rather than a branch. Before making changes inside a submodule, always check out a branch first (e.g., git checkout develop) to avoid losing commits.
Click the Clone button
Copy the HTTPS URL
Run the submodule add command from the project root, targeting the /Plugins folder.
git submodule add <CLONE_URL> Plugins/Phoenix.YourPlugin
Verify the .gitmodules file has the correct path and URL for the new submodule entry. Ensure the path matches your intended directory structure.
In Visual Studio, right-click the solution and select "Add Existing Project" to include the plugin's .csproj file.
Add a project reference from the client/host project to the plugin project so it compiles and links correctly.
Add the plugin to the registration chain in Startup.cs.
builder.AddPhoenixPlugin<YourPlugin>();
Add the plugin to the plugins array in the project's package.json so the Remix build system includes the plugin's frontend code.
{
"plugins": [
"phoenix-site",
"phoenix-payments",
"phoenix-your-plugin"
]
}
When a plugin has been updated in its own repository, you need to update the submodule reference in the parent project. Navigate into the submodule directory, pull the latest changes, then go back to the parent and commit the updated reference.
When your changes span both the plugin and the host project, create separate pull requests for each repository. In the host project's PR description, include a link to the plugin's PR so reviewers understand the full scope of changes. Merge the plugin PR first, then update the submodule reference and merge the host PR.
Each plugin lives in its own Git repository and is added to the main project as a Git submodule. This provides independent version control, branching, and release cycles for each plugin. The main repository tracks specific commits of each submodule, ensuring reproducible builds. Plugin updates are pulled by advancing the submodule pointer. See Submodules.
Adding a plugin involves: creating a new .NET class library project implementing IPlugin, registering the plugin in the Client's Startup.cs, and adding the project as a Git submodule. The IPlugin interface requires implementing RegisterServices (for dependency injection), RegisterPipelines (for pipeline and hook registration), and RunMigrations (for database schema setup). Once registered, the plugin's pipelines, entities, and frontend extensions are automatically available. See Adding a Submodule.