# NomiEsb — Full Documentation > Web-based management console for building, deploying, and operating .NET integration modules on Kubernetes. The documentation below covers product overview, installation, configuration, and a page-by-page user guide. Source files are published at https://nomiesb.com/content/.md and rendered at https://nomiesb.com/docs/. --- # NomiEsb Documentation NomiEsb is a web-based management console for building, deploying, and operating .NET integration modules on Kubernetes. ![NomiEsb Dashboard](images/dashboard.png) ## In this guide The documentation is organised into four sections. Use the sidebar to navigate, or follow the links below. ### Getting Started What NomiEsb is, who it's for, and the concepts you need to know before installing. - [What is NomiEsb?](/docs/gs-introduction) - [Core concepts](/docs/gs-concepts) - [Roles and access](/docs/gs-roles) ### Installation Step-by-step administrator guide to install NomiEsb on a server, register the Entra ID application, prepare the database, and apply the license. - [Prerequisites](/docs/install-prerequisites) - [Database setup](/docs/install-database) - [Entra ID application and groups](/docs/install-entra-id) - [Encryption key and license file](/docs/install-secrets) - [appsettings.json reference](/docs/install-configuration) - [Running and verifying NomiEsb](/docs/install-run) ### Configuration Everything you configure in the console after installation: license, app settings, integrations, environments, users, and tokens. - [License](/docs/config-license) - [App settings](/docs/config-app-settings) - [Environments, systems and tags](/docs/config-environments) - [Integrations](/docs/config-integrations) - [Users and CLI licenses](/docs/config-users) - [API and MCP tokens](/docs/config-tokens) ### User Guide Page-by-page walkthrough of every screen in the console. - [Layout and navigation](/docs/guide-overview) - [Dashboard](/docs/guide-dashboard) - [Solutions, modules and libraries](/docs/guide-solutions) - [Clusters and hosts](/docs/guide-clusters) - [Settings](/docs/guide-settings) - [Profile, applications and notifications](/docs/guide-account) --- # What is NomiEsb? NomiEsb is the management console for the Nomirun platform — a development and deployment system for .NET integration services running on Kubernetes. It is delivered as a single self-contained executable (or container image) that you host on your own infrastructure. The console is the place where teams: - organise their .NET **modules** and **libraries** into deployable **solutions**, - declare the **Kubernetes clusters** and **hosts** that run those modules, - connect **CI/CD platforms** (Azure DevOps, GitHub, GitLab, Bitbucket) and **ArgoCD** for GitOps delivery, - manage **users, roles, integrations, tags and licenses**, - and monitor **builds, deployments, and audit history** in one place. NomiEsb is the web tier. The companion **Nomirun CLI** is a separate tool that developers install on their workstations to scaffold and build modules locally; the console manages, schedules, and tracks the work the CLI produces. ## What NomiEsb is not NomiEsb does not replace your CI/CD platform, your Kubernetes control plane, or your Git provider — it orchestrates them. Builds run in your Azure DevOps / GitHub / GitLab / Bitbucket pipelines. Deployments are applied by ArgoCD against your own clusters. NomiEsb stores the configuration, triggers the actions, and shows you the status. ## How a typical day looks Once an administrator has installed NomiEsb, applied the license, and connected the integrations, a normal workflow is: 1. A **Developer** opens **Solutions → Quick Start**, fills in a solution name, picks a Git repo, lists the modules to create, and clicks initialise. NomiEsb pushes the solution template, creates the pipelines, and the first build runs. 2. A **DevOps** user opens **Clusters → Quick Start**, names the cluster, adds hosts, and assigns the new modules to them. 3. NomiEsb shows the live deployment state on the **Dashboard**, pulled from ArgoCD. 4. **Notifications** fire if a build fails, an integration token is about to expire, or a host becomes unhealthy. 5. The **Audit Trail** records every change for compliance. ## Next - [Core concepts](/docs/gs-concepts) — the six terms used throughout the console. - [Roles and access](/docs/gs-roles) — how Admin, Developer and DevOps map to Entra ID security groups. --- # Core concepts These six terms appear everywhere in the console. Read them once before going further — every page assumes you know what they mean. | Concept | Description | |---------|-------------| | **Module** | A single .NET project that does one job (an integration, a worker, an API). Versioned, packaged as NuGet, deployed as a container. | | **Library** | A reusable .NET project shared across modules. Same lifecycle as a module but consumed instead of deployed. | | **Solution** | A logical grouping of modules and libraries backed by a single Git repository. The unit of CI/CD initialisation. | | **Cluster** | A Kubernetes cluster definition in NomiEsb. Holds one or more hosts and is tagged with an environment and an optional system. | | **Host** | A deployable process running inside a cluster. A host runs one or more modules and can be extended with **extensions**. | | **Extension** | An optional capability (caching, telemetry, custom middleware) added to a host on top of its modules. | ## How they relate ``` Solution (Git repo) ├── Module A ├── Module B └── Library C Cluster (Kubernetes) ├── Host "api-gateway" ── Module A, Module B + Extensions └── Host "worker" ── Module B + Extensions ``` Solutions describe **what gets built**. Clusters describe **where it runs**. The same module can be deployed to multiple hosts in multiple clusters. ## How they map to console pages | Concept | Where you manage it | |---------|---------------------| | Solution | **Solutions** → expand a row, or **Solutions → Quick Start** for new solutions | | Module | **Solutions → Module Details** (deep link from any module table) | | Library | **Solutions → Library Details** | | Cluster | **Clusters** → expand a row, or **Clusters → Quick Start** | | Host | **Clusters** → expand a cluster, or **Host Details** | | Extension | Inside a host card on **Clusters** or **Host Details** | ## Next - [Roles and access](/docs/gs-roles) — who can do what. - [Installation prerequisites](/docs/install-prerequisites) — what you need before installing. --- # Roles and access NomiEsb has exactly three roles. Every page is gated by them, and every user is assigned to one through an Entra ID security group. | Role | Typical user | Responsibilities | |------|--------------|------------------| | **Admin** | Platform owner / IT lead | Installs and configures the system; manages users, integrations, license, audit trail. Can see everything. | | **Developer** | Backend / integration developer | Owns solutions, modules, and libraries. Creates and initialises new solutions through the Quick Start wizard. | | **DevOps** | Operations / SRE | Owns clusters, hosts, integrations, and deployments. Builds and deploys modules to hosts. | A user with no Nomirun group membership can sign in but will see only an unauthorised screen. ## What each role can see | Page | Admin | Developer | DevOps | |------|:-----:|:---------:|:------:| | Dashboard | ✓ | ✓ | ✓ | | Solutions, Module Details, Library Details | ✓ | ✓ | — | | Solution Quick Start | ✓ | ✓ | — | | Clusters, Host Details | ✓ | — | ✓ | | Cluster Quick Start | ✓ | — | ✓ | | Settings → Integrations | ✓ | — | ✓ | | Settings → App, Environments, Systems, Tags, Users, Roles, License | ✓ | — | — | | Audit Trail | ✓ | — | — | | Profile, Applications, Notifications, Documentation | ✓ | ✓ | ✓ | ## How roles are assigned Roles come from membership in three Microsoft Entra ID security groups. NomiEsb matches the group **display name** first; if your tenant uses different names, the **object ID** is matched as a fallback (configured under `NomirunGroups` in `appsettings.json`). | Entra ID group name | NomiEsb role | |---------------------|--------------| | `Nomirun_Admin` | Admin | | `Nomirun_Developer` | Developer | | `Nomirun_DevOps` | DevOps | When a user signs in, NomiEsb queries Microsoft Graph for the user's groups, picks the highest-precedence role (Admin > DevOps > Developer), and persists it to the database. Provisioning the groups is part of the [Entra ID setup](/docs/install-entra-id). ## Next If you are an administrator preparing to install NomiEsb, continue to [Installation prerequisites](/docs/install-prerequisites). Otherwise, skip ahead to the [User Guide](/docs/guide-overview). --- # Prerequisites This section starts the administrator-facing installation. Gather everything below before going further; each later page assumes the items here are in place. ## Hardware and OS NomiEsb is shipped as a self-contained binary, so you do not need to install .NET on the server. | Requirement | Notes | |-------------|-------| | **Operating system** | Windows 10/11, Windows Server, any modern Linux distribution, or macOS. x64 or arm64. | | **CPU / RAM** | 2 vCPU and 2 GB RAM are enough for small teams. The console is mostly idle between requests. | | **Disk** | A few hundred megabytes for the binary and assets. Logs and audit data live in the database. | | **Reachable hostname** | A DNS name and TLS certificate the browser can reach (for example `https://app.nomiesb.example.com`). Required by Entra ID for the OIDC redirect URI. | NomiEsb does **not** terminate TLS. Run it behind a reverse proxy (NGINX, IIS, Azure Front Door, Traefik, …) that provides the certificate and forwards to NomiEsb's listening port. ## External services | Requirement | Used for | |-------------|----------| | **Database** | PostgreSQL 14+ **or** Microsoft SQL Server 2019+. NomiEsb creates and migrates its own schema. See [Database setup](/docs/install-database). | | **Microsoft Entra ID tenant** | Sign-in and role assignment. You will register one application and three security groups. See [Entra ID setup](/docs/install-entra-id). | | **License file** | A `nomiesb.license` issued by Nomirun. The application refuses to start in release mode without one. See [Encryption key and license](/docs/install-secrets). | | **Outbound network** | Access to `login.microsoftonline.com`, `graph.microsoft.com`, your CI/CD platform APIs, and your ArgoCD server. | ## Optional, recommended - A reverse proxy with TLS (already mentioned). - An SMTP server, if you want notification emails. - Access to your Kubernetes clusters and an ArgoCD installation, if you want NomiEsb to drive deployments. ## Next When you have the items above, continue to [Database setup](/docs/install-database). --- # Database setup NomiEsb supports two database providers, selected by the `Database:Provider` setting in `appsettings.json`. The default is **PostgreSQL**. NomiEsb creates and migrates its own schema on first start — there is no separate `dotnet ef database update` step for operators. ## PostgreSQL 1. Create an empty database, for example `nomirun-esb`. 2. Create a user with full rights on that database. 3. Note the connection string in this format: ``` Server=db.example.com;Port=5432;Database=nomirun-esb;User ID=nomirun;Password=...;Include Error Detail=false ``` In `appsettings.json` no `Database:Provider` value is needed (PostgreSQL is the default). Set the connection string under `ConnectionStrings:DefaultConnection`. ## Microsoft SQL Server 1. Create an empty database, for example `nomirun`. 2. Create a SQL login with `db_owner` on that database (or use Windows / managed identity). 3. Note the connection string, for example: ``` Server=sql.example.com;Database=nomirun;User Id=nomirun;Password=...;TrustServerCertificate=True ``` In `appsettings.json` set `Database:Provider` to `SqlServer`. NomiEsb runs the matching migration set (`Migrations/Postgresql/` or `Migrations/SqlServer/`) automatically. ## Backup Treat the NomiEsb database as the source of truth. It stores integrations (with encrypted tokens), users, audit history, notifications, and every solution / cluster / host configuration. Take a backup before every upgrade and as part of your regular DR plan. ## Health check After NomiEsb is running, the unauthenticated endpoint `GET /health` returns `Healthy` only if the database is reachable. Use it for load-balancer health checks. For Kubernetes, prefer the dedicated `/startup`, `/readiness`, and `/liveness` probe endpoints described in **[Running and verifying](/docs/install-run)**. ## Next Continue to [Entra ID application and groups](/docs/install-entra-id). --- # Entra ID application and groups NomiEsb signs users in through OpenID Connect against Azure Entra ID and looks up their group memberships through Microsoft Graph. Two artifacts must exist in your tenant: an **app registration** and three **security groups**. ## 1. Register the application In the Azure portal go to **Microsoft Entra ID → App registrations → New registration**. | Field | Value | |-------|-------| | Name | `NomiEsb` | | Supported account types | *Accounts in this organizational directory only* | | Redirect URI | **Web**, value `https:///signin-oidc` | After it is created, copy the **Application (client) ID** and the **Directory (tenant) ID**. ### Client secret Open **Certificates & secrets → New client secret** and copy the secret **value** (not the ID). Store it somewhere safe — Azure shows it only once. ### Authentication Open the **Authentication** blade: - Set **Front-channel logout URL** to `https:///signout-callback-oidc`. - Tick **ID tokens (used for implicit and hybrid flows)** under *Implicit grant and hybrid flows*. ### API permissions Open **API permissions → Add a permission → Microsoft Graph → Delegated permissions** and add: - `User.Read` - `User.Read.All` - `GroupMember.Read.All` Click **Grant admin consent for ** so users can sign in without an interactive consent prompt. ## 2. Create the role security groups NomiEsb maps Entra ID security groups to its three roles. In **Microsoft Entra ID → Groups** create three groups: | Group name | Maps to NomiEsb role | |------------|----------------------| | `Nomirun_Admin` | Admin | | `Nomirun_Developer` | Developer | | `Nomirun_DevOps` | DevOps | Add at least one user to `Nomirun_Admin` — that account becomes your first administrator. Copy the **object ID** of each group. NomiEsb matches groups by their **display name** first; if you cannot use the names above (for example, you have a corporate naming standard), provide the object IDs in `appsettings.json` under `NomirunGroups` and the matching falls back to those. A user who authenticates successfully but is in none of the three groups can sign in but cannot reach any feature page. ## Next Continue to [Encryption key and license file](/docs/install-secrets). --- # Encryption key and license file Two secrets are required before NomiEsb starts: an encryption key for at-rest protection of integration credentials, and a license file from Nomirun. ## Generate the encryption key NomiEsb encrypts integration tokens, SMTP passwords, registry credentials, and other secrets at rest with AES-256-GCM. You must supply the 32-byte key as a Base64 string. Generate one with OpenSSL: ```bash openssl rand -base64 32 ``` Or with PowerShell: ```powershell [Convert]::ToBase64String([System.Security.Cryptography.RandomNumberGenerator]::GetBytes(32)) ``` Keep the output safe. Losing it makes the encrypted database rows unreadable, and the only recovery is to delete and re-enter every integration. The value is read from the `ENCRYPTION_KEY` environment variable (recommended) or from the `ENCRYPTION_KEY` key in `appsettings.json`. Use the environment variable in production. ## Place the license file Copy your `nomiesb.license` into one of these two locations next to the binary: ``` /nomiesb.license /license/nomiesb.license ``` NomiEsb checks both paths on startup, validates the file, prints a banner showing the company name and expiration date, and refuses to start (in release mode) if the file is missing, invalid, or expired. Inside a container, mount the directory containing the license file at `/app/license`, or place the file at `/app/nomiesb.license`. ## Where the license appears in the console After sign-in, the Admin can review the loaded license at **Settings → License**. The page shows the company details, subscription plan, expiration date, and the number of CLI seats included in the subscription. The same data is read directly from the file plus a periodic call to the Nomirun licensing service. ## Next Continue to the [appsettings.json reference](/docs/install-configuration). --- # appsettings.json reference Edit `appsettings.json` (or `appsettings.Production.json`) shipped beside the binary. The minimal production configuration is: ```json { "Hostname": "https://app.nomiesb.example.com", "ENCRYPTION_KEY": "", "Database": { "Provider": "Postgres" }, "ConnectionStrings": { "DefaultConnection": "Server=db.example.com;Port=5432;Database=nomirun-esb;User ID=nomirun;Password=...;Include Error Detail=false" }, "AzureAd": { "Instance": "https://login.microsoftonline.com/", "TenantId": "", "ClientId": "", "ClientSecret": "", "CallbackPath": "/signin-oidc", "SignedOutCallbackPath": "/signout-callback-oidc" }, "Graph": { "Scopes": [ "User.Read", "User.Read.All", "GroupMember.Read.All" ] }, "NomirunGroups": { "Admin": "", "Developer": "", "DevOps": "" } } ``` ## Setting reference | Setting | Required | Purpose | |---------|----------|---------| | `Hostname` | Yes | Public URL of the console. Used for CORS, the OIDC redirect-URI check, and the absolute links in notification emails. | | `ENCRYPTION_KEY` | Yes | Base64 32-byte key for symmetric encryption of secrets at rest. | | `Database:Provider` | No (defaults to `Postgres`) | `Postgres` or `SqlServer`. | | `ConnectionStrings:DefaultConnection` | Yes | Connection string for the chosen provider. | | `AzureAd:TenantId` / `ClientId` / `ClientSecret` | Yes | Values from your Entra ID app registration. | | `AzureAd:CallbackPath` / `SignedOutCallbackPath` | Yes | Must match the redirect URIs registered in Azure (`/signin-oidc`, `/signout-callback-oidc`). | | `Graph:Scopes` | Yes | Delegated Graph permissions; leave the three defaults unchanged. | | `NomirunGroups:Admin` / `Developer` / `DevOps` | Recommended | Object IDs of the three role groups. Optional if your group display names match `Nomirun_Admin` etc. | | `LicensingApi:BaseUrl` | No (defaults to the public Nomirun service) | Override only when pointing to a private licensing endpoint. | | `Logging:LogLevel:*` | No | Standard ASP.NET Core logging configuration consumed by Serilog (console sink). | ## Overriding with environment variables Every setting can be overridden by an environment variable using `__` (double underscore) for nesting. This is the recommended way to pass secrets in production: ```bash export ENCRYPTION_KEY="..." export ConnectionStrings__DefaultConnection="..." export AzureAd__ClientSecret="..." ``` `ASPNETCORE_ENVIRONMENT` defaults to `Production` if not set. `ASPNETCORE_URLS` controls the listening URLs (for example `http://0.0.0.0:8080;https://0.0.0.0:8443`). ## What is configured here vs in the console This file contains only the values NomiEsb needs at startup. Everything else — license details, app settings, integrations, environments, tags, users, tokens — is stored in the database and managed through the **Configuration** pages once you can sign in. ## Next Continue to [Running and verifying NomiEsb](/docs/install-run). --- # Running and verifying NomiEsb With prerequisites met, the database created, Entra ID configured, secrets in place and `appsettings.json` populated, NomiEsb is ready to start. ## Native binary Extract the release archive into your install directory and run the executable: ```bash ./Nomirun.Esb # Linux / macOS Nomirun.Esb.exe # Windows ``` On startup NomiEsb prints a banner, validates the license, runs database migrations, and begins listening on the URLs from `ASPNETCORE_URLS`. To run as a long-lived service, use **systemd** on Linux or **sc.exe** / **NSSM** on Windows. Point the service at the executable, set the working directory to the install folder, and pass the secrets through environment variables. ## Docker A container image is published with the binary and an Alpine base. Run it with: ```bash docker run -d \ --name nomiesb \ -p 8080:8080 \ -v /etc/nomiesb/license:/app/license:ro \ -e ASPNETCORE_URLS=http://0.0.0.0:8080 \ -e Hostname=https://app.nomiesb.example.com \ -e ENCRYPTION_KEY=... \ -e ConnectionStrings__DefaultConnection="Server=...;..." \ -e AzureAd__TenantId=... \ -e AzureAd__ClientId=... \ -e AzureAd__ClientSecret=... \ nomirun/nomiesb:latest ``` ## First sign-in 1. Open `https:///` in a browser. 2. Click **Sign in with Microsoft** and authenticate as a user belonging to `Nomirun_Admin`. 3. NomiEsb provisions your user record, persists your role, and lands you on the **Dashboard**. 4. The Dashboard shows yellow setup banners for any missing essentials (system settings, DevOps integration, ArgoCD integration). Follow the links to address them — they are covered in the **Configuration** section. ## Health checks NomiEsb exposes four unauthenticated health endpoints. `/health` is the aggregate check (every registered probe must pass); the other three match the Kubernetes probe lifecycle and only run the checks tagged for that probe so a temporary downstream blip cannot restart the pod unnecessarily. | Endpoint | Intended use | What it runs | |----------|--------------|--------------| | `GET /health` | Load-balancer or overall health page | All registered checks | | `GET /startup` | Kubernetes **startupProbe** | Waits until the application lifetime has fired `ApplicationStarted` (migrations done, listeners bound) | | `GET /readiness` | Kubernetes **readinessProbe** | Database reachable — the app can serve traffic | | `GET /liveness` | Kubernetes **livenessProbe** | Lightweight self-check — the process is alive | Example Kubernetes probe wiring: ```yaml startupProbe: httpGet: path: /startup port: 8080 failureThreshold: 30 periodSeconds: 10 readinessProbe: httpGet: path: /readiness port: 8080 periodSeconds: 10 livenessProbe: httpGet: path: /liveness port: 8080 periodSeconds: 20 ``` Each endpoint returns `200 Healthy` when every check matching its probe tag passes, and `503 Unhealthy` otherwise. ## Hardening notes These defaults are baked into the binary; you do not need to configure them, but you should be aware: - TLS: NomiEsb does **not** terminate TLS. Front it with a reverse proxy. - Security headers: HSTS, `X-Content-Type-Options`, `X-Frame-Options: DENY`, a strict `Referrer-Policy`, and a `Content-Security-Policy` are emitted on every non-development response. - Rate limiting: 1000 requests per minute per IP globally; 5 / minute on auth endpoints; 100 / minute on the MCP endpoint. - Authentication cookies are `HttpOnly`, `Secure`, `SameSite=Lax`, and stored server-side. - Incoming JSON bodies pass through HTML-stripping middleware to mitigate stored XSS. ## Upgrading Stop the service, replace the binary (or pull the new container image), and start it again. Migrations run automatically on the next startup. Always back up the database first. ## Troubleshooting | Symptom | Likely cause | |---------|--------------| | `No valid NomiEsb license found.` on startup | License file not in `./nomiesb.license` or `./license/nomiesb.license`, or expired. | | Sign-in loop or `AADSTS50011` | Redirect URI in the Entra ID app does not match `Hostname/signin-oidc`. | | User signs in but lands on the unauthorised page | User is in none of the three Nomirun groups, or `NomirunGroups` IDs are wrong. | | `Failed to map roles from MS Graph` warning in logs | Graph permissions not granted, or admin consent not given. | | `/health` or `/readiness` returns `Unhealthy` | Database unreachable, or `Database:Provider` does not match the actual server. | | `/startup` keeps returning `Unhealthy` | Application lifetime has not reported `Started` — migrations or bootstrap still running, or a fatal error before `app.Run()`. Check the startup log. | When in doubt, check the console output — Serilog logs to standard output and includes all startup decisions, the matched license file, the database provider, and any auth-pipeline warnings. ## Next Once the system starts successfully, continue with the [Configuration](/docs/config-license) section to wire up the rest. --- # License Open **Settings → License** as your first stop after sign-in. The page is the single source of truth for the license currently driving the system. ## What the page shows | Card | Contents | |------|----------| | **Organisation** | License ID, company, address, VAT, DUNS, primary contact and email. All read-only — values come from the license file. | | **Subscription** | Plan, start date, expiration date with a colour-coded status badge: *Active* (green), *Expiring soon* (yellow, ≤ 30 days), *Renew now* (red, ≤ 7 days), *Expired* (red). The **Renew** button links to support. | | **CLI licenses** | Total seats included in the subscription, currently used, and available, with a coloured progress bar. | ## When the page is empty If the system is unlicensed (file missing, invalid, or expired), every other Configuration page is locked and the License page shows a warning with renewal instructions. Re-check the file path next to the binary — it must be at `nomiesb.license` or `license/nomiesb.license` — and restart the service. ## How CLI seats are consumed Seats are not consumed automatically by sign-in. They only count once an Admin enables the **CLI license** toggle on a user's card in **Settings → Users**. Releasing a seat is just toggling the flag back off; the user keeps their account and history. ## Background renewal check The **Subscription expiry check** background job runs daily and creates a notification 30, 14, and 7 days before the recorded expiration. The notification goes to all Admins. The job's schedule is configurable on **Settings → App**. ## Next Continue to [App settings](/docs/config-app-settings). --- # App settings Open **Settings → App**. This is where the system-wide knobs live. The page is split into two tabs. ## General tab | Setting | What it controls | |---------|------------------| | **Application log retention** | Days of Serilog rolling logs to keep. Pick from 1 / 3 / 7 / 30. | | **Audit log retention** | Days of audit-trail rows to keep. Pick from 30 / 60 / 90 / 180 / 365. | | **Notification retention** | Days resolved notifications survive before deletion. | | **Background job schedules** | Cron expressions for the maintenance jobs (see below). | | **Host health monitoring** | Enable continuous polling of host health, set the interval (cron), and optionally restrict it to specific environments. Off by default. | | **LLM endpoints** | Connection details for AI-assisted features (release notes, AI chat). Pick a provider, endpoint URL, API key, and model name. Only one endpoint is active at a time. | | **Auto-generate release notes** | When on, NomiEsb asks the active LLM endpoint to draft release notes after a successful module / library build. | ### Cron schedules All schedules accept the standard 5-field cron syntax (`minute hour day month dow`). | Job | Default | Purpose | |-----|---------|---------| | Subscription expiry check | `0 1 * * *` | Notifies admins 7–30 days before the NomiEsb license expires. | | Integration token expiry | `5 1 * * *` | Notifies admins / DevOps when an integration credential is approaching its recorded expiry. | | Application log retention | `0 2 * * *` | Deletes app log rows older than the configured retention. | | Audit log retention | `15 2 * * *` | Deletes audit rows older than the configured retention. | | Notification retention | `30 2 * * *` | Removes resolved notifications. | | Email digest | `*/15 * * * *` | Sends the queued notification email batch. | | Host health monitor | `*/2 * * * *` (when enabled) | Polls ArgoCD for sync / health and creates notifications on degradation. | Two more jobs run continuously and are not user-scheduled: - **Build status poller** — polls running CI builds and updates their status. - **Device-code cleanup** — removes expired CLI device-login codes. ## System tab The System tab is the post-install checklist. The Dashboard shows a yellow setup banner until everything here is filled in. | Setting | What to enter | |---------|---------------| | **SMTP server** | Host, port, username, password, from-address, SSL/TLS flag. The password is encrypted at rest. A **Test email** button sends a test message to the logged-in user's address. | | **Default container registry** | Host, username, and password used when modules are pushed as container images. | | **Default NuGet repository** | URL plus credentials of the feed used to publish module / library packages. | | **Host API key** | Token the Nomirun Host service uses when calling back into the ESB API. Generated here, copied into each host installation. | | **Custom NuGet repositories** | Additional feeds (private feeds, Azure Artifacts, etc.). | | **Custom container registries** | Additional registries (ECR, GCR, private Docker, etc.). | Sensitive fields (passwords, tokens, API keys) are encrypted at rest using the encryption key configured at install time. ## Next Continue to [Environments, systems and tags](/docs/config-environments). --- # Environments, systems and tags These three pages are simple tables but they shape how every cluster, solution and module is filtered and grouped throughout the console. Set them up once before you create your first cluster. ## Environments Open **Settings → Environments**. Environments are the labels you attach to clusters so you can tell production apart from staging at a glance. Click **Add environment** and provide: - **Name** — `Production`, `Staging`, `Dev`, etc. - **Colour** — shown everywhere a cluster is rendered. - **Sort order** — controls the order in lists. Existing entries can be edited or deleted from their card. Without at least one environment defined, every new cluster is unlabelled. ## Systems Open **Settings → Systems**. Systems are an optional second axis for grouping clusters: typically a business domain (`Billing`, `Payments`, `Reporting`) or a tenant. The form is identical to Environments — name, description, colour, sort order. Use systems if you operate multiple parallel platforms inside the same NomiEsb deployment; otherwise leave the page empty. ## Tags Open **Settings → Tags**. Tags are free-form labels attached to solutions, modules, libraries, clusters, and hosts. They are organised in **tag types** (e.g. *Region*, *Team*, *Compliance*) so the UI can group them coherently. 1. Click **Add tag type**, enter a type name (for example *Region*) and pick a colour. 2. Inside the new card, type values into the input box and press **Add** for each tag (`eu-west`, `us-east`, …). 3. Use the search box and the sort dropdown to navigate when the list grows. Tags are purely descriptive — they do not affect deployment behaviour, but they drive the filters on the Solutions, Clusters, and Audit Trail pages. ## Next Continue to [Integrations](/docs/config-integrations). --- # Integrations Open **Settings → Integrations**. This is the most important page after sign-in: nothing meaningful happens in NomiEsb until you connect at least one DevOps platform and (for deployments) ArgoCD. The page is split into two sections: **ArgoCD** and **DevOps platforms**. Each integration entry stores a name, an endpoint, a credential, an expiration date, and an active/inactive toggle. The credential is encrypted at rest. A **Test** button validates the connection without saving. ## ArgoCD 1. In ArgoCD, go to **Settings → Accounts** and create a token with read/write rights on the relevant projects. Copy the bearer token and note its expiration. 2. In NomiEsb click **Add ArgoCD** and fill in: - **Name** (free-form, used everywhere the integration is referenced). - **Server URL** (e.g. `https://argocd.example.com`). - **Token** and **Token expires at** (used to drive the expiry-warning notification). - **Project filter** (optional regex limiting which ArgoCD projects NomiEsb sees). - **Skip TLS verification** if your ArgoCD uses a self-signed certificate. 3. Click **Test** to confirm reachability, then **Save**. NomiEsb uses ArgoCD to query application sync status, fetch pod health, and trigger syncs from the Cluster and Host pages. ## Azure DevOps 1. In Azure DevOps, generate a **Personal Access Token** with **Code (read & write)**, **Build (read & execute)**, and **Packaging (read & write)** scopes. 2. In NomiEsb click **Add DevOps → Azure DevOps** and enter: - **Name**. - **Organization** (the slug from `https://dev.azure.com/`). - **Personal Access Token** and its **expiry date**. 3. Click **Test** then **Save**. NomiEsb auto-discovers the projects and repositories. ## GitHub 1. In GitHub, create a **Personal Access Token** (classic or fine-grained) with **repo** and **workflow** scopes. 2. Click **Add DevOps → GitHub** in NomiEsb. Enter the **organisation or user**, the **PAT**, and its expiry date. For GitHub Enterprise Server, also fill in the **endpoint** (e.g. `https://github.example.com/api/v3`). ## GitLab 1. Create a **Personal Access Token** in GitLab with `api`, `read_repository`, and `write_repository` scopes. 2. Click **Add DevOps → GitLab**. Enter the **instance URL** (`https://gitlab.com` or self-hosted), the **group or project path**, the **PAT**, and its expiry date. GitLab pipelines are wired up through the auto-generated root `.gitlab-ci.yml` produced by the solution Quick Start. ## Bitbucket 1. In Bitbucket, create an **App password** with **Repositories (read/write)** and **Pipelines (read/write)** scopes. 2. Click **Add DevOps → Bitbucket**. Enter the **workspace**, the **username** and **app password**, and the expiry date. ## Working with integrations afterwards - The **Active** toggle on each card temporarily disables an integration without losing its credentials. Inactive integrations are hidden from the Quick Start dropdowns. - The **expiring / expired** badge appears 14 days before the recorded expiry. The Integration Token Expiry background job also creates a notification for Admins and DevOps users. - Edit a card to rotate the token without recreating the integration. ## Next Continue to [Users and CLI licenses](/docs/config-users). --- # Users and CLI licenses Open **Settings → Users**. The page is the source of truth for who has access and which CLI licenses are assigned. ## Listing and filtering - **Sync** pulls the latest user list and group memberships from Microsoft Graph. NomiEsb runs this automatically at every login, so manual sync is only needed for bulk changes. - **Filters** — text search (name / email), role (Admin / Developer / DevOps), status (active / disabled). - **Sort** — name, email, role, status, ascending / descending. - Expand a user card to see the full details, the AD security group the role came from, and the CLI license toggle. Disabled users keep their history but cannot sign in. ## Why roles cannot be edited here Roles come from the user's Entra ID group membership and are refreshed at every login (and on **Sync**). To change a user's role, change the group they belong to in Microsoft Entra ID. ## Assigning CLI licenses Each NomiEsb subscription includes a fixed number of CLI seats (visible on **Settings → License**). When you toggle **CLI license** on for a user: - The seat count on the License page goes up by one. - The user gains the right to download the Nomirun CLI binary, the per-user CLI configuration file, and a CLI license file from their **Applications** page. Toggling it back off frees the seat. The user's account and history are preserved. ## Roles overview page **Settings → Roles** is a read-only reference: each card lists the menu items the role can see, and the bottom of the page is a step-by-step provisioning guide that walks through creating the three Entra ID groups. Use it when onboarding a new admin or to remind yourself which menu items are visible to which role. ## Next Continue to [API and MCP tokens](/docs/config-tokens). --- # API and MCP tokens End-users manage their own programmatic credentials from **Profile**. Two token types live there. ## CLI tokens (`nomi_…`) These are the tokens the Nomirun CLI uses to authenticate against the NomiEsb API. - A user runs `nomirun login` on their workstation. - The CLI starts the OAuth 2.0 device authorisation flow (RFC 8628). It prints a short user code and a verification URL. - The user opens the URL in any browser, signs in, and approves the device on the **Device login** page. - NomiEsb issues a `nomi_…` token, the CLI stores it locally, and the token shows up on the user's Profile page. From Profile, the user can: - See when each CLI token was created and last used. - Revoke any token at any time. The auth endpoints behind this flow are protected by a strict rate limit (5 requests per IP per minute) to mitigate brute force. ## MCP tokens (`nmcp_…`) These tokens are for external clients calling NomiEsb's Model Context Protocol endpoint at `/api/mcp`. On **Profile → MCP API keys**: 1. Click **Generate API key**, give it a name, and copy the value. The full token is shown **only once**. 2. The new key appears in the list with its created date, last used date, and scope. 3. Use it as a bearer token: `Authorization: Bearer nmcp_…`. The MCP endpoint has its own rate limit policy (100 requests per IP per minute). ## Notification preferences Each user can decide which notifications they receive in-app and by email from **Profile → Notifications**. The system delivers in-app notifications immediately over WebSocket; email is either sent immediately for high-severity events or batched by the **Email digest** background job (default every 15 minutes). ## What to do once configuration is complete When the Dashboard banners are gone and at least one DevOps integration plus one ArgoCD integration are active, hand the system over to the development and DevOps teams: - Developers run **Solutions → Quick Start** to create their first solution. - DevOps users run **Clusters → Quick Start** to create the first cluster. - The full walkthrough of every page is in the [User Guide](/docs/guide-overview). --- # Layout and navigation This page describes the parts of the console that are the same on every screen. Use it as a quick reference for the shell — the rest of the User Guide covers the individual pages. > **Screenshots.** The references throughout the User Guide point at filenames inside `docs/images/`. Capture them from a running NomiEsb instance and drop the PNGs in with the indicated names. ## The shell Every authenticated page shares the same layout: - **Sidebar** — collapsible, grouped navigation. Items appear or hide based on your role. - **Top bar** — page breadcrumb, theme toggle (light / dark), the AI Lens button (when an LLM endpoint is configured), and the user menu. - **Content area** — the page itself. - **Footer** — installed version. A badge appears when a newer version is available; clicking it opens the release notes. ## Notifications Notifications stream in over WebSocket. The bell icon in the sidebar shows an unread count and pops a toast when something arrives. Click the bell to open the [Notifications page](/docs/guide-account#notifications). ## Theme and language The theme toggle in the top bar switches between light and dark and persists per user. Language, region and timezone live on **Profile** and apply immediately. ## Sign-in and error pages These pages do not appear in the navigation but you will encounter them. | Page | When you see it | |------|-----------------| | **Login** (`/login`) | Anonymous users — single **Sign in with Microsoft** button. | | **Device login** (`/device-login`) | Reached when a CLI device-flow user-code points your browser here; you approve or deny the CLI's pending sign-in. | | **Unlicensed** (`/unlicensed`) | The NomiEsb installation has no valid license. | | **Unauthorized** (`/unauthorized`) | Authenticated user not in any Nomirun group. | | **Access Denied** (`/access-denied`) | The page exists but your role cannot view it. | | **Forbidden** (`/forbidden`) | The server rejected the action. | | **Not Found** (catch-all) | Route does not exist. | ## Next Continue to [Dashboard](/docs/guide-dashboard). --- # Dashboard **Route:** `/` · **Roles:** Admin, Developer, DevOps ![Dashboard](images/dashboard.png) The dashboard is the landing page for everyone. What you see depends on your role. ## What is on the page - **Setup banners** (Admin only) — yellow alerts at the top until **System** settings are filled in and at least one DevOps + one ArgoCD integration exist. Each banner links straight to the page that fixes it. - **Quick Start cards** — link to **Solution Quick Start** (Developer / Admin) and **Cluster Quick Start** (DevOps / Admin). - **Stat cards** — counts of solutions, modules, clusters, hosts, and users; each card is filtered by the current role. - **Clusters map** (DevOps / Admin) — interactive network diagram of clusters → hosts → modules. Filter by environment, search a node, click to focus, or open fullscreen. - **Deployment activity** (DevOps / Admin) — month picker plus a daily histogram of deployments; tooltips show the hosts deployed each day. - **Deployment status** (DevOps / Admin) — table of every host with cluster, tags, last deploy, modules, and live ArgoCD status. - **Recent builds** (Developer / Admin) — paginated build history across all modules and libraries with status, version, branch, and a deep-link to the CI run. ## What to do here The Dashboard is a read-only summary; clicking any card or row jumps to the relevant detail page. New installations should treat it as a checklist: 1. Clear the setup banners. 2. Verify the cluster map shows the expected hosts and ArgoCD status. 3. Confirm builds appear within minutes of being triggered in CI. ## Next Continue to [Solutions, modules and libraries](/docs/guide-solutions). --- # Solutions, modules and libraries This page covers the four screens Developers and Admins use most: the Solutions list, the Solution Quick Start wizard, the Module Details page, and the Library Details page. ## Solutions **Route:** `/solutions` · **Roles:** Admin, Developer ![Solutions](images/solutions.png) Lists every solution. Each row expands to reveal its modules, libraries, configuration, and recent build activity. - **Filters and sort** — text search, *initialised* state filter, and sort by name or modified date. - **Per-solution actions** — view, create module, create library, **Initialise** (if not already), edit, delete. - **Inside an expanded solution** — - *Configuration* — tree-view editor for solution-level keys. - *Modules table* — name, type, package id, version, branch, status, row actions. - *Libraries table* — same shape as modules. - *Activity* — recent builds linked into module / library detail pages. When you click **Initialise** on a brand-new solution, NomiEsb runs a multi-step wizard (push template files, create CI pipelines, generate `.gitlab-ci.yml` for GitLab solutions, etc.) and shows progress in real time, with success / failed / skipped per step. ## Solution Quick Start **Route:** `/quickstart/solution` · **Roles:** Admin, Developer ![Solution Quick Start](images/solution-quickstart.png) A six-step wizard for spinning up a new solution end-to-end: 1. **Create solution** — name + description. The `.slnx` path is generated. 2. **Git repository** — pick a configured DevOps integration, choose or paste a repository URL. NomiEsb checks the repo is empty. 3. **Modules and libraries** — add as many as you like; each gets a generated `src//.csproj` path. 4. **Cluster (optional)** — name a cluster to create afterwards. 5. **Initialise** — flow diagram (Code → Pipeline → Ready); the **Start** button runs every step and shows live progress. 6. **Done** — confirmation, link to the new solution. The Quick Start works against Azure DevOps, GitHub, GitLab, and Bitbucket; per-platform pipeline files are pushed automatically. ## Module Details **Route:** `/modules/{Name}` · **Roles:** Admin, Developer ![Module Details](images/module-details.png) The full picture of a single module. - **Basic info** — name, package id, description, Git URL, project path, pipeline YAML path, latest version (clickable, opens release notes), target framework, language version, tags. - **Configuration** — tree editor of the module's configuration tree. - **Dependencies** — compliance badge, **Refresh dependencies**, **Download SBOM**, and a list of every NuGet dependency with version and license. - **Releases** — every published version with date and notes. - **Builds** — paginated CI history linked back to the pipeline run. - **Deployments** — where this module is currently running (cluster, host, version, sync status). ## Library Details **Route:** `/libraries/{Name}` · **Roles:** Admin, Developer ![Library Details](images/library-details.png) Same layout as Module Details — basic info, dependencies (with compliance and SBOM), releases, and builds. Libraries do not have a deployments tab because they are consumed, not deployed. ## Next Continue to [Clusters and hosts](/docs/guide-clusters). --- # Clusters and hosts This page covers the three screens DevOps and Admins use to define and operate the deployment targets: the Clusters list, the Cluster Quick Start wizard, and the Host Details page. ## Clusters **Route:** `/clusters` · **Roles:** Admin, DevOps ![Clusters](images/clusters.png) Lists every Kubernetes cluster registered in NomiEsb. - **Filters** — environment, system, text search, status. - **Per-cluster card** — name, environment colour, system, tags, host count, module count, last sync. - **Actions** — expand to view hosts, edit, delete, **New host**. - **Clusters map button** — opens the same interactive diagram from the Dashboard, with a fullscreen toggle. When a cluster is expanded, each host appears as a sub-card showing its K8s status (healthy / progressing / unknown), sync status, running vs desired pods, service / ingress details, exposed ports, resource requests / limits, deployed modules, and deployed extensions, plus add-module and add-extension buttons. ## Cluster Quick Start **Route:** `/quickstart/cluster` · **Roles:** Admin, DevOps ![Cluster Quick Start](images/cluster-quickstart.png) Three-step wizard: 1. **Name cluster** — name, optional environment, optional system, optional tags. 2. **Create hosts** — add any number of hosts; for each, attach modules (from the available list) and extensions, with a version per item. 3. **Done** — confirmation showing the created cluster structure. ## Host Details **Route:** `/clusters/{ClusterName}/{HostName}` · **Roles:** Admin, DevOps ![Host Details](images/host-details.png) Single-host deep dive. - **Overview** — name, description, address, framework, platform, version. - **Kubernetes status** — health, sync, pod counts, service name, ingress host & path, exposed ports, last sync timestamp, pod resource requests and limits. - **Modules and extensions** — two-column lists with version badges and add / remove controls. - **Configuration** — host-level configuration tree (ports, caching, metrics, Swagger, OpenTelemetry, rate limiting, authentication, Serilog, Azure Key Vault, Azure App Configuration, etc.). - **Build & deploy** — when integrations are connected, opens a dialog to pick modules + versions and trigger an Azure DevOps pipeline or ArgoCD sync. - **Deployment history** — table of past deploys with module, version, time, and sync status. ## Next Continue to [Settings](/docs/guide-settings). --- # Settings This page covers every screen under the **Settings** group in the sidebar. Each section corresponds to one route. Most settings are Admin-only; **Integrations** is also visible to DevOps. For the day-to-day instructions on what to put in each form, see the [Configuration](/docs/config-license) section. ## App **Route:** `/settings/app` · **Roles:** Admin ![App Settings](images/settings-app.png) System-wide configuration, split into a **General** tab (log retention, audit retention, notification retention, background-job cron schedules, host-health monitoring, LLM endpoints, auto-generate-release-notes toggle) and a **System** tab (SMTP, default container registry, default NuGet repository, host API key, custom registries / NuGet feeds). Filling in the **System** tab clears the Dashboard's *settings incomplete* banner. ## Environments **Route:** `/settings/environments` · **Roles:** Admin ![Environments](images/settings-environments.png) Add, edit, and delete environments. Each has a name, a colour swatch, and a sort order. Environments appear on every cluster as a coloured pill and feed the cluster-list filters. ## Systems **Route:** `/settings/systems` · **Roles:** Admin ![Systems](images/settings-systems.png) Optional logical grouping for clusters (business domain, tenant, line of business). Same form as Environments — name, description, colour, sort order. ## Tags **Route:** `/settings/tags` · **Roles:** Admin ![Tags](images/settings-tags.png) Two-level tag manager. - **Tag types** — colour-coded categories (e.g. *Region*, *Team*). - **Tags inside a type** — added inline with an input + **Add** button; deleted with the chip's × icon. Filter by text, sort by name or count. Tags are then attached on solutions, modules, libraries, clusters, and hosts. ## Users **Route:** `/settings/users` · **Roles:** Admin ![Users](images/settings-users.png) The user roster, synchronised from Microsoft Graph. - **Sync** button — force-refresh the user list and group memberships. - **Filters** — text, role (Admin / Developer / DevOps), status (active / disabled). - **Sort** — name, email, role, status (asc / desc). - **Per-user card** — full name, email, role badge, AD group, **CLI license** toggle. Toggling **CLI license** consumes one CLI seat and unlocks the **Applications** page for that user. Roles cannot be edited here — they come from Entra ID. ## Roles **Route:** `/settings/roles` · **Roles:** Admin ![Roles](images/settings-roles.png) Read-only reference for the three roles. Each card lists the menu items the role can see. The bottom of the page is a **provisioning guide** that walks through creating the `Nomirun_Admin`, `Nomirun_Developer`, and `Nomirun_DevOps` security groups in Microsoft Entra ID and assigning users to them. ## Integrations **Route:** `/settings/integrations` · **Roles:** Admin, DevOps ![Integrations](images/integrations.png) Two sections. - **ArgoCD** — list and manage ArgoCD endpoints. Each card shows the URL, token expiry status, project filter, and active toggle. - **DevOps platforms** — Azure DevOps, GitHub, GitLab, and Bitbucket. Each card shows the organisation / workspace, PAT expiry, discovered repository count, and active toggle. For every integration: **Test** validates the credentials live, **Edit** rotates them, **Active** toggles whether the integration is offered in the Quick Start wizards. The full setup walkthrough is in [Configuration → Integrations](/docs/config-integrations). ## License **Route:** `/settings/license` · **Roles:** Admin ![License](images/settings-license.png) Three cards: - **Organisation** — license id, company, address, VAT, DUNS, primary contact. - **Subscription** — plan, start date, expiry with a colour-coded status badge (active / expiring soon / renew now / expired) and a **Renew** link to support. - **CLI licenses** — total seats, used, available, with a coloured progress bar. If the system is unlicensed the page shows a warning with renewal instructions instead of the cards. ## Audit Trail **Route:** `/settings/audit-trail` · **Roles:** Admin ![Audit Trail](images/audit-trail.png) Every change in the system is logged here. - **Filters** — text search, user, action, entity type, date range. - **Sort** — date, user, action, object name (asc / desc). - **Columns** — action (colour-coded), entity type, object name, user, IP address, expandable details (JSON before/after), timestamp in your timezone. - **Export** — CSV download of the current filter set. ## Next Continue to [Profile, applications and notifications](/docs/guide-account). --- # Profile, applications, notifications and documentation These four pages are available to every authenticated user regardless of role. ## Profile **Route:** `/profile` · **Roles:** Admin, Developer, DevOps ![Profile](images/profile.png) Your personal account page. - **Account** — your name, email, and current role (read-only). - **Preferences** — language (one of the seven supported), regional culture, timezone, theme. Changes apply immediately and persist for next sign-in. - **MCP API keys** — generate, copy, and revoke `nmcp_…` tokens used by external MCP clients. The full token is shown only once at creation. - **CLI tokens** — view and revoke the `nomi_…` tokens granted to the CLI through `nomirun login`. - **Notification preferences** — opt in or out of in-app and email delivery per notification type. ## Applications **Route:** `/applications` · **Roles:** Admin, Developer, DevOps (with a CLI license) ![Applications](images/applications.png) Self-service downloads for the Nomirun CLI and Host. Each card walks the three-step flow: 1. **Download installer** — Windows or Linux build of the binary. 2. **Download config** — a per-user config file pointing at this NomiEsb instance. 3. **Generate license** — paste the hardware key printed by the CLI / Host on first run, click **Generate**, and download the resulting license file. If you have not been granted a CLI license, the page shows an info card asking your administrator to enable it on **Settings → Users**. ## Notifications **Route:** `/notifications` · **Roles:** Admin, Developer, DevOps ![Notifications](images/notifications.png) Your notification inbox. Two view modes: - **Individual** — flat list, one row per notification, with mark-read, open-entity, and delete buttons. **Mark all as read** clears the unread badge. - **Grouped** — collapses repeats by *(type, entity)* with a count and the latest timestamp. Mark or delete the whole group at once. Filters by status (read / unread), severity (info / warning / error / resolved), and type. New notifications stream in over WebSocket and pop a toast. ## Documentation **Route:** `/documentation` · **Roles:** Admin, Developer, DevOps ![Documentation](images/documentation.png) Your in-app entry point to the NomiEsb docs and NomiEsb Lens. The page links out to the hosted documentation, highlights popular topics (Getting started, Solutions, Clusters, Integrations), and embeds a **Contact support** form — expand it to send a request straight to the Nomirun support team. Pick a category (Solutions, Clusters, Integrations, Other), enter a subject and a message, and submit. **Submit another** resets the form for a follow-up request.