.NET / SQL / Enterprise Engineering
Modular Installation and Update Architecture for LocalEndpoints, RemoteEndpoints, and MemoryEndpoints
Report summary
Under the stated assumption that hosting model, scale, and operating system are not fixed in advance, the strongest design is a modular suite with independently deployable components and a hybrid distribution model : ship three separately versioned installable components (LocalEndpoints, RemoteEndpo
Key topics
- .NET / SQL / Enterprise Engineering
- .NET
- SQL
- Enterprise Engineering
- AI
- LocalEndpoint
- Runtime
- NuGet
- Semantic Systems
Research provenance
For citation, use the report title and canonical URL. Archival presence does not establish authorship or promote report statements into portfolio evidence.
Source availability: 48 citation markers in the source export have no recoverable source links. Those markers are omitted from this reader; any supplied bibliography and ordinary links remain. Check the original sources before relying on the cited claims.
This page renders the archived Markdown as safe, formatted HTML. It is background research and does not become a portfolio claim without evidence review.
Full report
On this page
Executive summary
Under the stated assumption that hosting model, scale, and operating system are not fixed in advance, the strongest design is a modular suite with independently deployable components and a hybrid distribution model: ship three separately versioned installable components (LocalEndpoints, RemoteEndpoints, MemoryEndpoints) while also offering a single Windows bootstrapper that can install any selected subset intentionally. For cloud and cross-platform deployments, publish each component as its own container image and treat the deployment manifest as the “installer” equivalent. This preserves the requirement that RemoteEndpoints and MemoryEndpoints remain deliberate, separate installs, while still giving administrators a convenient one-entry setup workflow. Microsoft’s installer and deployment stack supports this split well: Windows Installer provides transactional install/rollback and patching, WiX Burn can chain prerequisites and multiple packages, MSIX provides reliable install/update semantics but has service-specific Windows and privilege constraints, and ClickOnce is positioned primarily for Windows client applications rather than server-side web services.
For authentication, the cleanest boundary is: LocalEndpoints works standalone; RemoteEndpoints adds account and remote-access features only after explicit pairing and configuration; MemoryEndpoints is an optional external-memory connector/service exposed only through a bounded connector API. For user-facing web sign-in, ASP.NET Core guidance favors OpenID Connect code flow with PKCE for confidential web clients. For service-to-service calls, use JWT bearer access tokens and, for higher-assurance paths, mutual TLS. If LocalEndpoints.com and RemoteEndpoints.com are truly separate domains, prefer federation via OIDC instead of trying to share auth cookies. Cookie sharing in ASP.NET Core requires a shared cookie name, consistent scheme, shared data-protection key ring, and common application configuration, which is better suited to tightly related app estates than to intentionally separate product installations.
For updates, the recommended default is pull-based updates driven by a signed suite manifest for Windows-hosted services and registry/orchestrator-driven rolling updates for containers. Built-in update stacks such as MSIX App Installer and ClickOnce prove the value of pull-style update checks, prompts, mandatory updates, background checks, and downgrade/rollback controls, but for server-side services a signed compatibility manifest gives better control over cross-component compatibility, maintenance windows, staged installs, and rollback approval. For containers, prefer immutable images with unique tags or digests and let the platform perform rolling rollout and rollback.
The practical recommendation is therefore:
- Windows on-prem / single-node / edge: separate MSIs per component plus a WiX Burn bootstrapper EXE for unified selection; host each service as Kestrel + Windows Service by default, or under IIS when the customer standardizes on IIS operations.
- Cloud / multi-node / cross-platform: independent OCI containers per component with rolling deployment and health probes.
- Do not use ClickOnce for the services themselves.
- Use MSIX selectively for admin desktop tools or tightly controlled Windows-only service scenarios, not as the primary distribution mechanism for the entire suite.
Assumptions and decision criteria
This report assumes all three products are ASP.NET Core web services written in C#, with no hard constraint on Windows-only or Linux-only operation. Because the user explicitly asked about MSI, MSIX, ClickOnce, Windows Service, and containers, the design treats Windows server deployment as first-class, but not exclusive. It also assumes that existing deployments may be a mix of IIS-hosted, Windows Service-hosted, or early self-hosted/Kestrel setups. These are assumptions made for architectural completeness, not sourced facts about the products themselves.
The decision criteria that matter most are straightforward. The suite must preserve intentional separateness between local-only behavior and remote/account behavior. It must support silent enterprise installation, signed updates, and cross-component compatibility checks. It should also work cleanly in both single-machine customer installs and container/orchestrated environments. Those criteria align well with Microsoft’s hosting and deployment guidance: ASP.NET Core uses Kestrel as the default recommended server and can run under a process manager, as a Windows Service, or behind IIS; IIS remains a secure and manageable hosting option on Windows; and containerized ASP.NET Core is a first-class supported deployment path.
A second decision criterion is version governance. Shared libraries and contracts should be distributed through NuGet with SemVer, ideally with central package management, package source mapping, lock files, and signed packages to reduce supply-chain risk and version drift. That combination gives you reproducibility in CI/CD and tighter control over which internal or public feed a package can come from.
Recommended reference architecture
The architecture should revolve around three bounded services plus shared contracts and operational infrastructure. LocalEndpoints is the anchor product and must remain fully useful on its own. RemoteEndpoints is a separately installed companion that introduces account, identity, and remote-access capabilities. MemoryEndpoints is an optional third install or external service, reachable only through a connector boundary. Shared code should live in a small set of signed NuGet packages: contracts, auth primitives, discovery/health abstractions, configuration types, and update-manifest types.
flowchart LR
subgraph Suite["Endpoint Suite"]
LE["LocalEndpoints\nStandalone local web service"]
RE["RemoteEndpoints\nOptional remote/account service"]
ME["MemoryEndpoints\nOptional memory service / connector"]
end
subgraph Shared["Shared operational services"]
IDP["OIDC/OAuth IdP"]
FEED["Private NuGet feed"]
UPD["Signed release manifest + artifact store"]
end
LE --> FEED
RE --> FEED
ME --> FEED
LE -. explicit admin pairing .-> RE
LE -. optional connector .-> ME
RE -. optional connector .-> ME
RE --> IDP
LE -. service auth .-> IDP
ME -. optional service auth .-> IDP
LE --> UPD
RE --> UPD
ME --> UPD
This boundary model intentionally prevents RemoteEndpoints from being treated as just a feature flag buried inside LocalEndpoints. It is a separately deployable service with a distinct lifecycle, while still interoperating through contracts, version metadata, health endpoints, and a pairing handshake.
The runtime API shape should be explicit. Every component should expose a small, stable operational surface such as:
/.well-known/component-info/.well-known/capabilities/health/live/health/ready/health/startup/api/interop/...
ASP.NET Core health checks are built for dependency-aware readiness/liveness style probes, and .NET Aspire service discovery shows the general model for resolving services by name rather than hardcoded URLs when a service-discovery environment is available.
flowchart LR
Admin["Administrator / Installer"] -->|"select components"| Setup["Bootstrapper or deployment manifest"]
Setup --> LE["LocalEndpoints"]
Setup --> RE["RemoteEndpoints"]
Setup --> ME["MemoryEndpoints"]
LE <-->|HTTPS REST/gRPC\ncapabilities, pairing, remote ops| RE
LE <-->|HTTPS REST\nmemory read/write connector| ME
RE <-->|HTTPS REST\nmemory enrichment / retrieval| ME
LE --> INFO1["/.well-known/component-info"]
RE --> INFO2["/.well-known/component-info"]
ME --> INFO3["/.well-known/component-info"]
LE --> H1["/health/live /ready"]
RE --> H2["/health/live /ready"]
ME --> H3["/health/live /ready"]
A key architectural recommendation is to introduce a suite compatibility contract that is independent of product version strings. Each component should publish its own version and also:
- supported interop contract versions
- minimum/maximum compatible peer versions
- required schema generation
- required authentication modes
- optional feature flags
That pattern lets LocalEndpoints 4.2.x interoperate with a range of RemoteEndpoints versions, instead of forcing lockstep deployment. This is an architectural inference, but it follows the same compatibility discipline Microsoft recommends for .NET API versioning and breaking-change evaluation: don’t make silent breaking changes without explicit contract management.
The authentication boundary should also be explicit.
sequenceDiagram
participant User
participant Browser
participant RE as RemoteEndpoints
participant IdP as OIDC/OAuth IdP
participant LE as LocalEndpoints
participant ME as MemoryEndpoints
User->>Browser: Open remote UI
Browser->>RE: Request protected page
RE->>IdP: OIDC challenge (code flow + PKCE)
IdP-->>Browser: Sign-in and consent
Browser->>RE: Auth code
RE->>IdP: Redeem code
IdP-->>RE: ID token + access token
RE-->>Browser: App session cookie
LE->>IdP: Client credentials / service token request
IdP-->>LE: JWT access token
LE->>RE: API call with JWT (+ optional mTLS)
RE-->>LE: Response
LE->>ME: Scoped API call with connector credential
RE->>ME: Scoped API call with connector credential
ASP.NET Core’s current guidance recommends OIDC confidential clients with code flow and PKCE for web UI authentication. JWT bearer access tokens are for APIs, and Microsoft explicitly notes that ID tokens should never be used to access APIs. ASP.NET Core also supports certificate authentication for scenarios that need mTLS. If the suite ever needs shared cookies during an incremental migration inside one broader app estate, ASP.NET Core requires a shared cookie name, authentication scheme, common app name, and shared data-protection key ring; but for intentionally separate domains such as LocalEndpoints.com and RemoteEndpoints.com, federated OIDC is the cleaner pattern.
Installer and packaging strategy
The best Windows packaging strategy is independent MSI packages per component with an optional WiX Burn bootstrapper as the suite entry point. That gives you a single downloadable setup for administrators who want simplicity, while preserving fully separate installable units behind the scenes. Burn’s purpose is precisely to chain packages, prerequisites, and bootstrapper UX into one bundle. Windows Installer provides transactional install behavior, rollback, patching, service/resource configuration, and standard enterprise deployment semantics. Standard msiexec options also make unattended and silent deployment straightforward.
ClickOnce should not be the primary delivery vehicle for the services. Microsoft documents ClickOnce as a deployment technology for Windows-based applications and its current guidance is centered on Windows desktop applications such as Windows Forms and WPF. It can self-update and even support required updates and rollback, but it is not a strong fit for long-running server-side web services that need service registration, IIS setup, runtime dependencies, or unattended server provisioning. It remains useful only if the suite later adds a desktop admin console.
MSIX is more nuanced. It offers clean install/uninstall and strong update behavior, and Microsoft supports packages that include services starting with Windows 10 version 2004, but those service-inclusive packages require administrator privileges to install. MSIX App Installer can check on launch or in the background, prompt or update silently, and even allow downgrades via ForceUpdateFromAnyVersion. Those are attractive properties, but the service-packaging constraints and Windows-version dependency make MSIX a selective choice rather than the default suite packaging model for server roles. It is strongest for tightly controlled Windows environments or for companion desktop/admin tools.
For service hosting, prefer Kestrel as the application server. On Windows single-node or appliance-style installs, run each component as a Windows Service. On IIS-standardized customer estates, use one IIS site or app per component and one app pool per app, because ASP.NET Core in-process hosting does not support sharing an app pool among apps. For cross-platform or higher-scale environments, publish container images and avoid installer-centric thinking entirely.
The publish mode should vary by environment. Framework-dependent deployments are smaller, but require the appropriate runtime on the host. Self-contained deployments bundle the .NET runtime and simplify prerequisites, which is often worth the size increase for edge or disconnected installs. IIS-hosted framework-dependent deployments require the .NET Hosting Bundle, which installs the runtime and ASP.NET Core Module.
| Option | Best fit | Pros | Cons | Relative implementation and ops cost | Recommendation | Evidence |
|---|---|---|---|---|---|---|
| Separate MSIs per component + unified Burn bootstrapper | Windows on-prem, managed enterprise installs | Modular by design; good silent install story; prerequisites can be chained; MSI transactions and rollback; compatible with Windows Service/IIS hosting | Windows-only packaging path; more packaging work than raw file-copy | Medium | Recommended default for Windows | WiX Burn bundles can chain packages and prerequisites, and Windows Installer supports transactional install, rollback, and patching. |
| Separate MSIs only | Highly controlled enterprise automation | Clear separateness; easiest to reason about CI/CD; works well with RMM/enterprise software deployment | Less friendly first-run UX; admins must know component relationships | Low to Medium | Recommended if customers already use endpoint-management tooling | Windows Installer is the standard Windows install/configuration service and supports patches, rollback, services, and silent operation. |
| MSIX + App Installer | Controlled Windows-only estates, companion tools, some service scenarios | Clean install/uninstall; strong built-in update semantics; background or on-launch checks; signed package model | Service hosting support starts at Windows 10 2004; service packages require admin install; less natural for server-role provisioning | Medium | Use selectively, not as suite default | MSIX gives reliable installs and updates; App Installer supports background and on-launch checks; MSIX service packages have OS/admin constraints. |
| ClickOnce | Desktop admin companion only | Very easy self-updating client deployment | Officially oriented to Windows desktop/client scenarios; weak fit for web-service/server installation | Low | Not recommended for the services | Microsoft frames ClickOnce around Windows desktop application deployment and self-updating Windows apps. |
| Containers | Cloud, Linux, Kubernetes, scale-out, immutable infra | Environment parity; good isolation; rolling updates and rollback via orchestrator; cross-platform | Requires container runtime/orchestrator maturity; not ideal for all single-machine Windows customers | Medium to High | Recommended default for cloud / multi-node | ASP.NET Core container deployment is first-class, and Kubernetes Deployments provide rolling update and rollback workflows. |
A subtle but important UX point: the bootstrapper must make RemoteEndpoints and MemoryEndpoints opt-in, never implied. The default selection should install Local only. Choosing Remote should require an explicit explanation such as “enables account sign-in, remote access, and external connectivity,” and it should remain disabled until a second pairing step succeeds. Choosing Memory should likewise require an explicit explanation that it introduces external memory or connector behavior. Nothing in LocalEndpoints should automatically download or activate the other components.
That intent should be visible both at install time and at runtime. The Local admin UI should show “Remote features unavailable until RemoteEndpoints is installed and paired” rather than a mysterious broken setting. The Local service should refuse auto-discovery-based enablement unless an admin has flipped a signed or persisted opt-in state.
Update architecture and release management
For Windows-hosted services, build around a signed suite release manifest rather than a purely file-centric updater. Each release manifest should declare component versions, package URLs, hashes, digital signatures, compatible peer ranges, required schema versions, minimum OS/runtime prerequisites, rollout channel, and rollback targets. The updater on each node should pull the manifest, verify signature and hash, compare compatibility, stage the artifact, stop or drain the service, install the update, run post-update health checks, and either commit or roll back. This pattern is a deliberate generalization of what Microsoft already exposes in App Installer and ClickOnce: update checks, optional prompts, required updates, background checks, and controlled rollback.
flowchart LR
CI["CI/CD pipeline"] --> Build["Build + test + pack"]
Build --> Sign["Sign MSI/MSIX/EXE/NuGet artifacts"]
Sign --> Publish["Publish signed artifacts + suite manifest"]
Publish --> Agent1["LocalEndpoints update agent"]
Publish --> Agent2["RemoteEndpoints update agent"]
Publish --> Agent3["MemoryEndpoints update agent"]
Agent1 --> Verify1["Verify signature/hash\nand compatibility"]
Agent2 --> Verify2["Verify signature/hash\nand compatibility"]
Agent3 --> Verify3["Verify signature/hash\nand compatibility"]
Verify1 --> Deploy1["Stage, stop/drain, install, restart"]
Verify2 --> Deploy2["Stage, stop/drain, install, restart"]
Verify3 --> Deploy3["Stage, stop/drain, install, restart"]
Deploy1 --> Health1["Health / ready checks"]
Deploy2 --> Health2["Health / ready checks"]
Deploy3 --> Health3["Health / ready checks"]
Health1 -->|"pass"| Commit["Commit release state"]
Health2 -->|"pass"| Commit
Health3 -->|"pass"| Commit
Health1 -->|"fail"| Rollback["Rollback to previous version"]
Health2 -->|"fail"| Rollback
Health3 -->|"fail"| Rollback
Delta behavior depends on the distribution mode. MSI patches (.msp) can carry only changed file bits and Windows Installer supports transactional multi-package patching and rollback. MSIX uses a block map (AppxBlockMap.xml) with per-block hashes, which is the basis for efficient update behavior. Containers do not do “delta patching” the same way, but they capitalize on layer reuse and immutable image distribution.
A pull model is the right default for customer-controlled, sometimes disconnected installs, because the node can decide whether it is in a maintenance window, whether peers are compatible, and whether it is allowed to upgrade. A push model is still valuable in managed environments, but it should usually push policy and enrollment rather than raw executables. Containers are the clearest push-like deployment model: CI pushes a new image to the registry, and the orchestrator performs rolling rollout. MSIX App Installer is also fundamentally pull-oriented and can check either in the background or on launch, using fallback update URIs if the primary update source is unavailable.
Signing is non-negotiable. Windows installers and MSIX packages should be signed and time-stamped with SignTool. Internal NuGet packages should be signed as well. If the organization is Azure-centric and comfortable with preview services, Microsoft’s Artifact Signing service can integrate with SignTool, GitHub Actions, Azure DevOps tasks, and PowerShell; because it is in public preview, treat it as optional until it fits your risk posture.
The release-management model should be independent component SemVer plus a suite release manifest. In practice that means:
LocalEndpoints,RemoteEndpoints,MemoryEndpointseach have their own SemVer.- shared contracts and infrastructure packages also have SemVer.
- the “suite” has a release identifier that maps a tested combination.
- compatibility is enforced by contract version ranges, not just by string-equal product versions.
NuGet’s SemVer support and .NET library versioning guidance align well with this model.
| Update strategy | Strengths | Weaknesses | Relative implementation and ops cost | Recommended use | Evidence |
|---|---|---|---|---|---|
| MSIX App Installer pull updates | Built-in launch/background checks, prompt or silent modes, fallback UpdateURI, optional downgrade control | Windows-only; less ideal for multi-service orchestration; service packaging constraints still apply | Low to Medium | Good for companion tools or tightly controlled Windows-only deployments | App Installer supports on-launch and background checks, prompts, update blocking, fallback URIs, and downgrade support. |
| Custom signed suite manifest + MSI/Burn | Best compatibility control across multiple components; can enforce maintenance windows and peer-version checks; works well for server installs | More engineering than using only platform-native app updaters | Medium | Recommended for Windows-hosted services | Supports MSI transactions, rollback, patches, and silent install, while adding component-aware compatibility logic as an architectural layer. |
| Container image rollout via registry/orchestrator | Immutable artifacts, health-gated rollout, native rollback, scale-friendly | Requires container maturity; not ideal for every customer edge install | Medium | Recommended for cloud and multi-node | Kubernetes Deployments support rolling updates and rollback; registry image versioning benefits from unique tags/digests. |
| ClickOnce self-update | Simple update story for desktop apps, supports required updates and rollback | Not an appropriate primary strategy for server-side services | Low | Only for a future admin desktop app | ClickOnce supports self-updating Windows apps and rollback, but Microsoft positions it around Windows client applications. |
Deployment, configuration, discovery, and security
Deployment should be environment-shaped, not installer-shaped. On a small Windows customer machine, the cleanest setup is usually Kestrel hosted as a Windows Service per component, optionally fronted by a Windows reverse proxy if needed. In Windows server estates that already standardize on IIS operationally, use IIS for the public edge and isolate each component into its own site/app and app pool. For cloud or high-scale environments, package each service into its own container and let the platform manage rollout and recovery. Azure App Service deployment slots and Kubernetes rolling updates both provide controlled rollout surfaces; Kubernetes also supports rollback to previous revisions.
Configuration management should follow ASP.NET Core’s configuration system with strongly typed options, startup validation, and separation of secret from non-secret settings. In practical terms, keep defaults and non-sensitive settings in appsettings.json; use environment-specific providers for environment overrides; inject secrets from a controlled secret store; and validate options at startup so a bad remote URL, invalid thumbprint, or missing signing key fails fast. Microsoft’s guidance explicitly recommends the options pattern for grouped settings, and warns that the development Secret Manager is not an encrypted trusted store and is for development only. For production secrets in Azure-hosted environments, use Azure Key Vault; in Kubernetes, use the platform Secret store; on Windows on-prem, use an appropriate enterprise secret mechanism and protected service accounts.
A clean configuration taxonomy for this suite would be:
HostingOptionsServiceIdentityOptionsPeerDiscoveryOptionsPairingOptionsUpdateOptionsMemoryConnectorOptionsFeaturePolicyOptions
That structure is not from the docs directly; it is the recommended way to apply the options pattern cleanly to your bounded modules. The point is to keep local-only, remote-only, and memory-only configuration isolated so that installing one component never accidentally “lights up” another.
Runtime discovery should degrade gracefully. In the simplest deployments, use explicit configured peer URLs and certificate thumbprints. In orchestrated environments, rely on service discovery and DNS. The .NET Aspire service-discovery model shows the right shape: consumers reference services by name, not hardcoded host:port strings. Every component should also provide machine-readable health data so orchestrators and installers can distinguish “installed,” “started,” “dependency missing,” and “paired but degraded.” ASP.NET Core health checks and gRPC health checks are designed for that purpose.
Security should treat this as both an application problem and a supply-chain problem. Use OIDC for user sign-in, JWT bearer tokens for APIs, and policy-based authorization for feature-level access control. For high-trust component calls, add mTLS so the transport authenticates the caller’s certificate in addition to the bearer token. Store secrets outside source control, and prefer least-privilege service identities. On Windows, managed or virtual service accounts can reduce password-management burden; in containers, run as a non-root user wherever possible. Microsoft’s current .NET container images include a non-root app user and default to that in several image variants.
For ASP.NET Core cookie and token protection, do not neglect data-protection key management. If multiple instances of one authenticated web app need to scale out, they need a shared data-protection key store. Microsoft documents persistent key storage options, including file system, Azure Blob Storage, and EF Core-backed storage, and describes protecting keys with Azure Key Vault. In IIS, each app pool can have its own protected key material, and in web-farm scenarios keys must be shared intentionally.
The supply-chain side matters just as much. Use private NuGet feeds, signed NuGet packages, package source mapping, and lock files. This reduces the chance of restoring the wrong package from the wrong feed and improves repeatability. For containers, publish SBOMs and signed images where your registry/tooling supports it.
Testing, migration, and implementation roadmap
The testing strategy must go beyond normal unit testing because the center of risk is interop, upgrade, and rollback. ASP.NET Core’s integration-testing guidance is directly relevant here: stand up realistic test hosts with WebApplicationFactory or equivalent, and validate that multiple components work together. For this suite, test matrices should include Local alone, Local + Remote, Local + Memory, Remote + Memory, and the full three-way combination across supported version ranges.
Upgrade testing should be treated as a release gate. Maintain fixtures for at least:
- previous two production versions of each component
- the oldest still-supported suite combination
- interrupted-install scenarios
- rollback scenarios
- schema-forward and schema-backward compatibility windows
For database changes, prefer expand-and-contract migrations operationally, and deliver migrations as explicit artifacts. EF Core migration bundles are useful because they produce a single executable artifact to apply migrations, which is a better operational model than “the app migrates itself on startup” for customer-managed production environments.
Backward-compatibility review should be formalized. The .NET team’s compatibility rules and breaking-change documentation offer the right mental model: treat behavioral and source/binary breaks as deliberate decisions that must be reviewed, not accidental fallout. Every PR that changes the Local–Remote or Remote–Memory contract should update the compatibility manifest and the interop test matrix.
The migration plan for existing deployments should be incremental, not “big bang.” A sound sequence is:
- Inventory existing installs: hosting mode, runtime version, app identity, authentication mode, config sources, data-protection key storage, and any remote or memory-like behavior already embedded.
- Introduce common operational endpoints into the current services first:
component-info,capabilities, and health endpoints. - Extract shared contracts and infrastructure into signed NuGet packages in a private feed.
- Ship LocalEndpoints first with the new modular boundaries but keep remote/memory features disabled by policy.
- Add RemoteEndpoints as a truly separate package with a one-time pairing flow and compatibility handshake.
- Add MemoryEndpoints last as an external connector boundary or separate service.
- Move deployments to health-gated rollout: deployment slots on App Service, staged IIS rollout, or Kubernetes rolling Deployment, depending on environment.
- Preserve rollback artifacts for every release: previous MSI/MSIX/image, previous manifest, previous migration bundle, previous config schema.
The most actionable implementation plan is therefore:
- Define the interop contract first. Create shared NuGet packages for component metadata, capability negotiation, health payload contracts, pairing requests, and update manifests. Version those packages with SemVer and publish them from CI to a private feed.
- Create one host per component. Standardize each service on Kestrel, with Windows Service hosting for edge/on-prem defaults and container images for cloud. Keep IIS as an optional hosting profile, not the only profile.
- Build Windows packaging as three MSIs plus one Burn bootstrapper. Make component selection explicit and default to Local-only. Support silent install through
msiexecand bundle prerequisites when needed. - Use self-contained publish for edge/offline installs and framework-dependent publish for standardized server estates. Require the Hosting Bundle only for IIS-hosted framework-dependent deployments.
- Implement OIDC for UI, JWT for APIs, and optional mTLS for high-trust service paths. Avoid cross-domain shared-cookie dependence between Local and Remote unless you intentionally collapse them into one app estate.
- Introduce a signed suite release manifest. Gate updates on signature verification, compatibility checks, and post-install readiness checks. Sign Windows artifacts with SignTool and sign internal NuGet packages.
- Add environment-aware config and secret handling. Use options validation, external secret stores, least-privilege service identities, and shared data-protection keys only where multi-instance auth requires them.
- Set up CI/CD as a release train with rings. Build, test, pack, sign, publish NuGet packages, publish installers/images, generate the suite manifest, deploy to internal ring, then pilot ring, then broad release. GitHub Actions and Azure Pipelines both support .NET, package publishing, and signing integrations.
- Make upgrade and rollback a first-class test area. Use integration tests, multi-version interop tests, migration-bundle tests, and release-candidate replay from prior production versions.
- Document intentional enablement in the UI. Remote and Memory should remain visibly separate operational capabilities, not surprising side effects of a Local update.
In short: separate components, coordinated release metadata, platform-native delivery mechanisms, explicit pairing, signed artifacts, and health-gated updates is the architecture that best satisfies the modularity and interoperability requirements without sacrificing operational rigor.