@firela/api-types 0.0.0-canary.e1146c01 → 0.0.0-canary.ebb51de2

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.
@@ -466,6 +466,66 @@ export const $RegionsMetadataResponseDto = {
466
466
  required: ['regions']
467
467
  } as const;
468
468
 
469
+ export const $CostSpecDto = {
470
+ type: 'object',
471
+ properties: {
472
+ mode: {
473
+ type: 'string',
474
+ enum: ['per-unit', 'total', 'date', 'label', 'auto'],
475
+ description: 'Cost specification mode (mirrors engine CostSpec)'
476
+ },
477
+ numberPerUnit: {
478
+ type: 'string',
479
+ description: 'Per-unit cost (required when mode is "per-unit")',
480
+ example: '240'
481
+ },
482
+ totalNumber: {
483
+ type: 'string',
484
+ description: 'Total cost for all units (required when mode is "total")',
485
+ example: '12000'
486
+ },
487
+ currency: {
488
+ type: 'string',
489
+ description: 'Cost currency (required in all modes)',
490
+ example: 'USD'
491
+ },
492
+ date: {
493
+ type: 'string',
494
+ description:
495
+ 'Lot acquisition date, ISO 8601 (required when mode is "date")',
496
+ example: '2024-01-15'
497
+ },
498
+ label: {
499
+ type: 'string',
500
+ description:
501
+ 'Lot label (required when mode is "label"; optional tag in buy modes)'
502
+ },
503
+ merge: {
504
+ type: 'boolean',
505
+ description: 'Merge lots for AVERAGE booking (mode: auto)'
506
+ }
507
+ },
508
+ required: ['mode', 'currency']
509
+ } as const;
510
+
511
+ export const $AmountDto = {
512
+ type: 'object',
513
+ properties: {
514
+ number: {
515
+ type: 'string',
516
+ description:
517
+ 'Amount as decimal string (max 15 integer + 15 decimal digits)',
518
+ example: '170.50'
519
+ },
520
+ currency: {
521
+ type: 'string',
522
+ description: 'Currency/commodity code',
523
+ example: 'USD'
524
+ }
525
+ },
526
+ required: ['number', 'currency']
527
+ } as const;
528
+
469
529
  export const $CreatePostingDto = {
470
530
  type: 'object',
471
531
  properties: {
@@ -495,6 +555,33 @@ export const $CreatePostingDto = {
495
555
  example: {
496
556
  'tax-lot': 'Q1-2024'
497
557
  }
558
+ },
559
+ cost: {
560
+ description:
561
+ 'Cost basis (Beancount `{...}`). Maps to engine costSpec. Required for commodity holdings so they carry a monetary weight that can balance.',
562
+ example: {
563
+ mode: 'per-unit',
564
+ numberPerUnit: '240',
565
+ currency: 'USD'
566
+ },
567
+ allOf: [
568
+ {
569
+ $ref: '#/components/schemas/CostSpecDto'
570
+ }
571
+ ]
572
+ },
573
+ price: {
574
+ description:
575
+ 'Price annotation (Beancount `@...`). Maps to engine price. Used for valuation; cost takes priority for balance weight.',
576
+ example: {
577
+ number: '170',
578
+ currency: 'USD'
579
+ },
580
+ allOf: [
581
+ {
582
+ $ref: '#/components/schemas/AmountDto'
583
+ }
584
+ ]
498
585
  }
499
586
  },
500
587
  required: ['account']
@@ -573,6 +660,32 @@ export const $CreateTransactionDto = {
573
660
  required: ['date', 'narration', 'postings']
574
661
  } as const;
575
662
 
663
+ export const $CostDetailDto = {
664
+ type: 'object',
665
+ properties: {
666
+ number: {
667
+ type: 'string',
668
+ description: 'Per-unit cost basis (mirrors engine Cost.number)',
669
+ example: '240'
670
+ },
671
+ currency: {
672
+ type: 'string',
673
+ description: 'Cost currency',
674
+ example: 'USD'
675
+ },
676
+ date: {
677
+ type: 'string',
678
+ description: 'Lot acquisition date (ISO yyyy-mm-dd)',
679
+ example: '2024-01-15'
680
+ },
681
+ label: {
682
+ type: 'string',
683
+ description: 'Lot label',
684
+ example: 'lot-2024-01'
685
+ }
686
+ }
687
+ } as const;
688
+
576
689
  export const $PostingResponseDto = {
577
690
  type: 'object',
578
691
  properties: {
@@ -591,6 +704,15 @@ export const $PostingResponseDto = {
591
704
  type: 'string',
592
705
  description: 'Currency',
593
706
  example: 'USD'
707
+ },
708
+ cost: {
709
+ description:
710
+ 'Booking-resolved cost (mirrors engine Cost). Undefined when the posting has no cost basis.',
711
+ allOf: [
712
+ {
713
+ $ref: '#/components/schemas/CostDetailDto'
714
+ }
715
+ ]
594
716
  }
595
717
  },
596
718
  required: ['account']
@@ -933,9 +1055,9 @@ export const $PostingDetailDto = {
933
1055
  description: 'Account ID',
934
1056
  example: 'clh1234567890abcdef'
935
1057
  },
936
- accountName: {
1058
+ account: {
937
1059
  type: 'string',
938
- description: 'Account name',
1060
+ description: 'Fully-qualified Beancount account path',
939
1061
  example: 'Assets:Bank:Checking'
940
1062
  },
941
1063
  units: {
@@ -964,6 +1086,15 @@ export const $PostingDetailDto = {
964
1086
  description: 'Cost date',
965
1087
  example: '2024-01-15'
966
1088
  },
1089
+ cost: {
1090
+ description:
1091
+ 'Booking-resolved cost (mirrors engine Cost). Undefined when the posting has no cost basis.',
1092
+ allOf: [
1093
+ {
1094
+ $ref: '#/components/schemas/CostDetailDto'
1095
+ }
1096
+ ]
1097
+ },
967
1098
  priceAmount: {
968
1099
  type: 'string',
969
1100
  description: 'Price amount',
@@ -984,7 +1115,7 @@ export const $PostingDetailDto = {
984
1115
  description: 'Posting metadata'
985
1116
  }
986
1117
  },
987
- required: ['id', 'accountId', 'accountName']
1118
+ required: ['id', 'accountId', 'account']
988
1119
  } as const;
989
1120
 
990
1121
  export const $TransactionDetailDto = {
@@ -4780,49 +4911,6 @@ export const $ProviderSyncDto = {
4780
4911
  required: ['config', 'transactions']
4781
4912
  } as const;
4782
4913
 
4783
- export const $ProviderSyncResponseDto = {
4784
- type: 'object',
4785
- properties: {
4786
- imported: {
4787
- type: 'number',
4788
- description: 'Number of transactions successfully imported',
4789
- example: 10
4790
- },
4791
- skipped: {
4792
- type: 'number',
4793
- description: 'Number of transactions skipped (duplicates)',
4794
- example: 2
4795
- },
4796
- pendingReview: {
4797
- type: 'number',
4798
- description: 'Number of transactions pending review',
4799
- example: 3
4800
- },
4801
- failed: {
4802
- type: 'number',
4803
- description: 'Number of transactions that failed to import',
4804
- example: 0
4805
- },
4806
- importedTransactionIds: {
4807
- description: 'IDs of successfully imported transactions',
4808
- example: ['txn-001', 'txn-002'],
4809
- type: 'array',
4810
- items: {
4811
- type: 'string'
4812
- }
4813
- },
4814
- reviewItemIds: {
4815
- description: 'IDs of review items created for branched transactions',
4816
- example: ['review-001', 'review-002'],
4817
- type: 'array',
4818
- items: {
4819
- type: 'string'
4820
- }
4821
- }
4822
- },
4823
- required: ['imported', 'skipped', 'pendingReview', 'failed']
4824
- } as const;
4825
-
4826
4914
  export const $SupportedProvidersResponseDto = {
4827
4915
  type: 'object',
4828
4916
  properties: {
@@ -4852,6 +4940,11 @@ export const $ParserTelemetryReportDto = {
4852
4940
  properties: {}
4853
4941
  } as const;
4854
4942
 
4943
+ export const $UncoveredFormatMissDto = {
4944
+ type: 'object',
4945
+ properties: {}
4946
+ } as const;
4947
+
4855
4948
  export const $ProcessNlpDto = {
4856
4949
  type: 'object',
4857
4950
  properties: {
@@ -4881,825 +4974,599 @@ export const $ProcessNlpDto = {
4881
4974
  required: ['message']
4882
4975
  } as const;
4883
4976
 
4884
- export const $NlpTransactionInfoDto = {
4977
+ export const $BalanceByCurrencyDto = {
4885
4978
  type: 'object',
4886
4979
  properties: {
4887
- id: {
4888
- type: 'string',
4889
- description: 'Transaction ID'
4890
- },
4891
- date: {
4892
- type: 'string',
4893
- description: 'Transaction date (ISO format)'
4894
- },
4895
- amount: {
4896
- type: 'number',
4897
- description: 'Transaction amount'
4898
- },
4899
4980
  currency: {
4900
4981
  type: 'string',
4901
- description: 'Currency code'
4902
- },
4903
- payee: {
4904
- type: 'string',
4905
- description: 'Payee name'
4906
- },
4907
- narration: {
4908
- type: 'string',
4909
- description: 'Transaction narration'
4982
+ description: 'ISO 4217 currency code',
4983
+ example: 'CNY'
4910
4984
  },
4911
- warning: {
4985
+ balance: {
4912
4986
  type: 'string',
4913
- description:
4914
- 'Warning message for special transaction scenarios (e.g., cross-currency settlement)',
4915
- example: '此交易使用USD账户结算。如需记录CNY支出,请创建货币转换交易。'
4987
+ description: 'Balance amount',
4988
+ example: '50000.00'
4916
4989
  }
4917
4990
  },
4918
- required: ['id', 'date', 'amount', 'currency']
4991
+ required: ['currency', 'balance']
4919
4992
  } as const;
4920
4993
 
4921
- export const $NlpParsedDataDto = {
4994
+ export const $NetWorthByCurrencyDto = {
4922
4995
  type: 'object',
4923
4996
  properties: {
4924
- amount: {
4925
- type: 'number',
4926
- description: 'Extracted amount'
4927
- },
4928
- currency: {
4929
- type: 'string',
4930
- description: 'Currency code',
4931
- default: 'CNY'
4932
- },
4933
- date: {
4934
- type: 'string',
4935
- description: 'Transaction date (ISO format)'
4936
- },
4937
- payee: {
4938
- type: 'string',
4939
- description: 'Payee name'
4940
- },
4941
- narration: {
4942
- type: 'string',
4943
- description: 'Transaction narration'
4944
- },
4945
- category: {
4946
- type: 'string',
4947
- description: 'Category'
4948
- },
4949
- incomeType: {
4950
- type: 'string',
4951
- description: 'Income type (e.g., Salary, Bonus, Dividend, Interest)',
4952
- example: 'Salary'
4997
+ netWorth: {
4998
+ description: 'Net worth by currency',
4999
+ type: 'array',
5000
+ items: {
5001
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
5002
+ }
4953
5003
  },
4954
- incomeSource: {
4955
- type: 'string',
4956
- description: 'Income source (e.g., company name)',
4957
- example: 'Anthropic Inc.'
5004
+ assets: {
5005
+ description: 'Assets by currency',
5006
+ type: 'array',
5007
+ items: {
5008
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
5009
+ }
4958
5010
  },
4959
- symbol: {
5011
+ liabilities: {
5012
+ description: 'Liabilities by currency',
5013
+ type: 'array',
5014
+ items: {
5015
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
5016
+ }
5017
+ }
5018
+ },
5019
+ required: ['netWorth', 'assets', 'liabilities']
5020
+ } as const;
5021
+
5022
+ export const $ConvertedNetWorthDto = {
5023
+ type: 'object',
5024
+ properties: {
5025
+ baseCurrency: {
4960
5026
  type: 'string',
4961
- description: 'Security symbol code (e.g., 600519, AAPL)',
4962
- example: '600519'
4963
- },
4964
- quantity: {
4965
- type: 'number',
4966
- description: 'Quantity of shares/units',
4967
- example: 100
4968
- },
4969
- price: {
4970
- type: 'number',
4971
- description: 'Unit price per share/unit',
4972
- example: 1900
5027
+ description: 'Base currency for conversion',
5028
+ example: 'CNY'
4973
5029
  },
4974
- investmentAction: {
5030
+ netWorth: {
4975
5031
  type: 'string',
4976
- description: 'Investment action',
4977
- enum: ['buy', 'sell'],
4978
- example: 'buy'
5032
+ description: 'Converted net worth',
5033
+ example: '500000.00'
4979
5034
  },
4980
- paymentSource: {
5035
+ assets: {
4981
5036
  type: 'string',
4982
- description: 'Payment source: asset (default) or liability (credit card)',
4983
- enum: ['asset', 'liability'],
4984
- example: 'asset'
5037
+ description: 'Converted assets',
5038
+ example: '600000.00'
4985
5039
  },
4986
- liabilityHint: {
5040
+ liabilities: {
4987
5041
  type: 'string',
4988
- description: 'Liability account hint (CreditCard/Huabei/Baitiao)',
4989
- example: 'CreditCard'
5042
+ description: 'Converted liabilities',
5043
+ example: '100000.00'
4990
5044
  },
4991
- warning: {
4992
- type: 'string',
4993
- description:
4994
- 'Warning message for special scenarios (e.g., cross-currency settlement)',
4995
- example: '此交易使用USD账户结算。如需记录CNY支出,请创建货币转换交易。'
5045
+ exchangeRates: {
5046
+ type: 'object',
5047
+ description: 'Exchange rates used for conversion',
5048
+ example: {
5049
+ USD: '7.200000',
5050
+ EUR: '7.800000'
5051
+ }
4996
5052
  }
4997
- }
5053
+ },
5054
+ required: [
5055
+ 'baseCurrency',
5056
+ 'netWorth',
5057
+ 'assets',
5058
+ 'liabilities',
5059
+ 'exchangeRates'
5060
+ ]
4998
5061
  } as const;
4999
5062
 
5000
- export const $NlpSourceTransactionDto = {
5063
+ export const $ExchangeRateWarningDto = {
5001
5064
  type: 'object',
5002
5065
  properties: {
5003
- date: {
5004
- type: 'string',
5005
- description: 'Transaction date (ISO format)'
5006
- },
5007
- amount: {
5066
+ type: {
5008
5067
  type: 'string',
5009
- description: 'Amount as string'
5068
+ description: 'Warning type',
5069
+ example: 'MISSING_EXCHANGE_RATE'
5010
5070
  },
5011
5071
  currency: {
5012
5072
  type: 'string',
5013
- description: 'Currency code'
5014
- },
5015
- payee: {
5016
- type: 'string',
5017
- description: 'Payee name'
5073
+ description: 'Currency without exchange rate',
5074
+ example: 'EUR'
5018
5075
  },
5019
- narration: {
5076
+ totalAmount: {
5020
5077
  type: 'string',
5021
- description: 'Transaction narration'
5078
+ description: 'Total amount affected',
5079
+ example: '1000.00'
5022
5080
  }
5023
5081
  },
5024
- required: ['date', 'amount', 'currency', 'narration']
5082
+ required: ['type', 'currency', 'totalAmount']
5025
5083
  } as const;
5026
5084
 
5027
- export const $NlpTargetTransactionDto = {
5085
+ export const $NetWorthResponseDto = {
5028
5086
  type: 'object',
5029
5087
  properties: {
5030
- id: {
5088
+ netWorth: {
5031
5089
  type: 'string',
5032
- description: 'Existing transaction ID'
5090
+ description:
5091
+ 'Total net worth (assets - liabilities, converted to base currency)',
5092
+ example: '500000.00'
5033
5093
  },
5034
- date: {
5094
+ assets: {
5035
5095
  type: 'string',
5036
- description: 'Transaction date (ISO format)'
5096
+ description: 'Total assets value (converted)',
5097
+ example: '600000.00'
5037
5098
  },
5038
- amount: {
5099
+ liabilities: {
5039
5100
  type: 'string',
5040
- description: 'Amount as string'
5101
+ description: 'Total liabilities value (positive number, converted)',
5102
+ example: '100000.00'
5041
5103
  },
5042
- currency: {
5104
+ monthlyReturn: {
5043
5105
  type: 'string',
5044
- description: 'Currency code'
5106
+ description: 'Monthly return (change from last month)',
5107
+ example: '15000.00'
5045
5108
  },
5046
- payee: {
5109
+ monthlyReturnPercentage: {
5047
5110
  type: 'string',
5048
- description: 'Payee name'
5111
+ description: 'Monthly return percentage',
5112
+ example: '3.15'
5049
5113
  },
5050
- narration: {
5114
+ currency: {
5051
5115
  type: 'string',
5052
- description: 'Transaction narration'
5053
- }
5054
- },
5055
- required: ['id', 'date', 'amount', 'currency', 'narration']
5056
- } as const;
5057
-
5058
- export const $NlpSimilarityDto = {
5059
- type: 'object',
5060
- properties: {
5061
- dateMatch: {
5062
- type: 'boolean',
5063
- description: 'Whether dates match'
5064
- },
5065
- dateDiff: {
5066
- type: 'number',
5067
- description: 'Date difference in days'
5068
- },
5069
- amountMatch: {
5070
- type: 'boolean',
5071
- description: 'Whether amounts match'
5116
+ description: 'Base currency code',
5117
+ example: 'CNY'
5072
5118
  },
5073
- amountDiff: {
5119
+ asOf: {
5074
5120
  type: 'string',
5075
- description: 'Amount difference as decimal string'
5076
- },
5077
- payeeMatch: {
5078
- type: 'boolean',
5079
- description: 'Whether payees match'
5080
- },
5081
- payeeSimilarity: {
5082
- type: 'number',
5083
- description: 'Payee similarity score (0-1)'
5084
- },
5085
- accountOverlap: {
5086
- type: 'number',
5087
- description: 'Account overlap score (0-1)'
5088
- }
5089
- },
5090
- required: [
5091
- 'dateMatch',
5092
- 'dateDiff',
5093
- 'amountMatch',
5094
- 'amountDiff',
5095
- 'payeeMatch',
5096
- 'payeeSimilarity',
5097
- 'accountOverlap'
5098
- ]
5099
- } as const;
5100
-
5101
- export const $NlpDuplicateConfirmationDataDto = {
5102
- type: 'object',
5103
- properties: {
5104
- confidence: {
5105
- type: 'number',
5106
- description: 'Duplicate detection confidence score (0.5-0.89)',
5107
- example: 0.85
5108
- },
5109
- sourceTransaction: {
5110
- description:
5111
- 'Source transaction summary (the new transaction being entered)',
5112
- allOf: [
5113
- {
5114
- $ref: '#/components/schemas/NlpSourceTransactionDto'
5115
- }
5116
- ]
5121
+ description: 'Data as of date (ISO 8601)',
5122
+ example: '2024-06-15T00:00:00.000Z'
5117
5123
  },
5118
- targetTransaction: {
5119
- description: 'Target transaction summary (existing potential duplicate)',
5124
+ byCurrency: {
5125
+ description: 'Balances grouped by original currency',
5120
5126
  allOf: [
5121
5127
  {
5122
- $ref: '#/components/schemas/NlpTargetTransactionDto'
5128
+ $ref: '#/components/schemas/NetWorthByCurrencyDto'
5123
5129
  }
5124
5130
  ]
5125
5131
  },
5126
- similarity: {
5127
- description: 'Detailed similarity information',
5132
+ converted: {
5133
+ description:
5134
+ 'Converted values in base currency (undefined if no exchange rates available)',
5128
5135
  allOf: [
5129
5136
  {
5130
- $ref: '#/components/schemas/NlpSimilarityDto'
5137
+ $ref: '#/components/schemas/ConvertedNetWorthDto'
5131
5138
  }
5132
5139
  ]
5133
5140
  },
5134
- reasons: {
5135
- description: 'Human-readable reasons for duplicate detection',
5136
- example: ['日期匹配', '金额匹配', '商户相似'],
5137
- type: 'array',
5138
- items: {
5139
- type: 'string'
5140
- }
5141
- }
5142
- },
5143
- required: [
5144
- 'confidence',
5145
- 'sourceTransaction',
5146
- 'targetTransaction',
5147
- 'similarity',
5148
- 'reasons'
5149
- ]
5150
- } as const;
5151
-
5152
- export const $NlpRuleConfirmationDataDto = {
5153
- type: 'object',
5154
- properties: {
5155
- confidence: {
5156
- type: 'number',
5157
- description: 'Rule match confidence score (0.5-0.74)',
5158
- example: 0.65
5159
- },
5160
- matchedRule: {
5161
- type: 'object',
5162
- description: 'Matched rule information'
5163
- },
5164
- suggestedAccounts: {
5165
- type: 'object',
5166
- description: 'Suggested accounts from the rule'
5167
- },
5168
- alternatives: {
5169
- type: 'array',
5170
- description: 'Alternative rules that also match'
5171
- },
5172
- reasons: {
5173
- description: 'Human-readable reasons for the match',
5174
- example: [
5175
- 'Moderate confidence (65%)',
5176
- 'Some keywords matched (OR logic)'
5177
- ],
5141
+ warnings: {
5142
+ description: 'Exchange rate warnings',
5178
5143
  type: 'array',
5179
5144
  items: {
5180
- type: 'string'
5145
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
5181
5146
  }
5182
5147
  }
5183
5148
  },
5184
5149
  required: [
5185
- 'confidence',
5186
- 'matchedRule',
5187
- 'suggestedAccounts',
5188
- 'alternatives',
5189
- 'reasons'
5150
+ 'netWorth',
5151
+ 'assets',
5152
+ 'liabilities',
5153
+ 'monthlyReturn',
5154
+ 'monthlyReturnPercentage',
5155
+ 'currency',
5156
+ 'asOf'
5190
5157
  ]
5191
5158
  } as const;
5192
5159
 
5193
- export const $NlpAccountConfirmationDataDto = {
5160
+ export const $AccountItemDto = {
5194
5161
  type: 'object',
5195
5162
  properties: {
5196
- invalidAccount: {
5163
+ id: {
5197
5164
  type: 'string',
5198
- description: 'The invalid account name',
5199
- example: 'Expenses:Food:Coffee'
5165
+ description: 'Account ID'
5200
5166
  },
5201
- suggestedAccount: {
5167
+ name: {
5202
5168
  type: 'string',
5203
- description: 'Suggested replacement account',
5204
- example: 'Expenses:Food:Drinks'
5169
+ description: 'Full account name',
5170
+ example: 'Assets:Bank:CMB:Savings'
5205
5171
  },
5206
- similarAccounts: {
5207
- description: 'Similar accounts for user selection',
5208
- type: 'array',
5209
- items: {
5210
- type: 'string'
5211
- }
5172
+ displayName: {
5173
+ type: 'string',
5174
+ description: 'Display name (last part of account path)',
5175
+ example: 'Savings'
5212
5176
  },
5213
- errorMessage: {
5177
+ balance: {
5214
5178
  type: 'string',
5215
- description: 'Error message explaining the issue',
5216
- example: 'No similar account found'
5179
+ description: 'Account balance',
5180
+ example: '50000.00'
5217
5181
  },
5218
- transactionContext: {
5219
- type: 'object',
5220
- description: 'Transaction context for reference'
5182
+ currency: {
5183
+ type: 'string',
5184
+ description: 'Currency code',
5185
+ example: 'CNY'
5221
5186
  }
5222
5187
  },
5223
- required: [
5224
- 'invalidAccount',
5225
- 'suggestedAccount',
5226
- 'similarAccounts',
5227
- 'errorMessage',
5228
- 'transactionContext'
5229
- ]
5188
+ required: ['id', 'name', 'displayName', 'balance', 'currency']
5230
5189
  } as const;
5231
5190
 
5232
- export const $NlpSuggestedPayeeDto = {
5191
+ export const $PlatformGroupDto = {
5233
5192
  type: 'object',
5234
5193
  properties: {
5235
- id: {
5236
- type: 'string',
5237
- description: 'Payee ID',
5238
- example: 'payee-123'
5239
- },
5240
- name: {
5194
+ platformId: {
5241
5195
  type: 'string',
5242
- description: 'Payee name',
5243
- example: 'Starbucks'
5196
+ description: 'Platform ID'
5244
5197
  },
5245
- category: {
5198
+ platformName: {
5246
5199
  type: 'string',
5247
- description: 'Payee category',
5248
- example: 'food'
5200
+ description: 'Platform display name',
5201
+ example: 'CMB Bank'
5249
5202
  },
5250
- source: {
5251
- type: 'string',
5252
- description: 'Source of the payee',
5253
- enum: ['user', 'global']
5203
+ accounts: {
5204
+ description: 'Accounts within this platform',
5205
+ type: 'array',
5206
+ items: {
5207
+ $ref: '#/components/schemas/AccountItemDto'
5208
+ }
5254
5209
  },
5255
- payeeProfileId: {
5210
+ totalBalance: {
5256
5211
  type: 'string',
5257
- description: 'PayeeProfile ID (if matched from global)',
5258
- example: 'profile-456'
5212
+ description: 'Total balance across all accounts in platform',
5213
+ example: '100000.00'
5259
5214
  }
5260
5215
  },
5261
- required: ['id', 'name']
5216
+ required: ['platformId', 'platformName', 'accounts', 'totalBalance']
5262
5217
  } as const;
5263
5218
 
5264
- export const $NlpAlternativePayeeDto = {
5219
+ export const $AccountsSummaryDto = {
5265
5220
  type: 'object',
5266
5221
  properties: {
5267
- id: {
5268
- type: 'string',
5269
- description: 'Payee ID',
5270
- example: 'payee-alt-1'
5271
- },
5272
- name: {
5273
- type: 'string',
5274
- description: 'Payee name',
5275
- example: 'Starbucks Coffee'
5222
+ totalAccounts: {
5223
+ type: 'number',
5224
+ description: 'Total number of accounts'
5276
5225
  },
5277
- similarity: {
5226
+ totalPlatforms: {
5278
5227
  type: 'number',
5279
- description: 'Similarity score (0-1)',
5280
- example: 0.75
5228
+ description: 'Total number of platforms'
5281
5229
  }
5282
5230
  },
5283
- required: ['id', 'name', 'similarity']
5231
+ required: ['totalAccounts', 'totalPlatforms']
5284
5232
  } as const;
5285
5233
 
5286
- export const $NlpPayeeConfirmationDataDto = {
5234
+ export const $AccountsResponseDto = {
5287
5235
  type: 'object',
5288
5236
  properties: {
5289
- confidence: {
5290
- type: 'number',
5291
- description: 'Confidence score for the payee match (0-1)',
5292
- example: 0.65
5293
- },
5294
- originalPayee: {
5295
- type: 'string',
5296
- description: 'Original payee string from user input',
5297
- example: '星巴'
5237
+ groups: {
5238
+ description: 'Account groups by platform',
5239
+ type: 'array',
5240
+ items: {
5241
+ $ref: '#/components/schemas/PlatformGroupDto'
5242
+ }
5298
5243
  },
5299
- suggestedPayee: {
5300
- description: 'Suggested payee to use (null when no similar payees found)',
5301
- nullable: true,
5244
+ summary: {
5245
+ description: 'Summary statistics',
5302
5246
  allOf: [
5303
5247
  {
5304
- $ref: '#/components/schemas/NlpSuggestedPayeeDto'
5248
+ $ref: '#/components/schemas/AccountsSummaryDto'
5305
5249
  }
5306
5250
  ]
5307
- },
5308
- similarity: {
5309
- type: 'number',
5310
- description: 'Similarity score between original and suggested (0-1)',
5311
- example: 0.85
5312
- },
5313
- alternatives: {
5314
- description: 'Alternative payee options',
5315
- type: 'array',
5316
- items: {
5317
- $ref: '#/components/schemas/NlpAlternativePayeeDto'
5318
- }
5319
- },
5320
- reasons: {
5321
- description: 'Human-readable reasons for the match',
5322
- example: ['Moderate similarity (65%)', 'Fuzzy match on name'],
5323
- type: 'array',
5324
- items: {
5325
- type: 'string'
5326
- }
5327
5251
  }
5328
5252
  },
5329
- required: [
5330
- 'confidence',
5331
- 'originalPayee',
5332
- 'similarity',
5333
- 'alternatives',
5334
- 'reasons'
5335
- ]
5253
+ required: ['groups', 'summary']
5336
5254
  } as const;
5337
5255
 
5338
- export const $RecurringMatchInfoDto = {
5256
+ export const $AccountItemWithAssetClassDto = {
5339
5257
  type: 'object',
5340
5258
  properties: {
5341
- expectedId: {
5259
+ id: {
5342
5260
  type: 'string',
5343
- description: 'Expected transaction ID'
5261
+ description: 'Account ID'
5344
5262
  },
5345
- ruleId: {
5263
+ name: {
5346
5264
  type: 'string',
5347
- description: 'Recurring rule ID'
5265
+ description: 'Full account name',
5266
+ example: 'Assets:Bank:CMB:Savings'
5348
5267
  },
5349
- ruleName: {
5268
+ displayName: {
5350
5269
  type: 'string',
5351
- description: 'Rule name for display'
5270
+ description: 'Display name (last part of account path)',
5271
+ example: 'Savings'
5352
5272
  },
5353
- ruleIcon: {
5273
+ balance: {
5354
5274
  type: 'string',
5355
- description: 'Rule icon'
5275
+ description: 'Account balance',
5276
+ example: '50000.00'
5356
5277
  },
5357
- expectedDate: {
5278
+ currency: {
5358
5279
  type: 'string',
5359
- description: 'Expected date (YYYY-MM-DD)',
5360
- example: '2026-01-05'
5280
+ description: 'Currency code',
5281
+ example: 'CNY'
5361
5282
  },
5362
- expectedAmount: {
5363
- type: 'number',
5364
- description: 'Expected amount',
5365
- example: 3000
5283
+ assetClass: {
5284
+ type: 'string',
5285
+ description: 'Asset class',
5286
+ example: 'LIQUIDITY'
5366
5287
  },
5367
- confidence: {
5368
- type: 'number',
5369
- description: 'Match confidence score (0-1)',
5370
- example: 0.88
5288
+ assetSubClass: {
5289
+ type: 'string',
5290
+ description: 'Asset sub-class (Prisma-compatible)',
5291
+ example: 'RETIREMENT_ACCOUNT'
5371
5292
  },
5372
- isAutoMatched: {
5373
- type: 'boolean',
5374
- description: 'Whether auto-matched (confidence >= 0.82)'
5375
- }
5376
- },
5377
- required: [
5378
- 'expectedId',
5379
- 'ruleId',
5380
- 'ruleName',
5381
- 'expectedDate',
5382
- 'expectedAmount',
5383
- 'confidence',
5384
- 'isAutoMatched'
5385
- ]
5386
- } as const;
5387
-
5388
- export const $NlpSuggestedAccountDto = {
5389
- type: 'object',
5390
- properties: {
5391
- account: {
5293
+ regionalSubClass: {
5392
5294
  type: 'string',
5393
- description: 'Suggested account path',
5394
- example: 'Assets:Bank:Checking'
5295
+ description: 'Regional sub-class (region-specific, for display)',
5296
+ example: 'FOUR_ZERO_ONE_K'
5395
5297
  },
5396
- confidence: {
5397
- type: 'number',
5398
- description: 'Confidence score for this suggestion (0-1)',
5399
- example: 0.9
5400
- }
5401
- },
5402
- required: ['account']
5403
- } as const;
5404
-
5405
- export const $NlpSuggestedAccountsDto = {
5406
- type: 'object',
5407
- properties: {
5408
- source: {
5409
- description:
5410
- 'Source account suggestion (where money comes from). For expense: asset/liability account. For income: income account.',
5411
- allOf: [
5412
- {
5413
- $ref: '#/components/schemas/NlpSuggestedAccountDto'
5414
- }
5415
- ]
5298
+ riskLevel: {
5299
+ type: 'string',
5300
+ description: 'Risk level',
5301
+ example: 'LOW'
5416
5302
  },
5417
- destination: {
5303
+ source: {
5304
+ type: 'string',
5418
5305
  description:
5419
- 'Destination account suggestion (where money goes to). For expense: expense account. For income: asset/liability account.',
5420
- allOf: [
5421
- {
5422
- $ref: '#/components/schemas/NlpSuggestedAccountDto'
5423
- }
5424
- ]
5306
+ 'ADR-0105 classification provenance (holding level always; account level only on FALLBACK)',
5307
+ enum: ['USER_META', 'FIAT_CURRENCY', 'OPENBB_MAPPING', 'FALLBACK']
5425
5308
  }
5426
- }
5309
+ },
5310
+ required: ['id', 'name', 'displayName', 'balance', 'currency', 'assetClass']
5427
5311
  } as const;
5428
5312
 
5429
- export const $NlpDefaultAccountsDto = {
5313
+ export const $AssetClassGroupDto = {
5430
5314
  type: 'object',
5431
5315
  properties: {
5432
- asset: {
5316
+ assetClass: {
5433
5317
  type: 'string',
5434
- description: 'Default asset account',
5435
- example: 'Assets:Bank:Checking'
5318
+ description: 'Asset class name',
5319
+ example: 'LIQUIDITY',
5320
+ enum: [
5321
+ 'LIQUIDITY',
5322
+ 'EQUITY',
5323
+ 'FIXED_INCOME',
5324
+ 'PRECIOUS_METALS',
5325
+ 'COMMODITY',
5326
+ 'INSURANCE',
5327
+ 'ALTERNATIVE_INVESTMENT',
5328
+ 'PERSONAL_ASSETS',
5329
+ 'LIABILITY',
5330
+ 'REAL_ESTATE',
5331
+ 'INDEX'
5332
+ ]
5436
5333
  },
5437
- expense: {
5334
+ assetSubClass: {
5438
5335
  type: 'string',
5439
- description: 'Default expense account',
5440
- example: 'Expenses:Uncategorized'
5336
+ description: 'Asset sub-class name',
5337
+ example: 'DEPOSIT'
5441
5338
  },
5442
- income: {
5443
- type: 'string',
5444
- description: 'Default income account',
5445
- example: 'Income:Uncategorized'
5339
+ accounts: {
5340
+ description: 'Accounts within this asset class',
5341
+ type: 'array',
5342
+ items: {
5343
+ $ref: '#/components/schemas/AccountItemWithAssetClassDto'
5344
+ }
5345
+ },
5346
+ balanceByCurrency: {
5347
+ description: 'Balances grouped by currency',
5348
+ type: 'array',
5349
+ items: {
5350
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
5351
+ }
5446
5352
  },
5447
- liability: {
5353
+ convertedBalance: {
5448
5354
  type: 'string',
5449
- description: 'Default liability account',
5450
- example: 'Liabilities:CreditCard'
5355
+ description: 'Converted balance in base currency',
5356
+ example: '100000.00'
5451
5357
  }
5452
5358
  },
5453
- required: ['asset', 'expense', 'income', 'liability']
5359
+ required: ['assetClass', 'accounts', 'balanceByCurrency']
5454
5360
  } as const;
5455
5361
 
5456
- export const $NlpResponseDto = {
5362
+ export const $AccountExchangeRateWarningDto = {
5457
5363
  type: 'object',
5458
5364
  properties: {
5459
- status: {
5460
- type: 'string',
5461
- description: 'Response status',
5462
- enum: ['success', 'pending', 'error']
5463
- },
5464
- action: {
5465
- type: 'string',
5466
- description: 'Action taken or requested',
5467
- enum: [
5468
- 'created',
5469
- 'ask',
5470
- 'confirm',
5471
- 'confirm_duplicate',
5472
- 'confirm_rule',
5473
- 'confirm_account',
5474
- 'confirm_payee',
5475
- 'cancel'
5476
- ]
5477
- },
5478
- intent: {
5479
- type: 'string',
5480
- description:
5481
- 'Transaction intent detected by EntityRouter (v6.0: 5 core intents). Frontend uses this to render scenario-specific form fields.',
5482
- enum: ['expense', 'asset', 'income', 'liability', 'equity'],
5483
- example: 'expense'
5484
- },
5485
- assetSubType: {
5365
+ type: {
5486
5366
  type: 'string',
5487
- description:
5488
- 'Asset sub-type (only present when intent is "asset"). Determines which asset-related form to render.',
5489
- enum: ['transfer', 'banking', 'investment'],
5490
- example: 'investment'
5367
+ description: 'Warning type',
5368
+ example: 'MISSING_EXCHANGE_RATE'
5491
5369
  },
5492
- liabilitySubType: {
5370
+ currency: {
5493
5371
  type: 'string',
5494
- description:
5495
- 'Liability sub-type (only present when intent is "liability"). borrow: borrowing money (Liabilities → Assets), repay: repaying debt (Assets → Liabilities).',
5496
- enum: ['borrow', 'repay'],
5497
- example: 'borrow'
5372
+ description: 'Currency without exchange rate',
5373
+ example: 'USD'
5498
5374
  },
5499
- equitySubType: {
5500
- type: 'string',
5501
- description:
5502
- 'Equity sub-type (only present when intent is "equity"). opening: account opening balance (Equity → Assets), adjustment: balance correction.',
5503
- enum: ['opening', 'adjustment'],
5504
- example: 'opening'
5375
+ accounts: {
5376
+ description: 'Affected account paths',
5377
+ type: 'array',
5378
+ items: {
5379
+ type: 'string'
5380
+ }
5505
5381
  },
5506
- paymentSource: {
5382
+ totalAmount: {
5507
5383
  type: 'string',
5508
- description:
5509
- 'Payment source for expense transactions (v6.1). Indicates whether payment comes from asset or liability account. Only present when intent is "expense".',
5510
- enum: ['asset', 'liability'],
5511
- example: 'liability'
5384
+ description: 'Total amount in this currency',
5385
+ example: '5000.00'
5386
+ }
5387
+ },
5388
+ required: ['type', 'currency', 'accounts', 'totalAmount']
5389
+ } as const;
5390
+
5391
+ export const $AssetClassSummaryDto = {
5392
+ type: 'object',
5393
+ properties: {
5394
+ totalAccounts: {
5395
+ type: 'number',
5396
+ description: 'Total number of accounts'
5512
5397
  },
5513
- liabilityHint: {
5514
- type: 'string',
5515
- description:
5516
- 'Liability account type hint for credit card/BNPL spending (v6.1). Only present when paymentSource is "liability". Values: CreditCard, Huabei, Baitiao',
5517
- example: 'CreditCard'
5398
+ totalAssetClasses: {
5399
+ type: 'number',
5400
+ description: 'Total number of asset classes'
5518
5401
  },
5519
- message: {
5402
+ baseCurrency: {
5520
5403
  type: 'string',
5521
- description:
5522
- 'Human-readable message (for ask or error actions). Deprecated: Use messageKey for i18n support.',
5523
- example: 'How much did you spend?',
5524
- deprecated: true
5404
+ description: 'Base currency for conversion',
5405
+ example: 'CNY'
5525
5406
  },
5526
- messageKey: {
5527
- type: 'string',
5528
- description:
5529
- 'i18n message key for frontend translation. Use this instead of message for internationalization support.',
5530
- example: 'nlp.slot.prompt'
5407
+ warnings: {
5408
+ description: 'Exchange rate warnings',
5409
+ type: 'array',
5410
+ items: {
5411
+ $ref: '#/components/schemas/AccountExchangeRateWarningDto'
5412
+ }
5531
5413
  },
5532
- messageParams: {
5414
+ fallback: {
5533
5415
  type: 'object',
5534
5416
  description:
5535
- 'Parameters for message interpolation. Used with messageKey for dynamic values in translated messages.',
5536
- example: {
5537
- slot: 'amount',
5538
- name: 'Starbucks',
5539
- similarity: 85
5417
+ 'ADR-0105 §4 fallback provenance stats (holding level only). valueRatio is the grey-area share of total converted value; count is the number of source=FALLBACK holdings.'
5418
+ }
5419
+ },
5420
+ required: ['totalAccounts', 'totalAssetClasses', 'baseCurrency']
5421
+ } as const;
5422
+
5423
+ export const $AssetClassAccountsResponseDto = {
5424
+ type: 'object',
5425
+ properties: {
5426
+ groups: {
5427
+ description: 'Account groups by asset class',
5428
+ type: 'array',
5429
+ items: {
5430
+ $ref: '#/components/schemas/AssetClassGroupDto'
5540
5431
  }
5541
5432
  },
5542
- sessionId: {
5543
- type: 'string',
5544
- description:
5545
- 'Session ID for multi-turn dialogue. Must be included in subsequent requests to continue the conversation.',
5546
- example: 'session_abc123'
5547
- },
5548
- waitingFor: {
5549
- type: 'string',
5550
- description: 'Which slot is waiting for user input',
5551
- example: 'amount'
5552
- },
5553
- transaction: {
5554
- description: 'Created transaction info (for created action)',
5555
- allOf: [
5556
- {
5557
- $ref: '#/components/schemas/NlpTransactionInfoDto'
5558
- }
5559
- ]
5560
- },
5561
- parsedData: {
5562
- description:
5563
- 'Parsed data for confirmation (when action is "confirm"). Contains extracted fields that user should verify before transaction creation.',
5433
+ summary: {
5434
+ description: 'Summary statistics',
5564
5435
  allOf: [
5565
5436
  {
5566
- $ref: '#/components/schemas/NlpParsedDataDto'
5437
+ $ref: '#/components/schemas/AssetClassSummaryDto'
5567
5438
  }
5568
5439
  ]
5569
5440
  },
5570
- duplicateData: {
5441
+ uncategorized: {
5571
5442
  description:
5572
- 'Duplicate detection data (when action is "confirm_duplicate"). Contains information about potential duplicate transaction for user confirmation.',
5443
+ 'ADR-0105 §6 holding-level grey-area bucket (source=FALLBACK holdings peeled out of groups). Present only for groupBy=holdingAssetClass when FALLBACK holdings exist.',
5573
5444
  allOf: [
5574
5445
  {
5575
- $ref: '#/components/schemas/NlpDuplicateConfirmationDataDto'
5446
+ $ref: '#/components/schemas/AssetClassGroupDto'
5576
5447
  }
5577
5448
  ]
5449
+ }
5450
+ },
5451
+ required: ['groups', 'summary']
5452
+ } as const;
5453
+
5454
+ export const $HoldingAssetClassAccountSliceDto = {
5455
+ type: 'object',
5456
+ properties: {
5457
+ accountId: {
5458
+ type: 'string',
5459
+ description: 'Account ID'
5578
5460
  },
5579
- ruleData: {
5580
- description:
5581
- 'Rule match data (when action is "confirm_rule"). Contains information about medium-confidence rule match for user confirmation.',
5582
- allOf: [
5583
- {
5584
- $ref: '#/components/schemas/NlpRuleConfirmationDataDto'
5585
- }
5586
- ]
5461
+ accountPath: {
5462
+ type: 'string',
5463
+ description: 'Full account path',
5464
+ example: 'Assets:US:Investments:Brokerage'
5587
5465
  },
5588
- accountData: {
5466
+ accountCurrency: {
5467
+ type: 'string',
5589
5468
  description:
5590
- 'Account validation data (when action is "confirm_account"). Contains information about invalid account for user correction.',
5591
- allOf: [
5592
- {
5593
- $ref: '#/components/schemas/NlpAccountConfirmationDataDto'
5594
- }
5595
- ]
5469
+ 'Currency of the holding with the largest converted base value; undefined when no holding is convertible',
5470
+ example: 'USD'
5596
5471
  },
5597
- payeeData: {
5472
+ marketValueBase: {
5473
+ type: 'string',
5598
5474
  description:
5599
- 'Payee confirmation data (when action is "confirm_payee"). Contains information about medium/low confidence payee match for user confirmation.',
5600
- allOf: [
5601
- {
5602
- $ref: '#/components/schemas/NlpPayeeConfirmationDataDto'
5603
- }
5604
- ]
5605
- },
5606
- confidence: {
5607
- type: 'number',
5608
- description: 'Overall confidence score (0-1)',
5609
- example: 0.85
5475
+ "Account's market value in base currency (Σ converted holdings; grey bucket included)",
5476
+ example: '50000.00'
5610
5477
  },
5611
- confidenceThreshold: {
5478
+ shareOfTotalPct: {
5612
5479
  type: 'number',
5613
5480
  description:
5614
- 'Confidence threshold for automatic creation (default: 0.75). When confidence < threshold, action will be "confirm" requiring user verification.',
5615
- example: 0.75
5616
- },
5617
- recurringMatch: {
5618
- description:
5619
- 'Recurring transaction match info (when action is "created"). Contains match details when transaction matches a pending expected transaction.',
5620
- allOf: [
5621
- {
5622
- $ref: '#/components/schemas/RecurringMatchInfoDto'
5623
- }
5624
- ]
5481
+ 'Share of the global total (0-100). 0 when globalTotal is zero (no NaN/Infinity).',
5482
+ example: 42.5
5625
5483
  },
5626
- recurringSuggestion: {
5627
- description:
5628
- 'Recurring rule creation suggestion (when action is "created"). Contains suggestion to create a recurring rule based on detected patterns. Only present when no existing rule matched and similar historical transactions were found.',
5629
- allOf: [
5630
- {
5631
- $ref: '#/components/schemas/RecurringSuggestionDto'
5632
- }
5633
- ]
5484
+ groups: {
5485
+ description: 'Per-account asset-class breakdown',
5486
+ type: 'array',
5487
+ items: {
5488
+ $ref: '#/components/schemas/AssetClassGroupDto'
5489
+ }
5634
5490
  },
5635
- suggestedAccounts: {
5491
+ uncategorized: {
5636
5492
  description:
5637
- 'Suggested accounts for this transaction. Contains recommended source and destination accounts based on the detected intent and rules.',
5493
+ 'Per-account grey bucket (source=FALLBACK holdings, incl. broker cash)',
5638
5494
  allOf: [
5639
5495
  {
5640
- $ref: '#/components/schemas/NlpSuggestedAccountsDto'
5496
+ $ref: '#/components/schemas/AssetClassGroupDto'
5641
5497
  }
5642
5498
  ]
5643
5499
  },
5644
- defaultAccounts: {
5500
+ holdings: {
5645
5501
  description:
5646
- 'Default accounts for the user/region. These are fallback accounts used when no specific suggestion is available.',
5647
- allOf: [
5648
- {
5649
- $ref: '#/components/schemas/NlpDefaultAccountsDto'
5650
- }
5651
- ]
5502
+ 'Every holding row for this account (account ID in each row’s `id` field)',
5503
+ type: 'array',
5504
+ items: {
5505
+ $ref: '#/components/schemas/AccountItemWithAssetClassDto'
5506
+ }
5652
5507
  }
5653
5508
  },
5654
- required: ['status', 'action']
5509
+ required: [
5510
+ 'accountId',
5511
+ 'accountPath',
5512
+ 'marketValueBase',
5513
+ 'shareOfTotalPct',
5514
+ 'groups',
5515
+ 'holdings'
5516
+ ]
5655
5517
  } as const;
5656
5518
 
5657
- export const $BalanceByCurrencyDto = {
5519
+ export const $HoldingAssetClassCrossAccountResponseDto = {
5658
5520
  type: 'object',
5659
5521
  properties: {
5660
- currency: {
5661
- type: 'string',
5662
- description: 'ISO 4217 currency code',
5663
- example: 'CNY'
5522
+ global: {
5523
+ description: 'Merged cross-account holding aggregation',
5524
+ allOf: [
5525
+ {
5526
+ $ref: '#/components/schemas/AssetClassAccountsResponseDto'
5527
+ }
5528
+ ]
5664
5529
  },
5665
- balance: {
5666
- type: 'string',
5667
- description: 'Balance amount',
5668
- example: '50000.00'
5530
+ byAccount: {
5531
+ description: 'Per-account slices',
5532
+ type: 'array',
5533
+ items: {
5534
+ $ref: '#/components/schemas/HoldingAssetClassAccountSliceDto'
5535
+ }
5669
5536
  }
5670
5537
  },
5671
- required: ['currency', 'balance']
5538
+ required: ['global', 'byAccount']
5672
5539
  } as const;
5673
5540
 
5674
- export const $NetWorthByCurrencyDto = {
5541
+ export const $CashFlowByCurrencyDto = {
5675
5542
  type: 'object',
5676
5543
  properties: {
5677
- netWorth: {
5678
- description: 'Net worth by currency',
5544
+ income: {
5545
+ description: 'Income by currency',
5679
5546
  type: 'array',
5680
5547
  items: {
5681
5548
  $ref: '#/components/schemas/BalanceByCurrencyDto'
5682
5549
  }
5683
5550
  },
5684
- assets: {
5685
- description: 'Assets by currency',
5551
+ expense: {
5552
+ description: 'Expense by currency',
5686
5553
  type: 'array',
5687
5554
  items: {
5688
5555
  $ref: '#/components/schemas/BalanceByCurrencyDto'
5689
5556
  }
5690
5557
  },
5691
- liabilities: {
5692
- description: 'Liabilities by currency',
5693
- type: 'array',
5558
+ netSavings: {
5559
+ description: 'Net savings by currency',
5560
+ type: 'array',
5694
5561
  items: {
5695
5562
  $ref: '#/components/schemas/BalanceByCurrencyDto'
5696
5563
  }
5697
5564
  }
5698
5565
  },
5699
- required: ['netWorth', 'assets', 'liabilities']
5566
+ required: ['income', 'expense', 'netSavings']
5700
5567
  } as const;
5701
5568
 
5702
- export const $ConvertedNetWorthDto = {
5569
+ export const $ConvertedCashFlowDto = {
5703
5570
  type: 'object',
5704
5571
  properties: {
5705
5572
  baseCurrency: {
@@ -5707,114 +5574,78 @@ export const $ConvertedNetWorthDto = {
5707
5574
  description: 'Base currency for conversion',
5708
5575
  example: 'CNY'
5709
5576
  },
5710
- netWorth: {
5577
+ income: {
5711
5578
  type: 'string',
5712
- description: 'Converted net worth',
5713
- example: '500000.00'
5579
+ description: 'Converted income',
5580
+ example: '25000.00'
5714
5581
  },
5715
- assets: {
5582
+ expense: {
5716
5583
  type: 'string',
5717
- description: 'Converted assets',
5718
- example: '600000.00'
5584
+ description: 'Converted expense',
5585
+ example: '18000.00'
5719
5586
  },
5720
- liabilities: {
5587
+ netSavings: {
5721
5588
  type: 'string',
5722
- description: 'Converted liabilities',
5723
- example: '100000.00'
5589
+ description: 'Converted net savings',
5590
+ example: '7000.00'
5724
5591
  },
5725
5592
  exchangeRates: {
5726
5593
  type: 'object',
5727
5594
  description: 'Exchange rates used for conversion',
5728
5595
  example: {
5729
- USD: '7.200000',
5730
- EUR: '7.800000'
5596
+ USD: '7.200000'
5731
5597
  }
5732
5598
  }
5733
5599
  },
5734
- required: [
5735
- 'baseCurrency',
5736
- 'netWorth',
5737
- 'assets',
5738
- 'liabilities',
5739
- 'exchangeRates'
5740
- ]
5741
- } as const;
5742
-
5743
- export const $ExchangeRateWarningDto = {
5744
- type: 'object',
5745
- properties: {
5746
- type: {
5747
- type: 'string',
5748
- description: 'Warning type',
5749
- example: 'MISSING_EXCHANGE_RATE'
5750
- },
5751
- currency: {
5752
- type: 'string',
5753
- description: 'Currency without exchange rate',
5754
- example: 'EUR'
5755
- },
5756
- totalAmount: {
5757
- type: 'string',
5758
- description: 'Total amount affected',
5759
- example: '1000.00'
5760
- }
5761
- },
5762
- required: ['type', 'currency', 'totalAmount']
5600
+ required: ['baseCurrency', 'income', 'expense', 'netSavings', 'exchangeRates']
5763
5601
  } as const;
5764
5602
 
5765
- export const $NetWorthResponseDto = {
5603
+ export const $CashFlowResponseDto = {
5766
5604
  type: 'object',
5767
5605
  properties: {
5768
- netWorth: {
5606
+ period: {
5769
5607
  type: 'string',
5770
- description:
5771
- 'Total net worth (assets - liabilities, converted to base currency)',
5772
- example: '500000.00'
5608
+ description: 'Period identifier (YYYY-MM)',
5609
+ example: '2024-06'
5773
5610
  },
5774
- assets: {
5611
+ income: {
5775
5612
  type: 'string',
5776
- description: 'Total assets value (converted)',
5777
- example: '600000.00'
5613
+ description: 'Total income for the period (converted)',
5614
+ example: '25000.00'
5778
5615
  },
5779
- liabilities: {
5616
+ expense: {
5780
5617
  type: 'string',
5781
- description: 'Total liabilities value (positive number, converted)',
5782
- example: '100000.00'
5618
+ description: 'Total expenses for the period (converted)',
5619
+ example: '18000.00'
5783
5620
  },
5784
- monthlyReturn: {
5621
+ netSavings: {
5785
5622
  type: 'string',
5786
- description: 'Monthly return (change from last month)',
5787
- example: '15000.00'
5623
+ description: 'Net savings (income - expense, converted)',
5624
+ example: '7000.00'
5788
5625
  },
5789
- monthlyReturnPercentage: {
5626
+ savingsRate: {
5790
5627
  type: 'string',
5791
- description: 'Monthly return percentage',
5792
- example: '3.15'
5628
+ description: 'Savings rate percentage (netSavings / income * 100)',
5629
+ example: '28.00'
5793
5630
  },
5794
5631
  currency: {
5795
5632
  type: 'string',
5796
5633
  description: 'Base currency code',
5797
5634
  example: 'CNY'
5798
5635
  },
5799
- asOf: {
5800
- type: 'string',
5801
- description: 'Data as of date (ISO 8601)',
5802
- example: '2024-06-15T00:00:00.000Z'
5803
- },
5804
5636
  byCurrency: {
5805
- description: 'Balances grouped by original currency',
5637
+ description: 'Cash flow grouped by original currency',
5806
5638
  allOf: [
5807
5639
  {
5808
- $ref: '#/components/schemas/NetWorthByCurrencyDto'
5640
+ $ref: '#/components/schemas/CashFlowByCurrencyDto'
5809
5641
  }
5810
5642
  ]
5811
5643
  },
5812
5644
  converted: {
5813
- description:
5814
- 'Converted values in base currency (undefined if no exchange rates available)',
5645
+ description: 'Converted values in base currency',
5815
5646
  allOf: [
5816
5647
  {
5817
- $ref: '#/components/schemas/ConvertedNetWorthDto'
5648
+ $ref: '#/components/schemas/ConvertedCashFlowDto'
5818
5649
  }
5819
5650
  ]
5820
5651
  },
@@ -5827,417 +5658,459 @@ export const $NetWorthResponseDto = {
5827
5658
  }
5828
5659
  },
5829
5660
  required: [
5830
- 'netWorth',
5831
- 'assets',
5832
- 'liabilities',
5833
- 'monthlyReturn',
5834
- 'monthlyReturnPercentage',
5835
- 'currency',
5836
- 'asOf'
5661
+ 'period',
5662
+ 'income',
5663
+ 'expense',
5664
+ 'netSavings',
5665
+ 'savingsRate',
5666
+ 'currency'
5837
5667
  ]
5838
5668
  } as const;
5839
5669
 
5840
- export const $AccountItemDto = {
5670
+ export const $MonetaryDto = {
5841
5671
  type: 'object',
5842
5672
  properties: {
5843
- id: {
5844
- type: 'string',
5845
- description: 'Account ID'
5846
- },
5847
- name: {
5848
- type: 'string',
5849
- description: 'Full account name',
5850
- example: 'Assets:Bank:CMB:Savings'
5851
- },
5852
- displayName: {
5853
- type: 'string',
5854
- description: 'Display name (last part of account path)',
5855
- example: 'Savings'
5856
- },
5857
- balance: {
5673
+ amount: {
5858
5674
  type: 'string',
5859
- description: 'Account balance',
5860
- example: '50000.00'
5675
+ description: 'Amount (Decimal string)',
5676
+ example: '3000'
5861
5677
  },
5862
5678
  currency: {
5863
5679
  type: 'string',
5864
- description: 'Currency code',
5865
- example: 'CNY'
5680
+ description: 'ISO 4217 currency',
5681
+ example: 'USD'
5682
+ },
5683
+ baseCcyEquivalent: {
5684
+ type: 'object',
5685
+ description: 'Converted to user base currency (Decimal string)',
5686
+ example: '21600',
5687
+ nullable: true
5866
5688
  }
5867
5689
  },
5868
- required: ['id', 'name', 'displayName', 'balance', 'currency']
5690
+ required: ['amount', 'currency']
5869
5691
  } as const;
5870
5692
 
5871
- export const $PlatformGroupDto = {
5693
+ export const $CurrentPriceDto = {
5872
5694
  type: 'object',
5873
5695
  properties: {
5874
- platformId: {
5696
+ amount: {
5875
5697
  type: 'string',
5876
- description: 'Platform ID'
5698
+ description: 'Price amount (Decimal string)',
5699
+ example: '250'
5877
5700
  },
5878
- platformName: {
5701
+ currency: {
5879
5702
  type: 'string',
5880
- description: 'Platform display name',
5881
- example: 'CMB Bank'
5703
+ description: 'Price currency (ISO 4217)',
5704
+ example: 'USD'
5882
5705
  },
5883
- accounts: {
5884
- description: 'Accounts within this platform',
5885
- type: 'array',
5886
- items: {
5887
- $ref: '#/components/schemas/AccountItemDto'
5888
- }
5706
+ date: {
5707
+ type: 'string',
5708
+ description: 'Price date (ISO 8601)',
5709
+ example: '2024-06-01'
5889
5710
  },
5890
- totalBalance: {
5711
+ source: {
5891
5712
  type: 'string',
5892
- description: 'Total balance across all accounts in platform',
5893
- example: '100000.00'
5713
+ description: 'Price source',
5714
+ example: 'USER_OVERRIDE',
5715
+ enum: ['USER_OVERRIDE', 'OPENBB_EQUITY', 'OPENBB_CURRENCY']
5894
5716
  }
5895
5717
  },
5896
- required: ['platformId', 'platformName', 'accounts', 'totalBalance']
5718
+ required: ['amount', 'currency', 'date', 'source']
5897
5719
  } as const;
5898
5720
 
5899
- export const $AccountsSummaryDto = {
5721
+ export const $FxRateDto = {
5900
5722
  type: 'object',
5901
5723
  properties: {
5902
- totalAccounts: {
5903
- type: 'number',
5904
- description: 'Total number of accounts'
5724
+ from: {
5725
+ type: 'string',
5726
+ example: 'USD'
5905
5727
  },
5906
- totalPlatforms: {
5907
- type: 'number',
5908
- description: 'Total number of platforms'
5909
- }
5910
- },
5911
- required: ['totalAccounts', 'totalPlatforms']
5912
- } as const;
5913
-
5914
- export const $AccountsResponseDto = {
5915
- type: 'object',
5916
- properties: {
5917
- groups: {
5918
- description: 'Account groups by platform',
5919
- type: 'array',
5920
- items: {
5921
- $ref: '#/components/schemas/PlatformGroupDto'
5922
- }
5728
+ to: {
5729
+ type: 'string',
5730
+ example: 'CNY'
5923
5731
  },
5924
- summary: {
5925
- description: 'Summary statistics',
5926
- allOf: [
5927
- {
5928
- $ref: '#/components/schemas/AccountsSummaryDto'
5929
- }
5930
- ]
5732
+ rate: {
5733
+ type: 'string',
5734
+ description: 'FX rate (Decimal string)',
5735
+ example: '7.2'
5736
+ },
5737
+ date: {
5738
+ type: 'string',
5739
+ description: 'Rate date (ISO 8601)',
5740
+ example: '2024-01-15'
5931
5741
  }
5932
5742
  },
5933
- required: ['groups', 'summary']
5743
+ required: ['from', 'to', 'rate', 'date']
5934
5744
  } as const;
5935
5745
 
5936
- export const $AccountItemWithAssetClassDto = {
5746
+ export const $HoldingPnlRowDto = {
5937
5747
  type: 'object',
5938
5748
  properties: {
5939
- id: {
5749
+ accountId: {
5940
5750
  type: 'string',
5941
- description: 'Account ID'
5751
+ description: 'Account UUID',
5752
+ example: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
5942
5753
  },
5943
- name: {
5754
+ accountPath: {
5944
5755
  type: 'string',
5945
- description: 'Full account name',
5946
- example: 'Assets:Bank:CMB:Savings'
5756
+ description: 'Full account path',
5757
+ example: 'Assets:US:Broker:AAPL'
5947
5758
  },
5948
- displayName: {
5949
- type: 'string',
5950
- description: 'Display name (last part of account path)',
5951
- example: 'Savings'
5759
+ accountCcy: {
5760
+ type: 'object',
5761
+ description: 'Account settlement currency (ISO 4217), from cost currency',
5762
+ nullable: true,
5763
+ example: 'USD'
5952
5764
  },
5953
- balance: {
5765
+ brokerType: {
5766
+ type: 'object',
5767
+ description: 'Broker type derived from Platform.type',
5768
+ nullable: true,
5769
+ example: 'broker'
5770
+ },
5771
+ symbol: {
5954
5772
  type: 'string',
5955
- description: 'Account balance',
5956
- example: '50000.00'
5773
+ description: 'Commodity symbol',
5774
+ example: 'AAPL'
5957
5775
  },
5958
- currency: {
5776
+ chartToken: {
5959
5777
  type: 'string',
5960
- description: 'Currency code',
5961
- example: 'CNY'
5778
+ description: 'Chart segment token (libs/common resolver)',
5779
+ example: 'equity',
5780
+ enum: ['equity', 'fund', 'bond', 'cash', 'other']
5962
5781
  },
5963
5782
  assetClass: {
5964
5783
  type: 'string',
5965
- description: 'Asset class',
5966
- example: 'LIQUIDITY'
5784
+ example: 'EQUITY'
5967
5785
  },
5968
5786
  assetSubClass: {
5969
- type: 'string',
5970
- description: 'Asset sub-class (Prisma-compatible)',
5971
- example: 'RETIREMENT_ACCOUNT'
5787
+ type: 'object',
5788
+ nullable: true,
5789
+ example: 'STOCK'
5972
5790
  },
5973
- regionalSubClass: {
5791
+ units: {
5974
5792
  type: 'string',
5975
- description: 'Regional sub-class (region-specific, for display)',
5976
- example: 'FOUR_ZERO_ONE_K'
5793
+ description: 'Net held units (Decimal string)',
5794
+ example: '12'
5977
5795
  },
5978
- riskLevel: {
5979
- type: 'string',
5980
- description: 'Risk level',
5981
- example: 'LOW'
5982
- }
5983
- },
5984
- required: ['id', 'name', 'displayName', 'balance', 'currency', 'assetClass']
5985
- } as const;
5986
-
5987
- export const $AssetClassGroupDto = {
5988
- type: 'object',
5989
- properties: {
5990
- assetClass: {
5991
- type: 'string',
5992
- description: 'Asset class name',
5993
- example: 'LIQUIDITY',
5994
- enum: [
5995
- 'LIQUIDITY',
5996
- 'EQUITY',
5997
- 'FIXED_INCOME',
5998
- 'PRECIOUS_METALS',
5999
- 'COMMODITY',
6000
- 'INSURANCE',
6001
- 'ALTERNATIVE_INVESTMENT',
6002
- 'PERSONAL_ASSETS',
6003
- 'LIABILITY',
6004
- 'REAL_ESTATE',
6005
- 'INDEX'
5796
+ averageCostPerUnit: {
5797
+ description:
5798
+ 'Average cost per unit; null when cost currency conflicts or no cost',
5799
+ nullable: true,
5800
+ allOf: [
5801
+ {
5802
+ $ref: '#/components/schemas/MonetaryDto'
5803
+ }
6006
5804
  ]
6007
5805
  },
6008
- assetSubClass: {
6009
- type: 'string',
6010
- description: 'Asset sub-class name',
6011
- example: 'DEPOSIT'
5806
+ costBasis: {
5807
+ description: 'Cost basis of held units',
5808
+ nullable: true,
5809
+ allOf: [
5810
+ {
5811
+ $ref: '#/components/schemas/MonetaryDto'
5812
+ }
5813
+ ]
6012
5814
  },
6013
- accounts: {
6014
- description: 'Accounts within this asset class',
6015
- type: 'array',
6016
- items: {
6017
- $ref: '#/components/schemas/AccountItemWithAssetClassDto'
6018
- }
5815
+ marketValue: {
5816
+ description: 'Market value at asOf price',
5817
+ nullable: true,
5818
+ allOf: [
5819
+ {
5820
+ $ref: '#/components/schemas/MonetaryDto'
5821
+ }
5822
+ ]
6019
5823
  },
6020
- balanceByCurrency: {
6021
- description: 'Balances grouped by currency',
6022
- type: 'array',
6023
- items: {
6024
- $ref: '#/components/schemas/BalanceByCurrencyDto'
6025
- }
5824
+ currentPrice: {
5825
+ description: 'Price used for market value',
5826
+ nullable: true,
5827
+ allOf: [
5828
+ {
5829
+ $ref: '#/components/schemas/CurrentPriceDto'
5830
+ }
5831
+ ]
6026
5832
  },
6027
- convertedBalance: {
6028
- type: 'string',
6029
- description: 'Converted balance in base currency',
6030
- example: '100000.00'
5833
+ unrealizedPnlBase: {
5834
+ type: 'object',
5835
+ description:
5836
+ 'Unrealized P&L in base currency (Decimal string); null when any FX/price missing',
5837
+ nullable: true,
5838
+ example: '6000'
5839
+ },
5840
+ unrealizedPnlPct: {
5841
+ type: 'object',
5842
+ description: 'Unrealized P&L % (Decimal string)',
5843
+ nullable: true,
5844
+ example: '25'
5845
+ },
5846
+ costFxRate: {
5847
+ description: 'Historical FX rate applied to cost basis',
5848
+ nullable: true,
5849
+ allOf: [
5850
+ {
5851
+ $ref: '#/components/schemas/FxRateDto'
5852
+ }
5853
+ ]
5854
+ },
5855
+ marketFxRate: {
5856
+ description: 'FX rate applied to market value',
5857
+ nullable: true,
5858
+ allOf: [
5859
+ {
5860
+ $ref: '#/components/schemas/FxRateDto'
5861
+ }
5862
+ ]
5863
+ },
5864
+ pctOfInvestedAssets: {
5865
+ type: 'object',
5866
+ description:
5867
+ 'Share of invested assets % (Decimal string); only for invested chartTokens',
5868
+ nullable: true,
5869
+ example: '40'
5870
+ },
5871
+ realizedPnl: {
5872
+ description:
5873
+ 'Cumulative realized P&L on sold lots (asOf-date cutoff); null when the method has no applicable sells, a sell lacks a price, or any required FX rate is missing (never-mix). When a sell spans multiple currencies (cross-currency sale), amount and currency reflect the base currency; baseCcyEquivalent is always the authoritative dual-FX figure',
5874
+ nullable: true,
5875
+ allOf: [
5876
+ {
5877
+ $ref: '#/components/schemas/MonetaryDto'
5878
+ }
5879
+ ]
6031
5880
  }
6032
5881
  },
6033
- required: ['assetClass', 'accounts', 'balanceByCurrency']
5882
+ required: [
5883
+ 'accountId',
5884
+ 'accountPath',
5885
+ 'symbol',
5886
+ 'chartToken',
5887
+ 'assetClass',
5888
+ 'units'
5889
+ ]
6034
5890
  } as const;
6035
5891
 
6036
- export const $AccountExchangeRateWarningDto = {
5892
+ export const $HoldingPnlWarningDto = {
6037
5893
  type: 'object',
6038
5894
  properties: {
6039
5895
  type: {
6040
5896
  type: 'string',
6041
5897
  description: 'Warning type',
6042
- example: 'MISSING_EXCHANGE_RATE'
5898
+ example: 'MISSING_COST_FX_RATE',
5899
+ enum: [
5900
+ 'MISSING_COST_FX_RATE',
5901
+ 'MISSING_MARKET_FX_RATE',
5902
+ 'MISSING_SALE_PRICE',
5903
+ 'MISSING_REALIZED_FX_RATE',
5904
+ 'OVERSOLD_LOTS',
5905
+ 'NO_PRICE',
5906
+ 'MIXED_COST_CURRENCY'
5907
+ ]
6043
5908
  },
6044
- currency: {
6045
- type: 'string',
6046
- description: 'Currency without exchange rate',
6047
- example: 'USD'
5909
+ symbol: {
5910
+ type: 'object',
5911
+ nullable: true
6048
5912
  },
6049
- accounts: {
6050
- description: 'Affected account paths',
6051
- type: 'array',
6052
- items: {
6053
- type: 'string'
6054
- }
5913
+ accountId: {
5914
+ type: 'object',
5915
+ nullable: true
6055
5916
  },
6056
- totalAmount: {
6057
- type: 'string',
6058
- description: 'Total amount in this currency',
6059
- example: '5000.00'
5917
+ currency: {
5918
+ type: 'object',
5919
+ nullable: true
6060
5920
  }
6061
5921
  },
6062
- required: ['type', 'currency', 'accounts', 'totalAmount']
5922
+ required: ['type']
6063
5923
  } as const;
6064
5924
 
6065
- export const $AssetClassSummaryDto = {
5925
+ export const $HoldingPnlResponseDto = {
6066
5926
  type: 'object',
6067
5927
  properties: {
6068
- totalAccounts: {
6069
- type: 'number',
6070
- description: 'Total number of accounts'
6071
- },
6072
- totalAssetClasses: {
6073
- type: 'number',
6074
- description: 'Total number of asset classes'
5928
+ asOfDate: {
5929
+ type: 'string',
5930
+ example: '2026-07-08'
6075
5931
  },
6076
5932
  baseCurrency: {
6077
5933
  type: 'string',
6078
- description: 'Base currency for conversion',
6079
5934
  example: 'CNY'
6080
5935
  },
6081
- warnings: {
6082
- description: 'Exchange rate warnings',
6083
- type: 'array',
6084
- items: {
6085
- $ref: '#/components/schemas/AccountExchangeRateWarningDto'
6086
- }
6087
- }
6088
- },
6089
- required: ['totalAccounts', 'totalAssetClasses', 'baseCurrency']
6090
- } as const;
6091
-
6092
- export const $AssetClassAccountsResponseDto = {
6093
- type: 'object',
6094
- properties: {
6095
- groups: {
6096
- description: 'Account groups by asset class',
6097
- type: 'array',
6098
- items: {
6099
- $ref: '#/components/schemas/AssetClassGroupDto'
6100
- }
6101
- },
6102
- summary: {
6103
- description: 'Summary statistics',
6104
- allOf: [
6105
- {
6106
- $ref: '#/components/schemas/AssetClassSummaryDto'
6107
- }
6108
- ]
6109
- }
6110
- },
6111
- required: ['groups', 'summary']
6112
- } as const;
6113
-
6114
- export const $CashFlowByCurrencyDto = {
6115
- type: 'object',
6116
- properties: {
6117
- income: {
6118
- description: 'Income by currency',
6119
- type: 'array',
6120
- items: {
6121
- $ref: '#/components/schemas/BalanceByCurrencyDto'
6122
- }
5936
+ method: {
5937
+ type: 'string',
5938
+ description:
5939
+ 'Realized-P&L lot-matching method (FIFO or average). Unrealized cost basis remains average regardless of this value (#473).',
5940
+ enum: ['average', 'FIFO'],
5941
+ example: 'average'
6123
5942
  },
6124
- expense: {
6125
- description: 'Expense by currency',
5943
+ rows: {
6126
5944
  type: 'array',
6127
5945
  items: {
6128
- $ref: '#/components/schemas/BalanceByCurrencyDto'
5946
+ $ref: '#/components/schemas/HoldingPnlRowDto'
6129
5947
  }
6130
5948
  },
6131
- netSavings: {
6132
- description: 'Net savings by currency',
5949
+ warnings: {
6133
5950
  type: 'array',
6134
5951
  items: {
6135
- $ref: '#/components/schemas/BalanceByCurrencyDto'
5952
+ $ref: '#/components/schemas/HoldingPnlWarningDto'
6136
5953
  }
6137
5954
  }
6138
5955
  },
6139
- required: ['income', 'expense', 'netSavings']
5956
+ required: ['asOfDate', 'baseCurrency', 'method', 'rows', 'warnings']
6140
5957
  } as const;
6141
5958
 
6142
- export const $ConvertedCashFlowDto = {
5959
+ export const $CreateBeanPriceDto = {
6143
5960
  type: 'object',
6144
5961
  properties: {
6145
- baseCurrency: {
5962
+ currency: {
6146
5963
  type: 'string',
6147
- description: 'Base currency for conversion',
6148
- example: 'CNY'
5964
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
5965
+ example: 'USD'
6149
5966
  },
6150
- income: {
5967
+ quoteCurrency: {
6151
5968
  type: 'string',
6152
- description: 'Converted income',
6153
- example: '25000.00'
5969
+ description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
5970
+ example: 'CNY'
6154
5971
  },
6155
- expense: {
6156
- type: 'string',
6157
- description: 'Converted expense',
6158
- example: '18000.00'
5972
+ amount: {
5973
+ type: 'number',
5974
+ description:
5975
+ 'Price amount (MUST be >= 0 per Beancount spec, supports up to 15 decimal places). Zero allowed for conversion entries, negative strictly prohibited.',
5976
+ example: 175.5,
5977
+ minimum: 0
6159
5978
  },
6160
- netSavings: {
5979
+ date: {
6161
5980
  type: 'string',
6162
- description: 'Converted net savings',
6163
- example: '7000.00'
5981
+ description: 'Price date (ISO 8601 format)',
5982
+ example: '2024-11-05'
6164
5983
  },
6165
- exchangeRates: {
5984
+ metadata: {
6166
5985
  type: 'object',
6167
- description: 'Exchange rates used for conversion',
5986
+ description:
5987
+ 'Metadata (validated by Zod schema, max field lengths enforced)',
6168
5988
  example: {
6169
- USD: '7.200000'
5989
+ source: 'MANUAL',
5990
+ note: 'Bank valuation report',
5991
+ confidence: 0.95
6170
5992
  }
6171
5993
  }
6172
5994
  },
6173
- required: ['baseCurrency', 'income', 'expense', 'netSavings', 'exchangeRates']
5995
+ required: ['currency', 'quoteCurrency', 'amount', 'date']
6174
5996
  } as const;
6175
5997
 
6176
- export const $CashFlowResponseDto = {
5998
+ export const $PriceResponseDto = {
6177
5999
  type: 'object',
6178
6000
  properties: {
6179
- period: {
6001
+ id: {
6180
6002
  type: 'string',
6181
- description: 'Period identifier (YYYY-MM)',
6182
- example: '2024-06'
6003
+ description: 'Unique identifier',
6004
+ example: 'uuid-123-456'
6183
6005
  },
6184
- income: {
6006
+ userId: {
6185
6007
  type: 'string',
6186
- description: 'Total income for the period (converted)',
6187
- example: '25000.00'
6008
+ description: 'User ID (owner of the price)',
6009
+ example: 'user-123'
6188
6010
  },
6189
- expense: {
6011
+ currency: {
6190
6012
  type: 'string',
6191
- description: 'Total expenses for the period (converted)',
6192
- example: '18000.00'
6013
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
6014
+ example: 'BTC'
6193
6015
  },
6194
- netSavings: {
6016
+ quoteCurrency: {
6195
6017
  type: 'string',
6196
- description: 'Net savings (income - expense, converted)',
6197
- example: '7000.00'
6018
+ description: 'Quote currency (pricing currency, e.g., USD, CNY)',
6019
+ example: 'USD'
6198
6020
  },
6199
- savingsRate: {
6200
- type: 'string',
6201
- description: 'Savings rate percentage (netSavings / income * 100)',
6202
- example: '28.00'
6021
+ amount: {
6022
+ type: 'number',
6023
+ description:
6024
+ 'Price amount (corresponds to Beancount Amount.number). Supports up to 15 decimal places.',
6025
+ example: 50000
6203
6026
  },
6204
- currency: {
6027
+ date: {
6205
6028
  type: 'string',
6206
- description: 'Base currency code',
6207
- example: 'CNY'
6029
+ description:
6030
+ 'Price date (ISO 8601 format). Represents the date this price was valid.',
6031
+ example: '2024-01-01',
6032
+ format: 'date'
6208
6033
  },
6209
- byCurrency: {
6210
- description: 'Cash flow grouped by original currency',
6211
- allOf: [
6212
- {
6213
- $ref: '#/components/schemas/CashFlowByCurrencyDto'
6214
- }
6215
- ]
6034
+ meta: {
6035
+ type: 'object',
6036
+ description:
6037
+ 'Metadata (corresponds to Beancount meta field). Contains source, confidence, note, etc.',
6038
+ example: {
6039
+ source: 'MANUAL',
6040
+ note: 'User-defined price',
6041
+ confidence: 1
6042
+ }
6216
6043
  },
6217
- converted: {
6218
- description: 'Converted values in base currency',
6219
- allOf: [
6220
- {
6221
- $ref: '#/components/schemas/ConvertedCashFlowDto'
6222
- }
6223
- ]
6044
+ createdAt: {
6045
+ format: 'date-time',
6046
+ type: 'string',
6047
+ description: 'Creation timestamp',
6048
+ example: '2024-11-03T10:00:00Z'
6224
6049
  },
6225
- warnings: {
6226
- description: 'Exchange rate warnings',
6050
+ updatedAt: {
6051
+ format: 'date-time',
6052
+ type: 'string',
6053
+ description: 'Last update timestamp',
6054
+ example: '2024-11-03T10:00:00Z'
6055
+ }
6056
+ },
6057
+ required: [
6058
+ 'id',
6059
+ 'userId',
6060
+ 'currency',
6061
+ 'quoteCurrency',
6062
+ 'amount',
6063
+ 'date',
6064
+ 'meta',
6065
+ 'createdAt',
6066
+ 'updatedAt'
6067
+ ]
6068
+ } as const;
6069
+
6070
+ export const $PriceListResponseDto = {
6071
+ type: 'object',
6072
+ properties: {
6073
+ items: {
6074
+ description: 'List of prices',
6227
6075
  type: 'array',
6228
6076
  items: {
6229
- $ref: '#/components/schemas/ExchangeRateWarningDto'
6077
+ $ref: '#/components/schemas/PriceResponseDto'
6230
6078
  }
6079
+ },
6080
+ total: {
6081
+ type: 'number',
6082
+ description: 'Total number of prices',
6083
+ example: 42
6231
6084
  }
6232
6085
  },
6233
- required: [
6234
- 'period',
6235
- 'income',
6236
- 'expense',
6237
- 'netSavings',
6238
- 'savingsRate',
6239
- 'currency'
6240
- ]
6086
+ required: ['items', 'total']
6087
+ } as const;
6088
+
6089
+ export const $UpdateBeanPriceDto = {
6090
+ type: 'object',
6091
+ properties: {
6092
+ currency: {
6093
+ type: 'string',
6094
+ description: 'Currency being priced'
6095
+ },
6096
+ quoteCurrency: {
6097
+ type: 'string',
6098
+ description: 'Quote currency (pricing currency)'
6099
+ },
6100
+ amount: {
6101
+ type: 'number',
6102
+ description: 'Price amount (MUST be >= 0 per Beancount spec)',
6103
+ minimum: 0
6104
+ },
6105
+ date: {
6106
+ type: 'string',
6107
+ description: 'Price date (ISO 8601 format)'
6108
+ },
6109
+ metadata: {
6110
+ type: 'object',
6111
+ description: 'Metadata'
6112
+ }
6113
+ }
6241
6114
  } as const;
6242
6115
 
6243
6116
  export const $CurrencyBalanceDto = {