11 KiB
11 KiB
sessionId
| sessionId |
|---|
| session-260925-235814-7y2w |
Requirements
Overview & Goals
The goal is to modernize the ZeroSpace application by introducing .NET Aspire orchestration, adding a dedicated backend GraphQL API service powered by Hot Chocolate with Nitro UI (Banana Cake Pop), integrating a PostgreSQL database, containerizing components with Docker, and managing deployments on Kubernetes using industry-standard tooling (Aspirate / K8s manifests).
Scope
- In Scope:
- Creation of
.NET AspireAppHost (ZeroSpace.AppHost) and shared Service Defaults (ZeroSpace.ServiceDefaults). - Creation of an ASP.NET Core GraphQL API service (
ZeroSpace.ApiService) using Hot Chocolate with Entity Framework Core & PostgreSQL (Npgsql) support. - Interactive Nitro UI (Banana Cake Pop) GraphQL IDE integration at the
/graphqlendpoint for rapid schema exploration and testing. - GraphQL queries, mutations, filtering, sorting, and projections for
UnitData. - PostgreSQL container provisioning and database connection orchestration via Aspire.
- Updating
ZeroSpace.Web(Blazor WASM) to consume GraphQL operations fromZeroSpace.ApiService. - Docker containerization for both
ZeroSpace.ApiServiceandZeroSpace.Web. - Kubernetes manifest management and Aspirate integration for cluster deployment.
- Creation of
- Out of Scope:
- Modifying the unit model generation logic in
ZeroSpace.Build. - Cloud-specific managed Kubernetes cluster creation scripts (e.g. Terraform/Bicep for AKS/EKS).
- Modifying the unit model generation logic in
User Stories
- As a Developer, I want to start the web app, GraphQL API, and PostgreSQL database with a single command using .NET Aspire, and use Nitro UI to interactively explore and query schemas so that local development and testing maximize productivity.
- As an Operator, I want to generate Kubernetes deployment manifests from the Aspire architecture so that all services and databases deploy consistently to production Kubernetes clusters.
- As a User, I want to browse and manage ZeroSpace unit data through the Blazor Web UI backed by efficient, precision GraphQL data fetching and persistent database storage.
Functional Requirements
- FR-1: The Aspire AppHost must orchestrate the PostgreSQL container, GraphQL API service, and Web app with configured dependencies and environment variables.
- FR-2: The
ZeroSpace.ApiServicemust expose a Hot Chocolate GraphQL server with schema filtering, sorting, and projection capabilities over PostgreSQLUnitData. - FR-3: The Nitro UI GraphQL IDE must be hosted and accessible at
/graphqlto enable in-browser schema exploration, query execution, and debugging. - FR-4: Database schema migrations and initial seed data from
ZeroSpace.Model.Units.Allmust be executed automatically upon startup. - FR-5:
ZeroSpace.Webmust execute GraphQL queries/mutations againstZeroSpace.ApiServiceusing configured HTTP endpoints. - FR-6: Container definitions (Dockerfiles) must exist for all custom applications.
- FR-7: Kubernetes manifests must specify Deployments, Services, PersistentVolumeClaims, Secrets, and Ingress routing for Web and GraphQL endpoints.
Non-Functional Requirements
- Observability: OpenTelemetry tracing, metrics, and structured logging enabled across services via
ServiceDefaults(including Hot Chocolate diagnostic tracing). - Resilience & Health: Health check endpoints (
/health,/alive) configured for Kubernetes readiness and liveness probes. - Security: Database credentials managed through environment variables, Secrets, and Aspire connection strings without hardcoded passwords.
- Query Efficiency: GraphQL projections ensure only requested fields are fetched from PostgreSQL, minimizing network transfer and database payload overhead.
Technical Design
Current Implementation
ZeroSpace.Webis a standalone Blazor WebAssembly application (Microsoft.NET.Sdk.BlazorWebAssembly) targeting .NET 10, using native Blazor UI components only.ZeroSpace.Modelcontains records likeUnitData.cs,UnitEfficiency.cs, and generated static unit arrays inUnits.g.cs.ZeroSpace.Deploypublishes static files to Azure Static Web Apps.ZeroSpace.AppHost,ZeroSpace.ServiceDefaults, andZeroSpace.ApiServiceare integrated into the solution.
Key Decisions
- Hot Chocolate GraphQL Server with Nitro UI (
ZeroSpace.ApiService):- Decision: Introduce Hot Chocolate GraphQL server (
HotChocolate.AspNetCore,HotChocolate.Data.EntityFramework) and enable the embedded Nitro UI (Banana Cake Pop) GraphQL tool suite. - Rationale: GraphQL enables client-driven data fetching, reducing over-fetching and network serialization overhead. Nitro UI provides a rich developer and operator environment for real-time schema introspection, query building, and mutation execution directly in the browser.
- Decision: Introduce Hot Chocolate GraphQL server (
- .NET Aspire Orchestration & Aspirate for Kubernetes:
- Decision: Use .NET Aspire AppHost for local orchestration and developer dashboard, and use Aspirate (Aspir8) alongside standard Kubernetes manifests.
- Rationale: Aspire provides official .NET cloud-native developer tooling, OpenTelemetry defaults, and service discovery, while Aspirate transforms the Aspire manifest into production-ready Kubernetes Helm/Kustomize/YAML artifacts.
- Database Architecture & Seeding:
- Decision: Entity Framework Core with
Npgsql.EntityFrameworkCore.PostgreSQLand PostgreSQL 17 container. - Rationale: Native EF Core support with Aspire component
Aspire.Npgsql.EntityFrameworkCore.PostgreSQLenables automatic connection string binding, resilient retries, and database health checks.
- Decision: Entity Framework Core with
Architecture Diagram
graph TD
subgraph Local / Dev [Local .NET Aspire AppHost]
AppHost[ZeroSpace.AppHost]
Dash[Aspire Dashboard]
Nitro[Nitro UI / Banana Cake Pop]
AppHost --> Dash
AppHost --> Nitro
end
subgraph Kubernetes Cluster [Kubernetes Cluster]
Ingress[Kubernetes Ingress / Gateway]
subgraph Web Pod [Web Deployment]
Web[ZeroSpace.Web / Nginx]
end
subgraph API Pod [API Deployment]
API[ZeroSpace.ApiService / Hot Chocolate]
end
subgraph DB Pod [PostgreSQL StatefulSet / Pod]
DB[(PostgreSQL 17)]
PVC[PersistentVolumeClaim]
DB --- PVC
end
end
Ingress --> Web
Ingress --> API
Web -->|GraphQL Queries / Mutations| API
Nitro -->|Interactive Queries / Schema Docs| API
API -->|EF Core / Npgsql| DB
Components
ZeroSpace.AppHost: Aspire orchestrator project that links PostgreSQL container,ZeroSpace.ApiService, andZeroSpace.Web.ZeroSpace.ServiceDefaults: Shared project configuring OpenTelemetry, health checks, discovery, and resilience policies.ZeroSpace.ApiService: ASP.NET Core GraphQL API powered by Hot Chocolate, hosting Nitro UI at/graphql, and handling PostgreSQL persistence with EF Core.ZeroSpace.Web: Client-side Blazor WASM UI configured withIUnitsApiClientcommunicating withZeroSpace.ApiServicevia GraphQL.k8s/: Kubernetes manifests (Deployments, Services, PVC, Ingress, Secrets) and Aspirate generation configuration.
File Structure
ZeroSpace/
├── ZeroSpace.AppHost/
│ ├── Program.cs
│ ├── appsettings.json
│ └── ZeroSpace.AppHost.csproj
├── ZeroSpace.ServiceDefaults/
│ ├── Extensions.cs
│ └── ZeroSpace.ServiceDefaults.csproj
├── ZeroSpace.ApiService/
│ ├── Data/
│ │ ├── ZeroSpaceDbContext.cs
│ │ └── DbInitializer.cs
│ ├── GraphQL/
│ │ ├── Query.cs
│ │ ├── Mutation.cs
│ │ └── Types/
│ ├── Dockerfile
│ ├── Program.cs
│ └── ZeroSpace.ApiService.csproj
├── ZeroSpace.Web/
│ ├── Services/
│ │ ├── IUnitsApiClient.cs
│ │ └── UnitsApiClient.cs
│ ├── Dockerfile
│ ├── nginx.conf
│ └── ...
├── k8s/
│ ├── postgres-pvc.yaml
│ ├── postgres-deployment.yaml
│ ├── apiservice-deployment.yaml
│ ├── web-deployment.yaml
│ └── ingress.yaml
├── aspirate.json
└── ZeroSpace.sln
Data Models / Contracts
# GraphQL Schema Contract
type Query {
units(
where: UnitDataFilterInput
order: [UnitDataSortInput!]
): [UnitData!]!
unitById(id: String!): UnitData
}
type Mutation {
createUnit(input: CreateUnitInput!): UnitData!
updateUnit(id: String!, input: UpdateUnitInput!): UnitData!
deleteUnit(id: String!): Boolean!
}
Risks & Mitigations
- Risk: GraphQL N+1 or deep query performance impacts.
- Mitigation: Leverage Hot Chocolate's
[UseProjection],[UseFiltering], and[UseSorting]which translate GraphQL AST directly into optimized PostgreSQL SQL via EF CoreIQueryable.
- Mitigation: Leverage Hot Chocolate's
- Risk: Nitro UI access across different deployment environments.
- Mitigation: Configure Nitro UI / Banana Cake Pop middleware settings so developer tooling is available locally and behind authorized Ingress routes in staging/production as needed.
- Risk: Blazor WASM CORS issues when executing GraphQL POST requests.
- Mitigation: Configure permissive CORS policies in
ZeroSpace.ApiServicefor GraphQL endpoints and route requests through Kubernetes Ingress.
- Mitigation: Configure permissive CORS policies in
Testing
Validation Approach
- Verify local orchestration via
dotnet run --project ZeroSpace.AppHost. - Access Nitro UI at
http://localhost:5142/graphql(or through Aspire Dashboard endpoint) to test interactive queries, mutations, and schema documentation. - Test GraphQL queries and mutations executed by
ZeroSpace.WebagainstZeroSpace.ApiService. - Build and run Docker containers for
ZeroSpace.ApiServiceandZeroSpace.Web. - Validate Kubernetes manifest syntax and Aspirate manifest compilation (
aspirate generate).
Key Scenarios
- Aspire Local Launch: Starting
ZeroSpace.AppHostboots PostgreSQL container, runs EF Core migrations, startsZeroSpace.ApiServicewith Hot Chocolate GraphQL & Nitro UI, and launchesZeroSpace.Web. - Nitro UI Interactive Execution: Open
/graphqlin browser; Banana Cake Pop / Nitro UI loads; execute{ units { id name hexite flux tier faction } }and receive structured JSON response. - Blazor UI Data Flow: Navigating to
/unitsin the Blazor UI sends a GraphQL query payload toZeroSpace.ApiService, which queries PostgreSQL and returns unit records. - Container Build:
docker buildsucceeds for bothZeroSpace.ApiServiceandZeroSpace.WebDockerfiles. - Kubernetes Deployment: Applying the generated Kubernetes manifests provisions the PVC, deploys PostgreSQL, starts API/Web pods, and exposes them via Service and Ingress.
Edge Cases
- PostgreSQL Connection Failures: GraphQL queries gracefully return structured GraphQL errors and health checks report unhealthy status.
- Empty Database: Seeding logic populates initial units from
ZeroSpace.Modelif the database table is empty before serving GraphQL requests. - Complex GraphQL Filtering: Verify filtering by tier and faction compiles to efficient SQL
WHEREclauses in PostgreSQL without in-memory buffering.