use super::*;
pub(super) fn build_manifest(module: &OpsModule) -> ModuleManifest {
ModuleManifest::new(module.name().to_string())
.with_required_capabilities(required_capabilities())
.with_optional_capabilities(optional_capabilities())
.with_config_namespace(module.config_namespace().to_string())
.with_capability_contracts(capability_contracts())
.with_module_dependencies(module_dependencies())
.with_core_service_dependencies(core_service_dependencies())
.with_migrations(module_migrations())
.with_route_surfaces(route_surfaces())
.with_jobs(jobs())
.with_event_subscriptions(event_subscriptions())
.with_integration_points(integration_points())
.with_behaviors(module_behaviors())
.with_extension_slots(extension_slots())
.with_admin_resources(admin_resources())
.with_report_definitions(report_definitions())
.with_bulk_operations(bulk_operations())
.with_http_surfaces(http_surfaces())
}
fn required_capabilities() -> Vec<Capability> {
vec![
Capability::AdminShellAccess,
Capability::AdminAuditRead,
Capability::SystemModuleManage,
]
}
fn optional_capabilities() -> Vec<Capability> {
vec![
Capability::CmsPageRead,
Capability::CmsPageEdit,
Capability::CmsPagePublish,
Capability::CmsNavigationEdit,
Capability::CatalogProductRead,
Capability::CatalogProductEdit,
Capability::CatalogCollectionEdit,
Capability::OrderRead,
Capability::OrderRefundIssue,
Capability::MembershipSubscriptionManage,
Capability::MembershipTierEdit,
Capability::EventsEventPublish,
Capability::EventsSlotManage,
Capability::EventsBookingCreate,
Capability::EventsBookingCheckIn,
Capability::AssetRead,
Capability::AssetReadPublic,
Capability::AssetPublish,
Capability::AssetReplace,
Capability::AssetManageStorage,
]
}
fn capability_contracts() -> Vec<CapabilityContract> {
vec![
CapabilityContract::required(Capability::AdminShellAccess, ["admin_module"]),
CapabilityContract::required(Capability::AdminAuditRead, ["audit_entry"]),
CapabilityContract::required(Capability::SystemModuleManage, ["admin_module"]),
CapabilityContract::optional(Capability::CmsPageRead, ["page"]),
CapabilityContract::optional(Capability::CmsPageEdit, ["page"]),
CapabilityContract::optional(Capability::CmsPagePublish, ["page"]),
CapabilityContract::optional(Capability::CmsNavigationEdit, ["navigation"]),
CapabilityContract::optional(Capability::CatalogProductRead, ["product"]),
CapabilityContract::optional(Capability::CatalogProductEdit, ["product"]),
CapabilityContract::optional(Capability::CatalogCollectionEdit, ["collection"]),
CapabilityContract::optional(Capability::OrderRead, ["order"]),
CapabilityContract::optional(Capability::OrderRefundIssue, ["order"]),
CapabilityContract::optional(Capability::MembershipSubscriptionManage, ["subscription"]),
CapabilityContract::optional(Capability::MembershipTierEdit, ["membership_tier"]),
CapabilityContract::optional(Capability::EventsEventPublish, ["event"]),
CapabilityContract::optional(Capability::EventsSlotManage, ["event_slot"]),
CapabilityContract::optional(Capability::EventsBookingCreate, ["booking"]),
CapabilityContract::optional(Capability::EventsBookingCheckIn, ["booking"]),
CapabilityContract::optional(Capability::AssetRead, ["asset", "media"]),
CapabilityContract::optional(Capability::AssetReadPublic, ["asset", "media"]),
CapabilityContract::optional(Capability::AssetPublish, ["asset", "media"]),
CapabilityContract::optional(Capability::AssetReplace, ["asset", "media"]),
CapabilityContract::optional(
Capability::AssetManageStorage,
["asset", "asset_folder", "media_library"],
),
]
}
fn module_dependencies() -> Vec<ModuleDependency> {
vec![
ModuleDependency::required(
"admin",
"Operational search, reporting, and bulk actions surface through the shared admin shell",
),
ModuleDependency::optional(
"cms",
"Search and bulk publishing can index and mutate CMS content when that module is installed",
),
ModuleDependency::optional(
"commerce",
"Reporting and bulk operations can project order and catalog activity when commerce is installed",
),
ModuleDependency::optional(
"memberships",
"Operational reports can include subscription and entitlement state when memberships is installed",
),
ModuleDependency::optional(
"events",
"Search and bulk workflows can operate on bookings and check-in state when events is installed",
),
ModuleDependency::optional(
"media",
"Search and reporting can include managed assets and storage-policy inventory when media is installed",
),
]
}
fn core_service_dependencies() -> Vec<CoreServiceDependency> {
vec![
CoreServiceDependency::Auth,
CoreServiceDependency::Data,
CoreServiceDependency::Jobs,
CoreServiceDependency::Storage,
CoreServiceDependency::Cache,
CoreServiceDependency::Observability,
]
}
fn module_migrations() -> Vec<MigrationContract> {
vec![
MigrationContract::new(
"ops.search",
10,
"Creates search projection and rebuild-cursor tables for first-party indexing",
),
MigrationContract::new(
"ops.reports",
20,
"Creates report definition, export job, and output artifact metadata tables",
),
MigrationContract::new(
"ops.bulk",
30,
"Creates bulk-operation intent, idempotency, and audit coordination tables",
),
]
}
fn route_surfaces() -> Vec<RouteSurface> {
vec![
RouteSurface::new("ops.search", RouteSurfaceKind::AdminPage, "/admin/search")
.gated_by(Capability::AdminShellAccess),
RouteSurface::new("ops.reports", RouteSurfaceKind::AdminPage, "/admin/reports")
.gated_by(Capability::AdminAuditRead),
RouteSurface::new(
"ops.recovery",
RouteSurfaceKind::AdminPage,
"/admin/recovery",
)
.gated_by(Capability::SystemModuleManage),
RouteSurface::new("ops.bulk", RouteSurfaceKind::AdminAction, "/admin/bulk")
.gated_by(Capability::SystemModuleManage),
]
}
fn jobs() -> Vec<JobContract> {
vec![
JobContract::new(
"ops.search.rebuild",
JobTriggerKind::DomainEvent,
true,
"Rebuilds or repairs first-party search projections as domain records change",
),
JobContract::new(
"ops.report.export",
JobTriggerKind::Operator,
true,
"Runs asynchronous report exports and persists their output artifacts safely",
),
JobContract::new(
"ops.bulk.execute",
JobTriggerKind::Operator,
true,
"Executes audited bulk workflows behind idempotent job envelopes",
),
JobContract::new(
"ops.recovery.rehydrate",
JobTriggerKind::Operator,
true,
"Rebuilds derived state and recovery steps after source-of-truth restore completes",
),
]
}
fn event_subscriptions() -> Vec<EventSubscription> {
vec![
EventSubscription::new(
"cms.page.published",
Some("ops.search.rebuild"),
"Refreshes search projections after editorial publication changes",
),
EventSubscription::new(
"commerce.order.paid",
Some("ops.report.export"),
"Enables scheduled or on-demand reporting to capture completed transactional activity",
),
EventSubscription::new(
"events.booking.checked-in",
Some("ops.bulk.execute"),
"Keeps operational bulk and reporting views consistent with live attendance changes",
),
]
}
fn integration_points() -> Vec<IntegrationPoint> {
vec![
IntegrationPoint::new(
IntegrationKind::SearchIndex,
"ops.search",
"Collects explicit indexing contributions from official modules and customer app extensions",
),
IntegrationPoint::new(
IntegrationKind::AdminWorkflow,
"ops.bulk",
"Adds report export and bulk workflow surfaces into the shared admin shell",
),
IntegrationPoint::new(
IntegrationKind::StoragePolicy,
"ops.report-output",
"Routes generated report artifacts through the shared storage-policy and delivery model",
),
IntegrationPoint::new(
IntegrationKind::StoragePolicy,
"ops.recovery",
"Coordinates recovery ordering across Postgres, managed object storage, and local-only sensitive exceptions",
),
]
}
fn module_behaviors() -> Vec<ModuleBehavior> {
vec![
ModuleBehavior::AsyncJobs,
ModuleBehavior::AuditedBulkActions,
]
}
fn extension_slots() -> Vec<ExtensionSlotDescriptor> {
vec![
ExtensionSlotDescriptor::new(
ExtensionSlotKind::AdminWidget,
"ops.report.dashboard",
"Allows bounded customer widgets to contribute operator metrics and report affordances",
),
ExtensionSlotDescriptor::new(
ExtensionSlotKind::Job,
"ops.search.adapter",
"Allows search backends to participate through explicit background job contracts",
),
]
}
fn admin_resources() -> Vec<AdminResourceContribution> {
vec![
AdminResourceContribution::new(
"ops.search",
"/admin/search",
"Search",
"Search",
AdminNavigationSection::System,
AdminContributionKind::ResourceIndex,
Capability::AdminShellAccess,
),
AdminResourceContribution::new(
"ops.reports",
"/admin/reports",
"Reports",
"Reports",
AdminNavigationSection::System,
AdminContributionKind::ResourceIndex,
Capability::AdminAuditRead,
),
AdminResourceContribution::new(
"ops.bulk",
"/admin/bulk",
"Bulk operations",
"Bulk",
AdminNavigationSection::System,
AdminContributionKind::Workflow,
Capability::SystemModuleManage,
),
AdminResourceContribution::new(
"ops.recovery",
"/admin/recovery",
"Recovery",
"Recovery",
AdminNavigationSection::System,
AdminContributionKind::Workflow,
Capability::SystemModuleManage,
),
]
}
fn report_definitions() -> Vec<ManifestReportDefinition> {
vec![
ManifestReportDefinition::new(
"report.ops.search-health",
"Search health",
Some(
"Operational visibility into index freshness, drift, and rebuild lag"
.to_string(),
),
Capability::AdminAuditRead,
ManifestReportFormat::Json,
ManifestReportSensitivity::Internal,
ManifestReportDeliveryMode::SignedUrl,
"reports/ops/search",
default_retry_policy(),
),
ManifestReportDefinition::new(
"report.ops.backup-readiness",
"Backup readiness",
Some(
"Summarizes whether source-of-truth data classes follow the platform recovery model"
.to_string(),
),
Capability::AdminAuditRead,
ManifestReportFormat::Json,
ManifestReportSensitivity::Internal,
ManifestReportDeliveryMode::SignedUrl,
"reports/ops/backup",
default_retry_policy(),
),
]
}
fn bulk_operations() -> Vec<ManifestBulkOperationDefinition> {
vec![
ManifestBulkOperationDefinition::new(
"bulk.search.reindex",
"Reindex search",
Some("Queues a coordinated rebuild across declared search indexes".to_string()),
Capability::SystemModuleManage,
ManifestBulkOperationKind::Reindex,
ManifestBulkOperationScope::Search,
default_retry_policy(),
Some(100),
true,
),
ManifestBulkOperationDefinition::new(
"bulk.reports.export",
"Bulk export reports",
Some("Queues exports for multiple reports without request-time blocking".to_string()),
Capability::AdminAuditRead,
ManifestBulkOperationKind::Export,
ManifestBulkOperationScope::System,
default_retry_policy(),
Some(50),
true,
),
]
}
fn http_surfaces() -> Vec<HttpSurfaceContribution> {
vec![
HttpSurfaceContribution::page(
"ops.search",
HttpSurfaceArea::Admin,
"/admin/search",
"ops/search",
)
.gated_by(Capability::AdminShellAccess),
HttpSurfaceContribution::page(
"ops.reports",
HttpSurfaceArea::Admin,
"/admin/reports",
"ops/reports",
)
.gated_by(Capability::AdminAuditRead),
HttpSurfaceContribution::json(
"ops.recovery",
HttpSurfaceMethod::Post,
HttpSurfaceArea::Admin,
"/admin/recovery",
202,
std::collections::BTreeMap::from([("status".to_string(), "queued".to_string())]),
)
.gated_by(Capability::SystemModuleManage),
HttpSurfaceContribution::json(
"ops.bulk",
HttpSurfaceMethod::Post,
HttpSurfaceArea::Admin,
"/admin/bulk",
202,
std::collections::BTreeMap::from([("status".to_string(), "queued".to_string())]),
)
.gated_by(Capability::SystemModuleManage),
]
}