From be09534d10e7320eae831ae5a0f47388b8d0e167 Mon Sep 17 00:00:00 2001
From: Theaux Masquelier <43664045+Theauxm@users.noreply.github.com>
Date: Tue, 17 Mar 2026 10:16:14 -0600
Subject: [PATCH 1/2] feat: add Hub template, switch all templates to in-memory
default
Add Trax.Samples.Hub combining API + Scheduler + Dashboard in one
process. Switch Api and Scheduler templates from Postgres to
UseInMemory() so they run without external dependencies. Add
third-party license credits to all template Program.cs headers.
---
.gitignore | 3 +-
.../.template.config/template.json | 9 ---
templates/content/Trax.Samples.Api/Program.cs | 27 +++----
.../Junctions/LogGreetingJunction.cs | 3 +-
.../Lookup/Junctions/FetchDataJunction.cs | 3 +-
.../Trax.Samples.Api/Trax.Samples.Api.csproj | 3 +-
.../content/Trax.Samples.Api/appsettings.json | 3 -
.../.template.config/template.json | 14 ++++
templates/content/Trax.Samples.Hub/Program.cs | 78 +++++++++++++++++++
.../Properties/launchSettings.json | 15 ++++
.../Trains/HelloWorld/HelloWorldInput.cs | 11 +++
.../Trains/HelloWorld/HelloWorldTrain.cs | 17 ++++
.../Trains/HelloWorld/IHelloWorldTrain.cs | 6 ++
.../Junctions/LogGreetingJunction.cs | 26 +++++++
.../Trains/Lookup/ILookupTrain.cs | 5 ++
.../Lookup/Junctions/FetchDataJunction.cs | 23 ++++++
.../Trains/Lookup/LookupInput.cs | 9 +++
.../Trains/Lookup/LookupOutput.cs | 8 ++
.../Trains/Lookup/LookupTrain.cs | 17 ++++
.../Trax.Samples.Hub/Trax.Samples.Hub.csproj | 23 ++++++
.../content/Trax.Samples.Hub/appsettings.json | 15 ++++
.../.template.config/template.json | 9 ---
.../content/Trax.Samples.Scheduler/Program.cs | 37 ++++-----
.../Junctions/LogGreetingJunction.cs | 3 +-
.../Trax.Samples.Scheduler.csproj | 2 +-
.../Trax.Samples.Scheduler/appsettings.json | 3 -
26 files changed, 309 insertions(+), 63 deletions(-)
create mode 100644 templates/content/Trax.Samples.Hub/.template.config/template.json
create mode 100644 templates/content/Trax.Samples.Hub/Program.cs
create mode 100644 templates/content/Trax.Samples.Hub/Properties/launchSettings.json
create mode 100644 templates/content/Trax.Samples.Hub/Trains/HelloWorld/HelloWorldInput.cs
create mode 100644 templates/content/Trax.Samples.Hub/Trains/HelloWorld/HelloWorldTrain.cs
create mode 100644 templates/content/Trax.Samples.Hub/Trains/HelloWorld/IHelloWorldTrain.cs
create mode 100644 templates/content/Trax.Samples.Hub/Trains/HelloWorld/Junctions/LogGreetingJunction.cs
create mode 100644 templates/content/Trax.Samples.Hub/Trains/Lookup/ILookupTrain.cs
create mode 100644 templates/content/Trax.Samples.Hub/Trains/Lookup/Junctions/FetchDataJunction.cs
create mode 100644 templates/content/Trax.Samples.Hub/Trains/Lookup/LookupInput.cs
create mode 100644 templates/content/Trax.Samples.Hub/Trains/Lookup/LookupOutput.cs
create mode 100644 templates/content/Trax.Samples.Hub/Trains/Lookup/LookupTrain.cs
create mode 100644 templates/content/Trax.Samples.Hub/Trax.Samples.Hub.csproj
create mode 100644 templates/content/Trax.Samples.Hub/appsettings.json
diff --git a/.gitignore b/.gitignore
index ba93ac6..0559d2b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -144,6 +144,7 @@ BenchmarkDotNet.Artifacts/
# Semantic Release version file
.release-version
-# Node.js (React chat client)
+# Node.js (React clients)
node_modules/
+dist/
tsconfig.tsbuildinfo
diff --git a/templates/content/Trax.Samples.Api/.template.config/template.json b/templates/content/Trax.Samples.Api/.template.config/template.json
index 9e1e78e..bbd09e8 100644
--- a/templates/content/Trax.Samples.Api/.template.config/template.json
+++ b/templates/content/Trax.Samples.Api/.template.config/template.json
@@ -10,14 +10,5 @@
"tags": {
"language": "C#",
"type": "project"
- },
- "symbols": {
- "ConnectionString": {
- "type": "parameter",
- "datatype": "string",
- "defaultValue": "Host=localhost;Port=5432;Database=trax;Username=trax;Password=trax123",
- "replaces": "HOST_CONNECTION_STRING",
- "description": "The PostgreSQL connection string for Trax"
- }
}
}
diff --git a/templates/content/Trax.Samples.Api/Program.cs b/templates/content/Trax.Samples.Api/Program.cs
index ef6f28f..af7dbcc 100644
--- a/templates/content/Trax.Samples.Api/Program.cs
+++ b/templates/content/Trax.Samples.Api/Program.cs
@@ -3,13 +3,14 @@
//
// A GraphQL API powered by HotChocolate. Handles lightweight operations
// directly via mutations and can queue heavy work for a separate scheduler
-// process by passing mode: QUEUE.
+// process by passing mode: QUEUE. Uses an in-memory data provider by default
+// so you can run it immediately without any external dependencies.
//
-// Prerequisites:
-// 1. Start PostgreSQL (e.g. docker compose up -d)
-// 2. Run this project: dotnet run
+// To switch to PostgreSQL, replace UseInMemory() with UsePostgres(connectionString)
+// and swap the Trax.Effect.Data.InMemory package for Trax.Effect.Data.Postgres.
//
// Try it:
+// dotnet run
// Open http://localhost:5002/trax/graphql in a browser for Banana Cake Pop IDE
//
// # Query a train directly (typed query from [TraxQuery])
@@ -20,11 +21,16 @@
//
// # Health check
// curl http://localhost:5002/trax/health
+//
+// Third-party packages used by this project (via Trax dependencies):
+// HotChocolate — GraphQL server (MIT, https://github.com/ChilliCream/graphql-platform)
+// LanguageExt — Functional programming primitives (MIT, https://github.com/louthy/language-ext)
+// EF Core InMemory — In-memory database provider (MIT, https://github.com/dotnet/efcore)
// ─────────────────────────────────────────────────────────────────────────────
using Trax.Api.Extensions;
using Trax.Api.GraphQL.Extensions;
-using Trax.Effect.Data.Postgres.Extensions;
+using Trax.Effect.Data.InMemory.Extensions;
using Trax.Effect.Extensions;
using Trax.Effect.Provider.Json.Extensions;
using Trax.Effect.Provider.Parameter.Extensions;
@@ -32,21 +38,16 @@
var builder = WebApplication.CreateBuilder(args);
-var connectionString =
- builder.Configuration.GetConnectionString("TraxDatabase")
- ?? throw new InvalidOperationException("Connection string 'TraxDatabase' not found.");
-
builder.Services.AddLogging(logging => logging.AddConsole());
// ── Register Trax Effect + Mediator ─────────────────────────────────────
builder.Services.AddTrax(trax =>
- trax.AddEffects(effects =>
- effects.UsePostgres(connectionString).AddJson().SaveTrainParameters()
- )
- .AddMediator(typeof(Program).Assembly)
+ trax.AddEffects(effects => effects.UseInMemory())
+ .AddMediator(typeof(Program).Assembly)
);
// ── Register GraphQL API ────────────────────────────────────────────────
+builder.Services.AddAuthorization();
builder.Services.AddTraxGraphQL();
builder.Services.AddHealthChecks().AddTraxHealthCheck();
diff --git a/templates/content/Trax.Samples.Api/Trains/HelloWorld/Junctions/LogGreetingJunction.cs b/templates/content/Trax.Samples.Api/Trains/HelloWorld/Junctions/LogGreetingJunction.cs
index 7d5b382..688fa2d 100644
--- a/templates/content/Trax.Samples.Api/Trains/HelloWorld/Junctions/LogGreetingJunction.cs
+++ b/templates/content/Trax.Samples.Api/Trains/HelloWorld/Junctions/LogGreetingJunction.cs
@@ -1,5 +1,6 @@
using LanguageExt;
-using Trax.Core.Models;
+using Microsoft.Extensions.Logging;
+using Trax.Core.Junction;
namespace Trax.Samples.Api.Trains.HelloWorld.Junctions;
diff --git a/templates/content/Trax.Samples.Api/Trains/Lookup/Junctions/FetchDataJunction.cs b/templates/content/Trax.Samples.Api/Trains/Lookup/Junctions/FetchDataJunction.cs
index b144220..56b2b10 100644
--- a/templates/content/Trax.Samples.Api/Trains/Lookup/Junctions/FetchDataJunction.cs
+++ b/templates/content/Trax.Samples.Api/Trains/Lookup/Junctions/FetchDataJunction.cs
@@ -1,4 +1,5 @@
-using Trax.Core.Models;
+using Microsoft.Extensions.Logging;
+using Trax.Core.Junction;
namespace Trax.Samples.Api.Trains.Lookup.Junctions;
diff --git a/templates/content/Trax.Samples.Api/Trax.Samples.Api.csproj b/templates/content/Trax.Samples.Api/Trax.Samples.Api.csproj
index 48fdda6..7622d99 100644
--- a/templates/content/Trax.Samples.Api/Trax.Samples.Api.csproj
+++ b/templates/content/Trax.Samples.Api/Trax.Samples.Api.csproj
@@ -4,11 +4,12 @@
net10.0
enable
enable
+ true
-
+
diff --git a/templates/content/Trax.Samples.Api/appsettings.json b/templates/content/Trax.Samples.Api/appsettings.json
index 57480e9..a86dd58 100644
--- a/templates/content/Trax.Samples.Api/appsettings.json
+++ b/templates/content/Trax.Samples.Api/appsettings.json
@@ -1,7 +1,4 @@
{
- "ConnectionStrings": {
- "TraxDatabase": "HOST_CONNECTION_STRING"
- },
"Kestrel": {
"Endpoints": {
"Http": {
diff --git a/templates/content/Trax.Samples.Hub/.template.config/template.json b/templates/content/Trax.Samples.Hub/.template.config/template.json
new file mode 100644
index 0000000..8819323
--- /dev/null
+++ b/templates/content/Trax.Samples.Hub/.template.config/template.json
@@ -0,0 +1,14 @@
+{
+ "$schema": "http://json.schemastore.org/template",
+ "author": "Trax",
+ "classifications": ["Web", "Trax", "GraphQL", "Scheduler", "Dashboard"],
+ "identity": "Trax.Samples.Hub.CSharp",
+ "name": "Trax Hub (API + Scheduler + Dashboard)",
+ "shortName": "trax-hub",
+ "sourceName": "Trax.Samples.Hub",
+ "preferNameDirectory": true,
+ "tags": {
+ "language": "C#",
+ "type": "project"
+ }
+}
diff --git a/templates/content/Trax.Samples.Hub/Program.cs b/templates/content/Trax.Samples.Hub/Program.cs
new file mode 100644
index 0000000..bf6b0d7
--- /dev/null
+++ b/templates/content/Trax.Samples.Hub/Program.cs
@@ -0,0 +1,78 @@
+// ---------------------------------------------------------------------------
+// Trax Hub (API + Scheduler + Dashboard)
+//
+// A single process that serves a GraphQL API, runs scheduled trains, and
+// hosts the Trax Dashboard. Uses an in-memory data provider by default so
+// you can run it immediately without any external dependencies.
+//
+// To switch to PostgreSQL, replace UseInMemory() with UsePostgres(connectionString)
+// and swap the Trax.Effect.Data.InMemory package for Trax.Effect.Data.Postgres.
+//
+// Try it:
+// dotnet run
+// Open http://localhost:5000/trax/graphql for the GraphQL IDE
+// Open http://localhost:5000/trax for the Dashboard
+//
+// # Query a train directly
+// query { discover { lookup(input: { id: "42" }) { id name createdAt } } }
+//
+// # Run a mutation
+// mutation { dispatch { helloWorld(input: { name: "Trax" }) { externalId metadataId } } }
+//
+// # Health check
+// curl http://localhost:5000/trax/health
+//
+// Third-party packages used by this project (via Trax dependencies):
+// HotChocolate — GraphQL server (MIT, https://github.com/ChilliCream/graphql-platform)
+// Radzen.Blazor — Dashboard UI components (MIT, https://github.com/radzenhq/radzen-blazor)
+// LanguageExt — Functional programming primitives (MIT, https://github.com/louthy/language-ext)
+// Cronos — Cron expression parser (MIT, https://github.com/HangfireIO/Cronos)
+// EF Core InMemory — In-memory database provider (MIT, https://github.com/dotnet/efcore)
+// ---------------------------------------------------------------------------
+
+using Trax.Api.Extensions;
+using Trax.Api.GraphQL.Extensions;
+using Trax.Dashboard.Extensions;
+using Trax.Effect.Data.InMemory.Extensions;
+using Trax.Effect.Extensions;
+using Trax.Effect.JunctionProvider.Progress.Extensions;
+using Trax.Effect.Provider.Json.Extensions;
+using Trax.Effect.Provider.Parameter.Extensions;
+using Trax.Mediator.Extensions;
+using Trax.Samples.Hub.Trains.HelloWorld;
+using Trax.Scheduler.Extensions;
+using Trax.Scheduler.Services.Scheduling;
+
+var builder = WebApplication.CreateBuilder(args);
+
+builder.Services.AddLogging(logging => logging.AddConsole());
+
+// -- Trax Effect + Mediator + Scheduler --------------------------------------
+builder.Services.AddTrax(trax =>
+ trax.AddEffects(effects => effects.UseInMemory())
+ .AddMediator(typeof(Program).Assembly)
+ .AddScheduler(scheduler =>
+ scheduler.Schedule(
+ "hello-world",
+ new HelloWorldInput { Name = "Trax" },
+ Every.Seconds(20)
+ )
+ )
+);
+
+// -- Dashboard ---------------------------------------------------------------
+builder.AddTraxDashboard();
+
+// -- GraphQL API -------------------------------------------------------------
+builder.Services.AddAuthorization();
+builder.Services.AddTraxGraphQL();
+builder.Services.AddHealthChecks().AddTraxHealthCheck();
+
+var app = builder.Build();
+
+// -- Map endpoints -----------------------------------------------------------
+app.UseTraxDashboard();
+app.UseTraxGraphQL();
+app.MapHealthChecks("/trax/health");
+
+app.Run();
diff --git a/templates/content/Trax.Samples.Hub/Properties/launchSettings.json b/templates/content/Trax.Samples.Hub/Properties/launchSettings.json
new file mode 100644
index 0000000..584b530
--- /dev/null
+++ b/templates/content/Trax.Samples.Hub/Properties/launchSettings.json
@@ -0,0 +1,15 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "trax/graphql",
+ "applicationUrl": "http://localhost:5000",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/templates/content/Trax.Samples.Hub/Trains/HelloWorld/HelloWorldInput.cs b/templates/content/Trax.Samples.Hub/Trains/HelloWorld/HelloWorldInput.cs
new file mode 100644
index 0000000..5fac688
--- /dev/null
+++ b/templates/content/Trax.Samples.Hub/Trains/HelloWorld/HelloWorldInput.cs
@@ -0,0 +1,11 @@
+using Trax.Effect.Models.Manifest;
+
+namespace Trax.Samples.Hub.Trains.HelloWorld;
+
+public record HelloWorldInput : IManifestProperties
+{
+ ///
+ /// The name to greet in the train.
+ ///
+ public string Name { get; init; } = "World";
+}
diff --git a/templates/content/Trax.Samples.Hub/Trains/HelloWorld/HelloWorldTrain.cs b/templates/content/Trax.Samples.Hub/Trains/HelloWorld/HelloWorldTrain.cs
new file mode 100644
index 0000000..b3c3950
--- /dev/null
+++ b/templates/content/Trax.Samples.Hub/Trains/HelloWorld/HelloWorldTrain.cs
@@ -0,0 +1,17 @@
+using LanguageExt;
+using Trax.Effect.Attributes;
+using Trax.Effect.Services.ServiceTrain;
+using Trax.Samples.Hub.Trains.HelloWorld.Junctions;
+
+namespace Trax.Samples.Hub.Trains.HelloWorld;
+
+///
+/// A mutation train that logs a greeting. Also scheduled to run every 20 seconds.
+/// Exposed as a typed mutation field under mutation { dispatch { runHelloWorld(...) } }.
+///
+[TraxMutation(GraphQLOperation.Run, Description = "Runs a hello world greeting")]
+public class HelloWorldTrain : ServiceTrain, IHelloWorldTrain
+{
+ protected override async Task> RunInternal(HelloWorldInput input) =>
+ Activate(input).Chain().Resolve();
+}
diff --git a/templates/content/Trax.Samples.Hub/Trains/HelloWorld/IHelloWorldTrain.cs b/templates/content/Trax.Samples.Hub/Trains/HelloWorld/IHelloWorldTrain.cs
new file mode 100644
index 0000000..79df32a
--- /dev/null
+++ b/templates/content/Trax.Samples.Hub/Trains/HelloWorld/IHelloWorldTrain.cs
@@ -0,0 +1,6 @@
+using LanguageExt;
+using Trax.Effect.Services.ServiceTrain;
+
+namespace Trax.Samples.Hub.Trains.HelloWorld;
+
+public interface IHelloWorldTrain : IServiceTrain;
diff --git a/templates/content/Trax.Samples.Hub/Trains/HelloWorld/Junctions/LogGreetingJunction.cs b/templates/content/Trax.Samples.Hub/Trains/HelloWorld/Junctions/LogGreetingJunction.cs
new file mode 100644
index 0000000..acabf05
--- /dev/null
+++ b/templates/content/Trax.Samples.Hub/Trains/HelloWorld/Junctions/LogGreetingJunction.cs
@@ -0,0 +1,26 @@
+using LanguageExt;
+using Microsoft.Extensions.Logging;
+using Trax.Core.Junction;
+
+namespace Trax.Samples.Hub.Trains.HelloWorld.Junctions;
+
+public class LogGreetingJunction(ILogger logger)
+ : Junction
+{
+ public override async Task Run(HelloWorldInput input)
+ {
+ var timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss UTC");
+
+ logger.LogInformation(
+ "Hello, {Name}! This train ran at {Timestamp}",
+ input.Name,
+ timestamp
+ );
+
+ await Task.Delay(100);
+
+ logger.LogInformation("HelloWorld train completed successfully for {Name}", input.Name);
+
+ return Unit.Default;
+ }
+}
diff --git a/templates/content/Trax.Samples.Hub/Trains/Lookup/ILookupTrain.cs b/templates/content/Trax.Samples.Hub/Trains/Lookup/ILookupTrain.cs
new file mode 100644
index 0000000..eacfbb0
--- /dev/null
+++ b/templates/content/Trax.Samples.Hub/Trains/Lookup/ILookupTrain.cs
@@ -0,0 +1,5 @@
+using Trax.Effect.Services.ServiceTrain;
+
+namespace Trax.Samples.Hub.Trains.Lookup;
+
+public interface ILookupTrain : IServiceTrain;
diff --git a/templates/content/Trax.Samples.Hub/Trains/Lookup/Junctions/FetchDataJunction.cs b/templates/content/Trax.Samples.Hub/Trains/Lookup/Junctions/FetchDataJunction.cs
new file mode 100644
index 0000000..1402eb8
--- /dev/null
+++ b/templates/content/Trax.Samples.Hub/Trains/Lookup/Junctions/FetchDataJunction.cs
@@ -0,0 +1,23 @@
+using Microsoft.Extensions.Logging;
+using Trax.Core.Junction;
+
+namespace Trax.Samples.Hub.Trains.Lookup.Junctions;
+
+public class FetchDataJunction(ILogger logger)
+ : Junction
+{
+ public override async Task Run(LookupInput input)
+ {
+ logger.LogInformation("Looking up record {Id}", input.Id);
+
+ // Replace this with your actual data access logic.
+ await Task.Delay(50);
+
+ return new LookupOutput
+ {
+ Id = input.Id,
+ Name = $"Record {input.Id}",
+ CreatedAt = DateTime.UtcNow,
+ };
+ }
+}
diff --git a/templates/content/Trax.Samples.Hub/Trains/Lookup/LookupInput.cs b/templates/content/Trax.Samples.Hub/Trains/Lookup/LookupInput.cs
new file mode 100644
index 0000000..4927f63
--- /dev/null
+++ b/templates/content/Trax.Samples.Hub/Trains/Lookup/LookupInput.cs
@@ -0,0 +1,9 @@
+namespace Trax.Samples.Hub.Trains.Lookup;
+
+public record LookupInput
+{
+ ///
+ /// The ID of the record to look up.
+ ///
+ public required string Id { get; init; }
+}
diff --git a/templates/content/Trax.Samples.Hub/Trains/Lookup/LookupOutput.cs b/templates/content/Trax.Samples.Hub/Trains/Lookup/LookupOutput.cs
new file mode 100644
index 0000000..6eb5192
--- /dev/null
+++ b/templates/content/Trax.Samples.Hub/Trains/Lookup/LookupOutput.cs
@@ -0,0 +1,8 @@
+namespace Trax.Samples.Hub.Trains.Lookup;
+
+public record LookupOutput
+{
+ public required string Id { get; init; }
+ public required string Name { get; init; }
+ public required DateTime CreatedAt { get; init; }
+}
diff --git a/templates/content/Trax.Samples.Hub/Trains/Lookup/LookupTrain.cs b/templates/content/Trax.Samples.Hub/Trains/Lookup/LookupTrain.cs
new file mode 100644
index 0000000..3eb3edb
--- /dev/null
+++ b/templates/content/Trax.Samples.Hub/Trains/Lookup/LookupTrain.cs
@@ -0,0 +1,17 @@
+using LanguageExt;
+using Trax.Effect.Attributes;
+using Trax.Effect.Services.ServiceTrain;
+using Trax.Samples.Hub.Trains.Lookup.Junctions;
+
+namespace Trax.Samples.Hub.Trains.Lookup;
+
+///
+/// A query train that looks up a record by ID.
+/// Exposed as a typed query field under query { discover { lookup(...) } }.
+///
+[TraxQuery(Description = "Looks up a record by ID")]
+public class LookupTrain : ServiceTrain, ILookupTrain
+{
+ protected override async Task> RunInternal(LookupInput input) =>
+ Activate(input).Chain().Resolve();
+}
diff --git a/templates/content/Trax.Samples.Hub/Trax.Samples.Hub.csproj b/templates/content/Trax.Samples.Hub/Trax.Samples.Hub.csproj
new file mode 100644
index 0000000..76619a4
--- /dev/null
+++ b/templates/content/Trax.Samples.Hub/Trax.Samples.Hub.csproj
@@ -0,0 +1,23 @@
+
+
+ Exe
+ net10.0
+ enable
+ enable
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/templates/content/Trax.Samples.Hub/appsettings.json b/templates/content/Trax.Samples.Hub/appsettings.json
new file mode 100644
index 0000000..830fe81
--- /dev/null
+++ b/templates/content/Trax.Samples.Hub/appsettings.json
@@ -0,0 +1,15 @@
+{
+ "Kestrel": {
+ "Endpoints": {
+ "Http": {
+ "Url": "http://localhost:5000"
+ }
+ }
+ },
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/templates/content/Trax.Samples.Scheduler/.template.config/template.json b/templates/content/Trax.Samples.Scheduler/.template.config/template.json
index 45c8135..81e4d09 100644
--- a/templates/content/Trax.Samples.Scheduler/.template.config/template.json
+++ b/templates/content/Trax.Samples.Scheduler/.template.config/template.json
@@ -10,14 +10,5 @@
"tags": {
"language": "C#",
"type": "project"
- },
- "symbols": {
- "ConnectionString": {
- "type": "parameter",
- "datatype": "string",
- "defaultValue": "Host=localhost;Port=5432;Database=trax;Username=trax;Password=trax123",
- "replaces": "HOST_CONNECTION_STRING",
- "description": "The PostgreSQL connection string for Trax"
- }
}
}
diff --git a/templates/content/Trax.Samples.Scheduler/Program.cs b/templates/content/Trax.Samples.Scheduler/Program.cs
index cbd4c70..7ec1ac7 100644
--- a/templates/content/Trax.Samples.Scheduler/Program.cs
+++ b/templates/content/Trax.Samples.Scheduler/Program.cs
@@ -1,19 +1,26 @@
// ─────────────────────────────────────────────────────────────────────────────
// Trax Scheduler with Dashboard
//
-// Runs scheduled trains on a configurable interval using PostgreSQL as the
-// task server. Includes a Blazor dashboard for monitoring at /trax.
+// Runs scheduled trains on a configurable interval. Includes a Blazor
+// dashboard for monitoring at /trax. Uses an in-memory data provider by
+// default so you can run it immediately without any external dependencies.
//
-// Prerequisites:
-// 1. Start PostgreSQL (e.g. docker compose up -d)
-// 2. Run this project: dotnet run
+// To switch to PostgreSQL, replace UseInMemory() with UsePostgres(connectionString)
+// and swap the Trax.Effect.Data.InMemory package for Trax.Effect.Data.Postgres.
//
// Try it:
+// dotnet run
// Open http://localhost:5001/trax in a browser for the Trax Dashboard
+//
+// Third-party packages used by this project (via Trax dependencies):
+// Radzen.Blazor — Dashboard UI components (MIT, https://github.com/radzenhq/radzen-blazor)
+// LanguageExt — Functional programming primitives (MIT, https://github.com/louthy/language-ext)
+// Cronos — Cron expression parser (MIT, https://github.com/HangfireIO/Cronos)
+// EF Core InMemory — In-memory database provider (MIT, https://github.com/dotnet/efcore)
// ─────────────────────────────────────────────────────────────────────────────
using Trax.Dashboard.Extensions;
-using Trax.Effect.Data.Postgres.Extensions;
+using Trax.Effect.Data.InMemory.Extensions;
using Trax.Effect.Extensions;
using Trax.Effect.JunctionProvider.Progress.Extensions;
using Trax.Effect.Provider.Json.Extensions;
@@ -25,24 +32,11 @@
var builder = WebApplication.CreateBuilder(args);
-var connectionString =
- builder.Configuration.GetConnectionString("TraxDatabase")
- ?? throw new InvalidOperationException("Connection string 'TraxDatabase' not found.");
-
builder.Services.AddLogging(logging => logging.AddConsole());
-// ── Dashboard ───────────────────────────────────────────────────────────
-builder.AddTraxDashboard();
-
// ── Register Trax Effect + Scheduler ────────────────────────────────────
builder.Services.AddTrax(trax =>
- trax.AddEffects(effects =>
- effects
- .UsePostgres(connectionString)
- .AddJson()
- .SaveTrainParameters()
- .AddJunctionProgress()
- )
+ trax.AddEffects(effects => effects.UseInMemory())
.AddMediator(typeof(Program).Assembly)
.AddScheduler(scheduler =>
scheduler
@@ -56,6 +50,9 @@
)
);
+// ── Dashboard ───────────────────────────────────────────────────────────
+builder.AddTraxDashboard();
+
var app = builder.Build();
// ── Map dashboard ───────────────────────────────────────────────────────
diff --git a/templates/content/Trax.Samples.Scheduler/Trains/HelloWorld/Junctions/LogGreetingJunction.cs b/templates/content/Trax.Samples.Scheduler/Trains/HelloWorld/Junctions/LogGreetingJunction.cs
index 4a05f2e..fbc4800 100644
--- a/templates/content/Trax.Samples.Scheduler/Trains/HelloWorld/Junctions/LogGreetingJunction.cs
+++ b/templates/content/Trax.Samples.Scheduler/Trains/HelloWorld/Junctions/LogGreetingJunction.cs
@@ -1,5 +1,6 @@
using LanguageExt;
-using Trax.Core.Models;
+using Microsoft.Extensions.Logging;
+using Trax.Core.Junction;
namespace Trax.Samples.Scheduler.Trains.HelloWorld.Junctions;
diff --git a/templates/content/Trax.Samples.Scheduler/Trax.Samples.Scheduler.csproj b/templates/content/Trax.Samples.Scheduler/Trax.Samples.Scheduler.csproj
index bb46387..81f01f8 100644
--- a/templates/content/Trax.Samples.Scheduler/Trax.Samples.Scheduler.csproj
+++ b/templates/content/Trax.Samples.Scheduler/Trax.Samples.Scheduler.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/templates/content/Trax.Samples.Scheduler/appsettings.json b/templates/content/Trax.Samples.Scheduler/appsettings.json
index f2bdc73..abebe56 100644
--- a/templates/content/Trax.Samples.Scheduler/appsettings.json
+++ b/templates/content/Trax.Samples.Scheduler/appsettings.json
@@ -1,7 +1,4 @@
{
- "ConnectionStrings": {
- "TraxDatabase": "HOST_CONNECTION_STRING"
- },
"Kestrel": {
"Endpoints": {
"Http": {
From 9e0e1d15f9e94d9c3ca9c1de1bd0f0a5999c4261 Mon Sep 17 00:00:00 2001
From: Theaux Masquelier <43664045+Theauxm@users.noreply.github.com>
Date: Tue, 17 Mar 2026 10:47:31 -0600
Subject: [PATCH 2/2] fix: format Api template Program.cs for csharpier
---
templates/content/Trax.Samples.Api/Program.cs | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/templates/content/Trax.Samples.Api/Program.cs b/templates/content/Trax.Samples.Api/Program.cs
index af7dbcc..b9c58a6 100644
--- a/templates/content/Trax.Samples.Api/Program.cs
+++ b/templates/content/Trax.Samples.Api/Program.cs
@@ -42,8 +42,7 @@
// ── Register Trax Effect + Mediator ─────────────────────────────────────
builder.Services.AddTrax(trax =>
- trax.AddEffects(effects => effects.UseInMemory())
- .AddMediator(typeof(Program).Assembly)
+ trax.AddEffects(effects => effects.UseInMemory()).AddMediator(typeof(Program).Assembly)
);
// ── Register GraphQL API ────────────────────────────────────────────────