Skip to content

Comments

Apps#9345

Merged
evereq merged 20 commits intostage-appsfrom
stage
Jan 18, 2026
Merged

Apps#9345
evereq merged 20 commits intostage-appsfrom
stage

Conversation

@evereq
Copy link
Member

@evereq evereq commented Jan 18, 2026

PR

Please note: we will close your PR without comment if you do not check the boxes above and provide ALL requested information.



Summary by cubic

Adds Broadcast and Strategic Initiative backend modules with APIs and migrations, introduces a Monitoring settings page (PostHog, Sentry, Jitsu), and improves the desktop Agent’s tracking reliability and plugin routing across apps.

  • New Features

    • Backend: Broadcasts module with CRUD, permissions, notifications, reactions, and migrations; Organization Strategic Initiatives with relations to projects/goals, CQRS handlers, and migrations.
    • Web App: New Settings > Monitoring page to configure PostHog, Sentry, and Jitsu; Integrations header now links to Plugins.
    • Desktop Agent: Continue/pause/resume tracking flow, safer exit handling, onboarding/main menus, more reliable queues and offline sync, and screenshot upload resilience.
    • Plugins: Simplified routing to load PluginsModule across apps; Dockerfile now includes desktop-ui-lib; Angular bumped to 19.2.18.
  • Migration

    • Run database migrations to create Broadcast and OrganizationStrategicInitiative tables.

Written for commit 97b7e74. Summary will update on new commits.

syns2191 and others added 20 commits January 10, 2026 00:54
chore(deps): bump @angular/core from 19.2.17 to 19.2.18
* feat: continues tracking handle

* feat: handle continues tracking

* fix: record idle activity

* fix: typo variable name

* fix: remove unused imported binding

* fix: clean code

* fix: clean code

* fix: handle missing token before continue or resume tracking activity

* fix: clean code

* fix: clean code and remove immidiate record idle time

* fix: activityState type
* fix: hide some menu in setup window

* feat: prevent agent exit when don't have permission

* feat: prevent agent exit when don't have permission

* feat: prevent shortcut exit with condition

* fix: clean code implementation

* fix: clean code and added translation
Bumps [undici](https://github.com/nodejs/undici) from 6.21.2 to 6.23.0.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](nodejs/undici@v6.21.2...v6.23.0)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 6.23.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
* feat(marketplace): introduce plugin marketplace UI and state

Adds the foundational UI components and initial state management for the Plugin Marketplace feature. This includes:
- A placeholder component (`PluginMarketplaceWrapperComponent`) for the marketplace view in the integrations section.
- Basic styling for the placeholder component.
- Initialization of necessary services and state within `desktop-ui-lib/src/lib/settings/plugins/plugins.module.ts`, including `ElectronService` and `ToastrNotificationService`.
This commit lays the groundwork for the full plugin marketplace functionality, enabling future development of CRUD operations, subscriptions, and advanced filtering.

* feat(integrations): add plugin marketplace placeholder UI

Introduces a new UI component for the plugin marketplace, displaying a placeholder message while the full functionality is being integrated.
This commit adds the HTML template, SCSS styling, and a basic TypeScript component structure for the `PluginMarketplaceWrapperComponent`. The placeholder informs users that the marketplace features, including CRUD operations and subscriptions, are under development.

* refactor(integrations): remove plugin marketplace placeholder

Remove the placeholder component for the plugin marketplace. This component was used to indicate that the feature was under development. The actual plugin marketplace functionality will be implemented separately.

* refactor(plugins): restructure routing and module organization

Move plugin routes into a dedicated `plugin.route.ts` file and refactor `PluginRoutingModule` to use `RouterModule.forChild` with lazy loading for a cleaner module structure. This change separates routing definitions from module configurations and improves modularity within the desktop UI library.

* refactor(routing): update plugin route configuration to use PluginsModule

This commit refactors the plugin routing configuration across multiple applications. Instead of loading a component and then separately loading plugin routes, it now directly uses `PluginsModule` for loading children. This simplifies the route definitions and ensures consistent plugin integration.

* refactor(integrations): simplify UI and remove tabbed navigation

Refactor the integrations component UI to remove the tabbed navigation for plugins. The integrations list is now displayed directly, with a clear link to the 'Plugins' section. This change simplifies the user interface and removes unnecessary complexity.
SCSS styles related to the removed tabbed navigation have also been updated.

* refactor(plugins): streamline routing and layout components

Refactor plugin routing and layout components to improve efficiency and maintainability. This change updates the plugin installed routes to use direct component imports instead of lazy loading. The 'installed' tab in the plugin layout is now conditionally added based on whether the application is running in a desktop environment. The main plugin routing module also adopts direct component references for the plugin layout and its child routes.
The default redirection for the plugin route has been changed from 'installed' to 'marketplace'.

* refactor(plugin-marketplace): modularize tab modules and update routing

Removes `RouterModule.forChild` from individual plugin marketplace tab modules.
Updates the main `plugin-marketplace-routing.module.ts` to directly import tab components instead of lazy loading their modules.
The `PluginsModule` is updated to import these tab modules directly.
This change simplifies the routing configuration and improves the modularity of the plugin marketplace feature.

* feat(plugins): update services with providedIn: 'root' and desktop checks

Updates subscription-related services to use `providedIn: 'root'` for improved dependency injection.
Adds checks for `isDesktop` within `PluginElectronService` to ensure that Electron-specific methods are only invoked in a desktop environment, preventing potential runtime errors in non-desktop builds.

* refactor(plugins): use relative routing for marketplace navigation

Refactors the plugin marketplace navigation to utilize relative routing. This change involves injecting `ActivatedRoute` and using it with `router.navigate` to construct paths relative to the current route.
This approach provides more flexibility and robustness when navigating within the plugin marketplace, especially when routes are nested or change. It avoids hardcoding absolute paths, making the codebase easier to maintain and less prone to breaking if the application's routing structure evolves.
The following navigations have been updated:
- Navigating to plugin details.
- Navigating back from an error state.
- Navigating back from plugin item view.
- Navigating to version history.
- Navigating back from version history view.

* refactor(integrations): use styled button for plugins navigation

Refactor the integrations page header to replace the plain div link for "Plugins" with a styled `nb-button` component. This change improves the visual consistency and provides a more interactive user experience for navigating to the plugins section.
The button now includes an icon and uses specific styling to align with the application's design language.

* refactor(plugins): correct plugin category effects import and remove unused LanguageModule

The import path for `PluginCategoryEffects` was incorrect and has been updated to point to the correct location within the `+state/effects` directory. Additionally, the `LanguageModule` was not being used and has been removed from the imports and the `imports` array to clean up the module.

* feat: add PluginsModule to app modules

Integrate the PluginsModule into the imports of the AppModule for desktop-timer, desktop, server-api, and server applications. This change ensures that plugin functionality is available across these application contexts.

* feat(i18n): add plugins translation

Adds the "PLUGINS" key to the English translation file. This allows for the display of plugins in the UI.

* feat(plugins): add environment validation for plugin installation

Introduce environment checks at the effect level to ensure plugins are compatible with the current environment (web, mobile, desktop) before proceeding with installation.
This change enhances the robustness of plugin installation by:
- Checking `pluginEnvironmentService.canInstallPlugin(plugin)` to determine compatibility.
- Displaying a warning toast with a user-friendly message if the plugin is not compatible.
- Disabling the plugin toggle if the environment check fails, preventing further installation attempts.
- Optimistically enabling the plugin toggle only after the environment validation passes.

* feat(i18n): add plugin environment validation error strings

Adds new internationalization strings for various plugin environment validation errors. These strings will be used to provide clearer feedback to users when a plugin cannot be installed due to environment mismatches.

* refactor(plugins): rename PluginEnvironmentService and move validation

Rename `pluginEnvironmentService` to `environmentService` for brevity.
Move plugin environment validation logic from the start of the `install` effect to after the optimistic toggle and before opening the installation dialog. This ensures the toggle is set immediately, and the validation occurs just before user interaction or deeper installation steps. The validation now directly calls `notifyEnvironmentMismatch` which encapsulates toastr and translation logic.

* feat(plugins): introduce PluginEnvironmentService

Introduce `PluginEnvironmentService` to manage plugin environment detection and validation. This service provides methods to determine if the current environment is desktop, mobile, or web, and to validate if a plugin is compatible with the current environment. It also handles notifying the user of environment mismatches.

* feat(plugins): implement environment compatibility checks and warnings

Implement checks to ensure plugins are compatible with the current environment before installation. This includes:
- Disabling installation buttons and toggles if a plugin is not compatible.
- Displaying tooltips that explain the environment mismatch.
- Injecting `PluginEnvironmentService` into relevant components to utilize the new checks.
- Refactoring `PluginEnvironmentService` to provide a `getEnvironmentMismatchWarning` method.

* fix(plugins): update plugin environment mismatch translation keys

Updates translation keys used for plugin environment mismatches. This change aims to provide more specific and accurate error messages to the user when a plugin's environment requirements are not met.
The keys have been moved to the `PLUGIN.ERRORS` namespace to better categorize plugin-related errors. Specific keys have also been updated for clarity, including a new key for unsupported plugin types.

* fix(plugin-marketplace): type getContextMenuItems return value

The `getContextMenuItems` method in the `PluginMarketplaceDetailComponent` was missing a return type annotation. This commit adds `NbMenuItem[]` as the return type to improve code clarity and maintainability.

* refactor(plugins): use relative paths for plugin navigation

Replace hardcoded absolute paths in plugin layout and marketplace detail
components with routes generated relative to the current path. This
ensures navigation links remain functional regardless of the parent
route configuration.

* fix(plugins): disable install toggle only when explicitly disabled

The install toggle and subscribe button in the plugin marketplace were being disabled not only when the `disabled` input was true, but also when the `canInstallInEnvironment()` method returned false. This commit removes the dependency on `canInstallInEnvironment()` for disabling these elements, ensuring they are only disabled when the `disabled` input is explicitly set.

* fix(plugins): refine environment check for plan selection

Update the plugin subscription plan selection logic to correctly handle
environment compatibility. Ensure the ability to proceed without a
subscription is gated by the environment check and refine the button
disabled state for free plans when the environment is incompatible.

* chore(deps): remove unused RouterModule imports

The `RouterModule` and `Routes` imports were removed from several Angular modules as they were not being used. This is a cleanup task that does not affect the functionality of the application.
Additionally, a typo in the `.cspell.json` file has been corrected by adding "Mobi" to the list of allowed words.

* refactor(desktop-ui-lib): use inject and improve return type consistency

Update PluginElectronService to use the Angular inject function for
dependency injection.
Ensure all methods return consistent types (resolved Promises or EMPTY
Observables) instead of undefined when not in a desktop environment to
improve type safety.

* refactor(plugin-layout): improve tab list initialization

Use an explicit conditional check to populate the tabs array, avoiding
the inclusion of boolean values in the list. Additionally, mark the
router property as readonly and reorder imports for better consistency.

* refactor(plugins): use optional chaining for plugin type check

Update the canInstallPlugin method to use the optional chaining operator
instead of manual null and property checks to improve code readability.

* refactor(integrations): remove unused OnDestroy and cleanup code

Remove the empty ngOnDestroy lifecycle hook and its interface
implementation. Additionally, add the readonly modifier to the
searchElement ViewChild.

* refactor(integrations): move search styles and remove ng-deep wrapper

Relocate the #integrationSearch styling from the :host ::ng-deep block
to the main component stylesheet block to simplify the SCSS structure.

* refactor(plugins): use optional chaining for plugin type check

Update the null check in getEnvironmentMismatchMessage to use the
optional chaining operator for improved readability and conciseness.

* fix(plugins): update fallback redirect path

Change the wildcard route redirection from 'installed' to an empty
string to ensure that unknown sub-paths correctly resolve to the
base plugins route.
Bumps [undici](https://github.com/nodejs/undici) from 6.21.2 to 6.23.0.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](nodejs/undici@v6.21.2...v6.23.0)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 6.23.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
[Fix] Add desktop-ui-lib to Dockerfile
Remove @gauzy/constants, @gauzy/contracts, and @gauzy/desktop-window
from the package dependencies.
…rom-package.json

chore(desktop-ui-lib): Remove unnecessary local dependencies from package.json.
* feat: created new contracts for broadcast feature

* feat: created and registered broadcast entity

* feat: generated migrations for all DBs

* feat: created  broadcast validators

* feat: created broadcast service and CQRS

* fix: renamed the findAll method

* feat: created the broadcast API and module

* feat: created and registered the subscriber for broadcast entity

* feat: integrated notifications with broadcast feature

* fix: removed unused shared entity service

* Update packages/ui-core/i18n/assets/i18n/bg.json

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* fix: AIs suggestions

* fix: AIs suggestions

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
[Feat] Organization Strategic Initiative feature
* fix: agent failed sync queue

* fix: agent list queue history

* fix: agent list queue history

* fix: remove log

* fix: agent list queue history

* fix: incorrect import path

* fix: applyed ai suggestion

* fix: table queue header translation

---------

Co-authored-by: Ruslan Konviser <evereq@gmail.com>
* feat(contracts): add system-setting interfaces and config models

- Add ISystemSetting interface with scope enum (GLOBAL, TENANT, ORGANIZATION)
- Add ISentryConfig interface for Sentry error tracking configuration
- Add IUnleashConfig interface for Unleash feature flags configuration
- Add IGoogleMapsConfig interface for Google Maps configuration
- Export new models from contracts index

Refs: #3454

* feat(core): add SystemSetting entity and repositories

- Add SystemSetting entity extending TenantOrganizationBaseEntity
- Support multi-scope settings (GLOBAL, TENANT, ORGANIZATION)
- Add TypeORM repository for SystemSetting
- Add MikroORM repository for SystemSetting

Refs: #3454

* feat(core): add system-setting DTOs with validation

- Add CreateSystemSettingDTO and SaveSystemSettingsDTO
- Add SystemSettingQueryDTO for API queries
- Add SentryConfigDTO with @issecret decorator for DSN
- Add UnleashConfigDTO with @issecret decorator for API key
- Add GoogleMapsConfigDTO with @issecret decorator for API key

Refs: #3454

* feat(core): add system-setting CQRS commands and handlers

- Add SystemSettingGetCommand for cascade resolution
- Add SystemSettingGetByScopeCommand for scope-specific retrieval
- Add SystemSettingSaveCommand for saving settings
- Add handlers with WrapSecrets for sensitive data masking

Refs: #3454

* feat(core): add SystemSettingService with cascade resolution

- Implement cascade resolution: Organization -> Tenant -> Global -> ENV -> Default
- Add getSettingsWithCascade for resolving settings across scopes
- Add saveSettings with scope validation
- Add getSettingsByScope for scope-specific retrieval
- Support environment variable fallback mapping

Refs: #3454

* feat(core): add SystemSettingController and register module

- Add SystemSettingController with GET /resolve, GET /, POST / endpoints
- Add SystemSettingModule with CQRS, TypeORM and MikroORM support
- Register SystemSettingModule in AppModule
- Export public API from index.ts

Refs: #3454

* fix(core): use correct RequestContext method currentOrganizationId

Refs: #3454

* feat(core): register SystemSetting entity in coreEntities

* feat(core): add database migration for system_setting table

- PostgreSQL migration (up/down)
- MySQL migration (up/down)
- SQLite/BetterSQLite3 migration (up/down)

* refactor(system-setting): extract constants to separate file

* feat(contracts): add ISystemSettingMetadata interface for scope validation

* feat(system-setting): add metadata-based scope validation

- Add SYSTEM_SETTINGS_METADATA with allowedScopes per setting
- Add validateSettingScopeAllowed() in service
- Use getSettingMetadata(), getEnvVarName(), getDefaultValue() helpers
- Settings now validated against their allowed scopes on save

* feat(contracts): add config models for PostHog, Jitsu, GauzyAI, Cloudinary, Chatwoot

* feat(system-setting): add DTOs for PostHog, Jitsu, GauzyAI, Cloudinary, Chatwoot

- Each DTO includes @issecret decorator for sensitive fields
- Validation decorators for proper input validation

* feat(system-setting): integrate new config DTOs in WrapSecrets

* fix(system-setting): add multi-ORM support and fix type conversion bugs

- Replace direct TypeORM repository usage with multi-ORM pattern (TypeORM + MikroORM)
- Fix type conversion: preserve boolean/number types instead of stringifying
- Fix IsNull() operator: use ?? instead of || for correct null handling
- Add convertValueToType() and convertValueToString() helper methods
- Apply type conversion in all retrieval methods

* fix(system-setting): add unique constraint on (name, tenantId, organizationId)

- Prevents duplicate settings at the same scope
- Ensures data integrity for concurrent operations

* fix(migration): remove redundant index creation/drop pattern in SQLite migration

- Remove unnecessary index creation before temporary table operations
- Create indexes only once after final table rename
- Improves migration efficiency and clarity

* refactor(system-setting): simplify WrapSecrets usage with array of DTOs

- Replace 8 separate WrapSecrets calls with single call using array
- Matches function design that accepts targets: any | any[]
- Avoids multiple mutations of the same settings object

* fix(system-setting): use HttpStatus.OK for GET endpoints and remove @isurl() for PostHog

- Change HttpStatus.ACCEPTED to HttpStatus.OK for synchronous GET operations
- Remove @isurl() from posthog_api_host to allow relative paths (/ph) for reverse-proxy setups

* fix(migration): add unique constraint on (name, tenantId, organizationId) for all databases

- Add UNIQUE constraint in PostgreSQL, MySQL, and SQLite migrations
- Prevents duplicate settings at the same scope
- Ensures data integrity for cascade resolution logic

* fix(system-setting): fix race condition in saveSettings() using transactions

- Wrap save operations in transactions for both TypeORM and MikroORM
- Use queryRunner for TypeORM transaction management
- Use em.transactional() for MikroORM transaction management
- Process each setting individually within transaction to prevent concurrent conflicts
- Fix type casting issue for MikroORM findOne result
- Fix undefined defaultValue type conversion issue

* fix(core): fix WrapSecrets bug for overlapping substrings in short strings

- Handle case where offset * 2 >= string.length by masking entire string
- Fix overlapping substring replacement issue
- Use non-overlapping first/middle/last parts for proper masking

* chore(system-setting): remove unused IsUrl import from posthog-config.dto

* chore: remove unused imports and variables

- Remove unused imports: In, indexBy, object, pluck from system-setting.service.ts
- Remove unused variables: firstPart, lastPart from is-secret.ts
- Keep only necessary imports and variables

* fix(system-setting): inject MikroORM EntityManager for transactional operations

- Use @InjectEntityManager() from @mikro-orm/nestjs to access EntityManager
- Fix protected property access error for em.transactional()
- Restore is-secret.ts to original state from develop branch using git checkout

* fix(system-setting): use repository EntityManager instead of direct injection

- Remove direct EntityManager injection from SystemSettingService
- Add getEntityManager() method to MikroOrmBaseEntityRepository
- Use repository.getEntityManager() for transactional operations
- Fixes NestJS dependency resolution error for MikroORM EntityManager

* fix(system-setting): add security fixes and validation

- Add SUPER_ADMIN authorization check for GLOBAL scope settings
- Mask secrets in save response using WrapSecrets decorator
- Add null-safety validation for tenantId/organizationId based on scope
- Validate that names array is not empty in SystemSettingGetCommand

* perf(system-setting): optimize queries and fix N+1 problem

- Optimize getSettingsWithCascade to use In() queries instead of fetching all settings
- Add findSettingsByNamesAndScope() method for batch fetching by names
- Reuse resolveSettingValue() to avoid code duplication for ENV/DEFAULT fallback
- Batch flush operations in MikroORM transaction for better performance
- Add proper error logging without exposing internal details
- Improve race condition error handling with specific messages for unique constraint violations
- Fix empty string handling consistency in cascade resolution
- Wrap switch case declarations in blocks to prevent scope leakage

* fix(contracts): fix type mismatch in IResolvedSystemSetting

- Update value type from string to string | boolean | number to match actual implementation
- Ensures type safety for consumers expecting converted values

* fix(system-setting): improve DTO validation and types

- Add @isurl() validation to posthog_api_host and unleash_api_url
- Add @ISINT() and @min(1) validation to posthog_flush_interval
- Remove redundant @IsString() from cloudinary_cdn_url (already has @isurl())
- Fix CreateSystemSettingDto.settings type from Record<string, string> to Record<string, any>

* chore(core): reorganize system-setting.entity export alphabetically

- Move system-setting.entity export to correct alphabetical position

* refactor(system-setting): improve error handling and code quality

- Remove unused IsNumber import from posthog-config.dto
- Replace underscore keys() with native Object.keys()
- Normalize error code comparison to string for consistent handling
- Add unique constraint violation handling in MikroORM branch
- Improve error messages for race conditions

* refactor(system-setting): extract SECRET_DTO_LIST to shared constant

- Create secret-dto-list.ts module to avoid recreating DTOs on each call
- Use shared constant in both GET and SAVE handlers
- Improves performance and reduces code duplication

* fix(system-setting): improve validation and API documentation

- Replace Error with BadRequestException in SystemSettingGetCommand
- Add Swagger description for settings field in SaveSystemSettingsDTO
- Ensures consistent HTTP 400 behavior and better API docs

* refactor(contracts): improve type safety in system setting models

- Change ISystemSettingCreateInput to extend ISystemSetting (remove duplication)
- Update ISystemSettingMetadata.defaultValue type from any to string | boolean | number
- Ensures type safety aligns with SystemSettingValueType discriminator

* refactor(system-setting): improve validation and error handling

- Add validateScopeRequirements() to getSettingsByScope to prevent invalid queries
- Extract resolveEnvAndDefaultValue() to avoid redundant database queries
- Replace hardcoded error codes with error message checking (more portable)
- Improve error handling consistency across TypeORM and MikroORM

* refactor(system-setting): move validation to runtime and improve immutability

- Move names array validation from constructor to execute() method
- Allows command creation outside request context
- Replace let with const for immutable bindings in handlers

* refactor(system-setting): remove duplicate validation and forwardRef

- Remove duplicate scope/ID validation from handler (already in service)
- Remove unnecessary forwardRef wrapper (no circular dependency)
- Simplify dependency injection

* fix(system-setting): add authorization validation and improve error handling

- Add early 403 validation for TENANT/ORGANIZATION scopes in handler
- Use ForbiddenException (403) instead of UnauthorizedException (401) for authorization failures
- Add forwardRef to SystemSettingSaveHandler for consistency with GET handlers
- Keep authorization logic in handler layer, business validation in service layer

* fix(system-setting): improve scope validation and error detection

- Add isSettingAllowedAtScope() checks in getSettingsWithCascade to prevent disallowed settings
- Fix MySQL unique constraint detection (add 'duplicate entry' pattern)
- Move connect/startTransaction inside try block for proper error handling
- Ensures queryRunner is always released even if connect/startTransaction fails

* docs(system-setting): clarify scope default behavior in API documentation

- Add documentation note that scope defaults to TENANT if omitted
- Clarify that TenantPermissionGuard ensures tenantId is present
- Improves API clarity for callers

* fix indentation

* fix(system-setting): make repositories private and use atomic upsert for TypeORM

* feat(system-setting): update migration with partial unique indexes for scope-based uniqueness

* feat(system-setting): add @issecret decorator for sensitive value masking

* feat(system-setting): add helper for masking secret values and export utilities

* fix: restore is-secret.ts from develop

* fix(system-setting): handle TOCTOU race condition in upsert and improve error handling

* fix(system-settings): improve validation, transactions and null handling

- Change @min(1) to @min(1000) for posthog_flush_interval
- Add validation for empty strings on number/boolean settings
- Validate setting names before command bus in controller
- Wrap saveSettings in transaction for atomicity
- Replace isNotEmpty with explicit null/undefined checks (empty string is valid)
- Clarify null/undefined semantics (null clears value, undefined skips)
- Fix typing by using ISystemSettingCreateInput instead of 'as any'
- Document MySQL NULL unique constraint limitation

* fix: remove TOCTOU comment to fix cspell error

* refactor(system-settings): fix transaction atomicity and extract shared helper

- Use EntityManager in transaction callback for true atomicity
- Create upsertSettingWithManager using manager.getRepository()
- Extract resolveEnvOrDefault helper to eliminate duplication
- Both getSettingsWithCascade and resolveSettingValue now use the shared helper

* fix(system-settings): clarify undefined vs null semantics in saveSettings

- undefined = skip (no change to this setting)
- null = clear to NULL in database
- Update upsertSettingWithManager signature to string | null (no undefined)

* refactor(system-settings): improve encapsulation and null handling

- Change repository parameters to private readonly
- Mirror ENV null check in default branch of resolveEnvOrDefault

* feat(system-settings): add Multi-ORM support and MySQL NULL uniqueness handling

- Refactor saveSettings to use ORM switching pattern (this.ormType switch)
- Add saveSettingsWithTypeORM() using TypeORM's dataSource.transaction()
- Add saveSettingsWithMikroORM() using MikroORM's em.transactional()
- Add upsertSettingWithTypeORM() with NULL-safe where clause
- Add upsertSettingWithMikroORM() with MikroORM-style null filters
- Add explicit duplicate check for MySQL GLOBAL scope (NULL tenantId/orgId)
  using pessimistic write locks to prevent duplicate rows
- Add isMikroORMUniqueConstraintError() helper for MikroORM error detection
- Update config model interfaces to use proper ID type imports

* refactor(system-settings): use MikroORM types and LockMode enum

- Import EntityManager as MikroOrmEntityManager from @mikro-orm/core
- Import LockMode enum from @mikro-orm/core
- Change em parameter type from 'any' to MikroOrmEntityManager for type safety
- Replace magic number 2 with LockMode.PESSIMISTIC_WRITE enum value

* chore: remove system-setting implementation - will use tenant_setting instead

* feat(tenant-setting): add hierarchical settings resolution with global scope support

- Add getResolvedSettings() method with cascade priority: Tenant DB → Global DB → env vars
- Add saveGlobalSettings() method for saving global settings (tenantId = NULL)
- Add getGlobalSettings() method for retrieving global-only settings
- Restore mikro-orm-base-entity.repository.ts to develop state

* feat(tenant-setting): add global settings API and multi-tenant PostHog support

- Add GET/POST /api/tenant-setting/global endpoints for global settings (tenantId=NULL)
- Add GlobalSettingGetCommand, GlobalSettingSaveCommand and handlers
- Add DynamicSettingDTO for flexible key-value settings
- Add getGlobalSettings() and saveGlobalSettings() to TenantSettingService
- Add resolvedSettings to middleware (Global DB → Tenant DB cascade)
- Update PosthogService to read from resolvedSettings for multi-tenant config
- Add PosthogConfigService for frontend configuration endpoint
- Export PosthogConfigService from posthog plugin

* feat(settings): add monitoring settings page for PostHog configuration

- Add MonitoringSettingsComponent with PostHog configuration form
- Add route /pages/settings/monitoring
- Add menu item in settings navigation
- Add getGlobalSettings() and saveGlobalSettings() to TenantService
- Add translations for monitoring settings

* fix: remove unused imports and fix linting warnings

* feat(sentry): add tenant settings support with resolvedSettings cascade

- Read sentryEnabled from request.resolvedSettings
- Return null from instance() when disabled for current tenant
- Update SentryInterceptor to handle null instance gracefully
- Clean up code: remove redundant comments and simplify methods

* feat(jitsu): add tenant settings support with resolvedSettings cascade

- Read jitsuEnabled, jitsuHost, jitsuWriteKey, jitsuDebug from resolvedSettings
- Create per-tenant Jitsu clients with caching
- Add Jitsu configuration UI in Monitoring settings page
- Add English translations for Jitsu settings
- Clean up code: simplify getClient method and remove duplications

* fix(core): add MikroORM support and fix route ordering in tenant-setting

- Add serialize() for MikroORM find results in all methods
- Reorder controller routes: GET global → GET / → GET :id
- Prevents parameterized route from capturing named routes

* fix(plugins): address code review issues for monitoring plugins

- PostHog: isEnabled checks both posthogEnabled flag and apiKey
- PostHog: cache key includes all config properties
- PostHog: add NaN validation for parseInt
- Jitsu: handle both string and boolean for jitsuDebug
- Jitsu: cache key includes debug flag
- Sentry: add null check for instance() in GraphQL interceptor

* fix(monitoring): add OnPush, accessibility and Angular 19 patterns

- Add ChangeDetectionStrategy.OnPush
- Migrate to inject() pattern for services
- Mark ViewChild as protected readonly
- Mark forms as protected
- Add ARIA roles and keyboard navigation (Enter/Space)
- Optimize API calls: fetch settings once

* fix(monitoring): use Angular signal for loading state with OnPush

- Replace primitive loading boolean with signal(false)
- Use loading.set(true/false) in all async methods
- Use loading() in template bindings
- Ensures proper change detection with OnPush strategy

* fix(core): wrap switch case bodies in blocks for proper scoping

- Add braces to all MikroORM/TypeORM switch cases
- Prevents scope leakage for const/let declarations
- Applied to all methods: getResolvedSettings, saveGlobalSettings, getGlobalSettings, getSettings, saveSettings

* fix(jitsu): include debug in default client comparison

- Compare debug setting in early-return check for getClient
- Returns cached tenant-specific client when debug differs from default
- Ensures per-tenant jitsuDebug setting creates separate client

* feat: add GLOBAL_SETTING permission for global settings management

- Add GLOBAL_SETTING permission to PermissionsEnum
- Restrict global settings endpoints (GET/POST /global) to GLOBAL_SETTING permission
- Add GLOBAL_SETTING to PermissionGroups.ADMINISTRATION
- Grant GLOBAL_SETTING only to SUPER_ADMIN role (not ADMIN)
- Update monitoring route and menu to use GLOBAL_SETTING instead of TENANT_SETTING
- Add conditional display for global settings tabs using GLOBAL_SETTING permission
- Add translations for GLOBAL_SETTING permission

This ensures that only SUPER_ADMIN users can modify global settings (tenantId = NULL) that affect all tenants, addressing the security concern where TENANT_SETTING permission was incorrectly allowing access to global settings.

* fix: allow TENANT_SETTING permission for monitoring route access

- Change monitoring route to use TENANT_SETTING instead of GLOBAL_SETTING
- Update menu to use TENANT_SETTING for monitoring item display
- Keep GLOBAL_SETTING permission only for global settings tabs in template
- This allows ADMIN users to access monitoring page and modify tenant settings
- Only SUPER_ADMIN can modify global settings via GLOBAL_SETTING permission on global tabs

* fix: restrict GLOBAL_SETTING to SUPER_ADMIN only and fix monitoring page access

- Add GLOBAL_SETTING permission only to SUPER_ADMIN in default role permissions
- Remove GLOBAL_SETTING from PermissionGroups.ADMINISTRATION to prevent ADMIN from accessing it
- Fix monitoring page wrapper to allow TENANT_SETTING or GLOBAL_SETTING (so ADMIN can see the page)
- Keep GLOBAL_SETTING restriction only on global settings tabs (SUPER_ADMIN only)

This ensures:
- Only SUPER_ADMIN can modify global settings (tenantId = NULL)
- ADMIN users can access monitoring page and modify their tenant settings
- GLOBAL_SETTING is not visible/assignable by ADMIN in permissions UI

* feat: add monitoring provider config DTO to mask secret values

- Add MonitoringProviderConfigDTO with all monitoring settings fields
- Mask secret values (posthogKey, sentryDsn, jitsuWriteKey) in global and tenant settings
- Follow same pattern as other provider config DTOs (AWS, Wasabi, etc.)
- Apply WrapSecrets in GlobalSettingGetHandler and TenantSettingGetHandler

* fix: improve monitoring provider config DTO and return types

- Add @trimmed() decorator to posthogFlushInterval for consistency
- Change return type from Record<string, string> to Record<string, any> in:
  - GlobalSettingGetHandler
  - TenantSettingService.getGlobalSettings()
  - TenantSettingController.getGlobalSettings()
- Update JSDoc comment to reflect correct return type
- Settings include boolean fields, so Record<string, any> is more accurate
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 18, 2026

Skipped: This PR changes more files than the configured file change limit: (225 files found, 100 file limit)

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 18, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch stage

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@augmentcode
Copy link

augmentcode bot commented Jan 18, 2026

This pull request is too large for Augment to review. The PR exceeds the maximum size limit of 100000 tokens (approximately 400000 characters) for automated code review. Please consider breaking this PR into smaller, more focused changes.

@evereq evereq merged commit 3edd02a into stage-apps Jan 18, 2026
16 of 18 checks passed
@cla-assistant
Copy link

cla-assistant bot commented Jan 18, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
6 out of 7 committers have signed the CLA.

✅ syns2191
✅ evereq
✅ rahul-rocket
✅ GloireMutaliko21
✅ samuelmbabhazi
✅ adkif
❌ dependabot[bot]
You have signed the CLA already but the status is still pending? Let us recheck it.

@cla-assistant
Copy link

cla-assistant bot commented Jan 18, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
6 out of 7 committers have signed the CLA.

✅ rahul-rocket
✅ syns2191
✅ evereq
✅ GloireMutaliko21
✅ samuelmbabhazi
✅ adkif
❌ dependabot[bot]
You have signed the CLA already but the status is still pending? Let us recheck it.

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
9.3% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 225 files

Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/core/src/lib/broadcast/broadcast.service.ts">

<violation number="1" location="packages/core/src/lib/broadcast/broadcast.service.ts:190">
P2: Pagination is applied before visibility filtering, so pages can return fewer items and the `total` only reflects the filtered subset of the current page. Visible broadcasts beyond the DB page won’t be counted or returned, which breaks pagination for users.</violation>
</file>

<file name="apps/agent/src/main/workers/pull-activities.ts">

<violation number="1" location="apps/agent/src/main/workers/pull-activities.ts:584">
P2: For active activity slots, `afkDuration` should remain 0. The new elapsed-time calculation marks the entire interval as AFK even though `activityState` is `active`, which will skew activity/idle reporting. Set `afkDuration` to 0 here (or compute AFK only when the activity is actually idle).</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

...(skip !== undefined && { skip })
};

const { items } = await super.findAll(queryOptions);
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Pagination is applied before visibility filtering, so pages can return fewer items and the total only reflects the filtered subset of the current page. Visible broadcasts beyond the DB page won’t be counted or returned, which breaks pagination for users.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/src/lib/broadcast/broadcast.service.ts, line 190:

<comment>Pagination is applied before visibility filtering, so pages can return fewer items and the `total` only reflects the filtered subset of the current page. Visible broadcasts beyond the DB page won’t be counted or returned, which breaks pagination for users.</comment>

<file context>
@@ -0,0 +1,564 @@
+			...(skip !== undefined && { skip })
+		};
+
+		const { items } = await super.findAll(queryOptions);
+
+		// Filter broadcasts based on visibility mode and audience rules
</file context>
Fix with Cubic

0
);
screenShot: true,
afkDuration: Math.floor((currentTime.getTime() - this.startedDate.getTime()) / 1000),
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: For active activity slots, afkDuration should remain 0. The new elapsed-time calculation marks the entire interval as AFK even though activityState is active, which will skew activity/idle reporting. Set afkDuration to 0 here (or compute AFK only when the activity is actually idle).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/agent/src/main/workers/pull-activities.ts, line 584:

<comment>For active activity slots, `afkDuration` should remain 0. The new elapsed-time calculation marks the entire interval as AFK even though `activityState` is `active`, which will skew activity/idle reporting. Set `afkDuration` to 0 here (or compute AFK only when the activity is actually idle).</comment>

<file context>
@@ -528,14 +574,52 @@ class PullActivities {
-			0
-		);
+			screenShot: true,
+			afkDuration: Math.floor((currentTime.getTime() - this.startedDate.getTime()) / 1000),
+			activityState: ActivityState.active
+		});
</file context>
Suggested change
afkDuration: Math.floor((currentTime.getTime() - this.startedDate.getTime()) / 1000),
afkDuration: 0,
Fix with Cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants