You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As the UMS project evolves into an enterprise-grade monorepo and migrates core components to .NET 8, it is necessary to standardize the database engine preferences to optimize for ecosystem alignment, performance, and maintainability across different language stacks.
7
+
As the UMS project evolves into an enterprise-grade monorepo, it is necessary to standardize the database engine to optimize for operational simplicity, cross-service data integrity, and corporate licensing alignment.
8
8
9
-
Previously, PostgreSQL was used as the default relational engine for both Node.js and .NET prototypes. However, corporate standards for .NET excellence prioritize SQL Server for mission-critical .NET applications.
9
+
Previously, a polyglot engine strategy was proposed (SQL Server for .NET and PostgreSQL/MongoDB for Node.js). However, managing multiple database engines in production—especially in on-premise or localized deployments—increases infrastructure overhead, security complexity (multiple RLS implementations), and total cost of ownership.
10
10
11
11
## Decision
12
-
We will adopt a polyglot-aware database strategy based on the primary language of the application service:
12
+
We will adopt a **Unified Database Strategy** for all services within the UMS product ecosystem:
***Relational Engine:****SQL Server 2022** (Latest stable version).
16
-
***ORM:** Entity Framework Core (EF Core) with `Microsoft.EntityFrameworkCore.SqlServer`.
17
-
***Rationale:** Seamless integration with .NET ecosystem, superior tooling (SSMS/Azure Data Studio), and optimized execution plans for MediatR-based workloads.
14
+
1.**Unified Relational Engine:****SQL Server 2022** (Standard or Enterprise).
15
+
***All runtimes** (.NET 8 Core API and Node.js/NestJS Satellite services) must persist their data exclusively in SQL Server 2022.
16
+
***Rationale:** Standardizing on a single engine allows for a unified Row-Level Security (RLS) implementation, simplified backup/restore procedures, and consistent execution plan analysis.
18
17
19
-
2.**For Node.js / NestJS Applications:**
20
-
***Relational Engine:****PostgreSQL 16**.
21
-
***NoSQL Engine:****MongoDB**.
22
-
***Rationale:** Community maturity, native JSONB support in PG, and high developer velocity in the Node.js ecosystem.
18
+
2.**Schema-per-Context Isolation:**
19
+
* To maintain modularity, each Bounded Context will own a dedicated SQL Server Schema (e.g., `[ums_identity]`, `[ums_authz]`).
20
+
* Direct cross-schema joins are discouraged in favor of domain events, but permitted for optimized read-only reporting views under strict governance.
23
21
24
-
### Security Implementation
25
-
***Row-Level Security (RLS):** For .NET/SQL Server services, RLS will be implemented using SQL Server **Security Policies** and **Inline Table-Valued Functions (iTVF)** for filtering, instead of PostgreSQL policies.
26
-
***Multi-Tenancy:** The "Shared Database, Shared Schema" model remains mandatory, enforced via SQL Server RLS.
22
+
3.**ORM / Driver Support:**
23
+
***.NET 8**: Entity Framework Core with `Microsoft.EntityFrameworkCore.SqlServer`.
24
+
***Node.js / NestJS**: TypeORM or Prisma using the **`mssql`** driver.
25
+
26
+
4.**Security Implementation:**
27
+
***Unified RLS**: All services will utilize SQL Server **Security Policies** and **SESSION_CONTEXT** for multi-tenant isolation.
28
+
* This eliminates the need to maintain parallel RLS logic for PostgreSQL.
27
29
28
30
## Consequences
29
-
*The UMS migration plan from NestJS (Node) to .NET 8 must be updated to replace Npgsql with the SQL Server provider.
30
-
* Local development environments (Docker Compose) will include a `mssql-server-linux`container for the .NET API.
31
-
*Architectural blueprints and technical inventories must be updated to reflect SQL Server as the authoritative engine for the .NET stack.
32
-
*Satellite systems inheriting from this reference architecture must follow these same engine preferences based on their language stack.
31
+
***Correction**: All references to PostgreSQL or MongoDB for Node.js services in `stack.md` or earlier documentation are now deprecated.
32
+
***Infrastructure**: Local development environments (Docker Compose) will only require a single `mssql-server-linux`instance.
33
+
***Skill Set**: The team must ensure proficiency in T-SQL and SQL Server-specific performance tuning across all language stacks.
34
+
***Migration**: Any existing Node.js prototypes using PostgreSQL must be migrated to SQL Server.
This document serves as the authoritative mapping between system entities, their Bounded Contexts, owning services, and database schemas within the UMS enterprise ecosystem.
4
+
5
+
---
6
+
7
+
## 🏛️ 1. Entity Ownership & Schema Mapping
8
+
9
+
| Entity | Bounded Context | Service Owner (Write) | Runtime | SQL Server Schema |
10
+
| :--- | :--- | :--- | :--- | :--- |
11
+
|**TENANT**| Identity | UMS Core API | .NET 8 |`[ums_identity]`|
12
+
|**BRANCH**| Identity | UMS Core API | .NET 8 |`[ums_identity]`|
13
+
|**USER_ACCOUNT**| Identity | UMS Core API | .NET 8 |`[ums_identity]`|
14
+
|**ROLE**| Authorization | UMS Core API | .NET 8 |`[ums_authz]`|
15
+
|**PROFILE**| Authorization | UMS Core API | .NET 8 |`[ums_authz]`|
16
+
|**PROFILE_PERMISSION**| Authorization | UMS Core API | .NET 8 |`[ums_authz]`|
17
+
|**PERMISSION_TEMPLATE**| Authorization | UMS Core API | .NET 8 |`[ums_authz]`|
18
+
|**FUNCTIONAL_MODULE**| Authorization | UMS Core API | .NET 8 |`[ums_authz]`|
19
+
|**FUNCTIONAL_SUBMODULE**| Authorization | UMS Core API | .NET 8 |`[ums_authz]`|
20
+
|**FUNCTIONAL_OPTION**| Authorization | UMS Core API | .NET 8 |`[ums_authz]`|
21
+
|**ACTION**| Authorization | UMS Core API | .NET 8 |`[ums_authz]`|
22
+
|**SYSTEM_SUITE**| Authorization | UMS Core API | .NET 8 |`[ums_authz]`|
23
+
|**ROLE_PROMOTION_CRITERIA**| IGA | IGA Satellite | NestJS |`[ums_iga]`|
24
+
|**USER_PROMOTION_PROCESS**| IGA | IGA Satellite | NestJS |`[ums_iga]`|
25
+
|**USER_MANAGEMENT_DELEGATION**| IGA | IGA Satellite | NestJS |`[ums_iga]`|
|**APPROVAL_WORKFLOW**| Approvals | UMS Core API | .NET 8 |`[ums_approval]`|
31
+
|**APPROVAL_REQUIRED_DOCUMENT**| Approvals | UMS Core API | .NET 8 |`[ums_approval]`|
32
+
|**APPROVAL_REQUEST**| Approvals | UMS Core API | .NET 8 |`[ums_approval]`|
33
+
|**APPROVAL_LOG**| Approvals | UMS Core API | .NET 8 |`[ums_approval]`|
34
+
|**APP_CONFIGURATION**| Configuration | UMS Core API | .NET 8 |`[ums_config]`|
35
+
36
+
---
37
+
38
+
## 🛠️ 2. Data Access & Governance Rules
39
+
40
+
1.**Strict Write Ownership**: Only the **Service Owner** specified in the table above is allowed to perform `INSERT`, `UPDATE`, or `DELETE` operations on the corresponding entities.
41
+
2.**Cross-Service Reads (Read-Only)**:
42
+
* Satellite services (NestJS) may perform `SELECT` operations on `ums_identity` and `ums_authz` schemas to resolve context, but must do so through optimized views or read-only database users.
43
+
* Cross-service data dependency should ideally be resolved via **Domain Events** (Asynchronous) rather than direct cross-schema joins to maintain decoupling.
44
+
3.**Schema Isolation**: Each schema acts as a logical boundary. Permissions in SQL Server must be granted granularly per service account.
> **Unified Engine Strategy**: Although `architecture/blueprints/stack.md` and some early prototypes mention PostgreSQL for Node.js/NestJS components, the final authoritative decision for the UMS production product is **SQL Server 2022 for all services**, regardless of the runtime (.NET 8 or NestJS).
52
+
>
53
+
> **Action Required**: **ADR-0026** must be updated to reflect this unification, removing PostgreSQL and MongoDB from the relational/NoSQL requirements for this specific codebase.
54
+
55
+
---
56
+
57
+
## 🔗 4. References
58
+
* For the complete E/R diagram and relationship cardinality, refer to **[er-export-formats.md](er-export-formats.md)**.
59
+
* For technical implementation of Row-Level Security (RLS) in SQL Server, refer to the Identity Context documentation.
***Why Chosen:** Mandated to ensure the core Domain layer has **absolutely zero dependencies** on NestJS, TypeORM, PostgreSQL, or external cloud SDKs. Core logic communicates exclusively with interfaces (Ports), making the kernel completely sovereign and future-proof.
100
+
***Why Chosen:** Mandated to ensure the core Domain layer has **absolutely zero dependencies** on NestJS, TypeORM, SQL Server, or external cloud SDKs. Core logic communicates exclusively with interfaces (Ports), making the kernel completely sovereign and future-proof.
101
101
***Alternatives Rejected:**
102
102
**Standard 3-Tier Layered Architecture*: Creates strong coupling between business logic, database ORMs, and network frameworks, violating our non-negotiable sovereignty constraint.
103
103
@@ -109,7 +109,7 @@
109
109
110
110
### 4.3 CQRS Approach
111
111
***Chosen Tool:****Internal CQRS via NestJS CQRS module**
112
-
***Why Chosen:** Decouples heavy permission graph compilation (Queries) from basic identity mutations (Commands), optimizing read performance. Caches read-projections in Redis while writing sequentially to PostgreSQL.
112
+
***Why Chosen:** Decouples heavy permission graph compilation (Queries) from basic identity mutations (Commands), optimizing read performance. Caches read-projections in Redis while writing sequentially to **SQL Server 2022**.
113
113
***Alternatives Rejected:**
114
114
**Direct CRUD*: Directly querying and compiling relational tables on every read request degrades database performance under high concurrent loads.
***Why:** High flexibility for unstructured documents and rapid prototyping.
121
+
***Unified Relational Engine:****SQL Server 2022 (All Services)**
122
+
***For .NET 8 Services:** EF Core with SQL Server Provider.
123
+
***For Node.js Services:** TypeORM / Prisma with `mssql` driver.
124
+
***Why:** Official corporate standard, superior RLS via `SESSION_CONTEXT`, and operational simplicity for on-premise deployments.
127
125
128
126
### 5.2 Migration Strategy
129
127
***Chosen Tool:****TypeORM Migrations executed via K8s Init-Containers**
@@ -155,9 +153,8 @@
155
153
156
154
### 6.1 Isolation Model
157
155
***Strategy:****Shared Database with Native Row-Level Security (RLS)**
158
-
***Implementation (SQL Server):** Uses `SESSION_CONTEXT('TenantId', @value)` and Security Policies with iTVF predicates.
159
-
***Implementation (PostgreSQL):** Uses `SET LOCAL app.current_tenant = 'value'` and native `CREATE POLICY`.
160
-
***Why Chosen:** High packing density and low administrative overhead while maintaining absolute isolation at the engine level.
156
+
***Implementation (Unified):** Uses SQL Server `SESSION_CONTEXT('TenantId', @value)` and Security Policies with iTVF predicates for both .NET and Node.js.
157
+
***Why Chosen:** High packing density and absolute isolation at the engine level with a single implementation to maintain.
161
158
***Alternatives Rejected:**
162
159
**Database-per-tenant*: High infrastructure cost and severe administrative overhead when managing thousands of databases.
163
160
**Schema-per-tenant*: Becomes hard to scale and migrate when tenant counts exceed 1,000, causing connection pool exhaustion.
***Why Chosen:** Resolves the `tenant_id` from JWT claims or `X-Tenant-ID` headers at ingress, and uses a database transaction wrapper to inject the tenant context into the active PostgreSQL session dynamically.
168
165
***Alternatives Rejected:**
169
-
**Application-level filtering*: Prone to developer omissions (forgetting a `WHERE tenant_id = x` clause), leading to critical data leak vulnerabilities. RLS prevents this at the database level.
166
+
**Application-level filtering*: Prone to developer omissions (forgetting a `WHERE tenant_id = x` clause), leading to critical data leak vulnerabilities. RLS prevents this at the database level across all runtimes.
170
167
171
168
---
172
169
@@ -232,7 +229,7 @@
232
229
233
230
### 10.1 Local Development Setup
234
231
***Chosen Tool:****Docker Compose Spec**
235
-
***Why Chosen:** Allows developers to spin up the entire UMS dependency suite (**SQL Server**, **PostgreSQL**, Redis, RabbitMQ, MinIO) locally with a single command (`docker compose up -d`).
232
+
***Why Chosen:** Allows developers to spin up the entire UMS dependency suite (**SQL Server 2022**, Redis, RabbitMQ, MinIO) locally with a single command (`docker compose up -d`).
236
233
237
234
### 10.2 Monorepo vs. Multi-repo
238
235
***Chosen Tool:****Nx Monorepo**
@@ -241,7 +238,7 @@
241
238
### 10.3 Testing Pyramid
242
239
***Chosen Tool:**
243
240
**Unit Tests*: Jest (aiming for >80% coverage).
244
-
**Integration Tests*: Jest + Supertest with **Testcontainers** (spinning up ephemeral PostgreSQL and Redis instances in local Docker for realistic testing).
241
+
**Integration Tests*: Jest + Supertest with **Testcontainers** (spinning up ephemeral **SQL Server Edge/Express** and Redis instances in local Docker for realistic testing).
245
242
**End-to-End*: Playwright for Web Console regression testing.
246
243
247
244
---
@@ -261,7 +258,7 @@ To avoid cloud-provider lock-in and support offline, on-premise environments, **
|**Database**|PostgreSQL v16 |**Low**| Standard SQL compliance. Domain layer has no direct dependency (decoupled via Ports). | Exceeding 20 TB of active data|
261
+
|**Database**|SQL Server 2022 |**Medium**| Standard SQL compliance. Domain layer has no direct dependency (decoupled via Ports). Use of RLS creates some lock-in. | Licensing cost change|
265
262
|**Object Store**| MinIO |**Low**| MinIO uses the exact AWS S3 API contract. Swapping requires a simple config change. | Performance bottlenecks |
266
263
|**Secrets Store**| HashiCorp Vault |**Low**| Secret resolution is abstracted via K8s secrets injection or custom Adapter. | Licensing model changes |
267
264
|**Gateway**| Kong Gateway |**Low**| Configuration is managed via standard K8s Ingress resources. | Custom routing constraints |
@@ -275,10 +272,10 @@ To avoid cloud-provider lock-in and support offline, on-premise environments, **
275
272
***Rationale:** Balances high-performance/safety requirements for the core with development speed for utilities.
276
273
***Revisit When:** Organizational skills shift significantly or a unified single-runtime model is required.
0 commit comments