@firela/api-types 0.0.0-canary.55cba54a → 0.0.0-canary.5864871e

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:
@@ -181,7 +189,8 @@ export const $AccountResponseDto = {
181
189
  },
182
190
  displayName: {
183
191
  type: 'string',
184
- 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)',
185
194
  example: 'Checking'
186
195
  },
187
196
  icon: {
@@ -197,7 +206,7 @@ export const $AccountResponseDto = {
197
206
  }
198
207
  },
199
208
  platformId: {
200
- type: 'object',
209
+ type: 'string',
201
210
  description: 'Platform ID (null if unbound)',
202
211
  example: 'c98e5d4a-2f71-4a5a-bb3c-92c9f231d5e2'
203
212
  },
@@ -377,16 +386,43 @@ export const $AccountStandardResponseDto = {
377
386
  },
378
387
  name: {
379
388
  type: 'string',
380
- description: 'Short localized display name',
389
+ description:
390
+ '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).',
381
391
  example: 'Housing Fund'
382
392
  },
393
+ aliases: {
394
+ description:
395
+ '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.',
396
+ example: ['Alipay', 'WeChat Pay'],
397
+ type: 'array',
398
+ items: {
399
+ type: 'string'
400
+ }
401
+ },
402
+ searchTerms: {
403
+ description:
404
+ '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).',
405
+ example: ['yinhangka', 'jiejika'],
406
+ type: 'array',
407
+ items: {
408
+ type: 'string'
409
+ }
410
+ },
411
+ currency: {
412
+ type: 'string',
413
+ description:
414
+ '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).',
415
+ example: 'HKD'
416
+ },
383
417
  description: {
384
418
  type: 'string',
385
- description: 'Account description (stable semantics only)',
419
+ description:
420
+ '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).',
386
421
  example: 'ICBC checking account for daily transactions'
387
422
  },
388
423
  tags: {
389
- description: 'Account tags for categorization',
424
+ description:
425
+ 'Account tags for categorization — structured metadata delivered verbatim (not localized, not xlf-managed). ADR-0131 class A.',
390
426
  example: ['bank', 'checking', 'primary'],
391
427
  type: 'array',
392
428
  items: {
@@ -498,7 +534,10 @@ export const $RegionConfigDto = {
498
534
  },
499
535
  locale: {
500
536
  type: 'string',
501
- example: 'de-DE'
537
+ example: 'de-DE',
538
+ pattern: '^[a-z]{2,8}-[A-Z]{2}$',
539
+ description:
540
+ "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)"
502
541
  }
503
542
  },
504
543
  required: ['currency', 'dateFormat', 'locale']
@@ -511,6 +550,12 @@ export const $RegionInfoDto = {
511
550
  type: 'string',
512
551
  example: 'de'
513
552
  },
553
+ open: {
554
+ type: 'boolean',
555
+ example: true,
556
+ description:
557
+ '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.'
558
+ },
514
559
  displayName: {
515
560
  type: 'string',
516
561
  example: 'Germany'
@@ -529,7 +574,7 @@ export const $RegionInfoDto = {
529
574
  $ref: '#/components/schemas/RegionConfigDto'
530
575
  }
531
576
  },
532
- required: ['code', 'displayName', 'chain', 'config']
577
+ required: ['code', 'open', 'displayName', 'chain', 'config']
533
578
  } as const;
534
579
 
535
580
  export const $RegionsMetadataResponseDto = {
@@ -776,7 +821,7 @@ export const $PostingResponseDto = {
776
821
  units: {
777
822
  type: 'string',
778
823
  description:
779
- 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned.',
824
+ '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.',
780
825
  example: '100.50'
781
826
  },
782
827
  currency: {
@@ -1142,7 +1187,7 @@ export const $PostingDetailDto = {
1142
1187
  units: {
1143
1188
  type: 'string',
1144
1189
  description:
1145
- 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned.',
1190
+ '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.',
1146
1191
  example: '100.50'
1147
1192
  },
1148
1193
  currency: {
@@ -1326,6 +1371,147 @@ export const $TransactionDetailDto = {
1326
1371
  ]
1327
1372
  } as const;
1328
1373
 
1374
+ export const $TransactionListItemDto = {
1375
+ type: 'object',
1376
+ properties: {
1377
+ id: {
1378
+ type: 'string',
1379
+ description: 'Transaction ID',
1380
+ example: 'clh1234567890abcdef'
1381
+ },
1382
+ date: {
1383
+ type: 'string',
1384
+ description: 'Transaction date',
1385
+ example: '2024-11-28'
1386
+ },
1387
+ flag: {
1388
+ type: 'string',
1389
+ description: 'Transaction flag',
1390
+ enum: [
1391
+ 'CLEARED',
1392
+ 'PENDING',
1393
+ 'PADDING',
1394
+ 'SUMMARIZE',
1395
+ 'TRANSFER',
1396
+ 'CONVERSIONS'
1397
+ ],
1398
+ example: 'CLEARED'
1399
+ },
1400
+ customFlag: {
1401
+ type: 'string',
1402
+ description: 'Custom flag (if not using standard flags)',
1403
+ example: 'R'
1404
+ },
1405
+ payee: {
1406
+ type: 'string',
1407
+ description: 'Payee name',
1408
+ example: 'Whole Foods Market'
1409
+ },
1410
+ narration: {
1411
+ type: 'string',
1412
+ description: 'Transaction narration',
1413
+ example: 'Grocery shopping'
1414
+ },
1415
+ tags: {
1416
+ description: 'Transaction tags',
1417
+ example: ['groceries'],
1418
+ type: 'array',
1419
+ items: {
1420
+ type: 'string'
1421
+ }
1422
+ },
1423
+ links: {
1424
+ description: 'Transaction links',
1425
+ example: ['invoice-2024-001'],
1426
+ type: 'array',
1427
+ items: {
1428
+ type: 'string'
1429
+ }
1430
+ },
1431
+ meta: {
1432
+ type: 'object',
1433
+ description: 'Transaction metadata'
1434
+ },
1435
+ status: {
1436
+ type: 'string',
1437
+ description: 'Transaction status',
1438
+ enum: ['ACTIVE', 'VOIDED', 'SUPERSEDED'],
1439
+ example: 'ACTIVE'
1440
+ },
1441
+ sourceType: {
1442
+ type: 'string',
1443
+ description:
1444
+ 'Source type (free-form string from transaction metadata, e.g. import, api)'
1445
+ },
1446
+ sourcePlatform: {
1447
+ type: 'string',
1448
+ description: 'Source platform (e.g., alipay, wechat)',
1449
+ example: 'alipay'
1450
+ },
1451
+ postings: {
1452
+ description: 'Transaction postings',
1453
+ type: 'array',
1454
+ items: {
1455
+ $ref: '#/components/schemas/PostingDetailDto'
1456
+ }
1457
+ },
1458
+ createdAt: {
1459
+ type: 'string',
1460
+ description: 'Created at timestamp',
1461
+ example: '2024-11-28T10:30:00.000Z'
1462
+ },
1463
+ voidedAt: {
1464
+ type: 'string',
1465
+ description: 'Voided at timestamp (if voided)',
1466
+ example: '2024-11-29T15:00:00.000Z'
1467
+ },
1468
+ voidedBy: {
1469
+ type: 'string',
1470
+ description: 'User ID who voided this transaction',
1471
+ example: 'clh1234567890abcdef'
1472
+ },
1473
+ correctionReason: {
1474
+ type: 'string',
1475
+ description: 'Correction reason (if voided or superseded)',
1476
+ example: 'Duplicate entry'
1477
+ },
1478
+ supersededBy: {
1479
+ type: 'string',
1480
+ description:
1481
+ 'ID of the transaction that supersedes this one (set when status=SUPERSEDED)',
1482
+ example: 'clh1234567890abcdef'
1483
+ },
1484
+ originalTxn: {
1485
+ type: 'string',
1486
+ description:
1487
+ 'ID of the transaction this one corrected/replaced (back-link on the replacement)',
1488
+ example: 'clh1234567890abcdef'
1489
+ },
1490
+ viewpointAmount: {
1491
+ type: 'string',
1492
+ description:
1493
+ '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.',
1494
+ example: '10000.00'
1495
+ },
1496
+ viewpointCurrency: {
1497
+ type: 'string',
1498
+ description:
1499
+ 'Currency of viewpointAmount. A row spanning multiple currencies takes the largest-magnitude currency group (known simplification, ADR-0126).',
1500
+ example: 'CNY'
1501
+ }
1502
+ },
1503
+ required: [
1504
+ 'id',
1505
+ 'date',
1506
+ 'narration',
1507
+ 'tags',
1508
+ 'links',
1509
+ 'status',
1510
+ 'postings',
1511
+ 'createdAt'
1512
+ ]
1513
+ } as const;
1514
+
1329
1515
  export const $BalanceByCurrencyDto = {
1330
1516
  type: 'object',
1331
1517
  properties: {
@@ -1371,7 +1557,7 @@ export const $TransactionListSummaryDto = {
1371
1557
  totalAmount: {
1372
1558
  type: 'string',
1373
1559
  description:
1374
- '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.',
1560
+ '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.',
1375
1561
  example: '-6000.00'
1376
1562
  },
1377
1563
  currency: {
@@ -1397,6 +1583,26 @@ export const $TransactionListSummaryDto = {
1397
1583
  required: ['totalAmount', 'currency', 'balanceByCurrency']
1398
1584
  } as const;
1399
1585
 
1586
+ export const $TransactionListViewpointDto = {
1587
+ type: 'object',
1588
+ properties: {
1589
+ type: {
1590
+ type: 'string',
1591
+ description:
1592
+ 'Viewpoint type (only category drill-down carries a viewpoint today)',
1593
+ enum: ['category'],
1594
+ example: 'category'
1595
+ },
1596
+ flow: {
1597
+ type: 'string',
1598
+ description: 'Flow root the category account set is restricted to',
1599
+ enum: ['income', 'expense'],
1600
+ example: 'expense'
1601
+ }
1602
+ },
1603
+ required: ['type', 'flow']
1604
+ } as const;
1605
+
1400
1606
  export const $TransactionListResponseDto = {
1401
1607
  type: 'object',
1402
1608
  properties: {
@@ -1404,7 +1610,7 @@ export const $TransactionListResponseDto = {
1404
1610
  description: 'List of transactions',
1405
1611
  type: 'array',
1406
1612
  items: {
1407
- $ref: '#/components/schemas/TransactionDetailDto'
1613
+ $ref: '#/components/schemas/TransactionListItemDto'
1408
1614
  }
1409
1615
  },
1410
1616
  total: {
@@ -1430,6 +1636,15 @@ export const $TransactionListResponseDto = {
1430
1636
  $ref: '#/components/schemas/TransactionListSummaryDto'
1431
1637
  }
1432
1638
  ]
1639
+ },
1640
+ viewpoint: {
1641
+ description:
1642
+ '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).',
1643
+ allOf: [
1644
+ {
1645
+ $ref: '#/components/schemas/TransactionListViewpointDto'
1646
+ }
1647
+ ]
1433
1648
  }
1434
1649
  },
1435
1650
  required: ['data', 'total', 'limit', 'offset']
@@ -2340,10 +2555,10 @@ export const $UpdatePayeeDto = {
2340
2555
  meta: {
2341
2556
  type: 'object',
2342
2557
  description:
2343
- 'Metadata for extended information (location, notes, contact info, etc.). Will merge with existing metadata.',
2558
+ 'Metadata for extended information (location, notes, contact info, etc.)',
2344
2559
  example: {
2345
2560
  location: 'Zhongguancun',
2346
- note: 'Updated note',
2561
+ note: 'Near subway station',
2347
2562
  favorite: true
2348
2563
  }
2349
2564
  },
@@ -2904,568 +3119,660 @@ export const $UpdateCommodityDto = {
2904
3119
  }
2905
3120
  } as const;
2906
3121
 
2907
- export const $CreateBeanPriceDto = {
3122
+ export const $CurrencyBalanceDto = {
2908
3123
  type: 'object',
2909
3124
  properties: {
2910
3125
  currency: {
2911
3126
  type: 'string',
2912
- description: 'Currency being priced (e.g., USD, AAPL, BTC)',
2913
- example: 'USD'
2914
- },
2915
- quoteCurrency: {
2916
- type: 'string',
2917
- description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
3127
+ description: 'ISO 4217 currency code',
2918
3128
  example: 'CNY'
2919
3129
  },
2920
- amount: {
2921
- type: 'number',
2922
- description:
2923
- 'Price amount (MUST be >= 0 per Beancount spec, supports up to 15 decimal places). Zero allowed for conversion entries, negative strictly prohibited.',
2924
- example: 175.5,
2925
- minimum: 0
2926
- },
2927
- date: {
3130
+ balance: {
2928
3131
  type: 'string',
2929
- description: 'Price date (ISO 8601 format)',
2930
- example: '2024-11-05'
2931
- },
2932
- metadata: {
2933
- type: 'object',
2934
- description:
2935
- 'Metadata (validated by Zod schema, max field lengths enforced)',
2936
- example: {
2937
- source: 'MANUAL',
2938
- note: 'Bank valuation report',
2939
- confidence: 0.95
2940
- }
3132
+ description: 'Balance amount',
3133
+ example: '500000.00'
2941
3134
  }
2942
3135
  },
2943
- required: ['currency', 'quoteCurrency', 'amount', 'date']
3136
+ required: ['currency', 'balance']
2944
3137
  } as const;
2945
3138
 
2946
- export const $PriceResponseDto = {
3139
+ export const $TimeSeriesPointDto = {
2947
3140
  type: 'object',
2948
3141
  properties: {
2949
- id: {
3142
+ date: {
2950
3143
  type: 'string',
2951
- description: 'Unique identifier',
2952
- example: 'uuid-123-456'
3144
+ description: 'Date in YYYY-MM-DD format',
3145
+ example: '2024-06-15'
2953
3146
  },
2954
- userId: {
3147
+ value: {
2955
3148
  type: 'string',
2956
- description: 'User ID (owner of the price)',
2957
- example: 'user-123'
3149
+ description: 'Value at this date (in base currency)',
3150
+ example: '500000.00'
2958
3151
  },
2959
- currency: {
3152
+ change: {
2960
3153
  type: 'string',
2961
- description: 'Currency being priced (e.g., USD, AAPL, BTC)',
2962
- example: 'BTC'
3154
+ description: 'Change from previous point',
3155
+ example: '5000.00'
2963
3156
  },
2964
- quoteCurrency: {
3157
+ assets: {
2965
3158
  type: 'string',
2966
- description: 'Quote currency (pricing currency, e.g., USD, CNY)',
2967
- example: 'USD'
2968
- },
2969
- amount: {
2970
- type: 'number',
2971
- description:
2972
- 'Price amount (corresponds to Beancount Amount.number). Supports up to 15 decimal places.',
2973
- example: 50000
3159
+ description: 'Total assets at this date (in base currency)',
3160
+ example: '494338.00'
2974
3161
  },
2975
- date: {
3162
+ liabilities: {
2976
3163
  type: 'string',
2977
- description:
2978
- 'Price date (ISO 8601 format). Represents the date this price was valid.',
2979
- example: '2024-01-01',
2980
- format: 'date'
3164
+ description: 'Total liabilities at this date (in base currency)',
3165
+ example: '310098.00'
2981
3166
  },
2982
- meta: {
2983
- type: 'object',
2984
- description:
2985
- 'Metadata (corresponds to Beancount meta field). Contains source, confidence, note, etc.',
2986
- example: {
2987
- source: 'MANUAL',
2988
- note: 'User-defined price',
2989
- confidence: 1
3167
+ byCurrency: {
3168
+ description: 'Multi-currency breakdown for this point',
3169
+ type: 'array',
3170
+ items: {
3171
+ $ref: '#/components/schemas/CurrencyBalanceDto'
2990
3172
  }
3173
+ }
3174
+ },
3175
+ required: ['date', 'value']
3176
+ } as const;
3177
+
3178
+ export const $TrendSummaryDto = {
3179
+ type: 'object',
3180
+ properties: {
3181
+ startValue: {
3182
+ type: 'string',
3183
+ description: 'Value at start of period',
3184
+ example: '450000.00'
2991
3185
  },
2992
- createdAt: {
2993
- format: 'date-time',
3186
+ endValue: {
2994
3187
  type: 'string',
2995
- description: 'Creation timestamp',
2996
- example: '2024-11-03T10:00:00Z'
3188
+ description: 'Value at end of period',
3189
+ example: '500000.00'
2997
3190
  },
2998
- updatedAt: {
2999
- format: 'date-time',
3191
+ totalChange: {
3000
3192
  type: 'string',
3001
- description: 'Last update timestamp',
3002
- example: '2024-11-03T10:00:00Z'
3193
+ description: 'Total change over period',
3194
+ example: '50000.00'
3195
+ },
3196
+ totalChangePercentage: {
3197
+ type: 'string',
3198
+ description: 'Total change percentage',
3199
+ example: '+11.11%'
3003
3200
  }
3004
3201
  },
3005
- required: [
3006
- 'id',
3007
- 'userId',
3008
- 'currency',
3009
- 'quoteCurrency',
3010
- 'amount',
3011
- 'date',
3012
- 'meta',
3013
- 'createdAt',
3014
- 'updatedAt'
3015
- ]
3202
+ required: ['startValue', 'endValue', 'totalChange', 'totalChangePercentage']
3016
3203
  } as const;
3017
3204
 
3018
- export const $PriceListResponseDto = {
3205
+ export const $MultiCurrencyPointDto = {
3019
3206
  type: 'object',
3020
3207
  properties: {
3021
- items: {
3022
- description: 'List of prices',
3208
+ date: {
3209
+ type: 'string',
3210
+ description: 'Date in YYYY-MM-DD format',
3211
+ example: '2024-06-15'
3212
+ },
3213
+ byCurrency: {
3214
+ description: 'Balances by currency',
3023
3215
  type: 'array',
3024
3216
  items: {
3025
- $ref: '#/components/schemas/PriceResponseDto'
3217
+ $ref: '#/components/schemas/CurrencyBalanceDto'
3026
3218
  }
3027
- },
3028
- total: {
3029
- type: 'number',
3030
- description: 'Total number of prices',
3031
- example: 42
3032
3219
  }
3033
3220
  },
3034
- required: ['items', 'total']
3221
+ required: ['date', 'byCurrency']
3035
3222
  } as const;
3036
3223
 
3037
- export const $UpdateBeanPriceDto = {
3224
+ export const $PortfolioTrendsResponseDto = {
3038
3225
  type: 'object',
3039
3226
  properties: {
3040
- currency: {
3041
- type: 'string',
3042
- description: 'Currency being priced'
3227
+ series: {
3228
+ description: 'Time series data points',
3229
+ type: 'array',
3230
+ items: {
3231
+ $ref: '#/components/schemas/TimeSeriesPointDto'
3232
+ }
3043
3233
  },
3044
- quoteCurrency: {
3234
+ summary: {
3235
+ description: 'Period summary',
3236
+ allOf: [
3237
+ {
3238
+ $ref: '#/components/schemas/TrendSummaryDto'
3239
+ }
3240
+ ]
3241
+ },
3242
+ period: {
3045
3243
  type: 'string',
3046
- description: 'Quote currency (pricing currency)'
3244
+ description: 'Period requested',
3245
+ example: '6m'
3047
3246
  },
3048
- amount: {
3049
- type: 'number',
3050
- description: 'Price amount (MUST be >= 0 per Beancount spec)',
3051
- minimum: 0
3247
+ granularity: {
3248
+ type: 'string',
3249
+ description: 'Data granularity',
3250
+ example: 'month'
3052
3251
  },
3053
- date: {
3252
+ currency: {
3054
3253
  type: 'string',
3055
- description: 'Price date (ISO 8601 format)'
3254
+ description: 'Base currency for converted values',
3255
+ example: 'CNY'
3056
3256
  },
3057
- metadata: {
3058
- type: 'object',
3059
- description: 'Metadata'
3257
+ byCurrency: {
3258
+ description:
3259
+ 'Multi-currency time series (each point has currency breakdown)',
3260
+ type: 'array',
3261
+ items: {
3262
+ $ref: '#/components/schemas/MultiCurrencyPointDto'
3263
+ }
3264
+ },
3265
+ warnings: {
3266
+ description: 'Exchange rate warnings',
3267
+ type: 'array',
3268
+ items: {
3269
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
3270
+ }
3060
3271
  }
3061
- }
3272
+ },
3273
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
3062
3274
  } as const;
3063
3275
 
3064
- export const $CreateRecurringRuleDto = {
3276
+ export const $CashFlowPointDto = {
3065
3277
  type: 'object',
3066
3278
  properties: {
3067
- name: {
3068
- type: 'string',
3069
- description: 'Rule name (unique per user)',
3070
- maxLength: 100
3071
- },
3072
- icon: {
3073
- type: 'string',
3074
- description: 'Icon emoji',
3075
- maxLength: 10
3076
- },
3077
- frequency: {
3279
+ month: {
3078
3280
  type: 'string',
3079
- description: 'Recurring frequency',
3080
- enum: [
3081
- 'WEEKLY',
3082
- 'BIWEEKLY',
3083
- 'MONTHLY',
3084
- 'BIMONTHLY',
3085
- 'QUARTERLY',
3086
- 'YEARLY',
3087
- 'CUSTOM'
3088
- ]
3089
- },
3090
- expectedAmount: {
3091
- type: 'number',
3092
- description: 'Expected amount (positive number)',
3093
- minimum: 0
3094
- },
3095
- expectedDay: {
3096
- type: 'number',
3097
- description: 'Expected day of month (1-31)',
3098
- minimum: 1,
3099
- maximum: 31
3100
- },
3101
- customIntervalDays: {
3102
- type: 'number',
3103
- description: 'Custom interval in days (required for CUSTOM frequency)',
3104
- minimum: 1
3281
+ description: 'Month key (YYYY-MM)',
3282
+ example: '2024-03'
3105
3283
  },
3106
- currency: {
3284
+ income: {
3107
3285
  type: 'string',
3108
- description: 'Currency code',
3109
- default: 'CNY',
3110
- maxLength: 10
3286
+ description: 'Income in base currency (absolute, converted)',
3287
+ example: '10000.00'
3111
3288
  },
3112
- matchPayeePattern: {
3289
+ expense: {
3113
3290
  type: 'string',
3114
- description: 'Payee matching pattern (supports wildcards)',
3115
- maxLength: 200
3116
- },
3117
- matchAmountTolerance: {
3118
- type: 'number',
3119
- description: 'Amount tolerance percentage (0-1)',
3120
- default: 0.075,
3121
- minimum: 0,
3122
- maximum: 1
3291
+ description: 'Expense in base currency (absolute, converted)',
3292
+ example: '5000.00'
3123
3293
  },
3124
- defaultExpenseAccount: {
3294
+ netSavings: {
3125
3295
  type: 'string',
3126
- description: 'Default expense account for auto-create',
3127
- maxLength: 200
3128
- },
3129
- defaultPaymentAccount: {
3296
+ description: 'netSavings = income − expense (savings positive)',
3297
+ example: '5000.00'
3298
+ }
3299
+ },
3300
+ required: ['month', 'income', 'expense', 'netSavings']
3301
+ } as const;
3302
+
3303
+ export const $CashFlowTrendSummaryDto = {
3304
+ type: 'object',
3305
+ properties: {
3306
+ totalIncome: {
3130
3307
  type: 'string',
3131
- description: 'Default payment account for auto-create',
3132
- maxLength: 200
3308
+ description: 'Total income across the period',
3309
+ example: '60000.00'
3133
3310
  },
3134
- defaultPayee: {
3311
+ totalExpense: {
3135
3312
  type: 'string',
3136
- description: 'Default payee for auto-create',
3137
- maxLength: 200
3138
- },
3139
- autoCreate: {
3140
- type: 'boolean',
3141
- description: 'Auto-create transaction when expected date arrives',
3142
- default: false
3313
+ description: 'Total expense across the period',
3314
+ example: '30000.00'
3143
3315
  },
3144
- startDate: {
3316
+ totalNetSavings: {
3145
3317
  type: 'string',
3146
- description: 'Rule start date (ISO format)'
3318
+ description: 'income − expense across the period',
3319
+ example: '30000.00'
3147
3320
  },
3148
- endDate: {
3321
+ averageMonthlyNetSavings: {
3149
3322
  type: 'string',
3150
- description: 'Rule end date (ISO format)'
3323
+ description:
3324
+ 'totalNetSavings divided by the window length (N months, incl. zero-filled)',
3325
+ example: '5000.00'
3151
3326
  }
3152
3327
  },
3153
3328
  required: [
3154
- 'name',
3155
- 'frequency',
3156
- 'expectedAmount',
3157
- 'currency',
3158
- 'matchAmountTolerance',
3159
- 'autoCreate'
3329
+ 'totalIncome',
3330
+ 'totalExpense',
3331
+ 'totalNetSavings',
3332
+ 'averageMonthlyNetSavings'
3160
3333
  ]
3161
3334
  } as const;
3162
3335
 
3163
- export const $RecurringRuleResponseDto = {
3336
+ export const $CashFlowTrendsResponseDto = {
3164
3337
  type: 'object',
3165
3338
  properties: {
3166
- id: {
3167
- type: 'string',
3168
- description: 'Rule ID'
3339
+ series: {
3340
+ description:
3341
+ 'Monthly cash-flow series (fixed N-month window, zero-filled)',
3342
+ type: 'array',
3343
+ items: {
3344
+ $ref: '#/components/schemas/CashFlowPointDto'
3345
+ }
3169
3346
  },
3170
- userId: {
3171
- type: 'string',
3172
- description: 'User ID'
3347
+ summary: {
3348
+ description: 'Period totals',
3349
+ allOf: [
3350
+ {
3351
+ $ref: '#/components/schemas/CashFlowTrendSummaryDto'
3352
+ }
3353
+ ]
3173
3354
  },
3174
- name: {
3355
+ period: {
3175
3356
  type: 'string',
3176
- description: 'Rule name'
3177
- },
3178
- icon: {
3179
- type: 'object',
3180
- description: 'Icon emoji'
3357
+ description: 'Period requested',
3358
+ example: '6m'
3181
3359
  },
3182
- frequency: {
3360
+ granularity: {
3183
3361
  type: 'string',
3184
- description: 'Recurring frequency'
3185
- },
3186
- expectedAmount: {
3187
- type: 'number',
3188
- description: 'Expected amount'
3189
- },
3190
- expectedDay: {
3191
- type: 'object',
3192
- description: 'Expected day of month'
3362
+ description: 'Data granularity (v1 returns month buckets)',
3363
+ example: 'month'
3193
3364
  },
3194
- customIntervalDays: {
3195
- type: 'object',
3196
- description: 'Custom interval in days'
3365
+ currency: {
3366
+ type: 'string',
3367
+ description: 'Base currency for converted values',
3368
+ example: 'CNY'
3197
3369
  },
3370
+ warnings: {
3371
+ description: 'Exchange rate warnings (e.g. missing rate for a currency)',
3372
+ type: 'array',
3373
+ items: {
3374
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
3375
+ }
3376
+ }
3377
+ },
3378
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
3379
+ } as const;
3380
+
3381
+ export const $GenerateSnapshotBody = {
3382
+ type: 'object',
3383
+ properties: {}
3384
+ } as const;
3385
+
3386
+ export const $GenerateSnapshotResponse = {
3387
+ type: 'object',
3388
+ properties: {}
3389
+ } as const;
3390
+
3391
+ export const $BackfillSnapshotsBody = {
3392
+ type: 'object',
3393
+ properties: {}
3394
+ } as const;
3395
+
3396
+ export const $BackfillSnapshotsResponse = {
3397
+ type: 'object',
3398
+ properties: {}
3399
+ } as const;
3400
+
3401
+ export const $CreateBeanPriceDto = {
3402
+ type: 'object',
3403
+ properties: {
3198
3404
  currency: {
3199
3405
  type: 'string',
3200
- description: 'Currency code'
3406
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
3407
+ example: 'USD'
3201
3408
  },
3202
- matchPayeePattern: {
3203
- type: 'object',
3204
- description: 'Payee matching pattern'
3409
+ quoteCurrency: {
3410
+ type: 'string',
3411
+ description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
3412
+ example: 'CNY'
3205
3413
  },
3206
- matchAmountTolerance: {
3414
+ amount: {
3207
3415
  type: 'number',
3208
- description: 'Amount tolerance percentage'
3416
+ description:
3417
+ 'Price amount (MUST be >= 0 per Beancount spec, supports up to 15 decimal places). Zero allowed for conversion entries, negative strictly prohibited.',
3418
+ example: 175.5,
3419
+ minimum: 0
3209
3420
  },
3210
- defaultExpenseAccount: {
3211
- type: 'object',
3212
- description: 'Default expense account'
3421
+ date: {
3422
+ type: 'string',
3423
+ description: 'Price date (ISO 8601 format)',
3424
+ example: '2024-11-05'
3213
3425
  },
3214
- defaultPaymentAccount: {
3426
+ metadata: {
3215
3427
  type: 'object',
3216
- description: 'Default payment account'
3428
+ description:
3429
+ 'Metadata (validated by Zod schema, max field lengths enforced)',
3430
+ example: {
3431
+ source: 'MANUAL',
3432
+ note: 'Bank valuation report',
3433
+ confidence: 0.95
3434
+ }
3435
+ }
3436
+ },
3437
+ required: ['currency', 'quoteCurrency', 'amount', 'date']
3438
+ } as const;
3439
+
3440
+ export const $PriceResponseDto = {
3441
+ type: 'object',
3442
+ properties: {
3443
+ id: {
3444
+ type: 'string',
3445
+ description: 'Unique identifier',
3446
+ example: 'uuid-123-456'
3217
3447
  },
3218
- defaultPayee: {
3219
- type: 'object',
3220
- description: 'Default payee'
3448
+ userId: {
3449
+ type: 'string',
3450
+ description: 'User ID (owner of the price)',
3451
+ example: 'user-123'
3221
3452
  },
3222
- isActive: {
3223
- type: 'boolean',
3224
- description: 'Whether rule is active'
3453
+ currency: {
3454
+ type: 'string',
3455
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
3456
+ example: 'BTC'
3225
3457
  },
3226
- startDate: {
3458
+ quoteCurrency: {
3227
3459
  type: 'string',
3228
- description: 'Rule start date (YYYY-MM-DD)'
3460
+ description: 'Quote currency (pricing currency, e.g., USD, CNY)',
3461
+ example: 'USD'
3229
3462
  },
3230
- endDate: {
3231
- type: 'object',
3232
- description: 'Rule end date (YYYY-MM-DD)'
3463
+ amount: {
3464
+ type: 'number',
3465
+ description:
3466
+ 'Price amount (corresponds to Beancount Amount.number). Supports up to 15 decimal places.',
3467
+ example: 50000
3233
3468
  },
3234
- autoCreate: {
3235
- type: 'boolean',
3236
- description: 'Auto-create transaction on expected date'
3469
+ date: {
3470
+ type: 'string',
3471
+ description:
3472
+ 'Price date (ISO 8601 format). Represents the date this price was valid.',
3473
+ example: '2024-01-01',
3474
+ format: 'date'
3237
3475
  },
3238
- lastOccurrence: {
3476
+ meta: {
3239
3477
  type: 'object',
3240
- description: 'Last matched occurrence date (YYYY-MM-DD)'
3241
- },
3242
- totalCount: {
3243
- type: 'number',
3244
- description: 'Total matched transactions count'
3478
+ description:
3479
+ 'Metadata (corresponds to Beancount meta field). Contains source, confidence, note, etc.',
3480
+ example: {
3481
+ source: 'MANUAL',
3482
+ note: 'User-defined price',
3483
+ confidence: 1
3484
+ }
3245
3485
  },
3246
3486
  createdAt: {
3247
3487
  format: 'date-time',
3248
3488
  type: 'string',
3249
- description: 'Created at timestamp'
3489
+ description: 'Creation timestamp',
3490
+ example: '2024-11-03T10:00:00Z'
3250
3491
  },
3251
3492
  updatedAt: {
3252
3493
  format: 'date-time',
3253
3494
  type: 'string',
3254
- description: 'Updated at timestamp'
3495
+ description: 'Last update timestamp',
3496
+ example: '2024-11-03T10:00:00Z'
3255
3497
  }
3256
3498
  },
3257
3499
  required: [
3258
3500
  'id',
3259
3501
  'userId',
3260
- 'name',
3261
- 'frequency',
3262
- 'expectedAmount',
3263
3502
  'currency',
3264
- 'matchAmountTolerance',
3265
- 'isActive',
3266
- 'startDate',
3267
- 'autoCreate',
3268
- 'totalCount',
3503
+ 'quoteCurrency',
3504
+ 'amount',
3505
+ 'date',
3506
+ 'meta',
3269
3507
  'createdAt',
3270
3508
  'updatedAt'
3271
3509
  ]
3272
3510
  } as const;
3273
3511
 
3274
- export const $CreateRuleFromTransactionDto = {
3512
+ export const $PriceListResponseDto = {
3275
3513
  type: 'object',
3276
3514
  properties: {
3277
- frequency: {
3278
- type: 'string',
3279
- description: 'Recurring frequency',
3280
- enum: [
3281
- 'WEEKLY',
3282
- 'BIWEEKLY',
3283
- 'MONTHLY',
3284
- 'BIMONTHLY',
3285
- 'QUARTERLY',
3286
- 'YEARLY',
3287
- 'CUSTOM'
3288
- ],
3289
- example: 'MONTHLY'
3290
- },
3291
- name: {
3292
- type: 'string',
3293
- description: 'Optional name override (default: transaction payee)',
3294
- maxLength: 100
3515
+ items: {
3516
+ description: 'List of prices',
3517
+ type: 'array',
3518
+ items: {
3519
+ $ref: '#/components/schemas/PriceResponseDto'
3520
+ }
3295
3521
  },
3296
- icon: {
3297
- type: 'string',
3298
- description: 'Optional icon emoji',
3299
- maxLength: 10
3522
+ total: {
3523
+ type: 'number',
3524
+ description: 'Total number of prices',
3525
+ example: 42
3300
3526
  }
3301
3527
  },
3302
- required: ['frequency']
3528
+ required: ['items', 'total']
3303
3529
  } as const;
3304
3530
 
3305
- export const $RecurringRuleWithStatsResponseDto = {
3531
+ export const $UpdateBeanPriceDto = {
3306
3532
  type: 'object',
3307
3533
  properties: {
3308
- id: {
3534
+ currency: {
3309
3535
  type: 'string',
3310
- description: 'Rule ID'
3536
+ description: 'Currency being priced'
3311
3537
  },
3312
- userId: {
3538
+ quoteCurrency: {
3313
3539
  type: 'string',
3314
- description: 'User ID'
3540
+ description: 'Quote currency (pricing currency)'
3315
3541
  },
3316
- name: {
3542
+ amount: {
3543
+ type: 'number',
3544
+ description: 'Price amount (MUST be >= 0 per Beancount spec)',
3545
+ minimum: 0
3546
+ },
3547
+ date: {
3317
3548
  type: 'string',
3318
- description: 'Rule name'
3549
+ description: 'Price date (ISO 8601 format)'
3319
3550
  },
3320
- icon: {
3551
+ metadata: {
3321
3552
  type: 'object',
3322
- description: 'Icon emoji'
3323
- },
3324
- frequency: {
3553
+ description: 'Metadata'
3554
+ }
3555
+ }
3556
+ } as const;
3557
+
3558
+ export const $DeleteOwnUserDto = {
3559
+ type: 'object',
3560
+ properties: {
3561
+ accessToken: {
3325
3562
  type: 'string',
3326
- description: 'Recurring frequency'
3327
- },
3328
- expectedAmount: {
3329
- type: 'number',
3330
- description: 'Expected amount'
3563
+ description: 'Access token for user verification',
3564
+ example: 'abc123xyz'
3565
+ }
3566
+ },
3567
+ required: ['accessToken']
3568
+ } as const;
3569
+
3570
+ export const $UserSettingsResponseDto = {
3571
+ type: 'object',
3572
+ properties: {
3573
+ baseCurrency: {
3574
+ type: 'string',
3575
+ description:
3576
+ '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).',
3577
+ example: 'USD',
3578
+ nullable: true
3579
+ }
3580
+ },
3581
+ required: ['baseCurrency']
3582
+ } as const;
3583
+
3584
+ export const $UserResponseDto = {
3585
+ type: 'object',
3586
+ properties: {
3587
+ id: {
3588
+ type: 'string',
3589
+ description: 'User ID'
3331
3590
  },
3332
- expectedDay: {
3333
- type: 'object',
3334
- description: 'Expected day of month'
3591
+ role: {
3592
+ type: 'string',
3593
+ description: 'Assigned user role'
3335
3594
  },
3336
- customIntervalDays: {
3337
- type: 'object',
3338
- description: 'Custom interval in days'
3595
+ permissions: {
3596
+ description: 'Permission strings',
3597
+ type: 'array',
3598
+ items: {
3599
+ type: 'string'
3600
+ }
3339
3601
  },
3340
- currency: {
3602
+ settings: {
3603
+ description: 'User settings',
3604
+ allOf: [
3605
+ {
3606
+ $ref: '#/components/schemas/UserSettingsResponseDto'
3607
+ }
3608
+ ]
3609
+ }
3610
+ },
3611
+ required: ['id', 'role', 'permissions', 'settings']
3612
+ } as const;
3613
+
3614
+ export const $SignupDto = {
3615
+ type: 'object',
3616
+ properties: {
3617
+ turnstileToken: {
3341
3618
  type: 'string',
3342
- description: 'Currency code'
3619
+ description:
3620
+ 'Cloudflare Turnstile verification token (optional when Turnstile disabled)',
3621
+ example: '0.abc123def456...'
3622
+ }
3623
+ }
3624
+ } as const;
3625
+
3626
+ export const $SignupResponseDto = {
3627
+ type: 'object',
3628
+ properties: {
3629
+ authToken: {
3630
+ type: 'string',
3631
+ description: 'JWT auth token',
3632
+ example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
3343
3633
  },
3344
- matchPayeePattern: {
3345
- type: 'object',
3346
- description: 'Payee matching pattern'
3634
+ accessToken: {
3635
+ type: 'string',
3636
+ description: 'Auto-generated access token'
3347
3637
  },
3348
- matchAmountTolerance: {
3638
+ role: {
3639
+ type: 'string',
3640
+ description: 'Assigned user role',
3641
+ enum: ['USER', 'ADMIN', 'DEMO', 'INACTIVE', 'PAID', 'OPS']
3642
+ }
3643
+ },
3644
+ required: ['authToken', 'accessToken', 'role']
3645
+ } as const;
3646
+
3647
+ export const $UpdateUserSettingDto = {
3648
+ type: 'object',
3649
+ properties: {
3650
+ secId: {
3349
3651
  type: 'number',
3350
- description: 'Amount tolerance percentage'
3652
+ description: 'Security ID'
3351
3653
  },
3352
- defaultExpenseAccount: {
3353
- type: 'object',
3354
- description: 'Default expense account'
3654
+ annualInterestRate: {
3655
+ type: 'number',
3656
+ description: 'Annual interest rate',
3657
+ example: 0.05
3355
3658
  },
3356
- defaultPaymentAccount: {
3357
- type: 'object',
3358
- description: 'Default payment account'
3659
+ currency: {
3660
+ type: 'string',
3661
+ description: 'Currency code',
3662
+ example: 'USD'
3359
3663
  },
3360
- defaultPayee: {
3361
- type: 'object',
3362
- description: 'Default payee'
3664
+ baseCurrency: {
3665
+ type: 'string',
3666
+ description: 'Base currency code',
3667
+ example: 'USD'
3363
3668
  },
3364
- isActive: {
3365
- type: 'boolean',
3366
- description: 'Whether rule is active'
3669
+ benchmark: {
3670
+ type: 'string',
3671
+ description: 'Benchmark symbol',
3672
+ example: 'SPY'
3367
3673
  },
3368
- startDate: {
3674
+ colorScheme: {
3369
3675
  type: 'string',
3370
- description: 'Rule start date (YYYY-MM-DD)'
3676
+ description: 'Color scheme',
3677
+ enum: ['DARK', 'LIGHT']
3371
3678
  },
3372
- endDate: {
3373
- type: 'object',
3374
- description: 'Rule end date (YYYY-MM-DD)'
3679
+ dateRange: {
3680
+ type: 'string',
3681
+ description: 'Date range filter',
3682
+ example: '1y'
3375
3683
  },
3376
- autoCreate: {
3377
- type: 'boolean',
3378
- description: 'Auto-create transaction on expected date'
3684
+ emergencyFund: {
3685
+ type: 'number',
3686
+ description: 'Emergency fund amount',
3687
+ example: 10000
3379
3688
  },
3380
- lastOccurrence: {
3381
- type: 'object',
3382
- description: 'Last matched occurrence date (YYYY-MM-DD)'
3689
+ 'filters.accounts': {
3690
+ description: 'Account filter IDs',
3691
+ type: 'array',
3692
+ items: {
3693
+ type: 'string'
3694
+ }
3383
3695
  },
3384
- totalCount: {
3385
- type: 'number',
3386
- description: 'Total matched transactions count'
3696
+ 'filters.assetClasses': {
3697
+ description: 'Asset class filters',
3698
+ type: 'array',
3699
+ items: {
3700
+ type: 'string'
3701
+ }
3387
3702
  },
3388
- createdAt: {
3389
- format: 'date-time',
3703
+ 'filters.dataSource': {
3390
3704
  type: 'string',
3391
- description: 'Created at timestamp'
3705
+ description: 'Data source filter'
3392
3706
  },
3393
- updatedAt: {
3394
- format: 'date-time',
3707
+ 'filters.symbol': {
3395
3708
  type: 'string',
3396
- description: 'Updated at timestamp'
3709
+ description: 'Symbol filter'
3397
3710
  },
3398
- pendingCount: {
3399
- type: 'number',
3400
- description: 'Number of pending expected transactions'
3711
+ 'filters.tags': {
3712
+ description: 'Tag filters',
3713
+ type: 'array',
3714
+ items: {
3715
+ type: 'string'
3716
+ }
3401
3717
  },
3402
- overdueCount: {
3403
- type: 'number',
3404
- description: 'Number of overdue expected transactions'
3718
+ isExperimentalFeatures: {
3719
+ type: 'boolean',
3720
+ description: 'Enable experimental features'
3405
3721
  },
3406
- nextExpectedDate: {
3407
- type: 'object',
3408
- description: 'Next expected date (YYYY-MM-DD)'
3722
+ isRestrictedView: {
3723
+ type: 'boolean',
3724
+ description: 'Enable restricted view mode'
3409
3725
  },
3410
- totalAmount: {
3411
- type: 'number',
3412
- description: 'Total amount of all matched transactions'
3726
+ language: {
3727
+ type: 'string',
3728
+ description: 'Language code',
3729
+ example: 'en'
3413
3730
  },
3414
- averageAmount: {
3415
- type: 'number',
3416
- description: 'Average amount per transaction'
3731
+ locale: {
3732
+ type: 'string',
3733
+ description: 'Locale code',
3734
+ example: 'en-US'
3417
3735
  },
3418
- transactionCount: {
3736
+ projectedTotalAmount: {
3419
3737
  type: 'number',
3420
- description: 'Number of matched transactions'
3421
- },
3422
- firstDate: {
3423
- type: 'object',
3424
- description: 'First matched transaction date (YYYY-MM-DD)'
3738
+ description: 'Projected total amount',
3739
+ example: 1000000
3425
3740
  },
3426
- lastDate: {
3427
- type: 'object',
3428
- description: 'Last matched transaction date (YYYY-MM-DD)'
3741
+ retirementDate: {
3742
+ type: 'string',
3743
+ description: 'Retirement date in ISO 8601 format',
3744
+ example: '2050-01-01'
3429
3745
  },
3430
- variance: {
3746
+ savingsRate: {
3431
3747
  type: 'number',
3432
- description: 'Amount variance (standard deviation squared)'
3748
+ description: 'Savings rate percentage',
3749
+ example: 0.2
3433
3750
  },
3434
- upcomingCount: {
3435
- type: 'number',
3436
- description: 'Number of upcoming expected transactions'
3751
+ viewMode: {
3752
+ type: 'string',
3753
+ description: 'View mode',
3754
+ enum: ['DEFAULT', 'ZEN']
3755
+ }
3756
+ }
3757
+ } as const;
3758
+
3759
+ export const $UpdatePropertyDto = {
3760
+ type: 'object',
3761
+ properties: {
3762
+ value: {
3763
+ type: 'string',
3764
+ description: 'Property value'
3437
3765
  }
3438
3766
  },
3439
- required: [
3440
- 'id',
3441
- 'userId',
3442
- 'name',
3443
- 'frequency',
3444
- 'expectedAmount',
3445
- 'currency',
3446
- 'matchAmountTolerance',
3447
- 'isActive',
3448
- 'startDate',
3449
- 'autoCreate',
3450
- 'totalCount',
3451
- 'createdAt',
3452
- 'updatedAt',
3453
- 'pendingCount',
3454
- 'overdueCount',
3455
- 'totalAmount',
3456
- 'averageAmount',
3457
- 'transactionCount',
3458
- 'variance',
3459
- 'upcomingCount'
3460
- ]
3767
+ required: ['value']
3461
3768
  } as const;
3462
3769
 
3463
- export const $UpdateRecurringRuleDto = {
3770
+ export const $CreateRecurringRuleDto = {
3464
3771
  type: 'object',
3465
3772
  properties: {
3466
3773
  name: {
3467
3774
  type: 'string',
3468
- description: 'Rule name',
3775
+ description: 'Rule name (unique per user)',
3469
3776
  maxLength: 100
3470
3777
  },
3471
3778
  icon: {
@@ -3488,7 +3795,7 @@ export const $UpdateRecurringRuleDto = {
3488
3795
  },
3489
3796
  expectedAmount: {
3490
3797
  type: 'number',
3491
- description: 'Expected amount',
3798
+ description: 'Expected amount (positive number)',
3492
3799
  minimum: 0
3493
3800
  },
3494
3801
  expectedDay: {
@@ -3499,7 +3806,7 @@ export const $UpdateRecurringRuleDto = {
3499
3806
  },
3500
3807
  customIntervalDays: {
3501
3808
  type: 'number',
3502
- description: 'Custom interval in days',
3809
+ description: 'Custom interval in days (required for CUSTOM frequency)',
3503
3810
  minimum: 1
3504
3811
  },
3505
3812
  currency: {
@@ -3509,118 +3816,136 @@ export const $UpdateRecurringRuleDto = {
3509
3816
  },
3510
3817
  matchPayeePattern: {
3511
3818
  type: 'string',
3512
- description: 'Payee matching pattern',
3819
+ description: 'Payee matching pattern (supports wildcards)',
3513
3820
  maxLength: 200
3514
3821
  },
3515
3822
  matchAmountTolerance: {
3516
3823
  type: 'number',
3517
3824
  description: 'Amount tolerance percentage (0-1)',
3825
+ default: 0.075,
3518
3826
  minimum: 0,
3519
3827
  maximum: 1
3520
3828
  },
3521
3829
  defaultExpenseAccount: {
3522
3830
  type: 'string',
3523
- description: 'Default expense account',
3831
+ description: 'Default expense account for auto-create',
3524
3832
  maxLength: 200
3525
3833
  },
3526
3834
  defaultPaymentAccount: {
3527
3835
  type: 'string',
3528
- description: 'Default payment account',
3836
+ description: 'Default payment account for auto-create',
3529
3837
  maxLength: 200
3530
3838
  },
3531
3839
  defaultPayee: {
3532
3840
  type: 'string',
3533
- description: 'Default payee',
3841
+ description: 'Default payee for auto-create',
3534
3842
  maxLength: 200
3535
3843
  },
3536
3844
  autoCreate: {
3537
3845
  type: 'boolean',
3538
- description: 'Auto-create transaction'
3846
+ description: 'Auto-create transaction when expected date arrives',
3847
+ default: false
3539
3848
  },
3540
- isActive: {
3541
- type: 'boolean',
3542
- description: 'Rule active status'
3849
+ startDate: {
3850
+ type: 'string',
3851
+ description: 'Rule start date (ISO format)'
3543
3852
  },
3544
3853
  endDate: {
3545
3854
  type: 'string',
3546
3855
  description: 'Rule end date (ISO format)'
3547
3856
  }
3548
- }
3857
+ },
3858
+ required: [
3859
+ 'name',
3860
+ 'frequency',
3861
+ 'expectedAmount',
3862
+ 'matchAmountTolerance',
3863
+ 'autoCreate'
3864
+ ]
3549
3865
  } as const;
3550
3866
 
3551
- export const $ExpectedTransactionRuleDto = {
3867
+ export const $RecurringRuleResponseDto = {
3552
3868
  type: 'object',
3553
3869
  properties: {
3870
+ id: {
3871
+ type: 'string',
3872
+ description: 'Rule ID'
3873
+ },
3874
+ userId: {
3875
+ type: 'string',
3876
+ description: 'User ID'
3877
+ },
3554
3878
  name: {
3555
3879
  type: 'string',
3556
3880
  description: 'Rule name'
3557
3881
  },
3558
3882
  icon: {
3559
- type: 'object',
3560
- description: 'Rule icon'
3883
+ type: 'string',
3884
+ description: 'Icon emoji'
3561
3885
  },
3562
3886
  frequency: {
3563
3887
  type: 'string',
3564
- description: 'Rule frequency'
3888
+ description: 'Recurring frequency'
3889
+ },
3890
+ expectedAmount: {
3891
+ type: 'number',
3892
+ description: 'Expected amount'
3893
+ },
3894
+ expectedDay: {
3895
+ type: 'number',
3896
+ description: 'Expected day of month'
3897
+ },
3898
+ customIntervalDays: {
3899
+ type: 'number',
3900
+ description: 'Custom interval in days'
3565
3901
  },
3566
3902
  currency: {
3567
3903
  type: 'string',
3568
3904
  description: 'Currency code'
3569
- }
3570
- },
3571
- required: ['name', 'frequency', 'currency']
3572
- } as const;
3573
-
3574
- export const $ExpectedTransactionResponseDto = {
3575
- type: 'object',
3576
- properties: {
3577
- id: {
3578
- type: 'string',
3579
- description: 'Expected transaction ID'
3580
3905
  },
3581
- userId: {
3906
+ matchPayeePattern: {
3582
3907
  type: 'string',
3583
- description: 'User ID'
3908
+ description: 'Payee matching pattern'
3584
3909
  },
3585
- ruleId: {
3586
- type: 'string',
3587
- description: 'Associated rule ID'
3910
+ matchAmountTolerance: {
3911
+ type: 'number',
3912
+ description: 'Amount tolerance percentage'
3588
3913
  },
3589
- expectedDate: {
3914
+ defaultExpenseAccount: {
3590
3915
  type: 'string',
3591
- description: 'Expected date (YYYY-MM-DD)'
3916
+ description: 'Default expense account'
3592
3917
  },
3593
- expectedAmount: {
3594
- type: 'number',
3595
- description: 'Expected amount'
3918
+ defaultPaymentAccount: {
3919
+ type: 'string',
3920
+ description: 'Default payment account'
3596
3921
  },
3597
- status: {
3922
+ defaultPayee: {
3598
3923
  type: 'string',
3599
- description: 'Status (PENDING, COMPLETED, SKIPPED)'
3924
+ description: 'Default payee'
3600
3925
  },
3601
- matchedTransactionId: {
3602
- type: 'object',
3603
- description: 'Matched transaction ID'
3926
+ isActive: {
3927
+ type: 'boolean',
3928
+ description: 'Whether rule is active'
3604
3929
  },
3605
- matchedAt: {
3606
- type: 'object',
3607
- description: 'Match timestamp (ISO 8601)'
3930
+ startDate: {
3931
+ type: 'string',
3932
+ description: 'Rule start date (YYYY-MM-DD)'
3608
3933
  },
3609
- matchConfidence: {
3610
- type: 'object',
3611
- description: 'Match confidence score (0-1)'
3934
+ endDate: {
3935
+ type: 'string',
3936
+ description: 'Rule end date (YYYY-MM-DD)'
3612
3937
  },
3613
- isOverdue: {
3938
+ autoCreate: {
3614
3939
  type: 'boolean',
3615
- description: 'Whether this expected transaction is overdue'
3940
+ description: 'Auto-create transaction on expected date'
3616
3941
  },
3617
- rule: {
3618
- description: 'Rule information',
3619
- allOf: [
3620
- {
3621
- $ref: '#/components/schemas/ExpectedTransactionRuleDto'
3622
- }
3623
- ]
3942
+ lastOccurrence: {
3943
+ type: 'string',
3944
+ description: 'Last matched occurrence date (YYYY-MM-DD)'
3945
+ },
3946
+ totalCount: {
3947
+ type: 'number',
3948
+ description: 'Total matched transactions count'
3624
3949
  },
3625
3950
  createdAt: {
3626
3951
  format: 'date-time',
@@ -3636,647 +3961,581 @@ export const $ExpectedTransactionResponseDto = {
3636
3961
  required: [
3637
3962
  'id',
3638
3963
  'userId',
3639
- 'ruleId',
3640
- 'expectedDate',
3964
+ 'name',
3965
+ 'frequency',
3641
3966
  'expectedAmount',
3642
- 'status',
3643
- 'isOverdue',
3644
- 'rule',
3967
+ 'currency',
3968
+ 'matchAmountTolerance',
3969
+ 'isActive',
3970
+ 'startDate',
3971
+ 'autoCreate',
3972
+ 'totalCount',
3645
3973
  'createdAt',
3646
3974
  'updatedAt'
3647
3975
  ]
3648
3976
  } as const;
3649
3977
 
3650
- export const $ExpectedTransactionListResponseDto = {
3978
+ export const $CreateRuleFromTransactionDto = {
3651
3979
  type: 'object',
3652
3980
  properties: {
3653
- items: {
3654
- type: 'array',
3655
- items: {
3656
- $ref: '#/components/schemas/ExpectedTransactionResponseDto'
3657
- }
3981
+ frequency: {
3982
+ type: 'string',
3983
+ description: 'Recurring frequency',
3984
+ enum: [
3985
+ 'WEEKLY',
3986
+ 'BIWEEKLY',
3987
+ 'MONTHLY',
3988
+ 'BIMONTHLY',
3989
+ 'QUARTERLY',
3990
+ 'YEARLY',
3991
+ 'CUSTOM'
3992
+ ],
3993
+ example: 'MONTHLY'
3658
3994
  },
3659
- total: {
3660
- type: 'number',
3661
- description: 'Total count'
3662
- }
3663
- },
3664
- required: ['items', 'total']
3665
- } as const;
3666
-
3667
- export const $ConfirmMatchDto = {
3668
- type: 'object',
3669
- properties: {
3670
- transactionId: {
3995
+ name: {
3671
3996
  type: 'string',
3672
- description: 'Transaction ID to match with'
3997
+ description: 'Optional name override (default: transaction payee)',
3998
+ maxLength: 100
3999
+ },
4000
+ icon: {
4001
+ type: 'string',
4002
+ description: 'Optional icon emoji',
4003
+ maxLength: 10
3673
4004
  }
3674
4005
  },
3675
- required: ['transactionId']
4006
+ required: ['frequency']
3676
4007
  } as const;
3677
4008
 
3678
- export const $EnterNowDto = {
4009
+ export const $RecurringRuleWithStatsResponseDto = {
3679
4010
  type: 'object',
3680
4011
  properties: {
3681
- expenseAccount: {
4012
+ id: {
4013
+ type: 'string',
4014
+ description: 'Rule ID'
4015
+ },
4016
+ userId: {
4017
+ type: 'string',
4018
+ description: 'User ID'
4019
+ },
4020
+ name: {
4021
+ type: 'string',
4022
+ description: 'Rule name'
4023
+ },
4024
+ icon: {
4025
+ type: 'string',
4026
+ description: 'Icon emoji'
4027
+ },
4028
+ frequency: {
4029
+ type: 'string',
4030
+ description: 'Recurring frequency'
4031
+ },
4032
+ expectedAmount: {
4033
+ type: 'number',
4034
+ description: 'Expected amount'
4035
+ },
4036
+ expectedDay: {
4037
+ type: 'number',
4038
+ description: 'Expected day of month'
4039
+ },
4040
+ customIntervalDays: {
4041
+ type: 'number',
4042
+ description: 'Custom interval in days'
4043
+ },
4044
+ currency: {
3682
4045
  type: 'string',
3683
- description:
3684
- 'Override expense account (uses rule default if not provided)',
3685
- maxLength: 200
4046
+ description: 'Currency code'
3686
4047
  },
3687
- paymentAccount: {
4048
+ matchPayeePattern: {
3688
4049
  type: 'string',
3689
- description:
3690
- 'Override payment account (uses rule default if not provided)',
3691
- maxLength: 200
4050
+ description: 'Payee matching pattern'
3692
4051
  },
3693
- amount: {
4052
+ matchAmountTolerance: {
3694
4053
  type: 'number',
3695
- description: 'Override amount (uses expected amount if not provided)',
3696
- minimum: 0
4054
+ description: 'Amount tolerance percentage'
3697
4055
  },
3698
- payee: {
4056
+ defaultExpenseAccount: {
3699
4057
  type: 'string',
3700
- description: 'Override payee (uses rule default if not provided)',
3701
- maxLength: 200
4058
+ description: 'Default expense account'
3702
4059
  },
3703
- narration: {
3704
- type: 'string',
3705
- description: 'Optional narration',
3706
- maxLength: 500
3707
- }
3708
- }
3709
- } as const;
3710
-
3711
- export const $ForecastItemDto = {
3712
- type: 'object',
3713
- properties: {
3714
- rule: {
4060
+ defaultPaymentAccount: {
3715
4061
  type: 'string',
3716
- description: 'Rule name',
3717
- example: 'Rent'
4062
+ description: 'Default payment account'
3718
4063
  },
3719
- ruleId: {
4064
+ defaultPayee: {
3720
4065
  type: 'string',
3721
- description: 'Rule ID',
3722
- example: 'clx123...'
4066
+ description: 'Default payee'
3723
4067
  },
3724
- amount: {
3725
- type: 'number',
3726
- description: 'Expected amount',
3727
- example: 3000
4068
+ isActive: {
4069
+ type: 'boolean',
4070
+ description: 'Whether rule is active'
3728
4071
  },
3729
- date: {
4072
+ startDate: {
3730
4073
  type: 'string',
3731
- description: 'Expected date (YYYY-MM-DD)',
3732
- example: '2024-04-01'
4074
+ description: 'Rule start date (YYYY-MM-DD)'
3733
4075
  },
3734
- icon: {
4076
+ endDate: {
3735
4077
  type: 'string',
3736
- description: 'Rule icon emoji',
3737
- example: '🏠',
3738
- nullable: true
4078
+ description: 'Rule end date (YYYY-MM-DD)'
3739
4079
  },
3740
- currency: {
3741
- type: 'string',
3742
- description: 'Currency code',
3743
- example: 'CNY'
3744
- }
3745
- },
3746
- required: ['rule', 'ruleId', 'amount', 'date', 'icon', 'currency']
3747
- } as const;
3748
-
3749
- export const $MonthlyForecastDto = {
3750
- type: 'object',
3751
- properties: {
3752
- month: {
4080
+ autoCreate: {
4081
+ type: 'boolean',
4082
+ description: 'Auto-create transaction on expected date'
4083
+ },
4084
+ lastOccurrence: {
3753
4085
  type: 'string',
3754
- description: 'Month (YYYY-MM)',
3755
- example: '2024-04'
4086
+ description: 'Last matched occurrence date (YYYY-MM-DD)'
3756
4087
  },
3757
- expectedOutflow: {
4088
+ totalCount: {
3758
4089
  type: 'number',
3759
- description: 'Total expected outflow for the month',
3760
- example: 8500
4090
+ description: 'Total matched transactions count'
3761
4091
  },
3762
- itemCount: {
4092
+ createdAt: {
4093
+ format: 'date-time',
4094
+ type: 'string',
4095
+ description: 'Created at timestamp'
4096
+ },
4097
+ updatedAt: {
4098
+ format: 'date-time',
4099
+ type: 'string',
4100
+ description: 'Updated at timestamp'
4101
+ },
4102
+ pendingCount: {
3763
4103
  type: 'number',
3764
- description: 'Number of expected transactions',
3765
- example: 3
4104
+ description: 'Number of pending expected transactions'
3766
4105
  },
3767
- byCurrency: {
3768
- type: 'object',
3769
- description: 'Breakdown by currency',
3770
- example: {
3771
- CNY: 8500,
3772
- USD: 100
3773
- }
4106
+ overdueCount: {
4107
+ type: 'number',
4108
+ description: 'Number of overdue expected transactions'
3774
4109
  },
3775
- items: {
3776
- description: 'Individual forecast items',
3777
- type: 'array',
3778
- items: {
3779
- $ref: '#/components/schemas/ForecastItemDto'
3780
- }
3781
- }
3782
- },
3783
- required: ['month', 'expectedOutflow', 'itemCount', 'byCurrency', 'items']
3784
- } as const;
3785
-
3786
- export const $ForecastResponseDto = {
3787
- type: 'object',
3788
- properties: {
3789
- forecast: {
3790
- description: 'Monthly forecast data',
3791
- type: 'array',
3792
- items: {
3793
- $ref: '#/components/schemas/MonthlyForecastDto'
3794
- }
4110
+ nextExpectedDate: {
4111
+ type: 'string',
4112
+ description: 'Next expected date (YYYY-MM-DD)'
3795
4113
  },
3796
- totalOutflow: {
4114
+ totalAmount: {
3797
4115
  type: 'number',
3798
- description: 'Total expected outflow across all months',
3799
- example: 25500
4116
+ description: 'Total amount of all matched transactions'
3800
4117
  },
3801
- totalByCurrency: {
3802
- type: 'object',
3803
- description: 'Total by currency across all months',
3804
- example: {
3805
- CNY: 25500,
3806
- USD: 300
3807
- }
4118
+ averageAmount: {
4119
+ type: 'number',
4120
+ description: 'Average amount per transaction'
3808
4121
  },
3809
- rulesCount: {
4122
+ transactionCount: {
3810
4123
  type: 'number',
3811
- description: 'Number of active recurring rules included',
3812
- example: 5
4124
+ description: 'Number of matched transactions'
3813
4125
  },
3814
- periodStart: {
4126
+ firstDate: {
3815
4127
  type: 'string',
3816
- description: 'Forecast period start date',
3817
- example: '2024-04-01'
4128
+ description: 'First matched transaction date (YYYY-MM-DD)'
3818
4129
  },
3819
- periodEnd: {
4130
+ lastDate: {
3820
4131
  type: 'string',
3821
- description: 'Forecast period end date',
3822
- example: '2024-06-30'
4132
+ description: 'Last matched transaction date (YYYY-MM-DD)'
4133
+ },
4134
+ variance: {
4135
+ type: 'number',
4136
+ description: 'Amount variance (standard deviation squared)'
4137
+ },
4138
+ upcomingCount: {
4139
+ type: 'number',
4140
+ description: 'Number of upcoming expected transactions'
3823
4141
  }
3824
4142
  },
3825
4143
  required: [
3826
- 'forecast',
3827
- 'totalOutflow',
3828
- 'totalByCurrency',
3829
- 'rulesCount',
3830
- 'periodStart',
3831
- 'periodEnd'
4144
+ 'id',
4145
+ 'userId',
4146
+ 'name',
4147
+ 'frequency',
4148
+ 'expectedAmount',
4149
+ 'currency',
4150
+ 'matchAmountTolerance',
4151
+ 'isActive',
4152
+ 'startDate',
4153
+ 'autoCreate',
4154
+ 'totalCount',
4155
+ 'createdAt',
4156
+ 'updatedAt',
4157
+ 'pendingCount',
4158
+ 'overdueCount',
4159
+ 'totalAmount',
4160
+ 'averageAmount',
4161
+ 'transactionCount',
4162
+ 'variance',
4163
+ 'upcomingCount'
3832
4164
  ]
3833
4165
  } as const;
3834
4166
 
3835
- export const $CurrencyBalanceDto = {
4167
+ export const $UpdateRecurringRuleDto = {
3836
4168
  type: 'object',
3837
4169
  properties: {
3838
- currency: {
4170
+ name: {
3839
4171
  type: 'string',
3840
- description: 'ISO 4217 currency code',
3841
- example: 'CNY'
4172
+ description: 'Rule name (unique per user)',
4173
+ maxLength: 100
3842
4174
  },
3843
- balance: {
4175
+ icon: {
3844
4176
  type: 'string',
3845
- description: 'Balance amount',
3846
- example: '500000.00'
3847
- }
3848
- },
3849
- required: ['currency', 'balance']
3850
- } as const;
3851
-
3852
- export const $TimeSeriesPointDto = {
3853
- type: 'object',
3854
- properties: {
3855
- date: {
4177
+ description: 'Icon emoji',
4178
+ maxLength: 10
4179
+ },
4180
+ frequency: {
3856
4181
  type: 'string',
3857
- description: 'Date in YYYY-MM-DD format',
3858
- example: '2024-06-15'
4182
+ description: 'Recurring frequency',
4183
+ enum: [
4184
+ 'WEEKLY',
4185
+ 'BIWEEKLY',
4186
+ 'MONTHLY',
4187
+ 'BIMONTHLY',
4188
+ 'QUARTERLY',
4189
+ 'YEARLY',
4190
+ 'CUSTOM'
4191
+ ]
4192
+ },
4193
+ expectedAmount: {
4194
+ type: 'number',
4195
+ description: 'Expected amount (positive number)',
4196
+ minimum: 0
4197
+ },
4198
+ expectedDay: {
4199
+ type: 'number',
4200
+ description: 'Expected day of month (1-31)',
4201
+ minimum: 1,
4202
+ maximum: 31
4203
+ },
4204
+ currency: {
4205
+ type: 'string',
4206
+ description: 'Currency code',
4207
+ maxLength: 10
3859
4208
  },
3860
- value: {
4209
+ matchPayeePattern: {
3861
4210
  type: 'string',
3862
- description: 'Value at this date (in base currency)',
3863
- example: '500000.00'
4211
+ description: 'Payee matching pattern (supports wildcards)',
4212
+ maxLength: 200
3864
4213
  },
3865
- change: {
3866
- type: 'object',
3867
- description: 'Change from previous point',
3868
- example: '5000.00'
4214
+ matchAmountTolerance: {
4215
+ type: 'number',
4216
+ description: 'Amount tolerance percentage (0-1)',
4217
+ default: 0.075,
4218
+ minimum: 0,
4219
+ maximum: 1
3869
4220
  },
3870
- assets: {
4221
+ defaultExpenseAccount: {
3871
4222
  type: 'string',
3872
- description: 'Total assets at this date (in base currency)',
3873
- example: '494338.00'
4223
+ description: 'Default expense account for auto-create',
4224
+ maxLength: 200
3874
4225
  },
3875
- liabilities: {
4226
+ defaultPaymentAccount: {
3876
4227
  type: 'string',
3877
- description: 'Total liabilities at this date (in base currency)',
3878
- example: '310098.00'
4228
+ description: 'Default payment account for auto-create',
4229
+ maxLength: 200
3879
4230
  },
3880
- byCurrency: {
3881
- description: 'Multi-currency breakdown for this point',
3882
- type: 'array',
3883
- items: {
3884
- $ref: '#/components/schemas/CurrencyBalanceDto'
3885
- }
3886
- }
3887
- },
3888
- required: ['date', 'value']
3889
- } as const;
3890
-
3891
- export const $TrendSummaryDto = {
3892
- type: 'object',
3893
- properties: {
3894
- startValue: {
4231
+ defaultPayee: {
3895
4232
  type: 'string',
3896
- description: 'Value at start of period',
3897
- example: '450000.00'
4233
+ description: 'Default payee for auto-create',
4234
+ maxLength: 200
3898
4235
  },
3899
- endValue: {
3900
- type: 'string',
3901
- description: 'Value at end of period',
3902
- example: '500000.00'
4236
+ autoCreate: {
4237
+ type: 'boolean',
4238
+ description: 'Auto-create transaction when expected date arrives',
4239
+ default: false
3903
4240
  },
3904
- totalChange: {
4241
+ endDate: {
3905
4242
  type: 'string',
3906
- description: 'Total change over period',
3907
- example: '50000.00'
4243
+ description: 'Rule end date (ISO format)'
3908
4244
  },
3909
- totalChangePercentage: {
3910
- type: 'string',
3911
- description: 'Total change percentage',
3912
- example: '+11.11%'
3913
- }
3914
- },
3915
- required: ['startValue', 'endValue', 'totalChange', 'totalChangePercentage']
3916
- } as const;
3917
-
3918
- export const $MultiCurrencyPointDto = {
3919
- type: 'object',
3920
- properties: {
3921
- date: {
3922
- type: 'string',
3923
- description: 'Date in YYYY-MM-DD format',
3924
- example: '2024-06-15'
4245
+ customIntervalDays: {
4246
+ type: 'number',
4247
+ description: 'Custom interval in days',
4248
+ minimum: 1
3925
4249
  },
3926
- byCurrency: {
3927
- description: 'Balances by currency',
3928
- type: 'array',
3929
- items: {
3930
- $ref: '#/components/schemas/CurrencyBalanceDto'
3931
- }
4250
+ isActive: {
4251
+ type: 'boolean',
4252
+ description: 'Rule active status'
3932
4253
  }
3933
- },
3934
- required: ['date', 'byCurrency']
4254
+ }
3935
4255
  } as const;
3936
4256
 
3937
- export const $PortfolioTrendsResponseDto = {
4257
+ export const $ExpectedTransactionRuleDto = {
3938
4258
  type: 'object',
3939
4259
  properties: {
3940
- series: {
3941
- description: 'Time series data points',
3942
- type: 'array',
3943
- items: {
3944
- $ref: '#/components/schemas/TimeSeriesPointDto'
3945
- }
3946
- },
3947
- summary: {
3948
- description: 'Period summary',
3949
- allOf: [
3950
- {
3951
- $ref: '#/components/schemas/TrendSummaryDto'
3952
- }
3953
- ]
4260
+ name: {
4261
+ type: 'string',
4262
+ description: 'Rule name'
3954
4263
  },
3955
- period: {
4264
+ icon: {
3956
4265
  type: 'string',
3957
- description: 'Period requested',
3958
- example: '6m'
4266
+ description: 'Rule icon'
3959
4267
  },
3960
- granularity: {
4268
+ frequency: {
3961
4269
  type: 'string',
3962
- description: 'Data granularity',
3963
- example: 'month'
4270
+ description: 'Rule frequency'
3964
4271
  },
3965
4272
  currency: {
3966
4273
  type: 'string',
3967
- description: 'Base currency for converted values',
3968
- example: 'CNY'
3969
- },
3970
- byCurrency: {
3971
- description:
3972
- 'Multi-currency time series (each point has currency breakdown)',
3973
- type: 'array',
3974
- items: {
3975
- $ref: '#/components/schemas/MultiCurrencyPointDto'
3976
- }
3977
- },
3978
- warnings: {
3979
- description: 'Exchange rate warnings',
3980
- type: 'array',
3981
- items: {
3982
- $ref: '#/components/schemas/ExchangeRateWarningDto'
3983
- }
4274
+ description: 'Currency code'
3984
4275
  }
3985
4276
  },
3986
- required: ['series', 'summary', 'period', 'granularity', 'currency']
4277
+ required: ['name', 'frequency', 'currency']
3987
4278
  } as const;
3988
4279
 
3989
- export const $CashFlowPointDto = {
4280
+ export const $ExpectedTransactionResponseDto = {
3990
4281
  type: 'object',
3991
4282
  properties: {
3992
- month: {
4283
+ id: {
3993
4284
  type: 'string',
3994
- description: 'Month key (YYYY-MM)',
3995
- example: '2024-03'
4285
+ description: 'Expected transaction ID'
3996
4286
  },
3997
- income: {
4287
+ userId: {
3998
4288
  type: 'string',
3999
- description: 'Income in base currency (absolute, converted)',
4000
- example: '10000.00'
4289
+ description: 'User ID'
4001
4290
  },
4002
- expense: {
4291
+ ruleId: {
4003
4292
  type: 'string',
4004
- description: 'Expense in base currency (absolute, converted)',
4005
- example: '5000.00'
4293
+ description: 'Associated rule ID'
4006
4294
  },
4007
- netSavings: {
4008
- type: 'string',
4009
- description: 'netSavings = income − expense (savings positive)',
4010
- example: '5000.00'
4011
- }
4012
- },
4013
- required: ['month', 'income', 'expense', 'netSavings']
4014
- } as const;
4015
-
4016
- export const $CashFlowTrendSummaryDto = {
4017
- type: 'object',
4018
- properties: {
4019
- totalIncome: {
4295
+ expectedDate: {
4020
4296
  type: 'string',
4021
- description: 'Total income across the period',
4022
- example: '60000.00'
4297
+ description: 'Expected date (YYYY-MM-DD)'
4023
4298
  },
4024
- totalExpense: {
4299
+ expectedAmount: {
4300
+ type: 'number',
4301
+ description: 'Expected amount'
4302
+ },
4303
+ status: {
4025
4304
  type: 'string',
4026
- description: 'Total expense across the period',
4027
- example: '30000.00'
4305
+ description: 'Status (PENDING, COMPLETED, SKIPPED)'
4028
4306
  },
4029
- totalNetSavings: {
4307
+ matchedTransactionId: {
4030
4308
  type: 'string',
4031
- description: 'income − expense across the period',
4032
- example: '30000.00'
4309
+ description: 'Matched transaction ID'
4033
4310
  },
4034
- averageMonthlyNetSavings: {
4311
+ matchedAt: {
4035
4312
  type: 'string',
4036
- description:
4037
- 'totalNetSavings divided by the window length (N months, incl. zero-filled)',
4038
- example: '5000.00'
4039
- }
4040
- },
4041
- required: [
4042
- 'totalIncome',
4043
- 'totalExpense',
4044
- 'totalNetSavings',
4045
- 'averageMonthlyNetSavings'
4046
- ]
4047
- } as const;
4048
-
4049
- export const $CashFlowTrendsResponseDto = {
4050
- type: 'object',
4051
- properties: {
4052
- series: {
4053
- description:
4054
- 'Monthly cash-flow series (fixed N-month window, zero-filled)',
4055
- type: 'array',
4056
- items: {
4057
- $ref: '#/components/schemas/CashFlowPointDto'
4058
- }
4313
+ description: 'Match timestamp (ISO 8601)'
4059
4314
  },
4060
- summary: {
4061
- description: 'Period totals',
4315
+ matchConfidence: {
4316
+ type: 'number',
4317
+ description: 'Match confidence score (0-1)'
4318
+ },
4319
+ isOverdue: {
4320
+ type: 'boolean',
4321
+ description: 'Whether this expected transaction is overdue'
4322
+ },
4323
+ rule: {
4324
+ description: 'Rule information',
4062
4325
  allOf: [
4063
4326
  {
4064
- $ref: '#/components/schemas/CashFlowTrendSummaryDto'
4327
+ $ref: '#/components/schemas/ExpectedTransactionRuleDto'
4065
4328
  }
4066
4329
  ]
4067
4330
  },
4068
- period: {
4069
- type: 'string',
4070
- description: 'Period requested',
4071
- example: '6m'
4072
- },
4073
- granularity: {
4331
+ createdAt: {
4332
+ format: 'date-time',
4074
4333
  type: 'string',
4075
- description: 'Data granularity (v1 returns month buckets)',
4076
- example: 'month'
4334
+ description: 'Created at timestamp'
4077
4335
  },
4078
- currency: {
4336
+ updatedAt: {
4337
+ format: 'date-time',
4079
4338
  type: 'string',
4080
- description: 'Base currency for converted values',
4081
- example: 'CNY'
4082
- },
4083
- warnings: {
4084
- description: 'Exchange rate warnings (e.g. missing rate for a currency)',
4085
- type: 'array',
4086
- items: {
4087
- $ref: '#/components/schemas/ExchangeRateWarningDto'
4088
- }
4339
+ description: 'Updated at timestamp'
4089
4340
  }
4090
4341
  },
4091
- required: ['series', 'summary', 'period', 'granularity', 'currency']
4092
- } as const;
4093
-
4094
- export const $GenerateSnapshotBody = {
4095
- type: 'object',
4096
- properties: {}
4097
- } as const;
4098
-
4099
- export const $GenerateSnapshotResponse = {
4100
- type: 'object',
4101
- properties: {}
4102
- } as const;
4103
-
4104
- export const $BackfillSnapshotsBody = {
4105
- type: 'object',
4106
- properties: {}
4107
- } as const;
4108
-
4109
- export const $BackfillSnapshotsResponse = {
4110
- type: 'object',
4111
- properties: {}
4342
+ required: [
4343
+ 'id',
4344
+ 'userId',
4345
+ 'ruleId',
4346
+ 'expectedDate',
4347
+ 'expectedAmount',
4348
+ 'status',
4349
+ 'isOverdue',
4350
+ 'rule',
4351
+ 'createdAt',
4352
+ 'updatedAt'
4353
+ ]
4112
4354
  } as const;
4113
4355
 
4114
- export const $DeleteOwnUserDto = {
4356
+ export const $ExpectedTransactionListResponseDto = {
4115
4357
  type: 'object',
4116
4358
  properties: {
4117
- accessToken: {
4118
- type: 'string',
4119
- description: 'Access token for user verification',
4120
- example: 'abc123xyz'
4359
+ items: {
4360
+ type: 'array',
4361
+ items: {
4362
+ $ref: '#/components/schemas/ExpectedTransactionResponseDto'
4363
+ }
4364
+ },
4365
+ total: {
4366
+ type: 'number',
4367
+ description: 'Total count'
4121
4368
  }
4122
4369
  },
4123
- required: ['accessToken']
4370
+ required: ['items', 'total']
4124
4371
  } as const;
4125
4372
 
4126
- export const $SignupDto = {
4373
+ export const $ConfirmMatchDto = {
4127
4374
  type: 'object',
4128
4375
  properties: {
4129
- turnstileToken: {
4376
+ transactionId: {
4130
4377
  type: 'string',
4131
- description:
4132
- 'Cloudflare Turnstile verification token (optional when Turnstile disabled)',
4133
- example: '0.abc123def456...'
4378
+ description: 'Transaction ID to match with'
4134
4379
  }
4135
- }
4380
+ },
4381
+ required: ['transactionId']
4136
4382
  } as const;
4137
4383
 
4138
- export const $SignupResponseDto = {
4384
+ export const $EnterNowDto = {
4139
4385
  type: 'object',
4140
4386
  properties: {
4141
- authToken: {
4387
+ expenseAccount: {
4142
4388
  type: 'string',
4143
- description: 'JWT auth token',
4144
- example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
4389
+ description:
4390
+ 'Override expense account (uses rule default if not provided)',
4391
+ maxLength: 200
4145
4392
  },
4146
- accessToken: {
4393
+ paymentAccount: {
4147
4394
  type: 'string',
4148
- description: 'Auto-generated access token'
4395
+ description:
4396
+ 'Override payment account (uses rule default if not provided)',
4397
+ maxLength: 200
4149
4398
  },
4150
- role: {
4399
+ amount: {
4400
+ type: 'number',
4401
+ description: 'Override amount (uses expected amount if not provided)',
4402
+ minimum: 0
4403
+ },
4404
+ payee: {
4151
4405
  type: 'string',
4152
- description: 'Assigned user role',
4153
- enum: ['USER', 'ADMIN', 'DEMO', 'INACTIVE', 'PAID', 'OPS']
4406
+ description: 'Override payee (uses rule default if not provided)',
4407
+ maxLength: 200
4408
+ },
4409
+ narration: {
4410
+ type: 'string',
4411
+ description: 'Optional narration',
4412
+ maxLength: 500
4154
4413
  }
4155
- },
4156
- required: ['authToken', 'accessToken', 'role']
4414
+ }
4157
4415
  } as const;
4158
4416
 
4159
- export const $UpdateUserSettingDto = {
4417
+ export const $ForecastItemDto = {
4160
4418
  type: 'object',
4161
4419
  properties: {
4162
- secId: {
4163
- type: 'number',
4164
- description: 'Security ID'
4420
+ rule: {
4421
+ type: 'string',
4422
+ description: 'Rule name',
4423
+ example: 'Rent'
4165
4424
  },
4166
- annualInterestRate: {
4425
+ ruleId: {
4426
+ type: 'string',
4427
+ description: 'Rule ID',
4428
+ example: 'clx123...'
4429
+ },
4430
+ amount: {
4167
4431
  type: 'number',
4168
- description: 'Annual interest rate',
4169
- example: 0.05
4432
+ description: 'Expected amount',
4433
+ example: 3000
4170
4434
  },
4171
- currency: {
4435
+ date: {
4172
4436
  type: 'string',
4173
- description: 'Currency code',
4174
- example: 'USD'
4437
+ description: 'Expected date (YYYY-MM-DD)',
4438
+ example: '2024-04-01'
4175
4439
  },
4176
- baseCurrency: {
4440
+ icon: {
4177
4441
  type: 'string',
4178
- description: 'Base currency code',
4179
- example: 'USD'
4442
+ description: 'Rule icon emoji',
4443
+ example: '🏠',
4444
+ nullable: true
4180
4445
  },
4181
- benchmark: {
4446
+ currency: {
4182
4447
  type: 'string',
4183
- description: 'Benchmark symbol',
4184
- example: 'SPY'
4185
- },
4186
- colorScheme: {
4448
+ description: 'Currency code',
4449
+ example: 'CNY'
4450
+ }
4451
+ },
4452
+ required: ['rule', 'ruleId', 'amount', 'date', 'icon', 'currency']
4453
+ } as const;
4454
+
4455
+ export const $MonthlyForecastDto = {
4456
+ type: 'object',
4457
+ properties: {
4458
+ month: {
4187
4459
  type: 'string',
4188
- description: 'Color scheme',
4189
- enum: ['DARK', 'LIGHT']
4460
+ description: 'Month (YYYY-MM)',
4461
+ example: '2024-04'
4190
4462
  },
4191
- dateRange: {
4192
- type: 'string',
4193
- description: 'Date range filter',
4194
- example: '1y'
4463
+ expectedOutflow: {
4464
+ type: 'number',
4465
+ description: 'Total expected outflow for the month',
4466
+ example: 8500
4195
4467
  },
4196
- emergencyFund: {
4468
+ itemCount: {
4197
4469
  type: 'number',
4198
- description: 'Emergency fund amount',
4199
- example: 10000
4470
+ description: 'Number of expected transactions',
4471
+ example: 3
4200
4472
  },
4201
- 'filters.accounts': {
4202
- description: 'Account filter IDs',
4203
- type: 'array',
4204
- items: {
4205
- type: 'string'
4473
+ byCurrency: {
4474
+ type: 'object',
4475
+ description: 'Breakdown by currency',
4476
+ example: {
4477
+ CNY: 8500,
4478
+ USD: 100
4206
4479
  }
4207
4480
  },
4208
- 'filters.assetClasses': {
4209
- description: 'Asset class filters',
4481
+ items: {
4482
+ description: 'Individual forecast items',
4210
4483
  type: 'array',
4211
4484
  items: {
4212
- type: 'string'
4485
+ $ref: '#/components/schemas/ForecastItemDto'
4213
4486
  }
4214
- },
4215
- 'filters.dataSource': {
4216
- type: 'string',
4217
- description: 'Data source filter'
4218
- },
4219
- 'filters.symbol': {
4220
- type: 'string',
4221
- description: 'Symbol filter'
4222
- },
4223
- 'filters.tags': {
4224
- description: 'Tag filters',
4487
+ }
4488
+ },
4489
+ required: ['month', 'expectedOutflow', 'itemCount', 'byCurrency', 'items']
4490
+ } as const;
4491
+
4492
+ export const $ForecastResponseDto = {
4493
+ type: 'object',
4494
+ properties: {
4495
+ forecast: {
4496
+ description: 'Monthly forecast data',
4225
4497
  type: 'array',
4226
4498
  items: {
4227
- type: 'string'
4499
+ $ref: '#/components/schemas/MonthlyForecastDto'
4228
4500
  }
4229
4501
  },
4230
- isExperimentalFeatures: {
4231
- type: 'boolean',
4232
- description: 'Enable experimental features'
4233
- },
4234
- isRestrictedView: {
4235
- type: 'boolean',
4236
- description: 'Enable restricted view mode'
4237
- },
4238
- language: {
4239
- type: 'string',
4240
- description: 'Language code',
4241
- example: 'en'
4242
- },
4243
- locale: {
4244
- type: 'string',
4245
- description: 'Locale code',
4246
- example: 'en-US'
4247
- },
4248
- projectedTotalAmount: {
4502
+ totalOutflow: {
4249
4503
  type: 'number',
4250
- description: 'Projected total amount',
4251
- example: 1000000
4504
+ description: 'Total expected outflow across all months',
4505
+ example: 25500
4252
4506
  },
4253
- retirementDate: {
4254
- type: 'string',
4255
- description: 'Retirement date in ISO 8601 format',
4256
- example: '2050-01-01'
4507
+ totalByCurrency: {
4508
+ type: 'object',
4509
+ description: 'Total by currency across all months',
4510
+ example: {
4511
+ CNY: 25500,
4512
+ USD: 300
4513
+ }
4257
4514
  },
4258
- savingsRate: {
4515
+ rulesCount: {
4259
4516
  type: 'number',
4260
- description: 'Savings rate percentage',
4261
- example: 0.2
4517
+ description: 'Number of active recurring rules included',
4518
+ example: 5
4262
4519
  },
4263
- viewMode: {
4520
+ periodStart: {
4264
4521
  type: 'string',
4265
- description: 'View mode',
4266
- enum: ['DEFAULT', 'ZEN']
4267
- }
4268
- }
4269
- } as const;
4270
-
4271
- export const $UpdatePropertyDto = {
4272
- type: 'object',
4273
- properties: {
4274
- value: {
4522
+ description: 'Forecast period start date',
4523
+ example: '2024-04-01'
4524
+ },
4525
+ periodEnd: {
4275
4526
  type: 'string',
4276
- description: 'Property value'
4527
+ description: 'Forecast period end date',
4528
+ example: '2024-06-30'
4277
4529
  }
4278
4530
  },
4279
- required: ['value']
4531
+ required: [
4532
+ 'forecast',
4533
+ 'totalOutflow',
4534
+ 'totalByCurrency',
4535
+ 'rulesCount',
4536
+ 'periodStart',
4537
+ 'periodEnd'
4538
+ ]
4280
4539
  } as const;
4281
4540
 
4282
4541
  export const $CreateTransactionRuleDto = {
@@ -4838,7 +5097,8 @@ export const $UpdateTransactionRuleDto = {
4838
5097
  },
4839
5098
  matchLogic: {
4840
5099
  type: 'string',
4841
- enum: ['OR', 'AND']
5100
+ enum: ['OR', 'AND'],
5101
+ default: 'OR'
4842
5102
  },
4843
5103
  amountMin: {
4844
5104
  type: 'number',
@@ -4852,13 +5112,10 @@ export const $UpdateTransactionRuleDto = {
4852
5112
  },
4853
5113
  priority: {
4854
5114
  type: 'number',
5115
+ default: 50,
4855
5116
  minimum: 0,
4856
5117
  maximum: 1000
4857
5118
  },
4858
- enabled: {
4859
- type: 'boolean',
4860
- description: 'Enable or disable the rule'
4861
- },
4862
5119
  additionalTags: {
4863
5120
  items: {
4864
5121
  type: 'array'
@@ -4868,6 +5125,10 @@ export const $UpdateTransactionRuleDto = {
4868
5125
  },
4869
5126
  additionalMetadata: {
4870
5127
  type: 'object'
5128
+ },
5129
+ enabled: {
5130
+ type: 'boolean',
5131
+ description: 'Enable or disable the rule'
4871
5132
  }
4872
5133
  }
4873
5134
  } as const;
@@ -4928,6 +5189,69 @@ export const $TestRuleResponseDto = {
4928
5189
  required: ['ruleId', 'matches', 'confidence', 'matchDetails']
4929
5190
  } as const;
4930
5191
 
5192
+ export const $CategoryCatalogEntryDto = {
5193
+ type: 'object',
5194
+ properties: {
5195
+ slug: {
5196
+ type: 'string',
5197
+ description: 'Category slug (single source-of-truth)',
5198
+ example: 'food'
5199
+ },
5200
+ scenario: {
5201
+ type: 'string',
5202
+ description: 'Display scenario group (maps to frontend picker _scenario)',
5203
+ enum: [
5204
+ 'expense',
5205
+ 'income',
5206
+ 'investment',
5207
+ 'banking',
5208
+ 'transfer',
5209
+ 'payment'
5210
+ ],
5211
+ example: 'expense'
5212
+ },
5213
+ icon: {
5214
+ type: 'string',
5215
+ description: 'Lucide icon name',
5216
+ example: 'utensils'
5217
+ },
5218
+ regions: {
5219
+ description: "Applicable regions ('*' = all, 'cn' = CN-only)",
5220
+ example: ['*'],
5221
+ type: 'array',
5222
+ items: {
5223
+ type: 'string'
5224
+ }
5225
+ }
5226
+ },
5227
+ required: ['slug', 'scenario', 'icon', 'regions']
5228
+ } as const;
5229
+
5230
+ export const $CategoryCatalogListResponseDto = {
5231
+ type: 'object',
5232
+ properties: {
5233
+ items: {
5234
+ description: 'Category entries (region-scoped, query-filtered)',
5235
+ type: 'array',
5236
+ items: {
5237
+ $ref: '#/components/schemas/CategoryCatalogEntryDto'
5238
+ }
5239
+ },
5240
+ total: {
5241
+ type: 'number',
5242
+ description:
5243
+ 'Total category entries for the region (before query filtering)',
5244
+ example: 30
5245
+ },
5246
+ region: {
5247
+ type: 'string',
5248
+ description: 'Region code',
5249
+ example: 'cn'
5250
+ }
5251
+ },
5252
+ required: ['items', 'total', 'region']
5253
+ } as const;
5254
+
4931
5255
  export const $CreateBeanEventDto = {
4932
5256
  type: 'object',
4933
5257
  properties: {
@@ -5091,6 +5415,14 @@ export const $OnboardingAccountDto = {
5091
5415
  description:
5092
5416
  'Platform ID to bind the account to (references Platform.id); omit for unbound',
5093
5417
  example: 'c98e5d4a-2f71-4a5a-bb3c-92c9f231d5e2'
5418
+ },
5419
+ displayName: {
5420
+ type: 'string',
5421
+ description:
5422
+ 'User-set display name override (omit/null = keep the derived name)',
5423
+ nullable: true,
5424
+ maxLength: 50,
5425
+ example: 'Salary card'
5094
5426
  }
5095
5427
  },
5096
5428
  required: ['path', 'currency']
@@ -5982,6 +6314,89 @@ export const $UncoveredFormatMissDto = {
5982
6314
  properties: {}
5983
6315
  } as const;
5984
6316
 
6317
+ export const $ClientParsedDataDto = {
6318
+ type: 'object',
6319
+ properties: {
6320
+ amount: {
6321
+ type: 'number',
6322
+ description: 'Transaction amount',
6323
+ example: 35
6324
+ },
6325
+ currency: {
6326
+ type: 'string',
6327
+ description: 'Currency code',
6328
+ example: 'CNY'
6329
+ },
6330
+ date: {
6331
+ type: 'string',
6332
+ description: 'Transaction date (ISO 8601)',
6333
+ example: '2026-08-15'
6334
+ },
6335
+ payee: {
6336
+ type: 'string',
6337
+ description: 'Payee/merchant name',
6338
+ example: 'Starbucks'
6339
+ },
6340
+ narration: {
6341
+ type: 'string',
6342
+ description: 'Transaction narration'
6343
+ },
6344
+ category: {
6345
+ type: 'string',
6346
+ description: 'Category slug',
6347
+ example: 'food_restaurant'
6348
+ },
6349
+ incomeType: {
6350
+ type: 'string',
6351
+ description: 'Income type',
6352
+ example: 'Salary'
6353
+ },
6354
+ incomeSource: {
6355
+ type: 'string',
6356
+ description: 'Income source',
6357
+ example: 'Anthropic Inc.'
6358
+ },
6359
+ symbol: {
6360
+ type: 'string',
6361
+ description: 'Security symbol code (e.g., 600519, AAPL)',
6362
+ example: 'AAPL'
6363
+ },
6364
+ quantity: {
6365
+ type: 'number',
6366
+ description: 'Quantity of shares/units',
6367
+ example: 100
6368
+ },
6369
+ price: {
6370
+ type: 'number',
6371
+ description: 'Unit price per share/unit',
6372
+ example: 1900
6373
+ },
6374
+ investmentAction: {
6375
+ type: 'string',
6376
+ description: 'Investment action',
6377
+ enum: ['buy', 'sell'],
6378
+ example: 'buy'
6379
+ },
6380
+ paymentSource: {
6381
+ type: 'string',
6382
+ description: 'Payment source: asset (default) or liability (credit card)',
6383
+ enum: ['asset', 'liability'],
6384
+ example: 'asset'
6385
+ },
6386
+ liabilityHint: {
6387
+ type: 'string',
6388
+ description: 'Liability account hint (CreditCard/Huabei/Baitiao)',
6389
+ example: 'CreditCard'
6390
+ },
6391
+ warning: {
6392
+ type: 'string',
6393
+ description:
6394
+ 'Display-only warning from the prior response; accepted but ignored.',
6395
+ example: 'Cross-currency settlement applies.'
6396
+ }
6397
+ }
6398
+ } as const;
6399
+
5985
6400
  export const $ProcessNlpDto = {
5986
6401
  type: 'object',
5987
6402
  properties: {
@@ -6005,14 +6420,18 @@ export const $ProcessNlpDto = {
6005
6420
  example: 'session_abc123'
6006
6421
  },
6007
6422
  parsedData: {
6008
- type: 'object',
6009
6423
  description:
6010
6424
  'Parsed data from previous NLP response for session recovery. Send back the parsedData received in confirm_payee/confirm responses.',
6011
6425
  example: {
6012
6426
  amount: 35,
6013
6427
  currency: 'CNY',
6014
6428
  payee: 'Starbucks'
6015
- }
6429
+ },
6430
+ allOf: [
6431
+ {
6432
+ $ref: '#/components/schemas/ClientParsedDataDto'
6433
+ }
6434
+ ]
6016
6435
  },
6017
6436
  selectedRuleId: {
6018
6437
  type: 'string',
@@ -6023,8 +6442,27 @@ export const $ProcessNlpDto = {
6023
6442
  selectedAccount: {
6024
6443
  type: 'string',
6025
6444
  description:
6026
- 'confirm_account echo-back: account path selected from the prior confirm_account response (suggestedAccount, similarAccounts[i], or a typed path). Applied directly when the session is confirming_account — no NL re-parse.',
6445
+ '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.',
6027
6446
  example: 'Expenses:Food:Coffee'
6447
+ },
6448
+ viewpointAccount: {
6449
+ type: 'string',
6450
+ description:
6451
+ '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.',
6452
+ example: 'Assets:CN:Bank:ICBC'
6453
+ },
6454
+ viewpointCategory: {
6455
+ type: 'string',
6456
+ description:
6457
+ "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.",
6458
+ example: 'Food'
6459
+ },
6460
+ viewpointFlow: {
6461
+ type: 'string',
6462
+ description:
6463
+ "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.",
6464
+ enum: ['income', 'expense'],
6465
+ example: 'expense'
6028
6466
  }
6029
6467
  }
6030
6468
  } as const;
@@ -6338,6 +6776,24 @@ export const $NlpRuleConfirmationDataDto = {
6338
6776
  ]
6339
6777
  } as const;
6340
6778
 
6779
+ export const $NlpAccountCandidateDto = {
6780
+ type: 'object',
6781
+ properties: {
6782
+ path: {
6783
+ type: 'string',
6784
+ description: 'Canonical beancount account path (echo back on selection)',
6785
+ example: 'Expenses:Food:Dining'
6786
+ },
6787
+ name: {
6788
+ type: 'string',
6789
+ description:
6790
+ 'Localized display name (ADR-0114 read-time projection, user locale)',
6791
+ example: '餐饮'
6792
+ }
6793
+ },
6794
+ required: ['path', 'name']
6795
+ } as const;
6796
+
6341
6797
  export const $NlpAccountConfirmationDataDto = {
6342
6798
  type: 'object',
6343
6799
  properties: {
@@ -6353,10 +6809,11 @@ export const $NlpAccountConfirmationDataDto = {
6353
6809
  example: 'Expenses:Food:Drinks'
6354
6810
  },
6355
6811
  similarAccounts: {
6356
- description: 'Similar accounts for user selection',
6812
+ description:
6813
+ 'Similar accounts for user selection (path + localized name, #680)',
6357
6814
  type: 'array',
6358
6815
  items: {
6359
- type: 'string'
6816
+ $ref: '#/components/schemas/NlpAccountCandidateDto'
6360
6817
  }
6361
6818
  },
6362
6819
  errorMessage: {
@@ -6644,7 +7101,7 @@ export const $NlpResponseDto = {
6644
7101
  type: 'string',
6645
7102
  description:
6646
7103
  'Asset sub-type (only present when intent is "asset"). Determines which asset-related form to render.',
6647
- enum: ['transfer', 'banking', 'investment'],
7104
+ enum: ['transfer', 'banking', 'investment', 'lend', 'lend_collect'],
6648
7105
  example: 'investment'
6649
7106
  },
6650
7107
  liabilitySubType: {
@@ -6933,55 +7390,128 @@ export const $PlatformMatchResultDto = {
6933
7390
  category: {
6934
7391
  type: 'string',
6935
7392
  description:
6936
- 'Region-aware category (institution vocab, e.g. DigitalWallet/Bank). null = no region-aware suggestion; fall back to type.',
7393
+ 'Region-aware category (institution vocab, e.g. DigitalWallet/Bank). null = no region-aware suggestion; fall back to type.',
7394
+ nullable: true,
7395
+ example: 'DigitalWallet'
7396
+ },
7397
+ matchType: {
7398
+ type: 'string',
7399
+ description: "How this row matched: 'exact' > 'prefix' > 'substring'",
7400
+ enum: ['exact', 'prefix', 'substring']
7401
+ }
7402
+ },
7403
+ required: [
7404
+ 'id',
7405
+ 'name',
7406
+ 'canonical',
7407
+ 'type',
7408
+ 'suggestedSegment',
7409
+ 'logoUrl',
7410
+ 'countryCode',
7411
+ 'category',
7412
+ 'matchType'
7413
+ ]
7414
+ } as const;
7415
+
7416
+ export const $PlatformMatchResponseDto = {
7417
+ type: 'object',
7418
+ properties: {
7419
+ platforms: {
7420
+ description: 'Ranked matches, best tier first (at most 10 rows)',
7421
+ type: 'array',
7422
+ items: {
7423
+ $ref: '#/components/schemas/PlatformMatchResultDto'
7424
+ }
7425
+ },
7426
+ matchType: {
7427
+ type: 'string',
7428
+ description:
7429
+ "Overall match quality — top row's tier, or 'none' when no hits",
7430
+ enum: ['none', 'exact', 'prefix', 'substring']
7431
+ },
7432
+ total: {
7433
+ type: 'number',
7434
+ description: 'Total matches before LIMIT (truncation transparency)'
7435
+ },
7436
+ hasMore: {
7437
+ type: 'boolean',
7438
+ description: 'true when total > platforms.length (more matches exist)'
7439
+ }
7440
+ },
7441
+ required: ['platforms', 'matchType', 'total', 'hasMore']
7442
+ } as const;
7443
+
7444
+ export const $PlatformStandardsPlatformDto = {
7445
+ type: 'object',
7446
+ properties: {
7447
+ id: {
7448
+ type: 'string',
7449
+ description: 'Global platform ID'
7450
+ },
7451
+ name: {
7452
+ type: 'string',
7453
+ description: 'Platform name (e.g., "ICBC")'
7454
+ },
7455
+ canonical: {
7456
+ type: 'string',
7457
+ description: 'Canonical identifier in ACCOUNT_RE format (e.g., "icbc")'
7458
+ },
7459
+ suggestedSegment: {
7460
+ type: 'string',
7461
+ description:
7462
+ 'Suggested path segment — canonical PascalCased per hyphen-part, hyphens preserved (e.g. "Apple-Pay")'
7463
+ },
7464
+ type: {
7465
+ type: 'string',
7466
+ description: 'Platform type',
7467
+ enum: [
7468
+ 'BANK',
7469
+ 'BROKERAGE',
7470
+ 'CRYPTO_EXCHANGE',
7471
+ 'PAYMENT',
7472
+ 'INVESTMENT',
7473
+ 'INSURANCE',
7474
+ 'OTHER'
7475
+ ]
7476
+ },
7477
+ category: {
7478
+ type: 'string',
7479
+ description:
7480
+ 'Region-aware category (institution vocab, e.g. DigitalWallet/Bank) resolved against the final region. null = no region-aware suggestion; fall back to type.',
6937
7481
  nullable: true,
6938
- example: 'DigitalWallet'
6939
- },
6940
- matchType: {
6941
- type: 'string',
6942
- description: "How this row matched: 'exact' > 'prefix' > 'substring'",
6943
- enum: ['exact', 'prefix', 'substring']
7482
+ example: 'Bank'
6944
7483
  }
6945
7484
  },
6946
- required: [
6947
- 'id',
6948
- 'name',
6949
- 'canonical',
6950
- 'type',
6951
- 'suggestedSegment',
6952
- 'logoUrl',
6953
- 'countryCode',
6954
- 'category',
6955
- 'matchType'
6956
- ]
7485
+ required: ['id', 'name', 'canonical', 'suggestedSegment', 'type', 'category']
6957
7486
  } as const;
6958
7487
 
6959
- export const $PlatformMatchResponseDto = {
7488
+ export const $PlatformStandardsResponseDto = {
6960
7489
  type: 'object',
6961
7490
  properties: {
6962
- platforms: {
6963
- description: 'Ranked matches, best tier first (at most 10 rows)',
6964
- type: 'array',
6965
- items: {
6966
- $ref: '#/components/schemas/PlatformMatchResultDto'
6967
- }
7491
+ platform: {
7492
+ description: 'The selected platform (institution lock source)',
7493
+ allOf: [
7494
+ {
7495
+ $ref: '#/components/schemas/PlatformStandardsPlatformDto'
7496
+ }
7497
+ ]
6968
7498
  },
6969
- matchType: {
7499
+ region: {
6970
7500
  type: 'string',
6971
7501
  description:
6972
- "Overall match quality — top row's tier, or 'none' when no hits",
6973
- enum: ['none', 'exact', 'prefix', 'substring']
6974
- },
6975
- total: {
6976
- type: 'number',
6977
- description: 'Total matches before LIMIT (truncation transparency)'
7502
+ "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.",
7503
+ example: 'CN'
6978
7504
  },
6979
- hasMore: {
6980
- type: 'boolean',
6981
- description: 'true when total > platforms.length (more matches exist)'
7505
+ templates: {
7506
+ description:
7507
+ 'Candidate account-standard templates of the resolved region (groupable by productCategory client-side)',
7508
+ type: 'array',
7509
+ items: {
7510
+ $ref: '#/components/schemas/AccountStandardResponseDto'
7511
+ }
6982
7512
  }
6983
7513
  },
6984
- required: ['platforms', 'matchType', 'total', 'hasMore']
7514
+ required: ['platform', 'region', 'templates']
6985
7515
  } as const;
6986
7516
 
6987
7517
  export const $CreatePlatformDto = {
@@ -7085,7 +7615,8 @@ export const $UpdatePlatformDto = {
7085
7615
  },
7086
7616
  isActive: {
7087
7617
  type: 'boolean',
7088
- description: 'Whether the platform is active'
7618
+ description: 'Whether the platform is active',
7619
+ default: true
7089
7620
  }
7090
7621
  }
7091
7622
  } as const;
@@ -7248,7 +7779,8 @@ export const $AccountItemDto = {
7248
7779
  },
7249
7780
  displayName: {
7250
7781
  type: 'string',
7251
- description: 'Display name (last part of account path)',
7782
+ description:
7783
+ 'Display name: user-set name if provided (#762), else last part of account path',
7252
7784
  example: 'Savings'
7253
7785
  },
7254
7786
  balance: {
@@ -7284,7 +7816,8 @@ export const $PlatformGroupDto = {
7284
7816
  example: 'CMB Bank'
7285
7817
  },
7286
7818
  accounts: {
7287
- description: 'Accounts within this platform',
7819
+ description:
7820
+ 'Accounts within this platform (Assets and Liabilities rows, #696)',
7288
7821
  type: 'array',
7289
7822
  items: {
7290
7823
  $ref: '#/components/schemas/AccountItemDto'
@@ -7292,7 +7825,8 @@ export const $PlatformGroupDto = {
7292
7825
  },
7293
7826
  totalBalance: {
7294
7827
  type: 'string',
7295
- description: 'FX-converted total balance in base currency',
7828
+ description:
7829
+ 'FX-converted total balance in base currency (nets Assets + Liabilities rows; can be negative)',
7296
7830
  example: '100000.00'
7297
7831
  },
7298
7832
  balanceByCurrency: {
@@ -7311,7 +7845,7 @@ export const $PlatformGroupDto = {
7311
7845
  sharePct: {
7312
7846
  type: 'number',
7313
7847
  description:
7314
- 'Share of the grand converted total (0-100); 0 when grand total is 0',
7848
+ 'Share of the converted asset-side grand total (0-100); liability balances are excluded from the basis; 0 when grand total is 0 (#696)',
7315
7849
  example: 42.5
7316
7850
  }
7317
7851
  },
@@ -7359,7 +7893,8 @@ export const $AccountsSummaryDto = {
7359
7893
  properties: {
7360
7894
  totalAccounts: {
7361
7895
  type: 'number',
7362
- description: 'Total number of accounts'
7896
+ description:
7897
+ 'Total number of accounts (balance sheet: Assets + Liabilities, #696)'
7363
7898
  },
7364
7899
  totalPlatforms: {
7365
7900
  type: 'number',
@@ -7417,7 +7952,8 @@ export const $AccountItemWithAssetClassDto = {
7417
7952
  },
7418
7953
  displayName: {
7419
7954
  type: 'string',
7420
- description: 'Display name (last part of account path)',
7955
+ description:
7956
+ 'Display name: user-set name if provided (#762), else last part of account path',
7421
7957
  example: 'Savings'
7422
7958
  },
7423
7959
  balance: {
@@ -7903,7 +8439,7 @@ export const $MonetaryDto = {
7903
8439
  example: 'USD'
7904
8440
  },
7905
8441
  baseCcyEquivalent: {
7906
- type: 'object',
8442
+ type: 'string',
7907
8443
  description: 'Converted to user base currency (Decimal string)',
7908
8444
  example: '21600',
7909
8445
  nullable: true
@@ -7979,13 +8515,13 @@ export const $HoldingPnlRowDto = {
7979
8515
  example: 'Assets:US:Broker:AAPL'
7980
8516
  },
7981
8517
  accountCcy: {
7982
- type: 'object',
8518
+ type: 'string',
7983
8519
  description: 'Account settlement currency (ISO 4217), from cost currency',
7984
8520
  nullable: true,
7985
8521
  example: 'USD'
7986
8522
  },
7987
8523
  brokerType: {
7988
- type: 'object',
8524
+ type: 'string',
7989
8525
  description: 'Broker type derived from Platform.type',
7990
8526
  nullable: true,
7991
8527
  example: 'broker'
@@ -8006,7 +8542,7 @@ export const $HoldingPnlRowDto = {
8006
8542
  example: 'EQUITY'
8007
8543
  },
8008
8544
  assetSubClass: {
8009
- type: 'object',
8545
+ type: 'string',
8010
8546
  nullable: true,
8011
8547
  example: 'STOCK'
8012
8548
  },
@@ -8053,14 +8589,14 @@ export const $HoldingPnlRowDto = {
8053
8589
  ]
8054
8590
  },
8055
8591
  unrealizedPnlBase: {
8056
- type: 'object',
8592
+ type: 'string',
8057
8593
  description:
8058
8594
  'Unrealized P&L in base currency (Decimal string); null when any FX/price missing',
8059
8595
  nullable: true,
8060
8596
  example: '6000'
8061
8597
  },
8062
8598
  unrealizedPnlPct: {
8063
- type: 'object',
8599
+ type: 'string',
8064
8600
  description: 'Unrealized P&L % (Decimal string)',
8065
8601
  nullable: true,
8066
8602
  example: '25'
@@ -8084,7 +8620,7 @@ export const $HoldingPnlRowDto = {
8084
8620
  ]
8085
8621
  },
8086
8622
  pctOfInvestedAssets: {
8087
- type: 'object',
8623
+ type: 'string',
8088
8624
  description:
8089
8625
  'Share of invested assets % (Decimal string); only for invested chartTokens',
8090
8626
  nullable: true,
@@ -8129,15 +8665,15 @@ export const $HoldingPnlWarningDto = {
8129
8665
  ]
8130
8666
  },
8131
8667
  symbol: {
8132
- type: 'object',
8668
+ type: 'string',
8133
8669
  nullable: true
8134
8670
  },
8135
8671
  accountId: {
8136
- type: 'object',
8672
+ type: 'string',
8137
8673
  nullable: true
8138
8674
  },
8139
8675
  currency: {
8140
- type: 'object',
8676
+ type: 'string',
8141
8677
  nullable: true
8142
8678
  }
8143
8679
  },
@@ -8201,6 +8737,216 @@ export const $AnonymousLoginResponseDto = {
8201
8737
  required: ['authToken']
8202
8738
  } as const;
8203
8739
 
8740
+ export const $ParserContributionMetaDto = {
8741
+ type: 'object',
8742
+ properties: {
8743
+ institution: {
8744
+ type: 'string',
8745
+ description: 'Institution slug (lowercase kebab-case)',
8746
+ pattern: '^[a-z0-9]+(-[a-z0-9]+)*$',
8747
+ example: 'icbc'
8748
+ },
8749
+ region: {
8750
+ type: 'string',
8751
+ enum: [
8752
+ 'cn',
8753
+ 'us',
8754
+ 'de',
8755
+ 'fr',
8756
+ 'gb',
8757
+ 'hk',
8758
+ 'jp',
8759
+ 'sg',
8760
+ 'au',
8761
+ 'ca',
8762
+ 'other'
8763
+ ]
8764
+ },
8765
+ accountType: {
8766
+ type: 'string',
8767
+ enum: ['checking', 'savings', 'credit', 'debit', 'investment']
8768
+ },
8769
+ format: {
8770
+ type: 'string',
8771
+ enum: ['csv', 'xlsx', 'pdf', 'ofx', 'qif']
8772
+ },
8773
+ institutionDisplayName: {
8774
+ type: 'string',
8775
+ example: '中国工商银行'
8776
+ },
8777
+ encoding: {
8778
+ type: 'string',
8779
+ example: 'utf-8'
8780
+ },
8781
+ delimiter: {
8782
+ type: 'string',
8783
+ description: 'CSV delimiter character: ",", ";", "\\t" or "|"'
8784
+ },
8785
+ headerRows: {
8786
+ type: 'number',
8787
+ default: 1,
8788
+ description: 'Header row count; the client omits the field when it is 1'
8789
+ },
8790
+ notes: {
8791
+ type: 'string',
8792
+ maxLength: 2000
8793
+ }
8794
+ },
8795
+ required: ['institution', 'region', 'accountType', 'format']
8796
+ } as const;
8797
+
8798
+ export const $ParserContributionSamplesDto = {
8799
+ type: 'object',
8800
+ properties: {
8801
+ rows: {
8802
+ description:
8803
+ 'Client-sanitized sample rows (key = column name, value = cell)',
8804
+ type: 'array',
8805
+ items: {
8806
+ type: 'object'
8807
+ }
8808
+ },
8809
+ rawHeaders: {
8810
+ type: 'array',
8811
+ items: {
8812
+ type: 'string'
8813
+ }
8814
+ }
8815
+ },
8816
+ required: ['rows']
8817
+ } as const;
8818
+
8819
+ export const $FieldHintDto = {
8820
+ type: 'object',
8821
+ properties: {
8822
+ columnName: {
8823
+ type: 'string',
8824
+ example: '交易日期'
8825
+ },
8826
+ format: {
8827
+ type: 'string',
8828
+ description: 'Date format, e.g. yyyy-MM-dd HH:mm',
8829
+ example: 'yyyy-MM-dd'
8830
+ },
8831
+ signConvention: {
8832
+ type: 'string',
8833
+ enum: ['negative-expense', 'positive-expense', 'separate-columns']
8834
+ },
8835
+ creditColumn: {
8836
+ type: 'string'
8837
+ },
8838
+ debitColumn: {
8839
+ type: 'string'
8840
+ }
8841
+ },
8842
+ required: ['columnName']
8843
+ } as const;
8844
+
8845
+ export const $ParserContributionFieldHintsDto = {
8846
+ type: 'object',
8847
+ properties: {
8848
+ date: {
8849
+ $ref: '#/components/schemas/FieldHintDto'
8850
+ },
8851
+ amount: {
8852
+ $ref: '#/components/schemas/FieldHintDto'
8853
+ },
8854
+ description: {
8855
+ $ref: '#/components/schemas/FieldHintDto'
8856
+ },
8857
+ balance: {
8858
+ $ref: '#/components/schemas/FieldHintDto'
8859
+ },
8860
+ payee: {
8861
+ $ref: '#/components/schemas/FieldHintDto'
8862
+ },
8863
+ reference: {
8864
+ $ref: '#/components/schemas/FieldHintDto'
8865
+ },
8866
+ category: {
8867
+ $ref: '#/components/schemas/FieldHintDto'
8868
+ }
8869
+ },
8870
+ required: ['date', 'amount']
8871
+ } as const;
8872
+
8873
+ export const $ExpectedTransactionDto = {
8874
+ type: 'object',
8875
+ properties: {
8876
+ date: {
8877
+ type: 'string',
8878
+ example: '2026-08-01'
8879
+ },
8880
+ amount: {
8881
+ type: 'number',
8882
+ example: -45.5
8883
+ },
8884
+ description: {
8885
+ type: 'string',
8886
+ example: '星巴克-***店'
8887
+ },
8888
+ payee: {
8889
+ type: 'string'
8890
+ },
8891
+ category: {
8892
+ type: 'string'
8893
+ }
8894
+ },
8895
+ required: ['date', 'amount', 'description']
8896
+ } as const;
8897
+
8898
+ export const $ParserContributionExamplesDto = {
8899
+ type: 'object',
8900
+ properties: {
8901
+ expectedTransactions: {
8902
+ type: 'array',
8903
+ items: {
8904
+ $ref: '#/components/schemas/ExpectedTransactionDto'
8905
+ }
8906
+ }
8907
+ },
8908
+ required: ['expectedTransactions']
8909
+ } as const;
8910
+
8911
+ export const $ParserContributionRequestDto = {
8912
+ type: 'object',
8913
+ properties: {
8914
+ meta: {
8915
+ $ref: '#/components/schemas/ParserContributionMetaDto'
8916
+ },
8917
+ samples: {
8918
+ $ref: '#/components/schemas/ParserContributionSamplesDto'
8919
+ },
8920
+ fieldHints: {
8921
+ $ref: '#/components/schemas/ParserContributionFieldHintsDto'
8922
+ },
8923
+ examples: {
8924
+ description: 'Omitted entirely by the client when empty',
8925
+ allOf: [
8926
+ {
8927
+ $ref: '#/components/schemas/ParserContributionExamplesDto'
8928
+ }
8929
+ ]
8930
+ }
8931
+ },
8932
+ required: ['meta', 'samples', 'fieldHints']
8933
+ } as const;
8934
+
8935
+ export const $ParserContributionRelayResponseDto = {
8936
+ type: 'object',
8937
+ properties: {
8938
+ issueUrl: {
8939
+ type: 'string',
8940
+ example: 'https://github.com/fire-zu/firela-vlt/issues/42'
8941
+ },
8942
+ issueNumber: {
8943
+ type: 'number',
8944
+ example: 42
8945
+ }
8946
+ },
8947
+ required: ['issueUrl', 'issueNumber']
8948
+ } as const;
8949
+
8204
8950
  export const $SymbolSearchResultDto = {
8205
8951
  type: 'object',
8206
8952
  properties: {
@@ -8209,35 +8955,35 @@ export const $SymbolSearchResultDto = {
8209
8955
  example: 'AAPL'
8210
8956
  },
8211
8957
  name: {
8212
- type: 'object',
8958
+ type: 'string',
8213
8959
  example: 'Apple Inc.',
8214
8960
  nullable: true
8215
8961
  },
8216
8962
  exchange: {
8217
- type: 'object',
8963
+ type: 'string',
8218
8964
  example: 'US',
8219
8965
  nullable: true
8220
8966
  },
8221
8967
  assetType: {
8222
- type: 'object',
8968
+ type: 'string',
8223
8969
  description: 'OpenBB asset_type (e.g. stock, etf)',
8224
8970
  example: 'stock',
8225
8971
  nullable: true
8226
8972
  },
8227
8973
  assetClass: {
8228
- type: 'object',
8974
+ type: 'string',
8229
8975
  description: 'IGN asset class (region.types.ts ASSET_CLASSES)',
8230
8976
  example: 'EQUITY',
8231
8977
  nullable: true
8232
8978
  },
8233
8979
  assetSubClass: {
8234
- type: 'object',
8980
+ type: 'string',
8235
8981
  description: 'IGN asset sub-class (region.types.ts ASSET_SUB_CLASSES)',
8236
8982
  example: 'STOCK',
8237
8983
  nullable: true
8238
8984
  },
8239
8985
  currency: {
8240
- type: 'object',
8986
+ type: 'string',
8241
8987
  description: 'Trading currency (extra_data or inferred from exchange)',
8242
8988
  example: 'USD',
8243
8989
  nullable: true
@@ -8254,90 +9000,90 @@ export const $SymbolQuoteDto = {
8254
9000
  example: 'AAPL'
8255
9001
  },
8256
9002
  name: {
8257
- type: 'object',
9003
+ type: 'string',
8258
9004
  example: 'Apple Inc.',
8259
9005
  nullable: true
8260
9006
  },
8261
9007
  exchange: {
8262
- type: 'object',
9008
+ type: 'string',
8263
9009
  example: 'US',
8264
9010
  nullable: true
8265
9011
  },
8266
9012
  assetType: {
8267
- type: 'object',
9013
+ type: 'string',
8268
9014
  description: 'OpenBB asset_type',
8269
9015
  example: 'stock',
8270
9016
  nullable: true
8271
9017
  },
8272
9018
  assetClass: {
8273
- type: 'object',
9019
+ type: 'string',
8274
9020
  description: 'IGN asset class',
8275
9021
  example: 'EQUITY',
8276
9022
  nullable: true
8277
9023
  },
8278
9024
  assetSubClass: {
8279
- type: 'object',
9025
+ type: 'string',
8280
9026
  description: 'IGN asset sub-class',
8281
9027
  example: 'STOCK',
8282
9028
  nullable: true
8283
9029
  },
8284
9030
  currency: {
8285
- type: 'object',
9031
+ type: 'string',
8286
9032
  description: 'Trading currency (extra_data or inferred from exchange)',
8287
9033
  example: 'USD',
8288
9034
  nullable: true
8289
9035
  },
8290
9036
  price: {
8291
- type: 'object',
9037
+ type: 'string',
8292
9038
  description: 'Latest price (Decimal string)',
8293
9039
  example: '189.84',
8294
9040
  nullable: true
8295
9041
  },
8296
9042
  priceDate: {
8297
- type: 'object',
9043
+ type: 'string',
8298
9044
  description: 'Date the price was observed (ISO yyyy-MM-dd)',
8299
9045
  example: '2026-08-05',
8300
9046
  nullable: true
8301
9047
  },
8302
9048
  changePercent: {
8303
- type: 'object',
9049
+ type: 'number',
8304
9050
  description:
8305
9051
  '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.',
8306
9052
  example: 1.7,
8307
9053
  nullable: true
8308
9054
  },
8309
9055
  prevClose: {
8310
- type: 'object',
9056
+ type: 'string',
8311
9057
  description: 'Previous close (Decimal string)',
8312
9058
  nullable: true
8313
9059
  },
8314
9060
  open: {
8315
- type: 'object',
9061
+ type: 'string',
8316
9062
  description: 'Day open (Decimal string)',
8317
9063
  nullable: true
8318
9064
  },
8319
9065
  high: {
8320
- type: 'object',
9066
+ type: 'string',
8321
9067
  description: 'Day high (Decimal string)',
8322
9068
  nullable: true
8323
9069
  },
8324
9070
  low: {
8325
- type: 'object',
9071
+ type: 'string',
8326
9072
  description: 'Day low (Decimal string)',
8327
9073
  nullable: true
8328
9074
  },
8329
9075
  volume: {
8330
- type: 'object',
9076
+ type: 'string',
8331
9077
  description: 'Day volume (Decimal string)',
8332
9078
  nullable: true
8333
9079
  },
8334
9080
  yearHigh: {
8335
- type: 'object',
9081
+ type: 'string',
8336
9082
  description: '52-week high (Decimal string)',
8337
9083
  nullable: true
8338
9084
  },
8339
9085
  yearLow: {
8340
- type: 'object',
9086
+ type: 'string',
8341
9087
  description: '52-week low (Decimal string)',
8342
9088
  nullable: true
8343
9089
  }