Tenant Provisioning & Management
Struktural is inherently multi-tenant. Each application (Tenant) acts as a completely isolated environment with its own database schema, UI definitions, and business logic.
The File System Structure
Tenant definitions are stored in the Apps/ directory at the root of the hosting environment.
Apps/
├── default/ # The fallback tenant
│ └── Definitions/
│ ├── app-config.json # Infrastructure settings (DB, Storage)
│ ├── app-schema.json # Entity and External Service definitions
│ ├── app-ui.json # View and Menu definitions
│ ├── Scripts/ # C# .cs.script files
│ └── i18n/ # Translation JSONs
├── erp-client-a/
│ └── Definitions/ ...
└── crm-client-b/
└── Definitions/ ...
AppId Routing & Resolution
The AppIdentificationMiddleware resolves which tenant context to load using the following priority hierarchy:
- URL Path: Explicit API routing (e.g.,
/api/apps/erp-client-a/customer). - Apex Domain / Host Header: The platform maps incoming hostnames to AppIds via the
TenantDomainssection inappsettings.json.- Example:
portal.ejemplo.commaps tocrm-client-b.
- Example:
- Subdomain Routing: If the host is
erp-client-a.struktural.demo, the middleware automatically extractserp-client-aas the AppId. - Custom Header: In local development, the
X-Struktural-App-Idheader can dictate the context. - Fallback: If all else fails, it reads
Apps/default-tenant.txtto find the default application, or defaults todefault.
Configuration Overrides
While app-config.json stores tenant-specific settings, DevOps can override these securely via environment variables or appsettings.json using the Tenants section. This is crucial for CI/CD pipelines where you do not want connection strings stored in the file system definition.
"Tenants": {
"erp-client-a": {
"Database": {
"ConnectionString": "Server=prod-db;..."
}
}
}