@firela/api-types 0.0.0-canary.92e8f8e1 → 0.0.0-canary.9b21c9cd

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.
@@ -377,16 +377,43 @@ export const $AccountStandardResponseDto = {
377
377
  },
378
378
  name: {
379
379
  type: 'string',
380
- description: 'Short localized display name',
380
+ description:
381
+ 'Short display name. Universal rows project to the request locale (Accept-Language); regional rows keep the authored native name — mixed-language by design (ADR-0131 class P vs class A).',
381
382
  example: 'Housing Fund'
382
383
  },
384
+ aliases: {
385
+ description:
386
+ 'Authored market-language alternative names delivered verbatim (not localized copy, not xlf-managed, not locale-projected). Flat string[] per ADR-0129 D1; ADR-0131 class A.',
387
+ example: ['Alipay', 'WeChat Pay'],
388
+ type: 'array',
389
+ items: {
390
+ type: 'string'
391
+ }
392
+ },
393
+ searchTerms: {
394
+ description:
395
+ 'Locale-projected search synonyms (e.g. the zh bank-card / debit-card everyday terms for the checking account). Pure-locale projection — absent when the locale has no seeded synonyms; English fallback rides the authored aliases field. Search-only vocabulary, not the NLP routing corpus (#698, ADR-0131 fourth-class adjudication).',
396
+ example: ['yinhangka', 'jiejika'],
397
+ type: 'array',
398
+ items: {
399
+ type: 'string'
400
+ }
401
+ },
402
+ currency: {
403
+ type: 'string',
404
+ description:
405
+ 'Product denomination as a 3-letter ISO 4217 code, authored market data delivered verbatim (not localized, not xlf-managed). ADR-0131 class A. Absent = single-currency not asserted — consumers fall back to their own region currency (#714).',
406
+ example: 'HKD'
407
+ },
383
408
  description: {
384
409
  type: 'string',
385
- description: 'Account description (stable semantics only)',
410
+ description:
411
+ 'Account description (stable semantics only). Mixed-language contract: universal rows project to the request locale via the accountDesc xlf axis with an en fallback (ADR-0131 class P, ADR-0132; unseeded locales falling back to English are expected); regional rows deliver the authored market language (ADR-0131 class A, verbatim, never xlf-managed).',
386
412
  example: 'ICBC checking account for daily transactions'
387
413
  },
388
414
  tags: {
389
- description: 'Account tags for categorization',
415
+ description:
416
+ 'Account tags for categorization — structured metadata delivered verbatim (not localized, not xlf-managed). ADR-0131 class A.',
390
417
  example: ['bank', 'checking', 'primary'],
391
418
  type: 'array',
392
419
  items: {
@@ -776,7 +803,7 @@ export const $PostingResponseDto = {
776
803
  units: {
777
804
  type: 'string',
778
805
  description:
779
- 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned.',
806
+ 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned. Carries the raw Beancount sign (credit-normal accounts such as Income post negative — the accounting truth, ADR-0126); renderers must not infer economic semantics from this sign.',
780
807
  example: '100.50'
781
808
  },
782
809
  currency: {
@@ -1142,7 +1169,7 @@ export const $PostingDetailDto = {
1142
1169
  units: {
1143
1170
  type: 'string',
1144
1171
  description:
1145
- 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned.',
1172
+ 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned. Carries the raw Beancount sign (credit-normal accounts such as Income post negative — the accounting truth, ADR-0126); renderers must not infer economic semantics from this sign.',
1146
1173
  example: '100.50'
1147
1174
  },
1148
1175
  currency: {
@@ -1326,6 +1353,147 @@ export const $TransactionDetailDto = {
1326
1353
  ]
1327
1354
  } as const;
1328
1355
 
1356
+ export const $TransactionListItemDto = {
1357
+ type: 'object',
1358
+ properties: {
1359
+ id: {
1360
+ type: 'string',
1361
+ description: 'Transaction ID',
1362
+ example: 'clh1234567890abcdef'
1363
+ },
1364
+ date: {
1365
+ type: 'string',
1366
+ description: 'Transaction date',
1367
+ example: '2024-11-28'
1368
+ },
1369
+ flag: {
1370
+ type: 'string',
1371
+ description: 'Transaction flag',
1372
+ enum: [
1373
+ 'CLEARED',
1374
+ 'PENDING',
1375
+ 'PADDING',
1376
+ 'SUMMARIZE',
1377
+ 'TRANSFER',
1378
+ 'CONVERSIONS'
1379
+ ],
1380
+ example: 'CLEARED'
1381
+ },
1382
+ customFlag: {
1383
+ type: 'string',
1384
+ description: 'Custom flag (if not using standard flags)',
1385
+ example: 'R'
1386
+ },
1387
+ payee: {
1388
+ type: 'string',
1389
+ description: 'Payee name',
1390
+ example: 'Whole Foods Market'
1391
+ },
1392
+ narration: {
1393
+ type: 'string',
1394
+ description: 'Transaction narration',
1395
+ example: 'Grocery shopping'
1396
+ },
1397
+ tags: {
1398
+ description: 'Transaction tags',
1399
+ example: ['groceries'],
1400
+ type: 'array',
1401
+ items: {
1402
+ type: 'string'
1403
+ }
1404
+ },
1405
+ links: {
1406
+ description: 'Transaction links',
1407
+ example: ['invoice-2024-001'],
1408
+ type: 'array',
1409
+ items: {
1410
+ type: 'string'
1411
+ }
1412
+ },
1413
+ meta: {
1414
+ type: 'object',
1415
+ description: 'Transaction metadata'
1416
+ },
1417
+ status: {
1418
+ type: 'string',
1419
+ description: 'Transaction status',
1420
+ enum: ['ACTIVE', 'VOIDED', 'SUPERSEDED'],
1421
+ example: 'ACTIVE'
1422
+ },
1423
+ sourceType: {
1424
+ type: 'string',
1425
+ description:
1426
+ 'Source type (free-form string from transaction metadata, e.g. import, api)'
1427
+ },
1428
+ sourcePlatform: {
1429
+ type: 'string',
1430
+ description: 'Source platform (e.g., alipay, wechat)',
1431
+ example: 'alipay'
1432
+ },
1433
+ postings: {
1434
+ description: 'Transaction postings',
1435
+ type: 'array',
1436
+ items: {
1437
+ $ref: '#/components/schemas/PostingDetailDto'
1438
+ }
1439
+ },
1440
+ createdAt: {
1441
+ type: 'string',
1442
+ description: 'Created at timestamp',
1443
+ example: '2024-11-28T10:30:00.000Z'
1444
+ },
1445
+ voidedAt: {
1446
+ type: 'string',
1447
+ description: 'Voided at timestamp (if voided)',
1448
+ example: '2024-11-29T15:00:00.000Z'
1449
+ },
1450
+ voidedBy: {
1451
+ type: 'string',
1452
+ description: 'User ID who voided this transaction',
1453
+ example: 'clh1234567890abcdef'
1454
+ },
1455
+ correctionReason: {
1456
+ type: 'string',
1457
+ description: 'Correction reason (if voided or superseded)',
1458
+ example: 'Duplicate entry'
1459
+ },
1460
+ supersededBy: {
1461
+ type: 'string',
1462
+ description:
1463
+ 'ID of the transaction that supersedes this one (set when status=SUPERSEDED)',
1464
+ example: 'clh1234567890abcdef'
1465
+ },
1466
+ originalTxn: {
1467
+ type: 'string',
1468
+ description:
1469
+ 'ID of the transaction this one corrected/replaced (back-link on the replacement)',
1470
+ example: 'clh1234567890abcdef'
1471
+ },
1472
+ viewpointAmount: {
1473
+ type: 'string',
1474
+ description:
1475
+ '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.',
1476
+ example: '10000.00'
1477
+ },
1478
+ viewpointCurrency: {
1479
+ type: 'string',
1480
+ description:
1481
+ 'Currency of viewpointAmount. A row spanning multiple currencies takes the largest-magnitude currency group (known simplification, ADR-0126).',
1482
+ example: 'CNY'
1483
+ }
1484
+ },
1485
+ required: [
1486
+ 'id',
1487
+ 'date',
1488
+ 'narration',
1489
+ 'tags',
1490
+ 'links',
1491
+ 'status',
1492
+ 'postings',
1493
+ 'createdAt'
1494
+ ]
1495
+ } as const;
1496
+
1329
1497
  export const $BalanceByCurrencyDto = {
1330
1498
  type: 'object',
1331
1499
  properties: {
@@ -1371,7 +1539,7 @@ export const $TransactionListSummaryDto = {
1371
1539
  totalAmount: {
1372
1540
  type: 'string',
1373
1541
  description:
1374
- 'Partial converted total in base currency (rated currencies only, raw Beancount sign). When warnings is non-empty this excludes currencies missing an FX rate; may be "0.00" if ALL non-base currencies lack a rate. Converted at the dateTo (or current) available rate.',
1542
+ 'Partial converted total in base currency (rated currencies only). Sign by viewpoint (ADR-0126): account viewpoint keeps the raw Beancount sign (income negative); category viewpoint is per-leg sign-normalized (Income legs negated, Expenses legs identity — positive under normal booking, not clamped). When warnings is non-empty this excludes currencies missing an FX rate; may be "0.00" if ALL non-base currencies lack a rate. Converted at the dateTo (or current) available rate.',
1375
1543
  example: '-6000.00'
1376
1544
  },
1377
1545
  currency: {
@@ -1397,6 +1565,26 @@ export const $TransactionListSummaryDto = {
1397
1565
  required: ['totalAmount', 'currency', 'balanceByCurrency']
1398
1566
  } as const;
1399
1567
 
1568
+ export const $TransactionListViewpointDto = {
1569
+ type: 'object',
1570
+ properties: {
1571
+ type: {
1572
+ type: 'string',
1573
+ description:
1574
+ 'Viewpoint type (only category drill-down carries a viewpoint today)',
1575
+ enum: ['category'],
1576
+ example: 'category'
1577
+ },
1578
+ flow: {
1579
+ type: 'string',
1580
+ description: 'Flow root the category account set is restricted to',
1581
+ enum: ['income', 'expense'],
1582
+ example: 'expense'
1583
+ }
1584
+ },
1585
+ required: ['type', 'flow']
1586
+ } as const;
1587
+
1400
1588
  export const $TransactionListResponseDto = {
1401
1589
  type: 'object',
1402
1590
  properties: {
@@ -1404,7 +1592,7 @@ export const $TransactionListResponseDto = {
1404
1592
  description: 'List of transactions',
1405
1593
  type: 'array',
1406
1594
  items: {
1407
- $ref: '#/components/schemas/TransactionDetailDto'
1595
+ $ref: '#/components/schemas/TransactionListItemDto'
1408
1596
  }
1409
1597
  },
1410
1598
  total: {
@@ -1430,6 +1618,15 @@ export const $TransactionListResponseDto = {
1430
1618
  $ref: '#/components/schemas/TransactionListSummaryDto'
1431
1619
  }
1432
1620
  ]
1621
+ },
1622
+ viewpoint: {
1623
+ description:
1624
+ '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).',
1625
+ allOf: [
1626
+ {
1627
+ $ref: '#/components/schemas/TransactionListViewpointDto'
1628
+ }
1629
+ ]
1433
1630
  }
1434
1631
  },
1435
1632
  required: ['data', 'total', 'limit', 'offset']
@@ -2340,10 +2537,10 @@ export const $UpdatePayeeDto = {
2340
2537
  meta: {
2341
2538
  type: 'object',
2342
2539
  description:
2343
- 'Metadata for extended information (location, notes, contact info, etc.). Will merge with existing metadata.',
2540
+ 'Metadata for extended information (location, notes, contact info, etc.)',
2344
2541
  example: {
2345
2542
  location: 'Zhongguancun',
2346
- note: 'Updated note',
2543
+ note: 'Near subway station',
2347
2544
  favorite: true
2348
2545
  }
2349
2546
  },
@@ -2904,1423 +3101,1423 @@ export const $UpdateCommodityDto = {
2904
3101
  }
2905
3102
  } as const;
2906
3103
 
2907
- export const $CreateBeanPriceDto = {
3104
+ export const $CurrencyBalanceDto = {
2908
3105
  type: 'object',
2909
3106
  properties: {
2910
3107
  currency: {
2911
3108
  type: 'string',
2912
- description: 'Currency being priced (e.g., USD, AAPL, BTC)',
2913
- example: 'USD'
2914
- },
2915
- quoteCurrency: {
2916
- type: 'string',
2917
- description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
3109
+ description: 'ISO 4217 currency code',
2918
3110
  example: 'CNY'
2919
3111
  },
2920
- amount: {
2921
- type: 'number',
2922
- description:
2923
- 'Price amount (MUST be >= 0 per Beancount spec, supports up to 15 decimal places). Zero allowed for conversion entries, negative strictly prohibited.',
2924
- example: 175.5,
2925
- minimum: 0
2926
- },
2927
- date: {
3112
+ balance: {
2928
3113
  type: 'string',
2929
- description: 'Price date (ISO 8601 format)',
2930
- example: '2024-11-05'
2931
- },
2932
- metadata: {
2933
- type: 'object',
2934
- description:
2935
- 'Metadata (validated by Zod schema, max field lengths enforced)',
2936
- example: {
2937
- source: 'MANUAL',
2938
- note: 'Bank valuation report',
2939
- confidence: 0.95
2940
- }
3114
+ description: 'Balance amount',
3115
+ example: '500000.00'
2941
3116
  }
2942
3117
  },
2943
- required: ['currency', 'quoteCurrency', 'amount', 'date']
3118
+ required: ['currency', 'balance']
2944
3119
  } as const;
2945
3120
 
2946
- export const $PriceResponseDto = {
3121
+ export const $TimeSeriesPointDto = {
2947
3122
  type: 'object',
2948
3123
  properties: {
2949
- id: {
3124
+ date: {
2950
3125
  type: 'string',
2951
- description: 'Unique identifier',
2952
- example: 'uuid-123-456'
3126
+ description: 'Date in YYYY-MM-DD format',
3127
+ example: '2024-06-15'
2953
3128
  },
2954
- userId: {
3129
+ value: {
2955
3130
  type: 'string',
2956
- description: 'User ID (owner of the price)',
2957
- example: 'user-123'
3131
+ description: 'Value at this date (in base currency)',
3132
+ example: '500000.00'
2958
3133
  },
2959
- currency: {
2960
- type: 'string',
2961
- description: 'Currency being priced (e.g., USD, AAPL, BTC)',
2962
- example: 'BTC'
3134
+ change: {
3135
+ type: 'object',
3136
+ description: 'Change from previous point',
3137
+ example: '5000.00'
2963
3138
  },
2964
- quoteCurrency: {
3139
+ assets: {
2965
3140
  type: 'string',
2966
- description: 'Quote currency (pricing currency, e.g., USD, CNY)',
2967
- example: 'USD'
2968
- },
2969
- amount: {
2970
- type: 'number',
2971
- description:
2972
- 'Price amount (corresponds to Beancount Amount.number). Supports up to 15 decimal places.',
2973
- example: 50000
3141
+ description: 'Total assets at this date (in base currency)',
3142
+ example: '494338.00'
2974
3143
  },
2975
- date: {
3144
+ liabilities: {
2976
3145
  type: 'string',
2977
- description:
2978
- 'Price date (ISO 8601 format). Represents the date this price was valid.',
2979
- example: '2024-01-01',
2980
- format: 'date'
3146
+ description: 'Total liabilities at this date (in base currency)',
3147
+ example: '310098.00'
2981
3148
  },
2982
- meta: {
2983
- type: 'object',
2984
- description:
2985
- 'Metadata (corresponds to Beancount meta field). Contains source, confidence, note, etc.',
2986
- example: {
2987
- source: 'MANUAL',
2988
- note: 'User-defined price',
2989
- confidence: 1
3149
+ byCurrency: {
3150
+ description: 'Multi-currency breakdown for this point',
3151
+ type: 'array',
3152
+ items: {
3153
+ $ref: '#/components/schemas/CurrencyBalanceDto'
2990
3154
  }
3155
+ }
3156
+ },
3157
+ required: ['date', 'value']
3158
+ } as const;
3159
+
3160
+ export const $TrendSummaryDto = {
3161
+ type: 'object',
3162
+ properties: {
3163
+ startValue: {
3164
+ type: 'string',
3165
+ description: 'Value at start of period',
3166
+ example: '450000.00'
2991
3167
  },
2992
- createdAt: {
2993
- format: 'date-time',
3168
+ endValue: {
2994
3169
  type: 'string',
2995
- description: 'Creation timestamp',
2996
- example: '2024-11-03T10:00:00Z'
3170
+ description: 'Value at end of period',
3171
+ example: '500000.00'
2997
3172
  },
2998
- updatedAt: {
2999
- format: 'date-time',
3173
+ totalChange: {
3000
3174
  type: 'string',
3001
- description: 'Last update timestamp',
3002
- example: '2024-11-03T10:00:00Z'
3175
+ description: 'Total change over period',
3176
+ example: '50000.00'
3177
+ },
3178
+ totalChangePercentage: {
3179
+ type: 'string',
3180
+ description: 'Total change percentage',
3181
+ example: '+11.11%'
3003
3182
  }
3004
3183
  },
3005
- required: [
3006
- 'id',
3007
- 'userId',
3008
- 'currency',
3009
- 'quoteCurrency',
3010
- 'amount',
3011
- 'date',
3012
- 'meta',
3013
- 'createdAt',
3014
- 'updatedAt'
3015
- ]
3184
+ required: ['startValue', 'endValue', 'totalChange', 'totalChangePercentage']
3016
3185
  } as const;
3017
3186
 
3018
- export const $PriceListResponseDto = {
3187
+ export const $MultiCurrencyPointDto = {
3019
3188
  type: 'object',
3020
3189
  properties: {
3021
- items: {
3022
- description: 'List of prices',
3190
+ date: {
3191
+ type: 'string',
3192
+ description: 'Date in YYYY-MM-DD format',
3193
+ example: '2024-06-15'
3194
+ },
3195
+ byCurrency: {
3196
+ description: 'Balances by currency',
3023
3197
  type: 'array',
3024
3198
  items: {
3025
- $ref: '#/components/schemas/PriceResponseDto'
3199
+ $ref: '#/components/schemas/CurrencyBalanceDto'
3026
3200
  }
3027
- },
3028
- total: {
3029
- type: 'number',
3030
- description: 'Total number of prices',
3031
- example: 42
3032
3201
  }
3033
3202
  },
3034
- required: ['items', 'total']
3203
+ required: ['date', 'byCurrency']
3035
3204
  } as const;
3036
3205
 
3037
- export const $UpdateBeanPriceDto = {
3206
+ export const $PortfolioTrendsResponseDto = {
3038
3207
  type: 'object',
3039
3208
  properties: {
3040
- currency: {
3041
- type: 'string',
3042
- description: 'Currency being priced'
3209
+ series: {
3210
+ description: 'Time series data points',
3211
+ type: 'array',
3212
+ items: {
3213
+ $ref: '#/components/schemas/TimeSeriesPointDto'
3214
+ }
3043
3215
  },
3044
- quoteCurrency: {
3216
+ summary: {
3217
+ description: 'Period summary',
3218
+ allOf: [
3219
+ {
3220
+ $ref: '#/components/schemas/TrendSummaryDto'
3221
+ }
3222
+ ]
3223
+ },
3224
+ period: {
3045
3225
  type: 'string',
3046
- description: 'Quote currency (pricing currency)'
3226
+ description: 'Period requested',
3227
+ example: '6m'
3047
3228
  },
3048
- amount: {
3049
- type: 'number',
3050
- description: 'Price amount (MUST be >= 0 per Beancount spec)',
3051
- minimum: 0
3229
+ granularity: {
3230
+ type: 'string',
3231
+ description: 'Data granularity',
3232
+ example: 'month'
3052
3233
  },
3053
- date: {
3234
+ currency: {
3054
3235
  type: 'string',
3055
- description: 'Price date (ISO 8601 format)'
3236
+ description: 'Base currency for converted values',
3237
+ example: 'CNY'
3056
3238
  },
3057
- metadata: {
3058
- type: 'object',
3059
- description: 'Metadata'
3239
+ byCurrency: {
3240
+ description:
3241
+ 'Multi-currency time series (each point has currency breakdown)',
3242
+ type: 'array',
3243
+ items: {
3244
+ $ref: '#/components/schemas/MultiCurrencyPointDto'
3245
+ }
3246
+ },
3247
+ warnings: {
3248
+ description: 'Exchange rate warnings',
3249
+ type: 'array',
3250
+ items: {
3251
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
3252
+ }
3060
3253
  }
3061
- }
3254
+ },
3255
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
3062
3256
  } as const;
3063
3257
 
3064
- export const $CreateRecurringRuleDto = {
3258
+ export const $CashFlowPointDto = {
3065
3259
  type: 'object',
3066
3260
  properties: {
3067
- name: {
3068
- type: 'string',
3069
- description: 'Rule name (unique per user)',
3070
- maxLength: 100
3071
- },
3072
- icon: {
3073
- type: 'string',
3074
- description: 'Icon emoji',
3075
- maxLength: 10
3076
- },
3077
- frequency: {
3261
+ month: {
3078
3262
  type: 'string',
3079
- description: 'Recurring frequency',
3080
- enum: [
3081
- 'WEEKLY',
3082
- 'BIWEEKLY',
3083
- 'MONTHLY',
3084
- 'BIMONTHLY',
3085
- 'QUARTERLY',
3086
- 'YEARLY',
3087
- 'CUSTOM'
3088
- ]
3089
- },
3090
- expectedAmount: {
3091
- type: 'number',
3092
- description: 'Expected amount (positive number)',
3093
- minimum: 0
3094
- },
3095
- expectedDay: {
3096
- type: 'number',
3097
- description: 'Expected day of month (1-31)',
3098
- minimum: 1,
3099
- maximum: 31
3100
- },
3101
- customIntervalDays: {
3102
- type: 'number',
3103
- description: 'Custom interval in days (required for CUSTOM frequency)',
3104
- minimum: 1
3263
+ description: 'Month key (YYYY-MM)',
3264
+ example: '2024-03'
3105
3265
  },
3106
- currency: {
3266
+ income: {
3107
3267
  type: 'string',
3108
- description: 'Currency code',
3109
- default: 'CNY',
3110
- maxLength: 10
3268
+ description: 'Income in base currency (absolute, converted)',
3269
+ example: '10000.00'
3111
3270
  },
3112
- matchPayeePattern: {
3271
+ expense: {
3113
3272
  type: 'string',
3114
- description: 'Payee matching pattern (supports wildcards)',
3115
- maxLength: 200
3116
- },
3117
- matchAmountTolerance: {
3118
- type: 'number',
3119
- description: 'Amount tolerance percentage (0-1)',
3120
- default: 0.075,
3121
- minimum: 0,
3122
- maximum: 1
3273
+ description: 'Expense in base currency (absolute, converted)',
3274
+ example: '5000.00'
3123
3275
  },
3124
- defaultExpenseAccount: {
3276
+ netSavings: {
3125
3277
  type: 'string',
3126
- description: 'Default expense account for auto-create',
3127
- maxLength: 200
3128
- },
3129
- defaultPaymentAccount: {
3278
+ description: 'netSavings = income − expense (savings positive)',
3279
+ example: '5000.00'
3280
+ }
3281
+ },
3282
+ required: ['month', 'income', 'expense', 'netSavings']
3283
+ } as const;
3284
+
3285
+ export const $CashFlowTrendSummaryDto = {
3286
+ type: 'object',
3287
+ properties: {
3288
+ totalIncome: {
3130
3289
  type: 'string',
3131
- description: 'Default payment account for auto-create',
3132
- maxLength: 200
3290
+ description: 'Total income across the period',
3291
+ example: '60000.00'
3133
3292
  },
3134
- defaultPayee: {
3293
+ totalExpense: {
3135
3294
  type: 'string',
3136
- description: 'Default payee for auto-create',
3137
- maxLength: 200
3138
- },
3139
- autoCreate: {
3140
- type: 'boolean',
3141
- description: 'Auto-create transaction when expected date arrives',
3142
- default: false
3295
+ description: 'Total expense across the period',
3296
+ example: '30000.00'
3143
3297
  },
3144
- startDate: {
3298
+ totalNetSavings: {
3145
3299
  type: 'string',
3146
- description: 'Rule start date (ISO format)'
3300
+ description: 'income − expense across the period',
3301
+ example: '30000.00'
3147
3302
  },
3148
- endDate: {
3303
+ averageMonthlyNetSavings: {
3149
3304
  type: 'string',
3150
- description: 'Rule end date (ISO format)'
3305
+ description:
3306
+ 'totalNetSavings divided by the window length (N months, incl. zero-filled)',
3307
+ example: '5000.00'
3151
3308
  }
3152
3309
  },
3153
3310
  required: [
3154
- 'name',
3155
- 'frequency',
3156
- 'expectedAmount',
3157
- 'currency',
3158
- 'matchAmountTolerance',
3159
- 'autoCreate'
3311
+ 'totalIncome',
3312
+ 'totalExpense',
3313
+ 'totalNetSavings',
3314
+ 'averageMonthlyNetSavings'
3160
3315
  ]
3161
3316
  } as const;
3162
3317
 
3163
- export const $RecurringRuleResponseDto = {
3318
+ export const $CashFlowTrendsResponseDto = {
3164
3319
  type: 'object',
3165
3320
  properties: {
3166
- id: {
3167
- type: 'string',
3168
- description: 'Rule ID'
3321
+ series: {
3322
+ description:
3323
+ 'Monthly cash-flow series (fixed N-month window, zero-filled)',
3324
+ type: 'array',
3325
+ items: {
3326
+ $ref: '#/components/schemas/CashFlowPointDto'
3327
+ }
3169
3328
  },
3170
- userId: {
3171
- type: 'string',
3172
- description: 'User ID'
3329
+ summary: {
3330
+ description: 'Period totals',
3331
+ allOf: [
3332
+ {
3333
+ $ref: '#/components/schemas/CashFlowTrendSummaryDto'
3334
+ }
3335
+ ]
3173
3336
  },
3174
- name: {
3337
+ period: {
3175
3338
  type: 'string',
3176
- description: 'Rule name'
3177
- },
3178
- icon: {
3179
- type: 'object',
3180
- description: 'Icon emoji'
3339
+ description: 'Period requested',
3340
+ example: '6m'
3181
3341
  },
3182
- frequency: {
3342
+ granularity: {
3183
3343
  type: 'string',
3184
- description: 'Recurring frequency'
3185
- },
3186
- expectedAmount: {
3187
- type: 'number',
3188
- description: 'Expected amount'
3189
- },
3190
- expectedDay: {
3191
- type: 'object',
3192
- description: 'Expected day of month'
3344
+ description: 'Data granularity (v1 returns month buckets)',
3345
+ example: 'month'
3193
3346
  },
3194
- customIntervalDays: {
3195
- type: 'object',
3196
- description: 'Custom interval in days'
3347
+ currency: {
3348
+ type: 'string',
3349
+ description: 'Base currency for converted values',
3350
+ example: 'CNY'
3197
3351
  },
3352
+ warnings: {
3353
+ description: 'Exchange rate warnings (e.g. missing rate for a currency)',
3354
+ type: 'array',
3355
+ items: {
3356
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
3357
+ }
3358
+ }
3359
+ },
3360
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
3361
+ } as const;
3362
+
3363
+ export const $GenerateSnapshotBody = {
3364
+ type: 'object',
3365
+ properties: {}
3366
+ } as const;
3367
+
3368
+ export const $GenerateSnapshotResponse = {
3369
+ type: 'object',
3370
+ properties: {}
3371
+ } as const;
3372
+
3373
+ export const $BackfillSnapshotsBody = {
3374
+ type: 'object',
3375
+ properties: {}
3376
+ } as const;
3377
+
3378
+ export const $BackfillSnapshotsResponse = {
3379
+ type: 'object',
3380
+ properties: {}
3381
+ } as const;
3382
+
3383
+ export const $CreateBeanPriceDto = {
3384
+ type: 'object',
3385
+ properties: {
3198
3386
  currency: {
3199
3387
  type: 'string',
3200
- description: 'Currency code'
3388
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
3389
+ example: 'USD'
3201
3390
  },
3202
- matchPayeePattern: {
3203
- type: 'object',
3204
- description: 'Payee matching pattern'
3391
+ quoteCurrency: {
3392
+ type: 'string',
3393
+ description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
3394
+ example: 'CNY'
3205
3395
  },
3206
- matchAmountTolerance: {
3396
+ amount: {
3207
3397
  type: 'number',
3208
- description: 'Amount tolerance percentage'
3398
+ description:
3399
+ 'Price amount (MUST be >= 0 per Beancount spec, supports up to 15 decimal places). Zero allowed for conversion entries, negative strictly prohibited.',
3400
+ example: 175.5,
3401
+ minimum: 0
3209
3402
  },
3210
- defaultExpenseAccount: {
3211
- type: 'object',
3212
- description: 'Default expense account'
3403
+ date: {
3404
+ type: 'string',
3405
+ description: 'Price date (ISO 8601 format)',
3406
+ example: '2024-11-05'
3213
3407
  },
3214
- defaultPaymentAccount: {
3408
+ metadata: {
3215
3409
  type: 'object',
3216
- description: 'Default payment account'
3410
+ description:
3411
+ 'Metadata (validated by Zod schema, max field lengths enforced)',
3412
+ example: {
3413
+ source: 'MANUAL',
3414
+ note: 'Bank valuation report',
3415
+ confidence: 0.95
3416
+ }
3417
+ }
3418
+ },
3419
+ required: ['currency', 'quoteCurrency', 'amount', 'date']
3420
+ } as const;
3421
+
3422
+ export const $PriceResponseDto = {
3423
+ type: 'object',
3424
+ properties: {
3425
+ id: {
3426
+ type: 'string',
3427
+ description: 'Unique identifier',
3428
+ example: 'uuid-123-456'
3217
3429
  },
3218
- defaultPayee: {
3219
- type: 'object',
3220
- description: 'Default payee'
3430
+ userId: {
3431
+ type: 'string',
3432
+ description: 'User ID (owner of the price)',
3433
+ example: 'user-123'
3221
3434
  },
3222
- isActive: {
3223
- type: 'boolean',
3224
- description: 'Whether rule is active'
3435
+ currency: {
3436
+ type: 'string',
3437
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
3438
+ example: 'BTC'
3225
3439
  },
3226
- startDate: {
3440
+ quoteCurrency: {
3227
3441
  type: 'string',
3228
- description: 'Rule start date (YYYY-MM-DD)'
3442
+ description: 'Quote currency (pricing currency, e.g., USD, CNY)',
3443
+ example: 'USD'
3229
3444
  },
3230
- endDate: {
3231
- type: 'object',
3232
- description: 'Rule end date (YYYY-MM-DD)'
3445
+ amount: {
3446
+ type: 'number',
3447
+ description:
3448
+ 'Price amount (corresponds to Beancount Amount.number). Supports up to 15 decimal places.',
3449
+ example: 50000
3233
3450
  },
3234
- autoCreate: {
3235
- type: 'boolean',
3236
- description: 'Auto-create transaction on expected date'
3451
+ date: {
3452
+ type: 'string',
3453
+ description:
3454
+ 'Price date (ISO 8601 format). Represents the date this price was valid.',
3455
+ example: '2024-01-01',
3456
+ format: 'date'
3237
3457
  },
3238
- lastOccurrence: {
3458
+ meta: {
3239
3459
  type: 'object',
3240
- description: 'Last matched occurrence date (YYYY-MM-DD)'
3241
- },
3242
- totalCount: {
3243
- type: 'number',
3244
- description: 'Total matched transactions count'
3460
+ description:
3461
+ 'Metadata (corresponds to Beancount meta field). Contains source, confidence, note, etc.',
3462
+ example: {
3463
+ source: 'MANUAL',
3464
+ note: 'User-defined price',
3465
+ confidence: 1
3466
+ }
3245
3467
  },
3246
3468
  createdAt: {
3247
3469
  format: 'date-time',
3248
3470
  type: 'string',
3249
- description: 'Created at timestamp'
3471
+ description: 'Creation timestamp',
3472
+ example: '2024-11-03T10:00:00Z'
3250
3473
  },
3251
3474
  updatedAt: {
3252
3475
  format: 'date-time',
3253
3476
  type: 'string',
3254
- description: 'Updated at timestamp'
3477
+ description: 'Last update timestamp',
3478
+ example: '2024-11-03T10:00:00Z'
3255
3479
  }
3256
3480
  },
3257
3481
  required: [
3258
3482
  'id',
3259
3483
  'userId',
3260
- 'name',
3261
- 'frequency',
3262
- 'expectedAmount',
3263
3484
  'currency',
3264
- 'matchAmountTolerance',
3265
- 'isActive',
3266
- 'startDate',
3267
- 'autoCreate',
3268
- 'totalCount',
3485
+ 'quoteCurrency',
3486
+ 'amount',
3487
+ 'date',
3488
+ 'meta',
3269
3489
  'createdAt',
3270
3490
  'updatedAt'
3271
3491
  ]
3272
3492
  } as const;
3273
3493
 
3274
- export const $CreateRuleFromTransactionDto = {
3494
+ export const $PriceListResponseDto = {
3275
3495
  type: 'object',
3276
3496
  properties: {
3277
- frequency: {
3278
- type: 'string',
3279
- description: 'Recurring frequency',
3280
- enum: [
3281
- 'WEEKLY',
3282
- 'BIWEEKLY',
3283
- 'MONTHLY',
3284
- 'BIMONTHLY',
3285
- 'QUARTERLY',
3286
- 'YEARLY',
3287
- 'CUSTOM'
3288
- ],
3289
- example: 'MONTHLY'
3290
- },
3291
- name: {
3292
- type: 'string',
3293
- description: 'Optional name override (default: transaction payee)',
3294
- maxLength: 100
3497
+ items: {
3498
+ description: 'List of prices',
3499
+ type: 'array',
3500
+ items: {
3501
+ $ref: '#/components/schemas/PriceResponseDto'
3502
+ }
3295
3503
  },
3296
- icon: {
3297
- type: 'string',
3298
- description: 'Optional icon emoji',
3299
- maxLength: 10
3504
+ total: {
3505
+ type: 'number',
3506
+ description: 'Total number of prices',
3507
+ example: 42
3300
3508
  }
3301
3509
  },
3302
- required: ['frequency']
3510
+ required: ['items', 'total']
3303
3511
  } as const;
3304
3512
 
3305
- export const $RecurringRuleWithStatsResponseDto = {
3513
+ export const $UpdateBeanPriceDto = {
3306
3514
  type: 'object',
3307
3515
  properties: {
3308
- id: {
3309
- type: 'string',
3310
- description: 'Rule ID'
3311
- },
3312
- userId: {
3516
+ currency: {
3313
3517
  type: 'string',
3314
- description: 'User ID'
3518
+ description: 'Currency being priced'
3315
3519
  },
3316
- name: {
3520
+ quoteCurrency: {
3317
3521
  type: 'string',
3318
- description: 'Rule name'
3522
+ description: 'Quote currency (pricing currency)'
3319
3523
  },
3320
- icon: {
3321
- type: 'object',
3322
- description: 'Icon emoji'
3524
+ amount: {
3525
+ type: 'number',
3526
+ description: 'Price amount (MUST be >= 0 per Beancount spec)',
3527
+ minimum: 0
3323
3528
  },
3324
- frequency: {
3529
+ date: {
3325
3530
  type: 'string',
3326
- description: 'Recurring frequency'
3327
- },
3328
- expectedAmount: {
3329
- type: 'number',
3330
- description: 'Expected amount'
3531
+ description: 'Price date (ISO 8601 format)'
3331
3532
  },
3332
- expectedDay: {
3533
+ metadata: {
3333
3534
  type: 'object',
3334
- description: 'Expected day of month'
3335
- },
3336
- customIntervalDays: {
3337
- type: 'object',
3338
- description: 'Custom interval in days'
3339
- },
3340
- currency: {
3341
- type: 'string',
3342
- description: 'Currency code'
3343
- },
3344
- matchPayeePattern: {
3345
- type: 'object',
3346
- description: 'Payee matching pattern'
3347
- },
3348
- matchAmountTolerance: {
3349
- type: 'number',
3350
- description: 'Amount tolerance percentage'
3351
- },
3352
- defaultExpenseAccount: {
3353
- type: 'object',
3354
- description: 'Default expense account'
3355
- },
3356
- defaultPaymentAccount: {
3357
- type: 'object',
3358
- description: 'Default payment account'
3359
- },
3360
- defaultPayee: {
3361
- type: 'object',
3362
- description: 'Default payee'
3363
- },
3364
- isActive: {
3365
- type: 'boolean',
3366
- description: 'Whether rule is active'
3367
- },
3368
- startDate: {
3369
- type: 'string',
3370
- description: 'Rule start date (YYYY-MM-DD)'
3371
- },
3372
- endDate: {
3373
- type: 'object',
3374
- description: 'Rule end date (YYYY-MM-DD)'
3375
- },
3376
- autoCreate: {
3377
- type: 'boolean',
3378
- description: 'Auto-create transaction on expected date'
3379
- },
3380
- lastOccurrence: {
3381
- type: 'object',
3382
- description: 'Last matched occurrence date (YYYY-MM-DD)'
3383
- },
3384
- totalCount: {
3385
- type: 'number',
3386
- description: 'Total matched transactions count'
3387
- },
3388
- createdAt: {
3389
- format: 'date-time',
3390
- type: 'string',
3391
- description: 'Created at timestamp'
3392
- },
3393
- updatedAt: {
3394
- format: 'date-time',
3535
+ description: 'Metadata'
3536
+ }
3537
+ }
3538
+ } as const;
3539
+
3540
+ export const $DeleteOwnUserDto = {
3541
+ type: 'object',
3542
+ properties: {
3543
+ accessToken: {
3395
3544
  type: 'string',
3396
- description: 'Updated at timestamp'
3397
- },
3398
- pendingCount: {
3399
- type: 'number',
3400
- description: 'Number of pending expected transactions'
3401
- },
3402
- overdueCount: {
3403
- type: 'number',
3404
- description: 'Number of overdue expected transactions'
3405
- },
3406
- nextExpectedDate: {
3407
- type: 'object',
3408
- description: 'Next expected date (YYYY-MM-DD)'
3409
- },
3410
- totalAmount: {
3411
- type: 'number',
3412
- description: 'Total amount of all matched transactions'
3413
- },
3414
- averageAmount: {
3415
- type: 'number',
3416
- description: 'Average amount per transaction'
3417
- },
3418
- transactionCount: {
3419
- type: 'number',
3420
- description: 'Number of matched transactions'
3421
- },
3422
- firstDate: {
3423
- type: 'object',
3424
- description: 'First matched transaction date (YYYY-MM-DD)'
3425
- },
3426
- lastDate: {
3427
- type: 'object',
3428
- description: 'Last matched transaction date (YYYY-MM-DD)'
3429
- },
3430
- variance: {
3431
- type: 'number',
3432
- description: 'Amount variance (standard deviation squared)'
3433
- },
3434
- upcomingCount: {
3435
- type: 'number',
3436
- description: 'Number of upcoming expected transactions'
3545
+ description: 'Access token for user verification',
3546
+ example: 'abc123xyz'
3437
3547
  }
3438
3548
  },
3439
- required: [
3440
- 'id',
3441
- 'userId',
3442
- 'name',
3443
- 'frequency',
3444
- 'expectedAmount',
3445
- 'currency',
3446
- 'matchAmountTolerance',
3447
- 'isActive',
3448
- 'startDate',
3449
- 'autoCreate',
3450
- 'totalCount',
3451
- 'createdAt',
3452
- 'updatedAt',
3453
- 'pendingCount',
3454
- 'overdueCount',
3455
- 'totalAmount',
3456
- 'averageAmount',
3457
- 'transactionCount',
3458
- 'variance',
3459
- 'upcomingCount'
3460
- ]
3549
+ required: ['accessToken']
3461
3550
  } as const;
3462
3551
 
3463
- export const $UpdateRecurringRuleDto = {
3552
+ export const $UserSettingsResponseDto = {
3464
3553
  type: 'object',
3465
3554
  properties: {
3466
- name: {
3467
- type: 'string',
3468
- description: 'Rule name',
3469
- maxLength: 100
3470
- },
3471
- icon: {
3472
- type: 'string',
3473
- description: 'Icon emoji',
3474
- maxLength: 10
3475
- },
3476
- frequency: {
3477
- type: 'string',
3478
- description: 'Recurring frequency',
3479
- enum: [
3480
- 'WEEKLY',
3481
- 'BIWEEKLY',
3482
- 'MONTHLY',
3483
- 'BIMONTHLY',
3484
- 'QUARTERLY',
3485
- 'YEARLY',
3486
- 'CUSTOM'
3487
- ]
3488
- },
3489
- expectedAmount: {
3490
- type: 'number',
3491
- description: 'Expected amount',
3492
- minimum: 0
3493
- },
3494
- expectedDay: {
3495
- type: 'number',
3496
- description: 'Expected day of month (1-31)',
3497
- minimum: 1,
3498
- maximum: 31
3499
- },
3500
- customIntervalDays: {
3501
- type: 'number',
3502
- description: 'Custom interval in days',
3503
- minimum: 1
3504
- },
3505
- currency: {
3506
- type: 'string',
3507
- description: 'Currency code',
3508
- maxLength: 10
3509
- },
3510
- matchPayeePattern: {
3511
- type: 'string',
3512
- description: 'Payee matching pattern',
3513
- maxLength: 200
3514
- },
3515
- matchAmountTolerance: {
3516
- type: 'number',
3517
- description: 'Amount tolerance percentage (0-1)',
3518
- minimum: 0,
3519
- maximum: 1
3520
- },
3521
- defaultExpenseAccount: {
3555
+ baseCurrency: {
3522
3556
  type: 'string',
3523
- description: 'Default expense account',
3524
- maxLength: 200
3525
- },
3526
- defaultPaymentAccount: {
3557
+ description:
3558
+ '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).',
3559
+ example: 'USD',
3560
+ nullable: true
3561
+ }
3562
+ },
3563
+ required: ['baseCurrency']
3564
+ } as const;
3565
+
3566
+ export const $UserResponseDto = {
3567
+ type: 'object',
3568
+ properties: {
3569
+ id: {
3527
3570
  type: 'string',
3528
- description: 'Default payment account',
3529
- maxLength: 200
3571
+ description: 'User ID'
3530
3572
  },
3531
- defaultPayee: {
3573
+ role: {
3532
3574
  type: 'string',
3533
- description: 'Default payee',
3534
- maxLength: 200
3535
- },
3536
- autoCreate: {
3537
- type: 'boolean',
3538
- description: 'Auto-create transaction'
3575
+ description: 'Assigned user role'
3539
3576
  },
3540
- isActive: {
3541
- type: 'boolean',
3542
- description: 'Rule active status'
3577
+ permissions: {
3578
+ description: 'Permission strings',
3579
+ type: 'array',
3580
+ items: {
3581
+ type: 'string'
3582
+ }
3543
3583
  },
3544
- endDate: {
3584
+ settings: {
3585
+ description: 'User settings',
3586
+ allOf: [
3587
+ {
3588
+ $ref: '#/components/schemas/UserSettingsResponseDto'
3589
+ }
3590
+ ]
3591
+ }
3592
+ },
3593
+ required: ['id', 'role', 'permissions', 'settings']
3594
+ } as const;
3595
+
3596
+ export const $SignupDto = {
3597
+ type: 'object',
3598
+ properties: {
3599
+ turnstileToken: {
3545
3600
  type: 'string',
3546
- description: 'Rule end date (ISO format)'
3601
+ description:
3602
+ 'Cloudflare Turnstile verification token (optional when Turnstile disabled)',
3603
+ example: '0.abc123def456...'
3547
3604
  }
3548
3605
  }
3549
3606
  } as const;
3550
3607
 
3551
- export const $ExpectedTransactionRuleDto = {
3608
+ export const $SignupResponseDto = {
3552
3609
  type: 'object',
3553
3610
  properties: {
3554
- name: {
3611
+ authToken: {
3555
3612
  type: 'string',
3556
- description: 'Rule name'
3557
- },
3558
- icon: {
3559
- type: 'object',
3560
- description: 'Rule icon'
3613
+ description: 'JWT auth token',
3614
+ example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
3561
3615
  },
3562
- frequency: {
3616
+ accessToken: {
3563
3617
  type: 'string',
3564
- description: 'Rule frequency'
3618
+ description: 'Auto-generated access token'
3565
3619
  },
3566
- currency: {
3620
+ role: {
3567
3621
  type: 'string',
3568
- description: 'Currency code'
3622
+ description: 'Assigned user role',
3623
+ enum: ['USER', 'ADMIN', 'DEMO', 'INACTIVE', 'PAID', 'OPS']
3569
3624
  }
3570
3625
  },
3571
- required: ['name', 'frequency', 'currency']
3626
+ required: ['authToken', 'accessToken', 'role']
3572
3627
  } as const;
3573
3628
 
3574
- export const $ExpectedTransactionResponseDto = {
3629
+ export const $UpdateUserSettingDto = {
3575
3630
  type: 'object',
3576
3631
  properties: {
3577
- id: {
3632
+ secId: {
3633
+ type: 'number',
3634
+ description: 'Security ID'
3635
+ },
3636
+ annualInterestRate: {
3637
+ type: 'number',
3638
+ description: 'Annual interest rate',
3639
+ example: 0.05
3640
+ },
3641
+ currency: {
3578
3642
  type: 'string',
3579
- description: 'Expected transaction ID'
3643
+ description: 'Currency code',
3644
+ example: 'USD'
3580
3645
  },
3581
- userId: {
3646
+ baseCurrency: {
3582
3647
  type: 'string',
3583
- description: 'User ID'
3648
+ description: 'Base currency code',
3649
+ example: 'USD'
3584
3650
  },
3585
- ruleId: {
3651
+ benchmark: {
3586
3652
  type: 'string',
3587
- description: 'Associated rule ID'
3653
+ description: 'Benchmark symbol',
3654
+ example: 'SPY'
3588
3655
  },
3589
- expectedDate: {
3656
+ colorScheme: {
3590
3657
  type: 'string',
3591
- description: 'Expected date (YYYY-MM-DD)'
3658
+ description: 'Color scheme',
3659
+ enum: ['DARK', 'LIGHT']
3592
3660
  },
3593
- expectedAmount: {
3661
+ dateRange: {
3662
+ type: 'string',
3663
+ description: 'Date range filter',
3664
+ example: '1y'
3665
+ },
3666
+ emergencyFund: {
3594
3667
  type: 'number',
3595
- description: 'Expected amount'
3668
+ description: 'Emergency fund amount',
3669
+ example: 10000
3596
3670
  },
3597
- status: {
3671
+ 'filters.accounts': {
3672
+ description: 'Account filter IDs',
3673
+ type: 'array',
3674
+ items: {
3675
+ type: 'string'
3676
+ }
3677
+ },
3678
+ 'filters.assetClasses': {
3679
+ description: 'Asset class filters',
3680
+ type: 'array',
3681
+ items: {
3682
+ type: 'string'
3683
+ }
3684
+ },
3685
+ 'filters.dataSource': {
3598
3686
  type: 'string',
3599
- description: 'Status (PENDING, COMPLETED, SKIPPED)'
3687
+ description: 'Data source filter'
3600
3688
  },
3601
- matchedTransactionId: {
3602
- type: 'object',
3603
- description: 'Matched transaction ID'
3689
+ 'filters.symbol': {
3690
+ type: 'string',
3691
+ description: 'Symbol filter'
3604
3692
  },
3605
- matchedAt: {
3606
- type: 'object',
3607
- description: 'Match timestamp (ISO 8601)'
3693
+ 'filters.tags': {
3694
+ description: 'Tag filters',
3695
+ type: 'array',
3696
+ items: {
3697
+ type: 'string'
3698
+ }
3608
3699
  },
3609
- matchConfidence: {
3610
- type: 'object',
3611
- description: 'Match confidence score (0-1)'
3700
+ isExperimentalFeatures: {
3701
+ type: 'boolean',
3702
+ description: 'Enable experimental features'
3612
3703
  },
3613
- isOverdue: {
3704
+ isRestrictedView: {
3614
3705
  type: 'boolean',
3615
- description: 'Whether this expected transaction is overdue'
3706
+ description: 'Enable restricted view mode'
3616
3707
  },
3617
- rule: {
3618
- description: 'Rule information',
3619
- allOf: [
3620
- {
3621
- $ref: '#/components/schemas/ExpectedTransactionRuleDto'
3622
- }
3623
- ]
3708
+ language: {
3709
+ type: 'string',
3710
+ description: 'Language code',
3711
+ example: 'en'
3624
3712
  },
3625
- createdAt: {
3626
- format: 'date-time',
3713
+ locale: {
3627
3714
  type: 'string',
3628
- description: 'Created at timestamp'
3715
+ description: 'Locale code',
3716
+ example: 'en-US'
3629
3717
  },
3630
- updatedAt: {
3631
- format: 'date-time',
3718
+ projectedTotalAmount: {
3719
+ type: 'number',
3720
+ description: 'Projected total amount',
3721
+ example: 1000000
3722
+ },
3723
+ retirementDate: {
3632
3724
  type: 'string',
3633
- description: 'Updated at timestamp'
3634
- }
3635
- },
3636
- required: [
3637
- 'id',
3638
- 'userId',
3639
- 'ruleId',
3640
- 'expectedDate',
3641
- 'expectedAmount',
3642
- 'status',
3643
- 'isOverdue',
3644
- 'rule',
3645
- 'createdAt',
3646
- 'updatedAt'
3647
- ]
3648
- } as const;
3649
-
3650
- export const $ExpectedTransactionListResponseDto = {
3651
- type: 'object',
3652
- properties: {
3653
- items: {
3654
- type: 'array',
3655
- items: {
3656
- $ref: '#/components/schemas/ExpectedTransactionResponseDto'
3657
- }
3725
+ description: 'Retirement date in ISO 8601 format',
3726
+ example: '2050-01-01'
3658
3727
  },
3659
- total: {
3728
+ savingsRate: {
3660
3729
  type: 'number',
3661
- description: 'Total count'
3730
+ description: 'Savings rate percentage',
3731
+ example: 0.2
3732
+ },
3733
+ viewMode: {
3734
+ type: 'string',
3735
+ description: 'View mode',
3736
+ enum: ['DEFAULT', 'ZEN']
3662
3737
  }
3663
- },
3664
- required: ['items', 'total']
3738
+ }
3665
3739
  } as const;
3666
3740
 
3667
- export const $ConfirmMatchDto = {
3741
+ export const $UpdatePropertyDto = {
3668
3742
  type: 'object',
3669
3743
  properties: {
3670
- transactionId: {
3744
+ value: {
3671
3745
  type: 'string',
3672
- description: 'Transaction ID to match with'
3746
+ description: 'Property value'
3673
3747
  }
3674
3748
  },
3675
- required: ['transactionId']
3749
+ required: ['value']
3676
3750
  } as const;
3677
3751
 
3678
- export const $EnterNowDto = {
3752
+ export const $CreateRecurringRuleDto = {
3679
3753
  type: 'object',
3680
3754
  properties: {
3681
- expenseAccount: {
3755
+ name: {
3682
3756
  type: 'string',
3683
- description:
3684
- 'Override expense account (uses rule default if not provided)',
3685
- maxLength: 200
3757
+ description: 'Rule name (unique per user)',
3758
+ maxLength: 100
3686
3759
  },
3687
- paymentAccount: {
3760
+ icon: {
3688
3761
  type: 'string',
3689
- description:
3690
- 'Override payment account (uses rule default if not provided)',
3691
- maxLength: 200
3762
+ description: 'Icon emoji',
3763
+ maxLength: 10
3692
3764
  },
3693
- amount: {
3765
+ frequency: {
3766
+ type: 'string',
3767
+ description: 'Recurring frequency',
3768
+ enum: [
3769
+ 'WEEKLY',
3770
+ 'BIWEEKLY',
3771
+ 'MONTHLY',
3772
+ 'BIMONTHLY',
3773
+ 'QUARTERLY',
3774
+ 'YEARLY',
3775
+ 'CUSTOM'
3776
+ ]
3777
+ },
3778
+ expectedAmount: {
3694
3779
  type: 'number',
3695
- description: 'Override amount (uses expected amount if not provided)',
3780
+ description: 'Expected amount (positive number)',
3696
3781
  minimum: 0
3697
3782
  },
3698
- payee: {
3699
- type: 'string',
3700
- description: 'Override payee (uses rule default if not provided)',
3701
- maxLength: 200
3783
+ expectedDay: {
3784
+ type: 'number',
3785
+ description: 'Expected day of month (1-31)',
3786
+ minimum: 1,
3787
+ maximum: 31
3702
3788
  },
3703
- narration: {
3704
- type: 'string',
3705
- description: 'Optional narration',
3706
- maxLength: 500
3707
- }
3708
- }
3709
- } as const;
3710
-
3711
- export const $ForecastItemDto = {
3712
- type: 'object',
3713
- properties: {
3714
- rule: {
3789
+ customIntervalDays: {
3790
+ type: 'number',
3791
+ description: 'Custom interval in days (required for CUSTOM frequency)',
3792
+ minimum: 1
3793
+ },
3794
+ currency: {
3715
3795
  type: 'string',
3716
- description: 'Rule name',
3717
- example: 'Rent'
3796
+ description: 'Currency code',
3797
+ maxLength: 10
3718
3798
  },
3719
- ruleId: {
3799
+ matchPayeePattern: {
3720
3800
  type: 'string',
3721
- description: 'Rule ID',
3722
- example: 'clx123...'
3801
+ description: 'Payee matching pattern (supports wildcards)',
3802
+ maxLength: 200
3723
3803
  },
3724
- amount: {
3804
+ matchAmountTolerance: {
3725
3805
  type: 'number',
3726
- description: 'Expected amount',
3727
- example: 3000
3806
+ description: 'Amount tolerance percentage (0-1)',
3807
+ default: 0.075,
3808
+ minimum: 0,
3809
+ maximum: 1
3728
3810
  },
3729
- date: {
3811
+ defaultExpenseAccount: {
3730
3812
  type: 'string',
3731
- description: 'Expected date (YYYY-MM-DD)',
3732
- example: '2024-04-01'
3813
+ description: 'Default expense account for auto-create',
3814
+ maxLength: 200
3733
3815
  },
3734
- icon: {
3816
+ defaultPaymentAccount: {
3735
3817
  type: 'string',
3736
- description: 'Rule icon emoji',
3737
- example: '🏠',
3738
- nullable: true
3818
+ description: 'Default payment account for auto-create',
3819
+ maxLength: 200
3739
3820
  },
3740
- currency: {
3821
+ defaultPayee: {
3741
3822
  type: 'string',
3742
- description: 'Currency code',
3743
- example: 'CNY'
3823
+ description: 'Default payee for auto-create',
3824
+ maxLength: 200
3825
+ },
3826
+ autoCreate: {
3827
+ type: 'boolean',
3828
+ description: 'Auto-create transaction when expected date arrives',
3829
+ default: false
3830
+ },
3831
+ startDate: {
3832
+ type: 'string',
3833
+ description: 'Rule start date (ISO format)'
3834
+ },
3835
+ endDate: {
3836
+ type: 'string',
3837
+ description: 'Rule end date (ISO format)'
3744
3838
  }
3745
3839
  },
3746
- required: ['rule', 'ruleId', 'amount', 'date', 'icon', 'currency']
3840
+ required: [
3841
+ 'name',
3842
+ 'frequency',
3843
+ 'expectedAmount',
3844
+ 'matchAmountTolerance',
3845
+ 'autoCreate'
3846
+ ]
3747
3847
  } as const;
3748
3848
 
3749
- export const $MonthlyForecastDto = {
3849
+ export const $RecurringRuleResponseDto = {
3750
3850
  type: 'object',
3751
3851
  properties: {
3752
- month: {
3852
+ id: {
3753
3853
  type: 'string',
3754
- description: 'Month (YYYY-MM)',
3755
- example: '2024-04'
3854
+ description: 'Rule ID'
3756
3855
  },
3757
- expectedOutflow: {
3758
- type: 'number',
3759
- description: 'Total expected outflow for the month',
3760
- example: 8500
3856
+ userId: {
3857
+ type: 'string',
3858
+ description: 'User ID'
3761
3859
  },
3762
- itemCount: {
3860
+ name: {
3861
+ type: 'string',
3862
+ description: 'Rule name'
3863
+ },
3864
+ icon: {
3865
+ type: 'object',
3866
+ description: 'Icon emoji'
3867
+ },
3868
+ frequency: {
3869
+ type: 'string',
3870
+ description: 'Recurring frequency'
3871
+ },
3872
+ expectedAmount: {
3763
3873
  type: 'number',
3764
- description: 'Number of expected transactions',
3765
- example: 3
3874
+ description: 'Expected amount'
3766
3875
  },
3767
- byCurrency: {
3876
+ expectedDay: {
3768
3877
  type: 'object',
3769
- description: 'Breakdown by currency',
3770
- example: {
3771
- CNY: 8500,
3772
- USD: 100
3773
- }
3878
+ description: 'Expected day of month'
3774
3879
  },
3775
- items: {
3776
- description: 'Individual forecast items',
3777
- type: 'array',
3778
- items: {
3779
- $ref: '#/components/schemas/ForecastItemDto'
3780
- }
3781
- }
3782
- },
3783
- required: ['month', 'expectedOutflow', 'itemCount', 'byCurrency', 'items']
3784
- } as const;
3785
-
3786
- export const $ForecastResponseDto = {
3787
- type: 'object',
3788
- properties: {
3789
- forecast: {
3790
- description: 'Monthly forecast data',
3791
- type: 'array',
3792
- items: {
3793
- $ref: '#/components/schemas/MonthlyForecastDto'
3794
- }
3880
+ customIntervalDays: {
3881
+ type: 'object',
3882
+ description: 'Custom interval in days'
3795
3883
  },
3796
- totalOutflow: {
3884
+ currency: {
3885
+ type: 'string',
3886
+ description: 'Currency code'
3887
+ },
3888
+ matchPayeePattern: {
3889
+ type: 'object',
3890
+ description: 'Payee matching pattern'
3891
+ },
3892
+ matchAmountTolerance: {
3797
3893
  type: 'number',
3798
- description: 'Total expected outflow across all months',
3799
- example: 25500
3894
+ description: 'Amount tolerance percentage'
3800
3895
  },
3801
- totalByCurrency: {
3896
+ defaultExpenseAccount: {
3802
3897
  type: 'object',
3803
- description: 'Total by currency across all months',
3804
- example: {
3805
- CNY: 25500,
3806
- USD: 300
3807
- }
3898
+ description: 'Default expense account'
3808
3899
  },
3809
- rulesCount: {
3900
+ defaultPaymentAccount: {
3901
+ type: 'object',
3902
+ description: 'Default payment account'
3903
+ },
3904
+ defaultPayee: {
3905
+ type: 'object',
3906
+ description: 'Default payee'
3907
+ },
3908
+ isActive: {
3909
+ type: 'boolean',
3910
+ description: 'Whether rule is active'
3911
+ },
3912
+ startDate: {
3913
+ type: 'string',
3914
+ description: 'Rule start date (YYYY-MM-DD)'
3915
+ },
3916
+ endDate: {
3917
+ type: 'object',
3918
+ description: 'Rule end date (YYYY-MM-DD)'
3919
+ },
3920
+ autoCreate: {
3921
+ type: 'boolean',
3922
+ description: 'Auto-create transaction on expected date'
3923
+ },
3924
+ lastOccurrence: {
3925
+ type: 'object',
3926
+ description: 'Last matched occurrence date (YYYY-MM-DD)'
3927
+ },
3928
+ totalCount: {
3810
3929
  type: 'number',
3811
- description: 'Number of active recurring rules included',
3812
- example: 5
3930
+ description: 'Total matched transactions count'
3813
3931
  },
3814
- periodStart: {
3932
+ createdAt: {
3933
+ format: 'date-time',
3815
3934
  type: 'string',
3816
- description: 'Forecast period start date',
3817
- example: '2024-04-01'
3935
+ description: 'Created at timestamp'
3818
3936
  },
3819
- periodEnd: {
3937
+ updatedAt: {
3938
+ format: 'date-time',
3820
3939
  type: 'string',
3821
- description: 'Forecast period end date',
3822
- example: '2024-06-30'
3940
+ description: 'Updated at timestamp'
3823
3941
  }
3824
3942
  },
3825
3943
  required: [
3826
- 'forecast',
3827
- 'totalOutflow',
3828
- 'totalByCurrency',
3829
- 'rulesCount',
3830
- 'periodStart',
3831
- 'periodEnd'
3944
+ 'id',
3945
+ 'userId',
3946
+ 'name',
3947
+ 'frequency',
3948
+ 'expectedAmount',
3949
+ 'currency',
3950
+ 'matchAmountTolerance',
3951
+ 'isActive',
3952
+ 'startDate',
3953
+ 'autoCreate',
3954
+ 'totalCount',
3955
+ 'createdAt',
3956
+ 'updatedAt'
3832
3957
  ]
3833
3958
  } as const;
3834
3959
 
3835
- export const $CurrencyBalanceDto = {
3960
+ export const $CreateRuleFromTransactionDto = {
3836
3961
  type: 'object',
3837
3962
  properties: {
3838
- currency: {
3963
+ frequency: {
3839
3964
  type: 'string',
3840
- description: 'ISO 4217 currency code',
3841
- example: 'CNY'
3965
+ description: 'Recurring frequency',
3966
+ enum: [
3967
+ 'WEEKLY',
3968
+ 'BIWEEKLY',
3969
+ 'MONTHLY',
3970
+ 'BIMONTHLY',
3971
+ 'QUARTERLY',
3972
+ 'YEARLY',
3973
+ 'CUSTOM'
3974
+ ],
3975
+ example: 'MONTHLY'
3842
3976
  },
3843
- balance: {
3977
+ name: {
3844
3978
  type: 'string',
3845
- description: 'Balance amount',
3846
- example: '500000.00'
3979
+ description: 'Optional name override (default: transaction payee)',
3980
+ maxLength: 100
3981
+ },
3982
+ icon: {
3983
+ type: 'string',
3984
+ description: 'Optional icon emoji',
3985
+ maxLength: 10
3847
3986
  }
3848
3987
  },
3849
- required: ['currency', 'balance']
3988
+ required: ['frequency']
3850
3989
  } as const;
3851
3990
 
3852
- export const $TimeSeriesPointDto = {
3991
+ export const $RecurringRuleWithStatsResponseDto = {
3853
3992
  type: 'object',
3854
3993
  properties: {
3855
- date: {
3994
+ id: {
3856
3995
  type: 'string',
3857
- description: 'Date in YYYY-MM-DD format',
3858
- example: '2024-06-15'
3996
+ description: 'Rule ID'
3859
3997
  },
3860
- value: {
3998
+ userId: {
3861
3999
  type: 'string',
3862
- description: 'Value at this date (in base currency)',
3863
- example: '500000.00'
4000
+ description: 'User ID'
3864
4001
  },
3865
- change: {
4002
+ name: {
4003
+ type: 'string',
4004
+ description: 'Rule name'
4005
+ },
4006
+ icon: {
3866
4007
  type: 'object',
3867
- description: 'Change from previous point',
3868
- example: '5000.00'
4008
+ description: 'Icon emoji'
3869
4009
  },
3870
- assets: {
4010
+ frequency: {
3871
4011
  type: 'string',
3872
- description: 'Total assets at this date (in base currency)',
3873
- example: '494338.00'
4012
+ description: 'Recurring frequency'
3874
4013
  },
3875
- liabilities: {
3876
- type: 'string',
3877
- description: 'Total liabilities at this date (in base currency)',
3878
- example: '310098.00'
4014
+ expectedAmount: {
4015
+ type: 'number',
4016
+ description: 'Expected amount'
3879
4017
  },
3880
- byCurrency: {
3881
- description: 'Multi-currency breakdown for this point',
3882
- type: 'array',
3883
- items: {
3884
- $ref: '#/components/schemas/CurrencyBalanceDto'
3885
- }
3886
- }
3887
- },
3888
- required: ['date', 'value']
3889
- } as const;
3890
-
3891
- export const $TrendSummaryDto = {
3892
- type: 'object',
3893
- properties: {
3894
- startValue: {
3895
- type: 'string',
3896
- description: 'Value at start of period',
3897
- example: '450000.00'
4018
+ expectedDay: {
4019
+ type: 'object',
4020
+ description: 'Expected day of month'
3898
4021
  },
3899
- endValue: {
4022
+ customIntervalDays: {
4023
+ type: 'object',
4024
+ description: 'Custom interval in days'
4025
+ },
4026
+ currency: {
3900
4027
  type: 'string',
3901
- description: 'Value at end of period',
3902
- example: '500000.00'
4028
+ description: 'Currency code'
3903
4029
  },
3904
- totalChange: {
4030
+ matchPayeePattern: {
4031
+ type: 'object',
4032
+ description: 'Payee matching pattern'
4033
+ },
4034
+ matchAmountTolerance: {
4035
+ type: 'number',
4036
+ description: 'Amount tolerance percentage'
4037
+ },
4038
+ defaultExpenseAccount: {
4039
+ type: 'object',
4040
+ description: 'Default expense account'
4041
+ },
4042
+ defaultPaymentAccount: {
4043
+ type: 'object',
4044
+ description: 'Default payment account'
4045
+ },
4046
+ defaultPayee: {
4047
+ type: 'object',
4048
+ description: 'Default payee'
4049
+ },
4050
+ isActive: {
4051
+ type: 'boolean',
4052
+ description: 'Whether rule is active'
4053
+ },
4054
+ startDate: {
3905
4055
  type: 'string',
3906
- description: 'Total change over period',
3907
- example: '50000.00'
4056
+ description: 'Rule start date (YYYY-MM-DD)'
3908
4057
  },
3909
- totalChangePercentage: {
4058
+ endDate: {
4059
+ type: 'object',
4060
+ description: 'Rule end date (YYYY-MM-DD)'
4061
+ },
4062
+ autoCreate: {
4063
+ type: 'boolean',
4064
+ description: 'Auto-create transaction on expected date'
4065
+ },
4066
+ lastOccurrence: {
4067
+ type: 'object',
4068
+ description: 'Last matched occurrence date (YYYY-MM-DD)'
4069
+ },
4070
+ totalCount: {
4071
+ type: 'number',
4072
+ description: 'Total matched transactions count'
4073
+ },
4074
+ createdAt: {
4075
+ format: 'date-time',
3910
4076
  type: 'string',
3911
- description: 'Total change percentage',
3912
- example: '+11.11%'
3913
- }
3914
- },
3915
- required: ['startValue', 'endValue', 'totalChange', 'totalChangePercentage']
3916
- } as const;
3917
-
3918
- export const $MultiCurrencyPointDto = {
3919
- type: 'object',
3920
- properties: {
3921
- date: {
4077
+ description: 'Created at timestamp'
4078
+ },
4079
+ updatedAt: {
4080
+ format: 'date-time',
3922
4081
  type: 'string',
3923
- description: 'Date in YYYY-MM-DD format',
3924
- example: '2024-06-15'
4082
+ description: 'Updated at timestamp'
3925
4083
  },
3926
- byCurrency: {
3927
- description: 'Balances by currency',
3928
- type: 'array',
3929
- items: {
3930
- $ref: '#/components/schemas/CurrencyBalanceDto'
3931
- }
4084
+ pendingCount: {
4085
+ type: 'number',
4086
+ description: 'Number of pending expected transactions'
4087
+ },
4088
+ overdueCount: {
4089
+ type: 'number',
4090
+ description: 'Number of overdue expected transactions'
4091
+ },
4092
+ nextExpectedDate: {
4093
+ type: 'object',
4094
+ description: 'Next expected date (YYYY-MM-DD)'
4095
+ },
4096
+ totalAmount: {
4097
+ type: 'number',
4098
+ description: 'Total amount of all matched transactions'
4099
+ },
4100
+ averageAmount: {
4101
+ type: 'number',
4102
+ description: 'Average amount per transaction'
4103
+ },
4104
+ transactionCount: {
4105
+ type: 'number',
4106
+ description: 'Number of matched transactions'
4107
+ },
4108
+ firstDate: {
4109
+ type: 'object',
4110
+ description: 'First matched transaction date (YYYY-MM-DD)'
4111
+ },
4112
+ lastDate: {
4113
+ type: 'object',
4114
+ description: 'Last matched transaction date (YYYY-MM-DD)'
4115
+ },
4116
+ variance: {
4117
+ type: 'number',
4118
+ description: 'Amount variance (standard deviation squared)'
4119
+ },
4120
+ upcomingCount: {
4121
+ type: 'number',
4122
+ description: 'Number of upcoming expected transactions'
3932
4123
  }
3933
4124
  },
3934
- required: ['date', 'byCurrency']
4125
+ required: [
4126
+ 'id',
4127
+ 'userId',
4128
+ 'name',
4129
+ 'frequency',
4130
+ 'expectedAmount',
4131
+ 'currency',
4132
+ 'matchAmountTolerance',
4133
+ 'isActive',
4134
+ 'startDate',
4135
+ 'autoCreate',
4136
+ 'totalCount',
4137
+ 'createdAt',
4138
+ 'updatedAt',
4139
+ 'pendingCount',
4140
+ 'overdueCount',
4141
+ 'totalAmount',
4142
+ 'averageAmount',
4143
+ 'transactionCount',
4144
+ 'variance',
4145
+ 'upcomingCount'
4146
+ ]
3935
4147
  } as const;
3936
4148
 
3937
- export const $PortfolioTrendsResponseDto = {
4149
+ export const $UpdateRecurringRuleDto = {
3938
4150
  type: 'object',
3939
- properties: {
3940
- series: {
3941
- description: 'Time series data points',
3942
- type: 'array',
3943
- items: {
3944
- $ref: '#/components/schemas/TimeSeriesPointDto'
3945
- }
3946
- },
3947
- summary: {
3948
- description: 'Period summary',
3949
- allOf: [
3950
- {
3951
- $ref: '#/components/schemas/TrendSummaryDto'
3952
- }
3953
- ]
4151
+ properties: {
4152
+ name: {
4153
+ type: 'string',
4154
+ description: 'Rule name (unique per user)',
4155
+ maxLength: 100
3954
4156
  },
3955
- period: {
4157
+ icon: {
3956
4158
  type: 'string',
3957
- description: 'Period requested',
3958
- example: '6m'
4159
+ description: 'Icon emoji',
4160
+ maxLength: 10
3959
4161
  },
3960
- granularity: {
4162
+ frequency: {
3961
4163
  type: 'string',
3962
- description: 'Data granularity',
3963
- example: 'month'
4164
+ description: 'Recurring frequency',
4165
+ enum: [
4166
+ 'WEEKLY',
4167
+ 'BIWEEKLY',
4168
+ 'MONTHLY',
4169
+ 'BIMONTHLY',
4170
+ 'QUARTERLY',
4171
+ 'YEARLY',
4172
+ 'CUSTOM'
4173
+ ]
4174
+ },
4175
+ expectedAmount: {
4176
+ type: 'number',
4177
+ description: 'Expected amount (positive number)',
4178
+ minimum: 0
4179
+ },
4180
+ expectedDay: {
4181
+ type: 'number',
4182
+ description: 'Expected day of month (1-31)',
4183
+ minimum: 1,
4184
+ maximum: 31
3964
4185
  },
3965
4186
  currency: {
3966
4187
  type: 'string',
3967
- description: 'Base currency for converted values',
3968
- example: 'CNY'
4188
+ description: 'Currency code',
4189
+ maxLength: 10
3969
4190
  },
3970
- byCurrency: {
3971
- description:
3972
- 'Multi-currency time series (each point has currency breakdown)',
3973
- type: 'array',
3974
- items: {
3975
- $ref: '#/components/schemas/MultiCurrencyPointDto'
3976
- }
4191
+ matchPayeePattern: {
4192
+ type: 'string',
4193
+ description: 'Payee matching pattern (supports wildcards)',
4194
+ maxLength: 200
3977
4195
  },
3978
- warnings: {
3979
- description: 'Exchange rate warnings',
3980
- type: 'array',
3981
- items: {
3982
- $ref: '#/components/schemas/ExchangeRateWarningDto'
3983
- }
3984
- }
3985
- },
3986
- required: ['series', 'summary', 'period', 'granularity', 'currency']
3987
- } as const;
3988
-
3989
- export const $CashFlowPointDto = {
3990
- type: 'object',
3991
- properties: {
3992
- month: {
4196
+ matchAmountTolerance: {
4197
+ type: 'number',
4198
+ description: 'Amount tolerance percentage (0-1)',
4199
+ default: 0.075,
4200
+ minimum: 0,
4201
+ maximum: 1
4202
+ },
4203
+ defaultExpenseAccount: {
3993
4204
  type: 'string',
3994
- description: 'Month key (YYYY-MM)',
3995
- example: '2024-03'
4205
+ description: 'Default expense account for auto-create',
4206
+ maxLength: 200
3996
4207
  },
3997
- income: {
4208
+ defaultPaymentAccount: {
3998
4209
  type: 'string',
3999
- description: 'Income in base currency (absolute, converted)',
4000
- example: '10000.00'
4210
+ description: 'Default payment account for auto-create',
4211
+ maxLength: 200
4001
4212
  },
4002
- expense: {
4213
+ defaultPayee: {
4003
4214
  type: 'string',
4004
- description: 'Expense in base currency (absolute, converted)',
4005
- example: '5000.00'
4215
+ description: 'Default payee for auto-create',
4216
+ maxLength: 200
4006
4217
  },
4007
- netSavings: {
4218
+ autoCreate: {
4219
+ type: 'boolean',
4220
+ description: 'Auto-create transaction when expected date arrives',
4221
+ default: false
4222
+ },
4223
+ endDate: {
4008
4224
  type: 'string',
4009
- description: 'netSavings = income − expense (savings positive)',
4010
- example: '5000.00'
4225
+ description: 'Rule end date (ISO format)'
4226
+ },
4227
+ customIntervalDays: {
4228
+ type: 'number',
4229
+ description: 'Custom interval in days',
4230
+ minimum: 1
4231
+ },
4232
+ isActive: {
4233
+ type: 'boolean',
4234
+ description: 'Rule active status'
4011
4235
  }
4012
- },
4013
- required: ['month', 'income', 'expense', 'netSavings']
4236
+ }
4014
4237
  } as const;
4015
4238
 
4016
- export const $CashFlowTrendSummaryDto = {
4239
+ export const $ExpectedTransactionRuleDto = {
4017
4240
  type: 'object',
4018
4241
  properties: {
4019
- totalIncome: {
4242
+ name: {
4020
4243
  type: 'string',
4021
- description: 'Total income across the period',
4022
- example: '60000.00'
4244
+ description: 'Rule name'
4023
4245
  },
4024
- totalExpense: {
4025
- type: 'string',
4026
- description: 'Total expense across the period',
4027
- example: '30000.00'
4246
+ icon: {
4247
+ type: 'object',
4248
+ description: 'Rule icon'
4028
4249
  },
4029
- totalNetSavings: {
4250
+ frequency: {
4030
4251
  type: 'string',
4031
- description: 'income − expense across the period',
4032
- example: '30000.00'
4252
+ description: 'Rule frequency'
4033
4253
  },
4034
- averageMonthlyNetSavings: {
4254
+ currency: {
4035
4255
  type: 'string',
4036
- description:
4037
- 'totalNetSavings divided by the window length (N months, incl. zero-filled)',
4038
- example: '5000.00'
4256
+ description: 'Currency code'
4039
4257
  }
4040
4258
  },
4041
- required: [
4042
- 'totalIncome',
4043
- 'totalExpense',
4044
- 'totalNetSavings',
4045
- 'averageMonthlyNetSavings'
4046
- ]
4259
+ required: ['name', 'frequency', 'currency']
4047
4260
  } as const;
4048
4261
 
4049
- export const $CashFlowTrendsResponseDto = {
4262
+ export const $ExpectedTransactionResponseDto = {
4050
4263
  type: 'object',
4051
4264
  properties: {
4052
- series: {
4053
- description:
4054
- 'Monthly cash-flow series (fixed N-month window, zero-filled)',
4055
- type: 'array',
4056
- items: {
4057
- $ref: '#/components/schemas/CashFlowPointDto'
4058
- }
4059
- },
4060
- summary: {
4061
- description: 'Period totals',
4062
- allOf: [
4063
- {
4064
- $ref: '#/components/schemas/CashFlowTrendSummaryDto'
4065
- }
4066
- ]
4265
+ id: {
4266
+ type: 'string',
4267
+ description: 'Expected transaction ID'
4067
4268
  },
4068
- period: {
4269
+ userId: {
4069
4270
  type: 'string',
4070
- description: 'Period requested',
4071
- example: '6m'
4271
+ description: 'User ID'
4072
4272
  },
4073
- granularity: {
4273
+ ruleId: {
4074
4274
  type: 'string',
4075
- description: 'Data granularity (v1 returns month buckets)',
4076
- example: 'month'
4275
+ description: 'Associated rule ID'
4077
4276
  },
4078
- currency: {
4277
+ expectedDate: {
4079
4278
  type: 'string',
4080
- description: 'Base currency for converted values',
4081
- example: 'CNY'
4279
+ description: 'Expected date (YYYY-MM-DD)'
4082
4280
  },
4083
- warnings: {
4084
- description: 'Exchange rate warnings (e.g. missing rate for a currency)',
4085
- type: 'array',
4086
- items: {
4087
- $ref: '#/components/schemas/ExchangeRateWarningDto'
4088
- }
4089
- }
4090
- },
4091
- required: ['series', 'summary', 'period', 'granularity', 'currency']
4092
- } as const;
4093
-
4094
- export const $GenerateSnapshotBody = {
4095
- type: 'object',
4096
- properties: {}
4097
- } as const;
4098
-
4099
- export const $GenerateSnapshotResponse = {
4100
- type: 'object',
4101
- properties: {}
4102
- } as const;
4103
-
4104
- export const $BackfillSnapshotsBody = {
4105
- type: 'object',
4106
- properties: {}
4107
- } as const;
4108
-
4109
- export const $BackfillSnapshotsResponse = {
4110
- type: 'object',
4111
- properties: {}
4112
- } as const;
4113
-
4114
- export const $DeleteOwnUserDto = {
4115
- type: 'object',
4116
- properties: {
4117
- accessToken: {
4281
+ expectedAmount: {
4282
+ type: 'number',
4283
+ description: 'Expected amount'
4284
+ },
4285
+ status: {
4118
4286
  type: 'string',
4119
- description: 'Access token for user verification',
4120
- example: 'abc123xyz'
4121
- }
4122
- },
4123
- required: ['accessToken']
4124
- } as const;
4125
-
4126
- export const $UserSettingsResponseDto = {
4127
- type: 'object',
4128
- properties: {
4129
- baseCurrency: {
4287
+ description: 'Status (PENDING, COMPLETED, SKIPPED)'
4288
+ },
4289
+ matchedTransactionId: {
4290
+ type: 'object',
4291
+ description: 'Matched transaction ID'
4292
+ },
4293
+ matchedAt: {
4294
+ type: 'object',
4295
+ description: 'Match timestamp (ISO 8601)'
4296
+ },
4297
+ matchConfidence: {
4298
+ type: 'object',
4299
+ description: 'Match confidence score (0-1)'
4300
+ },
4301
+ isOverdue: {
4302
+ type: 'boolean',
4303
+ description: 'Whether this expected transaction is overdue'
4304
+ },
4305
+ rule: {
4306
+ description: 'Rule information',
4307
+ allOf: [
4308
+ {
4309
+ $ref: '#/components/schemas/ExpectedTransactionRuleDto'
4310
+ }
4311
+ ]
4312
+ },
4313
+ createdAt: {
4314
+ format: 'date-time',
4130
4315
  type: 'string',
4131
- description:
4132
- 'Base currency (ISO 4217) for net-worth/report aggregation. Independent of region (ADR-0006).',
4133
- example: 'USD',
4134
- nullable: true
4316
+ description: 'Created at timestamp'
4317
+ },
4318
+ updatedAt: {
4319
+ format: 'date-time',
4320
+ type: 'string',
4321
+ description: 'Updated at timestamp'
4135
4322
  }
4136
4323
  },
4137
- required: ['baseCurrency']
4324
+ required: [
4325
+ 'id',
4326
+ 'userId',
4327
+ 'ruleId',
4328
+ 'expectedDate',
4329
+ 'expectedAmount',
4330
+ 'status',
4331
+ 'isOverdue',
4332
+ 'rule',
4333
+ 'createdAt',
4334
+ 'updatedAt'
4335
+ ]
4138
4336
  } as const;
4139
4337
 
4140
- export const $UserResponseDto = {
4338
+ export const $ExpectedTransactionListResponseDto = {
4141
4339
  type: 'object',
4142
4340
  properties: {
4143
- id: {
4144
- type: 'string',
4145
- description: 'User ID'
4146
- },
4147
- role: {
4148
- type: 'string',
4149
- description: 'Assigned user role'
4150
- },
4151
- permissions: {
4152
- description: 'Permission strings',
4341
+ items: {
4153
4342
  type: 'array',
4154
4343
  items: {
4155
- type: 'string'
4344
+ $ref: '#/components/schemas/ExpectedTransactionResponseDto'
4156
4345
  }
4157
4346
  },
4158
- settings: {
4159
- description: 'User settings',
4160
- allOf: [
4161
- {
4162
- $ref: '#/components/schemas/UserSettingsResponseDto'
4163
- }
4164
- ]
4347
+ total: {
4348
+ type: 'number',
4349
+ description: 'Total count'
4165
4350
  }
4166
4351
  },
4167
- required: ['id', 'role', 'permissions', 'settings']
4352
+ required: ['items', 'total']
4168
4353
  } as const;
4169
4354
 
4170
- export const $SignupDto = {
4355
+ export const $ConfirmMatchDto = {
4171
4356
  type: 'object',
4172
4357
  properties: {
4173
- turnstileToken: {
4358
+ transactionId: {
4174
4359
  type: 'string',
4175
- description:
4176
- 'Cloudflare Turnstile verification token (optional when Turnstile disabled)',
4177
- example: '0.abc123def456...'
4360
+ description: 'Transaction ID to match with'
4178
4361
  }
4179
- }
4362
+ },
4363
+ required: ['transactionId']
4180
4364
  } as const;
4181
4365
 
4182
- export const $SignupResponseDto = {
4366
+ export const $EnterNowDto = {
4183
4367
  type: 'object',
4184
4368
  properties: {
4185
- authToken: {
4369
+ expenseAccount: {
4186
4370
  type: 'string',
4187
- description: 'JWT auth token',
4188
- example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
4371
+ description:
4372
+ 'Override expense account (uses rule default if not provided)',
4373
+ maxLength: 200
4189
4374
  },
4190
- accessToken: {
4375
+ paymentAccount: {
4191
4376
  type: 'string',
4192
- description: 'Auto-generated access token'
4377
+ description:
4378
+ 'Override payment account (uses rule default if not provided)',
4379
+ maxLength: 200
4193
4380
  },
4194
- role: {
4381
+ amount: {
4382
+ type: 'number',
4383
+ description: 'Override amount (uses expected amount if not provided)',
4384
+ minimum: 0
4385
+ },
4386
+ payee: {
4195
4387
  type: 'string',
4196
- description: 'Assigned user role',
4197
- enum: ['USER', 'ADMIN', 'DEMO', 'INACTIVE', 'PAID', 'OPS']
4388
+ description: 'Override payee (uses rule default if not provided)',
4389
+ maxLength: 200
4390
+ },
4391
+ narration: {
4392
+ type: 'string',
4393
+ description: 'Optional narration',
4394
+ maxLength: 500
4198
4395
  }
4199
- },
4200
- required: ['authToken', 'accessToken', 'role']
4396
+ }
4201
4397
  } as const;
4202
4398
 
4203
- export const $UpdateUserSettingDto = {
4399
+ export const $ForecastItemDto = {
4204
4400
  type: 'object',
4205
4401
  properties: {
4206
- secId: {
4207
- type: 'number',
4208
- description: 'Security ID'
4402
+ rule: {
4403
+ type: 'string',
4404
+ description: 'Rule name',
4405
+ example: 'Rent'
4209
4406
  },
4210
- annualInterestRate: {
4407
+ ruleId: {
4408
+ type: 'string',
4409
+ description: 'Rule ID',
4410
+ example: 'clx123...'
4411
+ },
4412
+ amount: {
4211
4413
  type: 'number',
4212
- description: 'Annual interest rate',
4213
- example: 0.05
4414
+ description: 'Expected amount',
4415
+ example: 3000
4214
4416
  },
4215
- currency: {
4417
+ date: {
4216
4418
  type: 'string',
4217
- description: 'Currency code',
4218
- example: 'USD'
4419
+ description: 'Expected date (YYYY-MM-DD)',
4420
+ example: '2024-04-01'
4219
4421
  },
4220
- baseCurrency: {
4422
+ icon: {
4221
4423
  type: 'string',
4222
- description: 'Base currency code',
4223
- example: 'USD'
4424
+ description: 'Rule icon emoji',
4425
+ example: '🏠',
4426
+ nullable: true
4224
4427
  },
4225
- benchmark: {
4428
+ currency: {
4226
4429
  type: 'string',
4227
- description: 'Benchmark symbol',
4228
- example: 'SPY'
4229
- },
4230
- colorScheme: {
4430
+ description: 'Currency code',
4431
+ example: 'CNY'
4432
+ }
4433
+ },
4434
+ required: ['rule', 'ruleId', 'amount', 'date', 'icon', 'currency']
4435
+ } as const;
4436
+
4437
+ export const $MonthlyForecastDto = {
4438
+ type: 'object',
4439
+ properties: {
4440
+ month: {
4231
4441
  type: 'string',
4232
- description: 'Color scheme',
4233
- enum: ['DARK', 'LIGHT']
4442
+ description: 'Month (YYYY-MM)',
4443
+ example: '2024-04'
4234
4444
  },
4235
- dateRange: {
4236
- type: 'string',
4237
- description: 'Date range filter',
4238
- example: '1y'
4445
+ expectedOutflow: {
4446
+ type: 'number',
4447
+ description: 'Total expected outflow for the month',
4448
+ example: 8500
4239
4449
  },
4240
- emergencyFund: {
4450
+ itemCount: {
4241
4451
  type: 'number',
4242
- description: 'Emergency fund amount',
4243
- example: 10000
4452
+ description: 'Number of expected transactions',
4453
+ example: 3
4244
4454
  },
4245
- 'filters.accounts': {
4246
- description: 'Account filter IDs',
4247
- type: 'array',
4248
- items: {
4249
- type: 'string'
4455
+ byCurrency: {
4456
+ type: 'object',
4457
+ description: 'Breakdown by currency',
4458
+ example: {
4459
+ CNY: 8500,
4460
+ USD: 100
4250
4461
  }
4251
4462
  },
4252
- 'filters.assetClasses': {
4253
- description: 'Asset class filters',
4463
+ items: {
4464
+ description: 'Individual forecast items',
4254
4465
  type: 'array',
4255
4466
  items: {
4256
- type: 'string'
4467
+ $ref: '#/components/schemas/ForecastItemDto'
4257
4468
  }
4258
- },
4259
- 'filters.dataSource': {
4260
- type: 'string',
4261
- description: 'Data source filter'
4262
- },
4263
- 'filters.symbol': {
4264
- type: 'string',
4265
- description: 'Symbol filter'
4266
- },
4267
- 'filters.tags': {
4268
- description: 'Tag filters',
4469
+ }
4470
+ },
4471
+ required: ['month', 'expectedOutflow', 'itemCount', 'byCurrency', 'items']
4472
+ } as const;
4473
+
4474
+ export const $ForecastResponseDto = {
4475
+ type: 'object',
4476
+ properties: {
4477
+ forecast: {
4478
+ description: 'Monthly forecast data',
4269
4479
  type: 'array',
4270
4480
  items: {
4271
- type: 'string'
4481
+ $ref: '#/components/schemas/MonthlyForecastDto'
4272
4482
  }
4273
4483
  },
4274
- isExperimentalFeatures: {
4275
- type: 'boolean',
4276
- description: 'Enable experimental features'
4277
- },
4278
- isRestrictedView: {
4279
- type: 'boolean',
4280
- description: 'Enable restricted view mode'
4281
- },
4282
- language: {
4283
- type: 'string',
4284
- description: 'Language code',
4285
- example: 'en'
4286
- },
4287
- locale: {
4288
- type: 'string',
4289
- description: 'Locale code',
4290
- example: 'en-US'
4291
- },
4292
- projectedTotalAmount: {
4484
+ totalOutflow: {
4293
4485
  type: 'number',
4294
- description: 'Projected total amount',
4295
- example: 1000000
4296
- },
4297
- retirementDate: {
4298
- type: 'string',
4299
- description: 'Retirement date in ISO 8601 format',
4300
- example: '2050-01-01'
4486
+ description: 'Total expected outflow across all months',
4487
+ example: 25500
4301
4488
  },
4302
- savingsRate: {
4303
- type: 'number',
4304
- description: 'Savings rate percentage',
4305
- example: 0.2
4489
+ totalByCurrency: {
4490
+ type: 'object',
4491
+ description: 'Total by currency across all months',
4492
+ example: {
4493
+ CNY: 25500,
4494
+ USD: 300
4495
+ }
4306
4496
  },
4307
- viewMode: {
4308
- type: 'string',
4309
- description: 'View mode',
4310
- enum: ['DEFAULT', 'ZEN']
4311
- }
4312
- }
4313
- } as const;
4314
-
4315
- export const $UpdatePropertyDto = {
4316
- type: 'object',
4317
- properties: {
4318
- value: {
4497
+ rulesCount: {
4498
+ type: 'number',
4499
+ description: 'Number of active recurring rules included',
4500
+ example: 5
4501
+ },
4502
+ periodStart: {
4319
4503
  type: 'string',
4320
- description: 'Property value'
4504
+ description: 'Forecast period start date',
4505
+ example: '2024-04-01'
4506
+ },
4507
+ periodEnd: {
4508
+ type: 'string',
4509
+ description: 'Forecast period end date',
4510
+ example: '2024-06-30'
4321
4511
  }
4322
4512
  },
4323
- required: ['value']
4513
+ required: [
4514
+ 'forecast',
4515
+ 'totalOutflow',
4516
+ 'totalByCurrency',
4517
+ 'rulesCount',
4518
+ 'periodStart',
4519
+ 'periodEnd'
4520
+ ]
4324
4521
  } as const;
4325
4522
 
4326
4523
  export const $CreateTransactionRuleDto = {
@@ -4882,7 +5079,8 @@ export const $UpdateTransactionRuleDto = {
4882
5079
  },
4883
5080
  matchLogic: {
4884
5081
  type: 'string',
4885
- enum: ['OR', 'AND']
5082
+ enum: ['OR', 'AND'],
5083
+ default: 'OR'
4886
5084
  },
4887
5085
  amountMin: {
4888
5086
  type: 'number',
@@ -4896,13 +5094,10 @@ export const $UpdateTransactionRuleDto = {
4896
5094
  },
4897
5095
  priority: {
4898
5096
  type: 'number',
5097
+ default: 50,
4899
5098
  minimum: 0,
4900
5099
  maximum: 1000
4901
5100
  },
4902
- enabled: {
4903
- type: 'boolean',
4904
- description: 'Enable or disable the rule'
4905
- },
4906
5101
  additionalTags: {
4907
5102
  items: {
4908
5103
  type: 'array'
@@ -4912,6 +5107,10 @@ export const $UpdateTransactionRuleDto = {
4912
5107
  },
4913
5108
  additionalMetadata: {
4914
5109
  type: 'object'
5110
+ },
5111
+ enabled: {
5112
+ type: 'boolean',
5113
+ description: 'Enable or disable the rule'
4915
5114
  }
4916
5115
  }
4917
5116
  } as const;
@@ -6217,8 +6416,27 @@ export const $ProcessNlpDto = {
6217
6416
  selectedAccount: {
6218
6417
  type: 'string',
6219
6418
  description:
6220
- '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.',
6419
+ '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.',
6221
6420
  example: 'Expenses:Food:Coffee'
6421
+ },
6422
+ viewpointAccount: {
6423
+ type: 'string',
6424
+ description:
6425
+ '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.',
6426
+ example: 'Assets:CN:Bank:ICBC'
6427
+ },
6428
+ viewpointCategory: {
6429
+ type: 'string',
6430
+ description:
6431
+ "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.",
6432
+ example: 'Food'
6433
+ },
6434
+ viewpointFlow: {
6435
+ type: 'string',
6436
+ description:
6437
+ "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.",
6438
+ enum: ['income', 'expense'],
6439
+ example: 'expense'
6222
6440
  }
6223
6441
  }
6224
6442
  } as const;
@@ -6532,6 +6750,24 @@ export const $NlpRuleConfirmationDataDto = {
6532
6750
  ]
6533
6751
  } as const;
6534
6752
 
6753
+ export const $NlpAccountCandidateDto = {
6754
+ type: 'object',
6755
+ properties: {
6756
+ path: {
6757
+ type: 'string',
6758
+ description: 'Canonical beancount account path (echo back on selection)',
6759
+ example: 'Expenses:Food:Dining'
6760
+ },
6761
+ name: {
6762
+ type: 'string',
6763
+ description:
6764
+ 'Localized display name (ADR-0114 read-time projection, user locale)',
6765
+ example: '餐饮'
6766
+ }
6767
+ },
6768
+ required: ['path', 'name']
6769
+ } as const;
6770
+
6535
6771
  export const $NlpAccountConfirmationDataDto = {
6536
6772
  type: 'object',
6537
6773
  properties: {
@@ -6547,10 +6783,11 @@ export const $NlpAccountConfirmationDataDto = {
6547
6783
  example: 'Expenses:Food:Drinks'
6548
6784
  },
6549
6785
  similarAccounts: {
6550
- description: 'Similar accounts for user selection',
6786
+ description:
6787
+ 'Similar accounts for user selection (path + localized name, #680)',
6551
6788
  type: 'array',
6552
6789
  items: {
6553
- type: 'string'
6790
+ $ref: '#/components/schemas/NlpAccountCandidateDto'
6554
6791
  }
6555
6792
  },
6556
6793
  errorMessage: {
@@ -6838,7 +7075,7 @@ export const $NlpResponseDto = {
6838
7075
  type: 'string',
6839
7076
  description:
6840
7077
  'Asset sub-type (only present when intent is "asset"). Determines which asset-related form to render.',
6841
- enum: ['transfer', 'banking', 'investment'],
7078
+ enum: ['transfer', 'banking', 'investment', 'lend', 'lend_collect'],
6842
7079
  example: 'investment'
6843
7080
  },
6844
7081
  liabilitySubType: {
@@ -7178,6 +7415,79 @@ export const $PlatformMatchResponseDto = {
7178
7415
  required: ['platforms', 'matchType', 'total', 'hasMore']
7179
7416
  } as const;
7180
7417
 
7418
+ export const $PlatformStandardsPlatformDto = {
7419
+ type: 'object',
7420
+ properties: {
7421
+ id: {
7422
+ type: 'string',
7423
+ description: 'Global platform ID'
7424
+ },
7425
+ name: {
7426
+ type: 'string',
7427
+ description: 'Platform name (e.g., "ICBC")'
7428
+ },
7429
+ canonical: {
7430
+ type: 'string',
7431
+ description: 'Canonical identifier in ACCOUNT_RE format (e.g., "icbc")'
7432
+ },
7433
+ suggestedSegment: {
7434
+ type: 'string',
7435
+ description:
7436
+ 'Suggested path segment — canonical PascalCased per hyphen-part, hyphens preserved (e.g. "Apple-Pay")'
7437
+ },
7438
+ type: {
7439
+ type: 'string',
7440
+ description: 'Platform type',
7441
+ enum: [
7442
+ 'BANK',
7443
+ 'BROKERAGE',
7444
+ 'CRYPTO_EXCHANGE',
7445
+ 'PAYMENT',
7446
+ 'INVESTMENT',
7447
+ 'INSURANCE',
7448
+ 'OTHER'
7449
+ ]
7450
+ },
7451
+ category: {
7452
+ type: 'string',
7453
+ description:
7454
+ 'Region-aware category (institution vocab, e.g. DigitalWallet/Bank) resolved against the final region. null = no region-aware suggestion; fall back to type.',
7455
+ nullable: true,
7456
+ example: 'Bank'
7457
+ }
7458
+ },
7459
+ required: ['id', 'name', 'canonical', 'suggestedSegment', 'type', 'category']
7460
+ } as const;
7461
+
7462
+ export const $PlatformStandardsResponseDto = {
7463
+ type: 'object',
7464
+ properties: {
7465
+ platform: {
7466
+ description: 'The selected platform (institution lock source)',
7467
+ allOf: [
7468
+ {
7469
+ $ref: '#/components/schemas/PlatformStandardsPlatformDto'
7470
+ }
7471
+ ]
7472
+ },
7473
+ region: {
7474
+ type: 'string',
7475
+ description:
7476
+ "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.",
7477
+ example: 'CN'
7478
+ },
7479
+ templates: {
7480
+ description:
7481
+ 'Candidate account-standard templates of the resolved region (groupable by productCategory client-side)',
7482
+ type: 'array',
7483
+ items: {
7484
+ $ref: '#/components/schemas/AccountStandardResponseDto'
7485
+ }
7486
+ }
7487
+ },
7488
+ required: ['platform', 'region', 'templates']
7489
+ } as const;
7490
+
7181
7491
  export const $CreatePlatformDto = {
7182
7492
  type: 'object',
7183
7493
  properties: {
@@ -7279,7 +7589,8 @@ export const $UpdatePlatformDto = {
7279
7589
  },
7280
7590
  isActive: {
7281
7591
  type: 'boolean',
7282
- description: 'Whether the platform is active'
7592
+ description: 'Whether the platform is active',
7593
+ default: true
7283
7594
  }
7284
7595
  }
7285
7596
  } as const;
@@ -7478,7 +7789,8 @@ export const $PlatformGroupDto = {
7478
7789
  example: 'CMB Bank'
7479
7790
  },
7480
7791
  accounts: {
7481
- description: 'Accounts within this platform',
7792
+ description:
7793
+ 'Accounts within this platform (Assets and Liabilities rows, #696)',
7482
7794
  type: 'array',
7483
7795
  items: {
7484
7796
  $ref: '#/components/schemas/AccountItemDto'
@@ -7486,7 +7798,8 @@ export const $PlatformGroupDto = {
7486
7798
  },
7487
7799
  totalBalance: {
7488
7800
  type: 'string',
7489
- description: 'FX-converted total balance in base currency',
7801
+ description:
7802
+ 'FX-converted total balance in base currency (nets Assets + Liabilities rows; can be negative)',
7490
7803
  example: '100000.00'
7491
7804
  },
7492
7805
  balanceByCurrency: {
@@ -7505,7 +7818,7 @@ export const $PlatformGroupDto = {
7505
7818
  sharePct: {
7506
7819
  type: 'number',
7507
7820
  description:
7508
- 'Share of the grand converted total (0-100); 0 when grand total is 0',
7821
+ 'Share of the converted asset-side grand total (0-100); liability balances are excluded from the basis; 0 when grand total is 0 (#696)',
7509
7822
  example: 42.5
7510
7823
  }
7511
7824
  },
@@ -7553,7 +7866,8 @@ export const $AccountsSummaryDto = {
7553
7866
  properties: {
7554
7867
  totalAccounts: {
7555
7868
  type: 'number',
7556
- description: 'Total number of accounts'
7869
+ description:
7870
+ 'Total number of accounts (balance sheet: Assets + Liabilities, #696)'
7557
7871
  },
7558
7872
  totalPlatforms: {
7559
7873
  type: 'number',
@@ -8395,6 +8709,216 @@ export const $AnonymousLoginResponseDto = {
8395
8709
  required: ['authToken']
8396
8710
  } as const;
8397
8711
 
8712
+ export const $ParserContributionMetaDto = {
8713
+ type: 'object',
8714
+ properties: {
8715
+ institution: {
8716
+ type: 'string',
8717
+ description: 'Institution slug (lowercase kebab-case)',
8718
+ pattern: '^[a-z0-9]+(-[a-z0-9]+)*$',
8719
+ example: 'icbc'
8720
+ },
8721
+ region: {
8722
+ type: 'string',
8723
+ enum: [
8724
+ 'cn',
8725
+ 'us',
8726
+ 'de',
8727
+ 'fr',
8728
+ 'gb',
8729
+ 'hk',
8730
+ 'jp',
8731
+ 'sg',
8732
+ 'au',
8733
+ 'ca',
8734
+ 'other'
8735
+ ]
8736
+ },
8737
+ accountType: {
8738
+ type: 'string',
8739
+ enum: ['checking', 'savings', 'credit', 'debit', 'investment']
8740
+ },
8741
+ format: {
8742
+ type: 'string',
8743
+ enum: ['csv', 'xlsx', 'pdf', 'ofx', 'qif']
8744
+ },
8745
+ institutionDisplayName: {
8746
+ type: 'string',
8747
+ example: '中国工商银行'
8748
+ },
8749
+ encoding: {
8750
+ type: 'string',
8751
+ example: 'utf-8'
8752
+ },
8753
+ delimiter: {
8754
+ type: 'string',
8755
+ description: 'CSV delimiter character: ",", ";", "\\t" or "|"'
8756
+ },
8757
+ headerRows: {
8758
+ type: 'number',
8759
+ default: 1,
8760
+ description: 'Header row count; the client omits the field when it is 1'
8761
+ },
8762
+ notes: {
8763
+ type: 'string',
8764
+ maxLength: 2000
8765
+ }
8766
+ },
8767
+ required: ['institution', 'region', 'accountType', 'format']
8768
+ } as const;
8769
+
8770
+ export const $ParserContributionSamplesDto = {
8771
+ type: 'object',
8772
+ properties: {
8773
+ rows: {
8774
+ description:
8775
+ 'Client-sanitized sample rows (key = column name, value = cell)',
8776
+ type: 'array',
8777
+ items: {
8778
+ type: 'object'
8779
+ }
8780
+ },
8781
+ rawHeaders: {
8782
+ type: 'array',
8783
+ items: {
8784
+ type: 'string'
8785
+ }
8786
+ }
8787
+ },
8788
+ required: ['rows']
8789
+ } as const;
8790
+
8791
+ export const $FieldHintDto = {
8792
+ type: 'object',
8793
+ properties: {
8794
+ columnName: {
8795
+ type: 'string',
8796
+ example: '交易日期'
8797
+ },
8798
+ format: {
8799
+ type: 'string',
8800
+ description: 'Date format, e.g. yyyy-MM-dd HH:mm',
8801
+ example: 'yyyy-MM-dd'
8802
+ },
8803
+ signConvention: {
8804
+ type: 'string',
8805
+ enum: ['negative-expense', 'positive-expense', 'separate-columns']
8806
+ },
8807
+ creditColumn: {
8808
+ type: 'string'
8809
+ },
8810
+ debitColumn: {
8811
+ type: 'string'
8812
+ }
8813
+ },
8814
+ required: ['columnName']
8815
+ } as const;
8816
+
8817
+ export const $ParserContributionFieldHintsDto = {
8818
+ type: 'object',
8819
+ properties: {
8820
+ date: {
8821
+ $ref: '#/components/schemas/FieldHintDto'
8822
+ },
8823
+ amount: {
8824
+ $ref: '#/components/schemas/FieldHintDto'
8825
+ },
8826
+ description: {
8827
+ $ref: '#/components/schemas/FieldHintDto'
8828
+ },
8829
+ balance: {
8830
+ $ref: '#/components/schemas/FieldHintDto'
8831
+ },
8832
+ payee: {
8833
+ $ref: '#/components/schemas/FieldHintDto'
8834
+ },
8835
+ reference: {
8836
+ $ref: '#/components/schemas/FieldHintDto'
8837
+ },
8838
+ category: {
8839
+ $ref: '#/components/schemas/FieldHintDto'
8840
+ }
8841
+ },
8842
+ required: ['date', 'amount']
8843
+ } as const;
8844
+
8845
+ export const $ExpectedTransactionDto = {
8846
+ type: 'object',
8847
+ properties: {
8848
+ date: {
8849
+ type: 'string',
8850
+ example: '2026-08-01'
8851
+ },
8852
+ amount: {
8853
+ type: 'number',
8854
+ example: -45.5
8855
+ },
8856
+ description: {
8857
+ type: 'string',
8858
+ example: '星巴克-***店'
8859
+ },
8860
+ payee: {
8861
+ type: 'string'
8862
+ },
8863
+ category: {
8864
+ type: 'string'
8865
+ }
8866
+ },
8867
+ required: ['date', 'amount', 'description']
8868
+ } as const;
8869
+
8870
+ export const $ParserContributionExamplesDto = {
8871
+ type: 'object',
8872
+ properties: {
8873
+ expectedTransactions: {
8874
+ type: 'array',
8875
+ items: {
8876
+ $ref: '#/components/schemas/ExpectedTransactionDto'
8877
+ }
8878
+ }
8879
+ },
8880
+ required: ['expectedTransactions']
8881
+ } as const;
8882
+
8883
+ export const $ParserContributionRequestDto = {
8884
+ type: 'object',
8885
+ properties: {
8886
+ meta: {
8887
+ $ref: '#/components/schemas/ParserContributionMetaDto'
8888
+ },
8889
+ samples: {
8890
+ $ref: '#/components/schemas/ParserContributionSamplesDto'
8891
+ },
8892
+ fieldHints: {
8893
+ $ref: '#/components/schemas/ParserContributionFieldHintsDto'
8894
+ },
8895
+ examples: {
8896
+ description: 'Omitted entirely by the client when empty',
8897
+ allOf: [
8898
+ {
8899
+ $ref: '#/components/schemas/ParserContributionExamplesDto'
8900
+ }
8901
+ ]
8902
+ }
8903
+ },
8904
+ required: ['meta', 'samples', 'fieldHints']
8905
+ } as const;
8906
+
8907
+ export const $ParserContributionRelayResponseDto = {
8908
+ type: 'object',
8909
+ properties: {
8910
+ issueUrl: {
8911
+ type: 'string',
8912
+ example: 'https://github.com/fire-zu/firela-vlt/issues/42'
8913
+ },
8914
+ issueNumber: {
8915
+ type: 'number',
8916
+ example: 42
8917
+ }
8918
+ },
8919
+ required: ['issueUrl', 'issueNumber']
8920
+ } as const;
8921
+
8398
8922
  export const $SymbolSearchResultDto = {
8399
8923
  type: 'object',
8400
8924
  properties: {