← Back to Activities Workflows
5.6.1 Activities Architecture
ActivitiesPlugin implements KMPPluginInterface and KMPApiPluginInterface. It owns /activities web routes and registers the member-authorizations API v1 route. app/config/plugins.php configures migration order 1; the plugin class fallback is 0.
Plugin initialization
bootstrap() registers:
ActivitiesNavigationProviderthroughNavigationRegistry;ActivitiesViewCellProviderthroughViewCellRegistry;ActivitiesApprovalContextRendererfor canonical workflow approvals; and- plugin-local settings/configuration version updates.
routes() installs compatibility redirects to unified /approvals, the /activities web scope, and fallback plugin routes. registerApiRoutes() adds the member-authorizations API v1 route.
Service registration
services() registers:
AuthorizationManagerInterface→DefaultAuthorizationManager;ActivitiesWorkflowActions;ActivitiesWorkflowConditions; andActivitiesApprovalContextRenderer.
Workflow metadata is supplied by ActivitiesWorkflowProvider, ActivitiesWorkflowActions, and ActivitiesWorkflowConditions. Current first-party providers are invoked by core WorkflowPluginLoader; keep provider registration and definition seeds aligned.
Code ownership
app/plugins/Activities/
├── config/Migrations/ # tenant schema
├── src/Controller/ # web and API request coordination
├── src/Model/{Entity,Table}/ # activities/groups/authorizations
├── src/Policy/ # entity, table, and reports policies
├── src/Services/ # managers, workflows, UI providers
├── src/KMP/GridColumns/ # Dataverse definitions
├── src/View/Cell/ # member/permission integrations
├── templates/ # plugin views
└── tests/TestCase/ # plugin tests
Boundary rules
- Lifecycle mutations live in
AuthorizationManagerInterfaceimplementations or workflow actions. - Durable orchestration lives in JSON workflow definitions.
- Authorization and query scope live in policies.
- Navigation/member detail additions use providers and cells.
- Core approval records and UI are reused; do not restore a plugin approval table.
- The API returns only policy-scoped tenant data.
Authorization identity and failures
Activation and denial resolve the workflow’s persisted entity_id first, then
context.trigger.authorizationId, then the configured action parameter for older
or custom definitions. Persisted workflow references must have the
Activities.Authorizations entity type. Conflicting entity and trigger IDs fail
before changing an authorization. Missing or invalid IDs never become ID zero.
Request creation returns the ID of the record it actually inserted. Creation, activation, and denial failures stop workflow execution before subsequent notifications or completion. A workflow approval decision and authorization activation remain distinct steps; completion must not hide a failed activation.
Legacy workflows that started at the approval gate may lack
nodes.validate-request.result.authorizationId. The 1.5.10 resolver accepts their
canonical references without requiring that synthetic node result. A separately
reviewed SQL repair can populate that compatibility field for installations still
running 1.5.9 and reconcile previously failed activations. See
the operator repair runbook.
Multi-tenant behavior
Migrations, settings, records, cached permission lookups, workflow instances, and mail are tenant-local. A background expiration/notification job must enter a tenant context before resolving the Activities tables. There is no tenant_id column inside plugin tables.
Verification
Run vendor/bin/phpunit plugins/Activities/tests/TestCase, plus targeted workflow and API tests. Changed plugin PHP should pass PHPCS. UI/controller changes should cover keyboard/focus/status behavior and use npm run test:js; run npm run dev if imports change.