Skip to content

Discoverability

Every Deepstaging module emits a documentation-only partial class alongside its functional code. These .Docs.g.cs files contain no logic — just XML doc comments that surface your application's architecture directly in the IDE.

Go to definition on any container type and the full topology is right there: entities, routes, handlers, subscriptions, configuration sections, activity sources — all visible without leaving your editor.


What Gets Documented

Each module generates docs on the type developers naturally navigate to — the container class they declared in their own code.

Module Container Type What You See
Runtime [Runtime] class Effects modules, data stores, config sections, activity sources, service registrations
DataStore [DataStore] class Entities, keys, foreign key relationships, lookup indexes
EventStore [EventStore] class Aggregates, stream types, projections, upcasters
Dispatch [DispatchModule] class Command → handler mapping, query → handler mapping, validation, authorization
REST API [RestApi] class Full route table with HTTP methods, paths, handlers, auth policies
Integration Events [IntegrationEvents] class Published events with wire names, plus all subscriptions in the assembly
Event Queue [EventQueue] class Queue configuration, capacity, concurrency, handler methods
Config [ConfigRoot] class Configuration sections, properties, secrets
Jobs Job worker class Job type → handler mapping

Example: Runtime Manifest

The [Runtime] class is the hub of your bounded context. Its docs aggregate everything — including auto-discovered modules:

// What you write — local modules are auto-discovered:
[Runtime]
[Uses(typeof(JobsModule))]   // external — needs [Uses]
public partial class OrderingRuntime;

Go to definition on OrderingRuntime and the XML doc shows:

/// <summary>
/// <c>OrderingRuntime</c>  Application Runtime Manifest.
/// <para><b>Effects Modules</b></para>
/// <list type="bullet">
///   <item>IHasPaymentGateway  IPaymentGateway</item>
/// </list>
/// <para><b>Data Stores</b></para>
/// <list type="bullet">
///   <item>IHasOrderingStore  IOrderStore, IBuyerStore</item>
/// </list>
/// </summary>
/// <remarks>
/// <para><b>Activity Sources (OpenTelemetry)</b></para>
/// <list type="bullet">
///   <item><c>eShop.Ordering.OrderingStore</c></item>
///   <item><c>eShop.Ordering.OrderingDispatch</c></item>
/// </list>
/// <para><b>Configuration Sections</b></para>
/// <list type="bullet">
///   <item><c>Ordering</c>  OrderingConfig</item>
/// </list>
/// </remarks>

Example: DataStore Manifest

// What you write:
[DataStore]
public static partial class OrderingStore;

[StoredEntity]
public partial class Order;

[StoredEntity]
public partial class Buyer;
/// <summary>
/// Data store containing 2 entities.
/// <list type="table">
///   <listheader><term>Entity</term><description>Key</description></listheader>
///   <item><term><see cref="Order"/></term><description>Id: OrderId</description></item>
///   <item><term><see cref="Buyer"/></term><description>Id: BuyerId</description></item>
/// </list>
/// </summary>
/// <remarks>
/// <para><b>Relationships</b></para>
/// <list type="bullet">
///   <item>Order.BuyerId  <see cref="Buyer"/></item>
/// </list>
/// </remarks>

Example: REST API Route Table

// What you write:
[RestApi("/api/catalog")]
public partial class CatalogRestApi;
/// <summary>
/// REST API  Route Table (prefix: <c>/api/catalog</c>).
/// <list type="table">
///   <listheader><term>Method</term><description>Route  Handler [Auth]</description></listheader>
///   <item><term>GET</term><description><c>/items</c>  GetCatalogItemsHandler.Handle</description></item>
///   <item><term>GET</term><description><c>/items/{id}</c>  GetCatalogItemByIdHandler.Handle</description></item>
///   <item><term>PUT</term><description><c>/items/{id}/price</c>  UpdatePriceHandler.Handle</description></item>
///   <item><term>GET</term><description><c>/brands</c>  GetBrandsHandler.Handle</description></item>
/// </list>
/// </summary>

Example: Integration Events Topology

The publisher container shows both what you publish and what you subscribe to — the full event topology for your bounded context:

// What you write:
[IntegrationEvents(typeof(OrderingEvents))]
public static partial class OrderingIntegrationEvents;

[IntegrationEventHandler<OrderingRuntime>(typeof(BasketEvents))]
public static partial class OrderingBasketEventHandlers { ... }

[IntegrationEventHandler<OrderingRuntime>(typeof(CatalogEvents))]
public static partial class OrderingCatalogEventHandlers { ... }
/// <summary>
/// Integration Events  Publisher (<c>ordering-events</c>).
/// <para><b>Published Events</b></para>
/// <list type="table">
///   <listheader><term>Wire Name</term><description>CLR Type</description></listheader>
///   <item><term><c>ordering.order-started</c></term><description>OrderStarted</description></item>
///   <item><term><c>ordering.order-paid</c></term><description>OrderStatusChangedToPaid</description></item>
/// </list>
/// </summary>
/// <remarks>
/// <para><b>Subscriptions</b></para>
/// <list type="table">
///   <listheader><term>Topic</term><description>Handler</description></listheader>
///   <item><term>basket-events (<c>basket.user-checkout-accepted</c>)</term>
///         <description>OrderingBasketEventHandlers.Handle</description></item>
///   <item><term>catalog-events (<c>catalog.order-stock-confirmed</c>)</term>
///         <description>OrderingCatalogEventHandlers.Handle</description></item>
/// </list>
/// </remarks>

Example: Dispatch Handlers

// What you write:
[DispatchModule]
public static partial class CatalogDispatch;
/// <summary>
/// Dispatch module with 2 command handlers and 3 query handlers.
/// <para><b>Commands</b></para>
/// <list type="table">
///   <listheader><term>Command</term><description>Handler  Result</description></listheader>
///   <item><term>UpdateCatalogItemPrice</term>
///         <description>UpdateCatalogItemPriceHandler.Handle  Unit</description></item>
///   <item><term>CreateCatalogItem</term>
///         <description>CreateCatalogItemHandler.Handle  CatalogItemId</description></item>
/// </list>
/// <para><b>Queries</b></para>
/// <list type="table">
///   <listheader><term>Query</term><description>Handler  Result</description></listheader>
///   <item><term>GetCatalogItems</term>
///         <description>GetCatalogItemsHandler.Handle  QueryResult&lt;CatalogItem&gt;</description></item>
///   <item><term>GetCatalogItemById</term>
///         <description>GetCatalogItemByIdHandler.Handle  CatalogItem</description></item>
/// </list>
/// </summary>

How It Works

Each generator emits a .Docs.g.cs file alongside the functional code. The file contains a partial declaration with only XML doc comments — no members, no logic:

// AppStore.Docs.g.cs (auto-generated)
/// <summary>
/// Data store containing 3 entities.
/// ...
/// </summary>
public static partial class AppStore
{
}

Because C# merges partial declarations, hovering over AppStore anywhere in your code shows the full manifest in IntelliSense. The docs are always up to date because they're regenerated on every build.

No competing docs

Deepstaging ensures only the .Docs.g.cs partial carries class-level XML comments. Other generated partials (effects, bootstrap, etc.) omit class-level docs so the manifest is always the one that surfaces.


Zero Configuration

Manifests are generated automatically. There's nothing to enable, no attributes to add beyond what you already use. If you have a [DataStore], you get a DataStore manifest. If you have a [Runtime], you get the full topology.