- Create
SharedKernelproject - Create
Contractsproject - Extract core
APITemplate.Domainentities toSharedKernel - Update
APITemplate.Domainlegacy references to point toSharedKernel - Finish
SharedKernelalignment with the agreed Unit 0 scope fromimplementation_plan.md- Move Application layer components (Context, DTOs, Batch, Sorting, Validation, Errors, Search, Http, Middleware, Options)
- Move remaining planned Application components (
Resilience,Startup) - Add
IUnitOfWork<TContext>toSharedKernel.Domain.Interfaces - Move/refactor planned
SharedKernel.Infrastructurecomponents (ModuleDbContext, generalizedRepositoryBase,UnitOfWork<TContext>,SoftDelete, configuration/registration utilities) - Move configuration/resilience helpers from
APITemplate.ApitoSharedKernel.Infrastructure - Move
AddQueueWithConsumer<>registration toSharedKernel.Infrastructure - Replace legacy compatibility imports with explicit namespace shims / wrappers for moved types
- Configure
Contracts.csproj(reference SharedKernel) - Move existing integration event records (Cache invalidation, Email, SoftDelete)
- Keep
Contractsevent-only; leaveCacheTagsandMessageBusExtensionspublic inSharedKernel - Define new
ProductSoftDeletedNotificationand extendTenantSoftDeletedNotification
- Add both to
APITemplate.slnxand add references to legacy projects - Ensure full solution compiles (
dotnet build) - Run targeted Unit 0 regression tests (
UnitOfWork, configuration/options, startup coordination, queues/webhooks, soft-delete`)
- Create 4 projects (
ProductCatalog.Domain,ProductCatalog.Application,ProductCatalog.Infrastructure,ProductCatalog.Api) - Migrate Domain entities & repos (
Product,Category,ProductDataLink, etc.) - Migrate Application features (
Features/Product,Features/Category, etc.) - Migrate Infrastructure (
ProductCatalogDbContext, MongoDB, configs, cascade rules) - Migrate API & GraphQL
- Verify
dotnet build& tests
- Create 4 domain-driven projects
- Setup
ReviewsDbContextand ProductReview entity - Implement
ProductSoftDeletedEventHandler - Verify
dotnet build& tests
- Create 4 domain-driven projects
- Setup
IdentityDbContext(AppUser,Tenant,TenantInvitation) - Migrate Auth infrastructure (Keycloak, BFF, Providers)
- Migrate Controllers & Authorization
- Verify
dotnet build& tests
- Create 4 domain-driven projects (
Notifications.Domain,Notifications.Application,Notifications.Infrastructure,Notifications.Api) - Setup
NotificationsDbContext(FailedEmail) withFailedEmailConfiguration - Setup
Notifications.Domain(FailedEmailentity,IFailedEmailRepository) - Setup
Notifications.Application(Email contracts:IEmailSender,IEmailQueue,IEmailTemplateRenderer,IEmailRetryService,IFailedEmailStore,EmailMessage,EmailOptions,EmailTemplateNames) - Setup
Notifications.ApplicationHandlers (UserRegisteredEmailHandler,TenantInvitationEmailHandler,UserRoleChangedEmailHandler) - Migrate Email infrastructure (
MailKitEmailSender,ChannelEmailQueue,FluidEmailTemplateRenderer,EmailSendingBackgroundService,FailedEmailStore,FailedEmailErrorNormalizer) - Migrate Email retry infrastructure (
EmailRetryService,EmailRetryRecurringJob,EmailRetryRecurringJobRegistration) - Setup stored procedures (
ClaimRetryableFailedEmailsProcedure,ClaimExpiredFailedEmailsProcedure) + SQL migrations - Setup Liquid email templates (
user-registration,tenant-invitation,user-role-changed) - Setup
FailedEmailRepositorywith stored procedure integration - Setup
NotificationsRuntimeBridge(DI registration: DbContext, UoW, repos, email queue, SMTP resilience pipeline) - Setup
NotificationsModule.cs(event-driven, no REST controllers) - Add all 4 projects to
APITemplate.slnx - Verify
dotnet build— 0 errors, 0 warnings - Verify
dotnet test— 49/49 passed
- Create 4 domain-driven projects for FileStorage
- Setup
FileStorage.Domain(StoredFile,IStoredFileRepository) - Setup
FileStorage.Application(File features, options, etc.) - Setup
FileStorage.Infrastructure(FileStorageDbContext,StoredFileRepository,StoredFileConfiguration,LocalFileStorageService) - Setup
FileStorage.Api(FilesController,FileStorageModule.cs) - Set up module references and wiring in
Program.cs - Verify
dotnet build& tests
- Create 4 domain-driven projects for BackgroundJobs
- Setup
BackgroundJobs.Domain(JobExecution,JobStatus,IJobExecutionRepository) - Setup
BackgroundJobs.Application- DTOs:
SubmitJobRequest,GetJobStatusRequest,JobStatusResponse - Commands:
SubmitJobCommand+ handler (create entity, enqueue, mark Failed on enqueue error) - Queries:
GetJobStatusQuery+ handler (find by Id, return NotFound error if null) - Mappings:
JobMappings.ToResponse() - Services interfaces:
IJobQueue,IJobQueueReader,ICleanupService,IReindexService,IExternalIntegrationSyncService - Options:
BackgroundJobsOptions(TickerQ, Cleanup, Reindex, ExternalSync crons, retention, batch sizes)
- DTOs:
- Setup
BackgroundJobs.Infrastructurepersistence-
BackgroundJobsDbContext(inheritsModuleDbContext,DbSet<JobExecution>) -
JobExecutionConfiguration(key,ConfigureTenantAuditable, Status/JobType/ProgressPercent constraints, indexes) -
JobExecutionRepository(inheritsRepositoryBase<JobExecution>)
-
- Setup Services in
BackgroundJobs.Infrastructure-
ChannelJobQueue(bounded channel capacity 100, implementsIJobQueue+IJobQueueReader) -
JobProcessingBackgroundService(dequeue → MarkProcessing → simulate work → MarkCompleted/MarkFailed → webhook callback) -
CleanupService(Wolverine cross-module commands +ISoftDeleteCleanupStrategycollection) -
ReindexService(FTS index bloat check via stored procs, REINDEX CONCURRENTLY if >30% bloat) -
ExternalIntegrationSyncServicePreview(placeholder, logs info) -
SoftDeleteCleanupStrategy<TEntity>(generic batch hard-delete viaExecuteDeleteAsync) -
GetFtsIndexNamesProcedure+GetIndexBloatPercentProcedure(stored procedure wrappers)
-
- Setup TickerQ in
BackgroundJobs.Infrastructure-
TickerQSchedulerDbContext(inheritsTickerQDbContext, schema "tq_scheduler") -
TickerQRecurringJobRegistrar(syncs cron job definitions to DB viaIRecurringBackgroundJobRegistration) -
CleanupRecurringJob([TickerFunction("cleanup-recurring-job")]) -
ReindexRecurringJob([TickerFunction("reindex-recurring-job")]) -
ExternalSyncRecurringJob([TickerFunction("external-sync-recurring-job")]) -
CleanupRecurringJobRegistration,ReindexRecurringJobRegistration,ExternalSyncRecurringJobRegistration -
DragonflyDistributedJobCoordinator(Redis Lua lease management, 5-min lease, renewal ~100s)
-
- Setup Validation in
BackgroundJobs.Infrastructure-
BackgroundJobsOptionsValidator(CRON syntax, InstanceNamePrefix, CoordinationConnection, batch sizes)
-
- Setup
BackgroundJobsRuntimeBridge(DI: DbContext, UoW, repo, queue consumer, services, TickerQ conditional) - Setup
BackgroundJobs.Api-
JobsController:POST /jobs→SubmitJobCommand(202 Accepted + Location),GET /jobs/{id}→GetJobStatusQuery -
[RequirePermission(Permission.Examples.Execute)]on Submit -
[RequirePermission(Permission.Examples.Read)]on GetStatus -
BackgroundJobsModule.cs:AddBackgroundJobsModule()+MapBackgroundJobsEndpoints()
-
- Add all 4 projects to
APITemplate.slnx - Set up module references and wiring in
Program.cs - Verify
dotnet build— 0 errors, 0 warnings - Verify
dotnet test— 49/49 passed
- Create 4 domain-driven projects (in-memory queues, no EF)
- Migrate HMAC validator, signer, and webhook jobs
- Verify
dotnet build& tests — 0 errors, 49/49 passed
- Wire up
Program.csextension methods - Update
APITemplate.csprojreferences - Delete legacy
APITemplate.Domain,APITemplate.Application,APITemplate.Infrastructure(already removed) - Final verification (
dotnet build,dotnet test)