From c197806e6b1b4e642eb0ad5ec77874f33718ef8b Mon Sep 17 00:00:00 2001 From: Kenrick Tandrian <60643640+KenTandrian@users.noreply.github.com> Date: Sun, 26 Jul 2026 00:07:46 +0700 Subject: [PATCH] Task/improve type safety in rule models (#7422) * fix(api): make some env optional * fix(api): resolve type errors in rules --- apps/api/src/models/rule.ts | 2 +- .../account-cluster-risk/current-investment.ts | 14 ++++++++------ .../rules/account-cluster-risk/single-account.ts | 6 +++++- .../rules/asset-class-cluster-risk/equity.ts | 5 +++-- .../rules/asset-class-cluster-risk/fixed-income.ts | 5 +++-- .../base-currency-current-investment.ts | 5 +++-- .../currency-cluster-risk/current-investment.ts | 5 +++-- .../developed-markets.ts | 5 +++-- .../emerging-markets.ts | 5 +++-- .../rules/emergency-fund/emergency-fund-setup.ts | 5 +++-- .../fees/fee-ratio-total-investment-volume.ts | 5 +++-- .../api/src/models/rules/liquidity/buying-power.ts | 5 +++-- .../regional-market-cluster-risk/asia-pacific.ts | 5 +++-- .../emerging-markets.ts | 5 +++-- .../rules/regional-market-cluster-risk/europe.ts | 5 +++-- .../rules/regional-market-cluster-risk/japan.ts | 5 +++-- .../regional-market-cluster-risk/north-america.ts | 5 +++-- .../services/interfaces/environment.interface.ts | 6 +++--- 18 files changed, 59 insertions(+), 39 deletions(-) diff --git a/apps/api/src/models/rule.ts b/apps/api/src/models/rule.ts index 66cda1d78..d47ea30f2 100644 --- a/apps/api/src/models/rule.ts +++ b/apps/api/src/models/rule.ts @@ -59,7 +59,7 @@ export abstract class Rule implements RuleInterface { new Big(currentValue.quantity) .mul(currentValue.marketPrice ?? 0) .toNumber(), - currentValue.assetProfile.currency, + currentValue.assetProfile.currency ?? baseCurrency, baseCurrency ), 0 diff --git a/apps/api/src/models/rules/account-cluster-risk/current-investment.ts b/apps/api/src/models/rules/account-cluster-risk/current-investment.ts index 11727e118..1b967c5db 100644 --- a/apps/api/src/models/rules/account-cluster-risk/current-investment.ts +++ b/apps/api/src/models/rules/account-cluster-risk/current-investment.ts @@ -1,6 +1,7 @@ import { Rule } from '@ghostfolio/api/models/rule'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; +import { DEFAULT_CURRENCY, DEFAULT_LOCALE } from '@ghostfolio/common/config'; import { PortfolioDetails, RuleSettings, @@ -50,7 +51,7 @@ export class AccountClusterRiskCurrentInvestment extends Rule { }; } - let maxAccount: (typeof accounts)[0]; + let maxAccount: (typeof accounts)[0] | undefined; let totalInvestment = 0; for (const account of Object.values(accounts)) { @@ -67,7 +68,8 @@ export class AccountClusterRiskCurrentInvestment extends Rule { } } - const maxInvestmentRatio = maxAccount?.investment / totalInvestment || 0; + const maxInvestmentRatio = + (maxAccount?.investment ?? 0) / totalInvestment || 0; if (maxInvestmentRatio > ruleSettings.thresholdMax) { return { @@ -75,7 +77,7 @@ export class AccountClusterRiskCurrentInvestment extends Rule { id: 'rule.accountClusterRiskCurrentInvestment.false', languageCode: this.getLanguageCode(), placeholders: { - maxAccountName: maxAccount.name, + maxAccountName: maxAccount?.name ?? '', maxInvestmentRatio: (maxInvestmentRatio * 100).toPrecision(3), thresholdMax: ruleSettings.thresholdMax * 100 } @@ -89,7 +91,7 @@ export class AccountClusterRiskCurrentInvestment extends Rule { id: 'rule.accountClusterRiskCurrentInvestment.true', languageCode: this.getLanguageCode(), placeholders: { - maxAccountName: maxAccount.name, + maxAccountName: maxAccount?.name ?? '', maxInvestmentRatio: (maxInvestmentRatio * 100).toPrecision(3), thresholdMax: ruleSettings.thresholdMax * 100 } @@ -118,8 +120,8 @@ export class AccountClusterRiskCurrentInvestment extends Rule { } public getSettings({ - baseCurrency, - locale, + baseCurrency = DEFAULT_CURRENCY, + locale = DEFAULT_LOCALE, xRayRules }: UserSettings): Settings { return { diff --git a/apps/api/src/models/rules/account-cluster-risk/single-account.ts b/apps/api/src/models/rules/account-cluster-risk/single-account.ts index 75f050316..9a6224ac2 100644 --- a/apps/api/src/models/rules/account-cluster-risk/single-account.ts +++ b/apps/api/src/models/rules/account-cluster-risk/single-account.ts @@ -1,6 +1,7 @@ import { Rule } from '@ghostfolio/api/models/rule'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; +import { DEFAULT_LOCALE } from '@ghostfolio/common/config'; import { PortfolioDetails, RuleSettings, @@ -68,7 +69,10 @@ export class AccountClusterRiskSingleAccount extends Rule { }); } - public getSettings({ locale, xRayRules }: UserSettings): RuleSettings { + public getSettings({ + locale = DEFAULT_LOCALE, + xRayRules + }: UserSettings): RuleSettings { return { locale, isActive: xRayRules?.[this.getKey()]?.isActive ?? true diff --git a/apps/api/src/models/rules/asset-class-cluster-risk/equity.ts b/apps/api/src/models/rules/asset-class-cluster-risk/equity.ts index ad5c82047..0e054f184 100644 --- a/apps/api/src/models/rules/asset-class-cluster-risk/equity.ts +++ b/apps/api/src/models/rules/asset-class-cluster-risk/equity.ts @@ -1,6 +1,7 @@ import { Rule } from '@ghostfolio/api/models/rule'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; +import { DEFAULT_CURRENCY, DEFAULT_LOCALE } from '@ghostfolio/common/config'; import { PortfolioPosition, RuleSettings, @@ -107,8 +108,8 @@ export class AssetClassClusterRiskEquity extends Rule { } public getSettings({ - baseCurrency, - locale, + baseCurrency = DEFAULT_CURRENCY, + locale = DEFAULT_LOCALE, xRayRules }: UserSettings): Settings { return { diff --git a/apps/api/src/models/rules/asset-class-cluster-risk/fixed-income.ts b/apps/api/src/models/rules/asset-class-cluster-risk/fixed-income.ts index 3bc8984db..94f359809 100644 --- a/apps/api/src/models/rules/asset-class-cluster-risk/fixed-income.ts +++ b/apps/api/src/models/rules/asset-class-cluster-risk/fixed-income.ts @@ -1,6 +1,7 @@ import { Rule } from '@ghostfolio/api/models/rule'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; +import { DEFAULT_CURRENCY, DEFAULT_LOCALE } from '@ghostfolio/common/config'; import { PortfolioPosition, RuleSettings, @@ -107,8 +108,8 @@ export class AssetClassClusterRiskFixedIncome extends Rule { } public getSettings({ - baseCurrency, - locale, + baseCurrency = DEFAULT_CURRENCY, + locale = DEFAULT_LOCALE, xRayRules }: UserSettings): Settings { return { diff --git a/apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts b/apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts index 96819e4d5..588c50ca1 100644 --- a/apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts +++ b/apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts @@ -1,6 +1,7 @@ import { Rule } from '@ghostfolio/api/models/rule'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; +import { DEFAULT_CURRENCY, DEFAULT_LOCALE } from '@ghostfolio/common/config'; import { PortfolioPosition, RuleSettings, @@ -94,8 +95,8 @@ export class CurrencyClusterRiskBaseCurrencyCurrentInvestment extends Rule { } public getSettings({ - baseCurrency, - locale, + baseCurrency = DEFAULT_CURRENCY, + locale = DEFAULT_LOCALE, xRayRules }: UserSettings): Settings { return { diff --git a/apps/api/src/models/rules/economic-market-cluster-risk/developed-markets.ts b/apps/api/src/models/rules/economic-market-cluster-risk/developed-markets.ts index ffab8c4c6..c3b8e618c 100644 --- a/apps/api/src/models/rules/economic-market-cluster-risk/developed-markets.ts +++ b/apps/api/src/models/rules/economic-market-cluster-risk/developed-markets.ts @@ -1,6 +1,7 @@ import { Rule } from '@ghostfolio/api/models/rule'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; +import { DEFAULT_CURRENCY, DEFAULT_LOCALE } from '@ghostfolio/common/config'; import { RuleSettings, UserSettings } from '@ghostfolio/common/interfaces'; export class EconomicMarketClusterRiskDevelopedMarkets extends Rule { @@ -97,8 +98,8 @@ export class EconomicMarketClusterRiskDevelopedMarkets extends Rule { } public getSettings({ - baseCurrency, - locale, + baseCurrency = DEFAULT_CURRENCY, + locale = DEFAULT_LOCALE, xRayRules }: UserSettings): Settings { return { diff --git a/apps/api/src/models/rules/economic-market-cluster-risk/emerging-markets.ts b/apps/api/src/models/rules/economic-market-cluster-risk/emerging-markets.ts index 6b834b52a..ad91bc554 100644 --- a/apps/api/src/models/rules/economic-market-cluster-risk/emerging-markets.ts +++ b/apps/api/src/models/rules/economic-market-cluster-risk/emerging-markets.ts @@ -1,6 +1,7 @@ import { Rule } from '@ghostfolio/api/models/rule'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; +import { DEFAULT_CURRENCY, DEFAULT_LOCALE } from '@ghostfolio/common/config'; import { RuleSettings, UserSettings } from '@ghostfolio/common/interfaces'; export class EconomicMarketClusterRiskEmergingMarkets extends Rule { @@ -97,8 +98,8 @@ export class EconomicMarketClusterRiskEmergingMarkets extends Rule { } public getSettings({ - baseCurrency, - locale, + baseCurrency = DEFAULT_CURRENCY, + locale = DEFAULT_LOCALE, xRayRules }: UserSettings): Settings { return { diff --git a/apps/api/src/models/rules/emergency-fund/emergency-fund-setup.ts b/apps/api/src/models/rules/emergency-fund/emergency-fund-setup.ts index fc1d8b0c0..1efd224ef 100644 --- a/apps/api/src/models/rules/emergency-fund/emergency-fund-setup.ts +++ b/apps/api/src/models/rules/emergency-fund/emergency-fund-setup.ts @@ -1,6 +1,7 @@ import { Rule } from '@ghostfolio/api/models/rule'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; +import { DEFAULT_CURRENCY, DEFAULT_LOCALE } from '@ghostfolio/common/config'; import { RuleSettings, UserSettings } from '@ghostfolio/common/interfaces'; export class EmergencyFundSetup extends Rule { @@ -52,8 +53,8 @@ export class EmergencyFundSetup extends Rule { } public getSettings({ - baseCurrency, - locale, + baseCurrency = DEFAULT_CURRENCY, + locale = DEFAULT_LOCALE, xRayRules }: UserSettings): Settings { return { diff --git a/apps/api/src/models/rules/fees/fee-ratio-total-investment-volume.ts b/apps/api/src/models/rules/fees/fee-ratio-total-investment-volume.ts index 8be31e6d4..1786c2f8e 100644 --- a/apps/api/src/models/rules/fees/fee-ratio-total-investment-volume.ts +++ b/apps/api/src/models/rules/fees/fee-ratio-total-investment-volume.ts @@ -1,6 +1,7 @@ import { Rule } from '@ghostfolio/api/models/rule'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; +import { DEFAULT_CURRENCY, DEFAULT_LOCALE } from '@ghostfolio/common/config'; import { RuleSettings, UserSettings } from '@ghostfolio/common/interfaces'; export class FeeRatioTotalInvestmentVolume extends Rule { @@ -76,8 +77,8 @@ export class FeeRatioTotalInvestmentVolume extends Rule { } public getSettings({ - baseCurrency, - locale, + baseCurrency = DEFAULT_CURRENCY, + locale = DEFAULT_LOCALE, xRayRules }: UserSettings): Settings { return { diff --git a/apps/api/src/models/rules/liquidity/buying-power.ts b/apps/api/src/models/rules/liquidity/buying-power.ts index 83493aabf..4017516cf 100644 --- a/apps/api/src/models/rules/liquidity/buying-power.ts +++ b/apps/api/src/models/rules/liquidity/buying-power.ts @@ -1,6 +1,7 @@ import { Rule } from '@ghostfolio/api/models/rule'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; +import { DEFAULT_CURRENCY, DEFAULT_LOCALE } from '@ghostfolio/common/config'; import { RuleSettings, UserSettings } from '@ghostfolio/common/interfaces'; export class BuyingPower extends Rule { @@ -83,8 +84,8 @@ export class BuyingPower extends Rule { } public getSettings({ - baseCurrency, - locale, + baseCurrency = DEFAULT_CURRENCY, + locale = DEFAULT_LOCALE, xRayRules }: UserSettings): Settings { return { diff --git a/apps/api/src/models/rules/regional-market-cluster-risk/asia-pacific.ts b/apps/api/src/models/rules/regional-market-cluster-risk/asia-pacific.ts index bf19fc734..b244641ae 100644 --- a/apps/api/src/models/rules/regional-market-cluster-risk/asia-pacific.ts +++ b/apps/api/src/models/rules/regional-market-cluster-risk/asia-pacific.ts @@ -1,6 +1,7 @@ import { Rule } from '@ghostfolio/api/models/rule'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; +import { DEFAULT_CURRENCY, DEFAULT_LOCALE } from '@ghostfolio/common/config'; import { UserSettings } from '@ghostfolio/common/interfaces'; import { Settings } from './interfaces/rule-settings.interface'; @@ -91,8 +92,8 @@ export class RegionalMarketClusterRiskAsiaPacific extends Rule { } public getSettings({ - baseCurrency, - locale, + baseCurrency = DEFAULT_CURRENCY, + locale = DEFAULT_LOCALE, xRayRules }: UserSettings): Settings { return { diff --git a/apps/api/src/models/rules/regional-market-cluster-risk/emerging-markets.ts b/apps/api/src/models/rules/regional-market-cluster-risk/emerging-markets.ts index 7f37abecd..eb7ed7815 100644 --- a/apps/api/src/models/rules/regional-market-cluster-risk/emerging-markets.ts +++ b/apps/api/src/models/rules/regional-market-cluster-risk/emerging-markets.ts @@ -1,6 +1,7 @@ import { Rule } from '@ghostfolio/api/models/rule'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; +import { DEFAULT_CURRENCY, DEFAULT_LOCALE } from '@ghostfolio/common/config'; import { UserSettings } from '@ghostfolio/common/interfaces'; import { Settings } from './interfaces/rule-settings.interface'; @@ -93,8 +94,8 @@ export class RegionalMarketClusterRiskEmergingMarkets extends Rule { } public getSettings({ - baseCurrency, - locale, + baseCurrency = DEFAULT_CURRENCY, + locale = DEFAULT_LOCALE, xRayRules }: UserSettings): Settings { return { diff --git a/apps/api/src/models/rules/regional-market-cluster-risk/europe.ts b/apps/api/src/models/rules/regional-market-cluster-risk/europe.ts index 1e10c29bf..24e0825a3 100644 --- a/apps/api/src/models/rules/regional-market-cluster-risk/europe.ts +++ b/apps/api/src/models/rules/regional-market-cluster-risk/europe.ts @@ -1,6 +1,7 @@ import { Rule } from '@ghostfolio/api/models/rule'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; +import { DEFAULT_CURRENCY, DEFAULT_LOCALE } from '@ghostfolio/common/config'; import { UserSettings } from '@ghostfolio/common/interfaces'; import { Settings } from './interfaces/rule-settings.interface'; @@ -91,8 +92,8 @@ export class RegionalMarketClusterRiskEurope extends Rule { } public getSettings({ - baseCurrency, - locale, + baseCurrency = DEFAULT_CURRENCY, + locale = DEFAULT_LOCALE, xRayRules }: UserSettings): Settings { return { diff --git a/apps/api/src/models/rules/regional-market-cluster-risk/japan.ts b/apps/api/src/models/rules/regional-market-cluster-risk/japan.ts index 22d616445..301cebf23 100644 --- a/apps/api/src/models/rules/regional-market-cluster-risk/japan.ts +++ b/apps/api/src/models/rules/regional-market-cluster-risk/japan.ts @@ -1,6 +1,7 @@ import { Rule } from '@ghostfolio/api/models/rule'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; +import { DEFAULT_CURRENCY, DEFAULT_LOCALE } from '@ghostfolio/common/config'; import { UserSettings } from '@ghostfolio/common/interfaces'; import { Settings } from './interfaces/rule-settings.interface'; @@ -91,8 +92,8 @@ export class RegionalMarketClusterRiskJapan extends Rule { } public getSettings({ - baseCurrency, - locale, + baseCurrency = DEFAULT_CURRENCY, + locale = DEFAULT_LOCALE, xRayRules }: UserSettings): Settings { return { diff --git a/apps/api/src/models/rules/regional-market-cluster-risk/north-america.ts b/apps/api/src/models/rules/regional-market-cluster-risk/north-america.ts index aa88dac7b..eda446f9a 100644 --- a/apps/api/src/models/rules/regional-market-cluster-risk/north-america.ts +++ b/apps/api/src/models/rules/regional-market-cluster-risk/north-america.ts @@ -1,6 +1,7 @@ import { Rule } from '@ghostfolio/api/models/rule'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; +import { DEFAULT_CURRENCY, DEFAULT_LOCALE } from '@ghostfolio/common/config'; import { UserSettings } from '@ghostfolio/common/interfaces'; import { Settings } from './interfaces/rule-settings.interface'; @@ -91,8 +92,8 @@ export class RegionalMarketClusterRiskNorthAmerica extends Rule { } public getSettings({ - baseCurrency, - locale, + baseCurrency = DEFAULT_CURRENCY, + locale = DEFAULT_LOCALE, xRayRules }: UserSettings): Settings { return { diff --git a/apps/api/src/services/interfaces/environment.interface.ts b/apps/api/src/services/interfaces/environment.interface.ts index bb58b01ab..7d9bfd1d4 100644 --- a/apps/api/src/services/interfaces/environment.interface.ts +++ b/apps/api/src/services/interfaces/environment.interface.ts @@ -38,9 +38,9 @@ export interface Environment extends CleanedEnvAccessors { MAX_CHART_ITEMS: number; OIDC_AUTHORIZATION_URL: string; OIDC_CALLBACK_URL: string; - OIDC_CLIENT_ID: string; - OIDC_CLIENT_SECRET: string; - OIDC_ISSUER: string; + OIDC_CLIENT_ID?: string; + OIDC_CLIENT_SECRET?: string; + OIDC_ISSUER?: string; OIDC_SCOPE: string[]; OIDC_TOKEN_URL: string; OIDC_USER_INFO_URL: string;