Skip to content
bitzorcas
中EN

Concept

Industry-neutral surfaces

The ownership rules that keep Framework, generic Profiles, and Hosts vertical-free, the template adoption contract, and the AssignedLawyerId to AssignedOwnerId migration.

Last updated

A caller learning BitzOrcas’s generic interfaces should not first have to understand a vertical industry’s objects, regulations, roles, or historical database column names. Legal, Finance, HR, and Auction capabilities live in explicit opt-in modules or commercial packages; the Framework shared kernel, generic-Profile platform modules, and Host registration stay industry-neutral.

must not leak back

Generic consumer

Framework / generic Profile / Host

Industry-neutral contracts and runtime surfaces

Finance / HR / Auction / Legal

Explicit opt-in owner package

What must stay vertical-free

  • src/Framework/**
  • generic-Profile-default platform modules
  • src/Hosts/** registration/config/display text for generic composition
  • the Consumer Solution and src/Modules/Sandbox/** example code

Ownership rules

  1. Vertical capabilities (Legal/Finance/HR/Auction) go into an explicit opt-in module or commercial package — never the Framework shared kernel.
  2. A vertical module’s types, error codes, and enums are published by the owner package; the default Host does not register runtime enums/adapters for unselected packages.
  3. Generic module CLR names, persistence columns, config keys, error text, notification templates, and ops diagnostics use industry-neutral terms.
  4. Examples show only generic business actions plus direct dependencies; vertical examples live in the opt-in module’s own tests and docs.
  5. A historical physical column with industry semantics is migrated to a neutral column name with an explicit, idempotent, stop-on-conflict data migration — never relying on ORM auto-column-creation to force manual data movement.
  6. Rule dates, holidays, and dynamic standards belong to the calling interface; a pure-calc module must not implicitly read process current time or fake dynamic regulations as fixed defaults.

Current ownership

CapabilityOwnerDefault surface
General + loan interest calcIndustryExtensions.Financenot in Framework or generic Profile
Legal deadline + court case numberLegalCalculatorsnot in Framework or default Host enum catalog
Legal fees, statute of limitations, damagesLegalCalculatorsexplicit opt-in only
HR leave policy + date rulesIndustryExtensions.Hrpass effectiveFrom explicitly; does not read process date
Website contact lead ownerWebsite.AssignedOwnerIdCLR + physical column both neutral names

The AssignedLawyerId → AssignedOwnerId migration

WebsiteLead.AssignedLawyerId exists only as a legacy DB upgrade input. The migration script 20260716-website-owner-industry-neutral.sql refuses to continue if both old and new columns exist simultaneously, avoiding silently overwriting owner data.

Template adoption contract

The template exposes a single coupled preset parameter, ProfileChoice. The legal space is mini-api-single, default-business-{single|multi}-{none|finance|hr|auction|legal}, with a default of default-business-single-none. A mini+api+industry combination cannot be expressed by the public parameter; the old --IndustryExtension flag is unknown and fails before any disk write. Each industry preset adds exactly one root PackageReference to the Business Starter Application and generates an IndustryExtensionAdoptionTests.cs that calls the selected package’s public API directly. The four industry packages never enter the Profile.Mini.Api or Profile.Default.Business default closure.

Adopting an industry preset takes one command; invalid combinations are rejected before anything touches disk:

Terminal window
# Generate a multi-tenant business Host with the legal preset; the template validates
# ProfileChoice before writing any file.
dotnet new bitzorcas-host --ProfileChoice default-business-multi-legal --output LegalHost

The generated solution carries IndustryExtensionAdoptionTests.cs, which calls the legal package’s public API directly — turning “the vertical package is really consumed” into a testable fact instead of a review promise. Full-chain verification of template output is handled by the framework repository’s scripts/build/verify-template.sh (install template → generate per ProfileChoice combination → cold-cache restore/build/test).

The three unselected industry packages never appear in generated project references — neutrality is proven by an empty closure, not asserted by comments.

Source evidence boundary

Fact to proveOwner evidence to inspect
Framework has no vertical typesnamespaces, public API, and dependency graph under src/Framework
Default Hosts do not adopt a vertical implicitlyHost references, composition, and generated Profile closure
Vertical capability ships from its ownerIndustryExtensions, LegalCalculators, and connector contracts
Website ownership is neutralAssignedOwnerId aggregate, metadata, and both ORM migrations
Legacy-column upgrade preserves datastop-on-conflict, copy, rerun, and migration-catalog tests
Template cannot express an invalid Profiletemplate parameter schema, clean-cache creation, and AdoptionTests

Keyword scans alone cannot prove neutrality. A generically named interface that returns a legal-industry DTO, or a default Profile that receives a vertical through a transitive package, still violates the boundary. Review public API, package closure, generated templates, and runtime registration together.

Change-review questions

  • Is the new type a generic platform fact, or meaningful only inside one industry?
  • Do its name, errors, configuration, columns, and diagnostics use the same neutral vocabulary?
  • Are time, jurisdiction rules, and policy versions explicit inputs?
  • Can the default Host, Mini Profile, and Consumer Solution still build without a vertical package?
  • Does the optional package integrate only through contracts, options, policies, store ports, or events?
  • Is migration behavior deterministic when both columns exist, the old column is absent, or the script reruns?
  • Does an industry preset add one root package and call its public API from an isolated consumer test?
  • After removing the package, are there no residual registrations, enums, or required settings?

Review commands

Terminal window
# Neutral migration, template preset, and explicit-adoption evidence.
rg -n "AssignedLawyerId|AssignedOwnerId|ProfileChoice|IndustryExtensionAdoptionTests" \
src scripts tests -g '*.cs' -g '*.json' -g '*.sql'
# Default project closures must not acquire the four vertical roots accidentally.
rg -n "IndustryExtensions|LegalCalculators" \
src/Tooling/BitzOrcas.Modern.Templates -g '*.csproj' -g '*.json'

See also

100%

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