Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .github/workflows/nuget-publish.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
name: NuGet Publish

on:
push:
tags: [ 'v*' ]
workflow_dispatch:

permissions:
contents: read
packages: write

env:
DOTNET_VERSION: '10.0.x'
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_NOLOGO: true

jobs:
publish:
name: Pack & publish SCDMS.Aspire.Hosting
runs-on: ubuntu-latest
timeout-minutes: 20

steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: Setup .NET 10
uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6
with:
dotnet-version: ${{ env.DOTNET_VERSION }}

- name: Compute version from git tag
shell: pwsh
id: version
run: |
$version = if ("${{ github.ref_type }}" -eq 'tag') { "${{ github.ref_name }}".TrimStart('v') } else { "1.0.0.0" }
Write-Host "Version: $version"
"value=$version" >> $env:GITHUB_OUTPUT

- name: Pack SCDMS.Aspire.Hosting
run: >
dotnet pack src/SCDMS.Aspire.Hosting/SCDMS.Aspire.Hosting.csproj
--configuration Release
--output ./artifacts
--configfile NuGet.Config
/p:ContinuousIntegrationBuild=true
/p:Version=${{ steps.version.outputs.value }}
/p:PackageReleaseNotes="SCDMS.Aspire.Hosting ${{ steps.version.outputs.value }} - see https://github.com/MPCoreDeveloper/SCDMS/blob/main/docs/aspire.md"

- name: Push to NuGet.org
shell: bash
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
run: |
set -euo pipefail
ls -1 ./artifacts/*.nupkg
dotnet nuget push ./artifacts/*.nupkg \
--api-key "$NUGET_API_KEY" \
--source https://api.nuget.org/v3/index.json \
--skip-duplicate

- name: Create release summary
run: |
echo "## 📦 NuGet Publish Completed" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Published **SCDMS.Aspire.Hosting ${{ steps.version.outputs.value }}** to NuGet.org." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Triggered by**: @${{ github.actor }} — commit \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY
8 changes: 8 additions & 0 deletions Directory.Packages.props
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,7 +9,15 @@
<PackageVersion Include="SharpCoreDB" Version="$(SharpCoreDBVersion)" />
<PackageVersion Include="SharpCoreDB.Data.Provider" Version="$(SharpCoreDBVersion)" />
<PackageVersion Include="SharpCoreDB.Client" Version="$(SharpCoreDBVersion)" />
<!-- Aspire hosting integration for the SharpCoreDB server container (same release train). -->
<PackageVersion Include="SharpCoreDB.Aspire.Hosting" Version="$(SharpCoreDBVersion)" />
<PackageVersion Include="SafeWebCore" Version="1.7.0" />
<PackageVersion Include="SharpDispatch" Version="1.0.1" />
</ItemGroup>

<ItemGroup>
<!-- .NET Aspire hosting (src/SCDMS.Aspire.Hosting + examples/Aspire). Version must match the
Aspire.Hosting dependency of SharpCoreDB.Aspire.Hosting (13.5.3). -->
<PackageVersion Include="Aspire.Hosting" Version="13.5.3" />
</ItemGroup>
</Project>
17 changes: 16 additions & 1 deletion README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -72,6 +72,7 @@ Dev launchers: `scripts/launch.ps1` (Windows), `scripts/launch.sh` (Linux/macOS)
1. Tag: `git tag v1.0.0 && git push origin v1.0.0`
2. The [release workflow](.github/workflows/release.yml) publishes self-contained single-file binaries for `win-x64`, `linux-x64`, `linux-arm64`, `osx-x64`, `osx-arm64` plus `SHA256SUMS.txt` to GitHub Releases.
3. The [Docker workflow](.github/workflows/docker-publish.yml) builds the container image (`ghcr.io/mpcoredeveloper/scdms`) for `linux/amd64` + `linux/arm64`.
4. The [NuGet workflow](.github/workflows/nuget-publish.yml) packs `SCDMS.Aspire.Hosting` and publishes it to NuGet.org.

## Docker & gRPC deployments

Expand All@@ -93,11 +94,25 @@ docker run --rm -p 8080:8080 \
ghcr.io/mpcoredeveloper/scdms:local
```

A full example (SCDMS + SharpCoreDB server + Caddy reverse proxy with Let's Encrypt) lives in [`samples/docker/`](samples/docker/). Configuration reference for container deployments (env variables, HTTP mode, default gRPC server, data volumes) is in [docs/usage.md](docs/usage.md).
A full example (SCDMS + SharpCoreDB server + Caddy reverse proxy with Let's Encrypt) lives in [`samples/docker/`](samples/docker/). Drop-in proxy alternatives with the same topology are [`samples/yarp/`](samples/yarp/) (all-.NET) and [`samples/haproxy/`](samples/haproxy/) (industry-standard HAProxy). Configuration reference for container deployments (env variables, HTTP mode, default gRPC server, data volumes) is in [docs/usage.md](docs/usage.md).

## .NET Aspire

SCDMS ships a `SCDMS.Aspire.Hosting` NuGet package (plus a runnable [AppHost example](examples/Aspire/SCDMS.AppHost/)) that runs SharpCoreDB server + SCDMS as one Aspire application — like pgweb/pgAdmin next to PostgreSQL:

```csharp
var db = builder.AddSharpCoreDB("db").WithServerContainer(); // SharpCoreDB server container
builder.AddSCDMS("admin", db); // SCDMS container auto-wired over gRPC
```

Requires the published images `ghcr.io/mpcoredeveloper/sharpcoredb-server` (published) and `ghcr.io/mpcoredeveloper/scdms` (built on `v*` tags; until then `docker build -t ghcr.io/mpcoredeveloper/scdms:latest .`). See [docs/aspire.md](docs/aspire.md) for the design, status and the TLS notes. A step-by-step run & test guide for **both** options (Compose and Aspire) is in [docs/container-and-aspire-guide.md](docs/container-and-aspire-guide.md).

## Documentation

- [Run & test guide — Docker Compose + .NET Aspire](docs/container-and-aspire-guide.md)

- [Usage & configuration](docs/usage.md)
- [.NET Aspire integration (design & status)](docs/aspire.md)
- [Standalone/migration plan](https://github.com/MPCoreDeveloper/SharpCoreDB/blob/master/docs/viewer/scdms-standalone-plan.md) (in the SharpCoreDB repo)
- [SharpCoreDB documentation](https://github.com/MPCoreDeveloper/SharpCoreDB)

Expand Down
4 changes: 4 additions & 0 deletions SCDMS.slnx
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
<Solution>
<Folder Name="/src/">
<Project Path="src/SCDMS/SCDMS.csproj" />
<Project Path="src/SCDMS.Aspire.Hosting/SCDMS.Aspire.Hosting.csproj" />
</Folder>
<Folder Name="/examples/">
<Project Path="examples/Aspire/SCDMS.AppHost/SCDMS.AppHost.csproj" />
</Folder>
<Folder Name="/tools/">
<Project Path="tools/SeedProbe/SeedProbe.csproj" />
Expand Down
149 changes: 58 additions & 91 deletions docs/aspire.md
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
# .NET Aspire integration (issue #10)

> **Status: design doc.** Fase 4 van de container/gRPC roadmap. Implementatie vereist eerst
> twee zaken in de **SharpCoreDB**-repo (zie "Prerequisites"), daarna kan dit repo een
> `SCDMS.Aspire.Hosting`-pakket toevoegen.
> **Status: geïmplementeerd (2026-09-05).** Fase 4 van de container/gRPC-roadmap is afgerond:
> beide SharpCoreDB-prerequisites (server-image + `SharpCoreDB.Aspire.Hosting`) zijn gepubliceerd,
> en dit repo levert nu het `SCDMS.Aspire.Hosting`-pakket, een voorbeeld-AppHost, een
> NuGet-publish-workflow en documentatie.

## Goal

Expand All@@ -14,111 +15,77 @@ var builder = DistributedApplication.CreateBuilder(args);
var sharpCoreDb = builder.AddSharpCoreDB("db")
.WithServerContainer(); // SharpCoreDB server container

builder.AddSCDMS("admin")
.WithGrpcReference(sharpCoreDb) // SCDMS container linked via gRPC
.WithHttpEndpoint(port: 8080, name: "http");
// SCDMS web studio, gekoppeld aan de server over gRPC. AddSCDMS registreert meteen het
// HTTP-endpoint (containerpoort 8080) en de SCDMS__* container-voorwaarden.
var scdms = builder.AddSCDMS("admin", sharpCoreDb);

builder.Build().Run();
```

Al het SCDMS ⇄ SharpCoreDB-dataverkeer loopt over **gRPC**.
Al het SCDMS ⇄ SharpCoreDB-dataverkeer loopt over **gRPC**. Browser-URL in de AppHost:
`scdms.GetEndpoint("http")`.

## Prerequisites (SharpCoreDBrepo — volgorde)
## Prerequisites (SharpCoreDB-repo)klaar

1. **Server-image publiceren** naar `ghcr.io/mpcoredeveloper/sharpcoredb-server`
(de `Dockerfile` in `src/SharpCoreDB.Server/` bestaat al; voeg een
`docker/build-push-action`-workflow toe op `v*`-tags, `linux/amd64`+`linux/arm64`).
2. **`SharpCoreDB.Aspire.Hosting`-pakket** publiceren met:
1. **Server-image gepubliceerd** `ghcr.io/mpcoredeveloper/sharpcoredb-server`
(`linux/amd64` + `linux/arm64`, getagd op elke `v*`-tag).
2. ✅ **`SharpCoreDB.Aspire.Hosting`-pakket gepubliceerd** → versie `2.0.0.2`
(dependency: `Aspire.Hosting` 13.5.3, net10.0).

```csharp
// SharpCoreDB.Aspire.Hosting / SharpCoreDbServerResource.cs
public sealed class SharpCoreDbServerResource(string name)
: ContainerResource(name), IResourceWithConnectionString
{
public string? JwtSecretKey { get; set; }
// ReferenceExpression voor de gRPC-connection string ("Host=...;Port=...;SSL=true")
}
```
Publieke API die dit repo gebruikt:

```csharp
public static class SharpCoreDbAspireExtensions
{
// Container-gebaseerd (gepubliceerde image)
public static IResourceBuilder<SharpCoreDbServerResource> AddSharpCoreDB(
this IDistributedApplicationBuilder builder, string name) =>
builder.AddResource(new SharpCoreDbServerResource(name))
.WithImage("ghcr.io/mpcoredeveloper/sharpcoredb-server")
.WithImageTag("latest")
.WithHttpEndpoint(port: 5001, name: "grpc");

// Convenience-alias voor het issue-snippet
public static IResourceBuilder<SharpCoreDbServerResource> WithServerContainer(
this IResourceBuilder<SharpCoreDbServerResource> resource) => resource;
}
```
| Lid | Betekenis |
|---|---|
| `AddSharpCoreDB(name, imageTag = null, grpcPort = null, httpsApiPort = null)` | Registreert de servercontainer |
| `.WithServerContainer()` | Documentatie-alias voor container-hosting |
| `.WithImageTag(...)` | Image-tag pinnen |
| `.WithJwtSecret(secret)` | Zet `Server__Security__JwtSecretKey` (min. 32 tekens) |
| `SharpCoreDbServerResource.GrpcEndpointName` (= `"grpc"`) | HTTPS-gRPC-endpoint, containerpoort 5001 |
| `SharpCoreDbServerResource.HttpsApiEndpointName` (= `"https"`) | HTTPS REST API, containerpoort 8443 |

## SCDMS-repo implementatie (zodra prerequisites klaar zijn)
Referentie (SharpCoreDB-kant): [`docs/server/ASPIRE_INTEGRATION.md`](https://github.com/MPCoreDeveloper/SharpCoreDB/blob/master/docs/server/ASPIRE_INTEGRATION.md)

### Nieuw project `src/SCDMS.Aspire.Hosting/SCDMS.Aspire.Hosting.csproj`
## Implementatie in dit repo (SCDMS)

- `TargetFramework: net10.0`
- PackageReference: `Aspire.Hosting` (zelfde versie als SharpCoreDB.AppHost gebruikt,
i.c. 13.x) + project/package-ref naar `SharpCoreDB.Aspire.Hosting`.
- `SCDMSResource : ContainerResource, IResourceWithConnectionString` (web-URL als
connection string).
### `src/SCDMS.Aspire.Hosting` → NuGet: `SCDMS.Aspire.Hosting`

### `SCDMSAspireExtensions.cs` (API-schets)
- **`ScdmsResource`** (`SCDMSResource.cs`) — `ContainerResource` + `IResourceWithConnectionString`
(web-URL als connection string). Endpoint-naam `http`, containerpoort 8080.
- **`ScdmsAspireExtensions`** (`ScdmsAspireExtensions.cs`):
- `AddSCDMS(builder, name, sharpCoreDb = null, imageTag = null, port = null)` — registreert de
SCDMS-container op `ghcr.io/mpcoredeveloper/scdms` met de container-voorwaarden
(`SCDMS__EnableHttps=false`, `SCDMS__BindAddress=0.0.0.0`, `SCDMS__DataDirectory=/app/data`,
update-check uit). Wordt `sharpCoreDb` meegegeven, dan volgt automatisch `WithGrpcReference`.
- `WithGrpcReference(scdms, sharpCoreDb)` — koppelt het `grpc`-endpoint van de server via
`SCDMS__DefaultServerHost` / `SCDMS__DefaultServerPort`, zet `SCDMS__DefaultServerUseSsl=true`
en `SCDMS__DefaultServerAutoConnect=true`.

```csharp
public static class ScdmsAspireExtensions
{
public static IResourceBuilder<SCDMSResource> AddSCDMS(
this IDistributedApplicationBuilder builder,
string name,
IResourceBuilder<SharpCoreDbServerResource>? sharpCoreDb = null)
{
var scdms = builder.AddResource(new SCDMSResource(name))
.WithImage("ghcr.io/mpcoredeveloper/scdms")
.WithImageTag("latest")
.WithHttpEndpoint(targetPort: 8080, name: "http")
.WithEnvironment("SCDMS__EnableHttps", "false")
.WithEnvironment("SCDMS__BindAddress", "0.0.0.0")
.WithEnvironment("SCDMS__DataDirectory", "/app/data")
.WithEnvironment("SCDMS__DefaultServerAutoConnect", "true");

return sharpCoreDb is null ? scdms : scdms.WithGrpcReference(sharpCoreDb);
}

// Koppelt de gRPC-server aan SCDMS via SCDMS__DefaultServer* omgevingsvariabelen.
public static IResourceBuilder<SCDMSResource> WithGrpcReference(
this IResourceBuilder<SCDMSResource> scdms,
IResourceBuilder<SharpCoreDbServerResource> sharpCoreDb)
{
var grpcEndpoint = sharpCoreDb.GetEndpoint("grpc");
return scdms
.WithEnvironment("SCDMS__DefaultServerHost", grpcEndpoint)
.WithEnvironment("SCDMS__DefaultServerPort", grpcEndpoint.Property(EndpointProperty.Port))
.WithEnvironment("SCDMS__DefaultServerUseSsl", "true")
.WithEnvironment("SCDMS__DefaultServerAutoConnect", "true");
}
}
```
### Voorbeeld-AppHost: `examples/Aspire/SCDMS.AppHost`

### Voorbeeld-AppHost (nieuw project, bijv. `examples/Aspire/SCDMS.AppHost`)
Volledig draaibaar voorbeeld. Starten:

```bash
dotnet run --project examples/Aspire/SCDMS.AppHost/SCDMS.AppHost.csproj
```

- `<ProjectReference Include="..\..\..\src\SCDMS.Aspire.Hosting" />` +
`SharpCoreDB.Aspire.Hosting` (NuGet).
- `Program.cs` met het snippet bovenaan dit document; browser-URL via
`scdms.GetEndpoint("http")`.
Lees `examples/Aspire/SCDMS.AppHost/README.md` voor de lokale-dev-/TLS-opmerkingen.

### CI
### CI/CD

- Bouw/pack `SCDMS.Aspire.Hosting` en publiceer naar NuGet.org bij releases.
- `ci.yml` bouwt de volledige oplossing (`SCDMS.slnx`, inclusief de nieuwe projecten) op
ubuntu/windows/macos.
- `nuget-publish.yml` packt `SCDMS.Aspire.Hosting` en publiceert naar NuGet.org bij elke `v*`-tag
(vereist het `NUGET_API_KEY`-secret).
- De SCDMS-image (`ghcr.io/mpcoredeveloper/scdms`) wordt gepubliceerd door `docker-publish.yml`
bij een `v*`-tag (deel 1 van het issue).

## Opmerkingen

- De Aspire-local-run kan de server als container draaien (`WithServerContainer`). Voor
TLS: in de Aspire-dev-omgeving is een publiek certificaat niet beschikbaar — gebruik de
publiek-vertrouwde-proxy-aanpak in productie (zie `samples/docker/`) en voor lokale dev
een dev-certificaat + `tls_insecure_skip_verify`-achtige optie in de hosting-extensie
(of rechtstreeks container-intern over het Aspire-netwerk met de server-`/health`-check).
- De SharpCoreDB-servercontainer spreekt **uitsluitend TLS** en heeft een certificaat nodig
(`Server__Security__TlsCertificatePath`); SCDMS valideert het certificaat van het gRPC-endpoint.
- **Productie:** beëindig TLS op een publiek vertrouwde reverse proxy (patroon in
`samples/docker/`), precies zoals de compose-sample.
- **Lokale dev:** de servercontainer heeft nog steeds een (dev-)certificaat nodig; lees de
server-side certificaatopties in de SharpCoreDB `ASPIRE_INTEGRATION.md`. Voor een volledig
vertrouwde lokale run zonder extra CA-mounts blijft de proxy-topologie van `samples/docker/`
de aanbevolen route.
Loading