@firela/api-types 0.0.0-canary.e7524e0a → 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.
@@ -124,6 +124,8 @@ export const $AccountResponseDto = {
124
124
  'STUDENT_LOAN',
125
125
  'CREDIT_CARD',
126
126
  'PERSONAL_LOAN',
127
+ 'ACCOUNTS_PAYABLE',
128
+ 'TAX_PAYABLE',
127
129
  'OTHER'
128
130
  ],
129
131
  nullable: true,
@@ -195,7 +197,7 @@ export const $AccountResponseDto = {
195
197
  }
196
198
  },
197
199
  platformId: {
198
- type: 'object',
200
+ type: 'string',
199
201
  description: 'Platform ID (null if unbound)',
200
202
  example: 'c98e5d4a-2f71-4a5a-bb3c-92c9f231d5e2'
201
203
  },
@@ -375,16 +377,43 @@ export const $AccountStandardResponseDto = {
375
377
  },
376
378
  name: {
377
379
  type: 'string',
378
- 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).',
379
382
  example: 'Housing Fund'
380
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
+ },
381
408
  description: {
382
409
  type: 'string',
383
- 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).',
384
412
  example: 'ICBC checking account for daily transactions'
385
413
  },
386
414
  tags: {
387
- 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.',
388
417
  example: ['bank', 'checking', 'primary'],
389
418
  type: 'array',
390
419
  items: {
@@ -395,9 +424,47 @@ export const $AccountStandardResponseDto = {
395
424
  type: 'string',
396
425
  description: 'Icon identifier for UI display',
397
426
  example: 'bank-icbc'
427
+ },
428
+ productCategory: {
429
+ type: 'string',
430
+ description:
431
+ 'Onboarding product category (coarse grouping derived from assetSubClass)',
432
+ enum: [
433
+ 'cash',
434
+ 'investment',
435
+ 'credit_card',
436
+ 'loan',
437
+ 'payable_tax',
438
+ 'other'
439
+ ],
440
+ example: 'investment'
441
+ },
442
+ assetClass: {
443
+ type: 'string',
444
+ description:
445
+ 'Asset class (LIQUIDITY/EQUITY/.../LIABILITY), derived at read time from classification rules',
446
+ enum: [
447
+ 'LIQUIDITY',
448
+ 'EQUITY',
449
+ 'FIXED_INCOME',
450
+ 'PRECIOUS_METALS',
451
+ 'COMMODITY',
452
+ 'INSURANCE',
453
+ 'ALTERNATIVE_INVESTMENT',
454
+ 'PERSONAL_ASSETS',
455
+ 'LIABILITY',
456
+ 'REAL_ESTATE',
457
+ 'INDEX'
458
+ ]
459
+ },
460
+ assetSubClass: {
461
+ type: 'string',
462
+ description:
463
+ 'Asset sub-class (product type, derived at read time from classification rules)',
464
+ example: 'STOCK'
398
465
  }
399
466
  },
400
- required: ['path', 'type', 'description', 'tags', 'icon']
467
+ required: ['path', 'type', 'description', 'tags', 'icon', 'productCategory']
401
468
  } as const;
402
469
 
403
470
  export const $AccountStandardListResponseDto = {
@@ -458,7 +525,10 @@ export const $RegionConfigDto = {
458
525
  },
459
526
  locale: {
460
527
  type: 'string',
461
- 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)"
462
532
  }
463
533
  },
464
534
  required: ['currency', 'dateFormat', 'locale']
@@ -471,6 +541,12 @@ export const $RegionInfoDto = {
471
541
  type: 'string',
472
542
  example: 'de'
473
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
+ },
474
550
  displayName: {
475
551
  type: 'string',
476
552
  example: 'Germany'
@@ -489,7 +565,7 @@ export const $RegionInfoDto = {
489
565
  $ref: '#/components/schemas/RegionConfigDto'
490
566
  }
491
567
  },
492
- required: ['code', 'displayName', 'chain', 'config']
568
+ required: ['code', 'open', 'displayName', 'chain', 'config']
493
569
  } as const;
494
570
 
495
571
  export const $RegionsMetadataResponseDto = {
@@ -736,7 +812,7 @@ export const $PostingResponseDto = {
736
812
  units: {
737
813
  type: 'string',
738
814
  description:
739
- '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.',
740
816
  example: '100.50'
741
817
  },
742
818
  currency: {
@@ -1102,7 +1178,7 @@ export const $PostingDetailDto = {
1102
1178
  units: {
1103
1179
  type: 'string',
1104
1180
  description:
1105
- '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.',
1106
1182
  example: '100.50'
1107
1183
  },
1108
1184
  currency: {
@@ -1286,6 +1362,147 @@ export const $TransactionDetailDto = {
1286
1362
  ]
1287
1363
  } as const;
1288
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
+
1289
1506
  export const $BalanceByCurrencyDto = {
1290
1507
  type: 'object',
1291
1508
  properties: {
@@ -1331,7 +1548,7 @@ export const $TransactionListSummaryDto = {
1331
1548
  totalAmount: {
1332
1549
  type: 'string',
1333
1550
  description:
1334
- '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.',
1335
1552
  example: '-6000.00'
1336
1553
  },
1337
1554
  currency: {
@@ -1357,6 +1574,26 @@ export const $TransactionListSummaryDto = {
1357
1574
  required: ['totalAmount', 'currency', 'balanceByCurrency']
1358
1575
  } as const;
1359
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
+
1360
1597
  export const $TransactionListResponseDto = {
1361
1598
  type: 'object',
1362
1599
  properties: {
@@ -1364,7 +1601,7 @@ export const $TransactionListResponseDto = {
1364
1601
  description: 'List of transactions',
1365
1602
  type: 'array',
1366
1603
  items: {
1367
- $ref: '#/components/schemas/TransactionDetailDto'
1604
+ $ref: '#/components/schemas/TransactionListItemDto'
1368
1605
  }
1369
1606
  },
1370
1607
  total: {
@@ -1390,6 +1627,15 @@ export const $TransactionListResponseDto = {
1390
1627
  $ref: '#/components/schemas/TransactionListSummaryDto'
1391
1628
  }
1392
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
+ ]
1393
1639
  }
1394
1640
  },
1395
1641
  required: ['data', 'total', 'limit', 'offset']
@@ -2300,10 +2546,10 @@ export const $UpdatePayeeDto = {
2300
2546
  meta: {
2301
2547
  type: 'object',
2302
2548
  description:
2303
- 'Metadata for extended information (location, notes, contact info, etc.). Will merge with existing metadata.',
2549
+ 'Metadata for extended information (location, notes, contact info, etc.)',
2304
2550
  example: {
2305
2551
  location: 'Zhongguancun',
2306
- note: 'Updated note',
2552
+ note: 'Near subway station',
2307
2553
  favorite: true
2308
2554
  }
2309
2555
  },
@@ -2864,568 +3110,660 @@ export const $UpdateCommodityDto = {
2864
3110
  }
2865
3111
  } as const;
2866
3112
 
2867
- export const $CreateBeanPriceDto = {
3113
+ export const $CurrencyBalanceDto = {
2868
3114
  type: 'object',
2869
3115
  properties: {
2870
3116
  currency: {
2871
3117
  type: 'string',
2872
- description: 'Currency being priced (e.g., USD, AAPL, BTC)',
2873
- example: 'USD'
2874
- },
2875
- quoteCurrency: {
2876
- type: 'string',
2877
- description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
3118
+ description: 'ISO 4217 currency code',
2878
3119
  example: 'CNY'
2879
3120
  },
2880
- amount: {
2881
- type: 'number',
2882
- description:
2883
- 'Price amount (MUST be >= 0 per Beancount spec, supports up to 15 decimal places). Zero allowed for conversion entries, negative strictly prohibited.',
2884
- example: 175.5,
2885
- minimum: 0
2886
- },
2887
- date: {
3121
+ balance: {
2888
3122
  type: 'string',
2889
- description: 'Price date (ISO 8601 format)',
2890
- example: '2024-11-05'
2891
- },
2892
- metadata: {
2893
- type: 'object',
2894
- description:
2895
- 'Metadata (validated by Zod schema, max field lengths enforced)',
2896
- example: {
2897
- source: 'MANUAL',
2898
- note: 'Bank valuation report',
2899
- confidence: 0.95
2900
- }
3123
+ description: 'Balance amount',
3124
+ example: '500000.00'
2901
3125
  }
2902
3126
  },
2903
- required: ['currency', 'quoteCurrency', 'amount', 'date']
3127
+ required: ['currency', 'balance']
2904
3128
  } as const;
2905
3129
 
2906
- export const $PriceResponseDto = {
3130
+ export const $TimeSeriesPointDto = {
2907
3131
  type: 'object',
2908
3132
  properties: {
2909
- id: {
3133
+ date: {
2910
3134
  type: 'string',
2911
- description: 'Unique identifier',
2912
- example: 'uuid-123-456'
3135
+ description: 'Date in YYYY-MM-DD format',
3136
+ example: '2024-06-15'
2913
3137
  },
2914
- userId: {
3138
+ value: {
2915
3139
  type: 'string',
2916
- description: 'User ID (owner of the price)',
2917
- example: 'user-123'
3140
+ description: 'Value at this date (in base currency)',
3141
+ example: '500000.00'
2918
3142
  },
2919
- currency: {
3143
+ change: {
2920
3144
  type: 'string',
2921
- description: 'Currency being priced (e.g., USD, AAPL, BTC)',
2922
- example: 'BTC'
3145
+ description: 'Change from previous point',
3146
+ example: '5000.00'
2923
3147
  },
2924
- quoteCurrency: {
3148
+ assets: {
2925
3149
  type: 'string',
2926
- description: 'Quote currency (pricing currency, e.g., USD, CNY)',
2927
- example: 'USD'
2928
- },
2929
- amount: {
2930
- type: 'number',
2931
- description:
2932
- 'Price amount (corresponds to Beancount Amount.number). Supports up to 15 decimal places.',
2933
- example: 50000
3150
+ description: 'Total assets at this date (in base currency)',
3151
+ example: '494338.00'
2934
3152
  },
2935
- date: {
3153
+ liabilities: {
2936
3154
  type: 'string',
2937
- description:
2938
- 'Price date (ISO 8601 format). Represents the date this price was valid.',
2939
- example: '2024-01-01',
2940
- format: 'date'
3155
+ description: 'Total liabilities at this date (in base currency)',
3156
+ example: '310098.00'
2941
3157
  },
2942
- meta: {
2943
- type: 'object',
2944
- description:
2945
- 'Metadata (corresponds to Beancount meta field). Contains source, confidence, note, etc.',
2946
- example: {
2947
- source: 'MANUAL',
2948
- note: 'User-defined price',
2949
- confidence: 1
3158
+ byCurrency: {
3159
+ description: 'Multi-currency breakdown for this point',
3160
+ type: 'array',
3161
+ items: {
3162
+ $ref: '#/components/schemas/CurrencyBalanceDto'
2950
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'
2951
3176
  },
2952
- createdAt: {
2953
- format: 'date-time',
3177
+ endValue: {
2954
3178
  type: 'string',
2955
- description: 'Creation timestamp',
2956
- example: '2024-11-03T10:00:00Z'
3179
+ description: 'Value at end of period',
3180
+ example: '500000.00'
2957
3181
  },
2958
- updatedAt: {
2959
- format: 'date-time',
3182
+ totalChange: {
2960
3183
  type: 'string',
2961
- description: 'Last update timestamp',
2962
- 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%'
2963
3191
  }
2964
3192
  },
2965
- required: [
2966
- 'id',
2967
- 'userId',
2968
- 'currency',
2969
- 'quoteCurrency',
2970
- 'amount',
2971
- 'date',
2972
- 'meta',
2973
- 'createdAt',
2974
- 'updatedAt'
2975
- ]
3193
+ required: ['startValue', 'endValue', 'totalChange', 'totalChangePercentage']
2976
3194
  } as const;
2977
3195
 
2978
- export const $PriceListResponseDto = {
3196
+ export const $MultiCurrencyPointDto = {
2979
3197
  type: 'object',
2980
3198
  properties: {
2981
- items: {
2982
- 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',
2983
3206
  type: 'array',
2984
3207
  items: {
2985
- $ref: '#/components/schemas/PriceResponseDto'
3208
+ $ref: '#/components/schemas/CurrencyBalanceDto'
2986
3209
  }
2987
- },
2988
- total: {
2989
- type: 'number',
2990
- description: 'Total number of prices',
2991
- example: 42
2992
3210
  }
2993
3211
  },
2994
- required: ['items', 'total']
3212
+ required: ['date', 'byCurrency']
2995
3213
  } as const;
2996
3214
 
2997
- export const $UpdateBeanPriceDto = {
3215
+ export const $PortfolioTrendsResponseDto = {
2998
3216
  type: 'object',
2999
3217
  properties: {
3000
- currency: {
3001
- type: 'string',
3002
- description: 'Currency being priced'
3218
+ series: {
3219
+ description: 'Time series data points',
3220
+ type: 'array',
3221
+ items: {
3222
+ $ref: '#/components/schemas/TimeSeriesPointDto'
3223
+ }
3003
3224
  },
3004
- quoteCurrency: {
3225
+ summary: {
3226
+ description: 'Period summary',
3227
+ allOf: [
3228
+ {
3229
+ $ref: '#/components/schemas/TrendSummaryDto'
3230
+ }
3231
+ ]
3232
+ },
3233
+ period: {
3005
3234
  type: 'string',
3006
- description: 'Quote currency (pricing currency)'
3235
+ description: 'Period requested',
3236
+ example: '6m'
3007
3237
  },
3008
- amount: {
3009
- type: 'number',
3010
- description: 'Price amount (MUST be >= 0 per Beancount spec)',
3011
- minimum: 0
3238
+ granularity: {
3239
+ type: 'string',
3240
+ description: 'Data granularity',
3241
+ example: 'month'
3012
3242
  },
3013
- date: {
3243
+ currency: {
3014
3244
  type: 'string',
3015
- description: 'Price date (ISO 8601 format)'
3245
+ description: 'Base currency for converted values',
3246
+ example: 'CNY'
3016
3247
  },
3017
- metadata: {
3018
- type: 'object',
3019
- 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
+ }
3020
3262
  }
3021
- }
3263
+ },
3264
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
3022
3265
  } as const;
3023
3266
 
3024
- export const $CreateRecurringRuleDto = {
3267
+ export const $CashFlowPointDto = {
3025
3268
  type: 'object',
3026
3269
  properties: {
3027
- name: {
3270
+ month: {
3028
3271
  type: 'string',
3029
- description: 'Rule name (unique per user)',
3030
- maxLength: 100
3272
+ description: 'Month key (YYYY-MM)',
3273
+ example: '2024-03'
3031
3274
  },
3032
- icon: {
3275
+ income: {
3033
3276
  type: 'string',
3034
- description: 'Icon emoji',
3035
- maxLength: 10
3277
+ description: 'Income in base currency (absolute, converted)',
3278
+ example: '10000.00'
3036
3279
  },
3037
- frequency: {
3280
+ expense: {
3038
3281
  type: 'string',
3039
- description: 'Recurring frequency',
3040
- enum: [
3041
- 'WEEKLY',
3042
- 'BIWEEKLY',
3043
- 'MONTHLY',
3044
- 'BIMONTHLY',
3045
- 'QUARTERLY',
3046
- 'YEARLY',
3047
- 'CUSTOM'
3048
- ]
3049
- },
3050
- expectedAmount: {
3051
- type: 'number',
3052
- description: 'Expected amount (positive number)',
3053
- minimum: 0
3054
- },
3055
- expectedDay: {
3056
- type: 'number',
3057
- description: 'Expected day of month (1-31)',
3058
- minimum: 1,
3059
- maximum: 31
3060
- },
3061
- customIntervalDays: {
3062
- type: 'number',
3063
- description: 'Custom interval in days (required for CUSTOM frequency)',
3064
- minimum: 1
3282
+ description: 'Expense in base currency (absolute, converted)',
3283
+ example: '5000.00'
3065
3284
  },
3066
- currency: {
3285
+ netSavings: {
3067
3286
  type: 'string',
3068
- description: 'Currency code',
3069
- default: 'CNY',
3070
- maxLength: 10
3071
- },
3072
- matchPayeePattern: {
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: {
3073
3298
  type: 'string',
3074
- description: 'Payee matching pattern (supports wildcards)',
3075
- maxLength: 200
3076
- },
3077
- matchAmountTolerance: {
3078
- type: 'number',
3079
- description: 'Amount tolerance percentage (0-1)',
3080
- default: 0.075,
3081
- minimum: 0,
3082
- maximum: 1
3299
+ description: 'Total income across the period',
3300
+ example: '60000.00'
3083
3301
  },
3084
- defaultExpenseAccount: {
3302
+ totalExpense: {
3085
3303
  type: 'string',
3086
- description: 'Default expense account for auto-create',
3087
- maxLength: 200
3304
+ description: 'Total expense across the period',
3305
+ example: '30000.00'
3088
3306
  },
3089
- defaultPaymentAccount: {
3307
+ totalNetSavings: {
3090
3308
  type: 'string',
3091
- description: 'Default payment account for auto-create',
3092
- maxLength: 200
3309
+ description: 'income − expense across the period',
3310
+ example: '30000.00'
3093
3311
  },
3094
- defaultPayee: {
3312
+ averageMonthlyNetSavings: {
3095
3313
  type: 'string',
3096
- description: 'Default payee for auto-create',
3097
- maxLength: 200
3098
- },
3099
- autoCreate: {
3100
- type: 'boolean',
3101
- description: 'Auto-create transaction when expected date arrives',
3102
- default: false
3103
- },
3104
- startDate: {
3105
- type: 'string',
3106
- description: 'Rule start date (ISO format)'
3107
- },
3108
- endDate: {
3109
- type: 'string',
3110
- description: 'Rule end date (ISO format)'
3314
+ description:
3315
+ 'totalNetSavings divided by the window length (N months, incl. zero-filled)',
3316
+ example: '5000.00'
3111
3317
  }
3112
3318
  },
3113
3319
  required: [
3114
- 'name',
3115
- 'frequency',
3116
- 'expectedAmount',
3117
- 'currency',
3118
- 'matchAmountTolerance',
3119
- 'autoCreate'
3320
+ 'totalIncome',
3321
+ 'totalExpense',
3322
+ 'totalNetSavings',
3323
+ 'averageMonthlyNetSavings'
3120
3324
  ]
3121
3325
  } as const;
3122
3326
 
3123
- export const $RecurringRuleResponseDto = {
3327
+ export const $CashFlowTrendsResponseDto = {
3124
3328
  type: 'object',
3125
3329
  properties: {
3126
- id: {
3127
- type: 'string',
3128
- description: 'Rule ID'
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
+ }
3129
3337
  },
3130
- userId: {
3131
- type: 'string',
3132
- description: 'User ID'
3338
+ summary: {
3339
+ description: 'Period totals',
3340
+ allOf: [
3341
+ {
3342
+ $ref: '#/components/schemas/CashFlowTrendSummaryDto'
3343
+ }
3344
+ ]
3133
3345
  },
3134
- name: {
3346
+ period: {
3135
3347
  type: 'string',
3136
- description: 'Rule name'
3137
- },
3138
- icon: {
3139
- type: 'object',
3140
- description: 'Icon emoji'
3348
+ description: 'Period requested',
3349
+ example: '6m'
3141
3350
  },
3142
- frequency: {
3351
+ granularity: {
3143
3352
  type: 'string',
3144
- description: 'Recurring frequency'
3145
- },
3146
- expectedAmount: {
3147
- type: 'number',
3148
- description: 'Expected amount'
3149
- },
3150
- expectedDay: {
3151
- type: 'object',
3152
- description: 'Expected day of month'
3353
+ description: 'Data granularity (v1 returns month buckets)',
3354
+ example: 'month'
3153
3355
  },
3154
- customIntervalDays: {
3155
- type: 'object',
3156
- description: 'Custom interval in days'
3356
+ currency: {
3357
+ type: 'string',
3358
+ description: 'Base currency for converted values',
3359
+ example: 'CNY'
3157
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: {
3158
3395
  currency: {
3159
3396
  type: 'string',
3160
- description: 'Currency code'
3397
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
3398
+ example: 'USD'
3161
3399
  },
3162
- matchPayeePattern: {
3163
- type: 'object',
3164
- description: 'Payee matching pattern'
3400
+ quoteCurrency: {
3401
+ type: 'string',
3402
+ description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
3403
+ example: 'CNY'
3165
3404
  },
3166
- matchAmountTolerance: {
3405
+ amount: {
3167
3406
  type: 'number',
3168
- 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
3169
3411
  },
3170
- defaultExpenseAccount: {
3171
- type: 'object',
3172
- description: 'Default expense account'
3412
+ date: {
3413
+ type: 'string',
3414
+ description: 'Price date (ISO 8601 format)',
3415
+ example: '2024-11-05'
3173
3416
  },
3174
- defaultPaymentAccount: {
3417
+ metadata: {
3175
3418
  type: 'object',
3176
- 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'
3177
3438
  },
3178
- defaultPayee: {
3179
- type: 'object',
3180
- description: 'Default payee'
3439
+ userId: {
3440
+ type: 'string',
3441
+ description: 'User ID (owner of the price)',
3442
+ example: 'user-123'
3181
3443
  },
3182
- isActive: {
3183
- type: 'boolean',
3184
- description: 'Whether rule is active'
3444
+ currency: {
3445
+ type: 'string',
3446
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
3447
+ example: 'BTC'
3185
3448
  },
3186
- startDate: {
3449
+ quoteCurrency: {
3187
3450
  type: 'string',
3188
- description: 'Rule start date (YYYY-MM-DD)'
3451
+ description: 'Quote currency (pricing currency, e.g., USD, CNY)',
3452
+ example: 'USD'
3189
3453
  },
3190
- endDate: {
3191
- type: 'object',
3192
- 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
3193
3459
  },
3194
- autoCreate: {
3195
- type: 'boolean',
3196
- 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'
3197
3466
  },
3198
- lastOccurrence: {
3467
+ meta: {
3199
3468
  type: 'object',
3200
- description: 'Last matched occurrence date (YYYY-MM-DD)'
3201
- },
3202
- totalCount: {
3203
- type: 'number',
3204
- 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
+ }
3205
3476
  },
3206
3477
  createdAt: {
3207
3478
  format: 'date-time',
3208
3479
  type: 'string',
3209
- description: 'Created at timestamp'
3480
+ description: 'Creation timestamp',
3481
+ example: '2024-11-03T10:00:00Z'
3210
3482
  },
3211
3483
  updatedAt: {
3212
3484
  format: 'date-time',
3213
3485
  type: 'string',
3214
- description: 'Updated at timestamp'
3486
+ description: 'Last update timestamp',
3487
+ example: '2024-11-03T10:00:00Z'
3215
3488
  }
3216
3489
  },
3217
3490
  required: [
3218
3491
  'id',
3219
3492
  'userId',
3220
- 'name',
3221
- 'frequency',
3222
- 'expectedAmount',
3223
3493
  'currency',
3224
- 'matchAmountTolerance',
3225
- 'isActive',
3226
- 'startDate',
3227
- 'autoCreate',
3228
- 'totalCount',
3494
+ 'quoteCurrency',
3495
+ 'amount',
3496
+ 'date',
3497
+ 'meta',
3229
3498
  'createdAt',
3230
3499
  'updatedAt'
3231
3500
  ]
3232
3501
  } as const;
3233
3502
 
3234
- export const $CreateRuleFromTransactionDto = {
3503
+ export const $PriceListResponseDto = {
3235
3504
  type: 'object',
3236
3505
  properties: {
3237
- frequency: {
3238
- type: 'string',
3239
- description: 'Recurring frequency',
3240
- enum: [
3241
- 'WEEKLY',
3242
- 'BIWEEKLY',
3243
- 'MONTHLY',
3244
- 'BIMONTHLY',
3245
- 'QUARTERLY',
3246
- 'YEARLY',
3247
- 'CUSTOM'
3248
- ],
3249
- example: 'MONTHLY'
3250
- },
3251
- name: {
3252
- type: 'string',
3253
- description: 'Optional name override (default: transaction payee)',
3254
- maxLength: 100
3506
+ items: {
3507
+ description: 'List of prices',
3508
+ type: 'array',
3509
+ items: {
3510
+ $ref: '#/components/schemas/PriceResponseDto'
3511
+ }
3255
3512
  },
3256
- icon: {
3257
- type: 'string',
3258
- description: 'Optional icon emoji',
3259
- maxLength: 10
3513
+ total: {
3514
+ type: 'number',
3515
+ description: 'Total number of prices',
3516
+ example: 42
3260
3517
  }
3261
3518
  },
3262
- required: ['frequency']
3519
+ required: ['items', 'total']
3263
3520
  } as const;
3264
3521
 
3265
- export const $RecurringRuleWithStatsResponseDto = {
3522
+ export const $UpdateBeanPriceDto = {
3266
3523
  type: 'object',
3267
3524
  properties: {
3268
- id: {
3525
+ currency: {
3269
3526
  type: 'string',
3270
- description: 'Rule ID'
3527
+ description: 'Currency being priced'
3271
3528
  },
3272
- userId: {
3529
+ quoteCurrency: {
3273
3530
  type: 'string',
3274
- description: 'User ID'
3531
+ description: 'Quote currency (pricing currency)'
3275
3532
  },
3276
- name: {
3533
+ amount: {
3534
+ type: 'number',
3535
+ description: 'Price amount (MUST be >= 0 per Beancount spec)',
3536
+ minimum: 0
3537
+ },
3538
+ date: {
3277
3539
  type: 'string',
3278
- description: 'Rule name'
3540
+ description: 'Price date (ISO 8601 format)'
3279
3541
  },
3280
- icon: {
3542
+ metadata: {
3281
3543
  type: 'object',
3282
- description: 'Icon emoji'
3283
- },
3284
- frequency: {
3544
+ description: 'Metadata'
3545
+ }
3546
+ }
3547
+ } as const;
3548
+
3549
+ export const $DeleteOwnUserDto = {
3550
+ type: 'object',
3551
+ properties: {
3552
+ accessToken: {
3285
3553
  type: 'string',
3286
- description: 'Recurring frequency'
3287
- },
3288
- expectedAmount: {
3289
- type: 'number',
3290
- description: 'Expected amount'
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'
3291
3581
  },
3292
- expectedDay: {
3293
- type: 'object',
3294
- description: 'Expected day of month'
3582
+ role: {
3583
+ type: 'string',
3584
+ description: 'Assigned user role'
3295
3585
  },
3296
- customIntervalDays: {
3297
- type: 'object',
3298
- description: 'Custom interval in days'
3586
+ permissions: {
3587
+ description: 'Permission strings',
3588
+ type: 'array',
3589
+ items: {
3590
+ type: 'string'
3591
+ }
3299
3592
  },
3300
- currency: {
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: {
3301
3609
  type: 'string',
3302
- 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...'
3303
3624
  },
3304
- matchPayeePattern: {
3305
- type: 'object',
3306
- description: 'Payee matching pattern'
3625
+ accessToken: {
3626
+ type: 'string',
3627
+ description: 'Auto-generated access token'
3307
3628
  },
3308
- 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: {
3309
3642
  type: 'number',
3310
- description: 'Amount tolerance percentage'
3643
+ description: 'Security ID'
3311
3644
  },
3312
- defaultExpenseAccount: {
3313
- type: 'object',
3314
- description: 'Default expense account'
3645
+ annualInterestRate: {
3646
+ type: 'number',
3647
+ description: 'Annual interest rate',
3648
+ example: 0.05
3315
3649
  },
3316
- defaultPaymentAccount: {
3317
- type: 'object',
3318
- description: 'Default payment account'
3650
+ currency: {
3651
+ type: 'string',
3652
+ description: 'Currency code',
3653
+ example: 'USD'
3319
3654
  },
3320
- defaultPayee: {
3321
- type: 'object',
3322
- description: 'Default payee'
3655
+ baseCurrency: {
3656
+ type: 'string',
3657
+ description: 'Base currency code',
3658
+ example: 'USD'
3323
3659
  },
3324
- isActive: {
3325
- type: 'boolean',
3326
- description: 'Whether rule is active'
3660
+ benchmark: {
3661
+ type: 'string',
3662
+ description: 'Benchmark symbol',
3663
+ example: 'SPY'
3327
3664
  },
3328
- startDate: {
3665
+ colorScheme: {
3329
3666
  type: 'string',
3330
- description: 'Rule start date (YYYY-MM-DD)'
3667
+ description: 'Color scheme',
3668
+ enum: ['DARK', 'LIGHT']
3331
3669
  },
3332
- endDate: {
3333
- type: 'object',
3334
- description: 'Rule end date (YYYY-MM-DD)'
3670
+ dateRange: {
3671
+ type: 'string',
3672
+ description: 'Date range filter',
3673
+ example: '1y'
3335
3674
  },
3336
- autoCreate: {
3337
- type: 'boolean',
3338
- description: 'Auto-create transaction on expected date'
3675
+ emergencyFund: {
3676
+ type: 'number',
3677
+ description: 'Emergency fund amount',
3678
+ example: 10000
3339
3679
  },
3340
- lastOccurrence: {
3341
- type: 'object',
3342
- 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
+ }
3343
3686
  },
3344
- totalCount: {
3345
- type: 'number',
3346
- description: 'Total matched transactions count'
3687
+ 'filters.assetClasses': {
3688
+ description: 'Asset class filters',
3689
+ type: 'array',
3690
+ items: {
3691
+ type: 'string'
3692
+ }
3347
3693
  },
3348
- createdAt: {
3349
- format: 'date-time',
3694
+ 'filters.dataSource': {
3350
3695
  type: 'string',
3351
- description: 'Created at timestamp'
3696
+ description: 'Data source filter'
3352
3697
  },
3353
- updatedAt: {
3354
- format: 'date-time',
3698
+ 'filters.symbol': {
3355
3699
  type: 'string',
3356
- description: 'Updated at timestamp'
3700
+ description: 'Symbol filter'
3357
3701
  },
3358
- pendingCount: {
3359
- type: 'number',
3360
- description: 'Number of pending expected transactions'
3702
+ 'filters.tags': {
3703
+ description: 'Tag filters',
3704
+ type: 'array',
3705
+ items: {
3706
+ type: 'string'
3707
+ }
3361
3708
  },
3362
- overdueCount: {
3363
- type: 'number',
3364
- description: 'Number of overdue expected transactions'
3709
+ isExperimentalFeatures: {
3710
+ type: 'boolean',
3711
+ description: 'Enable experimental features'
3365
3712
  },
3366
- nextExpectedDate: {
3367
- type: 'object',
3368
- description: 'Next expected date (YYYY-MM-DD)'
3713
+ isRestrictedView: {
3714
+ type: 'boolean',
3715
+ description: 'Enable restricted view mode'
3369
3716
  },
3370
- totalAmount: {
3371
- type: 'number',
3372
- description: 'Total amount of all matched transactions'
3717
+ language: {
3718
+ type: 'string',
3719
+ description: 'Language code',
3720
+ example: 'en'
3373
3721
  },
3374
- averageAmount: {
3375
- type: 'number',
3376
- description: 'Average amount per transaction'
3722
+ locale: {
3723
+ type: 'string',
3724
+ description: 'Locale code',
3725
+ example: 'en-US'
3377
3726
  },
3378
- transactionCount: {
3727
+ projectedTotalAmount: {
3379
3728
  type: 'number',
3380
- description: 'Number of matched transactions'
3381
- },
3382
- firstDate: {
3383
- type: 'object',
3384
- description: 'First matched transaction date (YYYY-MM-DD)'
3729
+ description: 'Projected total amount',
3730
+ example: 1000000
3385
3731
  },
3386
- lastDate: {
3387
- type: 'object',
3388
- 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'
3389
3736
  },
3390
- variance: {
3737
+ savingsRate: {
3391
3738
  type: 'number',
3392
- description: 'Amount variance (standard deviation squared)'
3739
+ description: 'Savings rate percentage',
3740
+ example: 0.2
3393
3741
  },
3394
- upcomingCount: {
3395
- type: 'number',
3396
- description: 'Number of upcoming expected transactions'
3397
- }
3398
- },
3399
- required: [
3400
- 'id',
3401
- 'userId',
3402
- 'name',
3403
- 'frequency',
3404
- 'expectedAmount',
3405
- 'currency',
3406
- 'matchAmountTolerance',
3407
- 'isActive',
3408
- 'startDate',
3409
- 'autoCreate',
3410
- 'totalCount',
3411
- 'createdAt',
3412
- 'updatedAt',
3413
- 'pendingCount',
3414
- 'overdueCount',
3415
- 'totalAmount',
3416
- 'averageAmount',
3417
- 'transactionCount',
3418
- 'variance',
3419
- 'upcomingCount'
3420
- ]
3742
+ viewMode: {
3743
+ type: 'string',
3744
+ description: 'View mode',
3745
+ enum: ['DEFAULT', 'ZEN']
3746
+ }
3747
+ }
3421
3748
  } as const;
3422
3749
 
3423
- export const $UpdateRecurringRuleDto = {
3750
+ export const $UpdatePropertyDto = {
3751
+ type: 'object',
3752
+ properties: {
3753
+ value: {
3754
+ type: 'string',
3755
+ description: 'Property value'
3756
+ }
3757
+ },
3758
+ required: ['value']
3759
+ } as const;
3760
+
3761
+ export const $CreateRecurringRuleDto = {
3424
3762
  type: 'object',
3425
3763
  properties: {
3426
3764
  name: {
3427
3765
  type: 'string',
3428
- description: 'Rule name',
3766
+ description: 'Rule name (unique per user)',
3429
3767
  maxLength: 100
3430
3768
  },
3431
3769
  icon: {
@@ -3448,7 +3786,7 @@ export const $UpdateRecurringRuleDto = {
3448
3786
  },
3449
3787
  expectedAmount: {
3450
3788
  type: 'number',
3451
- description: 'Expected amount',
3789
+ description: 'Expected amount (positive number)',
3452
3790
  minimum: 0
3453
3791
  },
3454
3792
  expectedDay: {
@@ -3459,7 +3797,7 @@ export const $UpdateRecurringRuleDto = {
3459
3797
  },
3460
3798
  customIntervalDays: {
3461
3799
  type: 'number',
3462
- description: 'Custom interval in days',
3800
+ description: 'Custom interval in days (required for CUSTOM frequency)',
3463
3801
  minimum: 1
3464
3802
  },
3465
3803
  currency: {
@@ -3469,118 +3807,136 @@ export const $UpdateRecurringRuleDto = {
3469
3807
  },
3470
3808
  matchPayeePattern: {
3471
3809
  type: 'string',
3472
- description: 'Payee matching pattern',
3810
+ description: 'Payee matching pattern (supports wildcards)',
3473
3811
  maxLength: 200
3474
3812
  },
3475
3813
  matchAmountTolerance: {
3476
3814
  type: 'number',
3477
3815
  description: 'Amount tolerance percentage (0-1)',
3816
+ default: 0.075,
3478
3817
  minimum: 0,
3479
3818
  maximum: 1
3480
3819
  },
3481
3820
  defaultExpenseAccount: {
3482
3821
  type: 'string',
3483
- description: 'Default expense account',
3822
+ description: 'Default expense account for auto-create',
3484
3823
  maxLength: 200
3485
3824
  },
3486
3825
  defaultPaymentAccount: {
3487
3826
  type: 'string',
3488
- description: 'Default payment account',
3827
+ description: 'Default payment account for auto-create',
3489
3828
  maxLength: 200
3490
3829
  },
3491
3830
  defaultPayee: {
3492
3831
  type: 'string',
3493
- description: 'Default payee',
3832
+ description: 'Default payee for auto-create',
3494
3833
  maxLength: 200
3495
3834
  },
3496
3835
  autoCreate: {
3497
3836
  type: 'boolean',
3498
- description: 'Auto-create transaction'
3837
+ description: 'Auto-create transaction when expected date arrives',
3838
+ default: false
3499
3839
  },
3500
- isActive: {
3501
- type: 'boolean',
3502
- description: 'Rule active status'
3840
+ startDate: {
3841
+ type: 'string',
3842
+ description: 'Rule start date (ISO format)'
3503
3843
  },
3504
3844
  endDate: {
3505
3845
  type: 'string',
3506
3846
  description: 'Rule end date (ISO format)'
3507
3847
  }
3508
- }
3848
+ },
3849
+ required: [
3850
+ 'name',
3851
+ 'frequency',
3852
+ 'expectedAmount',
3853
+ 'matchAmountTolerance',
3854
+ 'autoCreate'
3855
+ ]
3509
3856
  } as const;
3510
3857
 
3511
- export const $ExpectedTransactionRuleDto = {
3858
+ export const $RecurringRuleResponseDto = {
3512
3859
  type: 'object',
3513
3860
  properties: {
3861
+ id: {
3862
+ type: 'string',
3863
+ description: 'Rule ID'
3864
+ },
3865
+ userId: {
3866
+ type: 'string',
3867
+ description: 'User ID'
3868
+ },
3514
3869
  name: {
3515
3870
  type: 'string',
3516
3871
  description: 'Rule name'
3517
3872
  },
3518
3873
  icon: {
3519
- type: 'object',
3520
- description: 'Rule icon'
3874
+ type: 'string',
3875
+ description: 'Icon emoji'
3521
3876
  },
3522
3877
  frequency: {
3523
3878
  type: 'string',
3524
- 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'
3525
3892
  },
3526
3893
  currency: {
3527
3894
  type: 'string',
3528
3895
  description: 'Currency code'
3529
- }
3530
- },
3531
- required: ['name', 'frequency', 'currency']
3532
- } as const;
3533
-
3534
- export const $ExpectedTransactionResponseDto = {
3535
- type: 'object',
3536
- properties: {
3537
- id: {
3538
- type: 'string',
3539
- description: 'Expected transaction ID'
3540
3896
  },
3541
- userId: {
3897
+ matchPayeePattern: {
3542
3898
  type: 'string',
3543
- description: 'User ID'
3899
+ description: 'Payee matching pattern'
3544
3900
  },
3545
- ruleId: {
3546
- type: 'string',
3547
- description: 'Associated rule ID'
3901
+ matchAmountTolerance: {
3902
+ type: 'number',
3903
+ description: 'Amount tolerance percentage'
3548
3904
  },
3549
- expectedDate: {
3905
+ defaultExpenseAccount: {
3550
3906
  type: 'string',
3551
- description: 'Expected date (YYYY-MM-DD)'
3907
+ description: 'Default expense account'
3552
3908
  },
3553
- expectedAmount: {
3554
- type: 'number',
3555
- description: 'Expected amount'
3909
+ defaultPaymentAccount: {
3910
+ type: 'string',
3911
+ description: 'Default payment account'
3556
3912
  },
3557
- status: {
3913
+ defaultPayee: {
3558
3914
  type: 'string',
3559
- description: 'Status (PENDING, COMPLETED, SKIPPED)'
3915
+ description: 'Default payee'
3560
3916
  },
3561
- matchedTransactionId: {
3562
- type: 'object',
3563
- description: 'Matched transaction ID'
3917
+ isActive: {
3918
+ type: 'boolean',
3919
+ description: 'Whether rule is active'
3564
3920
  },
3565
- matchedAt: {
3566
- type: 'object',
3567
- description: 'Match timestamp (ISO 8601)'
3921
+ startDate: {
3922
+ type: 'string',
3923
+ description: 'Rule start date (YYYY-MM-DD)'
3568
3924
  },
3569
- matchConfidence: {
3570
- type: 'object',
3571
- description: 'Match confidence score (0-1)'
3925
+ endDate: {
3926
+ type: 'string',
3927
+ description: 'Rule end date (YYYY-MM-DD)'
3572
3928
  },
3573
- isOverdue: {
3929
+ autoCreate: {
3574
3930
  type: 'boolean',
3575
- description: 'Whether this expected transaction is overdue'
3931
+ description: 'Auto-create transaction on expected date'
3576
3932
  },
3577
- rule: {
3578
- description: 'Rule information',
3579
- allOf: [
3580
- {
3581
- $ref: '#/components/schemas/ExpectedTransactionRuleDto'
3582
- }
3583
- ]
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'
3584
3940
  },
3585
3941
  createdAt: {
3586
3942
  format: 'date-time',
@@ -3596,647 +3952,581 @@ export const $ExpectedTransactionResponseDto = {
3596
3952
  required: [
3597
3953
  'id',
3598
3954
  'userId',
3599
- 'ruleId',
3600
- 'expectedDate',
3955
+ 'name',
3956
+ 'frequency',
3601
3957
  'expectedAmount',
3602
- 'status',
3603
- 'isOverdue',
3604
- 'rule',
3958
+ 'currency',
3959
+ 'matchAmountTolerance',
3960
+ 'isActive',
3961
+ 'startDate',
3962
+ 'autoCreate',
3963
+ 'totalCount',
3605
3964
  'createdAt',
3606
3965
  'updatedAt'
3607
3966
  ]
3608
3967
  } as const;
3609
3968
 
3610
- export const $ExpectedTransactionListResponseDto = {
3969
+ export const $CreateRuleFromTransactionDto = {
3611
3970
  type: 'object',
3612
3971
  properties: {
3613
- items: {
3614
- type: 'array',
3615
- items: {
3616
- $ref: '#/components/schemas/ExpectedTransactionResponseDto'
3617
- }
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'
3618
3985
  },
3619
- total: {
3620
- type: 'number',
3621
- description: 'Total count'
3622
- }
3623
- },
3624
- required: ['items', 'total']
3625
- } as const;
3626
-
3627
- export const $ConfirmMatchDto = {
3628
- type: 'object',
3629
- properties: {
3630
- transactionId: {
3986
+ name: {
3631
3987
  type: 'string',
3632
- 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
3633
3995
  }
3634
3996
  },
3635
- required: ['transactionId']
3997
+ required: ['frequency']
3636
3998
  } as const;
3637
3999
 
3638
- export const $EnterNowDto = {
4000
+ export const $RecurringRuleWithStatsResponseDto = {
3639
4001
  type: 'object',
3640
4002
  properties: {
3641
- expenseAccount: {
4003
+ id: {
3642
4004
  type: 'string',
3643
- description:
3644
- 'Override expense account (uses rule default if not provided)',
3645
- maxLength: 200
4005
+ description: 'Rule ID'
3646
4006
  },
3647
- paymentAccount: {
4007
+ userId: {
3648
4008
  type: 'string',
3649
- description:
3650
- 'Override payment account (uses rule default if not provided)',
3651
- maxLength: 200
4009
+ description: 'User ID'
3652
4010
  },
3653
- amount: {
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: {
3654
4024
  type: 'number',
3655
- description: 'Override amount (uses expected amount if not provided)',
3656
- minimum: 0
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: {
4036
+ type: 'string',
4037
+ description: 'Currency code'
4038
+ },
4039
+ matchPayeePattern: {
4040
+ type: 'string',
4041
+ description: 'Payee matching pattern'
4042
+ },
4043
+ matchAmountTolerance: {
4044
+ type: 'number',
4045
+ description: 'Amount tolerance percentage'
4046
+ },
4047
+ defaultExpenseAccount: {
4048
+ type: 'string',
4049
+ description: 'Default expense account'
3657
4050
  },
3658
- payee: {
4051
+ defaultPaymentAccount: {
3659
4052
  type: 'string',
3660
- description: 'Override payee (uses rule default if not provided)',
3661
- maxLength: 200
4053
+ description: 'Default payment account'
3662
4054
  },
3663
- narration: {
4055
+ defaultPayee: {
3664
4056
  type: 'string',
3665
- description: 'Optional narration',
3666
- maxLength: 500
3667
- }
3668
- }
3669
- } as const;
3670
-
3671
- export const $ForecastItemDto = {
3672
- type: 'object',
3673
- properties: {
3674
- rule: {
4057
+ description: 'Default payee'
4058
+ },
4059
+ isActive: {
4060
+ type: 'boolean',
4061
+ description: 'Whether rule is active'
4062
+ },
4063
+ startDate: {
3675
4064
  type: 'string',
3676
- description: 'Rule name',
3677
- example: 'Rent'
4065
+ description: 'Rule start date (YYYY-MM-DD)'
3678
4066
  },
3679
- ruleId: {
4067
+ endDate: {
3680
4068
  type: 'string',
3681
- description: 'Rule ID',
3682
- example: 'clx123...'
4069
+ description: 'Rule end date (YYYY-MM-DD)'
3683
4070
  },
3684
- amount: {
3685
- type: 'number',
3686
- description: 'Expected amount',
3687
- example: 3000
4071
+ autoCreate: {
4072
+ type: 'boolean',
4073
+ description: 'Auto-create transaction on expected date'
3688
4074
  },
3689
- date: {
4075
+ lastOccurrence: {
3690
4076
  type: 'string',
3691
- description: 'Expected date (YYYY-MM-DD)',
3692
- example: '2024-04-01'
4077
+ description: 'Last matched occurrence date (YYYY-MM-DD)'
3693
4078
  },
3694
- icon: {
3695
- type: 'string',
3696
- description: 'Rule icon emoji',
3697
- example: '🏠',
3698
- nullable: true
4079
+ totalCount: {
4080
+ type: 'number',
4081
+ description: 'Total matched transactions count'
3699
4082
  },
3700
- currency: {
4083
+ createdAt: {
4084
+ format: 'date-time',
3701
4085
  type: 'string',
3702
- description: 'Currency code',
3703
- example: 'CNY'
3704
- }
3705
- },
3706
- required: ['rule', 'ruleId', 'amount', 'date', 'icon', 'currency']
3707
- } as const;
3708
-
3709
- export const $MonthlyForecastDto = {
3710
- type: 'object',
3711
- properties: {
3712
- month: {
4086
+ description: 'Created at timestamp'
4087
+ },
4088
+ updatedAt: {
4089
+ format: 'date-time',
3713
4090
  type: 'string',
3714
- description: 'Month (YYYY-MM)',
3715
- example: '2024-04'
4091
+ description: 'Updated at timestamp'
3716
4092
  },
3717
- expectedOutflow: {
4093
+ pendingCount: {
3718
4094
  type: 'number',
3719
- description: 'Total expected outflow for the month',
3720
- example: 8500
4095
+ description: 'Number of pending expected transactions'
3721
4096
  },
3722
- itemCount: {
4097
+ overdueCount: {
3723
4098
  type: 'number',
3724
- description: 'Number of expected transactions',
3725
- example: 3
3726
- },
3727
- byCurrency: {
3728
- type: 'object',
3729
- description: 'Breakdown by currency',
3730
- example: {
3731
- CNY: 8500,
3732
- USD: 100
3733
- }
4099
+ description: 'Number of overdue expected transactions'
3734
4100
  },
3735
- items: {
3736
- description: 'Individual forecast items',
3737
- type: 'array',
3738
- items: {
3739
- $ref: '#/components/schemas/ForecastItemDto'
3740
- }
3741
- }
3742
- },
3743
- required: ['month', 'expectedOutflow', 'itemCount', 'byCurrency', 'items']
3744
- } as const;
3745
-
3746
- export const $ForecastResponseDto = {
3747
- type: 'object',
3748
- properties: {
3749
- forecast: {
3750
- description: 'Monthly forecast data',
3751
- type: 'array',
3752
- items: {
3753
- $ref: '#/components/schemas/MonthlyForecastDto'
3754
- }
4101
+ nextExpectedDate: {
4102
+ type: 'string',
4103
+ description: 'Next expected date (YYYY-MM-DD)'
3755
4104
  },
3756
- totalOutflow: {
4105
+ totalAmount: {
3757
4106
  type: 'number',
3758
- description: 'Total expected outflow across all months',
3759
- example: 25500
4107
+ description: 'Total amount of all matched transactions'
3760
4108
  },
3761
- totalByCurrency: {
3762
- type: 'object',
3763
- description: 'Total by currency across all months',
3764
- example: {
3765
- CNY: 25500,
3766
- USD: 300
3767
- }
4109
+ averageAmount: {
4110
+ type: 'number',
4111
+ description: 'Average amount per transaction'
3768
4112
  },
3769
- rulesCount: {
4113
+ transactionCount: {
3770
4114
  type: 'number',
3771
- description: 'Number of active recurring rules included',
3772
- example: 5
4115
+ description: 'Number of matched transactions'
3773
4116
  },
3774
- periodStart: {
4117
+ firstDate: {
3775
4118
  type: 'string',
3776
- description: 'Forecast period start date',
3777
- example: '2024-04-01'
4119
+ description: 'First matched transaction date (YYYY-MM-DD)'
3778
4120
  },
3779
- periodEnd: {
4121
+ lastDate: {
3780
4122
  type: 'string',
3781
- description: 'Forecast period end date',
3782
- 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'
3783
4132
  }
3784
4133
  },
3785
4134
  required: [
3786
- 'forecast',
3787
- 'totalOutflow',
3788
- 'totalByCurrency',
3789
- 'rulesCount',
3790
- 'periodStart',
3791
- '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'
3792
4155
  ]
3793
4156
  } as const;
3794
4157
 
3795
- export const $CurrencyBalanceDto = {
4158
+ export const $UpdateRecurringRuleDto = {
3796
4159
  type: 'object',
3797
4160
  properties: {
3798
- currency: {
4161
+ name: {
3799
4162
  type: 'string',
3800
- description: 'ISO 4217 currency code',
3801
- example: 'CNY'
4163
+ description: 'Rule name (unique per user)',
4164
+ maxLength: 100
3802
4165
  },
3803
- balance: {
3804
- type: 'string',
3805
- description: 'Balance amount',
3806
- example: '500000.00'
3807
- }
3808
- },
3809
- required: ['currency', 'balance']
3810
- } as const;
3811
-
3812
- export const $TimeSeriesPointDto = {
3813
- type: 'object',
3814
- properties: {
3815
- date: {
4166
+ icon: {
3816
4167
  type: 'string',
3817
- description: 'Date in YYYY-MM-DD format',
3818
- example: '2024-06-15'
4168
+ description: 'Icon emoji',
4169
+ maxLength: 10
3819
4170
  },
3820
- value: {
4171
+ frequency: {
3821
4172
  type: 'string',
3822
- description: 'Value at this date (in base currency)',
3823
- example: '500000.00'
3824
- },
3825
- change: {
3826
- type: 'object',
3827
- description: 'Change from previous point',
3828
- example: '5000.00'
4173
+ description: 'Recurring frequency',
4174
+ enum: [
4175
+ 'WEEKLY',
4176
+ 'BIWEEKLY',
4177
+ 'MONTHLY',
4178
+ 'BIMONTHLY',
4179
+ 'QUARTERLY',
4180
+ 'YEARLY',
4181
+ 'CUSTOM'
4182
+ ]
3829
4183
  },
3830
- assets: {
3831
- type: 'string',
3832
- description: 'Total assets at this date (in base currency)',
3833
- example: '494338.00'
4184
+ expectedAmount: {
4185
+ type: 'number',
4186
+ description: 'Expected amount (positive number)',
4187
+ minimum: 0
3834
4188
  },
3835
- liabilities: {
3836
- type: 'string',
3837
- description: 'Total liabilities at this date (in base currency)',
3838
- example: '310098.00'
4189
+ expectedDay: {
4190
+ type: 'number',
4191
+ description: 'Expected day of month (1-31)',
4192
+ minimum: 1,
4193
+ maximum: 31
3839
4194
  },
3840
- byCurrency: {
3841
- description: 'Multi-currency breakdown for this point',
3842
- type: 'array',
3843
- items: {
3844
- $ref: '#/components/schemas/CurrencyBalanceDto'
3845
- }
3846
- }
3847
- },
3848
- required: ['date', 'value']
3849
- } as const;
3850
-
3851
- export const $TrendSummaryDto = {
3852
- type: 'object',
3853
- properties: {
3854
- startValue: {
4195
+ currency: {
3855
4196
  type: 'string',
3856
- description: 'Value at start of period',
3857
- example: '450000.00'
4197
+ description: 'Currency code',
4198
+ maxLength: 10
3858
4199
  },
3859
- endValue: {
4200
+ matchPayeePattern: {
3860
4201
  type: 'string',
3861
- description: 'Value at end of period',
3862
- example: '500000.00'
4202
+ description: 'Payee matching pattern (supports wildcards)',
4203
+ maxLength: 200
3863
4204
  },
3864
- totalChange: {
4205
+ matchAmountTolerance: {
4206
+ type: 'number',
4207
+ description: 'Amount tolerance percentage (0-1)',
4208
+ default: 0.075,
4209
+ minimum: 0,
4210
+ maximum: 1
4211
+ },
4212
+ defaultExpenseAccount: {
3865
4213
  type: 'string',
3866
- description: 'Total change over period',
3867
- example: '50000.00'
4214
+ description: 'Default expense account for auto-create',
4215
+ maxLength: 200
3868
4216
  },
3869
- totalChangePercentage: {
4217
+ defaultPaymentAccount: {
3870
4218
  type: 'string',
3871
- description: 'Total change percentage',
3872
- example: '+11.11%'
3873
- }
3874
- },
3875
- required: ['startValue', 'endValue', 'totalChange', 'totalChangePercentage']
3876
- } as const;
3877
-
3878
- export const $MultiCurrencyPointDto = {
3879
- type: 'object',
3880
- properties: {
3881
- date: {
4219
+ description: 'Default payment account for auto-create',
4220
+ maxLength: 200
4221
+ },
4222
+ defaultPayee: {
3882
4223
  type: 'string',
3883
- description: 'Date in YYYY-MM-DD format',
3884
- example: '2024-06-15'
4224
+ description: 'Default payee for auto-create',
4225
+ maxLength: 200
3885
4226
  },
3886
- byCurrency: {
3887
- description: 'Balances by currency',
3888
- type: 'array',
3889
- items: {
3890
- $ref: '#/components/schemas/CurrencyBalanceDto'
3891
- }
4227
+ autoCreate: {
4228
+ type: 'boolean',
4229
+ description: 'Auto-create transaction when expected date arrives',
4230
+ default: false
4231
+ },
4232
+ endDate: {
4233
+ type: 'string',
4234
+ description: 'Rule end date (ISO format)'
4235
+ },
4236
+ customIntervalDays: {
4237
+ type: 'number',
4238
+ description: 'Custom interval in days',
4239
+ minimum: 1
4240
+ },
4241
+ isActive: {
4242
+ type: 'boolean',
4243
+ description: 'Rule active status'
3892
4244
  }
3893
- },
3894
- required: ['date', 'byCurrency']
4245
+ }
3895
4246
  } as const;
3896
4247
 
3897
- export const $PortfolioTrendsResponseDto = {
4248
+ export const $ExpectedTransactionRuleDto = {
3898
4249
  type: 'object',
3899
4250
  properties: {
3900
- series: {
3901
- description: 'Time series data points',
3902
- type: 'array',
3903
- items: {
3904
- $ref: '#/components/schemas/TimeSeriesPointDto'
3905
- }
3906
- },
3907
- summary: {
3908
- description: 'Period summary',
3909
- allOf: [
3910
- {
3911
- $ref: '#/components/schemas/TrendSummaryDto'
3912
- }
3913
- ]
4251
+ name: {
4252
+ type: 'string',
4253
+ description: 'Rule name'
3914
4254
  },
3915
- period: {
4255
+ icon: {
3916
4256
  type: 'string',
3917
- description: 'Period requested',
3918
- example: '6m'
4257
+ description: 'Rule icon'
3919
4258
  },
3920
- granularity: {
4259
+ frequency: {
3921
4260
  type: 'string',
3922
- description: 'Data granularity',
3923
- example: 'month'
4261
+ description: 'Rule frequency'
3924
4262
  },
3925
4263
  currency: {
3926
4264
  type: 'string',
3927
- description: 'Base currency for converted values',
3928
- example: 'CNY'
3929
- },
3930
- byCurrency: {
3931
- description:
3932
- 'Multi-currency time series (each point has currency breakdown)',
3933
- type: 'array',
3934
- items: {
3935
- $ref: '#/components/schemas/MultiCurrencyPointDto'
3936
- }
3937
- },
3938
- warnings: {
3939
- description: 'Exchange rate warnings',
3940
- type: 'array',
3941
- items: {
3942
- $ref: '#/components/schemas/ExchangeRateWarningDto'
3943
- }
4265
+ description: 'Currency code'
3944
4266
  }
3945
4267
  },
3946
- required: ['series', 'summary', 'period', 'granularity', 'currency']
4268
+ required: ['name', 'frequency', 'currency']
3947
4269
  } as const;
3948
4270
 
3949
- export const $CashFlowPointDto = {
4271
+ export const $ExpectedTransactionResponseDto = {
3950
4272
  type: 'object',
3951
4273
  properties: {
3952
- month: {
4274
+ id: {
3953
4275
  type: 'string',
3954
- description: 'Month key (YYYY-MM)',
3955
- example: '2024-03'
4276
+ description: 'Expected transaction ID'
3956
4277
  },
3957
- income: {
4278
+ userId: {
3958
4279
  type: 'string',
3959
- description: 'Income in base currency (absolute, converted)',
3960
- example: '10000.00'
4280
+ description: 'User ID'
3961
4281
  },
3962
- expense: {
4282
+ ruleId: {
3963
4283
  type: 'string',
3964
- description: 'Expense in base currency (absolute, converted)',
3965
- example: '5000.00'
4284
+ description: 'Associated rule ID'
3966
4285
  },
3967
- netSavings: {
3968
- type: 'string',
3969
- description: 'netSavings = income − expense (savings positive)',
3970
- example: '5000.00'
3971
- }
3972
- },
3973
- required: ['month', 'income', 'expense', 'netSavings']
3974
- } as const;
3975
-
3976
- export const $CashFlowTrendSummaryDto = {
3977
- type: 'object',
3978
- properties: {
3979
- totalIncome: {
4286
+ expectedDate: {
3980
4287
  type: 'string',
3981
- description: 'Total income across the period',
3982
- example: '60000.00'
4288
+ description: 'Expected date (YYYY-MM-DD)'
3983
4289
  },
3984
- totalExpense: {
4290
+ expectedAmount: {
4291
+ type: 'number',
4292
+ description: 'Expected amount'
4293
+ },
4294
+ status: {
3985
4295
  type: 'string',
3986
- description: 'Total expense across the period',
3987
- example: '30000.00'
4296
+ description: 'Status (PENDING, COMPLETED, SKIPPED)'
3988
4297
  },
3989
- totalNetSavings: {
4298
+ matchedTransactionId: {
3990
4299
  type: 'string',
3991
- description: 'income − expense across the period',
3992
- example: '30000.00'
4300
+ description: 'Matched transaction ID'
3993
4301
  },
3994
- averageMonthlyNetSavings: {
4302
+ matchedAt: {
3995
4303
  type: 'string',
3996
- description:
3997
- 'totalNetSavings divided by the window length (N months, incl. zero-filled)',
3998
- example: '5000.00'
3999
- }
4000
- },
4001
- required: [
4002
- 'totalIncome',
4003
- 'totalExpense',
4004
- 'totalNetSavings',
4005
- 'averageMonthlyNetSavings'
4006
- ]
4007
- } as const;
4008
-
4009
- export const $CashFlowTrendsResponseDto = {
4010
- type: 'object',
4011
- properties: {
4012
- series: {
4013
- description:
4014
- 'Monthly cash-flow series (fixed N-month window, zero-filled)',
4015
- type: 'array',
4016
- items: {
4017
- $ref: '#/components/schemas/CashFlowPointDto'
4018
- }
4304
+ description: 'Match timestamp (ISO 8601)'
4019
4305
  },
4020
- summary: {
4021
- 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',
4022
4316
  allOf: [
4023
4317
  {
4024
- $ref: '#/components/schemas/CashFlowTrendSummaryDto'
4318
+ $ref: '#/components/schemas/ExpectedTransactionRuleDto'
4025
4319
  }
4026
4320
  ]
4027
4321
  },
4028
- period: {
4029
- type: 'string',
4030
- description: 'Period requested',
4031
- example: '6m'
4032
- },
4033
- granularity: {
4322
+ createdAt: {
4323
+ format: 'date-time',
4034
4324
  type: 'string',
4035
- description: 'Data granularity (v1 returns month buckets)',
4036
- example: 'month'
4325
+ description: 'Created at timestamp'
4037
4326
  },
4038
- currency: {
4327
+ updatedAt: {
4328
+ format: 'date-time',
4039
4329
  type: 'string',
4040
- description: 'Base currency for converted values',
4041
- example: 'CNY'
4042
- },
4043
- warnings: {
4044
- description: 'Exchange rate warnings (e.g. missing rate for a currency)',
4045
- type: 'array',
4046
- items: {
4047
- $ref: '#/components/schemas/ExchangeRateWarningDto'
4048
- }
4330
+ description: 'Updated at timestamp'
4049
4331
  }
4050
4332
  },
4051
- required: ['series', 'summary', 'period', 'granularity', 'currency']
4052
- } as const;
4053
-
4054
- export const $GenerateSnapshotBody = {
4055
- type: 'object',
4056
- properties: {}
4057
- } as const;
4058
-
4059
- export const $GenerateSnapshotResponse = {
4060
- type: 'object',
4061
- properties: {}
4062
- } as const;
4063
-
4064
- export const $BackfillSnapshotsBody = {
4065
- type: 'object',
4066
- properties: {}
4067
- } as const;
4068
-
4069
- export const $BackfillSnapshotsResponse = {
4070
- type: 'object',
4071
- properties: {}
4333
+ required: [
4334
+ 'id',
4335
+ 'userId',
4336
+ 'ruleId',
4337
+ 'expectedDate',
4338
+ 'expectedAmount',
4339
+ 'status',
4340
+ 'isOverdue',
4341
+ 'rule',
4342
+ 'createdAt',
4343
+ 'updatedAt'
4344
+ ]
4072
4345
  } as const;
4073
4346
 
4074
- export const $DeleteOwnUserDto = {
4347
+ export const $ExpectedTransactionListResponseDto = {
4075
4348
  type: 'object',
4076
4349
  properties: {
4077
- accessToken: {
4078
- type: 'string',
4079
- description: 'Access token for user verification',
4080
- example: 'abc123xyz'
4350
+ items: {
4351
+ type: 'array',
4352
+ items: {
4353
+ $ref: '#/components/schemas/ExpectedTransactionResponseDto'
4354
+ }
4355
+ },
4356
+ total: {
4357
+ type: 'number',
4358
+ description: 'Total count'
4081
4359
  }
4082
4360
  },
4083
- required: ['accessToken']
4361
+ required: ['items', 'total']
4084
4362
  } as const;
4085
4363
 
4086
- export const $SignupDto = {
4364
+ export const $ConfirmMatchDto = {
4087
4365
  type: 'object',
4088
4366
  properties: {
4089
- turnstileToken: {
4367
+ transactionId: {
4090
4368
  type: 'string',
4091
- description:
4092
- 'Cloudflare Turnstile verification token (optional when Turnstile disabled)',
4093
- example: '0.abc123def456...'
4369
+ description: 'Transaction ID to match with'
4094
4370
  }
4095
- }
4371
+ },
4372
+ required: ['transactionId']
4096
4373
  } as const;
4097
4374
 
4098
- export const $SignupResponseDto = {
4375
+ export const $EnterNowDto = {
4099
4376
  type: 'object',
4100
4377
  properties: {
4101
- authToken: {
4378
+ expenseAccount: {
4102
4379
  type: 'string',
4103
- description: 'JWT auth token',
4104
- example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
4380
+ description:
4381
+ 'Override expense account (uses rule default if not provided)',
4382
+ maxLength: 200
4105
4383
  },
4106
- accessToken: {
4384
+ paymentAccount: {
4107
4385
  type: 'string',
4108
- description: 'Auto-generated access token'
4386
+ description:
4387
+ 'Override payment account (uses rule default if not provided)',
4388
+ maxLength: 200
4109
4389
  },
4110
- role: {
4390
+ amount: {
4391
+ type: 'number',
4392
+ description: 'Override amount (uses expected amount if not provided)',
4393
+ minimum: 0
4394
+ },
4395
+ payee: {
4111
4396
  type: 'string',
4112
- description: 'Assigned user role',
4113
- enum: ['USER', 'ADMIN', 'DEMO', 'INACTIVE', 'PAID', 'OPS']
4397
+ description: 'Override payee (uses rule default if not provided)',
4398
+ maxLength: 200
4399
+ },
4400
+ narration: {
4401
+ type: 'string',
4402
+ description: 'Optional narration',
4403
+ maxLength: 500
4114
4404
  }
4115
- },
4116
- required: ['authToken', 'accessToken', 'role']
4405
+ }
4117
4406
  } as const;
4118
4407
 
4119
- export const $UpdateUserSettingDto = {
4408
+ export const $ForecastItemDto = {
4120
4409
  type: 'object',
4121
4410
  properties: {
4122
- secId: {
4123
- type: 'number',
4124
- description: 'Security ID'
4411
+ rule: {
4412
+ type: 'string',
4413
+ description: 'Rule name',
4414
+ example: 'Rent'
4125
4415
  },
4126
- annualInterestRate: {
4416
+ ruleId: {
4417
+ type: 'string',
4418
+ description: 'Rule ID',
4419
+ example: 'clx123...'
4420
+ },
4421
+ amount: {
4127
4422
  type: 'number',
4128
- description: 'Annual interest rate',
4129
- example: 0.05
4423
+ description: 'Expected amount',
4424
+ example: 3000
4130
4425
  },
4131
- currency: {
4426
+ date: {
4132
4427
  type: 'string',
4133
- description: 'Currency code',
4134
- example: 'USD'
4428
+ description: 'Expected date (YYYY-MM-DD)',
4429
+ example: '2024-04-01'
4135
4430
  },
4136
- baseCurrency: {
4431
+ icon: {
4137
4432
  type: 'string',
4138
- description: 'Base currency code',
4139
- example: 'USD'
4433
+ description: 'Rule icon emoji',
4434
+ example: '🏠',
4435
+ nullable: true
4140
4436
  },
4141
- benchmark: {
4437
+ currency: {
4142
4438
  type: 'string',
4143
- description: 'Benchmark symbol',
4144
- example: 'SPY'
4145
- },
4146
- 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: {
4147
4450
  type: 'string',
4148
- description: 'Color scheme',
4149
- enum: ['DARK', 'LIGHT']
4451
+ description: 'Month (YYYY-MM)',
4452
+ example: '2024-04'
4150
4453
  },
4151
- dateRange: {
4152
- type: 'string',
4153
- description: 'Date range filter',
4154
- example: '1y'
4454
+ expectedOutflow: {
4455
+ type: 'number',
4456
+ description: 'Total expected outflow for the month',
4457
+ example: 8500
4155
4458
  },
4156
- emergencyFund: {
4459
+ itemCount: {
4157
4460
  type: 'number',
4158
- description: 'Emergency fund amount',
4159
- example: 10000
4461
+ description: 'Number of expected transactions',
4462
+ example: 3
4160
4463
  },
4161
- 'filters.accounts': {
4162
- description: 'Account filter IDs',
4163
- type: 'array',
4164
- items: {
4165
- type: 'string'
4464
+ byCurrency: {
4465
+ type: 'object',
4466
+ description: 'Breakdown by currency',
4467
+ example: {
4468
+ CNY: 8500,
4469
+ USD: 100
4166
4470
  }
4167
4471
  },
4168
- 'filters.assetClasses': {
4169
- description: 'Asset class filters',
4472
+ items: {
4473
+ description: 'Individual forecast items',
4170
4474
  type: 'array',
4171
4475
  items: {
4172
- type: 'string'
4476
+ $ref: '#/components/schemas/ForecastItemDto'
4173
4477
  }
4174
- },
4175
- 'filters.dataSource': {
4176
- type: 'string',
4177
- description: 'Data source filter'
4178
- },
4179
- 'filters.symbol': {
4180
- type: 'string',
4181
- description: 'Symbol filter'
4182
- },
4183
- 'filters.tags': {
4184
- 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',
4185
4488
  type: 'array',
4186
4489
  items: {
4187
- type: 'string'
4490
+ $ref: '#/components/schemas/MonthlyForecastDto'
4188
4491
  }
4189
4492
  },
4190
- isExperimentalFeatures: {
4191
- type: 'boolean',
4192
- description: 'Enable experimental features'
4193
- },
4194
- isRestrictedView: {
4195
- type: 'boolean',
4196
- description: 'Enable restricted view mode'
4197
- },
4198
- language: {
4199
- type: 'string',
4200
- description: 'Language code',
4201
- example: 'en'
4202
- },
4203
- locale: {
4204
- type: 'string',
4205
- description: 'Locale code',
4206
- example: 'en-US'
4207
- },
4208
- projectedTotalAmount: {
4493
+ totalOutflow: {
4209
4494
  type: 'number',
4210
- description: 'Projected total amount',
4211
- example: 1000000
4495
+ description: 'Total expected outflow across all months',
4496
+ example: 25500
4212
4497
  },
4213
- retirementDate: {
4214
- type: 'string',
4215
- description: 'Retirement date in ISO 8601 format',
4216
- 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
+ }
4217
4505
  },
4218
- savingsRate: {
4506
+ rulesCount: {
4219
4507
  type: 'number',
4220
- description: 'Savings rate percentage',
4221
- example: 0.2
4508
+ description: 'Number of active recurring rules included',
4509
+ example: 5
4222
4510
  },
4223
- viewMode: {
4511
+ periodStart: {
4224
4512
  type: 'string',
4225
- description: 'View mode',
4226
- enum: ['DEFAULT', 'ZEN']
4227
- }
4228
- }
4229
- } as const;
4230
-
4231
- export const $UpdatePropertyDto = {
4232
- type: 'object',
4233
- properties: {
4234
- value: {
4513
+ description: 'Forecast period start date',
4514
+ example: '2024-04-01'
4515
+ },
4516
+ periodEnd: {
4235
4517
  type: 'string',
4236
- description: 'Property value'
4518
+ description: 'Forecast period end date',
4519
+ example: '2024-06-30'
4237
4520
  }
4238
4521
  },
4239
- required: ['value']
4522
+ required: [
4523
+ 'forecast',
4524
+ 'totalOutflow',
4525
+ 'totalByCurrency',
4526
+ 'rulesCount',
4527
+ 'periodStart',
4528
+ 'periodEnd'
4529
+ ]
4240
4530
  } as const;
4241
4531
 
4242
4532
  export const $CreateTransactionRuleDto = {
@@ -4798,7 +5088,8 @@ export const $UpdateTransactionRuleDto = {
4798
5088
  },
4799
5089
  matchLogic: {
4800
5090
  type: 'string',
4801
- enum: ['OR', 'AND']
5091
+ enum: ['OR', 'AND'],
5092
+ default: 'OR'
4802
5093
  },
4803
5094
  amountMin: {
4804
5095
  type: 'number',
@@ -4812,13 +5103,10 @@ export const $UpdateTransactionRuleDto = {
4812
5103
  },
4813
5104
  priority: {
4814
5105
  type: 'number',
5106
+ default: 50,
4815
5107
  minimum: 0,
4816
5108
  maximum: 1000
4817
5109
  },
4818
- enabled: {
4819
- type: 'boolean',
4820
- description: 'Enable or disable the rule'
4821
- },
4822
5110
  additionalTags: {
4823
5111
  items: {
4824
5112
  type: 'array'
@@ -4828,6 +5116,10 @@ export const $UpdateTransactionRuleDto = {
4828
5116
  },
4829
5117
  additionalMetadata: {
4830
5118
  type: 'object'
5119
+ },
5120
+ enabled: {
5121
+ type: 'boolean',
5122
+ description: 'Enable or disable the rule'
4831
5123
  }
4832
5124
  }
4833
5125
  } as const;
@@ -4888,6 +5180,69 @@ export const $TestRuleResponseDto = {
4888
5180
  required: ['ruleId', 'matches', 'confidence', 'matchDetails']
4889
5181
  } as const;
4890
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
+
4891
5246
  export const $CreateBeanEventDto = {
4892
5247
  type: 'object',
4893
5248
  properties: {
@@ -5630,7 +5985,8 @@ export const $UpdateMapperDefaultsDto = {
5630
5985
  type: 'string',
5631
5986
  description: 'Source account for transactions (Beancount format)',
5632
5987
  example: 'Assets:CN:Alipay:Balance',
5633
- 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-]*)+$'
5634
5990
  },
5635
5991
  currency: {
5636
5992
  type: 'string',
@@ -5644,13 +6000,15 @@ export const $UpdateMapperDefaultsDto = {
5644
6000
  type: 'string',
5645
6001
  description: 'Default expense account (optional)',
5646
6002
  example: 'Expenses:Unknown',
5647
- 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-]*)+$'
5648
6005
  },
5649
6006
  incomeAccount: {
5650
6007
  type: 'string',
5651
6008
  description: 'Default income account (optional)',
5652
6009
  example: 'Income:Unknown',
5653
- 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-]*)+$'
5654
6012
  },
5655
6013
  methodAccountMapping: {
5656
6014
  type: 'object',
@@ -5707,12 +6065,14 @@ export const $ProviderSyncConfigDto = {
5707
6065
  },
5708
6066
  defaultExpenseAccount: {
5709
6067
  type: 'string',
5710
- description: 'Default expense account for the second posting',
6068
+ description:
6069
+ 'Default expense account for the second posting. Omit when no real default exists; the pipeline routes to Review via the Uncategorized sentinel (#618).',
5711
6070
  example: 'Expenses:Unknown'
5712
6071
  },
5713
6072
  defaultIncomeAccount: {
5714
6073
  type: 'string',
5715
- description: 'Default income account for the second posting',
6074
+ description:
6075
+ 'Default income account for the second posting. Omit when no real default exists; the pipeline routes to Review via the Uncategorized sentinel (#618).',
5716
6076
  example: 'Income:Unknown'
5717
6077
  },
5718
6078
  filterPending: {
@@ -5727,12 +6087,7 @@ export const $ProviderSyncConfigDto = {
5727
6087
  example: 'acc_gocardless_001'
5728
6088
  }
5729
6089
  },
5730
- required: [
5731
- 'sourceAccount',
5732
- 'defaultCurrency',
5733
- 'defaultExpenseAccount',
5734
- 'defaultIncomeAccount'
5735
- ]
6090
+ required: ['sourceAccount', 'defaultCurrency']
5736
6091
  } as const;
5737
6092
 
5738
6093
  export const $ProviderSyncDto = {
@@ -5942,15 +6297,105 @@ export const $UncoveredFormatMissDto = {
5942
6297
  properties: {}
5943
6298
  } as const;
5944
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
+
5945
6383
  export const $ProcessNlpDto = {
5946
6384
  type: 'object',
5947
6385
  properties: {
5948
6386
  message: {
5949
6387
  type: 'string',
5950
- description: 'Natural language text describing a transaction (Chinese)',
5951
- 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',
5952
6391
  maxLength: 500
5953
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
+ },
5954
6399
  sessionId: {
5955
6400
  type: 'string',
5956
6401
  description:
@@ -5958,14 +6403,18 @@ export const $ProcessNlpDto = {
5958
6403
  example: 'session_abc123'
5959
6404
  },
5960
6405
  parsedData: {
5961
- type: 'object',
5962
6406
  description:
5963
6407
  'Parsed data from previous NLP response for session recovery. Send back the parsedData received in confirm_payee/confirm responses.',
5964
6408
  example: {
5965
6409
  amount: 35,
5966
6410
  currency: 'CNY',
5967
6411
  payee: 'Starbucks'
5968
- }
6412
+ },
6413
+ allOf: [
6414
+ {
6415
+ $ref: '#/components/schemas/ClientParsedDataDto'
6416
+ }
6417
+ ]
5969
6418
  },
5970
6419
  selectedRuleId: {
5971
6420
  type: 'string',
@@ -5976,11 +6425,29 @@ export const $ProcessNlpDto = {
5976
6425
  selectedAccount: {
5977
6426
  type: 'string',
5978
6427
  description:
5979
- '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.',
5980
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'
5981
6449
  }
5982
- },
5983
- required: ['message']
6450
+ }
5984
6451
  } as const;
5985
6452
 
5986
6453
  export const $NlpTransactionInfoDto = {
@@ -6292,6 +6759,24 @@ export const $NlpRuleConfirmationDataDto = {
6292
6759
  ]
6293
6760
  } as const;
6294
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
+
6295
6780
  export const $NlpAccountConfirmationDataDto = {
6296
6781
  type: 'object',
6297
6782
  properties: {
@@ -6307,10 +6792,11 @@ export const $NlpAccountConfirmationDataDto = {
6307
6792
  example: 'Expenses:Food:Drinks'
6308
6793
  },
6309
6794
  similarAccounts: {
6310
- description: 'Similar accounts for user selection',
6795
+ description:
6796
+ 'Similar accounts for user selection (path + localized name, #680)',
6311
6797
  type: 'array',
6312
6798
  items: {
6313
- type: 'string'
6799
+ $ref: '#/components/schemas/NlpAccountCandidateDto'
6314
6800
  }
6315
6801
  },
6316
6802
  errorMessage: {
@@ -6598,7 +7084,7 @@ export const $NlpResponseDto = {
6598
7084
  type: 'string',
6599
7085
  description:
6600
7086
  'Asset sub-type (only present when intent is "asset"). Determines which asset-related form to render.',
6601
- enum: ['transfer', 'banking', 'investment'],
7087
+ enum: ['transfer', 'banking', 'investment', 'lend', 'lend_collect'],
6602
7088
  example: 'investment'
6603
7089
  },
6604
7090
  liabilitySubType: {
@@ -6801,13 +7287,26 @@ export const $PlatformListItemDto = {
6801
7287
  suggestedSegment: {
6802
7288
  type: 'string',
6803
7289
  description:
6804
- 'Suggested path segment — canonical with first char uppercased (ACC_COMP_NAME_RE)'
7290
+ 'Suggested path segment — canonical PascalCased per hyphen-part, hyphens preserved (e.g. "Apple-Pay")'
6805
7291
  },
6806
7292
  logoUrl: {
6807
7293
  type: 'string',
6808
7294
  description: 'Logo URL',
6809
7295
  nullable: true
6810
7296
  },
7297
+ countryCode: {
7298
+ type: 'string',
7299
+ description: 'ISO 3166-1 alpha-2 (UPPERCASE); null = global platform',
7300
+ example: 'CN',
7301
+ nullable: true
7302
+ },
7303
+ category: {
7304
+ type: 'string',
7305
+ description:
7306
+ 'Region-aware category (institution vocab, e.g. DigitalWallet/Bank). null = no region-aware suggestion; fall back to type.',
7307
+ nullable: true,
7308
+ example: 'DigitalWallet'
7309
+ },
6811
7310
  isBound: {
6812
7311
  type: 'boolean',
6813
7312
  description: 'Whether user has accounts using this platform'
@@ -6821,11 +7320,111 @@ export const $PlatformListItemDto = {
6821
7320
  'canonical',
6822
7321
  'suggestedSegment',
6823
7322
  'logoUrl',
7323
+ 'countryCode',
7324
+ 'category',
6824
7325
  'isBound'
6825
7326
  ]
6826
7327
  } as const;
6827
7328
 
6828
- export const $PlatformMatchResultDto = {
7329
+ export const $PlatformMatchResultDto = {
7330
+ type: 'object',
7331
+ properties: {
7332
+ id: {
7333
+ type: 'string',
7334
+ description: 'Global platform ID'
7335
+ },
7336
+ name: {
7337
+ type: 'string',
7338
+ description: 'Platform name (e.g., "ICBC")'
7339
+ },
7340
+ canonical: {
7341
+ type: 'string',
7342
+ description: 'Canonical identifier in ACCOUNT_RE format (e.g., "icbc")'
7343
+ },
7344
+ type: {
7345
+ type: 'string',
7346
+ description: 'Platform type',
7347
+ enum: [
7348
+ 'BANK',
7349
+ 'BROKERAGE',
7350
+ 'CRYPTO_EXCHANGE',
7351
+ 'PAYMENT',
7352
+ 'INVESTMENT',
7353
+ 'INSURANCE',
7354
+ 'OTHER'
7355
+ ]
7356
+ },
7357
+ suggestedSegment: {
7358
+ type: 'string',
7359
+ description:
7360
+ 'Suggested path segment — canonical PascalCased per hyphen-part, hyphens preserved (e.g. "Apple-Pay")'
7361
+ },
7362
+ logoUrl: {
7363
+ type: 'string',
7364
+ description: 'Logo URL',
7365
+ nullable: true
7366
+ },
7367
+ countryCode: {
7368
+ type: 'string',
7369
+ description: 'ISO 3166-1 alpha-2 (UPPERCASE); null = global platform',
7370
+ example: 'CN',
7371
+ nullable: true
7372
+ },
7373
+ category: {
7374
+ type: 'string',
7375
+ description:
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 = {
6829
7428
  type: 'object',
6830
7429
  properties: {
6831
7430
  id: {
@@ -6840,6 +7439,11 @@ export const $PlatformMatchResultDto = {
6840
7439
  type: 'string',
6841
7440
  description: 'Canonical identifier in ACCOUNT_RE format (e.g., "icbc")'
6842
7441
  },
7442
+ suggestedSegment: {
7443
+ type: 'string',
7444
+ description:
7445
+ 'Suggested path segment — canonical PascalCased per hyphen-part, hyphens preserved (e.g. "Apple-Pay")'
7446
+ },
6843
7447
  type: {
6844
7448
  type: 'string',
6845
7449
  description: 'Platform type',
@@ -6853,59 +7457,44 @@ export const $PlatformMatchResultDto = {
6853
7457
  'OTHER'
6854
7458
  ]
6855
7459
  },
6856
- suggestedSegment: {
7460
+ category: {
6857
7461
  type: 'string',
6858
7462
  description:
6859
- 'Suggested path segment — canonical, already in ACCOUNT_RE format'
6860
- },
6861
- logoUrl: {
6862
- type: 'string',
6863
- description: 'Logo URL',
6864
- nullable: true
6865
- },
6866
- matchType: {
6867
- type: 'string',
6868
- description: "How this row matched: 'exact' > 'prefix' > 'substring'",
6869
- enum: ['exact', 'prefix', 'substring']
7463
+ 'Region-aware category (institution vocab, e.g. DigitalWallet/Bank) resolved against the final region. null = no region-aware suggestion; fall back to type.',
7464
+ nullable: true,
7465
+ example: 'Bank'
6870
7466
  }
6871
7467
  },
6872
- required: [
6873
- 'id',
6874
- 'name',
6875
- 'canonical',
6876
- 'type',
6877
- 'suggestedSegment',
6878
- 'logoUrl',
6879
- 'matchType'
6880
- ]
7468
+ required: ['id', 'name', 'canonical', 'suggestedSegment', 'type', 'category']
6881
7469
  } as const;
6882
7470
 
6883
- export const $PlatformMatchResponseDto = {
7471
+ export const $PlatformStandardsResponseDto = {
6884
7472
  type: 'object',
6885
7473
  properties: {
6886
- platforms: {
6887
- description: 'Ranked matches, best tier first (at most 10 rows)',
6888
- type: 'array',
6889
- items: {
6890
- $ref: '#/components/schemas/PlatformMatchResultDto'
6891
- }
7474
+ platform: {
7475
+ description: 'The selected platform (institution lock source)',
7476
+ allOf: [
7477
+ {
7478
+ $ref: '#/components/schemas/PlatformStandardsPlatformDto'
7479
+ }
7480
+ ]
6892
7481
  },
6893
- matchType: {
7482
+ region: {
6894
7483
  type: 'string',
6895
7484
  description:
6896
- "Overall match quality — top row's tier, or 'none' when no hits",
6897
- enum: ['none', 'exact', 'prefix', 'substring']
6898
- },
6899
- total: {
6900
- type: 'number',
6901
- 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'
6902
7487
  },
6903
- hasMore: {
6904
- type: 'boolean',
6905
- 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
+ }
6906
7495
  }
6907
7496
  },
6908
- required: ['platforms', 'matchType', 'total', 'hasMore']
7497
+ required: ['platform', 'region', 'templates']
6909
7498
  } as const;
6910
7499
 
6911
7500
  export const $CreatePlatformDto = {
@@ -7009,7 +7598,8 @@ export const $UpdatePlatformDto = {
7009
7598
  },
7010
7599
  isActive: {
7011
7600
  type: 'boolean',
7012
- description: 'Whether the platform is active'
7601
+ description: 'Whether the platform is active',
7602
+ default: true
7013
7603
  }
7014
7604
  }
7015
7605
  } as const;
@@ -7208,7 +7798,8 @@ export const $PlatformGroupDto = {
7208
7798
  example: 'CMB Bank'
7209
7799
  },
7210
7800
  accounts: {
7211
- description: 'Accounts within this platform',
7801
+ description:
7802
+ 'Accounts within this platform (Assets and Liabilities rows, #696)',
7212
7803
  type: 'array',
7213
7804
  items: {
7214
7805
  $ref: '#/components/schemas/AccountItemDto'
@@ -7216,7 +7807,8 @@ export const $PlatformGroupDto = {
7216
7807
  },
7217
7808
  totalBalance: {
7218
7809
  type: 'string',
7219
- 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)',
7220
7812
  example: '100000.00'
7221
7813
  },
7222
7814
  balanceByCurrency: {
@@ -7235,7 +7827,7 @@ export const $PlatformGroupDto = {
7235
7827
  sharePct: {
7236
7828
  type: 'number',
7237
7829
  description:
7238
- '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)',
7239
7831
  example: 42.5
7240
7832
  }
7241
7833
  },
@@ -7283,7 +7875,8 @@ export const $AccountsSummaryDto = {
7283
7875
  properties: {
7284
7876
  totalAccounts: {
7285
7877
  type: 'number',
7286
- description: 'Total number of accounts'
7878
+ description:
7879
+ 'Total number of accounts (balance sheet: Assets + Liabilities, #696)'
7287
7880
  },
7288
7881
  totalPlatforms: {
7289
7882
  type: 'number',
@@ -7827,7 +8420,7 @@ export const $MonetaryDto = {
7827
8420
  example: 'USD'
7828
8421
  },
7829
8422
  baseCcyEquivalent: {
7830
- type: 'object',
8423
+ type: 'string',
7831
8424
  description: 'Converted to user base currency (Decimal string)',
7832
8425
  example: '21600',
7833
8426
  nullable: true
@@ -7903,13 +8496,13 @@ export const $HoldingPnlRowDto = {
7903
8496
  example: 'Assets:US:Broker:AAPL'
7904
8497
  },
7905
8498
  accountCcy: {
7906
- type: 'object',
8499
+ type: 'string',
7907
8500
  description: 'Account settlement currency (ISO 4217), from cost currency',
7908
8501
  nullable: true,
7909
8502
  example: 'USD'
7910
8503
  },
7911
8504
  brokerType: {
7912
- type: 'object',
8505
+ type: 'string',
7913
8506
  description: 'Broker type derived from Platform.type',
7914
8507
  nullable: true,
7915
8508
  example: 'broker'
@@ -7930,7 +8523,7 @@ export const $HoldingPnlRowDto = {
7930
8523
  example: 'EQUITY'
7931
8524
  },
7932
8525
  assetSubClass: {
7933
- type: 'object',
8526
+ type: 'string',
7934
8527
  nullable: true,
7935
8528
  example: 'STOCK'
7936
8529
  },
@@ -7977,14 +8570,14 @@ export const $HoldingPnlRowDto = {
7977
8570
  ]
7978
8571
  },
7979
8572
  unrealizedPnlBase: {
7980
- type: 'object',
8573
+ type: 'string',
7981
8574
  description:
7982
8575
  'Unrealized P&L in base currency (Decimal string); null when any FX/price missing',
7983
8576
  nullable: true,
7984
8577
  example: '6000'
7985
8578
  },
7986
8579
  unrealizedPnlPct: {
7987
- type: 'object',
8580
+ type: 'string',
7988
8581
  description: 'Unrealized P&L % (Decimal string)',
7989
8582
  nullable: true,
7990
8583
  example: '25'
@@ -8008,7 +8601,7 @@ export const $HoldingPnlRowDto = {
8008
8601
  ]
8009
8602
  },
8010
8603
  pctOfInvestedAssets: {
8011
- type: 'object',
8604
+ type: 'string',
8012
8605
  description:
8013
8606
  'Share of invested assets % (Decimal string); only for invested chartTokens',
8014
8607
  nullable: true,
@@ -8053,15 +8646,15 @@ export const $HoldingPnlWarningDto = {
8053
8646
  ]
8054
8647
  },
8055
8648
  symbol: {
8056
- type: 'object',
8649
+ type: 'string',
8057
8650
  nullable: true
8058
8651
  },
8059
8652
  accountId: {
8060
- type: 'object',
8653
+ type: 'string',
8061
8654
  nullable: true
8062
8655
  },
8063
8656
  currency: {
8064
- type: 'object',
8657
+ type: 'string',
8065
8658
  nullable: true
8066
8659
  }
8067
8660
  },
@@ -8125,6 +8718,216 @@ export const $AnonymousLoginResponseDto = {
8125
8718
  required: ['authToken']
8126
8719
  } as const;
8127
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
+
8128
8931
  export const $SymbolSearchResultDto = {
8129
8932
  type: 'object',
8130
8933
  properties: {
@@ -8133,35 +8936,35 @@ export const $SymbolSearchResultDto = {
8133
8936
  example: 'AAPL'
8134
8937
  },
8135
8938
  name: {
8136
- type: 'object',
8939
+ type: 'string',
8137
8940
  example: 'Apple Inc.',
8138
8941
  nullable: true
8139
8942
  },
8140
8943
  exchange: {
8141
- type: 'object',
8944
+ type: 'string',
8142
8945
  example: 'US',
8143
8946
  nullable: true
8144
8947
  },
8145
8948
  assetType: {
8146
- type: 'object',
8949
+ type: 'string',
8147
8950
  description: 'OpenBB asset_type (e.g. stock, etf)',
8148
8951
  example: 'stock',
8149
8952
  nullable: true
8150
8953
  },
8151
8954
  assetClass: {
8152
- type: 'object',
8955
+ type: 'string',
8153
8956
  description: 'IGN asset class (region.types.ts ASSET_CLASSES)',
8154
8957
  example: 'EQUITY',
8155
8958
  nullable: true
8156
8959
  },
8157
8960
  assetSubClass: {
8158
- type: 'object',
8961
+ type: 'string',
8159
8962
  description: 'IGN asset sub-class (region.types.ts ASSET_SUB_CLASSES)',
8160
8963
  example: 'STOCK',
8161
8964
  nullable: true
8162
8965
  },
8163
8966
  currency: {
8164
- type: 'object',
8967
+ type: 'string',
8165
8968
  description: 'Trading currency (extra_data or inferred from exchange)',
8166
8969
  example: 'USD',
8167
8970
  nullable: true
@@ -8178,90 +8981,90 @@ export const $SymbolQuoteDto = {
8178
8981
  example: 'AAPL'
8179
8982
  },
8180
8983
  name: {
8181
- type: 'object',
8984
+ type: 'string',
8182
8985
  example: 'Apple Inc.',
8183
8986
  nullable: true
8184
8987
  },
8185
8988
  exchange: {
8186
- type: 'object',
8989
+ type: 'string',
8187
8990
  example: 'US',
8188
8991
  nullable: true
8189
8992
  },
8190
8993
  assetType: {
8191
- type: 'object',
8994
+ type: 'string',
8192
8995
  description: 'OpenBB asset_type',
8193
8996
  example: 'stock',
8194
8997
  nullable: true
8195
8998
  },
8196
8999
  assetClass: {
8197
- type: 'object',
9000
+ type: 'string',
8198
9001
  description: 'IGN asset class',
8199
9002
  example: 'EQUITY',
8200
9003
  nullable: true
8201
9004
  },
8202
9005
  assetSubClass: {
8203
- type: 'object',
9006
+ type: 'string',
8204
9007
  description: 'IGN asset sub-class',
8205
9008
  example: 'STOCK',
8206
9009
  nullable: true
8207
9010
  },
8208
9011
  currency: {
8209
- type: 'object',
9012
+ type: 'string',
8210
9013
  description: 'Trading currency (extra_data or inferred from exchange)',
8211
9014
  example: 'USD',
8212
9015
  nullable: true
8213
9016
  },
8214
9017
  price: {
8215
- type: 'object',
9018
+ type: 'string',
8216
9019
  description: 'Latest price (Decimal string)',
8217
9020
  example: '189.84',
8218
9021
  nullable: true
8219
9022
  },
8220
9023
  priceDate: {
8221
- type: 'object',
9024
+ type: 'string',
8222
9025
  description: 'Date the price was observed (ISO yyyy-MM-dd)',
8223
9026
  example: '2026-08-05',
8224
9027
  nullable: true
8225
9028
  },
8226
9029
  changePercent: {
8227
- type: 'object',
9030
+ type: 'number',
8228
9031
  description:
8229
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.',
8230
9033
  example: 1.7,
8231
9034
  nullable: true
8232
9035
  },
8233
9036
  prevClose: {
8234
- type: 'object',
9037
+ type: 'string',
8235
9038
  description: 'Previous close (Decimal string)',
8236
9039
  nullable: true
8237
9040
  },
8238
9041
  open: {
8239
- type: 'object',
9042
+ type: 'string',
8240
9043
  description: 'Day open (Decimal string)',
8241
9044
  nullable: true
8242
9045
  },
8243
9046
  high: {
8244
- type: 'object',
9047
+ type: 'string',
8245
9048
  description: 'Day high (Decimal string)',
8246
9049
  nullable: true
8247
9050
  },
8248
9051
  low: {
8249
- type: 'object',
9052
+ type: 'string',
8250
9053
  description: 'Day low (Decimal string)',
8251
9054
  nullable: true
8252
9055
  },
8253
9056
  volume: {
8254
- type: 'object',
9057
+ type: 'string',
8255
9058
  description: 'Day volume (Decimal string)',
8256
9059
  nullable: true
8257
9060
  },
8258
9061
  yearHigh: {
8259
- type: 'object',
9062
+ type: 'string',
8260
9063
  description: '52-week high (Decimal string)',
8261
9064
  nullable: true
8262
9065
  },
8263
9066
  yearLow: {
8264
- type: 'object',
9067
+ type: 'string',
8265
9068
  description: '52-week low (Decimal string)',
8266
9069
  nullable: true
8267
9070
  }