The backend API for Eventuras - a comprehensive platform for knowledge managent, courses, events, and conferences.
This API serves as the core backend service for the Eventuras platform, providing:
Before you can run the API locally, ensure you have the following installed:
uuidv7() function added in PostgreSQL 18.NET Aspire orchestrates the whole stack — database, identity provider, mail and both apps — with a single command:
dotnet run --project src/Eventuras.AppHost
This will:
eventuras databaseghcr.io/losol/tessera-idp) with the development realm importedhttps://*.dev.localhostEverything is reached through Traefik, on hostnames rather than ports:
| Service | URL | Direct (bypasses the proxy) |
|---|---|---|
| Web | https://eventuras-web.dev.localhost | http://localhost:5100 |
| API | https://eventuras-api.dev.localhost | http://localhost:5101 |
| Keycloak | https://eventuras-id.dev.localhost (realm eventuras-dev, admin admin / admin) | — |
| Mailpit | https://eventuras-mail.dev.localhost | http://localhost:5103 |
Deployed environments sit behind Traefik, so development does too. That is not cosmetic: Keycloak derives issuer and redirect URLs from forwarded headers, and getting that wrong is invisible until it breaks in staging. Keycloak is therefore reachable only through the proxy, so there is one canonical issuer URL.
*.dev.localhost resolves to loopback without a hosts file, and the development
certificate already covers that suffix — so the browser, Node and .NET all trust
it with no extra setup. TLS ends at Traefik; the hop to Keycloak is plain http,
exactly as in a cluster.
Log in as [email protected]. Login is passwordless — the same email plus
one-time code flow that staging runs — so the code arrives in Mailpit.
The API's receipts and notifications land in Mailpit too, so a registration can be followed all the way to the message it produces. Two things make that work, and both are set up for you: Mailpit serves STARTTLS with the development certificate, because the API's SMTP sender always requires it, and the migration step points the first organization's SMTP settings at Mailpit. The API reads SMTP from organization settings rather than configuration, so without those rows it refuses to send at all. Deployments pass none of this and nothing is written.
No identity provider setup is needed: everything the realm needs is in
src/Eventuras.AppHost/realms/eventuras-dev-realm.json, which is the single
source of truth for it. Keycloak runs without a data volume on purpose, so the
realm is re-imported on every start and cannot drift into a container nobody can
reproduce. Anything you need on every run belongs in that file.
The realm lists every required action, with VERIFY_PROFILE switched off. The
login authenticator creates a user on first sign-in with no name, and that action
would stop each one on a profile form before the login completes, so no test
persona could ever log in. An import replaces the defaults wholesale, which is why
the list is there in full rather than the single entry that differs.
The realm's client secret and admin password are development fixtures for a localhost-only realm, deliberately committed so the setup is reproducible. Never import that realm into a deployed Keycloak.
The web app's OIDC client refuses a plain-http issuer and the API validates the
issuer's metadata over TLS, so Keycloak has to serve HTTPS locally. The AppHost
exports the ASP.NET Core development certificate to .certs/ (gitignored) on
first run, because it is the one certificate a .NET machine already trusts. If
the export fails, run this once:
dotnet dev-certs https --trust
The *.dev.localhost names are only in certificates created by the .NET 10 SDK. A
certificate from an older SDK covers localhost alone and has to be regenerated
with dotnet dev-certs https --clean, then the trust command above.
Node does not read the OS trust store, so the AppHost passes the same certificate
to the web app via NODE_EXTRA_CA_CERTS. Running pnpm dev by hand needs that
variable set too — see apps/web/.env-template.
The Playwright suite drives the same login flow, and reads the code from Mailpit.
The session secret is read from apps/web/.env, and Node needs the exported
certificate to reach the stack over HTTPS:
cd ../../tests/e2e
NODE_EXTRA_CA_CERTS=../../apps/api/src/Eventuras.AppHost/.certs/kc.pem \
E2E_WEB_URL=https://eventuras-web.dev.localhost E2E_API_URL=http://localhost:5101 \
[email protected] [email protected] \
E2E_OTP_SOURCE=mailpit E2E_MAILPIT_API_URL=http://localhost:5103 \
pnpm test
https://*.dev.localhost resets the connectionDocker Desktop can keep a stale forward for port 443 when a restart of the AppHost recreates the Traefik container: TCP connects, then every TLS handshake is reset, while the stack is otherwise healthy. Restarting the proxy registers the forward again:
aspire resource traefik restart
If you prefer to manage PostgreSQL yourself, follow the steps below.
The easiest way would be to use a docker compose file, for example from the losol/dockers repo.
Create a new PostgreSQL database for the project, and assign a user with permissions to use the database.
Set the environment variable for the connection string, or use dotnet user-secrets for local development.
dotnet user-secrets set "ConnectionStrings:DefaultConnection" "Host=localhost;Port=5432;Database=eventuras;Username=pguser;Password=pgpwd" --project src/Eventuras.WebApi
If using Azure PostgreSQL, the connection string would look something like this:
dotnet user-secrets set "ConnectionStrings:DefaultConnection" "Server=SERVER_NAME.postgres.database.azure.com;Database=DATABASE_NAME;Port=5432;User Id=DATABASE_USERNAME;Password=DATABASE_PASSWORD;Ssl Mode=Require;Trust Server Certificate=True" --project src/Eventuras.WebApi
Remember to open the necessary firewall rules to allow your local machine to connect to the Azure PostgreSQL instance.
Run Entity Framework migrations to set up the database schema:
dotnet ef database update --project src/Eventuras.WebApi
Start the development server:
dotnet run --project src/Eventuras.WebApi
Set environment variables for identity provider details, or set user-secrets for local development. You should at least set the following: Auth:ClientId, Auth:ClientSecret, Auth:Issuer, and Auth:ApiIdentifier.
Example using dotnet user-secrets:
dotnet user-secrets set "Auth:ClientId" "your-client-id" --project src/Eventuras.WebApi
dotnet user-secrets set "Auth:ClientSecret" "your-client-secret" --project src/Eventuras.WebApi
dotnet user-secrets set "Auth:Issuer" "https://your-tenant.auth0.com/" --project src/Eventuras.WebApi
dotnet user-secrets set "Auth:ApiIdentifier" "your-api-id" --project src/Eventuras.WebApi
If you want to use ConvertoAPI for PDF generation, set Converto:ClientId, Converto:ClientSecret, Converto:PdfEndpointUrl, and Converto:TokenEndpointUrl.
The API will be available at:
http://localhost:5000https://localhost:5001http://localhost:5000/docs (enabled in Development, or via FeatureManagement:EnableApiDocs)https://localhost:5002dotnet test
Create a new migration:
dotnet ef migrations add MigrationName
Apply migrations:
dotnet ef database update
Rollback to a specific migration:
dotnet ef database update PreviousMigrationName
Generate idempotent SQL script (for manual or CI/CD deployments):
cd src/Eventuras.Infrastructure
dotnet ef migrations script --idempotent \
-o sqlscript/database-migrations.sql \
--startup-project ../Eventuras.WebApi
Once the application is running, you can explore the API documentation at:
https://localhost:5001/docshttps://localhost:5001/openapi/v3.jsonAPI docs are enabled by default in Development. In other environments, set FeatureManagement:EnableApiDocs to true.
The API uses OpenTelemetry (via the ServiceDefaults project) to emit traces, metrics, and structured logs. During local development these are visible in the Aspire Dashboard. In production you can export the same telemetry to your Grafana stack.
Set the OTEL_EXPORTER_OTLP_ENDPOINT environment variable to point at an OpenTelemetry Collector or Grafana Alloy instance:
OTEL_EXPORTER_OTLP_ENDPOINT=http://alloy.internal:4317
The collector/Alloy then forwards:
Example Alloy receiver config:
otelcol.receiver.otlp "default" {
grpc { endpoint = "0.0.0.0:4317" }
http { endpoint = "0.0.0.0:4318" }
output {
metrics = [otelcol.exporter.prometheus.default.input]
traces = [otelcol.exporter.otlp.tempo.input]
logs = [otelcol.exporter.loki.default.input]
}
}
When running via the AppHost locally, OTEL_EXPORTER_OTLP_ENDPOINT is set automatically to point at the Aspire Dashboard. No extra config is needed for local development.
├── Controllers/ # API endpoints
├── Models/ # Domain models - should only be used for technical models, not business models
├── Services/ # Business logic
├── Infrastructure/ # Database context and configurations
├── Migrations/ # EF Core migrations
└── appsettings.json # Configuration files
Please read CONTRIBUTING.md for details on our code of conduct and the process for submitting pull requests.
Content type
Image
Digest
sha256:577e8fba4…
Size
153 MB
Last updated
3 days ago
docker pull losolio/eventuras-api