Skip to content
bitzorcas
中EN

Concept

License Management

Owns the runtime-license control plane: request, four-eyes review, durable asynchronous signing, download, and revocation.

Last updated

Owns the runtime-license control plane: request, four-eyes review, durable asynchronous signing, download, and revocation.

Primary path at a glance

Create immutable request

Different operator approves

Queue idempotent signing operation

Worker leases and calls remote signer

Verify and publish signed envelope

The coral node marks the module’s central decision or state boundary.

Capability boundary

  • Immutable license request facts and review state
  • Four-eyes approval and control-plane tenant boundary
  • Durable signing/revocation operations and signed-envelope download

The module explicitly does not own the following: LicenseManagement issues signed envelopes; runtime enforcement belongs to the licensing pipeline and product composition. Private keys stay in LicenseSigner, KMS, or HSM and must never enter this module’s database or API process.

Code map

ProjectPrimary responsibility
BitzOrcas.Platform.LicenseManagement.ContractsPublic contracts, ports, DTOs, and events
BitzOrcas.Platform.LicenseManagement.ApplicationCommands, queries, handlers, and application policy
BitzOrcas.Platform.LicenseManagement.InfrastructurePersistence, connectors, and framework adapters

Source location: src/Platform/LicenseManagement

Core use cases

  • CreateRuntimeLicenseCommand
  • ApproveRuntimeLicenseCommand
  • RejectRuntimeLicenseCommand
  • IssueRuntimeLicenseCommand
  • RevokeRuntimeLicenseCommand
  • DownloadRuntimeLicenseQuery
  • GetLicenseSignerReadinessQuery

When reading a use case, start with its request contract and permission declaration, follow how the handler coordinates an aggregate or port, then inspect post-commit events, cache changes, and audit.

Key models and contracts

Key typeWhat to inspect
RuntimeLicenseIssuanceControl-plane aggregate
IRuntimeLicenseIssuanceCommandStoreAtomic command and lease port
ILicenseEnvelopeSignerRemote signing boundary
ILicenseManagementControlPlaneTenantPolicyDedicated tenant guard

Use-case boundary example

FieldValue
Representative contractIssueRuntimeLicenseCommand
ResultResult<RuntimeLicenseIssuanceDto>
Review focusAdjudicate the control-plane tenant first, then freeze the issuance request into a persistent queue by idempotency key; never sign inline in the HTTP request.

Pseudocode

IssueRuntimeLicenseCommand pseudocode
// ① A missing idempotency key is rejected; RequireActor adjudicates IsTrustedTenant inside.
if (string.IsNullOrWhiteSpace(command.IdempotencyKey)
|| command.IdempotencyKey.Length > 128)
return LicenseManagementErrors.IdempotencyKeyRequired;
var actor = LicenseManagementApplicationSupport.RequireActor(currentUser, tenantPolicy);
if (actor.IsFailure) return Result<RuntimeLicenseIssuanceDto>.Failure(actor.Error);
// ② An already-Issued aggregate reads back from the read model, so repeats are idempotent.
var found = await store.FindAsync(command.LicenseId, cancellationToken);
if (found.IsFailure) return Result<RuntimeLicenseIssuanceDto>.Failure(found.Error);
var issuance = found.GetValueOrThrow();
if (issuance.Status == RuntimeLicenseIssuanceStatus.Issued)
return await readModels.GetAsync(issuance.LicenseId, cancellationToken);
// ③ QueueIssuance freezes the first request into a persistent queue; repeats get false.
var queued = issuance.QueueIssuance(
actor.GetValueOrThrow(), clock.UtcNow, command.IdempotencyKey);
if (queued.IsFailure) return Result<RuntimeLicenseIssuanceDto>.Failure(queued.Error);
if (!queued.GetValueOrThrow())
return await readModels.GetAsync(issuance.LicenseId, cancellationToken);
// ④ SaveAsync persists the aggregate and its embedded signing operation together.
await store.SaveAsync(issuance, cancellationToken);
return await readModels.GetAsync(issuance.LicenseId, cancellationToken);

Integration relationships

The API queues signing work; RuntimeLicenseSigningWorker claims bounded leases and calls ILicenseEnvelopeSigner. The remote result is accepted only when its payload is unchanged and its signature verifies against the configured public key.

See license issuance for the full control-plane state machine, LicenseSigner network boundary, key custody, and failure drills. Runtime verification and degradation policy are covered by runtime licensing.

Cross-module collaboration follows these directions:

  • Callers depend on this module’s public Contracts or a narrow port.
  • State changes propagate through versioned integration events.
  • Database, messaging, cache, file, and vendor SDK details stay in Infrastructure.
  • The composition root registers fail-closed defaults before production adapters.

Security, tenancy, and privacy

Every operation must pass LicenseManagement:ControlPlane:TenantId before touching a store. The requester cannot approve the same request, routes use operation-specific permissions, downloads expose only signed envelopes and SHA-256, and signer failure closes the path.

Every tenant-scoped write persists TenantId, and list/detail paths share one authorization boundary. Logs, events, and audit retain only the minimum fields needed for diagnosis.

Failure semantics, idempotency, and observability

Issue and revoke use durable operations with idempotency keys, leases, bounded retries, and terminal failure. Worker completion validates that the aggregate and operation still match before committing the envelope.

SituationRequired behavior
Validation, not found, conflict, or forbiddenReturn typed Result/Error data and let the shared mapper produce Problem Details
Adapter or critical state unavailableFail closed for security/high-value work; mark read-only degradation explicitly
Duplicate request or eventUse a stable idempotency key with a database uniqueness constraint as the final guard
External timeoutPropagate cancellation, record redacted diagnostics, and retry only safe operations with bounds

Test matrix

#Required scenarioSuggested level
1control-plane tenant mismatch before store accessunit + integration
2requester cannot self-approveintegration/contract
3signer payload mutation or invalid signatureintegration/contract
4lease expiry, retry, idempotency, and terminal failureintegration/contract

Keep one universal red line under test: no identifier, cache key, event, or query condition from tenant A may let tenant B read or mutate data.

Source navigation and change checks

Run from the BitzOrcasVNext repository root:

Terminal window
# List public types and confirm that new contracts belong to the module boundary.
rg -n "^public (sealed |abstract |static |partial )*(record|class|interface|enum)" src/Platform/LicenseManagement -g '*.cs'
# Inspect cross-layer references; callers must not depend on another module's Infrastructure.
rg -n "ProjectReference|PackageReference" src/Platform/LicenseManagement -g '*.csproj'
# Find unfinished or elided implementation; expect no matches.
rg -n "TODO|FIXME|// \.\.\." src/Platform/LicenseManagement -g '*.cs'

Extension and release checklist

  1. Is the new capability expressed through explicit Contracts, permissions, and a feature key?
  2. Can persistence, connectors, and providers be replaced through narrow adapters?
  3. Does production still resolve a Null/Unavailable default, and could health checks report a false green?
  4. Is there evidence for transaction, event, cache-invalidation, audit, and background-job failure/retry behavior?
  5. Did bilingual docs, diagrams, contract tests, and runbooks change with the code?

Back to module catalog · Module dependency diagram · Add a module guide

100%

Scroll or use controls to zoom · drag when enlarged · double-click for 100% / 200%