Hamza/feature/bus gateway - #188
Conversation
Bus-triggered counterpart to the API gateway: when a message arrives for a document, each matching route runs its subscription, optionally injecting a partner's values. - New SubscriptionType.BusGateway (32) + create/update validation - BusGateway + BusGatewayRoute entities, EF config (base + PgSql), and migrations for PgSql/MySql/MsSql - FilterResult.GatewayHits; FilterService evaluates routes and excludes gateway subs from normal matching; XchangeService dispatches gateway hits via the existing API-gateway xchange path (partner + globals injection) - Cache routes per document; CRUD handlers under Resources/BusGateways - Handle BusGateway in the Xchange created-event switch
|
Warning Review limit reached
Next review available in: 32 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Repository: simplify9/coderabbit/.coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThis PR introduces a BusGateway feature: new domain entities ( ChangesBusGateway feature
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
SW.Bitween.Sdk/JsonConverters/PropertyMatchSpecificationJsonConverter.cs (1)
56-98: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicate single-sided fallback logic between
EvaluateAnd/EvaluateOr.Both methods repeat the same three checks (both-present, left-only, right-only) verbatim; only the combinator differs. Extract a shared helper.
♻️ Proposed refactor
- IPropertyMatchSpecification EvaluateAnd(JObject jObj) - { - var jLeft = jObj.Property("left")?.Value; - var jRight = jObj.Property("right")?.Value; - if (jLeft is JObject jLeftObj && jRight is JObject jRightObj) - { - return new AndSpec(Evaluate(jLeftObj), Evaluate(jRightObj)); - } - - if (jLeft is JObject soleLeftObj && IsNullOrMissing(jRight)) - { - return Evaluate(soleLeftObj); - } - - if (jRight is JObject soleRightObj && IsNullOrMissing(jLeft)) - { - return Evaluate(soleRightObj); - } - - throw new JsonSerializationException("Invalid Match Specification Format"); - } - - IPropertyMatchSpecification EvaluateOr(JObject jObj) - { - var jLeft = jObj.Property("left")?.Value; - var jRight = jObj.Property("right")?.Value; - if (jLeft is JObject jLeftObj && jRight is JObject jRightObj) - { - return new OrSpec(Evaluate(jLeftObj), Evaluate(jRightObj)); - } - - if (jLeft is JObject soleLeftObj && IsNullOrMissing(jRight)) - { - return Evaluate(soleLeftObj); - } - - if (jRight is JObject soleRightObj && IsNullOrMissing(jLeft)) - { - return Evaluate(soleRightObj); - } - - throw new JsonSerializationException("Invalid Match Specification Format"); - } + IPropertyMatchSpecification EvaluateAnd(JObject jObj) => + EvaluateBinary(jObj, (l, r) => new AndSpec(l, r)); + + IPropertyMatchSpecification EvaluateOr(JObject jObj) => + EvaluateBinary(jObj, (l, r) => new OrSpec(l, r)); + + IPropertyMatchSpecification EvaluateBinary(JObject jObj, + Func<IPropertyMatchSpecification, IPropertyMatchSpecification, IPropertyMatchSpecification> combine) + { + var jLeft = jObj.Property("left")?.Value; + var jRight = jObj.Property("right")?.Value; + if (jLeft is JObject jLeftObj && jRight is JObject jRightObj) + return combine(Evaluate(jLeftObj), Evaluate(jRightObj)); + + if (jLeft is JObject soleLeftObj && IsNullOrMissing(jRight)) + return Evaluate(soleLeftObj); + + if (jRight is JObject soleRightObj && IsNullOrMissing(jLeft)) + return Evaluate(soleRightObj); + + throw new JsonSerializationException("Invalid Match Specification Format"); + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@SW.Bitween.Sdk/JsonConverters/PropertyMatchSpecificationJsonConverter.cs` around lines 56 - 98, Both EvaluateAnd and EvaluateOr duplicate the same left/right fallback checks, with only the spec combinator changing. Extract the shared branching logic into a helper inside PropertyMatchSpecificationJsonConverter that handles both-present, left-only, and right-only cases, and pass in the constructor/combinator so EvaluateAnd and EvaluateOr simply delegate to it.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@SW.Bitween.Api/Resources/BusGateways/Create.cs`:
- Around line 11-42: Add validation for BusGatewayCreate.Name before
Create.Handle persists the entity, since it currently stores model.Name directly
without any FluentValidation guard. Update the BusGatewayCreate validator (or
add one if missing) to require a non-empty, non-whitespace Name, and ensure the
Create command path in Create.Handle only accepts validated input before saving
the BusGateway entity.
In `@SW.Bitween.Api/Resources/BusGateways/Update.cs`:
- Around line 33-38: The Update flow in BusGateway resource currently persists
entity.Name directly without validating model.Name, so empty or whitespace-only
names can be saved. Add input validation in the update handler before assigning
and saving: check model.Name is not null/empty/whitespace, reject invalid values
with the existing validation/error pattern, and only proceed with entity.Name,
SaveChangesAsync, and BroadcastRevoke when the name is valid.
In `@SW.Bitween.Api/Resources/Subscriptions/Create.cs`:
- Around line 39-42: In Create.cs, the GatewayApiCall and BusGateway path in the
create flow is silently dropping a supplied PartnerId because Subscription(name,
documentId, type) always sets it to null. Update the create validation and
entity construction to match Subscriptions/Update.cs: if model.Type is
GatewayApiCall or BusGateway and model.PartnerId has a value, reject the request
instead of ignoring it. Use the existing Create validator and the subscription
creation branch to ensure PartnerId is only accepted for types that support it.
In `@SW.Bitween.Api/Services/XchangeService.cs`:
- Around line 420-436: Use the cached global adapter values list instead of
querying the DB directly in XchangeService’s bus-gateway route handling. Replace
the _dbContext.Set<GlobalAdapterValuesSet>().ToArrayAsync() call with
_BitweenCache.ListGlobalAdapterValuesSetsAsync(), and keep the existing loop
over result.GatewayHits unchanged so the partner/global injection path still
works through the cache layer.
In `@SW.Bitween.MsSql/Migrations/20260702125359_AddBusGateway.cs`:
- Around line 38-89: The BusGatewayRoutes table currently allows duplicate route
rows for the same BusGatewayId, SubscriptionId, and PartnerId, so add a DB-level
uniqueness guard in the AddBusGateway migration. Update the BusGatewayRoutes
creation in AddBusGateway to define a unique index or alternate key over the
route identity columns, and ensure it aligns with the AddRoute/UpdateRoute
behavior so duplicate subscription+partner routes cannot be inserted.
In `@SW.Bitween.Sdk/Model/BusGateway.cs`:
- Around line 12-15: Remove the Routes property from BusGatewayUpdate so the
update contract only exposes Name and does not suggest route changes are
supported here. Update the BusGatewayUpdate model in BusGateway.cs to inherit
the create fields without Routes, and keep route modifications confined to the
dedicated route endpoints and their DTOs/handlers.
---
Outside diff comments:
In `@SW.Bitween.Sdk/JsonConverters/PropertyMatchSpecificationJsonConverter.cs`:
- Around line 56-98: Both EvaluateAnd and EvaluateOr duplicate the same
left/right fallback checks, with only the spec combinator changing. Extract the
shared branching logic into a helper inside
PropertyMatchSpecificationJsonConverter that handles both-present, left-only,
and right-only cases, and pass in the constructor/combinator so EvaluateAnd and
EvaluateOr simply delegate to it.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: simplify9/coderabbit/.coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 14a81a00-96b5-499d-9ac9-b38e285040c6
📒 Files selected for processing (33)
SW.Bitween.Api/Data/BitweenDbContext.csSW.Bitween.Api/Domain/Gateway/BusGateway.csSW.Bitween.Api/Domain/Gateway/BusGatewayRoute.csSW.Bitween.Api/Domain/Subscription/Subscription.csSW.Bitween.Api/Domain/Xchange/Xchange.csSW.Bitween.Api/Interfaces/IInfolinkCache.csSW.Bitween.Api/Resources/BusGateways/AddRoute.csSW.Bitween.Api/Resources/BusGateways/Create.csSW.Bitween.Api/Resources/BusGateways/Delete.csSW.Bitween.Api/Resources/BusGateways/Get.csSW.Bitween.Api/Resources/BusGateways/RemoveRoute.csSW.Bitween.Api/Resources/BusGateways/Search.csSW.Bitween.Api/Resources/BusGateways/Update.csSW.Bitween.Api/Resources/BusGateways/UpdateRoute.csSW.Bitween.Api/Resources/Subscriptions/Create.csSW.Bitween.Api/Resources/Subscriptions/Update.csSW.Bitween.Api/Services/Caching/InMemoryInfolinkCache.csSW.Bitween.Api/Services/FilterService.csSW.Bitween.Api/Services/XchangeService.csSW.Bitween.MsSql/Migrations/20260702125359_AddBusGateway.Designer.csSW.Bitween.MsSql/Migrations/20260702125359_AddBusGateway.csSW.Bitween.MsSql/Migrations/BitweenDbContextModelSnapshot.csSW.Bitween.MySql/Migrations/20260702125335_AddBusGateway.Designer.csSW.Bitween.MySql/Migrations/20260702125335_AddBusGateway.csSW.Bitween.MySql/Migrations/BitweenDbContextModelSnapshot.csSW.Bitween.PgSql/BitweenDbContext.csSW.Bitween.PgSql/Migrations/20260702125227_AddBusGateway.Designer.csSW.Bitween.PgSql/Migrations/20260702125227_AddBusGateway.csSW.Bitween.PgSql/Migrations/BitweenDbContextModelSnapshot.csSW.Bitween.Sdk/JsonConverters/PropertyMatchSpecificationJsonConverter.csSW.Bitween.Sdk/Model/BusGateway.csSW.Bitween.Sdk/Model/FilterResult.csSW.Bitween.Sdk/Model/Subscription.cs
📜 Review details
🧰 Additional context used
🪛 Betterleaks (1.6.0)
SW.Bitween.MsSql/Migrations/20260702125359_AddBusGateway.Designer.cs
[high] 1079-1079: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
SW.Bitween.PgSql/Migrations/20260702125227_AddBusGateway.Designer.cs
[high] 1297-1297: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
SW.Bitween.MySql/Migrations/20260702125335_AddBusGateway.Designer.cs
[high] 1076-1076: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🔇 Additional comments (34)
SW.Bitween.Api/Domain/Gateway/BusGateway.cs (1)
1-16: LGTM!SW.Bitween.Api/Domain/Gateway/BusGatewayRoute.cs (1)
1-25: LGTM!SW.Bitween.Sdk/Model/Subscription.cs (1)
15-15: LGTM!SW.Bitween.Api/Domain/Subscription/Subscription.cs (1)
38-44: LGTM!SW.Bitween.Api/Domain/Xchange/Xchange.cs (1)
33-34: LGTM!SW.Bitween.Sdk/Model/FilterResult.cs (1)
9-27: LGTM!SW.Bitween.PgSql/Migrations/BitweenDbContextModelSnapshot.cs (1)
409-414: Same MatchExpression converter concern as above.SW.Bitween.Api/Data/BitweenDbContext.cs (1)
118-146: LGTM!SW.Bitween.PgSql/BitweenDbContext.cs (1)
143-171: LGTM!SW.Bitween.Api/Interfaces/IInfolinkCache.cs (1)
3-10: LGTM!SW.Bitween.PgSql/Migrations/20260702125227_AddBusGateway.Designer.cs (1)
409-414: 🗄️ Data Integrity & IntegrationVerify the generated model preserves the
MatchExpressionconverter.
SW.Bitween.PgSql/BitweenDbContext.csmapsBusGatewayRoute.MatchExpressionthroughMatchSpecValueConverter, andSW.Bitween.Api/Services/FilterService.cslater callsIsMatch(...)on the deserialized object. This generated model records the property as plainstring; please confirm that is intentional. Otherwise future migrations will drift from the runtime model and route matching will stop round-tripping.SW.Bitween.PgSql/Migrations/20260702125227_AddBusGateway.cs (1)
15-105: LGTM!SW.Bitween.MySql/Migrations/20260702125335_AddBusGateway.Designer.cs (2)
285-318: 🗄️ Data Integrity & IntegrationDuplicate of MsSql Designer.cs comment on BusGateway/Document cardinality.
Same missing unique constraint on
DocumentIdas flagged inSW.Bitween.MsSql/Migrations/20260702125359_AddBusGateway.Designer.cs(Lines 287-320); root cause lives in the shared domain model, not per-provider migration code.
1-284: LGTM!Also applies to: 320-1226
SW.Bitween.MySql/Migrations/BitweenDbContextModelSnapshot.cs (2)
20-20: 📐 Maintainability & Code QualitySame ProductVersion regression as the MsSql snapshot (8.0.26 → 8.0.23).
See the equivalent comment on
SW.Bitween.MsSql/Migrations/BitweenDbContextModelSnapshot.cs(Line 20) — confirm intended EF Core tooling version once and apply consistently across providers.
282-359: LGTM!Also applies to: 999-1033, 1210-1214
SW.Bitween.MsSql/Migrations/20260702125359_AddBusGateway.Designer.cs (2)
287-320: 🗄️ Data Integrity & IntegrationVerify BusGateway↔Document cardinality intent.
BusGatewayhas no unique index onDocumentId(contrast withApiGateway.UrlName, which is unique at Line 249-250). If multipleBusGatewayrows can reference the sameDocument, downstream routing (FilterService gateway-hit evaluation) may become ambiguous about which gateway's routes apply for a given document. Confirm this is intentional; if not, add a unique index onDocumentId.
322-363: LGTM!Also applies to: 1014-1038, 1216-1219
SW.Bitween.MsSql/Migrations/20260702125359_AddBusGateway.cs (1)
1-37: LGTM!Also applies to: 90-107
SW.Bitween.MsSql/Migrations/BitweenDbContextModelSnapshot.cs (2)
284-361: LGTM!Also applies to: 999-1033, 1213-1217
20-20: 📐 Maintainability & Code QualityProductVersion 8.0.23 matches the repo’s EF Core version; no action needed.
> Likely an incorrect or invalid review comment.SW.Bitween.MySql/Migrations/20260702125335_AddBusGateway.cs (1)
1-117: LGTM!SW.Bitween.Api/Resources/BusGateways/AddRoute.cs (1)
1-78: LGTM!SW.Bitween.Api/Resources/BusGateways/Delete.cs (1)
1-43: LGTM!SW.Bitween.Api/Resources/Subscriptions/Update.cs (1)
104-116: LGTM!Also applies to: 255-266
SW.Bitween.Api/Resources/BusGateways/Get.cs (1)
11-20: 🔒 Security & PrivacyClarify whether
BusGateways/Getshould be role-restricted. It returns gateway, route, subscription, and partner details with no access check; add the same guard used by the mutating handlers if this data should not be broadly readable.SW.Bitween.Api/Resources/BusGateways/RemoveRoute.cs (1)
1-40: LGTM!SW.Bitween.Api/Resources/BusGateways/UpdateRoute.cs (1)
1-53: LGTM!SW.Bitween.Api/Services/Caching/InMemoryInfolinkCache.cs (1)
9-9: LGTM!Also applies to: 44-52, 66-79, 192-192
SW.Bitween.Api/Services/FilterService.cs (2)
48-52: LGTM!
62-76: 🩺 Stability & Availability
GatewayHitsis initialized inSW.Bitween.Sdk/Model/FilterResult.cs, so this null-reference concern doesn’t apply.> Likely an incorrect or invalid review comment.SW.Bitween.Api/Services/XchangeService.cs (1)
402-419: LGTM!SW.Bitween.Api/Resources/BusGateways/Search.cs (2)
25-34: 🎯 Functional CorrectnessDocumentId is already inherited on BusGatewayRow, so this projection is valid.
> Likely an incorrect or invalid review comment.
12-21: 🔒 Security & PrivacyCheck BusGateways search access control.
Search.cshas no localRequestContext/EnsureAccessgate; if read access isn’t enforced in the controller/dispatch layer, this should mirror the other BusGateway handlers and requireAccountRole.AdminorAccountRole.Member.
| // Bus-gateway routes: run the assigned subscription with the route's optional partner values, | ||
| // reusing the same xchange path the API gateway uses (partner + globals injection). | ||
| var globalAdapterValuesSets = await _dbContext.Set<GlobalAdapterValuesSet>().ToArrayAsync(); | ||
| foreach (var hit in result.GatewayHits) | ||
| { | ||
| var subscription = await _BitweenCache.SubscriptionByIdAsync(hit.SubscriptionId); | ||
| if (subscription == null) | ||
| { | ||
| _logger.LogWarning( | ||
| "Bus gateway route references subscription {SubscriptionId}, which is not active; skipping.", | ||
| hit.SubscriptionId); | ||
| continue; | ||
| } | ||
|
|
||
| var partner = hit.PartnerId.HasValue | ||
| ? await _dbContext.FindAsync<Partner>(hit.PartnerId.Value) | ||
| : null; |
There was a problem hiding this comment.
🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win
Use cached ListGlobalAdapterValuesSetsAsync instead of a direct DB query.
_BitweenCache.ListGlobalAdapterValuesSetsAsync() already exists and is cached (see InMemoryInfolinkCache.cs). Querying _dbContext.Set<GlobalAdapterValuesSet>() directly here re-hits the DB on every gateway-hit message and bypasses the existing cache layer this class already depends on for subscriptions.
Proposed fix
- var globalAdapterValuesSets = await _dbContext.Set<GlobalAdapterValuesSet>().ToArrayAsync();
+ var globalAdapterValuesSets = await _BitweenCache.ListGlobalAdapterValuesSetsAsync();📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Bus-gateway routes: run the assigned subscription with the route's optional partner values, | |
| // reusing the same xchange path the API gateway uses (partner + globals injection). | |
| var globalAdapterValuesSets = await _dbContext.Set<GlobalAdapterValuesSet>().ToArrayAsync(); | |
| foreach (var hit in result.GatewayHits) | |
| { | |
| var subscription = await _BitweenCache.SubscriptionByIdAsync(hit.SubscriptionId); | |
| if (subscription == null) | |
| { | |
| _logger.LogWarning( | |
| "Bus gateway route references subscription {SubscriptionId}, which is not active; skipping.", | |
| hit.SubscriptionId); | |
| continue; | |
| } | |
| var partner = hit.PartnerId.HasValue | |
| ? await _dbContext.FindAsync<Partner>(hit.PartnerId.Value) | |
| : null; | |
| // Bus-gateway routes: run the assigned subscription with the route's optional partner values, | |
| // reusing the same xchange path the API gateway uses (partner + globals injection). | |
| var globalAdapterValuesSets = await _BitweenCache.ListGlobalAdapterValuesSetsAsync(); | |
| foreach (var hit in result.GatewayHits) | |
| { | |
| var subscription = await _BitweenCache.SubscriptionByIdAsync(hit.SubscriptionId); | |
| if (subscription == null) | |
| { | |
| _logger.LogWarning( | |
| "Bus gateway route references subscription {SubscriptionId}, which is not active; skipping.", | |
| hit.SubscriptionId); | |
| continue; | |
| } | |
| var partner = hit.PartnerId.HasValue | |
| ? await _dbContext.FindAsync<Partner>(hit.PartnerId.Value) | |
| : null; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@SW.Bitween.Api/Services/XchangeService.cs` around lines 420 - 436, Use the
cached global adapter values list instead of querying the DB directly in
XchangeService’s bus-gateway route handling. Replace the
_dbContext.Set<GlobalAdapterValuesSet>().ToArrayAsync() call with
_BitweenCache.ListGlobalAdapterValuesSetsAsync(), and keep the existing loop
over result.GatewayHits unchanged so the partner/global injection path still
works through the cache layer.
| migrationBuilder.CreateTable( | ||
| name: "BusGatewayRoutes", | ||
| columns: table => new | ||
| { | ||
| Id = table.Column<int>(type: "int", nullable: false) | ||
| .Annotation("SqlServer:Identity", "1, 1"), | ||
| BusGatewayId = table.Column<int>(type: "int", nullable: false), | ||
| SubscriptionId = table.Column<int>(type: "int", nullable: false), | ||
| PartnerId = table.Column<int>(type: "int", nullable: true), | ||
| MatchExpression = table.Column<string>(type: "nvarchar(max)", nullable: true), | ||
| CreatedOn = table.Column<DateTime>(type: "datetime2", nullable: false), | ||
| CreatedBy = table.Column<string>(type: "nvarchar(max)", nullable: true), | ||
| ModifiedOn = table.Column<DateTime>(type: "datetime2", nullable: true), | ||
| ModifiedBy = table.Column<string>(type: "nvarchar(max)", nullable: true) | ||
| }, | ||
| constraints: table => | ||
| { | ||
| table.PrimaryKey("PK_BusGatewayRoutes", x => x.Id); | ||
| table.ForeignKey( | ||
| name: "FK_BusGatewayRoutes_BusGateways_BusGatewayId", | ||
| column: x => x.BusGatewayId, | ||
| principalTable: "BusGateways", | ||
| principalColumn: "Id", | ||
| onDelete: ReferentialAction.Restrict); | ||
| table.ForeignKey( | ||
| name: "FK_BusGatewayRoutes_Partners_PartnerId", | ||
| column: x => x.PartnerId, | ||
| principalTable: "Partners", | ||
| principalColumn: "Id", | ||
| onDelete: ReferentialAction.Restrict); | ||
| table.ForeignKey( | ||
| name: "FK_BusGatewayRoutes_Subscriptions_SubscriptionId", | ||
| column: x => x.SubscriptionId, | ||
| principalTable: "Subscriptions", | ||
| principalColumn: "Id", | ||
| onDelete: ReferentialAction.Restrict); | ||
| }); | ||
|
|
||
| migrationBuilder.CreateIndex( | ||
| name: "IX_BusGatewayRoutes_BusGatewayId", | ||
| table: "BusGatewayRoutes", | ||
| column: "BusGatewayId"); | ||
|
|
||
| migrationBuilder.CreateIndex( | ||
| name: "IX_BusGatewayRoutes_PartnerId", | ||
| table: "BusGatewayRoutes", | ||
| column: "PartnerId"); | ||
|
|
||
| migrationBuilder.CreateIndex( | ||
| name: "IX_BusGatewayRoutes_SubscriptionId", | ||
| table: "BusGatewayRoutes", | ||
| column: "SubscriptionId"); |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win
Consider a uniqueness guard for route definitions.
No DB-level constraint prevents duplicate (BusGatewayId, SubscriptionId, PartnerId) route rows. If the API layer (AddRoute/UpdateRoute) doesn't already dedupe, this table could accumulate conflicting/duplicate routes for the same subscription+partner pair.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@SW.Bitween.MsSql/Migrations/20260702125359_AddBusGateway.cs` around lines 38
- 89, The BusGatewayRoutes table currently allows duplicate route rows for the
same BusGatewayId, SubscriptionId, and PartnerId, so add a DB-level uniqueness
guard in the AddBusGateway migration. Update the BusGatewayRoutes creation in
AddBusGateway to define a unique index or alternate key over the route identity
columns, and ensure it aligns with the AddRoute/UpdateRoute behavior so
duplicate subscription+partner routes cannot be inserted.
- Validate Name (required, max 200) on BusGateway create and update; reject empty/whitespace names - Reject a supplied PartnerId for GatewayApiCall/BusGateway subscriptions on create instead of silently discarding it (mirrors Update) - Drop the ignored Routes property from BusGatewayUpdate; it now lives on BusGatewayRow. Route changes go through the dedicated route endpoints
No description provided.