@firela/api-types 0.0.0-canary.3d558482 → 0.0.0-canary.3e45eeb0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -88,6 +88,49 @@ export const $AccountResponseDto = {
88
88
  enum: ['Assets', 'Liabilities', 'Income', 'Expenses', 'Equity'],
89
89
  example: 'Assets'
90
90
  },
91
+ assetSubClass: {
92
+ type: 'string',
93
+ description:
94
+ 'Account-level asset sub-class (product type, e.g. STOCK/DEPOSIT/CREDIT_CARD/PERSONAL_LOAN). Computed from the account path via the asset-classifier (ADR-0077). Null for non-asset accounts (Income/Expenses/Equity) or unmatched paths.',
95
+ enum: [
96
+ 'DEPOSIT',
97
+ 'CASH',
98
+ 'MONEY_MARKET_FUND',
99
+ 'STOCK',
100
+ 'ETF',
101
+ 'MUTUAL_FUND',
102
+ 'EQUITY_COMPENSATION',
103
+ 'GOVERNMENT_BOND',
104
+ 'CORPORATE_BOND',
105
+ 'BOND_FUND',
106
+ 'PRIMARY_RESIDENCE',
107
+ 'INVESTMENT_PROPERTY',
108
+ 'REIT',
109
+ 'GOLD',
110
+ 'SILVER',
111
+ 'PRECIOUS_METAL',
112
+ 'PRECIOUS_METAL_FUND',
113
+ 'COMMODITY',
114
+ 'COMMODITY_FUND',
115
+ 'CRYPTOCURRENCY',
116
+ 'RETIREMENT_ACCOUNT',
117
+ 'HEALTH_ACCOUNT',
118
+ 'EDUCATION_ACCOUNT',
119
+ 'INSURANCE',
120
+ 'PRIVATE_EQUITY',
121
+ 'HEDGE_FUND',
122
+ 'COLLECTIBLES',
123
+ 'MORTGAGE',
124
+ 'STUDENT_LOAN',
125
+ 'CREDIT_CARD',
126
+ 'PERSONAL_LOAN',
127
+ 'ACCOUNTS_PAYABLE',
128
+ 'TAX_PAYABLE',
129
+ 'OTHER'
130
+ ],
131
+ nullable: true,
132
+ example: 'STOCK'
133
+ },
91
134
  status: {
92
135
  type: 'string',
93
136
  description: 'Account status',
@@ -354,9 +397,47 @@ export const $AccountStandardResponseDto = {
354
397
  type: 'string',
355
398
  description: 'Icon identifier for UI display',
356
399
  example: 'bank-icbc'
400
+ },
401
+ productCategory: {
402
+ type: 'string',
403
+ description:
404
+ 'Onboarding product category (coarse grouping derived from assetSubClass)',
405
+ enum: [
406
+ 'cash',
407
+ 'investment',
408
+ 'credit_card',
409
+ 'loan',
410
+ 'payable_tax',
411
+ 'other'
412
+ ],
413
+ example: 'investment'
414
+ },
415
+ assetClass: {
416
+ type: 'string',
417
+ description:
418
+ 'Asset class (LIQUIDITY/EQUITY/.../LIABILITY), derived at read time from classification rules',
419
+ enum: [
420
+ 'LIQUIDITY',
421
+ 'EQUITY',
422
+ 'FIXED_INCOME',
423
+ 'PRECIOUS_METALS',
424
+ 'COMMODITY',
425
+ 'INSURANCE',
426
+ 'ALTERNATIVE_INVESTMENT',
427
+ 'PERSONAL_ASSETS',
428
+ 'LIABILITY',
429
+ 'REAL_ESTATE',
430
+ 'INDEX'
431
+ ]
432
+ },
433
+ assetSubClass: {
434
+ type: 'string',
435
+ description:
436
+ 'Asset sub-class (product type, derived at read time from classification rules)',
437
+ example: 'STOCK'
357
438
  }
358
439
  },
359
- required: ['path', 'type', 'description', 'tags', 'icon']
440
+ required: ['path', 'type', 'description', 'tags', 'icon', 'productCategory']
360
441
  } as const;
361
442
 
362
443
  export const $AccountStandardListResponseDto = {
@@ -3751,517 +3832,498 @@ export const $ForecastResponseDto = {
3751
3832
  ]
3752
3833
  } as const;
3753
3834
 
3754
- export const $CreateTransactionRuleDto = {
3835
+ export const $CurrencyBalanceDto = {
3755
3836
  type: 'object',
3756
3837
  properties: {
3757
- name: {
3838
+ currency: {
3758
3839
  type: 'string',
3759
- minLength: 1,
3760
- maxLength: 100
3840
+ description: 'ISO 4217 currency code',
3841
+ example: 'CNY'
3761
3842
  },
3762
- description: {
3843
+ balance: {
3763
3844
  type: 'string',
3764
- maxLength: 500
3765
- },
3766
- narrationKeywords: {
3767
- items: {
3768
- type: 'array'
3769
- },
3770
- maxItems: 50,
3771
- type: 'array'
3772
- },
3773
- payeeKeywords: {
3774
- items: {
3775
- type: 'array'
3776
- },
3777
- maxItems: 50,
3778
- type: 'array'
3779
- },
3780
- categoryKeywords: {
3781
- items: {
3782
- type: 'array'
3783
- },
3784
- maxItems: 50,
3785
- type: 'array'
3786
- },
3787
- methodKeywords: {
3788
- items: {
3789
- type: 'array'
3790
- },
3791
- maxItems: 50,
3792
- description: 'Payment method keywords (e.g., HuaBei, YuEBao)',
3793
- type: 'array'
3794
- },
3795
- categoryAccount: {
3845
+ description: 'Balance amount',
3846
+ example: '500000.00'
3847
+ }
3848
+ },
3849
+ required: ['currency', 'balance']
3850
+ } as const;
3851
+
3852
+ export const $TimeSeriesPointDto = {
3853
+ type: 'object',
3854
+ properties: {
3855
+ date: {
3796
3856
  type: 'string',
3797
- maxLength: 200,
3798
- description:
3799
- 'Destination account for expenses/income (e.g., Expenses:Food:Coffee)'
3857
+ description: 'Date in YYYY-MM-DD format',
3858
+ example: '2024-06-15'
3800
3859
  },
3801
- matchLogic: {
3860
+ value: {
3802
3861
  type: 'string',
3803
- enum: ['OR', 'AND'],
3804
- default: 'OR'
3862
+ description: 'Value at this date (in base currency)',
3863
+ example: '500000.00'
3805
3864
  },
3806
- amountMin: {
3807
- type: 'number',
3808
- minimum: 0,
3809
- description: 'Minimum transaction amount (inclusive)'
3865
+ change: {
3866
+ type: 'object',
3867
+ description: 'Change from previous point',
3868
+ example: '5000.00'
3810
3869
  },
3811
- amountMax: {
3812
- type: 'number',
3813
- minimum: 0,
3814
- description: 'Maximum transaction amount (inclusive)'
3870
+ assets: {
3871
+ type: 'string',
3872
+ description: 'Total assets at this date (in base currency)',
3873
+ example: '494338.00'
3815
3874
  },
3816
- priority: {
3817
- type: 'number',
3818
- default: 50,
3819
- minimum: 0,
3820
- maximum: 1000
3875
+ liabilities: {
3876
+ type: 'string',
3877
+ description: 'Total liabilities at this date (in base currency)',
3878
+ example: '310098.00'
3821
3879
  },
3822
- additionalTags: {
3880
+ byCurrency: {
3881
+ description: 'Multi-currency breakdown for this point',
3882
+ type: 'array',
3823
3883
  items: {
3824
- type: 'array'
3825
- },
3826
- maxItems: 20,
3827
- type: 'array'
3828
- },
3829
- additionalMetadata: {
3830
- type: 'object'
3831
- },
3832
- upsertByPayee: {
3833
- type: 'boolean',
3834
- description:
3835
- 'If true, update existing rule with matching payeeKeywords[0] instead of creating new rule'
3884
+ $ref: '#/components/schemas/CurrencyBalanceDto'
3885
+ }
3836
3886
  }
3837
3887
  },
3838
- required: ['name', 'matchLogic', 'priority']
3888
+ required: ['date', 'value']
3839
3889
  } as const;
3840
3890
 
3841
- export const $AmountRangeDto = {
3891
+ export const $TrendSummaryDto = {
3842
3892
  type: 'object',
3843
3893
  properties: {
3844
- min: {
3845
- type: 'number',
3846
- description: 'Minimum amount'
3894
+ startValue: {
3895
+ type: 'string',
3896
+ description: 'Value at start of period',
3897
+ example: '450000.00'
3847
3898
  },
3848
- max: {
3849
- type: 'number',
3850
- description: 'Maximum amount'
3899
+ endValue: {
3900
+ type: 'string',
3901
+ description: 'Value at end of period',
3902
+ example: '500000.00'
3903
+ },
3904
+ totalChange: {
3905
+ type: 'string',
3906
+ description: 'Total change over period',
3907
+ example: '50000.00'
3908
+ },
3909
+ totalChangePercentage: {
3910
+ type: 'string',
3911
+ description: 'Total change percentage',
3912
+ example: '+11.11%'
3851
3913
  }
3852
- }
3914
+ },
3915
+ required: ['startValue', 'endValue', 'totalChange', 'totalChangePercentage']
3853
3916
  } as const;
3854
3917
 
3855
- export const $TransactionRuleResponseDto = {
3918
+ export const $MultiCurrencyPointDto = {
3856
3919
  type: 'object',
3857
3920
  properties: {
3858
- id: {
3859
- type: 'string',
3860
- description: 'Rule ID'
3861
- },
3862
- name: {
3863
- type: 'string',
3864
- description: 'Rule name'
3865
- },
3866
- description: {
3921
+ date: {
3867
3922
  type: 'string',
3868
- description: 'Rule description'
3923
+ description: 'Date in YYYY-MM-DD format',
3924
+ example: '2024-06-15'
3869
3925
  },
3870
- narrationKeywords: {
3871
- description: 'Keywords to match in transaction narration',
3926
+ byCurrency: {
3927
+ description: 'Balances by currency',
3872
3928
  type: 'array',
3873
3929
  items: {
3874
- type: 'string'
3930
+ $ref: '#/components/schemas/CurrencyBalanceDto'
3875
3931
  }
3876
- },
3877
- payeeKeywords: {
3878
- description: 'Keywords to match in payee name',
3932
+ }
3933
+ },
3934
+ required: ['date', 'byCurrency']
3935
+ } as const;
3936
+
3937
+ export const $PortfolioTrendsResponseDto = {
3938
+ type: 'object',
3939
+ properties: {
3940
+ series: {
3941
+ description: 'Time series data points',
3879
3942
  type: 'array',
3880
3943
  items: {
3881
- type: 'string'
3944
+ $ref: '#/components/schemas/TimeSeriesPointDto'
3882
3945
  }
3883
3946
  },
3884
- categoryKeywords: {
3885
- description: 'Keywords to match in category',
3947
+ summary: {
3948
+ description: 'Period summary',
3949
+ allOf: [
3950
+ {
3951
+ $ref: '#/components/schemas/TrendSummaryDto'
3952
+ }
3953
+ ]
3954
+ },
3955
+ period: {
3956
+ type: 'string',
3957
+ description: 'Period requested',
3958
+ example: '6m'
3959
+ },
3960
+ granularity: {
3961
+ type: 'string',
3962
+ description: 'Data granularity',
3963
+ example: 'month'
3964
+ },
3965
+ currency: {
3966
+ type: 'string',
3967
+ description: 'Base currency for converted values',
3968
+ example: 'CNY'
3969
+ },
3970
+ byCurrency: {
3971
+ description:
3972
+ 'Multi-currency time series (each point has currency breakdown)',
3886
3973
  type: 'array',
3887
3974
  items: {
3888
- type: 'string'
3975
+ $ref: '#/components/schemas/MultiCurrencyPointDto'
3889
3976
  }
3890
3977
  },
3891
- methodKeywords: {
3892
- description: 'Keywords to match in payment method',
3978
+ warnings: {
3979
+ description: 'Exchange rate warnings',
3893
3980
  type: 'array',
3894
3981
  items: {
3895
- type: 'string'
3982
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
3896
3983
  }
3897
- },
3898
- categoryAccount: {
3899
- type: 'string',
3900
- description: 'Destination account for categorization'
3901
- },
3902
- matchLogic: {
3903
- type: 'string',
3904
- description: 'Keyword matching logic',
3905
- enum: ['OR', 'AND'],
3906
- example: 'OR'
3907
- },
3908
- amountRange: {
3909
- description: 'Amount range for matching',
3910
- allOf: [
3911
- {
3912
- $ref: '#/components/schemas/AmountRangeDto'
3913
- }
3914
- ]
3915
- },
3916
- priority: {
3917
- type: 'number',
3918
- description: 'Rule priority (0-1000, higher = first match)',
3919
- example: 50
3920
- },
3921
- enabled: {
3922
- type: 'boolean',
3923
- description: 'Whether the rule is enabled'
3924
- },
3925
- learningSource: {
3984
+ }
3985
+ },
3986
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
3987
+ } as const;
3988
+
3989
+ export const $CashFlowPointDto = {
3990
+ type: 'object',
3991
+ properties: {
3992
+ month: {
3926
3993
  type: 'string',
3927
- description: 'Learning source: NLP, REVIEW_CENTER, or null for manual',
3928
- enum: ['NLP', 'REVIEW_CENTER'],
3929
- nullable: true,
3930
- example: 'REVIEW_CENTER'
3931
- },
3932
- autoApplyEnabled: {
3933
- type: 'boolean',
3934
- description: 'Whether auto-apply is enabled for this rule'
3935
- },
3936
- confirmationCount: {
3937
- type: 'number',
3938
- description: 'Number of confirmations for NLP-learned rules',
3939
- example: 3
3940
- },
3941
- additionalTags: {
3942
- description: 'Additional tags',
3943
- type: 'array',
3944
- items: {
3945
- type: 'string'
3946
- }
3994
+ description: 'Month key (YYYY-MM)',
3995
+ example: '2024-03'
3947
3996
  },
3948
- additionalMetadata: {
3949
- type: 'object',
3950
- description: 'Additional metadata',
3951
- additionalProperties: {
3952
- type: 'string'
3953
- }
3997
+ income: {
3998
+ type: 'string',
3999
+ description: 'Income in base currency (absolute, converted)',
4000
+ example: '10000.00'
3954
4001
  },
3955
- createdAt: {
3956
- format: 'date-time',
4002
+ expense: {
3957
4003
  type: 'string',
3958
- description: 'Created timestamp'
4004
+ description: 'Expense in base currency (absolute, converted)',
4005
+ example: '5000.00'
3959
4006
  },
3960
- updatedAt: {
3961
- format: 'date-time',
4007
+ netSavings: {
3962
4008
  type: 'string',
3963
- description: 'Updated timestamp'
4009
+ description: 'netSavings = income − expense (savings positive)',
4010
+ example: '5000.00'
3964
4011
  }
3965
4012
  },
3966
- required: [
3967
- 'id',
3968
- 'name',
3969
- 'narrationKeywords',
3970
- 'payeeKeywords',
3971
- 'categoryKeywords',
3972
- 'methodKeywords',
3973
- 'matchLogic',
3974
- 'priority',
3975
- 'enabled',
3976
- 'autoApplyEnabled',
3977
- 'confirmationCount',
3978
- 'additionalTags',
3979
- 'createdAt',
3980
- 'updatedAt'
3981
- ]
4013
+ required: ['month', 'income', 'expense', 'netSavings']
3982
4014
  } as const;
3983
4015
 
3984
- export const $TransactionRuleListResponseDto = {
4016
+ export const $CashFlowTrendSummaryDto = {
3985
4017
  type: 'object',
3986
4018
  properties: {
3987
- data: {
3988
- type: 'array',
3989
- items: {
3990
- $ref: '#/components/schemas/TransactionRuleResponseDto'
3991
- }
4019
+ totalIncome: {
4020
+ type: 'string',
4021
+ description: 'Total income across the period',
4022
+ example: '60000.00'
3992
4023
  },
3993
- total: {
3994
- type: 'number',
3995
- description: 'Total count of rules'
4024
+ totalExpense: {
4025
+ type: 'string',
4026
+ description: 'Total expense across the period',
4027
+ example: '30000.00'
3996
4028
  },
3997
- limit: {
3998
- type: 'number',
3999
- description: 'Results per page'
4029
+ totalNetSavings: {
4030
+ type: 'string',
4031
+ description: 'income − expense across the period',
4032
+ example: '30000.00'
4000
4033
  },
4001
- offset: {
4002
- type: 'number',
4003
- description: 'Pagination offset'
4034
+ averageMonthlyNetSavings: {
4035
+ type: 'string',
4036
+ description:
4037
+ 'totalNetSavings divided by the window length (N months, incl. zero-filled)',
4038
+ example: '5000.00'
4004
4039
  }
4005
4040
  },
4006
- required: ['data', 'total', 'limit', 'offset']
4041
+ required: [
4042
+ 'totalIncome',
4043
+ 'totalExpense',
4044
+ 'totalNetSavings',
4045
+ 'averageMonthlyNetSavings'
4046
+ ]
4007
4047
  } as const;
4008
4048
 
4009
- export const $ValidateRuleDto = {
4049
+ export const $CashFlowTrendsResponseDto = {
4010
4050
  type: 'object',
4011
4051
  properties: {
4012
- name: {
4013
- type: 'string',
4014
- minLength: 1,
4015
- maxLength: 100
4016
- },
4017
- description: {
4018
- type: 'string',
4019
- maxLength: 500
4020
- },
4021
- narrationKeywords: {
4022
- items: {
4023
- type: 'array'
4024
- },
4025
- maxItems: 50,
4026
- type: 'array'
4027
- },
4028
- payeeKeywords: {
4029
- items: {
4030
- type: 'array'
4031
- },
4032
- maxItems: 50,
4033
- type: 'array'
4034
- },
4035
- categoryKeywords: {
4052
+ series: {
4053
+ description:
4054
+ 'Monthly cash-flow series (fixed N-month window, zero-filled)',
4055
+ type: 'array',
4036
4056
  items: {
4037
- type: 'array'
4038
- },
4039
- maxItems: 50,
4040
- type: 'array'
4057
+ $ref: '#/components/schemas/CashFlowPointDto'
4058
+ }
4041
4059
  },
4042
- methodKeywords: {
4043
- items: {
4044
- type: 'array'
4045
- },
4046
- maxItems: 50,
4047
- description: 'Payment method keywords (e.g., HuaBei, YuEBao)',
4048
- type: 'array'
4060
+ summary: {
4061
+ description: 'Period totals',
4062
+ allOf: [
4063
+ {
4064
+ $ref: '#/components/schemas/CashFlowTrendSummaryDto'
4065
+ }
4066
+ ]
4049
4067
  },
4050
- categoryAccount: {
4068
+ period: {
4051
4069
  type: 'string',
4052
- maxLength: 200,
4053
- description:
4054
- 'Destination account for expenses/income (e.g., Expenses:Food:Coffee)'
4070
+ description: 'Period requested',
4071
+ example: '6m'
4055
4072
  },
4056
- matchLogic: {
4073
+ granularity: {
4057
4074
  type: 'string',
4058
- enum: ['OR', 'AND'],
4059
- default: 'OR'
4060
- },
4061
- amountMin: {
4062
- type: 'number',
4063
- minimum: 0,
4064
- description: 'Minimum transaction amount (inclusive)'
4065
- },
4066
- amountMax: {
4067
- type: 'number',
4068
- minimum: 0,
4069
- description: 'Maximum transaction amount (inclusive)'
4075
+ description: 'Data granularity (v1 returns month buckets)',
4076
+ example: 'month'
4070
4077
  },
4071
- priority: {
4072
- type: 'number',
4073
- default: 50,
4074
- minimum: 0,
4075
- maximum: 1000
4078
+ currency: {
4079
+ type: 'string',
4080
+ description: 'Base currency for converted values',
4081
+ example: 'CNY'
4076
4082
  },
4077
- additionalTags: {
4083
+ warnings: {
4084
+ description: 'Exchange rate warnings (e.g. missing rate for a currency)',
4085
+ type: 'array',
4078
4086
  items: {
4079
- type: 'array'
4080
- },
4081
- maxItems: 20,
4082
- type: 'array'
4083
- },
4084
- additionalMetadata: {
4085
- type: 'object'
4086
- },
4087
- upsertByPayee: {
4088
- type: 'boolean',
4089
- description:
4090
- 'If true, update existing rule with matching payeeKeywords[0] instead of creating new rule'
4087
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
4088
+ }
4091
4089
  }
4092
4090
  },
4093
- required: ['name', 'matchLogic', 'priority']
4091
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
4094
4092
  } as const;
4095
4093
 
4096
- export const $ValidateRuleResponseDto = {
4094
+ export const $GenerateSnapshotBody = {
4097
4095
  type: 'object',
4098
- properties: {
4099
- valid: {
4100
- type: 'boolean',
4101
- description: 'Whether the rule configuration is valid',
4102
- example: true
4103
- },
4104
- errors: {
4105
- description: 'List of validation errors (empty if valid)',
4106
- example: [],
4107
- items: {
4108
- type: 'array'
4109
- },
4110
- type: 'array'
4111
- },
4112
- warnings: {
4113
- description: 'List of validation warnings (non-blocking issues)',
4114
- example: [
4115
- 'No account constraints specified - rule will match any account'
4116
- ],
4117
- items: {
4118
- type: 'array'
4119
- },
4120
- type: 'array'
4096
+ properties: {}
4097
+ } as const;
4098
+
4099
+ export const $GenerateSnapshotResponse = {
4100
+ type: 'object',
4101
+ properties: {}
4102
+ } as const;
4103
+
4104
+ export const $BackfillSnapshotsBody = {
4105
+ type: 'object',
4106
+ properties: {}
4107
+ } as const;
4108
+
4109
+ export const $BackfillSnapshotsResponse = {
4110
+ type: 'object',
4111
+ properties: {}
4112
+ } as const;
4113
+
4114
+ export const $DeleteOwnUserDto = {
4115
+ type: 'object',
4116
+ properties: {
4117
+ accessToken: {
4118
+ type: 'string',
4119
+ description: 'Access token for user verification',
4120
+ example: 'abc123xyz'
4121
4121
  }
4122
4122
  },
4123
- required: ['valid', 'errors', 'warnings']
4123
+ required: ['accessToken']
4124
4124
  } as const;
4125
4125
 
4126
- export const $BulkCreateRulesDto = {
4126
+ export const $UserSettingsResponseDto = {
4127
4127
  type: 'object',
4128
4128
  properties: {
4129
- rules: {
4130
- items: {
4131
- type: 'array'
4132
- },
4133
- description: 'Array of rules to import',
4134
- type: 'array'
4135
- },
4136
- conflictStrategy: {
4129
+ baseCurrency: {
4137
4130
  type: 'string',
4138
- enum: ['replace', 'skip'],
4139
- default: 'skip',
4140
4131
  description:
4141
- 'Conflict handling strategy: skip (default) ignores duplicates, replace soft-deletes existing rule'
4132
+ 'Base currency (ISO 4217) for net-worth/report aggregation. Independent of region (ADR-0006).',
4133
+ example: 'USD',
4134
+ nullable: true
4142
4135
  }
4143
4136
  },
4144
- required: ['rules', 'conflictStrategy']
4137
+ required: ['baseCurrency']
4145
4138
  } as const;
4146
4139
 
4147
- export const $BulkCreateRulesResponseDto = {
4140
+ export const $UserResponseDto = {
4148
4141
  type: 'object',
4149
4142
  properties: {
4150
- successCount: {
4151
- type: 'number',
4152
- description: 'Number of successfully created rules'
4153
- },
4154
- failureCount: {
4155
- type: 'number',
4156
- description: 'Number of failed rules'
4143
+ id: {
4144
+ type: 'string',
4145
+ description: 'User ID'
4157
4146
  },
4158
- errors: {
4159
- type: 'array',
4160
- description: 'Error details for failed rules',
4161
- items: {
4162
- type: 'object',
4163
- properties: {
4164
- index: {
4165
- type: 'number'
4166
- },
4167
- message: {
4168
- type: 'string'
4169
- }
4170
- }
4171
- }
4147
+ role: {
4148
+ type: 'string',
4149
+ description: 'Assigned user role'
4172
4150
  },
4173
- createdRuleIds: {
4174
- description: 'IDs of successfully created rules',
4151
+ permissions: {
4152
+ description: 'Permission strings',
4175
4153
  type: 'array',
4176
4154
  items: {
4177
4155
  type: 'string'
4178
4156
  }
4157
+ },
4158
+ settings: {
4159
+ description: 'User settings',
4160
+ allOf: [
4161
+ {
4162
+ $ref: '#/components/schemas/UserSettingsResponseDto'
4163
+ }
4164
+ ]
4179
4165
  }
4180
4166
  },
4181
- required: ['successCount', 'failureCount', 'errors', 'createdRuleIds']
4167
+ required: ['id', 'role', 'permissions', 'settings']
4182
4168
  } as const;
4183
4169
 
4184
- export const $ExportRulesResponseDto = {
4170
+ export const $SignupDto = {
4185
4171
  type: 'object',
4186
4172
  properties: {
4187
- exportedAt: {
4173
+ turnstileToken: {
4188
4174
  type: 'string',
4189
- description: 'Export timestamp'
4190
- },
4191
- userId: {
4175
+ description:
4176
+ 'Cloudflare Turnstile verification token (optional when Turnstile disabled)',
4177
+ example: '0.abc123def456...'
4178
+ }
4179
+ }
4180
+ } as const;
4181
+
4182
+ export const $SignupResponseDto = {
4183
+ type: 'object',
4184
+ properties: {
4185
+ authToken: {
4192
4186
  type: 'string',
4193
- description: 'User ID'
4187
+ description: 'JWT auth token',
4188
+ example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
4194
4189
  },
4195
- ruleCount: {
4196
- type: 'number',
4197
- description: 'Number of exported rules'
4190
+ accessToken: {
4191
+ type: 'string',
4192
+ description: 'Auto-generated access token'
4198
4193
  },
4199
- rules: {
4200
- type: 'array',
4201
- description: 'Exported rules'
4194
+ role: {
4195
+ type: 'string',
4196
+ description: 'Assigned user role',
4197
+ enum: ['USER', 'ADMIN', 'DEMO', 'INACTIVE', 'PAID', 'OPS']
4202
4198
  }
4203
4199
  },
4204
- required: ['exportedAt', 'userId', 'ruleCount', 'rules']
4200
+ required: ['authToken', 'accessToken', 'role']
4205
4201
  } as const;
4206
4202
 
4207
- export const $RuleStatisticsResponseDto = {
4203
+ export const $UpdateUserSettingDto = {
4208
4204
  type: 'object',
4209
4205
  properties: {
4210
- period: {
4211
- type: 'string',
4212
- description: 'Statistics time period',
4213
- enum: ['7d', '30d', '90d']
4214
- },
4215
- totalRules: {
4206
+ secId: {
4216
4207
  type: 'number',
4217
- description: 'Total number of rules'
4208
+ description: 'Security ID'
4218
4209
  },
4219
- rulesWithMatches: {
4210
+ annualInterestRate: {
4220
4211
  type: 'number',
4221
- description: 'Number of rules with at least one match'
4212
+ description: 'Annual interest rate',
4213
+ example: 0.05
4222
4214
  },
4223
- totalMatches: {
4224
- type: 'number',
4225
- description: 'Total number of matches across all rules'
4215
+ currency: {
4216
+ type: 'string',
4217
+ description: 'Currency code',
4218
+ example: 'USD'
4226
4219
  },
4227
- averageConfidence: {
4220
+ baseCurrency: {
4221
+ type: 'string',
4222
+ description: 'Base currency code',
4223
+ example: 'USD'
4224
+ },
4225
+ benchmark: {
4226
+ type: 'string',
4227
+ description: 'Benchmark symbol',
4228
+ example: 'SPY'
4229
+ },
4230
+ colorScheme: {
4231
+ type: 'string',
4232
+ description: 'Color scheme',
4233
+ enum: ['DARK', 'LIGHT']
4234
+ },
4235
+ dateRange: {
4236
+ type: 'string',
4237
+ description: 'Date range filter',
4238
+ example: '1y'
4239
+ },
4240
+ emergencyFund: {
4228
4241
  type: 'number',
4229
- description: 'Average confidence score across all matches',
4230
- example: 0.82
4242
+ description: 'Emergency fund amount',
4243
+ example: 10000
4231
4244
  },
4232
- ruleStats: {
4245
+ 'filters.accounts': {
4246
+ description: 'Account filter IDs',
4233
4247
  type: 'array',
4234
- description: 'Per-rule statistics',
4235
4248
  items: {
4236
- type: 'object',
4237
- properties: {
4238
- ruleId: {
4239
- type: 'string'
4240
- },
4241
- ruleName: {
4242
- type: 'string'
4243
- },
4244
- matchCount: {
4245
- type: 'number'
4246
- },
4247
- averageConfidence: {
4248
- type: 'number'
4249
- }
4250
- }
4249
+ type: 'string'
4250
+ }
4251
+ },
4252
+ 'filters.assetClasses': {
4253
+ description: 'Asset class filters',
4254
+ type: 'array',
4255
+ items: {
4256
+ type: 'string'
4257
+ }
4258
+ },
4259
+ 'filters.dataSource': {
4260
+ type: 'string',
4261
+ description: 'Data source filter'
4262
+ },
4263
+ 'filters.symbol': {
4264
+ type: 'string',
4265
+ description: 'Symbol filter'
4266
+ },
4267
+ 'filters.tags': {
4268
+ description: 'Tag filters',
4269
+ type: 'array',
4270
+ items: {
4271
+ type: 'string'
4251
4272
  }
4273
+ },
4274
+ isExperimentalFeatures: {
4275
+ type: 'boolean',
4276
+ description: 'Enable experimental features'
4277
+ },
4278
+ isRestrictedView: {
4279
+ type: 'boolean',
4280
+ description: 'Enable restricted view mode'
4281
+ },
4282
+ language: {
4283
+ type: 'string',
4284
+ description: 'Language code',
4285
+ example: 'en'
4286
+ },
4287
+ locale: {
4288
+ type: 'string',
4289
+ description: 'Locale code',
4290
+ example: 'en-US'
4291
+ },
4292
+ projectedTotalAmount: {
4293
+ type: 'number',
4294
+ description: 'Projected total amount',
4295
+ example: 1000000
4296
+ },
4297
+ retirementDate: {
4298
+ type: 'string',
4299
+ description: 'Retirement date in ISO 8601 format',
4300
+ example: '2050-01-01'
4301
+ },
4302
+ savingsRate: {
4303
+ type: 'number',
4304
+ description: 'Savings rate percentage',
4305
+ example: 0.2
4306
+ },
4307
+ viewMode: {
4308
+ type: 'string',
4309
+ description: 'View mode',
4310
+ enum: ['DEFAULT', 'ZEN']
4311
+ }
4312
+ }
4313
+ } as const;
4314
+
4315
+ export const $UpdatePropertyDto = {
4316
+ type: 'object',
4317
+ properties: {
4318
+ value: {
4319
+ type: 'string',
4320
+ description: 'Property value'
4252
4321
  }
4253
4322
  },
4254
- required: [
4255
- 'period',
4256
- 'totalRules',
4257
- 'rulesWithMatches',
4258
- 'totalMatches',
4259
- 'averageConfidence',
4260
- 'ruleStats'
4261
- ]
4323
+ required: ['value']
4262
4324
  } as const;
4263
4325
 
4264
- export const $UpdateTransactionRuleDto = {
4326
+ export const $CreateTransactionRuleDto = {
4265
4327
  type: 'object',
4266
4328
  properties: {
4267
4329
  name: {
@@ -4310,7 +4372,8 @@ export const $UpdateTransactionRuleDto = {
4310
4372
  },
4311
4373
  matchLogic: {
4312
4374
  type: 'string',
4313
- enum: ['OR', 'AND']
4375
+ enum: ['OR', 'AND'],
4376
+ default: 'OR'
4314
4377
  },
4315
4378
  amountMin: {
4316
4379
  type: 'number',
@@ -4324,12 +4387,9 @@ export const $UpdateTransactionRuleDto = {
4324
4387
  },
4325
4388
  priority: {
4326
4389
  type: 'number',
4327
- minimum: 0,
4328
- maximum: 1000
4329
- },
4330
- enabled: {
4331
- type: 'boolean',
4332
- description: 'Enable or disable the rule'
4390
+ default: 50,
4391
+ minimum: 0,
4392
+ maximum: 1000
4333
4393
  },
4334
4394
  additionalTags: {
4335
4395
  items: {
@@ -4340,511 +4400,639 @@ export const $UpdateTransactionRuleDto = {
4340
4400
  },
4341
4401
  additionalMetadata: {
4342
4402
  type: 'object'
4343
- }
4344
- }
4345
- } as const;
4346
-
4347
- export const $TestRuleDto = {
4348
- type: 'object',
4349
- properties: {
4350
- narration: {
4351
- type: 'string',
4352
- minLength: 1,
4353
- maxLength: 500
4354
- },
4355
- payee: {
4356
- type: 'string',
4357
- maxLength: 200
4358
- },
4359
- categoryAccount: {
4360
- type: 'string',
4361
- maxLength: 200
4362
- },
4363
- amount: {
4364
- type: 'number'
4365
4403
  },
4366
- currency: {
4367
- type: 'string',
4368
- maxLength: 10
4404
+ upsertByPayee: {
4405
+ type: 'boolean',
4406
+ description:
4407
+ 'If true, update existing rule with matching payeeKeywords[0] instead of creating new rule'
4369
4408
  }
4370
4409
  },
4371
- required: ['narration']
4410
+ required: ['name', 'matchLogic', 'priority']
4372
4411
  } as const;
4373
4412
 
4374
- export const $TestRuleResponseDto = {
4413
+ export const $AmountRangeDto = {
4375
4414
  type: 'object',
4376
4415
  properties: {
4377
- ruleId: {
4378
- type: 'string',
4379
- description: 'Rule ID that was tested'
4380
- },
4381
- matches: {
4382
- type: 'boolean',
4383
- description: 'Whether the rule matched the test data'
4384
- },
4385
- confidence: {
4416
+ min: {
4386
4417
  type: 'number',
4387
- description: 'Match confidence score (0-1)',
4388
- example: 0.85
4418
+ description: 'Minimum amount'
4389
4419
  },
4390
- matchDetails: {
4391
- type: 'object',
4392
- description: 'Details of which fields matched',
4393
- example: {
4394
- narration: true,
4395
- payee: false,
4396
- categoryAccount: false
4397
- }
4398
- }
4399
- },
4400
- required: ['ruleId', 'matches', 'confidence', 'matchDetails']
4401
- } as const;
4402
-
4403
- export const $DeleteOwnUserDto = {
4404
- type: 'object',
4405
- properties: {
4406
- accessToken: {
4407
- type: 'string',
4408
- description: 'Access token for user verification',
4409
- example: 'abc123xyz'
4410
- }
4411
- },
4412
- required: ['accessToken']
4413
- } as const;
4414
-
4415
- export const $SignupDto = {
4416
- type: 'object',
4417
- properties: {
4418
- turnstileToken: {
4419
- type: 'string',
4420
- description:
4421
- 'Cloudflare Turnstile verification token (optional when Turnstile disabled)',
4422
- example: '0.abc123def456...'
4420
+ max: {
4421
+ type: 'number',
4422
+ description: 'Maximum amount'
4423
4423
  }
4424
4424
  }
4425
4425
  } as const;
4426
4426
 
4427
- export const $SignupResponseDto = {
4427
+ export const $TransactionRuleResponseDto = {
4428
4428
  type: 'object',
4429
4429
  properties: {
4430
- authToken: {
4430
+ id: {
4431
4431
  type: 'string',
4432
- description: 'JWT auth token',
4433
- example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
4432
+ description: 'Rule ID'
4434
4433
  },
4435
- accessToken: {
4434
+ name: {
4436
4435
  type: 'string',
4437
- description: 'Auto-generated access token'
4436
+ description: 'Rule name'
4438
4437
  },
4439
- role: {
4438
+ description: {
4440
4439
  type: 'string',
4441
- description: 'Assigned user role',
4442
- enum: ['USER', 'ADMIN', 'DEMO', 'INACTIVE', 'PAID', 'OPS']
4443
- }
4444
- },
4445
- required: ['authToken', 'accessToken', 'role']
4446
- } as const;
4447
-
4448
- export const $UpdateUserSettingDto = {
4449
- type: 'object',
4450
- properties: {
4451
- secId: {
4452
- type: 'number',
4453
- description: 'Security ID'
4440
+ description: 'Rule description'
4454
4441
  },
4455
- annualInterestRate: {
4456
- type: 'number',
4457
- description: 'Annual interest rate',
4458
- example: 0.05
4442
+ narrationKeywords: {
4443
+ description: 'Keywords to match in transaction narration',
4444
+ type: 'array',
4445
+ items: {
4446
+ type: 'string'
4447
+ }
4459
4448
  },
4460
- currency: {
4461
- type: 'string',
4462
- description: 'Currency code',
4463
- example: 'USD'
4449
+ payeeKeywords: {
4450
+ description: 'Keywords to match in payee name',
4451
+ type: 'array',
4452
+ items: {
4453
+ type: 'string'
4454
+ }
4464
4455
  },
4465
- baseCurrency: {
4466
- type: 'string',
4467
- description: 'Base currency code',
4468
- example: 'USD'
4456
+ categoryKeywords: {
4457
+ description: 'Keywords to match in category',
4458
+ type: 'array',
4459
+ items: {
4460
+ type: 'string'
4461
+ }
4469
4462
  },
4470
- benchmark: {
4463
+ methodKeywords: {
4464
+ description: 'Keywords to match in payment method',
4465
+ type: 'array',
4466
+ items: {
4467
+ type: 'string'
4468
+ }
4469
+ },
4470
+ categoryAccount: {
4471
4471
  type: 'string',
4472
- description: 'Benchmark symbol',
4473
- example: 'SPY'
4472
+ description: 'Destination account for categorization'
4474
4473
  },
4475
- colorScheme: {
4474
+ matchLogic: {
4476
4475
  type: 'string',
4477
- description: 'Color scheme',
4478
- enum: ['DARK', 'LIGHT']
4476
+ description: 'Keyword matching logic',
4477
+ enum: ['OR', 'AND'],
4478
+ example: 'OR'
4479
4479
  },
4480
- dateRange: {
4480
+ amountRange: {
4481
+ description: 'Amount range for matching',
4482
+ allOf: [
4483
+ {
4484
+ $ref: '#/components/schemas/AmountRangeDto'
4485
+ }
4486
+ ]
4487
+ },
4488
+ priority: {
4489
+ type: 'number',
4490
+ description: 'Rule priority (0-1000, higher = first match)',
4491
+ example: 50
4492
+ },
4493
+ enabled: {
4494
+ type: 'boolean',
4495
+ description: 'Whether the rule is enabled'
4496
+ },
4497
+ learningSource: {
4481
4498
  type: 'string',
4482
- description: 'Date range filter',
4483
- example: '1y'
4499
+ description: 'Learning source: NLP, REVIEW_CENTER, or null for manual',
4500
+ enum: ['NLP', 'REVIEW_CENTER'],
4501
+ nullable: true,
4502
+ example: 'REVIEW_CENTER'
4484
4503
  },
4485
- emergencyFund: {
4504
+ autoApplyEnabled: {
4505
+ type: 'boolean',
4506
+ description: 'Whether auto-apply is enabled for this rule'
4507
+ },
4508
+ confirmationCount: {
4486
4509
  type: 'number',
4487
- description: 'Emergency fund amount',
4488
- example: 10000
4510
+ description: 'Number of confirmations for NLP-learned rules',
4511
+ example: 3
4489
4512
  },
4490
- 'filters.accounts': {
4491
- description: 'Account filter IDs',
4513
+ additionalTags: {
4514
+ description: 'Additional tags',
4492
4515
  type: 'array',
4493
4516
  items: {
4494
4517
  type: 'string'
4495
4518
  }
4496
4519
  },
4497
- 'filters.assetClasses': {
4498
- description: 'Asset class filters',
4520
+ additionalMetadata: {
4521
+ type: 'object',
4522
+ description: 'Additional metadata',
4523
+ additionalProperties: {
4524
+ type: 'string'
4525
+ }
4526
+ },
4527
+ createdAt: {
4528
+ format: 'date-time',
4529
+ type: 'string',
4530
+ description: 'Created timestamp'
4531
+ },
4532
+ updatedAt: {
4533
+ format: 'date-time',
4534
+ type: 'string',
4535
+ description: 'Updated timestamp'
4536
+ }
4537
+ },
4538
+ required: [
4539
+ 'id',
4540
+ 'name',
4541
+ 'narrationKeywords',
4542
+ 'payeeKeywords',
4543
+ 'categoryKeywords',
4544
+ 'methodKeywords',
4545
+ 'matchLogic',
4546
+ 'priority',
4547
+ 'enabled',
4548
+ 'autoApplyEnabled',
4549
+ 'confirmationCount',
4550
+ 'additionalTags',
4551
+ 'createdAt',
4552
+ 'updatedAt'
4553
+ ]
4554
+ } as const;
4555
+
4556
+ export const $TransactionRuleListResponseDto = {
4557
+ type: 'object',
4558
+ properties: {
4559
+ data: {
4499
4560
  type: 'array',
4500
4561
  items: {
4501
- type: 'string'
4562
+ $ref: '#/components/schemas/TransactionRuleResponseDto'
4502
4563
  }
4503
4564
  },
4504
- 'filters.dataSource': {
4565
+ total: {
4566
+ type: 'number',
4567
+ description: 'Total count of rules'
4568
+ },
4569
+ limit: {
4570
+ type: 'number',
4571
+ description: 'Results per page'
4572
+ },
4573
+ offset: {
4574
+ type: 'number',
4575
+ description: 'Pagination offset'
4576
+ }
4577
+ },
4578
+ required: ['data', 'total', 'limit', 'offset']
4579
+ } as const;
4580
+
4581
+ export const $ValidateRuleDto = {
4582
+ type: 'object',
4583
+ properties: {
4584
+ name: {
4505
4585
  type: 'string',
4506
- description: 'Data source filter'
4586
+ minLength: 1,
4587
+ maxLength: 100
4507
4588
  },
4508
- 'filters.symbol': {
4589
+ description: {
4509
4590
  type: 'string',
4510
- description: 'Symbol filter'
4591
+ maxLength: 500
4511
4592
  },
4512
- 'filters.tags': {
4513
- description: 'Tag filters',
4514
- type: 'array',
4593
+ narrationKeywords: {
4515
4594
  items: {
4516
- type: 'string'
4517
- }
4595
+ type: 'array'
4596
+ },
4597
+ maxItems: 50,
4598
+ type: 'array'
4518
4599
  },
4519
- isExperimentalFeatures: {
4520
- type: 'boolean',
4521
- description: 'Enable experimental features'
4600
+ payeeKeywords: {
4601
+ items: {
4602
+ type: 'array'
4603
+ },
4604
+ maxItems: 50,
4605
+ type: 'array'
4522
4606
  },
4523
- isRestrictedView: {
4524
- type: 'boolean',
4525
- description: 'Enable restricted view mode'
4607
+ categoryKeywords: {
4608
+ items: {
4609
+ type: 'array'
4610
+ },
4611
+ maxItems: 50,
4612
+ type: 'array'
4526
4613
  },
4527
- language: {
4614
+ methodKeywords: {
4615
+ items: {
4616
+ type: 'array'
4617
+ },
4618
+ maxItems: 50,
4619
+ description: 'Payment method keywords (e.g., HuaBei, YuEBao)',
4620
+ type: 'array'
4621
+ },
4622
+ categoryAccount: {
4528
4623
  type: 'string',
4529
- description: 'Language code',
4530
- example: 'en'
4624
+ maxLength: 200,
4625
+ description:
4626
+ 'Destination account for expenses/income (e.g., Expenses:Food:Coffee)'
4531
4627
  },
4532
- locale: {
4628
+ matchLogic: {
4533
4629
  type: 'string',
4534
- description: 'Locale code',
4535
- example: 'en-US'
4630
+ enum: ['OR', 'AND'],
4631
+ default: 'OR'
4536
4632
  },
4537
- projectedTotalAmount: {
4633
+ amountMin: {
4538
4634
  type: 'number',
4539
- description: 'Projected total amount',
4540
- example: 1000000
4635
+ minimum: 0,
4636
+ description: 'Minimum transaction amount (inclusive)'
4541
4637
  },
4542
- retirementDate: {
4543
- type: 'string',
4544
- description: 'Retirement date in ISO 8601 format',
4545
- example: '2050-01-01'
4638
+ amountMax: {
4639
+ type: 'number',
4640
+ minimum: 0,
4641
+ description: 'Maximum transaction amount (inclusive)'
4546
4642
  },
4547
- savingsRate: {
4643
+ priority: {
4548
4644
  type: 'number',
4549
- description: 'Savings rate percentage',
4550
- example: 0.2
4645
+ default: 50,
4646
+ minimum: 0,
4647
+ maximum: 1000
4551
4648
  },
4552
- viewMode: {
4553
- type: 'string',
4554
- description: 'View mode',
4555
- enum: ['DEFAULT', 'ZEN']
4649
+ additionalTags: {
4650
+ items: {
4651
+ type: 'array'
4652
+ },
4653
+ maxItems: 20,
4654
+ type: 'array'
4655
+ },
4656
+ additionalMetadata: {
4657
+ type: 'object'
4658
+ },
4659
+ upsertByPayee: {
4660
+ type: 'boolean',
4661
+ description:
4662
+ 'If true, update existing rule with matching payeeKeywords[0] instead of creating new rule'
4556
4663
  }
4557
- }
4664
+ },
4665
+ required: ['name', 'matchLogic', 'priority']
4558
4666
  } as const;
4559
4667
 
4560
- export const $UpdatePropertyDto = {
4668
+ export const $ValidateRuleResponseDto = {
4561
4669
  type: 'object',
4562
4670
  properties: {
4563
- value: {
4564
- type: 'string',
4565
- description: 'Property value'
4671
+ valid: {
4672
+ type: 'boolean',
4673
+ description: 'Whether the rule configuration is valid',
4674
+ example: true
4675
+ },
4676
+ errors: {
4677
+ description: 'List of validation errors (empty if valid)',
4678
+ example: [],
4679
+ items: {
4680
+ type: 'array'
4681
+ },
4682
+ type: 'array'
4683
+ },
4684
+ warnings: {
4685
+ description: 'List of validation warnings (non-blocking issues)',
4686
+ example: [
4687
+ 'No account constraints specified - rule will match any account'
4688
+ ],
4689
+ items: {
4690
+ type: 'array'
4691
+ },
4692
+ type: 'array'
4566
4693
  }
4567
4694
  },
4568
- required: ['value']
4695
+ required: ['valid', 'errors', 'warnings']
4569
4696
  } as const;
4570
4697
 
4571
- export const $CurrencyBalanceDto = {
4698
+ export const $BulkCreateRulesDto = {
4572
4699
  type: 'object',
4573
4700
  properties: {
4574
- currency: {
4575
- type: 'string',
4576
- description: 'ISO 4217 currency code',
4577
- example: 'CNY'
4701
+ rules: {
4702
+ items: {
4703
+ type: 'array'
4704
+ },
4705
+ description: 'Array of rules to import',
4706
+ type: 'array'
4578
4707
  },
4579
- balance: {
4708
+ conflictStrategy: {
4580
4709
  type: 'string',
4581
- description: 'Balance amount',
4582
- example: '500000.00'
4710
+ enum: ['replace', 'skip'],
4711
+ default: 'skip',
4712
+ description:
4713
+ 'Conflict handling strategy: skip (default) ignores duplicates, replace soft-deletes existing rule'
4583
4714
  }
4584
4715
  },
4585
- required: ['currency', 'balance']
4716
+ required: ['rules', 'conflictStrategy']
4586
4717
  } as const;
4587
4718
 
4588
- export const $TimeSeriesPointDto = {
4719
+ export const $BulkCreateRulesResponseDto = {
4589
4720
  type: 'object',
4590
4721
  properties: {
4591
- date: {
4592
- type: 'string',
4593
- description: 'Date in YYYY-MM-DD format',
4594
- example: '2024-06-15'
4595
- },
4596
- value: {
4597
- type: 'string',
4598
- description: 'Value at this date (in base currency)',
4599
- example: '500000.00'
4600
- },
4601
- change: {
4602
- type: 'object',
4603
- description: 'Change from previous point',
4604
- example: '5000.00'
4722
+ successCount: {
4723
+ type: 'number',
4724
+ description: 'Number of successfully created rules'
4605
4725
  },
4606
- assets: {
4607
- type: 'string',
4608
- description: 'Total assets at this date (in base currency)',
4609
- example: '494338.00'
4726
+ failureCount: {
4727
+ type: 'number',
4728
+ description: 'Number of failed rules'
4610
4729
  },
4611
- liabilities: {
4612
- type: 'string',
4613
- description: 'Total liabilities at this date (in base currency)',
4614
- example: '310098.00'
4730
+ errors: {
4731
+ type: 'array',
4732
+ description: 'Error details for failed rules',
4733
+ items: {
4734
+ type: 'object',
4735
+ properties: {
4736
+ index: {
4737
+ type: 'number'
4738
+ },
4739
+ message: {
4740
+ type: 'string'
4741
+ }
4742
+ }
4743
+ }
4615
4744
  },
4616
- byCurrency: {
4617
- description: 'Multi-currency breakdown for this point',
4745
+ createdRuleIds: {
4746
+ description: 'IDs of successfully created rules',
4618
4747
  type: 'array',
4619
4748
  items: {
4620
- $ref: '#/components/schemas/CurrencyBalanceDto'
4749
+ type: 'string'
4621
4750
  }
4622
4751
  }
4623
4752
  },
4624
- required: ['date', 'value']
4753
+ required: ['successCount', 'failureCount', 'errors', 'createdRuleIds']
4625
4754
  } as const;
4626
4755
 
4627
- export const $TrendSummaryDto = {
4756
+ export const $ExportRulesResponseDto = {
4628
4757
  type: 'object',
4629
4758
  properties: {
4630
- startValue: {
4759
+ exportedAt: {
4631
4760
  type: 'string',
4632
- description: 'Value at start of period',
4633
- example: '450000.00'
4761
+ description: 'Export timestamp'
4634
4762
  },
4635
- endValue: {
4763
+ userId: {
4636
4764
  type: 'string',
4637
- description: 'Value at end of period',
4638
- example: '500000.00'
4765
+ description: 'User ID'
4639
4766
  },
4640
- totalChange: {
4641
- type: 'string',
4642
- description: 'Total change over period',
4643
- example: '50000.00'
4767
+ ruleCount: {
4768
+ type: 'number',
4769
+ description: 'Number of exported rules'
4644
4770
  },
4645
- totalChangePercentage: {
4646
- type: 'string',
4647
- description: 'Total change percentage',
4648
- example: '+11.11%'
4771
+ rules: {
4772
+ type: 'array',
4773
+ description: 'Exported rules'
4649
4774
  }
4650
4775
  },
4651
- required: ['startValue', 'endValue', 'totalChange', 'totalChangePercentage']
4776
+ required: ['exportedAt', 'userId', 'ruleCount', 'rules']
4652
4777
  } as const;
4653
4778
 
4654
- export const $MultiCurrencyPointDto = {
4779
+ export const $RuleStatisticsResponseDto = {
4655
4780
  type: 'object',
4656
4781
  properties: {
4657
- date: {
4782
+ period: {
4658
4783
  type: 'string',
4659
- description: 'Date in YYYY-MM-DD format',
4660
- example: '2024-06-15'
4784
+ description: 'Statistics time period',
4785
+ enum: ['7d', '30d', '90d']
4786
+ },
4787
+ totalRules: {
4788
+ type: 'number',
4789
+ description: 'Total number of rules'
4790
+ },
4791
+ rulesWithMatches: {
4792
+ type: 'number',
4793
+ description: 'Number of rules with at least one match'
4794
+ },
4795
+ totalMatches: {
4796
+ type: 'number',
4797
+ description: 'Total number of matches across all rules'
4661
4798
  },
4662
- byCurrency: {
4663
- description: 'Balances by currency',
4799
+ averageConfidence: {
4800
+ type: 'number',
4801
+ description: 'Average confidence score across all matches',
4802
+ example: 0.82
4803
+ },
4804
+ ruleStats: {
4664
4805
  type: 'array',
4806
+ description: 'Per-rule statistics',
4665
4807
  items: {
4666
- $ref: '#/components/schemas/CurrencyBalanceDto'
4808
+ type: 'object',
4809
+ properties: {
4810
+ ruleId: {
4811
+ type: 'string'
4812
+ },
4813
+ ruleName: {
4814
+ type: 'string'
4815
+ },
4816
+ matchCount: {
4817
+ type: 'number'
4818
+ },
4819
+ averageConfidence: {
4820
+ type: 'number'
4821
+ }
4822
+ }
4667
4823
  }
4668
4824
  }
4669
4825
  },
4670
- required: ['date', 'byCurrency']
4826
+ required: [
4827
+ 'period',
4828
+ 'totalRules',
4829
+ 'rulesWithMatches',
4830
+ 'totalMatches',
4831
+ 'averageConfidence',
4832
+ 'ruleStats'
4833
+ ]
4671
4834
  } as const;
4672
4835
 
4673
- export const $PortfolioTrendsResponseDto = {
4836
+ export const $UpdateTransactionRuleDto = {
4674
4837
  type: 'object',
4675
4838
  properties: {
4676
- series: {
4677
- description: 'Time series data points',
4678
- type: 'array',
4839
+ name: {
4840
+ type: 'string',
4841
+ minLength: 1,
4842
+ maxLength: 100
4843
+ },
4844
+ description: {
4845
+ type: 'string',
4846
+ maxLength: 500
4847
+ },
4848
+ narrationKeywords: {
4679
4849
  items: {
4680
- $ref: '#/components/schemas/TimeSeriesPointDto'
4681
- }
4850
+ type: 'array'
4851
+ },
4852
+ maxItems: 50,
4853
+ type: 'array'
4682
4854
  },
4683
- summary: {
4684
- description: 'Period summary',
4685
- allOf: [
4686
- {
4687
- $ref: '#/components/schemas/TrendSummaryDto'
4688
- }
4689
- ]
4855
+ payeeKeywords: {
4856
+ items: {
4857
+ type: 'array'
4858
+ },
4859
+ maxItems: 50,
4860
+ type: 'array'
4690
4861
  },
4691
- period: {
4692
- type: 'string',
4693
- description: 'Period requested',
4694
- example: '6m'
4862
+ categoryKeywords: {
4863
+ items: {
4864
+ type: 'array'
4865
+ },
4866
+ maxItems: 50,
4867
+ type: 'array'
4695
4868
  },
4696
- granularity: {
4869
+ methodKeywords: {
4870
+ items: {
4871
+ type: 'array'
4872
+ },
4873
+ maxItems: 50,
4874
+ description: 'Payment method keywords (e.g., HuaBei, YuEBao)',
4875
+ type: 'array'
4876
+ },
4877
+ categoryAccount: {
4697
4878
  type: 'string',
4698
- description: 'Data granularity',
4699
- example: 'month'
4879
+ maxLength: 200,
4880
+ description:
4881
+ 'Destination account for expenses/income (e.g., Expenses:Food:Coffee)'
4700
4882
  },
4701
- currency: {
4883
+ matchLogic: {
4702
4884
  type: 'string',
4703
- description: 'Base currency for converted values',
4704
- example: 'CNY'
4885
+ enum: ['OR', 'AND']
4705
4886
  },
4706
- byCurrency: {
4707
- description:
4708
- 'Multi-currency time series (each point has currency breakdown)',
4709
- type: 'array',
4710
- items: {
4711
- $ref: '#/components/schemas/MultiCurrencyPointDto'
4712
- }
4887
+ amountMin: {
4888
+ type: 'number',
4889
+ minimum: 0,
4890
+ description: 'Minimum transaction amount (inclusive)'
4713
4891
  },
4714
- warnings: {
4715
- description: 'Exchange rate warnings',
4716
- type: 'array',
4892
+ amountMax: {
4893
+ type: 'number',
4894
+ minimum: 0,
4895
+ description: 'Maximum transaction amount (inclusive)'
4896
+ },
4897
+ priority: {
4898
+ type: 'number',
4899
+ minimum: 0,
4900
+ maximum: 1000
4901
+ },
4902
+ enabled: {
4903
+ type: 'boolean',
4904
+ description: 'Enable or disable the rule'
4905
+ },
4906
+ additionalTags: {
4717
4907
  items: {
4718
- $ref: '#/components/schemas/ExchangeRateWarningDto'
4719
- }
4908
+ type: 'array'
4909
+ },
4910
+ maxItems: 20,
4911
+ type: 'array'
4912
+ },
4913
+ additionalMetadata: {
4914
+ type: 'object'
4720
4915
  }
4721
- },
4722
- required: ['series', 'summary', 'period', 'granularity', 'currency']
4916
+ }
4723
4917
  } as const;
4724
4918
 
4725
- export const $CashFlowPointDto = {
4919
+ export const $TestRuleDto = {
4726
4920
  type: 'object',
4727
4921
  properties: {
4728
- month: {
4922
+ narration: {
4729
4923
  type: 'string',
4730
- description: 'Month key (YYYY-MM)',
4731
- example: '2024-03'
4924
+ minLength: 1,
4925
+ maxLength: 500
4732
4926
  },
4733
- income: {
4927
+ payee: {
4734
4928
  type: 'string',
4735
- description: 'Income in base currency (absolute, converted)',
4736
- example: '10000.00'
4929
+ maxLength: 200
4737
4930
  },
4738
- expense: {
4931
+ categoryAccount: {
4739
4932
  type: 'string',
4740
- description: 'Expense in base currency (absolute, converted)',
4741
- example: '5000.00'
4933
+ maxLength: 200
4742
4934
  },
4743
- netSavings: {
4935
+ amount: {
4936
+ type: 'number'
4937
+ },
4938
+ currency: {
4744
4939
  type: 'string',
4745
- description: 'netSavings = income − expense (savings positive)',
4746
- example: '5000.00'
4940
+ maxLength: 10
4747
4941
  }
4748
4942
  },
4749
- required: ['month', 'income', 'expense', 'netSavings']
4943
+ required: ['narration']
4750
4944
  } as const;
4751
4945
 
4752
- export const $CashFlowTrendSummaryDto = {
4946
+ export const $TestRuleResponseDto = {
4753
4947
  type: 'object',
4754
4948
  properties: {
4755
- totalIncome: {
4949
+ ruleId: {
4756
4950
  type: 'string',
4757
- description: 'Total income across the period',
4758
- example: '60000.00'
4951
+ description: 'Rule ID that was tested'
4759
4952
  },
4760
- totalExpense: {
4761
- type: 'string',
4762
- description: 'Total expense across the period',
4763
- example: '30000.00'
4953
+ matches: {
4954
+ type: 'boolean',
4955
+ description: 'Whether the rule matched the test data'
4764
4956
  },
4765
- totalNetSavings: {
4766
- type: 'string',
4767
- description: 'income − expense across the period',
4768
- example: '30000.00'
4957
+ confidence: {
4958
+ type: 'number',
4959
+ description: 'Match confidence score (0-1)',
4960
+ example: 0.85
4769
4961
  },
4770
- averageMonthlyNetSavings: {
4771
- type: 'string',
4772
- description:
4773
- 'totalNetSavings divided by the window length (N months, incl. zero-filled)',
4774
- example: '5000.00'
4962
+ matchDetails: {
4963
+ type: 'object',
4964
+ description: 'Details of which fields matched',
4965
+ example: {
4966
+ narration: true,
4967
+ payee: false,
4968
+ categoryAccount: false
4969
+ }
4775
4970
  }
4776
4971
  },
4777
- required: [
4778
- 'totalIncome',
4779
- 'totalExpense',
4780
- 'totalNetSavings',
4781
- 'averageMonthlyNetSavings'
4782
- ]
4972
+ required: ['ruleId', 'matches', 'confidence', 'matchDetails']
4783
4973
  } as const;
4784
4974
 
4785
- export const $CashFlowTrendsResponseDto = {
4975
+ export const $CategoryCatalogEntryDto = {
4786
4976
  type: 'object',
4787
4977
  properties: {
4788
- series: {
4789
- description:
4790
- 'Monthly cash-flow series (fixed N-month window, zero-filled)',
4791
- type: 'array',
4792
- items: {
4793
- $ref: '#/components/schemas/CashFlowPointDto'
4794
- }
4795
- },
4796
- summary: {
4797
- description: 'Period totals',
4798
- allOf: [
4799
- {
4800
- $ref: '#/components/schemas/CashFlowTrendSummaryDto'
4801
- }
4802
- ]
4803
- },
4804
- period: {
4978
+ slug: {
4805
4979
  type: 'string',
4806
- description: 'Period requested',
4807
- example: '6m'
4980
+ description: 'Category slug (single source-of-truth)',
4981
+ example: 'food'
4808
4982
  },
4809
- granularity: {
4983
+ scenario: {
4810
4984
  type: 'string',
4811
- description: 'Data granularity (v1 returns month buckets)',
4812
- example: 'month'
4985
+ description: 'Display scenario group (maps to frontend picker _scenario)',
4986
+ enum: [
4987
+ 'expense',
4988
+ 'income',
4989
+ 'investment',
4990
+ 'banking',
4991
+ 'transfer',
4992
+ 'payment'
4993
+ ],
4994
+ example: 'expense'
4813
4995
  },
4814
- currency: {
4996
+ icon: {
4815
4997
  type: 'string',
4816
- description: 'Base currency for converted values',
4817
- example: 'CNY'
4998
+ description: 'Lucide icon name',
4999
+ example: 'utensils'
4818
5000
  },
4819
- warnings: {
4820
- description: 'Exchange rate warnings (e.g. missing rate for a currency)',
5001
+ regions: {
5002
+ description: "Applicable regions ('*' = all, 'cn' = CN-only)",
5003
+ example: ['*'],
5004
+ type: 'array',
5005
+ items: {
5006
+ type: 'string'
5007
+ }
5008
+ }
5009
+ },
5010
+ required: ['slug', 'scenario', 'icon', 'regions']
5011
+ } as const;
5012
+
5013
+ export const $CategoryCatalogListResponseDto = {
5014
+ type: 'object',
5015
+ properties: {
5016
+ items: {
5017
+ description: 'Category entries (region-scoped, query-filtered)',
4821
5018
  type: 'array',
4822
5019
  items: {
4823
- $ref: '#/components/schemas/ExchangeRateWarningDto'
5020
+ $ref: '#/components/schemas/CategoryCatalogEntryDto'
4824
5021
  }
5022
+ },
5023
+ total: {
5024
+ type: 'number',
5025
+ description:
5026
+ 'Total category entries for the region (before query filtering)',
5027
+ example: 30
5028
+ },
5029
+ region: {
5030
+ type: 'string',
5031
+ description: 'Region code',
5032
+ example: 'cn'
4825
5033
  }
4826
5034
  },
4827
- required: ['series', 'summary', 'period', 'granularity', 'currency']
4828
- } as const;
4829
-
4830
- export const $GenerateSnapshotBody = {
4831
- type: 'object',
4832
- properties: {}
4833
- } as const;
4834
-
4835
- export const $GenerateSnapshotResponse = {
4836
- type: 'object',
4837
- properties: {}
4838
- } as const;
4839
-
4840
- export const $BackfillSnapshotsBody = {
4841
- type: 'object',
4842
- properties: {}
4843
- } as const;
4844
-
4845
- export const $BackfillSnapshotsResponse = {
4846
- type: 'object',
4847
- properties: {}
5035
+ required: ['items', 'total', 'region']
4848
5036
  } as const;
4849
5037
 
4850
5038
  export const $CreateBeanEventDto = {
@@ -5589,7 +5777,8 @@ export const $UpdateMapperDefaultsDto = {
5589
5777
  type: 'string',
5590
5778
  description: 'Source account for transactions (Beancount format)',
5591
5779
  example: 'Assets:CN:Alipay:Balance',
5592
- pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
5780
+ pattern:
5781
+ '^(Assets|Liabilities|Income|Expenses|Equity)(:[A-Za-z0-9][A-Za-z0-9-]*)+$'
5593
5782
  },
5594
5783
  currency: {
5595
5784
  type: 'string',
@@ -5603,13 +5792,15 @@ export const $UpdateMapperDefaultsDto = {
5603
5792
  type: 'string',
5604
5793
  description: 'Default expense account (optional)',
5605
5794
  example: 'Expenses:Unknown',
5606
- pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
5795
+ pattern:
5796
+ '^(Assets|Liabilities|Income|Expenses|Equity)(:[A-Za-z0-9][A-Za-z0-9-]*)+$'
5607
5797
  },
5608
5798
  incomeAccount: {
5609
5799
  type: 'string',
5610
5800
  description: 'Default income account (optional)',
5611
5801
  example: 'Income:Unknown',
5612
- pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
5802
+ pattern:
5803
+ '^(Assets|Liabilities|Income|Expenses|Equity)(:[A-Za-z0-9][A-Za-z0-9-]*)+$'
5613
5804
  },
5614
5805
  methodAccountMapping: {
5615
5806
  type: 'object',
@@ -5666,12 +5857,14 @@ export const $ProviderSyncConfigDto = {
5666
5857
  },
5667
5858
  defaultExpenseAccount: {
5668
5859
  type: 'string',
5669
- description: 'Default expense account for the second posting',
5860
+ description:
5861
+ 'Default expense account for the second posting. Omit when no real default exists; the pipeline routes to Review via the Uncategorized sentinel (#618).',
5670
5862
  example: 'Expenses:Unknown'
5671
5863
  },
5672
5864
  defaultIncomeAccount: {
5673
5865
  type: 'string',
5674
- description: 'Default income account for the second posting',
5866
+ description:
5867
+ 'Default income account for the second posting. Omit when no real default exists; the pipeline routes to Review via the Uncategorized sentinel (#618).',
5675
5868
  example: 'Income:Unknown'
5676
5869
  },
5677
5870
  filterPending: {
@@ -5686,12 +5879,7 @@ export const $ProviderSyncConfigDto = {
5686
5879
  example: 'acc_gocardless_001'
5687
5880
  }
5688
5881
  },
5689
- required: [
5690
- 'sourceAccount',
5691
- 'defaultCurrency',
5692
- 'defaultExpenseAccount',
5693
- 'defaultIncomeAccount'
5694
- ]
5882
+ required: ['sourceAccount', 'defaultCurrency']
5695
5883
  } as const;
5696
5884
 
5697
5885
  export const $ProviderSyncDto = {
@@ -5901,15 +6089,105 @@ export const $UncoveredFormatMissDto = {
5901
6089
  properties: {}
5902
6090
  } as const;
5903
6091
 
6092
+ export const $ClientParsedDataDto = {
6093
+ type: 'object',
6094
+ properties: {
6095
+ amount: {
6096
+ type: 'number',
6097
+ description: 'Transaction amount',
6098
+ example: 35
6099
+ },
6100
+ currency: {
6101
+ type: 'string',
6102
+ description: 'Currency code',
6103
+ example: 'CNY'
6104
+ },
6105
+ date: {
6106
+ type: 'string',
6107
+ description: 'Transaction date (ISO 8601)',
6108
+ example: '2026-08-15'
6109
+ },
6110
+ payee: {
6111
+ type: 'string',
6112
+ description: 'Payee/merchant name',
6113
+ example: 'Starbucks'
6114
+ },
6115
+ narration: {
6116
+ type: 'string',
6117
+ description: 'Transaction narration'
6118
+ },
6119
+ category: {
6120
+ type: 'string',
6121
+ description: 'Category slug',
6122
+ example: 'food_restaurant'
6123
+ },
6124
+ incomeType: {
6125
+ type: 'string',
6126
+ description: 'Income type',
6127
+ example: 'Salary'
6128
+ },
6129
+ incomeSource: {
6130
+ type: 'string',
6131
+ description: 'Income source',
6132
+ example: 'Anthropic Inc.'
6133
+ },
6134
+ symbol: {
6135
+ type: 'string',
6136
+ description: 'Security symbol code (e.g., 600519, AAPL)',
6137
+ example: 'AAPL'
6138
+ },
6139
+ quantity: {
6140
+ type: 'number',
6141
+ description: 'Quantity of shares/units',
6142
+ example: 100
6143
+ },
6144
+ price: {
6145
+ type: 'number',
6146
+ description: 'Unit price per share/unit',
6147
+ example: 1900
6148
+ },
6149
+ investmentAction: {
6150
+ type: 'string',
6151
+ description: 'Investment action',
6152
+ enum: ['buy', 'sell'],
6153
+ example: 'buy'
6154
+ },
6155
+ paymentSource: {
6156
+ type: 'string',
6157
+ description: 'Payment source: asset (default) or liability (credit card)',
6158
+ enum: ['asset', 'liability'],
6159
+ example: 'asset'
6160
+ },
6161
+ liabilityHint: {
6162
+ type: 'string',
6163
+ description: 'Liability account hint (CreditCard/Huabei/Baitiao)',
6164
+ example: 'CreditCard'
6165
+ },
6166
+ warning: {
6167
+ type: 'string',
6168
+ description:
6169
+ 'Display-only warning from the prior response; accepted but ignored.',
6170
+ example: 'Cross-currency settlement applies.'
6171
+ }
6172
+ }
6173
+ } as const;
6174
+
5904
6175
  export const $ProcessNlpDto = {
5905
6176
  type: 'object',
5906
6177
  properties: {
5907
6178
  message: {
5908
6179
  type: 'string',
5909
- description: 'Natural language text describing a transaction (Chinese)',
5910
- example: 'yesterday Starbucks spent 35 yuan',
6180
+ description:
6181
+ 'Natural language text describing a transaction. Optional when `confirm` is true (structured confirm); otherwise required.',
6182
+ example: 'Starbucks 35',
5911
6183
  maxLength: 500
5912
6184
  },
6185
+ confirm: {
6186
+ type: 'boolean',
6187
+ description:
6188
+ 'Structured confirm signal — bypasses NL confirm-word matching when true. Send parsedData field edits alongside. The NL word-list path is the fallback.',
6189
+ example: true
6190
+ },
5913
6191
  sessionId: {
5914
6192
  type: 'string',
5915
6193
  description:
@@ -5917,17 +6195,32 @@ export const $ProcessNlpDto = {
5917
6195
  example: 'session_abc123'
5918
6196
  },
5919
6197
  parsedData: {
5920
- type: 'object',
5921
6198
  description:
5922
6199
  'Parsed data from previous NLP response for session recovery. Send back the parsedData received in confirm_payee/confirm responses.',
5923
6200
  example: {
5924
6201
  amount: 35,
5925
6202
  currency: 'CNY',
5926
6203
  payee: 'Starbucks'
5927
- }
6204
+ },
6205
+ allOf: [
6206
+ {
6207
+ $ref: '#/components/schemas/ClientParsedDataDto'
6208
+ }
6209
+ ]
6210
+ },
6211
+ selectedRuleId: {
6212
+ type: 'string',
6213
+ description:
6214
+ 'confirm_rule echo-back: rule id selected from the prior confirm_rule response (matchedRule.id or alternatives[i].ruleId). Applied directly when the session is confirming_rule — no NL re-parse.',
6215
+ example: 'rule_abc123'
6216
+ },
6217
+ selectedAccount: {
6218
+ type: 'string',
6219
+ description:
6220
+ 'confirm_account echo-back: account path selected from the prior confirm_account response (suggestedAccount, similarAccounts[i], or a typed path). Applied directly when the session is confirming_account — no NL re-parse.',
6221
+ example: 'Expenses:Food:Coffee'
5928
6222
  }
5929
- },
5930
- required: ['message']
6223
+ }
5931
6224
  } as const;
5932
6225
 
5933
6226
  export const $NlpTransactionInfoDto = {
@@ -6249,7 +6542,8 @@ export const $NlpAccountConfirmationDataDto = {
6249
6542
  },
6250
6543
  suggestedAccount: {
6251
6544
  type: 'string',
6252
- description: 'Suggested replacement account',
6545
+ description:
6546
+ 'Suggested replacement account (omitted when no clear candidate)',
6253
6547
  example: 'Expenses:Food:Drinks'
6254
6548
  },
6255
6549
  similarAccounts: {
@@ -6271,7 +6565,6 @@ export const $NlpAccountConfirmationDataDto = {
6271
6565
  },
6272
6566
  required: [
6273
6567
  'invalidAccount',
6274
- 'suggestedAccount',
6275
6568
  'similarAccounts',
6276
6569
  'errorMessage',
6277
6570
  'transactionContext'
@@ -6444,7 +6737,8 @@ export const $NlpSuggestedAccountDto = {
6444
6737
  },
6445
6738
  confidence: {
6446
6739
  type: 'number',
6447
- description: 'Confidence score for this suggestion (0-1)',
6740
+ description:
6741
+ 'Confidence score for this suggestion (0-1). Present = predicted (confirm/confirm_rule/confirm_account); omitted = actual persisted account (created). (#586)',
6448
6742
  example: 0.9
6449
6743
  }
6450
6744
  },
@@ -6480,23 +6774,31 @@ export const $NlpDefaultAccountsDto = {
6480
6774
  properties: {
6481
6775
  asset: {
6482
6776
  type: 'string',
6483
- description: 'Default asset account',
6484
- example: 'Assets:Checking'
6777
+ description:
6778
+ 'Default OPEN asset account (MRU when multiple), or null when none/ambiguous',
6779
+ example: 'Assets:Checking',
6780
+ nullable: true
6485
6781
  },
6486
6782
  expense: {
6487
6783
  type: 'string',
6488
- description: 'Default expense account',
6489
- example: 'Expenses:Uncategorized'
6784
+ description:
6785
+ 'Default OPEN expense account (MRU when multiple), or null when none/ambiguous',
6786
+ example: 'Expenses:Food:Coffee',
6787
+ nullable: true
6490
6788
  },
6491
6789
  income: {
6492
6790
  type: 'string',
6493
- description: 'Default income account',
6494
- example: 'Income:Uncategorized'
6791
+ description:
6792
+ 'Default OPEN income account (MRU when multiple), or null when none/ambiguous',
6793
+ example: 'Income:Salary',
6794
+ nullable: true
6495
6795
  },
6496
6796
  liability: {
6497
6797
  type: 'string',
6498
- description: 'Default liability account',
6499
- example: 'Liabilities:CreditCard'
6798
+ description:
6799
+ 'Default OPEN liability account (MRU when multiple), or null when none/ambiguous',
6800
+ example: 'Liabilities:CreditCard',
6801
+ nullable: true
6500
6802
  }
6501
6803
  },
6502
6804
  required: ['asset', 'expense', 'income', 'liability']
@@ -6521,7 +6823,8 @@ export const $NlpResponseDto = {
6521
6823
  'confirm_rule',
6522
6824
  'confirm_account',
6523
6825
  'confirm_payee',
6524
- 'cancel'
6826
+ 'cancel',
6827
+ 'aborted'
6525
6828
  ]
6526
6829
  },
6527
6830
  intent: {
@@ -6535,7 +6838,7 @@ export const $NlpResponseDto = {
6535
6838
  type: 'string',
6536
6839
  description:
6537
6840
  'Asset sub-type (only present when intent is "asset"). Determines which asset-related form to render.',
6538
- enum: ['transfer', 'banking', 'investment'],
6841
+ enum: ['transfer', 'banking', 'investment', 'lend', 'lend_collect'],
6539
6842
  example: 'investment'
6540
6843
  },
6541
6844
  liabilitySubType: {
@@ -6683,7 +6986,7 @@ export const $NlpResponseDto = {
6683
6986
  },
6684
6987
  suggestedAccounts: {
6685
6988
  description:
6686
- 'Suggested accounts for this transaction. Contains recommended source and destination accounts based on the detected intent and rules.',
6989
+ 'Suggested accounts for this transaction (#586). confirm/confirm_rule/confirm_account: predicted (source/destination carry confidence); created: actual persisted accounts (confidence omitted). confirm_account destination is the suggested replacement, never the invalid account.',
6687
6990
  allOf: [
6688
6991
  {
6689
6992
  $ref: '#/components/schemas/NlpSuggestedAccountsDto'
@@ -6692,7 +6995,7 @@ export const $NlpResponseDto = {
6692
6995
  },
6693
6996
  defaultAccounts: {
6694
6997
  description:
6695
- 'Default accounts for the user/region. These are fallback accounts used when no specific suggestion is available.',
6998
+ 'Default fallback accounts for the user/region (#586). v1 returns universal constants; per-user personalization is planned.',
6696
6999
  allOf: [
6697
7000
  {
6698
7001
  $ref: '#/components/schemas/NlpDefaultAccountsDto'
@@ -6738,13 +7041,26 @@ export const $PlatformListItemDto = {
6738
7041
  suggestedSegment: {
6739
7042
  type: 'string',
6740
7043
  description:
6741
- 'Suggested path segment — canonical with first char uppercased (ACC_COMP_NAME_RE)'
7044
+ 'Suggested path segment — canonical PascalCased per hyphen-part, hyphens preserved (e.g. "Apple-Pay")'
6742
7045
  },
6743
7046
  logoUrl: {
6744
7047
  type: 'string',
6745
7048
  description: 'Logo URL',
6746
7049
  nullable: true
6747
7050
  },
7051
+ countryCode: {
7052
+ type: 'string',
7053
+ description: 'ISO 3166-1 alpha-2 (UPPERCASE); null = global platform',
7054
+ example: 'CN',
7055
+ nullable: true
7056
+ },
7057
+ category: {
7058
+ type: 'string',
7059
+ description:
7060
+ 'Region-aware category (institution vocab, e.g. DigitalWallet/Bank). null = no region-aware suggestion; fall back to type.',
7061
+ nullable: true,
7062
+ example: 'DigitalWallet'
7063
+ },
6748
7064
  isBound: {
6749
7065
  type: 'boolean',
6750
7066
  description: 'Whether user has accounts using this platform'
@@ -6758,6 +7074,8 @@ export const $PlatformListItemDto = {
6758
7074
  'canonical',
6759
7075
  'suggestedSegment',
6760
7076
  'logoUrl',
7077
+ 'countryCode',
7078
+ 'category',
6761
7079
  'isBound'
6762
7080
  ]
6763
7081
  } as const;
@@ -6793,13 +7111,26 @@ export const $PlatformMatchResultDto = {
6793
7111
  suggestedSegment: {
6794
7112
  type: 'string',
6795
7113
  description:
6796
- 'Suggested path segment — canonical, already in ACCOUNT_RE format'
7114
+ 'Suggested path segment — canonical PascalCased per hyphen-part, hyphens preserved (e.g. "Apple-Pay")'
6797
7115
  },
6798
7116
  logoUrl: {
6799
7117
  type: 'string',
6800
7118
  description: 'Logo URL',
6801
7119
  nullable: true
6802
7120
  },
7121
+ countryCode: {
7122
+ type: 'string',
7123
+ description: 'ISO 3166-1 alpha-2 (UPPERCASE); null = global platform',
7124
+ example: 'CN',
7125
+ nullable: true
7126
+ },
7127
+ category: {
7128
+ type: 'string',
7129
+ description:
7130
+ 'Region-aware category (institution vocab, e.g. DigitalWallet/Bank). null = no region-aware suggestion; fall back to type.',
7131
+ nullable: true,
7132
+ example: 'DigitalWallet'
7133
+ },
6803
7134
  matchType: {
6804
7135
  type: 'string',
6805
7136
  description: "How this row matched: 'exact' > 'prefix' > 'substring'",
@@ -6813,6 +7144,8 @@ export const $PlatformMatchResultDto = {
6813
7144
  'type',
6814
7145
  'suggestedSegment',
6815
7146
  'logoUrl',
7147
+ 'countryCode',
7148
+ 'category',
6816
7149
  'matchType'
6817
7150
  ]
6818
7151
  } as const;
@@ -8061,3 +8394,146 @@ export const $AnonymousLoginResponseDto = {
8061
8394
  },
8062
8395
  required: ['authToken']
8063
8396
  } as const;
8397
+
8398
+ export const $SymbolSearchResultDto = {
8399
+ type: 'object',
8400
+ properties: {
8401
+ symbol: {
8402
+ type: 'string',
8403
+ example: 'AAPL'
8404
+ },
8405
+ name: {
8406
+ type: 'object',
8407
+ example: 'Apple Inc.',
8408
+ nullable: true
8409
+ },
8410
+ exchange: {
8411
+ type: 'object',
8412
+ example: 'US',
8413
+ nullable: true
8414
+ },
8415
+ assetType: {
8416
+ type: 'object',
8417
+ description: 'OpenBB asset_type (e.g. stock, etf)',
8418
+ example: 'stock',
8419
+ nullable: true
8420
+ },
8421
+ assetClass: {
8422
+ type: 'object',
8423
+ description: 'IGN asset class (region.types.ts ASSET_CLASSES)',
8424
+ example: 'EQUITY',
8425
+ nullable: true
8426
+ },
8427
+ assetSubClass: {
8428
+ type: 'object',
8429
+ description: 'IGN asset sub-class (region.types.ts ASSET_SUB_CLASSES)',
8430
+ example: 'STOCK',
8431
+ nullable: true
8432
+ },
8433
+ currency: {
8434
+ type: 'object',
8435
+ description: 'Trading currency (extra_data or inferred from exchange)',
8436
+ example: 'USD',
8437
+ nullable: true
8438
+ }
8439
+ },
8440
+ required: ['symbol']
8441
+ } as const;
8442
+
8443
+ export const $SymbolQuoteDto = {
8444
+ type: 'object',
8445
+ properties: {
8446
+ symbol: {
8447
+ type: 'string',
8448
+ example: 'AAPL'
8449
+ },
8450
+ name: {
8451
+ type: 'object',
8452
+ example: 'Apple Inc.',
8453
+ nullable: true
8454
+ },
8455
+ exchange: {
8456
+ type: 'object',
8457
+ example: 'US',
8458
+ nullable: true
8459
+ },
8460
+ assetType: {
8461
+ type: 'object',
8462
+ description: 'OpenBB asset_type',
8463
+ example: 'stock',
8464
+ nullable: true
8465
+ },
8466
+ assetClass: {
8467
+ type: 'object',
8468
+ description: 'IGN asset class',
8469
+ example: 'EQUITY',
8470
+ nullable: true
8471
+ },
8472
+ assetSubClass: {
8473
+ type: 'object',
8474
+ description: 'IGN asset sub-class',
8475
+ example: 'STOCK',
8476
+ nullable: true
8477
+ },
8478
+ currency: {
8479
+ type: 'object',
8480
+ description: 'Trading currency (extra_data or inferred from exchange)',
8481
+ example: 'USD',
8482
+ nullable: true
8483
+ },
8484
+ price: {
8485
+ type: 'object',
8486
+ description: 'Latest price (Decimal string)',
8487
+ example: '189.84',
8488
+ nullable: true
8489
+ },
8490
+ priceDate: {
8491
+ type: 'object',
8492
+ description: 'Date the price was observed (ISO yyyy-MM-dd)',
8493
+ example: '2026-08-05',
8494
+ nullable: true
8495
+ },
8496
+ changePercent: {
8497
+ type: 'object',
8498
+ description:
8499
+ 'Change vs previous close, in percentage points (1.7 == 1.7%). openbb stores change_percent as a normalized decimal; this exposes percentage points for frontend convenience.',
8500
+ example: 1.7,
8501
+ nullable: true
8502
+ },
8503
+ prevClose: {
8504
+ type: 'object',
8505
+ description: 'Previous close (Decimal string)',
8506
+ nullable: true
8507
+ },
8508
+ open: {
8509
+ type: 'object',
8510
+ description: 'Day open (Decimal string)',
8511
+ nullable: true
8512
+ },
8513
+ high: {
8514
+ type: 'object',
8515
+ description: 'Day high (Decimal string)',
8516
+ nullable: true
8517
+ },
8518
+ low: {
8519
+ type: 'object',
8520
+ description: 'Day low (Decimal string)',
8521
+ nullable: true
8522
+ },
8523
+ volume: {
8524
+ type: 'object',
8525
+ description: 'Day volume (Decimal string)',
8526
+ nullable: true
8527
+ },
8528
+ yearHigh: {
8529
+ type: 'object',
8530
+ description: '52-week high (Decimal string)',
8531
+ nullable: true
8532
+ },
8533
+ yearLow: {
8534
+ type: 'object',
8535
+ description: '52-week low (Decimal string)',
8536
+ nullable: true
8537
+ }
8538
+ }
8539
+ } as const;