{
"schema_version": 1,
"diagram_type": "architecture",
"meta": {
"title": "dpz.core Runtime Architecture",
"subtitle": ".NET 10 hosts, shared service spine, durable state, messaging, and external trust edges",
"output": "architecture-runtime.html",
"quality_profile": "showcase",
"visual_preset": "blueprint",
"repository": {
"url": "https://github.com/pengqian089/dpz.core.git",
"revision": "09ce8c21cefdecf5c48c8ed2b877c1bf435f0cde"
},
"views": [
{
"id": "primary-request",
"label": "Primary request path",
"focus": ["users", "edge", "web", "serviceCore", "mongo"],
"note": "Follow the normal browser path through MVC, shared services, and MongoDB."
},
{
"id": "identity",
"label": "Identity boundary",
"focus": ["users", "edge", "web", "auth", "api"],
"note": "Web uses the OpenIddict client; WebApi validates JWTs against the auth issuer."
},
{
"id": "async-runtime",
"label": "Async runtime",
"focus": ["serviceCore", "rabbit", "jobs", "mongo", "externalServices"],
"note": "Outbox-backed publishing is drained by RabbitMQ consumers and Hangfire workers."
},
{
"id": "platform-state",
"label": "Platform state",
"focus": ["serviceCore", "mongo", "redis", "rabbit", "config"],
"note": "MongoDB is the durable store; Redis backs cache, SignalR, and locks."
}
]
},
"components": [
{
"id": "users",
"type": "external",
"label": "Clients",
"sublabel": "Public users, member UI, API callers",
"pos": [40, 270],
"size": [150, 68]
},
{
"id": "edge",
"type": "cloud",
"label": "Reverse Proxy / Edge",
"sublabel": "Forwarded headers, HTTPS boundary",
"pos": [260, 270],
"size": [150, 68]
},
{
"id": "web",
"type": "frontend",
"label": "Dpz.Core.Web",
"sublabel": "MVC, static assets, SignalR, /runtask",
"tag": "port 2372",
"pos": [500, 270],
"size": [166, 74],
"sources": [
{ "path": "src/Dpz.Core.Web/Program.cs", "line": 193, "label": "shared services" },
{ "path": "src/Dpz.Core.Web/Program.cs", "line": 254, "label": "OIDC client" },
{ "path": "src/Dpz.Core.Web/Library/AppExtensions.cs", "line": 120, "label": "SignalR hubs" }
]
},
{
"id": "serviceCore",
"type": "backend",
"label": "Shared Service Core",
"sublabel": "Repositories, Mapster, Mediator, cache, outbox",
"pos": [745, 270],
"size": [176, 78],
"sources": [
{ "path": "src/Dpz.Core.Service/ServiceExtensions.cs", "line": 20, "label": "AddBusinessServices" },
{ "path": "src/Dpz.Core.Service/ServiceExtensions.cs", "line": 66, "label": "RabbitMQ outbox" },
{ "path": "src/Dpz.Core.Service.Mediator/MediatorExtensions.cs", "line": 17, "label": "Mediator" }
]
},
{
"id": "mongo",
"type": "database",
"label": "MongoDB",
"sublabel": "Domain data, OIDC stores, outbox, Hangfire",
"pos": [990, 270],
"size": [165, 74],
"sources": [
{ "path": "src/Dpz.Core.MongodbAccess/UnitOfWork.cs", "line": 15, "label": "transactions" },
{ "path": "src/Dpz.Core.Hangfire/HangfireExtensions.cs", "line": 15, "label": "Hangfire storage" }
]
},
{
"id": "auth",
"type": "security",
"label": "Dpz.Core.Auth",
"sublabel": "OpenIddict issuer, cookies, MFA, passkeys",
"tag": "port 2377",
"pos": [500, 75],
"size": [166, 76],
"sources": [
{ "path": "src/Dpz.Core.Auth/Program.cs", "line": 71, "label": "shared services" },
{ "path": "src/Dpz.Core.Auth/OpenIddictRegister.cs", "line": 89, "label": "OIDC endpoints" }
]
},
{
"id": "api",
"type": "backend",
"label": "Dpz.Core.WebApi",
"sublabel": "REST, MessagePack, Scalar, JWT auth",
"tag": "port 2376",
"pos": [500, 455],
"size": [166, 76],
"sources": [
{ "path": "src/Dpz.Core.WebApi/Program.cs", "line": 161, "label": "shared services" },
{ "path": "src/Dpz.Core.WebApi/Program.cs", "line": 182, "label": "JWT bearer" },
{ "path": "src/Dpz.Core.WebApi/Program.cs", "line": 240, "label": "Scalar docs" }
]
},
{
"id": "jobs",
"type": "backend",
"label": "Dpz.Core.Web.Jobs",
"sublabel": "Hangfire workers, MQ consumers, file transfer",
"tag": "systemd",
"pos": [745, 455],
"size": [176, 76],
"sources": [
{ "path": "src/Dpz.Core.Web.Jobs/Program.cs", "line": 89, "label": "shared services" },
{ "path": "src/Dpz.Core.Web.Jobs/Program.cs", "line": 93, "label": "Hangfire" },
{ "path": "src/Dpz.Core.Web.Jobs/RegisterDependencyInjectionExtensions.cs", "line": 69, "label": "consumers" }
]
},
{
"id": "redis",
"type": "database",
"label": "Redis",
"sublabel": "FusionCache L2, backplane, locks, SignalR",
"pos": [745, 75],
"size": [176, 72],
"sources": [
{ "path": "src/Dpz.Core.Service/ServiceExtensions.cs", "line": 47, "label": "distributed lock" },
{ "path": "src/Dpz.Core.Service/ServiceExtensions.cs", "line": 76, "label": "FusionCache" },
{ "path": "src/Dpz.Core.Web/Program.cs", "line": 258, "label": "SignalR Redis" }
]
},
{
"id": "rabbit",
"type": "messagebus",
"label": "RabbitMQ",
"sublabel": "Typed publishers, route convention, consumers",
"pos": [990, 455],
"size": [165, 72],
"sources": [
{ "path": "src/Dpz.Core.MessageQueue/Extensions/MessageQueueServiceExtensions.cs", "line": 23, "label": "registration" },
{ "path": "src/Dpz.Core.MessageQueue/Extensions/MessageQueueServiceExtensions.cs", "line": 53, "label": "consumer host" }
]
},
{
"id": "config",
"type": "external",
"label": "AgileConfig and Secrets",
"sublabel": "Runtime configuration, issuers, connection strings",
"pos": [260, 75],
"size": [150, 72],
"sources": [
{ "path": "src/Dpz.Core.Web/Program.cs", "line": 22, "label": "Web config" },
{ "path": "src/Dpz.Core.WebApi/Program.cs", "line": 17, "label": "API config" },
{ "path": "src/Dpz.Core.Web.Jobs/Program.cs", "line": 20, "label": "Jobs config" }
]
},
{
"id": "externalServices",
"type": "external",
"label": "External Integrations",
"sublabel": "Object storage, OpenAI/network, email, upstream APIs",
"pos": [745, 625],
"size": [165, 72],
"sources": [
{ "path": "src/Dpz.Core.Web.Jobs/RegisterDependencyInjectionExtensions.cs", "line": 39, "label": "HTTP edge" },
{ "path": "src/Dpz.Core.Web.Jobs/RegisterDependencyInjectionExtensions.cs", "line": 52, "label": "object storage" }
]
}
],
"boundaries": [
{
"kind": "security-group",
"label": "Public Internet",
"wraps": ["users"],
"pad": 24
},
{
"kind": "region",
"label": "Application Trust Boundary",
"wraps": ["edge", "web", "api", "auth", "jobs", "serviceCore"],
"pad": 34
},
{
"kind": "security-group",
"label": "Stateful Infrastructure Boundary",
"wraps": ["mongo", "redis", "rabbit"],
"pad": 30
},
{
"kind": "security-group",
"label": "Third-Party / Configuration Boundary",
"wraps": ["config", "externalServices"],
"pad": 26
}
],
"connections": [
{
"id": "user-edge",
"from": "users",
"to": "edge",
"label": "HTTPS",
"variant": "emphasis"
},
{
"id": "edge-web",
"from": "edge",
"to": "web",
"label": "MVC request",
"variant": "emphasis",
"labelDy": 48
},
{
"id": "web-service",
"from": "web",
"to": "serviceCore",
"label": "commands / queries",
"variant": "emphasis",
"labelDy": 52
},
{
"id": "service-mongo",
"from": "serviceCore",
"to": "mongo",
"label": "repository / UoW",
"variant": "emphasis",
"labelDy": 55,
"labelDx": 72
},
{
"id": "web-auth",
"from": "web",
"to": "auth",
"variant": "security",
"fromSide": "top",
"toSide": "bottom"
},
{
"id": "edge-api",
"from": "edge",
"to": "api",
"fromSide": "bottom",
"toSide": "left"
},
{
"id": "api-service",
"from": "api",
"to": "serviceCore",
"fromSide": "right",
"toSide": "bottom"
},
{
"id": "service-redis",
"from": "serviceCore",
"to": "redis",
"fromSide": "top",
"toSide": "bottom"
},
{
"id": "service-rabbit",
"from": "serviceCore",
"to": "rabbit",
"variant": "dashed",
"fromSide": "right",
"toSide": "top"
},
{
"id": "rabbit-jobs",
"from": "rabbit",
"to": "jobs",
"variant": "dashed"
},
{
"id": "config-edge",
"from": "config",
"to": "edge",
"variant": "dashed"
},
{
"id": "jobs-external",
"from": "jobs",
"to": "externalServices",
"variant": "dashed",
"fromSide": "bottom",
"toSide": "top"
}
],
"cards": [
{
"dot": "cyan",
"title": "Primary Path",
"items": [
"Browser traffic crosses the edge boundary, lands in Dpz.Core.Web, then reaches repositories through the shared service core.",
"The main path intentionally ends at MongoDB because service public APIs and mediator handlers isolate persistence details from callers."
]
},
{
"dot": "rose",
"title": "Trust Boundaries",
"items": [
"Public Internet, application hosts, stateful infrastructure, and third-party/configuration systems are drawn as separate boundaries.",
"OpenIddict centralizes token issuance in Auth; Web challenges via OIDC client and WebApi validates JWT bearer tokens against the issuer."
]
},
{
"dot": "emerald",
"title": "Shared Runtime Spine",
"items": [
"AddBusinessServices registers repository/unit-of-work access, Mapster mapping, FusionCache, distributed locking, RabbitMQ outbox, and Mediator governance.",
"MongoDB stores domain data, OpenIddict entities, outbox records, and Hangfire collections; Redis supports L2 cache, backplane, locks, and SignalR scale-out."
]
},
{
"dot": "amber",
"title": "Async and Operations",
"items": [
"RabbitMQ publishers use route conventions; Jobs hosts consumers for markdown cleanup, counters, code analysis, email, and image metadata work.",
"Hangfire runs in Web and Jobs, with Jobs deployed as a systemd service rather than Docker."
]
},
{
"dot": "violet",
"title": "External Dependencies",
"items": [
"AgileConfig supplies runtime settings such as issuer URLs, connection strings, origins, and feature flags.",
"Object storage, outbound HTTP/OpenAI-style network services, email delivery, and upstream APIs are represented as one external integration surface to avoid extra edges."
]
}
]
}
AI 正在分析代码…
评论加载中...