@firela/api-types 0.0.0-canary.a85ace93 → 0.0.0-canary.a90ce0e4

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,18 +6,12 @@ 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',
19
13
  type: 'string',
20
- description: 'Account open date',
14
+ description: 'Account open date (server defaults to today)',
21
15
  example: '2024-01-01'
22
16
  },
23
17
  currencies: {
@@ -45,26 +39,22 @@ 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)',
63
52
  example: 'bank-custom'
64
53
  },
65
- openMeta: {
54
+ openDirectiveMeta: {
66
55
  type: 'object',
67
- description: 'Additional metadata',
56
+ description:
57
+ 'Open directive metadata (NOT an opening-balance amount — use the opening-balance endpoint)',
68
58
  example: {
69
59
  branch: 'Downtown',
70
60
  accountNumber: '1234'
@@ -76,7 +66,7 @@ export const $CreateAccountDto = {
76
66
  example: 'c98e5d4a-2f71-4a5a-bb3c-92c9f231d5e2'
77
67
  }
78
68
  },
79
- required: ['path', 'openDate']
69
+ required: ['path']
80
70
  } as const;
81
71
 
82
72
  export const $AccountResponseDto = {
@@ -90,13 +80,7 @@ export const $AccountResponseDto = {
90
80
  path: {
91
81
  type: 'string',
92
82
  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: '工资卡'
83
+ example: 'Assets:CN:ICBC:Checking'
100
84
  },
101
85
  type: {
102
86
  type: 'string',
@@ -145,26 +129,26 @@ export const $AccountResponseDto = {
145
129
  templatePath: {
146
130
  type: 'string',
147
131
  description: 'Template path reference',
148
- example: 'Assets:CN:Bank:ICBC:Checking'
132
+ example: 'Assets:CN:Checking'
149
133
  },
150
134
  isCustom: {
151
135
  type: 'boolean',
152
136
  description: 'Whether this is a custom (user-created) account',
153
137
  example: false
154
138
  },
155
- i18nKey: {
139
+ displayName: {
156
140
  type: 'string',
157
- description: 'i18n key for display name',
158
- example: 'account.assets.cn.bank.icbc.checking'
141
+ description: 'Localized display name (ADR-0114, read-time projection)',
142
+ example: 'Checking'
159
143
  },
160
144
  icon: {
161
145
  type: 'string',
162
146
  description: 'Icon identifier',
163
147
  example: 'bank-icbc'
164
148
  },
165
- openMeta: {
149
+ openDirectiveMeta: {
166
150
  type: 'object',
167
- description: 'Account metadata',
151
+ description: 'Open directive metadata (ADR-0115 Decision 9)',
168
152
  example: {
169
153
  branch: 'Downtown'
170
154
  }
@@ -192,7 +176,6 @@ export const $AccountResponseDto = {
192
176
  required: [
193
177
  'id',
194
178
  'path',
195
- 'displayName',
196
179
  'type',
197
180
  'status',
198
181
  'openDate',
@@ -225,11 +208,6 @@ export const $AccountListResponseDto = {
225
208
  export const $UpdateAccountDto = {
226
209
  type: 'object',
227
210
  properties: {
228
- displayName: {
229
- type: 'string',
230
- description: 'Display name to distinguish accounts at the same path',
231
- example: '招行工资卡'
232
- },
233
211
  currencies: {
234
212
  description: 'Allowed currencies (null = no restriction)',
235
213
  example: ['CNY', 'USD'],
@@ -251,19 +229,15 @@ export const $UpdateAccountDto = {
251
229
  'NONE'
252
230
  ]
253
231
  },
254
- i18nKey: {
255
- type: 'string',
256
- description: 'i18n key for display name',
257
- example: 'account.custom.mybank'
258
- },
259
232
  icon: {
260
233
  type: 'string',
261
234
  description: 'Icon identifier',
262
235
  example: 'bank-custom'
263
236
  },
264
- openMeta: {
237
+ openDirectiveMeta: {
265
238
  type: 'object',
266
- description: 'Additional metadata (merged with existing)',
239
+ description:
240
+ 'Open directive metadata (merged with existing; NOT an opening-balance amount)',
267
241
  example: {
268
242
  branch: 'Uptown'
269
243
  }
@@ -310,13 +284,47 @@ export const $ReopenAccountDto = {
310
284
  }
311
285
  } as const;
312
286
 
287
+ export const $CreateOpeningBalanceDto = {
288
+ type: 'object',
289
+ properties: {
290
+ amount: {
291
+ type: 'number',
292
+ description: 'Opening balance amount (non-negative)',
293
+ example: 1000
294
+ },
295
+ currency: {
296
+ type: 'string',
297
+ description: 'Currency code',
298
+ example: 'CNY'
299
+ },
300
+ date: {
301
+ format: 'date-time',
302
+ type: 'string',
303
+ description: 'Opening-balance date (defaults to now)',
304
+ example: '2024-01-01'
305
+ }
306
+ },
307
+ required: ['amount', 'currency']
308
+ } as const;
309
+
310
+ export const $OpeningBalanceResultDto = {
311
+ type: 'object',
312
+ properties: {
313
+ transactionId: {
314
+ type: 'string',
315
+ description: 'Created opening-balance transaction id.'
316
+ }
317
+ },
318
+ required: ['transactionId']
319
+ } as const;
320
+
313
321
  export const $AccountStandardResponseDto = {
314
322
  type: 'object',
315
323
  properties: {
316
324
  path: {
317
325
  type: 'string',
318
326
  description: 'Account path (hierarchical, colon-separated)',
319
- example: 'Assets:CN:Bank:ICBC:Checking'
327
+ example: 'Assets:CN:Checking'
320
328
  },
321
329
  type: {
322
330
  type: 'string',
@@ -324,11 +332,6 @@ export const $AccountStandardResponseDto = {
324
332
  enum: ['Assets', 'Liabilities', 'Income', 'Expenses', 'Equity'],
325
333
  example: 'Assets'
326
334
  },
327
- i18nKey: {
328
- type: 'string',
329
- description: 'i18n key for localized display name',
330
- example: 'account.assets.cn.bank.icbc.checking'
331
- },
332
335
  name: {
333
336
  type: 'string',
334
337
  description: 'Short localized display name',
@@ -353,7 +356,7 @@ export const $AccountStandardResponseDto = {
353
356
  example: 'bank-icbc'
354
357
  }
355
358
  },
356
- required: ['path', 'type', 'i18nKey', 'description', 'tags', 'icon']
359
+ required: ['path', 'type', 'description', 'tags', 'icon']
357
360
  } as const;
358
361
 
359
362
  export const $AccountStandardListResponseDto = {
@@ -383,18 +386,13 @@ export const $AccountStandardListResponseDto = {
383
386
  export const $TemplateMetadataDto = {
384
387
  type: 'object',
385
388
  properties: {
386
- extendable: {
387
- type: 'boolean',
388
- description: 'Whether this path can be extended',
389
- example: true
390
- },
391
389
  rootType: {
392
390
  type: 'string',
393
391
  description: 'Root account type',
394
392
  example: 'Assets'
395
393
  }
396
394
  },
397
- required: ['extendable', 'rootType']
395
+ required: ['rootType']
398
396
  } as const;
399
397
 
400
398
  export const $TemplateMetadataResponseDto = {
@@ -466,6 +464,66 @@ export const $RegionsMetadataResponseDto = {
466
464
  required: ['regions']
467
465
  } as const;
468
466
 
467
+ export const $CostSpecDto = {
468
+ type: 'object',
469
+ properties: {
470
+ mode: {
471
+ type: 'string',
472
+ enum: ['per-unit', 'total', 'date', 'label', 'auto'],
473
+ description: 'Cost specification mode (mirrors engine CostSpec)'
474
+ },
475
+ numberPerUnit: {
476
+ type: 'string',
477
+ description: 'Per-unit cost (required when mode is "per-unit")',
478
+ example: '240'
479
+ },
480
+ totalNumber: {
481
+ type: 'string',
482
+ description: 'Total cost for all units (required when mode is "total")',
483
+ example: '12000'
484
+ },
485
+ currency: {
486
+ type: 'string',
487
+ description: 'Cost currency (required in all modes)',
488
+ example: 'USD'
489
+ },
490
+ date: {
491
+ type: 'string',
492
+ description:
493
+ 'Lot acquisition date, ISO 8601 (required when mode is "date")',
494
+ example: '2024-01-15'
495
+ },
496
+ label: {
497
+ type: 'string',
498
+ description:
499
+ 'Lot label (required when mode is "label"; optional tag in buy modes)'
500
+ },
501
+ merge: {
502
+ type: 'boolean',
503
+ description: 'Merge lots for AVERAGE booking (mode: auto)'
504
+ }
505
+ },
506
+ required: ['mode', 'currency']
507
+ } as const;
508
+
509
+ export const $AmountDto = {
510
+ type: 'object',
511
+ properties: {
512
+ number: {
513
+ type: 'string',
514
+ description:
515
+ 'Amount as decimal string (max 15 integer + 15 decimal digits)',
516
+ example: '170.50'
517
+ },
518
+ currency: {
519
+ type: 'string',
520
+ description: 'Currency/commodity code',
521
+ example: 'USD'
522
+ }
523
+ },
524
+ required: ['number', 'currency']
525
+ } as const;
526
+
469
527
  export const $CreatePostingDto = {
470
528
  type: 'object',
471
529
  properties: {
@@ -473,7 +531,7 @@ export const $CreatePostingDto = {
473
531
  type: 'string',
474
532
  description:
475
533
  'Account name in Beancount format (must start with uppercase, colon-separated)',
476
- example: 'Assets:Bank:Checking'
534
+ example: 'Assets:Checking'
477
535
  },
478
536
  units: {
479
537
  type: 'string',
@@ -495,6 +553,33 @@ export const $CreatePostingDto = {
495
553
  example: {
496
554
  'tax-lot': 'Q1-2024'
497
555
  }
556
+ },
557
+ cost: {
558
+ description:
559
+ 'Cost basis (Beancount `{...}`). Maps to engine costSpec. Required for commodity holdings so they carry a monetary weight that can balance.',
560
+ example: {
561
+ mode: 'per-unit',
562
+ numberPerUnit: '240',
563
+ currency: 'USD'
564
+ },
565
+ allOf: [
566
+ {
567
+ $ref: '#/components/schemas/CostSpecDto'
568
+ }
569
+ ]
570
+ },
571
+ price: {
572
+ description:
573
+ 'Price annotation (Beancount `@...`). Maps to engine price. Used for valuation; cost takes priority for balance weight.',
574
+ example: {
575
+ number: '170',
576
+ currency: 'USD'
577
+ },
578
+ allOf: [
579
+ {
580
+ $ref: '#/components/schemas/AmountDto'
581
+ }
582
+ ]
498
583
  }
499
584
  },
500
585
  required: ['account']
@@ -573,13 +658,39 @@ export const $CreateTransactionDto = {
573
658
  required: ['date', 'narration', 'postings']
574
659
  } as const;
575
660
 
661
+ export const $CostDetailDto = {
662
+ type: 'object',
663
+ properties: {
664
+ number: {
665
+ type: 'string',
666
+ description: 'Per-unit cost basis (mirrors engine Cost.number)',
667
+ example: '240'
668
+ },
669
+ currency: {
670
+ type: 'string',
671
+ description: 'Cost currency',
672
+ example: 'USD'
673
+ },
674
+ date: {
675
+ type: 'string',
676
+ description: 'Lot acquisition date (ISO yyyy-mm-dd)',
677
+ example: '2024-01-15'
678
+ },
679
+ label: {
680
+ type: 'string',
681
+ description: 'Lot label',
682
+ example: 'lot-2024-01'
683
+ }
684
+ }
685
+ } as const;
686
+
576
687
  export const $PostingResponseDto = {
577
688
  type: 'object',
578
689
  properties: {
579
690
  account: {
580
691
  type: 'string',
581
692
  description: 'Account name',
582
- example: 'Assets:Bank:Checking'
693
+ example: 'Assets:Checking'
583
694
  },
584
695
  units: {
585
696
  type: 'string',
@@ -591,6 +702,15 @@ export const $PostingResponseDto = {
591
702
  type: 'string',
592
703
  description: 'Currency',
593
704
  example: 'USD'
705
+ },
706
+ cost: {
707
+ description:
708
+ 'Booking-resolved cost (mirrors engine Cost). Undefined when the posting has no cost basis.',
709
+ allOf: [
710
+ {
711
+ $ref: '#/components/schemas/CostDetailDto'
712
+ }
713
+ ]
594
714
  }
595
715
  },
596
716
  required: ['account']
@@ -936,7 +1056,7 @@ export const $PostingDetailDto = {
936
1056
  account: {
937
1057
  type: 'string',
938
1058
  description: 'Fully-qualified Beancount account path',
939
- example: 'Assets:Bank:Checking'
1059
+ example: 'Assets:Checking'
940
1060
  },
941
1061
  units: {
942
1062
  type: 'string',
@@ -964,6 +1084,15 @@ export const $PostingDetailDto = {
964
1084
  description: 'Cost date',
965
1085
  example: '2024-01-15'
966
1086
  },
1087
+ cost: {
1088
+ description:
1089
+ 'Booking-resolved cost (mirrors engine Cost). Undefined when the posting has no cost basis.',
1090
+ allOf: [
1091
+ {
1092
+ $ref: '#/components/schemas/CostDetailDto'
1093
+ }
1094
+ ]
1095
+ },
967
1096
  priceAmount: {
968
1097
  type: 'string',
969
1098
  description: 'Price amount',
@@ -1116,6 +1245,77 @@ export const $TransactionDetailDto = {
1116
1245
  ]
1117
1246
  } as const;
1118
1247
 
1248
+ export const $BalanceByCurrencyDto = {
1249
+ type: 'object',
1250
+ properties: {
1251
+ currency: {
1252
+ type: 'string',
1253
+ description: 'ISO 4217 currency code',
1254
+ example: 'CNY'
1255
+ },
1256
+ balance: {
1257
+ type: 'string',
1258
+ description: 'Balance amount',
1259
+ example: '50000.00'
1260
+ }
1261
+ },
1262
+ required: ['currency', 'balance']
1263
+ } as const;
1264
+
1265
+ export const $ExchangeRateWarningDto = {
1266
+ type: 'object',
1267
+ properties: {
1268
+ type: {
1269
+ type: 'string',
1270
+ description: 'Warning type',
1271
+ example: 'MISSING_EXCHANGE_RATE'
1272
+ },
1273
+ currency: {
1274
+ type: 'string',
1275
+ description: 'Currency without exchange rate',
1276
+ example: 'EUR'
1277
+ },
1278
+ totalAmount: {
1279
+ type: 'string',
1280
+ description: 'Total amount affected',
1281
+ example: '1000.00'
1282
+ }
1283
+ },
1284
+ required: ['type', 'currency', 'totalAmount']
1285
+ } as const;
1286
+
1287
+ export const $TransactionListSummaryDto = {
1288
+ type: 'object',
1289
+ properties: {
1290
+ totalAmount: {
1291
+ type: 'string',
1292
+ description:
1293
+ '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.',
1294
+ example: '-6000.00'
1295
+ },
1296
+ currency: {
1297
+ type: 'string',
1298
+ description: 'Base currency (ISO 4217)',
1299
+ example: 'CNY'
1300
+ },
1301
+ balanceByCurrency: {
1302
+ description: 'Raw (unconverted) balance per currency',
1303
+ type: 'array',
1304
+ items: {
1305
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
1306
+ }
1307
+ },
1308
+ warnings: {
1309
+ description: 'Currencies missing an FX rate (omitted when empty)',
1310
+ type: 'array',
1311
+ items: {
1312
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
1313
+ }
1314
+ }
1315
+ },
1316
+ required: ['totalAmount', 'currency', 'balanceByCurrency']
1317
+ } as const;
1318
+
1119
1319
  export const $TransactionListResponseDto = {
1120
1320
  type: 'object',
1121
1321
  properties: {
@@ -1140,6 +1340,15 @@ export const $TransactionListResponseDto = {
1140
1340
  type: 'number',
1141
1341
  description: 'Number of items skipped',
1142
1342
  example: 0
1343
+ },
1344
+ summary: {
1345
+ description:
1346
+ '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.',
1347
+ allOf: [
1348
+ {
1349
+ $ref: '#/components/schemas/TransactionListSummaryDto'
1350
+ }
1351
+ ]
1143
1352
  }
1144
1353
  },
1145
1354
  required: ['data', 'total', 'limit', 'offset']
@@ -1239,7 +1448,7 @@ export const $BalanceResponseDto = {
1239
1448
  account: {
1240
1449
  type: 'string',
1241
1450
  description: 'Account name',
1242
- example: 'Assets:Bank:Checking'
1451
+ example: 'Assets:Checking'
1243
1452
  },
1244
1453
  balance: {
1245
1454
  type: 'string',
@@ -1266,7 +1475,7 @@ export const $MultiCurrencyBalanceResponseDto = {
1266
1475
  account: {
1267
1476
  type: 'string',
1268
1477
  description: 'Account name',
1269
- example: 'Assets:Bank:Checking'
1478
+ example: 'Assets:Checking'
1270
1479
  },
1271
1480
  balances: {
1272
1481
  type: 'object',
@@ -1322,7 +1531,7 @@ export const $TransactionSummaryDto = {
1322
1531
  accountName: {
1323
1532
  type: 'string',
1324
1533
  description: 'Source account name (first posting)',
1325
- example: 'Assets:Bank:Checking'
1534
+ example: 'Assets:Checking'
1326
1535
  },
1327
1536
  sourceType: {
1328
1537
  type: 'string',
@@ -1724,7 +1933,8 @@ export const $ResolveResultDto = {
1724
1933
  },
1725
1934
  resolutionId: {
1726
1935
  type: 'string',
1727
- description: 'Resolution ID for undo'
1936
+ description:
1937
+ 'Resolution ID for undo. Absent when the resolver rejected the decision (review stayed PENDING).'
1728
1938
  },
1729
1939
  canUndo: {
1730
1940
  type: 'boolean',
@@ -1742,7 +1952,7 @@ export const $ResolveResultDto = {
1742
1952
  example: 'rule_01HXK5V8N2M3P4Q5R6S7T8U9V0'
1743
1953
  }
1744
1954
  },
1745
- required: ['success', 'resolutionId', 'canUndo', 'undoDeadline']
1955
+ required: ['success']
1746
1956
  } as const;
1747
1957
 
1748
1958
  export const $UndoResultDto = {
@@ -2613,44 +2823,201 @@ export const $UpdateCommodityDto = {
2613
2823
  }
2614
2824
  } as const;
2615
2825
 
2616
- export const $CreateRecurringRuleDto = {
2826
+ export const $CreateBeanPriceDto = {
2617
2827
  type: 'object',
2618
2828
  properties: {
2619
- name: {
2620
- type: 'string',
2621
- description: 'Rule name (unique per user)',
2622
- maxLength: 100
2623
- },
2624
- icon: {
2829
+ currency: {
2625
2830
  type: 'string',
2626
- description: 'Icon emoji',
2627
- maxLength: 10
2831
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
2832
+ example: 'USD'
2628
2833
  },
2629
- frequency: {
2834
+ quoteCurrency: {
2630
2835
  type: 'string',
2631
- description: 'Recurring frequency',
2632
- enum: [
2633
- 'WEEKLY',
2634
- 'BIWEEKLY',
2635
- 'MONTHLY',
2636
- 'BIMONTHLY',
2637
- 'QUARTERLY',
2638
- 'YEARLY',
2639
- 'CUSTOM'
2640
- ]
2836
+ description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
2837
+ example: 'CNY'
2641
2838
  },
2642
- expectedAmount: {
2839
+ amount: {
2643
2840
  type: 'number',
2644
- description: 'Expected amount (positive number)',
2841
+ description:
2842
+ 'Price amount (MUST be >= 0 per Beancount spec, supports up to 15 decimal places). Zero allowed for conversion entries, negative strictly prohibited.',
2843
+ example: 175.5,
2645
2844
  minimum: 0
2646
2845
  },
2647
- expectedDay: {
2648
- type: 'number',
2649
- description: 'Expected day of month (1-31)',
2650
- minimum: 1,
2651
- maximum: 31
2846
+ date: {
2847
+ type: 'string',
2848
+ description: 'Price date (ISO 8601 format)',
2849
+ example: '2024-11-05'
2652
2850
  },
2653
- customIntervalDays: {
2851
+ metadata: {
2852
+ type: 'object',
2853
+ description:
2854
+ 'Metadata (validated by Zod schema, max field lengths enforced)',
2855
+ example: {
2856
+ source: 'MANUAL',
2857
+ note: 'Bank valuation report',
2858
+ confidence: 0.95
2859
+ }
2860
+ }
2861
+ },
2862
+ required: ['currency', 'quoteCurrency', 'amount', 'date']
2863
+ } as const;
2864
+
2865
+ export const $PriceResponseDto = {
2866
+ type: 'object',
2867
+ properties: {
2868
+ id: {
2869
+ type: 'string',
2870
+ description: 'Unique identifier',
2871
+ example: 'uuid-123-456'
2872
+ },
2873
+ userId: {
2874
+ type: 'string',
2875
+ description: 'User ID (owner of the price)',
2876
+ example: 'user-123'
2877
+ },
2878
+ currency: {
2879
+ type: 'string',
2880
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
2881
+ example: 'BTC'
2882
+ },
2883
+ quoteCurrency: {
2884
+ type: 'string',
2885
+ description: 'Quote currency (pricing currency, e.g., USD, CNY)',
2886
+ example: 'USD'
2887
+ },
2888
+ amount: {
2889
+ type: 'number',
2890
+ description:
2891
+ 'Price amount (corresponds to Beancount Amount.number). Supports up to 15 decimal places.',
2892
+ example: 50000
2893
+ },
2894
+ date: {
2895
+ type: 'string',
2896
+ description:
2897
+ 'Price date (ISO 8601 format). Represents the date this price was valid.',
2898
+ example: '2024-01-01',
2899
+ format: 'date'
2900
+ },
2901
+ meta: {
2902
+ type: 'object',
2903
+ description:
2904
+ 'Metadata (corresponds to Beancount meta field). Contains source, confidence, note, etc.',
2905
+ example: {
2906
+ source: 'MANUAL',
2907
+ note: 'User-defined price',
2908
+ confidence: 1
2909
+ }
2910
+ },
2911
+ createdAt: {
2912
+ format: 'date-time',
2913
+ type: 'string',
2914
+ description: 'Creation timestamp',
2915
+ example: '2024-11-03T10:00:00Z'
2916
+ },
2917
+ updatedAt: {
2918
+ format: 'date-time',
2919
+ type: 'string',
2920
+ description: 'Last update timestamp',
2921
+ example: '2024-11-03T10:00:00Z'
2922
+ }
2923
+ },
2924
+ required: [
2925
+ 'id',
2926
+ 'userId',
2927
+ 'currency',
2928
+ 'quoteCurrency',
2929
+ 'amount',
2930
+ 'date',
2931
+ 'meta',
2932
+ 'createdAt',
2933
+ 'updatedAt'
2934
+ ]
2935
+ } as const;
2936
+
2937
+ export const $PriceListResponseDto = {
2938
+ type: 'object',
2939
+ properties: {
2940
+ items: {
2941
+ description: 'List of prices',
2942
+ type: 'array',
2943
+ items: {
2944
+ $ref: '#/components/schemas/PriceResponseDto'
2945
+ }
2946
+ },
2947
+ total: {
2948
+ type: 'number',
2949
+ description: 'Total number of prices',
2950
+ example: 42
2951
+ }
2952
+ },
2953
+ required: ['items', 'total']
2954
+ } as const;
2955
+
2956
+ export const $UpdateBeanPriceDto = {
2957
+ type: 'object',
2958
+ properties: {
2959
+ currency: {
2960
+ type: 'string',
2961
+ description: 'Currency being priced'
2962
+ },
2963
+ quoteCurrency: {
2964
+ type: 'string',
2965
+ description: 'Quote currency (pricing currency)'
2966
+ },
2967
+ amount: {
2968
+ type: 'number',
2969
+ description: 'Price amount (MUST be >= 0 per Beancount spec)',
2970
+ minimum: 0
2971
+ },
2972
+ date: {
2973
+ type: 'string',
2974
+ description: 'Price date (ISO 8601 format)'
2975
+ },
2976
+ metadata: {
2977
+ type: 'object',
2978
+ description: 'Metadata'
2979
+ }
2980
+ }
2981
+ } as const;
2982
+
2983
+ export const $CreateRecurringRuleDto = {
2984
+ type: 'object',
2985
+ properties: {
2986
+ name: {
2987
+ type: 'string',
2988
+ description: 'Rule name (unique per user)',
2989
+ maxLength: 100
2990
+ },
2991
+ icon: {
2992
+ type: 'string',
2993
+ description: 'Icon emoji',
2994
+ maxLength: 10
2995
+ },
2996
+ frequency: {
2997
+ type: 'string',
2998
+ description: 'Recurring frequency',
2999
+ enum: [
3000
+ 'WEEKLY',
3001
+ 'BIWEEKLY',
3002
+ 'MONTHLY',
3003
+ 'BIMONTHLY',
3004
+ 'QUARTERLY',
3005
+ 'YEARLY',
3006
+ 'CUSTOM'
3007
+ ]
3008
+ },
3009
+ expectedAmount: {
3010
+ type: 'number',
3011
+ description: 'Expected amount (positive number)',
3012
+ minimum: 0
3013
+ },
3014
+ expectedDay: {
3015
+ type: 'number',
3016
+ description: 'Expected day of month (1-31)',
3017
+ minimum: 1,
3018
+ maximum: 31
3019
+ },
3020
+ customIntervalDays: {
2654
3021
  type: 'number',
2655
3022
  description: 'Custom interval in days (required for CUSTOM frequency)',
2656
3023
  minimum: 1
@@ -4180,84 +4547,473 @@ export const $UpdatePropertyDto = {
4180
4547
  required: ['value']
4181
4548
  } as const;
4182
4549
 
4183
- export const $FileImportDto = {
4550
+ export const $CreateBeanEventDto = {
4184
4551
  type: 'object',
4185
4552
  properties: {
4186
- file: {
4553
+ date: {
4187
4554
  type: 'string',
4188
- format: 'binary',
4189
- description: 'Bill file to import (CSV, PDF, OFX, etc.)',
4190
- example: 'alipay.csv'
4191
- }
4192
- },
4193
- required: ['file']
4194
- } as const;
4195
-
4196
- export const $ImportErrorDto = {
4197
- type: 'object',
4198
- properties: {
4199
- index: {
4200
- type: 'number',
4201
- description: 'Index of failed transaction in the file',
4202
- example: 5
4555
+ description: 'Life event date (ISO 8601)',
4556
+ example: '2024-03-15'
4203
4557
  },
4204
- error: {
4558
+ type: {
4205
4559
  type: 'string',
4206
- description: 'Error message',
4207
- example: 'Transaction does not balance: -100 USD != 0'
4560
+ description:
4561
+ 'Life event type (e.g., "employer", "location", "marital-status") — user-defined, no enum constraint at engine layer',
4562
+ example: 'employer'
4563
+ },
4564
+ description: {
4565
+ type: 'string',
4566
+ description:
4567
+ 'Life event description. Empty string is a VALID value (distinct from absence).',
4568
+ example: 'Acme Corp'
4569
+ },
4570
+ meta: {
4571
+ type: 'object',
4572
+ description:
4573
+ 'Product-side metadata (lives in BeanEvent.meta JSON, never in engine Event fields)',
4574
+ example: {
4575
+ note: 'Promotion'
4576
+ }
4208
4577
  }
4209
4578
  },
4210
- required: ['index', 'error']
4579
+ required: ['date', 'type', 'description']
4211
4580
  } as const;
4212
4581
 
4213
- export const $ReviewItemPreviewDto = {
4582
+ export const $EventResponseDto = {
4214
4583
  type: 'object',
4215
4584
  properties: {
4216
- index: {
4217
- type: 'number',
4218
- description: 'Index in the import batch (for tracking)',
4219
- example: 0
4220
- },
4221
- date: {
4585
+ id: {
4222
4586
  type: 'string',
4223
- description: 'Transaction date (ISO format)',
4224
- example: '2026-03-05'
4225
- },
4226
- amount: {
4227
- type: 'number',
4228
- description: 'Transaction amount (absolute value)',
4229
- example: 99
4587
+ description: 'Unique identifier',
4588
+ example: 'uuid-123-456'
4230
4589
  },
4231
- currency: {
4590
+ userId: {
4232
4591
  type: 'string',
4233
- description: 'Currency code',
4234
- example: 'CNY'
4592
+ description: 'User ID (owner of the life event)',
4593
+ example: 'user-123'
4235
4594
  },
4236
- narration: {
4595
+ date: {
4237
4596
  type: 'string',
4238
- description: 'Transaction narration/description',
4239
- example: 'Restaurant expense'
4597
+ description: 'Life event date (ISO 8601 format)',
4598
+ example: '2024-03-15',
4599
+ format: 'date'
4240
4600
  },
4241
- payee: {
4601
+ type: {
4242
4602
  type: 'string',
4243
- description: 'Payee name',
4244
- example: 'Restaurant ABC'
4603
+ description:
4604
+ 'Life event type (user-defined, e.g., "employer", "location")',
4605
+ example: 'employer'
4245
4606
  },
4246
- category: {
4607
+ description: {
4247
4608
  type: 'string',
4248
- description: 'Inferred category from rule matching',
4249
- example: 'food'
4609
+ description:
4610
+ 'Life event description. May be an empty string (a valid value distinct from absence).',
4611
+ example: 'Acme Corp'
4250
4612
  },
4251
- confidence: {
4252
- type: 'number',
4253
- description: 'Confidence score for the match (0-1)',
4254
- example: 0.85
4613
+ meta: {
4614
+ type: 'object',
4615
+ description: 'Product-side metadata (free-form JSON)',
4616
+ example: {
4617
+ note: 'Promotion'
4618
+ }
4255
4619
  },
4256
- branchType: {
4620
+ createdAt: {
4621
+ format: 'date-time',
4257
4622
  type: 'string',
4258
- description: 'Type of branch requiring review',
4259
- enum: [
4260
- 'DUPLICATE',
4623
+ description: 'Creation timestamp',
4624
+ example: '2024-03-15T10:00:00Z'
4625
+ },
4626
+ updatedAt: {
4627
+ format: 'date-time',
4628
+ type: 'string',
4629
+ description:
4630
+ 'Last update timestamp. Also emitted as the ETag response header for If-Match optimistic concurrency.',
4631
+ example: '2024-03-15T10:00:00Z'
4632
+ }
4633
+ },
4634
+ required: [
4635
+ 'id',
4636
+ 'userId',
4637
+ 'date',
4638
+ 'type',
4639
+ 'description',
4640
+ 'meta',
4641
+ 'createdAt',
4642
+ 'updatedAt'
4643
+ ]
4644
+ } as const;
4645
+
4646
+ export const $EventListResponseDto = {
4647
+ type: 'object',
4648
+ properties: {
4649
+ items: {
4650
+ description: 'List of life events',
4651
+ type: 'array',
4652
+ items: {
4653
+ $ref: '#/components/schemas/EventResponseDto'
4654
+ }
4655
+ },
4656
+ total: {
4657
+ type: 'number',
4658
+ description: 'Total number of life events matching the query',
4659
+ example: 42
4660
+ }
4661
+ },
4662
+ required: ['items', 'total']
4663
+ } as const;
4664
+
4665
+ export const $UpdateBeanEventDto = {
4666
+ type: 'object',
4667
+ properties: {
4668
+ date: {
4669
+ type: 'string',
4670
+ description: 'Life event date (ISO 8601)'
4671
+ },
4672
+ type: {
4673
+ type: 'string',
4674
+ description: 'Life event type (user-defined)'
4675
+ },
4676
+ description: {
4677
+ type: 'string',
4678
+ description:
4679
+ 'Life event description. Empty string is a VALID value (distinct from absence).'
4680
+ },
4681
+ meta: {
4682
+ type: 'object',
4683
+ description: 'Product-side metadata (free-form JSON)'
4684
+ }
4685
+ }
4686
+ } as const;
4687
+
4688
+ export const $OnboardingAccountDto = {
4689
+ type: 'object',
4690
+ properties: {
4691
+ path: {
4692
+ type: 'string',
4693
+ description:
4694
+ 'Account path (Assets/Liabilities only; format validated by the account service)',
4695
+ example: 'Assets:Checking'
4696
+ },
4697
+ currency: {
4698
+ type: 'string',
4699
+ description: 'ISO 4217 currency code (3 letters)',
4700
+ example: 'USD'
4701
+ },
4702
+ openingBalance: {
4703
+ type: 'string',
4704
+ description:
4705
+ 'Opening balance as a non-negative Decimal string (e.g. "1000.00")',
4706
+ example: '1000.00'
4707
+ },
4708
+ platformId: {
4709
+ type: 'string',
4710
+ description:
4711
+ 'Platform ID to bind the account to (references Platform.id); omit for unbound',
4712
+ example: 'c98e5d4a-2f71-4a5a-bb3c-92c9f231d5e2'
4713
+ }
4714
+ },
4715
+ required: ['path', 'currency']
4716
+ } as const;
4717
+
4718
+ export const $OnboardingDto = {
4719
+ type: 'object',
4720
+ properties: {
4721
+ accounts: {
4722
+ description: 'Asset/Liability accounts to register with opening balances',
4723
+ type: 'array',
4724
+ items: {
4725
+ $ref: '#/components/schemas/OnboardingAccountDto'
4726
+ }
4727
+ },
4728
+ skipAssetRegistration: {
4729
+ type: 'boolean',
4730
+ description:
4731
+ 'Skip asset registration; only bootstrap the core account set',
4732
+ default: false
4733
+ }
4734
+ }
4735
+ } as const;
4736
+
4737
+ export const $ActualBalanceDto = {
4738
+ type: 'object',
4739
+ properties: {
4740
+ amount: {
4741
+ type: 'string',
4742
+ description:
4743
+ 'Actual balance amount as a decimal string (preserves precision for tolerance inference).',
4744
+ example: '1234.56'
4745
+ },
4746
+ ccy: {
4747
+ type: 'string',
4748
+ description: 'Currency code (ISO 4217 or commodity ticker).',
4749
+ example: 'CNY'
4750
+ }
4751
+ },
4752
+ required: ['amount', 'ccy']
4753
+ } as const;
4754
+
4755
+ export const $ComputeReconciliationDto = {
4756
+ type: 'object',
4757
+ properties: {
4758
+ accountId: {
4759
+ type: 'string',
4760
+ description: 'BeanAccount id to reconcile.'
4761
+ },
4762
+ asOfDate: {
4763
+ type: 'string',
4764
+ description: 'Assertion date (ISO 8601, e.g. "2026-07-24").',
4765
+ example: '2026-07-24'
4766
+ },
4767
+ actualBalance: {
4768
+ description: 'Actual balance from the external statement.',
4769
+ allOf: [
4770
+ {
4771
+ $ref: '#/components/schemas/ActualBalanceDto'
4772
+ }
4773
+ ]
4774
+ }
4775
+ },
4776
+ required: ['accountId', 'asOfDate', 'actualBalance']
4777
+ } as const;
4778
+
4779
+ export const $ReconciliationComputeResultDto = {
4780
+ type: 'object',
4781
+ properties: {
4782
+ accountId: {
4783
+ type: 'string'
4784
+ },
4785
+ asOfDate: {
4786
+ type: 'string'
4787
+ },
4788
+ bookBalance: {
4789
+ type: 'string',
4790
+ description: 'System-computed book balance (decimal string).'
4791
+ },
4792
+ actualBalance: {
4793
+ type: 'string',
4794
+ description: 'User-entered actual balance (decimal string).'
4795
+ },
4796
+ currency: {
4797
+ type: 'string'
4798
+ },
4799
+ diff: {
4800
+ type: 'string',
4801
+ description: 'Diff = book − actual (decimal string).'
4802
+ },
4803
+ tolerance: {
4804
+ type: 'string',
4805
+ description: 'Applied tolerance (decimal string).'
4806
+ },
4807
+ withinTolerance: {
4808
+ type: 'boolean',
4809
+ description: 'true when |diff| ≤ tolerance.'
4810
+ },
4811
+ suggestedAction: {
4812
+ type: 'string',
4813
+ enum: ['assert', 'pad'],
4814
+ description:
4815
+ 'Suggested next action: assert when within tolerance, pad otherwise.'
4816
+ }
4817
+ },
4818
+ required: [
4819
+ 'accountId',
4820
+ 'asOfDate',
4821
+ 'bookBalance',
4822
+ 'actualBalance',
4823
+ 'currency',
4824
+ 'diff',
4825
+ 'tolerance',
4826
+ 'withinTolerance',
4827
+ 'suggestedAction'
4828
+ ]
4829
+ } as const;
4830
+
4831
+ export const $AssertReconciliationDto = {
4832
+ type: 'object',
4833
+ properties: {
4834
+ accountId: {
4835
+ type: 'string',
4836
+ description: 'BeanAccount id to reconcile.'
4837
+ },
4838
+ asOfDate: {
4839
+ type: 'string',
4840
+ description: 'Assertion date (ISO 8601, e.g. "2026-07-24").',
4841
+ example: '2026-07-24'
4842
+ },
4843
+ actualBalance: {
4844
+ description: 'Actual balance from the external statement.',
4845
+ allOf: [
4846
+ {
4847
+ $ref: '#/components/schemas/ActualBalanceDto'
4848
+ }
4849
+ ]
4850
+ },
4851
+ tolerance: {
4852
+ type: 'string',
4853
+ description:
4854
+ 'Optional explicit tolerance override. Omit to infer from amount precision (Beancount default).',
4855
+ example: '0.01'
4856
+ }
4857
+ },
4858
+ required: ['accountId', 'asOfDate', 'actualBalance']
4859
+ } as const;
4860
+
4861
+ export const $ReconciliationRecordDto = {
4862
+ type: 'object',
4863
+ properties: {
4864
+ id: {
4865
+ type: 'string'
4866
+ },
4867
+ accountId: {
4868
+ type: 'string'
4869
+ },
4870
+ date: {
4871
+ type: 'string'
4872
+ },
4873
+ amount: {
4874
+ type: 'string',
4875
+ description: 'Asserted (actual) amount.'
4876
+ },
4877
+ currency: {
4878
+ type: 'string'
4879
+ },
4880
+ tolerance: {
4881
+ type: 'string'
4882
+ },
4883
+ diffAmount: {
4884
+ type: 'string',
4885
+ description: 'book − actual.'
4886
+ },
4887
+ diffCurrency: {
4888
+ type: 'string'
4889
+ },
4890
+ createdAt: {
4891
+ type: 'string'
4892
+ }
4893
+ },
4894
+ required: ['id', 'accountId', 'date', 'amount', 'currency', 'createdAt']
4895
+ } as const;
4896
+
4897
+ export const $PadReconciliationDto = {
4898
+ type: 'object',
4899
+ properties: {
4900
+ accountId: {
4901
+ type: 'string',
4902
+ description: 'BeanAccount id to reconcile.'
4903
+ },
4904
+ asOfDate: {
4905
+ type: 'string',
4906
+ description: 'Assertion date (ISO 8601, e.g. "2026-07-24").',
4907
+ example: '2026-07-24'
4908
+ },
4909
+ actualBalance: {
4910
+ description: 'Actual balance from the external statement.',
4911
+ allOf: [
4912
+ {
4913
+ $ref: '#/components/schemas/ActualBalanceDto'
4914
+ }
4915
+ ]
4916
+ },
4917
+ sourceAccount: {
4918
+ type: 'string',
4919
+ description:
4920
+ 'Pad source account. Defaults to Equity:Opening-Balances (official Beancount convention).',
4921
+ example: 'Equity:Opening-Balances',
4922
+ default: 'Equity:Opening-Balances'
4923
+ }
4924
+ },
4925
+ required: ['accountId', 'asOfDate', 'actualBalance']
4926
+ } as const;
4927
+
4928
+ export const $PadResultDto = {
4929
+ type: 'object',
4930
+ properties: {
4931
+ transactionId: {
4932
+ type: 'string',
4933
+ description: 'Created pad adjusting transaction id.'
4934
+ }
4935
+ },
4936
+ required: ['transactionId']
4937
+ } as const;
4938
+
4939
+ export const $FileImportDto = {
4940
+ type: 'object',
4941
+ properties: {
4942
+ file: {
4943
+ type: 'string',
4944
+ format: 'binary',
4945
+ description: 'Bill file to import (CSV, PDF, OFX, etc.)',
4946
+ example: 'alipay.csv'
4947
+ }
4948
+ },
4949
+ required: ['file']
4950
+ } as const;
4951
+
4952
+ export const $ImportErrorDto = {
4953
+ type: 'object',
4954
+ properties: {
4955
+ index: {
4956
+ type: 'number',
4957
+ description: 'Index of failed transaction in the file',
4958
+ example: 5
4959
+ },
4960
+ error: {
4961
+ type: 'string',
4962
+ description: 'Error message',
4963
+ example: 'Transaction does not balance: -100 USD != 0'
4964
+ }
4965
+ },
4966
+ required: ['index', 'error']
4967
+ } as const;
4968
+
4969
+ export const $ReviewItemPreviewDto = {
4970
+ type: 'object',
4971
+ properties: {
4972
+ index: {
4973
+ type: 'number',
4974
+ description: 'Index in the import batch (for tracking)',
4975
+ example: 0
4976
+ },
4977
+ date: {
4978
+ type: 'string',
4979
+ description: 'Transaction date (ISO format)',
4980
+ example: '2026-03-05'
4981
+ },
4982
+ amount: {
4983
+ type: 'number',
4984
+ description: 'Transaction amount (absolute value)',
4985
+ example: 99
4986
+ },
4987
+ currency: {
4988
+ type: 'string',
4989
+ description: 'Currency code',
4990
+ example: 'CNY'
4991
+ },
4992
+ narration: {
4993
+ type: 'string',
4994
+ description: 'Transaction narration/description',
4995
+ example: 'Restaurant expense'
4996
+ },
4997
+ payee: {
4998
+ type: 'string',
4999
+ description: 'Payee name',
5000
+ example: 'Restaurant ABC'
5001
+ },
5002
+ category: {
5003
+ type: 'string',
5004
+ description: 'Inferred category from rule matching',
5005
+ example: 'food'
5006
+ },
5007
+ confidence: {
5008
+ type: 'number',
5009
+ description: 'Confidence score for the match (0-1)',
5010
+ example: 0.85
5011
+ },
5012
+ branchType: {
5013
+ type: 'string',
5014
+ description: 'Type of branch requiring review',
5015
+ enum: [
5016
+ 'DUPLICATE',
4261
5017
  'PAYEE_MATCH',
4262
5018
  'RULE_MATCH',
4263
5019
  'ACCOUNT_VALIDATION',
@@ -4346,7 +5102,7 @@ export const $IdentifyResultDto = {
4346
5102
  account: {
4347
5103
  type: 'string',
4348
5104
  description: 'Default account used by this importer',
4349
- example: 'Assets:Alipay:Balance'
5105
+ example: 'Assets:CN:Alipay:Balance'
4350
5106
  },
4351
5107
  message: {
4352
5108
  type: 'string',
@@ -4363,7 +5119,7 @@ export const $MapperDefaultsDto = {
4363
5119
  sourceAccount: {
4364
5120
  type: 'string',
4365
5121
  description: 'Source account for transactions (Beancount format)',
4366
- example: 'Assets:Alipay:Balance'
5122
+ example: 'Assets:CN:Alipay:Balance'
4367
5123
  },
4368
5124
  currency: {
4369
5125
  type: 'string',
@@ -4400,7 +5156,7 @@ export const $MapperDefaultsDto = {
4400
5156
  description:
4401
5157
  '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).',
4402
5158
  example: {
4403
- HuaBei: 'Liabilities:Alipay:Huabei',
5159
+ HuaBei: 'Liabilities:CN:CreditLine',
4404
5160
  CreditCard: 'Liabilities:CreditCard'
4405
5161
  }
4406
5162
  }
@@ -4532,7 +5288,7 @@ export const $UpdateMapperDefaultsDto = {
4532
5288
  sourceAccount: {
4533
5289
  type: 'string',
4534
5290
  description: 'Source account for transactions (Beancount format)',
4535
- example: 'Assets:Alipay:Balance',
5291
+ example: 'Assets:CN:Alipay:Balance',
4536
5292
  pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
4537
5293
  },
4538
5294
  currency: {
@@ -4560,7 +5316,7 @@ export const $UpdateMapperDefaultsDto = {
4560
5316
  description:
4561
5317
  '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).',
4562
5318
  example: {
4563
- HuaBei: 'Liabilities:Alipay:Huabei',
5319
+ HuaBei: 'Liabilities:CN:CreditLine',
4564
5320
  CreditCard: 'Liabilities:CreditCard'
4565
5321
  }
4566
5322
  }
@@ -4595,119 +5351,13 @@ export const $UpdateImporterConfigDto = {
4595
5351
  }
4596
5352
  } as const;
4597
5353
 
4598
- export const $CreatePlatformDto = {
4599
- type: 'object',
4600
- properties: {
4601
- name: {
4602
- type: 'string',
4603
- description: 'Platform name',
4604
- example: 'Binance'
4605
- },
4606
- canonical: {
4607
- type: 'string',
4608
- description: 'Platform canonical identifier (lowercase, kebab-case)',
4609
- example: 'binance'
4610
- },
4611
- aliases: {
4612
- description: 'Platform aliases (multi-language names for lookup)',
4613
- example: ['Binance', 'Binance Exchange', 'BNB'],
4614
- type: 'array',
4615
- items: {
4616
- type: 'string'
4617
- }
4618
- },
4619
- url: {
4620
- type: 'string',
4621
- description: 'Platform URL',
4622
- example: 'https://www.binance.com'
4623
- },
4624
- type: {
4625
- type: 'string',
4626
- description: 'Platform type',
4627
- enum: [
4628
- 'BANK',
4629
- 'BROKERAGE',
4630
- 'CRYPTO_EXCHANGE',
4631
- 'PAYMENT',
4632
- 'INVESTMENT',
4633
- 'INSURANCE',
4634
- 'OTHER'
4635
- ],
4636
- example: 'CRYPTO_EXCHANGE'
4637
- },
4638
- logoUrl: {
4639
- type: 'string',
4640
- description: 'Platform logo URL',
4641
- example: 'https://example.com/logos/binance.png'
4642
- },
4643
- isActive: {
4644
- type: 'boolean',
4645
- description: 'Whether the platform is active',
4646
- default: true
4647
- }
4648
- },
4649
- required: ['name', 'canonical', 'aliases', 'url', 'type']
4650
- } as const;
4651
-
4652
- export const $UpdatePlatformDto = {
4653
- type: 'object',
4654
- properties: {
4655
- name: {
4656
- type: 'string',
4657
- description: 'Platform name',
4658
- example: 'Binance'
4659
- },
4660
- canonical: {
4661
- type: 'string',
4662
- description: 'Platform canonical identifier (lowercase, kebab-case)',
4663
- example: 'binance'
4664
- },
4665
- aliases: {
4666
- description: 'Platform aliases (multi-language names for lookup)',
4667
- example: ['Binance', 'Binance Exchange', 'BNB'],
4668
- type: 'array',
4669
- items: {
4670
- type: 'string'
4671
- }
4672
- },
4673
- url: {
4674
- type: 'string',
4675
- description: 'Platform URL',
4676
- example: 'https://www.binance.com'
4677
- },
4678
- type: {
4679
- type: 'string',
4680
- description: 'Platform type',
4681
- enum: [
4682
- 'BANK',
4683
- 'BROKERAGE',
4684
- 'CRYPTO_EXCHANGE',
4685
- 'PAYMENT',
4686
- 'INVESTMENT',
4687
- 'INSURANCE',
4688
- 'OTHER'
4689
- ],
4690
- example: 'CRYPTO_EXCHANGE'
4691
- },
4692
- logoUrl: {
4693
- type: 'string',
4694
- description: 'Platform logo URL',
4695
- example: 'https://example.com/logos/binance.png'
4696
- },
4697
- isActive: {
4698
- type: 'boolean',
4699
- description: 'Whether the platform is active'
4700
- }
4701
- }
4702
- } as const;
4703
-
4704
5354
  export const $ProviderSyncConfigDto = {
4705
5355
  type: 'object',
4706
5356
  properties: {
4707
5357
  sourceAccount: {
4708
5358
  type: 'string',
4709
5359
  description: 'Source account for the first posting',
4710
- example: 'Assets:Bank:Chase'
5360
+ example: 'Assets:US:Chase:Checking'
4711
5361
  },
4712
5362
  defaultCurrency: {
4713
5363
  type: 'string',
@@ -4728,6 +5378,12 @@ export const $ProviderSyncConfigDto = {
4728
5378
  type: 'boolean',
4729
5379
  description: 'Filter pending transactions',
4730
5380
  default: true
5381
+ },
5382
+ externalAccountId: {
5383
+ type: 'string',
5384
+ description:
5385
+ 'External account ID for per-batch providers (e.g. GoCardless). Overrides sourceAccount when an ExternalAccountLink mapping exists.',
5386
+ example: 'acc_gocardless_001'
4731
5387
  }
4732
5388
  },
4733
5389
  required: [
@@ -4847,6 +5503,94 @@ export const $SupportedProvidersResponseDto = {
4847
5503
  required: ['providers']
4848
5504
  } as const;
4849
5505
 
5506
+ export const $CreateExternalAccountLinkDto = {
5507
+ type: 'object',
5508
+ properties: {
5509
+ provider: {
5510
+ type: 'string',
5511
+ enum: [
5512
+ 'plaid',
5513
+ 'teller',
5514
+ 'truelayer',
5515
+ 'gocardless',
5516
+ 'simplefin',
5517
+ 'yodlee',
5518
+ 'beancount-direct',
5519
+ 'parsed-bill'
5520
+ ],
5521
+ example: 'plaid',
5522
+ description: 'Open Banking provider (whitelist)'
5523
+ },
5524
+ externalAccountId: {
5525
+ type: 'string',
5526
+ example: 'acc-plaid-001',
5527
+ description: 'External account ID from the provider'
5528
+ },
5529
+ beanAccountId: {
5530
+ type: 'string',
5531
+ example: '550e8400-e29b-41d4-a716-446655440000',
5532
+ description: 'Target BeanAccount ID (must belong to the JWT user)'
5533
+ }
5534
+ },
5535
+ required: ['provider', 'externalAccountId', 'beanAccountId']
5536
+ } as const;
5537
+
5538
+ export const $ExternalAccountLinkResponseDto = {
5539
+ type: 'object',
5540
+ properties: {
5541
+ id: {
5542
+ type: 'string'
5543
+ },
5544
+ provider: {
5545
+ type: 'string'
5546
+ },
5547
+ externalAccountId: {
5548
+ type: 'string'
5549
+ },
5550
+ beanAccountId: {
5551
+ type: 'string'
5552
+ },
5553
+ isActive: {
5554
+ type: 'boolean'
5555
+ },
5556
+ createdAt: {
5557
+ type: 'string'
5558
+ },
5559
+ updatedAt: {
5560
+ type: 'string'
5561
+ }
5562
+ },
5563
+ required: [
5564
+ 'id',
5565
+ 'provider',
5566
+ 'externalAccountId',
5567
+ 'beanAccountId',
5568
+ 'isActive',
5569
+ 'createdAt',
5570
+ 'updatedAt'
5571
+ ]
5572
+ } as const;
5573
+
5574
+ export const $ExternalAccountLinkListResponseDto = {
5575
+ type: 'object',
5576
+ properties: {
5577
+ items: {
5578
+ type: 'array',
5579
+ items: {
5580
+ $ref: '#/components/schemas/ExternalAccountLinkResponseDto'
5581
+ }
5582
+ },
5583
+ total: {
5584
+ type: 'number'
5585
+ },
5586
+ provider: {
5587
+ type: 'string',
5588
+ description: 'Filter by provider (query param)'
5589
+ }
5590
+ },
5591
+ required: ['items', 'total']
5592
+ } as const;
5593
+
4850
5594
  export const $ParserTelemetryReportDto = {
4851
5595
  type: 'object',
4852
5596
  properties: {}
@@ -5396,7 +6140,7 @@ export const $NlpSuggestedAccountDto = {
5396
6140
  account: {
5397
6141
  type: 'string',
5398
6142
  description: 'Suggested account path',
5399
- example: 'Assets:Bank:Checking'
6143
+ example: 'Assets:Checking'
5400
6144
  },
5401
6145
  confidence: {
5402
6146
  type: 'number',
@@ -5437,7 +6181,7 @@ export const $NlpDefaultAccountsDto = {
5437
6181
  asset: {
5438
6182
  type: 'string',
5439
6183
  description: 'Default asset account',
5440
- example: 'Assets:Bank:Checking'
6184
+ example: 'Assets:Checking'
5441
6185
  },
5442
6186
  expense: {
5443
6187
  type: 'string',
@@ -5656,24 +6400,113 @@ export const $NlpResponseDto = {
5656
6400
  ]
5657
6401
  }
5658
6402
  },
5659
- required: ['status', 'action']
6403
+ required: ['status', 'action']
6404
+ } as const;
6405
+
6406
+ export const $CreatePlatformDto = {
6407
+ type: 'object',
6408
+ properties: {
6409
+ name: {
6410
+ type: 'string',
6411
+ description: 'Platform name',
6412
+ example: 'Binance'
6413
+ },
6414
+ canonical: {
6415
+ type: 'string',
6416
+ description: 'Platform canonical identifier (lowercase, kebab-case)',
6417
+ example: 'binance'
6418
+ },
6419
+ aliases: {
6420
+ description: 'Platform aliases (multi-language names for lookup)',
6421
+ example: ['Binance', 'Binance Exchange', 'BNB'],
6422
+ type: 'array',
6423
+ items: {
6424
+ type: 'string'
6425
+ }
6426
+ },
6427
+ url: {
6428
+ type: 'string',
6429
+ description: 'Platform URL',
6430
+ example: 'https://www.binance.com'
6431
+ },
6432
+ type: {
6433
+ type: 'string',
6434
+ description: 'Platform type',
6435
+ enum: [
6436
+ 'BANK',
6437
+ 'BROKERAGE',
6438
+ 'CRYPTO_EXCHANGE',
6439
+ 'PAYMENT',
6440
+ 'INVESTMENT',
6441
+ 'INSURANCE',
6442
+ 'OTHER'
6443
+ ],
6444
+ example: 'CRYPTO_EXCHANGE'
6445
+ },
6446
+ logoUrl: {
6447
+ type: 'string',
6448
+ description: 'Platform logo URL',
6449
+ example: 'https://example.com/logos/binance.png'
6450
+ },
6451
+ isActive: {
6452
+ type: 'boolean',
6453
+ description: 'Whether the platform is active',
6454
+ default: true
6455
+ }
6456
+ },
6457
+ required: ['name', 'canonical', 'aliases', 'url', 'type']
5660
6458
  } as const;
5661
6459
 
5662
- export const $BalanceByCurrencyDto = {
6460
+ export const $UpdatePlatformDto = {
5663
6461
  type: 'object',
5664
6462
  properties: {
5665
- currency: {
6463
+ name: {
5666
6464
  type: 'string',
5667
- description: 'ISO 4217 currency code',
5668
- example: 'CNY'
6465
+ description: 'Platform name',
6466
+ example: 'Binance'
5669
6467
  },
5670
- balance: {
6468
+ canonical: {
5671
6469
  type: 'string',
5672
- description: 'Balance amount',
5673
- example: '50000.00'
6470
+ description: 'Platform canonical identifier (lowercase, kebab-case)',
6471
+ example: 'binance'
6472
+ },
6473
+ aliases: {
6474
+ description: 'Platform aliases (multi-language names for lookup)',
6475
+ example: ['Binance', 'Binance Exchange', 'BNB'],
6476
+ type: 'array',
6477
+ items: {
6478
+ type: 'string'
6479
+ }
6480
+ },
6481
+ url: {
6482
+ type: 'string',
6483
+ description: 'Platform URL',
6484
+ example: 'https://www.binance.com'
6485
+ },
6486
+ type: {
6487
+ type: 'string',
6488
+ description: 'Platform type',
6489
+ enum: [
6490
+ 'BANK',
6491
+ 'BROKERAGE',
6492
+ 'CRYPTO_EXCHANGE',
6493
+ 'PAYMENT',
6494
+ 'INVESTMENT',
6495
+ 'INSURANCE',
6496
+ 'OTHER'
6497
+ ],
6498
+ example: 'CRYPTO_EXCHANGE'
6499
+ },
6500
+ logoUrl: {
6501
+ type: 'string',
6502
+ description: 'Platform logo URL',
6503
+ example: 'https://example.com/logos/binance.png'
6504
+ },
6505
+ isActive: {
6506
+ type: 'boolean',
6507
+ description: 'Whether the platform is active'
5674
6508
  }
5675
- },
5676
- required: ['currency', 'balance']
6509
+ }
5677
6510
  } as const;
5678
6511
 
5679
6512
  export const $NetWorthByCurrencyDto = {
@@ -5745,28 +6578,6 @@ export const $ConvertedNetWorthDto = {
5745
6578
  ]
5746
6579
  } as const;
5747
6580
 
5748
- export const $ExchangeRateWarningDto = {
5749
- type: 'object',
5750
- properties: {
5751
- type: {
5752
- type: 'string',
5753
- description: 'Warning type',
5754
- example: 'MISSING_EXCHANGE_RATE'
5755
- },
5756
- currency: {
5757
- type: 'string',
5758
- description: 'Currency without exchange rate',
5759
- example: 'EUR'
5760
- },
5761
- totalAmount: {
5762
- type: 'string',
5763
- description: 'Total amount affected',
5764
- example: '1000.00'
5765
- }
5766
- },
5767
- required: ['type', 'currency', 'totalAmount']
5768
- } as const;
5769
-
5770
6581
  export const $NetWorthResponseDto = {
5771
6582
  type: 'object',
5772
6583
  properties: {
@@ -5852,7 +6663,7 @@ export const $AccountItemDto = {
5852
6663
  name: {
5853
6664
  type: 'string',
5854
6665
  description: 'Full account name',
5855
- example: 'Assets:Bank:CMB:Savings'
6666
+ example: 'Assets:CN:CMB:Savings'
5856
6667
  },
5857
6668
  displayName: {
5858
6669
  type: 'string',
@@ -5868,6 +6679,12 @@ export const $AccountItemDto = {
5868
6679
  type: 'string',
5869
6680
  description: 'Currency code',
5870
6681
  example: 'CNY'
6682
+ },
6683
+ convertedBalance: {
6684
+ type: 'string',
6685
+ description:
6686
+ 'FX-converted balance in base currency; omitted when not convertible',
6687
+ example: '50000.00'
5871
6688
  }
5872
6689
  },
5873
6690
  required: ['id', 'name', 'displayName', 'balance', 'currency']
@@ -5894,11 +6711,66 @@ export const $PlatformGroupDto = {
5894
6711
  },
5895
6712
  totalBalance: {
5896
6713
  type: 'string',
5897
- description: 'Total balance across all accounts in platform',
6714
+ description: 'FX-converted total balance in base currency',
6715
+ example: '100000.00'
6716
+ },
6717
+ balanceByCurrency: {
6718
+ description: 'Raw (unconverted) balances grouped by currency',
6719
+ type: 'array',
6720
+ items: {
6721
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
6722
+ }
6723
+ },
6724
+ convertedBalance: {
6725
+ type: 'string',
6726
+ description:
6727
+ 'Converted balance in base currency (omitted when no currency is convertible)',
5898
6728
  example: '100000.00'
6729
+ },
6730
+ sharePct: {
6731
+ type: 'number',
6732
+ description:
6733
+ 'Share of the grand converted total (0-100); 0 when grand total is 0',
6734
+ example: 42.5
6735
+ }
6736
+ },
6737
+ required: [
6738
+ 'platformId',
6739
+ 'platformName',
6740
+ 'accounts',
6741
+ 'totalBalance',
6742
+ 'balanceByCurrency',
6743
+ 'sharePct'
6744
+ ]
6745
+ } as const;
6746
+
6747
+ export const $AccountExchangeRateWarningDto = {
6748
+ type: 'object',
6749
+ properties: {
6750
+ type: {
6751
+ type: 'string',
6752
+ description: 'Warning type',
6753
+ example: 'MISSING_EXCHANGE_RATE'
6754
+ },
6755
+ currency: {
6756
+ type: 'string',
6757
+ description: 'Currency without exchange rate',
6758
+ example: 'USD'
6759
+ },
6760
+ accounts: {
6761
+ description: 'Affected account paths',
6762
+ type: 'array',
6763
+ items: {
6764
+ type: 'string'
6765
+ }
6766
+ },
6767
+ totalAmount: {
6768
+ type: 'string',
6769
+ description: 'Total amount in this currency',
6770
+ example: '5000.00'
5899
6771
  }
5900
6772
  },
5901
- required: ['platformId', 'platformName', 'accounts', 'totalBalance']
6773
+ required: ['type', 'currency', 'accounts', 'totalAmount']
5902
6774
  } as const;
5903
6775
 
5904
6776
  export const $AccountsSummaryDto = {
@@ -5911,9 +6783,21 @@ export const $AccountsSummaryDto = {
5911
6783
  totalPlatforms: {
5912
6784
  type: 'number',
5913
6785
  description: 'Total number of platforms'
6786
+ },
6787
+ baseCurrency: {
6788
+ type: 'string',
6789
+ description: 'Base currency for conversion',
6790
+ example: 'CNY'
6791
+ },
6792
+ warnings: {
6793
+ description: 'Per-account exchange rate warnings',
6794
+ type: 'array',
6795
+ items: {
6796
+ $ref: '#/components/schemas/AccountExchangeRateWarningDto'
6797
+ }
5914
6798
  }
5915
6799
  },
5916
- required: ['totalAccounts', 'totalPlatforms']
6800
+ required: ['totalAccounts', 'totalPlatforms', 'baseCurrency']
5917
6801
  } as const;
5918
6802
 
5919
6803
  export const $AccountsResponseDto = {
@@ -5948,7 +6832,7 @@ export const $AccountItemWithAssetClassDto = {
5948
6832
  name: {
5949
6833
  type: 'string',
5950
6834
  description: 'Full account name',
5951
- example: 'Assets:Bank:CMB:Savings'
6835
+ example: 'Assets:CN:CMB:Savings'
5952
6836
  },
5953
6837
  displayName: {
5954
6838
  type: 'string',
@@ -5965,6 +6849,12 @@ export const $AccountItemWithAssetClassDto = {
5965
6849
  description: 'Currency code',
5966
6850
  example: 'CNY'
5967
6851
  },
6852
+ convertedBalance: {
6853
+ type: 'string',
6854
+ description:
6855
+ 'FX-converted balance in base currency; omitted when not convertible',
6856
+ example: '50000.00'
6857
+ },
5968
6858
  assetClass: {
5969
6859
  type: 'string',
5970
6860
  description: 'Asset class',
@@ -6044,35 +6934,6 @@ export const $AssetClassGroupDto = {
6044
6934
  required: ['assetClass', 'accounts', 'balanceByCurrency']
6045
6935
  } as const;
6046
6936
 
6047
- export const $AccountExchangeRateWarningDto = {
6048
- type: 'object',
6049
- properties: {
6050
- type: {
6051
- type: 'string',
6052
- description: 'Warning type',
6053
- example: 'MISSING_EXCHANGE_RATE'
6054
- },
6055
- currency: {
6056
- type: 'string',
6057
- description: 'Currency without exchange rate',
6058
- example: 'USD'
6059
- },
6060
- accounts: {
6061
- description: 'Affected account paths',
6062
- type: 'array',
6063
- items: {
6064
- type: 'string'
6065
- }
6066
- },
6067
- totalAmount: {
6068
- type: 'string',
6069
- description: 'Total amount in this currency',
6070
- example: '5000.00'
6071
- }
6072
- },
6073
- required: ['type', 'currency', 'accounts', 'totalAmount']
6074
- } as const;
6075
-
6076
6937
  export const $AssetClassSummaryDto = {
6077
6938
  type: 'object',
6078
6939
  properties: {
@@ -6146,7 +7007,7 @@ export const $HoldingAssetClassAccountSliceDto = {
6146
7007
  accountPath: {
6147
7008
  type: 'string',
6148
7009
  description: 'Full account path',
6149
- example: 'Assets:US:Investments:Brokerage'
7010
+ example: 'Assets:US:Fidelity:Brokerage'
6150
7011
  },
6151
7012
  accountCurrency: {
6152
7013
  type: 'string',
@@ -6326,30 +7187,125 @@ export const $CashFlowResponseDto = {
6326
7187
  }
6327
7188
  ]
6328
7189
  },
6329
- converted: {
6330
- description: 'Converted values in base currency',
7190
+ converted: {
7191
+ description: 'Converted values in base currency',
7192
+ allOf: [
7193
+ {
7194
+ $ref: '#/components/schemas/ConvertedCashFlowDto'
7195
+ }
7196
+ ]
7197
+ },
7198
+ warnings: {
7199
+ description: 'Exchange rate warnings',
7200
+ type: 'array',
7201
+ items: {
7202
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
7203
+ }
7204
+ }
7205
+ },
7206
+ required: [
7207
+ 'period',
7208
+ 'income',
7209
+ 'expense',
7210
+ 'netSavings',
7211
+ 'savingsRate',
7212
+ 'currency'
7213
+ ]
7214
+ } as const;
7215
+
7216
+ export const $CategoryGroupDto = {
7217
+ type: 'object',
7218
+ properties: {
7219
+ category: {
7220
+ type: 'string',
7221
+ description:
7222
+ 'Functional category (account-path Group segment); regional and universal account paths merge under it',
7223
+ example: 'Food'
7224
+ },
7225
+ totalExpense: {
7226
+ type: 'string',
7227
+ description:
7228
+ 'Converted total for this category in base currency (expense amount when flow=expense, income amount when flow=income)',
7229
+ example: '1200.00'
7230
+ },
7231
+ sharePct: {
7232
+ type: 'number',
7233
+ description: 'Share of grand total (0-100); 0 when grand total is 0',
7234
+ example: 42.5
7235
+ },
7236
+ balanceByCurrency: {
7237
+ description: 'Raw (unconverted) expense per currency',
7238
+ type: 'array',
7239
+ items: {
7240
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
7241
+ }
7242
+ },
7243
+ convertedBalance: {
7244
+ type: 'string',
7245
+ description:
7246
+ 'Converted total in base currency (omitted when FX missing for all currencies in this category)',
7247
+ example: '1200.00'
7248
+ }
7249
+ },
7250
+ required: ['category', 'totalExpense', 'sharePct', 'balanceByCurrency']
7251
+ } as const;
7252
+
7253
+ export const $ExpensesByCategorySummaryDto = {
7254
+ type: 'object',
7255
+ properties: {
7256
+ totalExpense: {
7257
+ type: 'string',
7258
+ description:
7259
+ 'Total across all categories, converted (convertible categories only); expense totals when flow=expense, income totals when flow=income',
7260
+ example: '5000.00'
7261
+ },
7262
+ categoryCount: {
7263
+ type: 'number',
7264
+ description: 'Number of categories',
7265
+ example: 8
7266
+ }
7267
+ },
7268
+ required: ['totalExpense', 'categoryCount']
7269
+ } as const;
7270
+
7271
+ export const $ExpensesByCategoryResponseDto = {
7272
+ type: 'object',
7273
+ properties: {
7274
+ period: {
7275
+ type: 'string',
7276
+ description: 'Period requested',
7277
+ example: '1m'
7278
+ },
7279
+ baseCurrency: {
7280
+ type: 'string',
7281
+ description: 'Base currency for converted values',
7282
+ example: 'CNY'
7283
+ },
7284
+ groups: {
7285
+ description:
7286
+ 'Expense groups by functional category, sorted by converted total desc',
7287
+ type: 'array',
7288
+ items: {
7289
+ $ref: '#/components/schemas/CategoryGroupDto'
7290
+ }
7291
+ },
7292
+ summary: {
7293
+ description: 'Summary statistics',
6331
7294
  allOf: [
6332
7295
  {
6333
- $ref: '#/components/schemas/ConvertedCashFlowDto'
7296
+ $ref: '#/components/schemas/ExpensesByCategorySummaryDto'
6334
7297
  }
6335
7298
  ]
6336
7299
  },
6337
7300
  warnings: {
6338
- description: 'Exchange rate warnings',
7301
+ description: 'Exchange rate warnings (e.g. missing rate for a currency)',
6339
7302
  type: 'array',
6340
7303
  items: {
6341
7304
  $ref: '#/components/schemas/ExchangeRateWarningDto'
6342
7305
  }
6343
7306
  }
6344
7307
  },
6345
- required: [
6346
- 'period',
6347
- 'income',
6348
- 'expense',
6349
- 'netSavings',
6350
- 'savingsRate',
6351
- 'currency'
6352
- ]
7308
+ required: ['period', 'baseCurrency', 'groups', 'summary']
6353
7309
  } as const;
6354
7310
 
6355
7311
  export const $MonetaryDto = {
@@ -6641,163 +7597,6 @@ export const $HoldingPnlResponseDto = {
6641
7597
  required: ['asOfDate', 'baseCurrency', 'method', 'rows', 'warnings']
6642
7598
  } as const;
6643
7599
 
6644
- export const $CreateBeanPriceDto = {
6645
- type: 'object',
6646
- properties: {
6647
- currency: {
6648
- type: 'string',
6649
- description: 'Currency being priced (e.g., USD, AAPL, BTC)',
6650
- example: 'USD'
6651
- },
6652
- quoteCurrency: {
6653
- type: 'string',
6654
- description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
6655
- example: 'CNY'
6656
- },
6657
- amount: {
6658
- type: 'number',
6659
- description:
6660
- 'Price amount (MUST be >= 0 per Beancount spec, supports up to 15 decimal places). Zero allowed for conversion entries, negative strictly prohibited.',
6661
- example: 175.5,
6662
- minimum: 0
6663
- },
6664
- date: {
6665
- type: 'string',
6666
- description: 'Price date (ISO 8601 format)',
6667
- example: '2024-11-05'
6668
- },
6669
- metadata: {
6670
- type: 'object',
6671
- description:
6672
- 'Metadata (validated by Zod schema, max field lengths enforced)',
6673
- example: {
6674
- source: 'MANUAL',
6675
- note: 'Bank valuation report',
6676
- confidence: 0.95
6677
- }
6678
- }
6679
- },
6680
- required: ['currency', 'quoteCurrency', 'amount', 'date']
6681
- } as const;
6682
-
6683
- export const $PriceResponseDto = {
6684
- type: 'object',
6685
- properties: {
6686
- id: {
6687
- type: 'string',
6688
- description: 'Unique identifier',
6689
- example: 'uuid-123-456'
6690
- },
6691
- userId: {
6692
- type: 'string',
6693
- description: 'User ID (owner of the price)',
6694
- example: 'user-123'
6695
- },
6696
- currency: {
6697
- type: 'string',
6698
- description: 'Currency being priced (e.g., USD, AAPL, BTC)',
6699
- example: 'BTC'
6700
- },
6701
- quoteCurrency: {
6702
- type: 'string',
6703
- description: 'Quote currency (pricing currency, e.g., USD, CNY)',
6704
- example: 'USD'
6705
- },
6706
- amount: {
6707
- type: 'number',
6708
- description:
6709
- 'Price amount (corresponds to Beancount Amount.number). Supports up to 15 decimal places.',
6710
- example: 50000
6711
- },
6712
- date: {
6713
- type: 'string',
6714
- description:
6715
- 'Price date (ISO 8601 format). Represents the date this price was valid.',
6716
- example: '2024-01-01',
6717
- format: 'date'
6718
- },
6719
- meta: {
6720
- type: 'object',
6721
- description:
6722
- 'Metadata (corresponds to Beancount meta field). Contains source, confidence, note, etc.',
6723
- example: {
6724
- source: 'MANUAL',
6725
- note: 'User-defined price',
6726
- confidence: 1
6727
- }
6728
- },
6729
- createdAt: {
6730
- format: 'date-time',
6731
- type: 'string',
6732
- description: 'Creation timestamp',
6733
- example: '2024-11-03T10:00:00Z'
6734
- },
6735
- updatedAt: {
6736
- format: 'date-time',
6737
- type: 'string',
6738
- description: 'Last update timestamp',
6739
- example: '2024-11-03T10:00:00Z'
6740
- }
6741
- },
6742
- required: [
6743
- 'id',
6744
- 'userId',
6745
- 'currency',
6746
- 'quoteCurrency',
6747
- 'amount',
6748
- 'date',
6749
- 'meta',
6750
- 'createdAt',
6751
- 'updatedAt'
6752
- ]
6753
- } as const;
6754
-
6755
- export const $PriceListResponseDto = {
6756
- type: 'object',
6757
- properties: {
6758
- items: {
6759
- description: 'List of prices',
6760
- type: 'array',
6761
- items: {
6762
- $ref: '#/components/schemas/PriceResponseDto'
6763
- }
6764
- },
6765
- total: {
6766
- type: 'number',
6767
- description: 'Total number of prices',
6768
- example: 42
6769
- }
6770
- },
6771
- required: ['items', 'total']
6772
- } as const;
6773
-
6774
- export const $UpdateBeanPriceDto = {
6775
- type: 'object',
6776
- properties: {
6777
- currency: {
6778
- type: 'string',
6779
- description: 'Currency being priced'
6780
- },
6781
- quoteCurrency: {
6782
- type: 'string',
6783
- description: 'Quote currency (pricing currency)'
6784
- },
6785
- amount: {
6786
- type: 'number',
6787
- description: 'Price amount (MUST be >= 0 per Beancount spec)',
6788
- minimum: 0
6789
- },
6790
- date: {
6791
- type: 'string',
6792
- description: 'Price date (ISO 8601 format)'
6793
- },
6794
- metadata: {
6795
- type: 'object',
6796
- description: 'Metadata'
6797
- }
6798
- }
6799
- } as const;
6800
-
6801
7600
  export const $CurrencyBalanceDto = {
6802
7601
  type: 'object',
6803
7602
  properties: {
@@ -6833,6 +7632,16 @@ export const $TimeSeriesPointDto = {
6833
7632
  description: 'Change from previous point',
6834
7633
  example: '5000.00'
6835
7634
  },
7635
+ assets: {
7636
+ type: 'string',
7637
+ description: 'Total assets at this date (in base currency)',
7638
+ example: '494338.00'
7639
+ },
7640
+ liabilities: {
7641
+ type: 'string',
7642
+ description: 'Total liabilities at this date (in base currency)',
7643
+ example: '310098.00'
7644
+ },
6836
7645
  byCurrency: {
6837
7646
  description: 'Multi-currency breakdown for this point',
6838
7647
  type: 'array',
@@ -6942,6 +7751,111 @@ export const $PortfolioTrendsResponseDto = {
6942
7751
  required: ['series', 'summary', 'period', 'granularity', 'currency']
6943
7752
  } as const;
6944
7753
 
7754
+ export const $CashFlowPointDto = {
7755
+ type: 'object',
7756
+ properties: {
7757
+ month: {
7758
+ type: 'string',
7759
+ description: 'Month key (YYYY-MM)',
7760
+ example: '2024-03'
7761
+ },
7762
+ income: {
7763
+ type: 'string',
7764
+ description: 'Income in base currency (absolute, converted)',
7765
+ example: '10000.00'
7766
+ },
7767
+ expense: {
7768
+ type: 'string',
7769
+ description: 'Expense in base currency (absolute, converted)',
7770
+ example: '5000.00'
7771
+ },
7772
+ netSavings: {
7773
+ type: 'string',
7774
+ description: 'netSavings = income − expense (savings positive)',
7775
+ example: '5000.00'
7776
+ }
7777
+ },
7778
+ required: ['month', 'income', 'expense', 'netSavings']
7779
+ } as const;
7780
+
7781
+ export const $CashFlowTrendSummaryDto = {
7782
+ type: 'object',
7783
+ properties: {
7784
+ totalIncome: {
7785
+ type: 'string',
7786
+ description: 'Total income across the period',
7787
+ example: '60000.00'
7788
+ },
7789
+ totalExpense: {
7790
+ type: 'string',
7791
+ description: 'Total expense across the period',
7792
+ example: '30000.00'
7793
+ },
7794
+ totalNetSavings: {
7795
+ type: 'string',
7796
+ description: 'income − expense across the period',
7797
+ example: '30000.00'
7798
+ },
7799
+ averageMonthlyNetSavings: {
7800
+ type: 'string',
7801
+ description:
7802
+ 'totalNetSavings divided by the window length (N months, incl. zero-filled)',
7803
+ example: '5000.00'
7804
+ }
7805
+ },
7806
+ required: [
7807
+ 'totalIncome',
7808
+ 'totalExpense',
7809
+ 'totalNetSavings',
7810
+ 'averageMonthlyNetSavings'
7811
+ ]
7812
+ } as const;
7813
+
7814
+ export const $CashFlowTrendsResponseDto = {
7815
+ type: 'object',
7816
+ properties: {
7817
+ series: {
7818
+ description:
7819
+ 'Monthly cash-flow series (fixed N-month window, zero-filled)',
7820
+ type: 'array',
7821
+ items: {
7822
+ $ref: '#/components/schemas/CashFlowPointDto'
7823
+ }
7824
+ },
7825
+ summary: {
7826
+ description: 'Period totals',
7827
+ allOf: [
7828
+ {
7829
+ $ref: '#/components/schemas/CashFlowTrendSummaryDto'
7830
+ }
7831
+ ]
7832
+ },
7833
+ period: {
7834
+ type: 'string',
7835
+ description: 'Period requested',
7836
+ example: '6m'
7837
+ },
7838
+ granularity: {
7839
+ type: 'string',
7840
+ description: 'Data granularity (v1 returns month buckets)',
7841
+ example: 'month'
7842
+ },
7843
+ currency: {
7844
+ type: 'string',
7845
+ description: 'Base currency for converted values',
7846
+ example: 'CNY'
7847
+ },
7848
+ warnings: {
7849
+ description: 'Exchange rate warnings (e.g. missing rate for a currency)',
7850
+ type: 'array',
7851
+ items: {
7852
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
7853
+ }
7854
+ }
7855
+ },
7856
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
7857
+ } as const;
7858
+
6945
7859
  export const $GenerateSnapshotBody = {
6946
7860
  type: 'object',
6947
7861
  properties: {}