@firela/api-types 0.0.0-canary.e7fcdb9d → 0.0.0-canary.e85e9088

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.
@@ -197,7 +197,7 @@ export const $AccountResponseDto = {
197
197
  }
198
198
  },
199
199
  platformId: {
200
- type: 'object',
200
+ type: 'string',
201
201
  description: 'Platform ID (null if unbound)',
202
202
  example: 'c98e5d4a-2f71-4a5a-bb3c-92c9f231d5e2'
203
203
  },
@@ -377,16 +377,43 @@ export const $AccountStandardResponseDto = {
377
377
  },
378
378
  name: {
379
379
  type: 'string',
380
- description: 'Short localized display name',
380
+ description:
381
+ '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
382
  example: 'Housing Fund'
382
383
  },
384
+ aliases: {
385
+ description:
386
+ '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.',
387
+ example: ['Alipay', 'WeChat Pay'],
388
+ type: 'array',
389
+ items: {
390
+ type: 'string'
391
+ }
392
+ },
393
+ searchTerms: {
394
+ description:
395
+ '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).',
396
+ example: ['yinhangka', 'jiejika'],
397
+ type: 'array',
398
+ items: {
399
+ type: 'string'
400
+ }
401
+ },
402
+ currency: {
403
+ type: 'string',
404
+ description:
405
+ '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).',
406
+ example: 'HKD'
407
+ },
383
408
  description: {
384
409
  type: 'string',
385
- description: 'Account description (stable semantics only)',
410
+ description:
411
+ '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
412
  example: 'ICBC checking account for daily transactions'
387
413
  },
388
414
  tags: {
389
- description: 'Account tags for categorization',
415
+ description:
416
+ 'Account tags for categorization — structured metadata delivered verbatim (not localized, not xlf-managed). ADR-0131 class A.',
390
417
  example: ['bank', 'checking', 'primary'],
391
418
  type: 'array',
392
419
  items: {
@@ -498,7 +525,10 @@ export const $RegionConfigDto = {
498
525
  },
499
526
  locale: {
500
527
  type: 'string',
501
- example: 'de-DE'
528
+ example: 'de-DE',
529
+ pattern: '^[a-z]{2,8}-[A-Z]{2}$',
530
+ description:
531
+ "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
532
  }
503
533
  },
504
534
  required: ['currency', 'dateFormat', 'locale']
@@ -511,6 +541,12 @@ export const $RegionInfoDto = {
511
541
  type: 'string',
512
542
  example: 'de'
513
543
  },
544
+ open: {
545
+ type: 'boolean',
546
+ example: true,
547
+ description:
548
+ '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.'
549
+ },
514
550
  displayName: {
515
551
  type: 'string',
516
552
  example: 'Germany'
@@ -529,7 +565,7 @@ export const $RegionInfoDto = {
529
565
  $ref: '#/components/schemas/RegionConfigDto'
530
566
  }
531
567
  },
532
- required: ['code', 'displayName', 'chain', 'config']
568
+ required: ['code', 'open', 'displayName', 'chain', 'config']
533
569
  } as const;
534
570
 
535
571
  export const $RegionsMetadataResponseDto = {
@@ -776,7 +812,7 @@ export const $PostingResponseDto = {
776
812
  units: {
777
813
  type: 'string',
778
814
  description:
779
- 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned.',
815
+ '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
816
  example: '100.50'
781
817
  },
782
818
  currency: {
@@ -1142,7 +1178,7 @@ export const $PostingDetailDto = {
1142
1178
  units: {
1143
1179
  type: 'string',
1144
1180
  description:
1145
- 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned.',
1181
+ '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
1182
  example: '100.50'
1147
1183
  },
1148
1184
  currency: {
@@ -1326,6 +1362,147 @@ export const $TransactionDetailDto = {
1326
1362
  ]
1327
1363
  } as const;
1328
1364
 
1365
+ export const $TransactionListItemDto = {
1366
+ type: 'object',
1367
+ properties: {
1368
+ id: {
1369
+ type: 'string',
1370
+ description: 'Transaction ID',
1371
+ example: 'clh1234567890abcdef'
1372
+ },
1373
+ date: {
1374
+ type: 'string',
1375
+ description: 'Transaction date',
1376
+ example: '2024-11-28'
1377
+ },
1378
+ flag: {
1379
+ type: 'string',
1380
+ description: 'Transaction flag',
1381
+ enum: [
1382
+ 'CLEARED',
1383
+ 'PENDING',
1384
+ 'PADDING',
1385
+ 'SUMMARIZE',
1386
+ 'TRANSFER',
1387
+ 'CONVERSIONS'
1388
+ ],
1389
+ example: 'CLEARED'
1390
+ },
1391
+ customFlag: {
1392
+ type: 'string',
1393
+ description: 'Custom flag (if not using standard flags)',
1394
+ example: 'R'
1395
+ },
1396
+ payee: {
1397
+ type: 'string',
1398
+ description: 'Payee name',
1399
+ example: 'Whole Foods Market'
1400
+ },
1401
+ narration: {
1402
+ type: 'string',
1403
+ description: 'Transaction narration',
1404
+ example: 'Grocery shopping'
1405
+ },
1406
+ tags: {
1407
+ description: 'Transaction tags',
1408
+ example: ['groceries'],
1409
+ type: 'array',
1410
+ items: {
1411
+ type: 'string'
1412
+ }
1413
+ },
1414
+ links: {
1415
+ description: 'Transaction links',
1416
+ example: ['invoice-2024-001'],
1417
+ type: 'array',
1418
+ items: {
1419
+ type: 'string'
1420
+ }
1421
+ },
1422
+ meta: {
1423
+ type: 'object',
1424
+ description: 'Transaction metadata'
1425
+ },
1426
+ status: {
1427
+ type: 'string',
1428
+ description: 'Transaction status',
1429
+ enum: ['ACTIVE', 'VOIDED', 'SUPERSEDED'],
1430
+ example: 'ACTIVE'
1431
+ },
1432
+ sourceType: {
1433
+ type: 'string',
1434
+ description:
1435
+ 'Source type (free-form string from transaction metadata, e.g. import, api)'
1436
+ },
1437
+ sourcePlatform: {
1438
+ type: 'string',
1439
+ description: 'Source platform (e.g., alipay, wechat)',
1440
+ example: 'alipay'
1441
+ },
1442
+ postings: {
1443
+ description: 'Transaction postings',
1444
+ type: 'array',
1445
+ items: {
1446
+ $ref: '#/components/schemas/PostingDetailDto'
1447
+ }
1448
+ },
1449
+ createdAt: {
1450
+ type: 'string',
1451
+ description: 'Created at timestamp',
1452
+ example: '2024-11-28T10:30:00.000Z'
1453
+ },
1454
+ voidedAt: {
1455
+ type: 'string',
1456
+ description: 'Voided at timestamp (if voided)',
1457
+ example: '2024-11-29T15:00:00.000Z'
1458
+ },
1459
+ voidedBy: {
1460
+ type: 'string',
1461
+ description: 'User ID who voided this transaction',
1462
+ example: 'clh1234567890abcdef'
1463
+ },
1464
+ correctionReason: {
1465
+ type: 'string',
1466
+ description: 'Correction reason (if voided or superseded)',
1467
+ example: 'Duplicate entry'
1468
+ },
1469
+ supersededBy: {
1470
+ type: 'string',
1471
+ description:
1472
+ 'ID of the transaction that supersedes this one (set when status=SUPERSEDED)',
1473
+ example: 'clh1234567890abcdef'
1474
+ },
1475
+ originalTxn: {
1476
+ type: 'string',
1477
+ description:
1478
+ 'ID of the transaction this one corrected/replaced (back-link on the replacement)',
1479
+ example: 'clh1234567890abcdef'
1480
+ },
1481
+ viewpointAmount: {
1482
+ type: 'string',
1483
+ description:
1484
+ '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.',
1485
+ example: '10000.00'
1486
+ },
1487
+ viewpointCurrency: {
1488
+ type: 'string',
1489
+ description:
1490
+ 'Currency of viewpointAmount. A row spanning multiple currencies takes the largest-magnitude currency group (known simplification, ADR-0126).',
1491
+ example: 'CNY'
1492
+ }
1493
+ },
1494
+ required: [
1495
+ 'id',
1496
+ 'date',
1497
+ 'narration',
1498
+ 'tags',
1499
+ 'links',
1500
+ 'status',
1501
+ 'postings',
1502
+ 'createdAt'
1503
+ ]
1504
+ } as const;
1505
+
1329
1506
  export const $BalanceByCurrencyDto = {
1330
1507
  type: 'object',
1331
1508
  properties: {
@@ -1371,7 +1548,7 @@ export const $TransactionListSummaryDto = {
1371
1548
  totalAmount: {
1372
1549
  type: 'string',
1373
1550
  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.',
1551
+ '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
1552
  example: '-6000.00'
1376
1553
  },
1377
1554
  currency: {
@@ -1397,6 +1574,26 @@ export const $TransactionListSummaryDto = {
1397
1574
  required: ['totalAmount', 'currency', 'balanceByCurrency']
1398
1575
  } as const;
1399
1576
 
1577
+ export const $TransactionListViewpointDto = {
1578
+ type: 'object',
1579
+ properties: {
1580
+ type: {
1581
+ type: 'string',
1582
+ description:
1583
+ 'Viewpoint type (only category drill-down carries a viewpoint today)',
1584
+ enum: ['category'],
1585
+ example: 'category'
1586
+ },
1587
+ flow: {
1588
+ type: 'string',
1589
+ description: 'Flow root the category account set is restricted to',
1590
+ enum: ['income', 'expense'],
1591
+ example: 'expense'
1592
+ }
1593
+ },
1594
+ required: ['type', 'flow']
1595
+ } as const;
1596
+
1400
1597
  export const $TransactionListResponseDto = {
1401
1598
  type: 'object',
1402
1599
  properties: {
@@ -1404,7 +1601,7 @@ export const $TransactionListResponseDto = {
1404
1601
  description: 'List of transactions',
1405
1602
  type: 'array',
1406
1603
  items: {
1407
- $ref: '#/components/schemas/TransactionDetailDto'
1604
+ $ref: '#/components/schemas/TransactionListItemDto'
1408
1605
  }
1409
1606
  },
1410
1607
  total: {
@@ -1430,6 +1627,15 @@ export const $TransactionListResponseDto = {
1430
1627
  $ref: '#/components/schemas/TransactionListSummaryDto'
1431
1628
  }
1432
1629
  ]
1630
+ },
1631
+ viewpoint: {
1632
+ description:
1633
+ '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).',
1634
+ allOf: [
1635
+ {
1636
+ $ref: '#/components/schemas/TransactionListViewpointDto'
1637
+ }
1638
+ ]
1433
1639
  }
1434
1640
  },
1435
1641
  required: ['data', 'total', 'limit', 'offset']
@@ -2340,10 +2546,10 @@ export const $UpdatePayeeDto = {
2340
2546
  meta: {
2341
2547
  type: 'object',
2342
2548
  description:
2343
- 'Metadata for extended information (location, notes, contact info, etc.). Will merge with existing metadata.',
2549
+ 'Metadata for extended information (location, notes, contact info, etc.)',
2344
2550
  example: {
2345
2551
  location: 'Zhongguancun',
2346
- note: 'Updated note',
2552
+ note: 'Near subway station',
2347
2553
  favorite: true
2348
2554
  }
2349
2555
  },
@@ -2904,568 +3110,660 @@ export const $UpdateCommodityDto = {
2904
3110
  }
2905
3111
  } as const;
2906
3112
 
2907
- export const $CreateBeanPriceDto = {
3113
+ export const $CurrencyBalanceDto = {
2908
3114
  type: 'object',
2909
3115
  properties: {
2910
3116
  currency: {
2911
3117
  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)',
3118
+ description: 'ISO 4217 currency code',
2918
3119
  example: 'CNY'
2919
3120
  },
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: {
3121
+ balance: {
2928
3122
  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
- }
3123
+ description: 'Balance amount',
3124
+ example: '500000.00'
2941
3125
  }
2942
3126
  },
2943
- required: ['currency', 'quoteCurrency', 'amount', 'date']
3127
+ required: ['currency', 'balance']
2944
3128
  } as const;
2945
3129
 
2946
- export const $PriceResponseDto = {
3130
+ export const $TimeSeriesPointDto = {
2947
3131
  type: 'object',
2948
3132
  properties: {
2949
- id: {
3133
+ date: {
2950
3134
  type: 'string',
2951
- description: 'Unique identifier',
2952
- example: 'uuid-123-456'
3135
+ description: 'Date in YYYY-MM-DD format',
3136
+ example: '2024-06-15'
2953
3137
  },
2954
- userId: {
3138
+ value: {
2955
3139
  type: 'string',
2956
- description: 'User ID (owner of the price)',
2957
- example: 'user-123'
3140
+ description: 'Value at this date (in base currency)',
3141
+ example: '500000.00'
2958
3142
  },
2959
- currency: {
3143
+ change: {
2960
3144
  type: 'string',
2961
- description: 'Currency being priced (e.g., USD, AAPL, BTC)',
2962
- example: 'BTC'
3145
+ description: 'Change from previous point',
3146
+ example: '5000.00'
2963
3147
  },
2964
- quoteCurrency: {
3148
+ assets: {
2965
3149
  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
3150
+ description: 'Total assets at this date (in base currency)',
3151
+ example: '494338.00'
2974
3152
  },
2975
- date: {
3153
+ liabilities: {
2976
3154
  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'
2981
- },
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
3155
+ description: 'Total liabilities at this date (in base currency)',
3156
+ example: '310098.00'
3157
+ },
3158
+ byCurrency: {
3159
+ description: 'Multi-currency breakdown for this point',
3160
+ type: 'array',
3161
+ items: {
3162
+ $ref: '#/components/schemas/CurrencyBalanceDto'
2990
3163
  }
3164
+ }
3165
+ },
3166
+ required: ['date', 'value']
3167
+ } as const;
3168
+
3169
+ export const $TrendSummaryDto = {
3170
+ type: 'object',
3171
+ properties: {
3172
+ startValue: {
3173
+ type: 'string',
3174
+ description: 'Value at start of period',
3175
+ example: '450000.00'
2991
3176
  },
2992
- createdAt: {
2993
- format: 'date-time',
3177
+ endValue: {
2994
3178
  type: 'string',
2995
- description: 'Creation timestamp',
2996
- example: '2024-11-03T10:00:00Z'
3179
+ description: 'Value at end of period',
3180
+ example: '500000.00'
2997
3181
  },
2998
- updatedAt: {
2999
- format: 'date-time',
3182
+ totalChange: {
3000
3183
  type: 'string',
3001
- description: 'Last update timestamp',
3002
- example: '2024-11-03T10:00:00Z'
3184
+ description: 'Total change over period',
3185
+ example: '50000.00'
3186
+ },
3187
+ totalChangePercentage: {
3188
+ type: 'string',
3189
+ description: 'Total change percentage',
3190
+ example: '+11.11%'
3003
3191
  }
3004
3192
  },
3005
- required: [
3006
- 'id',
3007
- 'userId',
3008
- 'currency',
3009
- 'quoteCurrency',
3010
- 'amount',
3011
- 'date',
3012
- 'meta',
3013
- 'createdAt',
3014
- 'updatedAt'
3015
- ]
3193
+ required: ['startValue', 'endValue', 'totalChange', 'totalChangePercentage']
3016
3194
  } as const;
3017
3195
 
3018
- export const $PriceListResponseDto = {
3196
+ export const $MultiCurrencyPointDto = {
3019
3197
  type: 'object',
3020
3198
  properties: {
3021
- items: {
3022
- description: 'List of prices',
3199
+ date: {
3200
+ type: 'string',
3201
+ description: 'Date in YYYY-MM-DD format',
3202
+ example: '2024-06-15'
3203
+ },
3204
+ byCurrency: {
3205
+ description: 'Balances by currency',
3023
3206
  type: 'array',
3024
3207
  items: {
3025
- $ref: '#/components/schemas/PriceResponseDto'
3208
+ $ref: '#/components/schemas/CurrencyBalanceDto'
3026
3209
  }
3027
- },
3028
- total: {
3029
- type: 'number',
3030
- description: 'Total number of prices',
3031
- example: 42
3032
3210
  }
3033
3211
  },
3034
- required: ['items', 'total']
3212
+ required: ['date', 'byCurrency']
3035
3213
  } as const;
3036
3214
 
3037
- export const $UpdateBeanPriceDto = {
3215
+ export const $PortfolioTrendsResponseDto = {
3038
3216
  type: 'object',
3039
3217
  properties: {
3040
- currency: {
3041
- type: 'string',
3042
- description: 'Currency being priced'
3218
+ series: {
3219
+ description: 'Time series data points',
3220
+ type: 'array',
3221
+ items: {
3222
+ $ref: '#/components/schemas/TimeSeriesPointDto'
3223
+ }
3043
3224
  },
3044
- quoteCurrency: {
3225
+ summary: {
3226
+ description: 'Period summary',
3227
+ allOf: [
3228
+ {
3229
+ $ref: '#/components/schemas/TrendSummaryDto'
3230
+ }
3231
+ ]
3232
+ },
3233
+ period: {
3045
3234
  type: 'string',
3046
- description: 'Quote currency (pricing currency)'
3235
+ description: 'Period requested',
3236
+ example: '6m'
3047
3237
  },
3048
- amount: {
3049
- type: 'number',
3050
- description: 'Price amount (MUST be >= 0 per Beancount spec)',
3051
- minimum: 0
3238
+ granularity: {
3239
+ type: 'string',
3240
+ description: 'Data granularity',
3241
+ example: 'month'
3052
3242
  },
3053
- date: {
3243
+ currency: {
3054
3244
  type: 'string',
3055
- description: 'Price date (ISO 8601 format)'
3245
+ description: 'Base currency for converted values',
3246
+ example: 'CNY'
3056
3247
  },
3057
- metadata: {
3058
- type: 'object',
3059
- description: 'Metadata'
3248
+ byCurrency: {
3249
+ description:
3250
+ 'Multi-currency time series (each point has currency breakdown)',
3251
+ type: 'array',
3252
+ items: {
3253
+ $ref: '#/components/schemas/MultiCurrencyPointDto'
3254
+ }
3255
+ },
3256
+ warnings: {
3257
+ description: 'Exchange rate warnings',
3258
+ type: 'array',
3259
+ items: {
3260
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
3261
+ }
3060
3262
  }
3061
- }
3263
+ },
3264
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
3062
3265
  } as const;
3063
3266
 
3064
- export const $CreateRecurringRuleDto = {
3267
+ export const $CashFlowPointDto = {
3065
3268
  type: 'object',
3066
3269
  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: {
3270
+ month: {
3078
3271
  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
3272
+ description: 'Month key (YYYY-MM)',
3273
+ example: '2024-03'
3105
3274
  },
3106
- currency: {
3275
+ income: {
3107
3276
  type: 'string',
3108
- description: 'Currency code',
3109
- default: 'CNY',
3110
- maxLength: 10
3277
+ description: 'Income in base currency (absolute, converted)',
3278
+ example: '10000.00'
3111
3279
  },
3112
- matchPayeePattern: {
3280
+ expense: {
3113
3281
  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
3282
+ description: 'Expense in base currency (absolute, converted)',
3283
+ example: '5000.00'
3123
3284
  },
3124
- defaultExpenseAccount: {
3285
+ netSavings: {
3125
3286
  type: 'string',
3126
- description: 'Default expense account for auto-create',
3127
- maxLength: 200
3128
- },
3129
- defaultPaymentAccount: {
3287
+ description: 'netSavings = income − expense (savings positive)',
3288
+ example: '5000.00'
3289
+ }
3290
+ },
3291
+ required: ['month', 'income', 'expense', 'netSavings']
3292
+ } as const;
3293
+
3294
+ export const $CashFlowTrendSummaryDto = {
3295
+ type: 'object',
3296
+ properties: {
3297
+ totalIncome: {
3130
3298
  type: 'string',
3131
- description: 'Default payment account for auto-create',
3132
- maxLength: 200
3299
+ description: 'Total income across the period',
3300
+ example: '60000.00'
3133
3301
  },
3134
- defaultPayee: {
3302
+ totalExpense: {
3135
3303
  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
3304
+ description: 'Total expense across the period',
3305
+ example: '30000.00'
3143
3306
  },
3144
- startDate: {
3307
+ totalNetSavings: {
3145
3308
  type: 'string',
3146
- description: 'Rule start date (ISO format)'
3309
+ description: 'income − expense across the period',
3310
+ example: '30000.00'
3147
3311
  },
3148
- endDate: {
3312
+ averageMonthlyNetSavings: {
3149
3313
  type: 'string',
3150
- description: 'Rule end date (ISO format)'
3314
+ description:
3315
+ 'totalNetSavings divided by the window length (N months, incl. zero-filled)',
3316
+ example: '5000.00'
3151
3317
  }
3152
3318
  },
3153
3319
  required: [
3154
- 'name',
3155
- 'frequency',
3156
- 'expectedAmount',
3157
- 'currency',
3158
- 'matchAmountTolerance',
3159
- 'autoCreate'
3320
+ 'totalIncome',
3321
+ 'totalExpense',
3322
+ 'totalNetSavings',
3323
+ 'averageMonthlyNetSavings'
3160
3324
  ]
3161
3325
  } as const;
3162
3326
 
3163
- export const $RecurringRuleResponseDto = {
3327
+ export const $CashFlowTrendsResponseDto = {
3164
3328
  type: 'object',
3165
3329
  properties: {
3166
- id: {
3167
- type: 'string',
3168
- description: 'Rule ID'
3169
- },
3170
- userId: {
3171
- type: 'string',
3172
- description: 'User ID'
3173
- },
3174
- name: {
3175
- type: 'string',
3176
- description: 'Rule name'
3330
+ series: {
3331
+ description:
3332
+ 'Monthly cash-flow series (fixed N-month window, zero-filled)',
3333
+ type: 'array',
3334
+ items: {
3335
+ $ref: '#/components/schemas/CashFlowPointDto'
3336
+ }
3177
3337
  },
3178
- icon: {
3179
- type: 'object',
3180
- description: 'Icon emoji'
3338
+ summary: {
3339
+ description: 'Period totals',
3340
+ allOf: [
3341
+ {
3342
+ $ref: '#/components/schemas/CashFlowTrendSummaryDto'
3343
+ }
3344
+ ]
3181
3345
  },
3182
- frequency: {
3346
+ period: {
3183
3347
  type: 'string',
3184
- description: 'Recurring frequency'
3185
- },
3186
- expectedAmount: {
3187
- type: 'number',
3188
- description: 'Expected amount'
3348
+ description: 'Period requested',
3349
+ example: '6m'
3189
3350
  },
3190
- expectedDay: {
3191
- type: 'object',
3192
- description: 'Expected day of month'
3351
+ granularity: {
3352
+ type: 'string',
3353
+ description: 'Data granularity (v1 returns month buckets)',
3354
+ example: 'month'
3193
3355
  },
3194
- customIntervalDays: {
3195
- type: 'object',
3196
- description: 'Custom interval in days'
3356
+ currency: {
3357
+ type: 'string',
3358
+ description: 'Base currency for converted values',
3359
+ example: 'CNY'
3197
3360
  },
3361
+ warnings: {
3362
+ description: 'Exchange rate warnings (e.g. missing rate for a currency)',
3363
+ type: 'array',
3364
+ items: {
3365
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
3366
+ }
3367
+ }
3368
+ },
3369
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
3370
+ } as const;
3371
+
3372
+ export const $GenerateSnapshotBody = {
3373
+ type: 'object',
3374
+ properties: {}
3375
+ } as const;
3376
+
3377
+ export const $GenerateSnapshotResponse = {
3378
+ type: 'object',
3379
+ properties: {}
3380
+ } as const;
3381
+
3382
+ export const $BackfillSnapshotsBody = {
3383
+ type: 'object',
3384
+ properties: {}
3385
+ } as const;
3386
+
3387
+ export const $BackfillSnapshotsResponse = {
3388
+ type: 'object',
3389
+ properties: {}
3390
+ } as const;
3391
+
3392
+ export const $CreateBeanPriceDto = {
3393
+ type: 'object',
3394
+ properties: {
3198
3395
  currency: {
3199
3396
  type: 'string',
3200
- description: 'Currency code'
3397
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
3398
+ example: 'USD'
3201
3399
  },
3202
- matchPayeePattern: {
3203
- type: 'object',
3204
- description: 'Payee matching pattern'
3400
+ quoteCurrency: {
3401
+ type: 'string',
3402
+ description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
3403
+ example: 'CNY'
3205
3404
  },
3206
- matchAmountTolerance: {
3405
+ amount: {
3207
3406
  type: 'number',
3208
- description: 'Amount tolerance percentage'
3407
+ description:
3408
+ 'Price amount (MUST be >= 0 per Beancount spec, supports up to 15 decimal places). Zero allowed for conversion entries, negative strictly prohibited.',
3409
+ example: 175.5,
3410
+ minimum: 0
3209
3411
  },
3210
- defaultExpenseAccount: {
3211
- type: 'object',
3212
- description: 'Default expense account'
3412
+ date: {
3413
+ type: 'string',
3414
+ description: 'Price date (ISO 8601 format)',
3415
+ example: '2024-11-05'
3213
3416
  },
3214
- defaultPaymentAccount: {
3417
+ metadata: {
3215
3418
  type: 'object',
3216
- description: 'Default payment account'
3419
+ description:
3420
+ 'Metadata (validated by Zod schema, max field lengths enforced)',
3421
+ example: {
3422
+ source: 'MANUAL',
3423
+ note: 'Bank valuation report',
3424
+ confidence: 0.95
3425
+ }
3426
+ }
3427
+ },
3428
+ required: ['currency', 'quoteCurrency', 'amount', 'date']
3429
+ } as const;
3430
+
3431
+ export const $PriceResponseDto = {
3432
+ type: 'object',
3433
+ properties: {
3434
+ id: {
3435
+ type: 'string',
3436
+ description: 'Unique identifier',
3437
+ example: 'uuid-123-456'
3217
3438
  },
3218
- defaultPayee: {
3219
- type: 'object',
3220
- description: 'Default payee'
3439
+ userId: {
3440
+ type: 'string',
3441
+ description: 'User ID (owner of the price)',
3442
+ example: 'user-123'
3221
3443
  },
3222
- isActive: {
3223
- type: 'boolean',
3224
- description: 'Whether rule is active'
3444
+ currency: {
3445
+ type: 'string',
3446
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
3447
+ example: 'BTC'
3225
3448
  },
3226
- startDate: {
3449
+ quoteCurrency: {
3227
3450
  type: 'string',
3228
- description: 'Rule start date (YYYY-MM-DD)'
3451
+ description: 'Quote currency (pricing currency, e.g., USD, CNY)',
3452
+ example: 'USD'
3229
3453
  },
3230
- endDate: {
3231
- type: 'object',
3232
- description: 'Rule end date (YYYY-MM-DD)'
3454
+ amount: {
3455
+ type: 'number',
3456
+ description:
3457
+ 'Price amount (corresponds to Beancount Amount.number). Supports up to 15 decimal places.',
3458
+ example: 50000
3233
3459
  },
3234
- autoCreate: {
3235
- type: 'boolean',
3236
- description: 'Auto-create transaction on expected date'
3460
+ date: {
3461
+ type: 'string',
3462
+ description:
3463
+ 'Price date (ISO 8601 format). Represents the date this price was valid.',
3464
+ example: '2024-01-01',
3465
+ format: 'date'
3237
3466
  },
3238
- lastOccurrence: {
3467
+ meta: {
3239
3468
  type: 'object',
3240
- description: 'Last matched occurrence date (YYYY-MM-DD)'
3241
- },
3242
- totalCount: {
3243
- type: 'number',
3244
- description: 'Total matched transactions count'
3469
+ description:
3470
+ 'Metadata (corresponds to Beancount meta field). Contains source, confidence, note, etc.',
3471
+ example: {
3472
+ source: 'MANUAL',
3473
+ note: 'User-defined price',
3474
+ confidence: 1
3475
+ }
3245
3476
  },
3246
3477
  createdAt: {
3247
3478
  format: 'date-time',
3248
3479
  type: 'string',
3249
- description: 'Created at timestamp'
3480
+ description: 'Creation timestamp',
3481
+ example: '2024-11-03T10:00:00Z'
3250
3482
  },
3251
3483
  updatedAt: {
3252
3484
  format: 'date-time',
3253
3485
  type: 'string',
3254
- description: 'Updated at timestamp'
3486
+ description: 'Last update timestamp',
3487
+ example: '2024-11-03T10:00:00Z'
3255
3488
  }
3256
3489
  },
3257
3490
  required: [
3258
3491
  'id',
3259
3492
  'userId',
3260
- 'name',
3261
- 'frequency',
3262
- 'expectedAmount',
3263
3493
  'currency',
3264
- 'matchAmountTolerance',
3265
- 'isActive',
3266
- 'startDate',
3267
- 'autoCreate',
3268
- 'totalCount',
3494
+ 'quoteCurrency',
3495
+ 'amount',
3496
+ 'date',
3497
+ 'meta',
3269
3498
  'createdAt',
3270
3499
  'updatedAt'
3271
3500
  ]
3272
3501
  } as const;
3273
3502
 
3274
- export const $CreateRuleFromTransactionDto = {
3503
+ export const $PriceListResponseDto = {
3275
3504
  type: 'object',
3276
3505
  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
3506
+ items: {
3507
+ description: 'List of prices',
3508
+ type: 'array',
3509
+ items: {
3510
+ $ref: '#/components/schemas/PriceResponseDto'
3511
+ }
3295
3512
  },
3296
- icon: {
3297
- type: 'string',
3298
- description: 'Optional icon emoji',
3299
- maxLength: 10
3513
+ total: {
3514
+ type: 'number',
3515
+ description: 'Total number of prices',
3516
+ example: 42
3300
3517
  }
3301
3518
  },
3302
- required: ['frequency']
3519
+ required: ['items', 'total']
3303
3520
  } as const;
3304
3521
 
3305
- export const $RecurringRuleWithStatsResponseDto = {
3522
+ export const $UpdateBeanPriceDto = {
3306
3523
  type: 'object',
3307
3524
  properties: {
3308
- id: {
3309
- type: 'string',
3310
- description: 'Rule ID'
3311
- },
3312
- userId: {
3525
+ currency: {
3313
3526
  type: 'string',
3314
- description: 'User ID'
3527
+ description: 'Currency being priced'
3315
3528
  },
3316
- name: {
3529
+ quoteCurrency: {
3317
3530
  type: 'string',
3318
- description: 'Rule name'
3531
+ description: 'Quote currency (pricing currency)'
3319
3532
  },
3320
- icon: {
3321
- type: 'object',
3322
- description: 'Icon emoji'
3533
+ amount: {
3534
+ type: 'number',
3535
+ description: 'Price amount (MUST be >= 0 per Beancount spec)',
3536
+ minimum: 0
3323
3537
  },
3324
- frequency: {
3538
+ date: {
3325
3539
  type: 'string',
3326
- description: 'Recurring frequency'
3540
+ description: 'Price date (ISO 8601 format)'
3327
3541
  },
3328
- expectedAmount: {
3329
- type: 'number',
3330
- description: 'Expected amount'
3331
- },
3332
- expectedDay: {
3542
+ metadata: {
3333
3543
  type: 'object',
3334
- description: 'Expected day of month'
3544
+ description: 'Metadata'
3545
+ }
3546
+ }
3547
+ } as const;
3548
+
3549
+ export const $DeleteOwnUserDto = {
3550
+ type: 'object',
3551
+ properties: {
3552
+ accessToken: {
3553
+ type: 'string',
3554
+ description: 'Access token for user verification',
3555
+ example: 'abc123xyz'
3556
+ }
3557
+ },
3558
+ required: ['accessToken']
3559
+ } as const;
3560
+
3561
+ export const $UserSettingsResponseDto = {
3562
+ type: 'object',
3563
+ properties: {
3564
+ baseCurrency: {
3565
+ type: 'string',
3566
+ description:
3567
+ '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).',
3568
+ example: 'USD',
3569
+ nullable: true
3570
+ }
3571
+ },
3572
+ required: ['baseCurrency']
3573
+ } as const;
3574
+
3575
+ export const $UserResponseDto = {
3576
+ type: 'object',
3577
+ properties: {
3578
+ id: {
3579
+ type: 'string',
3580
+ description: 'User ID'
3335
3581
  },
3336
- customIntervalDays: {
3337
- type: 'object',
3338
- description: 'Custom interval in days'
3582
+ role: {
3583
+ type: 'string',
3584
+ description: 'Assigned user role'
3339
3585
  },
3340
- currency: {
3586
+ permissions: {
3587
+ description: 'Permission strings',
3588
+ type: 'array',
3589
+ items: {
3590
+ type: 'string'
3591
+ }
3592
+ },
3593
+ settings: {
3594
+ description: 'User settings',
3595
+ allOf: [
3596
+ {
3597
+ $ref: '#/components/schemas/UserSettingsResponseDto'
3598
+ }
3599
+ ]
3600
+ }
3601
+ },
3602
+ required: ['id', 'role', 'permissions', 'settings']
3603
+ } as const;
3604
+
3605
+ export const $SignupDto = {
3606
+ type: 'object',
3607
+ properties: {
3608
+ turnstileToken: {
3341
3609
  type: 'string',
3342
- description: 'Currency code'
3610
+ description:
3611
+ 'Cloudflare Turnstile verification token (optional when Turnstile disabled)',
3612
+ example: '0.abc123def456...'
3613
+ }
3614
+ }
3615
+ } as const;
3616
+
3617
+ export const $SignupResponseDto = {
3618
+ type: 'object',
3619
+ properties: {
3620
+ authToken: {
3621
+ type: 'string',
3622
+ description: 'JWT auth token',
3623
+ example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
3343
3624
  },
3344
- matchPayeePattern: {
3345
- type: 'object',
3346
- description: 'Payee matching pattern'
3625
+ accessToken: {
3626
+ type: 'string',
3627
+ description: 'Auto-generated access token'
3347
3628
  },
3348
- matchAmountTolerance: {
3629
+ role: {
3630
+ type: 'string',
3631
+ description: 'Assigned user role',
3632
+ enum: ['USER', 'ADMIN', 'DEMO', 'INACTIVE', 'PAID', 'OPS']
3633
+ }
3634
+ },
3635
+ required: ['authToken', 'accessToken', 'role']
3636
+ } as const;
3637
+
3638
+ export const $UpdateUserSettingDto = {
3639
+ type: 'object',
3640
+ properties: {
3641
+ secId: {
3349
3642
  type: 'number',
3350
- description: 'Amount tolerance percentage'
3643
+ description: 'Security ID'
3351
3644
  },
3352
- defaultExpenseAccount: {
3353
- type: 'object',
3354
- description: 'Default expense account'
3645
+ annualInterestRate: {
3646
+ type: 'number',
3647
+ description: 'Annual interest rate',
3648
+ example: 0.05
3355
3649
  },
3356
- defaultPaymentAccount: {
3357
- type: 'object',
3358
- description: 'Default payment account'
3650
+ currency: {
3651
+ type: 'string',
3652
+ description: 'Currency code',
3653
+ example: 'USD'
3359
3654
  },
3360
- defaultPayee: {
3361
- type: 'object',
3362
- description: 'Default payee'
3655
+ baseCurrency: {
3656
+ type: 'string',
3657
+ description: 'Base currency code',
3658
+ example: 'USD'
3363
3659
  },
3364
- isActive: {
3365
- type: 'boolean',
3366
- description: 'Whether rule is active'
3660
+ benchmark: {
3661
+ type: 'string',
3662
+ description: 'Benchmark symbol',
3663
+ example: 'SPY'
3367
3664
  },
3368
- startDate: {
3665
+ colorScheme: {
3369
3666
  type: 'string',
3370
- description: 'Rule start date (YYYY-MM-DD)'
3667
+ description: 'Color scheme',
3668
+ enum: ['DARK', 'LIGHT']
3371
3669
  },
3372
- endDate: {
3373
- type: 'object',
3374
- description: 'Rule end date (YYYY-MM-DD)'
3670
+ dateRange: {
3671
+ type: 'string',
3672
+ description: 'Date range filter',
3673
+ example: '1y'
3375
3674
  },
3376
- autoCreate: {
3377
- type: 'boolean',
3378
- description: 'Auto-create transaction on expected date'
3675
+ emergencyFund: {
3676
+ type: 'number',
3677
+ description: 'Emergency fund amount',
3678
+ example: 10000
3379
3679
  },
3380
- lastOccurrence: {
3381
- type: 'object',
3382
- description: 'Last matched occurrence date (YYYY-MM-DD)'
3680
+ 'filters.accounts': {
3681
+ description: 'Account filter IDs',
3682
+ type: 'array',
3683
+ items: {
3684
+ type: 'string'
3685
+ }
3383
3686
  },
3384
- totalCount: {
3385
- type: 'number',
3386
- description: 'Total matched transactions count'
3687
+ 'filters.assetClasses': {
3688
+ description: 'Asset class filters',
3689
+ type: 'array',
3690
+ items: {
3691
+ type: 'string'
3692
+ }
3387
3693
  },
3388
- createdAt: {
3389
- format: 'date-time',
3694
+ 'filters.dataSource': {
3390
3695
  type: 'string',
3391
- description: 'Created at timestamp'
3696
+ description: 'Data source filter'
3392
3697
  },
3393
- updatedAt: {
3394
- format: 'date-time',
3698
+ 'filters.symbol': {
3395
3699
  type: 'string',
3396
- description: 'Updated at timestamp'
3700
+ description: 'Symbol filter'
3397
3701
  },
3398
- pendingCount: {
3399
- type: 'number',
3400
- description: 'Number of pending expected transactions'
3702
+ 'filters.tags': {
3703
+ description: 'Tag filters',
3704
+ type: 'array',
3705
+ items: {
3706
+ type: 'string'
3707
+ }
3401
3708
  },
3402
- overdueCount: {
3403
- type: 'number',
3404
- description: 'Number of overdue expected transactions'
3709
+ isExperimentalFeatures: {
3710
+ type: 'boolean',
3711
+ description: 'Enable experimental features'
3405
3712
  },
3406
- nextExpectedDate: {
3407
- type: 'object',
3408
- description: 'Next expected date (YYYY-MM-DD)'
3713
+ isRestrictedView: {
3714
+ type: 'boolean',
3715
+ description: 'Enable restricted view mode'
3409
3716
  },
3410
- totalAmount: {
3411
- type: 'number',
3412
- description: 'Total amount of all matched transactions'
3717
+ language: {
3718
+ type: 'string',
3719
+ description: 'Language code',
3720
+ example: 'en'
3413
3721
  },
3414
- averageAmount: {
3415
- type: 'number',
3416
- description: 'Average amount per transaction'
3722
+ locale: {
3723
+ type: 'string',
3724
+ description: 'Locale code',
3725
+ example: 'en-US'
3417
3726
  },
3418
- transactionCount: {
3727
+ projectedTotalAmount: {
3419
3728
  type: 'number',
3420
- description: 'Number of matched transactions'
3421
- },
3422
- firstDate: {
3423
- type: 'object',
3424
- description: 'First matched transaction date (YYYY-MM-DD)'
3729
+ description: 'Projected total amount',
3730
+ example: 1000000
3425
3731
  },
3426
- lastDate: {
3427
- type: 'object',
3428
- description: 'Last matched transaction date (YYYY-MM-DD)'
3732
+ retirementDate: {
3733
+ type: 'string',
3734
+ description: 'Retirement date in ISO 8601 format',
3735
+ example: '2050-01-01'
3429
3736
  },
3430
- variance: {
3737
+ savingsRate: {
3431
3738
  type: 'number',
3432
- description: 'Amount variance (standard deviation squared)'
3739
+ description: 'Savings rate percentage',
3740
+ example: 0.2
3433
3741
  },
3434
- upcomingCount: {
3435
- type: 'number',
3436
- description: 'Number of upcoming expected transactions'
3742
+ viewMode: {
3743
+ type: 'string',
3744
+ description: 'View mode',
3745
+ enum: ['DEFAULT', 'ZEN']
3746
+ }
3747
+ }
3748
+ } as const;
3749
+
3750
+ export const $UpdatePropertyDto = {
3751
+ type: 'object',
3752
+ properties: {
3753
+ value: {
3754
+ type: 'string',
3755
+ description: 'Property value'
3437
3756
  }
3438
3757
  },
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
- ]
3758
+ required: ['value']
3461
3759
  } as const;
3462
3760
 
3463
- export const $UpdateRecurringRuleDto = {
3761
+ export const $CreateRecurringRuleDto = {
3464
3762
  type: 'object',
3465
3763
  properties: {
3466
3764
  name: {
3467
3765
  type: 'string',
3468
- description: 'Rule name',
3766
+ description: 'Rule name (unique per user)',
3469
3767
  maxLength: 100
3470
3768
  },
3471
3769
  icon: {
@@ -3488,7 +3786,7 @@ export const $UpdateRecurringRuleDto = {
3488
3786
  },
3489
3787
  expectedAmount: {
3490
3788
  type: 'number',
3491
- description: 'Expected amount',
3789
+ description: 'Expected amount (positive number)',
3492
3790
  minimum: 0
3493
3791
  },
3494
3792
  expectedDay: {
@@ -3499,7 +3797,7 @@ export const $UpdateRecurringRuleDto = {
3499
3797
  },
3500
3798
  customIntervalDays: {
3501
3799
  type: 'number',
3502
- description: 'Custom interval in days',
3800
+ description: 'Custom interval in days (required for CUSTOM frequency)',
3503
3801
  minimum: 1
3504
3802
  },
3505
3803
  currency: {
@@ -3509,118 +3807,136 @@ export const $UpdateRecurringRuleDto = {
3509
3807
  },
3510
3808
  matchPayeePattern: {
3511
3809
  type: 'string',
3512
- description: 'Payee matching pattern',
3810
+ description: 'Payee matching pattern (supports wildcards)',
3513
3811
  maxLength: 200
3514
3812
  },
3515
3813
  matchAmountTolerance: {
3516
3814
  type: 'number',
3517
3815
  description: 'Amount tolerance percentage (0-1)',
3816
+ default: 0.075,
3518
3817
  minimum: 0,
3519
3818
  maximum: 1
3520
3819
  },
3521
3820
  defaultExpenseAccount: {
3522
3821
  type: 'string',
3523
- description: 'Default expense account',
3822
+ description: 'Default expense account for auto-create',
3524
3823
  maxLength: 200
3525
3824
  },
3526
3825
  defaultPaymentAccount: {
3527
3826
  type: 'string',
3528
- description: 'Default payment account',
3827
+ description: 'Default payment account for auto-create',
3529
3828
  maxLength: 200
3530
3829
  },
3531
3830
  defaultPayee: {
3532
3831
  type: 'string',
3533
- description: 'Default payee',
3832
+ description: 'Default payee for auto-create',
3534
3833
  maxLength: 200
3535
3834
  },
3536
3835
  autoCreate: {
3537
3836
  type: 'boolean',
3538
- description: 'Auto-create transaction'
3837
+ description: 'Auto-create transaction when expected date arrives',
3838
+ default: false
3539
3839
  },
3540
- isActive: {
3541
- type: 'boolean',
3542
- description: 'Rule active status'
3840
+ startDate: {
3841
+ type: 'string',
3842
+ description: 'Rule start date (ISO format)'
3543
3843
  },
3544
3844
  endDate: {
3545
3845
  type: 'string',
3546
3846
  description: 'Rule end date (ISO format)'
3547
3847
  }
3548
- }
3848
+ },
3849
+ required: [
3850
+ 'name',
3851
+ 'frequency',
3852
+ 'expectedAmount',
3853
+ 'matchAmountTolerance',
3854
+ 'autoCreate'
3855
+ ]
3549
3856
  } as const;
3550
3857
 
3551
- export const $ExpectedTransactionRuleDto = {
3858
+ export const $RecurringRuleResponseDto = {
3552
3859
  type: 'object',
3553
3860
  properties: {
3861
+ id: {
3862
+ type: 'string',
3863
+ description: 'Rule ID'
3864
+ },
3865
+ userId: {
3866
+ type: 'string',
3867
+ description: 'User ID'
3868
+ },
3554
3869
  name: {
3555
3870
  type: 'string',
3556
3871
  description: 'Rule name'
3557
3872
  },
3558
3873
  icon: {
3559
- type: 'object',
3560
- description: 'Rule icon'
3874
+ type: 'string',
3875
+ description: 'Icon emoji'
3561
3876
  },
3562
3877
  frequency: {
3563
3878
  type: 'string',
3564
- description: 'Rule frequency'
3879
+ description: 'Recurring frequency'
3880
+ },
3881
+ expectedAmount: {
3882
+ type: 'number',
3883
+ description: 'Expected amount'
3884
+ },
3885
+ expectedDay: {
3886
+ type: 'number',
3887
+ description: 'Expected day of month'
3888
+ },
3889
+ customIntervalDays: {
3890
+ type: 'number',
3891
+ description: 'Custom interval in days'
3565
3892
  },
3566
3893
  currency: {
3567
3894
  type: 'string',
3568
3895
  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
3896
  },
3581
- userId: {
3897
+ matchPayeePattern: {
3582
3898
  type: 'string',
3583
- description: 'User ID'
3899
+ description: 'Payee matching pattern'
3584
3900
  },
3585
- ruleId: {
3586
- type: 'string',
3587
- description: 'Associated rule ID'
3901
+ matchAmountTolerance: {
3902
+ type: 'number',
3903
+ description: 'Amount tolerance percentage'
3588
3904
  },
3589
- expectedDate: {
3905
+ defaultExpenseAccount: {
3590
3906
  type: 'string',
3591
- description: 'Expected date (YYYY-MM-DD)'
3907
+ description: 'Default expense account'
3592
3908
  },
3593
- expectedAmount: {
3594
- type: 'number',
3595
- description: 'Expected amount'
3909
+ defaultPaymentAccount: {
3910
+ type: 'string',
3911
+ description: 'Default payment account'
3596
3912
  },
3597
- status: {
3913
+ defaultPayee: {
3598
3914
  type: 'string',
3599
- description: 'Status (PENDING, COMPLETED, SKIPPED)'
3915
+ description: 'Default payee'
3600
3916
  },
3601
- matchedTransactionId: {
3602
- type: 'object',
3603
- description: 'Matched transaction ID'
3917
+ isActive: {
3918
+ type: 'boolean',
3919
+ description: 'Whether rule is active'
3604
3920
  },
3605
- matchedAt: {
3606
- type: 'object',
3607
- description: 'Match timestamp (ISO 8601)'
3921
+ startDate: {
3922
+ type: 'string',
3923
+ description: 'Rule start date (YYYY-MM-DD)'
3608
3924
  },
3609
- matchConfidence: {
3610
- type: 'object',
3611
- description: 'Match confidence score (0-1)'
3925
+ endDate: {
3926
+ type: 'string',
3927
+ description: 'Rule end date (YYYY-MM-DD)'
3612
3928
  },
3613
- isOverdue: {
3929
+ autoCreate: {
3614
3930
  type: 'boolean',
3615
- description: 'Whether this expected transaction is overdue'
3931
+ description: 'Auto-create transaction on expected date'
3616
3932
  },
3617
- rule: {
3618
- description: 'Rule information',
3619
- allOf: [
3620
- {
3621
- $ref: '#/components/schemas/ExpectedTransactionRuleDto'
3622
- }
3623
- ]
3933
+ lastOccurrence: {
3934
+ type: 'string',
3935
+ description: 'Last matched occurrence date (YYYY-MM-DD)'
3936
+ },
3937
+ totalCount: {
3938
+ type: 'number',
3939
+ description: 'Total matched transactions count'
3624
3940
  },
3625
3941
  createdAt: {
3626
3942
  format: 'date-time',
@@ -3636,647 +3952,581 @@ export const $ExpectedTransactionResponseDto = {
3636
3952
  required: [
3637
3953
  'id',
3638
3954
  'userId',
3639
- 'ruleId',
3640
- 'expectedDate',
3955
+ 'name',
3956
+ 'frequency',
3641
3957
  'expectedAmount',
3642
- 'status',
3643
- 'isOverdue',
3644
- 'rule',
3958
+ 'currency',
3959
+ 'matchAmountTolerance',
3960
+ 'isActive',
3961
+ 'startDate',
3962
+ 'autoCreate',
3963
+ 'totalCount',
3645
3964
  'createdAt',
3646
3965
  'updatedAt'
3647
3966
  ]
3648
3967
  } as const;
3649
3968
 
3650
- export const $ExpectedTransactionListResponseDto = {
3969
+ export const $CreateRuleFromTransactionDto = {
3651
3970
  type: 'object',
3652
3971
  properties: {
3653
- items: {
3654
- type: 'array',
3655
- items: {
3656
- $ref: '#/components/schemas/ExpectedTransactionResponseDto'
3657
- }
3972
+ frequency: {
3973
+ type: 'string',
3974
+ description: 'Recurring frequency',
3975
+ enum: [
3976
+ 'WEEKLY',
3977
+ 'BIWEEKLY',
3978
+ 'MONTHLY',
3979
+ 'BIMONTHLY',
3980
+ 'QUARTERLY',
3981
+ 'YEARLY',
3982
+ 'CUSTOM'
3983
+ ],
3984
+ example: 'MONTHLY'
3658
3985
  },
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: {
3986
+ name: {
3671
3987
  type: 'string',
3672
- description: 'Transaction ID to match with'
3988
+ description: 'Optional name override (default: transaction payee)',
3989
+ maxLength: 100
3990
+ },
3991
+ icon: {
3992
+ type: 'string',
3993
+ description: 'Optional icon emoji',
3994
+ maxLength: 10
3673
3995
  }
3674
3996
  },
3675
- required: ['transactionId']
3997
+ required: ['frequency']
3676
3998
  } as const;
3677
3999
 
3678
- export const $EnterNowDto = {
4000
+ export const $RecurringRuleWithStatsResponseDto = {
3679
4001
  type: 'object',
3680
4002
  properties: {
3681
- expenseAccount: {
4003
+ id: {
4004
+ type: 'string',
4005
+ description: 'Rule ID'
4006
+ },
4007
+ userId: {
4008
+ type: 'string',
4009
+ description: 'User ID'
4010
+ },
4011
+ name: {
4012
+ type: 'string',
4013
+ description: 'Rule name'
4014
+ },
4015
+ icon: {
4016
+ type: 'string',
4017
+ description: 'Icon emoji'
4018
+ },
4019
+ frequency: {
4020
+ type: 'string',
4021
+ description: 'Recurring frequency'
4022
+ },
4023
+ expectedAmount: {
4024
+ type: 'number',
4025
+ description: 'Expected amount'
4026
+ },
4027
+ expectedDay: {
4028
+ type: 'number',
4029
+ description: 'Expected day of month'
4030
+ },
4031
+ customIntervalDays: {
4032
+ type: 'number',
4033
+ description: 'Custom interval in days'
4034
+ },
4035
+ currency: {
3682
4036
  type: 'string',
3683
- description:
3684
- 'Override expense account (uses rule default if not provided)',
3685
- maxLength: 200
4037
+ description: 'Currency code'
3686
4038
  },
3687
- paymentAccount: {
4039
+ matchPayeePattern: {
3688
4040
  type: 'string',
3689
- description:
3690
- 'Override payment account (uses rule default if not provided)',
3691
- maxLength: 200
4041
+ description: 'Payee matching pattern'
3692
4042
  },
3693
- amount: {
4043
+ matchAmountTolerance: {
3694
4044
  type: 'number',
3695
- description: 'Override amount (uses expected amount if not provided)',
3696
- minimum: 0
4045
+ description: 'Amount tolerance percentage'
3697
4046
  },
3698
- payee: {
4047
+ defaultExpenseAccount: {
3699
4048
  type: 'string',
3700
- description: 'Override payee (uses rule default if not provided)',
3701
- maxLength: 200
4049
+ description: 'Default expense account'
3702
4050
  },
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: {
4051
+ defaultPaymentAccount: {
3715
4052
  type: 'string',
3716
- description: 'Rule name',
3717
- example: 'Rent'
4053
+ description: 'Default payment account'
3718
4054
  },
3719
- ruleId: {
4055
+ defaultPayee: {
3720
4056
  type: 'string',
3721
- description: 'Rule ID',
3722
- example: 'clx123...'
4057
+ description: 'Default payee'
3723
4058
  },
3724
- amount: {
3725
- type: 'number',
3726
- description: 'Expected amount',
3727
- example: 3000
4059
+ isActive: {
4060
+ type: 'boolean',
4061
+ description: 'Whether rule is active'
3728
4062
  },
3729
- date: {
4063
+ startDate: {
3730
4064
  type: 'string',
3731
- description: 'Expected date (YYYY-MM-DD)',
3732
- example: '2024-04-01'
4065
+ description: 'Rule start date (YYYY-MM-DD)'
3733
4066
  },
3734
- icon: {
4067
+ endDate: {
3735
4068
  type: 'string',
3736
- description: 'Rule icon emoji',
3737
- example: '🏠',
3738
- nullable: true
4069
+ description: 'Rule end date (YYYY-MM-DD)'
3739
4070
  },
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: {
4071
+ autoCreate: {
4072
+ type: 'boolean',
4073
+ description: 'Auto-create transaction on expected date'
4074
+ },
4075
+ lastOccurrence: {
3753
4076
  type: 'string',
3754
- description: 'Month (YYYY-MM)',
3755
- example: '2024-04'
4077
+ description: 'Last matched occurrence date (YYYY-MM-DD)'
3756
4078
  },
3757
- expectedOutflow: {
4079
+ totalCount: {
3758
4080
  type: 'number',
3759
- description: 'Total expected outflow for the month',
3760
- example: 8500
4081
+ description: 'Total matched transactions count'
3761
4082
  },
3762
- itemCount: {
4083
+ createdAt: {
4084
+ format: 'date-time',
4085
+ type: 'string',
4086
+ description: 'Created at timestamp'
4087
+ },
4088
+ updatedAt: {
4089
+ format: 'date-time',
4090
+ type: 'string',
4091
+ description: 'Updated at timestamp'
4092
+ },
4093
+ pendingCount: {
3763
4094
  type: 'number',
3764
- description: 'Number of expected transactions',
3765
- example: 3
4095
+ description: 'Number of pending expected transactions'
3766
4096
  },
3767
- byCurrency: {
3768
- type: 'object',
3769
- description: 'Breakdown by currency',
3770
- example: {
3771
- CNY: 8500,
3772
- USD: 100
3773
- }
4097
+ overdueCount: {
4098
+ type: 'number',
4099
+ description: 'Number of overdue expected transactions'
3774
4100
  },
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
- }
4101
+ nextExpectedDate: {
4102
+ type: 'string',
4103
+ description: 'Next expected date (YYYY-MM-DD)'
3795
4104
  },
3796
- totalOutflow: {
4105
+ totalAmount: {
3797
4106
  type: 'number',
3798
- description: 'Total expected outflow across all months',
3799
- example: 25500
4107
+ description: 'Total amount of all matched transactions'
3800
4108
  },
3801
- totalByCurrency: {
3802
- type: 'object',
3803
- description: 'Total by currency across all months',
3804
- example: {
3805
- CNY: 25500,
3806
- USD: 300
3807
- }
4109
+ averageAmount: {
4110
+ type: 'number',
4111
+ description: 'Average amount per transaction'
3808
4112
  },
3809
- rulesCount: {
4113
+ transactionCount: {
3810
4114
  type: 'number',
3811
- description: 'Number of active recurring rules included',
3812
- example: 5
4115
+ description: 'Number of matched transactions'
3813
4116
  },
3814
- periodStart: {
4117
+ firstDate: {
3815
4118
  type: 'string',
3816
- description: 'Forecast period start date',
3817
- example: '2024-04-01'
4119
+ description: 'First matched transaction date (YYYY-MM-DD)'
3818
4120
  },
3819
- periodEnd: {
4121
+ lastDate: {
3820
4122
  type: 'string',
3821
- description: 'Forecast period end date',
3822
- example: '2024-06-30'
4123
+ description: 'Last matched transaction date (YYYY-MM-DD)'
4124
+ },
4125
+ variance: {
4126
+ type: 'number',
4127
+ description: 'Amount variance (standard deviation squared)'
4128
+ },
4129
+ upcomingCount: {
4130
+ type: 'number',
4131
+ description: 'Number of upcoming expected transactions'
3823
4132
  }
3824
4133
  },
3825
4134
  required: [
3826
- 'forecast',
3827
- 'totalOutflow',
3828
- 'totalByCurrency',
3829
- 'rulesCount',
3830
- 'periodStart',
3831
- 'periodEnd'
4135
+ 'id',
4136
+ 'userId',
4137
+ 'name',
4138
+ 'frequency',
4139
+ 'expectedAmount',
4140
+ 'currency',
4141
+ 'matchAmountTolerance',
4142
+ 'isActive',
4143
+ 'startDate',
4144
+ 'autoCreate',
4145
+ 'totalCount',
4146
+ 'createdAt',
4147
+ 'updatedAt',
4148
+ 'pendingCount',
4149
+ 'overdueCount',
4150
+ 'totalAmount',
4151
+ 'averageAmount',
4152
+ 'transactionCount',
4153
+ 'variance',
4154
+ 'upcomingCount'
3832
4155
  ]
3833
4156
  } as const;
3834
4157
 
3835
- export const $CurrencyBalanceDto = {
4158
+ export const $UpdateRecurringRuleDto = {
3836
4159
  type: 'object',
3837
4160
  properties: {
3838
- currency: {
4161
+ name: {
3839
4162
  type: 'string',
3840
- description: 'ISO 4217 currency code',
3841
- example: 'CNY'
4163
+ description: 'Rule name (unique per user)',
4164
+ maxLength: 100
3842
4165
  },
3843
- balance: {
4166
+ icon: {
3844
4167
  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: {
4168
+ description: 'Icon emoji',
4169
+ maxLength: 10
4170
+ },
4171
+ frequency: {
3856
4172
  type: 'string',
3857
- description: 'Date in YYYY-MM-DD format',
3858
- example: '2024-06-15'
4173
+ description: 'Recurring frequency',
4174
+ enum: [
4175
+ 'WEEKLY',
4176
+ 'BIWEEKLY',
4177
+ 'MONTHLY',
4178
+ 'BIMONTHLY',
4179
+ 'QUARTERLY',
4180
+ 'YEARLY',
4181
+ 'CUSTOM'
4182
+ ]
4183
+ },
4184
+ expectedAmount: {
4185
+ type: 'number',
4186
+ description: 'Expected amount (positive number)',
4187
+ minimum: 0
4188
+ },
4189
+ expectedDay: {
4190
+ type: 'number',
4191
+ description: 'Expected day of month (1-31)',
4192
+ minimum: 1,
4193
+ maximum: 31
4194
+ },
4195
+ currency: {
4196
+ type: 'string',
4197
+ description: 'Currency code',
4198
+ maxLength: 10
3859
4199
  },
3860
- value: {
4200
+ matchPayeePattern: {
3861
4201
  type: 'string',
3862
- description: 'Value at this date (in base currency)',
3863
- example: '500000.00'
4202
+ description: 'Payee matching pattern (supports wildcards)',
4203
+ maxLength: 200
3864
4204
  },
3865
- change: {
3866
- type: 'object',
3867
- description: 'Change from previous point',
3868
- example: '5000.00'
4205
+ matchAmountTolerance: {
4206
+ type: 'number',
4207
+ description: 'Amount tolerance percentage (0-1)',
4208
+ default: 0.075,
4209
+ minimum: 0,
4210
+ maximum: 1
3869
4211
  },
3870
- assets: {
4212
+ defaultExpenseAccount: {
3871
4213
  type: 'string',
3872
- description: 'Total assets at this date (in base currency)',
3873
- example: '494338.00'
4214
+ description: 'Default expense account for auto-create',
4215
+ maxLength: 200
3874
4216
  },
3875
- liabilities: {
4217
+ defaultPaymentAccount: {
3876
4218
  type: 'string',
3877
- description: 'Total liabilities at this date (in base currency)',
3878
- example: '310098.00'
4219
+ description: 'Default payment account for auto-create',
4220
+ maxLength: 200
3879
4221
  },
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: {
4222
+ defaultPayee: {
3895
4223
  type: 'string',
3896
- description: 'Value at start of period',
3897
- example: '450000.00'
4224
+ description: 'Default payee for auto-create',
4225
+ maxLength: 200
3898
4226
  },
3899
- endValue: {
3900
- type: 'string',
3901
- description: 'Value at end of period',
3902
- example: '500000.00'
4227
+ autoCreate: {
4228
+ type: 'boolean',
4229
+ description: 'Auto-create transaction when expected date arrives',
4230
+ default: false
3903
4231
  },
3904
- totalChange: {
4232
+ endDate: {
3905
4233
  type: 'string',
3906
- description: 'Total change over period',
3907
- example: '50000.00'
4234
+ description: 'Rule end date (ISO format)'
3908
4235
  },
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'
4236
+ customIntervalDays: {
4237
+ type: 'number',
4238
+ description: 'Custom interval in days',
4239
+ minimum: 1
3925
4240
  },
3926
- byCurrency: {
3927
- description: 'Balances by currency',
3928
- type: 'array',
3929
- items: {
3930
- $ref: '#/components/schemas/CurrencyBalanceDto'
3931
- }
4241
+ isActive: {
4242
+ type: 'boolean',
4243
+ description: 'Rule active status'
3932
4244
  }
3933
- },
3934
- required: ['date', 'byCurrency']
4245
+ }
3935
4246
  } as const;
3936
4247
 
3937
- export const $PortfolioTrendsResponseDto = {
4248
+ export const $ExpectedTransactionRuleDto = {
3938
4249
  type: 'object',
3939
4250
  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
- ]
4251
+ name: {
4252
+ type: 'string',
4253
+ description: 'Rule name'
3954
4254
  },
3955
- period: {
4255
+ icon: {
3956
4256
  type: 'string',
3957
- description: 'Period requested',
3958
- example: '6m'
4257
+ description: 'Rule icon'
3959
4258
  },
3960
- granularity: {
4259
+ frequency: {
3961
4260
  type: 'string',
3962
- description: 'Data granularity',
3963
- example: 'month'
4261
+ description: 'Rule frequency'
3964
4262
  },
3965
4263
  currency: {
3966
4264
  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
- }
4265
+ description: 'Currency code'
3984
4266
  }
3985
4267
  },
3986
- required: ['series', 'summary', 'period', 'granularity', 'currency']
4268
+ required: ['name', 'frequency', 'currency']
3987
4269
  } as const;
3988
4270
 
3989
- export const $CashFlowPointDto = {
4271
+ export const $ExpectedTransactionResponseDto = {
3990
4272
  type: 'object',
3991
4273
  properties: {
3992
- month: {
4274
+ id: {
3993
4275
  type: 'string',
3994
- description: 'Month key (YYYY-MM)',
3995
- example: '2024-03'
4276
+ description: 'Expected transaction ID'
3996
4277
  },
3997
- income: {
4278
+ userId: {
3998
4279
  type: 'string',
3999
- description: 'Income in base currency (absolute, converted)',
4000
- example: '10000.00'
4280
+ description: 'User ID'
4001
4281
  },
4002
- expense: {
4282
+ ruleId: {
4003
4283
  type: 'string',
4004
- description: 'Expense in base currency (absolute, converted)',
4005
- example: '5000.00'
4284
+ description: 'Associated rule ID'
4006
4285
  },
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: {
4286
+ expectedDate: {
4020
4287
  type: 'string',
4021
- description: 'Total income across the period',
4022
- example: '60000.00'
4288
+ description: 'Expected date (YYYY-MM-DD)'
4023
4289
  },
4024
- totalExpense: {
4290
+ expectedAmount: {
4291
+ type: 'number',
4292
+ description: 'Expected amount'
4293
+ },
4294
+ status: {
4025
4295
  type: 'string',
4026
- description: 'Total expense across the period',
4027
- example: '30000.00'
4296
+ description: 'Status (PENDING, COMPLETED, SKIPPED)'
4028
4297
  },
4029
- totalNetSavings: {
4298
+ matchedTransactionId: {
4030
4299
  type: 'string',
4031
- description: 'income − expense across the period',
4032
- example: '30000.00'
4300
+ description: 'Matched transaction ID'
4033
4301
  },
4034
- averageMonthlyNetSavings: {
4302
+ matchedAt: {
4035
4303
  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
- }
4304
+ description: 'Match timestamp (ISO 8601)'
4059
4305
  },
4060
- summary: {
4061
- description: 'Period totals',
4306
+ matchConfidence: {
4307
+ type: 'number',
4308
+ description: 'Match confidence score (0-1)'
4309
+ },
4310
+ isOverdue: {
4311
+ type: 'boolean',
4312
+ description: 'Whether this expected transaction is overdue'
4313
+ },
4314
+ rule: {
4315
+ description: 'Rule information',
4062
4316
  allOf: [
4063
4317
  {
4064
- $ref: '#/components/schemas/CashFlowTrendSummaryDto'
4318
+ $ref: '#/components/schemas/ExpectedTransactionRuleDto'
4065
4319
  }
4066
4320
  ]
4067
4321
  },
4068
- period: {
4069
- type: 'string',
4070
- description: 'Period requested',
4071
- example: '6m'
4072
- },
4073
- granularity: {
4322
+ createdAt: {
4323
+ format: 'date-time',
4074
4324
  type: 'string',
4075
- description: 'Data granularity (v1 returns month buckets)',
4076
- example: 'month'
4325
+ description: 'Created at timestamp'
4077
4326
  },
4078
- currency: {
4327
+ updatedAt: {
4328
+ format: 'date-time',
4079
4329
  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)',
4330
+ description: 'Updated at timestamp'
4331
+ }
4332
+ },
4333
+ required: [
4334
+ 'id',
4335
+ 'userId',
4336
+ 'ruleId',
4337
+ 'expectedDate',
4338
+ 'expectedAmount',
4339
+ 'status',
4340
+ 'isOverdue',
4341
+ 'rule',
4342
+ 'createdAt',
4343
+ 'updatedAt'
4344
+ ]
4345
+ } as const;
4346
+
4347
+ export const $ExpectedTransactionListResponseDto = {
4348
+ type: 'object',
4349
+ properties: {
4350
+ items: {
4085
4351
  type: 'array',
4086
4352
  items: {
4087
- $ref: '#/components/schemas/ExchangeRateWarningDto'
4353
+ $ref: '#/components/schemas/ExpectedTransactionResponseDto'
4088
4354
  }
4355
+ },
4356
+ total: {
4357
+ type: 'number',
4358
+ description: 'Total count'
4089
4359
  }
4090
4360
  },
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: {}
4361
+ required: ['items', 'total']
4112
4362
  } as const;
4113
4363
 
4114
- export const $DeleteOwnUserDto = {
4364
+ export const $ConfirmMatchDto = {
4115
4365
  type: 'object',
4116
4366
  properties: {
4117
- accessToken: {
4367
+ transactionId: {
4118
4368
  type: 'string',
4119
- description: 'Access token for user verification',
4120
- example: 'abc123xyz'
4369
+ description: 'Transaction ID to match with'
4121
4370
  }
4122
4371
  },
4123
- required: ['accessToken']
4372
+ required: ['transactionId']
4124
4373
  } as const;
4125
4374
 
4126
- export const $SignupDto = {
4375
+ export const $EnterNowDto = {
4127
4376
  type: 'object',
4128
4377
  properties: {
4129
- turnstileToken: {
4378
+ expenseAccount: {
4130
4379
  type: 'string',
4131
4380
  description:
4132
- 'Cloudflare Turnstile verification token (optional when Turnstile disabled)',
4133
- example: '0.abc123def456...'
4134
- }
4135
- }
4136
- } as const;
4137
-
4138
- export const $SignupResponseDto = {
4139
- type: 'object',
4140
- properties: {
4141
- authToken: {
4381
+ 'Override expense account (uses rule default if not provided)',
4382
+ maxLength: 200
4383
+ },
4384
+ paymentAccount: {
4142
4385
  type: 'string',
4143
- description: 'JWT auth token',
4144
- example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
4386
+ description:
4387
+ 'Override payment account (uses rule default if not provided)',
4388
+ maxLength: 200
4145
4389
  },
4146
- accessToken: {
4390
+ amount: {
4391
+ type: 'number',
4392
+ description: 'Override amount (uses expected amount if not provided)',
4393
+ minimum: 0
4394
+ },
4395
+ payee: {
4147
4396
  type: 'string',
4148
- description: 'Auto-generated access token'
4397
+ description: 'Override payee (uses rule default if not provided)',
4398
+ maxLength: 200
4149
4399
  },
4150
- role: {
4400
+ narration: {
4151
4401
  type: 'string',
4152
- description: 'Assigned user role',
4153
- enum: ['USER', 'ADMIN', 'DEMO', 'INACTIVE', 'PAID', 'OPS']
4402
+ description: 'Optional narration',
4403
+ maxLength: 500
4154
4404
  }
4155
- },
4156
- required: ['authToken', 'accessToken', 'role']
4405
+ }
4157
4406
  } as const;
4158
4407
 
4159
- export const $UpdateUserSettingDto = {
4408
+ export const $ForecastItemDto = {
4160
4409
  type: 'object',
4161
4410
  properties: {
4162
- secId: {
4163
- type: 'number',
4164
- description: 'Security ID'
4411
+ rule: {
4412
+ type: 'string',
4413
+ description: 'Rule name',
4414
+ example: 'Rent'
4165
4415
  },
4166
- annualInterestRate: {
4416
+ ruleId: {
4417
+ type: 'string',
4418
+ description: 'Rule ID',
4419
+ example: 'clx123...'
4420
+ },
4421
+ amount: {
4167
4422
  type: 'number',
4168
- description: 'Annual interest rate',
4169
- example: 0.05
4423
+ description: 'Expected amount',
4424
+ example: 3000
4170
4425
  },
4171
- currency: {
4426
+ date: {
4172
4427
  type: 'string',
4173
- description: 'Currency code',
4174
- example: 'USD'
4428
+ description: 'Expected date (YYYY-MM-DD)',
4429
+ example: '2024-04-01'
4175
4430
  },
4176
- baseCurrency: {
4431
+ icon: {
4177
4432
  type: 'string',
4178
- description: 'Base currency code',
4179
- example: 'USD'
4433
+ description: 'Rule icon emoji',
4434
+ example: '🏠',
4435
+ nullable: true
4180
4436
  },
4181
- benchmark: {
4437
+ currency: {
4182
4438
  type: 'string',
4183
- description: 'Benchmark symbol',
4184
- example: 'SPY'
4185
- },
4186
- colorScheme: {
4439
+ description: 'Currency code',
4440
+ example: 'CNY'
4441
+ }
4442
+ },
4443
+ required: ['rule', 'ruleId', 'amount', 'date', 'icon', 'currency']
4444
+ } as const;
4445
+
4446
+ export const $MonthlyForecastDto = {
4447
+ type: 'object',
4448
+ properties: {
4449
+ month: {
4187
4450
  type: 'string',
4188
- description: 'Color scheme',
4189
- enum: ['DARK', 'LIGHT']
4451
+ description: 'Month (YYYY-MM)',
4452
+ example: '2024-04'
4190
4453
  },
4191
- dateRange: {
4192
- type: 'string',
4193
- description: 'Date range filter',
4194
- example: '1y'
4454
+ expectedOutflow: {
4455
+ type: 'number',
4456
+ description: 'Total expected outflow for the month',
4457
+ example: 8500
4195
4458
  },
4196
- emergencyFund: {
4459
+ itemCount: {
4197
4460
  type: 'number',
4198
- description: 'Emergency fund amount',
4199
- example: 10000
4461
+ description: 'Number of expected transactions',
4462
+ example: 3
4200
4463
  },
4201
- 'filters.accounts': {
4202
- description: 'Account filter IDs',
4203
- type: 'array',
4204
- items: {
4205
- type: 'string'
4464
+ byCurrency: {
4465
+ type: 'object',
4466
+ description: 'Breakdown by currency',
4467
+ example: {
4468
+ CNY: 8500,
4469
+ USD: 100
4206
4470
  }
4207
4471
  },
4208
- 'filters.assetClasses': {
4209
- description: 'Asset class filters',
4472
+ items: {
4473
+ description: 'Individual forecast items',
4210
4474
  type: 'array',
4211
4475
  items: {
4212
- type: 'string'
4476
+ $ref: '#/components/schemas/ForecastItemDto'
4213
4477
  }
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',
4478
+ }
4479
+ },
4480
+ required: ['month', 'expectedOutflow', 'itemCount', 'byCurrency', 'items']
4481
+ } as const;
4482
+
4483
+ export const $ForecastResponseDto = {
4484
+ type: 'object',
4485
+ properties: {
4486
+ forecast: {
4487
+ description: 'Monthly forecast data',
4225
4488
  type: 'array',
4226
4489
  items: {
4227
- type: 'string'
4490
+ $ref: '#/components/schemas/MonthlyForecastDto'
4228
4491
  }
4229
4492
  },
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: {
4493
+ totalOutflow: {
4249
4494
  type: 'number',
4250
- description: 'Projected total amount',
4251
- example: 1000000
4495
+ description: 'Total expected outflow across all months',
4496
+ example: 25500
4252
4497
  },
4253
- retirementDate: {
4254
- type: 'string',
4255
- description: 'Retirement date in ISO 8601 format',
4256
- example: '2050-01-01'
4498
+ totalByCurrency: {
4499
+ type: 'object',
4500
+ description: 'Total by currency across all months',
4501
+ example: {
4502
+ CNY: 25500,
4503
+ USD: 300
4504
+ }
4257
4505
  },
4258
- savingsRate: {
4506
+ rulesCount: {
4259
4507
  type: 'number',
4260
- description: 'Savings rate percentage',
4261
- example: 0.2
4508
+ description: 'Number of active recurring rules included',
4509
+ example: 5
4262
4510
  },
4263
- viewMode: {
4264
- 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: {
4511
+ periodStart: {
4275
4512
  type: 'string',
4276
- description: 'Property value'
4513
+ description: 'Forecast period start date',
4514
+ example: '2024-04-01'
4515
+ },
4516
+ periodEnd: {
4517
+ type: 'string',
4518
+ description: 'Forecast period end date',
4519
+ example: '2024-06-30'
4277
4520
  }
4278
4521
  },
4279
- required: ['value']
4522
+ required: [
4523
+ 'forecast',
4524
+ 'totalOutflow',
4525
+ 'totalByCurrency',
4526
+ 'rulesCount',
4527
+ 'periodStart',
4528
+ 'periodEnd'
4529
+ ]
4280
4530
  } as const;
4281
4531
 
4282
4532
  export const $CreateTransactionRuleDto = {
@@ -4838,7 +5088,8 @@ export const $UpdateTransactionRuleDto = {
4838
5088
  },
4839
5089
  matchLogic: {
4840
5090
  type: 'string',
4841
- enum: ['OR', 'AND']
5091
+ enum: ['OR', 'AND'],
5092
+ default: 'OR'
4842
5093
  },
4843
5094
  amountMin: {
4844
5095
  type: 'number',
@@ -4852,13 +5103,10 @@ export const $UpdateTransactionRuleDto = {
4852
5103
  },
4853
5104
  priority: {
4854
5105
  type: 'number',
5106
+ default: 50,
4855
5107
  minimum: 0,
4856
5108
  maximum: 1000
4857
5109
  },
4858
- enabled: {
4859
- type: 'boolean',
4860
- description: 'Enable or disable the rule'
4861
- },
4862
5110
  additionalTags: {
4863
5111
  items: {
4864
5112
  type: 'array'
@@ -4868,6 +5116,10 @@ export const $UpdateTransactionRuleDto = {
4868
5116
  },
4869
5117
  additionalMetadata: {
4870
5118
  type: 'object'
5119
+ },
5120
+ enabled: {
5121
+ type: 'boolean',
5122
+ description: 'Enable or disable the rule'
4871
5123
  }
4872
5124
  }
4873
5125
  } as const;
@@ -4928,6 +5180,69 @@ export const $TestRuleResponseDto = {
4928
5180
  required: ['ruleId', 'matches', 'confidence', 'matchDetails']
4929
5181
  } as const;
4930
5182
 
5183
+ export const $CategoryCatalogEntryDto = {
5184
+ type: 'object',
5185
+ properties: {
5186
+ slug: {
5187
+ type: 'string',
5188
+ description: 'Category slug (single source-of-truth)',
5189
+ example: 'food'
5190
+ },
5191
+ scenario: {
5192
+ type: 'string',
5193
+ description: 'Display scenario group (maps to frontend picker _scenario)',
5194
+ enum: [
5195
+ 'expense',
5196
+ 'income',
5197
+ 'investment',
5198
+ 'banking',
5199
+ 'transfer',
5200
+ 'payment'
5201
+ ],
5202
+ example: 'expense'
5203
+ },
5204
+ icon: {
5205
+ type: 'string',
5206
+ description: 'Lucide icon name',
5207
+ example: 'utensils'
5208
+ },
5209
+ regions: {
5210
+ description: "Applicable regions ('*' = all, 'cn' = CN-only)",
5211
+ example: ['*'],
5212
+ type: 'array',
5213
+ items: {
5214
+ type: 'string'
5215
+ }
5216
+ }
5217
+ },
5218
+ required: ['slug', 'scenario', 'icon', 'regions']
5219
+ } as const;
5220
+
5221
+ export const $CategoryCatalogListResponseDto = {
5222
+ type: 'object',
5223
+ properties: {
5224
+ items: {
5225
+ description: 'Category entries (region-scoped, query-filtered)',
5226
+ type: 'array',
5227
+ items: {
5228
+ $ref: '#/components/schemas/CategoryCatalogEntryDto'
5229
+ }
5230
+ },
5231
+ total: {
5232
+ type: 'number',
5233
+ description:
5234
+ 'Total category entries for the region (before query filtering)',
5235
+ example: 30
5236
+ },
5237
+ region: {
5238
+ type: 'string',
5239
+ description: 'Region code',
5240
+ example: 'cn'
5241
+ }
5242
+ },
5243
+ required: ['items', 'total', 'region']
5244
+ } as const;
5245
+
4931
5246
  export const $CreateBeanEventDto = {
4932
5247
  type: 'object',
4933
5248
  properties: {
@@ -5670,7 +5985,8 @@ export const $UpdateMapperDefaultsDto = {
5670
5985
  type: 'string',
5671
5986
  description: 'Source account for transactions (Beancount format)',
5672
5987
  example: 'Assets:CN:Alipay:Balance',
5673
- pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
5988
+ pattern:
5989
+ '^(Assets|Liabilities|Income|Expenses|Equity)(:[A-Za-z0-9][A-Za-z0-9-]*)+$'
5674
5990
  },
5675
5991
  currency: {
5676
5992
  type: 'string',
@@ -5684,13 +6000,15 @@ export const $UpdateMapperDefaultsDto = {
5684
6000
  type: 'string',
5685
6001
  description: 'Default expense account (optional)',
5686
6002
  example: 'Expenses:Unknown',
5687
- pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
6003
+ pattern:
6004
+ '^(Assets|Liabilities|Income|Expenses|Equity)(:[A-Za-z0-9][A-Za-z0-9-]*)+$'
5688
6005
  },
5689
6006
  incomeAccount: {
5690
6007
  type: 'string',
5691
6008
  description: 'Default income account (optional)',
5692
6009
  example: 'Income:Unknown',
5693
- pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
6010
+ pattern:
6011
+ '^(Assets|Liabilities|Income|Expenses|Equity)(:[A-Za-z0-9][A-Za-z0-9-]*)+$'
5694
6012
  },
5695
6013
  methodAccountMapping: {
5696
6014
  type: 'object',
@@ -5979,15 +6297,105 @@ export const $UncoveredFormatMissDto = {
5979
6297
  properties: {}
5980
6298
  } as const;
5981
6299
 
6300
+ export const $ClientParsedDataDto = {
6301
+ type: 'object',
6302
+ properties: {
6303
+ amount: {
6304
+ type: 'number',
6305
+ description: 'Transaction amount',
6306
+ example: 35
6307
+ },
6308
+ currency: {
6309
+ type: 'string',
6310
+ description: 'Currency code',
6311
+ example: 'CNY'
6312
+ },
6313
+ date: {
6314
+ type: 'string',
6315
+ description: 'Transaction date (ISO 8601)',
6316
+ example: '2026-08-15'
6317
+ },
6318
+ payee: {
6319
+ type: 'string',
6320
+ description: 'Payee/merchant name',
6321
+ example: 'Starbucks'
6322
+ },
6323
+ narration: {
6324
+ type: 'string',
6325
+ description: 'Transaction narration'
6326
+ },
6327
+ category: {
6328
+ type: 'string',
6329
+ description: 'Category slug',
6330
+ example: 'food_restaurant'
6331
+ },
6332
+ incomeType: {
6333
+ type: 'string',
6334
+ description: 'Income type',
6335
+ example: 'Salary'
6336
+ },
6337
+ incomeSource: {
6338
+ type: 'string',
6339
+ description: 'Income source',
6340
+ example: 'Anthropic Inc.'
6341
+ },
6342
+ symbol: {
6343
+ type: 'string',
6344
+ description: 'Security symbol code (e.g., 600519, AAPL)',
6345
+ example: 'AAPL'
6346
+ },
6347
+ quantity: {
6348
+ type: 'number',
6349
+ description: 'Quantity of shares/units',
6350
+ example: 100
6351
+ },
6352
+ price: {
6353
+ type: 'number',
6354
+ description: 'Unit price per share/unit',
6355
+ example: 1900
6356
+ },
6357
+ investmentAction: {
6358
+ type: 'string',
6359
+ description: 'Investment action',
6360
+ enum: ['buy', 'sell'],
6361
+ example: 'buy'
6362
+ },
6363
+ paymentSource: {
6364
+ type: 'string',
6365
+ description: 'Payment source: asset (default) or liability (credit card)',
6366
+ enum: ['asset', 'liability'],
6367
+ example: 'asset'
6368
+ },
6369
+ liabilityHint: {
6370
+ type: 'string',
6371
+ description: 'Liability account hint (CreditCard/Huabei/Baitiao)',
6372
+ example: 'CreditCard'
6373
+ },
6374
+ warning: {
6375
+ type: 'string',
6376
+ description:
6377
+ 'Display-only warning from the prior response; accepted but ignored.',
6378
+ example: 'Cross-currency settlement applies.'
6379
+ }
6380
+ }
6381
+ } as const;
6382
+
5982
6383
  export const $ProcessNlpDto = {
5983
6384
  type: 'object',
5984
6385
  properties: {
5985
6386
  message: {
5986
6387
  type: 'string',
5987
- description: 'Natural language text describing a transaction (Chinese)',
5988
- example: 'yesterday Starbucks spent 35 yuan',
6388
+ description:
6389
+ 'Natural language text describing a transaction. Optional when `confirm` is true (structured confirm); otherwise required.',
6390
+ example: 'Starbucks 35',
5989
6391
  maxLength: 500
5990
6392
  },
6393
+ confirm: {
6394
+ type: 'boolean',
6395
+ description:
6396
+ 'Structured confirm signal — bypasses NL confirm-word matching when true. Send parsedData field edits alongside. The NL word-list path is the fallback.',
6397
+ example: true
6398
+ },
5991
6399
  sessionId: {
5992
6400
  type: 'string',
5993
6401
  description:
@@ -5995,14 +6403,18 @@ export const $ProcessNlpDto = {
5995
6403
  example: 'session_abc123'
5996
6404
  },
5997
6405
  parsedData: {
5998
- type: 'object',
5999
6406
  description:
6000
6407
  'Parsed data from previous NLP response for session recovery. Send back the parsedData received in confirm_payee/confirm responses.',
6001
6408
  example: {
6002
6409
  amount: 35,
6003
6410
  currency: 'CNY',
6004
6411
  payee: 'Starbucks'
6005
- }
6412
+ },
6413
+ allOf: [
6414
+ {
6415
+ $ref: '#/components/schemas/ClientParsedDataDto'
6416
+ }
6417
+ ]
6006
6418
  },
6007
6419
  selectedRuleId: {
6008
6420
  type: 'string',
@@ -6013,11 +6425,29 @@ export const $ProcessNlpDto = {
6013
6425
  selectedAccount: {
6014
6426
  type: 'string',
6015
6427
  description:
6016
- '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.',
6428
+ '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.',
6017
6429
  example: 'Expenses:Food:Coffee'
6430
+ },
6431
+ viewpointAccount: {
6432
+ type: 'string',
6433
+ description:
6434
+ '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.',
6435
+ example: 'Assets:CN:Bank:ICBC'
6436
+ },
6437
+ viewpointCategory: {
6438
+ type: 'string',
6439
+ description:
6440
+ "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.",
6441
+ example: 'Food'
6442
+ },
6443
+ viewpointFlow: {
6444
+ type: 'string',
6445
+ description:
6446
+ "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.",
6447
+ enum: ['income', 'expense'],
6448
+ example: 'expense'
6018
6449
  }
6019
- },
6020
- required: ['message']
6450
+ }
6021
6451
  } as const;
6022
6452
 
6023
6453
  export const $NlpTransactionInfoDto = {
@@ -6329,6 +6759,24 @@ export const $NlpRuleConfirmationDataDto = {
6329
6759
  ]
6330
6760
  } as const;
6331
6761
 
6762
+ export const $NlpAccountCandidateDto = {
6763
+ type: 'object',
6764
+ properties: {
6765
+ path: {
6766
+ type: 'string',
6767
+ description: 'Canonical beancount account path (echo back on selection)',
6768
+ example: 'Expenses:Food:Dining'
6769
+ },
6770
+ name: {
6771
+ type: 'string',
6772
+ description:
6773
+ 'Localized display name (ADR-0114 read-time projection, user locale)',
6774
+ example: '餐饮'
6775
+ }
6776
+ },
6777
+ required: ['path', 'name']
6778
+ } as const;
6779
+
6332
6780
  export const $NlpAccountConfirmationDataDto = {
6333
6781
  type: 'object',
6334
6782
  properties: {
@@ -6344,10 +6792,11 @@ export const $NlpAccountConfirmationDataDto = {
6344
6792
  example: 'Expenses:Food:Drinks'
6345
6793
  },
6346
6794
  similarAccounts: {
6347
- description: 'Similar accounts for user selection',
6795
+ description:
6796
+ 'Similar accounts for user selection (path + localized name, #680)',
6348
6797
  type: 'array',
6349
6798
  items: {
6350
- type: 'string'
6799
+ $ref: '#/components/schemas/NlpAccountCandidateDto'
6351
6800
  }
6352
6801
  },
6353
6802
  errorMessage: {
@@ -6635,7 +7084,7 @@ export const $NlpResponseDto = {
6635
7084
  type: 'string',
6636
7085
  description:
6637
7086
  'Asset sub-type (only present when intent is "asset"). Determines which asset-related form to render.',
6638
- enum: ['transfer', 'banking', 'investment'],
7087
+ enum: ['transfer', 'banking', 'investment', 'lend', 'lend_collect'],
6639
7088
  example: 'investment'
6640
7089
  },
6641
7090
  liabilitySubType: {
@@ -6838,7 +7287,7 @@ export const $PlatformListItemDto = {
6838
7287
  suggestedSegment: {
6839
7288
  type: 'string',
6840
7289
  description:
6841
- 'Suggested path segment — PascalCase of canonical, hyphens removed (e.g. "ApplePay")'
7290
+ 'Suggested path segment — canonical PascalCased per hyphen-part, hyphens preserved (e.g. "Apple-Pay")'
6842
7291
  },
6843
7292
  logoUrl: {
6844
7293
  type: 'string',
@@ -6908,7 +7357,7 @@ export const $PlatformMatchResultDto = {
6908
7357
  suggestedSegment: {
6909
7358
  type: 'string',
6910
7359
  description:
6911
- 'Suggested path segment — PascalCase of canonical, hyphens removed (e.g. "ApplePay")'
7360
+ 'Suggested path segment — canonical PascalCased per hyphen-part, hyphens preserved (e.g. "Apple-Pay")'
6912
7361
  },
6913
7362
  logoUrl: {
6914
7363
  type: 'string',
@@ -6924,55 +7373,128 @@ export const $PlatformMatchResultDto = {
6924
7373
  category: {
6925
7374
  type: 'string',
6926
7375
  description:
6927
- 'Region-aware category (institution vocab, e.g. DigitalWallet/Bank). null = no region-aware suggestion; fall back to type.',
7376
+ 'Region-aware category (institution vocab, e.g. DigitalWallet/Bank). null = no region-aware suggestion; fall back to type.',
7377
+ nullable: true,
7378
+ example: 'DigitalWallet'
7379
+ },
7380
+ matchType: {
7381
+ type: 'string',
7382
+ description: "How this row matched: 'exact' > 'prefix' > 'substring'",
7383
+ enum: ['exact', 'prefix', 'substring']
7384
+ }
7385
+ },
7386
+ required: [
7387
+ 'id',
7388
+ 'name',
7389
+ 'canonical',
7390
+ 'type',
7391
+ 'suggestedSegment',
7392
+ 'logoUrl',
7393
+ 'countryCode',
7394
+ 'category',
7395
+ 'matchType'
7396
+ ]
7397
+ } as const;
7398
+
7399
+ export const $PlatformMatchResponseDto = {
7400
+ type: 'object',
7401
+ properties: {
7402
+ platforms: {
7403
+ description: 'Ranked matches, best tier first (at most 10 rows)',
7404
+ type: 'array',
7405
+ items: {
7406
+ $ref: '#/components/schemas/PlatformMatchResultDto'
7407
+ }
7408
+ },
7409
+ matchType: {
7410
+ type: 'string',
7411
+ description:
7412
+ "Overall match quality — top row's tier, or 'none' when no hits",
7413
+ enum: ['none', 'exact', 'prefix', 'substring']
7414
+ },
7415
+ total: {
7416
+ type: 'number',
7417
+ description: 'Total matches before LIMIT (truncation transparency)'
7418
+ },
7419
+ hasMore: {
7420
+ type: 'boolean',
7421
+ description: 'true when total > platforms.length (more matches exist)'
7422
+ }
7423
+ },
7424
+ required: ['platforms', 'matchType', 'total', 'hasMore']
7425
+ } as const;
7426
+
7427
+ export const $PlatformStandardsPlatformDto = {
7428
+ type: 'object',
7429
+ properties: {
7430
+ id: {
7431
+ type: 'string',
7432
+ description: 'Global platform ID'
7433
+ },
7434
+ name: {
7435
+ type: 'string',
7436
+ description: 'Platform name (e.g., "ICBC")'
7437
+ },
7438
+ canonical: {
7439
+ type: 'string',
7440
+ description: 'Canonical identifier in ACCOUNT_RE format (e.g., "icbc")'
7441
+ },
7442
+ suggestedSegment: {
7443
+ type: 'string',
7444
+ description:
7445
+ 'Suggested path segment — canonical PascalCased per hyphen-part, hyphens preserved (e.g. "Apple-Pay")'
7446
+ },
7447
+ type: {
7448
+ type: 'string',
7449
+ description: 'Platform type',
7450
+ enum: [
7451
+ 'BANK',
7452
+ 'BROKERAGE',
7453
+ 'CRYPTO_EXCHANGE',
7454
+ 'PAYMENT',
7455
+ 'INVESTMENT',
7456
+ 'INSURANCE',
7457
+ 'OTHER'
7458
+ ]
7459
+ },
7460
+ category: {
7461
+ type: 'string',
7462
+ description:
7463
+ 'Region-aware category (institution vocab, e.g. DigitalWallet/Bank) resolved against the final region. null = no region-aware suggestion; fall back to type.',
6928
7464
  nullable: true,
6929
- example: 'DigitalWallet'
6930
- },
6931
- matchType: {
6932
- type: 'string',
6933
- description: "How this row matched: 'exact' > 'prefix' > 'substring'",
6934
- enum: ['exact', 'prefix', 'substring']
7465
+ example: 'Bank'
6935
7466
  }
6936
7467
  },
6937
- required: [
6938
- 'id',
6939
- 'name',
6940
- 'canonical',
6941
- 'type',
6942
- 'suggestedSegment',
6943
- 'logoUrl',
6944
- 'countryCode',
6945
- 'category',
6946
- 'matchType'
6947
- ]
7468
+ required: ['id', 'name', 'canonical', 'suggestedSegment', 'type', 'category']
6948
7469
  } as const;
6949
7470
 
6950
- export const $PlatformMatchResponseDto = {
7471
+ export const $PlatformStandardsResponseDto = {
6951
7472
  type: 'object',
6952
7473
  properties: {
6953
- platforms: {
6954
- description: 'Ranked matches, best tier first (at most 10 rows)',
6955
- type: 'array',
6956
- items: {
6957
- $ref: '#/components/schemas/PlatformMatchResultDto'
6958
- }
7474
+ platform: {
7475
+ description: 'The selected platform (institution lock source)',
7476
+ allOf: [
7477
+ {
7478
+ $ref: '#/components/schemas/PlatformStandardsPlatformDto'
7479
+ }
7480
+ ]
6959
7481
  },
6960
- matchType: {
7482
+ region: {
6961
7483
  type: 'string',
6962
7484
  description:
6963
- "Overall match quality — top row's tier, or 'none' when no hits",
6964
- enum: ['none', 'exact', 'prefix', 'substring']
6965
- },
6966
- total: {
6967
- type: 'number',
6968
- description: 'Total matches before LIMIT (truncation transparency)'
7485
+ "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.",
7486
+ example: 'CN'
6969
7487
  },
6970
- hasMore: {
6971
- type: 'boolean',
6972
- description: 'true when total > platforms.length (more matches exist)'
7488
+ templates: {
7489
+ description:
7490
+ 'Candidate account-standard templates of the resolved region (groupable by productCategory client-side)',
7491
+ type: 'array',
7492
+ items: {
7493
+ $ref: '#/components/schemas/AccountStandardResponseDto'
7494
+ }
6973
7495
  }
6974
7496
  },
6975
- required: ['platforms', 'matchType', 'total', 'hasMore']
7497
+ required: ['platform', 'region', 'templates']
6976
7498
  } as const;
6977
7499
 
6978
7500
  export const $CreatePlatformDto = {
@@ -7076,7 +7598,8 @@ export const $UpdatePlatformDto = {
7076
7598
  },
7077
7599
  isActive: {
7078
7600
  type: 'boolean',
7079
- description: 'Whether the platform is active'
7601
+ description: 'Whether the platform is active',
7602
+ default: true
7080
7603
  }
7081
7604
  }
7082
7605
  } as const;
@@ -7275,7 +7798,8 @@ export const $PlatformGroupDto = {
7275
7798
  example: 'CMB Bank'
7276
7799
  },
7277
7800
  accounts: {
7278
- description: 'Accounts within this platform',
7801
+ description:
7802
+ 'Accounts within this platform (Assets and Liabilities rows, #696)',
7279
7803
  type: 'array',
7280
7804
  items: {
7281
7805
  $ref: '#/components/schemas/AccountItemDto'
@@ -7283,7 +7807,8 @@ export const $PlatformGroupDto = {
7283
7807
  },
7284
7808
  totalBalance: {
7285
7809
  type: 'string',
7286
- description: 'FX-converted total balance in base currency',
7810
+ description:
7811
+ 'FX-converted total balance in base currency (nets Assets + Liabilities rows; can be negative)',
7287
7812
  example: '100000.00'
7288
7813
  },
7289
7814
  balanceByCurrency: {
@@ -7302,7 +7827,7 @@ export const $PlatformGroupDto = {
7302
7827
  sharePct: {
7303
7828
  type: 'number',
7304
7829
  description:
7305
- 'Share of the grand converted total (0-100); 0 when grand total is 0',
7830
+ 'Share of the converted asset-side grand total (0-100); liability balances are excluded from the basis; 0 when grand total is 0 (#696)',
7306
7831
  example: 42.5
7307
7832
  }
7308
7833
  },
@@ -7350,7 +7875,8 @@ export const $AccountsSummaryDto = {
7350
7875
  properties: {
7351
7876
  totalAccounts: {
7352
7877
  type: 'number',
7353
- description: 'Total number of accounts'
7878
+ description:
7879
+ 'Total number of accounts (balance sheet: Assets + Liabilities, #696)'
7354
7880
  },
7355
7881
  totalPlatforms: {
7356
7882
  type: 'number',
@@ -7894,7 +8420,7 @@ export const $MonetaryDto = {
7894
8420
  example: 'USD'
7895
8421
  },
7896
8422
  baseCcyEquivalent: {
7897
- type: 'object',
8423
+ type: 'string',
7898
8424
  description: 'Converted to user base currency (Decimal string)',
7899
8425
  example: '21600',
7900
8426
  nullable: true
@@ -7970,13 +8496,13 @@ export const $HoldingPnlRowDto = {
7970
8496
  example: 'Assets:US:Broker:AAPL'
7971
8497
  },
7972
8498
  accountCcy: {
7973
- type: 'object',
8499
+ type: 'string',
7974
8500
  description: 'Account settlement currency (ISO 4217), from cost currency',
7975
8501
  nullable: true,
7976
8502
  example: 'USD'
7977
8503
  },
7978
8504
  brokerType: {
7979
- type: 'object',
8505
+ type: 'string',
7980
8506
  description: 'Broker type derived from Platform.type',
7981
8507
  nullable: true,
7982
8508
  example: 'broker'
@@ -7997,7 +8523,7 @@ export const $HoldingPnlRowDto = {
7997
8523
  example: 'EQUITY'
7998
8524
  },
7999
8525
  assetSubClass: {
8000
- type: 'object',
8526
+ type: 'string',
8001
8527
  nullable: true,
8002
8528
  example: 'STOCK'
8003
8529
  },
@@ -8044,14 +8570,14 @@ export const $HoldingPnlRowDto = {
8044
8570
  ]
8045
8571
  },
8046
8572
  unrealizedPnlBase: {
8047
- type: 'object',
8573
+ type: 'string',
8048
8574
  description:
8049
8575
  'Unrealized P&L in base currency (Decimal string); null when any FX/price missing',
8050
8576
  nullable: true,
8051
8577
  example: '6000'
8052
8578
  },
8053
8579
  unrealizedPnlPct: {
8054
- type: 'object',
8580
+ type: 'string',
8055
8581
  description: 'Unrealized P&L % (Decimal string)',
8056
8582
  nullable: true,
8057
8583
  example: '25'
@@ -8075,7 +8601,7 @@ export const $HoldingPnlRowDto = {
8075
8601
  ]
8076
8602
  },
8077
8603
  pctOfInvestedAssets: {
8078
- type: 'object',
8604
+ type: 'string',
8079
8605
  description:
8080
8606
  'Share of invested assets % (Decimal string); only for invested chartTokens',
8081
8607
  nullable: true,
@@ -8120,15 +8646,15 @@ export const $HoldingPnlWarningDto = {
8120
8646
  ]
8121
8647
  },
8122
8648
  symbol: {
8123
- type: 'object',
8649
+ type: 'string',
8124
8650
  nullable: true
8125
8651
  },
8126
8652
  accountId: {
8127
- type: 'object',
8653
+ type: 'string',
8128
8654
  nullable: true
8129
8655
  },
8130
8656
  currency: {
8131
- type: 'object',
8657
+ type: 'string',
8132
8658
  nullable: true
8133
8659
  }
8134
8660
  },
@@ -8192,6 +8718,216 @@ export const $AnonymousLoginResponseDto = {
8192
8718
  required: ['authToken']
8193
8719
  } as const;
8194
8720
 
8721
+ export const $ParserContributionMetaDto = {
8722
+ type: 'object',
8723
+ properties: {
8724
+ institution: {
8725
+ type: 'string',
8726
+ description: 'Institution slug (lowercase kebab-case)',
8727
+ pattern: '^[a-z0-9]+(-[a-z0-9]+)*$',
8728
+ example: 'icbc'
8729
+ },
8730
+ region: {
8731
+ type: 'string',
8732
+ enum: [
8733
+ 'cn',
8734
+ 'us',
8735
+ 'de',
8736
+ 'fr',
8737
+ 'gb',
8738
+ 'hk',
8739
+ 'jp',
8740
+ 'sg',
8741
+ 'au',
8742
+ 'ca',
8743
+ 'other'
8744
+ ]
8745
+ },
8746
+ accountType: {
8747
+ type: 'string',
8748
+ enum: ['checking', 'savings', 'credit', 'debit', 'investment']
8749
+ },
8750
+ format: {
8751
+ type: 'string',
8752
+ enum: ['csv', 'xlsx', 'pdf', 'ofx', 'qif']
8753
+ },
8754
+ institutionDisplayName: {
8755
+ type: 'string',
8756
+ example: '中国工商银行'
8757
+ },
8758
+ encoding: {
8759
+ type: 'string',
8760
+ example: 'utf-8'
8761
+ },
8762
+ delimiter: {
8763
+ type: 'string',
8764
+ description: 'CSV delimiter character: ",", ";", "\\t" or "|"'
8765
+ },
8766
+ headerRows: {
8767
+ type: 'number',
8768
+ default: 1,
8769
+ description: 'Header row count; the client omits the field when it is 1'
8770
+ },
8771
+ notes: {
8772
+ type: 'string',
8773
+ maxLength: 2000
8774
+ }
8775
+ },
8776
+ required: ['institution', 'region', 'accountType', 'format']
8777
+ } as const;
8778
+
8779
+ export const $ParserContributionSamplesDto = {
8780
+ type: 'object',
8781
+ properties: {
8782
+ rows: {
8783
+ description:
8784
+ 'Client-sanitized sample rows (key = column name, value = cell)',
8785
+ type: 'array',
8786
+ items: {
8787
+ type: 'object'
8788
+ }
8789
+ },
8790
+ rawHeaders: {
8791
+ type: 'array',
8792
+ items: {
8793
+ type: 'string'
8794
+ }
8795
+ }
8796
+ },
8797
+ required: ['rows']
8798
+ } as const;
8799
+
8800
+ export const $FieldHintDto = {
8801
+ type: 'object',
8802
+ properties: {
8803
+ columnName: {
8804
+ type: 'string',
8805
+ example: '交易日期'
8806
+ },
8807
+ format: {
8808
+ type: 'string',
8809
+ description: 'Date format, e.g. yyyy-MM-dd HH:mm',
8810
+ example: 'yyyy-MM-dd'
8811
+ },
8812
+ signConvention: {
8813
+ type: 'string',
8814
+ enum: ['negative-expense', 'positive-expense', 'separate-columns']
8815
+ },
8816
+ creditColumn: {
8817
+ type: 'string'
8818
+ },
8819
+ debitColumn: {
8820
+ type: 'string'
8821
+ }
8822
+ },
8823
+ required: ['columnName']
8824
+ } as const;
8825
+
8826
+ export const $ParserContributionFieldHintsDto = {
8827
+ type: 'object',
8828
+ properties: {
8829
+ date: {
8830
+ $ref: '#/components/schemas/FieldHintDto'
8831
+ },
8832
+ amount: {
8833
+ $ref: '#/components/schemas/FieldHintDto'
8834
+ },
8835
+ description: {
8836
+ $ref: '#/components/schemas/FieldHintDto'
8837
+ },
8838
+ balance: {
8839
+ $ref: '#/components/schemas/FieldHintDto'
8840
+ },
8841
+ payee: {
8842
+ $ref: '#/components/schemas/FieldHintDto'
8843
+ },
8844
+ reference: {
8845
+ $ref: '#/components/schemas/FieldHintDto'
8846
+ },
8847
+ category: {
8848
+ $ref: '#/components/schemas/FieldHintDto'
8849
+ }
8850
+ },
8851
+ required: ['date', 'amount']
8852
+ } as const;
8853
+
8854
+ export const $ExpectedTransactionDto = {
8855
+ type: 'object',
8856
+ properties: {
8857
+ date: {
8858
+ type: 'string',
8859
+ example: '2026-08-01'
8860
+ },
8861
+ amount: {
8862
+ type: 'number',
8863
+ example: -45.5
8864
+ },
8865
+ description: {
8866
+ type: 'string',
8867
+ example: '星巴克-***店'
8868
+ },
8869
+ payee: {
8870
+ type: 'string'
8871
+ },
8872
+ category: {
8873
+ type: 'string'
8874
+ }
8875
+ },
8876
+ required: ['date', 'amount', 'description']
8877
+ } as const;
8878
+
8879
+ export const $ParserContributionExamplesDto = {
8880
+ type: 'object',
8881
+ properties: {
8882
+ expectedTransactions: {
8883
+ type: 'array',
8884
+ items: {
8885
+ $ref: '#/components/schemas/ExpectedTransactionDto'
8886
+ }
8887
+ }
8888
+ },
8889
+ required: ['expectedTransactions']
8890
+ } as const;
8891
+
8892
+ export const $ParserContributionRequestDto = {
8893
+ type: 'object',
8894
+ properties: {
8895
+ meta: {
8896
+ $ref: '#/components/schemas/ParserContributionMetaDto'
8897
+ },
8898
+ samples: {
8899
+ $ref: '#/components/schemas/ParserContributionSamplesDto'
8900
+ },
8901
+ fieldHints: {
8902
+ $ref: '#/components/schemas/ParserContributionFieldHintsDto'
8903
+ },
8904
+ examples: {
8905
+ description: 'Omitted entirely by the client when empty',
8906
+ allOf: [
8907
+ {
8908
+ $ref: '#/components/schemas/ParserContributionExamplesDto'
8909
+ }
8910
+ ]
8911
+ }
8912
+ },
8913
+ required: ['meta', 'samples', 'fieldHints']
8914
+ } as const;
8915
+
8916
+ export const $ParserContributionRelayResponseDto = {
8917
+ type: 'object',
8918
+ properties: {
8919
+ issueUrl: {
8920
+ type: 'string',
8921
+ example: 'https://github.com/fire-zu/firela-vlt/issues/42'
8922
+ },
8923
+ issueNumber: {
8924
+ type: 'number',
8925
+ example: 42
8926
+ }
8927
+ },
8928
+ required: ['issueUrl', 'issueNumber']
8929
+ } as const;
8930
+
8195
8931
  export const $SymbolSearchResultDto = {
8196
8932
  type: 'object',
8197
8933
  properties: {
@@ -8200,35 +8936,35 @@ export const $SymbolSearchResultDto = {
8200
8936
  example: 'AAPL'
8201
8937
  },
8202
8938
  name: {
8203
- type: 'object',
8939
+ type: 'string',
8204
8940
  example: 'Apple Inc.',
8205
8941
  nullable: true
8206
8942
  },
8207
8943
  exchange: {
8208
- type: 'object',
8944
+ type: 'string',
8209
8945
  example: 'US',
8210
8946
  nullable: true
8211
8947
  },
8212
8948
  assetType: {
8213
- type: 'object',
8949
+ type: 'string',
8214
8950
  description: 'OpenBB asset_type (e.g. stock, etf)',
8215
8951
  example: 'stock',
8216
8952
  nullable: true
8217
8953
  },
8218
8954
  assetClass: {
8219
- type: 'object',
8955
+ type: 'string',
8220
8956
  description: 'IGN asset class (region.types.ts ASSET_CLASSES)',
8221
8957
  example: 'EQUITY',
8222
8958
  nullable: true
8223
8959
  },
8224
8960
  assetSubClass: {
8225
- type: 'object',
8961
+ type: 'string',
8226
8962
  description: 'IGN asset sub-class (region.types.ts ASSET_SUB_CLASSES)',
8227
8963
  example: 'STOCK',
8228
8964
  nullable: true
8229
8965
  },
8230
8966
  currency: {
8231
- type: 'object',
8967
+ type: 'string',
8232
8968
  description: 'Trading currency (extra_data or inferred from exchange)',
8233
8969
  example: 'USD',
8234
8970
  nullable: true
@@ -8245,90 +8981,90 @@ export const $SymbolQuoteDto = {
8245
8981
  example: 'AAPL'
8246
8982
  },
8247
8983
  name: {
8248
- type: 'object',
8984
+ type: 'string',
8249
8985
  example: 'Apple Inc.',
8250
8986
  nullable: true
8251
8987
  },
8252
8988
  exchange: {
8253
- type: 'object',
8989
+ type: 'string',
8254
8990
  example: 'US',
8255
8991
  nullable: true
8256
8992
  },
8257
8993
  assetType: {
8258
- type: 'object',
8994
+ type: 'string',
8259
8995
  description: 'OpenBB asset_type',
8260
8996
  example: 'stock',
8261
8997
  nullable: true
8262
8998
  },
8263
8999
  assetClass: {
8264
- type: 'object',
9000
+ type: 'string',
8265
9001
  description: 'IGN asset class',
8266
9002
  example: 'EQUITY',
8267
9003
  nullable: true
8268
9004
  },
8269
9005
  assetSubClass: {
8270
- type: 'object',
9006
+ type: 'string',
8271
9007
  description: 'IGN asset sub-class',
8272
9008
  example: 'STOCK',
8273
9009
  nullable: true
8274
9010
  },
8275
9011
  currency: {
8276
- type: 'object',
9012
+ type: 'string',
8277
9013
  description: 'Trading currency (extra_data or inferred from exchange)',
8278
9014
  example: 'USD',
8279
9015
  nullable: true
8280
9016
  },
8281
9017
  price: {
8282
- type: 'object',
9018
+ type: 'string',
8283
9019
  description: 'Latest price (Decimal string)',
8284
9020
  example: '189.84',
8285
9021
  nullable: true
8286
9022
  },
8287
9023
  priceDate: {
8288
- type: 'object',
9024
+ type: 'string',
8289
9025
  description: 'Date the price was observed (ISO yyyy-MM-dd)',
8290
9026
  example: '2026-08-05',
8291
9027
  nullable: true
8292
9028
  },
8293
9029
  changePercent: {
8294
- type: 'object',
9030
+ type: 'number',
8295
9031
  description:
8296
9032
  '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.',
8297
9033
  example: 1.7,
8298
9034
  nullable: true
8299
9035
  },
8300
9036
  prevClose: {
8301
- type: 'object',
9037
+ type: 'string',
8302
9038
  description: 'Previous close (Decimal string)',
8303
9039
  nullable: true
8304
9040
  },
8305
9041
  open: {
8306
- type: 'object',
9042
+ type: 'string',
8307
9043
  description: 'Day open (Decimal string)',
8308
9044
  nullable: true
8309
9045
  },
8310
9046
  high: {
8311
- type: 'object',
9047
+ type: 'string',
8312
9048
  description: 'Day high (Decimal string)',
8313
9049
  nullable: true
8314
9050
  },
8315
9051
  low: {
8316
- type: 'object',
9052
+ type: 'string',
8317
9053
  description: 'Day low (Decimal string)',
8318
9054
  nullable: true
8319
9055
  },
8320
9056
  volume: {
8321
- type: 'object',
9057
+ type: 'string',
8322
9058
  description: 'Day volume (Decimal string)',
8323
9059
  nullable: true
8324
9060
  },
8325
9061
  yearHigh: {
8326
- type: 'object',
9062
+ type: 'string',
8327
9063
  description: '52-week high (Decimal string)',
8328
9064
  nullable: true
8329
9065
  },
8330
9066
  yearLow: {
8331
- type: 'object',
9067
+ type: 'string',
8332
9068
  description: '52-week low (Decimal string)',
8333
9069
  nullable: true
8334
9070
  }