Module Registry gRPC Service Reference
Package platform.module_registry.v1 contains the ModuleRegistryService —
the gRPC interface for module lifecycle management.
The Module Registry is the control plane for all third-party modules that
extend the Platform-Kernel. It validates module manifests, manages the
MODULE_STATUS_* lifecycle FSM, and serves active module metadata to the
UI Shell (Module Federation 2.0 host) and the API Gateway (tenant
routing: modules:active:{tenantId} Valkey cache).
See the gRPC Overview for buf configuration, Go package conventions, deadlines, mTLS, and error mapping.
Proto file: proto/platform/module_registry/v1/module_registry_service.proto
Go package: kernel.internal/platform-kernel/gen/go/platform/module_registry/v1;module_registryv1
ModuleRegistryService — All RPCs
service ModuleRegistryService {
rpc RegisterModule(RegisterModuleRequest) returns (RegisterModuleResponse);
rpc GetModule(GetModuleRequest) returns (GetModuleResponse);
rpc ListModules(ListModulesRequest) returns (ListModulesResponse);
rpc ListActiveModules(ListActiveModulesRequest) returns (ListActiveModulesResponse);
rpc ActivateModule(ActivateModuleRequest) returns (ActivateModuleResponse);
rpc DeactivateModule(DeactivateModuleRequest) returns (DeactivateModuleResponse);
rpc DeleteModule(DeleteModuleRequest) returns (DeleteModuleResponse);
rpc ListModuleVersions(ListModuleVersionsRequest) returns (ListModuleVersionsResponse);
}
| RPC | Description |
|---|---|
RegisterModule | Validate and register a new module from its manifest |
GetModule | Retrieve a module by ID |
ListModules | Paginated list with status and category filters |
ListActiveModules | All ACTIVE modules for a tenant — used by UI Shell |
ActivateModule | Transition a module to ACTIVE status |
DeactivateModule | Transition a module to DISABLED status |
DeleteModule | Soft-delete a module |
ListModuleVersions | Full version history for a module |
Enum — ModuleStatus
enum ModuleStatus {
MODULE_STATUS_UNSPECIFIED = 0;
MODULE_STATUS_PENDING = 1;
MODULE_STATUS_INSTALLING = 2;
MODULE_STATUS_ACTIVE = 3;
MODULE_STATUS_DISABLED = 4;
MODULE_STATUS_FAILED = 5;
MODULE_STATUS_ERROR = 6;
MODULE_STATUS_INCOMPATIBLE = 7;
}
| Status | Description |
|---|---|
PENDING | Registered but not yet installed. Awaiting activation. |
INSTALLING | Installation in progress (manifest validation, DB migrations). |
ACTIVE | Fully operational. Accessible to tenant users. Gateway allows routing. |
DISABLED | Administratively deactivated. Not accessible to users. |
FAILED | Installation or migration failed. Requires manual intervention. |
ERROR | Runtime error detected by health check. |
INCOMPATIBLE | Kernel version incompatibility detected during registration. |
Module lifecycle FSM:
RegisterModule → PENDING
│
manifest valid
│
▼
INSTALLING
│
migrations succeed ──────────── migrations fail
│ │
▼ ▼
ACTIVE FAILED
│
ActivateModule / DeactivateModule
│
┌───────────┴──────────┐
▼ ▼
ACTIVE DISABLED
Shared Message — Module
message Module {
string id = 1;
string tenant_id = 2;
string name = 3;
string slug = 4; // URL-safe identifier
string version = 5; // Semantic version (e.g. "1.2.0")
string description = 6;
ModuleStatus status = 7;
google.protobuf.Struct manifest = 8; // Full module.manifest.json contents
string entry_url = 9; // Module Federation 2.0 remote entry URL
string exposed_component = 10; // MF2 exposed component name (e.g. "./App")
string route = 11; // Base route (e.g. "/crm")
string icon = 12; // Icon URL or icon key
string health_check_path = 13; // Path for health probe (e.g. "/health")
string category = 14; // e.g. "crm", "analytics", "integrations"
google.protobuf.Timestamp created_at = 15;
google.protobuf.Timestamp updated_at = 16;
}
| Field | Description |
|---|---|
slug | URL-safe identifier. Unique per tenant. E.g. crm-pro. |
version | Semantic version. Updated by RegisterModule on each version upload. |
manifest | Full module.manifest.json as a google.protobuf.Struct. Managed by Registry. |
entry_url | Module Federation 2.0 remote entry: https://cdn.example.com/crm/remoteEntry.js. |
exposed_component | MF2 component export path: "./App". Used by UI Shell for dynamic import. |
route | Base path mounted in the UI Shell router. Must be unique per tenant. |
health_check_path | Gateway polls this path for module health. Default: /health. |
Shared Message — ModuleVersion
Immutable version record. Each RegisterModule call with a new version creates
a ModuleVersion entry. Previous versions are never deleted (audit trail).
message ModuleVersion {
string id = 1;
string module_id = 2;
string version = 3; // Semantic version
google.protobuf.Struct manifest = 4; // Manifest snapshot at registration time
string bundle_hash = 5; // SHA-256 of the JS bundle (integrity check)
string entry_url = 6; // Remote entry URL for this version
string changelog = 7; // Human-readable changelog (Markdown)
google.protobuf.Timestamp created_at = 8;
}
RegisterModule
Validates and registers a new module (or a new version of an existing module).
The manifest is parsed and validated against the Module Registry schema.
On success, the module enters PENDING status.
Request — RegisterModuleRequest
message RegisterModuleRequest {
bytes manifest = 1; // Required. Raw JSON manifest (module.manifest.json).
}
The manifest field must be valid JSON conforming to the Module Manifest
schema (module.manifest.json). Key required fields:
| Manifest field | Type | Description |
|---|---|---|
name | string | Human-readable name |
slug | string | URL-safe identifier (unique per tenant) |
version | string | Semantic version |
entry_url | string | Module Federation 2.0 remote entry URL |
exposed_component | string | Exposed MF2 component (e.g. "./App") |
route | string | Base route (e.g. "/crm") |
kernel_version | string | Compatible kernel version range (semver range) |
Response — RegisterModuleResponse
message RegisterModuleResponse {
Module module = 1; // Module in PENDING status.
}
gRPC errors:
| gRPC status | Condition |
|---|---|
INVALID_ARGUMENT | Manifest fails JSON schema validation or missing required fields |
ALREADY_EXISTS | Module with the same slug and version already registered |
FAILED_PRECONDITION | kernel_version range incompatible with current kernel — status: INCOMPATIBLE |
RESOURCE_EXHAUSTED | Tenant's modules billing limit exceeded |
GetModule
Request — GetModuleRequest
message GetModuleRequest {
string id = 1; // Required. Module UUID.
}
Response — GetModuleResponse
message GetModuleResponse {
Module module = 1;
}
ListModules
Cursor-paginated list of modules for a tenant, with optional status and category filtering.
Request — ListModulesRequest
message ListModulesRequest {
string cursor = 1; // Opaque cursor from ListModulesResponse.next_cursor.
int32 limit = 2; // Page size. Default: 20. Max: 100.
ModuleStatus status_filter = 3; // 0 = all statuses.
string category_filter = 4; // Empty = all categories.
}
Response — ListModulesResponse
message ListModulesResponse {
repeated Module modules = 1;
string next_cursor = 2; // Empty string = no more pages.
bool has_more = 3;
}
ListActiveModules
Returns all modules in ACTIVE status for the calling tenant. This is the
primary RPC consumed by the UI Shell to build the navigation menu and
Module Federation 2.0 remote manifest.
Request — ListActiveModulesRequest
message ListActiveModulesRequest {}
Response — ListActiveModulesResponse
message ListActiveModulesResponse {
repeated Module modules = 1;
int32 count = 2; // Total number of active modules.
}
Results from
ListActiveModulesare cached in Valkey using keymodules:active:{tenantId}. Cache is invalidated on everyActivateModuleorDeactivateModulecall. The Gateway uses this cache to block routing to uninstalled modules (404 Not Foundwhen module not in active set).
ActivateModule
Transitions a module from PENDING, DISABLED, or FAILED to ACTIVE.
Triggers the ModuleActivatedEvent on platform.module.events.
Request — ActivateModuleRequest
message ActivateModuleRequest {
string id = 1; // Required. Module UUID.
}
Response — ActivateModuleResponse
message ActivateModuleResponse {
Module module = 1; // Module in ACTIVE status.
}
gRPC errors:
| gRPC status | Condition |
|---|---|
NOT_FOUND | Module ID does not exist |
FAILED_PRECONDITION | Module is in INCOMPATIBLE status — cannot be activated |
RESOURCE_EXHAUSTED | Tenant's modules billing limit exceeded |
DeactivateModule
Transitions an ACTIVE module to DISABLED. The module's route is removed
from the Gateway routing table and the Valkey modules:active:{tenantId} cache
is invalidated. A ModuleDeactivatedEvent is published.
Request — DeactivateModuleRequest
message DeactivateModuleRequest {
string id = 1; // Required. Module UUID.
}
Response — DeactivateModuleResponse
message DeactivateModuleResponse {
Module module = 1; // Module in DISABLED status.
}
DeleteModule
Soft-deletes a module. The module record is retained in the database for
audit purposes but becomes invisible to all List* and Get operations.
Published modules in registered state cannot be permanently deleted.
Request — DeleteModuleRequest
message DeleteModuleRequest {
string id = 1; // Required. Module UUID.
}
Response — DeleteModuleResponse
message DeleteModuleResponse {}
gRPC errors:
| gRPC status | Condition |
|---|---|
NOT_FOUND | Module ID does not exist |
FAILED_PRECONDITION | Module is in ACTIVE status — must DeactivateModule first |
ListModuleVersions
Returns the complete immutable version history for a module. Used by the Admin UI for version rollback and changelog display.
Request — ListModuleVersionsRequest
message ListModuleVersionsRequest {
string module_id = 1; // Required. Module UUID.
}
Response — ListModuleVersionsResponse
message ListModuleVersionsResponse {
repeated ModuleVersion versions = 1; // Ordered newest-first by created_at.
}
Gateway Integration
The Module Registry drives two Gateway behaviours:
| Behaviour | Mechanism |
|---|---|
| Tenant routing | On every request, Gateway checks modules:active:{tenantId} Valkey cache. If module is not in the active set → 404 Not Found |
| xDS config reload | ActivateModule / DeactivateModule → Envoy xDS LDS/RDS update via xDS control plane. Zero-downtime config reload — no Envoy restart |
Valkey cache key pattern:
modules:active:{tenantId} → SET of active module slugs
TTL: no expiry (invalidated on write via ActivateModule / DeactivateModule)