@firela/api-types 0.0.0-canary.da5984a1 → 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']
@@ -841,6 +963,85 @@ export const $BatchTransactionResponseDto = {
841
963
  required: ['succeeded', 'failed']
842
964
  } as const;
843
965
 
966
+ export const $CorrectTransactionDto = {
967
+ type: 'object',
968
+ properties: {
969
+ date: {
970
+ type: 'string',
971
+ description: 'Transaction date (ISO 8601 format)',
972
+ example: '2024-11-28'
973
+ },
974
+ flag: {
975
+ type: 'string',
976
+ description: 'Transaction flag: * (cleared), ! (pending)',
977
+ enum: ['*', '!'],
978
+ example: '*'
979
+ },
980
+ payee: {
981
+ type: 'string',
982
+ description: 'Payee name',
983
+ example: 'Whole Foods Market'
984
+ },
985
+ narration: {
986
+ type: 'string',
987
+ description: 'Transaction narration/description',
988
+ example: 'Grocery shopping'
989
+ },
990
+ tags: {
991
+ description: 'Transaction tags (without # prefix)',
992
+ example: ['vacation', 'personal'],
993
+ type: 'array',
994
+ items: {
995
+ type: 'string'
996
+ }
997
+ },
998
+ links: {
999
+ description: 'Transaction links (without ^ prefix)',
1000
+ example: ['invoice-123'],
1001
+ type: 'array',
1002
+ items: {
1003
+ type: 'string'
1004
+ }
1005
+ },
1006
+ postings: {
1007
+ description:
1008
+ 'Transaction postings (minimum 1, typically 2 for double-entry)',
1009
+ type: 'array',
1010
+ items: {
1011
+ $ref: '#/components/schemas/CreatePostingDto'
1012
+ }
1013
+ },
1014
+ meta: {
1015
+ type: 'object',
1016
+ description: 'Transaction-level metadata',
1017
+ example: {
1018
+ invoice: '12345'
1019
+ }
1020
+ },
1021
+ idempotencyKey: {
1022
+ type: 'string',
1023
+ description:
1024
+ 'Unique key for idempotent transaction creation. If provided, duplicate requests with the same key will return the existing transaction.',
1025
+ example: 'import-2024-01-15-batch-001',
1026
+ maxLength: 128
1027
+ },
1028
+ autoCreateAccounts: {
1029
+ type: 'boolean',
1030
+ description:
1031
+ 'Auto-create accounts if not found. When true, missing accounts will be automatically created. When false (default for API), missing accounts will cause a validation error. Set to true for quick entry scenarios where you want to create accounts on-the-fly.',
1032
+ default: true,
1033
+ example: true
1034
+ },
1035
+ correctionReason: {
1036
+ type: 'string',
1037
+ description: 'Reason for correcting/superseding the original transaction',
1038
+ example: 'Wrong amount — corrected from receipt',
1039
+ maxLength: 500
1040
+ }
1041
+ },
1042
+ required: ['date', 'narration', 'postings']
1043
+ } as const;
1044
+
844
1045
  export const $PostingDetailDto = {
845
1046
  type: 'object',
846
1047
  properties: {
@@ -854,9 +1055,9 @@ export const $PostingDetailDto = {
854
1055
  description: 'Account ID',
855
1056
  example: 'clh1234567890abcdef'
856
1057
  },
857
- accountName: {
1058
+ account: {
858
1059
  type: 'string',
859
- description: 'Account name',
1060
+ description: 'Fully-qualified Beancount account path',
860
1061
  example: 'Assets:Bank:Checking'
861
1062
  },
862
1063
  units: {
@@ -885,6 +1086,15 @@ export const $PostingDetailDto = {
885
1086
  description: 'Cost date',
886
1087
  example: '2024-01-15'
887
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
+ },
888
1098
  priceAmount: {
889
1099
  type: 'string',
890
1100
  description: 'Price amount',
@@ -905,7 +1115,7 @@ export const $PostingDetailDto = {
905
1115
  description: 'Posting metadata'
906
1116
  }
907
1117
  },
908
- required: ['id', 'accountId', 'accountName']
1118
+ required: ['id', 'accountId', 'account']
909
1119
  } as const;
910
1120
 
911
1121
  export const $TransactionDetailDto = {
@@ -977,8 +1187,8 @@ export const $TransactionDetailDto = {
977
1187
  },
978
1188
  sourceType: {
979
1189
  type: 'string',
980
- description: 'Source type (how the transaction was created)',
981
- enum: ['NLP', 'CSV', 'OCR', 'API']
1190
+ description:
1191
+ 'Source type (free-form string from transaction metadata, e.g. import, api)'
982
1192
  },
983
1193
  sourcePlatform: {
984
1194
  type: 'string',
@@ -1011,6 +1221,18 @@ export const $TransactionDetailDto = {
1011
1221
  type: 'string',
1012
1222
  description: 'Correction reason (if voided or superseded)',
1013
1223
  example: 'Duplicate entry'
1224
+ },
1225
+ supersededBy: {
1226
+ type: 'string',
1227
+ description:
1228
+ 'ID of the transaction that supersedes this one (set when status=SUPERSEDED)',
1229
+ example: 'clh1234567890abcdef'
1230
+ },
1231
+ originalTxn: {
1232
+ type: 'string',
1233
+ description:
1234
+ 'ID of the transaction this one corrected/replaced (back-link on the replacement)',
1235
+ example: 'clh1234567890abcdef'
1014
1236
  }
1015
1237
  },
1016
1238
  required: [
@@ -1235,8 +1457,8 @@ export const $TransactionSummaryDto = {
1235
1457
  },
1236
1458
  sourceType: {
1237
1459
  type: 'string',
1238
- description: 'Source type (NLP, CSV, OCR, API)',
1239
- enum: ['NLP', 'CSV', 'OCR', 'API']
1460
+ description:
1461
+ 'Source type (free-form string from transaction metadata, e.g. import, api)'
1240
1462
  },
1241
1463
  sourcePlatform: {
1242
1464
  type: 'string',
@@ -1303,7 +1525,8 @@ export const $ReviewSummaryDto = {
1303
1525
  },
1304
1526
  sourceType: {
1305
1527
  type: 'string',
1306
- description: 'Source type (NLP, CSV, OCR, API)'
1528
+ description:
1529
+ 'Source type (free-form string from transaction metadata, e.g. import, api)'
1307
1530
  },
1308
1531
  sourcePlatform: {
1309
1532
  type: 'string',
@@ -1413,7 +1636,20 @@ export const $DecisionOptionDto = {
1413
1636
  properties: {
1414
1637
  value: {
1415
1638
  type: 'string',
1416
- description: 'The action value to submit (e.g., UPGRADE_REPLACE, ACCEPT)'
1639
+ description: 'The action value to submit (e.g., UPGRADE_REPLACE, ACCEPT)',
1640
+ enum: [
1641
+ 'UPGRADE_REPLACE',
1642
+ 'LINK_KEEP_BOTH',
1643
+ 'IGNORE_NEW',
1644
+ 'CONFIRM_DIFFERENT',
1645
+ 'ACCEPT',
1646
+ 'REJECT',
1647
+ 'ACCEPT_AND_LEARN',
1648
+ 'CHOOSE_OTHER',
1649
+ 'CANCEL',
1650
+ 'FIX',
1651
+ 'IGNORE'
1652
+ ]
1417
1653
  },
1418
1654
  labelKey: {
1419
1655
  type: 'string',
@@ -1488,7 +1724,8 @@ export const $ReviewDetailDto = {
1488
1724
  },
1489
1725
  sourceType: {
1490
1726
  type: 'string',
1491
- description: 'Source type (NLP, CSV, OCR, API)'
1727
+ description:
1728
+ 'Source type (free-form string from transaction metadata, e.g. import, api)'
1492
1729
  },
1493
1730
  sourcePlatform: {
1494
1731
  type: 'string',
@@ -1568,7 +1805,20 @@ export const $ResolveReviewDto = {
1568
1805
  action: {
1569
1806
  type: 'string',
1570
1807
  description:
1571
- 'Decision action. Available actions vary by review type: DUPLICATE: UPGRADE_REPLACE, KEEP_EXISTING, KEEP_BOTH | PAYEE_MATCH: ACCEPT, REJECT, ACCEPT_AND_LEARN | ACCOUNT_VALIDATION: FIX, REJECT | RULE_MATCH: ACCEPT, REJECT, ACCEPT_AND_LEARN',
1808
+ 'Decision action. Valid actions vary by review type — see DecisionOptionDto.value returned by the review detail endpoint.',
1809
+ enum: [
1810
+ 'UPGRADE_REPLACE',
1811
+ 'LINK_KEEP_BOTH',
1812
+ 'IGNORE_NEW',
1813
+ 'CONFIRM_DIFFERENT',
1814
+ 'ACCEPT',
1815
+ 'REJECT',
1816
+ 'ACCEPT_AND_LEARN',
1817
+ 'CHOOSE_OTHER',
1818
+ 'CANCEL',
1819
+ 'FIX',
1820
+ 'IGNORE'
1821
+ ],
1572
1822
  example: 'ACCEPT'
1573
1823
  },
1574
1824
  data: {
@@ -1659,6 +1909,19 @@ export const $BatchResolveDto = {
1659
1909
  action: {
1660
1910
  type: 'string',
1661
1911
  description: 'Decision action to apply to all items',
1912
+ enum: [
1913
+ 'UPGRADE_REPLACE',
1914
+ 'LINK_KEEP_BOTH',
1915
+ 'IGNORE_NEW',
1916
+ 'CONFIRM_DIFFERENT',
1917
+ 'ACCEPT',
1918
+ 'REJECT',
1919
+ 'ACCEPT_AND_LEARN',
1920
+ 'CHOOSE_OTHER',
1921
+ 'CANCEL',
1922
+ 'FIX',
1923
+ 'IGNORE'
1924
+ ],
1662
1925
  example: 'ACCEPT'
1663
1926
  },
1664
1927
  data: {
@@ -4648,49 +4911,6 @@ export const $ProviderSyncDto = {
4648
4911
  required: ['config', 'transactions']
4649
4912
  } as const;
4650
4913
 
4651
- export const $ProviderSyncResponseDto = {
4652
- type: 'object',
4653
- properties: {
4654
- imported: {
4655
- type: 'number',
4656
- description: 'Number of transactions successfully imported',
4657
- example: 10
4658
- },
4659
- skipped: {
4660
- type: 'number',
4661
- description: 'Number of transactions skipped (duplicates)',
4662
- example: 2
4663
- },
4664
- pendingReview: {
4665
- type: 'number',
4666
- description: 'Number of transactions pending review',
4667
- example: 3
4668
- },
4669
- failed: {
4670
- type: 'number',
4671
- description: 'Number of transactions that failed to import',
4672
- example: 0
4673
- },
4674
- importedTransactionIds: {
4675
- description: 'IDs of successfully imported transactions',
4676
- example: ['txn-001', 'txn-002'],
4677
- type: 'array',
4678
- items: {
4679
- type: 'string'
4680
- }
4681
- },
4682
- reviewItemIds: {
4683
- description: 'IDs of review items created for branched transactions',
4684
- example: ['review-001', 'review-002'],
4685
- type: 'array',
4686
- items: {
4687
- type: 'string'
4688
- }
4689
- }
4690
- },
4691
- required: ['imported', 'skipped', 'pendingReview', 'failed']
4692
- } as const;
4693
-
4694
4914
  export const $SupportedProvidersResponseDto = {
4695
4915
  type: 'object',
4696
4916
  properties: {
@@ -4720,6 +4940,11 @@ export const $ParserTelemetryReportDto = {
4720
4940
  properties: {}
4721
4941
  } as const;
4722
4942
 
4943
+ export const $UncoveredFormatMissDto = {
4944
+ type: 'object',
4945
+ properties: {}
4946
+ } as const;
4947
+
4723
4948
  export const $ProcessNlpDto = {
4724
4949
  type: 'object',
4725
4950
  properties: {
@@ -4749,825 +4974,599 @@ export const $ProcessNlpDto = {
4749
4974
  required: ['message']
4750
4975
  } as const;
4751
4976
 
4752
- export const $NlpTransactionInfoDto = {
4977
+ export const $BalanceByCurrencyDto = {
4753
4978
  type: 'object',
4754
4979
  properties: {
4755
- id: {
4756
- type: 'string',
4757
- description: 'Transaction ID'
4758
- },
4759
- date: {
4760
- type: 'string',
4761
- description: 'Transaction date (ISO format)'
4762
- },
4763
- amount: {
4764
- type: 'number',
4765
- description: 'Transaction amount'
4766
- },
4767
4980
  currency: {
4768
4981
  type: 'string',
4769
- description: 'Currency code'
4770
- },
4771
- payee: {
4772
- type: 'string',
4773
- description: 'Payee name'
4774
- },
4775
- narration: {
4776
- type: 'string',
4777
- description: 'Transaction narration'
4982
+ description: 'ISO 4217 currency code',
4983
+ example: 'CNY'
4778
4984
  },
4779
- warning: {
4985
+ balance: {
4780
4986
  type: 'string',
4781
- description:
4782
- 'Warning message for special transaction scenarios (e.g., cross-currency settlement)',
4783
- example: '此交易使用USD账户结算。如需记录CNY支出,请创建货币转换交易。'
4987
+ description: 'Balance amount',
4988
+ example: '50000.00'
4784
4989
  }
4785
4990
  },
4786
- required: ['id', 'date', 'amount', 'currency']
4991
+ required: ['currency', 'balance']
4787
4992
  } as const;
4788
4993
 
4789
- export const $NlpParsedDataDto = {
4994
+ export const $NetWorthByCurrencyDto = {
4790
4995
  type: 'object',
4791
4996
  properties: {
4792
- amount: {
4793
- type: 'number',
4794
- description: 'Extracted amount'
4795
- },
4796
- currency: {
4797
- type: 'string',
4798
- description: 'Currency code',
4799
- default: 'CNY'
4800
- },
4801
- date: {
4802
- type: 'string',
4803
- description: 'Transaction date (ISO format)'
4997
+ netWorth: {
4998
+ description: 'Net worth by currency',
4999
+ type: 'array',
5000
+ items: {
5001
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
5002
+ }
4804
5003
  },
4805
- payee: {
4806
- type: 'string',
4807
- description: 'Payee name'
4808
- },
4809
- narration: {
4810
- type: 'string',
4811
- description: 'Transaction narration'
4812
- },
4813
- category: {
4814
- type: 'string',
4815
- description: 'Category'
4816
- },
4817
- incomeType: {
4818
- type: 'string',
4819
- description: 'Income type (e.g., Salary, Bonus, Dividend, Interest)',
4820
- example: 'Salary'
4821
- },
4822
- incomeSource: {
4823
- type: 'string',
4824
- description: 'Income source (e.g., company name)',
4825
- example: 'Anthropic Inc.'
4826
- },
4827
- symbol: {
4828
- type: 'string',
4829
- description: 'Security symbol code (e.g., 600519, AAPL)',
4830
- example: '600519'
4831
- },
4832
- quantity: {
4833
- type: 'number',
4834
- description: 'Quantity of shares/units',
4835
- example: 100
4836
- },
4837
- price: {
4838
- type: 'number',
4839
- description: 'Unit price per share/unit',
4840
- example: 1900
4841
- },
4842
- investmentAction: {
4843
- type: 'string',
4844
- description: 'Investment action',
4845
- enum: ['buy', 'sell'],
4846
- example: 'buy'
4847
- },
4848
- paymentSource: {
4849
- type: 'string',
4850
- description: 'Payment source: asset (default) or liability (credit card)',
4851
- enum: ['asset', 'liability'],
4852
- example: 'asset'
4853
- },
4854
- liabilityHint: {
4855
- type: 'string',
4856
- description: 'Liability account hint (CreditCard/Huabei/Baitiao)',
4857
- example: 'CreditCard'
5004
+ assets: {
5005
+ description: 'Assets by currency',
5006
+ type: 'array',
5007
+ items: {
5008
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
5009
+ }
4858
5010
  },
4859
- warning: {
4860
- type: 'string',
4861
- description:
4862
- 'Warning message for special scenarios (e.g., cross-currency settlement)',
4863
- example: '此交易使用USD账户结算。如需记录CNY支出,请创建货币转换交易。'
5011
+ liabilities: {
5012
+ description: 'Liabilities by currency',
5013
+ type: 'array',
5014
+ items: {
5015
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
5016
+ }
4864
5017
  }
4865
- }
5018
+ },
5019
+ required: ['netWorth', 'assets', 'liabilities']
4866
5020
  } as const;
4867
5021
 
4868
- export const $NlpSourceTransactionDto = {
5022
+ export const $ConvertedNetWorthDto = {
4869
5023
  type: 'object',
4870
5024
  properties: {
4871
- date: {
5025
+ baseCurrency: {
4872
5026
  type: 'string',
4873
- description: 'Transaction date (ISO format)'
5027
+ description: 'Base currency for conversion',
5028
+ example: 'CNY'
4874
5029
  },
4875
- amount: {
5030
+ netWorth: {
4876
5031
  type: 'string',
4877
- description: 'Amount as string'
5032
+ description: 'Converted net worth',
5033
+ example: '500000.00'
4878
5034
  },
4879
- currency: {
5035
+ assets: {
4880
5036
  type: 'string',
4881
- description: 'Currency code'
5037
+ description: 'Converted assets',
5038
+ example: '600000.00'
4882
5039
  },
4883
- payee: {
5040
+ liabilities: {
4884
5041
  type: 'string',
4885
- description: 'Payee name'
5042
+ description: 'Converted liabilities',
5043
+ example: '100000.00'
4886
5044
  },
4887
- narration: {
4888
- type: 'string',
4889
- description: 'Transaction narration'
5045
+ exchangeRates: {
5046
+ type: 'object',
5047
+ description: 'Exchange rates used for conversion',
5048
+ example: {
5049
+ USD: '7.200000',
5050
+ EUR: '7.800000'
5051
+ }
4890
5052
  }
4891
5053
  },
4892
- required: ['date', 'amount', 'currency', 'narration']
5054
+ required: [
5055
+ 'baseCurrency',
5056
+ 'netWorth',
5057
+ 'assets',
5058
+ 'liabilities',
5059
+ 'exchangeRates'
5060
+ ]
4893
5061
  } as const;
4894
5062
 
4895
- export const $NlpTargetTransactionDto = {
5063
+ export const $ExchangeRateWarningDto = {
4896
5064
  type: 'object',
4897
5065
  properties: {
4898
- id: {
4899
- type: 'string',
4900
- description: 'Existing transaction ID'
4901
- },
4902
- date: {
4903
- type: 'string',
4904
- description: 'Transaction date (ISO format)'
4905
- },
4906
- amount: {
5066
+ type: {
4907
5067
  type: 'string',
4908
- description: 'Amount as string'
5068
+ description: 'Warning type',
5069
+ example: 'MISSING_EXCHANGE_RATE'
4909
5070
  },
4910
5071
  currency: {
4911
5072
  type: 'string',
4912
- description: 'Currency code'
4913
- },
4914
- payee: {
4915
- type: 'string',
4916
- description: 'Payee name'
5073
+ description: 'Currency without exchange rate',
5074
+ example: 'EUR'
4917
5075
  },
4918
- narration: {
5076
+ totalAmount: {
4919
5077
  type: 'string',
4920
- description: 'Transaction narration'
5078
+ description: 'Total amount affected',
5079
+ example: '1000.00'
4921
5080
  }
4922
5081
  },
4923
- required: ['id', 'date', 'amount', 'currency', 'narration']
5082
+ required: ['type', 'currency', 'totalAmount']
4924
5083
  } as const;
4925
5084
 
4926
- export const $NlpSimilarityDto = {
5085
+ export const $NetWorthResponseDto = {
4927
5086
  type: 'object',
4928
5087
  properties: {
4929
- dateMatch: {
4930
- type: 'boolean',
4931
- description: 'Whether dates match'
4932
- },
4933
- dateDiff: {
4934
- type: 'number',
4935
- description: 'Date difference in days'
5088
+ netWorth: {
5089
+ type: 'string',
5090
+ description:
5091
+ 'Total net worth (assets - liabilities, converted to base currency)',
5092
+ example: '500000.00'
4936
5093
  },
4937
- amountMatch: {
4938
- type: 'boolean',
4939
- description: 'Whether amounts match'
5094
+ assets: {
5095
+ type: 'string',
5096
+ description: 'Total assets value (converted)',
5097
+ example: '600000.00'
4940
5098
  },
4941
- amountDiff: {
5099
+ liabilities: {
4942
5100
  type: 'string',
4943
- description: 'Amount difference as decimal string'
5101
+ description: 'Total liabilities value (positive number, converted)',
5102
+ example: '100000.00'
4944
5103
  },
4945
- payeeMatch: {
4946
- type: 'boolean',
4947
- description: 'Whether payees match'
5104
+ monthlyReturn: {
5105
+ type: 'string',
5106
+ description: 'Monthly return (change from last month)',
5107
+ example: '15000.00'
4948
5108
  },
4949
- payeeSimilarity: {
4950
- type: 'number',
4951
- description: 'Payee similarity score (0-1)'
5109
+ monthlyReturnPercentage: {
5110
+ type: 'string',
5111
+ description: 'Monthly return percentage',
5112
+ example: '3.15'
4952
5113
  },
4953
- accountOverlap: {
4954
- type: 'number',
4955
- description: 'Account overlap score (0-1)'
4956
- }
4957
- },
4958
- required: [
4959
- 'dateMatch',
4960
- 'dateDiff',
4961
- 'amountMatch',
4962
- 'amountDiff',
4963
- 'payeeMatch',
4964
- 'payeeSimilarity',
4965
- 'accountOverlap'
4966
- ]
4967
- } as const;
4968
-
4969
- export const $NlpDuplicateConfirmationDataDto = {
4970
- type: 'object',
4971
- properties: {
4972
- confidence: {
4973
- type: 'number',
4974
- description: 'Duplicate detection confidence score (0.5-0.89)',
4975
- example: 0.85
5114
+ currency: {
5115
+ type: 'string',
5116
+ description: 'Base currency code',
5117
+ example: 'CNY'
4976
5118
  },
4977
- sourceTransaction: {
4978
- description:
4979
- 'Source transaction summary (the new transaction being entered)',
4980
- allOf: [
4981
- {
4982
- $ref: '#/components/schemas/NlpSourceTransactionDto'
4983
- }
4984
- ]
5119
+ asOf: {
5120
+ type: 'string',
5121
+ description: 'Data as of date (ISO 8601)',
5122
+ example: '2024-06-15T00:00:00.000Z'
4985
5123
  },
4986
- targetTransaction: {
4987
- description: 'Target transaction summary (existing potential duplicate)',
5124
+ byCurrency: {
5125
+ description: 'Balances grouped by original currency',
4988
5126
  allOf: [
4989
5127
  {
4990
- $ref: '#/components/schemas/NlpTargetTransactionDto'
5128
+ $ref: '#/components/schemas/NetWorthByCurrencyDto'
4991
5129
  }
4992
5130
  ]
4993
5131
  },
4994
- similarity: {
4995
- description: 'Detailed similarity information',
5132
+ converted: {
5133
+ description:
5134
+ 'Converted values in base currency (undefined if no exchange rates available)',
4996
5135
  allOf: [
4997
5136
  {
4998
- $ref: '#/components/schemas/NlpSimilarityDto'
5137
+ $ref: '#/components/schemas/ConvertedNetWorthDto'
4999
5138
  }
5000
5139
  ]
5001
5140
  },
5002
- reasons: {
5003
- description: 'Human-readable reasons for duplicate detection',
5004
- example: ['日期匹配', '金额匹配', '商户相似'],
5141
+ warnings: {
5142
+ description: 'Exchange rate warnings',
5005
5143
  type: 'array',
5006
5144
  items: {
5007
- type: 'string'
5145
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
5008
5146
  }
5009
5147
  }
5010
5148
  },
5011
5149
  required: [
5012
- 'confidence',
5013
- 'sourceTransaction',
5014
- 'targetTransaction',
5015
- 'similarity',
5016
- 'reasons'
5150
+ 'netWorth',
5151
+ 'assets',
5152
+ 'liabilities',
5153
+ 'monthlyReturn',
5154
+ 'monthlyReturnPercentage',
5155
+ 'currency',
5156
+ 'asOf'
5017
5157
  ]
5018
5158
  } as const;
5019
5159
 
5020
- export const $NlpRuleConfirmationDataDto = {
5160
+ export const $AccountItemDto = {
5021
5161
  type: 'object',
5022
5162
  properties: {
5023
- confidence: {
5024
- type: 'number',
5025
- description: 'Rule match confidence score (0.5-0.74)',
5026
- example: 0.65
5163
+ id: {
5164
+ type: 'string',
5165
+ description: 'Account ID'
5027
5166
  },
5028
- matchedRule: {
5029
- type: 'object',
5030
- description: 'Matched rule information'
5167
+ name: {
5168
+ type: 'string',
5169
+ description: 'Full account name',
5170
+ example: 'Assets:Bank:CMB:Savings'
5031
5171
  },
5032
- suggestedAccounts: {
5033
- type: 'object',
5034
- description: 'Suggested accounts from the rule'
5172
+ displayName: {
5173
+ type: 'string',
5174
+ description: 'Display name (last part of account path)',
5175
+ example: 'Savings'
5035
5176
  },
5036
- alternatives: {
5037
- type: 'array',
5038
- description: 'Alternative rules that also match'
5177
+ balance: {
5178
+ type: 'string',
5179
+ description: 'Account balance',
5180
+ example: '50000.00'
5039
5181
  },
5040
- reasons: {
5041
- description: 'Human-readable reasons for the match',
5042
- example: [
5043
- 'Moderate confidence (65%)',
5044
- 'Some keywords matched (OR logic)'
5045
- ],
5046
- type: 'array',
5047
- items: {
5048
- type: 'string'
5049
- }
5182
+ currency: {
5183
+ type: 'string',
5184
+ description: 'Currency code',
5185
+ example: 'CNY'
5050
5186
  }
5051
5187
  },
5052
- required: [
5053
- 'confidence',
5054
- 'matchedRule',
5055
- 'suggestedAccounts',
5056
- 'alternatives',
5057
- 'reasons'
5058
- ]
5188
+ required: ['id', 'name', 'displayName', 'balance', 'currency']
5059
5189
  } as const;
5060
5190
 
5061
- export const $NlpAccountConfirmationDataDto = {
5191
+ export const $PlatformGroupDto = {
5062
5192
  type: 'object',
5063
5193
  properties: {
5064
- invalidAccount: {
5194
+ platformId: {
5065
5195
  type: 'string',
5066
- description: 'The invalid account name',
5067
- example: 'Expenses:Food:Coffee'
5196
+ description: 'Platform ID'
5068
5197
  },
5069
- suggestedAccount: {
5198
+ platformName: {
5070
5199
  type: 'string',
5071
- description: 'Suggested replacement account',
5072
- example: 'Expenses:Food:Drinks'
5200
+ description: 'Platform display name',
5201
+ example: 'CMB Bank'
5073
5202
  },
5074
- similarAccounts: {
5075
- description: 'Similar accounts for user selection',
5203
+ accounts: {
5204
+ description: 'Accounts within this platform',
5076
5205
  type: 'array',
5077
5206
  items: {
5078
- type: 'string'
5207
+ $ref: '#/components/schemas/AccountItemDto'
5079
5208
  }
5080
5209
  },
5081
- errorMessage: {
5210
+ totalBalance: {
5082
5211
  type: 'string',
5083
- description: 'Error message explaining the issue',
5084
- example: 'No similar account found'
5085
- },
5086
- transactionContext: {
5087
- type: 'object',
5088
- description: 'Transaction context for reference'
5212
+ description: 'Total balance across all accounts in platform',
5213
+ example: '100000.00'
5089
5214
  }
5090
5215
  },
5091
- required: [
5092
- 'invalidAccount',
5093
- 'suggestedAccount',
5094
- 'similarAccounts',
5095
- 'errorMessage',
5096
- 'transactionContext'
5097
- ]
5216
+ required: ['platformId', 'platformName', 'accounts', 'totalBalance']
5098
5217
  } as const;
5099
5218
 
5100
- export const $NlpSuggestedPayeeDto = {
5219
+ export const $AccountsSummaryDto = {
5101
5220
  type: 'object',
5102
5221
  properties: {
5103
- id: {
5104
- type: 'string',
5105
- description: 'Payee ID',
5106
- example: 'payee-123'
5107
- },
5108
- name: {
5109
- type: 'string',
5110
- description: 'Payee name',
5111
- example: 'Starbucks'
5112
- },
5113
- category: {
5114
- type: 'string',
5115
- description: 'Payee category',
5116
- example: 'food'
5117
- },
5118
- source: {
5119
- type: 'string',
5120
- description: 'Source of the payee',
5121
- enum: ['user', 'global']
5222
+ totalAccounts: {
5223
+ type: 'number',
5224
+ description: 'Total number of accounts'
5122
5225
  },
5123
- payeeProfileId: {
5124
- type: 'string',
5125
- description: 'PayeeProfile ID (if matched from global)',
5126
- example: 'profile-456'
5226
+ totalPlatforms: {
5227
+ type: 'number',
5228
+ description: 'Total number of platforms'
5127
5229
  }
5128
5230
  },
5129
- required: ['id', 'name']
5231
+ required: ['totalAccounts', 'totalPlatforms']
5130
5232
  } as const;
5131
5233
 
5132
- export const $NlpAlternativePayeeDto = {
5234
+ export const $AccountsResponseDto = {
5133
5235
  type: 'object',
5134
5236
  properties: {
5135
- id: {
5136
- type: 'string',
5137
- description: 'Payee ID',
5138
- example: 'payee-alt-1'
5139
- },
5140
- name: {
5141
- type: 'string',
5142
- description: 'Payee name',
5143
- example: 'Starbucks Coffee'
5237
+ groups: {
5238
+ description: 'Account groups by platform',
5239
+ type: 'array',
5240
+ items: {
5241
+ $ref: '#/components/schemas/PlatformGroupDto'
5242
+ }
5144
5243
  },
5145
- similarity: {
5146
- type: 'number',
5147
- description: 'Similarity score (0-1)',
5148
- example: 0.75
5244
+ summary: {
5245
+ description: 'Summary statistics',
5246
+ allOf: [
5247
+ {
5248
+ $ref: '#/components/schemas/AccountsSummaryDto'
5249
+ }
5250
+ ]
5149
5251
  }
5150
5252
  },
5151
- required: ['id', 'name', 'similarity']
5253
+ required: ['groups', 'summary']
5152
5254
  } as const;
5153
5255
 
5154
- export const $NlpPayeeConfirmationDataDto = {
5256
+ export const $AccountItemWithAssetClassDto = {
5155
5257
  type: 'object',
5156
5258
  properties: {
5157
- confidence: {
5158
- type: 'number',
5159
- description: 'Confidence score for the payee match (0-1)',
5160
- example: 0.65
5259
+ id: {
5260
+ type: 'string',
5261
+ description: 'Account ID'
5161
5262
  },
5162
- originalPayee: {
5263
+ name: {
5163
5264
  type: 'string',
5164
- description: 'Original payee string from user input',
5165
- example: '星巴'
5265
+ description: 'Full account name',
5266
+ example: 'Assets:Bank:CMB:Savings'
5166
5267
  },
5167
- suggestedPayee: {
5168
- description: 'Suggested payee to use (null when no similar payees found)',
5169
- nullable: true,
5170
- allOf: [
5171
- {
5172
- $ref: '#/components/schemas/NlpSuggestedPayeeDto'
5173
- }
5268
+ displayName: {
5269
+ type: 'string',
5270
+ description: 'Display name (last part of account path)',
5271
+ example: 'Savings'
5272
+ },
5273
+ balance: {
5274
+ type: 'string',
5275
+ description: 'Account balance',
5276
+ example: '50000.00'
5277
+ },
5278
+ currency: {
5279
+ type: 'string',
5280
+ description: 'Currency code',
5281
+ example: 'CNY'
5282
+ },
5283
+ assetClass: {
5284
+ type: 'string',
5285
+ description: 'Asset class',
5286
+ example: 'LIQUIDITY'
5287
+ },
5288
+ assetSubClass: {
5289
+ type: 'string',
5290
+ description: 'Asset sub-class (Prisma-compatible)',
5291
+ example: 'RETIREMENT_ACCOUNT'
5292
+ },
5293
+ regionalSubClass: {
5294
+ type: 'string',
5295
+ description: 'Regional sub-class (region-specific, for display)',
5296
+ example: 'FOUR_ZERO_ONE_K'
5297
+ },
5298
+ riskLevel: {
5299
+ type: 'string',
5300
+ description: 'Risk level',
5301
+ example: 'LOW'
5302
+ },
5303
+ source: {
5304
+ type: 'string',
5305
+ description:
5306
+ 'ADR-0105 classification provenance (holding level always; account level only on FALLBACK)',
5307
+ enum: ['USER_META', 'FIAT_CURRENCY', 'OPENBB_MAPPING', 'FALLBACK']
5308
+ }
5309
+ },
5310
+ required: ['id', 'name', 'displayName', 'balance', 'currency', 'assetClass']
5311
+ } as const;
5312
+
5313
+ export const $AssetClassGroupDto = {
5314
+ type: 'object',
5315
+ properties: {
5316
+ assetClass: {
5317
+ type: 'string',
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'
5174
5332
  ]
5175
5333
  },
5176
- similarity: {
5177
- type: 'number',
5178
- description: 'Similarity score between original and suggested (0-1)',
5179
- example: 0.85
5334
+ assetSubClass: {
5335
+ type: 'string',
5336
+ description: 'Asset sub-class name',
5337
+ example: 'DEPOSIT'
5180
5338
  },
5181
- alternatives: {
5182
- description: 'Alternative payee options',
5339
+ accounts: {
5340
+ description: 'Accounts within this asset class',
5183
5341
  type: 'array',
5184
5342
  items: {
5185
- $ref: '#/components/schemas/NlpAlternativePayeeDto'
5343
+ $ref: '#/components/schemas/AccountItemWithAssetClassDto'
5186
5344
  }
5187
5345
  },
5188
- reasons: {
5189
- description: 'Human-readable reasons for the match',
5190
- example: ['Moderate similarity (65%)', 'Fuzzy match on name'],
5346
+ balanceByCurrency: {
5347
+ description: 'Balances grouped by currency',
5191
5348
  type: 'array',
5192
5349
  items: {
5193
- type: 'string'
5350
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
5194
5351
  }
5352
+ },
5353
+ convertedBalance: {
5354
+ type: 'string',
5355
+ description: 'Converted balance in base currency',
5356
+ example: '100000.00'
5195
5357
  }
5196
5358
  },
5197
- required: [
5198
- 'confidence',
5199
- 'originalPayee',
5200
- 'similarity',
5201
- 'alternatives',
5202
- 'reasons'
5203
- ]
5359
+ required: ['assetClass', 'accounts', 'balanceByCurrency']
5204
5360
  } as const;
5205
5361
 
5206
- export const $RecurringMatchInfoDto = {
5362
+ export const $AccountExchangeRateWarningDto = {
5207
5363
  type: 'object',
5208
5364
  properties: {
5209
- expectedId: {
5210
- type: 'string',
5211
- description: 'Expected transaction ID'
5212
- },
5213
- ruleId: {
5365
+ type: {
5214
5366
  type: 'string',
5215
- description: 'Recurring rule ID'
5367
+ description: 'Warning type',
5368
+ example: 'MISSING_EXCHANGE_RATE'
5216
5369
  },
5217
- ruleName: {
5370
+ currency: {
5218
5371
  type: 'string',
5219
- description: 'Rule name for display'
5372
+ description: 'Currency without exchange rate',
5373
+ example: 'USD'
5220
5374
  },
5221
- ruleIcon: {
5222
- type: 'string',
5223
- description: 'Rule icon'
5375
+ accounts: {
5376
+ description: 'Affected account paths',
5377
+ type: 'array',
5378
+ items: {
5379
+ type: 'string'
5380
+ }
5224
5381
  },
5225
- expectedDate: {
5382
+ totalAmount: {
5226
5383
  type: 'string',
5227
- description: 'Expected date (YYYY-MM-DD)',
5228
- example: '2026-01-05'
5229
- },
5230
- expectedAmount: {
5231
- type: 'number',
5232
- description: 'Expected amount',
5233
- example: 3000
5234
- },
5235
- confidence: {
5236
- type: 'number',
5237
- description: 'Match confidence score (0-1)',
5238
- example: 0.88
5239
- },
5240
- isAutoMatched: {
5241
- type: 'boolean',
5242
- description: 'Whether auto-matched (confidence >= 0.82)'
5384
+ description: 'Total amount in this currency',
5385
+ example: '5000.00'
5243
5386
  }
5244
5387
  },
5245
- required: [
5246
- 'expectedId',
5247
- 'ruleId',
5248
- 'ruleName',
5249
- 'expectedDate',
5250
- 'expectedAmount',
5251
- 'confidence',
5252
- 'isAutoMatched'
5253
- ]
5388
+ required: ['type', 'currency', 'accounts', 'totalAmount']
5254
5389
  } as const;
5255
5390
 
5256
- export const $NlpSuggestedAccountDto = {
5391
+ export const $AssetClassSummaryDto = {
5257
5392
  type: 'object',
5258
5393
  properties: {
5259
- account: {
5260
- type: 'string',
5261
- description: 'Suggested account path',
5262
- example: 'Assets:Bank:Checking'
5394
+ totalAccounts: {
5395
+ type: 'number',
5396
+ description: 'Total number of accounts'
5263
5397
  },
5264
- confidence: {
5398
+ totalAssetClasses: {
5265
5399
  type: 'number',
5266
- description: 'Confidence score for this suggestion (0-1)',
5267
- example: 0.9
5400
+ description: 'Total number of asset classes'
5401
+ },
5402
+ baseCurrency: {
5403
+ type: 'string',
5404
+ description: 'Base currency for conversion',
5405
+ example: 'CNY'
5406
+ },
5407
+ warnings: {
5408
+ description: 'Exchange rate warnings',
5409
+ type: 'array',
5410
+ items: {
5411
+ $ref: '#/components/schemas/AccountExchangeRateWarningDto'
5412
+ }
5413
+ },
5414
+ fallback: {
5415
+ type: 'object',
5416
+ description:
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.'
5268
5418
  }
5269
5419
  },
5270
- required: ['account']
5420
+ required: ['totalAccounts', 'totalAssetClasses', 'baseCurrency']
5271
5421
  } as const;
5272
5422
 
5273
- export const $NlpSuggestedAccountsDto = {
5423
+ export const $AssetClassAccountsResponseDto = {
5274
5424
  type: 'object',
5275
5425
  properties: {
5276
- source: {
5277
- description:
5278
- 'Source account suggestion (where money comes from). For expense: asset/liability account. For income: income account.',
5426
+ groups: {
5427
+ description: 'Account groups by asset class',
5428
+ type: 'array',
5429
+ items: {
5430
+ $ref: '#/components/schemas/AssetClassGroupDto'
5431
+ }
5432
+ },
5433
+ summary: {
5434
+ description: 'Summary statistics',
5279
5435
  allOf: [
5280
5436
  {
5281
- $ref: '#/components/schemas/NlpSuggestedAccountDto'
5437
+ $ref: '#/components/schemas/AssetClassSummaryDto'
5282
5438
  }
5283
5439
  ]
5284
5440
  },
5285
- destination: {
5441
+ uncategorized: {
5286
5442
  description:
5287
- 'Destination account suggestion (where money goes to). For expense: expense account. For income: asset/liability account.',
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.',
5288
5444
  allOf: [
5289
5445
  {
5290
- $ref: '#/components/schemas/NlpSuggestedAccountDto'
5446
+ $ref: '#/components/schemas/AssetClassGroupDto'
5291
5447
  }
5292
5448
  ]
5293
5449
  }
5294
- }
5295
- } as const;
5296
-
5297
- export const $NlpDefaultAccountsDto = {
5298
- type: 'object',
5299
- properties: {
5300
- asset: {
5301
- type: 'string',
5302
- description: 'Default asset account',
5303
- example: 'Assets:Bank:Checking'
5304
- },
5305
- expense: {
5306
- type: 'string',
5307
- description: 'Default expense account',
5308
- example: 'Expenses:Uncategorized'
5309
- },
5310
- income: {
5311
- type: 'string',
5312
- description: 'Default income account',
5313
- example: 'Income:Uncategorized'
5314
- },
5315
- liability: {
5316
- type: 'string',
5317
- description: 'Default liability account',
5318
- example: 'Liabilities:CreditCard'
5319
- }
5320
5450
  },
5321
- required: ['asset', 'expense', 'income', 'liability']
5451
+ required: ['groups', 'summary']
5322
5452
  } as const;
5323
5453
 
5324
- export const $NlpResponseDto = {
5454
+ export const $HoldingAssetClassAccountSliceDto = {
5325
5455
  type: 'object',
5326
5456
  properties: {
5327
- status: {
5328
- type: 'string',
5329
- description: 'Response status',
5330
- enum: ['success', 'pending', 'error']
5331
- },
5332
- action: {
5333
- type: 'string',
5334
- description: 'Action taken or requested',
5335
- enum: [
5336
- 'created',
5337
- 'ask',
5338
- 'confirm',
5339
- 'confirm_duplicate',
5340
- 'confirm_rule',
5341
- 'confirm_account',
5342
- 'confirm_payee',
5343
- 'cancel'
5344
- ]
5345
- },
5346
- intent: {
5347
- type: 'string',
5348
- description:
5349
- 'Transaction intent detected by EntityRouter (v6.0: 5 core intents). Frontend uses this to render scenario-specific form fields.',
5350
- enum: ['expense', 'asset', 'income', 'liability', 'equity'],
5351
- example: 'expense'
5352
- },
5353
- assetSubType: {
5457
+ accountId: {
5354
5458
  type: 'string',
5355
- description:
5356
- 'Asset sub-type (only present when intent is "asset"). Determines which asset-related form to render.',
5357
- enum: ['transfer', 'banking', 'investment'],
5358
- example: 'investment'
5459
+ description: 'Account ID'
5359
5460
  },
5360
- liabilitySubType: {
5461
+ accountPath: {
5361
5462
  type: 'string',
5362
- description:
5363
- 'Liability sub-type (only present when intent is "liability"). borrow: borrowing money (Liabilities → Assets), repay: repaying debt (Assets → Liabilities).',
5364
- enum: ['borrow', 'repay'],
5365
- example: 'borrow'
5463
+ description: 'Full account path',
5464
+ example: 'Assets:US:Investments:Brokerage'
5366
5465
  },
5367
- equitySubType: {
5466
+ accountCurrency: {
5368
5467
  type: 'string',
5369
5468
  description:
5370
- 'Equity sub-type (only present when intent is "equity"). opening: account opening balance (Equity → Assets), adjustment: balance correction.',
5371
- enum: ['opening', 'adjustment'],
5372
- example: 'opening'
5469
+ 'Currency of the holding with the largest converted base value; undefined when no holding is convertible',
5470
+ example: 'USD'
5373
5471
  },
5374
- paymentSource: {
5472
+ marketValueBase: {
5375
5473
  type: 'string',
5376
5474
  description:
5377
- 'Payment source for expense transactions (v6.1). Indicates whether payment comes from asset or liability account. Only present when intent is "expense".',
5378
- enum: ['asset', 'liability'],
5379
- example: 'liability'
5475
+ "Account's market value in base currency (Σ converted holdings; grey bucket included)",
5476
+ example: '50000.00'
5380
5477
  },
5381
- liabilityHint: {
5382
- type: 'string',
5478
+ shareOfTotalPct: {
5479
+ type: 'number',
5383
5480
  description:
5384
- 'Liability account type hint for credit card/BNPL spending (v6.1). Only present when paymentSource is "liability". Values: CreditCard, Huabei, Baitiao',
5385
- example: 'CreditCard'
5481
+ 'Share of the global total (0-100). 0 when globalTotal is zero (no NaN/Infinity).',
5482
+ example: 42.5
5386
5483
  },
5387
- message: {
5388
- type: 'string',
5389
- description:
5390
- 'Human-readable message (for ask or error actions). Deprecated: Use messageKey for i18n support.',
5391
- example: 'How much did you spend?',
5392
- deprecated: true
5484
+ groups: {
5485
+ description: 'Per-account asset-class breakdown',
5486
+ type: 'array',
5487
+ items: {
5488
+ $ref: '#/components/schemas/AssetClassGroupDto'
5489
+ }
5393
5490
  },
5394
- messageKey: {
5395
- type: 'string',
5491
+ uncategorized: {
5396
5492
  description:
5397
- 'i18n message key for frontend translation. Use this instead of message for internationalization support.',
5398
- example: 'nlp.slot.prompt'
5493
+ 'Per-account grey bucket (source=FALLBACK holdings, incl. broker cash)',
5494
+ allOf: [
5495
+ {
5496
+ $ref: '#/components/schemas/AssetClassGroupDto'
5497
+ }
5498
+ ]
5399
5499
  },
5400
- messageParams: {
5401
- type: 'object',
5500
+ holdings: {
5402
5501
  description:
5403
- 'Parameters for message interpolation. Used with messageKey for dynamic values in translated messages.',
5404
- example: {
5405
- slot: 'amount',
5406
- name: 'Starbucks',
5407
- similarity: 85
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'
5408
5506
  }
5409
- },
5410
- sessionId: {
5411
- type: 'string',
5412
- description:
5413
- 'Session ID for multi-turn dialogue. Must be included in subsequent requests to continue the conversation.',
5414
- example: 'session_abc123'
5415
- },
5416
- waitingFor: {
5417
- type: 'string',
5418
- description: 'Which slot is waiting for user input',
5419
- example: 'amount'
5420
- },
5421
- transaction: {
5422
- description: 'Created transaction info (for created action)',
5423
- allOf: [
5424
- {
5425
- $ref: '#/components/schemas/NlpTransactionInfoDto'
5426
- }
5427
- ]
5428
- },
5429
- parsedData: {
5430
- description:
5431
- 'Parsed data for confirmation (when action is "confirm"). Contains extracted fields that user should verify before transaction creation.',
5432
- allOf: [
5433
- {
5434
- $ref: '#/components/schemas/NlpParsedDataDto'
5435
- }
5436
- ]
5437
- },
5438
- duplicateData: {
5439
- description:
5440
- 'Duplicate detection data (when action is "confirm_duplicate"). Contains information about potential duplicate transaction for user confirmation.',
5441
- allOf: [
5442
- {
5443
- $ref: '#/components/schemas/NlpDuplicateConfirmationDataDto'
5444
- }
5445
- ]
5446
- },
5447
- ruleData: {
5448
- description:
5449
- 'Rule match data (when action is "confirm_rule"). Contains information about medium-confidence rule match for user confirmation.',
5450
- allOf: [
5451
- {
5452
- $ref: '#/components/schemas/NlpRuleConfirmationDataDto'
5453
- }
5454
- ]
5455
- },
5456
- accountData: {
5457
- description:
5458
- 'Account validation data (when action is "confirm_account"). Contains information about invalid account for user correction.',
5459
- allOf: [
5460
- {
5461
- $ref: '#/components/schemas/NlpAccountConfirmationDataDto'
5462
- }
5463
- ]
5464
- },
5465
- payeeData: {
5466
- description:
5467
- 'Payee confirmation data (when action is "confirm_payee"). Contains information about medium/low confidence payee match for user confirmation.',
5468
- allOf: [
5469
- {
5470
- $ref: '#/components/schemas/NlpPayeeConfirmationDataDto'
5471
- }
5472
- ]
5473
- },
5474
- confidence: {
5475
- type: 'number',
5476
- description: 'Overall confidence score (0-1)',
5477
- example: 0.85
5478
- },
5479
- confidenceThreshold: {
5480
- type: 'number',
5481
- description:
5482
- 'Confidence threshold for automatic creation (default: 0.75). When confidence < threshold, action will be "confirm" requiring user verification.',
5483
- example: 0.75
5484
- },
5485
- recurringMatch: {
5486
- description:
5487
- 'Recurring transaction match info (when action is "created"). Contains match details when transaction matches a pending expected transaction.',
5488
- allOf: [
5489
- {
5490
- $ref: '#/components/schemas/RecurringMatchInfoDto'
5491
- }
5492
- ]
5493
- },
5494
- recurringSuggestion: {
5495
- description:
5496
- '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.',
5497
- allOf: [
5498
- {
5499
- $ref: '#/components/schemas/RecurringSuggestionDto'
5500
- }
5501
- ]
5502
- },
5503
- suggestedAccounts: {
5504
- description:
5505
- 'Suggested accounts for this transaction. Contains recommended source and destination accounts based on the detected intent and rules.',
5506
- allOf: [
5507
- {
5508
- $ref: '#/components/schemas/NlpSuggestedAccountsDto'
5509
- }
5510
- ]
5511
- },
5512
- defaultAccounts: {
5513
- description:
5514
- 'Default accounts for the user/region. These are fallback accounts used when no specific suggestion is available.',
5515
- allOf: [
5516
- {
5517
- $ref: '#/components/schemas/NlpDefaultAccountsDto'
5518
- }
5519
- ]
5520
5507
  }
5521
5508
  },
5522
- required: ['status', 'action']
5509
+ required: [
5510
+ 'accountId',
5511
+ 'accountPath',
5512
+ 'marketValueBase',
5513
+ 'shareOfTotalPct',
5514
+ 'groups',
5515
+ 'holdings'
5516
+ ]
5523
5517
  } as const;
5524
5518
 
5525
- export const $BalanceByCurrencyDto = {
5519
+ export const $HoldingAssetClassCrossAccountResponseDto = {
5526
5520
  type: 'object',
5527
5521
  properties: {
5528
- currency: {
5529
- type: 'string',
5530
- description: 'ISO 4217 currency code',
5531
- example: 'CNY'
5522
+ global: {
5523
+ description: 'Merged cross-account holding aggregation',
5524
+ allOf: [
5525
+ {
5526
+ $ref: '#/components/schemas/AssetClassAccountsResponseDto'
5527
+ }
5528
+ ]
5532
5529
  },
5533
- balance: {
5534
- type: 'string',
5535
- description: 'Balance amount',
5536
- example: '50000.00'
5530
+ byAccount: {
5531
+ description: 'Per-account slices',
5532
+ type: 'array',
5533
+ items: {
5534
+ $ref: '#/components/schemas/HoldingAssetClassAccountSliceDto'
5535
+ }
5537
5536
  }
5538
5537
  },
5539
- required: ['currency', 'balance']
5538
+ required: ['global', 'byAccount']
5540
5539
  } as const;
5541
5540
 
5542
- export const $NetWorthByCurrencyDto = {
5541
+ export const $CashFlowByCurrencyDto = {
5543
5542
  type: 'object',
5544
5543
  properties: {
5545
- netWorth: {
5546
- description: 'Net worth by currency',
5544
+ income: {
5545
+ description: 'Income by currency',
5547
5546
  type: 'array',
5548
5547
  items: {
5549
5548
  $ref: '#/components/schemas/BalanceByCurrencyDto'
5550
5549
  }
5551
5550
  },
5552
- assets: {
5553
- description: 'Assets by currency',
5551
+ expense: {
5552
+ description: 'Expense by currency',
5554
5553
  type: 'array',
5555
5554
  items: {
5556
5555
  $ref: '#/components/schemas/BalanceByCurrencyDto'
5557
5556
  }
5558
5557
  },
5559
- liabilities: {
5560
- description: 'Liabilities by currency',
5558
+ netSavings: {
5559
+ description: 'Net savings by currency',
5561
5560
  type: 'array',
5562
5561
  items: {
5563
5562
  $ref: '#/components/schemas/BalanceByCurrencyDto'
5564
5563
  }
5565
5564
  }
5566
5565
  },
5567
- required: ['netWorth', 'assets', 'liabilities']
5566
+ required: ['income', 'expense', 'netSavings']
5568
5567
  } as const;
5569
5568
 
5570
- export const $ConvertedNetWorthDto = {
5569
+ export const $ConvertedCashFlowDto = {
5571
5570
  type: 'object',
5572
5571
  properties: {
5573
5572
  baseCurrency: {
@@ -5575,114 +5574,78 @@ export const $ConvertedNetWorthDto = {
5575
5574
  description: 'Base currency for conversion',
5576
5575
  example: 'CNY'
5577
5576
  },
5578
- netWorth: {
5577
+ income: {
5579
5578
  type: 'string',
5580
- description: 'Converted net worth',
5581
- example: '500000.00'
5579
+ description: 'Converted income',
5580
+ example: '25000.00'
5582
5581
  },
5583
- assets: {
5582
+ expense: {
5584
5583
  type: 'string',
5585
- description: 'Converted assets',
5586
- example: '600000.00'
5584
+ description: 'Converted expense',
5585
+ example: '18000.00'
5587
5586
  },
5588
- liabilities: {
5587
+ netSavings: {
5589
5588
  type: 'string',
5590
- description: 'Converted liabilities',
5591
- example: '100000.00'
5589
+ description: 'Converted net savings',
5590
+ example: '7000.00'
5592
5591
  },
5593
5592
  exchangeRates: {
5594
5593
  type: 'object',
5595
5594
  description: 'Exchange rates used for conversion',
5596
5595
  example: {
5597
- USD: '7.200000',
5598
- EUR: '7.800000'
5596
+ USD: '7.200000'
5599
5597
  }
5600
5598
  }
5601
5599
  },
5602
- required: [
5603
- 'baseCurrency',
5604
- 'netWorth',
5605
- 'assets',
5606
- 'liabilities',
5607
- 'exchangeRates'
5608
- ]
5609
- } as const;
5610
-
5611
- export const $ExchangeRateWarningDto = {
5612
- type: 'object',
5613
- properties: {
5614
- type: {
5615
- type: 'string',
5616
- description: 'Warning type',
5617
- example: 'MISSING_EXCHANGE_RATE'
5618
- },
5619
- currency: {
5620
- type: 'string',
5621
- description: 'Currency without exchange rate',
5622
- example: 'EUR'
5623
- },
5624
- totalAmount: {
5625
- type: 'string',
5626
- description: 'Total amount affected',
5627
- example: '1000.00'
5628
- }
5629
- },
5630
- required: ['type', 'currency', 'totalAmount']
5600
+ required: ['baseCurrency', 'income', 'expense', 'netSavings', 'exchangeRates']
5631
5601
  } as const;
5632
5602
 
5633
- export const $NetWorthResponseDto = {
5603
+ export const $CashFlowResponseDto = {
5634
5604
  type: 'object',
5635
5605
  properties: {
5636
- netWorth: {
5606
+ period: {
5637
5607
  type: 'string',
5638
- description:
5639
- 'Total net worth (assets - liabilities, converted to base currency)',
5640
- example: '500000.00'
5608
+ description: 'Period identifier (YYYY-MM)',
5609
+ example: '2024-06'
5641
5610
  },
5642
- assets: {
5611
+ income: {
5643
5612
  type: 'string',
5644
- description: 'Total assets value (converted)',
5645
- example: '600000.00'
5613
+ description: 'Total income for the period (converted)',
5614
+ example: '25000.00'
5646
5615
  },
5647
- liabilities: {
5616
+ expense: {
5648
5617
  type: 'string',
5649
- description: 'Total liabilities value (positive number, converted)',
5650
- example: '100000.00'
5618
+ description: 'Total expenses for the period (converted)',
5619
+ example: '18000.00'
5651
5620
  },
5652
- monthlyReturn: {
5621
+ netSavings: {
5653
5622
  type: 'string',
5654
- description: 'Monthly return (change from last month)',
5655
- example: '15000.00'
5623
+ description: 'Net savings (income - expense, converted)',
5624
+ example: '7000.00'
5656
5625
  },
5657
- monthlyReturnPercentage: {
5626
+ savingsRate: {
5658
5627
  type: 'string',
5659
- description: 'Monthly return percentage',
5660
- example: '3.15'
5628
+ description: 'Savings rate percentage (netSavings / income * 100)',
5629
+ example: '28.00'
5661
5630
  },
5662
5631
  currency: {
5663
5632
  type: 'string',
5664
5633
  description: 'Base currency code',
5665
5634
  example: 'CNY'
5666
5635
  },
5667
- asOf: {
5668
- type: 'string',
5669
- description: 'Data as of date (ISO 8601)',
5670
- example: '2024-06-15T00:00:00.000Z'
5671
- },
5672
5636
  byCurrency: {
5673
- description: 'Balances grouped by original currency',
5637
+ description: 'Cash flow grouped by original currency',
5674
5638
  allOf: [
5675
5639
  {
5676
- $ref: '#/components/schemas/NetWorthByCurrencyDto'
5640
+ $ref: '#/components/schemas/CashFlowByCurrencyDto'
5677
5641
  }
5678
5642
  ]
5679
5643
  },
5680
5644
  converted: {
5681
- description:
5682
- 'Converted values in base currency (undefined if no exchange rates available)',
5645
+ description: 'Converted values in base currency',
5683
5646
  allOf: [
5684
5647
  {
5685
- $ref: '#/components/schemas/ConvertedNetWorthDto'
5648
+ $ref: '#/components/schemas/ConvertedCashFlowDto'
5686
5649
  }
5687
5650
  ]
5688
5651
  },
@@ -5695,417 +5658,459 @@ export const $NetWorthResponseDto = {
5695
5658
  }
5696
5659
  },
5697
5660
  required: [
5698
- 'netWorth',
5699
- 'assets',
5700
- 'liabilities',
5701
- 'monthlyReturn',
5702
- 'monthlyReturnPercentage',
5703
- 'currency',
5704
- 'asOf'
5661
+ 'period',
5662
+ 'income',
5663
+ 'expense',
5664
+ 'netSavings',
5665
+ 'savingsRate',
5666
+ 'currency'
5705
5667
  ]
5706
5668
  } as const;
5707
5669
 
5708
- export const $AccountItemDto = {
5670
+ export const $MonetaryDto = {
5709
5671
  type: 'object',
5710
5672
  properties: {
5711
- id: {
5712
- type: 'string',
5713
- description: 'Account ID'
5714
- },
5715
- name: {
5716
- type: 'string',
5717
- description: 'Full account name',
5718
- example: 'Assets:Bank:CMB:Savings'
5719
- },
5720
- displayName: {
5721
- type: 'string',
5722
- description: 'Display name (last part of account path)',
5723
- example: 'Savings'
5724
- },
5725
- balance: {
5673
+ amount: {
5726
5674
  type: 'string',
5727
- description: 'Account balance',
5728
- example: '50000.00'
5675
+ description: 'Amount (Decimal string)',
5676
+ example: '3000'
5729
5677
  },
5730
5678
  currency: {
5731
5679
  type: 'string',
5732
- description: 'Currency code',
5733
- 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
5734
5688
  }
5735
5689
  },
5736
- required: ['id', 'name', 'displayName', 'balance', 'currency']
5690
+ required: ['amount', 'currency']
5737
5691
  } as const;
5738
5692
 
5739
- export const $PlatformGroupDto = {
5693
+ export const $CurrentPriceDto = {
5740
5694
  type: 'object',
5741
5695
  properties: {
5742
- platformId: {
5696
+ amount: {
5743
5697
  type: 'string',
5744
- description: 'Platform ID'
5698
+ description: 'Price amount (Decimal string)',
5699
+ example: '250'
5745
5700
  },
5746
- platformName: {
5701
+ currency: {
5747
5702
  type: 'string',
5748
- description: 'Platform display name',
5749
- example: 'CMB Bank'
5703
+ description: 'Price currency (ISO 4217)',
5704
+ example: 'USD'
5750
5705
  },
5751
- accounts: {
5752
- description: 'Accounts within this platform',
5753
- type: 'array',
5754
- items: {
5755
- $ref: '#/components/schemas/AccountItemDto'
5756
- }
5706
+ date: {
5707
+ type: 'string',
5708
+ description: 'Price date (ISO 8601)',
5709
+ example: '2024-06-01'
5757
5710
  },
5758
- totalBalance: {
5711
+ source: {
5759
5712
  type: 'string',
5760
- description: 'Total balance across all accounts in platform',
5761
- example: '100000.00'
5713
+ description: 'Price source',
5714
+ example: 'USER_OVERRIDE',
5715
+ enum: ['USER_OVERRIDE', 'OPENBB_EQUITY', 'OPENBB_CURRENCY']
5762
5716
  }
5763
5717
  },
5764
- required: ['platformId', 'platformName', 'accounts', 'totalBalance']
5718
+ required: ['amount', 'currency', 'date', 'source']
5765
5719
  } as const;
5766
5720
 
5767
- export const $AccountsSummaryDto = {
5721
+ export const $FxRateDto = {
5768
5722
  type: 'object',
5769
5723
  properties: {
5770
- totalAccounts: {
5771
- type: 'number',
5772
- description: 'Total number of accounts'
5724
+ from: {
5725
+ type: 'string',
5726
+ example: 'USD'
5773
5727
  },
5774
- totalPlatforms: {
5775
- type: 'number',
5776
- description: 'Total number of platforms'
5777
- }
5778
- },
5779
- required: ['totalAccounts', 'totalPlatforms']
5780
- } as const;
5781
-
5782
- export const $AccountsResponseDto = {
5783
- type: 'object',
5784
- properties: {
5785
- groups: {
5786
- description: 'Account groups by platform',
5787
- type: 'array',
5788
- items: {
5789
- $ref: '#/components/schemas/PlatformGroupDto'
5790
- }
5728
+ to: {
5729
+ type: 'string',
5730
+ example: 'CNY'
5791
5731
  },
5792
- summary: {
5793
- description: 'Summary statistics',
5794
- allOf: [
5795
- {
5796
- $ref: '#/components/schemas/AccountsSummaryDto'
5797
- }
5798
- ]
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'
5799
5741
  }
5800
5742
  },
5801
- required: ['groups', 'summary']
5743
+ required: ['from', 'to', 'rate', 'date']
5802
5744
  } as const;
5803
5745
 
5804
- export const $AccountItemWithAssetClassDto = {
5746
+ export const $HoldingPnlRowDto = {
5805
5747
  type: 'object',
5806
5748
  properties: {
5807
- id: {
5749
+ accountId: {
5808
5750
  type: 'string',
5809
- description: 'Account ID'
5751
+ description: 'Account UUID',
5752
+ example: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
5810
5753
  },
5811
- name: {
5754
+ accountPath: {
5812
5755
  type: 'string',
5813
- description: 'Full account name',
5814
- example: 'Assets:Bank:CMB:Savings'
5756
+ description: 'Full account path',
5757
+ example: 'Assets:US:Broker:AAPL'
5815
5758
  },
5816
- displayName: {
5817
- type: 'string',
5818
- description: 'Display name (last part of account path)',
5819
- example: 'Savings'
5759
+ accountCcy: {
5760
+ type: 'object',
5761
+ description: 'Account settlement currency (ISO 4217), from cost currency',
5762
+ nullable: true,
5763
+ example: 'USD'
5820
5764
  },
5821
- balance: {
5765
+ brokerType: {
5766
+ type: 'object',
5767
+ description: 'Broker type derived from Platform.type',
5768
+ nullable: true,
5769
+ example: 'broker'
5770
+ },
5771
+ symbol: {
5822
5772
  type: 'string',
5823
- description: 'Account balance',
5824
- example: '50000.00'
5773
+ description: 'Commodity symbol',
5774
+ example: 'AAPL'
5825
5775
  },
5826
- currency: {
5776
+ chartToken: {
5827
5777
  type: 'string',
5828
- description: 'Currency code',
5829
- example: 'CNY'
5778
+ description: 'Chart segment token (libs/common resolver)',
5779
+ example: 'equity',
5780
+ enum: ['equity', 'fund', 'bond', 'cash', 'other']
5830
5781
  },
5831
5782
  assetClass: {
5832
5783
  type: 'string',
5833
- description: 'Asset class',
5834
- example: 'LIQUIDITY'
5784
+ example: 'EQUITY'
5835
5785
  },
5836
5786
  assetSubClass: {
5837
- type: 'string',
5838
- description: 'Asset sub-class (Prisma-compatible)',
5839
- example: 'RETIREMENT_ACCOUNT'
5787
+ type: 'object',
5788
+ nullable: true,
5789
+ example: 'STOCK'
5840
5790
  },
5841
- regionalSubClass: {
5791
+ units: {
5842
5792
  type: 'string',
5843
- description: 'Regional sub-class (region-specific, for display)',
5844
- example: 'FOUR_ZERO_ONE_K'
5793
+ description: 'Net held units (Decimal string)',
5794
+ example: '12'
5845
5795
  },
5846
- riskLevel: {
5847
- type: 'string',
5848
- description: 'Risk level',
5849
- example: 'LOW'
5850
- }
5851
- },
5852
- required: ['id', 'name', 'displayName', 'balance', 'currency', 'assetClass']
5853
- } as const;
5854
-
5855
- export const $AssetClassGroupDto = {
5856
- type: 'object',
5857
- properties: {
5858
- assetClass: {
5859
- type: 'string',
5860
- description: 'Asset class name',
5861
- example: 'LIQUIDITY',
5862
- enum: [
5863
- 'LIQUIDITY',
5864
- 'EQUITY',
5865
- 'FIXED_INCOME',
5866
- 'PRECIOUS_METALS',
5867
- 'COMMODITY',
5868
- 'INSURANCE',
5869
- 'ALTERNATIVE_INVESTMENT',
5870
- 'PERSONAL_ASSETS',
5871
- 'LIABILITY',
5872
- 'REAL_ESTATE',
5873
- '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
+ }
5874
5804
  ]
5875
5805
  },
5876
- assetSubClass: {
5877
- type: 'string',
5878
- description: 'Asset sub-class name',
5879
- example: 'DEPOSIT'
5806
+ costBasis: {
5807
+ description: 'Cost basis of held units',
5808
+ nullable: true,
5809
+ allOf: [
5810
+ {
5811
+ $ref: '#/components/schemas/MonetaryDto'
5812
+ }
5813
+ ]
5880
5814
  },
5881
- accounts: {
5882
- description: 'Accounts within this asset class',
5883
- type: 'array',
5884
- items: {
5885
- $ref: '#/components/schemas/AccountItemWithAssetClassDto'
5886
- }
5815
+ marketValue: {
5816
+ description: 'Market value at asOf price',
5817
+ nullable: true,
5818
+ allOf: [
5819
+ {
5820
+ $ref: '#/components/schemas/MonetaryDto'
5821
+ }
5822
+ ]
5887
5823
  },
5888
- balanceByCurrency: {
5889
- description: 'Balances grouped by currency',
5890
- type: 'array',
5891
- items: {
5892
- $ref: '#/components/schemas/BalanceByCurrencyDto'
5893
- }
5824
+ currentPrice: {
5825
+ description: 'Price used for market value',
5826
+ nullable: true,
5827
+ allOf: [
5828
+ {
5829
+ $ref: '#/components/schemas/CurrentPriceDto'
5830
+ }
5831
+ ]
5894
5832
  },
5895
- convertedBalance: {
5896
- type: 'string',
5897
- description: 'Converted balance in base currency',
5898
- 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
+ ]
5899
5880
  }
5900
5881
  },
5901
- required: ['assetClass', 'accounts', 'balanceByCurrency']
5882
+ required: [
5883
+ 'accountId',
5884
+ 'accountPath',
5885
+ 'symbol',
5886
+ 'chartToken',
5887
+ 'assetClass',
5888
+ 'units'
5889
+ ]
5902
5890
  } as const;
5903
5891
 
5904
- export const $AccountExchangeRateWarningDto = {
5892
+ export const $HoldingPnlWarningDto = {
5905
5893
  type: 'object',
5906
5894
  properties: {
5907
5895
  type: {
5908
5896
  type: 'string',
5909
5897
  description: 'Warning type',
5910
- 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
+ ]
5911
5908
  },
5912
- currency: {
5913
- type: 'string',
5914
- description: 'Currency without exchange rate',
5915
- example: 'USD'
5909
+ symbol: {
5910
+ type: 'object',
5911
+ nullable: true
5916
5912
  },
5917
- accounts: {
5918
- description: 'Affected account paths',
5919
- type: 'array',
5920
- items: {
5921
- type: 'string'
5922
- }
5913
+ accountId: {
5914
+ type: 'object',
5915
+ nullable: true
5923
5916
  },
5924
- totalAmount: {
5925
- type: 'string',
5926
- description: 'Total amount in this currency',
5927
- example: '5000.00'
5917
+ currency: {
5918
+ type: 'object',
5919
+ nullable: true
5928
5920
  }
5929
5921
  },
5930
- required: ['type', 'currency', 'accounts', 'totalAmount']
5922
+ required: ['type']
5931
5923
  } as const;
5932
5924
 
5933
- export const $AssetClassSummaryDto = {
5925
+ export const $HoldingPnlResponseDto = {
5934
5926
  type: 'object',
5935
5927
  properties: {
5936
- totalAccounts: {
5937
- type: 'number',
5938
- description: 'Total number of accounts'
5939
- },
5940
- totalAssetClasses: {
5941
- type: 'number',
5942
- description: 'Total number of asset classes'
5928
+ asOfDate: {
5929
+ type: 'string',
5930
+ example: '2026-07-08'
5943
5931
  },
5944
5932
  baseCurrency: {
5945
5933
  type: 'string',
5946
- description: 'Base currency for conversion',
5947
5934
  example: 'CNY'
5948
5935
  },
5949
- warnings: {
5950
- description: 'Exchange rate warnings',
5951
- type: 'array',
5952
- items: {
5953
- $ref: '#/components/schemas/AccountExchangeRateWarningDto'
5954
- }
5955
- }
5956
- },
5957
- required: ['totalAccounts', 'totalAssetClasses', 'baseCurrency']
5958
- } as const;
5959
-
5960
- export const $AssetClassAccountsResponseDto = {
5961
- type: 'object',
5962
- properties: {
5963
- groups: {
5964
- description: 'Account groups by asset class',
5965
- type: 'array',
5966
- items: {
5967
- $ref: '#/components/schemas/AssetClassGroupDto'
5968
- }
5969
- },
5970
- summary: {
5971
- description: 'Summary statistics',
5972
- allOf: [
5973
- {
5974
- $ref: '#/components/schemas/AssetClassSummaryDto'
5975
- }
5976
- ]
5977
- }
5978
- },
5979
- required: ['groups', 'summary']
5980
- } as const;
5981
-
5982
- export const $CashFlowByCurrencyDto = {
5983
- type: 'object',
5984
- properties: {
5985
- income: {
5986
- description: 'Income by currency',
5987
- type: 'array',
5988
- items: {
5989
- $ref: '#/components/schemas/BalanceByCurrencyDto'
5990
- }
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'
5991
5942
  },
5992
- expense: {
5993
- description: 'Expense by currency',
5943
+ rows: {
5994
5944
  type: 'array',
5995
5945
  items: {
5996
- $ref: '#/components/schemas/BalanceByCurrencyDto'
5946
+ $ref: '#/components/schemas/HoldingPnlRowDto'
5997
5947
  }
5998
5948
  },
5999
- netSavings: {
6000
- description: 'Net savings by currency',
5949
+ warnings: {
6001
5950
  type: 'array',
6002
5951
  items: {
6003
- $ref: '#/components/schemas/BalanceByCurrencyDto'
5952
+ $ref: '#/components/schemas/HoldingPnlWarningDto'
6004
5953
  }
6005
5954
  }
6006
5955
  },
6007
- required: ['income', 'expense', 'netSavings']
5956
+ required: ['asOfDate', 'baseCurrency', 'method', 'rows', 'warnings']
6008
5957
  } as const;
6009
5958
 
6010
- export const $ConvertedCashFlowDto = {
5959
+ export const $CreateBeanPriceDto = {
6011
5960
  type: 'object',
6012
5961
  properties: {
6013
- baseCurrency: {
5962
+ currency: {
6014
5963
  type: 'string',
6015
- description: 'Base currency for conversion',
6016
- example: 'CNY'
5964
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
5965
+ example: 'USD'
6017
5966
  },
6018
- income: {
5967
+ quoteCurrency: {
6019
5968
  type: 'string',
6020
- description: 'Converted income',
6021
- example: '25000.00'
5969
+ description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
5970
+ example: 'CNY'
6022
5971
  },
6023
- expense: {
6024
- type: 'string',
6025
- description: 'Converted expense',
6026
- 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
6027
5978
  },
6028
- netSavings: {
5979
+ date: {
6029
5980
  type: 'string',
6030
- description: 'Converted net savings',
6031
- example: '7000.00'
5981
+ description: 'Price date (ISO 8601 format)',
5982
+ example: '2024-11-05'
6032
5983
  },
6033
- exchangeRates: {
5984
+ metadata: {
6034
5985
  type: 'object',
6035
- description: 'Exchange rates used for conversion',
5986
+ description:
5987
+ 'Metadata (validated by Zod schema, max field lengths enforced)',
6036
5988
  example: {
6037
- USD: '7.200000'
5989
+ source: 'MANUAL',
5990
+ note: 'Bank valuation report',
5991
+ confidence: 0.95
6038
5992
  }
6039
5993
  }
6040
5994
  },
6041
- required: ['baseCurrency', 'income', 'expense', 'netSavings', 'exchangeRates']
5995
+ required: ['currency', 'quoteCurrency', 'amount', 'date']
6042
5996
  } as const;
6043
5997
 
6044
- export const $CashFlowResponseDto = {
5998
+ export const $PriceResponseDto = {
6045
5999
  type: 'object',
6046
6000
  properties: {
6047
- period: {
6001
+ id: {
6048
6002
  type: 'string',
6049
- description: 'Period identifier (YYYY-MM)',
6050
- example: '2024-06'
6003
+ description: 'Unique identifier',
6004
+ example: 'uuid-123-456'
6051
6005
  },
6052
- income: {
6006
+ userId: {
6053
6007
  type: 'string',
6054
- description: 'Total income for the period (converted)',
6055
- example: '25000.00'
6008
+ description: 'User ID (owner of the price)',
6009
+ example: 'user-123'
6056
6010
  },
6057
- expense: {
6011
+ currency: {
6058
6012
  type: 'string',
6059
- description: 'Total expenses for the period (converted)',
6060
- example: '18000.00'
6013
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
6014
+ example: 'BTC'
6061
6015
  },
6062
- netSavings: {
6016
+ quoteCurrency: {
6063
6017
  type: 'string',
6064
- description: 'Net savings (income - expense, converted)',
6065
- example: '7000.00'
6018
+ description: 'Quote currency (pricing currency, e.g., USD, CNY)',
6019
+ example: 'USD'
6066
6020
  },
6067
- savingsRate: {
6068
- type: 'string',
6069
- description: 'Savings rate percentage (netSavings / income * 100)',
6070
- 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
6071
6026
  },
6072
- currency: {
6027
+ date: {
6073
6028
  type: 'string',
6074
- description: 'Base currency code',
6075
- 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'
6076
6033
  },
6077
- byCurrency: {
6078
- description: 'Cash flow grouped by original currency',
6079
- allOf: [
6080
- {
6081
- $ref: '#/components/schemas/CashFlowByCurrencyDto'
6082
- }
6083
- ]
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
+ }
6084
6043
  },
6085
- converted: {
6086
- description: 'Converted values in base currency',
6087
- allOf: [
6088
- {
6089
- $ref: '#/components/schemas/ConvertedCashFlowDto'
6090
- }
6091
- ]
6044
+ createdAt: {
6045
+ format: 'date-time',
6046
+ type: 'string',
6047
+ description: 'Creation timestamp',
6048
+ example: '2024-11-03T10:00:00Z'
6092
6049
  },
6093
- warnings: {
6094
- 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',
6095
6075
  type: 'array',
6096
6076
  items: {
6097
- $ref: '#/components/schemas/ExchangeRateWarningDto'
6077
+ $ref: '#/components/schemas/PriceResponseDto'
6098
6078
  }
6079
+ },
6080
+ total: {
6081
+ type: 'number',
6082
+ description: 'Total number of prices',
6083
+ example: 42
6099
6084
  }
6100
6085
  },
6101
- required: [
6102
- 'period',
6103
- 'income',
6104
- 'expense',
6105
- 'netSavings',
6106
- 'savingsRate',
6107
- 'currency'
6108
- ]
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
+ }
6109
6114
  } as const;
6110
6115
 
6111
6116
  export const $CurrencyBalanceDto = {