GSM Application uses a strict database-per-tenant architecture: every company that subscribes to the platform gets its own dedicated SQL Server database. No tenant shares tables, schemas, or connection pools with another. The centralDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/ti-infinite/GSMApplication/llms.txt
Use this file to discover all available pages before exploring further.
TenantRegistryDb database acts as a routing directory — it maps a company identifier to the precise server and database that holds that company’s data.
The Tenants Registry Table
All tenant routing metadata lives inTenantRegistryDb.Tenants. The table is created by the following DDL:
Primary key. Short alphanumeric identifier for the company — e.g.
IH001. This value is embedded in every JWT as the companyId claim.Hostname or instance name of the SQL Server that hosts the tenant database.
Name of the tenant-specific database on the target server.
SQL login username used when building the dynamic connection string.
Password for the SQL login. Store this value in an encrypted column or a secrets manager in production environments.
Controls whether the tenant is operational. Only rows where
IsActive = 1 are returned by TenantConnectionResolver.Runtime Tenant Resolution
Every authenticated API request travels through the following resolution chain before any microservice reads from a database.Client sends a Bearer token
The browser or API client attaches
Authorization: Bearer <jwt> to the outbound HTTP request and sends it to the GSM Gateway.Gateway validates the JWT
The gateway’s JWT middleware validates the signature, issuer, and audience of the token. If validation fails the gateway returns
401 Unauthorized immediately and the request never reaches a microservice.Tenant header injection
TenantHeaderInjectionMiddleware runs after JWT validation. It performs two operations atomically:- Strips any
X-Company-IdorX-Profile-Idheaders that the client may have sent — clients must never be trusted to supply their own tenant identity. - Injects a fresh
X-Company-Idheader derived from the JWT’scompanyIdclaim, and anX-Profile-Idheader derived from theidProfileclaim.
YARP forwards the enriched request
The reverse proxy routes the request — now carrying the trusted
X-Company-Id header — to the appropriate downstream microservice cluster.Microservice reads the tenant header
Each microservice’s
TenantMiddleware reads X-Company-Id from the incoming request and stores it in its local TenantContext for the duration of that request scope.Dynamic DbContext is constructed
The microservice’s
TenantConnectionResolver queries TenantRegistryDb.Tenants using the CompanyId value, builds a connection string from the returned Server, Database, DbUser, and DbPassword columns, and instantiates an EF Core DbContext bound to that specific tenant database.Fallback for Direct Service Calls
In development it is sometimes useful to call a microservice directly without routing through the gateway. For these scenarios each microservice’sTenantExtensions logic attempts to read X-Company-Id first and, if the header is absent, falls back to the companyId JWT claim embedded in the bearer token.
The JWT-claim fallback is intended only for local development and integration testing. In production all traffic passes through the gateway, which always supplies the verified header.
TenantContext and TenantMiddleware Pattern
Every microservice in the GSM ecosystem replicates the same lightweight tenant-awareness pattern:TenantContext
A scoped service that holds the resolved
CompanyId string for the current HTTP request. Business logic, repositories, and DbContext factories inject this object to know which tenant they are serving.TenantMiddleware
Registered early in the middleware pipeline. Reads
X-Company-Id (or falls back to the JWT claim) and populates TenantContext. Downstream handlers never parse the header themselves.Adding a New Tenant
Create the tenant database
On the target SQL Server, create a new database following the naming convention — for example
GSM_{CompanyId}_Db.Run the schema scripts
Apply all tenant schema migrations to the new database. Each microservice ships its own schema script for its domain tables (Users, Employees, Suppliers, etc.).
Insert the registry row
Add a record to
TenantRegistryDb.Tenants. Set IsActive = 1 only when the database and schema are fully ready.Seed initial data
Insert the default users, profiles, menu configuration, and any tenant-specific parameters required for the new company to function.
Set JsonStyles (optional)
Populate the
JsonStyles column if the tenant requires custom branding. See Tenant Theming for the full JSON structure.Sample Tenants row for development
Sample Tenants row for development
tenant-registry.sql. Use it to bootstrap a local development environment against SQL Server LocalDB.