Files
git.stella-ops.org/docs/router/SPRINT_7000_0010_0001_migration.md
master 75f6942769
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Add integration tests for migration categories and execution
- Implemented MigrationCategoryTests to validate migration categorization for startup, release, seed, and data migrations.
- Added tests for edge cases, including null, empty, and whitespace migration names.
- Created StartupMigrationHostTests to verify the behavior of the migration host with real PostgreSQL instances using Testcontainers.
- Included tests for migration execution, schema creation, and handling of pending release migrations.
- Added SQL migration files for testing: creating a test table, adding a column, a release migration, and seeding data.
2025-12-04 19:10:54 +02:00

9.8 KiB

Sprint 7000-0010-0001 · Migration · WebService to Microservice

Topic & Scope

Define and document the migration path from existing StellaOps.*.WebService projects to the new microservice pattern with router. This is the final sprint that connects the router infrastructure to the rest of StellaOps.

Goal: Clear migration guide and tooling for converting WebServices to Microservices.

Working directories:

  • docs/router/ (migration documentation)
  • Potentially existing WebService projects (for pilot migration)

Dependencies & Concurrency

  • Upstream: All router sprints complete (7000-0001 through 7000-0009)
  • Downstream: None. Final sprint.
  • Parallel work: None.
  • Cross-module impact: YES - This sprint affects existing StellaOps modules.

Documentation Prerequisites

  • docs/router/specs.md (section 14 - Migration requirements)
  • docs/router/implplan.md (phase 11-12 guidance)
  • Existing WebService project structures

BLOCKED Tasks: Before working on BLOCKED tasks, review ../implplan/BLOCKED_DEPENDENCY_TREE.md for root blockers and dependencies.

Delivery Tracker

# Task ID Status Description Notes
1 MIG-001 TODO Inventory all existing WebService projects List all services
2 MIG-002 TODO Document HTTP routes per service Method + Path
3 MIG-010 TODO Document Strategy A: In-place adaptation
4 MIG-011 TODO Add SDK to existing WebService
5 MIG-012 TODO Wrap controllers in [StellaEndpoint] handlers
6 MIG-013 TODO Register with router alongside HTTP
7 MIG-014 TODO Gradual traffic shift from HTTP to router
8 MIG-020 TODO Document Strategy B: Clean split
9 MIG-021 TODO Extract domain logic to shared library
10 MIG-022 TODO Create new Microservice project
11 MIG-023 TODO Map routes to handlers
12 MIG-024 TODO Phase out original WebService
13 MIG-030 TODO Document CancellationToken wiring
14 MIG-031 TODO Identify async operations needing token
15 MIG-032 TODO Update DB calls, HTTP calls, etc.
16 MIG-040 TODO Document streaming migration
17 MIG-041 TODO Convert file upload controllers
18 MIG-042 TODO Convert file download controllers
19 MIG-050 TODO Create migration checklist template
20 MIG-051 TODO Create automated route inventory tool Optional
21 MIG-060 TODO Pilot migration: choose one WebService
22 MIG-061 TODO Execute pilot migration
23 MIG-062 TODO Document lessons learned
24 MIG-070 TODO Merge Router.sln into StellaOps.sln
25 MIG-071 TODO Update CI/CD for router components

Migration Strategies

Strategy A: In-Place Adaptation

Best for: Services that need to maintain HTTP compatibility during transition.

┌─────────────────────────────────────┐
│  StellaOps.Billing.WebService       │
│  ┌─────────────────────────────┐    │
│  │  Existing HTTP Controllers  │◄───┼──── HTTP clients (legacy)
│  └─────────────────────────────┘    │
│  ┌─────────────────────────────┐    │
│  │  [StellaEndpoint] Handlers  │◄───┼──── Router (new)
│  └─────────────────────────────┘    │
│  ┌─────────────────────────────┐    │
│  │  Shared Domain Logic        │    │
│  └─────────────────────────────┘    │
└─────────────────────────────────────┘

Steps:

  1. Add StellaOps.Microservice package reference
  2. Create handler classes for each route
  3. Handlers call existing service layer
  4. Register with router pool
  5. Test via router
  6. Shift traffic gradually
  7. Remove HTTP controllers when ready

Strategy B: Clean Split

Best for: Major refactoring or when HTTP compatibility not needed.

┌─────────────────────────────────────┐
│  StellaOps.Billing.Domain           │  ◄── Shared library
│  (extracted business logic)         │
└─────────────────────────────────────┘
          ▲                 ▲
          │                 │
┌─────────┴───────┐ ┌───────┴─────────┐
│ (Legacy)        │ │ (New)           │
│ Billing.Web     │ │ Billing.Micro   │
│ Service         │ │ service         │
│ HTTP only       │ │ Router only     │
└─────────────────┘ └─────────────────┘

Steps:

  1. Extract domain logic to .Domain library
  2. Create new .Microservice project
  3. Implement handlers using domain library
  4. Deploy alongside WebService
  5. Shift traffic to router
  6. Deprecate WebService

Controller to Handler Mapping

Before (ASP.NET Controller)

[ApiController]
[Route("api/invoices")]
public class InvoicesController : ControllerBase
{
    private readonly IInvoiceService _service;

    [HttpPost]
    [Authorize(Roles = "billing-admin")]
    public async Task<IActionResult> Create(
        [FromBody] CreateInvoiceRequest request,
        CancellationToken ct)  // <-- Often missing!
    {
        var invoice = await _service.CreateAsync(request);
        return Ok(new { invoice.Id });
    }
}

After (Microservice Handler)

[StellaEndpoint("POST", "/api/invoices")]
public sealed class CreateInvoiceEndpoint : IStellaEndpoint<CreateInvoiceRequest, CreateInvoiceResponse>
{
    private readonly IInvoiceService _service;

    public CreateInvoiceEndpoint(IInvoiceService service) => _service = service;

    public async Task<CreateInvoiceResponse> HandleAsync(
        CreateInvoiceRequest request,
        CancellationToken ct)  // <-- Required, propagated
    {
        var invoice = await _service.CreateAsync(request, ct);  // Pass token!
        return new CreateInvoiceResponse { InvoiceId = invoice.Id };
    }
}

CancellationToken Checklist

For each migrated handler, verify:

  • Handler accepts CancellationToken parameter
  • Token passed to all database calls
  • Token passed to all HTTP client calls
  • Token passed to all file I/O operations
  • Long-running loops check ct.IsCancellationRequested
  • Token passed to Task.Delay, WaitAsync, etc.

Streaming Migration

File Upload (Before)

[HttpPost("upload")]
public async Task<IActionResult> Upload(IFormFile file)
{
    using var stream = file.OpenReadStream();
    await _storage.SaveAsync(stream);
    return Ok();
}

File Upload (After)

[StellaEndpoint("POST", "/upload", SupportsStreaming = true)]
public sealed class UploadEndpoint : IRawStellaEndpoint
{
    public async Task<RawResponse> HandleAsync(RawRequestContext ctx, CancellationToken ct)
    {
        await _storage.SaveAsync(ctx.Body, ct);  // Body is already a stream
        return RawResponse.Ok();
    }
}

Migration Checklist Template

# Migration Checklist: [ServiceName]

## Inventory
- [ ] List all HTTP routes (Method + Path)
- [ ] Identify streaming endpoints
- [ ] Identify authorization requirements
- [ ] Document external dependencies

## Preparation
- [ ] Add StellaOps.Microservice package
- [ ] Configure router connection
- [ ] Set up local gateway for testing

## Per-Route Migration
For each route:
- [ ] Create [StellaEndpoint] handler class
- [ ] Map request/response types
- [ ] Wire CancellationToken throughout
- [ ] Convert to IRawStellaEndpoint if streaming
- [ ] Write unit tests
- [ ] Write integration tests

## Cutover
- [ ] Deploy alongside existing WebService
- [ ] Verify via router routing
- [ ] Shift percentage of traffic
- [ ] Monitor for errors
- [ ] Full cutover
- [ ] Remove WebService HTTP listeners

## Cleanup
- [ ] Remove unused controller code
- [ ] Remove HTTP pipeline configuration
- [ ] Update documentation

StellaOps Modules to Migrate

Module WebService Priority Complexity
Concelier StellaOps.Concelier.WebService High Medium
Scanner StellaOps.Scanner.WebService High High (streaming)
Authority StellaOps.Authority.WebService Medium Low
Orchestrator StellaOps.Orchestrator.WebService Medium Medium
Scheduler StellaOps.Scheduler.WebService Low Low
Notify StellaOps.Notify.WebService Low Low

Exit Criteria

Before marking this sprint DONE:

  1. Migration strategies documented
  2. Controller-to-handler mapping guide complete
  3. CancellationToken checklist complete
  4. Streaming migration guide complete
  5. Migration checklist template created
  6. Pilot migration executed successfully
  7. Router.sln merged into StellaOps.sln
  8. CI/CD updated

Execution Log

Date (UTC) Update Owner

Decisions & Risks

  • Pilot migration should be a low-risk service first
  • Strategy A preferred for gradual transition
  • Strategy B preferred for greenfield-like rewrites
  • CancellationToken wiring is the #1 source of migration bugs
  • Streaming endpoints require IRawStellaEndpoint, not typed handlers
  • Authorization migrates from [Authorize(Roles)] to RequiringClaims