@firela/api-types 0.0.0-canary.9256c41b → 0.0.0-canary.95d33734

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.
@@ -51,6 +51,14 @@ export const $CreateAccountDto = {
51
51
  description: 'Icon identifier (overrides template)',
52
52
  example: 'bank-custom'
53
53
  },
54
+ displayName: {
55
+ type: 'string',
56
+ description:
57
+ 'User-set display name override (omit/null = keep the derived name)',
58
+ nullable: true,
59
+ maxLength: 50,
60
+ example: 'Salary card'
61
+ },
54
62
  openDirectiveMeta: {
55
63
  type: 'object',
56
64
  description:
@@ -88,6 +96,49 @@ export const $AccountResponseDto = {
88
96
  enum: ['Assets', 'Liabilities', 'Income', 'Expenses', 'Equity'],
89
97
  example: 'Assets'
90
98
  },
99
+ assetSubClass: {
100
+ type: 'string',
101
+ description:
102
+ 'Account-level asset sub-class (product type, e.g. STOCK/DEPOSIT/CREDIT_CARD/PERSONAL_LOAN). Computed from the account path via the asset-classifier (ADR-0077). Null for non-asset accounts (Income/Expenses/Equity) or unmatched paths.',
103
+ enum: [
104
+ 'DEPOSIT',
105
+ 'CASH',
106
+ 'MONEY_MARKET_FUND',
107
+ 'STOCK',
108
+ 'ETF',
109
+ 'MUTUAL_FUND',
110
+ 'EQUITY_COMPENSATION',
111
+ 'GOVERNMENT_BOND',
112
+ 'CORPORATE_BOND',
113
+ 'BOND_FUND',
114
+ 'PRIMARY_RESIDENCE',
115
+ 'INVESTMENT_PROPERTY',
116
+ 'REIT',
117
+ 'GOLD',
118
+ 'SILVER',
119
+ 'PRECIOUS_METAL',
120
+ 'PRECIOUS_METAL_FUND',
121
+ 'COMMODITY',
122
+ 'COMMODITY_FUND',
123
+ 'CRYPTOCURRENCY',
124
+ 'RETIREMENT_ACCOUNT',
125
+ 'HEALTH_ACCOUNT',
126
+ 'EDUCATION_ACCOUNT',
127
+ 'INSURANCE',
128
+ 'PRIVATE_EQUITY',
129
+ 'HEDGE_FUND',
130
+ 'COLLECTIBLES',
131
+ 'MORTGAGE',
132
+ 'STUDENT_LOAN',
133
+ 'CREDIT_CARD',
134
+ 'PERSONAL_LOAN',
135
+ 'ACCOUNTS_PAYABLE',
136
+ 'TAX_PAYABLE',
137
+ 'OTHER'
138
+ ],
139
+ nullable: true,
140
+ example: 'STOCK'
141
+ },
91
142
  status: {
92
143
  type: 'string',
93
144
  description: 'Account status',
@@ -138,7 +189,8 @@ export const $AccountResponseDto = {
138
189
  },
139
190
  displayName: {
140
191
  type: 'string',
141
- description: 'Localized display name (ADR-0114, read-time projection)',
192
+ description:
193
+ 'Display name with precedence: user-set name (#762) > ADR-0114 localized name > path leaf (read-time projection)',
142
194
  example: 'Checking'
143
195
  },
144
196
  icon: {
@@ -154,7 +206,7 @@ export const $AccountResponseDto = {
154
206
  }
155
207
  },
156
208
  platformId: {
157
- type: 'object',
209
+ type: 'string',
158
210
  description: 'Platform ID (null if unbound)',
159
211
  example: 'c98e5d4a-2f71-4a5a-bb3c-92c9f231d5e2'
160
212
  },
@@ -234,6 +286,14 @@ export const $UpdateAccountDto = {
234
286
  description: 'Icon identifier',
235
287
  example: 'bank-custom'
236
288
  },
289
+ displayName: {
290
+ type: 'string',
291
+ description:
292
+ 'User-set display name override (null = clear the override and fall back to the derived name, omit = unchanged)',
293
+ nullable: true,
294
+ maxLength: 50,
295
+ example: 'Salary card'
296
+ },
237
297
  openDirectiveMeta: {
238
298
  type: 'object',
239
299
  description:
@@ -334,16 +394,43 @@ export const $AccountStandardResponseDto = {
334
394
  },
335
395
  name: {
336
396
  type: 'string',
337
- description: 'Short localized display name',
397
+ description:
398
+ 'Short display name. Universal rows project to the request locale (Accept-Language); regional rows keep the authored native name — mixed-language by design (ADR-0131 class P vs class A).',
338
399
  example: 'Housing Fund'
339
400
  },
401
+ aliases: {
402
+ description:
403
+ 'Authored market-language alternative names delivered verbatim (not localized copy, not xlf-managed, not locale-projected). Flat string[] per ADR-0129 D1; ADR-0131 class A.',
404
+ example: ['Alipay', 'WeChat Pay'],
405
+ type: 'array',
406
+ items: {
407
+ type: 'string'
408
+ }
409
+ },
410
+ searchTerms: {
411
+ description:
412
+ 'Locale-projected search synonyms (e.g. the zh bank-card / debit-card everyday terms for the checking account). Pure-locale projection — absent when the locale has no seeded synonyms; English fallback rides the authored aliases field. Search-only vocabulary, not the NLP routing corpus (#698, ADR-0131 fourth-class adjudication).',
413
+ example: ['yinhangka', 'jiejika'],
414
+ type: 'array',
415
+ items: {
416
+ type: 'string'
417
+ }
418
+ },
419
+ currency: {
420
+ type: 'string',
421
+ description:
422
+ 'Product denomination as a 3-letter ISO 4217 code, authored market data delivered verbatim (not localized, not xlf-managed). ADR-0131 class A. Absent = single-currency not asserted — consumers fall back to their own region currency (#714).',
423
+ example: 'HKD'
424
+ },
340
425
  description: {
341
426
  type: 'string',
342
- description: 'Account description (stable semantics only)',
427
+ description:
428
+ 'Account description (stable semantics only). Mixed-language contract: universal rows project to the request locale via the accountDesc xlf axis with an en fallback (ADR-0131 class P, ADR-0132; unseeded locales falling back to English are expected); regional rows deliver the authored market language (ADR-0131 class A, verbatim, never xlf-managed).',
343
429
  example: 'ICBC checking account for daily transactions'
344
430
  },
345
431
  tags: {
346
- description: 'Account tags for categorization',
432
+ description:
433
+ 'Account tags for categorization — structured metadata delivered verbatim (not localized, not xlf-managed). ADR-0131 class A.',
347
434
  example: ['bank', 'checking', 'primary'],
348
435
  type: 'array',
349
436
  items: {
@@ -354,9 +441,47 @@ export const $AccountStandardResponseDto = {
354
441
  type: 'string',
355
442
  description: 'Icon identifier for UI display',
356
443
  example: 'bank-icbc'
444
+ },
445
+ productCategory: {
446
+ type: 'string',
447
+ description:
448
+ 'Onboarding product category (coarse grouping derived from assetSubClass)',
449
+ enum: [
450
+ 'cash',
451
+ 'investment',
452
+ 'credit_card',
453
+ 'loan',
454
+ 'payable_tax',
455
+ 'other'
456
+ ],
457
+ example: 'investment'
458
+ },
459
+ assetClass: {
460
+ type: 'string',
461
+ description:
462
+ 'Asset class (LIQUIDITY/EQUITY/.../LIABILITY), derived at read time from classification rules',
463
+ enum: [
464
+ 'LIQUIDITY',
465
+ 'EQUITY',
466
+ 'FIXED_INCOME',
467
+ 'PRECIOUS_METALS',
468
+ 'COMMODITY',
469
+ 'INSURANCE',
470
+ 'ALTERNATIVE_INVESTMENT',
471
+ 'PERSONAL_ASSETS',
472
+ 'LIABILITY',
473
+ 'REAL_ESTATE',
474
+ 'INDEX'
475
+ ]
476
+ },
477
+ assetSubClass: {
478
+ type: 'string',
479
+ description:
480
+ 'Asset sub-class (product type, derived at read time from classification rules)',
481
+ example: 'STOCK'
357
482
  }
358
483
  },
359
- required: ['path', 'type', 'description', 'tags', 'icon']
484
+ required: ['path', 'type', 'description', 'tags', 'icon', 'productCategory']
360
485
  } as const;
361
486
 
362
487
  export const $AccountStandardListResponseDto = {
@@ -417,7 +542,10 @@ export const $RegionConfigDto = {
417
542
  },
418
543
  locale: {
419
544
  type: 'string',
420
- example: 'de-DE'
545
+ example: 'de-DE',
546
+ pattern: '^[a-z]{2,8}-[A-Z]{2}$',
547
+ description:
548
+ "Region-qualified BCP-47 tag whose region subtag equals the region's own ISO 3166-1 code (e.g., ja-JP, zh-CN, zh-HK)"
421
549
  }
422
550
  },
423
551
  required: ['currency', 'dateFormat', 'locale']
@@ -430,6 +558,12 @@ export const $RegionInfoDto = {
430
558
  type: 'string',
431
559
  example: 'de'
432
560
  },
561
+ open: {
562
+ type: 'boolean',
563
+ example: true,
564
+ description:
565
+ 'Whether the region is open (has a ready regional account template). Not-yet-open regions still return identity metadata and degrade to the universal-only catalog.'
566
+ },
433
567
  displayName: {
434
568
  type: 'string',
435
569
  example: 'Germany'
@@ -448,7 +582,7 @@ export const $RegionInfoDto = {
448
582
  $ref: '#/components/schemas/RegionConfigDto'
449
583
  }
450
584
  },
451
- required: ['code', 'displayName', 'chain', 'config']
585
+ required: ['code', 'open', 'displayName', 'chain', 'config']
452
586
  } as const;
453
587
 
454
588
  export const $RegionsMetadataResponseDto = {
@@ -695,7 +829,7 @@ export const $PostingResponseDto = {
695
829
  units: {
696
830
  type: 'string',
697
831
  description:
698
- 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned.',
832
+ 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned. Carries the raw Beancount sign (credit-normal accounts such as Income post negative — the accounting truth, ADR-0126); renderers must not infer economic semantics from this sign.',
699
833
  example: '100.50'
700
834
  },
701
835
  currency: {
@@ -1061,7 +1195,7 @@ export const $PostingDetailDto = {
1061
1195
  units: {
1062
1196
  type: 'string',
1063
1197
  description:
1064
- 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned.',
1198
+ 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned. Carries the raw Beancount sign (credit-normal accounts such as Income post negative — the accounting truth, ADR-0126); renderers must not infer economic semantics from this sign.',
1065
1199
  example: '100.50'
1066
1200
  },
1067
1201
  currency: {
@@ -1245,6 +1379,147 @@ export const $TransactionDetailDto = {
1245
1379
  ]
1246
1380
  } as const;
1247
1381
 
1382
+ export const $TransactionListItemDto = {
1383
+ type: 'object',
1384
+ properties: {
1385
+ id: {
1386
+ type: 'string',
1387
+ description: 'Transaction ID',
1388
+ example: 'clh1234567890abcdef'
1389
+ },
1390
+ date: {
1391
+ type: 'string',
1392
+ description: 'Transaction date',
1393
+ example: '2024-11-28'
1394
+ },
1395
+ flag: {
1396
+ type: 'string',
1397
+ description: 'Transaction flag',
1398
+ enum: [
1399
+ 'CLEARED',
1400
+ 'PENDING',
1401
+ 'PADDING',
1402
+ 'SUMMARIZE',
1403
+ 'TRANSFER',
1404
+ 'CONVERSIONS'
1405
+ ],
1406
+ example: 'CLEARED'
1407
+ },
1408
+ customFlag: {
1409
+ type: 'string',
1410
+ description: 'Custom flag (if not using standard flags)',
1411
+ example: 'R'
1412
+ },
1413
+ payee: {
1414
+ type: 'string',
1415
+ description: 'Payee name',
1416
+ example: 'Whole Foods Market'
1417
+ },
1418
+ narration: {
1419
+ type: 'string',
1420
+ description: 'Transaction narration',
1421
+ example: 'Grocery shopping'
1422
+ },
1423
+ tags: {
1424
+ description: 'Transaction tags',
1425
+ example: ['groceries'],
1426
+ type: 'array',
1427
+ items: {
1428
+ type: 'string'
1429
+ }
1430
+ },
1431
+ links: {
1432
+ description: 'Transaction links',
1433
+ example: ['invoice-2024-001'],
1434
+ type: 'array',
1435
+ items: {
1436
+ type: 'string'
1437
+ }
1438
+ },
1439
+ meta: {
1440
+ type: 'object',
1441
+ description: 'Transaction metadata'
1442
+ },
1443
+ status: {
1444
+ type: 'string',
1445
+ description: 'Transaction status',
1446
+ enum: ['ACTIVE', 'VOIDED', 'SUPERSEDED'],
1447
+ example: 'ACTIVE'
1448
+ },
1449
+ sourceType: {
1450
+ type: 'string',
1451
+ description:
1452
+ 'Source type (free-form string from transaction metadata, e.g. import, api)'
1453
+ },
1454
+ sourcePlatform: {
1455
+ type: 'string',
1456
+ description: 'Source platform (e.g., alipay, wechat)',
1457
+ example: 'alipay'
1458
+ },
1459
+ postings: {
1460
+ description: 'Transaction postings',
1461
+ type: 'array',
1462
+ items: {
1463
+ $ref: '#/components/schemas/PostingDetailDto'
1464
+ }
1465
+ },
1466
+ createdAt: {
1467
+ type: 'string',
1468
+ description: 'Created at timestamp',
1469
+ example: '2024-11-28T10:30:00.000Z'
1470
+ },
1471
+ voidedAt: {
1472
+ type: 'string',
1473
+ description: 'Voided at timestamp (if voided)',
1474
+ example: '2024-11-29T15:00:00.000Z'
1475
+ },
1476
+ voidedBy: {
1477
+ type: 'string',
1478
+ description: 'User ID who voided this transaction',
1479
+ example: 'clh1234567890abcdef'
1480
+ },
1481
+ correctionReason: {
1482
+ type: 'string',
1483
+ description: 'Correction reason (if voided or superseded)',
1484
+ example: 'Duplicate entry'
1485
+ },
1486
+ supersededBy: {
1487
+ type: 'string',
1488
+ description:
1489
+ 'ID of the transaction that supersedes this one (set when status=SUPERSEDED)',
1490
+ example: 'clh1234567890abcdef'
1491
+ },
1492
+ originalTxn: {
1493
+ type: 'string',
1494
+ description:
1495
+ 'ID of the transaction this one corrected/replaced (back-link on the replacement)',
1496
+ example: 'clh1234567890abcdef'
1497
+ },
1498
+ viewpointAmount: {
1499
+ type: 'string',
1500
+ description:
1501
+ 'Row amount under the request viewpoint (ADR-0126). Category viewpoint (category + flow): per-leg sign-normalized sum over the category account set (Income-root legs negated, Expenses-root identity) — positive under normal booking but NOT clamped (explicit negative expense legs and net-flip refund months stay negative). No viewpoint (plain list / search, no accountId): wallet money-flow net = raw-sign sum over cost-less Assets/Liabilities legs (income positive, expenses negative, transfers net ~0); color cue is the wallet sign (net < 0 = wealth-decreasing). Status-orthogonal: audit views match too (ADR-0128 amount-as-matching-key). Omitted under the account viewpoint (incl. dual) and for rows with no wallet leg.',
1502
+ example: '10000.00'
1503
+ },
1504
+ viewpointCurrency: {
1505
+ type: 'string',
1506
+ description:
1507
+ 'Currency of viewpointAmount. A row spanning multiple currencies takes the largest-magnitude currency group (known simplification, ADR-0126).',
1508
+ example: 'CNY'
1509
+ }
1510
+ },
1511
+ required: [
1512
+ 'id',
1513
+ 'date',
1514
+ 'narration',
1515
+ 'tags',
1516
+ 'links',
1517
+ 'status',
1518
+ 'postings',
1519
+ 'createdAt'
1520
+ ]
1521
+ } as const;
1522
+
1248
1523
  export const $BalanceByCurrencyDto = {
1249
1524
  type: 'object',
1250
1525
  properties: {
@@ -1290,7 +1565,7 @@ export const $TransactionListSummaryDto = {
1290
1565
  totalAmount: {
1291
1566
  type: 'string',
1292
1567
  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.',
1568
+ 'Partial converted total in base currency (rated currencies only). Sign by viewpoint (ADR-0126): account viewpoint keeps the raw Beancount sign (income negative); category viewpoint is per-leg sign-normalized (Income legs negated, Expenses legs identity — positive under normal booking, not clamped). 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
1569
  example: '-6000.00'
1295
1570
  },
1296
1571
  currency: {
@@ -1316,6 +1591,26 @@ export const $TransactionListSummaryDto = {
1316
1591
  required: ['totalAmount', 'currency', 'balanceByCurrency']
1317
1592
  } as const;
1318
1593
 
1594
+ export const $TransactionListViewpointDto = {
1595
+ type: 'object',
1596
+ properties: {
1597
+ type: {
1598
+ type: 'string',
1599
+ description:
1600
+ 'Viewpoint type (only category drill-down carries a viewpoint today)',
1601
+ enum: ['category'],
1602
+ example: 'category'
1603
+ },
1604
+ flow: {
1605
+ type: 'string',
1606
+ description: 'Flow root the category account set is restricted to',
1607
+ enum: ['income', 'expense'],
1608
+ example: 'expense'
1609
+ }
1610
+ },
1611
+ required: ['type', 'flow']
1612
+ } as const;
1613
+
1319
1614
  export const $TransactionListResponseDto = {
1320
1615
  type: 'object',
1321
1616
  properties: {
@@ -1323,7 +1618,7 @@ export const $TransactionListResponseDto = {
1323
1618
  description: 'List of transactions',
1324
1619
  type: 'array',
1325
1620
  items: {
1326
- $ref: '#/components/schemas/TransactionDetailDto'
1621
+ $ref: '#/components/schemas/TransactionListItemDto'
1327
1622
  }
1328
1623
  },
1329
1624
  total: {
@@ -1349,6 +1644,15 @@ export const $TransactionListResponseDto = {
1349
1644
  $ref: '#/components/schemas/TransactionListSummaryDto'
1350
1645
  }
1351
1646
  ]
1647
+ },
1648
+ viewpoint: {
1649
+ description:
1650
+ 'Viewpoint metadata (ADR-0126). Present only for a single category filter (category + flow, no accountId); dual-perspective requests are viewpoint-less (raw signs, no viewpointAmount).',
1651
+ allOf: [
1652
+ {
1653
+ $ref: '#/components/schemas/TransactionListViewpointDto'
1654
+ }
1655
+ ]
1352
1656
  }
1353
1657
  },
1354
1658
  required: ['data', 'total', 'limit', 'offset']
@@ -1700,13 +2004,17 @@ export const $ReviewStatsDto = {
1700
2004
  type: 'object',
1701
2005
  description: 'Count by type'
1702
2006
  },
2007
+ resolved: {
2008
+ type: 'number',
2009
+ description: 'Current count of reviews in RESOLVED status'
2010
+ },
1703
2011
  oldestPending: {
1704
2012
  format: 'date-time',
1705
2013
  type: 'string',
1706
2014
  description: 'Oldest pending review date'
1707
2015
  }
1708
2016
  },
1709
- required: ['total', 'byType']
2017
+ required: ['total', 'byType', 'resolved']
1710
2018
  } as const;
1711
2019
 
1712
2020
  export const $DecisionOptionDto = {
@@ -2011,29 +2319,67 @@ export const $BatchResolveDto = {
2011
2319
  required: ['reviewIds', 'action']
2012
2320
  } as const;
2013
2321
 
2014
- export const $BatchResolveResultDto = {
2322
+ export const $BatchResolveItemDto = {
2015
2323
  type: 'object',
2016
2324
  properties: {
2017
- successCount: {
2018
- type: 'number',
2019
- description: 'Number of successfully resolved items'
2325
+ reviewId: {
2326
+ type: 'string',
2327
+ description: 'Review item ID'
2020
2328
  },
2021
- failedCount: {
2022
- type: 'number',
2023
- description: 'Number of failed items'
2329
+ success: {
2330
+ type: 'boolean',
2331
+ description: 'Whether this item was resolved successfully'
2024
2332
  },
2025
- results: {
2026
- description: 'Details for each item',
2027
- type: 'array',
2028
- items: {
2029
- type: 'string'
2030
- }
2031
- }
2032
- },
2033
- required: ['successCount', 'failedCount', 'results']
2034
- } as const;
2035
-
2036
- export const $CreatePayeeDto = {
2333
+ resolutionId: {
2334
+ type: 'string',
2335
+ description:
2336
+ 'Resolution ID for undo. Present only on successful items (failed items stay PENDING).'
2337
+ },
2338
+ messageKey: {
2339
+ type: 'string',
2340
+ description:
2341
+ 'i18n message key for the per-item failure reason (e.g., review.payee.error.no_suggestion), mirroring the single-item resolve response. Present only on resolver rejections, not on unexpected errors.'
2342
+ },
2343
+ messageParams: {
2344
+ type: 'object',
2345
+ description:
2346
+ 'Parameters for message interpolation (e.g., { name: "PayeeName" })',
2347
+ additionalProperties: {
2348
+ type: 'string'
2349
+ }
2350
+ },
2351
+ error: {
2352
+ type: 'string',
2353
+ description:
2354
+ 'Diagnostic string: the messageKey on the resolver-rejection path; an i18n key mapped from the exception type on the unexpected-error path (#903, raw exception detail stays in server logs).'
2355
+ }
2356
+ },
2357
+ required: ['reviewId', 'success']
2358
+ } as const;
2359
+
2360
+ export const $BatchResolveResultDto = {
2361
+ type: 'object',
2362
+ properties: {
2363
+ successCount: {
2364
+ type: 'number',
2365
+ description: 'Number of successfully resolved items'
2366
+ },
2367
+ failedCount: {
2368
+ type: 'number',
2369
+ description: 'Number of failed items'
2370
+ },
2371
+ results: {
2372
+ description: 'Details for each item',
2373
+ type: 'array',
2374
+ items: {
2375
+ $ref: '#/components/schemas/BatchResolveItemDto'
2376
+ }
2377
+ }
2378
+ },
2379
+ required: ['successCount', 'failedCount', 'results']
2380
+ } as const;
2381
+
2382
+ export const $CreatePayeeDto = {
2037
2383
  type: 'object',
2038
2384
  properties: {
2039
2385
  payee: {
@@ -2259,10 +2605,10 @@ export const $UpdatePayeeDto = {
2259
2605
  meta: {
2260
2606
  type: 'object',
2261
2607
  description:
2262
- 'Metadata for extended information (location, notes, contact info, etc.). Will merge with existing metadata.',
2608
+ 'Metadata for extended information (location, notes, contact info, etc.)',
2263
2609
  example: {
2264
2610
  location: 'Zhongguancun',
2265
- note: 'Updated note',
2611
+ note: 'Near subway station',
2266
2612
  favorite: true
2267
2613
  }
2268
2614
  },
@@ -2823,164 +3169,655 @@ export const $UpdateCommodityDto = {
2823
3169
  }
2824
3170
  } as const;
2825
3171
 
2826
- export const $CreateBeanPriceDto = {
3172
+ export const $CurrencyBalanceDto = {
2827
3173
  type: 'object',
2828
3174
  properties: {
2829
3175
  currency: {
2830
3176
  type: 'string',
2831
- description: 'Currency being priced (e.g., USD, AAPL, BTC)',
2832
- example: 'USD'
2833
- },
2834
- quoteCurrency: {
2835
- type: 'string',
2836
- description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
3177
+ description: 'ISO 4217 currency code',
2837
3178
  example: 'CNY'
2838
3179
  },
2839
- amount: {
2840
- type: '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,
2844
- minimum: 0
2845
- },
2846
- date: {
3180
+ balance: {
2847
3181
  type: 'string',
2848
- description: 'Price date (ISO 8601 format)',
2849
- example: '2024-11-05'
2850
- },
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
- }
3182
+ description: 'Balance amount',
3183
+ example: '500000.00'
2860
3184
  }
2861
3185
  },
2862
- required: ['currency', 'quoteCurrency', 'amount', 'date']
3186
+ required: ['currency', 'balance']
2863
3187
  } as const;
2864
3188
 
2865
- export const $PriceResponseDto = {
3189
+ export const $TimeSeriesPointDto = {
2866
3190
  type: 'object',
2867
3191
  properties: {
2868
- id: {
3192
+ date: {
2869
3193
  type: 'string',
2870
- description: 'Unique identifier',
2871
- example: 'uuid-123-456'
3194
+ description: 'Date in YYYY-MM-DD format',
3195
+ example: '2024-06-15'
2872
3196
  },
2873
- userId: {
3197
+ value: {
2874
3198
  type: 'string',
2875
- description: 'User ID (owner of the price)',
2876
- example: 'user-123'
3199
+ description: 'Value at this date (in base currency)',
3200
+ example: '500000.00'
2877
3201
  },
2878
- currency: {
3202
+ change: {
2879
3203
  type: 'string',
2880
- description: 'Currency being priced (e.g., USD, AAPL, BTC)',
2881
- example: 'BTC'
3204
+ description: 'Change from previous point',
3205
+ example: '5000.00'
2882
3206
  },
2883
- quoteCurrency: {
3207
+ assets: {
2884
3208
  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
3209
+ description: 'Total assets at this date (in base currency)',
3210
+ example: '494338.00'
2893
3211
  },
2894
- date: {
3212
+ liabilities: {
2895
3213
  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'
3214
+ description: 'Total liabilities at this date (in base currency)',
3215
+ example: '310098.00'
2900
3216
  },
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
3217
+ byCurrency: {
3218
+ description: 'Multi-currency breakdown for this point',
3219
+ type: 'array',
3220
+ items: {
3221
+ $ref: '#/components/schemas/CurrencyBalanceDto'
2909
3222
  }
3223
+ }
3224
+ },
3225
+ required: ['date', 'value']
3226
+ } as const;
3227
+
3228
+ export const $TrendSummaryDto = {
3229
+ type: 'object',
3230
+ properties: {
3231
+ startValue: {
3232
+ type: 'string',
3233
+ description: 'Value at start of period',
3234
+ example: '450000.00'
2910
3235
  },
2911
- createdAt: {
2912
- format: 'date-time',
3236
+ endValue: {
2913
3237
  type: 'string',
2914
- description: 'Creation timestamp',
2915
- example: '2024-11-03T10:00:00Z'
3238
+ description: 'Value at end of period',
3239
+ example: '500000.00'
2916
3240
  },
2917
- updatedAt: {
2918
- format: 'date-time',
3241
+ totalChange: {
2919
3242
  type: 'string',
2920
- description: 'Last update timestamp',
2921
- example: '2024-11-03T10:00:00Z'
3243
+ description: 'Total change over period',
3244
+ example: '50000.00'
3245
+ },
3246
+ totalChangePercentage: {
3247
+ type: 'string',
3248
+ description: 'Total change percentage',
3249
+ example: '+11.11%'
2922
3250
  }
2923
3251
  },
2924
- required: [
2925
- 'id',
2926
- 'userId',
2927
- 'currency',
2928
- 'quoteCurrency',
2929
- 'amount',
2930
- 'date',
2931
- 'meta',
2932
- 'createdAt',
2933
- 'updatedAt'
2934
- ]
3252
+ required: ['startValue', 'endValue', 'totalChange', 'totalChangePercentage']
2935
3253
  } as const;
2936
3254
 
2937
- export const $PriceListResponseDto = {
3255
+ export const $MultiCurrencyPointDto = {
2938
3256
  type: 'object',
2939
3257
  properties: {
2940
- items: {
2941
- description: 'List of prices',
3258
+ date: {
3259
+ type: 'string',
3260
+ description: 'Date in YYYY-MM-DD format',
3261
+ example: '2024-06-15'
3262
+ },
3263
+ byCurrency: {
3264
+ description: 'Balances by currency',
2942
3265
  type: 'array',
2943
3266
  items: {
2944
- $ref: '#/components/schemas/PriceResponseDto'
3267
+ $ref: '#/components/schemas/CurrencyBalanceDto'
2945
3268
  }
2946
- },
2947
- total: {
2948
- type: 'number',
2949
- description: 'Total number of prices',
2950
- example: 42
2951
3269
  }
2952
3270
  },
2953
- required: ['items', 'total']
3271
+ required: ['date', 'byCurrency']
2954
3272
  } as const;
2955
3273
 
2956
- export const $UpdateBeanPriceDto = {
3274
+ export const $PortfolioTrendsResponseDto = {
2957
3275
  type: 'object',
2958
3276
  properties: {
2959
- currency: {
2960
- type: 'string',
2961
- description: 'Currency being priced'
3277
+ series: {
3278
+ description: 'Time series data points',
3279
+ type: 'array',
3280
+ items: {
3281
+ $ref: '#/components/schemas/TimeSeriesPointDto'
3282
+ }
2962
3283
  },
2963
- quoteCurrency: {
3284
+ summary: {
3285
+ description: 'Period summary',
3286
+ allOf: [
3287
+ {
3288
+ $ref: '#/components/schemas/TrendSummaryDto'
3289
+ }
3290
+ ]
3291
+ },
3292
+ period: {
2964
3293
  type: 'string',
2965
- description: 'Quote currency (pricing currency)'
3294
+ description: 'Period requested',
3295
+ example: '6m'
2966
3296
  },
2967
- amount: {
2968
- type: 'number',
2969
- description: 'Price amount (MUST be >= 0 per Beancount spec)',
2970
- minimum: 0
3297
+ granularity: {
3298
+ type: 'string',
3299
+ description: 'Data granularity',
3300
+ example: 'month'
2971
3301
  },
2972
- date: {
3302
+ currency: {
2973
3303
  type: 'string',
2974
- description: 'Price date (ISO 8601 format)'
3304
+ description: 'Base currency for converted values',
3305
+ example: 'CNY'
2975
3306
  },
2976
- metadata: {
2977
- type: 'object',
2978
- description: 'Metadata'
3307
+ byCurrency: {
3308
+ description:
3309
+ 'Multi-currency time series (each point has currency breakdown)',
3310
+ type: 'array',
3311
+ items: {
3312
+ $ref: '#/components/schemas/MultiCurrencyPointDto'
3313
+ }
3314
+ },
3315
+ warnings: {
3316
+ description: 'Exchange rate warnings',
3317
+ type: 'array',
3318
+ items: {
3319
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
3320
+ }
2979
3321
  }
2980
- }
3322
+ },
3323
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
2981
3324
  } as const;
2982
3325
 
2983
- export const $CreateRecurringRuleDto = {
3326
+ export const $CashFlowPointDto = {
3327
+ type: 'object',
3328
+ properties: {
3329
+ month: {
3330
+ type: 'string',
3331
+ description: 'Month key (YYYY-MM)',
3332
+ example: '2024-03'
3333
+ },
3334
+ income: {
3335
+ type: 'string',
3336
+ description: 'Income in base currency (absolute, converted)',
3337
+ example: '10000.00'
3338
+ },
3339
+ expense: {
3340
+ type: 'string',
3341
+ description: 'Expense in base currency (absolute, converted)',
3342
+ example: '5000.00'
3343
+ },
3344
+ netSavings: {
3345
+ type: 'string',
3346
+ description: 'netSavings = income − expense (savings positive)',
3347
+ example: '5000.00'
3348
+ }
3349
+ },
3350
+ required: ['month', 'income', 'expense', 'netSavings']
3351
+ } as const;
3352
+
3353
+ export const $CashFlowTrendSummaryDto = {
3354
+ type: 'object',
3355
+ properties: {
3356
+ totalIncome: {
3357
+ type: 'string',
3358
+ description: 'Total income across the period',
3359
+ example: '60000.00'
3360
+ },
3361
+ totalExpense: {
3362
+ type: 'string',
3363
+ description: 'Total expense across the period',
3364
+ example: '30000.00'
3365
+ },
3366
+ totalNetSavings: {
3367
+ type: 'string',
3368
+ description: 'income − expense across the period',
3369
+ example: '30000.00'
3370
+ },
3371
+ averageMonthlyNetSavings: {
3372
+ type: 'string',
3373
+ description:
3374
+ 'totalNetSavings divided by the window length (N months, incl. zero-filled)',
3375
+ example: '5000.00'
3376
+ }
3377
+ },
3378
+ required: [
3379
+ 'totalIncome',
3380
+ 'totalExpense',
3381
+ 'totalNetSavings',
3382
+ 'averageMonthlyNetSavings'
3383
+ ]
3384
+ } as const;
3385
+
3386
+ export const $CashFlowTrendsResponseDto = {
3387
+ type: 'object',
3388
+ properties: {
3389
+ series: {
3390
+ description:
3391
+ 'Monthly cash-flow series (fixed N-month window, zero-filled)',
3392
+ type: 'array',
3393
+ items: {
3394
+ $ref: '#/components/schemas/CashFlowPointDto'
3395
+ }
3396
+ },
3397
+ summary: {
3398
+ description: 'Period totals',
3399
+ allOf: [
3400
+ {
3401
+ $ref: '#/components/schemas/CashFlowTrendSummaryDto'
3402
+ }
3403
+ ]
3404
+ },
3405
+ period: {
3406
+ type: 'string',
3407
+ description: 'Period requested',
3408
+ example: '6m'
3409
+ },
3410
+ granularity: {
3411
+ type: 'string',
3412
+ description: 'Data granularity (v1 returns month buckets)',
3413
+ example: 'month'
3414
+ },
3415
+ currency: {
3416
+ type: 'string',
3417
+ description: 'Base currency for converted values',
3418
+ example: 'CNY'
3419
+ },
3420
+ warnings: {
3421
+ description: 'Exchange rate warnings (e.g. missing rate for a currency)',
3422
+ type: 'array',
3423
+ items: {
3424
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
3425
+ }
3426
+ }
3427
+ },
3428
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
3429
+ } as const;
3430
+
3431
+ export const $GenerateSnapshotBody = {
3432
+ type: 'object',
3433
+ properties: {}
3434
+ } as const;
3435
+
3436
+ export const $GenerateSnapshotResponse = {
3437
+ type: 'object',
3438
+ properties: {}
3439
+ } as const;
3440
+
3441
+ export const $BackfillSnapshotsBody = {
3442
+ type: 'object',
3443
+ properties: {}
3444
+ } as const;
3445
+
3446
+ export const $BackfillSnapshotsResponse = {
3447
+ type: 'object',
3448
+ properties: {}
3449
+ } as const;
3450
+
3451
+ export const $CreateBeanPriceDto = {
3452
+ type: 'object',
3453
+ properties: {
3454
+ currency: {
3455
+ type: 'string',
3456
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
3457
+ example: 'USD'
3458
+ },
3459
+ quoteCurrency: {
3460
+ type: 'string',
3461
+ description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
3462
+ example: 'CNY'
3463
+ },
3464
+ amount: {
3465
+ type: 'number',
3466
+ description:
3467
+ 'Price amount (MUST be >= 0 per Beancount spec, supports up to 15 decimal places). Zero allowed for conversion entries, negative strictly prohibited.',
3468
+ example: 175.5,
3469
+ minimum: 0
3470
+ },
3471
+ date: {
3472
+ type: 'string',
3473
+ description: 'Price date (ISO 8601 format)',
3474
+ example: '2024-11-05'
3475
+ },
3476
+ metadata: {
3477
+ type: 'object',
3478
+ description:
3479
+ 'Metadata (validated by Zod schema, max field lengths enforced)',
3480
+ example: {
3481
+ source: 'MANUAL',
3482
+ note: 'Bank valuation report',
3483
+ confidence: 0.95
3484
+ }
3485
+ }
3486
+ },
3487
+ required: ['currency', 'quoteCurrency', 'amount', 'date']
3488
+ } as const;
3489
+
3490
+ export const $PriceResponseDto = {
3491
+ type: 'object',
3492
+ properties: {
3493
+ id: {
3494
+ type: 'string',
3495
+ description: 'Unique identifier',
3496
+ example: 'uuid-123-456'
3497
+ },
3498
+ userId: {
3499
+ type: 'string',
3500
+ description: 'User ID (owner of the price)',
3501
+ example: 'user-123'
3502
+ },
3503
+ currency: {
3504
+ type: 'string',
3505
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
3506
+ example: 'BTC'
3507
+ },
3508
+ quoteCurrency: {
3509
+ type: 'string',
3510
+ description: 'Quote currency (pricing currency, e.g., USD, CNY)',
3511
+ example: 'USD'
3512
+ },
3513
+ amount: {
3514
+ type: 'number',
3515
+ description:
3516
+ 'Price amount (corresponds to Beancount Amount.number). Supports up to 15 decimal places.',
3517
+ example: 50000
3518
+ },
3519
+ date: {
3520
+ type: 'string',
3521
+ description:
3522
+ 'Price date (ISO 8601 format). Represents the date this price was valid.',
3523
+ example: '2024-01-01',
3524
+ format: 'date'
3525
+ },
3526
+ meta: {
3527
+ type: 'object',
3528
+ description:
3529
+ 'Metadata (corresponds to Beancount meta field). Contains source, confidence, note, etc.',
3530
+ example: {
3531
+ source: 'MANUAL',
3532
+ note: 'User-defined price',
3533
+ confidence: 1
3534
+ }
3535
+ },
3536
+ createdAt: {
3537
+ format: 'date-time',
3538
+ type: 'string',
3539
+ description: 'Creation timestamp',
3540
+ example: '2024-11-03T10:00:00Z'
3541
+ },
3542
+ updatedAt: {
3543
+ format: 'date-time',
3544
+ type: 'string',
3545
+ description: 'Last update timestamp',
3546
+ example: '2024-11-03T10:00:00Z'
3547
+ }
3548
+ },
3549
+ required: [
3550
+ 'id',
3551
+ 'userId',
3552
+ 'currency',
3553
+ 'quoteCurrency',
3554
+ 'amount',
3555
+ 'date',
3556
+ 'meta',
3557
+ 'createdAt',
3558
+ 'updatedAt'
3559
+ ]
3560
+ } as const;
3561
+
3562
+ export const $PriceListResponseDto = {
3563
+ type: 'object',
3564
+ properties: {
3565
+ items: {
3566
+ description: 'List of prices',
3567
+ type: 'array',
3568
+ items: {
3569
+ $ref: '#/components/schemas/PriceResponseDto'
3570
+ }
3571
+ },
3572
+ total: {
3573
+ type: 'number',
3574
+ description: 'Total number of prices',
3575
+ example: 42
3576
+ }
3577
+ },
3578
+ required: ['items', 'total']
3579
+ } as const;
3580
+
3581
+ export const $UpdateBeanPriceDto = {
3582
+ type: 'object',
3583
+ properties: {
3584
+ currency: {
3585
+ type: 'string',
3586
+ description: 'Currency being priced'
3587
+ },
3588
+ quoteCurrency: {
3589
+ type: 'string',
3590
+ description: 'Quote currency (pricing currency)'
3591
+ },
3592
+ amount: {
3593
+ type: 'number',
3594
+ description: 'Price amount (MUST be >= 0 per Beancount spec)',
3595
+ minimum: 0
3596
+ },
3597
+ date: {
3598
+ type: 'string',
3599
+ description: 'Price date (ISO 8601 format)'
3600
+ },
3601
+ metadata: {
3602
+ type: 'object',
3603
+ description: 'Metadata'
3604
+ }
3605
+ }
3606
+ } as const;
3607
+
3608
+ export const $DeleteOwnUserDto = {
3609
+ type: 'object',
3610
+ properties: {
3611
+ accessToken: {
3612
+ type: 'string',
3613
+ description: 'Access token for user verification',
3614
+ example: 'abc123xyz'
3615
+ }
3616
+ },
3617
+ required: ['accessToken']
3618
+ } as const;
3619
+
3620
+ export const $UserSettingsResponseDto = {
3621
+ type: 'object',
3622
+ properties: {
3623
+ baseCurrency: {
3624
+ type: 'string',
3625
+ description:
3626
+ 'Stored base currency choice (ISO 4217) for net-worth/report aggregation. null = user never chose; aggregates fall back to the region default at display time (#713).',
3627
+ example: 'USD',
3628
+ nullable: true
3629
+ }
3630
+ },
3631
+ required: ['baseCurrency']
3632
+ } as const;
3633
+
3634
+ export const $UserResponseDto = {
3635
+ type: 'object',
3636
+ properties: {
3637
+ id: {
3638
+ type: 'string',
3639
+ description: 'User ID'
3640
+ },
3641
+ role: {
3642
+ type: 'string',
3643
+ description: 'Assigned user role'
3644
+ },
3645
+ permissions: {
3646
+ description: 'Permission strings',
3647
+ type: 'array',
3648
+ items: {
3649
+ type: 'string'
3650
+ }
3651
+ },
3652
+ settings: {
3653
+ description: 'User settings',
3654
+ allOf: [
3655
+ {
3656
+ $ref: '#/components/schemas/UserSettingsResponseDto'
3657
+ }
3658
+ ]
3659
+ }
3660
+ },
3661
+ required: ['id', 'role', 'permissions', 'settings']
3662
+ } as const;
3663
+
3664
+ export const $SignupDto = {
3665
+ type: 'object',
3666
+ properties: {
3667
+ turnstileToken: {
3668
+ type: 'string',
3669
+ description:
3670
+ 'Cloudflare Turnstile verification token (optional when Turnstile disabled)',
3671
+ example: '0.abc123def456...'
3672
+ }
3673
+ }
3674
+ } as const;
3675
+
3676
+ export const $SignupResponseDto = {
3677
+ type: 'object',
3678
+ properties: {
3679
+ authToken: {
3680
+ type: 'string',
3681
+ description: 'JWT auth token',
3682
+ example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
3683
+ },
3684
+ accessToken: {
3685
+ type: 'string',
3686
+ description: 'Auto-generated access token'
3687
+ },
3688
+ role: {
3689
+ type: 'string',
3690
+ description: 'Assigned user role',
3691
+ enum: ['USER', 'ADMIN', 'DEMO', 'INACTIVE', 'PAID', 'OPS']
3692
+ }
3693
+ },
3694
+ required: ['authToken', 'accessToken', 'role']
3695
+ } as const;
3696
+
3697
+ export const $UpdateUserSettingDto = {
3698
+ type: 'object',
3699
+ properties: {
3700
+ secId: {
3701
+ type: 'number',
3702
+ description: 'Security ID'
3703
+ },
3704
+ annualInterestRate: {
3705
+ type: 'number',
3706
+ description: 'Annual interest rate',
3707
+ example: 0.05
3708
+ },
3709
+ currency: {
3710
+ type: 'string',
3711
+ description: 'Currency code',
3712
+ example: 'USD'
3713
+ },
3714
+ baseCurrency: {
3715
+ type: 'string',
3716
+ description: 'Base currency code',
3717
+ example: 'USD'
3718
+ },
3719
+ benchmark: {
3720
+ type: 'string',
3721
+ description: 'Benchmark symbol',
3722
+ example: 'SPY'
3723
+ },
3724
+ colorScheme: {
3725
+ type: 'string',
3726
+ description: 'Color scheme',
3727
+ enum: ['DARK', 'LIGHT']
3728
+ },
3729
+ dateRange: {
3730
+ type: 'string',
3731
+ description: 'Date range filter',
3732
+ example: '1y'
3733
+ },
3734
+ emergencyFund: {
3735
+ type: 'number',
3736
+ description: 'Emergency fund amount',
3737
+ example: 10000
3738
+ },
3739
+ 'filters.accounts': {
3740
+ description: 'Account filter IDs',
3741
+ type: 'array',
3742
+ items: {
3743
+ type: 'string'
3744
+ }
3745
+ },
3746
+ 'filters.assetClasses': {
3747
+ description: 'Asset class filters',
3748
+ type: 'array',
3749
+ items: {
3750
+ type: 'string'
3751
+ }
3752
+ },
3753
+ 'filters.dataSource': {
3754
+ type: 'string',
3755
+ description: 'Data source filter'
3756
+ },
3757
+ 'filters.symbol': {
3758
+ type: 'string',
3759
+ description: 'Symbol filter'
3760
+ },
3761
+ 'filters.tags': {
3762
+ description: 'Tag filters',
3763
+ type: 'array',
3764
+ items: {
3765
+ type: 'string'
3766
+ }
3767
+ },
3768
+ isExperimentalFeatures: {
3769
+ type: 'boolean',
3770
+ description: 'Enable experimental features'
3771
+ },
3772
+ isRestrictedView: {
3773
+ type: 'boolean',
3774
+ description: 'Enable restricted view mode'
3775
+ },
3776
+ language: {
3777
+ type: 'string',
3778
+ description: 'Language code',
3779
+ example: 'en'
3780
+ },
3781
+ locale: {
3782
+ type: 'string',
3783
+ description: 'Locale code',
3784
+ example: 'en-US'
3785
+ },
3786
+ projectedTotalAmount: {
3787
+ type: 'number',
3788
+ description: 'Projected total amount',
3789
+ example: 1000000
3790
+ },
3791
+ retirementDate: {
3792
+ type: 'string',
3793
+ description: 'Retirement date in ISO 8601 format',
3794
+ example: '2050-01-01'
3795
+ },
3796
+ savingsRate: {
3797
+ type: 'number',
3798
+ description: 'Savings rate percentage',
3799
+ example: 0.2
3800
+ },
3801
+ viewMode: {
3802
+ type: 'string',
3803
+ description: 'View mode',
3804
+ enum: ['DEFAULT', 'ZEN']
3805
+ }
3806
+ }
3807
+ } as const;
3808
+
3809
+ export const $UpdatePropertyDto = {
3810
+ type: 'object',
3811
+ properties: {
3812
+ value: {
3813
+ type: 'string',
3814
+ description: 'Property value'
3815
+ }
3816
+ },
3817
+ required: ['value']
3818
+ } as const;
3819
+
3820
+ export const $CreateRecurringRuleDto = {
2984
3821
  type: 'object',
2985
3822
  properties: {
2986
3823
  name: {
@@ -3025,7 +3862,6 @@ export const $CreateRecurringRuleDto = {
3025
3862
  currency: {
3026
3863
  type: 'string',
3027
3864
  description: 'Currency code',
3028
- default: 'CNY',
3029
3865
  maxLength: 10
3030
3866
  },
3031
3867
  matchPayeePattern: {
@@ -3073,7 +3909,6 @@ export const $CreateRecurringRuleDto = {
3073
3909
  'name',
3074
3910
  'frequency',
3075
3911
  'expectedAmount',
3076
- 'currency',
3077
3912
  'matchAmountTolerance',
3078
3913
  'autoCreate'
3079
3914
  ]
@@ -3095,7 +3930,7 @@ export const $RecurringRuleResponseDto = {
3095
3930
  description: 'Rule name'
3096
3931
  },
3097
3932
  icon: {
3098
- type: 'object',
3933
+ type: 'string',
3099
3934
  description: 'Icon emoji'
3100
3935
  },
3101
3936
  frequency: {
@@ -3107,11 +3942,11 @@ export const $RecurringRuleResponseDto = {
3107
3942
  description: 'Expected amount'
3108
3943
  },
3109
3944
  expectedDay: {
3110
- type: 'object',
3945
+ type: 'number',
3111
3946
  description: 'Expected day of month'
3112
3947
  },
3113
3948
  customIntervalDays: {
3114
- type: 'object',
3949
+ type: 'number',
3115
3950
  description: 'Custom interval in days'
3116
3951
  },
3117
3952
  currency: {
@@ -3119,7 +3954,7 @@ export const $RecurringRuleResponseDto = {
3119
3954
  description: 'Currency code'
3120
3955
  },
3121
3956
  matchPayeePattern: {
3122
- type: 'object',
3957
+ type: 'string',
3123
3958
  description: 'Payee matching pattern'
3124
3959
  },
3125
3960
  matchAmountTolerance: {
@@ -3127,15 +3962,15 @@ export const $RecurringRuleResponseDto = {
3127
3962
  description: 'Amount tolerance percentage'
3128
3963
  },
3129
3964
  defaultExpenseAccount: {
3130
- type: 'object',
3965
+ type: 'string',
3131
3966
  description: 'Default expense account'
3132
3967
  },
3133
3968
  defaultPaymentAccount: {
3134
- type: 'object',
3969
+ type: 'string',
3135
3970
  description: 'Default payment account'
3136
3971
  },
3137
3972
  defaultPayee: {
3138
- type: 'object',
3973
+ type: 'string',
3139
3974
  description: 'Default payee'
3140
3975
  },
3141
3976
  isActive: {
@@ -3147,7 +3982,7 @@ export const $RecurringRuleResponseDto = {
3147
3982
  description: 'Rule start date (YYYY-MM-DD)'
3148
3983
  },
3149
3984
  endDate: {
3150
- type: 'object',
3985
+ type: 'string',
3151
3986
  description: 'Rule end date (YYYY-MM-DD)'
3152
3987
  },
3153
3988
  autoCreate: {
@@ -3155,7 +3990,7 @@ export const $RecurringRuleResponseDto = {
3155
3990
  description: 'Auto-create transaction on expected date'
3156
3991
  },
3157
3992
  lastOccurrence: {
3158
- type: 'object',
3993
+ type: 'string',
3159
3994
  description: 'Last matched occurrence date (YYYY-MM-DD)'
3160
3995
  },
3161
3996
  totalCount: {
@@ -3237,7 +4072,7 @@ export const $RecurringRuleWithStatsResponseDto = {
3237
4072
  description: 'Rule name'
3238
4073
  },
3239
4074
  icon: {
3240
- type: 'object',
4075
+ type: 'string',
3241
4076
  description: 'Icon emoji'
3242
4077
  },
3243
4078
  frequency: {
@@ -3249,11 +4084,11 @@ export const $RecurringRuleWithStatsResponseDto = {
3249
4084
  description: 'Expected amount'
3250
4085
  },
3251
4086
  expectedDay: {
3252
- type: 'object',
4087
+ type: 'number',
3253
4088
  description: 'Expected day of month'
3254
4089
  },
3255
4090
  customIntervalDays: {
3256
- type: 'object',
4091
+ type: 'number',
3257
4092
  description: 'Custom interval in days'
3258
4093
  },
3259
4094
  currency: {
@@ -3261,7 +4096,7 @@ export const $RecurringRuleWithStatsResponseDto = {
3261
4096
  description: 'Currency code'
3262
4097
  },
3263
4098
  matchPayeePattern: {
3264
- type: 'object',
4099
+ type: 'string',
3265
4100
  description: 'Payee matching pattern'
3266
4101
  },
3267
4102
  matchAmountTolerance: {
@@ -3269,15 +4104,15 @@ export const $RecurringRuleWithStatsResponseDto = {
3269
4104
  description: 'Amount tolerance percentage'
3270
4105
  },
3271
4106
  defaultExpenseAccount: {
3272
- type: 'object',
4107
+ type: 'string',
3273
4108
  description: 'Default expense account'
3274
4109
  },
3275
4110
  defaultPaymentAccount: {
3276
- type: 'object',
4111
+ type: 'string',
3277
4112
  description: 'Default payment account'
3278
4113
  },
3279
4114
  defaultPayee: {
3280
- type: 'object',
4115
+ type: 'string',
3281
4116
  description: 'Default payee'
3282
4117
  },
3283
4118
  isActive: {
@@ -3289,7 +4124,7 @@ export const $RecurringRuleWithStatsResponseDto = {
3289
4124
  description: 'Rule start date (YYYY-MM-DD)'
3290
4125
  },
3291
4126
  endDate: {
3292
- type: 'object',
4127
+ type: 'string',
3293
4128
  description: 'Rule end date (YYYY-MM-DD)'
3294
4129
  },
3295
4130
  autoCreate: {
@@ -3297,7 +4132,7 @@ export const $RecurringRuleWithStatsResponseDto = {
3297
4132
  description: 'Auto-create transaction on expected date'
3298
4133
  },
3299
4134
  lastOccurrence: {
3300
- type: 'object',
4135
+ type: 'string',
3301
4136
  description: 'Last matched occurrence date (YYYY-MM-DD)'
3302
4137
  },
3303
4138
  totalCount: {
@@ -3323,7 +4158,7 @@ export const $RecurringRuleWithStatsResponseDto = {
3323
4158
  description: 'Number of overdue expected transactions'
3324
4159
  },
3325
4160
  nextExpectedDate: {
3326
- type: 'object',
4161
+ type: 'string',
3327
4162
  description: 'Next expected date (YYYY-MM-DD)'
3328
4163
  },
3329
4164
  totalAmount: {
@@ -3339,11 +4174,11 @@ export const $RecurringRuleWithStatsResponseDto = {
3339
4174
  description: 'Number of matched transactions'
3340
4175
  },
3341
4176
  firstDate: {
3342
- type: 'object',
4177
+ type: 'string',
3343
4178
  description: 'First matched transaction date (YYYY-MM-DD)'
3344
4179
  },
3345
4180
  lastDate: {
3346
- type: 'object',
4181
+ type: 'string',
3347
4182
  description: 'Last matched transaction date (YYYY-MM-DD)'
3348
4183
  },
3349
4184
  variance: {
@@ -3384,7 +4219,7 @@ export const $UpdateRecurringRuleDto = {
3384
4219
  properties: {
3385
4220
  name: {
3386
4221
  type: 'string',
3387
- description: 'Rule name',
4222
+ description: 'Rule name (unique per user)',
3388
4223
  maxLength: 100
3389
4224
  },
3390
4225
  icon: {
@@ -3407,7 +4242,7 @@ export const $UpdateRecurringRuleDto = {
3407
4242
  },
3408
4243
  expectedAmount: {
3409
4244
  type: 'number',
3410
- description: 'Expected amount',
4245
+ description: 'Expected amount (positive number)',
3411
4246
  minimum: 0
3412
4247
  },
3413
4248
  expectedDay: {
@@ -3416,11 +4251,6 @@ export const $UpdateRecurringRuleDto = {
3416
4251
  minimum: 1,
3417
4252
  maximum: 31
3418
4253
  },
3419
- customIntervalDays: {
3420
- type: 'number',
3421
- description: 'Custom interval in days',
3422
- minimum: 1
3423
- },
3424
4254
  currency: {
3425
4255
  type: 'string',
3426
4256
  description: 'Currency code',
@@ -3428,41 +4258,48 @@ export const $UpdateRecurringRuleDto = {
3428
4258
  },
3429
4259
  matchPayeePattern: {
3430
4260
  type: 'string',
3431
- description: 'Payee matching pattern',
4261
+ description: 'Payee matching pattern (supports wildcards)',
3432
4262
  maxLength: 200
3433
4263
  },
3434
4264
  matchAmountTolerance: {
3435
4265
  type: 'number',
3436
4266
  description: 'Amount tolerance percentage (0-1)',
4267
+ default: 0.075,
3437
4268
  minimum: 0,
3438
4269
  maximum: 1
3439
4270
  },
3440
4271
  defaultExpenseAccount: {
3441
4272
  type: 'string',
3442
- description: 'Default expense account',
4273
+ description: 'Default expense account for auto-create',
3443
4274
  maxLength: 200
3444
4275
  },
3445
4276
  defaultPaymentAccount: {
3446
4277
  type: 'string',
3447
- description: 'Default payment account',
4278
+ description: 'Default payment account for auto-create',
3448
4279
  maxLength: 200
3449
4280
  },
3450
4281
  defaultPayee: {
3451
4282
  type: 'string',
3452
- description: 'Default payee',
4283
+ description: 'Default payee for auto-create',
3453
4284
  maxLength: 200
3454
4285
  },
3455
4286
  autoCreate: {
3456
4287
  type: 'boolean',
3457
- description: 'Auto-create transaction'
3458
- },
3459
- isActive: {
3460
- type: 'boolean',
3461
- description: 'Rule active status'
4288
+ description: 'Auto-create transaction when expected date arrives',
4289
+ default: false
3462
4290
  },
3463
4291
  endDate: {
3464
4292
  type: 'string',
3465
4293
  description: 'Rule end date (ISO format)'
4294
+ },
4295
+ customIntervalDays: {
4296
+ type: 'number',
4297
+ description: 'Custom interval in days',
4298
+ minimum: 1
4299
+ },
4300
+ isActive: {
4301
+ type: 'boolean',
4302
+ description: 'Rule active status'
3466
4303
  }
3467
4304
  }
3468
4305
  } as const;
@@ -3475,7 +4312,7 @@ export const $ExpectedTransactionRuleDto = {
3475
4312
  description: 'Rule name'
3476
4313
  },
3477
4314
  icon: {
3478
- type: 'object',
4315
+ type: 'string',
3479
4316
  description: 'Rule icon'
3480
4317
  },
3481
4318
  frequency: {
@@ -3518,15 +4355,15 @@ export const $ExpectedTransactionResponseDto = {
3518
4355
  description: 'Status (PENDING, COMPLETED, SKIPPED)'
3519
4356
  },
3520
4357
  matchedTransactionId: {
3521
- type: 'object',
4358
+ type: 'string',
3522
4359
  description: 'Matched transaction ID'
3523
4360
  },
3524
4361
  matchedAt: {
3525
- type: 'object',
4362
+ type: 'string',
3526
4363
  description: 'Match timestamp (ISO 8601)'
3527
4364
  },
3528
4365
  matchConfidence: {
3529
- type: 'object',
4366
+ type: 'number',
3530
4367
  description: 'Match confidence score (0-1)'
3531
4368
  },
3532
4369
  isOverdue: {
@@ -4310,7 +5147,8 @@ export const $UpdateTransactionRuleDto = {
4310
5147
  },
4311
5148
  matchLogic: {
4312
5149
  type: 'string',
4313
- enum: ['OR', 'AND']
5150
+ enum: ['OR', 'AND'],
5151
+ default: 'OR'
4314
5152
  },
4315
5153
  amountMin: {
4316
5154
  type: 'number',
@@ -4324,13 +5162,10 @@ export const $UpdateTransactionRuleDto = {
4324
5162
  },
4325
5163
  priority: {
4326
5164
  type: 'number',
5165
+ default: 50,
4327
5166
  minimum: 0,
4328
5167
  maximum: 1000
4329
5168
  },
4330
- enabled: {
4331
- type: 'boolean',
4332
- description: 'Enable or disable the rule'
4333
- },
4334
5169
  additionalTags: {
4335
5170
  items: {
4336
5171
  type: 'array'
@@ -4340,6 +5175,10 @@ export const $UpdateTransactionRuleDto = {
4340
5175
  },
4341
5176
  additionalMetadata: {
4342
5177
  type: 'object'
5178
+ },
5179
+ enabled: {
5180
+ type: 'boolean',
5181
+ description: 'Enable or disable the rule'
4343
5182
  }
4344
5183
  }
4345
5184
  } as const;
@@ -4364,208 +5203,117 @@ export const $TestRuleDto = {
4364
5203
  type: 'number'
4365
5204
  },
4366
5205
  currency: {
4367
- type: 'string',
4368
- maxLength: 10
4369
- }
4370
- },
4371
- required: ['narration']
4372
- } as const;
4373
-
4374
- export const $TestRuleResponseDto = {
4375
- type: 'object',
4376
- properties: {
4377
- ruleId: {
4378
- type: 'string',
4379
- description: 'Rule ID that was tested'
4380
- },
4381
- matches: {
4382
- type: 'boolean',
4383
- description: 'Whether the rule matched the test data'
4384
- },
4385
- confidence: {
4386
- type: 'number',
4387
- description: 'Match confidence score (0-1)',
4388
- example: 0.85
4389
- },
4390
- matchDetails: {
4391
- type: 'object',
4392
- description: 'Details of which fields matched',
4393
- example: {
4394
- narration: true,
4395
- payee: false,
4396
- categoryAccount: false
4397
- }
4398
- }
4399
- },
4400
- required: ['ruleId', 'matches', 'confidence', 'matchDetails']
4401
- } as const;
4402
-
4403
- export const $DeleteOwnUserDto = {
4404
- type: 'object',
4405
- properties: {
4406
- accessToken: {
4407
- type: 'string',
4408
- description: 'Access token for user verification',
4409
- example: 'abc123xyz'
4410
- }
4411
- },
4412
- required: ['accessToken']
4413
- } as const;
4414
-
4415
- export const $SignupDto = {
4416
- type: 'object',
4417
- properties: {
4418
- turnstileToken: {
4419
- type: 'string',
4420
- description:
4421
- 'Cloudflare Turnstile verification token (optional when Turnstile disabled)',
4422
- example: '0.abc123def456...'
4423
- }
4424
- }
4425
- } as const;
4426
-
4427
- export const $SignupResponseDto = {
4428
- type: 'object',
4429
- properties: {
4430
- authToken: {
4431
- type: 'string',
4432
- description: 'JWT auth token',
4433
- example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
4434
- },
4435
- accessToken: {
4436
- type: 'string',
4437
- description: 'Auto-generated access token'
4438
- },
4439
- role: {
4440
- type: 'string',
4441
- description: 'Assigned user role',
4442
- enum: ['USER', 'ADMIN', 'DEMO', 'INACTIVE', 'PAID', 'OPS']
5206
+ type: 'string',
5207
+ maxLength: 10
4443
5208
  }
4444
5209
  },
4445
- required: ['authToken', 'accessToken', 'role']
5210
+ required: ['narration']
4446
5211
  } as const;
4447
5212
 
4448
- export const $UpdateUserSettingDto = {
5213
+ export const $TestRuleResponseDto = {
4449
5214
  type: 'object',
4450
5215
  properties: {
4451
- secId: {
4452
- type: 'number',
4453
- description: 'Security ID'
4454
- },
4455
- annualInterestRate: {
4456
- type: 'number',
4457
- description: 'Annual interest rate',
4458
- example: 0.05
4459
- },
4460
- currency: {
5216
+ ruleId: {
4461
5217
  type: 'string',
4462
- description: 'Currency code',
4463
- example: 'USD'
5218
+ description: 'Rule ID that was tested'
4464
5219
  },
4465
- baseCurrency: {
4466
- type: 'string',
4467
- description: 'Base currency code',
4468
- example: 'USD'
5220
+ matches: {
5221
+ type: 'boolean',
5222
+ description: 'Whether the rule matched the test data'
4469
5223
  },
4470
- benchmark: {
4471
- type: 'string',
4472
- description: 'Benchmark symbol',
4473
- example: 'SPY'
5224
+ confidence: {
5225
+ type: 'number',
5226
+ description: 'Match confidence score (0-1)',
5227
+ example: 0.85
4474
5228
  },
4475
- colorScheme: {
5229
+ matchDetails: {
5230
+ type: 'object',
5231
+ description: 'Details of which fields matched',
5232
+ example: {
5233
+ narration: true,
5234
+ payee: false,
5235
+ categoryAccount: false
5236
+ }
5237
+ }
5238
+ },
5239
+ required: ['ruleId', 'matches', 'confidence', 'matchDetails']
5240
+ } as const;
5241
+
5242
+ export const $CategoryCatalogEntryDto = {
5243
+ type: 'object',
5244
+ properties: {
5245
+ slug: {
4476
5246
  type: 'string',
4477
- description: 'Color scheme',
4478
- enum: ['DARK', 'LIGHT']
5247
+ description: 'Category slug (single source-of-truth)',
5248
+ example: 'food'
4479
5249
  },
4480
- dateRange: {
5250
+ scenario: {
4481
5251
  type: 'string',
4482
- description: 'Date range filter',
4483
- example: '1y'
5252
+ description: 'Display scenario group (maps to frontend picker _scenario)',
5253
+ enum: [
5254
+ 'expense',
5255
+ 'income',
5256
+ 'investment',
5257
+ 'banking',
5258
+ 'transfer',
5259
+ 'payment'
5260
+ ],
5261
+ example: 'expense'
4484
5262
  },
4485
- emergencyFund: {
4486
- type: 'number',
4487
- description: 'Emergency fund amount',
4488
- example: 10000
5263
+ icon: {
5264
+ type: 'string',
5265
+ description: 'Lucide icon name',
5266
+ example: 'utensils'
4489
5267
  },
4490
- 'filters.accounts': {
4491
- description: 'Account filter IDs',
5268
+ regions: {
5269
+ description: "Applicable regions ('*' = all, 'cn' = CN-only)",
5270
+ example: ['*'],
4492
5271
  type: 'array',
4493
5272
  items: {
4494
5273
  type: 'string'
4495
5274
  }
4496
5275
  },
4497
- 'filters.assetClasses': {
4498
- description: 'Asset class filters',
5276
+ categoryAccounts: {
5277
+ description:
5278
+ "Beancount account paths (categoryAccount) of the region-enabled system rules whose categoryKeywords include this slug (#816). System rules only (public endpoint — user rules excluded); one-to-many by design (e.g. 'utilities' → Electricity/Water/Internet/Gas), sorted, [] when no rule maps the slug.",
5279
+ example: [
5280
+ 'Expenses:Utilities:Electricity',
5281
+ 'Expenses:Utilities:Gas',
5282
+ 'Expenses:Utilities:Internet',
5283
+ 'Expenses:Utilities:Water'
5284
+ ],
4499
5285
  type: 'array',
4500
5286
  items: {
4501
5287
  type: 'string'
4502
5288
  }
4503
- },
4504
- 'filters.dataSource': {
4505
- type: 'string',
4506
- description: 'Data source filter'
4507
- },
4508
- 'filters.symbol': {
4509
- type: 'string',
4510
- description: 'Symbol filter'
4511
- },
4512
- 'filters.tags': {
4513
- description: 'Tag filters',
5289
+ }
5290
+ },
5291
+ required: ['slug', 'scenario', 'icon', 'regions', 'categoryAccounts']
5292
+ } as const;
5293
+
5294
+ export const $CategoryCatalogListResponseDto = {
5295
+ type: 'object',
5296
+ properties: {
5297
+ items: {
5298
+ description: 'Category entries (region-scoped, query-filtered)',
4514
5299
  type: 'array',
4515
5300
  items: {
4516
- type: 'string'
5301
+ $ref: '#/components/schemas/CategoryCatalogEntryDto'
4517
5302
  }
4518
5303
  },
4519
- isExperimentalFeatures: {
4520
- type: 'boolean',
4521
- description: 'Enable experimental features'
4522
- },
4523
- isRestrictedView: {
4524
- type: 'boolean',
4525
- description: 'Enable restricted view mode'
4526
- },
4527
- language: {
4528
- type: 'string',
4529
- description: 'Language code',
4530
- example: 'en'
4531
- },
4532
- locale: {
4533
- type: 'string',
4534
- description: 'Locale code',
4535
- example: 'en-US'
4536
- },
4537
- projectedTotalAmount: {
4538
- type: 'number',
4539
- description: 'Projected total amount',
4540
- example: 1000000
4541
- },
4542
- retirementDate: {
4543
- type: 'string',
4544
- description: 'Retirement date in ISO 8601 format',
4545
- example: '2050-01-01'
4546
- },
4547
- savingsRate: {
5304
+ total: {
4548
5305
  type: 'number',
4549
- description: 'Savings rate percentage',
4550
- example: 0.2
5306
+ description:
5307
+ 'Total category entries for the region (before query filtering)',
5308
+ example: 30
4551
5309
  },
4552
- viewMode: {
4553
- type: 'string',
4554
- description: 'View mode',
4555
- enum: ['DEFAULT', 'ZEN']
4556
- }
4557
- }
4558
- } as const;
4559
-
4560
- export const $UpdatePropertyDto = {
4561
- type: 'object',
4562
- properties: {
4563
- value: {
5310
+ region: {
4564
5311
  type: 'string',
4565
- description: 'Property value'
5312
+ description: 'Region code',
5313
+ example: 'cn'
4566
5314
  }
4567
5315
  },
4568
- required: ['value']
5316
+ required: ['items', 'total', 'region']
4569
5317
  } as const;
4570
5318
 
4571
5319
  export const $CreateBeanEventDto = {
@@ -4731,6 +5479,14 @@ export const $OnboardingAccountDto = {
4731
5479
  description:
4732
5480
  'Platform ID to bind the account to (references Platform.id); omit for unbound',
4733
5481
  example: 'c98e5d4a-2f71-4a5a-bb3c-92c9f231d5e2'
5482
+ },
5483
+ displayName: {
5484
+ type: 'string',
5485
+ description:
5486
+ 'User-set display name override (omit/null = keep the derived name)',
5487
+ nullable: true,
5488
+ maxLength: 50,
5489
+ example: 'Salary card'
4734
5490
  }
4735
5491
  },
4736
5492
  required: ['path', 'currency']
@@ -5310,7 +6066,8 @@ export const $UpdateMapperDefaultsDto = {
5310
6066
  type: 'string',
5311
6067
  description: 'Source account for transactions (Beancount format)',
5312
6068
  example: 'Assets:CN:Alipay:Balance',
5313
- pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
6069
+ pattern:
6070
+ '^(Assets|Liabilities|Income|Expenses|Equity)(:[A-Za-z0-9][A-Za-z0-9-]*)+$'
5314
6071
  },
5315
6072
  currency: {
5316
6073
  type: 'string',
@@ -5324,13 +6081,15 @@ export const $UpdateMapperDefaultsDto = {
5324
6081
  type: 'string',
5325
6082
  description: 'Default expense account (optional)',
5326
6083
  example: 'Expenses:Unknown',
5327
- pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
6084
+ pattern:
6085
+ '^(Assets|Liabilities|Income|Expenses|Equity)(:[A-Za-z0-9][A-Za-z0-9-]*)+$'
5328
6086
  },
5329
6087
  incomeAccount: {
5330
6088
  type: 'string',
5331
6089
  description: 'Default income account (optional)',
5332
6090
  example: 'Income:Unknown',
5333
- pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
6091
+ pattern:
6092
+ '^(Assets|Liabilities|Income|Expenses|Equity)(:[A-Za-z0-9][A-Za-z0-9-]*)+$'
5334
6093
  },
5335
6094
  methodAccountMapping: {
5336
6095
  type: 'object',
@@ -5387,12 +6146,14 @@ export const $ProviderSyncConfigDto = {
5387
6146
  },
5388
6147
  defaultExpenseAccount: {
5389
6148
  type: 'string',
5390
- description: 'Default expense account for the second posting',
6149
+ description:
6150
+ 'Default expense account for the second posting. Omit when no real default exists; the pipeline routes to Review via the Uncategorized sentinel (#618).',
5391
6151
  example: 'Expenses:Unknown'
5392
6152
  },
5393
6153
  defaultIncomeAccount: {
5394
6154
  type: 'string',
5395
- description: 'Default income account for the second posting',
6155
+ description:
6156
+ 'Default income account for the second posting. Omit when no real default exists; the pipeline routes to Review via the Uncategorized sentinel (#618).',
5396
6157
  example: 'Income:Unknown'
5397
6158
  },
5398
6159
  filterPending: {
@@ -5407,12 +6168,7 @@ export const $ProviderSyncConfigDto = {
5407
6168
  example: 'acc_gocardless_001'
5408
6169
  }
5409
6170
  },
5410
- required: [
5411
- 'sourceAccount',
5412
- 'defaultCurrency',
5413
- 'defaultExpenseAccount',
5414
- 'defaultIncomeAccount'
5415
- ]
6171
+ required: ['sourceAccount', 'defaultCurrency']
5416
6172
  } as const;
5417
6173
 
5418
6174
  export const $ProviderSyncDto = {
@@ -5622,15 +6378,106 @@ export const $UncoveredFormatMissDto = {
5622
6378
  properties: {}
5623
6379
  } as const;
5624
6380
 
6381
+ export const $ClientParsedDataDto = {
6382
+ type: 'object',
6383
+ properties: {
6384
+ amount: {
6385
+ type: 'number',
6386
+ description: 'Transaction amount',
6387
+ example: 35
6388
+ },
6389
+ currency: {
6390
+ type: 'string',
6391
+ description: 'Currency code',
6392
+ example: 'CNY'
6393
+ },
6394
+ date: {
6395
+ type: 'string',
6396
+ description: 'Transaction date (ISO 8601)',
6397
+ example: '2026-08-15'
6398
+ },
6399
+ payee: {
6400
+ type: 'string',
6401
+ description: 'Payee/merchant name',
6402
+ example: 'Starbucks'
6403
+ },
6404
+ narration: {
6405
+ type: 'string',
6406
+ description: 'Transaction narration'
6407
+ },
6408
+ category: {
6409
+ type: 'string',
6410
+ description:
6411
+ 'Category in canonical form (catalog slug or Stage-2 rule keyword token, ADR-0116) — echo back verbatim from parsedData.category. Foreign forms (locale display names, account paths) are rejected with nlp.category.invalid.',
6412
+ example: 'food'
6413
+ },
6414
+ incomeType: {
6415
+ type: 'string',
6416
+ description: 'Income type',
6417
+ example: 'Salary'
6418
+ },
6419
+ incomeSource: {
6420
+ type: 'string',
6421
+ description: 'Income source',
6422
+ example: 'Anthropic Inc.'
6423
+ },
6424
+ symbol: {
6425
+ type: 'string',
6426
+ description: 'Security symbol code (e.g., 600519, AAPL)',
6427
+ example: 'AAPL'
6428
+ },
6429
+ quantity: {
6430
+ type: 'number',
6431
+ description: 'Quantity of shares/units',
6432
+ example: 100
6433
+ },
6434
+ price: {
6435
+ type: 'number',
6436
+ description: 'Unit price per share/unit',
6437
+ example: 1900
6438
+ },
6439
+ investmentAction: {
6440
+ type: 'string',
6441
+ description: 'Investment action',
6442
+ enum: ['buy', 'sell'],
6443
+ example: 'buy'
6444
+ },
6445
+ paymentSource: {
6446
+ type: 'string',
6447
+ description: 'Payment source: asset (default) or liability (credit card)',
6448
+ enum: ['asset', 'liability'],
6449
+ example: 'asset'
6450
+ },
6451
+ liabilityHint: {
6452
+ type: 'string',
6453
+ description: 'Liability account hint (CreditCard/Huabei/Baitiao)',
6454
+ example: 'CreditCard'
6455
+ },
6456
+ warning: {
6457
+ type: 'string',
6458
+ description:
6459
+ 'Display-only warning from the prior response; accepted but ignored.',
6460
+ example: 'Cross-currency settlement applies.'
6461
+ }
6462
+ }
6463
+ } as const;
6464
+
5625
6465
  export const $ProcessNlpDto = {
5626
6466
  type: 'object',
5627
6467
  properties: {
5628
6468
  message: {
5629
6469
  type: 'string',
5630
- description: 'Natural language text describing a transaction (Chinese)',
5631
- example: 'yesterday Starbucks spent 35 yuan',
6470
+ description:
6471
+ 'Natural language text describing a transaction. Optional when `confirm` is true (structured confirm); otherwise required.',
6472
+ example: 'Starbucks 35',
5632
6473
  maxLength: 500
5633
6474
  },
6475
+ confirm: {
6476
+ type: 'boolean',
6477
+ description:
6478
+ 'Structured confirm signal — bypasses NL confirm-word matching when true. Send parsedData field edits alongside. The NL word-list path is the fallback.',
6479
+ example: true
6480
+ },
5634
6481
  sessionId: {
5635
6482
  type: 'string',
5636
6483
  description:
@@ -5638,17 +6485,51 @@ export const $ProcessNlpDto = {
5638
6485
  example: 'session_abc123'
5639
6486
  },
5640
6487
  parsedData: {
5641
- type: 'object',
5642
6488
  description:
5643
- 'Parsed data from previous NLP response for session recovery. Send back the parsedData received in confirm_payee/confirm responses.',
5644
- example: {
5645
- amount: 35,
5646
- currency: 'CNY',
5647
- payee: 'Starbucks'
5648
- }
6489
+ 'Parsed data from previous NLP response for session recovery. Send back the parsedData received in confirm_payee/confirm responses.',
6490
+ example: {
6491
+ amount: 35,
6492
+ currency: 'CNY',
6493
+ payee: 'Starbucks'
6494
+ },
6495
+ allOf: [
6496
+ {
6497
+ $ref: '#/components/schemas/ClientParsedDataDto'
6498
+ }
6499
+ ]
6500
+ },
6501
+ selectedRuleId: {
6502
+ type: 'string',
6503
+ description:
6504
+ 'confirm_rule echo-back: rule id selected from the prior confirm_rule response (matchedRule.id or alternatives[i].ruleId). Applied directly when the session is confirming_rule — no NL re-parse.',
6505
+ example: 'rule_abc123'
6506
+ },
6507
+ selectedAccount: {
6508
+ type: 'string',
6509
+ description:
6510
+ 'confirm_account echo-back: account path selected from the prior confirm_account response (suggestedAccount, similarAccounts[i].path, or a typed path). Applied directly when the session is confirming_account — no NL re-parse.',
6511
+ example: 'Expenses:Food:Coffee'
6512
+ },
6513
+ viewpointAccount: {
6514
+ type: 'string',
6515
+ description:
6516
+ 'Viewpoint account hint: the beancount path the user drilled into (e.g. from an account drill-down). Tie-break only — never overrides accounts resolved from the text. Must be an owned, OPEN Assets:/Liabilities: account; unresolvable hints are silently ignored.',
6517
+ example: 'Assets:CN:Bank:ICBC'
6518
+ },
6519
+ viewpointCategory: {
6520
+ type: 'string',
6521
+ description:
6522
+ "Viewpoint category hint: the ADR-0075 Group segment the user drilled into (e.g. 'Food'). Resolved to a concrete OPEN account in that group; tie-break only — never overrides a category resolved from the text.",
6523
+ example: 'Food'
6524
+ },
6525
+ viewpointFlow: {
6526
+ type: 'string',
6527
+ description:
6528
+ "Companion flow root for viewpointCategory ('income' | 'expense'), mirroring the ADR-0126 list-endpoint invariant. Derived from the session's routed intent (multi-turn) when absent; a first-turn flow-less category hint is dropped — send the flow explicitly.",
6529
+ enum: ['income', 'expense'],
6530
+ example: 'expense'
5649
6531
  }
5650
- },
5651
- required: ['message']
6532
+ }
5652
6533
  } as const;
5653
6534
 
5654
6535
  export const $NlpTransactionInfoDto = {
@@ -5714,7 +6595,9 @@ export const $NlpParsedDataDto = {
5714
6595
  },
5715
6596
  category: {
5716
6597
  type: 'string',
5717
- description: 'Category'
6598
+ description:
6599
+ 'Category in canonical form: a CATEGORY_CATALOG slug (GET /{region}/bean/categories) or a Stage-2 rule categoryKeywords token (ADR-0116 D2). Never a locale display name or a beancount account path. Echo back verbatim on confirm.',
6600
+ example: 'food'
5718
6601
  },
5719
6602
  incomeType: {
5720
6603
  type: 'string',
@@ -5960,6 +6843,24 @@ export const $NlpRuleConfirmationDataDto = {
5960
6843
  ]
5961
6844
  } as const;
5962
6845
 
6846
+ export const $NlpAccountCandidateDto = {
6847
+ type: 'object',
6848
+ properties: {
6849
+ path: {
6850
+ type: 'string',
6851
+ description: 'Canonical beancount account path (echo back on selection)',
6852
+ example: 'Expenses:Food:Dining'
6853
+ },
6854
+ name: {
6855
+ type: 'string',
6856
+ description:
6857
+ 'Localized display name (ADR-0114 read-time projection, user locale)',
6858
+ example: '餐饮'
6859
+ }
6860
+ },
6861
+ required: ['path', 'name']
6862
+ } as const;
6863
+
5963
6864
  export const $NlpAccountConfirmationDataDto = {
5964
6865
  type: 'object',
5965
6866
  properties: {
@@ -5970,14 +6871,16 @@ export const $NlpAccountConfirmationDataDto = {
5970
6871
  },
5971
6872
  suggestedAccount: {
5972
6873
  type: 'string',
5973
- description: 'Suggested replacement account',
6874
+ description:
6875
+ 'Suggested replacement account (omitted when no clear candidate)',
5974
6876
  example: 'Expenses:Food:Drinks'
5975
6877
  },
5976
6878
  similarAccounts: {
5977
- description: 'Similar accounts for user selection',
6879
+ description:
6880
+ 'Similar accounts for user selection (path + localized name, #680)',
5978
6881
  type: 'array',
5979
6882
  items: {
5980
- type: 'string'
6883
+ $ref: '#/components/schemas/NlpAccountCandidateDto'
5981
6884
  }
5982
6885
  },
5983
6886
  errorMessage: {
@@ -5992,7 +6895,6 @@ export const $NlpAccountConfirmationDataDto = {
5992
6895
  },
5993
6896
  required: [
5994
6897
  'invalidAccount',
5995
- 'suggestedAccount',
5996
6898
  'similarAccounts',
5997
6899
  'errorMessage',
5998
6900
  'transactionContext'
@@ -6165,7 +7067,8 @@ export const $NlpSuggestedAccountDto = {
6165
7067
  },
6166
7068
  confidence: {
6167
7069
  type: 'number',
6168
- description: 'Confidence score for this suggestion (0-1)',
7070
+ description:
7071
+ 'Confidence score for this suggestion (0-1). Present = predicted (confirm/confirm_rule/confirm_account); omitted = actual persisted account (created). (#586)',
6169
7072
  example: 0.9
6170
7073
  }
6171
7074
  },
@@ -6201,23 +7104,31 @@ export const $NlpDefaultAccountsDto = {
6201
7104
  properties: {
6202
7105
  asset: {
6203
7106
  type: 'string',
6204
- description: 'Default asset account',
6205
- example: 'Assets:Checking'
7107
+ description:
7108
+ 'Default OPEN asset account (MRU when multiple), or null when none/ambiguous',
7109
+ example: 'Assets:Checking',
7110
+ nullable: true
6206
7111
  },
6207
7112
  expense: {
6208
7113
  type: 'string',
6209
- description: 'Default expense account',
6210
- example: 'Expenses:Uncategorized'
7114
+ description:
7115
+ 'Default OPEN expense account (MRU when multiple), or null when none/ambiguous',
7116
+ example: 'Expenses:Food:Coffee',
7117
+ nullable: true
6211
7118
  },
6212
7119
  income: {
6213
7120
  type: 'string',
6214
- description: 'Default income account',
6215
- example: 'Income:Uncategorized'
7121
+ description:
7122
+ 'Default OPEN income account (MRU when multiple), or null when none/ambiguous',
7123
+ example: 'Income:Salary',
7124
+ nullable: true
6216
7125
  },
6217
7126
  liability: {
6218
7127
  type: 'string',
6219
- description: 'Default liability account',
6220
- example: 'Liabilities:CreditCard'
7128
+ description:
7129
+ 'Default OPEN liability account (MRU when multiple), or null when none/ambiguous',
7130
+ example: 'Liabilities:CreditCard',
7131
+ nullable: true
6221
7132
  }
6222
7133
  },
6223
7134
  required: ['asset', 'expense', 'income', 'liability']
@@ -6242,7 +7153,8 @@ export const $NlpResponseDto = {
6242
7153
  'confirm_rule',
6243
7154
  'confirm_account',
6244
7155
  'confirm_payee',
6245
- 'cancel'
7156
+ 'cancel',
7157
+ 'aborted'
6246
7158
  ]
6247
7159
  },
6248
7160
  intent: {
@@ -6256,7 +7168,7 @@ export const $NlpResponseDto = {
6256
7168
  type: 'string',
6257
7169
  description:
6258
7170
  'Asset sub-type (only present when intent is "asset"). Determines which asset-related form to render.',
6259
- enum: ['transfer', 'banking', 'investment'],
7171
+ enum: ['transfer', 'banking', 'investment', 'lend', 'lend_collect'],
6260
7172
  example: 'investment'
6261
7173
  },
6262
7174
  liabilitySubType: {
@@ -6404,7 +7316,7 @@ export const $NlpResponseDto = {
6404
7316
  },
6405
7317
  suggestedAccounts: {
6406
7318
  description:
6407
- 'Suggested accounts for this transaction. Contains recommended source and destination accounts based on the detected intent and rules.',
7319
+ 'Suggested accounts for this transaction (#586). confirm/confirm_rule/confirm_account: predicted (source/destination carry confidence); created: actual persisted accounts (confidence omitted). confirm_account destination is the suggested replacement, never the invalid account.',
6408
7320
  allOf: [
6409
7321
  {
6410
7322
  $ref: '#/components/schemas/NlpSuggestedAccountsDto'
@@ -6413,7 +7325,7 @@ export const $NlpResponseDto = {
6413
7325
  },
6414
7326
  defaultAccounts: {
6415
7327
  description:
6416
- 'Default accounts for the user/region. These are fallback accounts used when no specific suggestion is available.',
7328
+ 'Default fallback accounts for the user/region (#586). v1 returns universal constants; per-user personalization is planned.',
6417
7329
  allOf: [
6418
7330
  {
6419
7331
  $ref: '#/components/schemas/NlpDefaultAccountsDto'
@@ -6459,13 +7371,26 @@ export const $PlatformListItemDto = {
6459
7371
  suggestedSegment: {
6460
7372
  type: 'string',
6461
7373
  description:
6462
- 'Suggested path segment — canonical with first char uppercased (ACC_COMP_NAME_RE)'
7374
+ 'Suggested path segment — canonical PascalCased per hyphen-part, hyphens preserved (e.g. "Apple-Pay")'
6463
7375
  },
6464
7376
  logoUrl: {
6465
7377
  type: 'string',
6466
7378
  description: 'Logo URL',
6467
7379
  nullable: true
6468
7380
  },
7381
+ countryCode: {
7382
+ type: 'string',
7383
+ description: 'ISO 3166-1 alpha-2 (UPPERCASE); null = global platform',
7384
+ example: 'CN',
7385
+ nullable: true
7386
+ },
7387
+ category: {
7388
+ type: 'string',
7389
+ description:
7390
+ 'Region-aware category (institution vocab, e.g. DigitalWallet/Bank). null = no region-aware suggestion; fall back to type.',
7391
+ nullable: true,
7392
+ example: 'DigitalWallet'
7393
+ },
6469
7394
  isBound: {
6470
7395
  type: 'boolean',
6471
7396
  description: 'Whether user has accounts using this platform'
@@ -6479,6 +7404,8 @@ export const $PlatformListItemDto = {
6479
7404
  'canonical',
6480
7405
  'suggestedSegment',
6481
7406
  'logoUrl',
7407
+ 'countryCode',
7408
+ 'category',
6482
7409
  'isBound'
6483
7410
  ]
6484
7411
  } as const;
@@ -6514,13 +7441,26 @@ export const $PlatformMatchResultDto = {
6514
7441
  suggestedSegment: {
6515
7442
  type: 'string',
6516
7443
  description:
6517
- 'Suggested path segment — canonical, already in ACCOUNT_RE format'
7444
+ 'Suggested path segment — canonical PascalCased per hyphen-part, hyphens preserved (e.g. "Apple-Pay")'
6518
7445
  },
6519
7446
  logoUrl: {
6520
7447
  type: 'string',
6521
7448
  description: 'Logo URL',
6522
7449
  nullable: true
6523
7450
  },
7451
+ countryCode: {
7452
+ type: 'string',
7453
+ description: 'ISO 3166-1 alpha-2 (UPPERCASE); null = global platform',
7454
+ example: 'CN',
7455
+ nullable: true
7456
+ },
7457
+ category: {
7458
+ type: 'string',
7459
+ description:
7460
+ 'Region-aware category (institution vocab, e.g. DigitalWallet/Bank). null = no region-aware suggestion; fall back to type.',
7461
+ nullable: true,
7462
+ example: 'DigitalWallet'
7463
+ },
6524
7464
  matchType: {
6525
7465
  type: 'string',
6526
7466
  description: "How this row matched: 'exact' > 'prefix' > 'substring'",
@@ -6534,6 +7474,8 @@ export const $PlatformMatchResultDto = {
6534
7474
  'type',
6535
7475
  'suggestedSegment',
6536
7476
  'logoUrl',
7477
+ 'countryCode',
7478
+ 'category',
6537
7479
  'matchType'
6538
7480
  ]
6539
7481
  } as const;
@@ -6566,6 +7508,79 @@ export const $PlatformMatchResponseDto = {
6566
7508
  required: ['platforms', 'matchType', 'total', 'hasMore']
6567
7509
  } as const;
6568
7510
 
7511
+ export const $PlatformStandardsPlatformDto = {
7512
+ type: 'object',
7513
+ properties: {
7514
+ id: {
7515
+ type: 'string',
7516
+ description: 'Global platform ID'
7517
+ },
7518
+ name: {
7519
+ type: 'string',
7520
+ description: 'Platform name (e.g., "ICBC")'
7521
+ },
7522
+ canonical: {
7523
+ type: 'string',
7524
+ description: 'Canonical identifier in ACCOUNT_RE format (e.g., "icbc")'
7525
+ },
7526
+ suggestedSegment: {
7527
+ type: 'string',
7528
+ description:
7529
+ 'Suggested path segment — canonical PascalCased per hyphen-part, hyphens preserved (e.g. "Apple-Pay")'
7530
+ },
7531
+ type: {
7532
+ type: 'string',
7533
+ description: 'Platform type',
7534
+ enum: [
7535
+ 'BANK',
7536
+ 'BROKERAGE',
7537
+ 'CRYPTO_EXCHANGE',
7538
+ 'PAYMENT',
7539
+ 'INVESTMENT',
7540
+ 'INSURANCE',
7541
+ 'OTHER'
7542
+ ]
7543
+ },
7544
+ category: {
7545
+ type: 'string',
7546
+ description:
7547
+ 'Region-aware category (institution vocab, e.g. DigitalWallet/Bank) resolved against the final region. null = no region-aware suggestion; fall back to type.',
7548
+ nullable: true,
7549
+ example: 'Bank'
7550
+ }
7551
+ },
7552
+ required: ['id', 'name', 'canonical', 'suggestedSegment', 'type', 'category']
7553
+ } as const;
7554
+
7555
+ export const $PlatformStandardsResponseDto = {
7556
+ type: 'object',
7557
+ properties: {
7558
+ platform: {
7559
+ description: 'The selected platform (institution lock source)',
7560
+ allOf: [
7561
+ {
7562
+ $ref: '#/components/schemas/PlatformStandardsPlatformDto'
7563
+ }
7564
+ ]
7565
+ },
7566
+ region: {
7567
+ type: 'string',
7568
+ description:
7569
+ "Resolved template region (ISO 3166-1 alpha-2, UPPERCASE): the platform's own countryCode when set, else the region query param. For regions without a regional template file the template list falls back to the universal-only catalog while region still echoes the code.",
7570
+ example: 'CN'
7571
+ },
7572
+ templates: {
7573
+ description:
7574
+ 'Candidate account-standard templates of the resolved region (groupable by productCategory client-side)',
7575
+ type: 'array',
7576
+ items: {
7577
+ $ref: '#/components/schemas/AccountStandardResponseDto'
7578
+ }
7579
+ }
7580
+ },
7581
+ required: ['platform', 'region', 'templates']
7582
+ } as const;
7583
+
6569
7584
  export const $CreatePlatformDto = {
6570
7585
  type: 'object',
6571
7586
  properties: {
@@ -6667,7 +7682,8 @@ export const $UpdatePlatformDto = {
6667
7682
  },
6668
7683
  isActive: {
6669
7684
  type: 'boolean',
6670
- description: 'Whether the platform is active'
7685
+ description: 'Whether the platform is active',
7686
+ default: true
6671
7687
  }
6672
7688
  }
6673
7689
  } as const;
@@ -6830,7 +7846,8 @@ export const $AccountItemDto = {
6830
7846
  },
6831
7847
  displayName: {
6832
7848
  type: 'string',
6833
- description: 'Display name (last part of account path)',
7849
+ description:
7850
+ 'Display name: user-set name if provided (#762), else the ADR-0114 chain — request-locale catalog name, en pivot, then the last part of the account path (#771)',
6834
7851
  example: 'Savings'
6835
7852
  },
6836
7853
  balance: {
@@ -6866,7 +7883,8 @@ export const $PlatformGroupDto = {
6866
7883
  example: 'CMB Bank'
6867
7884
  },
6868
7885
  accounts: {
6869
- description: 'Accounts within this platform',
7886
+ description:
7887
+ 'Accounts within this platform (Assets and Liabilities rows, #696)',
6870
7888
  type: 'array',
6871
7889
  items: {
6872
7890
  $ref: '#/components/schemas/AccountItemDto'
@@ -6874,7 +7892,8 @@ export const $PlatformGroupDto = {
6874
7892
  },
6875
7893
  totalBalance: {
6876
7894
  type: 'string',
6877
- description: 'FX-converted total balance in base currency',
7895
+ description:
7896
+ 'FX-converted total balance in base currency (nets Assets + Liabilities rows; can be negative)',
6878
7897
  example: '100000.00'
6879
7898
  },
6880
7899
  balanceByCurrency: {
@@ -6893,7 +7912,7 @@ export const $PlatformGroupDto = {
6893
7912
  sharePct: {
6894
7913
  type: 'number',
6895
7914
  description:
6896
- 'Share of the grand converted total (0-100); 0 when grand total is 0',
7915
+ 'Share of the converted asset-side grand total (0-100); liability balances are excluded from the basis; 0 when grand total is 0 (#696)',
6897
7916
  example: 42.5
6898
7917
  }
6899
7918
  },
@@ -6941,7 +7960,8 @@ export const $AccountsSummaryDto = {
6941
7960
  properties: {
6942
7961
  totalAccounts: {
6943
7962
  type: 'number',
6944
- description: 'Total number of accounts'
7963
+ description:
7964
+ 'Total number of accounts (balance sheet: Assets + Liabilities, #696)'
6945
7965
  },
6946
7966
  totalPlatforms: {
6947
7967
  type: 'number',
@@ -6999,7 +8019,8 @@ export const $AccountItemWithAssetClassDto = {
6999
8019
  },
7000
8020
  displayName: {
7001
8021
  type: 'string',
7002
- description: 'Display name (last part of account path)',
8022
+ description:
8023
+ 'Display name: user-set name if provided (#762), else the ADR-0114 chain — request-locale catalog name, en pivot, then the last part of the account path (#771)',
7003
8024
  example: 'Savings'
7004
8025
  },
7005
8026
  balance: {
@@ -7485,7 +8506,7 @@ export const $MonetaryDto = {
7485
8506
  example: 'USD'
7486
8507
  },
7487
8508
  baseCcyEquivalent: {
7488
- type: 'object',
8509
+ type: 'string',
7489
8510
  description: 'Converted to user base currency (Decimal string)',
7490
8511
  example: '21600',
7491
8512
  nullable: true
@@ -7561,13 +8582,13 @@ export const $HoldingPnlRowDto = {
7561
8582
  example: 'Assets:US:Broker:AAPL'
7562
8583
  },
7563
8584
  accountCcy: {
7564
- type: 'object',
8585
+ type: 'string',
7565
8586
  description: 'Account settlement currency (ISO 4217), from cost currency',
7566
8587
  nullable: true,
7567
8588
  example: 'USD'
7568
8589
  },
7569
8590
  brokerType: {
7570
- type: 'object',
8591
+ type: 'string',
7571
8592
  description: 'Broker type derived from Platform.type',
7572
8593
  nullable: true,
7573
8594
  example: 'broker'
@@ -7588,7 +8609,7 @@ export const $HoldingPnlRowDto = {
7588
8609
  example: 'EQUITY'
7589
8610
  },
7590
8611
  assetSubClass: {
7591
- type: 'object',
8612
+ type: 'string',
7592
8613
  nullable: true,
7593
8614
  example: 'STOCK'
7594
8615
  },
@@ -7635,14 +8656,14 @@ export const $HoldingPnlRowDto = {
7635
8656
  ]
7636
8657
  },
7637
8658
  unrealizedPnlBase: {
7638
- type: 'object',
8659
+ type: 'string',
7639
8660
  description:
7640
8661
  'Unrealized P&L in base currency (Decimal string); null when any FX/price missing',
7641
8662
  nullable: true,
7642
8663
  example: '6000'
7643
8664
  },
7644
8665
  unrealizedPnlPct: {
7645
- type: 'object',
8666
+ type: 'string',
7646
8667
  description: 'Unrealized P&L % (Decimal string)',
7647
8668
  nullable: true,
7648
8669
  example: '25'
@@ -7666,7 +8687,7 @@ export const $HoldingPnlRowDto = {
7666
8687
  ]
7667
8688
  },
7668
8689
  pctOfInvestedAssets: {
7669
- type: 'object',
8690
+ type: 'string',
7670
8691
  description:
7671
8692
  'Share of invested assets % (Decimal string); only for invested chartTokens',
7672
8693
  nullable: true,
@@ -7711,15 +8732,15 @@ export const $HoldingPnlWarningDto = {
7711
8732
  ]
7712
8733
  },
7713
8734
  symbol: {
7714
- type: 'object',
8735
+ type: 'string',
7715
8736
  nullable: true
7716
8737
  },
7717
8738
  accountId: {
7718
- type: 'object',
8739
+ type: 'string',
7719
8740
  nullable: true
7720
8741
  },
7721
8742
  currency: {
7722
- type: 'object',
8743
+ type: 'string',
7723
8744
  nullable: true
7724
8745
  }
7725
8746
  },
@@ -7760,304 +8781,378 @@ export const $HoldingPnlResponseDto = {
7760
8781
  required: ['asOfDate', 'baseCurrency', 'method', 'rows', 'warnings']
7761
8782
  } as const;
7762
8783
 
7763
- export const $CurrencyBalanceDto = {
8784
+ export const $AnonymousLoginDto = {
7764
8785
  type: 'object',
7765
8786
  properties: {
7766
- currency: {
7767
- type: 'string',
7768
- description: 'ISO 4217 currency code',
7769
- example: 'CNY'
7770
- },
7771
- balance: {
8787
+ accessToken: {
7772
8788
  type: 'string',
7773
- description: 'Balance amount',
7774
- example: '500000.00'
8789
+ description: 'Access token for anonymous login'
7775
8790
  }
7776
8791
  },
7777
- required: ['currency', 'balance']
8792
+ required: ['accessToken']
7778
8793
  } as const;
7779
8794
 
7780
- export const $TimeSeriesPointDto = {
8795
+ export const $AnonymousLoginResponseDto = {
7781
8796
  type: 'object',
7782
8797
  properties: {
7783
- date: {
7784
- type: 'string',
7785
- description: 'Date in YYYY-MM-DD format',
7786
- example: '2024-06-15'
7787
- },
7788
- value: {
7789
- type: 'string',
7790
- description: 'Value at this date (in base currency)',
7791
- example: '500000.00'
7792
- },
7793
- change: {
7794
- type: 'object',
7795
- description: 'Change from previous point',
7796
- example: '5000.00'
7797
- },
7798
- assets: {
7799
- type: 'string',
7800
- description: 'Total assets at this date (in base currency)',
7801
- example: '494338.00'
7802
- },
7803
- liabilities: {
8798
+ authToken: {
7804
8799
  type: 'string',
7805
- description: 'Total liabilities at this date (in base currency)',
7806
- example: '310098.00'
7807
- },
7808
- byCurrency: {
7809
- description: 'Multi-currency breakdown for this point',
7810
- type: 'array',
7811
- items: {
7812
- $ref: '#/components/schemas/CurrencyBalanceDto'
7813
- }
8800
+ description: 'JWT auth token',
8801
+ example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
7814
8802
  }
7815
8803
  },
7816
- required: ['date', 'value']
8804
+ required: ['authToken']
7817
8805
  } as const;
7818
8806
 
7819
- export const $TrendSummaryDto = {
8807
+ export const $ParserContributionMetaDto = {
7820
8808
  type: 'object',
7821
8809
  properties: {
7822
- startValue: {
7823
- type: 'string',
7824
- description: 'Value at start of period',
7825
- example: '450000.00'
7826
- },
7827
- endValue: {
7828
- type: 'string',
7829
- description: 'Value at end of period',
7830
- example: '500000.00'
7831
- },
7832
- totalChange: {
8810
+ institution: {
7833
8811
  type: 'string',
7834
- description: 'Total change over period',
7835
- example: '50000.00'
8812
+ description: 'Institution slug (lowercase kebab-case)',
8813
+ pattern: '^[a-z0-9]+(-[a-z0-9]+)*$',
8814
+ example: 'icbc'
7836
8815
  },
7837
- totalChangePercentage: {
7838
- type: 'string',
7839
- description: 'Total change percentage',
7840
- example: '+11.11%'
7841
- }
7842
- },
7843
- required: ['startValue', 'endValue', 'totalChange', 'totalChangePercentage']
7844
- } as const;
7845
-
7846
- export const $MultiCurrencyPointDto = {
7847
- type: 'object',
7848
- properties: {
7849
- date: {
8816
+ region: {
7850
8817
  type: 'string',
7851
- description: 'Date in YYYY-MM-DD format',
7852
- example: '2024-06-15'
7853
- },
7854
- byCurrency: {
7855
- description: 'Balances by currency',
7856
- type: 'array',
7857
- items: {
7858
- $ref: '#/components/schemas/CurrencyBalanceDto'
7859
- }
7860
- }
7861
- },
7862
- required: ['date', 'byCurrency']
7863
- } as const;
7864
-
7865
- export const $PortfolioTrendsResponseDto = {
7866
- type: 'object',
7867
- properties: {
7868
- series: {
7869
- description: 'Time series data points',
7870
- type: 'array',
7871
- items: {
7872
- $ref: '#/components/schemas/TimeSeriesPointDto'
7873
- }
7874
- },
7875
- summary: {
7876
- description: 'Period summary',
7877
- allOf: [
7878
- {
7879
- $ref: '#/components/schemas/TrendSummaryDto'
7880
- }
8818
+ enum: [
8819
+ 'cn',
8820
+ 'us',
8821
+ 'de',
8822
+ 'fr',
8823
+ 'gb',
8824
+ 'hk',
8825
+ 'jp',
8826
+ 'sg',
8827
+ 'au',
8828
+ 'ca',
8829
+ 'other'
7881
8830
  ]
7882
8831
  },
7883
- period: {
8832
+ accountType: {
7884
8833
  type: 'string',
7885
- description: 'Period requested',
7886
- example: '6m'
8834
+ enum: ['checking', 'savings', 'credit', 'debit', 'investment']
7887
8835
  },
7888
- granularity: {
8836
+ format: {
7889
8837
  type: 'string',
7890
- description: 'Data granularity',
7891
- example: 'month'
8838
+ enum: ['csv', 'xlsx', 'pdf', 'ofx', 'qif']
7892
8839
  },
7893
- currency: {
8840
+ institutionDisplayName: {
7894
8841
  type: 'string',
7895
- description: 'Base currency for converted values',
7896
- example: 'CNY'
8842
+ example: '中国工商银行'
7897
8843
  },
7898
- byCurrency: {
8844
+ encoding: {
8845
+ type: 'string',
8846
+ example: 'utf-8'
8847
+ },
8848
+ delimiter: {
8849
+ type: 'string',
8850
+ description: 'CSV delimiter character: ",", ";", "\\t" or "|"'
8851
+ },
8852
+ headerRows: {
8853
+ type: 'number',
8854
+ default: 1,
8855
+ description: 'Header row count; the client omits the field when it is 1'
8856
+ },
8857
+ notes: {
8858
+ type: 'string',
8859
+ maxLength: 2000
8860
+ }
8861
+ },
8862
+ required: ['institution', 'region', 'accountType', 'format']
8863
+ } as const;
8864
+
8865
+ export const $ParserContributionSamplesDto = {
8866
+ type: 'object',
8867
+ properties: {
8868
+ rows: {
7899
8869
  description:
7900
- 'Multi-currency time series (each point has currency breakdown)',
8870
+ 'Client-sanitized sample rows (key = column name, value = cell)',
7901
8871
  type: 'array',
7902
8872
  items: {
7903
- $ref: '#/components/schemas/MultiCurrencyPointDto'
8873
+ type: 'object'
7904
8874
  }
7905
8875
  },
7906
- warnings: {
7907
- description: 'Exchange rate warnings',
8876
+ rawHeaders: {
7908
8877
  type: 'array',
7909
8878
  items: {
7910
- $ref: '#/components/schemas/ExchangeRateWarningDto'
8879
+ type: 'string'
7911
8880
  }
7912
8881
  }
7913
8882
  },
7914
- required: ['series', 'summary', 'period', 'granularity', 'currency']
8883
+ required: ['rows']
7915
8884
  } as const;
7916
8885
 
7917
- export const $CashFlowPointDto = {
8886
+ export const $FieldHintDto = {
7918
8887
  type: 'object',
7919
8888
  properties: {
7920
- month: {
8889
+ columnName: {
7921
8890
  type: 'string',
7922
- description: 'Month key (YYYY-MM)',
7923
- example: '2024-03'
8891
+ example: '交易日期'
7924
8892
  },
7925
- income: {
8893
+ format: {
7926
8894
  type: 'string',
7927
- description: 'Income in base currency (absolute, converted)',
7928
- example: '10000.00'
8895
+ description: 'Date format, e.g. yyyy-MM-dd HH:mm',
8896
+ example: 'yyyy-MM-dd'
7929
8897
  },
7930
- expense: {
8898
+ signConvention: {
7931
8899
  type: 'string',
7932
- description: 'Expense in base currency (absolute, converted)',
7933
- example: '5000.00'
8900
+ enum: ['negative-expense', 'positive-expense', 'separate-columns']
7934
8901
  },
7935
- netSavings: {
7936
- type: 'string',
7937
- description: 'netSavings = income − expense (savings positive)',
7938
- example: '5000.00'
8902
+ creditColumn: {
8903
+ type: 'string'
8904
+ },
8905
+ debitColumn: {
8906
+ type: 'string'
7939
8907
  }
7940
8908
  },
7941
- required: ['month', 'income', 'expense', 'netSavings']
8909
+ required: ['columnName']
7942
8910
  } as const;
7943
8911
 
7944
- export const $CashFlowTrendSummaryDto = {
8912
+ export const $ParserContributionFieldHintsDto = {
7945
8913
  type: 'object',
7946
8914
  properties: {
7947
- totalIncome: {
7948
- type: 'string',
7949
- description: 'Total income across the period',
7950
- example: '60000.00'
8915
+ date: {
8916
+ $ref: '#/components/schemas/FieldHintDto'
7951
8917
  },
7952
- totalExpense: {
7953
- type: 'string',
7954
- description: 'Total expense across the period',
7955
- example: '30000.00'
8918
+ amount: {
8919
+ $ref: '#/components/schemas/FieldHintDto'
7956
8920
  },
7957
- totalNetSavings: {
7958
- type: 'string',
7959
- description: 'income − expense across the period',
7960
- example: '30000.00'
8921
+ description: {
8922
+ $ref: '#/components/schemas/FieldHintDto'
7961
8923
  },
7962
- averageMonthlyNetSavings: {
7963
- type: 'string',
7964
- description:
7965
- 'totalNetSavings divided by the window length (N months, incl. zero-filled)',
7966
- example: '5000.00'
8924
+ balance: {
8925
+ $ref: '#/components/schemas/FieldHintDto'
8926
+ },
8927
+ payee: {
8928
+ $ref: '#/components/schemas/FieldHintDto'
8929
+ },
8930
+ reference: {
8931
+ $ref: '#/components/schemas/FieldHintDto'
8932
+ },
8933
+ category: {
8934
+ $ref: '#/components/schemas/FieldHintDto'
7967
8935
  }
7968
8936
  },
7969
- required: [
7970
- 'totalIncome',
7971
- 'totalExpense',
7972
- 'totalNetSavings',
7973
- 'averageMonthlyNetSavings'
7974
- ]
8937
+ required: ['date', 'amount']
7975
8938
  } as const;
7976
8939
 
7977
- export const $CashFlowTrendsResponseDto = {
8940
+ export const $ExpectedTransactionDto = {
7978
8941
  type: 'object',
7979
8942
  properties: {
7980
- series: {
7981
- description:
7982
- 'Monthly cash-flow series (fixed N-month window, zero-filled)',
7983
- type: 'array',
7984
- items: {
7985
- $ref: '#/components/schemas/CashFlowPointDto'
7986
- }
7987
- },
7988
- summary: {
7989
- description: 'Period totals',
7990
- allOf: [
7991
- {
7992
- $ref: '#/components/schemas/CashFlowTrendSummaryDto'
7993
- }
7994
- ]
7995
- },
7996
- period: {
8943
+ date: {
7997
8944
  type: 'string',
7998
- description: 'Period requested',
7999
- example: '6m'
8945
+ example: '2026-08-01'
8000
8946
  },
8001
- granularity: {
8002
- type: 'string',
8003
- description: 'Data granularity (v1 returns month buckets)',
8004
- example: 'month'
8947
+ amount: {
8948
+ type: 'number',
8949
+ example: -45.5
8005
8950
  },
8006
- currency: {
8951
+ description: {
8007
8952
  type: 'string',
8008
- description: 'Base currency for converted values',
8009
- example: 'CNY'
8953
+ example: '星巴克-***店'
8010
8954
  },
8011
- warnings: {
8012
- description: 'Exchange rate warnings (e.g. missing rate for a currency)',
8013
- type: 'array',
8014
- items: {
8015
- $ref: '#/components/schemas/ExchangeRateWarningDto'
8016
- }
8955
+ payee: {
8956
+ type: 'string'
8957
+ },
8958
+ category: {
8959
+ type: 'string'
8017
8960
  }
8018
8961
  },
8019
- required: ['series', 'summary', 'period', 'granularity', 'currency']
8020
- } as const;
8021
-
8022
- export const $GenerateSnapshotBody = {
8023
- type: 'object',
8024
- properties: {}
8962
+ required: ['date', 'amount', 'description']
8025
8963
  } as const;
8026
8964
 
8027
- export const $GenerateSnapshotResponse = {
8965
+ export const $ParserContributionExamplesDto = {
8028
8966
  type: 'object',
8029
- properties: {}
8967
+ properties: {
8968
+ expectedTransactions: {
8969
+ type: 'array',
8970
+ items: {
8971
+ $ref: '#/components/schemas/ExpectedTransactionDto'
8972
+ }
8973
+ }
8974
+ },
8975
+ required: ['expectedTransactions']
8030
8976
  } as const;
8031
8977
 
8032
- export const $BackfillSnapshotsBody = {
8978
+ export const $ParserContributionRequestDto = {
8033
8979
  type: 'object',
8034
- properties: {}
8980
+ properties: {
8981
+ meta: {
8982
+ $ref: '#/components/schemas/ParserContributionMetaDto'
8983
+ },
8984
+ samples: {
8985
+ $ref: '#/components/schemas/ParserContributionSamplesDto'
8986
+ },
8987
+ fieldHints: {
8988
+ $ref: '#/components/schemas/ParserContributionFieldHintsDto'
8989
+ },
8990
+ examples: {
8991
+ description: 'Omitted entirely by the client when empty',
8992
+ allOf: [
8993
+ {
8994
+ $ref: '#/components/schemas/ParserContributionExamplesDto'
8995
+ }
8996
+ ]
8997
+ }
8998
+ },
8999
+ required: ['meta', 'samples', 'fieldHints']
8035
9000
  } as const;
8036
9001
 
8037
- export const $BackfillSnapshotsResponse = {
9002
+ export const $ParserContributionRelayResponseDto = {
8038
9003
  type: 'object',
8039
- properties: {}
9004
+ properties: {
9005
+ issueUrl: {
9006
+ type: 'string',
9007
+ example: 'https://github.com/fire-zu/firela-vlt/issues/42'
9008
+ },
9009
+ issueNumber: {
9010
+ type: 'number',
9011
+ example: 42
9012
+ }
9013
+ },
9014
+ required: ['issueUrl', 'issueNumber']
8040
9015
  } as const;
8041
9016
 
8042
- export const $AnonymousLoginDto = {
9017
+ export const $SymbolSearchResultDto = {
8043
9018
  type: 'object',
8044
9019
  properties: {
8045
- accessToken: {
9020
+ symbol: {
8046
9021
  type: 'string',
8047
- description: 'Access token for anonymous login'
9022
+ example: 'AAPL'
9023
+ },
9024
+ name: {
9025
+ type: 'string',
9026
+ example: 'Apple Inc.',
9027
+ nullable: true
9028
+ },
9029
+ exchange: {
9030
+ type: 'string',
9031
+ example: 'US',
9032
+ nullable: true
9033
+ },
9034
+ assetType: {
9035
+ type: 'string',
9036
+ description: 'OpenBB asset_type (e.g. stock, etf)',
9037
+ example: 'stock',
9038
+ nullable: true
9039
+ },
9040
+ assetClass: {
9041
+ type: 'string',
9042
+ description: 'IGN asset class (region.types.ts ASSET_CLASSES)',
9043
+ example: 'EQUITY',
9044
+ nullable: true
9045
+ },
9046
+ assetSubClass: {
9047
+ type: 'string',
9048
+ description: 'IGN asset sub-class (region.types.ts ASSET_SUB_CLASSES)',
9049
+ example: 'STOCK',
9050
+ nullable: true
9051
+ },
9052
+ currency: {
9053
+ type: 'string',
9054
+ description: 'Trading currency (extra_data or inferred from exchange)',
9055
+ example: 'USD',
9056
+ nullable: true
8048
9057
  }
8049
9058
  },
8050
- required: ['accessToken']
9059
+ required: ['symbol']
8051
9060
  } as const;
8052
9061
 
8053
- export const $AnonymousLoginResponseDto = {
9062
+ export const $SymbolQuoteDto = {
8054
9063
  type: 'object',
8055
9064
  properties: {
8056
- authToken: {
9065
+ symbol: {
8057
9066
  type: 'string',
8058
- description: 'JWT auth token',
8059
- example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
9067
+ example: 'AAPL'
9068
+ },
9069
+ name: {
9070
+ type: 'string',
9071
+ example: 'Apple Inc.',
9072
+ nullable: true
9073
+ },
9074
+ exchange: {
9075
+ type: 'string',
9076
+ example: 'US',
9077
+ nullable: true
9078
+ },
9079
+ assetType: {
9080
+ type: 'string',
9081
+ description: 'OpenBB asset_type',
9082
+ example: 'stock',
9083
+ nullable: true
9084
+ },
9085
+ assetClass: {
9086
+ type: 'string',
9087
+ description: 'IGN asset class',
9088
+ example: 'EQUITY',
9089
+ nullable: true
9090
+ },
9091
+ assetSubClass: {
9092
+ type: 'string',
9093
+ description: 'IGN asset sub-class',
9094
+ example: 'STOCK',
9095
+ nullable: true
9096
+ },
9097
+ currency: {
9098
+ type: 'string',
9099
+ description: 'Trading currency (extra_data or inferred from exchange)',
9100
+ example: 'USD',
9101
+ nullable: true
9102
+ },
9103
+ price: {
9104
+ type: 'string',
9105
+ description: 'Latest price (Decimal string)',
9106
+ example: '189.84',
9107
+ nullable: true
9108
+ },
9109
+ priceDate: {
9110
+ type: 'string',
9111
+ description: 'Date the price was observed (ISO yyyy-MM-dd)',
9112
+ example: '2026-08-05',
9113
+ nullable: true
9114
+ },
9115
+ changePercent: {
9116
+ type: 'number',
9117
+ description:
9118
+ 'Change vs previous close, in percentage points (1.7 == 1.7%). openbb stores change_percent as a normalized decimal; this exposes percentage points for frontend convenience.',
9119
+ example: 1.7,
9120
+ nullable: true
9121
+ },
9122
+ prevClose: {
9123
+ type: 'string',
9124
+ description: 'Previous close (Decimal string)',
9125
+ nullable: true
9126
+ },
9127
+ open: {
9128
+ type: 'string',
9129
+ description: 'Day open (Decimal string)',
9130
+ nullable: true
9131
+ },
9132
+ high: {
9133
+ type: 'string',
9134
+ description: 'Day high (Decimal string)',
9135
+ nullable: true
9136
+ },
9137
+ low: {
9138
+ type: 'string',
9139
+ description: 'Day low (Decimal string)',
9140
+ nullable: true
9141
+ },
9142
+ volume: {
9143
+ type: 'string',
9144
+ description: 'Day volume (Decimal string)',
9145
+ nullable: true
9146
+ },
9147
+ yearHigh: {
9148
+ type: 'string',
9149
+ description: '52-week high (Decimal string)',
9150
+ nullable: true
9151
+ },
9152
+ yearLow: {
9153
+ type: 'string',
9154
+ description: '52-week low (Decimal string)',
9155
+ nullable: true
8060
9156
  }
8061
- },
8062
- required: ['authToken']
9157
+ }
8063
9158
  } as const;