@firela/api-types 0.0.0-canary.2b7765ff → 0.0.0-canary.2fbeefe9

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.
@@ -6,13 +6,7 @@ export const $CreateAccountDto = {
6
6
  path: {
7
7
  type: 'string',
8
8
  description: 'Account path (hierarchical, colon-separated)',
9
- example: 'Assets:CN:Bank:ICBC:Checking'
10
- },
11
- displayName: {
12
- type: 'string',
13
- description:
14
- 'Display name to distinguish accounts at the same path (default: "")',
15
- example: '工资卡'
9
+ example: 'Assets:CN:ICBC:Checking'
16
10
  },
17
11
  openDate: {
18
12
  format: 'date-time',
@@ -45,18 +39,13 @@ export const $CreateAccountDto = {
45
39
  templatePath: {
46
40
  type: 'string',
47
41
  description: 'Reference to account-standards template path',
48
- example: 'Assets:CN:Bank:ICBC:Checking'
42
+ example: 'Assets:CN:Checking'
49
43
  },
50
44
  isCustom: {
51
45
  type: 'boolean',
52
46
  description: 'Whether this is a custom (user-created) account',
53
47
  default: false
54
48
  },
55
- i18nKey: {
56
- type: 'string',
57
- description: 'i18n key for display name (overrides template)',
58
- example: 'account.custom.mybank'
59
- },
60
49
  icon: {
61
50
  type: 'string',
62
51
  description: 'Icon identifier (overrides template)',
@@ -90,13 +79,7 @@ export const $AccountResponseDto = {
90
79
  path: {
91
80
  type: 'string',
92
81
  description: 'Account path (hierarchical, colon-separated)',
93
- example: 'Assets:CN:Bank:ICBC:Checking'
94
- },
95
- displayName: {
96
- type: 'string',
97
- description:
98
- 'Display name distinguishing multiple accounts at the same path',
99
- example: '工资卡'
82
+ example: 'Assets:CN:ICBC:Checking'
100
83
  },
101
84
  type: {
102
85
  type: 'string',
@@ -145,17 +128,17 @@ export const $AccountResponseDto = {
145
128
  templatePath: {
146
129
  type: 'string',
147
130
  description: 'Template path reference',
148
- example: 'Assets:CN:Bank:ICBC:Checking'
131
+ example: 'Assets:CN:Checking'
149
132
  },
150
133
  isCustom: {
151
134
  type: 'boolean',
152
135
  description: 'Whether this is a custom (user-created) account',
153
136
  example: false
154
137
  },
155
- i18nKey: {
138
+ displayName: {
156
139
  type: 'string',
157
- description: 'i18n key for display name',
158
- example: 'account.assets.cn.bank.icbc.checking'
140
+ description: 'Localized display name (ADR-0114, read-time projection)',
141
+ example: 'Checking'
159
142
  },
160
143
  icon: {
161
144
  type: 'string',
@@ -192,7 +175,6 @@ export const $AccountResponseDto = {
192
175
  required: [
193
176
  'id',
194
177
  'path',
195
- 'displayName',
196
178
  'type',
197
179
  'status',
198
180
  'openDate',
@@ -225,11 +207,6 @@ export const $AccountListResponseDto = {
225
207
  export const $UpdateAccountDto = {
226
208
  type: 'object',
227
209
  properties: {
228
- displayName: {
229
- type: 'string',
230
- description: 'Display name to distinguish accounts at the same path',
231
- example: '招行工资卡'
232
- },
233
210
  currencies: {
234
211
  description: 'Allowed currencies (null = no restriction)',
235
212
  example: ['CNY', 'USD'],
@@ -251,11 +228,6 @@ export const $UpdateAccountDto = {
251
228
  'NONE'
252
229
  ]
253
230
  },
254
- i18nKey: {
255
- type: 'string',
256
- description: 'i18n key for display name',
257
- example: 'account.custom.mybank'
258
- },
259
231
  icon: {
260
232
  type: 'string',
261
233
  description: 'Icon identifier',
@@ -316,7 +288,7 @@ export const $AccountStandardResponseDto = {
316
288
  path: {
317
289
  type: 'string',
318
290
  description: 'Account path (hierarchical, colon-separated)',
319
- example: 'Assets:CN:Bank:ICBC:Checking'
291
+ example: 'Assets:CN:Checking'
320
292
  },
321
293
  type: {
322
294
  type: 'string',
@@ -324,11 +296,6 @@ export const $AccountStandardResponseDto = {
324
296
  enum: ['Assets', 'Liabilities', 'Income', 'Expenses', 'Equity'],
325
297
  example: 'Assets'
326
298
  },
327
- i18nKey: {
328
- type: 'string',
329
- description: 'i18n key for localized display name',
330
- example: 'account.assets.cn.bank.icbc.checking'
331
- },
332
299
  name: {
333
300
  type: 'string',
334
301
  description: 'Short localized display name',
@@ -353,7 +320,7 @@ export const $AccountStandardResponseDto = {
353
320
  example: 'bank-icbc'
354
321
  }
355
322
  },
356
- required: ['path', 'type', 'i18nKey', 'description', 'tags', 'icon']
323
+ required: ['path', 'type', 'description', 'tags', 'icon']
357
324
  } as const;
358
325
 
359
326
  export const $AccountStandardListResponseDto = {
@@ -383,18 +350,13 @@ export const $AccountStandardListResponseDto = {
383
350
  export const $TemplateMetadataDto = {
384
351
  type: 'object',
385
352
  properties: {
386
- extendable: {
387
- type: 'boolean',
388
- description: 'Whether this path can be extended',
389
- example: true
390
- },
391
353
  rootType: {
392
354
  type: 'string',
393
355
  description: 'Root account type',
394
356
  example: 'Assets'
395
357
  }
396
358
  },
397
- required: ['extendable', 'rootType']
359
+ required: ['rootType']
398
360
  } as const;
399
361
 
400
362
  export const $TemplateMetadataResponseDto = {
@@ -533,7 +495,7 @@ export const $CreatePostingDto = {
533
495
  type: 'string',
534
496
  description:
535
497
  'Account name in Beancount format (must start with uppercase, colon-separated)',
536
- example: 'Assets:Bank:Checking'
498
+ example: 'Assets:Checking'
537
499
  },
538
500
  units: {
539
501
  type: 'string',
@@ -660,13 +622,39 @@ export const $CreateTransactionDto = {
660
622
  required: ['date', 'narration', 'postings']
661
623
  } as const;
662
624
 
625
+ export const $CostDetailDto = {
626
+ type: 'object',
627
+ properties: {
628
+ number: {
629
+ type: 'string',
630
+ description: 'Per-unit cost basis (mirrors engine Cost.number)',
631
+ example: '240'
632
+ },
633
+ currency: {
634
+ type: 'string',
635
+ description: 'Cost currency',
636
+ example: 'USD'
637
+ },
638
+ date: {
639
+ type: 'string',
640
+ description: 'Lot acquisition date (ISO yyyy-mm-dd)',
641
+ example: '2024-01-15'
642
+ },
643
+ label: {
644
+ type: 'string',
645
+ description: 'Lot label',
646
+ example: 'lot-2024-01'
647
+ }
648
+ }
649
+ } as const;
650
+
663
651
  export const $PostingResponseDto = {
664
652
  type: 'object',
665
653
  properties: {
666
654
  account: {
667
655
  type: 'string',
668
656
  description: 'Account name',
669
- example: 'Assets:Bank:Checking'
657
+ example: 'Assets:Checking'
670
658
  },
671
659
  units: {
672
660
  type: 'string',
@@ -678,6 +666,15 @@ export const $PostingResponseDto = {
678
666
  type: 'string',
679
667
  description: 'Currency',
680
668
  example: 'USD'
669
+ },
670
+ cost: {
671
+ description:
672
+ 'Booking-resolved cost (mirrors engine Cost). Undefined when the posting has no cost basis.',
673
+ allOf: [
674
+ {
675
+ $ref: '#/components/schemas/CostDetailDto'
676
+ }
677
+ ]
681
678
  }
682
679
  },
683
680
  required: ['account']
@@ -1023,7 +1020,7 @@ export const $PostingDetailDto = {
1023
1020
  account: {
1024
1021
  type: 'string',
1025
1022
  description: 'Fully-qualified Beancount account path',
1026
- example: 'Assets:Bank:Checking'
1023
+ example: 'Assets:Checking'
1027
1024
  },
1028
1025
  units: {
1029
1026
  type: 'string',
@@ -1051,6 +1048,15 @@ export const $PostingDetailDto = {
1051
1048
  description: 'Cost date',
1052
1049
  example: '2024-01-15'
1053
1050
  },
1051
+ cost: {
1052
+ description:
1053
+ 'Booking-resolved cost (mirrors engine Cost). Undefined when the posting has no cost basis.',
1054
+ allOf: [
1055
+ {
1056
+ $ref: '#/components/schemas/CostDetailDto'
1057
+ }
1058
+ ]
1059
+ },
1054
1060
  priceAmount: {
1055
1061
  type: 'string',
1056
1062
  description: 'Price amount',
@@ -1203,6 +1209,77 @@ export const $TransactionDetailDto = {
1203
1209
  ]
1204
1210
  } as const;
1205
1211
 
1212
+ export const $BalanceByCurrencyDto = {
1213
+ type: 'object',
1214
+ properties: {
1215
+ currency: {
1216
+ type: 'string',
1217
+ description: 'ISO 4217 currency code',
1218
+ example: 'CNY'
1219
+ },
1220
+ balance: {
1221
+ type: 'string',
1222
+ description: 'Balance amount',
1223
+ example: '50000.00'
1224
+ }
1225
+ },
1226
+ required: ['currency', 'balance']
1227
+ } as const;
1228
+
1229
+ export const $ExchangeRateWarningDto = {
1230
+ type: 'object',
1231
+ properties: {
1232
+ type: {
1233
+ type: 'string',
1234
+ description: 'Warning type',
1235
+ example: 'MISSING_EXCHANGE_RATE'
1236
+ },
1237
+ currency: {
1238
+ type: 'string',
1239
+ description: 'Currency without exchange rate',
1240
+ example: 'EUR'
1241
+ },
1242
+ totalAmount: {
1243
+ type: 'string',
1244
+ description: 'Total amount affected',
1245
+ example: '1000.00'
1246
+ }
1247
+ },
1248
+ required: ['type', 'currency', 'totalAmount']
1249
+ } as const;
1250
+
1251
+ export const $TransactionListSummaryDto = {
1252
+ type: 'object',
1253
+ properties: {
1254
+ totalAmount: {
1255
+ type: 'string',
1256
+ description:
1257
+ 'Partial converted total in base currency (rated currencies only, raw Beancount sign). When warnings is non-empty this excludes currencies missing an FX rate; may be "0.00" if ALL non-base currencies lack a rate. Converted at the dateTo (or current) available rate.',
1258
+ example: '-6000.00'
1259
+ },
1260
+ currency: {
1261
+ type: 'string',
1262
+ description: 'Base currency (ISO 4217)',
1263
+ example: 'CNY'
1264
+ },
1265
+ balanceByCurrency: {
1266
+ description: 'Raw (unconverted) balance per currency',
1267
+ type: 'array',
1268
+ items: {
1269
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
1270
+ }
1271
+ },
1272
+ warnings: {
1273
+ description: 'Currencies missing an FX rate (omitted when empty)',
1274
+ type: 'array',
1275
+ items: {
1276
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
1277
+ }
1278
+ }
1279
+ },
1280
+ required: ['totalAmount', 'currency', 'balanceByCurrency']
1281
+ } as const;
1282
+
1206
1283
  export const $TransactionListResponseDto = {
1207
1284
  type: 'object',
1208
1285
  properties: {
@@ -1227,6 +1304,15 @@ export const $TransactionListResponseDto = {
1227
1304
  type: 'number',
1228
1305
  description: 'Number of items skipped',
1229
1306
  example: 0
1307
+ },
1308
+ summary: {
1309
+ description:
1310
+ 'Amount summary for the full filtered set (#514). Present only when the request has a single account OR category viewpoint; omitted for search-only / plain-list / dual-perspective requests.',
1311
+ allOf: [
1312
+ {
1313
+ $ref: '#/components/schemas/TransactionListSummaryDto'
1314
+ }
1315
+ ]
1230
1316
  }
1231
1317
  },
1232
1318
  required: ['data', 'total', 'limit', 'offset']
@@ -1326,7 +1412,7 @@ export const $BalanceResponseDto = {
1326
1412
  account: {
1327
1413
  type: 'string',
1328
1414
  description: 'Account name',
1329
- example: 'Assets:Bank:Checking'
1415
+ example: 'Assets:Checking'
1330
1416
  },
1331
1417
  balance: {
1332
1418
  type: 'string',
@@ -1353,7 +1439,7 @@ export const $MultiCurrencyBalanceResponseDto = {
1353
1439
  account: {
1354
1440
  type: 'string',
1355
1441
  description: 'Account name',
1356
- example: 'Assets:Bank:Checking'
1442
+ example: 'Assets:Checking'
1357
1443
  },
1358
1444
  balances: {
1359
1445
  type: 'object',
@@ -1409,7 +1495,7 @@ export const $TransactionSummaryDto = {
1409
1495
  accountName: {
1410
1496
  type: 'string',
1411
1497
  description: 'Source account name (first posting)',
1412
- example: 'Assets:Bank:Checking'
1498
+ example: 'Assets:Checking'
1413
1499
  },
1414
1500
  sourceType: {
1415
1501
  type: 'string',
@@ -1811,7 +1897,8 @@ export const $ResolveResultDto = {
1811
1897
  },
1812
1898
  resolutionId: {
1813
1899
  type: 'string',
1814
- description: 'Resolution ID for undo'
1900
+ description:
1901
+ 'Resolution ID for undo. Absent when the resolver rejected the decision (review stayed PENDING).'
1815
1902
  },
1816
1903
  canUndo: {
1817
1904
  type: 'boolean',
@@ -1829,7 +1916,7 @@ export const $ResolveResultDto = {
1829
1916
  example: 'rule_01HXK5V8N2M3P4Q5R6S7T8U9V0'
1830
1917
  }
1831
1918
  },
1832
- required: ['success', 'resolutionId', 'canUndo', 'undoDeadline']
1919
+ required: ['success']
1833
1920
  } as const;
1834
1921
 
1835
1922
  export const $UndoResultDto = {
@@ -2700,123 +2787,280 @@ export const $UpdateCommodityDto = {
2700
2787
  }
2701
2788
  } as const;
2702
2789
 
2703
- export const $CreateRecurringRuleDto = {
2790
+ export const $CreateBeanPriceDto = {
2704
2791
  type: 'object',
2705
2792
  properties: {
2706
- name: {
2707
- type: 'string',
2708
- description: 'Rule name (unique per user)',
2709
- maxLength: 100
2710
- },
2711
- icon: {
2712
- type: 'string',
2713
- description: 'Icon emoji',
2714
- maxLength: 10
2715
- },
2716
- frequency: {
2717
- type: 'string',
2718
- description: 'Recurring frequency',
2719
- enum: [
2720
- 'WEEKLY',
2721
- 'BIWEEKLY',
2722
- 'MONTHLY',
2723
- 'BIMONTHLY',
2724
- 'QUARTERLY',
2725
- 'YEARLY',
2726
- 'CUSTOM'
2727
- ]
2728
- },
2729
- expectedAmount: {
2730
- type: 'number',
2731
- description: 'Expected amount (positive number)',
2732
- minimum: 0
2733
- },
2734
- expectedDay: {
2735
- type: 'number',
2736
- description: 'Expected day of month (1-31)',
2737
- minimum: 1,
2738
- maximum: 31
2739
- },
2740
- customIntervalDays: {
2741
- type: 'number',
2742
- description: 'Custom interval in days (required for CUSTOM frequency)',
2743
- minimum: 1
2744
- },
2745
2793
  currency: {
2746
2794
  type: 'string',
2747
- description: 'Currency code',
2748
- default: 'CNY',
2749
- maxLength: 10
2795
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
2796
+ example: 'USD'
2750
2797
  },
2751
- matchPayeePattern: {
2798
+ quoteCurrency: {
2752
2799
  type: 'string',
2753
- description: 'Payee matching pattern (supports wildcards)',
2754
- maxLength: 200
2800
+ description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
2801
+ example: 'CNY'
2755
2802
  },
2756
- matchAmountTolerance: {
2803
+ amount: {
2757
2804
  type: 'number',
2758
- description: 'Amount tolerance percentage (0-1)',
2759
- default: 0.075,
2760
- minimum: 0,
2761
- maximum: 1
2762
- },
2763
- defaultExpenseAccount: {
2764
- type: 'string',
2765
- description: 'Default expense account for auto-create',
2766
- maxLength: 200
2767
- },
2768
- defaultPaymentAccount: {
2769
- type: 'string',
2770
- description: 'Default payment account for auto-create',
2771
- maxLength: 200
2772
- },
2773
- defaultPayee: {
2774
- type: 'string',
2775
- description: 'Default payee for auto-create',
2776
- maxLength: 200
2777
- },
2778
- autoCreate: {
2779
- type: 'boolean',
2780
- description: 'Auto-create transaction when expected date arrives',
2781
- default: false
2805
+ description:
2806
+ 'Price amount (MUST be >= 0 per Beancount spec, supports up to 15 decimal places). Zero allowed for conversion entries, negative strictly prohibited.',
2807
+ example: 175.5,
2808
+ minimum: 0
2782
2809
  },
2783
- startDate: {
2810
+ date: {
2784
2811
  type: 'string',
2785
- description: 'Rule start date (ISO format)'
2812
+ description: 'Price date (ISO 8601 format)',
2813
+ example: '2024-11-05'
2786
2814
  },
2787
- endDate: {
2788
- type: 'string',
2789
- description: 'Rule end date (ISO format)'
2815
+ metadata: {
2816
+ type: 'object',
2817
+ description:
2818
+ 'Metadata (validated by Zod schema, max field lengths enforced)',
2819
+ example: {
2820
+ source: 'MANUAL',
2821
+ note: 'Bank valuation report',
2822
+ confidence: 0.95
2823
+ }
2790
2824
  }
2791
2825
  },
2792
- required: [
2793
- 'name',
2794
- 'frequency',
2795
- 'expectedAmount',
2796
- 'currency',
2797
- 'matchAmountTolerance',
2798
- 'autoCreate'
2799
- ]
2826
+ required: ['currency', 'quoteCurrency', 'amount', 'date']
2800
2827
  } as const;
2801
2828
 
2802
- export const $RecurringRuleResponseDto = {
2829
+ export const $PriceResponseDto = {
2803
2830
  type: 'object',
2804
2831
  properties: {
2805
2832
  id: {
2806
2833
  type: 'string',
2807
- description: 'Rule ID'
2834
+ description: 'Unique identifier',
2835
+ example: 'uuid-123-456'
2808
2836
  },
2809
2837
  userId: {
2810
2838
  type: 'string',
2811
- description: 'User ID'
2839
+ description: 'User ID (owner of the price)',
2840
+ example: 'user-123'
2812
2841
  },
2813
- name: {
2842
+ currency: {
2814
2843
  type: 'string',
2815
- description: 'Rule name'
2844
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
2845
+ example: 'BTC'
2816
2846
  },
2817
- icon: {
2818
- type: 'object',
2819
- description: 'Icon emoji'
2847
+ quoteCurrency: {
2848
+ type: 'string',
2849
+ description: 'Quote currency (pricing currency, e.g., USD, CNY)',
2850
+ example: 'USD'
2851
+ },
2852
+ amount: {
2853
+ type: 'number',
2854
+ description:
2855
+ 'Price amount (corresponds to Beancount Amount.number). Supports up to 15 decimal places.',
2856
+ example: 50000
2857
+ },
2858
+ date: {
2859
+ type: 'string',
2860
+ description:
2861
+ 'Price date (ISO 8601 format). Represents the date this price was valid.',
2862
+ example: '2024-01-01',
2863
+ format: 'date'
2864
+ },
2865
+ meta: {
2866
+ type: 'object',
2867
+ description:
2868
+ 'Metadata (corresponds to Beancount meta field). Contains source, confidence, note, etc.',
2869
+ example: {
2870
+ source: 'MANUAL',
2871
+ note: 'User-defined price',
2872
+ confidence: 1
2873
+ }
2874
+ },
2875
+ createdAt: {
2876
+ format: 'date-time',
2877
+ type: 'string',
2878
+ description: 'Creation timestamp',
2879
+ example: '2024-11-03T10:00:00Z'
2880
+ },
2881
+ updatedAt: {
2882
+ format: 'date-time',
2883
+ type: 'string',
2884
+ description: 'Last update timestamp',
2885
+ example: '2024-11-03T10:00:00Z'
2886
+ }
2887
+ },
2888
+ required: [
2889
+ 'id',
2890
+ 'userId',
2891
+ 'currency',
2892
+ 'quoteCurrency',
2893
+ 'amount',
2894
+ 'date',
2895
+ 'meta',
2896
+ 'createdAt',
2897
+ 'updatedAt'
2898
+ ]
2899
+ } as const;
2900
+
2901
+ export const $PriceListResponseDto = {
2902
+ type: 'object',
2903
+ properties: {
2904
+ items: {
2905
+ description: 'List of prices',
2906
+ type: 'array',
2907
+ items: {
2908
+ $ref: '#/components/schemas/PriceResponseDto'
2909
+ }
2910
+ },
2911
+ total: {
2912
+ type: 'number',
2913
+ description: 'Total number of prices',
2914
+ example: 42
2915
+ }
2916
+ },
2917
+ required: ['items', 'total']
2918
+ } as const;
2919
+
2920
+ export const $UpdateBeanPriceDto = {
2921
+ type: 'object',
2922
+ properties: {
2923
+ currency: {
2924
+ type: 'string',
2925
+ description: 'Currency being priced'
2926
+ },
2927
+ quoteCurrency: {
2928
+ type: 'string',
2929
+ description: 'Quote currency (pricing currency)'
2930
+ },
2931
+ amount: {
2932
+ type: 'number',
2933
+ description: 'Price amount (MUST be >= 0 per Beancount spec)',
2934
+ minimum: 0
2935
+ },
2936
+ date: {
2937
+ type: 'string',
2938
+ description: 'Price date (ISO 8601 format)'
2939
+ },
2940
+ metadata: {
2941
+ type: 'object',
2942
+ description: 'Metadata'
2943
+ }
2944
+ }
2945
+ } as const;
2946
+
2947
+ export const $CreateRecurringRuleDto = {
2948
+ type: 'object',
2949
+ properties: {
2950
+ name: {
2951
+ type: 'string',
2952
+ description: 'Rule name (unique per user)',
2953
+ maxLength: 100
2954
+ },
2955
+ icon: {
2956
+ type: 'string',
2957
+ description: 'Icon emoji',
2958
+ maxLength: 10
2959
+ },
2960
+ frequency: {
2961
+ type: 'string',
2962
+ description: 'Recurring frequency',
2963
+ enum: [
2964
+ 'WEEKLY',
2965
+ 'BIWEEKLY',
2966
+ 'MONTHLY',
2967
+ 'BIMONTHLY',
2968
+ 'QUARTERLY',
2969
+ 'YEARLY',
2970
+ 'CUSTOM'
2971
+ ]
2972
+ },
2973
+ expectedAmount: {
2974
+ type: 'number',
2975
+ description: 'Expected amount (positive number)',
2976
+ minimum: 0
2977
+ },
2978
+ expectedDay: {
2979
+ type: 'number',
2980
+ description: 'Expected day of month (1-31)',
2981
+ minimum: 1,
2982
+ maximum: 31
2983
+ },
2984
+ customIntervalDays: {
2985
+ type: 'number',
2986
+ description: 'Custom interval in days (required for CUSTOM frequency)',
2987
+ minimum: 1
2988
+ },
2989
+ currency: {
2990
+ type: 'string',
2991
+ description: 'Currency code',
2992
+ default: 'CNY',
2993
+ maxLength: 10
2994
+ },
2995
+ matchPayeePattern: {
2996
+ type: 'string',
2997
+ description: 'Payee matching pattern (supports wildcards)',
2998
+ maxLength: 200
2999
+ },
3000
+ matchAmountTolerance: {
3001
+ type: 'number',
3002
+ description: 'Amount tolerance percentage (0-1)',
3003
+ default: 0.075,
3004
+ minimum: 0,
3005
+ maximum: 1
3006
+ },
3007
+ defaultExpenseAccount: {
3008
+ type: 'string',
3009
+ description: 'Default expense account for auto-create',
3010
+ maxLength: 200
3011
+ },
3012
+ defaultPaymentAccount: {
3013
+ type: 'string',
3014
+ description: 'Default payment account for auto-create',
3015
+ maxLength: 200
3016
+ },
3017
+ defaultPayee: {
3018
+ type: 'string',
3019
+ description: 'Default payee for auto-create',
3020
+ maxLength: 200
3021
+ },
3022
+ autoCreate: {
3023
+ type: 'boolean',
3024
+ description: 'Auto-create transaction when expected date arrives',
3025
+ default: false
3026
+ },
3027
+ startDate: {
3028
+ type: 'string',
3029
+ description: 'Rule start date (ISO format)'
3030
+ },
3031
+ endDate: {
3032
+ type: 'string',
3033
+ description: 'Rule end date (ISO format)'
3034
+ }
3035
+ },
3036
+ required: [
3037
+ 'name',
3038
+ 'frequency',
3039
+ 'expectedAmount',
3040
+ 'currency',
3041
+ 'matchAmountTolerance',
3042
+ 'autoCreate'
3043
+ ]
3044
+ } as const;
3045
+
3046
+ export const $RecurringRuleResponseDto = {
3047
+ type: 'object',
3048
+ properties: {
3049
+ id: {
3050
+ type: 'string',
3051
+ description: 'Rule ID'
3052
+ },
3053
+ userId: {
3054
+ type: 'string',
3055
+ description: 'User ID'
3056
+ },
3057
+ name: {
3058
+ type: 'string',
3059
+ description: 'Rule name'
3060
+ },
3061
+ icon: {
3062
+ type: 'object',
3063
+ description: 'Icon emoji'
2820
3064
  },
2821
3065
  frequency: {
2822
3066
  type: 'string',
@@ -4267,42 +4511,431 @@ export const $UpdatePropertyDto = {
4267
4511
  required: ['value']
4268
4512
  } as const;
4269
4513
 
4270
- export const $FileImportDto = {
4514
+ export const $CreateBeanEventDto = {
4271
4515
  type: 'object',
4272
4516
  properties: {
4273
- file: {
4517
+ date: {
4274
4518
  type: 'string',
4275
- format: 'binary',
4276
- description: 'Bill file to import (CSV, PDF, OFX, etc.)',
4277
- example: 'alipay.csv'
4278
- }
4279
- },
4280
- required: ['file']
4281
- } as const;
4282
-
4283
- export const $ImportErrorDto = {
4284
- type: 'object',
4285
- properties: {
4286
- index: {
4287
- type: 'number',
4288
- description: 'Index of failed transaction in the file',
4289
- example: 5
4519
+ description: 'Life event date (ISO 8601)',
4520
+ example: '2024-03-15'
4290
4521
  },
4291
- error: {
4522
+ type: {
4292
4523
  type: 'string',
4293
- description: 'Error message',
4294
- example: 'Transaction does not balance: -100 USD != 0'
4524
+ description:
4525
+ 'Life event type (e.g., "employer", "location", "marital-status") user-defined, no enum constraint at engine layer',
4526
+ example: 'employer'
4527
+ },
4528
+ description: {
4529
+ type: 'string',
4530
+ description:
4531
+ 'Life event description. Empty string is a VALID value (distinct from absence).',
4532
+ example: 'Acme Corp'
4533
+ },
4534
+ meta: {
4535
+ type: 'object',
4536
+ description:
4537
+ 'Product-side metadata (lives in BeanEvent.meta JSON, never in engine Event fields)',
4538
+ example: {
4539
+ note: 'Promotion'
4540
+ }
4295
4541
  }
4296
4542
  },
4297
- required: ['index', 'error']
4543
+ required: ['date', 'type', 'description']
4298
4544
  } as const;
4299
4545
 
4300
- export const $ReviewItemPreviewDto = {
4546
+ export const $EventResponseDto = {
4301
4547
  type: 'object',
4302
4548
  properties: {
4303
- index: {
4304
- type: 'number',
4305
- description: 'Index in the import batch (for tracking)',
4549
+ id: {
4550
+ type: 'string',
4551
+ description: 'Unique identifier',
4552
+ example: 'uuid-123-456'
4553
+ },
4554
+ userId: {
4555
+ type: 'string',
4556
+ description: 'User ID (owner of the life event)',
4557
+ example: 'user-123'
4558
+ },
4559
+ date: {
4560
+ type: 'string',
4561
+ description: 'Life event date (ISO 8601 format)',
4562
+ example: '2024-03-15',
4563
+ format: 'date'
4564
+ },
4565
+ type: {
4566
+ type: 'string',
4567
+ description:
4568
+ 'Life event type (user-defined, e.g., "employer", "location")',
4569
+ example: 'employer'
4570
+ },
4571
+ description: {
4572
+ type: 'string',
4573
+ description:
4574
+ 'Life event description. May be an empty string (a valid value distinct from absence).',
4575
+ example: 'Acme Corp'
4576
+ },
4577
+ meta: {
4578
+ type: 'object',
4579
+ description: 'Product-side metadata (free-form JSON)',
4580
+ example: {
4581
+ note: 'Promotion'
4582
+ }
4583
+ },
4584
+ createdAt: {
4585
+ format: 'date-time',
4586
+ type: 'string',
4587
+ description: 'Creation timestamp',
4588
+ example: '2024-03-15T10:00:00Z'
4589
+ },
4590
+ updatedAt: {
4591
+ format: 'date-time',
4592
+ type: 'string',
4593
+ description:
4594
+ 'Last update timestamp. Also emitted as the ETag response header for If-Match optimistic concurrency.',
4595
+ example: '2024-03-15T10:00:00Z'
4596
+ }
4597
+ },
4598
+ required: [
4599
+ 'id',
4600
+ 'userId',
4601
+ 'date',
4602
+ 'type',
4603
+ 'description',
4604
+ 'meta',
4605
+ 'createdAt',
4606
+ 'updatedAt'
4607
+ ]
4608
+ } as const;
4609
+
4610
+ export const $EventListResponseDto = {
4611
+ type: 'object',
4612
+ properties: {
4613
+ items: {
4614
+ description: 'List of life events',
4615
+ type: 'array',
4616
+ items: {
4617
+ $ref: '#/components/schemas/EventResponseDto'
4618
+ }
4619
+ },
4620
+ total: {
4621
+ type: 'number',
4622
+ description: 'Total number of life events matching the query',
4623
+ example: 42
4624
+ }
4625
+ },
4626
+ required: ['items', 'total']
4627
+ } as const;
4628
+
4629
+ export const $UpdateBeanEventDto = {
4630
+ type: 'object',
4631
+ properties: {
4632
+ date: {
4633
+ type: 'string',
4634
+ description: 'Life event date (ISO 8601)'
4635
+ },
4636
+ type: {
4637
+ type: 'string',
4638
+ description: 'Life event type (user-defined)'
4639
+ },
4640
+ description: {
4641
+ type: 'string',
4642
+ description:
4643
+ 'Life event description. Empty string is a VALID value (distinct from absence).'
4644
+ },
4645
+ meta: {
4646
+ type: 'object',
4647
+ description: 'Product-side metadata (free-form JSON)'
4648
+ }
4649
+ }
4650
+ } as const;
4651
+
4652
+ export const $OnboardingAccountDto = {
4653
+ type: 'object',
4654
+ properties: {
4655
+ path: {
4656
+ type: 'string',
4657
+ description:
4658
+ 'Account path (Assets/Liabilities only; format validated by the account service)',
4659
+ example: 'Assets:Checking'
4660
+ },
4661
+ currency: {
4662
+ type: 'string',
4663
+ description: 'ISO 4217 currency code (3 letters)',
4664
+ example: 'USD'
4665
+ },
4666
+ openingBalance: {
4667
+ type: 'string',
4668
+ description:
4669
+ 'Opening balance as a non-negative Decimal string (e.g. "1000.00")',
4670
+ example: '1000.00'
4671
+ },
4672
+ platformId: {
4673
+ type: 'string',
4674
+ description:
4675
+ 'Platform ID to bind the account to (references Platform.id); omit for unbound',
4676
+ example: 'c98e5d4a-2f71-4a5a-bb3c-92c9f231d5e2'
4677
+ }
4678
+ },
4679
+ required: ['path', 'currency']
4680
+ } as const;
4681
+
4682
+ export const $OnboardingDto = {
4683
+ type: 'object',
4684
+ properties: {
4685
+ accounts: {
4686
+ description: 'Asset/Liability accounts to register with opening balances',
4687
+ type: 'array',
4688
+ items: {
4689
+ $ref: '#/components/schemas/OnboardingAccountDto'
4690
+ }
4691
+ },
4692
+ skipAssetRegistration: {
4693
+ type: 'boolean',
4694
+ description:
4695
+ 'Skip asset registration; only bootstrap the core account set',
4696
+ default: false
4697
+ }
4698
+ }
4699
+ } as const;
4700
+
4701
+ export const $ActualBalanceDto = {
4702
+ type: 'object',
4703
+ properties: {
4704
+ amount: {
4705
+ type: 'string',
4706
+ description:
4707
+ 'Actual balance amount as a decimal string (preserves precision for tolerance inference).',
4708
+ example: '1234.56'
4709
+ },
4710
+ ccy: {
4711
+ type: 'string',
4712
+ description: 'Currency code (ISO 4217 or commodity ticker).',
4713
+ example: 'CNY'
4714
+ }
4715
+ },
4716
+ required: ['amount', 'ccy']
4717
+ } as const;
4718
+
4719
+ export const $ComputeReconciliationDto = {
4720
+ type: 'object',
4721
+ properties: {
4722
+ accountId: {
4723
+ type: 'string',
4724
+ description: 'BeanAccount id to reconcile.'
4725
+ },
4726
+ asOfDate: {
4727
+ type: 'string',
4728
+ description: 'Assertion date (ISO 8601, e.g. "2026-07-24").',
4729
+ example: '2026-07-24'
4730
+ },
4731
+ actualBalance: {
4732
+ description: 'Actual balance from the external statement.',
4733
+ allOf: [
4734
+ {
4735
+ $ref: '#/components/schemas/ActualBalanceDto'
4736
+ }
4737
+ ]
4738
+ }
4739
+ },
4740
+ required: ['accountId', 'asOfDate', 'actualBalance']
4741
+ } as const;
4742
+
4743
+ export const $ReconciliationComputeResultDto = {
4744
+ type: 'object',
4745
+ properties: {
4746
+ accountId: {
4747
+ type: 'string'
4748
+ },
4749
+ asOfDate: {
4750
+ type: 'string'
4751
+ },
4752
+ bookBalance: {
4753
+ type: 'string',
4754
+ description: 'System-computed book balance (decimal string).'
4755
+ },
4756
+ actualBalance: {
4757
+ type: 'string',
4758
+ description: 'User-entered actual balance (decimal string).'
4759
+ },
4760
+ currency: {
4761
+ type: 'string'
4762
+ },
4763
+ diff: {
4764
+ type: 'string',
4765
+ description: 'Diff = book − actual (decimal string).'
4766
+ },
4767
+ tolerance: {
4768
+ type: 'string',
4769
+ description: 'Applied tolerance (decimal string).'
4770
+ },
4771
+ withinTolerance: {
4772
+ type: 'boolean',
4773
+ description: 'true when |diff| ≤ tolerance.'
4774
+ },
4775
+ suggestedAction: {
4776
+ type: 'string',
4777
+ enum: ['assert', 'pad'],
4778
+ description:
4779
+ 'Suggested next action: assert when within tolerance, pad otherwise.'
4780
+ }
4781
+ },
4782
+ required: [
4783
+ 'accountId',
4784
+ 'asOfDate',
4785
+ 'bookBalance',
4786
+ 'actualBalance',
4787
+ 'currency',
4788
+ 'diff',
4789
+ 'tolerance',
4790
+ 'withinTolerance',
4791
+ 'suggestedAction'
4792
+ ]
4793
+ } as const;
4794
+
4795
+ export const $AssertReconciliationDto = {
4796
+ type: 'object',
4797
+ properties: {
4798
+ accountId: {
4799
+ type: 'string',
4800
+ description: 'BeanAccount id to reconcile.'
4801
+ },
4802
+ asOfDate: {
4803
+ type: 'string',
4804
+ description: 'Assertion date (ISO 8601, e.g. "2026-07-24").',
4805
+ example: '2026-07-24'
4806
+ },
4807
+ actualBalance: {
4808
+ description: 'Actual balance from the external statement.',
4809
+ allOf: [
4810
+ {
4811
+ $ref: '#/components/schemas/ActualBalanceDto'
4812
+ }
4813
+ ]
4814
+ },
4815
+ tolerance: {
4816
+ type: 'string',
4817
+ description:
4818
+ 'Optional explicit tolerance override. Omit to infer from amount precision (Beancount default).',
4819
+ example: '0.01'
4820
+ }
4821
+ },
4822
+ required: ['accountId', 'asOfDate', 'actualBalance']
4823
+ } as const;
4824
+
4825
+ export const $ReconciliationRecordDto = {
4826
+ type: 'object',
4827
+ properties: {
4828
+ id: {
4829
+ type: 'string'
4830
+ },
4831
+ accountId: {
4832
+ type: 'string'
4833
+ },
4834
+ date: {
4835
+ type: 'string'
4836
+ },
4837
+ amount: {
4838
+ type: 'string',
4839
+ description: 'Asserted (actual) amount.'
4840
+ },
4841
+ currency: {
4842
+ type: 'string'
4843
+ },
4844
+ tolerance: {
4845
+ type: 'string'
4846
+ },
4847
+ diffAmount: {
4848
+ type: 'string',
4849
+ description: 'book − actual.'
4850
+ },
4851
+ diffCurrency: {
4852
+ type: 'string'
4853
+ },
4854
+ createdAt: {
4855
+ type: 'string'
4856
+ }
4857
+ },
4858
+ required: ['id', 'accountId', 'date', 'amount', 'currency', 'createdAt']
4859
+ } as const;
4860
+
4861
+ export const $PadReconciliationDto = {
4862
+ type: 'object',
4863
+ properties: {
4864
+ accountId: {
4865
+ type: 'string',
4866
+ description: 'BeanAccount id to reconcile.'
4867
+ },
4868
+ asOfDate: {
4869
+ type: 'string',
4870
+ description: 'Assertion date (ISO 8601, e.g. "2026-07-24").',
4871
+ example: '2026-07-24'
4872
+ },
4873
+ actualBalance: {
4874
+ description: 'Actual balance from the external statement.',
4875
+ allOf: [
4876
+ {
4877
+ $ref: '#/components/schemas/ActualBalanceDto'
4878
+ }
4879
+ ]
4880
+ },
4881
+ sourceAccount: {
4882
+ type: 'string',
4883
+ description:
4884
+ 'Pad source account. Defaults to Equity:Opening-Balances (official Beancount convention).',
4885
+ example: 'Equity:Opening-Balances',
4886
+ default: 'Equity:Opening-Balances'
4887
+ }
4888
+ },
4889
+ required: ['accountId', 'asOfDate', 'actualBalance']
4890
+ } as const;
4891
+
4892
+ export const $PadResultDto = {
4893
+ type: 'object',
4894
+ properties: {
4895
+ transactionId: {
4896
+ type: 'string',
4897
+ description: 'Created pad adjusting transaction id.'
4898
+ }
4899
+ },
4900
+ required: ['transactionId']
4901
+ } as const;
4902
+
4903
+ export const $FileImportDto = {
4904
+ type: 'object',
4905
+ properties: {
4906
+ file: {
4907
+ type: 'string',
4908
+ format: 'binary',
4909
+ description: 'Bill file to import (CSV, PDF, OFX, etc.)',
4910
+ example: 'alipay.csv'
4911
+ }
4912
+ },
4913
+ required: ['file']
4914
+ } as const;
4915
+
4916
+ export const $ImportErrorDto = {
4917
+ type: 'object',
4918
+ properties: {
4919
+ index: {
4920
+ type: 'number',
4921
+ description: 'Index of failed transaction in the file',
4922
+ example: 5
4923
+ },
4924
+ error: {
4925
+ type: 'string',
4926
+ description: 'Error message',
4927
+ example: 'Transaction does not balance: -100 USD != 0'
4928
+ }
4929
+ },
4930
+ required: ['index', 'error']
4931
+ } as const;
4932
+
4933
+ export const $ReviewItemPreviewDto = {
4934
+ type: 'object',
4935
+ properties: {
4936
+ index: {
4937
+ type: 'number',
4938
+ description: 'Index in the import batch (for tracking)',
4306
4939
  example: 0
4307
4940
  },
4308
4941
  date: {
@@ -4433,7 +5066,7 @@ export const $IdentifyResultDto = {
4433
5066
  account: {
4434
5067
  type: 'string',
4435
5068
  description: 'Default account used by this importer',
4436
- example: 'Assets:Alipay:Balance'
5069
+ example: 'Assets:CN:Alipay:Balance'
4437
5070
  },
4438
5071
  message: {
4439
5072
  type: 'string',
@@ -4450,7 +5083,7 @@ export const $MapperDefaultsDto = {
4450
5083
  sourceAccount: {
4451
5084
  type: 'string',
4452
5085
  description: 'Source account for transactions (Beancount format)',
4453
- example: 'Assets:Alipay:Balance'
5086
+ example: 'Assets:CN:Alipay:Balance'
4454
5087
  },
4455
5088
  currency: {
4456
5089
  type: 'string',
@@ -4487,7 +5120,7 @@ export const $MapperDefaultsDto = {
4487
5120
  description:
4488
5121
  'Payment method to source account mapping. Maps payment method keywords to Beancount account paths. Used by Alipay/WeChat importers to determine sourceAccount based on payment method (e.g., HuaBei, CreditCard).',
4489
5122
  example: {
4490
- HuaBei: 'Liabilities:Alipay:Huabei',
5123
+ HuaBei: 'Liabilities:CN:CreditLine',
4491
5124
  CreditCard: 'Liabilities:CreditCard'
4492
5125
  }
4493
5126
  }
@@ -4619,7 +5252,7 @@ export const $UpdateMapperDefaultsDto = {
4619
5252
  sourceAccount: {
4620
5253
  type: 'string',
4621
5254
  description: 'Source account for transactions (Beancount format)',
4622
- example: 'Assets:Alipay:Balance',
5255
+ example: 'Assets:CN:Alipay:Balance',
4623
5256
  pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
4624
5257
  },
4625
5258
  currency: {
@@ -4647,7 +5280,7 @@ export const $UpdateMapperDefaultsDto = {
4647
5280
  description:
4648
5281
  'Payment method to source account mapping. Maps payment method keywords to Beancount account paths. Used by Alipay/WeChat importers to determine sourceAccount based on payment method (e.g., HuaBei, CreditCard).',
4649
5282
  example: {
4650
- HuaBei: 'Liabilities:Alipay:Huabei',
5283
+ HuaBei: 'Liabilities:CN:CreditLine',
4651
5284
  CreditCard: 'Liabilities:CreditCard'
4652
5285
  }
4653
5286
  }
@@ -4682,119 +5315,13 @@ export const $UpdateImporterConfigDto = {
4682
5315
  }
4683
5316
  } as const;
4684
5317
 
4685
- export const $CreatePlatformDto = {
4686
- type: 'object',
4687
- properties: {
4688
- name: {
4689
- type: 'string',
4690
- description: 'Platform name',
4691
- example: 'Binance'
4692
- },
4693
- canonical: {
4694
- type: 'string',
4695
- description: 'Platform canonical identifier (lowercase, kebab-case)',
4696
- example: 'binance'
4697
- },
4698
- aliases: {
4699
- description: 'Platform aliases (multi-language names for lookup)',
4700
- example: ['Binance', 'Binance Exchange', 'BNB'],
4701
- type: 'array',
4702
- items: {
4703
- type: 'string'
4704
- }
4705
- },
4706
- url: {
4707
- type: 'string',
4708
- description: 'Platform URL',
4709
- example: 'https://www.binance.com'
4710
- },
4711
- type: {
4712
- type: 'string',
4713
- description: 'Platform type',
4714
- enum: [
4715
- 'BANK',
4716
- 'BROKERAGE',
4717
- 'CRYPTO_EXCHANGE',
4718
- 'PAYMENT',
4719
- 'INVESTMENT',
4720
- 'INSURANCE',
4721
- 'OTHER'
4722
- ],
4723
- example: 'CRYPTO_EXCHANGE'
4724
- },
4725
- logoUrl: {
4726
- type: 'string',
4727
- description: 'Platform logo URL',
4728
- example: 'https://example.com/logos/binance.png'
4729
- },
4730
- isActive: {
4731
- type: 'boolean',
4732
- description: 'Whether the platform is active',
4733
- default: true
4734
- }
4735
- },
4736
- required: ['name', 'canonical', 'aliases', 'url', 'type']
4737
- } as const;
4738
-
4739
- export const $UpdatePlatformDto = {
4740
- type: 'object',
4741
- properties: {
4742
- name: {
4743
- type: 'string',
4744
- description: 'Platform name',
4745
- example: 'Binance'
4746
- },
4747
- canonical: {
4748
- type: 'string',
4749
- description: 'Platform canonical identifier (lowercase, kebab-case)',
4750
- example: 'binance'
4751
- },
4752
- aliases: {
4753
- description: 'Platform aliases (multi-language names for lookup)',
4754
- example: ['Binance', 'Binance Exchange', 'BNB'],
4755
- type: 'array',
4756
- items: {
4757
- type: 'string'
4758
- }
4759
- },
4760
- url: {
4761
- type: 'string',
4762
- description: 'Platform URL',
4763
- example: 'https://www.binance.com'
4764
- },
4765
- type: {
4766
- type: 'string',
4767
- description: 'Platform type',
4768
- enum: [
4769
- 'BANK',
4770
- 'BROKERAGE',
4771
- 'CRYPTO_EXCHANGE',
4772
- 'PAYMENT',
4773
- 'INVESTMENT',
4774
- 'INSURANCE',
4775
- 'OTHER'
4776
- ],
4777
- example: 'CRYPTO_EXCHANGE'
4778
- },
4779
- logoUrl: {
4780
- type: 'string',
4781
- description: 'Platform logo URL',
4782
- example: 'https://example.com/logos/binance.png'
4783
- },
4784
- isActive: {
4785
- type: 'boolean',
4786
- description: 'Whether the platform is active'
4787
- }
4788
- }
4789
- } as const;
4790
-
4791
5318
  export const $ProviderSyncConfigDto = {
4792
5319
  type: 'object',
4793
5320
  properties: {
4794
5321
  sourceAccount: {
4795
5322
  type: 'string',
4796
5323
  description: 'Source account for the first posting',
4797
- example: 'Assets:Bank:Chase'
5324
+ example: 'Assets:US:Chase:Checking'
4798
5325
  },
4799
5326
  defaultCurrency: {
4800
5327
  type: 'string',
@@ -4815,6 +5342,12 @@ export const $ProviderSyncConfigDto = {
4815
5342
  type: 'boolean',
4816
5343
  description: 'Filter pending transactions',
4817
5344
  default: true
5345
+ },
5346
+ externalAccountId: {
5347
+ type: 'string',
5348
+ description:
5349
+ 'External account ID for per-batch providers (e.g. GoCardless). Overrides sourceAccount when an ExternalAccountLink mapping exists.',
5350
+ example: 'acc_gocardless_001'
4818
5351
  }
4819
5352
  },
4820
5353
  required: [
@@ -4934,6 +5467,94 @@ export const $SupportedProvidersResponseDto = {
4934
5467
  required: ['providers']
4935
5468
  } as const;
4936
5469
 
5470
+ export const $CreateExternalAccountLinkDto = {
5471
+ type: 'object',
5472
+ properties: {
5473
+ provider: {
5474
+ type: 'string',
5475
+ enum: [
5476
+ 'plaid',
5477
+ 'teller',
5478
+ 'truelayer',
5479
+ 'gocardless',
5480
+ 'simplefin',
5481
+ 'yodlee',
5482
+ 'beancount-direct',
5483
+ 'parsed-bill'
5484
+ ],
5485
+ example: 'plaid',
5486
+ description: 'Open Banking provider (whitelist)'
5487
+ },
5488
+ externalAccountId: {
5489
+ type: 'string',
5490
+ example: 'acc-plaid-001',
5491
+ description: 'External account ID from the provider'
5492
+ },
5493
+ beanAccountId: {
5494
+ type: 'string',
5495
+ example: '550e8400-e29b-41d4-a716-446655440000',
5496
+ description: 'Target BeanAccount ID (must belong to the JWT user)'
5497
+ }
5498
+ },
5499
+ required: ['provider', 'externalAccountId', 'beanAccountId']
5500
+ } as const;
5501
+
5502
+ export const $ExternalAccountLinkResponseDto = {
5503
+ type: 'object',
5504
+ properties: {
5505
+ id: {
5506
+ type: 'string'
5507
+ },
5508
+ provider: {
5509
+ type: 'string'
5510
+ },
5511
+ externalAccountId: {
5512
+ type: 'string'
5513
+ },
5514
+ beanAccountId: {
5515
+ type: 'string'
5516
+ },
5517
+ isActive: {
5518
+ type: 'boolean'
5519
+ },
5520
+ createdAt: {
5521
+ type: 'string'
5522
+ },
5523
+ updatedAt: {
5524
+ type: 'string'
5525
+ }
5526
+ },
5527
+ required: [
5528
+ 'id',
5529
+ 'provider',
5530
+ 'externalAccountId',
5531
+ 'beanAccountId',
5532
+ 'isActive',
5533
+ 'createdAt',
5534
+ 'updatedAt'
5535
+ ]
5536
+ } as const;
5537
+
5538
+ export const $ExternalAccountLinkListResponseDto = {
5539
+ type: 'object',
5540
+ properties: {
5541
+ items: {
5542
+ type: 'array',
5543
+ items: {
5544
+ $ref: '#/components/schemas/ExternalAccountLinkResponseDto'
5545
+ }
5546
+ },
5547
+ total: {
5548
+ type: 'number'
5549
+ },
5550
+ provider: {
5551
+ type: 'string',
5552
+ description: 'Filter by provider (query param)'
5553
+ }
5554
+ },
5555
+ required: ['items', 'total']
5556
+ } as const;
5557
+
4937
5558
  export const $ParserTelemetryReportDto = {
4938
5559
  type: 'object',
4939
5560
  properties: {}
@@ -5483,7 +6104,7 @@ export const $NlpSuggestedAccountDto = {
5483
6104
  account: {
5484
6105
  type: 'string',
5485
6106
  description: 'Suggested account path',
5486
- example: 'Assets:Bank:Checking'
6107
+ example: 'Assets:Checking'
5487
6108
  },
5488
6109
  confidence: {
5489
6110
  type: 'number',
@@ -5524,7 +6145,7 @@ export const $NlpDefaultAccountsDto = {
5524
6145
  asset: {
5525
6146
  type: 'string',
5526
6147
  description: 'Default asset account',
5527
- example: 'Assets:Bank:Checking'
6148
+ example: 'Assets:Checking'
5528
6149
  },
5529
6150
  expense: {
5530
6151
  type: 'string',
@@ -5743,24 +6364,113 @@ export const $NlpResponseDto = {
5743
6364
  ]
5744
6365
  }
5745
6366
  },
5746
- required: ['status', 'action']
6367
+ required: ['status', 'action']
6368
+ } as const;
6369
+
6370
+ export const $CreatePlatformDto = {
6371
+ type: 'object',
6372
+ properties: {
6373
+ name: {
6374
+ type: 'string',
6375
+ description: 'Platform name',
6376
+ example: 'Binance'
6377
+ },
6378
+ canonical: {
6379
+ type: 'string',
6380
+ description: 'Platform canonical identifier (lowercase, kebab-case)',
6381
+ example: 'binance'
6382
+ },
6383
+ aliases: {
6384
+ description: 'Platform aliases (multi-language names for lookup)',
6385
+ example: ['Binance', 'Binance Exchange', 'BNB'],
6386
+ type: 'array',
6387
+ items: {
6388
+ type: 'string'
6389
+ }
6390
+ },
6391
+ url: {
6392
+ type: 'string',
6393
+ description: 'Platform URL',
6394
+ example: 'https://www.binance.com'
6395
+ },
6396
+ type: {
6397
+ type: 'string',
6398
+ description: 'Platform type',
6399
+ enum: [
6400
+ 'BANK',
6401
+ 'BROKERAGE',
6402
+ 'CRYPTO_EXCHANGE',
6403
+ 'PAYMENT',
6404
+ 'INVESTMENT',
6405
+ 'INSURANCE',
6406
+ 'OTHER'
6407
+ ],
6408
+ example: 'CRYPTO_EXCHANGE'
6409
+ },
6410
+ logoUrl: {
6411
+ type: 'string',
6412
+ description: 'Platform logo URL',
6413
+ example: 'https://example.com/logos/binance.png'
6414
+ },
6415
+ isActive: {
6416
+ type: 'boolean',
6417
+ description: 'Whether the platform is active',
6418
+ default: true
6419
+ }
6420
+ },
6421
+ required: ['name', 'canonical', 'aliases', 'url', 'type']
5747
6422
  } as const;
5748
6423
 
5749
- export const $BalanceByCurrencyDto = {
6424
+ export const $UpdatePlatformDto = {
5750
6425
  type: 'object',
5751
6426
  properties: {
5752
- currency: {
6427
+ name: {
5753
6428
  type: 'string',
5754
- description: 'ISO 4217 currency code',
5755
- example: 'CNY'
6429
+ description: 'Platform name',
6430
+ example: 'Binance'
5756
6431
  },
5757
- balance: {
6432
+ canonical: {
5758
6433
  type: 'string',
5759
- description: 'Balance amount',
5760
- example: '50000.00'
6434
+ description: 'Platform canonical identifier (lowercase, kebab-case)',
6435
+ example: 'binance'
6436
+ },
6437
+ aliases: {
6438
+ description: 'Platform aliases (multi-language names for lookup)',
6439
+ example: ['Binance', 'Binance Exchange', 'BNB'],
6440
+ type: 'array',
6441
+ items: {
6442
+ type: 'string'
6443
+ }
6444
+ },
6445
+ url: {
6446
+ type: 'string',
6447
+ description: 'Platform URL',
6448
+ example: 'https://www.binance.com'
6449
+ },
6450
+ type: {
6451
+ type: 'string',
6452
+ description: 'Platform type',
6453
+ enum: [
6454
+ 'BANK',
6455
+ 'BROKERAGE',
6456
+ 'CRYPTO_EXCHANGE',
6457
+ 'PAYMENT',
6458
+ 'INVESTMENT',
6459
+ 'INSURANCE',
6460
+ 'OTHER'
6461
+ ],
6462
+ example: 'CRYPTO_EXCHANGE'
6463
+ },
6464
+ logoUrl: {
6465
+ type: 'string',
6466
+ description: 'Platform logo URL',
6467
+ example: 'https://example.com/logos/binance.png'
6468
+ },
6469
+ isActive: {
6470
+ type: 'boolean',
6471
+ description: 'Whether the platform is active'
5761
6472
  }
5762
- },
5763
- required: ['currency', 'balance']
6473
+ }
5764
6474
  } as const;
5765
6475
 
5766
6476
  export const $NetWorthByCurrencyDto = {
@@ -5832,28 +6542,6 @@ export const $ConvertedNetWorthDto = {
5832
6542
  ]
5833
6543
  } as const;
5834
6544
 
5835
- export const $ExchangeRateWarningDto = {
5836
- type: 'object',
5837
- properties: {
5838
- type: {
5839
- type: 'string',
5840
- description: 'Warning type',
5841
- example: 'MISSING_EXCHANGE_RATE'
5842
- },
5843
- currency: {
5844
- type: 'string',
5845
- description: 'Currency without exchange rate',
5846
- example: 'EUR'
5847
- },
5848
- totalAmount: {
5849
- type: 'string',
5850
- description: 'Total amount affected',
5851
- example: '1000.00'
5852
- }
5853
- },
5854
- required: ['type', 'currency', 'totalAmount']
5855
- } as const;
5856
-
5857
6545
  export const $NetWorthResponseDto = {
5858
6546
  type: 'object',
5859
6547
  properties: {
@@ -5939,7 +6627,7 @@ export const $AccountItemDto = {
5939
6627
  name: {
5940
6628
  type: 'string',
5941
6629
  description: 'Full account name',
5942
- example: 'Assets:Bank:CMB:Savings'
6630
+ example: 'Assets:CN:CMB:Savings'
5943
6631
  },
5944
6632
  displayName: {
5945
6633
  type: 'string',
@@ -5955,6 +6643,12 @@ export const $AccountItemDto = {
5955
6643
  type: 'string',
5956
6644
  description: 'Currency code',
5957
6645
  example: 'CNY'
6646
+ },
6647
+ convertedBalance: {
6648
+ type: 'string',
6649
+ description:
6650
+ 'FX-converted balance in base currency; omitted when not convertible',
6651
+ example: '50000.00'
5958
6652
  }
5959
6653
  },
5960
6654
  required: ['id', 'name', 'displayName', 'balance', 'currency']
@@ -5981,11 +6675,66 @@ export const $PlatformGroupDto = {
5981
6675
  },
5982
6676
  totalBalance: {
5983
6677
  type: 'string',
5984
- description: 'Total balance across all accounts in platform',
6678
+ description: 'FX-converted total balance in base currency',
6679
+ example: '100000.00'
6680
+ },
6681
+ balanceByCurrency: {
6682
+ description: 'Raw (unconverted) balances grouped by currency',
6683
+ type: 'array',
6684
+ items: {
6685
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
6686
+ }
6687
+ },
6688
+ convertedBalance: {
6689
+ type: 'string',
6690
+ description:
6691
+ 'Converted balance in base currency (omitted when no currency is convertible)',
5985
6692
  example: '100000.00'
6693
+ },
6694
+ sharePct: {
6695
+ type: 'number',
6696
+ description:
6697
+ 'Share of the grand converted total (0-100); 0 when grand total is 0',
6698
+ example: 42.5
6699
+ }
6700
+ },
6701
+ required: [
6702
+ 'platformId',
6703
+ 'platformName',
6704
+ 'accounts',
6705
+ 'totalBalance',
6706
+ 'balanceByCurrency',
6707
+ 'sharePct'
6708
+ ]
6709
+ } as const;
6710
+
6711
+ export const $AccountExchangeRateWarningDto = {
6712
+ type: 'object',
6713
+ properties: {
6714
+ type: {
6715
+ type: 'string',
6716
+ description: 'Warning type',
6717
+ example: 'MISSING_EXCHANGE_RATE'
6718
+ },
6719
+ currency: {
6720
+ type: 'string',
6721
+ description: 'Currency without exchange rate',
6722
+ example: 'USD'
6723
+ },
6724
+ accounts: {
6725
+ description: 'Affected account paths',
6726
+ type: 'array',
6727
+ items: {
6728
+ type: 'string'
6729
+ }
6730
+ },
6731
+ totalAmount: {
6732
+ type: 'string',
6733
+ description: 'Total amount in this currency',
6734
+ example: '5000.00'
5986
6735
  }
5987
6736
  },
5988
- required: ['platformId', 'platformName', 'accounts', 'totalBalance']
6737
+ required: ['type', 'currency', 'accounts', 'totalAmount']
5989
6738
  } as const;
5990
6739
 
5991
6740
  export const $AccountsSummaryDto = {
@@ -5998,9 +6747,21 @@ export const $AccountsSummaryDto = {
5998
6747
  totalPlatforms: {
5999
6748
  type: 'number',
6000
6749
  description: 'Total number of platforms'
6750
+ },
6751
+ baseCurrency: {
6752
+ type: 'string',
6753
+ description: 'Base currency for conversion',
6754
+ example: 'CNY'
6755
+ },
6756
+ warnings: {
6757
+ description: 'Per-account exchange rate warnings',
6758
+ type: 'array',
6759
+ items: {
6760
+ $ref: '#/components/schemas/AccountExchangeRateWarningDto'
6761
+ }
6001
6762
  }
6002
6763
  },
6003
- required: ['totalAccounts', 'totalPlatforms']
6764
+ required: ['totalAccounts', 'totalPlatforms', 'baseCurrency']
6004
6765
  } as const;
6005
6766
 
6006
6767
  export const $AccountsResponseDto = {
@@ -6035,7 +6796,7 @@ export const $AccountItemWithAssetClassDto = {
6035
6796
  name: {
6036
6797
  type: 'string',
6037
6798
  description: 'Full account name',
6038
- example: 'Assets:Bank:CMB:Savings'
6799
+ example: 'Assets:CN:CMB:Savings'
6039
6800
  },
6040
6801
  displayName: {
6041
6802
  type: 'string',
@@ -6052,6 +6813,12 @@ export const $AccountItemWithAssetClassDto = {
6052
6813
  description: 'Currency code',
6053
6814
  example: 'CNY'
6054
6815
  },
6816
+ convertedBalance: {
6817
+ type: 'string',
6818
+ description:
6819
+ 'FX-converted balance in base currency; omitted when not convertible',
6820
+ example: '50000.00'
6821
+ },
6055
6822
  assetClass: {
6056
6823
  type: 'string',
6057
6824
  description: 'Asset class',
@@ -6131,35 +6898,6 @@ export const $AssetClassGroupDto = {
6131
6898
  required: ['assetClass', 'accounts', 'balanceByCurrency']
6132
6899
  } as const;
6133
6900
 
6134
- export const $AccountExchangeRateWarningDto = {
6135
- type: 'object',
6136
- properties: {
6137
- type: {
6138
- type: 'string',
6139
- description: 'Warning type',
6140
- example: 'MISSING_EXCHANGE_RATE'
6141
- },
6142
- currency: {
6143
- type: 'string',
6144
- description: 'Currency without exchange rate',
6145
- example: 'USD'
6146
- },
6147
- accounts: {
6148
- description: 'Affected account paths',
6149
- type: 'array',
6150
- items: {
6151
- type: 'string'
6152
- }
6153
- },
6154
- totalAmount: {
6155
- type: 'string',
6156
- description: 'Total amount in this currency',
6157
- example: '5000.00'
6158
- }
6159
- },
6160
- required: ['type', 'currency', 'accounts', 'totalAmount']
6161
- } as const;
6162
-
6163
6901
  export const $AssetClassSummaryDto = {
6164
6902
  type: 'object',
6165
6903
  properties: {
@@ -6233,7 +6971,7 @@ export const $HoldingAssetClassAccountSliceDto = {
6233
6971
  accountPath: {
6234
6972
  type: 'string',
6235
6973
  description: 'Full account path',
6236
- example: 'Assets:US:Investments:Brokerage'
6974
+ example: 'Assets:US:Fidelity:Brokerage'
6237
6975
  },
6238
6976
  accountCurrency: {
6239
6977
  type: 'string',
@@ -6413,30 +7151,125 @@ export const $CashFlowResponseDto = {
6413
7151
  }
6414
7152
  ]
6415
7153
  },
6416
- converted: {
6417
- description: 'Converted values in base currency',
7154
+ converted: {
7155
+ description: 'Converted values in base currency',
7156
+ allOf: [
7157
+ {
7158
+ $ref: '#/components/schemas/ConvertedCashFlowDto'
7159
+ }
7160
+ ]
7161
+ },
7162
+ warnings: {
7163
+ description: 'Exchange rate warnings',
7164
+ type: 'array',
7165
+ items: {
7166
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
7167
+ }
7168
+ }
7169
+ },
7170
+ required: [
7171
+ 'period',
7172
+ 'income',
7173
+ 'expense',
7174
+ 'netSavings',
7175
+ 'savingsRate',
7176
+ 'currency'
7177
+ ]
7178
+ } as const;
7179
+
7180
+ export const $CategoryGroupDto = {
7181
+ type: 'object',
7182
+ properties: {
7183
+ category: {
7184
+ type: 'string',
7185
+ description:
7186
+ 'Functional category (account-path Group segment); regional and universal account paths merge under it',
7187
+ example: 'Food'
7188
+ },
7189
+ totalExpense: {
7190
+ type: 'string',
7191
+ description:
7192
+ 'Converted total for this category in base currency (expense amount when flow=expense, income amount when flow=income)',
7193
+ example: '1200.00'
7194
+ },
7195
+ sharePct: {
7196
+ type: 'number',
7197
+ description: 'Share of grand total (0-100); 0 when grand total is 0',
7198
+ example: 42.5
7199
+ },
7200
+ balanceByCurrency: {
7201
+ description: 'Raw (unconverted) expense per currency',
7202
+ type: 'array',
7203
+ items: {
7204
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
7205
+ }
7206
+ },
7207
+ convertedBalance: {
7208
+ type: 'string',
7209
+ description:
7210
+ 'Converted total in base currency (omitted when FX missing for all currencies in this category)',
7211
+ example: '1200.00'
7212
+ }
7213
+ },
7214
+ required: ['category', 'totalExpense', 'sharePct', 'balanceByCurrency']
7215
+ } as const;
7216
+
7217
+ export const $ExpensesByCategorySummaryDto = {
7218
+ type: 'object',
7219
+ properties: {
7220
+ totalExpense: {
7221
+ type: 'string',
7222
+ description:
7223
+ 'Total across all categories, converted (convertible categories only); expense totals when flow=expense, income totals when flow=income',
7224
+ example: '5000.00'
7225
+ },
7226
+ categoryCount: {
7227
+ type: 'number',
7228
+ description: 'Number of categories',
7229
+ example: 8
7230
+ }
7231
+ },
7232
+ required: ['totalExpense', 'categoryCount']
7233
+ } as const;
7234
+
7235
+ export const $ExpensesByCategoryResponseDto = {
7236
+ type: 'object',
7237
+ properties: {
7238
+ period: {
7239
+ type: 'string',
7240
+ description: 'Period requested',
7241
+ example: '1m'
7242
+ },
7243
+ baseCurrency: {
7244
+ type: 'string',
7245
+ description: 'Base currency for converted values',
7246
+ example: 'CNY'
7247
+ },
7248
+ groups: {
7249
+ description:
7250
+ 'Expense groups by functional category, sorted by converted total desc',
7251
+ type: 'array',
7252
+ items: {
7253
+ $ref: '#/components/schemas/CategoryGroupDto'
7254
+ }
7255
+ },
7256
+ summary: {
7257
+ description: 'Summary statistics',
6418
7258
  allOf: [
6419
7259
  {
6420
- $ref: '#/components/schemas/ConvertedCashFlowDto'
7260
+ $ref: '#/components/schemas/ExpensesByCategorySummaryDto'
6421
7261
  }
6422
7262
  ]
6423
7263
  },
6424
7264
  warnings: {
6425
- description: 'Exchange rate warnings',
7265
+ description: 'Exchange rate warnings (e.g. missing rate for a currency)',
6426
7266
  type: 'array',
6427
7267
  items: {
6428
7268
  $ref: '#/components/schemas/ExchangeRateWarningDto'
6429
7269
  }
6430
7270
  }
6431
7271
  },
6432
- required: [
6433
- 'period',
6434
- 'income',
6435
- 'expense',
6436
- 'netSavings',
6437
- 'savingsRate',
6438
- 'currency'
6439
- ]
7272
+ required: ['period', 'baseCurrency', 'groups', 'summary']
6440
7273
  } as const;
6441
7274
 
6442
7275
  export const $MonetaryDto = {
@@ -6728,163 +7561,6 @@ export const $HoldingPnlResponseDto = {
6728
7561
  required: ['asOfDate', 'baseCurrency', 'method', 'rows', 'warnings']
6729
7562
  } as const;
6730
7563
 
6731
- export const $CreateBeanPriceDto = {
6732
- type: 'object',
6733
- properties: {
6734
- currency: {
6735
- type: 'string',
6736
- description: 'Currency being priced (e.g., USD, AAPL, BTC)',
6737
- example: 'USD'
6738
- },
6739
- quoteCurrency: {
6740
- type: 'string',
6741
- description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
6742
- example: 'CNY'
6743
- },
6744
- amount: {
6745
- type: 'number',
6746
- description:
6747
- 'Price amount (MUST be >= 0 per Beancount spec, supports up to 15 decimal places). Zero allowed for conversion entries, negative strictly prohibited.',
6748
- example: 175.5,
6749
- minimum: 0
6750
- },
6751
- date: {
6752
- type: 'string',
6753
- description: 'Price date (ISO 8601 format)',
6754
- example: '2024-11-05'
6755
- },
6756
- metadata: {
6757
- type: 'object',
6758
- description:
6759
- 'Metadata (validated by Zod schema, max field lengths enforced)',
6760
- example: {
6761
- source: 'MANUAL',
6762
- note: 'Bank valuation report',
6763
- confidence: 0.95
6764
- }
6765
- }
6766
- },
6767
- required: ['currency', 'quoteCurrency', 'amount', 'date']
6768
- } as const;
6769
-
6770
- export const $PriceResponseDto = {
6771
- type: 'object',
6772
- properties: {
6773
- id: {
6774
- type: 'string',
6775
- description: 'Unique identifier',
6776
- example: 'uuid-123-456'
6777
- },
6778
- userId: {
6779
- type: 'string',
6780
- description: 'User ID (owner of the price)',
6781
- example: 'user-123'
6782
- },
6783
- currency: {
6784
- type: 'string',
6785
- description: 'Currency being priced (e.g., USD, AAPL, BTC)',
6786
- example: 'BTC'
6787
- },
6788
- quoteCurrency: {
6789
- type: 'string',
6790
- description: 'Quote currency (pricing currency, e.g., USD, CNY)',
6791
- example: 'USD'
6792
- },
6793
- amount: {
6794
- type: 'number',
6795
- description:
6796
- 'Price amount (corresponds to Beancount Amount.number). Supports up to 15 decimal places.',
6797
- example: 50000
6798
- },
6799
- date: {
6800
- type: 'string',
6801
- description:
6802
- 'Price date (ISO 8601 format). Represents the date this price was valid.',
6803
- example: '2024-01-01',
6804
- format: 'date'
6805
- },
6806
- meta: {
6807
- type: 'object',
6808
- description:
6809
- 'Metadata (corresponds to Beancount meta field). Contains source, confidence, note, etc.',
6810
- example: {
6811
- source: 'MANUAL',
6812
- note: 'User-defined price',
6813
- confidence: 1
6814
- }
6815
- },
6816
- createdAt: {
6817
- format: 'date-time',
6818
- type: 'string',
6819
- description: 'Creation timestamp',
6820
- example: '2024-11-03T10:00:00Z'
6821
- },
6822
- updatedAt: {
6823
- format: 'date-time',
6824
- type: 'string',
6825
- description: 'Last update timestamp',
6826
- example: '2024-11-03T10:00:00Z'
6827
- }
6828
- },
6829
- required: [
6830
- 'id',
6831
- 'userId',
6832
- 'currency',
6833
- 'quoteCurrency',
6834
- 'amount',
6835
- 'date',
6836
- 'meta',
6837
- 'createdAt',
6838
- 'updatedAt'
6839
- ]
6840
- } as const;
6841
-
6842
- export const $PriceListResponseDto = {
6843
- type: 'object',
6844
- properties: {
6845
- items: {
6846
- description: 'List of prices',
6847
- type: 'array',
6848
- items: {
6849
- $ref: '#/components/schemas/PriceResponseDto'
6850
- }
6851
- },
6852
- total: {
6853
- type: 'number',
6854
- description: 'Total number of prices',
6855
- example: 42
6856
- }
6857
- },
6858
- required: ['items', 'total']
6859
- } as const;
6860
-
6861
- export const $UpdateBeanPriceDto = {
6862
- type: 'object',
6863
- properties: {
6864
- currency: {
6865
- type: 'string',
6866
- description: 'Currency being priced'
6867
- },
6868
- quoteCurrency: {
6869
- type: 'string',
6870
- description: 'Quote currency (pricing currency)'
6871
- },
6872
- amount: {
6873
- type: 'number',
6874
- description: 'Price amount (MUST be >= 0 per Beancount spec)',
6875
- minimum: 0
6876
- },
6877
- date: {
6878
- type: 'string',
6879
- description: 'Price date (ISO 8601 format)'
6880
- },
6881
- metadata: {
6882
- type: 'object',
6883
- description: 'Metadata'
6884
- }
6885
- }
6886
- } as const;
6887
-
6888
7564
  export const $CurrencyBalanceDto = {
6889
7565
  type: 'object',
6890
7566
  properties: {
@@ -6920,6 +7596,16 @@ export const $TimeSeriesPointDto = {
6920
7596
  description: 'Change from previous point',
6921
7597
  example: '5000.00'
6922
7598
  },
7599
+ assets: {
7600
+ type: 'string',
7601
+ description: 'Total assets at this date (in base currency)',
7602
+ example: '494338.00'
7603
+ },
7604
+ liabilities: {
7605
+ type: 'string',
7606
+ description: 'Total liabilities at this date (in base currency)',
7607
+ example: '310098.00'
7608
+ },
6923
7609
  byCurrency: {
6924
7610
  description: 'Multi-currency breakdown for this point',
6925
7611
  type: 'array',
@@ -7029,6 +7715,111 @@ export const $PortfolioTrendsResponseDto = {
7029
7715
  required: ['series', 'summary', 'period', 'granularity', 'currency']
7030
7716
  } as const;
7031
7717
 
7718
+ export const $CashFlowPointDto = {
7719
+ type: 'object',
7720
+ properties: {
7721
+ month: {
7722
+ type: 'string',
7723
+ description: 'Month key (YYYY-MM)',
7724
+ example: '2024-03'
7725
+ },
7726
+ income: {
7727
+ type: 'string',
7728
+ description: 'Income in base currency (absolute, converted)',
7729
+ example: '10000.00'
7730
+ },
7731
+ expense: {
7732
+ type: 'string',
7733
+ description: 'Expense in base currency (absolute, converted)',
7734
+ example: '5000.00'
7735
+ },
7736
+ netSavings: {
7737
+ type: 'string',
7738
+ description: 'netSavings = income − expense (savings positive)',
7739
+ example: '5000.00'
7740
+ }
7741
+ },
7742
+ required: ['month', 'income', 'expense', 'netSavings']
7743
+ } as const;
7744
+
7745
+ export const $CashFlowTrendSummaryDto = {
7746
+ type: 'object',
7747
+ properties: {
7748
+ totalIncome: {
7749
+ type: 'string',
7750
+ description: 'Total income across the period',
7751
+ example: '60000.00'
7752
+ },
7753
+ totalExpense: {
7754
+ type: 'string',
7755
+ description: 'Total expense across the period',
7756
+ example: '30000.00'
7757
+ },
7758
+ totalNetSavings: {
7759
+ type: 'string',
7760
+ description: 'income − expense across the period',
7761
+ example: '30000.00'
7762
+ },
7763
+ averageMonthlyNetSavings: {
7764
+ type: 'string',
7765
+ description:
7766
+ 'totalNetSavings divided by the window length (N months, incl. zero-filled)',
7767
+ example: '5000.00'
7768
+ }
7769
+ },
7770
+ required: [
7771
+ 'totalIncome',
7772
+ 'totalExpense',
7773
+ 'totalNetSavings',
7774
+ 'averageMonthlyNetSavings'
7775
+ ]
7776
+ } as const;
7777
+
7778
+ export const $CashFlowTrendsResponseDto = {
7779
+ type: 'object',
7780
+ properties: {
7781
+ series: {
7782
+ description:
7783
+ 'Monthly cash-flow series (fixed N-month window, zero-filled)',
7784
+ type: 'array',
7785
+ items: {
7786
+ $ref: '#/components/schemas/CashFlowPointDto'
7787
+ }
7788
+ },
7789
+ summary: {
7790
+ description: 'Period totals',
7791
+ allOf: [
7792
+ {
7793
+ $ref: '#/components/schemas/CashFlowTrendSummaryDto'
7794
+ }
7795
+ ]
7796
+ },
7797
+ period: {
7798
+ type: 'string',
7799
+ description: 'Period requested',
7800
+ example: '6m'
7801
+ },
7802
+ granularity: {
7803
+ type: 'string',
7804
+ description: 'Data granularity (v1 returns month buckets)',
7805
+ example: 'month'
7806
+ },
7807
+ currency: {
7808
+ type: 'string',
7809
+ description: 'Base currency for converted values',
7810
+ example: 'CNY'
7811
+ },
7812
+ warnings: {
7813
+ description: 'Exchange rate warnings (e.g. missing rate for a currency)',
7814
+ type: 'array',
7815
+ items: {
7816
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
7817
+ }
7818
+ }
7819
+ },
7820
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
7821
+ } as const;
7822
+
7032
7823
  export const $GenerateSnapshotBody = {
7033
7824
  type: 'object',
7034
7825
  properties: {}