Skip to content

Quick Start Guide

Get the Cargonerds application running locally with a single command. The whole stack — SQL Server, Redis, RabbitMQ, the database migrator, three ABP .NET hosts and the Next.js frontend — is orchestrated by the .NET Aspire AppHost (src/Cargonerds.AppHost). You start that one project; it brings up everything else.

If you just want the short version

Clone → pwsh .githooks/install.ps1abp install-libs → generate openiddict.pfxdotnet run --project src/Cargonerds.AppHost → log in as admin / 1q2w3E*. The rest of this page explains each step and what to do when something goes wrong.

How the local stack fits together

The AppHost is a DistributedApplication whose resource graph is declared in src/Cargonerds.AppHost/Program.cs. In run mode (local dotnet run / F5) every infrastructure dependency is a real Docker container and the .NET hosts run as local processes. The wait edges below are what make the order deterministic: the migrator must finish before Auth/Api start, and the frontend waits for the API.

flowchart TD
    subgraph infra["Docker containers (persistent)"]
        DB["spark-db<br/>SQL Server :14330"]
        REDIS["spark-redis<br/>Redis (+ Insight/Commander)"]
        MQ["spark-rabbitmq<br/>RabbitMQ (+ mgmt plugin)"]
    end

    MIG["db-migrator<br/>Cargonerds.DbMigrator<br/>(runs to completion)"]
    AUTH["auth :44345<br/>Cargonerds.AuthServer"]
    API["api :44354<br/>Cargonerds.HttpApi.Host"]
    ADMIN["admin :44381<br/>Cargonerds.Blazor"]
    RT["realtime :4200<br/>frontend/realtime (Next.js)"]

    DB --> MIG
    MIG -->|WaitForCompletion| AUTH
    MIG -->|WaitForCompletion| API
    REDIS --> AUTH
    REDIS --> API
    MQ --> AUTH
    MQ --> API
    AUTH --> API
    AUTH --> ADMIN
    API --> ADMIN
    API --> RT
    AUTH --> RT

You do not start SQL Server / Redis / RabbitMQ yourself, and you do not run the DbMigrator separately — Aspire does both. See Architecture Overview and Aspire Integration for the full picture, and Running Locally for environment toggles and infra-only workflows.

Prerequisites

Make sure you have the following installed (see Prerequisites for details and version pins):

  • .NET 10 SDK + the .NET Aspire workload — Download
  • Node.js 22.x (the frontend/realtime app declares "engines": { "node": "22.x" }) — Download
  • Docker Desktop, running — Download
  • Git and PowerShell (pwsh)
  • ABP CLIdotnet tool install -g Volo.Abp.Cli (the repo pins AbpVersion 10.1.1 in common.props)

Docker must be running before you start the AppHost

The final line of Program.cs is builder.Build().EnsureDockerRunningIfLocalDebug().Run();. That Nextended.Aspire guard fails fast with a clear message if Docker Desktop is not running during local debugging — so start Docker first.

1. Clone the repository

git clone https://github.com/Cargonerds/CargonerdsApp.git
cd CargonerdsApp

2. Install Git hooks and frontend deps

pwsh .githooks/install.ps1

.githooks/install.ps1 does three things:

  1. Sets core.hooksPath to .githooks so the Husky.Net pre-commit hook (CSharpier + Prettier) is active.
  2. Runs dotnet tool restore to restore the local .NET tools (CSharpier + Husky).
  3. Runs npm i inside frontend/.

It also adds /.claude and .worktrees to .git/info/exclude (per-clone ignore for AI worktrees; see AGENTS.md). The script requires PowerShell (pwsh); it ships natively on Windows, and on Linux/macOS you install PowerShell Core. Formatting also runs automatically on every commit — see the Development Workflow for what the hook formats and how to run it manually.

3. Install ABP client-side libraries

abp install-libs

This downloads the JavaScript/CSS libraries the Blazor/MVC UIs expect (the LeptonX theme assets and ABP's bundled scripts). ABP normally runs this when a solution is first created; after a fresh clone you must run it yourself, and again whenever a new client-side package dependency is added.

4. Generate the OpenIddict signing certificate

The AuthServer needs an openiddict.pfx certificate for token signing/encryption. From the repo root:

dotnet dev-certs https -v -ep openiddict.pfx -p d9efcd01-fbd8-42b1-a9d1-a5cf44afe714

In Development, ABP's OpenIddict module uses a development encryption/signing certificate automatically, so this file is primarily what non-Development runs expect. CargonerdsAuthServerModule only calls AddProductionEncryptionAndSigningCertificate("openiddict.pfx", configuration["AuthServer:CertificatePassPhrase"]!) outside Development; the passphrase default lives in src/Cargonerds.AuthServer/appsettings.json (AuthServer:CertificatePassPhrase = d9efcd01-fbd8-42b1-a9d1-a5cf44afe714).

The default password is for development only

d9efcd01-fbd8-42b1-a9d1-a5cf44afe714 is the well-known development password and is fine for local work. Use a different certificate and password in production — see the root README.md (it also documents the extra Linux steps to trust the cert) and the OpenIddict docs.

5. Configure connection strings and secrets

For a default local run you can skip this step — the solution ships with working defaults and Aspire injects the database connection string for you. Read this section only if you need to point at your own database or a real Hub data source.

What Aspire injects automatically

When you launch the AppHost, each .NET host is started with USE_ASPIRE_CONFIG=true (set by AddProjectWithDefaults in src/Cargonerds.AppHost/Extensions/ResourceBuilderExtensions.cs). That flag makes the host load its committed appsettings.aspire.json, whose {token} placeholders are resolved to live Aspire endpoints/connection strings at startup. For example src/Cargonerds.HttpApi.Host/appsettings.aspire.json resolves {auth}, {api}, {redis} and {messaging} to the real containers and services Aspire just started. The Default (Spark) database connection string is supplied by Aspire via .WithReference(db, "Default").

USE_ASPIRE_CONFIG is mandatory under the AppHost

Per EnvVars.UseAspireConfig: "If not set the default ABP configuration will be used which is not compatible with the Aspire AppHost." The AppHost always sets it for the four hosted projects. If you ever launch a single host directly (IIS Express / dotnet run on that project) you must set USE_ASPIRE_CONFIG=true yourself, or it falls back to the static appsettings.json values.

The two databases

There are two connection strings, and they are selected independently:

Connection string Constant Holds Selected by
Default ConnectionStringNames.SparkDb ABP Identity, OpenIddict, Settings, Features, AuditLogging, CmsKit, BlobStoring (DB) and Hangfire storage Aspire db container locally; AZURE_ENVIRONMENT in the cloud
Hub ConnectionStringNames.HubDb Hub domain DB (shipments, organizations, tracking, pricing) SPARK_ENVIRONMENT (defaults to dev)

The local default for Default (in the AuthServer/API appsettings.json) is LocalDB: Server=(LocalDb)\MSSQLLocalDB;Database=CargonerdsAppDb;Trusted_Connection=True;TrustServerCertificate=true — but under Aspire it is overridden by the injected container connection string. The Hub DB has no local default; it comes from the appsettings.spark.<env>.json files. With SPARK_ENVIRONMENT unset, SparkEnvironment.FromName(null) resolves to dev, so the backend talks to the Hub-Dev database out of the box. See Configuration & appsettings for the full layering and token system.

Running against your own local Hub database

To use a local Hub DB instead of Hub-Dev, set SPARK_ENVIRONMENT=local and create src/Cargonerds.HttpApi.Host/appsettings.spark.local.user.json with your local App:CargonerdsCustomerId (the file is git-ignored). Details and the full per-environment matrix are in Running Locally.

Secrets / user-secrets

The only ABP user-secrets file in play is appsettings.secrets.json, which holds the AbpLicenseCode and is loaded by ABP's AddAppSettingsSecretsJson() in each host's Program.cs. The AppHost project carries a UserSecretsId (cd27754a-…) so you can store machine-local overrides there if needed, but a default clone does not require populating it.

Committed credentials

Several appsettings.*.json files (appsettings.azure.*.json, appsettings.spark.*.json, appsettings.rohlig.json, appsettings.secrets.json) contain real SQL/Redis/RabbitMQ credentials, API keys and the ABP license that are checked into the repo. Treat them as sensitive, and never re-commit rotated secrets. This is a known issue flagged in the configuration analysis.

6. Run the application

dotnet run --project src/Cargonerds.AppHost

This single command:

  • Provisions SQL Server (spark-db, fixed TCP port 14330), Redis (spark-redis, with RedisInsight + Redis Commander side-cars) and RabbitMQ (spark-rabbitmq, management plugin) as persistent Docker containers (ContainerLifetime.Persistent, so data survives restarts).
  • Runs the db-migrator (Cargonerds.DbMigrator) to apply EF Core migrations and seed data, then waits for it to complete (WaitForCompletion) before starting Auth and Api.
  • Starts auth (Cargonerds.AuthServer), api (Cargonerds.HttpApi.Host) and admin (Cargonerds.Blazor).
  • Discovers and starts every frontend under frontend/ that has a Dockerfile (currently the realtime Next.js app) via AddAllFrontends(), wiring API_URL, AuthServer__Authority, APP_URL and the MapTiler key through WithNextAuth.
  • Registers the documentation site as a container resource — but with WithExplicitStart(), so it is not started automatically; start it from the dashboard when you want it.
  • Opens the Aspire dashboard, which lists the live URLs, health status, logs and distributed traces for every resource.

What comes up — services and run-mode ports

Always read live URLs from the Aspire dashboard; endpoints are assigned dynamically. In local run mode these HTTPS ports are fixed in src/Cargonerds.AppHost/RunModeServicePorts.cs (the realtime port is pinned in Extensions/DistributedAppBuilderExtensions.cs):

Aspire resource Project URL Notes
auth Cargonerds.AuthServer https://localhost:44345 OpenIddict / login UI
api Cargonerds.HttpApi.Host https://localhost:44354 REST API + Swagger
admin Cargonerds.Blazor https://localhost:44381 LeptonX admin shell
realtime frontend/realtime (Next.js) http://localhost:4200 the main app UI
db-migrator Cargonerds.DbMigrator console runs to completion, then exits
documentation this MkDocs site started on demand from the dashboard WithExplicitStart()

First run is slow

The first launch pulls the SQL Server / Redis / RabbitMQ images and runs all migrations, so it takes noticeably longer than subsequent runs. The persistent data volumes (spark-db, spark-redis) mean later starts are much faster — the migrator finds the schema already current.

Speeding up iteration

The AppHost reads two env vars (see EnvVars.cs) that relax the inter-service wait/health gating when you are iterating on a single service:

  • SKIP_WAITING_IN_BACKEND=1 — don't wait for migrator/auth/health before starting dependents.
  • EXPLICIT_FRONTEND_START=1 — require manually starting the frontends from the dashboard.

7. Log in

Use the seeded administrator account (created by the DbMigrator's identity seeding):

  • Username: admin (email admin@cargonerds.com)
  • Password: 1q2w3E*

Open the realtime app (http://localhost:4200) or the admin Blazor app (https://localhost:44381) and sign in — both redirect to the AuthServer (auth) for authentication via OpenIddict. The admin user is a full administrator managed by ABP Identity.

Trust the dev HTTPS certificate

The backend hosts run on HTTPS. If your browser refuses the localhost certificate, trust the ASP.NET Core dev cert (dotnet dev-certs https --trust) — see Certificate errors below.

Verify the installation

  • Aspire dashboard: every resource should show a healthy / running state, and db-migrator should show as completed.
  • API: the api resource exposes the ABP application-configuration endpoint at /api/abp/application-configuration (used as its readiness check); Swagger is at {api}/swagger. The AppHost also wires a /health-status check via WithHealthStatusCheck().
  • Admin UI: the admin resource has a / health check and should render the LeptonX shell after login.

Common issues

Docker not running

Start Docker Desktop before running the AppHost — EnsureDockerRunningIfLocalDebug() aborts startup otherwise.

Port already in use

The fixed run-mode ports must be free: 44345 (auth), 44354 (api), 44381 (admin), 4200 (realtime), and the SQL container's TCP 14330. The SQL endpoint is un-proxied (IsProxied = false), so a stray local SQL Server on 14330 will conflict. Stop whatever is bound to the port, or adjust RunModeServicePorts.cs (and the FrontendPorts map for realtime).

Certificate errors

dotnet dev-certs https --clean
dotnet dev-certs https --trust

Then regenerate openiddict.pfx (step 4).

Service-discovery token error at startup

If a host throws an InvalidOperationException listing "Available: …" services, an appsettings.aspire.json value references a {name} token that has no matching Aspire endpoint or connection string. This usually means a resource was renamed/removed in Program.cs but the token was left behind. See Configuration & appsettings.

Database / connection issues

Inspect the spark-db, spark-redis and spark-rabbitmq containers from the Aspire dashboard or docker ps. The Default connection string is injected by Aspire; for Hub data, check your SPARK_ENVIRONMENT value (defaults to dev). A typo'd SPARK_ENVIRONMENT crashes startup (SparkEnvironment.FromName throws on unknown names) rather than silently defaulting — see Running Locally.

Next steps