siesa-agents 2.1.50 → 2.1.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,667 @@
1
+ # PostgreSQL Database Conventions
2
+
3
+ ## 1. PostgreSQL Database Conventions
4
+
5
+ ### 1.1 Tables
6
+
7
+ **Convention:** snake_case, PLURAL or SINGULAR form (configurable per project)
8
+
9
+ **EF Core Pluralization:** This standard supports both approaches:
10
+ - **Option A (Pluralization Enabled):** EF Core automatically pluralizes table names
11
+ - **Option B (Pluralization Disabled):** Manual control with singular names
12
+
13
+ **Example with Pluralization Enabled:**
14
+ ```sql
15
+ -- ✅ CORRECT (Plural, snake_case)
16
+ CREATE TABLE products ( ... ); -- class: Product
17
+ CREATE TABLE customers ( ... ); -- class: Customer
18
+ CREATE TABLE order_items ( ... ); -- class: OrderItem
19
+ CREATE TABLE user_roles ( ... ); -- class: UserRole
20
+
21
+ -- ❌ INCORRECT
22
+ CREATE TABLE Products ( ... ); -- PascalCase
23
+ CREATE TABLE product ( ... ); -- Singular (if pluralization enabled)
24
+ CREATE TABLE product-items ( ... ); -- Hyphens not allowed
25
+ ```
26
+
27
+ **Example with Pluralization Disabled:**
28
+ ```sql
29
+ -- ✅ CORRECT (Singular, snake_case)
30
+ CREATE TABLE product ( ... ); -- class: Product
31
+ CREATE TABLE customer ( ... ); -- class: Customer
32
+ CREATE TABLE order_item ( ... ); -- class: OrderItem
33
+ CREATE TABLE user_role ( ... ); -- class: UserRole
34
+ ```
35
+
36
+ **Key Identifiers:**
37
+ - **Primary Key (Guid):** Use `id` column name
38
+ - **Business Identifier (string):** Use `code` column name
39
+
40
+ ```sql
41
+ -- ✅ CORRECT (with pluralization)
42
+ CREATE TABLE products (
43
+ id UUID PRIMARY KEY DEFAULT uuidv7(),
44
+ code VARCHAR(50) NOT NULL,
45
+ name VARCHAR(200) NOT NULL,
46
+ price DECIMAL(18,2) NOT NULL,
47
+ is_active BOOLEAN DEFAULT true,
48
+ created_at TIMESTAMP DEFAULT NOW(),
49
+ created_by_user_id UUID REFERENCES users(id)
50
+ );
51
+
52
+ CREATE UNIQUE INDEX uk_products_code ON products(code);
53
+ ```
54
+
55
+ ### 1.2 Columns
56
+
57
+ **Convention:** snake_case (mapped automatically from C# PascalCase properties)
58
+
59
+ ```sql
60
+ -- ✅ CORRECT (snake_case, PostgreSQL standard)
61
+ CREATE TABLE products (
62
+ id UUID PRIMARY KEY, -- PK
63
+ code VARCHAR(50), -- Business identifier
64
+ name VARCHAR(200),
65
+ price DECIMAL(18,2),
66
+ is_active BOOLEAN, -- Boolean flag
67
+ created_at TIMESTAMP, -- Audit field
68
+ created_by_user_id UUID REFERENCES users(id),
69
+ updated_at TIMESTAMP,
70
+ updated_by_user_id UUID REFERENCES users(id)
71
+ );
72
+
73
+ -- C# class with PascalCase (maps automatically)
74
+ public class Product
75
+ {
76
+ public Guid ID { get; set; } // → id
77
+ public string Code { get; set; } // → code
78
+ public string Name { get; set; } // → name
79
+ public decimal Price { get; set; } // → price
80
+ public bool IsActive { get; set; } // → is_active
81
+ public DateTime CreatedAt { get; set; } // → created_at
82
+ public Guid CreatedByUserID { get; set; } // → created_by_user_id
83
+ }
84
+
85
+ -- ❌ INCORRECT
86
+ CREATE TABLE products (
87
+ ID UUID PRIMARY KEY, -- PascalCase
88
+ Price DECIMAL(18,2), -- PascalCase
89
+ IsActive BOOLEAN, -- PascalCase
90
+ created-at TIMESTAMP, -- Hyphens not allowed
91
+ Created_At TIMESTAMP -- Mixed case
92
+ );
93
+ ```
94
+
95
+ **Acronym Columns:**
96
+ ```sql
97
+ -- C# properties with acronyms
98
+ public string APIKey { get; set; } // → api_key
99
+ public string HTTPEndpoint { get; set; } // → http_endpoint
100
+ public string XMLContent { get; set; } // → xml_content
101
+ public string JSONPayload { get; set; } // → json_payload
102
+ public int HTTPStatusCode { get; set; } // → http_status_code
103
+
104
+ -- PostgreSQL columns (snake_case)
105
+ CREATE TABLE api_configurations (
106
+ id UUID PRIMARY KEY,
107
+ api_key VARCHAR(100),
108
+ http_endpoint VARCHAR(500),
109
+ xml_content TEXT,
110
+ json_payload JSONB,
111
+ http_status_code INTEGER
112
+ );
113
+ ```
114
+
115
+ ### 1.3 Foreign Key Columns
116
+
117
+ **Convention:** C# uses `{EntityName}ID`, database uses `{entity_name}_id` (snake_case)
118
+
119
+ **Foreign Keys:**
120
+
121
+ Use the exact entity name + ID suffix in C#. Database columns are automatically converted to snake_case.
122
+
123
+ ```sql
124
+ -- ✅ CORRECT - Specific entity references (snake_case in database)
125
+ CREATE TABLE orders (
126
+ id UUID PRIMARY KEY,
127
+ customer_id UUID REFERENCES customers(id), -- FK to customers table
128
+ product_id UUID REFERENCES products(id), -- FK to products table
129
+ company_id UUID REFERENCES companies(id), -- FK to companies table
130
+ warehouse_id UUID REFERENCES warehouses(id) -- FK to warehouses table
131
+ );
132
+
133
+ -- C# class (PascalCase properties → snake_case columns)
134
+ public class Order
135
+ {
136
+ public Guid ID { get; set; } // → id
137
+ public Guid CustomerID { get; set; } // → customer_id
138
+ public Guid ProductID { get; set; } // → product_id
139
+ public Guid CompanyID { get; set; } // → company_id
140
+ }
141
+ ```
142
+
143
+ **Multiple References to Same Entity:**
144
+
145
+ When a table has multiple foreign keys to the same entity, use a context prefix to differentiate them.
146
+
147
+ **Pattern:** C# uses `{Context}{EntityName}ID`, database uses `{context}_{entity_name}_id`
148
+
149
+ ```sql
150
+ -- ✅ CORRECT - Multiple FKs to same entity with context prefix
151
+ CREATE TABLE shipments (
152
+ id UUID PRIMARY KEY,
153
+ origin_warehouse_id UUID REFERENCES warehouses(id), -- Origin warehouse
154
+ destination_warehouse_id UUID REFERENCES warehouses(id), -- Destination warehouse
155
+ shipped_at TIMESTAMP
156
+ );
157
+
158
+ CREATE TABLE transfers (
159
+ id UUID PRIMARY KEY,
160
+ source_account_id UUID REFERENCES accounts(id), -- Source account
161
+ destination_account_id UUID REFERENCES accounts(id), -- Destination account
162
+ amount DECIMAL(18,2)
163
+ );
164
+
165
+ CREATE TABLE transactions (
166
+ id UUID PRIMARY KEY,
167
+ sender_user_id UUID REFERENCES users(id), -- Sender user
168
+ receiver_user_id UUID REFERENCES users(id), -- Receiver user
169
+ amount DECIMAL(18,2)
170
+ );
171
+
172
+ -- C# classes
173
+ public class Shipment
174
+ {
175
+ public Guid ID { get; set; }
176
+ public Guid OriginWarehouseID { get; set; } // → origin_warehouse_id
177
+ public Guid DestinationWarehouseID { get; set; } // → destination_warehouse_id
178
+ }
179
+
180
+ public class Transfer
181
+ {
182
+ public Guid ID { get; set; }
183
+ public Guid SourceAccountID { get; set; } // → source_account_id
184
+ public Guid DestinationAccountID { get; set; } // → destination_account_id
185
+ }
186
+ ```
187
+
188
+ **Common Context Prefixes:**
189
+ - `Origin` / `Destination` - Origin and destination locations
190
+ - `Source` / `Destination` - Source and destination entities
191
+ - `Sender` / `Receiver` - Sender and receiver in transactions
192
+ - `Parent` / `Child` - Hierarchical relationships
193
+ - `Primary` / `Secondary` - Primary and secondary references
194
+ - `Manager` / `Subordinate` - Management relationships
195
+
196
+ **Audit Foreign Keys:**
197
+
198
+ For audit fields that reference Users, use `{Action}ByUserID` pattern in C#:
199
+
200
+ ```sql
201
+ -- ✅ CORRECT - Explicit User references with action context (snake_case in database)
202
+ CREATE TABLE products (
203
+ id UUID PRIMARY KEY,
204
+ code VARCHAR(50),
205
+ name VARCHAR(200),
206
+ created_by_user_id UUID REFERENCES users(id), -- Who created
207
+ updated_by_user_id UUID REFERENCES users(id), -- Who last updated
208
+ created_at TIMESTAMP,
209
+ updated_at TIMESTAMP
210
+ );
211
+
212
+ -- C# class
213
+ public class Product
214
+ {
215
+ public Guid ID { get; set; } // → id
216
+ public string Code { get; set; } // → code
217
+ public string Name { get; set; } // → name
218
+ public Guid CreatedByUserID { get; set; } // → created_by_user_id
219
+ public Guid? UpdatedByUserID { get; set; } // → updated_by_user_id
220
+ public DateTime CreatedAt { get; set; } // → created_at
221
+ public DateTime? UpdatedAt { get; set; } // → updated_at
222
+ }
223
+ ```
224
+
225
+ **Rationale:**
226
+ - C# `ProductID` is clearer than `ID` (ID of what?)
227
+ - C# `CreatedByUserID` is clearer than `CreatedBy` (created by what entity?)
228
+ - Database `product_id` follows PostgreSQL convention (snake_case)
229
+ - Self-documenting: no need to check FK constraints to understand relationships
230
+ - Consistent pattern: `{EntityName}ID` in C# → `{entity_name}_id` in database
231
+
232
+ ```sql
233
+ -- ❌ INCORRECT - Generic or ambiguous names
234
+ CreatedBy UUID -- By what entity? Users? Systems?
235
+ product_id UUID -- C# side (should be ProductID in PascalCase)
236
+ Product_ID UUID -- Mixed case
237
+ PRODUCTID UUID -- All caps
238
+ ProductId UUID -- camelCase suffix (prefer ID)
239
+ ```
240
+
241
+ ### 1.4 Indexes
242
+
243
+ **Convention:** `ix_{table}_{column(s)}` or `uk_{table}_{column(s)}` (for unique) in snake_case
244
+
245
+ ```sql
246
+ -- ✅ CORRECT (all snake_case)
247
+ CREATE INDEX ix_products_code ON products(code);
248
+ CREATE INDEX ix_products_name ON products(name);
249
+ CREATE INDEX ix_products_is_active ON products(is_active);
250
+ CREATE INDEX ix_orders_customer_id ON orders(customer_id);
251
+ CREATE INDEX ix_user_roles_user_id ON user_roles(user_id);
252
+
253
+ -- For multi-column indexes
254
+ CREATE INDEX ix_orders_customer_id_created_at ON orders(customer_id, created_at);
255
+
256
+ -- For unique indexes, use uk_ prefix
257
+ CREATE UNIQUE INDEX uk_products_code ON products(code);
258
+ CREATE UNIQUE INDEX uk_customers_email ON customers(email);
259
+
260
+ -- ❌ INCORRECT
261
+ CREATE INDEX ProductCodeIndex ON products(code); -- PascalCase
262
+ CREATE INDEX idx_Products_Code ON products(code); -- Mixed case
263
+ CREATE INDEX idx_orders_CustomerID ON orders(customer_id); -- PascalCase column
264
+ ```
265
+
266
+ ### 1.5 Constraints
267
+
268
+ **Convention:** `{type}_{table}_{column(s)}` in snake_case
269
+
270
+ ```sql
271
+ -- Primary Key
272
+ CONSTRAINT pk_products PRIMARY KEY (id)
273
+
274
+ -- Foreign Key
275
+ CONSTRAINT fk_orders_customers FOREIGN KEY (customer_id) REFERENCES customers(id)
276
+ CONSTRAINT fk_orders_products FOREIGN KEY (product_id) REFERENCES products(id)
277
+
278
+ -- Unique
279
+ CONSTRAINT uk_products_code UNIQUE (code)
280
+ CONSTRAINT uk_customers_email UNIQUE (email)
281
+
282
+ -- Check
283
+ CONSTRAINT chk_products_price_positive CHECK (price > 0)
284
+ CONSTRAINT chk_orders_quantity_positive CHECK (quantity > 0)
285
+ ```
286
+
287
+ ### 1.6 PostgreSQL Schemas
288
+
289
+ **Convention:** lowercase with underscores (snake_case)
290
+
291
+ ```sql
292
+ -- ✅ CORRECT
293
+ CREATE SCHEMA authentication;
294
+ CREATE SCHEMA inventory;
295
+ CREATE SCHEMA sales;
296
+ CREATE SCHEMA accounting;
297
+ CREATE SCHEMA product_management;
298
+
299
+ -- ❌ INCORRECT
300
+ CREATE SCHEMA Authentication; -- PascalCase
301
+ CREATE SCHEMA ProductManagement; -- PascalCase
302
+ CREATE SCHEMA "product-management"; -- Hyphenated (prefer underscores)
303
+ ```
304
+
305
+ **Schema-to-Service Mapping Example:**
306
+
307
+ | Microservice | Schema Name | Purpose |
308
+ |--------------|-------------|---------|
309
+ | AuthenticationService | `authentication` | Users, Roles, Permissions |
310
+ | InventoryService | `inventory` | Products, Warehouses, Stock |
311
+ | SalesService | `sales` | Customers, Orders, Invoices |
312
+ | AccountingService | `accounting` | Accounts, Ledgers, Transactions |
313
+
314
+ **EF Core Configuration:**
315
+
316
+ ```csharp
317
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
318
+ {
319
+ // Set default schema for all entities in this context
320
+ modelBuilder.HasDefaultSchema("inventory");
321
+
322
+ // Configure specific entity table names
323
+ modelBuilder.Entity<Product>(entity =>
324
+ {
325
+ entity.ToTable("products", "inventory");
326
+ });
327
+
328
+ // Apply snake_case naming to all entities
329
+ modelBuilder.ApplySnakeCaseNaming();
330
+ }
331
+ ```
332
+
333
+ ### 1.7 Projection Tables (Cross-Service References)
334
+
335
+ **Convention:** C# class `{PREFIX}_{Entity}Prj`, database table `{prefix}_{origin_table_name}_prj` (snake_case)
336
+
337
+ **Purpose:** Tables that maintain eventual-consistent copies of data from other microservices for referential integrity without database-level foreign keys.
338
+
339
+ **Pattern:**
340
+ ```
341
+ Prefix: 4 uppercase characters identifying the source service/module
342
+ C# Class: {PREFIX}_{Entity}Prj (singular - class convention)
343
+ Database: {prefix}_{origin_table_name}_prj (maintains origin table plurality)
344
+ ```
345
+
346
+ **Rule:** The projection table name must maintain the same plurality (singular/plural) as the origin table it projects from.
347
+
348
+ **Prefix Examples:**
349
+ - `AUTH` - Authentication service
350
+ - `INVT` - Inventory service
351
+ - `SALE` - Sales service
352
+ - `ACCT` - Accounting service
353
+ - `PROD` - Product management service
354
+
355
+ **Examples:**
356
+
357
+ | Origin Table | Origin Schema | C# Class | Database Projection | Consumer Schema | Purpose |
358
+ |--------------|---------------|----------|---------------------|-----------------|---------|
359
+ | users | authentication | **AUTH_UserPrj** | **auth_users_prj** | accounting | Audit fields (created_by_user_id) |
360
+ | users | authentication | **AUTH_UserPrj** | **auth_users_prj** | inventory | Audit fields (created_by_user_id) |
361
+ | products | inventory | **INVT_ProductPrj** | **invt_products_prj** | sales | Product references (product_id) |
362
+ | customers | sales | **SALE_CustomerPrj** | **sale_customers_prj** | accounting | Customer references (customer_id) |
363
+ | accounts | accounting | **ACCT_AccountPrj** | **acct_accounts_prj** | sales | Account references (account_id) |
364
+
365
+ **SQL Schema Template:**
366
+
367
+ ```sql
368
+ -- ✅ CORRECT: Projection table in consumer schema (snake_case with prefix, maintains origin plurality)
369
+ -- Schema: inventory (consuming users from authentication service)
370
+ -- Origin: users (plural) → Projection: auth_users_prj (plural)
371
+ CREATE TABLE auth_users_prj (
372
+ id UUID PRIMARY KEY,
373
+ code VARCHAR(50) NOT NULL,
374
+ name VARCHAR(200) NOT NULL,
375
+ is_active BOOLEAN NOT NULL,
376
+ last_synced_at TIMESTAMP NOT NULL DEFAULT NOW()
377
+ );
378
+
379
+ CREATE INDEX ix_auth_users_prj_code ON auth_users_prj(code);
380
+ CREATE INDEX ix_auth_users_prj_is_active ON auth_users_prj(is_active);
381
+
382
+ -- Schema: sales (consuming products from inventory service)
383
+ -- Origin: products (plural) → Projection: invt_products_prj (plural)
384
+ CREATE TABLE invt_products_prj (
385
+ id UUID PRIMARY KEY,
386
+ code VARCHAR(50) NOT NULL,
387
+ name VARCHAR(200) NOT NULL,
388
+ price DECIMAL(18,2),
389
+ is_active BOOLEAN NOT NULL,
390
+ last_synced_at TIMESTAMP NOT NULL DEFAULT NOW()
391
+ );
392
+
393
+ -- ❌ INCORRECT: Old naming conventions
394
+ CREATE TABLE UsersPrj (...); -- PascalCase (wrong)
395
+ CREATE TABLE user_projection (...); -- Too verbose (wrong)
396
+ CREATE TABLE users_prj (...); -- Missing prefix (wrong)
397
+ CREATE TABLE auth_user_prj (...); -- Wrong plurality (origin is plural 'users')
398
+ CREATE TABLE AUTH_UsersPrj (...); -- PascalCase in DB (wrong)
399
+ CREATE TABLE authUserPrj (...); -- camelCase (wrong)
400
+ ```
401
+
402
+ **C# Entity Example:**
403
+
404
+ ```csharp
405
+ // ✅ CORRECT: C# class uses PREFIX_EntityPrj pattern
406
+ public class AUTH_UserPrj
407
+ {
408
+ public Guid ID { get; set; }
409
+ public string Code { get; set; } = null!;
410
+ public string Name { get; set; } = null!;
411
+ public bool IsActive { get; set; }
412
+ public DateTime LastSyncedAt { get; set; }
413
+ }
414
+
415
+ public class INVT_ProductPrj
416
+ {
417
+ public Guid ID { get; set; }
418
+ public string Code { get; set; } = null!;
419
+ public string Name { get; set; } = null!;
420
+ public decimal Price { get; set; }
421
+ public bool IsActive { get; set; }
422
+ public DateTime LastSyncedAt { get; set; }
423
+ }
424
+
425
+ // DbContext with explicit table mapping
426
+ public DbSet<AUTH_UserPrj> AUTH_UserPrj => Set<AUTH_UserPrj>();
427
+ public DbSet<INVT_ProductPrj> INVT_ProductPrj => Set<INVT_ProductPrj>();
428
+
429
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
430
+ {
431
+ modelBuilder.Entity<AUTH_UserPrj>(entity =>
432
+ {
433
+ // Table name maintains origin table plurality (users → auth_users_prj)
434
+ entity.ToTable("auth_users_prj", "inventory");
435
+ // Column mappings applied automatically via SnakeCaseNamingConvention
436
+ });
437
+
438
+ modelBuilder.Entity<INVT_ProductPrj>(entity =>
439
+ {
440
+ // Table name maintains origin table plurality (products → invt_products_prj)
441
+ entity.ToTable("invt_products_prj", "sales");
442
+ });
443
+ }
444
+ ```
445
+
446
+ **Synchronization:**
447
+ - Via domain events (message bus): `UserCreated`, `UserUpdated`, `ProductUpdated`
448
+ - Eventual consistency model
449
+ - No database-level FK constraints
450
+ - Application-level validation before insert
451
+
452
+ **Usage in Business Tables:**
453
+
454
+ ```sql
455
+ -- Business table references projection (no FK constraint)
456
+ CREATE TABLE orders (
457
+ id UUID PRIMARY KEY DEFAULT uuidv7(),
458
+ customer_id UUID NOT NULL, -- References sale_customers_prj.id (no FK)
459
+ created_by_user_id UUID NOT NULL, -- References auth_users_prj.id (no FK)
460
+ amount DECIMAL(18,2) NOT NULL,
461
+ created_at TIMESTAMP DEFAULT NOW()
462
+ );
463
+
464
+ -- Validation in application layer before insert:
465
+ -- 1. Check sale_customers_prj
466
+ -- 2. Check auth_users_prj
467
+ -- 3. Then insert order
468
+ ```
469
+
470
+ **Rationale:**
471
+ - **4-char prefix:** Identifies source service/module clearly (`AUTH`, `INVT`, `SALE`, `ACCT`)
472
+ - **`Prj` suffix in C#:** Short (3 chars), recognizable abbreviation for "Projection"
473
+ - **Brevity over verbosity:** `AUTH_UserPrj` preferred over `AuthenticationUserProjection`
474
+ - **snake_case in database:** Consistent with PostgreSQL standard
475
+ - **Maintains origin plurality:** `users` → `auth_users_prj`, `products` → `invt_products_prj` (clear relationship to origin)
476
+ - **Direct mapping:** Visual consistency between origin and projection (`users` ↔ `auth_users_prj`)
477
+ - **Self-documenting:** Clear distinction from origin table via prefix + `_prj` suffix
478
+ - **Namespace isolation:** Prefix prevents naming collisions across services
479
+ - **Query clarity:** Queries clearly show which origin table is being referenced
480
+
481
+ **Plurality Examples:**
482
+
483
+ ```csharp
484
+ // With Pluralization Enabled (origin tables are plural)
485
+ Origin: users (plural) → Projection: auth_users_prj (plural)
486
+ Origin: products (plural) → Projection: invt_products_prj (plural)
487
+ Origin: categories (plural) → Projection: acct_categories_prj (plural)
488
+
489
+ // With Pluralization Disabled (origin tables are singular)
490
+ Origin: user (singular) → Projection: auth_user_prj (singular)
491
+ Origin: product (singular) → Projection: invt_product_prj (singular)
492
+ Origin: category (singular) → Projection: acct_category_prj (singular)
493
+ ```
494
+
495
+ **Key Principle:** Always mirror the origin table's plurality in the projection table name for maximum clarity and consistency.
496
+
497
+ ## 2. EF Core Mapping Strategy
498
+
499
+ ### 2.1 Strategy: Automatic snake_case Conversion
500
+
501
+ **Decision:** C# classes use idiomatic PascalCase, PostgreSQL uses idiomatic snake_case. EF Core automatically converts between them via `SnakeCaseNamingConvention`.
502
+
503
+ **Benefits:**
504
+ - ✅ Idiomatic C# code (PascalCase properties)
505
+ - ✅ PostgreSQL standard naming (snake_case columns)
506
+ - ✅ Zero manual `[Column]` or `[Table]` attributes needed
507
+ - ✅ Handles acronyms correctly (APIKey → api_key, HTTPClient → http_client)
508
+ - ✅ Single source of truth (C# classes define structure)
509
+
510
+ **Implementation:**
511
+
512
+ ```csharp
513
+ // File: Shared/EntityFramework/SnakeCaseNamingConvention.cs
514
+ public static class SnakeCaseNamingConvention
515
+ {
516
+ public static string ToSnakeCase(string input)
517
+ {
518
+ if (string.IsNullOrEmpty(input)) return input;
519
+
520
+ // Handle acronyms and PascalCase correctly:
521
+ // ID → id, APIKey → api_key, CreatedAt → created_at, HTTPClient → http_client
522
+ var snakeCase = Regex.Replace(input, "([a-z0-9])([A-Z])", "$1_$2");
523
+ snakeCase = Regex.Replace(snakeCase, "([A-Z]+)([A-Z][a-z])", "$1_$2");
524
+ return snakeCase.ToLowerInvariant();
525
+ }
526
+
527
+ public static void ApplySnakeCaseNaming(this ModelBuilder modelBuilder)
528
+ {
529
+ foreach (var entity in modelBuilder.Model.GetEntityTypes())
530
+ {
531
+ // Convert table names: Product → product (or products if pluralization enabled)
532
+ entity.SetTableName(ToSnakeCase(entity.GetTableName()));
533
+
534
+ // Convert column names: CreatedAt → created_at
535
+ foreach (var property in entity.GetProperties())
536
+ {
537
+ property.SetColumnName(ToSnakeCase(property.Name));
538
+ }
539
+
540
+ // Convert indexes: ix_Product_Code → ix_product_code
541
+ foreach (var index in entity.GetIndexes())
542
+ {
543
+ var prefix = index.IsUnique ? "uk_" : "ix_";
544
+ var tableName = ToSnakeCase(entity.GetTableName());
545
+ var columnNames = string.Join("_", index.Properties.Select(p => ToSnakeCase(p.Name)));
546
+ index.SetDatabaseName($"{prefix}{tableName}_{columnNames}");
547
+ }
548
+
549
+ // Convert FK constraints: fk_Order_Customer → fk_order_customer
550
+ foreach (var foreignKey in entity.GetForeignKeys())
551
+ {
552
+ var dependentTable = ToSnakeCase(foreignKey.DeclaringEntityType.GetTableName());
553
+ var principalTable = ToSnakeCase(foreignKey.PrincipalEntityType.GetTableName());
554
+ foreignKey.SetConstraintName($"fk_{dependentTable}_{principalTable}");
555
+ }
556
+ }
557
+ }
558
+ }
559
+ ```
560
+
561
+ **Example Mapping:**
562
+
563
+ ```csharp
564
+ // C# Entity (idiomatic PascalCase)
565
+ public class Product
566
+ {
567
+ public Guid ID { get; set; } // → id
568
+ public string Code { get; set; } // → code
569
+ public string Name { get; set; } // → name
570
+ public decimal Price { get; set; } // → price
571
+ public bool IsActive { get; set; } // → is_active
572
+ public DateTime CreatedAt { get; set; } // → created_at
573
+ public Guid CreatedByUserID { get; set; } // → created_by_user_id
574
+ public string APIKey { get; set; } // → api_key
575
+ public string HTTPEndpoint { get; set; } // → http_endpoint
576
+ }
577
+
578
+ // PostgreSQL Table (PostgreSQL standard snake_case) - GENERATED AUTOMATICALLY
579
+ CREATE TABLE products ( -- or 'product' if pluralization disabled
580
+ id UUID PRIMARY KEY DEFAULT uuidv7(),
581
+ code VARCHAR(50) NOT NULL,
582
+ name VARCHAR(200) NOT NULL,
583
+ price DECIMAL(18,2) NOT NULL,
584
+ is_active BOOLEAN NOT NULL,
585
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
586
+ created_by_user_id UUID NOT NULL REFERENCES users(id),
587
+ api_key VARCHAR(100),
588
+ http_endpoint VARCHAR(500)
589
+ );
590
+
591
+ CREATE UNIQUE INDEX uk_products_code ON products(code);
592
+ CREATE INDEX ix_products_is_active ON products(is_active);
593
+ ```
594
+
595
+ ### 2.2 DbContext Configuration
596
+
597
+ **CRITICAL:** Apply snake_case naming **AFTER** all entity configurations:
598
+
599
+ ```csharp
600
+ // Example DbContext
601
+ public class ApplicationDbContext : DbContext
602
+ {
603
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
604
+ {
605
+ // Set schema
606
+ modelBuilder.HasDefaultSchema("inventory");
607
+
608
+ // Configure entities (explicit table naming)
609
+ modelBuilder.Entity<Product>(entity =>
610
+ {
611
+ // Explicit snake_case table name
612
+ // Use "products" if pluralization enabled, "product" if disabled
613
+ entity.ToTable("products", "inventory");
614
+
615
+ entity.HasKey(e => e.ID);
616
+
617
+ entity.Property(e => e.Code).IsRequired().HasMaxLength(50);
618
+ entity.HasIndex(e => e.Code).IsUnique();
619
+
620
+ entity.Property(e => e.Price).HasPrecision(18, 2);
621
+ });
622
+
623
+ // CRITICAL: Apply snake_case naming LAST
624
+ modelBuilder.ApplySnakeCaseNaming();
625
+ }
626
+ }
627
+ ```
628
+
629
+ **Why apply last?** The convention needs to process all configured entities, indexes, and constraints.
630
+
631
+ ### 2.3 When to Use [Column] or [Table] Attributes
632
+
633
+ **Short answer: RARELY**
634
+
635
+ The `SnakeCaseNamingConvention` handles all mapping automatically. Manual attributes are:
636
+ - ❌ Usually not needed
637
+ - ❌ Can create inconsistency
638
+ - ❌ Bypass the convention
639
+ - ❌ Increase maintenance burden
640
+
641
+ ```csharp
642
+ // ❌ INCORRECT - Don't use manual attributes (convention handles this)
643
+ public class Product
644
+ {
645
+ [Column("price")] // WRONG - convention handles this
646
+ public decimal Price { get; set; }
647
+
648
+ [Table("products")] // WRONG - use ToTable() in OnModelCreating instead
649
+ }
650
+
651
+ // ✅ CORRECT - Let convention handle everything
652
+ public class Product
653
+ {
654
+ public decimal Price { get; set; } // → price automatically
655
+ }
656
+ ```
657
+
658
+ **Exception:** If you legitimately need a database column name that doesn't follow snake_case (e.g., legacy integration), document it clearly and use `[Column]` with a comment explaining why.
659
+
660
+ ## 3. Tooling
661
+
662
+ ### 3.1 SQL - pg_format
663
+
664
+ ```bash
665
+ # Format SQL files with snake_case
666
+ pg_format --function-case 2 --keyword-case 2 --spaces 2 migration.sql
667
+ ```
@@ -4,10 +4,10 @@
4
4
  Based on Frontend Development Standards and Clean Architecture Implementation
5
5
 
6
6
  ### Technology Stack
7
- - **Framework**: Next.js 16+ with App Router
7
+ - **Framework**: Vite 6+ with TanStack Router
8
8
  - **Language**: TypeScript (strict mode)
9
9
  - **Styling**: TailwindCSS + Shadcn/ui + Radix UI
10
- - **State Management**: Zustand
10
+ - **State Management**: Zustand + TanStack Query
11
11
  - **Testing**: Vitest + React Testing Library
12
12
  - **Architecture**: Clean Architecture with DDD patterns
13
13
  - **Loading States**: React Loading Skeleton (for placeholders/preloading)
@@ -1,5 +1,5 @@
1
1
  project_type,detection_signals,description,typical_starters
2
- web_app,"website,web application,browser,frontend,UI,interface",Web-based applications running in browsers,Next.js, Vite, Remix
2
+ web_app,"website,web application,browser,frontend,UI,interface",Web-based applications running in browsers,Vite, Remix
3
3
  mobile_app,"mobile,iOS,Android,app,smartphone,tablet",Native mobile applications,React Native, Expo, Flutter
4
4
  api_backend,"API,REST,GraphQL,backend,service,microservice",Backend services and APIs,NestJS, Express, Fastify
5
5
  full_stack,"full-stack,complete,web+mobile,frontend+backend",Applications with both frontend and backend,T3 App, RedwoodJS, Blitz
@@ -87,7 +87,7 @@ No existing technical preferences found in project context file. We'll establish
87
87
  {{primary_technology_category}} Preferences:
88
88
 
89
89
  - **Languages**: Do you have preferences between TypeScript/JavaScript, Python, Go, Rust, etc.?
90
- - **Frameworks**: Any existing familiarity or preferences (React, Vue, Angular, Next.js, etc.)?
90
+ - **Frameworks**: Any existing familiarity or preferences (React, Vue, Angular, Vite, etc.)?
91
91
  - **Databases**: Any preferences or existing infrastructure (PostgreSQL, MongoDB, MySQL, etc.)?
92
92
 
93
93
  **Development Experience:**
@@ -111,11 +111,11 @@ These preferences will help me recommend the most suitable starter templates and
111
111
 
112
112
  Based on project context analysis and technical preferences, identify the primary technology stack:
113
113
 
114
- - **Web application** → Look for Next.js, Vite, Remix, SvelteKit starters
114
+ - **Web application** → Look for Vite, Remix, SvelteKit starters
115
115
  - **Mobile app** → Look for React Native, Expo, Flutter starters
116
116
  - **API/Backend** → Look for NestJS, Express, Fastify, Supabase starters
117
117
  - **CLI tool** → Look for CLI framework starters (oclif, commander, etc.)
118
- - **Full-stack** → Look for T3, RedwoodJS, Blitz, Next.js starters
118
+ - **Full-stack** → Look for T3, RedwoodJS, Blitz starters
119
119
  - **Desktop** → Look for Electron, Tauri starters
120
120
 
121
121
  ### 2. UX Requirements Consideration
@@ -133,39 +133,41 @@ Generate a comprehensive directory structure showing all files and directories:
133
133
 
134
134
  **Technology-Specific Structure Examples:**
135
135
 
136
- **Next.js Full-Stack:**
136
+ **Vite + TanStack Full-Stack:**
137
137
 
138
138
  ```
139
139
  project-name/
140
140
  ├── README.md
141
141
  ├── package.json
142
- ├── next.config.js
142
+ ├── vite.config.ts
143
143
  ├── tailwind.config.js
144
144
  ├── tsconfig.json
145
- ├── .env.local
145
+ ├── .env
146
146
  ├── .env.example
147
147
  ├── .gitignore
148
148
  ├── .github/
149
149
  │ └── workflows/
150
150
  │ └── ci.yml
151
151
  ├── src/
152
- │ ├── app/
153
- ├── globals.css
154
- ├── layout.tsx
155
- │ └── page.tsx
152
+ │ ├── main.tsx
153
+ │ ├── App.tsx
154
+ │ ├── index.css
155
+ ├── assets/
156
156
  │ ├── components/
157
157
  │ │ ├── ui/
158
158
  │ │ ├── forms/
159
159
  │ │ └── features/
160
+ │ ├── hooks/
160
161
  │ ├── lib/
161
- │ │ ├── db.ts
162
+ │ │ ├── query-client.ts
162
163
  │ │ ├── auth.ts
163
164
  │ │ └── utils.ts
164
- │ ├── types/
165
- └── middleware.ts
166
- ├── prisma/
167
- ├── schema.prisma
168
- └── migrations/
165
+ │ ├── routes/
166
+ │ ├── __root.tsx
167
+ │ │ ├── index.tsx
168
+ │ └── ...
169
+ ├── stores/
170
+ │ └── types/
169
171
  ├── tests/
170
172
  │ ├── __mocks__/
171
173
  │ ├── components/
@@ -60,6 +60,7 @@ Check for and load company-specific technology standards:
60
60
  **If directory exists, load ALL markdown files:**
61
61
 
62
62
  - `technology-stack.md` - Predefined technology stack and versions
63
+ - `database-conventions.md` - PostgreSQL database naming conventions
63
64
  - `backend-standards.md` - Backend development patterns and rules
64
65
  - `frontend-standards.md` - Frontend development patterns
65
66
  - `architecture-patterns.md` - Architectural decision patterns
@@ -78,7 +79,7 @@ When loading company standards, specifically look for and highlight:
78
79
  - 🔴 **siesa-ui-kit requirement** - Must check siesa-ui-kit before creating components
79
80
  - 🔴 **Spanish UI text** - All user-facing text must be in Spanish
80
81
  - 🔴 **DateTimeOffset** - Use DateTimeOffset not DateTime for PostgreSQL
81
- - Technology stack versions (.NET 10, Next.js 16, etc.)
82
+ - Technology stack versions (.NET 10, Vite 6+, etc.)
82
83
 
83
84
  Report: "✅ Estándares corporativos cargados: {count} archivos con {rules_count} reglas críticas"
84
85
 
@@ -125,7 +125,7 @@ Document framework-specific patterns:
125
125
  Should I add any other React-specific rules?"
126
126
 
127
127
  **Other Framework Rules:**
128
- Adapt for Vue, Angular, Next.js, Express, etc.
128
+ Adapt for Vue, Angular, Vite, Express, etc.
129
129
 
130
130
  ### 4. Testing Rules
131
131
 
@@ -10,7 +10,7 @@ Before starting the workflow:
10
10
 
11
11
  - [ ] Project root contains valid `package.json`
12
12
  - [ ] No existing modern E2E framework detected (`playwright.config.*`, `cypress.config.*`)
13
- - [ ] Project type identifiable (React, Vue, Angular, Next.js, Node, etc.)
13
+ - [ ] Project type identifiable (React, Vue, Angular, Vite, Node, etc.)
14
14
  - [ ] Bundler identifiable (Vite, Webpack, Rollup, esbuild) or not applicable
15
15
  - [ ] User has write permissions to create directories and files
16
16
 
@@ -29,7 +29,7 @@ Initialize a production-ready test framework architecture (Playwright or Cypress
29
29
 
30
30
  1. **Validate package.json**
31
31
  - Read `{project-root}/package.json`
32
- - Extract project type (React, Vue, Angular, Next.js, Node, etc.)
32
+ - Extract project type (React, Vue, Angular, Vite, Node, etc.)
33
33
  - Identify bundler (Vite, Webpack, Rollup, esbuild)
34
34
  - Note existing test dependencies
35
35
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "siesa-agents",
3
- "version": "2.1.50",
3
+ "version": "2.1.52",
4
4
  "description": "Paquete para instalar y configurar agentes SIESA en tu proyecto",
5
5
  "main": "index.js",
6
6
  "bin": {