SonarCloud Issue Triage Report¶
Date: 2026-03-13 Project: devgem_forma-3d-connect Branch analyzed: main Total issues: 244 code smells + 15.7% code duplication (10,743 lines / 202 blocks / 105 files) Previous report: 2026-03-12 — 769 issues + 19.5% duplication
Summary¶
| Severity | Count | Auto-fixable | Manual Refactor | Won't Fix / Suppress |
|---|---|---|---|---|
| CRITICAL | 23 | 0 | 23 | 0 |
| MAJOR | 87 | 18 | 59 | 10 |
| MINOR | 134 | 83 | 46 | 5 |
| Total | 244 | 101 | 128 | 15 |
All 244 issues are CODE_SMELL (no bugs or vulnerabilities remaining).
Recommended Action Plan¶
| Phase | Action | Issues | Effort |
|---|---|---|---|
| 1 | Quick auto-fixes (replaceAll, ??=, .at()) | 22 | ~30 min |
| 2 | Readonly props + template literals + a11y | 70 | ~2 hours |
| 3 | Nested ternaries + form labels + assertions | 71 | ~4 hours |
| 4 | Cognitive complexity + toString coercion | 72 | ~8 hours |
| 5 | Won't Fix suppressions | 10 | ~15 min |
| 6 | Duplication reduction | ~105 | ~16 hours |
Phase 1: Quick Auto-fixes (22 issues)¶
S7781 — Prefer String#replaceAll() over String#replace() (9 issues) → FIX¶
| File | Line |
|---|---|
apps/gateway/src/feature-flags-admin/feature-flags-admin.service.ts |
20 |
apps/gateway/src/feature-flags-admin/feature-flags-admin.service.ts |
21 |
apps/gateway/src/proxy/proxy.middleware.ts |
124 |
libs/utils/src/lib/string.ts |
24 |
libs/utils/src/lib/string.ts |
25 |
libs/utils/src/lib/string.ts |
34 |
libs/utils/src/lib/string.ts |
45 |
libs/utils/src/lib/string.ts |
46 |
libs/utils/src/lib/string.ts |
47 |
Fix: Replace .replace(/pattern/g, ...) with .replaceAll(pattern, ...).
S7741 — Compare with undefined directly instead of typeof (2 issues) → FIX¶
| File | Line |
|---|---|
apps/web/src/contexts/theme-context.tsx |
44 |
apps/web/src/contexts/theme-context.tsx |
49 |
Fix: Change typeof x !== 'undefined' to x !== undefined.
S7755 — Use .at() instead of [length - index] (2 issues) → FIX¶
| File | Line |
|---|---|
apps/order-service/src/storefront/storefront.service.ts |
152 |
libs/gridflock-core/src/lib/geometry/base-plate.ts |
234 |
Fix: Replace arr[arr.length - 1] with arr.at(-1).
S6606 — Use ??= instead of assignment expression (2 issues) → FIX¶
| File | Line |
|---|---|
apps/web/src/lib/indexed-db.ts |
41 |
libs/gridflock-core/src/lib/geometry/grid-cells.ts |
17 |
Fix: Replace x = x ?? value or if (x == null) x = value with x ??= value.
S3863 — Merge duplicate imports (2 issues) → FIX¶
| File | Line |
|---|---|
apps/order-service/src/orders/orders.controller.ts |
21 |
apps/order-service/src/orders/orders.controller.ts |
31 |
Fix: Merge duplicate @forma3d/service-common import statements into one.
S7778 — Consolidate multiple Array#push() calls (1 issue) → FIX¶
| File | Line |
|---|---|
libs/config/src/lib/env-validation.ts |
127 |
Fix: Combine consecutive .push() calls into a single .push(a, b, c).
S7744 — Remove unnecessary fallback object in spread (1 issue) → FIX¶
| File | Line |
|---|---|
apps/gateway/src/swagger/swagger-aggregator.service.ts |
53 |
Fix: Remove the empty object fallback (e.g., { ...(obj || {}) } → { ...obj }).
S7735 — Flip negated condition (1 issue) → FIX¶
| File | Line |
|---|---|
apps/web/src/components/mappings/simplyprint-file-picker-modal.tsx |
78 |
Fix: Flip !condition ? a : b to condition ? b : a.
S7780 — Use String.raw for escaped backslashes (1 issue) → FIX¶
| File | Line |
|---|---|
libs/service-common/src/lib/storefront/storefront-origins.ts |
34 |
Fix: Use String.raw\...`` for regex patterns with backslash escapes.
S7787 — Empty export specifiers (1 issue) → SUPPRESS¶
| File | Line |
|---|---|
apps/order-service/src/common/decorators/index.ts |
1 |
Verdict: This export {}; was intentionally placed to keep the barrel file after moving decorators to @forma3d/service-common. Suppress in sonar properties.
Phase 2: Moderate Auto-fixes (70 issues)¶
S6759 — React props should be read-only (49 issues) → FIX¶
All 49 in apps/web/src/. Component props interfaces/types need to be wrapped with Readonly<Props> or use readonly modifiers.
Full file list (49 files)
| File | Line | |------|-----:| | `apps/web/src/components/analytics/analytics-period-dropdown.tsx` | 15 | | `apps/web/src/components/analytics/order-status-chart.tsx` | 26 | | `apps/web/src/components/analytics/print-job-status-chart.tsx` | 25 | | `apps/web/src/components/analytics/shipment-status-chart.tsx` | 26 | | `apps/web/src/components/charts/bar-chart.tsx` | 23 | | `apps/web/src/components/charts/chart-card.tsx` | 13 | | `apps/web/src/components/charts/donut-chart.tsx` | 27 | | `apps/web/src/components/charts/line-chart.tsx` | 22 | | `apps/web/src/components/inventory/stock-adjustment-modal.tsx` | 31 | | `apps/web/src/components/logo.tsx` | 11 | | `apps/web/src/components/logo.tsx` | 44 | | `apps/web/src/components/logs/log-detail-modal.tsx` | 116 | | `apps/web/src/components/logs/log-detail-modal.tsx` | 175 | | `apps/web/src/components/mappings/part-library-modal.tsx` | 30 | | `apps/web/src/components/mappings/shopify-product-picker-modal.tsx` | 29 | | `apps/web/src/components/mappings/simplyprint-file-picker-modal.tsx` | 22 | | `apps/web/src/components/orders/shipping-info.tsx` | 43 | | `apps/web/src/components/ui/badge.tsx` | 10 | | `apps/web/src/components/ui/card.tsx` | 42 | | `apps/web/src/components/ui/confirm-modal.tsx` | 18 | | `apps/web/src/components/ui/empty-state.tsx` | 12 | | `apps/web/src/components/ui/loading.tsx` | 8 | | `apps/web/src/components/ui/loading.tsx` | 42 | | `apps/web/src/components/ui/loading.tsx` | 55 | | `apps/web/src/components/ui/modal.tsx` | 14 | | `apps/web/src/components/ui/pagination.tsx` | 47 | | `apps/web/src/components/users/change-password-modal.tsx` | 12 | | `apps/web/src/components/users/user-form-modal.tsx` | 32 | | `apps/web/src/contexts/auth-context.tsx` | 40 | | `apps/web/src/contexts/service-worker-context.tsx` | 32 | | `apps/web/src/contexts/socket-context.tsx` | 20 | | `apps/web/src/contexts/theme-context.tsx` | 57 | | `apps/web/src/pages/dashboard.tsx` | 67 | | `apps/web/src/pages/inventory/config.tsx` | 44 | | `apps/web/src/pages/inventory/config.tsx` | 217 | | `apps/web/src/pages/inventory/index.tsx` | 44 | | `apps/web/src/pages/inventory/index.tsx` | 65 | | `apps/web/src/pages/inventory/replenishment.tsx` | 48 | | `apps/web/src/pages/mappings/new.tsx` | 25 | | `apps/web/src/pages/orders/index.tsx` | 34 | | `apps/web/src/pages/orders/index.tsx` | 48 | | `apps/web/src/pages/settings/feature-flags.tsx` | 16 | | `apps/web/src/pages/settings/feature-flags.tsx` | 48 | | `apps/web/src/pages/settings/simplyprint-files.tsx` | 219 | | `apps/web/src/pages/settings/simplyprint-files.tsx` | 367 | | `apps/web/src/pwa/pull-to-refresh.tsx` | 11 | | `apps/web/src/pwa/push-permission.tsx` | 85 | | `apps/web/src/router.tsx` | 87 | | `apps/web/src/router.tsx` | 113 |Fix pattern: Change function Component(props: Props) or interface Props { ... } to use Readonly<Props>.
S4624 — Nested template literals (10 issues) → FIX¶
| File | Line |
|---|---|
apps/order-service/src/print-jobs/print-jobs.service.ts |
341, 355 |
apps/print-service/src/internal/internal.controller.ts |
208 |
apps/print-service/src/print-jobs/print-jobs.service.ts |
344, 358 |
apps/web/src/components/analytics/order-status-chart.tsx |
55 |
apps/order-service/src/shopify/shopify-admin.controller.ts |
99 |
apps/order-service/src/shopify/shopify-api.client.ts |
316, 419 |
apps/print-service/src/simplyprint/simplyprint-api.client.ts |
1301 |
Fix: Extract inner template literal to a variable before the outer template.
S6819 — Use <section> tag instead of ARIA role="region" (6 issues) → FIX¶
| File | Line |
|---|---|
apps/web/src/components/charts/chart-card.tsx |
22 |
apps/web/src/components/mappings/part-library-modal.tsx |
86 |
apps/web/src/components/mappings/shopify-product-picker-modal.tsx |
111, 184, 206 |
apps/web/src/components/mappings/simplyprint-file-picker-modal.tsx |
90 |
Fix: Replace <div role="region" aria-label="..."> with <section aria-label="...">.
S4323 — Type aliases should be used (2 issues) → FIX¶
| File | Line |
|---|---|
apps/order-service/src/shopify/shopify-api.client.ts |
164 |
apps/web/src/lib/constants.ts |
7 |
Fix: Extract inline union types to named type aliases.
S6571 — Redundant unknown in union type (2 issues) → FIX¶
| File | Line |
|---|---|
libs/service-common/src/lib/auth/decorators/current-user.decorator.ts |
6 |
libs/domain-contracts/src/lib/types.ts |
68 |
Fix: unknown absorbs all other types in a union — simplify to just unknown or remove it.
S6754 — useState should be destructured symmetrically (1 issue) → FIX¶
| File | Line |
|---|---|
apps/web/src/contexts/theme-context.tsx |
58 |
Fix: Ensure useState is destructured as [value, setValue] with matching naming.
Phase 3: Manual Refactoring (71 issues)¶
S3358 — Nested ternary operations (45 issues) → MIXED¶
Most appear in React JSX where ternaries are a common rendering pattern. Some in backend services are genuinely hard to read.
Full file list (45 locations)
| File | Line | |------|-----:| | `apps/gateway/src/health/health.controller.ts` | 79 | | `apps/order-service/src/common/guards/ws-api-key.guard.ts` | 47 | | `apps/order-service/src/simplyprint/simplyprint-api.client.ts` | 286 | | `apps/print-service/src/simplyprint/simplyprint-api.client.ts` | 439 | | `apps/web/src/components/charts/chart-card.tsx` | 45 | | `apps/web/src/components/inventory/stock-adjustment-modal.tsx` | 73 | | `apps/web/src/components/logs/log-detail-modal.tsx` | 152 | | `apps/web/src/components/mappings/part-library-modal.tsx` | 80 | | `apps/web/src/components/mappings/shopify-product-picker-modal.tsx` | 90, 96, 98 | | `apps/web/src/components/mappings/simplyprint-file-picker-modal.tsx` | 68, 68, 76, 78, 82 | | `apps/web/src/components/users/user-form-modal.tsx` | 213 | | `apps/web/src/pages/admin/audit-logs/index.tsx` | 294 | | `apps/web/src/pages/admin/users.tsx` | 252 | | `apps/web/src/pages/dashboard.tsx` | 323, 367 | | `apps/web/src/pages/inventory/config.tsx` | 170 | | `apps/web/src/pages/inventory/index.tsx` | 214 | | `apps/web/src/pages/logs/index.tsx` | 301 | | `apps/web/src/pages/mappings/index.tsx` | 87 | | `apps/web/src/pages/mappings/new.tsx` | 567 | | `apps/web/src/pages/orders/[id].tsx` | 313 | | `apps/web/src/pages/orders/index.tsx` | 147, 149, 249 | | `apps/web/src/pages/settings/index.tsx` | 688, 879, 887, 889, 954, 986, 1038, 1040, 1288 | | `apps/web/src/pages/settings/integrations.tsx` | 520, 582, 733 | | `apps/web/src/pages/settings/simplyprint-files.tsx` | 253, 399 | | `apps/web/src/pwa/push-permission.tsx` | 228 |Recommendation:
- Backend (5 issues): Refactor to if/else or lookup maps — these are readable improvements.
- Frontend JSX (40 issues): Many are idiomatic JSX patterns (conditional rendering). Consider suppressing S3358 for apps/web/src/** in sonar properties if the team accepts this pattern, or refactor the most deeply nested ones (3+ levels) into helper functions.
S6853 — Form labels must be associated with a control (19 issues) → FIX¶
All in apps/web/src/. These are accessibility violations where <label> elements lack htmlFor or don't wrap the associated <input>.
Full file list (19 locations)
| File | Line | |------|-----:| | `apps/web/src/components/inventory/stock-adjustment-modal.tsx` | 147 | | `apps/web/src/components/orders/shipping-info.tsx` | 230 | | `apps/web/src/components/users/user-form-modal.tsx` | 152 | | `apps/web/src/pages/inventory/config.tsx` | 271, 283, 299, 318 | | `apps/web/src/pages/inventory/transactions.tsx` | 90 | | `apps/web/src/pages/mappings/new.tsx` | 157, 174, 195, 219 | | `apps/web/src/pages/settings/integrations.tsx` | 622, 634, 776, 793, 842, 854 | | `apps/web/src/pwa/push-permission.tsx` | 246 |Fix: Add htmlFor="inputId" to <label> and matching id="inputId" to the input, or wrap the input inside the label element.
S4325 — Unnecessary type assertions (7 issues) → CAREFUL REVIEW¶
| File | Line |
|---|---|
apps/order-service/src/sendcloud/sendcloud.service.ts |
84 |
apps/order-service/src/users/users.repository.ts |
170 |
apps/order-service/src/users/users.service.ts |
143, 158, 178 |
apps/shipping-service/src/sendcloud/sendcloud.service.ts |
107 |
apps/web/src/components/logs/log-detail-modal.tsx |
106 |
⚠️ Caution: Previous attempts to remove type assertions in sendcloud.service.ts and users.service.ts caused TypeScript compilation errors. Each must be individually verified — only remove if the compiler agrees the type is already correct.
Phase 4: Complex Refactoring (72 issues)¶
S3776 — Cognitive Complexity too high (23 issues) → REFACTOR¶
These are the most architecturally significant issues. Each function exceeds the complexity threshold of 15.
| File | Line | Description |
|---|---|---|
libs/service-common/src/lib/shipments/shipments.service.ts |
192 | Shipment status sync |
apps/gateway/src/swagger/swagger-aggregator.service.ts |
109 | Swagger merge |
apps/gridflock-service/src/gridflock/gridflock-pipeline.service.ts |
73 | Generation pipeline |
apps/order-service/src/orchestration/orchestration.service.ts |
100 | Order orchestration |
apps/order-service/src/print-jobs/print-jobs.service.ts |
248, 370 | Print job sync |
apps/order-service/src/shopify/shopify-backfill.service.ts |
237, 312 | Shopify backfill |
apps/order-service/src/stock-replenishment/stock-replenishment.service.ts |
80 | Stock replenishment |
apps/print-service/src/internal/internal.controller.ts |
157 | Internal endpoint |
apps/print-service/src/print-jobs/print-jobs.service.ts |
251, 373 | Print job sync |
apps/print-service/src/simplyprint/simplyprint-reconciliation.service.ts |
95 | Reconciliation |
apps/shipping-service/src/sendcloud/sendcloud-reconciliation.service.ts |
89 | Reconciliation |
apps/web/src/components/mappings/simplyprint-file-picker-modal.tsx |
22 | File picker UI |
apps/web/src/pages/orders/index.tsx |
98 | Orders page |
apps/web/src/pages/settings/index.tsx |
123, 475, 767 | Settings page |
apps/web/src/pages/settings/integrations.tsx |
71 | Integrations |
libs/gridflock-core/src/lib/border-generator.ts |
209 | Border generation |
libs/gridflock-core/src/lib/plate-set-calculator.ts |
45 | Plate calculation |
libs/gridflock-core/src/lib/preview-generator.ts |
199 | Preview generation |
Recommendation: Prioritize functions with complexity > 25. Extract helper functions, use early returns, replace nested if/else with guard clauses. settings/index.tsx alone has 3 flagged functions — consider splitting into sub-components.
S6551 — Objects coerced to strings without toString() (47 issues) → MIXED¶
Concentrated in 3 files:
- libs/service-common/src/lib/notifications/email.service.ts — 5 issues
- apps/order-service/src/simplyprint/simplyprint-api.client.ts — 18 issues
- apps/print-service/src/simplyprint/simplyprint-api.client.ts — 21 issues
- apps/web/src/components/charts/donut-chart.tsx — 1 issue
- apps/web/src/components/logs/log-detail-modal.tsx — 2 issues
Analysis: Most are template literal interpolations like `${context['someKey']}` where the value is typed as unknown or Record<string, unknown> but is actually a string at runtime. These are typically safe but SonarCloud flags them because the static type could be an object.
Recommendation:
- For email.service.ts: Add explicit String(value) casts or narrow the type of context values.
- For simplyprint-api.client.ts (both services): These are API response interpolations — add String() wrapping or type-narrow the response fields.
S107 — Too many parameters (2 issues) → MIXED¶
| File | Line | Verdict |
|---|---|---|
apps/order-service/src/audit/audit.controller.ts |
28 | Fix — consolidate query params into a DTO |
libs/gridflock-core/src/lib/border-generator.ts |
26 | Won't fix — geometric parameters are inherently numerous |
Phase 5: Won't Fix / Suppress (10 issues)¶
S7785 — Top-level await preferred (5 issues) → WON'T FIX¶
| File | Line |
|---|---|
apps/gateway/src/main.ts |
270 |
apps/gridflock-service/src/main.ts |
75 |
apps/order-service/src/main.ts |
83 |
apps/print-service/src/main.ts |
72 |
apps/shipping-service/src/main.ts |
70 |
Reason: NestJS bootstrap uses bootstrap().catch(...) by convention. Top-level await changes module loading semantics and is not recommended for NestJS entry points.
S7726 — Default exports should be named (4 issues) → WON'T FIX¶
| File | Line |
|---|---|
apps/gridflock-service/src/config/configuration.ts |
26 |
apps/order-service/src/config/configuration.ts |
88 |
apps/print-service/src/config/configuration.ts |
38 |
apps/shipping-service/src/config/configuration.ts |
47 |
Reason: NestJS registerAs() returns a factory function — naming it is unnecessary and adds noise.
S7787 — Empty export specifiers (1 issue) → WON'T FIX¶
| File | Line |
|---|---|
apps/order-service/src/common/decorators/index.ts |
1 |
Reason: Intentional empty barrel file after moving decorators to @forma3d/service-common. Keeps import paths stable.
Phase 6: Duplication Reduction¶
Overall duplication dropped from 19.5% → 15.7% after the D1–D9 extraction effort (2026-03-12). Remaining duplication: 10,743 lines across 105 files in 202 blocks.
Top Duplication Clusters¶
D1: Retry Queue — order-service ↔ shipping-service (~95%)¶
| File | Dup % |
|---|---|
apps/order-service/src/retry-queue/retry-queue.repository.ts |
94.9% |
apps/shipping-service/src/retry-queue/retry-queue.repository.ts |
94.9% |
apps/order-service/src/retry-queue/retry-queue.service.ts |
94.6% |
apps/shipping-service/src/retry-queue/retry-queue.service.ts |
94.6% |
apps/order-service/src/retry-queue/retry-queue.processor.ts |
48.2% |
apps/shipping-service/src/retry-queue/retry-queue.processor.ts |
60.4% |
Recommendation: Extract to libs/service-common/src/lib/retry-queue/. Repository and service are nearly identical. Processor has service-specific job handling but a shared base class could be extracted.
D2: SendCloud — order-service ↔ shipping-service (~90%)¶
| File | Dup % |
|---|---|
apps/order-service/src/sendcloud/sendcloud.service.ts |
94.4% |
apps/shipping-service/src/sendcloud/sendcloud.service.ts |
90.3% |
apps/order-service/src/sendcloud/sendcloud-webhook.service.ts |
90.2% |
apps/shipping-service/src/sendcloud/sendcloud-webhook.service.ts |
92.9% |
apps/order-service/src/sendcloud/sendcloud.controller.ts |
74.9% |
apps/shipping-service/src/sendcloud/sendcloud.controller.ts |
65.8% |
apps/order-service/src/sendcloud/sendcloud-initializer.service.ts |
81.3% |
apps/shipping-service/src/sendcloud/sendcloud-initializer.service.ts |
81.3% |
apps/shipping-service/src/sendcloud/sendcloud-api.client.ts |
73.4% |
Recommendation: Extract shared SendCloud service, webhook handler, and initializer to libs/service-common/src/lib/sendcloud/. The API client is only in shipping-service but shares patterns.
D3: SimplyPrint — order-service ↔ print-service (~88%)¶
| File | Dup % |
|---|---|
apps/order-service/src/simplyprint/dto/simplyprint-job.dto.ts |
91.7% |
apps/print-service/src/simplyprint/dto/simplyprint-job.dto.ts |
91.7% |
apps/order-service/src/simplyprint/dto/simplyprint-printer.dto.ts |
85.2% |
apps/print-service/src/simplyprint/dto/simplyprint-printer.dto.ts |
85.2% |
apps/order-service/src/simplyprint/simplyprint.service.ts |
89.8% |
apps/print-service/src/simplyprint/simplyprint.service.ts |
87.4% |
apps/order-service/src/simplyprint/simplyprint-api.client.ts |
89.2% |
apps/print-service/src/simplyprint/simplyprint-api.client.ts |
50.1% |
apps/order-service/src/simplyprint/simplyprint-initializer.service.ts |
50.8% |
apps/print-service/src/simplyprint/simplyprint-initializer.service.ts |
48.5% |
apps/order-service/src/simplyprint/simplyprint-files.controller.ts |
56.3% |
apps/print-service/src/simplyprint/simplyprint-files.controller.ts |
19.0% |
Recommendation: Extract shared SimplyPrint DTOs, base API client, and shared service to a libs/simplyprint-common or libs/service-common/src/lib/simplyprint/ module. The API client in print-service is a superset — use it as the shared base.
D4: Cross-Service Infrastructure (~85%)¶
| File | Dup % | Count |
|---|---|---|
*/auth/permissions.ts |
87.7% | 4 services |
*/common/correlation/correlation.service.ts |
87.5% | 4 services |
*/common/correlation/correlation.middleware.ts |
85.7% | 4 services |
*/common/guards/api-key.guard.ts |
67.0% | 4 services |
*/throttler/throttler.module.ts |
73.3% | 4 services |
Recommendation: Extract correlation service/middleware, API key guard, and throttler module to libs/service-common. The permissions.ts files are intentionally per-service (different permission sets) — these are expected duplicates.
D5: Print Jobs — order-service ↔ print-service (~83%)¶
| File | Dup % |
|---|---|
apps/order-service/src/print-jobs/print-jobs-admin.controller.ts |
87.6% |
apps/print-service/src/print-jobs/print-jobs-admin.controller.ts |
87.6% |
apps/order-service/src/print-jobs/print-jobs.controller.ts |
82.9% |
apps/print-service/src/print-jobs/print-jobs.controller.ts |
82.9% |
apps/order-service/src/print-jobs/print-jobs.service.ts |
80.9% |
apps/print-service/src/print-jobs/print-jobs.service.ts |
76.3% |
Recommendation: The admin controllers and main controllers are near-identical. Extract shared controllers to libs/service-common (similar to the existing D8 pattern for print-job DTOs/events/repository). The services differ more — keep service-specific.
D6: Auth Controllers (~83%)¶
| File | Dup % |
|---|---|
apps/print-service/src/auth/auth.controller.ts |
82.9% |
apps/gridflock-service/src/auth/auth.controller.ts |
82.9% |
apps/gateway/src/auth/auth.controller.ts |
28.8% |
Recommendation: Extract shared auth controller to libs/service-common. Gateway's auth controller is a superset (SSO + standard auth).
D7: Health Controllers (~55%)¶
| File | Dup % |
|---|---|
apps/print-service/src/health/health.controller.ts |
54.5% |
apps/shipping-service/src/health/health.controller.ts |
54.5% |
apps/gridflock-service/src/health/health.controller.ts |
26.0% |
apps/order-service/src/health/health.controller.ts |
8.4% |
Recommendation: Extract a shared health controller base class. Each service adds its own health indicators, but the boilerplate is identical.
D8: Notification Event Handlers (~71%)¶
| File | Dup % |
|---|---|
apps/order-service/src/notifications/notification-event-handlers.service.ts |
71.1% |
apps/print-service/src/notifications/notification-event-handlers.service.ts |
71.1% |
apps/shipping-service/src/notifications/notification-event-handlers.service.ts |
71.1% |
Recommendation: Extract shared event handler patterns. Each service handles different events but the handler structure (logging, error handling, notification dispatch) is identical.
D9: App Modules (~60%)¶
| File | Dup % |
|---|---|
apps/print-service/src/app/app.module.ts |
60.4% |
apps/shipping-service/src/app/app.module.ts |
60.4% |
apps/gridflock-service/src/app/app.module.ts |
26.4% |
apps/order-service/src/app/app.module.ts |
14.8% |
Recommendation: The shared module imports (Database, Auth, Observability, Config, etc.) are already extracted to libs/service-common. The remaining duplication is the import list itself — this is structural and expected for NestJS. Won't fix.
Duplication Priority¶
| Priority | Cluster | Est. Reduction | Effort |
|---|---|---|---|
| High | D1: Retry Queue | ~700 lines | 4 hours |
| High | D4: Infrastructure (correlation, guards, throttler) | ~600 lines | 3 hours |
| Medium | D2: SendCloud | ~1,200 lines | 6 hours |
| Medium | D3: SimplyPrint | ~1,500 lines | 8 hours |
| Low | D5: Print Jobs controllers | ~400 lines | 2 hours |
| Low | D6: Auth Controllers | ~200 lines | 1 hour |
| Low | D7: Health Controllers | ~150 lines | 1 hour |
| Low | D8: Notification Handlers | ~200 lines | 1 hour |
| Skip | D9: App Modules | — | Structural duplication |
Progress Since Previous Report¶
| Metric | 2026-03-12 | 2026-03-13 | Change |
|---|---|---|---|
| Total issues | 769 | 244 | -68% |
| Bugs | 9 | 0 | -100% |
| Vulnerabilities | 12 | 0 | -100% |
| Code smells | 748 | 244 | -67% |
| Duplication | 19.5% | 15.7% | -3.8pp |
| Duplicated lines | ~13,300 | 10,743 | -19% |
| Security hotspots | 6 (TO_REVIEW) | 6 (suppressed) | resolved |