- Follow
.github/copilot-instructions.md,.squad/team.md, and.squad/routing.mdbefore autonomous work. Squad branches usesquad/{issue-number}-{slug}; do not commit.squad/files onfeature/*branches.
src/AppHost/AppHost.csis the local-dev entry point: it wireswebtoConnectionStrings:mongodb, provisionsredis(with RedisCommander in Development), waits for Redis, and health-checks/health.src/Web/Program.csis the real composition root: DI, Auth0, MediatR, minimal APIs, SignalR, background services, and startup seeding all start here.src/ServiceDefaults/Extensions.cscentralizes OpenTelemetry, service discovery, resilience, and the/health+/aliveendpoints.src/Domain/holds business logic in vertical slices underFeatures/*; shared contracts live inDTOs/,Models/, andAbstractions/(Result<T>,IRepository<T>). Feature slices: Issues, Comments, Attachments, Categories, Statuses, Analytics, Dashboard, Notifications.src/Domain/Events/holds domain event records (IssueCreatedEvent,IssueUpdatedEvent,IssueAssignedEvent,IssueStatusChangedEvent,CommentAddedEvent) published via MediatRINotificationHandler.src/Domain/Features/Notifications/holdsINotificationHandlerimplementations that react to domain events and enqueue emails viaQueueEmailCommand.src/Persistence.MongoDb/is the Mongo persistence layer:IssueTrackerDbContext, EF Core Mongo configurations, and the genericRepository<T>implementation.src/Persistence.AzureStorage/is optional file storage;Webfalls back toLocalFileStorageServicewhenBlobStorage:ConnectionStringis missing.src/Web/Components/Theme/holdsThemeProvider.razorandThemeSelector.razorfor system-aware dark mode with 4 colour schemes.src/Web/Components/Charts/holdsBarChart.razor,LineChart.razor, andPieChart.razorBlazor components used in the Analytics admin page.src/Web/Helpers/holdsObjectIdJsonConverter(registered globally inProgram.csfor MongoDBObjectId↔ JSON string) andCsvExportHelper(reflection-based CSV export used by bulk-export).- Cache strategy:
DistributedCacheHelper(src/Web/Services/DistributedCacheHelper.cs) wrapsIDistributedCache(Redis in prod,DistributedMemoryCachein test) with typed JSON get/set/remove and version-token helpers. All services inject it for cache-aside reads (miss → DB → cache) and CRUD invalidation. TTLs: reference data (Category/Status) 60 min, lookups 30 min, issues/comments/dashboard 5–10 min, Auth0 users 5–10 min. See Sprint issues #218–#240 for full invalidation matrix.
- Typical flow is
Webpage/endpoint ->src/Web/Services/*facade -> MediatR command/query insrc/Domain/Features/*->IRepository<T>-> MongoDB. - Example:
src/Web/Services/IssueService.cssendsCreateIssueCommand;src/Domain/Features/Issues/Commands/CreateIssueCommand.csmaps DTOs to models and persists through repositories. - Minimal API endpoints live in two directories:
src/Web/Endpoints/(CategoryEndpoints.cs,StatusEndpoints.cs) andsrc/Web/Features/(CommentEndpoints.cs,AttachmentEndpoints.cs). Both follow the same route-group +AdminPolicy/RequireAuthorizationpattern shown inCategoryEndpoints.cs. - Startup seeds categories and statuses via
src/Web/Data/DataSeeder.cs;InitializeMongoDbAsync()and seeding are skipped whenEnvironment == "Testing". - Comment flow:
CommentEndpoints→CommentService→ MediatR →IRepository<Comment>→ MongoDB. - Attachment flow:
AttachmentEndpoints→AttachmentService→ MediatR →IFileStorageService(Azure Blob orLocalFileStorageService). - Analytics flow:
AnalyticsService→ MediatRDomain/Features/Analyticsqueries → MongoDB aggregation; results are cached inIMemoryCachewith a 5-minute TTL. - Dashboard flow:
DashboardService→GetUserDashboardQuery→ MongoDB; Dashboard page uses@attribute [StreamRendering]. - Bulk operations:
IBulkOperationServiceenqueues operations onInMemoryBulkOperationQueue(IBulkOperationQueue);BulkOperationBackgroundServicedequeues and dispatches MediatR commands fromDomain/Features/Issues/Commands/Bulk/. Undo is provided byInMemoryUndoService. - Email pipeline: domain events (
src/Domain/Events/) are published with MediatRIPublisher;Domain/Features/Notifications/handlers react and dispatchQueueEmailCommand;EmailQueueBackgroundServicepolls the queue every 10 s and sends viaIEmailService(SendGrid ifSendGrid:ApiKeyis set, SMTP otherwise).
tests/Architecture.Tests/LayerDependencyTests.csenforces boundaries:Domaincannot depend onWeborPersistence.*;Persistence.*cannot depend onWeb.tests/Architecture.Tests/NamingConventionTests.cs,AdvancedArchitectureTests.cs, andCodeStructureTests.csenforce the repo's shape: commands end withCommand, queries withQuery, validators withValidator, handlers withHandlerand should besealed.- CQRS types belong under
Domain.Features.*; validators live inValidatorsor next to commands; DTOs inDomain.DTOsshould be records. - Repositories must implement
IRepository<>; preserveResult<T>/ResultErrorCodefor expected failures instead of switching to exception-driven control flow. - Commands may reside in either a
Commandsor aNotificationsnamespace;AdvancedArchitectureTests.csexplicitly allows both locations.
- Auth0 is configured in
src/Web/Program.cs; role claim remapping happens insrc/Web/Auth/Auth0ClaimsTransformation.cs, and policy names/constants live insrc/Web/Auth/*. src/Persistence.MongoDb/ServiceCollectionExtensions.csfalls back fromMongoDB:ConnectionStringtoConnectionStrings:mongodb, which matters under Aspire and in tests.- Redis is provisioned in
AppHostand health-check helpers exist inServiceDefaults, but current app code leans onIMemoryCachemore than distributed cache. - SignalR updates flow through
src/Web/Hubs/IssueHuband notification-aware services such asIssueService.
- Branching model:
devis the active development branch (feature PRs targetdevvia squash merge);mainis releases only (promoted fromdevvia merge commit, then tagged). Direct pushes to bothdevandmainare blocked. - From repo root:
dotnet restore,dotnet build,dotnet test IssueTrackerApp.slnx. - Run locally through Aspire:
dotnet run --project src/AppHost/AppHost.csproj. - UI changes:
src/Web/Web.csprojauto-runsnpm install(if needed) andnpm run css:build; usenpm run css:watchinsrc/Webfor Tailwind iteration. - Integration tests need Docker;
tests/Persistence.MongoDb.Tests.Integration/MongoDbFixture.csandtests/Web.Tests.Integration/CustomWebApplicationFactory.csusemongo:7.0with replica setrs0. CI can override withMONGODB_CONNECTION_STRING. - NuGet versions are centralized in
Directory.Packages.props; do not add package versions in individual.csprojfiles.