@firela/api-types 0.0.0-canary.84b23d91 → 0.0.0-canary.89313ec3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -51,6 +51,14 @@ export const $CreateAccountDto = {
51
51
  description: 'Icon identifier (overrides template)',
52
52
  example: 'bank-custom'
53
53
  },
54
+ displayName: {
55
+ type: 'string',
56
+ description:
57
+ 'User-set display name override (omit/null = keep the derived name)',
58
+ nullable: true,
59
+ maxLength: 50,
60
+ example: 'Salary card'
61
+ },
54
62
  openDirectiveMeta: {
55
63
  type: 'object',
56
64
  description:
@@ -124,6 +132,8 @@ export const $AccountResponseDto = {
124
132
  'STUDENT_LOAN',
125
133
  'CREDIT_CARD',
126
134
  'PERSONAL_LOAN',
135
+ 'ACCOUNTS_PAYABLE',
136
+ 'TAX_PAYABLE',
127
137
  'OTHER'
128
138
  ],
129
139
  nullable: true,
@@ -179,7 +189,8 @@ export const $AccountResponseDto = {
179
189
  },
180
190
  displayName: {
181
191
  type: 'string',
182
- description: 'Localized display name (ADR-0114, read-time projection)',
192
+ description:
193
+ 'Display name with precedence: user-set name (#762) > ADR-0114 localized name > path leaf (read-time projection)',
183
194
  example: 'Checking'
184
195
  },
185
196
  icon: {
@@ -195,7 +206,7 @@ export const $AccountResponseDto = {
195
206
  }
196
207
  },
197
208
  platformId: {
198
- type: 'object',
209
+ type: 'string',
199
210
  description: 'Platform ID (null if unbound)',
200
211
  example: 'c98e5d4a-2f71-4a5a-bb3c-92c9f231d5e2'
201
212
  },
@@ -375,16 +386,43 @@ export const $AccountStandardResponseDto = {
375
386
  },
376
387
  name: {
377
388
  type: 'string',
378
- description: 'Short localized display name',
389
+ description:
390
+ 'Short display name. Universal rows project to the request locale (Accept-Language); regional rows keep the authored native name — mixed-language by design (ADR-0131 class P vs class A).',
379
391
  example: 'Housing Fund'
380
392
  },
393
+ aliases: {
394
+ description:
395
+ 'Authored market-language alternative names delivered verbatim (not localized copy, not xlf-managed, not locale-projected). Flat string[] per ADR-0129 D1; ADR-0131 class A.',
396
+ example: ['Alipay', 'WeChat Pay'],
397
+ type: 'array',
398
+ items: {
399
+ type: 'string'
400
+ }
401
+ },
402
+ searchTerms: {
403
+ description:
404
+ 'Locale-projected search synonyms (e.g. the zh bank-card / debit-card everyday terms for the checking account). Pure-locale projection — absent when the locale has no seeded synonyms; English fallback rides the authored aliases field. Search-only vocabulary, not the NLP routing corpus (#698, ADR-0131 fourth-class adjudication).',
405
+ example: ['yinhangka', 'jiejika'],
406
+ type: 'array',
407
+ items: {
408
+ type: 'string'
409
+ }
410
+ },
411
+ currency: {
412
+ type: 'string',
413
+ description:
414
+ 'Product denomination as a 3-letter ISO 4217 code, authored market data delivered verbatim (not localized, not xlf-managed). ADR-0131 class A. Absent = single-currency not asserted — consumers fall back to their own region currency (#714).',
415
+ example: 'HKD'
416
+ },
381
417
  description: {
382
418
  type: 'string',
383
- description: 'Account description (stable semantics only)',
419
+ description:
420
+ 'Account description (stable semantics only). Mixed-language contract: universal rows project to the request locale via the accountDesc xlf axis with an en fallback (ADR-0131 class P, ADR-0132; unseeded locales falling back to English are expected); regional rows deliver the authored market language (ADR-0131 class A, verbatim, never xlf-managed).',
384
421
  example: 'ICBC checking account for daily transactions'
385
422
  },
386
423
  tags: {
387
- description: 'Account tags for categorization',
424
+ description:
425
+ 'Account tags for categorization — structured metadata delivered verbatim (not localized, not xlf-managed). ADR-0131 class A.',
388
426
  example: ['bank', 'checking', 'primary'],
389
427
  type: 'array',
390
428
  items: {
@@ -395,9 +433,47 @@ export const $AccountStandardResponseDto = {
395
433
  type: 'string',
396
434
  description: 'Icon identifier for UI display',
397
435
  example: 'bank-icbc'
436
+ },
437
+ productCategory: {
438
+ type: 'string',
439
+ description:
440
+ 'Onboarding product category (coarse grouping derived from assetSubClass)',
441
+ enum: [
442
+ 'cash',
443
+ 'investment',
444
+ 'credit_card',
445
+ 'loan',
446
+ 'payable_tax',
447
+ 'other'
448
+ ],
449
+ example: 'investment'
450
+ },
451
+ assetClass: {
452
+ type: 'string',
453
+ description:
454
+ 'Asset class (LIQUIDITY/EQUITY/.../LIABILITY), derived at read time from classification rules',
455
+ enum: [
456
+ 'LIQUIDITY',
457
+ 'EQUITY',
458
+ 'FIXED_INCOME',
459
+ 'PRECIOUS_METALS',
460
+ 'COMMODITY',
461
+ 'INSURANCE',
462
+ 'ALTERNATIVE_INVESTMENT',
463
+ 'PERSONAL_ASSETS',
464
+ 'LIABILITY',
465
+ 'REAL_ESTATE',
466
+ 'INDEX'
467
+ ]
468
+ },
469
+ assetSubClass: {
470
+ type: 'string',
471
+ description:
472
+ 'Asset sub-class (product type, derived at read time from classification rules)',
473
+ example: 'STOCK'
398
474
  }
399
475
  },
400
- required: ['path', 'type', 'description', 'tags', 'icon']
476
+ required: ['path', 'type', 'description', 'tags', 'icon', 'productCategory']
401
477
  } as const;
402
478
 
403
479
  export const $AccountStandardListResponseDto = {
@@ -458,7 +534,10 @@ export const $RegionConfigDto = {
458
534
  },
459
535
  locale: {
460
536
  type: 'string',
461
- example: 'de-DE'
537
+ example: 'de-DE',
538
+ pattern: '^[a-z]{2,8}-[A-Z]{2}$',
539
+ description:
540
+ "Region-qualified BCP-47 tag whose region subtag equals the region's own ISO 3166-1 code (e.g., ja-JP, zh-CN, zh-HK)"
462
541
  }
463
542
  },
464
543
  required: ['currency', 'dateFormat', 'locale']
@@ -471,6 +550,12 @@ export const $RegionInfoDto = {
471
550
  type: 'string',
472
551
  example: 'de'
473
552
  },
553
+ open: {
554
+ type: 'boolean',
555
+ example: true,
556
+ description:
557
+ 'Whether the region is open (has a ready regional account template). Not-yet-open regions still return identity metadata and degrade to the universal-only catalog.'
558
+ },
474
559
  displayName: {
475
560
  type: 'string',
476
561
  example: 'Germany'
@@ -489,7 +574,7 @@ export const $RegionInfoDto = {
489
574
  $ref: '#/components/schemas/RegionConfigDto'
490
575
  }
491
576
  },
492
- required: ['code', 'displayName', 'chain', 'config']
577
+ required: ['code', 'open', 'displayName', 'chain', 'config']
493
578
  } as const;
494
579
 
495
580
  export const $RegionsMetadataResponseDto = {
@@ -736,7 +821,7 @@ export const $PostingResponseDto = {
736
821
  units: {
737
822
  type: 'string',
738
823
  description:
739
- 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned.',
824
+ 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned. Carries the raw Beancount sign (credit-normal accounts such as Income post negative — the accounting truth, ADR-0126); renderers must not infer economic semantics from this sign.',
740
825
  example: '100.50'
741
826
  },
742
827
  currency: {
@@ -1102,7 +1187,7 @@ export const $PostingDetailDto = {
1102
1187
  units: {
1103
1188
  type: 'string',
1104
1189
  description:
1105
- 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned.',
1190
+ 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned. Carries the raw Beancount sign (credit-normal accounts such as Income post negative — the accounting truth, ADR-0126); renderers must not infer economic semantics from this sign.',
1106
1191
  example: '100.50'
1107
1192
  },
1108
1193
  currency: {
@@ -1286,6 +1371,147 @@ export const $TransactionDetailDto = {
1286
1371
  ]
1287
1372
  } as const;
1288
1373
 
1374
+ export const $TransactionListItemDto = {
1375
+ type: 'object',
1376
+ properties: {
1377
+ id: {
1378
+ type: 'string',
1379
+ description: 'Transaction ID',
1380
+ example: 'clh1234567890abcdef'
1381
+ },
1382
+ date: {
1383
+ type: 'string',
1384
+ description: 'Transaction date',
1385
+ example: '2024-11-28'
1386
+ },
1387
+ flag: {
1388
+ type: 'string',
1389
+ description: 'Transaction flag',
1390
+ enum: [
1391
+ 'CLEARED',
1392
+ 'PENDING',
1393
+ 'PADDING',
1394
+ 'SUMMARIZE',
1395
+ 'TRANSFER',
1396
+ 'CONVERSIONS'
1397
+ ],
1398
+ example: 'CLEARED'
1399
+ },
1400
+ customFlag: {
1401
+ type: 'string',
1402
+ description: 'Custom flag (if not using standard flags)',
1403
+ example: 'R'
1404
+ },
1405
+ payee: {
1406
+ type: 'string',
1407
+ description: 'Payee name',
1408
+ example: 'Whole Foods Market'
1409
+ },
1410
+ narration: {
1411
+ type: 'string',
1412
+ description: 'Transaction narration',
1413
+ example: 'Grocery shopping'
1414
+ },
1415
+ tags: {
1416
+ description: 'Transaction tags',
1417
+ example: ['groceries'],
1418
+ type: 'array',
1419
+ items: {
1420
+ type: 'string'
1421
+ }
1422
+ },
1423
+ links: {
1424
+ description: 'Transaction links',
1425
+ example: ['invoice-2024-001'],
1426
+ type: 'array',
1427
+ items: {
1428
+ type: 'string'
1429
+ }
1430
+ },
1431
+ meta: {
1432
+ type: 'object',
1433
+ description: 'Transaction metadata'
1434
+ },
1435
+ status: {
1436
+ type: 'string',
1437
+ description: 'Transaction status',
1438
+ enum: ['ACTIVE', 'VOIDED', 'SUPERSEDED'],
1439
+ example: 'ACTIVE'
1440
+ },
1441
+ sourceType: {
1442
+ type: 'string',
1443
+ description:
1444
+ 'Source type (free-form string from transaction metadata, e.g. import, api)'
1445
+ },
1446
+ sourcePlatform: {
1447
+ type: 'string',
1448
+ description: 'Source platform (e.g., alipay, wechat)',
1449
+ example: 'alipay'
1450
+ },
1451
+ postings: {
1452
+ description: 'Transaction postings',
1453
+ type: 'array',
1454
+ items: {
1455
+ $ref: '#/components/schemas/PostingDetailDto'
1456
+ }
1457
+ },
1458
+ createdAt: {
1459
+ type: 'string',
1460
+ description: 'Created at timestamp',
1461
+ example: '2024-11-28T10:30:00.000Z'
1462
+ },
1463
+ voidedAt: {
1464
+ type: 'string',
1465
+ description: 'Voided at timestamp (if voided)',
1466
+ example: '2024-11-29T15:00:00.000Z'
1467
+ },
1468
+ voidedBy: {
1469
+ type: 'string',
1470
+ description: 'User ID who voided this transaction',
1471
+ example: 'clh1234567890abcdef'
1472
+ },
1473
+ correctionReason: {
1474
+ type: 'string',
1475
+ description: 'Correction reason (if voided or superseded)',
1476
+ example: 'Duplicate entry'
1477
+ },
1478
+ supersededBy: {
1479
+ type: 'string',
1480
+ description:
1481
+ 'ID of the transaction that supersedes this one (set when status=SUPERSEDED)',
1482
+ example: 'clh1234567890abcdef'
1483
+ },
1484
+ originalTxn: {
1485
+ type: 'string',
1486
+ description:
1487
+ 'ID of the transaction this one corrected/replaced (back-link on the replacement)',
1488
+ example: 'clh1234567890abcdef'
1489
+ },
1490
+ viewpointAmount: {
1491
+ type: 'string',
1492
+ description:
1493
+ 'Row amount under the request viewpoint (ADR-0126). Category viewpoint (category + flow): per-leg sign-normalized sum over the category account set (Income-root legs negated, Expenses-root identity) — positive under normal booking but NOT clamped (explicit negative expense legs and net-flip refund months stay negative). No viewpoint (plain list / search, no accountId): wallet money-flow net = raw-sign sum over cost-less Assets/Liabilities legs (income positive, expenses negative, transfers net ~0); color cue is the wallet sign (net < 0 = wealth-decreasing). Status-orthogonal: audit views match too (ADR-0128 amount-as-matching-key). Omitted under the account viewpoint (incl. dual) and for rows with no wallet leg.',
1494
+ example: '10000.00'
1495
+ },
1496
+ viewpointCurrency: {
1497
+ type: 'string',
1498
+ description:
1499
+ 'Currency of viewpointAmount. A row spanning multiple currencies takes the largest-magnitude currency group (known simplification, ADR-0126).',
1500
+ example: 'CNY'
1501
+ }
1502
+ },
1503
+ required: [
1504
+ 'id',
1505
+ 'date',
1506
+ 'narration',
1507
+ 'tags',
1508
+ 'links',
1509
+ 'status',
1510
+ 'postings',
1511
+ 'createdAt'
1512
+ ]
1513
+ } as const;
1514
+
1289
1515
  export const $BalanceByCurrencyDto = {
1290
1516
  type: 'object',
1291
1517
  properties: {
@@ -1331,7 +1557,7 @@ export const $TransactionListSummaryDto = {
1331
1557
  totalAmount: {
1332
1558
  type: 'string',
1333
1559
  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.',
1560
+ 'Partial converted total in base currency (rated currencies only). Sign by viewpoint (ADR-0126): account viewpoint keeps the raw Beancount sign (income negative); category viewpoint is per-leg sign-normalized (Income legs negated, Expenses legs identity — positive under normal booking, not clamped). When warnings is non-empty this excludes currencies missing an FX rate; may be "0.00" if ALL non-base currencies lack a rate. Converted at the dateTo (or current) available rate.',
1335
1561
  example: '-6000.00'
1336
1562
  },
1337
1563
  currency: {
@@ -1357,6 +1583,26 @@ export const $TransactionListSummaryDto = {
1357
1583
  required: ['totalAmount', 'currency', 'balanceByCurrency']
1358
1584
  } as const;
1359
1585
 
1586
+ export const $TransactionListViewpointDto = {
1587
+ type: 'object',
1588
+ properties: {
1589
+ type: {
1590
+ type: 'string',
1591
+ description:
1592
+ 'Viewpoint type (only category drill-down carries a viewpoint today)',
1593
+ enum: ['category'],
1594
+ example: 'category'
1595
+ },
1596
+ flow: {
1597
+ type: 'string',
1598
+ description: 'Flow root the category account set is restricted to',
1599
+ enum: ['income', 'expense'],
1600
+ example: 'expense'
1601
+ }
1602
+ },
1603
+ required: ['type', 'flow']
1604
+ } as const;
1605
+
1360
1606
  export const $TransactionListResponseDto = {
1361
1607
  type: 'object',
1362
1608
  properties: {
@@ -1364,7 +1610,7 @@ export const $TransactionListResponseDto = {
1364
1610
  description: 'List of transactions',
1365
1611
  type: 'array',
1366
1612
  items: {
1367
- $ref: '#/components/schemas/TransactionDetailDto'
1613
+ $ref: '#/components/schemas/TransactionListItemDto'
1368
1614
  }
1369
1615
  },
1370
1616
  total: {
@@ -1390,6 +1636,15 @@ export const $TransactionListResponseDto = {
1390
1636
  $ref: '#/components/schemas/TransactionListSummaryDto'
1391
1637
  }
1392
1638
  ]
1639
+ },
1640
+ viewpoint: {
1641
+ description:
1642
+ 'Viewpoint metadata (ADR-0126). Present only for a single category filter (category + flow, no accountId); dual-perspective requests are viewpoint-less (raw signs, no viewpointAmount).',
1643
+ allOf: [
1644
+ {
1645
+ $ref: '#/components/schemas/TransactionListViewpointDto'
1646
+ }
1647
+ ]
1393
1648
  }
1394
1649
  },
1395
1650
  required: ['data', 'total', 'limit', 'offset']
@@ -2300,10 +2555,10 @@ export const $UpdatePayeeDto = {
2300
2555
  meta: {
2301
2556
  type: 'object',
2302
2557
  description:
2303
- 'Metadata for extended information (location, notes, contact info, etc.). Will merge with existing metadata.',
2558
+ 'Metadata for extended information (location, notes, contact info, etc.)',
2304
2559
  example: {
2305
2560
  location: 'Zhongguancun',
2306
- note: 'Updated note',
2561
+ note: 'Near subway station',
2307
2562
  favorite: true
2308
2563
  }
2309
2564
  },
@@ -2864,568 +3119,660 @@ export const $UpdateCommodityDto = {
2864
3119
  }
2865
3120
  } as const;
2866
3121
 
2867
- export const $CreateBeanPriceDto = {
3122
+ export const $CurrencyBalanceDto = {
2868
3123
  type: 'object',
2869
3124
  properties: {
2870
3125
  currency: {
2871
3126
  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)',
3127
+ description: 'ISO 4217 currency code',
2878
3128
  example: 'CNY'
2879
3129
  },
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: {
3130
+ balance: {
2888
3131
  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
- }
3132
+ description: 'Balance amount',
3133
+ example: '500000.00'
2901
3134
  }
2902
3135
  },
2903
- required: ['currency', 'quoteCurrency', 'amount', 'date']
3136
+ required: ['currency', 'balance']
2904
3137
  } as const;
2905
3138
 
2906
- export const $PriceResponseDto = {
3139
+ export const $TimeSeriesPointDto = {
2907
3140
  type: 'object',
2908
3141
  properties: {
2909
- id: {
3142
+ date: {
2910
3143
  type: 'string',
2911
- description: 'Unique identifier',
2912
- example: 'uuid-123-456'
3144
+ description: 'Date in YYYY-MM-DD format',
3145
+ example: '2024-06-15'
2913
3146
  },
2914
- userId: {
3147
+ value: {
2915
3148
  type: 'string',
2916
- description: 'User ID (owner of the price)',
2917
- example: 'user-123'
3149
+ description: 'Value at this date (in base currency)',
3150
+ example: '500000.00'
2918
3151
  },
2919
- currency: {
3152
+ change: {
2920
3153
  type: 'string',
2921
- description: 'Currency being priced (e.g., USD, AAPL, BTC)',
2922
- example: 'BTC'
3154
+ description: 'Change from previous point',
3155
+ example: '5000.00'
2923
3156
  },
2924
- quoteCurrency: {
3157
+ assets: {
2925
3158
  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
3159
+ description: 'Total assets at this date (in base currency)',
3160
+ example: '494338.00'
2934
3161
  },
2935
- date: {
3162
+ liabilities: {
2936
3163
  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'
3164
+ description: 'Total liabilities at this date (in base currency)',
3165
+ example: '310098.00'
2941
3166
  },
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
3167
+ byCurrency: {
3168
+ description: 'Multi-currency breakdown for this point',
3169
+ type: 'array',
3170
+ items: {
3171
+ $ref: '#/components/schemas/CurrencyBalanceDto'
2950
3172
  }
3173
+ }
3174
+ },
3175
+ required: ['date', 'value']
3176
+ } as const;
3177
+
3178
+ export const $TrendSummaryDto = {
3179
+ type: 'object',
3180
+ properties: {
3181
+ startValue: {
3182
+ type: 'string',
3183
+ description: 'Value at start of period',
3184
+ example: '450000.00'
2951
3185
  },
2952
- createdAt: {
2953
- format: 'date-time',
3186
+ endValue: {
2954
3187
  type: 'string',
2955
- description: 'Creation timestamp',
2956
- example: '2024-11-03T10:00:00Z'
3188
+ description: 'Value at end of period',
3189
+ example: '500000.00'
2957
3190
  },
2958
- updatedAt: {
2959
- format: 'date-time',
3191
+ totalChange: {
2960
3192
  type: 'string',
2961
- description: 'Last update timestamp',
2962
- example: '2024-11-03T10:00:00Z'
3193
+ description: 'Total change over period',
3194
+ example: '50000.00'
3195
+ },
3196
+ totalChangePercentage: {
3197
+ type: 'string',
3198
+ description: 'Total change percentage',
3199
+ example: '+11.11%'
2963
3200
  }
2964
3201
  },
2965
- required: [
2966
- 'id',
2967
- 'userId',
2968
- 'currency',
2969
- 'quoteCurrency',
2970
- 'amount',
2971
- 'date',
2972
- 'meta',
2973
- 'createdAt',
2974
- 'updatedAt'
2975
- ]
3202
+ required: ['startValue', 'endValue', 'totalChange', 'totalChangePercentage']
2976
3203
  } as const;
2977
3204
 
2978
- export const $PriceListResponseDto = {
3205
+ export const $MultiCurrencyPointDto = {
2979
3206
  type: 'object',
2980
3207
  properties: {
2981
- items: {
2982
- description: 'List of prices',
3208
+ date: {
3209
+ type: 'string',
3210
+ description: 'Date in YYYY-MM-DD format',
3211
+ example: '2024-06-15'
3212
+ },
3213
+ byCurrency: {
3214
+ description: 'Balances by currency',
2983
3215
  type: 'array',
2984
3216
  items: {
2985
- $ref: '#/components/schemas/PriceResponseDto'
3217
+ $ref: '#/components/schemas/CurrencyBalanceDto'
2986
3218
  }
2987
- },
2988
- total: {
2989
- type: 'number',
2990
- description: 'Total number of prices',
2991
- example: 42
2992
3219
  }
2993
3220
  },
2994
- required: ['items', 'total']
3221
+ required: ['date', 'byCurrency']
2995
3222
  } as const;
2996
3223
 
2997
- export const $UpdateBeanPriceDto = {
3224
+ export const $PortfolioTrendsResponseDto = {
2998
3225
  type: 'object',
2999
3226
  properties: {
3000
- currency: {
3001
- type: 'string',
3002
- description: 'Currency being priced'
3227
+ series: {
3228
+ description: 'Time series data points',
3229
+ type: 'array',
3230
+ items: {
3231
+ $ref: '#/components/schemas/TimeSeriesPointDto'
3232
+ }
3003
3233
  },
3004
- quoteCurrency: {
3234
+ summary: {
3235
+ description: 'Period summary',
3236
+ allOf: [
3237
+ {
3238
+ $ref: '#/components/schemas/TrendSummaryDto'
3239
+ }
3240
+ ]
3241
+ },
3242
+ period: {
3005
3243
  type: 'string',
3006
- description: 'Quote currency (pricing currency)'
3244
+ description: 'Period requested',
3245
+ example: '6m'
3007
3246
  },
3008
- amount: {
3009
- type: 'number',
3010
- description: 'Price amount (MUST be >= 0 per Beancount spec)',
3011
- minimum: 0
3247
+ granularity: {
3248
+ type: 'string',
3249
+ description: 'Data granularity',
3250
+ example: 'month'
3012
3251
  },
3013
- date: {
3252
+ currency: {
3014
3253
  type: 'string',
3015
- description: 'Price date (ISO 8601 format)'
3254
+ description: 'Base currency for converted values',
3255
+ example: 'CNY'
3016
3256
  },
3017
- metadata: {
3018
- type: 'object',
3019
- description: 'Metadata'
3257
+ byCurrency: {
3258
+ description:
3259
+ 'Multi-currency time series (each point has currency breakdown)',
3260
+ type: 'array',
3261
+ items: {
3262
+ $ref: '#/components/schemas/MultiCurrencyPointDto'
3263
+ }
3264
+ },
3265
+ warnings: {
3266
+ description: 'Exchange rate warnings',
3267
+ type: 'array',
3268
+ items: {
3269
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
3270
+ }
3020
3271
  }
3021
- }
3272
+ },
3273
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
3022
3274
  } as const;
3023
3275
 
3024
- export const $CreateRecurringRuleDto = {
3276
+ export const $CashFlowPointDto = {
3025
3277
  type: 'object',
3026
3278
  properties: {
3027
- name: {
3279
+ month: {
3028
3280
  type: 'string',
3029
- description: 'Rule name (unique per user)',
3030
- maxLength: 100
3281
+ description: 'Month key (YYYY-MM)',
3282
+ example: '2024-03'
3031
3283
  },
3032
- icon: {
3284
+ income: {
3033
3285
  type: 'string',
3034
- description: 'Icon emoji',
3035
- maxLength: 10
3286
+ description: 'Income in base currency (absolute, converted)',
3287
+ example: '10000.00'
3036
3288
  },
3037
- frequency: {
3289
+ expense: {
3038
3290
  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
3291
+ description: 'Expense in base currency (absolute, converted)',
3292
+ example: '5000.00'
3065
3293
  },
3066
- currency: {
3294
+ netSavings: {
3067
3295
  type: 'string',
3068
- description: 'Currency code',
3069
- default: 'CNY',
3070
- maxLength: 10
3071
- },
3072
- matchPayeePattern: {
3296
+ description: 'netSavings = income − expense (savings positive)',
3297
+ example: '5000.00'
3298
+ }
3299
+ },
3300
+ required: ['month', 'income', 'expense', 'netSavings']
3301
+ } as const;
3302
+
3303
+ export const $CashFlowTrendSummaryDto = {
3304
+ type: 'object',
3305
+ properties: {
3306
+ totalIncome: {
3073
3307
  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
3308
+ description: 'Total income across the period',
3309
+ example: '60000.00'
3083
3310
  },
3084
- defaultExpenseAccount: {
3311
+ totalExpense: {
3085
3312
  type: 'string',
3086
- description: 'Default expense account for auto-create',
3087
- maxLength: 200
3313
+ description: 'Total expense across the period',
3314
+ example: '30000.00'
3088
3315
  },
3089
- defaultPaymentAccount: {
3316
+ totalNetSavings: {
3090
3317
  type: 'string',
3091
- description: 'Default payment account for auto-create',
3092
- maxLength: 200
3318
+ description: 'income − expense across the period',
3319
+ example: '30000.00'
3093
3320
  },
3094
- defaultPayee: {
3321
+ averageMonthlyNetSavings: {
3095
3322
  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)'
3323
+ description:
3324
+ 'totalNetSavings divided by the window length (N months, incl. zero-filled)',
3325
+ example: '5000.00'
3111
3326
  }
3112
3327
  },
3113
3328
  required: [
3114
- 'name',
3115
- 'frequency',
3116
- 'expectedAmount',
3117
- 'currency',
3118
- 'matchAmountTolerance',
3119
- 'autoCreate'
3329
+ 'totalIncome',
3330
+ 'totalExpense',
3331
+ 'totalNetSavings',
3332
+ 'averageMonthlyNetSavings'
3120
3333
  ]
3121
3334
  } as const;
3122
3335
 
3123
- export const $RecurringRuleResponseDto = {
3336
+ export const $CashFlowTrendsResponseDto = {
3124
3337
  type: 'object',
3125
3338
  properties: {
3126
- id: {
3127
- type: 'string',
3128
- description: 'Rule ID'
3339
+ series: {
3340
+ description:
3341
+ 'Monthly cash-flow series (fixed N-month window, zero-filled)',
3342
+ type: 'array',
3343
+ items: {
3344
+ $ref: '#/components/schemas/CashFlowPointDto'
3345
+ }
3129
3346
  },
3130
- userId: {
3131
- type: 'string',
3132
- description: 'User ID'
3347
+ summary: {
3348
+ description: 'Period totals',
3349
+ allOf: [
3350
+ {
3351
+ $ref: '#/components/schemas/CashFlowTrendSummaryDto'
3352
+ }
3353
+ ]
3133
3354
  },
3134
- name: {
3355
+ period: {
3135
3356
  type: 'string',
3136
- description: 'Rule name'
3137
- },
3138
- icon: {
3139
- type: 'object',
3140
- description: 'Icon emoji'
3357
+ description: 'Period requested',
3358
+ example: '6m'
3141
3359
  },
3142
- frequency: {
3360
+ granularity: {
3143
3361
  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'
3362
+ description: 'Data granularity (v1 returns month buckets)',
3363
+ example: 'month'
3153
3364
  },
3154
- customIntervalDays: {
3155
- type: 'object',
3156
- description: 'Custom interval in days'
3365
+ currency: {
3366
+ type: 'string',
3367
+ description: 'Base currency for converted values',
3368
+ example: 'CNY'
3157
3369
  },
3370
+ warnings: {
3371
+ description: 'Exchange rate warnings (e.g. missing rate for a currency)',
3372
+ type: 'array',
3373
+ items: {
3374
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
3375
+ }
3376
+ }
3377
+ },
3378
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
3379
+ } as const;
3380
+
3381
+ export const $GenerateSnapshotBody = {
3382
+ type: 'object',
3383
+ properties: {}
3384
+ } as const;
3385
+
3386
+ export const $GenerateSnapshotResponse = {
3387
+ type: 'object',
3388
+ properties: {}
3389
+ } as const;
3390
+
3391
+ export const $BackfillSnapshotsBody = {
3392
+ type: 'object',
3393
+ properties: {}
3394
+ } as const;
3395
+
3396
+ export const $BackfillSnapshotsResponse = {
3397
+ type: 'object',
3398
+ properties: {}
3399
+ } as const;
3400
+
3401
+ export const $CreateBeanPriceDto = {
3402
+ type: 'object',
3403
+ properties: {
3158
3404
  currency: {
3159
3405
  type: 'string',
3160
- description: 'Currency code'
3406
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
3407
+ example: 'USD'
3161
3408
  },
3162
- matchPayeePattern: {
3163
- type: 'object',
3164
- description: 'Payee matching pattern'
3409
+ quoteCurrency: {
3410
+ type: 'string',
3411
+ description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
3412
+ example: 'CNY'
3165
3413
  },
3166
- matchAmountTolerance: {
3414
+ amount: {
3167
3415
  type: 'number',
3168
- description: 'Amount tolerance percentage'
3416
+ description:
3417
+ 'Price amount (MUST be >= 0 per Beancount spec, supports up to 15 decimal places). Zero allowed for conversion entries, negative strictly prohibited.',
3418
+ example: 175.5,
3419
+ minimum: 0
3169
3420
  },
3170
- defaultExpenseAccount: {
3171
- type: 'object',
3172
- description: 'Default expense account'
3421
+ date: {
3422
+ type: 'string',
3423
+ description: 'Price date (ISO 8601 format)',
3424
+ example: '2024-11-05'
3173
3425
  },
3174
- defaultPaymentAccount: {
3426
+ metadata: {
3175
3427
  type: 'object',
3176
- description: 'Default payment account'
3428
+ description:
3429
+ 'Metadata (validated by Zod schema, max field lengths enforced)',
3430
+ example: {
3431
+ source: 'MANUAL',
3432
+ note: 'Bank valuation report',
3433
+ confidence: 0.95
3434
+ }
3435
+ }
3436
+ },
3437
+ required: ['currency', 'quoteCurrency', 'amount', 'date']
3438
+ } as const;
3439
+
3440
+ export const $PriceResponseDto = {
3441
+ type: 'object',
3442
+ properties: {
3443
+ id: {
3444
+ type: 'string',
3445
+ description: 'Unique identifier',
3446
+ example: 'uuid-123-456'
3177
3447
  },
3178
- defaultPayee: {
3179
- type: 'object',
3180
- description: 'Default payee'
3448
+ userId: {
3449
+ type: 'string',
3450
+ description: 'User ID (owner of the price)',
3451
+ example: 'user-123'
3181
3452
  },
3182
- isActive: {
3183
- type: 'boolean',
3184
- description: 'Whether rule is active'
3453
+ currency: {
3454
+ type: 'string',
3455
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
3456
+ example: 'BTC'
3185
3457
  },
3186
- startDate: {
3458
+ quoteCurrency: {
3187
3459
  type: 'string',
3188
- description: 'Rule start date (YYYY-MM-DD)'
3460
+ description: 'Quote currency (pricing currency, e.g., USD, CNY)',
3461
+ example: 'USD'
3189
3462
  },
3190
- endDate: {
3191
- type: 'object',
3192
- description: 'Rule end date (YYYY-MM-DD)'
3463
+ amount: {
3464
+ type: 'number',
3465
+ description:
3466
+ 'Price amount (corresponds to Beancount Amount.number). Supports up to 15 decimal places.',
3467
+ example: 50000
3193
3468
  },
3194
- autoCreate: {
3195
- type: 'boolean',
3196
- description: 'Auto-create transaction on expected date'
3469
+ date: {
3470
+ type: 'string',
3471
+ description:
3472
+ 'Price date (ISO 8601 format). Represents the date this price was valid.',
3473
+ example: '2024-01-01',
3474
+ format: 'date'
3197
3475
  },
3198
- lastOccurrence: {
3476
+ meta: {
3199
3477
  type: 'object',
3200
- description: 'Last matched occurrence date (YYYY-MM-DD)'
3201
- },
3202
- totalCount: {
3203
- type: 'number',
3204
- description: 'Total matched transactions count'
3478
+ description:
3479
+ 'Metadata (corresponds to Beancount meta field). Contains source, confidence, note, etc.',
3480
+ example: {
3481
+ source: 'MANUAL',
3482
+ note: 'User-defined price',
3483
+ confidence: 1
3484
+ }
3205
3485
  },
3206
3486
  createdAt: {
3207
3487
  format: 'date-time',
3208
3488
  type: 'string',
3209
- description: 'Created at timestamp'
3489
+ description: 'Creation timestamp',
3490
+ example: '2024-11-03T10:00:00Z'
3210
3491
  },
3211
3492
  updatedAt: {
3212
3493
  format: 'date-time',
3213
3494
  type: 'string',
3214
- description: 'Updated at timestamp'
3495
+ description: 'Last update timestamp',
3496
+ example: '2024-11-03T10:00:00Z'
3215
3497
  }
3216
3498
  },
3217
3499
  required: [
3218
3500
  'id',
3219
3501
  'userId',
3220
- 'name',
3221
- 'frequency',
3222
- 'expectedAmount',
3223
3502
  'currency',
3224
- 'matchAmountTolerance',
3225
- 'isActive',
3226
- 'startDate',
3227
- 'autoCreate',
3228
- 'totalCount',
3503
+ 'quoteCurrency',
3504
+ 'amount',
3505
+ 'date',
3506
+ 'meta',
3229
3507
  'createdAt',
3230
3508
  'updatedAt'
3231
3509
  ]
3232
3510
  } as const;
3233
3511
 
3234
- export const $CreateRuleFromTransactionDto = {
3512
+ export const $PriceListResponseDto = {
3235
3513
  type: 'object',
3236
3514
  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
3515
+ items: {
3516
+ description: 'List of prices',
3517
+ type: 'array',
3518
+ items: {
3519
+ $ref: '#/components/schemas/PriceResponseDto'
3520
+ }
3255
3521
  },
3256
- icon: {
3257
- type: 'string',
3258
- description: 'Optional icon emoji',
3259
- maxLength: 10
3260
- }
3261
- },
3262
- required: ['frequency']
3522
+ total: {
3523
+ type: 'number',
3524
+ description: 'Total number of prices',
3525
+ example: 42
3526
+ }
3527
+ },
3528
+ required: ['items', 'total']
3263
3529
  } as const;
3264
3530
 
3265
- export const $RecurringRuleWithStatsResponseDto = {
3531
+ export const $UpdateBeanPriceDto = {
3266
3532
  type: 'object',
3267
3533
  properties: {
3268
- id: {
3534
+ currency: {
3269
3535
  type: 'string',
3270
- description: 'Rule ID'
3536
+ description: 'Currency being priced'
3271
3537
  },
3272
- userId: {
3538
+ quoteCurrency: {
3273
3539
  type: 'string',
3274
- description: 'User ID'
3540
+ description: 'Quote currency (pricing currency)'
3275
3541
  },
3276
- name: {
3542
+ amount: {
3543
+ type: 'number',
3544
+ description: 'Price amount (MUST be >= 0 per Beancount spec)',
3545
+ minimum: 0
3546
+ },
3547
+ date: {
3277
3548
  type: 'string',
3278
- description: 'Rule name'
3549
+ description: 'Price date (ISO 8601 format)'
3279
3550
  },
3280
- icon: {
3551
+ metadata: {
3281
3552
  type: 'object',
3282
- description: 'Icon emoji'
3283
- },
3284
- frequency: {
3553
+ description: 'Metadata'
3554
+ }
3555
+ }
3556
+ } as const;
3557
+
3558
+ export const $DeleteOwnUserDto = {
3559
+ type: 'object',
3560
+ properties: {
3561
+ accessToken: {
3285
3562
  type: 'string',
3286
- description: 'Recurring frequency'
3287
- },
3288
- expectedAmount: {
3289
- type: 'number',
3290
- description: 'Expected amount'
3563
+ description: 'Access token for user verification',
3564
+ example: 'abc123xyz'
3565
+ }
3566
+ },
3567
+ required: ['accessToken']
3568
+ } as const;
3569
+
3570
+ export const $UserSettingsResponseDto = {
3571
+ type: 'object',
3572
+ properties: {
3573
+ baseCurrency: {
3574
+ type: 'string',
3575
+ description:
3576
+ 'Stored base currency choice (ISO 4217) for net-worth/report aggregation. null = user never chose; aggregates fall back to the region default at display time (#713).',
3577
+ example: 'USD',
3578
+ nullable: true
3579
+ }
3580
+ },
3581
+ required: ['baseCurrency']
3582
+ } as const;
3583
+
3584
+ export const $UserResponseDto = {
3585
+ type: 'object',
3586
+ properties: {
3587
+ id: {
3588
+ type: 'string',
3589
+ description: 'User ID'
3291
3590
  },
3292
- expectedDay: {
3293
- type: 'object',
3294
- description: 'Expected day of month'
3591
+ role: {
3592
+ type: 'string',
3593
+ description: 'Assigned user role'
3295
3594
  },
3296
- customIntervalDays: {
3297
- type: 'object',
3298
- description: 'Custom interval in days'
3595
+ permissions: {
3596
+ description: 'Permission strings',
3597
+ type: 'array',
3598
+ items: {
3599
+ type: 'string'
3600
+ }
3299
3601
  },
3300
- currency: {
3602
+ settings: {
3603
+ description: 'User settings',
3604
+ allOf: [
3605
+ {
3606
+ $ref: '#/components/schemas/UserSettingsResponseDto'
3607
+ }
3608
+ ]
3609
+ }
3610
+ },
3611
+ required: ['id', 'role', 'permissions', 'settings']
3612
+ } as const;
3613
+
3614
+ export const $SignupDto = {
3615
+ type: 'object',
3616
+ properties: {
3617
+ turnstileToken: {
3301
3618
  type: 'string',
3302
- description: 'Currency code'
3619
+ description:
3620
+ 'Cloudflare Turnstile verification token (optional when Turnstile disabled)',
3621
+ example: '0.abc123def456...'
3622
+ }
3623
+ }
3624
+ } as const;
3625
+
3626
+ export const $SignupResponseDto = {
3627
+ type: 'object',
3628
+ properties: {
3629
+ authToken: {
3630
+ type: 'string',
3631
+ description: 'JWT auth token',
3632
+ example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
3303
3633
  },
3304
- matchPayeePattern: {
3305
- type: 'object',
3306
- description: 'Payee matching pattern'
3634
+ accessToken: {
3635
+ type: 'string',
3636
+ description: 'Auto-generated access token'
3307
3637
  },
3308
- matchAmountTolerance: {
3638
+ role: {
3639
+ type: 'string',
3640
+ description: 'Assigned user role',
3641
+ enum: ['USER', 'ADMIN', 'DEMO', 'INACTIVE', 'PAID', 'OPS']
3642
+ }
3643
+ },
3644
+ required: ['authToken', 'accessToken', 'role']
3645
+ } as const;
3646
+
3647
+ export const $UpdateUserSettingDto = {
3648
+ type: 'object',
3649
+ properties: {
3650
+ secId: {
3309
3651
  type: 'number',
3310
- description: 'Amount tolerance percentage'
3652
+ description: 'Security ID'
3311
3653
  },
3312
- defaultExpenseAccount: {
3313
- type: 'object',
3314
- description: 'Default expense account'
3654
+ annualInterestRate: {
3655
+ type: 'number',
3656
+ description: 'Annual interest rate',
3657
+ example: 0.05
3315
3658
  },
3316
- defaultPaymentAccount: {
3317
- type: 'object',
3318
- description: 'Default payment account'
3659
+ currency: {
3660
+ type: 'string',
3661
+ description: 'Currency code',
3662
+ example: 'USD'
3319
3663
  },
3320
- defaultPayee: {
3321
- type: 'object',
3322
- description: 'Default payee'
3664
+ baseCurrency: {
3665
+ type: 'string',
3666
+ description: 'Base currency code',
3667
+ example: 'USD'
3323
3668
  },
3324
- isActive: {
3325
- type: 'boolean',
3326
- description: 'Whether rule is active'
3669
+ benchmark: {
3670
+ type: 'string',
3671
+ description: 'Benchmark symbol',
3672
+ example: 'SPY'
3327
3673
  },
3328
- startDate: {
3674
+ colorScheme: {
3329
3675
  type: 'string',
3330
- description: 'Rule start date (YYYY-MM-DD)'
3676
+ description: 'Color scheme',
3677
+ enum: ['DARK', 'LIGHT']
3331
3678
  },
3332
- endDate: {
3333
- type: 'object',
3334
- description: 'Rule end date (YYYY-MM-DD)'
3679
+ dateRange: {
3680
+ type: 'string',
3681
+ description: 'Date range filter',
3682
+ example: '1y'
3335
3683
  },
3336
- autoCreate: {
3337
- type: 'boolean',
3338
- description: 'Auto-create transaction on expected date'
3684
+ emergencyFund: {
3685
+ type: 'number',
3686
+ description: 'Emergency fund amount',
3687
+ example: 10000
3339
3688
  },
3340
- lastOccurrence: {
3341
- type: 'object',
3342
- description: 'Last matched occurrence date (YYYY-MM-DD)'
3689
+ 'filters.accounts': {
3690
+ description: 'Account filter IDs',
3691
+ type: 'array',
3692
+ items: {
3693
+ type: 'string'
3694
+ }
3343
3695
  },
3344
- totalCount: {
3345
- type: 'number',
3346
- description: 'Total matched transactions count'
3696
+ 'filters.assetClasses': {
3697
+ description: 'Asset class filters',
3698
+ type: 'array',
3699
+ items: {
3700
+ type: 'string'
3701
+ }
3347
3702
  },
3348
- createdAt: {
3349
- format: 'date-time',
3703
+ 'filters.dataSource': {
3350
3704
  type: 'string',
3351
- description: 'Created at timestamp'
3705
+ description: 'Data source filter'
3352
3706
  },
3353
- updatedAt: {
3354
- format: 'date-time',
3707
+ 'filters.symbol': {
3355
3708
  type: 'string',
3356
- description: 'Updated at timestamp'
3709
+ description: 'Symbol filter'
3357
3710
  },
3358
- pendingCount: {
3359
- type: 'number',
3360
- description: 'Number of pending expected transactions'
3711
+ 'filters.tags': {
3712
+ description: 'Tag filters',
3713
+ type: 'array',
3714
+ items: {
3715
+ type: 'string'
3716
+ }
3361
3717
  },
3362
- overdueCount: {
3363
- type: 'number',
3364
- description: 'Number of overdue expected transactions'
3718
+ isExperimentalFeatures: {
3719
+ type: 'boolean',
3720
+ description: 'Enable experimental features'
3365
3721
  },
3366
- nextExpectedDate: {
3367
- type: 'object',
3368
- description: 'Next expected date (YYYY-MM-DD)'
3722
+ isRestrictedView: {
3723
+ type: 'boolean',
3724
+ description: 'Enable restricted view mode'
3369
3725
  },
3370
- totalAmount: {
3371
- type: 'number',
3372
- description: 'Total amount of all matched transactions'
3726
+ language: {
3727
+ type: 'string',
3728
+ description: 'Language code',
3729
+ example: 'en'
3373
3730
  },
3374
- averageAmount: {
3375
- type: 'number',
3376
- description: 'Average amount per transaction'
3731
+ locale: {
3732
+ type: 'string',
3733
+ description: 'Locale code',
3734
+ example: 'en-US'
3377
3735
  },
3378
- transactionCount: {
3736
+ projectedTotalAmount: {
3379
3737
  type: 'number',
3380
- description: 'Number of matched transactions'
3381
- },
3382
- firstDate: {
3383
- type: 'object',
3384
- description: 'First matched transaction date (YYYY-MM-DD)'
3738
+ description: 'Projected total amount',
3739
+ example: 1000000
3385
3740
  },
3386
- lastDate: {
3387
- type: 'object',
3388
- description: 'Last matched transaction date (YYYY-MM-DD)'
3741
+ retirementDate: {
3742
+ type: 'string',
3743
+ description: 'Retirement date in ISO 8601 format',
3744
+ example: '2050-01-01'
3389
3745
  },
3390
- variance: {
3746
+ savingsRate: {
3391
3747
  type: 'number',
3392
- description: 'Amount variance (standard deviation squared)'
3748
+ description: 'Savings rate percentage',
3749
+ example: 0.2
3393
3750
  },
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
- ]
3751
+ viewMode: {
3752
+ type: 'string',
3753
+ description: 'View mode',
3754
+ enum: ['DEFAULT', 'ZEN']
3755
+ }
3756
+ }
3421
3757
  } as const;
3422
3758
 
3423
- export const $UpdateRecurringRuleDto = {
3759
+ export const $UpdatePropertyDto = {
3760
+ type: 'object',
3761
+ properties: {
3762
+ value: {
3763
+ type: 'string',
3764
+ description: 'Property value'
3765
+ }
3766
+ },
3767
+ required: ['value']
3768
+ } as const;
3769
+
3770
+ export const $CreateRecurringRuleDto = {
3424
3771
  type: 'object',
3425
3772
  properties: {
3426
3773
  name: {
3427
3774
  type: 'string',
3428
- description: 'Rule name',
3775
+ description: 'Rule name (unique per user)',
3429
3776
  maxLength: 100
3430
3777
  },
3431
3778
  icon: {
@@ -3448,7 +3795,7 @@ export const $UpdateRecurringRuleDto = {
3448
3795
  },
3449
3796
  expectedAmount: {
3450
3797
  type: 'number',
3451
- description: 'Expected amount',
3798
+ description: 'Expected amount (positive number)',
3452
3799
  minimum: 0
3453
3800
  },
3454
3801
  expectedDay: {
@@ -3459,7 +3806,7 @@ export const $UpdateRecurringRuleDto = {
3459
3806
  },
3460
3807
  customIntervalDays: {
3461
3808
  type: 'number',
3462
- description: 'Custom interval in days',
3809
+ description: 'Custom interval in days (required for CUSTOM frequency)',
3463
3810
  minimum: 1
3464
3811
  },
3465
3812
  currency: {
@@ -3469,118 +3816,136 @@ export const $UpdateRecurringRuleDto = {
3469
3816
  },
3470
3817
  matchPayeePattern: {
3471
3818
  type: 'string',
3472
- description: 'Payee matching pattern',
3819
+ description: 'Payee matching pattern (supports wildcards)',
3473
3820
  maxLength: 200
3474
3821
  },
3475
3822
  matchAmountTolerance: {
3476
3823
  type: 'number',
3477
3824
  description: 'Amount tolerance percentage (0-1)',
3825
+ default: 0.075,
3478
3826
  minimum: 0,
3479
3827
  maximum: 1
3480
3828
  },
3481
3829
  defaultExpenseAccount: {
3482
3830
  type: 'string',
3483
- description: 'Default expense account',
3831
+ description: 'Default expense account for auto-create',
3484
3832
  maxLength: 200
3485
3833
  },
3486
3834
  defaultPaymentAccount: {
3487
3835
  type: 'string',
3488
- description: 'Default payment account',
3836
+ description: 'Default payment account for auto-create',
3489
3837
  maxLength: 200
3490
3838
  },
3491
3839
  defaultPayee: {
3492
3840
  type: 'string',
3493
- description: 'Default payee',
3841
+ description: 'Default payee for auto-create',
3494
3842
  maxLength: 200
3495
3843
  },
3496
3844
  autoCreate: {
3497
3845
  type: 'boolean',
3498
- description: 'Auto-create transaction'
3846
+ description: 'Auto-create transaction when expected date arrives',
3847
+ default: false
3499
3848
  },
3500
- isActive: {
3501
- type: 'boolean',
3502
- description: 'Rule active status'
3849
+ startDate: {
3850
+ type: 'string',
3851
+ description: 'Rule start date (ISO format)'
3503
3852
  },
3504
3853
  endDate: {
3505
3854
  type: 'string',
3506
3855
  description: 'Rule end date (ISO format)'
3507
3856
  }
3508
- }
3857
+ },
3858
+ required: [
3859
+ 'name',
3860
+ 'frequency',
3861
+ 'expectedAmount',
3862
+ 'matchAmountTolerance',
3863
+ 'autoCreate'
3864
+ ]
3509
3865
  } as const;
3510
3866
 
3511
- export const $ExpectedTransactionRuleDto = {
3867
+ export const $RecurringRuleResponseDto = {
3512
3868
  type: 'object',
3513
3869
  properties: {
3870
+ id: {
3871
+ type: 'string',
3872
+ description: 'Rule ID'
3873
+ },
3874
+ userId: {
3875
+ type: 'string',
3876
+ description: 'User ID'
3877
+ },
3514
3878
  name: {
3515
3879
  type: 'string',
3516
3880
  description: 'Rule name'
3517
3881
  },
3518
3882
  icon: {
3519
- type: 'object',
3520
- description: 'Rule icon'
3883
+ type: 'string',
3884
+ description: 'Icon emoji'
3521
3885
  },
3522
3886
  frequency: {
3523
3887
  type: 'string',
3524
- description: 'Rule frequency'
3888
+ description: 'Recurring frequency'
3889
+ },
3890
+ expectedAmount: {
3891
+ type: 'number',
3892
+ description: 'Expected amount'
3893
+ },
3894
+ expectedDay: {
3895
+ type: 'number',
3896
+ description: 'Expected day of month'
3897
+ },
3898
+ customIntervalDays: {
3899
+ type: 'number',
3900
+ description: 'Custom interval in days'
3525
3901
  },
3526
3902
  currency: {
3527
3903
  type: 'string',
3528
3904
  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
3905
  },
3541
- userId: {
3906
+ matchPayeePattern: {
3542
3907
  type: 'string',
3543
- description: 'User ID'
3908
+ description: 'Payee matching pattern'
3544
3909
  },
3545
- ruleId: {
3546
- type: 'string',
3547
- description: 'Associated rule ID'
3910
+ matchAmountTolerance: {
3911
+ type: 'number',
3912
+ description: 'Amount tolerance percentage'
3548
3913
  },
3549
- expectedDate: {
3914
+ defaultExpenseAccount: {
3550
3915
  type: 'string',
3551
- description: 'Expected date (YYYY-MM-DD)'
3916
+ description: 'Default expense account'
3552
3917
  },
3553
- expectedAmount: {
3554
- type: 'number',
3555
- description: 'Expected amount'
3918
+ defaultPaymentAccount: {
3919
+ type: 'string',
3920
+ description: 'Default payment account'
3556
3921
  },
3557
- status: {
3922
+ defaultPayee: {
3558
3923
  type: 'string',
3559
- description: 'Status (PENDING, COMPLETED, SKIPPED)'
3924
+ description: 'Default payee'
3560
3925
  },
3561
- matchedTransactionId: {
3562
- type: 'object',
3563
- description: 'Matched transaction ID'
3926
+ isActive: {
3927
+ type: 'boolean',
3928
+ description: 'Whether rule is active'
3564
3929
  },
3565
- matchedAt: {
3566
- type: 'object',
3567
- description: 'Match timestamp (ISO 8601)'
3930
+ startDate: {
3931
+ type: 'string',
3932
+ description: 'Rule start date (YYYY-MM-DD)'
3568
3933
  },
3569
- matchConfidence: {
3570
- type: 'object',
3571
- description: 'Match confidence score (0-1)'
3934
+ endDate: {
3935
+ type: 'string',
3936
+ description: 'Rule end date (YYYY-MM-DD)'
3572
3937
  },
3573
- isOverdue: {
3938
+ autoCreate: {
3574
3939
  type: 'boolean',
3575
- description: 'Whether this expected transaction is overdue'
3940
+ description: 'Auto-create transaction on expected date'
3576
3941
  },
3577
- rule: {
3578
- description: 'Rule information',
3579
- allOf: [
3580
- {
3581
- $ref: '#/components/schemas/ExpectedTransactionRuleDto'
3582
- }
3583
- ]
3942
+ lastOccurrence: {
3943
+ type: 'string',
3944
+ description: 'Last matched occurrence date (YYYY-MM-DD)'
3945
+ },
3946
+ totalCount: {
3947
+ type: 'number',
3948
+ description: 'Total matched transactions count'
3584
3949
  },
3585
3950
  createdAt: {
3586
3951
  format: 'date-time',
@@ -3596,647 +3961,581 @@ export const $ExpectedTransactionResponseDto = {
3596
3961
  required: [
3597
3962
  'id',
3598
3963
  'userId',
3599
- 'ruleId',
3600
- 'expectedDate',
3964
+ 'name',
3965
+ 'frequency',
3601
3966
  'expectedAmount',
3602
- 'status',
3603
- 'isOverdue',
3604
- 'rule',
3967
+ 'currency',
3968
+ 'matchAmountTolerance',
3969
+ 'isActive',
3970
+ 'startDate',
3971
+ 'autoCreate',
3972
+ 'totalCount',
3605
3973
  'createdAt',
3606
3974
  'updatedAt'
3607
3975
  ]
3608
3976
  } as const;
3609
3977
 
3610
- export const $ExpectedTransactionListResponseDto = {
3978
+ export const $CreateRuleFromTransactionDto = {
3611
3979
  type: 'object',
3612
3980
  properties: {
3613
- items: {
3614
- type: 'array',
3615
- items: {
3616
- $ref: '#/components/schemas/ExpectedTransactionResponseDto'
3617
- }
3981
+ frequency: {
3982
+ type: 'string',
3983
+ description: 'Recurring frequency',
3984
+ enum: [
3985
+ 'WEEKLY',
3986
+ 'BIWEEKLY',
3987
+ 'MONTHLY',
3988
+ 'BIMONTHLY',
3989
+ 'QUARTERLY',
3990
+ 'YEARLY',
3991
+ 'CUSTOM'
3992
+ ],
3993
+ example: 'MONTHLY'
3618
3994
  },
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: {
3995
+ name: {
3631
3996
  type: 'string',
3632
- description: 'Transaction ID to match with'
3997
+ description: 'Optional name override (default: transaction payee)',
3998
+ maxLength: 100
3999
+ },
4000
+ icon: {
4001
+ type: 'string',
4002
+ description: 'Optional icon emoji',
4003
+ maxLength: 10
3633
4004
  }
3634
4005
  },
3635
- required: ['transactionId']
4006
+ required: ['frequency']
3636
4007
  } as const;
3637
4008
 
3638
- export const $EnterNowDto = {
4009
+ export const $RecurringRuleWithStatsResponseDto = {
3639
4010
  type: 'object',
3640
4011
  properties: {
3641
- expenseAccount: {
4012
+ id: {
3642
4013
  type: 'string',
3643
- description:
3644
- 'Override expense account (uses rule default if not provided)',
3645
- maxLength: 200
4014
+ description: 'Rule ID'
3646
4015
  },
3647
- paymentAccount: {
4016
+ userId: {
3648
4017
  type: 'string',
3649
- description:
3650
- 'Override payment account (uses rule default if not provided)',
3651
- maxLength: 200
4018
+ description: 'User ID'
3652
4019
  },
3653
- amount: {
4020
+ name: {
4021
+ type: 'string',
4022
+ description: 'Rule name'
4023
+ },
4024
+ icon: {
4025
+ type: 'string',
4026
+ description: 'Icon emoji'
4027
+ },
4028
+ frequency: {
4029
+ type: 'string',
4030
+ description: 'Recurring frequency'
4031
+ },
4032
+ expectedAmount: {
3654
4033
  type: 'number',
3655
- description: 'Override amount (uses expected amount if not provided)',
3656
- minimum: 0
4034
+ description: 'Expected amount'
4035
+ },
4036
+ expectedDay: {
4037
+ type: 'number',
4038
+ description: 'Expected day of month'
4039
+ },
4040
+ customIntervalDays: {
4041
+ type: 'number',
4042
+ description: 'Custom interval in days'
4043
+ },
4044
+ currency: {
4045
+ type: 'string',
4046
+ description: 'Currency code'
4047
+ },
4048
+ matchPayeePattern: {
4049
+ type: 'string',
4050
+ description: 'Payee matching pattern'
4051
+ },
4052
+ matchAmountTolerance: {
4053
+ type: 'number',
4054
+ description: 'Amount tolerance percentage'
4055
+ },
4056
+ defaultExpenseAccount: {
4057
+ type: 'string',
4058
+ description: 'Default expense account'
3657
4059
  },
3658
- payee: {
4060
+ defaultPaymentAccount: {
3659
4061
  type: 'string',
3660
- description: 'Override payee (uses rule default if not provided)',
3661
- maxLength: 200
4062
+ description: 'Default payment account'
3662
4063
  },
3663
- narration: {
4064
+ defaultPayee: {
3664
4065
  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: {
4066
+ description: 'Default payee'
4067
+ },
4068
+ isActive: {
4069
+ type: 'boolean',
4070
+ description: 'Whether rule is active'
4071
+ },
4072
+ startDate: {
3675
4073
  type: 'string',
3676
- description: 'Rule name',
3677
- example: 'Rent'
4074
+ description: 'Rule start date (YYYY-MM-DD)'
3678
4075
  },
3679
- ruleId: {
4076
+ endDate: {
3680
4077
  type: 'string',
3681
- description: 'Rule ID',
3682
- example: 'clx123...'
4078
+ description: 'Rule end date (YYYY-MM-DD)'
3683
4079
  },
3684
- amount: {
3685
- type: 'number',
3686
- description: 'Expected amount',
3687
- example: 3000
4080
+ autoCreate: {
4081
+ type: 'boolean',
4082
+ description: 'Auto-create transaction on expected date'
3688
4083
  },
3689
- date: {
4084
+ lastOccurrence: {
3690
4085
  type: 'string',
3691
- description: 'Expected date (YYYY-MM-DD)',
3692
- example: '2024-04-01'
4086
+ description: 'Last matched occurrence date (YYYY-MM-DD)'
3693
4087
  },
3694
- icon: {
3695
- type: 'string',
3696
- description: 'Rule icon emoji',
3697
- example: '🏠',
3698
- nullable: true
4088
+ totalCount: {
4089
+ type: 'number',
4090
+ description: 'Total matched transactions count'
3699
4091
  },
3700
- currency: {
4092
+ createdAt: {
4093
+ format: 'date-time',
3701
4094
  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: {
4095
+ description: 'Created at timestamp'
4096
+ },
4097
+ updatedAt: {
4098
+ format: 'date-time',
3713
4099
  type: 'string',
3714
- description: 'Month (YYYY-MM)',
3715
- example: '2024-04'
4100
+ description: 'Updated at timestamp'
3716
4101
  },
3717
- expectedOutflow: {
4102
+ pendingCount: {
3718
4103
  type: 'number',
3719
- description: 'Total expected outflow for the month',
3720
- example: 8500
4104
+ description: 'Number of pending expected transactions'
3721
4105
  },
3722
- itemCount: {
4106
+ overdueCount: {
3723
4107
  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
- }
4108
+ description: 'Number of overdue expected transactions'
3734
4109
  },
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
- }
4110
+ nextExpectedDate: {
4111
+ type: 'string',
4112
+ description: 'Next expected date (YYYY-MM-DD)'
3755
4113
  },
3756
- totalOutflow: {
4114
+ totalAmount: {
3757
4115
  type: 'number',
3758
- description: 'Total expected outflow across all months',
3759
- example: 25500
4116
+ description: 'Total amount of all matched transactions'
3760
4117
  },
3761
- totalByCurrency: {
3762
- type: 'object',
3763
- description: 'Total by currency across all months',
3764
- example: {
3765
- CNY: 25500,
3766
- USD: 300
3767
- }
4118
+ averageAmount: {
4119
+ type: 'number',
4120
+ description: 'Average amount per transaction'
3768
4121
  },
3769
- rulesCount: {
4122
+ transactionCount: {
3770
4123
  type: 'number',
3771
- description: 'Number of active recurring rules included',
3772
- example: 5
4124
+ description: 'Number of matched transactions'
3773
4125
  },
3774
- periodStart: {
4126
+ firstDate: {
3775
4127
  type: 'string',
3776
- description: 'Forecast period start date',
3777
- example: '2024-04-01'
4128
+ description: 'First matched transaction date (YYYY-MM-DD)'
3778
4129
  },
3779
- periodEnd: {
4130
+ lastDate: {
3780
4131
  type: 'string',
3781
- description: 'Forecast period end date',
3782
- example: '2024-06-30'
4132
+ description: 'Last matched transaction date (YYYY-MM-DD)'
4133
+ },
4134
+ variance: {
4135
+ type: 'number',
4136
+ description: 'Amount variance (standard deviation squared)'
4137
+ },
4138
+ upcomingCount: {
4139
+ type: 'number',
4140
+ description: 'Number of upcoming expected transactions'
3783
4141
  }
3784
4142
  },
3785
4143
  required: [
3786
- 'forecast',
3787
- 'totalOutflow',
3788
- 'totalByCurrency',
3789
- 'rulesCount',
3790
- 'periodStart',
3791
- 'periodEnd'
4144
+ 'id',
4145
+ 'userId',
4146
+ 'name',
4147
+ 'frequency',
4148
+ 'expectedAmount',
4149
+ 'currency',
4150
+ 'matchAmountTolerance',
4151
+ 'isActive',
4152
+ 'startDate',
4153
+ 'autoCreate',
4154
+ 'totalCount',
4155
+ 'createdAt',
4156
+ 'updatedAt',
4157
+ 'pendingCount',
4158
+ 'overdueCount',
4159
+ 'totalAmount',
4160
+ 'averageAmount',
4161
+ 'transactionCount',
4162
+ 'variance',
4163
+ 'upcomingCount'
3792
4164
  ]
3793
4165
  } as const;
3794
4166
 
3795
- export const $CurrencyBalanceDto = {
4167
+ export const $UpdateRecurringRuleDto = {
3796
4168
  type: 'object',
3797
4169
  properties: {
3798
- currency: {
4170
+ name: {
3799
4171
  type: 'string',
3800
- description: 'ISO 4217 currency code',
3801
- example: 'CNY'
4172
+ description: 'Rule name (unique per user)',
4173
+ maxLength: 100
3802
4174
  },
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: {
4175
+ icon: {
3816
4176
  type: 'string',
3817
- description: 'Date in YYYY-MM-DD format',
3818
- example: '2024-06-15'
4177
+ description: 'Icon emoji',
4178
+ maxLength: 10
3819
4179
  },
3820
- value: {
4180
+ frequency: {
3821
4181
  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'
4182
+ description: 'Recurring frequency',
4183
+ enum: [
4184
+ 'WEEKLY',
4185
+ 'BIWEEKLY',
4186
+ 'MONTHLY',
4187
+ 'BIMONTHLY',
4188
+ 'QUARTERLY',
4189
+ 'YEARLY',
4190
+ 'CUSTOM'
4191
+ ]
3829
4192
  },
3830
- assets: {
3831
- type: 'string',
3832
- description: 'Total assets at this date (in base currency)',
3833
- example: '494338.00'
4193
+ expectedAmount: {
4194
+ type: 'number',
4195
+ description: 'Expected amount (positive number)',
4196
+ minimum: 0
3834
4197
  },
3835
- liabilities: {
3836
- type: 'string',
3837
- description: 'Total liabilities at this date (in base currency)',
3838
- example: '310098.00'
4198
+ expectedDay: {
4199
+ type: 'number',
4200
+ description: 'Expected day of month (1-31)',
4201
+ minimum: 1,
4202
+ maximum: 31
3839
4203
  },
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: {
4204
+ currency: {
3855
4205
  type: 'string',
3856
- description: 'Value at start of period',
3857
- example: '450000.00'
4206
+ description: 'Currency code',
4207
+ maxLength: 10
3858
4208
  },
3859
- endValue: {
4209
+ matchPayeePattern: {
3860
4210
  type: 'string',
3861
- description: 'Value at end of period',
3862
- example: '500000.00'
4211
+ description: 'Payee matching pattern (supports wildcards)',
4212
+ maxLength: 200
3863
4213
  },
3864
- totalChange: {
4214
+ matchAmountTolerance: {
4215
+ type: 'number',
4216
+ description: 'Amount tolerance percentage (0-1)',
4217
+ default: 0.075,
4218
+ minimum: 0,
4219
+ maximum: 1
4220
+ },
4221
+ defaultExpenseAccount: {
3865
4222
  type: 'string',
3866
- description: 'Total change over period',
3867
- example: '50000.00'
4223
+ description: 'Default expense account for auto-create',
4224
+ maxLength: 200
3868
4225
  },
3869
- totalChangePercentage: {
4226
+ defaultPaymentAccount: {
3870
4227
  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: {
4228
+ description: 'Default payment account for auto-create',
4229
+ maxLength: 200
4230
+ },
4231
+ defaultPayee: {
3882
4232
  type: 'string',
3883
- description: 'Date in YYYY-MM-DD format',
3884
- example: '2024-06-15'
4233
+ description: 'Default payee for auto-create',
4234
+ maxLength: 200
3885
4235
  },
3886
- byCurrency: {
3887
- description: 'Balances by currency',
3888
- type: 'array',
3889
- items: {
3890
- $ref: '#/components/schemas/CurrencyBalanceDto'
3891
- }
4236
+ autoCreate: {
4237
+ type: 'boolean',
4238
+ description: 'Auto-create transaction when expected date arrives',
4239
+ default: false
4240
+ },
4241
+ endDate: {
4242
+ type: 'string',
4243
+ description: 'Rule end date (ISO format)'
4244
+ },
4245
+ customIntervalDays: {
4246
+ type: 'number',
4247
+ description: 'Custom interval in days',
4248
+ minimum: 1
4249
+ },
4250
+ isActive: {
4251
+ type: 'boolean',
4252
+ description: 'Rule active status'
3892
4253
  }
3893
- },
3894
- required: ['date', 'byCurrency']
4254
+ }
3895
4255
  } as const;
3896
4256
 
3897
- export const $PortfolioTrendsResponseDto = {
4257
+ export const $ExpectedTransactionRuleDto = {
3898
4258
  type: 'object',
3899
4259
  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
- ]
4260
+ name: {
4261
+ type: 'string',
4262
+ description: 'Rule name'
3914
4263
  },
3915
- period: {
4264
+ icon: {
3916
4265
  type: 'string',
3917
- description: 'Period requested',
3918
- example: '6m'
4266
+ description: 'Rule icon'
3919
4267
  },
3920
- granularity: {
4268
+ frequency: {
3921
4269
  type: 'string',
3922
- description: 'Data granularity',
3923
- example: 'month'
4270
+ description: 'Rule frequency'
3924
4271
  },
3925
4272
  currency: {
3926
4273
  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
- }
4274
+ description: 'Currency code'
3944
4275
  }
3945
4276
  },
3946
- required: ['series', 'summary', 'period', 'granularity', 'currency']
4277
+ required: ['name', 'frequency', 'currency']
3947
4278
  } as const;
3948
4279
 
3949
- export const $CashFlowPointDto = {
4280
+ export const $ExpectedTransactionResponseDto = {
3950
4281
  type: 'object',
3951
4282
  properties: {
3952
- month: {
4283
+ id: {
3953
4284
  type: 'string',
3954
- description: 'Month key (YYYY-MM)',
3955
- example: '2024-03'
4285
+ description: 'Expected transaction ID'
3956
4286
  },
3957
- income: {
4287
+ userId: {
3958
4288
  type: 'string',
3959
- description: 'Income in base currency (absolute, converted)',
3960
- example: '10000.00'
4289
+ description: 'User ID'
3961
4290
  },
3962
- expense: {
4291
+ ruleId: {
3963
4292
  type: 'string',
3964
- description: 'Expense in base currency (absolute, converted)',
3965
- example: '5000.00'
4293
+ description: 'Associated rule ID'
3966
4294
  },
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: {
4295
+ expectedDate: {
3980
4296
  type: 'string',
3981
- description: 'Total income across the period',
3982
- example: '60000.00'
4297
+ description: 'Expected date (YYYY-MM-DD)'
3983
4298
  },
3984
- totalExpense: {
4299
+ expectedAmount: {
4300
+ type: 'number',
4301
+ description: 'Expected amount'
4302
+ },
4303
+ status: {
3985
4304
  type: 'string',
3986
- description: 'Total expense across the period',
3987
- example: '30000.00'
4305
+ description: 'Status (PENDING, COMPLETED, SKIPPED)'
3988
4306
  },
3989
- totalNetSavings: {
4307
+ matchedTransactionId: {
3990
4308
  type: 'string',
3991
- description: 'income − expense across the period',
3992
- example: '30000.00'
4309
+ description: 'Matched transaction ID'
3993
4310
  },
3994
- averageMonthlyNetSavings: {
4311
+ matchedAt: {
3995
4312
  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
- }
4313
+ description: 'Match timestamp (ISO 8601)'
4019
4314
  },
4020
- summary: {
4021
- description: 'Period totals',
4315
+ matchConfidence: {
4316
+ type: 'number',
4317
+ description: 'Match confidence score (0-1)'
4318
+ },
4319
+ isOverdue: {
4320
+ type: 'boolean',
4321
+ description: 'Whether this expected transaction is overdue'
4322
+ },
4323
+ rule: {
4324
+ description: 'Rule information',
4022
4325
  allOf: [
4023
4326
  {
4024
- $ref: '#/components/schemas/CashFlowTrendSummaryDto'
4327
+ $ref: '#/components/schemas/ExpectedTransactionRuleDto'
4025
4328
  }
4026
4329
  ]
4027
4330
  },
4028
- period: {
4029
- type: 'string',
4030
- description: 'Period requested',
4031
- example: '6m'
4032
- },
4033
- granularity: {
4331
+ createdAt: {
4332
+ format: 'date-time',
4034
4333
  type: 'string',
4035
- description: 'Data granularity (v1 returns month buckets)',
4036
- example: 'month'
4334
+ description: 'Created at timestamp'
4037
4335
  },
4038
- currency: {
4336
+ updatedAt: {
4337
+ format: 'date-time',
4039
4338
  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
- }
4339
+ description: 'Updated at timestamp'
4049
4340
  }
4050
4341
  },
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: {}
4342
+ required: [
4343
+ 'id',
4344
+ 'userId',
4345
+ 'ruleId',
4346
+ 'expectedDate',
4347
+ 'expectedAmount',
4348
+ 'status',
4349
+ 'isOverdue',
4350
+ 'rule',
4351
+ 'createdAt',
4352
+ 'updatedAt'
4353
+ ]
4072
4354
  } as const;
4073
4355
 
4074
- export const $DeleteOwnUserDto = {
4356
+ export const $ExpectedTransactionListResponseDto = {
4075
4357
  type: 'object',
4076
4358
  properties: {
4077
- accessToken: {
4078
- type: 'string',
4079
- description: 'Access token for user verification',
4080
- example: 'abc123xyz'
4359
+ items: {
4360
+ type: 'array',
4361
+ items: {
4362
+ $ref: '#/components/schemas/ExpectedTransactionResponseDto'
4363
+ }
4364
+ },
4365
+ total: {
4366
+ type: 'number',
4367
+ description: 'Total count'
4081
4368
  }
4082
4369
  },
4083
- required: ['accessToken']
4370
+ required: ['items', 'total']
4084
4371
  } as const;
4085
4372
 
4086
- export const $SignupDto = {
4373
+ export const $ConfirmMatchDto = {
4087
4374
  type: 'object',
4088
4375
  properties: {
4089
- turnstileToken: {
4376
+ transactionId: {
4090
4377
  type: 'string',
4091
- description:
4092
- 'Cloudflare Turnstile verification token (optional when Turnstile disabled)',
4093
- example: '0.abc123def456...'
4378
+ description: 'Transaction ID to match with'
4094
4379
  }
4095
- }
4380
+ },
4381
+ required: ['transactionId']
4096
4382
  } as const;
4097
4383
 
4098
- export const $SignupResponseDto = {
4384
+ export const $EnterNowDto = {
4099
4385
  type: 'object',
4100
4386
  properties: {
4101
- authToken: {
4387
+ expenseAccount: {
4102
4388
  type: 'string',
4103
- description: 'JWT auth token',
4104
- example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
4389
+ description:
4390
+ 'Override expense account (uses rule default if not provided)',
4391
+ maxLength: 200
4105
4392
  },
4106
- accessToken: {
4393
+ paymentAccount: {
4107
4394
  type: 'string',
4108
- description: 'Auto-generated access token'
4395
+ description:
4396
+ 'Override payment account (uses rule default if not provided)',
4397
+ maxLength: 200
4109
4398
  },
4110
- role: {
4399
+ amount: {
4400
+ type: 'number',
4401
+ description: 'Override amount (uses expected amount if not provided)',
4402
+ minimum: 0
4403
+ },
4404
+ payee: {
4111
4405
  type: 'string',
4112
- description: 'Assigned user role',
4113
- enum: ['USER', 'ADMIN', 'DEMO', 'INACTIVE', 'PAID', 'OPS']
4406
+ description: 'Override payee (uses rule default if not provided)',
4407
+ maxLength: 200
4408
+ },
4409
+ narration: {
4410
+ type: 'string',
4411
+ description: 'Optional narration',
4412
+ maxLength: 500
4114
4413
  }
4115
- },
4116
- required: ['authToken', 'accessToken', 'role']
4414
+ }
4117
4415
  } as const;
4118
4416
 
4119
- export const $UpdateUserSettingDto = {
4417
+ export const $ForecastItemDto = {
4120
4418
  type: 'object',
4121
4419
  properties: {
4122
- secId: {
4123
- type: 'number',
4124
- description: 'Security ID'
4420
+ rule: {
4421
+ type: 'string',
4422
+ description: 'Rule name',
4423
+ example: 'Rent'
4125
4424
  },
4126
- annualInterestRate: {
4425
+ ruleId: {
4426
+ type: 'string',
4427
+ description: 'Rule ID',
4428
+ example: 'clx123...'
4429
+ },
4430
+ amount: {
4127
4431
  type: 'number',
4128
- description: 'Annual interest rate',
4129
- example: 0.05
4432
+ description: 'Expected amount',
4433
+ example: 3000
4130
4434
  },
4131
- currency: {
4435
+ date: {
4132
4436
  type: 'string',
4133
- description: 'Currency code',
4134
- example: 'USD'
4437
+ description: 'Expected date (YYYY-MM-DD)',
4438
+ example: '2024-04-01'
4135
4439
  },
4136
- baseCurrency: {
4440
+ icon: {
4137
4441
  type: 'string',
4138
- description: 'Base currency code',
4139
- example: 'USD'
4442
+ description: 'Rule icon emoji',
4443
+ example: '🏠',
4444
+ nullable: true
4140
4445
  },
4141
- benchmark: {
4446
+ currency: {
4142
4447
  type: 'string',
4143
- description: 'Benchmark symbol',
4144
- example: 'SPY'
4145
- },
4146
- colorScheme: {
4448
+ description: 'Currency code',
4449
+ example: 'CNY'
4450
+ }
4451
+ },
4452
+ required: ['rule', 'ruleId', 'amount', 'date', 'icon', 'currency']
4453
+ } as const;
4454
+
4455
+ export const $MonthlyForecastDto = {
4456
+ type: 'object',
4457
+ properties: {
4458
+ month: {
4147
4459
  type: 'string',
4148
- description: 'Color scheme',
4149
- enum: ['DARK', 'LIGHT']
4460
+ description: 'Month (YYYY-MM)',
4461
+ example: '2024-04'
4150
4462
  },
4151
- dateRange: {
4152
- type: 'string',
4153
- description: 'Date range filter',
4154
- example: '1y'
4463
+ expectedOutflow: {
4464
+ type: 'number',
4465
+ description: 'Total expected outflow for the month',
4466
+ example: 8500
4155
4467
  },
4156
- emergencyFund: {
4468
+ itemCount: {
4157
4469
  type: 'number',
4158
- description: 'Emergency fund amount',
4159
- example: 10000
4470
+ description: 'Number of expected transactions',
4471
+ example: 3
4160
4472
  },
4161
- 'filters.accounts': {
4162
- description: 'Account filter IDs',
4163
- type: 'array',
4164
- items: {
4165
- type: 'string'
4473
+ byCurrency: {
4474
+ type: 'object',
4475
+ description: 'Breakdown by currency',
4476
+ example: {
4477
+ CNY: 8500,
4478
+ USD: 100
4166
4479
  }
4167
4480
  },
4168
- 'filters.assetClasses': {
4169
- description: 'Asset class filters',
4481
+ items: {
4482
+ description: 'Individual forecast items',
4170
4483
  type: 'array',
4171
4484
  items: {
4172
- type: 'string'
4485
+ $ref: '#/components/schemas/ForecastItemDto'
4173
4486
  }
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',
4487
+ }
4488
+ },
4489
+ required: ['month', 'expectedOutflow', 'itemCount', 'byCurrency', 'items']
4490
+ } as const;
4491
+
4492
+ export const $ForecastResponseDto = {
4493
+ type: 'object',
4494
+ properties: {
4495
+ forecast: {
4496
+ description: 'Monthly forecast data',
4185
4497
  type: 'array',
4186
4498
  items: {
4187
- type: 'string'
4499
+ $ref: '#/components/schemas/MonthlyForecastDto'
4188
4500
  }
4189
4501
  },
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: {
4502
+ totalOutflow: {
4209
4503
  type: 'number',
4210
- description: 'Projected total amount',
4211
- example: 1000000
4504
+ description: 'Total expected outflow across all months',
4505
+ example: 25500
4212
4506
  },
4213
- retirementDate: {
4214
- type: 'string',
4215
- description: 'Retirement date in ISO 8601 format',
4216
- example: '2050-01-01'
4507
+ totalByCurrency: {
4508
+ type: 'object',
4509
+ description: 'Total by currency across all months',
4510
+ example: {
4511
+ CNY: 25500,
4512
+ USD: 300
4513
+ }
4217
4514
  },
4218
- savingsRate: {
4515
+ rulesCount: {
4219
4516
  type: 'number',
4220
- description: 'Savings rate percentage',
4221
- example: 0.2
4517
+ description: 'Number of active recurring rules included',
4518
+ example: 5
4222
4519
  },
4223
- viewMode: {
4520
+ periodStart: {
4224
4521
  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: {
4522
+ description: 'Forecast period start date',
4523
+ example: '2024-04-01'
4524
+ },
4525
+ periodEnd: {
4235
4526
  type: 'string',
4236
- description: 'Property value'
4527
+ description: 'Forecast period end date',
4528
+ example: '2024-06-30'
4237
4529
  }
4238
4530
  },
4239
- required: ['value']
4531
+ required: [
4532
+ 'forecast',
4533
+ 'totalOutflow',
4534
+ 'totalByCurrency',
4535
+ 'rulesCount',
4536
+ 'periodStart',
4537
+ 'periodEnd'
4538
+ ]
4240
4539
  } as const;
4241
4540
 
4242
4541
  export const $CreateTransactionRuleDto = {
@@ -4798,7 +5097,8 @@ export const $UpdateTransactionRuleDto = {
4798
5097
  },
4799
5098
  matchLogic: {
4800
5099
  type: 'string',
4801
- enum: ['OR', 'AND']
5100
+ enum: ['OR', 'AND'],
5101
+ default: 'OR'
4802
5102
  },
4803
5103
  amountMin: {
4804
5104
  type: 'number',
@@ -4812,12 +5112,9 @@ export const $UpdateTransactionRuleDto = {
4812
5112
  },
4813
5113
  priority: {
4814
5114
  type: 'number',
5115
+ default: 50,
4815
5116
  minimum: 0,
4816
- maximum: 1000
4817
- },
4818
- enabled: {
4819
- type: 'boolean',
4820
- description: 'Enable or disable the rule'
5117
+ maximum: 1000
4821
5118
  },
4822
5119
  additionalTags: {
4823
5120
  items: {
@@ -4828,6 +5125,10 @@ export const $UpdateTransactionRuleDto = {
4828
5125
  },
4829
5126
  additionalMetadata: {
4830
5127
  type: 'object'
5128
+ },
5129
+ enabled: {
5130
+ type: 'boolean',
5131
+ description: 'Enable or disable the rule'
4831
5132
  }
4832
5133
  }
4833
5134
  } as const;
@@ -4888,6 +5189,69 @@ export const $TestRuleResponseDto = {
4888
5189
  required: ['ruleId', 'matches', 'confidence', 'matchDetails']
4889
5190
  } as const;
4890
5191
 
5192
+ export const $CategoryCatalogEntryDto = {
5193
+ type: 'object',
5194
+ properties: {
5195
+ slug: {
5196
+ type: 'string',
5197
+ description: 'Category slug (single source-of-truth)',
5198
+ example: 'food'
5199
+ },
5200
+ scenario: {
5201
+ type: 'string',
5202
+ description: 'Display scenario group (maps to frontend picker _scenario)',
5203
+ enum: [
5204
+ 'expense',
5205
+ 'income',
5206
+ 'investment',
5207
+ 'banking',
5208
+ 'transfer',
5209
+ 'payment'
5210
+ ],
5211
+ example: 'expense'
5212
+ },
5213
+ icon: {
5214
+ type: 'string',
5215
+ description: 'Lucide icon name',
5216
+ example: 'utensils'
5217
+ },
5218
+ regions: {
5219
+ description: "Applicable regions ('*' = all, 'cn' = CN-only)",
5220
+ example: ['*'],
5221
+ type: 'array',
5222
+ items: {
5223
+ type: 'string'
5224
+ }
5225
+ }
5226
+ },
5227
+ required: ['slug', 'scenario', 'icon', 'regions']
5228
+ } as const;
5229
+
5230
+ export const $CategoryCatalogListResponseDto = {
5231
+ type: 'object',
5232
+ properties: {
5233
+ items: {
5234
+ description: 'Category entries (region-scoped, query-filtered)',
5235
+ type: 'array',
5236
+ items: {
5237
+ $ref: '#/components/schemas/CategoryCatalogEntryDto'
5238
+ }
5239
+ },
5240
+ total: {
5241
+ type: 'number',
5242
+ description:
5243
+ 'Total category entries for the region (before query filtering)',
5244
+ example: 30
5245
+ },
5246
+ region: {
5247
+ type: 'string',
5248
+ description: 'Region code',
5249
+ example: 'cn'
5250
+ }
5251
+ },
5252
+ required: ['items', 'total', 'region']
5253
+ } as const;
5254
+
4891
5255
  export const $CreateBeanEventDto = {
4892
5256
  type: 'object',
4893
5257
  properties: {
@@ -5051,6 +5415,14 @@ export const $OnboardingAccountDto = {
5051
5415
  description:
5052
5416
  'Platform ID to bind the account to (references Platform.id); omit for unbound',
5053
5417
  example: 'c98e5d4a-2f71-4a5a-bb3c-92c9f231d5e2'
5418
+ },
5419
+ displayName: {
5420
+ type: 'string',
5421
+ description:
5422
+ 'User-set display name override (omit/null = keep the derived name)',
5423
+ nullable: true,
5424
+ maxLength: 50,
5425
+ example: 'Salary card'
5054
5426
  }
5055
5427
  },
5056
5428
  required: ['path', 'currency']
@@ -5630,7 +6002,8 @@ export const $UpdateMapperDefaultsDto = {
5630
6002
  type: 'string',
5631
6003
  description: 'Source account for transactions (Beancount format)',
5632
6004
  example: 'Assets:CN:Alipay:Balance',
5633
- pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
6005
+ pattern:
6006
+ '^(Assets|Liabilities|Income|Expenses|Equity)(:[A-Za-z0-9][A-Za-z0-9-]*)+$'
5634
6007
  },
5635
6008
  currency: {
5636
6009
  type: 'string',
@@ -5644,13 +6017,15 @@ export const $UpdateMapperDefaultsDto = {
5644
6017
  type: 'string',
5645
6018
  description: 'Default expense account (optional)',
5646
6019
  example: 'Expenses:Unknown',
5647
- pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
6020
+ pattern:
6021
+ '^(Assets|Liabilities|Income|Expenses|Equity)(:[A-Za-z0-9][A-Za-z0-9-]*)+$'
5648
6022
  },
5649
6023
  incomeAccount: {
5650
6024
  type: 'string',
5651
6025
  description: 'Default income account (optional)',
5652
6026
  example: 'Income:Unknown',
5653
- pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
6027
+ pattern:
6028
+ '^(Assets|Liabilities|Income|Expenses|Equity)(:[A-Za-z0-9][A-Za-z0-9-]*)+$'
5654
6029
  },
5655
6030
  methodAccountMapping: {
5656
6031
  type: 'object',
@@ -5707,12 +6082,14 @@ export const $ProviderSyncConfigDto = {
5707
6082
  },
5708
6083
  defaultExpenseAccount: {
5709
6084
  type: 'string',
5710
- description: 'Default expense account for the second posting',
6085
+ description:
6086
+ 'Default expense account for the second posting. Omit when no real default exists; the pipeline routes to Review via the Uncategorized sentinel (#618).',
5711
6087
  example: 'Expenses:Unknown'
5712
6088
  },
5713
6089
  defaultIncomeAccount: {
5714
6090
  type: 'string',
5715
- description: 'Default income account for the second posting',
6091
+ description:
6092
+ 'Default income account for the second posting. Omit when no real default exists; the pipeline routes to Review via the Uncategorized sentinel (#618).',
5716
6093
  example: 'Income:Unknown'
5717
6094
  },
5718
6095
  filterPending: {
@@ -5727,12 +6104,7 @@ export const $ProviderSyncConfigDto = {
5727
6104
  example: 'acc_gocardless_001'
5728
6105
  }
5729
6106
  },
5730
- required: [
5731
- 'sourceAccount',
5732
- 'defaultCurrency',
5733
- 'defaultExpenseAccount',
5734
- 'defaultIncomeAccount'
5735
- ]
6107
+ required: ['sourceAccount', 'defaultCurrency']
5736
6108
  } as const;
5737
6109
 
5738
6110
  export const $ProviderSyncDto = {
@@ -5942,15 +6314,105 @@ export const $UncoveredFormatMissDto = {
5942
6314
  properties: {}
5943
6315
  } as const;
5944
6316
 
6317
+ export const $ClientParsedDataDto = {
6318
+ type: 'object',
6319
+ properties: {
6320
+ amount: {
6321
+ type: 'number',
6322
+ description: 'Transaction amount',
6323
+ example: 35
6324
+ },
6325
+ currency: {
6326
+ type: 'string',
6327
+ description: 'Currency code',
6328
+ example: 'CNY'
6329
+ },
6330
+ date: {
6331
+ type: 'string',
6332
+ description: 'Transaction date (ISO 8601)',
6333
+ example: '2026-08-15'
6334
+ },
6335
+ payee: {
6336
+ type: 'string',
6337
+ description: 'Payee/merchant name',
6338
+ example: 'Starbucks'
6339
+ },
6340
+ narration: {
6341
+ type: 'string',
6342
+ description: 'Transaction narration'
6343
+ },
6344
+ category: {
6345
+ type: 'string',
6346
+ description: 'Category slug',
6347
+ example: 'food_restaurant'
6348
+ },
6349
+ incomeType: {
6350
+ type: 'string',
6351
+ description: 'Income type',
6352
+ example: 'Salary'
6353
+ },
6354
+ incomeSource: {
6355
+ type: 'string',
6356
+ description: 'Income source',
6357
+ example: 'Anthropic Inc.'
6358
+ },
6359
+ symbol: {
6360
+ type: 'string',
6361
+ description: 'Security symbol code (e.g., 600519, AAPL)',
6362
+ example: 'AAPL'
6363
+ },
6364
+ quantity: {
6365
+ type: 'number',
6366
+ description: 'Quantity of shares/units',
6367
+ example: 100
6368
+ },
6369
+ price: {
6370
+ type: 'number',
6371
+ description: 'Unit price per share/unit',
6372
+ example: 1900
6373
+ },
6374
+ investmentAction: {
6375
+ type: 'string',
6376
+ description: 'Investment action',
6377
+ enum: ['buy', 'sell'],
6378
+ example: 'buy'
6379
+ },
6380
+ paymentSource: {
6381
+ type: 'string',
6382
+ description: 'Payment source: asset (default) or liability (credit card)',
6383
+ enum: ['asset', 'liability'],
6384
+ example: 'asset'
6385
+ },
6386
+ liabilityHint: {
6387
+ type: 'string',
6388
+ description: 'Liability account hint (CreditCard/Huabei/Baitiao)',
6389
+ example: 'CreditCard'
6390
+ },
6391
+ warning: {
6392
+ type: 'string',
6393
+ description:
6394
+ 'Display-only warning from the prior response; accepted but ignored.',
6395
+ example: 'Cross-currency settlement applies.'
6396
+ }
6397
+ }
6398
+ } as const;
6399
+
5945
6400
  export const $ProcessNlpDto = {
5946
6401
  type: 'object',
5947
6402
  properties: {
5948
6403
  message: {
5949
6404
  type: 'string',
5950
- description: 'Natural language text describing a transaction (Chinese)',
5951
- example: 'yesterday Starbucks spent 35 yuan',
6405
+ description:
6406
+ 'Natural language text describing a transaction. Optional when `confirm` is true (structured confirm); otherwise required.',
6407
+ example: 'Starbucks 35',
5952
6408
  maxLength: 500
5953
6409
  },
6410
+ confirm: {
6411
+ type: 'boolean',
6412
+ description:
6413
+ 'Structured confirm signal — bypasses NL confirm-word matching when true. Send parsedData field edits alongside. The NL word-list path is the fallback.',
6414
+ example: true
6415
+ },
5954
6416
  sessionId: {
5955
6417
  type: 'string',
5956
6418
  description:
@@ -5958,14 +6420,18 @@ export const $ProcessNlpDto = {
5958
6420
  example: 'session_abc123'
5959
6421
  },
5960
6422
  parsedData: {
5961
- type: 'object',
5962
6423
  description:
5963
6424
  'Parsed data from previous NLP response for session recovery. Send back the parsedData received in confirm_payee/confirm responses.',
5964
6425
  example: {
5965
6426
  amount: 35,
5966
6427
  currency: 'CNY',
5967
6428
  payee: 'Starbucks'
5968
- }
6429
+ },
6430
+ allOf: [
6431
+ {
6432
+ $ref: '#/components/schemas/ClientParsedDataDto'
6433
+ }
6434
+ ]
5969
6435
  },
5970
6436
  selectedRuleId: {
5971
6437
  type: 'string',
@@ -5976,11 +6442,29 @@ export const $ProcessNlpDto = {
5976
6442
  selectedAccount: {
5977
6443
  type: 'string',
5978
6444
  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.',
6445
+ 'confirm_account echo-back: account path selected from the prior confirm_account response (suggestedAccount, similarAccounts[i].path, or a typed path). Applied directly when the session is confirming_account — no NL re-parse.',
5980
6446
  example: 'Expenses:Food:Coffee'
6447
+ },
6448
+ viewpointAccount: {
6449
+ type: 'string',
6450
+ description:
6451
+ 'Viewpoint account hint: the beancount path the user drilled into (e.g. from an account drill-down). Tie-break only — never overrides accounts resolved from the text. Must be an owned, OPEN Assets:/Liabilities: account; unresolvable hints are silently ignored.',
6452
+ example: 'Assets:CN:Bank:ICBC'
6453
+ },
6454
+ viewpointCategory: {
6455
+ type: 'string',
6456
+ description:
6457
+ "Viewpoint category hint: the ADR-0075 Group segment the user drilled into (e.g. 'Food'). Resolved to a concrete OPEN account in that group; tie-break only — never overrides a category resolved from the text.",
6458
+ example: 'Food'
6459
+ },
6460
+ viewpointFlow: {
6461
+ type: 'string',
6462
+ description:
6463
+ "Companion flow root for viewpointCategory ('income' | 'expense'), mirroring the ADR-0126 list-endpoint invariant. Derived from the session's routed intent (multi-turn) when absent; a first-turn flow-less category hint is dropped — send the flow explicitly.",
6464
+ enum: ['income', 'expense'],
6465
+ example: 'expense'
5981
6466
  }
5982
- },
5983
- required: ['message']
6467
+ }
5984
6468
  } as const;
5985
6469
 
5986
6470
  export const $NlpTransactionInfoDto = {
@@ -6292,6 +6776,24 @@ export const $NlpRuleConfirmationDataDto = {
6292
6776
  ]
6293
6777
  } as const;
6294
6778
 
6779
+ export const $NlpAccountCandidateDto = {
6780
+ type: 'object',
6781
+ properties: {
6782
+ path: {
6783
+ type: 'string',
6784
+ description: 'Canonical beancount account path (echo back on selection)',
6785
+ example: 'Expenses:Food:Dining'
6786
+ },
6787
+ name: {
6788
+ type: 'string',
6789
+ description:
6790
+ 'Localized display name (ADR-0114 read-time projection, user locale)',
6791
+ example: '餐饮'
6792
+ }
6793
+ },
6794
+ required: ['path', 'name']
6795
+ } as const;
6796
+
6295
6797
  export const $NlpAccountConfirmationDataDto = {
6296
6798
  type: 'object',
6297
6799
  properties: {
@@ -6307,10 +6809,11 @@ export const $NlpAccountConfirmationDataDto = {
6307
6809
  example: 'Expenses:Food:Drinks'
6308
6810
  },
6309
6811
  similarAccounts: {
6310
- description: 'Similar accounts for user selection',
6812
+ description:
6813
+ 'Similar accounts for user selection (path + localized name, #680)',
6311
6814
  type: 'array',
6312
6815
  items: {
6313
- type: 'string'
6816
+ $ref: '#/components/schemas/NlpAccountCandidateDto'
6314
6817
  }
6315
6818
  },
6316
6819
  errorMessage: {
@@ -6497,7 +7000,8 @@ export const $NlpSuggestedAccountDto = {
6497
7000
  },
6498
7001
  confidence: {
6499
7002
  type: 'number',
6500
- description: 'Confidence score for this suggestion (0-1)',
7003
+ description:
7004
+ 'Confidence score for this suggestion (0-1). Present = predicted (confirm/confirm_rule/confirm_account); omitted = actual persisted account (created). (#586)',
6501
7005
  example: 0.9
6502
7006
  }
6503
7007
  },
@@ -6533,23 +7037,31 @@ export const $NlpDefaultAccountsDto = {
6533
7037
  properties: {
6534
7038
  asset: {
6535
7039
  type: 'string',
6536
- description: 'Default asset account',
6537
- example: 'Assets:Checking'
7040
+ description:
7041
+ 'Default OPEN asset account (MRU when multiple), or null when none/ambiguous',
7042
+ example: 'Assets:Checking',
7043
+ nullable: true
6538
7044
  },
6539
7045
  expense: {
6540
7046
  type: 'string',
6541
- description: 'Default expense account',
6542
- example: 'Expenses:Uncategorized'
7047
+ description:
7048
+ 'Default OPEN expense account (MRU when multiple), or null when none/ambiguous',
7049
+ example: 'Expenses:Food:Coffee',
7050
+ nullable: true
6543
7051
  },
6544
7052
  income: {
6545
7053
  type: 'string',
6546
- description: 'Default income account',
6547
- example: 'Income:Uncategorized'
7054
+ description:
7055
+ 'Default OPEN income account (MRU when multiple), or null when none/ambiguous',
7056
+ example: 'Income:Salary',
7057
+ nullable: true
6548
7058
  },
6549
7059
  liability: {
6550
7060
  type: 'string',
6551
- description: 'Default liability account',
6552
- example: 'Liabilities:CreditCard'
7061
+ description:
7062
+ 'Default OPEN liability account (MRU when multiple), or null when none/ambiguous',
7063
+ example: 'Liabilities:CreditCard',
7064
+ nullable: true
6553
7065
  }
6554
7066
  },
6555
7067
  required: ['asset', 'expense', 'income', 'liability']
@@ -6589,7 +7101,7 @@ export const $NlpResponseDto = {
6589
7101
  type: 'string',
6590
7102
  description:
6591
7103
  'Asset sub-type (only present when intent is "asset"). Determines which asset-related form to render.',
6592
- enum: ['transfer', 'banking', 'investment'],
7104
+ enum: ['transfer', 'banking', 'investment', 'lend', 'lend_collect'],
6593
7105
  example: 'investment'
6594
7106
  },
6595
7107
  liabilitySubType: {
@@ -6737,7 +7249,7 @@ export const $NlpResponseDto = {
6737
7249
  },
6738
7250
  suggestedAccounts: {
6739
7251
  description:
6740
- 'Suggested accounts for this transaction. Contains recommended source and destination accounts based on the detected intent and rules.',
7252
+ 'Suggested accounts for this transaction (#586). confirm/confirm_rule/confirm_account: predicted (source/destination carry confidence); created: actual persisted accounts (confidence omitted). confirm_account destination is the suggested replacement, never the invalid account.',
6741
7253
  allOf: [
6742
7254
  {
6743
7255
  $ref: '#/components/schemas/NlpSuggestedAccountsDto'
@@ -6746,7 +7258,7 @@ export const $NlpResponseDto = {
6746
7258
  },
6747
7259
  defaultAccounts: {
6748
7260
  description:
6749
- 'Default accounts for the user/region. These are fallback accounts used when no specific suggestion is available.',
7261
+ 'Default fallback accounts for the user/region (#586). v1 returns universal constants; per-user personalization is planned.',
6750
7262
  allOf: [
6751
7263
  {
6752
7264
  $ref: '#/components/schemas/NlpDefaultAccountsDto'
@@ -6792,13 +7304,26 @@ export const $PlatformListItemDto = {
6792
7304
  suggestedSegment: {
6793
7305
  type: 'string',
6794
7306
  description:
6795
- 'Suggested path segment — canonical with first char uppercased (ACC_COMP_NAME_RE)'
7307
+ 'Suggested path segment — canonical PascalCased per hyphen-part, hyphens preserved (e.g. "Apple-Pay")'
6796
7308
  },
6797
7309
  logoUrl: {
6798
7310
  type: 'string',
6799
7311
  description: 'Logo URL',
6800
7312
  nullable: true
6801
7313
  },
7314
+ countryCode: {
7315
+ type: 'string',
7316
+ description: 'ISO 3166-1 alpha-2 (UPPERCASE); null = global platform',
7317
+ example: 'CN',
7318
+ nullable: true
7319
+ },
7320
+ category: {
7321
+ type: 'string',
7322
+ description:
7323
+ 'Region-aware category (institution vocab, e.g. DigitalWallet/Bank). null = no region-aware suggestion; fall back to type.',
7324
+ nullable: true,
7325
+ example: 'DigitalWallet'
7326
+ },
6802
7327
  isBound: {
6803
7328
  type: 'boolean',
6804
7329
  description: 'Whether user has accounts using this platform'
@@ -6812,6 +7337,8 @@ export const $PlatformListItemDto = {
6812
7337
  'canonical',
6813
7338
  'suggestedSegment',
6814
7339
  'logoUrl',
7340
+ 'countryCode',
7341
+ 'category',
6815
7342
  'isBound'
6816
7343
  ]
6817
7344
  } as const;
@@ -6847,13 +7374,26 @@ export const $PlatformMatchResultDto = {
6847
7374
  suggestedSegment: {
6848
7375
  type: 'string',
6849
7376
  description:
6850
- 'Suggested path segment — canonical, already in ACCOUNT_RE format'
7377
+ 'Suggested path segment — canonical PascalCased per hyphen-part, hyphens preserved (e.g. "Apple-Pay")'
6851
7378
  },
6852
7379
  logoUrl: {
6853
7380
  type: 'string',
6854
7381
  description: 'Logo URL',
6855
7382
  nullable: true
6856
7383
  },
7384
+ countryCode: {
7385
+ type: 'string',
7386
+ description: 'ISO 3166-1 alpha-2 (UPPERCASE); null = global platform',
7387
+ example: 'CN',
7388
+ nullable: true
7389
+ },
7390
+ category: {
7391
+ type: 'string',
7392
+ description:
7393
+ 'Region-aware category (institution vocab, e.g. DigitalWallet/Bank). null = no region-aware suggestion; fall back to type.',
7394
+ nullable: true,
7395
+ example: 'DigitalWallet'
7396
+ },
6857
7397
  matchType: {
6858
7398
  type: 'string',
6859
7399
  description: "How this row matched: 'exact' > 'prefix' > 'substring'",
@@ -6867,6 +7407,8 @@ export const $PlatformMatchResultDto = {
6867
7407
  'type',
6868
7408
  'suggestedSegment',
6869
7409
  'logoUrl',
7410
+ 'countryCode',
7411
+ 'category',
6870
7412
  'matchType'
6871
7413
  ]
6872
7414
  } as const;
@@ -6896,7 +7438,80 @@ export const $PlatformMatchResponseDto = {
6896
7438
  description: 'true when total > platforms.length (more matches exist)'
6897
7439
  }
6898
7440
  },
6899
- required: ['platforms', 'matchType', 'total', 'hasMore']
7441
+ required: ['platforms', 'matchType', 'total', 'hasMore']
7442
+ } as const;
7443
+
7444
+ export const $PlatformStandardsPlatformDto = {
7445
+ type: 'object',
7446
+ properties: {
7447
+ id: {
7448
+ type: 'string',
7449
+ description: 'Global platform ID'
7450
+ },
7451
+ name: {
7452
+ type: 'string',
7453
+ description: 'Platform name (e.g., "ICBC")'
7454
+ },
7455
+ canonical: {
7456
+ type: 'string',
7457
+ description: 'Canonical identifier in ACCOUNT_RE format (e.g., "icbc")'
7458
+ },
7459
+ suggestedSegment: {
7460
+ type: 'string',
7461
+ description:
7462
+ 'Suggested path segment — canonical PascalCased per hyphen-part, hyphens preserved (e.g. "Apple-Pay")'
7463
+ },
7464
+ type: {
7465
+ type: 'string',
7466
+ description: 'Platform type',
7467
+ enum: [
7468
+ 'BANK',
7469
+ 'BROKERAGE',
7470
+ 'CRYPTO_EXCHANGE',
7471
+ 'PAYMENT',
7472
+ 'INVESTMENT',
7473
+ 'INSURANCE',
7474
+ 'OTHER'
7475
+ ]
7476
+ },
7477
+ category: {
7478
+ type: 'string',
7479
+ description:
7480
+ 'Region-aware category (institution vocab, e.g. DigitalWallet/Bank) resolved against the final region. null = no region-aware suggestion; fall back to type.',
7481
+ nullable: true,
7482
+ example: 'Bank'
7483
+ }
7484
+ },
7485
+ required: ['id', 'name', 'canonical', 'suggestedSegment', 'type', 'category']
7486
+ } as const;
7487
+
7488
+ export const $PlatformStandardsResponseDto = {
7489
+ type: 'object',
7490
+ properties: {
7491
+ platform: {
7492
+ description: 'The selected platform (institution lock source)',
7493
+ allOf: [
7494
+ {
7495
+ $ref: '#/components/schemas/PlatformStandardsPlatformDto'
7496
+ }
7497
+ ]
7498
+ },
7499
+ region: {
7500
+ type: 'string',
7501
+ description:
7502
+ "Resolved template region (ISO 3166-1 alpha-2, UPPERCASE): the platform's own countryCode when set, else the region query param. For regions without a regional template file the template list falls back to the universal-only catalog while region still echoes the code.",
7503
+ example: 'CN'
7504
+ },
7505
+ templates: {
7506
+ description:
7507
+ 'Candidate account-standard templates of the resolved region (groupable by productCategory client-side)',
7508
+ type: 'array',
7509
+ items: {
7510
+ $ref: '#/components/schemas/AccountStandardResponseDto'
7511
+ }
7512
+ }
7513
+ },
7514
+ required: ['platform', 'region', 'templates']
6900
7515
  } as const;
6901
7516
 
6902
7517
  export const $CreatePlatformDto = {
@@ -7000,7 +7615,8 @@ export const $UpdatePlatformDto = {
7000
7615
  },
7001
7616
  isActive: {
7002
7617
  type: 'boolean',
7003
- description: 'Whether the platform is active'
7618
+ description: 'Whether the platform is active',
7619
+ default: true
7004
7620
  }
7005
7621
  }
7006
7622
  } as const;
@@ -7163,7 +7779,8 @@ export const $AccountItemDto = {
7163
7779
  },
7164
7780
  displayName: {
7165
7781
  type: 'string',
7166
- description: 'Display name (last part of account path)',
7782
+ description:
7783
+ 'Display name: user-set name if provided (#762), else last part of account path',
7167
7784
  example: 'Savings'
7168
7785
  },
7169
7786
  balance: {
@@ -7199,7 +7816,8 @@ export const $PlatformGroupDto = {
7199
7816
  example: 'CMB Bank'
7200
7817
  },
7201
7818
  accounts: {
7202
- description: 'Accounts within this platform',
7819
+ description:
7820
+ 'Accounts within this platform (Assets and Liabilities rows, #696)',
7203
7821
  type: 'array',
7204
7822
  items: {
7205
7823
  $ref: '#/components/schemas/AccountItemDto'
@@ -7207,7 +7825,8 @@ export const $PlatformGroupDto = {
7207
7825
  },
7208
7826
  totalBalance: {
7209
7827
  type: 'string',
7210
- description: 'FX-converted total balance in base currency',
7828
+ description:
7829
+ 'FX-converted total balance in base currency (nets Assets + Liabilities rows; can be negative)',
7211
7830
  example: '100000.00'
7212
7831
  },
7213
7832
  balanceByCurrency: {
@@ -7226,7 +7845,7 @@ export const $PlatformGroupDto = {
7226
7845
  sharePct: {
7227
7846
  type: 'number',
7228
7847
  description:
7229
- 'Share of the grand converted total (0-100); 0 when grand total is 0',
7848
+ 'Share of the converted asset-side grand total (0-100); liability balances are excluded from the basis; 0 when grand total is 0 (#696)',
7230
7849
  example: 42.5
7231
7850
  }
7232
7851
  },
@@ -7274,7 +7893,8 @@ export const $AccountsSummaryDto = {
7274
7893
  properties: {
7275
7894
  totalAccounts: {
7276
7895
  type: 'number',
7277
- description: 'Total number of accounts'
7896
+ description:
7897
+ 'Total number of accounts (balance sheet: Assets + Liabilities, #696)'
7278
7898
  },
7279
7899
  totalPlatforms: {
7280
7900
  type: 'number',
@@ -7332,7 +7952,8 @@ export const $AccountItemWithAssetClassDto = {
7332
7952
  },
7333
7953
  displayName: {
7334
7954
  type: 'string',
7335
- description: 'Display name (last part of account path)',
7955
+ description:
7956
+ 'Display name: user-set name if provided (#762), else last part of account path',
7336
7957
  example: 'Savings'
7337
7958
  },
7338
7959
  balance: {
@@ -7818,7 +8439,7 @@ export const $MonetaryDto = {
7818
8439
  example: 'USD'
7819
8440
  },
7820
8441
  baseCcyEquivalent: {
7821
- type: 'object',
8442
+ type: 'string',
7822
8443
  description: 'Converted to user base currency (Decimal string)',
7823
8444
  example: '21600',
7824
8445
  nullable: true
@@ -7894,13 +8515,13 @@ export const $HoldingPnlRowDto = {
7894
8515
  example: 'Assets:US:Broker:AAPL'
7895
8516
  },
7896
8517
  accountCcy: {
7897
- type: 'object',
8518
+ type: 'string',
7898
8519
  description: 'Account settlement currency (ISO 4217), from cost currency',
7899
8520
  nullable: true,
7900
8521
  example: 'USD'
7901
8522
  },
7902
8523
  brokerType: {
7903
- type: 'object',
8524
+ type: 'string',
7904
8525
  description: 'Broker type derived from Platform.type',
7905
8526
  nullable: true,
7906
8527
  example: 'broker'
@@ -7921,7 +8542,7 @@ export const $HoldingPnlRowDto = {
7921
8542
  example: 'EQUITY'
7922
8543
  },
7923
8544
  assetSubClass: {
7924
- type: 'object',
8545
+ type: 'string',
7925
8546
  nullable: true,
7926
8547
  example: 'STOCK'
7927
8548
  },
@@ -7968,14 +8589,14 @@ export const $HoldingPnlRowDto = {
7968
8589
  ]
7969
8590
  },
7970
8591
  unrealizedPnlBase: {
7971
- type: 'object',
8592
+ type: 'string',
7972
8593
  description:
7973
8594
  'Unrealized P&L in base currency (Decimal string); null when any FX/price missing',
7974
8595
  nullable: true,
7975
8596
  example: '6000'
7976
8597
  },
7977
8598
  unrealizedPnlPct: {
7978
- type: 'object',
8599
+ type: 'string',
7979
8600
  description: 'Unrealized P&L % (Decimal string)',
7980
8601
  nullable: true,
7981
8602
  example: '25'
@@ -7999,7 +8620,7 @@ export const $HoldingPnlRowDto = {
7999
8620
  ]
8000
8621
  },
8001
8622
  pctOfInvestedAssets: {
8002
- type: 'object',
8623
+ type: 'string',
8003
8624
  description:
8004
8625
  'Share of invested assets % (Decimal string); only for invested chartTokens',
8005
8626
  nullable: true,
@@ -8044,15 +8665,15 @@ export const $HoldingPnlWarningDto = {
8044
8665
  ]
8045
8666
  },
8046
8667
  symbol: {
8047
- type: 'object',
8668
+ type: 'string',
8048
8669
  nullable: true
8049
8670
  },
8050
8671
  accountId: {
8051
- type: 'object',
8672
+ type: 'string',
8052
8673
  nullable: true
8053
8674
  },
8054
8675
  currency: {
8055
- type: 'object',
8676
+ type: 'string',
8056
8677
  nullable: true
8057
8678
  }
8058
8679
  },
@@ -8115,3 +8736,356 @@ export const $AnonymousLoginResponseDto = {
8115
8736
  },
8116
8737
  required: ['authToken']
8117
8738
  } as const;
8739
+
8740
+ export const $ParserContributionMetaDto = {
8741
+ type: 'object',
8742
+ properties: {
8743
+ institution: {
8744
+ type: 'string',
8745
+ description: 'Institution slug (lowercase kebab-case)',
8746
+ pattern: '^[a-z0-9]+(-[a-z0-9]+)*$',
8747
+ example: 'icbc'
8748
+ },
8749
+ region: {
8750
+ type: 'string',
8751
+ enum: [
8752
+ 'cn',
8753
+ 'us',
8754
+ 'de',
8755
+ 'fr',
8756
+ 'gb',
8757
+ 'hk',
8758
+ 'jp',
8759
+ 'sg',
8760
+ 'au',
8761
+ 'ca',
8762
+ 'other'
8763
+ ]
8764
+ },
8765
+ accountType: {
8766
+ type: 'string',
8767
+ enum: ['checking', 'savings', 'credit', 'debit', 'investment']
8768
+ },
8769
+ format: {
8770
+ type: 'string',
8771
+ enum: ['csv', 'xlsx', 'pdf', 'ofx', 'qif']
8772
+ },
8773
+ institutionDisplayName: {
8774
+ type: 'string',
8775
+ example: '中国工商银行'
8776
+ },
8777
+ encoding: {
8778
+ type: 'string',
8779
+ example: 'utf-8'
8780
+ },
8781
+ delimiter: {
8782
+ type: 'string',
8783
+ description: 'CSV delimiter character: ",", ";", "\\t" or "|"'
8784
+ },
8785
+ headerRows: {
8786
+ type: 'number',
8787
+ default: 1,
8788
+ description: 'Header row count; the client omits the field when it is 1'
8789
+ },
8790
+ notes: {
8791
+ type: 'string',
8792
+ maxLength: 2000
8793
+ }
8794
+ },
8795
+ required: ['institution', 'region', 'accountType', 'format']
8796
+ } as const;
8797
+
8798
+ export const $ParserContributionSamplesDto = {
8799
+ type: 'object',
8800
+ properties: {
8801
+ rows: {
8802
+ description:
8803
+ 'Client-sanitized sample rows (key = column name, value = cell)',
8804
+ type: 'array',
8805
+ items: {
8806
+ type: 'object'
8807
+ }
8808
+ },
8809
+ rawHeaders: {
8810
+ type: 'array',
8811
+ items: {
8812
+ type: 'string'
8813
+ }
8814
+ }
8815
+ },
8816
+ required: ['rows']
8817
+ } as const;
8818
+
8819
+ export const $FieldHintDto = {
8820
+ type: 'object',
8821
+ properties: {
8822
+ columnName: {
8823
+ type: 'string',
8824
+ example: '交易日期'
8825
+ },
8826
+ format: {
8827
+ type: 'string',
8828
+ description: 'Date format, e.g. yyyy-MM-dd HH:mm',
8829
+ example: 'yyyy-MM-dd'
8830
+ },
8831
+ signConvention: {
8832
+ type: 'string',
8833
+ enum: ['negative-expense', 'positive-expense', 'separate-columns']
8834
+ },
8835
+ creditColumn: {
8836
+ type: 'string'
8837
+ },
8838
+ debitColumn: {
8839
+ type: 'string'
8840
+ }
8841
+ },
8842
+ required: ['columnName']
8843
+ } as const;
8844
+
8845
+ export const $ParserContributionFieldHintsDto = {
8846
+ type: 'object',
8847
+ properties: {
8848
+ date: {
8849
+ $ref: '#/components/schemas/FieldHintDto'
8850
+ },
8851
+ amount: {
8852
+ $ref: '#/components/schemas/FieldHintDto'
8853
+ },
8854
+ description: {
8855
+ $ref: '#/components/schemas/FieldHintDto'
8856
+ },
8857
+ balance: {
8858
+ $ref: '#/components/schemas/FieldHintDto'
8859
+ },
8860
+ payee: {
8861
+ $ref: '#/components/schemas/FieldHintDto'
8862
+ },
8863
+ reference: {
8864
+ $ref: '#/components/schemas/FieldHintDto'
8865
+ },
8866
+ category: {
8867
+ $ref: '#/components/schemas/FieldHintDto'
8868
+ }
8869
+ },
8870
+ required: ['date', 'amount']
8871
+ } as const;
8872
+
8873
+ export const $ExpectedTransactionDto = {
8874
+ type: 'object',
8875
+ properties: {
8876
+ date: {
8877
+ type: 'string',
8878
+ example: '2026-08-01'
8879
+ },
8880
+ amount: {
8881
+ type: 'number',
8882
+ example: -45.5
8883
+ },
8884
+ description: {
8885
+ type: 'string',
8886
+ example: '星巴克-***店'
8887
+ },
8888
+ payee: {
8889
+ type: 'string'
8890
+ },
8891
+ category: {
8892
+ type: 'string'
8893
+ }
8894
+ },
8895
+ required: ['date', 'amount', 'description']
8896
+ } as const;
8897
+
8898
+ export const $ParserContributionExamplesDto = {
8899
+ type: 'object',
8900
+ properties: {
8901
+ expectedTransactions: {
8902
+ type: 'array',
8903
+ items: {
8904
+ $ref: '#/components/schemas/ExpectedTransactionDto'
8905
+ }
8906
+ }
8907
+ },
8908
+ required: ['expectedTransactions']
8909
+ } as const;
8910
+
8911
+ export const $ParserContributionRequestDto = {
8912
+ type: 'object',
8913
+ properties: {
8914
+ meta: {
8915
+ $ref: '#/components/schemas/ParserContributionMetaDto'
8916
+ },
8917
+ samples: {
8918
+ $ref: '#/components/schemas/ParserContributionSamplesDto'
8919
+ },
8920
+ fieldHints: {
8921
+ $ref: '#/components/schemas/ParserContributionFieldHintsDto'
8922
+ },
8923
+ examples: {
8924
+ description: 'Omitted entirely by the client when empty',
8925
+ allOf: [
8926
+ {
8927
+ $ref: '#/components/schemas/ParserContributionExamplesDto'
8928
+ }
8929
+ ]
8930
+ }
8931
+ },
8932
+ required: ['meta', 'samples', 'fieldHints']
8933
+ } as const;
8934
+
8935
+ export const $ParserContributionRelayResponseDto = {
8936
+ type: 'object',
8937
+ properties: {
8938
+ issueUrl: {
8939
+ type: 'string',
8940
+ example: 'https://github.com/fire-zu/firela-vlt/issues/42'
8941
+ },
8942
+ issueNumber: {
8943
+ type: 'number',
8944
+ example: 42
8945
+ }
8946
+ },
8947
+ required: ['issueUrl', 'issueNumber']
8948
+ } as const;
8949
+
8950
+ export const $SymbolSearchResultDto = {
8951
+ type: 'object',
8952
+ properties: {
8953
+ symbol: {
8954
+ type: 'string',
8955
+ example: 'AAPL'
8956
+ },
8957
+ name: {
8958
+ type: 'string',
8959
+ example: 'Apple Inc.',
8960
+ nullable: true
8961
+ },
8962
+ exchange: {
8963
+ type: 'string',
8964
+ example: 'US',
8965
+ nullable: true
8966
+ },
8967
+ assetType: {
8968
+ type: 'string',
8969
+ description: 'OpenBB asset_type (e.g. stock, etf)',
8970
+ example: 'stock',
8971
+ nullable: true
8972
+ },
8973
+ assetClass: {
8974
+ type: 'string',
8975
+ description: 'IGN asset class (region.types.ts ASSET_CLASSES)',
8976
+ example: 'EQUITY',
8977
+ nullable: true
8978
+ },
8979
+ assetSubClass: {
8980
+ type: 'string',
8981
+ description: 'IGN asset sub-class (region.types.ts ASSET_SUB_CLASSES)',
8982
+ example: 'STOCK',
8983
+ nullable: true
8984
+ },
8985
+ currency: {
8986
+ type: 'string',
8987
+ description: 'Trading currency (extra_data or inferred from exchange)',
8988
+ example: 'USD',
8989
+ nullable: true
8990
+ }
8991
+ },
8992
+ required: ['symbol']
8993
+ } as const;
8994
+
8995
+ export const $SymbolQuoteDto = {
8996
+ type: 'object',
8997
+ properties: {
8998
+ symbol: {
8999
+ type: 'string',
9000
+ example: 'AAPL'
9001
+ },
9002
+ name: {
9003
+ type: 'string',
9004
+ example: 'Apple Inc.',
9005
+ nullable: true
9006
+ },
9007
+ exchange: {
9008
+ type: 'string',
9009
+ example: 'US',
9010
+ nullable: true
9011
+ },
9012
+ assetType: {
9013
+ type: 'string',
9014
+ description: 'OpenBB asset_type',
9015
+ example: 'stock',
9016
+ nullable: true
9017
+ },
9018
+ assetClass: {
9019
+ type: 'string',
9020
+ description: 'IGN asset class',
9021
+ example: 'EQUITY',
9022
+ nullable: true
9023
+ },
9024
+ assetSubClass: {
9025
+ type: 'string',
9026
+ description: 'IGN asset sub-class',
9027
+ example: 'STOCK',
9028
+ nullable: true
9029
+ },
9030
+ currency: {
9031
+ type: 'string',
9032
+ description: 'Trading currency (extra_data or inferred from exchange)',
9033
+ example: 'USD',
9034
+ nullable: true
9035
+ },
9036
+ price: {
9037
+ type: 'string',
9038
+ description: 'Latest price (Decimal string)',
9039
+ example: '189.84',
9040
+ nullable: true
9041
+ },
9042
+ priceDate: {
9043
+ type: 'string',
9044
+ description: 'Date the price was observed (ISO yyyy-MM-dd)',
9045
+ example: '2026-08-05',
9046
+ nullable: true
9047
+ },
9048
+ changePercent: {
9049
+ type: 'number',
9050
+ description:
9051
+ 'Change vs previous close, in percentage points (1.7 == 1.7%). openbb stores change_percent as a normalized decimal; this exposes percentage points for frontend convenience.',
9052
+ example: 1.7,
9053
+ nullable: true
9054
+ },
9055
+ prevClose: {
9056
+ type: 'string',
9057
+ description: 'Previous close (Decimal string)',
9058
+ nullable: true
9059
+ },
9060
+ open: {
9061
+ type: 'string',
9062
+ description: 'Day open (Decimal string)',
9063
+ nullable: true
9064
+ },
9065
+ high: {
9066
+ type: 'string',
9067
+ description: 'Day high (Decimal string)',
9068
+ nullable: true
9069
+ },
9070
+ low: {
9071
+ type: 'string',
9072
+ description: 'Day low (Decimal string)',
9073
+ nullable: true
9074
+ },
9075
+ volume: {
9076
+ type: 'string',
9077
+ description: 'Day volume (Decimal string)',
9078
+ nullable: true
9079
+ },
9080
+ yearHigh: {
9081
+ type: 'string',
9082
+ description: '52-week high (Decimal string)',
9083
+ nullable: true
9084
+ },
9085
+ yearLow: {
9086
+ type: 'string',
9087
+ description: '52-week low (Decimal string)',
9088
+ nullable: true
9089
+ }
9090
+ }
9091
+ } as const;