@firela/api-types 0.0.0-canary.6a42fd0e → 0.0.0-canary.6af2ffd3

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.
@@ -6,18 +6,12 @@ export const $CreateAccountDto = {
6
6
  path: {
7
7
  type: 'string',
8
8
  description: 'Account path (hierarchical, colon-separated)',
9
- example: 'Assets:CN:Bank:ICBC:Checking'
10
- },
11
- displayName: {
12
- type: 'string',
13
- description:
14
- 'Display name to distinguish accounts at the same path (default: "")',
15
- example: '工资卡'
9
+ example: 'Assets:CN:ICBC:Checking'
16
10
  },
17
11
  openDate: {
18
12
  format: 'date-time',
19
13
  type: 'string',
20
- description: 'Account open date',
14
+ description: 'Account open date (server defaults to today)',
21
15
  example: '2024-01-01'
22
16
  },
23
17
  currencies: {
@@ -45,26 +39,30 @@ export const $CreateAccountDto = {
45
39
  templatePath: {
46
40
  type: 'string',
47
41
  description: 'Reference to account-standards template path',
48
- example: 'Assets:CN:Bank:ICBC:Checking'
42
+ example: 'Assets:CN:Checking'
49
43
  },
50
44
  isCustom: {
51
45
  type: 'boolean',
52
46
  description: 'Whether this is a custom (user-created) account',
53
47
  default: false
54
48
  },
55
- i18nKey: {
56
- type: 'string',
57
- description: 'i18n key for display name (overrides template)',
58
- example: 'account.custom.mybank'
59
- },
60
49
  icon: {
61
50
  type: 'string',
62
51
  description: 'Icon identifier (overrides template)',
63
52
  example: 'bank-custom'
64
53
  },
65
- openMeta: {
54
+ displayName: {
55
+ type: 'string',
56
+ description:
57
+ 'User-set display name override (omit/null = keep the derived name)',
58
+ nullable: true,
59
+ maxLength: 50,
60
+ example: 'Salary card'
61
+ },
62
+ openDirectiveMeta: {
66
63
  type: 'object',
67
- description: 'Additional metadata',
64
+ description:
65
+ 'Open directive metadata (NOT an opening-balance amount — use the opening-balance endpoint)',
68
66
  example: {
69
67
  branch: 'Downtown',
70
68
  accountNumber: '1234'
@@ -76,7 +74,7 @@ export const $CreateAccountDto = {
76
74
  example: 'c98e5d4a-2f71-4a5a-bb3c-92c9f231d5e2'
77
75
  }
78
76
  },
79
- required: ['path', 'openDate']
77
+ required: ['path']
80
78
  } as const;
81
79
 
82
80
  export const $AccountResponseDto = {
@@ -90,13 +88,7 @@ export const $AccountResponseDto = {
90
88
  path: {
91
89
  type: 'string',
92
90
  description: 'Account path (hierarchical, colon-separated)',
93
- example: 'Assets:CN:Bank:ICBC:Checking'
94
- },
95
- displayName: {
96
- type: 'string',
97
- description:
98
- 'Display name distinguishing multiple accounts at the same path',
99
- example: '工资卡'
91
+ example: 'Assets:CN:ICBC:Checking'
100
92
  },
101
93
  type: {
102
94
  type: 'string',
@@ -104,6 +96,49 @@ export const $AccountResponseDto = {
104
96
  enum: ['Assets', 'Liabilities', 'Income', 'Expenses', 'Equity'],
105
97
  example: 'Assets'
106
98
  },
99
+ assetSubClass: {
100
+ type: 'string',
101
+ description:
102
+ 'Account-level asset sub-class (product type, e.g. STOCK/DEPOSIT/CREDIT_CARD/PERSONAL_LOAN). Computed from the account path via the asset-classifier (ADR-0077). Null for non-asset accounts (Income/Expenses/Equity) or unmatched paths.',
103
+ enum: [
104
+ 'DEPOSIT',
105
+ 'CASH',
106
+ 'MONEY_MARKET_FUND',
107
+ 'STOCK',
108
+ 'ETF',
109
+ 'MUTUAL_FUND',
110
+ 'EQUITY_COMPENSATION',
111
+ 'GOVERNMENT_BOND',
112
+ 'CORPORATE_BOND',
113
+ 'BOND_FUND',
114
+ 'PRIMARY_RESIDENCE',
115
+ 'INVESTMENT_PROPERTY',
116
+ 'REIT',
117
+ 'GOLD',
118
+ 'SILVER',
119
+ 'PRECIOUS_METAL',
120
+ 'PRECIOUS_METAL_FUND',
121
+ 'COMMODITY',
122
+ 'COMMODITY_FUND',
123
+ 'CRYPTOCURRENCY',
124
+ 'RETIREMENT_ACCOUNT',
125
+ 'HEALTH_ACCOUNT',
126
+ 'EDUCATION_ACCOUNT',
127
+ 'INSURANCE',
128
+ 'PRIVATE_EQUITY',
129
+ 'HEDGE_FUND',
130
+ 'COLLECTIBLES',
131
+ 'MORTGAGE',
132
+ 'STUDENT_LOAN',
133
+ 'CREDIT_CARD',
134
+ 'PERSONAL_LOAN',
135
+ 'ACCOUNTS_PAYABLE',
136
+ 'TAX_PAYABLE',
137
+ 'OTHER'
138
+ ],
139
+ nullable: true,
140
+ example: 'STOCK'
141
+ },
107
142
  status: {
108
143
  type: 'string',
109
144
  description: 'Account status',
@@ -145,32 +180,33 @@ export const $AccountResponseDto = {
145
180
  templatePath: {
146
181
  type: 'string',
147
182
  description: 'Template path reference',
148
- example: 'Assets:CN:Bank:ICBC:Checking'
183
+ example: 'Assets:CN:Checking'
149
184
  },
150
185
  isCustom: {
151
186
  type: 'boolean',
152
187
  description: 'Whether this is a custom (user-created) account',
153
188
  example: false
154
189
  },
155
- i18nKey: {
190
+ displayName: {
156
191
  type: 'string',
157
- description: 'i18n key for display name',
158
- example: 'account.assets.cn.bank.icbc.checking'
192
+ description:
193
+ 'Display name with precedence: user-set name (#762) > ADR-0114 localized name > path leaf (read-time projection)',
194
+ example: 'Checking'
159
195
  },
160
196
  icon: {
161
197
  type: 'string',
162
198
  description: 'Icon identifier',
163
199
  example: 'bank-icbc'
164
200
  },
165
- openMeta: {
201
+ openDirectiveMeta: {
166
202
  type: 'object',
167
- description: 'Account metadata',
203
+ description: 'Open directive metadata (ADR-0115 Decision 9)',
168
204
  example: {
169
205
  branch: 'Downtown'
170
206
  }
171
207
  },
172
208
  platformId: {
173
- type: 'object',
209
+ type: 'string',
174
210
  description: 'Platform ID (null if unbound)',
175
211
  example: 'c98e5d4a-2f71-4a5a-bb3c-92c9f231d5e2'
176
212
  },
@@ -192,7 +228,6 @@ export const $AccountResponseDto = {
192
228
  required: [
193
229
  'id',
194
230
  'path',
195
- 'displayName',
196
231
  'type',
197
232
  'status',
198
233
  'openDate',
@@ -225,11 +260,6 @@ export const $AccountListResponseDto = {
225
260
  export const $UpdateAccountDto = {
226
261
  type: 'object',
227
262
  properties: {
228
- displayName: {
229
- type: 'string',
230
- description: 'Display name to distinguish accounts at the same path',
231
- example: '招行工资卡'
232
- },
233
263
  currencies: {
234
264
  description: 'Allowed currencies (null = no restriction)',
235
265
  example: ['CNY', 'USD'],
@@ -251,19 +281,23 @@ export const $UpdateAccountDto = {
251
281
  'NONE'
252
282
  ]
253
283
  },
254
- i18nKey: {
255
- type: 'string',
256
- description: 'i18n key for display name',
257
- example: 'account.custom.mybank'
258
- },
259
284
  icon: {
260
285
  type: 'string',
261
286
  description: 'Icon identifier',
262
287
  example: 'bank-custom'
263
288
  },
264
- openMeta: {
289
+ displayName: {
290
+ type: 'string',
291
+ description:
292
+ 'User-set display name override (null = clear the override and fall back to the derived name, omit = unchanged)',
293
+ nullable: true,
294
+ maxLength: 50,
295
+ example: 'Salary card'
296
+ },
297
+ openDirectiveMeta: {
265
298
  type: 'object',
266
- description: 'Additional metadata (merged with existing)',
299
+ description:
300
+ 'Open directive metadata (merged with existing; NOT an opening-balance amount)',
267
301
  example: {
268
302
  branch: 'Uptown'
269
303
  }
@@ -310,13 +344,47 @@ export const $ReopenAccountDto = {
310
344
  }
311
345
  } as const;
312
346
 
347
+ export const $CreateOpeningBalanceDto = {
348
+ type: 'object',
349
+ properties: {
350
+ amount: {
351
+ type: 'number',
352
+ description: 'Opening balance amount (non-negative)',
353
+ example: 1000
354
+ },
355
+ currency: {
356
+ type: 'string',
357
+ description: 'Currency code',
358
+ example: 'CNY'
359
+ },
360
+ date: {
361
+ format: 'date-time',
362
+ type: 'string',
363
+ description: 'Opening-balance date (defaults to now)',
364
+ example: '2024-01-01'
365
+ }
366
+ },
367
+ required: ['amount', 'currency']
368
+ } as const;
369
+
370
+ export const $OpeningBalanceResultDto = {
371
+ type: 'object',
372
+ properties: {
373
+ transactionId: {
374
+ type: 'string',
375
+ description: 'Created opening-balance transaction id.'
376
+ }
377
+ },
378
+ required: ['transactionId']
379
+ } as const;
380
+
313
381
  export const $AccountStandardResponseDto = {
314
382
  type: 'object',
315
383
  properties: {
316
384
  path: {
317
385
  type: 'string',
318
386
  description: 'Account path (hierarchical, colon-separated)',
319
- example: 'Assets:CN:Bank:ICBC:Checking'
387
+ example: 'Assets:CN:Checking'
320
388
  },
321
389
  type: {
322
390
  type: 'string',
@@ -324,23 +392,45 @@ export const $AccountStandardResponseDto = {
324
392
  enum: ['Assets', 'Liabilities', 'Income', 'Expenses', 'Equity'],
325
393
  example: 'Assets'
326
394
  },
327
- i18nKey: {
328
- type: 'string',
329
- description: 'i18n key for localized display name',
330
- example: 'account.assets.cn.bank.icbc.checking'
331
- },
332
395
  name: {
333
396
  type: 'string',
334
- description: 'Short localized display name',
397
+ description:
398
+ '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).',
335
399
  example: 'Housing Fund'
336
400
  },
401
+ aliases: {
402
+ description:
403
+ '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.',
404
+ example: ['Alipay', 'WeChat Pay'],
405
+ type: 'array',
406
+ items: {
407
+ type: 'string'
408
+ }
409
+ },
410
+ searchTerms: {
411
+ description:
412
+ '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).',
413
+ example: ['yinhangka', 'jiejika'],
414
+ type: 'array',
415
+ items: {
416
+ type: 'string'
417
+ }
418
+ },
419
+ currency: {
420
+ type: 'string',
421
+ description:
422
+ '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).',
423
+ example: 'HKD'
424
+ },
337
425
  description: {
338
426
  type: 'string',
339
- description: 'Account description (stable semantics only)',
427
+ description:
428
+ '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).',
340
429
  example: 'ICBC checking account for daily transactions'
341
430
  },
342
431
  tags: {
343
- description: 'Account tags for categorization',
432
+ description:
433
+ 'Account tags for categorization — structured metadata delivered verbatim (not localized, not xlf-managed). ADR-0131 class A.',
344
434
  example: ['bank', 'checking', 'primary'],
345
435
  type: 'array',
346
436
  items: {
@@ -351,9 +441,47 @@ export const $AccountStandardResponseDto = {
351
441
  type: 'string',
352
442
  description: 'Icon identifier for UI display',
353
443
  example: 'bank-icbc'
444
+ },
445
+ productCategory: {
446
+ type: 'string',
447
+ description:
448
+ 'Onboarding product category (coarse grouping derived from assetSubClass)',
449
+ enum: [
450
+ 'cash',
451
+ 'investment',
452
+ 'credit_card',
453
+ 'loan',
454
+ 'payable_tax',
455
+ 'other'
456
+ ],
457
+ example: 'investment'
458
+ },
459
+ assetClass: {
460
+ type: 'string',
461
+ description:
462
+ 'Asset class (LIQUIDITY/EQUITY/.../LIABILITY), derived at read time from classification rules',
463
+ enum: [
464
+ 'LIQUIDITY',
465
+ 'EQUITY',
466
+ 'FIXED_INCOME',
467
+ 'PRECIOUS_METALS',
468
+ 'COMMODITY',
469
+ 'INSURANCE',
470
+ 'ALTERNATIVE_INVESTMENT',
471
+ 'PERSONAL_ASSETS',
472
+ 'LIABILITY',
473
+ 'REAL_ESTATE',
474
+ 'INDEX'
475
+ ]
476
+ },
477
+ assetSubClass: {
478
+ type: 'string',
479
+ description:
480
+ 'Asset sub-class (product type, derived at read time from classification rules)',
481
+ example: 'STOCK'
354
482
  }
355
483
  },
356
- required: ['path', 'type', 'i18nKey', 'description', 'tags', 'icon']
484
+ required: ['path', 'type', 'description', 'tags', 'icon', 'productCategory']
357
485
  } as const;
358
486
 
359
487
  export const $AccountStandardListResponseDto = {
@@ -383,18 +511,13 @@ export const $AccountStandardListResponseDto = {
383
511
  export const $TemplateMetadataDto = {
384
512
  type: 'object',
385
513
  properties: {
386
- extendable: {
387
- type: 'boolean',
388
- description: 'Whether this path can be extended',
389
- example: true
390
- },
391
514
  rootType: {
392
515
  type: 'string',
393
516
  description: 'Root account type',
394
517
  example: 'Assets'
395
518
  }
396
519
  },
397
- required: ['extendable', 'rootType']
520
+ required: ['rootType']
398
521
  } as const;
399
522
 
400
523
  export const $TemplateMetadataResponseDto = {
@@ -419,7 +542,10 @@ export const $RegionConfigDto = {
419
542
  },
420
543
  locale: {
421
544
  type: 'string',
422
- example: 'de-DE'
545
+ example: 'de-DE',
546
+ pattern: '^[a-z]{2,8}-[A-Z]{2}$',
547
+ description:
548
+ "Region-qualified BCP-47 tag whose region subtag equals the region's own ISO 3166-1 code (e.g., ja-JP, zh-CN, zh-HK)"
423
549
  }
424
550
  },
425
551
  required: ['currency', 'dateFormat', 'locale']
@@ -432,6 +558,12 @@ export const $RegionInfoDto = {
432
558
  type: 'string',
433
559
  example: 'de'
434
560
  },
561
+ open: {
562
+ type: 'boolean',
563
+ example: true,
564
+ description:
565
+ 'Whether the region is open (has a ready regional account template). Not-yet-open regions still return identity metadata and degrade to the universal-only catalog.'
566
+ },
435
567
  displayName: {
436
568
  type: 'string',
437
569
  example: 'Germany'
@@ -450,7 +582,7 @@ export const $RegionInfoDto = {
450
582
  $ref: '#/components/schemas/RegionConfigDto'
451
583
  }
452
584
  },
453
- required: ['code', 'displayName', 'chain', 'config']
585
+ required: ['code', 'open', 'displayName', 'chain', 'config']
454
586
  } as const;
455
587
 
456
588
  export const $RegionsMetadataResponseDto = {
@@ -533,7 +665,7 @@ export const $CreatePostingDto = {
533
665
  type: 'string',
534
666
  description:
535
667
  'Account name in Beancount format (must start with uppercase, colon-separated)',
536
- example: 'Assets:Bank:Checking'
668
+ example: 'Assets:Checking'
537
669
  },
538
670
  units: {
539
671
  type: 'string',
@@ -692,12 +824,12 @@ export const $PostingResponseDto = {
692
824
  account: {
693
825
  type: 'string',
694
826
  description: 'Account name',
695
- example: 'Assets:Bank:Checking'
827
+ example: 'Assets:Checking'
696
828
  },
697
829
  units: {
698
830
  type: 'string',
699
831
  description:
700
- 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned.',
832
+ '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.',
701
833
  example: '100.50'
702
834
  },
703
835
  currency: {
@@ -1058,12 +1190,12 @@ export const $PostingDetailDto = {
1058
1190
  account: {
1059
1191
  type: 'string',
1060
1192
  description: 'Fully-qualified Beancount account path',
1061
- example: 'Assets:Bank:Checking'
1193
+ example: 'Assets:Checking'
1062
1194
  },
1063
1195
  units: {
1064
1196
  type: 'string',
1065
1197
  description:
1066
- 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned.',
1198
+ '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.',
1067
1199
  example: '100.50'
1068
1200
  },
1069
1201
  currency: {
@@ -1247,93 +1379,254 @@ export const $TransactionDetailDto = {
1247
1379
  ]
1248
1380
  } as const;
1249
1381
 
1250
- export const $BalanceByCurrencyDto = {
1382
+ export const $TransactionListItemDto = {
1251
1383
  type: 'object',
1252
1384
  properties: {
1253
- currency: {
1385
+ id: {
1254
1386
  type: 'string',
1255
- description: 'ISO 4217 currency code',
1256
- example: 'CNY'
1387
+ description: 'Transaction ID',
1388
+ example: 'clh1234567890abcdef'
1257
1389
  },
1258
- balance: {
1259
- type: 'string',
1260
- description: 'Balance amount',
1261
- example: '50000.00'
1262
- }
1263
- },
1264
- required: ['currency', 'balance']
1265
- } as const;
1266
-
1267
- export const $ExchangeRateWarningDto = {
1268
- type: 'object',
1269
- properties: {
1270
- type: {
1390
+ date: {
1271
1391
  type: 'string',
1272
- description: 'Warning type',
1273
- example: 'MISSING_EXCHANGE_RATE'
1392
+ description: 'Transaction date',
1393
+ example: '2024-11-28'
1274
1394
  },
1275
- currency: {
1395
+ flag: {
1276
1396
  type: 'string',
1277
- description: 'Currency without exchange rate',
1278
- example: 'EUR'
1397
+ description: 'Transaction flag',
1398
+ enum: [
1399
+ 'CLEARED',
1400
+ 'PENDING',
1401
+ 'PADDING',
1402
+ 'SUMMARIZE',
1403
+ 'TRANSFER',
1404
+ 'CONVERSIONS'
1405
+ ],
1406
+ example: 'CLEARED'
1279
1407
  },
1280
- totalAmount: {
1408
+ customFlag: {
1281
1409
  type: 'string',
1282
- description: 'Total amount affected',
1283
- example: '1000.00'
1284
- }
1285
- },
1286
- required: ['type', 'currency', 'totalAmount']
1287
- } as const;
1288
-
1289
- export const $TransactionListSummaryDto = {
1290
- type: 'object',
1291
- properties: {
1292
- totalAmount: {
1410
+ description: 'Custom flag (if not using standard flags)',
1411
+ example: 'R'
1412
+ },
1413
+ payee: {
1293
1414
  type: 'string',
1294
- description:
1295
- '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.',
1296
- example: '-6000.00'
1415
+ description: 'Payee name',
1416
+ example: 'Whole Foods Market'
1297
1417
  },
1298
- currency: {
1418
+ narration: {
1299
1419
  type: 'string',
1300
- description: 'Base currency (ISO 4217)',
1301
- example: 'CNY'
1420
+ description: 'Transaction narration',
1421
+ example: 'Grocery shopping'
1302
1422
  },
1303
- balanceByCurrency: {
1304
- description: 'Raw (unconverted) balance per currency',
1423
+ tags: {
1424
+ description: 'Transaction tags',
1425
+ example: ['groceries'],
1305
1426
  type: 'array',
1306
1427
  items: {
1307
- $ref: '#/components/schemas/BalanceByCurrencyDto'
1428
+ type: 'string'
1308
1429
  }
1309
1430
  },
1310
- warnings: {
1311
- description: 'Currencies missing an FX rate (omitted when empty)',
1431
+ links: {
1432
+ description: 'Transaction links',
1433
+ example: ['invoice-2024-001'],
1312
1434
  type: 'array',
1313
1435
  items: {
1314
- $ref: '#/components/schemas/ExchangeRateWarningDto'
1436
+ type: 'string'
1315
1437
  }
1316
- }
1317
- },
1318
- required: ['totalAmount', 'currency', 'balanceByCurrency']
1319
- } as const;
1320
-
1321
- export const $TransactionListResponseDto = {
1322
- type: 'object',
1323
- properties: {
1324
- data: {
1325
- description: 'List of transactions',
1438
+ },
1439
+ meta: {
1440
+ type: 'object',
1441
+ description: 'Transaction metadata'
1442
+ },
1443
+ status: {
1444
+ type: 'string',
1445
+ description: 'Transaction status',
1446
+ enum: ['ACTIVE', 'VOIDED', 'SUPERSEDED'],
1447
+ example: 'ACTIVE'
1448
+ },
1449
+ sourceType: {
1450
+ type: 'string',
1451
+ description:
1452
+ 'Source type (free-form string from transaction metadata, e.g. import, api)'
1453
+ },
1454
+ sourcePlatform: {
1455
+ type: 'string',
1456
+ description: 'Source platform (e.g., alipay, wechat)',
1457
+ example: 'alipay'
1458
+ },
1459
+ postings: {
1460
+ description: 'Transaction postings',
1326
1461
  type: 'array',
1327
1462
  items: {
1328
- $ref: '#/components/schemas/TransactionDetailDto'
1463
+ $ref: '#/components/schemas/PostingDetailDto'
1329
1464
  }
1330
1465
  },
1331
- total: {
1332
- type: 'number',
1333
- description: 'Total count of matching transactions',
1334
- example: 100
1466
+ createdAt: {
1467
+ type: 'string',
1468
+ description: 'Created at timestamp',
1469
+ example: '2024-11-28T10:30:00.000Z'
1335
1470
  },
1336
- limit: {
1471
+ voidedAt: {
1472
+ type: 'string',
1473
+ description: 'Voided at timestamp (if voided)',
1474
+ example: '2024-11-29T15:00:00.000Z'
1475
+ },
1476
+ voidedBy: {
1477
+ type: 'string',
1478
+ description: 'User ID who voided this transaction',
1479
+ example: 'clh1234567890abcdef'
1480
+ },
1481
+ correctionReason: {
1482
+ type: 'string',
1483
+ description: 'Correction reason (if voided or superseded)',
1484
+ example: 'Duplicate entry'
1485
+ },
1486
+ supersededBy: {
1487
+ type: 'string',
1488
+ description:
1489
+ 'ID of the transaction that supersedes this one (set when status=SUPERSEDED)',
1490
+ example: 'clh1234567890abcdef'
1491
+ },
1492
+ originalTxn: {
1493
+ type: 'string',
1494
+ description:
1495
+ 'ID of the transaction this one corrected/replaced (back-link on the replacement)',
1496
+ example: 'clh1234567890abcdef'
1497
+ },
1498
+ viewpointAmount: {
1499
+ type: 'string',
1500
+ description:
1501
+ '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.',
1502
+ example: '10000.00'
1503
+ },
1504
+ viewpointCurrency: {
1505
+ type: 'string',
1506
+ description:
1507
+ 'Currency of viewpointAmount. A row spanning multiple currencies takes the largest-magnitude currency group (known simplification, ADR-0126).',
1508
+ example: 'CNY'
1509
+ }
1510
+ },
1511
+ required: [
1512
+ 'id',
1513
+ 'date',
1514
+ 'narration',
1515
+ 'tags',
1516
+ 'links',
1517
+ 'status',
1518
+ 'postings',
1519
+ 'createdAt'
1520
+ ]
1521
+ } as const;
1522
+
1523
+ export const $BalanceByCurrencyDto = {
1524
+ type: 'object',
1525
+ properties: {
1526
+ currency: {
1527
+ type: 'string',
1528
+ description: 'ISO 4217 currency code',
1529
+ example: 'CNY'
1530
+ },
1531
+ balance: {
1532
+ type: 'string',
1533
+ description: 'Balance amount',
1534
+ example: '50000.00'
1535
+ }
1536
+ },
1537
+ required: ['currency', 'balance']
1538
+ } as const;
1539
+
1540
+ export const $ExchangeRateWarningDto = {
1541
+ type: 'object',
1542
+ properties: {
1543
+ type: {
1544
+ type: 'string',
1545
+ description: 'Warning type',
1546
+ example: 'MISSING_EXCHANGE_RATE'
1547
+ },
1548
+ currency: {
1549
+ type: 'string',
1550
+ description: 'Currency without exchange rate',
1551
+ example: 'EUR'
1552
+ },
1553
+ totalAmount: {
1554
+ type: 'string',
1555
+ description: 'Total amount affected',
1556
+ example: '1000.00'
1557
+ }
1558
+ },
1559
+ required: ['type', 'currency', 'totalAmount']
1560
+ } as const;
1561
+
1562
+ export const $TransactionListSummaryDto = {
1563
+ type: 'object',
1564
+ properties: {
1565
+ totalAmount: {
1566
+ type: 'string',
1567
+ description:
1568
+ '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.',
1569
+ example: '-6000.00'
1570
+ },
1571
+ currency: {
1572
+ type: 'string',
1573
+ description: 'Base currency (ISO 4217)',
1574
+ example: 'CNY'
1575
+ },
1576
+ balanceByCurrency: {
1577
+ description: 'Raw (unconverted) balance per currency',
1578
+ type: 'array',
1579
+ items: {
1580
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
1581
+ }
1582
+ },
1583
+ warnings: {
1584
+ description: 'Currencies missing an FX rate (omitted when empty)',
1585
+ type: 'array',
1586
+ items: {
1587
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
1588
+ }
1589
+ }
1590
+ },
1591
+ required: ['totalAmount', 'currency', 'balanceByCurrency']
1592
+ } as const;
1593
+
1594
+ export const $TransactionListViewpointDto = {
1595
+ type: 'object',
1596
+ properties: {
1597
+ type: {
1598
+ type: 'string',
1599
+ description:
1600
+ 'Viewpoint type (only category drill-down carries a viewpoint today)',
1601
+ enum: ['category'],
1602
+ example: 'category'
1603
+ },
1604
+ flow: {
1605
+ type: 'string',
1606
+ description: 'Flow root the category account set is restricted to',
1607
+ enum: ['income', 'expense'],
1608
+ example: 'expense'
1609
+ }
1610
+ },
1611
+ required: ['type', 'flow']
1612
+ } as const;
1613
+
1614
+ export const $TransactionListResponseDto = {
1615
+ type: 'object',
1616
+ properties: {
1617
+ data: {
1618
+ description: 'List of transactions',
1619
+ type: 'array',
1620
+ items: {
1621
+ $ref: '#/components/schemas/TransactionListItemDto'
1622
+ }
1623
+ },
1624
+ total: {
1625
+ type: 'number',
1626
+ description: 'Total count of matching transactions',
1627
+ example: 100
1628
+ },
1629
+ limit: {
1337
1630
  type: 'number',
1338
1631
  description: 'Number of items per page',
1339
1632
  example: 20
@@ -1351,6 +1644,15 @@ export const $TransactionListResponseDto = {
1351
1644
  $ref: '#/components/schemas/TransactionListSummaryDto'
1352
1645
  }
1353
1646
  ]
1647
+ },
1648
+ viewpoint: {
1649
+ description:
1650
+ '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).',
1651
+ allOf: [
1652
+ {
1653
+ $ref: '#/components/schemas/TransactionListViewpointDto'
1654
+ }
1655
+ ]
1354
1656
  }
1355
1657
  },
1356
1658
  required: ['data', 'total', 'limit', 'offset']
@@ -1450,7 +1752,7 @@ export const $BalanceResponseDto = {
1450
1752
  account: {
1451
1753
  type: 'string',
1452
1754
  description: 'Account name',
1453
- example: 'Assets:Bank:Checking'
1755
+ example: 'Assets:Checking'
1454
1756
  },
1455
1757
  balance: {
1456
1758
  type: 'string',
@@ -1477,7 +1779,7 @@ export const $MultiCurrencyBalanceResponseDto = {
1477
1779
  account: {
1478
1780
  type: 'string',
1479
1781
  description: 'Account name',
1480
- example: 'Assets:Bank:Checking'
1782
+ example: 'Assets:Checking'
1481
1783
  },
1482
1784
  balances: {
1483
1785
  type: 'object',
@@ -1533,7 +1835,7 @@ export const $TransactionSummaryDto = {
1533
1835
  accountName: {
1534
1836
  type: 'string',
1535
1837
  description: 'Source account name (first posting)',
1536
- example: 'Assets:Bank:Checking'
1838
+ example: 'Assets:Checking'
1537
1839
  },
1538
1840
  sourceType: {
1539
1841
  type: 'string',
@@ -1702,13 +2004,17 @@ export const $ReviewStatsDto = {
1702
2004
  type: 'object',
1703
2005
  description: 'Count by type'
1704
2006
  },
2007
+ resolved: {
2008
+ type: 'number',
2009
+ description: 'Current count of reviews in RESOLVED status'
2010
+ },
1705
2011
  oldestPending: {
1706
2012
  format: 'date-time',
1707
2013
  type: 'string',
1708
2014
  description: 'Oldest pending review date'
1709
2015
  }
1710
2016
  },
1711
- required: ['total', 'byType']
2017
+ required: ['total', 'byType', 'resolved']
1712
2018
  } as const;
1713
2019
 
1714
2020
  export const $DecisionOptionDto = {
@@ -2261,10 +2567,10 @@ export const $UpdatePayeeDto = {
2261
2567
  meta: {
2262
2568
  type: 'object',
2263
2569
  description:
2264
- 'Metadata for extended information (location, notes, contact info, etc.). Will merge with existing metadata.',
2570
+ 'Metadata for extended information (location, notes, contact info, etc.)',
2265
2571
  example: {
2266
2572
  location: 'Zhongguancun',
2267
- note: 'Updated note',
2573
+ note: 'Near subway station',
2268
2574
  favorite: true
2269
2575
  }
2270
2576
  },
@@ -2825,106 +3131,385 @@ export const $UpdateCommodityDto = {
2825
3131
  }
2826
3132
  } as const;
2827
3133
 
2828
- export const $CreateBeanPriceDto = {
3134
+ export const $CurrencyBalanceDto = {
2829
3135
  type: 'object',
2830
3136
  properties: {
2831
3137
  currency: {
2832
3138
  type: 'string',
2833
- description: 'Currency being priced (e.g., USD, AAPL, BTC)',
2834
- example: 'USD'
2835
- },
2836
- quoteCurrency: {
2837
- type: 'string',
2838
- description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
3139
+ description: 'ISO 4217 currency code',
2839
3140
  example: 'CNY'
2840
3141
  },
2841
- amount: {
2842
- type: 'number',
2843
- description:
2844
- 'Price amount (MUST be >= 0 per Beancount spec, supports up to 15 decimal places). Zero allowed for conversion entries, negative strictly prohibited.',
2845
- example: 175.5,
2846
- minimum: 0
2847
- },
2848
- date: {
3142
+ balance: {
2849
3143
  type: 'string',
2850
- description: 'Price date (ISO 8601 format)',
2851
- example: '2024-11-05'
2852
- },
2853
- metadata: {
2854
- type: 'object',
2855
- description:
2856
- 'Metadata (validated by Zod schema, max field lengths enforced)',
2857
- example: {
2858
- source: 'MANUAL',
2859
- note: 'Bank valuation report',
2860
- confidence: 0.95
2861
- }
3144
+ description: 'Balance amount',
3145
+ example: '500000.00'
2862
3146
  }
2863
3147
  },
2864
- required: ['currency', 'quoteCurrency', 'amount', 'date']
3148
+ required: ['currency', 'balance']
2865
3149
  } as const;
2866
3150
 
2867
- export const $PriceResponseDto = {
3151
+ export const $TimeSeriesPointDto = {
2868
3152
  type: 'object',
2869
3153
  properties: {
2870
- id: {
3154
+ date: {
2871
3155
  type: 'string',
2872
- description: 'Unique identifier',
2873
- example: 'uuid-123-456'
3156
+ description: 'Date in YYYY-MM-DD format',
3157
+ example: '2024-06-15'
2874
3158
  },
2875
- userId: {
3159
+ value: {
2876
3160
  type: 'string',
2877
- description: 'User ID (owner of the price)',
2878
- example: 'user-123'
3161
+ description: 'Value at this date (in base currency)',
3162
+ example: '500000.00'
2879
3163
  },
2880
- currency: {
3164
+ change: {
2881
3165
  type: 'string',
2882
- description: 'Currency being priced (e.g., USD, AAPL, BTC)',
2883
- example: 'BTC'
3166
+ description: 'Change from previous point',
3167
+ example: '5000.00'
2884
3168
  },
2885
- quoteCurrency: {
3169
+ assets: {
2886
3170
  type: 'string',
2887
- description: 'Quote currency (pricing currency, e.g., USD, CNY)',
2888
- example: 'USD'
2889
- },
2890
- amount: {
2891
- type: 'number',
2892
- description:
2893
- 'Price amount (corresponds to Beancount Amount.number). Supports up to 15 decimal places.',
2894
- example: 50000
3171
+ description: 'Total assets at this date (in base currency)',
3172
+ example: '494338.00'
2895
3173
  },
2896
- date: {
3174
+ liabilities: {
2897
3175
  type: 'string',
2898
- description:
2899
- 'Price date (ISO 8601 format). Represents the date this price was valid.',
2900
- example: '2024-01-01',
2901
- format: 'date'
3176
+ description: 'Total liabilities at this date (in base currency)',
3177
+ example: '310098.00'
2902
3178
  },
2903
- meta: {
2904
- type: 'object',
2905
- description:
2906
- 'Metadata (corresponds to Beancount meta field). Contains source, confidence, note, etc.',
2907
- example: {
2908
- source: 'MANUAL',
2909
- note: 'User-defined price',
2910
- confidence: 1
3179
+ byCurrency: {
3180
+ description: 'Multi-currency breakdown for this point',
3181
+ type: 'array',
3182
+ items: {
3183
+ $ref: '#/components/schemas/CurrencyBalanceDto'
2911
3184
  }
2912
- },
2913
- createdAt: {
2914
- format: 'date-time',
2915
- type: 'string',
2916
- description: 'Creation timestamp',
2917
- example: '2024-11-03T10:00:00Z'
2918
- },
2919
- updatedAt: {
2920
- format: 'date-time',
2921
- type: 'string',
2922
- description: 'Last update timestamp',
2923
- example: '2024-11-03T10:00:00Z'
2924
3185
  }
2925
3186
  },
2926
- required: [
2927
- 'id',
3187
+ required: ['date', 'value']
3188
+ } as const;
3189
+
3190
+ export const $TrendSummaryDto = {
3191
+ type: 'object',
3192
+ properties: {
3193
+ startValue: {
3194
+ type: 'string',
3195
+ description: 'Value at start of period',
3196
+ example: '450000.00'
3197
+ },
3198
+ endValue: {
3199
+ type: 'string',
3200
+ description: 'Value at end of period',
3201
+ example: '500000.00'
3202
+ },
3203
+ totalChange: {
3204
+ type: 'string',
3205
+ description: 'Total change over period',
3206
+ example: '50000.00'
3207
+ },
3208
+ totalChangePercentage: {
3209
+ type: 'string',
3210
+ description: 'Total change percentage',
3211
+ example: '+11.11%'
3212
+ }
3213
+ },
3214
+ required: ['startValue', 'endValue', 'totalChange', 'totalChangePercentage']
3215
+ } as const;
3216
+
3217
+ export const $MultiCurrencyPointDto = {
3218
+ type: 'object',
3219
+ properties: {
3220
+ date: {
3221
+ type: 'string',
3222
+ description: 'Date in YYYY-MM-DD format',
3223
+ example: '2024-06-15'
3224
+ },
3225
+ byCurrency: {
3226
+ description: 'Balances by currency',
3227
+ type: 'array',
3228
+ items: {
3229
+ $ref: '#/components/schemas/CurrencyBalanceDto'
3230
+ }
3231
+ }
3232
+ },
3233
+ required: ['date', 'byCurrency']
3234
+ } as const;
3235
+
3236
+ export const $PortfolioTrendsResponseDto = {
3237
+ type: 'object',
3238
+ properties: {
3239
+ series: {
3240
+ description: 'Time series data points',
3241
+ type: 'array',
3242
+ items: {
3243
+ $ref: '#/components/schemas/TimeSeriesPointDto'
3244
+ }
3245
+ },
3246
+ summary: {
3247
+ description: 'Period summary',
3248
+ allOf: [
3249
+ {
3250
+ $ref: '#/components/schemas/TrendSummaryDto'
3251
+ }
3252
+ ]
3253
+ },
3254
+ period: {
3255
+ type: 'string',
3256
+ description: 'Period requested',
3257
+ example: '6m'
3258
+ },
3259
+ granularity: {
3260
+ type: 'string',
3261
+ description: 'Data granularity',
3262
+ example: 'month'
3263
+ },
3264
+ currency: {
3265
+ type: 'string',
3266
+ description: 'Base currency for converted values',
3267
+ example: 'CNY'
3268
+ },
3269
+ byCurrency: {
3270
+ description:
3271
+ 'Multi-currency time series (each point has currency breakdown)',
3272
+ type: 'array',
3273
+ items: {
3274
+ $ref: '#/components/schemas/MultiCurrencyPointDto'
3275
+ }
3276
+ },
3277
+ warnings: {
3278
+ description: 'Exchange rate warnings',
3279
+ type: 'array',
3280
+ items: {
3281
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
3282
+ }
3283
+ }
3284
+ },
3285
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
3286
+ } as const;
3287
+
3288
+ export const $CashFlowPointDto = {
3289
+ type: 'object',
3290
+ properties: {
3291
+ month: {
3292
+ type: 'string',
3293
+ description: 'Month key (YYYY-MM)',
3294
+ example: '2024-03'
3295
+ },
3296
+ income: {
3297
+ type: 'string',
3298
+ description: 'Income in base currency (absolute, converted)',
3299
+ example: '10000.00'
3300
+ },
3301
+ expense: {
3302
+ type: 'string',
3303
+ description: 'Expense in base currency (absolute, converted)',
3304
+ example: '5000.00'
3305
+ },
3306
+ netSavings: {
3307
+ type: 'string',
3308
+ description: 'netSavings = income − expense (savings positive)',
3309
+ example: '5000.00'
3310
+ }
3311
+ },
3312
+ required: ['month', 'income', 'expense', 'netSavings']
3313
+ } as const;
3314
+
3315
+ export const $CashFlowTrendSummaryDto = {
3316
+ type: 'object',
3317
+ properties: {
3318
+ totalIncome: {
3319
+ type: 'string',
3320
+ description: 'Total income across the period',
3321
+ example: '60000.00'
3322
+ },
3323
+ totalExpense: {
3324
+ type: 'string',
3325
+ description: 'Total expense across the period',
3326
+ example: '30000.00'
3327
+ },
3328
+ totalNetSavings: {
3329
+ type: 'string',
3330
+ description: 'income − expense across the period',
3331
+ example: '30000.00'
3332
+ },
3333
+ averageMonthlyNetSavings: {
3334
+ type: 'string',
3335
+ description:
3336
+ 'totalNetSavings divided by the window length (N months, incl. zero-filled)',
3337
+ example: '5000.00'
3338
+ }
3339
+ },
3340
+ required: [
3341
+ 'totalIncome',
3342
+ 'totalExpense',
3343
+ 'totalNetSavings',
3344
+ 'averageMonthlyNetSavings'
3345
+ ]
3346
+ } as const;
3347
+
3348
+ export const $CashFlowTrendsResponseDto = {
3349
+ type: 'object',
3350
+ properties: {
3351
+ series: {
3352
+ description:
3353
+ 'Monthly cash-flow series (fixed N-month window, zero-filled)',
3354
+ type: 'array',
3355
+ items: {
3356
+ $ref: '#/components/schemas/CashFlowPointDto'
3357
+ }
3358
+ },
3359
+ summary: {
3360
+ description: 'Period totals',
3361
+ allOf: [
3362
+ {
3363
+ $ref: '#/components/schemas/CashFlowTrendSummaryDto'
3364
+ }
3365
+ ]
3366
+ },
3367
+ period: {
3368
+ type: 'string',
3369
+ description: 'Period requested',
3370
+ example: '6m'
3371
+ },
3372
+ granularity: {
3373
+ type: 'string',
3374
+ description: 'Data granularity (v1 returns month buckets)',
3375
+ example: 'month'
3376
+ },
3377
+ currency: {
3378
+ type: 'string',
3379
+ description: 'Base currency for converted values',
3380
+ example: 'CNY'
3381
+ },
3382
+ warnings: {
3383
+ description: 'Exchange rate warnings (e.g. missing rate for a currency)',
3384
+ type: 'array',
3385
+ items: {
3386
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
3387
+ }
3388
+ }
3389
+ },
3390
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
3391
+ } as const;
3392
+
3393
+ export const $GenerateSnapshotBody = {
3394
+ type: 'object',
3395
+ properties: {}
3396
+ } as const;
3397
+
3398
+ export const $GenerateSnapshotResponse = {
3399
+ type: 'object',
3400
+ properties: {}
3401
+ } as const;
3402
+
3403
+ export const $BackfillSnapshotsBody = {
3404
+ type: 'object',
3405
+ properties: {}
3406
+ } as const;
3407
+
3408
+ export const $BackfillSnapshotsResponse = {
3409
+ type: 'object',
3410
+ properties: {}
3411
+ } as const;
3412
+
3413
+ export const $CreateBeanPriceDto = {
3414
+ type: 'object',
3415
+ properties: {
3416
+ currency: {
3417
+ type: 'string',
3418
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
3419
+ example: 'USD'
3420
+ },
3421
+ quoteCurrency: {
3422
+ type: 'string',
3423
+ description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
3424
+ example: 'CNY'
3425
+ },
3426
+ amount: {
3427
+ type: 'number',
3428
+ description:
3429
+ 'Price amount (MUST be >= 0 per Beancount spec, supports up to 15 decimal places). Zero allowed for conversion entries, negative strictly prohibited.',
3430
+ example: 175.5,
3431
+ minimum: 0
3432
+ },
3433
+ date: {
3434
+ type: 'string',
3435
+ description: 'Price date (ISO 8601 format)',
3436
+ example: '2024-11-05'
3437
+ },
3438
+ metadata: {
3439
+ type: 'object',
3440
+ description:
3441
+ 'Metadata (validated by Zod schema, max field lengths enforced)',
3442
+ example: {
3443
+ source: 'MANUAL',
3444
+ note: 'Bank valuation report',
3445
+ confidence: 0.95
3446
+ }
3447
+ }
3448
+ },
3449
+ required: ['currency', 'quoteCurrency', 'amount', 'date']
3450
+ } as const;
3451
+
3452
+ export const $PriceResponseDto = {
3453
+ type: 'object',
3454
+ properties: {
3455
+ id: {
3456
+ type: 'string',
3457
+ description: 'Unique identifier',
3458
+ example: 'uuid-123-456'
3459
+ },
3460
+ userId: {
3461
+ type: 'string',
3462
+ description: 'User ID (owner of the price)',
3463
+ example: 'user-123'
3464
+ },
3465
+ currency: {
3466
+ type: 'string',
3467
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
3468
+ example: 'BTC'
3469
+ },
3470
+ quoteCurrency: {
3471
+ type: 'string',
3472
+ description: 'Quote currency (pricing currency, e.g., USD, CNY)',
3473
+ example: 'USD'
3474
+ },
3475
+ amount: {
3476
+ type: 'number',
3477
+ description:
3478
+ 'Price amount (corresponds to Beancount Amount.number). Supports up to 15 decimal places.',
3479
+ example: 50000
3480
+ },
3481
+ date: {
3482
+ type: 'string',
3483
+ description:
3484
+ 'Price date (ISO 8601 format). Represents the date this price was valid.',
3485
+ example: '2024-01-01',
3486
+ format: 'date'
3487
+ },
3488
+ meta: {
3489
+ type: 'object',
3490
+ description:
3491
+ 'Metadata (corresponds to Beancount meta field). Contains source, confidence, note, etc.',
3492
+ example: {
3493
+ source: 'MANUAL',
3494
+ note: 'User-defined price',
3495
+ confidence: 1
3496
+ }
3497
+ },
3498
+ createdAt: {
3499
+ format: 'date-time',
3500
+ type: 'string',
3501
+ description: 'Creation timestamp',
3502
+ example: '2024-11-03T10:00:00Z'
3503
+ },
3504
+ updatedAt: {
3505
+ format: 'date-time',
3506
+ type: 'string',
3507
+ description: 'Last update timestamp',
3508
+ example: '2024-11-03T10:00:00Z'
3509
+ }
3510
+ },
3511
+ required: [
3512
+ 'id',
2928
3513
  'userId',
2929
3514
  'currency',
2930
3515
  'quoteCurrency',
@@ -2943,45 +3528,257 @@ export const $PriceListResponseDto = {
2943
3528
  description: 'List of prices',
2944
3529
  type: 'array',
2945
3530
  items: {
2946
- $ref: '#/components/schemas/PriceResponseDto'
3531
+ $ref: '#/components/schemas/PriceResponseDto'
3532
+ }
3533
+ },
3534
+ total: {
3535
+ type: 'number',
3536
+ description: 'Total number of prices',
3537
+ example: 42
3538
+ }
3539
+ },
3540
+ required: ['items', 'total']
3541
+ } as const;
3542
+
3543
+ export const $UpdateBeanPriceDto = {
3544
+ type: 'object',
3545
+ properties: {
3546
+ currency: {
3547
+ type: 'string',
3548
+ description: 'Currency being priced'
3549
+ },
3550
+ quoteCurrency: {
3551
+ type: 'string',
3552
+ description: 'Quote currency (pricing currency)'
3553
+ },
3554
+ amount: {
3555
+ type: 'number',
3556
+ description: 'Price amount (MUST be >= 0 per Beancount spec)',
3557
+ minimum: 0
3558
+ },
3559
+ date: {
3560
+ type: 'string',
3561
+ description: 'Price date (ISO 8601 format)'
3562
+ },
3563
+ metadata: {
3564
+ type: 'object',
3565
+ description: 'Metadata'
3566
+ }
3567
+ }
3568
+ } as const;
3569
+
3570
+ export const $DeleteOwnUserDto = {
3571
+ type: 'object',
3572
+ properties: {
3573
+ accessToken: {
3574
+ type: 'string',
3575
+ description: 'Access token for user verification',
3576
+ example: 'abc123xyz'
3577
+ }
3578
+ },
3579
+ required: ['accessToken']
3580
+ } as const;
3581
+
3582
+ export const $UserSettingsResponseDto = {
3583
+ type: 'object',
3584
+ properties: {
3585
+ baseCurrency: {
3586
+ type: 'string',
3587
+ description:
3588
+ '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).',
3589
+ example: 'USD',
3590
+ nullable: true
3591
+ }
3592
+ },
3593
+ required: ['baseCurrency']
3594
+ } as const;
3595
+
3596
+ export const $UserResponseDto = {
3597
+ type: 'object',
3598
+ properties: {
3599
+ id: {
3600
+ type: 'string',
3601
+ description: 'User ID'
3602
+ },
3603
+ role: {
3604
+ type: 'string',
3605
+ description: 'Assigned user role'
3606
+ },
3607
+ permissions: {
3608
+ description: 'Permission strings',
3609
+ type: 'array',
3610
+ items: {
3611
+ type: 'string'
3612
+ }
3613
+ },
3614
+ settings: {
3615
+ description: 'User settings',
3616
+ allOf: [
3617
+ {
3618
+ $ref: '#/components/schemas/UserSettingsResponseDto'
3619
+ }
3620
+ ]
3621
+ }
3622
+ },
3623
+ required: ['id', 'role', 'permissions', 'settings']
3624
+ } as const;
3625
+
3626
+ export const $SignupDto = {
3627
+ type: 'object',
3628
+ properties: {
3629
+ turnstileToken: {
3630
+ type: 'string',
3631
+ description:
3632
+ 'Cloudflare Turnstile verification token (optional when Turnstile disabled)',
3633
+ example: '0.abc123def456...'
3634
+ }
3635
+ }
3636
+ } as const;
3637
+
3638
+ export const $SignupResponseDto = {
3639
+ type: 'object',
3640
+ properties: {
3641
+ authToken: {
3642
+ type: 'string',
3643
+ description: 'JWT auth token',
3644
+ example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
3645
+ },
3646
+ accessToken: {
3647
+ type: 'string',
3648
+ description: 'Auto-generated access token'
3649
+ },
3650
+ role: {
3651
+ type: 'string',
3652
+ description: 'Assigned user role',
3653
+ enum: ['USER', 'ADMIN', 'DEMO', 'INACTIVE', 'PAID', 'OPS']
3654
+ }
3655
+ },
3656
+ required: ['authToken', 'accessToken', 'role']
3657
+ } as const;
3658
+
3659
+ export const $UpdateUserSettingDto = {
3660
+ type: 'object',
3661
+ properties: {
3662
+ secId: {
3663
+ type: 'number',
3664
+ description: 'Security ID'
3665
+ },
3666
+ annualInterestRate: {
3667
+ type: 'number',
3668
+ description: 'Annual interest rate',
3669
+ example: 0.05
3670
+ },
3671
+ currency: {
3672
+ type: 'string',
3673
+ description: 'Currency code',
3674
+ example: 'USD'
3675
+ },
3676
+ baseCurrency: {
3677
+ type: 'string',
3678
+ description: 'Base currency code',
3679
+ example: 'USD'
3680
+ },
3681
+ benchmark: {
3682
+ type: 'string',
3683
+ description: 'Benchmark symbol',
3684
+ example: 'SPY'
3685
+ },
3686
+ colorScheme: {
3687
+ type: 'string',
3688
+ description: 'Color scheme',
3689
+ enum: ['DARK', 'LIGHT']
3690
+ },
3691
+ dateRange: {
3692
+ type: 'string',
3693
+ description: 'Date range filter',
3694
+ example: '1y'
3695
+ },
3696
+ emergencyFund: {
3697
+ type: 'number',
3698
+ description: 'Emergency fund amount',
3699
+ example: 10000
3700
+ },
3701
+ 'filters.accounts': {
3702
+ description: 'Account filter IDs',
3703
+ type: 'array',
3704
+ items: {
3705
+ type: 'string'
2947
3706
  }
2948
3707
  },
2949
- total: {
2950
- type: 'number',
2951
- description: 'Total number of prices',
2952
- example: 42
2953
- }
2954
- },
2955
- required: ['items', 'total']
2956
- } as const;
2957
-
2958
- export const $UpdateBeanPriceDto = {
2959
- type: 'object',
2960
- properties: {
2961
- currency: {
3708
+ 'filters.assetClasses': {
3709
+ description: 'Asset class filters',
3710
+ type: 'array',
3711
+ items: {
3712
+ type: 'string'
3713
+ }
3714
+ },
3715
+ 'filters.dataSource': {
2962
3716
  type: 'string',
2963
- description: 'Currency being priced'
3717
+ description: 'Data source filter'
2964
3718
  },
2965
- quoteCurrency: {
3719
+ 'filters.symbol': {
2966
3720
  type: 'string',
2967
- description: 'Quote currency (pricing currency)'
3721
+ description: 'Symbol filter'
2968
3722
  },
2969
- amount: {
3723
+ 'filters.tags': {
3724
+ description: 'Tag filters',
3725
+ type: 'array',
3726
+ items: {
3727
+ type: 'string'
3728
+ }
3729
+ },
3730
+ isExperimentalFeatures: {
3731
+ type: 'boolean',
3732
+ description: 'Enable experimental features'
3733
+ },
3734
+ isRestrictedView: {
3735
+ type: 'boolean',
3736
+ description: 'Enable restricted view mode'
3737
+ },
3738
+ language: {
3739
+ type: 'string',
3740
+ description: 'Language code',
3741
+ example: 'en'
3742
+ },
3743
+ locale: {
3744
+ type: 'string',
3745
+ description: 'Locale code',
3746
+ example: 'en-US'
3747
+ },
3748
+ projectedTotalAmount: {
2970
3749
  type: 'number',
2971
- description: 'Price amount (MUST be >= 0 per Beancount spec)',
2972
- minimum: 0
3750
+ description: 'Projected total amount',
3751
+ example: 1000000
2973
3752
  },
2974
- date: {
3753
+ retirementDate: {
2975
3754
  type: 'string',
2976
- description: 'Price date (ISO 8601 format)'
3755
+ description: 'Retirement date in ISO 8601 format',
3756
+ example: '2050-01-01'
2977
3757
  },
2978
- metadata: {
2979
- type: 'object',
2980
- description: 'Metadata'
3758
+ savingsRate: {
3759
+ type: 'number',
3760
+ description: 'Savings rate percentage',
3761
+ example: 0.2
3762
+ },
3763
+ viewMode: {
3764
+ type: 'string',
3765
+ description: 'View mode',
3766
+ enum: ['DEFAULT', 'ZEN']
2981
3767
  }
2982
3768
  }
2983
3769
  } as const;
2984
3770
 
3771
+ export const $UpdatePropertyDto = {
3772
+ type: 'object',
3773
+ properties: {
3774
+ value: {
3775
+ type: 'string',
3776
+ description: 'Property value'
3777
+ }
3778
+ },
3779
+ required: ['value']
3780
+ } as const;
3781
+
2985
3782
  export const $CreateRecurringRuleDto = {
2986
3783
  type: 'object',
2987
3784
  properties: {
@@ -3027,7 +3824,6 @@ export const $CreateRecurringRuleDto = {
3027
3824
  currency: {
3028
3825
  type: 'string',
3029
3826
  description: 'Currency code',
3030
- default: 'CNY',
3031
3827
  maxLength: 10
3032
3828
  },
3033
3829
  matchPayeePattern: {
@@ -3075,7 +3871,6 @@ export const $CreateRecurringRuleDto = {
3075
3871
  'name',
3076
3872
  'frequency',
3077
3873
  'expectedAmount',
3078
- 'currency',
3079
3874
  'matchAmountTolerance',
3080
3875
  'autoCreate'
3081
3876
  ]
@@ -3097,7 +3892,7 @@ export const $RecurringRuleResponseDto = {
3097
3892
  description: 'Rule name'
3098
3893
  },
3099
3894
  icon: {
3100
- type: 'object',
3895
+ type: 'string',
3101
3896
  description: 'Icon emoji'
3102
3897
  },
3103
3898
  frequency: {
@@ -3109,11 +3904,11 @@ export const $RecurringRuleResponseDto = {
3109
3904
  description: 'Expected amount'
3110
3905
  },
3111
3906
  expectedDay: {
3112
- type: 'object',
3907
+ type: 'number',
3113
3908
  description: 'Expected day of month'
3114
3909
  },
3115
3910
  customIntervalDays: {
3116
- type: 'object',
3911
+ type: 'number',
3117
3912
  description: 'Custom interval in days'
3118
3913
  },
3119
3914
  currency: {
@@ -3121,7 +3916,7 @@ export const $RecurringRuleResponseDto = {
3121
3916
  description: 'Currency code'
3122
3917
  },
3123
3918
  matchPayeePattern: {
3124
- type: 'object',
3919
+ type: 'string',
3125
3920
  description: 'Payee matching pattern'
3126
3921
  },
3127
3922
  matchAmountTolerance: {
@@ -3129,15 +3924,15 @@ export const $RecurringRuleResponseDto = {
3129
3924
  description: 'Amount tolerance percentage'
3130
3925
  },
3131
3926
  defaultExpenseAccount: {
3132
- type: 'object',
3927
+ type: 'string',
3133
3928
  description: 'Default expense account'
3134
3929
  },
3135
3930
  defaultPaymentAccount: {
3136
- type: 'object',
3931
+ type: 'string',
3137
3932
  description: 'Default payment account'
3138
3933
  },
3139
3934
  defaultPayee: {
3140
- type: 'object',
3935
+ type: 'string',
3141
3936
  description: 'Default payee'
3142
3937
  },
3143
3938
  isActive: {
@@ -3149,7 +3944,7 @@ export const $RecurringRuleResponseDto = {
3149
3944
  description: 'Rule start date (YYYY-MM-DD)'
3150
3945
  },
3151
3946
  endDate: {
3152
- type: 'object',
3947
+ type: 'string',
3153
3948
  description: 'Rule end date (YYYY-MM-DD)'
3154
3949
  },
3155
3950
  autoCreate: {
@@ -3157,7 +3952,7 @@ export const $RecurringRuleResponseDto = {
3157
3952
  description: 'Auto-create transaction on expected date'
3158
3953
  },
3159
3954
  lastOccurrence: {
3160
- type: 'object',
3955
+ type: 'string',
3161
3956
  description: 'Last matched occurrence date (YYYY-MM-DD)'
3162
3957
  },
3163
3958
  totalCount: {
@@ -3239,7 +4034,7 @@ export const $RecurringRuleWithStatsResponseDto = {
3239
4034
  description: 'Rule name'
3240
4035
  },
3241
4036
  icon: {
3242
- type: 'object',
4037
+ type: 'string',
3243
4038
  description: 'Icon emoji'
3244
4039
  },
3245
4040
  frequency: {
@@ -3251,11 +4046,11 @@ export const $RecurringRuleWithStatsResponseDto = {
3251
4046
  description: 'Expected amount'
3252
4047
  },
3253
4048
  expectedDay: {
3254
- type: 'object',
4049
+ type: 'number',
3255
4050
  description: 'Expected day of month'
3256
4051
  },
3257
4052
  customIntervalDays: {
3258
- type: 'object',
4053
+ type: 'number',
3259
4054
  description: 'Custom interval in days'
3260
4055
  },
3261
4056
  currency: {
@@ -3263,7 +4058,7 @@ export const $RecurringRuleWithStatsResponseDto = {
3263
4058
  description: 'Currency code'
3264
4059
  },
3265
4060
  matchPayeePattern: {
3266
- type: 'object',
4061
+ type: 'string',
3267
4062
  description: 'Payee matching pattern'
3268
4063
  },
3269
4064
  matchAmountTolerance: {
@@ -3271,15 +4066,15 @@ export const $RecurringRuleWithStatsResponseDto = {
3271
4066
  description: 'Amount tolerance percentage'
3272
4067
  },
3273
4068
  defaultExpenseAccount: {
3274
- type: 'object',
4069
+ type: 'string',
3275
4070
  description: 'Default expense account'
3276
4071
  },
3277
4072
  defaultPaymentAccount: {
3278
- type: 'object',
4073
+ type: 'string',
3279
4074
  description: 'Default payment account'
3280
4075
  },
3281
4076
  defaultPayee: {
3282
- type: 'object',
4077
+ type: 'string',
3283
4078
  description: 'Default payee'
3284
4079
  },
3285
4080
  isActive: {
@@ -3291,7 +4086,7 @@ export const $RecurringRuleWithStatsResponseDto = {
3291
4086
  description: 'Rule start date (YYYY-MM-DD)'
3292
4087
  },
3293
4088
  endDate: {
3294
- type: 'object',
4089
+ type: 'string',
3295
4090
  description: 'Rule end date (YYYY-MM-DD)'
3296
4091
  },
3297
4092
  autoCreate: {
@@ -3299,7 +4094,7 @@ export const $RecurringRuleWithStatsResponseDto = {
3299
4094
  description: 'Auto-create transaction on expected date'
3300
4095
  },
3301
4096
  lastOccurrence: {
3302
- type: 'object',
4097
+ type: 'string',
3303
4098
  description: 'Last matched occurrence date (YYYY-MM-DD)'
3304
4099
  },
3305
4100
  totalCount: {
@@ -3325,7 +4120,7 @@ export const $RecurringRuleWithStatsResponseDto = {
3325
4120
  description: 'Number of overdue expected transactions'
3326
4121
  },
3327
4122
  nextExpectedDate: {
3328
- type: 'object',
4123
+ type: 'string',
3329
4124
  description: 'Next expected date (YYYY-MM-DD)'
3330
4125
  },
3331
4126
  totalAmount: {
@@ -3341,11 +4136,11 @@ export const $RecurringRuleWithStatsResponseDto = {
3341
4136
  description: 'Number of matched transactions'
3342
4137
  },
3343
4138
  firstDate: {
3344
- type: 'object',
4139
+ type: 'string',
3345
4140
  description: 'First matched transaction date (YYYY-MM-DD)'
3346
4141
  },
3347
4142
  lastDate: {
3348
- type: 'object',
4143
+ type: 'string',
3349
4144
  description: 'Last matched transaction date (YYYY-MM-DD)'
3350
4145
  },
3351
4146
  variance: {
@@ -3386,7 +4181,7 @@ export const $UpdateRecurringRuleDto = {
3386
4181
  properties: {
3387
4182
  name: {
3388
4183
  type: 'string',
3389
- description: 'Rule name',
4184
+ description: 'Rule name (unique per user)',
3390
4185
  maxLength: 100
3391
4186
  },
3392
4187
  icon: {
@@ -3409,7 +4204,7 @@ export const $UpdateRecurringRuleDto = {
3409
4204
  },
3410
4205
  expectedAmount: {
3411
4206
  type: 'number',
3412
- description: 'Expected amount',
4207
+ description: 'Expected amount (positive number)',
3413
4208
  minimum: 0
3414
4209
  },
3415
4210
  expectedDay: {
@@ -3418,11 +4213,6 @@ export const $UpdateRecurringRuleDto = {
3418
4213
  minimum: 1,
3419
4214
  maximum: 31
3420
4215
  },
3421
- customIntervalDays: {
3422
- type: 'number',
3423
- description: 'Custom interval in days',
3424
- minimum: 1
3425
- },
3426
4216
  currency: {
3427
4217
  type: 'string',
3428
4218
  description: 'Currency code',
@@ -3430,41 +4220,48 @@ export const $UpdateRecurringRuleDto = {
3430
4220
  },
3431
4221
  matchPayeePattern: {
3432
4222
  type: 'string',
3433
- description: 'Payee matching pattern',
4223
+ description: 'Payee matching pattern (supports wildcards)',
3434
4224
  maxLength: 200
3435
4225
  },
3436
4226
  matchAmountTolerance: {
3437
4227
  type: 'number',
3438
4228
  description: 'Amount tolerance percentage (0-1)',
4229
+ default: 0.075,
3439
4230
  minimum: 0,
3440
4231
  maximum: 1
3441
4232
  },
3442
4233
  defaultExpenseAccount: {
3443
4234
  type: 'string',
3444
- description: 'Default expense account',
4235
+ description: 'Default expense account for auto-create',
3445
4236
  maxLength: 200
3446
4237
  },
3447
4238
  defaultPaymentAccount: {
3448
4239
  type: 'string',
3449
- description: 'Default payment account',
4240
+ description: 'Default payment account for auto-create',
3450
4241
  maxLength: 200
3451
4242
  },
3452
4243
  defaultPayee: {
3453
4244
  type: 'string',
3454
- description: 'Default payee',
4245
+ description: 'Default payee for auto-create',
3455
4246
  maxLength: 200
3456
4247
  },
3457
4248
  autoCreate: {
3458
4249
  type: 'boolean',
3459
- description: 'Auto-create transaction'
3460
- },
3461
- isActive: {
3462
- type: 'boolean',
3463
- description: 'Rule active status'
4250
+ description: 'Auto-create transaction when expected date arrives',
4251
+ default: false
3464
4252
  },
3465
4253
  endDate: {
3466
4254
  type: 'string',
3467
4255
  description: 'Rule end date (ISO format)'
4256
+ },
4257
+ customIntervalDays: {
4258
+ type: 'number',
4259
+ description: 'Custom interval in days',
4260
+ minimum: 1
4261
+ },
4262
+ isActive: {
4263
+ type: 'boolean',
4264
+ description: 'Rule active status'
3468
4265
  }
3469
4266
  }
3470
4267
  } as const;
@@ -3477,7 +4274,7 @@ export const $ExpectedTransactionRuleDto = {
3477
4274
  description: 'Rule name'
3478
4275
  },
3479
4276
  icon: {
3480
- type: 'object',
4277
+ type: 'string',
3481
4278
  description: 'Rule icon'
3482
4279
  },
3483
4280
  frequency: {
@@ -3520,15 +4317,15 @@ export const $ExpectedTransactionResponseDto = {
3520
4317
  description: 'Status (PENDING, COMPLETED, SKIPPED)'
3521
4318
  },
3522
4319
  matchedTransactionId: {
3523
- type: 'object',
4320
+ type: 'string',
3524
4321
  description: 'Matched transaction ID'
3525
4322
  },
3526
4323
  matchedAt: {
3527
- type: 'object',
4324
+ type: 'string',
3528
4325
  description: 'Match timestamp (ISO 8601)'
3529
4326
  },
3530
4327
  matchConfidence: {
3531
- type: 'object',
4328
+ type: 'number',
3532
4329
  description: 'Match confidence score (0-1)'
3533
4330
  },
3534
4331
  isOverdue: {
@@ -4312,7 +5109,8 @@ export const $UpdateTransactionRuleDto = {
4312
5109
  },
4313
5110
  matchLogic: {
4314
5111
  type: 'string',
4315
- enum: ['OR', 'AND']
5112
+ enum: ['OR', 'AND'],
5113
+ default: 'OR'
4316
5114
  },
4317
5115
  amountMin: {
4318
5116
  type: 'number',
@@ -4326,13 +5124,10 @@ export const $UpdateTransactionRuleDto = {
4326
5124
  },
4327
5125
  priority: {
4328
5126
  type: 'number',
5127
+ default: 50,
4329
5128
  minimum: 0,
4330
5129
  maximum: 1000
4331
5130
  },
4332
- enabled: {
4333
- type: 'boolean',
4334
- description: 'Enable or disable the rule'
4335
- },
4336
5131
  additionalTags: {
4337
5132
  items: {
4338
5133
  type: 'array'
@@ -4342,6 +5137,10 @@ export const $UpdateTransactionRuleDto = {
4342
5137
  },
4343
5138
  additionalMetadata: {
4344
5139
  type: 'object'
5140
+ },
5141
+ enabled: {
5142
+ type: 'boolean',
5143
+ description: 'Enable or disable the rule'
4345
5144
  }
4346
5145
  }
4347
5146
  } as const;
@@ -4402,151 +5201,81 @@ export const $TestRuleResponseDto = {
4402
5201
  required: ['ruleId', 'matches', 'confidence', 'matchDetails']
4403
5202
  } as const;
4404
5203
 
4405
- export const $DeleteOwnUserDto = {
4406
- type: 'object',
4407
- properties: {
4408
- accessToken: {
4409
- type: 'string',
4410
- description: 'Access token for user verification',
4411
- example: 'abc123xyz'
4412
- }
4413
- },
4414
- required: ['accessToken']
4415
- } as const;
4416
-
4417
- export const $SignupDto = {
4418
- type: 'object',
4419
- properties: {
4420
- turnstileToken: {
4421
- type: 'string',
4422
- description:
4423
- 'Cloudflare Turnstile verification token (optional when Turnstile disabled)',
4424
- example: '0.abc123def456...'
4425
- }
4426
- }
4427
- } as const;
4428
-
4429
- export const $UpdateUserSettingDto = {
5204
+ export const $CategoryCatalogEntryDto = {
4430
5205
  type: 'object',
4431
5206
  properties: {
4432
- secId: {
4433
- type: 'number',
4434
- description: 'Security ID'
4435
- },
4436
- annualInterestRate: {
4437
- type: 'number',
4438
- description: 'Annual interest rate',
4439
- example: 0.05
4440
- },
4441
- currency: {
4442
- type: 'string',
4443
- description: 'Currency code',
4444
- example: 'USD'
4445
- },
4446
- baseCurrency: {
4447
- type: 'string',
4448
- description: 'Base currency code',
4449
- example: 'USD'
4450
- },
4451
- benchmark: {
5207
+ slug: {
4452
5208
  type: 'string',
4453
- description: 'Benchmark symbol',
4454
- example: 'SPY'
5209
+ description: 'Category slug (single source-of-truth)',
5210
+ example: 'food'
4455
5211
  },
4456
- colorScheme: {
5212
+ scenario: {
4457
5213
  type: 'string',
4458
- description: 'Color scheme',
4459
- enum: ['DARK', 'LIGHT']
5214
+ description: 'Display scenario group (maps to frontend picker _scenario)',
5215
+ enum: [
5216
+ 'expense',
5217
+ 'income',
5218
+ 'investment',
5219
+ 'banking',
5220
+ 'transfer',
5221
+ 'payment'
5222
+ ],
5223
+ example: 'expense'
4460
5224
  },
4461
- dateRange: {
5225
+ icon: {
4462
5226
  type: 'string',
4463
- description: 'Date range filter',
4464
- example: '1y'
4465
- },
4466
- emergencyFund: {
4467
- type: 'number',
4468
- description: 'Emergency fund amount',
4469
- example: 10000
5227
+ description: 'Lucide icon name',
5228
+ example: 'utensils'
4470
5229
  },
4471
- 'filters.accounts': {
4472
- description: 'Account filter IDs',
5230
+ regions: {
5231
+ description: "Applicable regions ('*' = all, 'cn' = CN-only)",
5232
+ example: ['*'],
4473
5233
  type: 'array',
4474
5234
  items: {
4475
5235
  type: 'string'
4476
5236
  }
4477
5237
  },
4478
- 'filters.assetClasses': {
4479
- description: 'Asset class filters',
5238
+ categoryAccounts: {
5239
+ description:
5240
+ "Beancount account paths (categoryAccount) of the region-enabled system rules whose categoryKeywords include this slug (#816). System rules only (public endpoint — user rules excluded); one-to-many by design (e.g. 'utilities' → Electricity/Water/Internet/Gas), sorted, [] when no rule maps the slug.",
5241
+ example: [
5242
+ 'Expenses:Utilities:Electricity',
5243
+ 'Expenses:Utilities:Gas',
5244
+ 'Expenses:Utilities:Internet',
5245
+ 'Expenses:Utilities:Water'
5246
+ ],
4480
5247
  type: 'array',
4481
5248
  items: {
4482
5249
  type: 'string'
4483
5250
  }
4484
- },
4485
- 'filters.dataSource': {
4486
- type: 'string',
4487
- description: 'Data source filter'
4488
- },
4489
- 'filters.symbol': {
4490
- type: 'string',
4491
- description: 'Symbol filter'
4492
- },
4493
- 'filters.tags': {
4494
- description: 'Tag filters',
5251
+ }
5252
+ },
5253
+ required: ['slug', 'scenario', 'icon', 'regions', 'categoryAccounts']
5254
+ } as const;
5255
+
5256
+ export const $CategoryCatalogListResponseDto = {
5257
+ type: 'object',
5258
+ properties: {
5259
+ items: {
5260
+ description: 'Category entries (region-scoped, query-filtered)',
4495
5261
  type: 'array',
4496
5262
  items: {
4497
- type: 'string'
5263
+ $ref: '#/components/schemas/CategoryCatalogEntryDto'
4498
5264
  }
4499
5265
  },
4500
- isExperimentalFeatures: {
4501
- type: 'boolean',
4502
- description: 'Enable experimental features'
4503
- },
4504
- isRestrictedView: {
4505
- type: 'boolean',
4506
- description: 'Enable restricted view mode'
4507
- },
4508
- language: {
4509
- type: 'string',
4510
- description: 'Language code',
4511
- example: 'en'
4512
- },
4513
- locale: {
4514
- type: 'string',
4515
- description: 'Locale code',
4516
- example: 'en-US'
4517
- },
4518
- projectedTotalAmount: {
4519
- type: 'number',
4520
- description: 'Projected total amount',
4521
- example: 1000000
4522
- },
4523
- retirementDate: {
4524
- type: 'string',
4525
- description: 'Retirement date in ISO 8601 format',
4526
- example: '2050-01-01'
4527
- },
4528
- savingsRate: {
5266
+ total: {
4529
5267
  type: 'number',
4530
- description: 'Savings rate percentage',
4531
- example: 0.2
5268
+ description:
5269
+ 'Total category entries for the region (before query filtering)',
5270
+ example: 30
4532
5271
  },
4533
- viewMode: {
4534
- type: 'string',
4535
- description: 'View mode',
4536
- enum: ['DEFAULT', 'ZEN']
4537
- }
4538
- }
4539
- } as const;
4540
-
4541
- export const $UpdatePropertyDto = {
4542
- type: 'object',
4543
- properties: {
4544
- value: {
5272
+ region: {
4545
5273
  type: 'string',
4546
- description: 'Property value'
5274
+ description: 'Region code',
5275
+ example: 'cn'
4547
5276
  }
4548
5277
  },
4549
- required: ['value']
5278
+ required: ['items', 'total', 'region']
4550
5279
  } as const;
4551
5280
 
4552
5281
  export const $CreateBeanEventDto = {
@@ -4687,6 +5416,63 @@ export const $UpdateBeanEventDto = {
4687
5416
  }
4688
5417
  } as const;
4689
5418
 
5419
+ export const $OnboardingAccountDto = {
5420
+ type: 'object',
5421
+ properties: {
5422
+ path: {
5423
+ type: 'string',
5424
+ description:
5425
+ 'Account path (Assets/Liabilities only; format validated by the account service)',
5426
+ example: 'Assets:Checking'
5427
+ },
5428
+ currency: {
5429
+ type: 'string',
5430
+ description: 'ISO 4217 currency code (3 letters)',
5431
+ example: 'USD'
5432
+ },
5433
+ openingBalance: {
5434
+ type: 'string',
5435
+ description:
5436
+ 'Opening balance as a non-negative Decimal string (e.g. "1000.00")',
5437
+ example: '1000.00'
5438
+ },
5439
+ platformId: {
5440
+ type: 'string',
5441
+ description:
5442
+ 'Platform ID to bind the account to (references Platform.id); omit for unbound',
5443
+ example: 'c98e5d4a-2f71-4a5a-bb3c-92c9f231d5e2'
5444
+ },
5445
+ displayName: {
5446
+ type: 'string',
5447
+ description:
5448
+ 'User-set display name override (omit/null = keep the derived name)',
5449
+ nullable: true,
5450
+ maxLength: 50,
5451
+ example: 'Salary card'
5452
+ }
5453
+ },
5454
+ required: ['path', 'currency']
5455
+ } as const;
5456
+
5457
+ export const $OnboardingDto = {
5458
+ type: 'object',
5459
+ properties: {
5460
+ accounts: {
5461
+ description: 'Asset/Liability accounts to register with opening balances',
5462
+ type: 'array',
5463
+ items: {
5464
+ $ref: '#/components/schemas/OnboardingAccountDto'
5465
+ }
5466
+ },
5467
+ skipAssetRegistration: {
5468
+ type: 'boolean',
5469
+ description:
5470
+ 'Skip asset registration; only bootstrap the core account set',
5471
+ default: false
5472
+ }
5473
+ }
5474
+ } as const;
5475
+
4690
5476
  export const $ActualBalanceDto = {
4691
5477
  type: 'object',
4692
5478
  properties: {
@@ -5055,7 +5841,7 @@ export const $IdentifyResultDto = {
5055
5841
  account: {
5056
5842
  type: 'string',
5057
5843
  description: 'Default account used by this importer',
5058
- example: 'Assets:Alipay:Balance'
5844
+ example: 'Assets:CN:Alipay:Balance'
5059
5845
  },
5060
5846
  message: {
5061
5847
  type: 'string',
@@ -5072,7 +5858,7 @@ export const $MapperDefaultsDto = {
5072
5858
  sourceAccount: {
5073
5859
  type: 'string',
5074
5860
  description: 'Source account for transactions (Beancount format)',
5075
- example: 'Assets:Alipay:Balance'
5861
+ example: 'Assets:CN:Alipay:Balance'
5076
5862
  },
5077
5863
  currency: {
5078
5864
  type: 'string',
@@ -5109,7 +5895,7 @@ export const $MapperDefaultsDto = {
5109
5895
  description:
5110
5896
  'Payment method to source account mapping. Maps payment method keywords to Beancount account paths. Used by Alipay/WeChat importers to determine sourceAccount based on payment method (e.g., HuaBei, CreditCard).',
5111
5897
  example: {
5112
- HuaBei: 'Liabilities:Alipay:Huabei',
5898
+ HuaBei: 'Liabilities:CN:CreditLine',
5113
5899
  CreditCard: 'Liabilities:CreditCard'
5114
5900
  }
5115
5901
  }
@@ -5220,192 +6006,89 @@ export const $ImporterConfigDto = {
5220
6006
  format: 'date-time',
5221
6007
  type: 'string',
5222
6008
  description: 'Last update timestamp',
5223
- example: '2025-01-27T10:00:00Z'
5224
- }
5225
- },
5226
- required: [
5227
- 'id',
5228
- 'userId',
5229
- 'importerId',
5230
- 'version',
5231
- 'schema',
5232
- 'config',
5233
- 'createdAt',
5234
- 'updatedAt'
5235
- ]
5236
- } as const;
5237
-
5238
- export const $UpdateMapperDefaultsDto = {
5239
- type: 'object',
5240
- properties: {
5241
- sourceAccount: {
5242
- type: 'string',
5243
- description: 'Source account for transactions (Beancount format)',
5244
- example: 'Assets:Alipay:Balance',
5245
- pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
5246
- },
5247
- currency: {
5248
- type: 'string',
5249
- description: 'Default currency (ISO 4217 code)',
5250
- example: 'CNY',
5251
- minLength: 3,
5252
- maxLength: 3,
5253
- pattern: '^[A-Z]{3}$'
5254
- },
5255
- expenseAccount: {
5256
- type: 'string',
5257
- description: 'Default expense account (optional)',
5258
- example: 'Expenses:Unknown',
5259
- pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
5260
- },
5261
- incomeAccount: {
5262
- type: 'string',
5263
- description: 'Default income account (optional)',
5264
- example: 'Income:Unknown',
5265
- pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
5266
- },
5267
- methodAccountMapping: {
5268
- type: 'object',
5269
- description:
5270
- 'Payment method to source account mapping. Maps payment method keywords to Beancount account paths. Used by Alipay/WeChat importers to determine sourceAccount based on payment method (e.g., HuaBei, CreditCard).',
5271
- example: {
5272
- HuaBei: 'Liabilities:Alipay:Huabei',
5273
- CreditCard: 'Liabilities:CreditCard'
5274
- }
5275
- }
5276
- }
5277
- } as const;
5278
-
5279
- export const $UpdateConfigDataDto = {
5280
- type: 'object',
5281
- properties: {
5282
- defaults: {
5283
- description: 'Mapper defaults configuration',
5284
- allOf: [
5285
- {
5286
- $ref: '#/components/schemas/UpdateMapperDefaultsDto'
5287
- }
5288
- ]
5289
- }
5290
- }
5291
- } as const;
5292
-
5293
- export const $UpdateImporterConfigDto = {
5294
- type: 'object',
5295
- properties: {
5296
- data: {
5297
- description: 'Configuration data (v1 schema)',
5298
- allOf: [
5299
- {
5300
- $ref: '#/components/schemas/UpdateConfigDataDto'
5301
- }
5302
- ]
5303
- }
5304
- }
5305
- } as const;
5306
-
5307
- export const $CreatePlatformDto = {
5308
- type: 'object',
5309
- properties: {
5310
- name: {
5311
- type: 'string',
5312
- description: 'Platform name',
5313
- example: 'Binance'
5314
- },
5315
- canonical: {
5316
- type: 'string',
5317
- description: 'Platform canonical identifier (lowercase, kebab-case)',
5318
- example: 'binance'
5319
- },
5320
- aliases: {
5321
- description: 'Platform aliases (multi-language names for lookup)',
5322
- example: ['Binance', 'Binance Exchange', 'BNB'],
5323
- type: 'array',
5324
- items: {
5325
- type: 'string'
5326
- }
5327
- },
5328
- url: {
5329
- type: 'string',
5330
- description: 'Platform URL',
5331
- example: 'https://www.binance.com'
5332
- },
5333
- type: {
5334
- type: 'string',
5335
- description: 'Platform type',
5336
- enum: [
5337
- 'BANK',
5338
- 'BROKERAGE',
5339
- 'CRYPTO_EXCHANGE',
5340
- 'PAYMENT',
5341
- 'INVESTMENT',
5342
- 'INSURANCE',
5343
- 'OTHER'
5344
- ],
5345
- example: 'CRYPTO_EXCHANGE'
5346
- },
5347
- logoUrl: {
5348
- type: 'string',
5349
- description: 'Platform logo URL',
5350
- example: 'https://example.com/logos/binance.png'
5351
- },
5352
- isActive: {
5353
- type: 'boolean',
5354
- description: 'Whether the platform is active',
5355
- default: true
6009
+ example: '2025-01-27T10:00:00Z'
5356
6010
  }
5357
6011
  },
5358
- required: ['name', 'canonical', 'aliases', 'url', 'type']
6012
+ required: [
6013
+ 'id',
6014
+ 'userId',
6015
+ 'importerId',
6016
+ 'version',
6017
+ 'schema',
6018
+ 'config',
6019
+ 'createdAt',
6020
+ 'updatedAt'
6021
+ ]
5359
6022
  } as const;
5360
6023
 
5361
- export const $UpdatePlatformDto = {
6024
+ export const $UpdateMapperDefaultsDto = {
5362
6025
  type: 'object',
5363
6026
  properties: {
5364
- name: {
5365
- type: 'string',
5366
- description: 'Platform name',
5367
- example: 'Binance'
5368
- },
5369
- canonical: {
6027
+ sourceAccount: {
5370
6028
  type: 'string',
5371
- description: 'Platform canonical identifier (lowercase, kebab-case)',
5372
- example: 'binance'
5373
- },
5374
- aliases: {
5375
- description: 'Platform aliases (multi-language names for lookup)',
5376
- example: ['Binance', 'Binance Exchange', 'BNB'],
5377
- type: 'array',
5378
- items: {
5379
- type: 'string'
5380
- }
6029
+ description: 'Source account for transactions (Beancount format)',
6030
+ example: 'Assets:CN:Alipay:Balance',
6031
+ pattern:
6032
+ '^(Assets|Liabilities|Income|Expenses|Equity)(:[A-Za-z0-9][A-Za-z0-9-]*)+$'
5381
6033
  },
5382
- url: {
6034
+ currency: {
5383
6035
  type: 'string',
5384
- description: 'Platform URL',
5385
- example: 'https://www.binance.com'
6036
+ description: 'Default currency (ISO 4217 code)',
6037
+ example: 'CNY',
6038
+ minLength: 3,
6039
+ maxLength: 3,
6040
+ pattern: '^[A-Z]{3}$'
5386
6041
  },
5387
- type: {
6042
+ expenseAccount: {
5388
6043
  type: 'string',
5389
- description: 'Platform type',
5390
- enum: [
5391
- 'BANK',
5392
- 'BROKERAGE',
5393
- 'CRYPTO_EXCHANGE',
5394
- 'PAYMENT',
5395
- 'INVESTMENT',
5396
- 'INSURANCE',
5397
- 'OTHER'
5398
- ],
5399
- example: 'CRYPTO_EXCHANGE'
6044
+ description: 'Default expense account (optional)',
6045
+ example: 'Expenses:Unknown',
6046
+ pattern:
6047
+ '^(Assets|Liabilities|Income|Expenses|Equity)(:[A-Za-z0-9][A-Za-z0-9-]*)+$'
5400
6048
  },
5401
- logoUrl: {
6049
+ incomeAccount: {
5402
6050
  type: 'string',
5403
- description: 'Platform logo URL',
5404
- example: 'https://example.com/logos/binance.png'
6051
+ description: 'Default income account (optional)',
6052
+ example: 'Income:Unknown',
6053
+ pattern:
6054
+ '^(Assets|Liabilities|Income|Expenses|Equity)(:[A-Za-z0-9][A-Za-z0-9-]*)+$'
5405
6055
  },
5406
- isActive: {
5407
- type: 'boolean',
5408
- description: 'Whether the platform is active'
6056
+ methodAccountMapping: {
6057
+ type: 'object',
6058
+ description:
6059
+ 'Payment method to source account mapping. Maps payment method keywords to Beancount account paths. Used by Alipay/WeChat importers to determine sourceAccount based on payment method (e.g., HuaBei, CreditCard).',
6060
+ example: {
6061
+ HuaBei: 'Liabilities:CN:CreditLine',
6062
+ CreditCard: 'Liabilities:CreditCard'
6063
+ }
6064
+ }
6065
+ }
6066
+ } as const;
6067
+
6068
+ export const $UpdateConfigDataDto = {
6069
+ type: 'object',
6070
+ properties: {
6071
+ defaults: {
6072
+ description: 'Mapper defaults configuration',
6073
+ allOf: [
6074
+ {
6075
+ $ref: '#/components/schemas/UpdateMapperDefaultsDto'
6076
+ }
6077
+ ]
6078
+ }
6079
+ }
6080
+ } as const;
6081
+
6082
+ export const $UpdateImporterConfigDto = {
6083
+ type: 'object',
6084
+ properties: {
6085
+ data: {
6086
+ description: 'Configuration data (v1 schema)',
6087
+ allOf: [
6088
+ {
6089
+ $ref: '#/components/schemas/UpdateConfigDataDto'
6090
+ }
6091
+ ]
5409
6092
  }
5410
6093
  }
5411
6094
  } as const;
@@ -5416,7 +6099,7 @@ export const $ProviderSyncConfigDto = {
5416
6099
  sourceAccount: {
5417
6100
  type: 'string',
5418
6101
  description: 'Source account for the first posting',
5419
- example: 'Assets:Bank:Chase'
6102
+ example: 'Assets:US:Chase:Checking'
5420
6103
  },
5421
6104
  defaultCurrency: {
5422
6105
  type: 'string',
@@ -5425,26 +6108,29 @@ export const $ProviderSyncConfigDto = {
5425
6108
  },
5426
6109
  defaultExpenseAccount: {
5427
6110
  type: 'string',
5428
- description: 'Default expense account for the second posting',
6111
+ description:
6112
+ 'Default expense account for the second posting. Omit when no real default exists; the pipeline routes to Review via the Uncategorized sentinel (#618).',
5429
6113
  example: 'Expenses:Unknown'
5430
6114
  },
5431
6115
  defaultIncomeAccount: {
5432
6116
  type: 'string',
5433
- description: 'Default income account for the second posting',
6117
+ description:
6118
+ 'Default income account for the second posting. Omit when no real default exists; the pipeline routes to Review via the Uncategorized sentinel (#618).',
5434
6119
  example: 'Income:Unknown'
5435
6120
  },
5436
6121
  filterPending: {
5437
6122
  type: 'boolean',
5438
6123
  description: 'Filter pending transactions',
5439
6124
  default: true
6125
+ },
6126
+ externalAccountId: {
6127
+ type: 'string',
6128
+ description:
6129
+ 'External account ID for per-batch providers (e.g. GoCardless). Overrides sourceAccount when an ExternalAccountLink mapping exists.',
6130
+ example: 'acc_gocardless_001'
5440
6131
  }
5441
6132
  },
5442
- required: [
5443
- 'sourceAccount',
5444
- 'defaultCurrency',
5445
- 'defaultExpenseAccount',
5446
- 'defaultIncomeAccount'
5447
- ]
6133
+ required: ['sourceAccount', 'defaultCurrency']
5448
6134
  } as const;
5449
6135
 
5450
6136
  export const $ProviderSyncDto = {
@@ -5552,18 +6238,190 @@ export const $SupportedProvidersResponseDto = {
5552
6238
  type: 'string'
5553
6239
  }
5554
6240
  }
5555
- },
5556
- required: ['providers']
5557
- } as const;
5558
-
5559
- export const $ParserTelemetryReportDto = {
5560
- type: 'object',
5561
- properties: {}
5562
- } as const;
5563
-
5564
- export const $UncoveredFormatMissDto = {
5565
- type: 'object',
5566
- properties: {}
6241
+ },
6242
+ required: ['providers']
6243
+ } as const;
6244
+
6245
+ export const $CreateExternalAccountLinkDto = {
6246
+ type: 'object',
6247
+ properties: {
6248
+ provider: {
6249
+ type: 'string',
6250
+ enum: [
6251
+ 'plaid',
6252
+ 'teller',
6253
+ 'truelayer',
6254
+ 'gocardless',
6255
+ 'simplefin',
6256
+ 'yodlee',
6257
+ 'beancount-direct',
6258
+ 'parsed-bill'
6259
+ ],
6260
+ example: 'plaid',
6261
+ description: 'Open Banking provider (whitelist)'
6262
+ },
6263
+ externalAccountId: {
6264
+ type: 'string',
6265
+ example: 'acc-plaid-001',
6266
+ description: 'External account ID from the provider'
6267
+ },
6268
+ beanAccountId: {
6269
+ type: 'string',
6270
+ example: '550e8400-e29b-41d4-a716-446655440000',
6271
+ description: 'Target BeanAccount ID (must belong to the JWT user)'
6272
+ }
6273
+ },
6274
+ required: ['provider', 'externalAccountId', 'beanAccountId']
6275
+ } as const;
6276
+
6277
+ export const $ExternalAccountLinkResponseDto = {
6278
+ type: 'object',
6279
+ properties: {
6280
+ id: {
6281
+ type: 'string'
6282
+ },
6283
+ provider: {
6284
+ type: 'string'
6285
+ },
6286
+ externalAccountId: {
6287
+ type: 'string'
6288
+ },
6289
+ beanAccountId: {
6290
+ type: 'string'
6291
+ },
6292
+ isActive: {
6293
+ type: 'boolean'
6294
+ },
6295
+ createdAt: {
6296
+ type: 'string'
6297
+ },
6298
+ updatedAt: {
6299
+ type: 'string'
6300
+ }
6301
+ },
6302
+ required: [
6303
+ 'id',
6304
+ 'provider',
6305
+ 'externalAccountId',
6306
+ 'beanAccountId',
6307
+ 'isActive',
6308
+ 'createdAt',
6309
+ 'updatedAt'
6310
+ ]
6311
+ } as const;
6312
+
6313
+ export const $ExternalAccountLinkListResponseDto = {
6314
+ type: 'object',
6315
+ properties: {
6316
+ items: {
6317
+ type: 'array',
6318
+ items: {
6319
+ $ref: '#/components/schemas/ExternalAccountLinkResponseDto'
6320
+ }
6321
+ },
6322
+ total: {
6323
+ type: 'number'
6324
+ },
6325
+ provider: {
6326
+ type: 'string',
6327
+ description: 'Filter by provider (query param)'
6328
+ }
6329
+ },
6330
+ required: ['items', 'total']
6331
+ } as const;
6332
+
6333
+ export const $ParserTelemetryReportDto = {
6334
+ type: 'object',
6335
+ properties: {}
6336
+ } as const;
6337
+
6338
+ export const $UncoveredFormatMissDto = {
6339
+ type: 'object',
6340
+ properties: {}
6341
+ } as const;
6342
+
6343
+ export const $ClientParsedDataDto = {
6344
+ type: 'object',
6345
+ properties: {
6346
+ amount: {
6347
+ type: 'number',
6348
+ description: 'Transaction amount',
6349
+ example: 35
6350
+ },
6351
+ currency: {
6352
+ type: 'string',
6353
+ description: 'Currency code',
6354
+ example: 'CNY'
6355
+ },
6356
+ date: {
6357
+ type: 'string',
6358
+ description: 'Transaction date (ISO 8601)',
6359
+ example: '2026-08-15'
6360
+ },
6361
+ payee: {
6362
+ type: 'string',
6363
+ description: 'Payee/merchant name',
6364
+ example: 'Starbucks'
6365
+ },
6366
+ narration: {
6367
+ type: 'string',
6368
+ description: 'Transaction narration'
6369
+ },
6370
+ category: {
6371
+ type: 'string',
6372
+ description:
6373
+ 'Category in canonical form (catalog slug or Stage-2 rule keyword token, ADR-0116) — echo back verbatim from parsedData.category. Foreign forms (locale display names, account paths) are rejected with nlp.category.invalid.',
6374
+ example: 'food'
6375
+ },
6376
+ incomeType: {
6377
+ type: 'string',
6378
+ description: 'Income type',
6379
+ example: 'Salary'
6380
+ },
6381
+ incomeSource: {
6382
+ type: 'string',
6383
+ description: 'Income source',
6384
+ example: 'Anthropic Inc.'
6385
+ },
6386
+ symbol: {
6387
+ type: 'string',
6388
+ description: 'Security symbol code (e.g., 600519, AAPL)',
6389
+ example: 'AAPL'
6390
+ },
6391
+ quantity: {
6392
+ type: 'number',
6393
+ description: 'Quantity of shares/units',
6394
+ example: 100
6395
+ },
6396
+ price: {
6397
+ type: 'number',
6398
+ description: 'Unit price per share/unit',
6399
+ example: 1900
6400
+ },
6401
+ investmentAction: {
6402
+ type: 'string',
6403
+ description: 'Investment action',
6404
+ enum: ['buy', 'sell'],
6405
+ example: 'buy'
6406
+ },
6407
+ paymentSource: {
6408
+ type: 'string',
6409
+ description: 'Payment source: asset (default) or liability (credit card)',
6410
+ enum: ['asset', 'liability'],
6411
+ example: 'asset'
6412
+ },
6413
+ liabilityHint: {
6414
+ type: 'string',
6415
+ description: 'Liability account hint (CreditCard/Huabei/Baitiao)',
6416
+ example: 'CreditCard'
6417
+ },
6418
+ warning: {
6419
+ type: 'string',
6420
+ description:
6421
+ 'Display-only warning from the prior response; accepted but ignored.',
6422
+ example: 'Cross-currency settlement applies.'
6423
+ }
6424
+ }
5567
6425
  } as const;
5568
6426
 
5569
6427
  export const $ProcessNlpDto = {
@@ -5571,10 +6429,17 @@ export const $ProcessNlpDto = {
5571
6429
  properties: {
5572
6430
  message: {
5573
6431
  type: 'string',
5574
- description: 'Natural language text describing a transaction (Chinese)',
5575
- example: 'yesterday Starbucks spent 35 yuan',
6432
+ description:
6433
+ 'Natural language text describing a transaction. Optional when `confirm` is true (structured confirm); otherwise required.',
6434
+ example: 'Starbucks 35',
5576
6435
  maxLength: 500
5577
6436
  },
6437
+ confirm: {
6438
+ type: 'boolean',
6439
+ description:
6440
+ 'Structured confirm signal — bypasses NL confirm-word matching when true. Send parsedData field edits alongside. The NL word-list path is the fallback.',
6441
+ example: true
6442
+ },
5578
6443
  sessionId: {
5579
6444
  type: 'string',
5580
6445
  description:
@@ -5582,17 +6447,51 @@ export const $ProcessNlpDto = {
5582
6447
  example: 'session_abc123'
5583
6448
  },
5584
6449
  parsedData: {
5585
- type: 'object',
5586
6450
  description:
5587
6451
  'Parsed data from previous NLP response for session recovery. Send back the parsedData received in confirm_payee/confirm responses.',
5588
6452
  example: {
5589
6453
  amount: 35,
5590
6454
  currency: 'CNY',
5591
6455
  payee: 'Starbucks'
5592
- }
6456
+ },
6457
+ allOf: [
6458
+ {
6459
+ $ref: '#/components/schemas/ClientParsedDataDto'
6460
+ }
6461
+ ]
6462
+ },
6463
+ selectedRuleId: {
6464
+ type: 'string',
6465
+ description:
6466
+ 'confirm_rule echo-back: rule id selected from the prior confirm_rule response (matchedRule.id or alternatives[i].ruleId). Applied directly when the session is confirming_rule — no NL re-parse.',
6467
+ example: 'rule_abc123'
6468
+ },
6469
+ selectedAccount: {
6470
+ type: 'string',
6471
+ description:
6472
+ '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.',
6473
+ example: 'Expenses:Food:Coffee'
6474
+ },
6475
+ viewpointAccount: {
6476
+ type: 'string',
6477
+ description:
6478
+ '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.',
6479
+ example: 'Assets:CN:Bank:ICBC'
6480
+ },
6481
+ viewpointCategory: {
6482
+ type: 'string',
6483
+ description:
6484
+ "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.",
6485
+ example: 'Food'
6486
+ },
6487
+ viewpointFlow: {
6488
+ type: 'string',
6489
+ description:
6490
+ "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.",
6491
+ enum: ['income', 'expense'],
6492
+ example: 'expense'
5593
6493
  }
5594
- },
5595
- required: ['message']
6494
+ }
5596
6495
  } as const;
5597
6496
 
5598
6497
  export const $NlpTransactionInfoDto = {
@@ -5658,7 +6557,9 @@ export const $NlpParsedDataDto = {
5658
6557
  },
5659
6558
  category: {
5660
6559
  type: 'string',
5661
- description: 'Category'
6560
+ description:
6561
+ 'Category in canonical form: a CATEGORY_CATALOG slug (GET /{region}/bean/categories) or a Stage-2 rule categoryKeywords token (ADR-0116 D2). Never a locale display name or a beancount account path. Echo back verbatim on confirm.',
6562
+ example: 'food'
5662
6563
  },
5663
6564
  incomeType: {
5664
6565
  type: 'string',
@@ -5904,6 +6805,24 @@ export const $NlpRuleConfirmationDataDto = {
5904
6805
  ]
5905
6806
  } as const;
5906
6807
 
6808
+ export const $NlpAccountCandidateDto = {
6809
+ type: 'object',
6810
+ properties: {
6811
+ path: {
6812
+ type: 'string',
6813
+ description: 'Canonical beancount account path (echo back on selection)',
6814
+ example: 'Expenses:Food:Dining'
6815
+ },
6816
+ name: {
6817
+ type: 'string',
6818
+ description:
6819
+ 'Localized display name (ADR-0114 read-time projection, user locale)',
6820
+ example: '餐饮'
6821
+ }
6822
+ },
6823
+ required: ['path', 'name']
6824
+ } as const;
6825
+
5907
6826
  export const $NlpAccountConfirmationDataDto = {
5908
6827
  type: 'object',
5909
6828
  properties: {
@@ -5914,14 +6833,16 @@ export const $NlpAccountConfirmationDataDto = {
5914
6833
  },
5915
6834
  suggestedAccount: {
5916
6835
  type: 'string',
5917
- description: 'Suggested replacement account',
6836
+ description:
6837
+ 'Suggested replacement account (omitted when no clear candidate)',
5918
6838
  example: 'Expenses:Food:Drinks'
5919
6839
  },
5920
6840
  similarAccounts: {
5921
- description: 'Similar accounts for user selection',
6841
+ description:
6842
+ 'Similar accounts for user selection (path + localized name, #680)',
5922
6843
  type: 'array',
5923
6844
  items: {
5924
- type: 'string'
6845
+ $ref: '#/components/schemas/NlpAccountCandidateDto'
5925
6846
  }
5926
6847
  },
5927
6848
  errorMessage: {
@@ -5936,7 +6857,6 @@ export const $NlpAccountConfirmationDataDto = {
5936
6857
  },
5937
6858
  required: [
5938
6859
  'invalidAccount',
5939
- 'suggestedAccount',
5940
6860
  'similarAccounts',
5941
6861
  'errorMessage',
5942
6862
  'transactionContext'
@@ -6105,11 +7025,12 @@ export const $NlpSuggestedAccountDto = {
6105
7025
  account: {
6106
7026
  type: 'string',
6107
7027
  description: 'Suggested account path',
6108
- example: 'Assets:Bank:Checking'
7028
+ example: 'Assets:Checking'
6109
7029
  },
6110
7030
  confidence: {
6111
7031
  type: 'number',
6112
- description: 'Confidence score for this suggestion (0-1)',
7032
+ description:
7033
+ 'Confidence score for this suggestion (0-1). Present = predicted (confirm/confirm_rule/confirm_account); omitted = actual persisted account (created). (#586)',
6113
7034
  example: 0.9
6114
7035
  }
6115
7036
  },
@@ -6145,23 +7066,31 @@ export const $NlpDefaultAccountsDto = {
6145
7066
  properties: {
6146
7067
  asset: {
6147
7068
  type: 'string',
6148
- description: 'Default asset account',
6149
- example: 'Assets:Bank:Checking'
7069
+ description:
7070
+ 'Default OPEN asset account (MRU when multiple), or null when none/ambiguous',
7071
+ example: 'Assets:Checking',
7072
+ nullable: true
6150
7073
  },
6151
7074
  expense: {
6152
7075
  type: 'string',
6153
- description: 'Default expense account',
6154
- example: 'Expenses:Uncategorized'
7076
+ description:
7077
+ 'Default OPEN expense account (MRU when multiple), or null when none/ambiguous',
7078
+ example: 'Expenses:Food:Coffee',
7079
+ nullable: true
6155
7080
  },
6156
7081
  income: {
6157
7082
  type: 'string',
6158
- description: 'Default income account',
6159
- example: 'Income:Uncategorized'
7083
+ description:
7084
+ 'Default OPEN income account (MRU when multiple), or null when none/ambiguous',
7085
+ example: 'Income:Salary',
7086
+ nullable: true
6160
7087
  },
6161
7088
  liability: {
6162
7089
  type: 'string',
6163
- description: 'Default liability account',
6164
- example: 'Liabilities:CreditCard'
7090
+ description:
7091
+ 'Default OPEN liability account (MRU when multiple), or null when none/ambiguous',
7092
+ example: 'Liabilities:CreditCard',
7093
+ nullable: true
6165
7094
  }
6166
7095
  },
6167
7096
  required: ['asset', 'expense', 'income', 'liability']
@@ -6186,7 +7115,8 @@ export const $NlpResponseDto = {
6186
7115
  'confirm_rule',
6187
7116
  'confirm_account',
6188
7117
  'confirm_payee',
6189
- 'cancel'
7118
+ 'cancel',
7119
+ 'aborted'
6190
7120
  ]
6191
7121
  },
6192
7122
  intent: {
@@ -6200,7 +7130,7 @@ export const $NlpResponseDto = {
6200
7130
  type: 'string',
6201
7131
  description:
6202
7132
  'Asset sub-type (only present when intent is "asset"). Determines which asset-related form to render.',
6203
- enum: ['transfer', 'banking', 'investment'],
7133
+ enum: ['transfer', 'banking', 'investment', 'lend', 'lend_collect'],
6204
7134
  example: 'investment'
6205
7135
  },
6206
7136
  liabilitySubType: {
@@ -6337,35 +7267,387 @@ export const $NlpResponseDto = {
6337
7267
  }
6338
7268
  ]
6339
7269
  },
6340
- recurringSuggestion: {
7270
+ recurringSuggestion: {
7271
+ description:
7272
+ 'Recurring rule creation suggestion (when action is "created"). Contains suggestion to create a recurring rule based on detected patterns. Only present when no existing rule matched and similar historical transactions were found.',
7273
+ allOf: [
7274
+ {
7275
+ $ref: '#/components/schemas/RecurringSuggestionDto'
7276
+ }
7277
+ ]
7278
+ },
7279
+ suggestedAccounts: {
7280
+ description:
7281
+ 'Suggested accounts for this transaction (#586). confirm/confirm_rule/confirm_account: predicted (source/destination carry confidence); created: actual persisted accounts (confidence omitted). confirm_account destination is the suggested replacement, never the invalid account.',
7282
+ allOf: [
7283
+ {
7284
+ $ref: '#/components/schemas/NlpSuggestedAccountsDto'
7285
+ }
7286
+ ]
7287
+ },
7288
+ defaultAccounts: {
7289
+ description:
7290
+ 'Default fallback accounts for the user/region (#586). v1 returns universal constants; per-user personalization is planned.',
7291
+ allOf: [
7292
+ {
7293
+ $ref: '#/components/schemas/NlpDefaultAccountsDto'
7294
+ }
7295
+ ]
7296
+ }
7297
+ },
7298
+ required: ['status', 'action']
7299
+ } as const;
7300
+
7301
+ export const $PlatformListItemDto = {
7302
+ type: 'object',
7303
+ properties: {
7304
+ id: {
7305
+ type: 'string',
7306
+ description: 'Global platform ID'
7307
+ },
7308
+ name: {
7309
+ type: 'string',
7310
+ description: 'Platform name'
7311
+ },
7312
+ url: {
7313
+ type: 'string',
7314
+ description: 'Platform URL'
7315
+ },
7316
+ type: {
7317
+ type: 'string',
7318
+ description: 'Platform type',
7319
+ enum: [
7320
+ 'BANK',
7321
+ 'BROKERAGE',
7322
+ 'CRYPTO_EXCHANGE',
7323
+ 'PAYMENT',
7324
+ 'INVESTMENT',
7325
+ 'INSURANCE',
7326
+ 'OTHER'
7327
+ ]
7328
+ },
7329
+ canonical: {
7330
+ type: 'string',
7331
+ description: 'Canonical identifier in ACCOUNT_RE format (e.g., "icbc")'
7332
+ },
7333
+ suggestedSegment: {
7334
+ type: 'string',
7335
+ description:
7336
+ 'Suggested path segment — canonical PascalCased per hyphen-part, hyphens preserved (e.g. "Apple-Pay")'
7337
+ },
7338
+ logoUrl: {
7339
+ type: 'string',
7340
+ description: 'Logo URL',
7341
+ nullable: true
7342
+ },
7343
+ countryCode: {
7344
+ type: 'string',
7345
+ description: 'ISO 3166-1 alpha-2 (UPPERCASE); null = global platform',
7346
+ example: 'CN',
7347
+ nullable: true
7348
+ },
7349
+ category: {
7350
+ type: 'string',
7351
+ description:
7352
+ 'Region-aware category (institution vocab, e.g. DigitalWallet/Bank). null = no region-aware suggestion; fall back to type.',
7353
+ nullable: true,
7354
+ example: 'DigitalWallet'
7355
+ },
7356
+ isBound: {
7357
+ type: 'boolean',
7358
+ description: 'Whether user has accounts using this platform'
7359
+ }
7360
+ },
7361
+ required: [
7362
+ 'id',
7363
+ 'name',
7364
+ 'url',
7365
+ 'type',
7366
+ 'canonical',
7367
+ 'suggestedSegment',
7368
+ 'logoUrl',
7369
+ 'countryCode',
7370
+ 'category',
7371
+ 'isBound'
7372
+ ]
7373
+ } as const;
7374
+
7375
+ export const $PlatformMatchResultDto = {
7376
+ type: 'object',
7377
+ properties: {
7378
+ id: {
7379
+ type: 'string',
7380
+ description: 'Global platform ID'
7381
+ },
7382
+ name: {
7383
+ type: 'string',
7384
+ description: 'Platform name (e.g., "ICBC")'
7385
+ },
7386
+ canonical: {
7387
+ type: 'string',
7388
+ description: 'Canonical identifier in ACCOUNT_RE format (e.g., "icbc")'
7389
+ },
7390
+ type: {
7391
+ type: 'string',
7392
+ description: 'Platform type',
7393
+ enum: [
7394
+ 'BANK',
7395
+ 'BROKERAGE',
7396
+ 'CRYPTO_EXCHANGE',
7397
+ 'PAYMENT',
7398
+ 'INVESTMENT',
7399
+ 'INSURANCE',
7400
+ 'OTHER'
7401
+ ]
7402
+ },
7403
+ suggestedSegment: {
7404
+ type: 'string',
7405
+ description:
7406
+ 'Suggested path segment — canonical PascalCased per hyphen-part, hyphens preserved (e.g. "Apple-Pay")'
7407
+ },
7408
+ logoUrl: {
7409
+ type: 'string',
7410
+ description: 'Logo URL',
7411
+ nullable: true
7412
+ },
7413
+ countryCode: {
7414
+ type: 'string',
7415
+ description: 'ISO 3166-1 alpha-2 (UPPERCASE); null = global platform',
7416
+ example: 'CN',
7417
+ nullable: true
7418
+ },
7419
+ category: {
7420
+ type: 'string',
7421
+ description:
7422
+ 'Region-aware category (institution vocab, e.g. DigitalWallet/Bank). null = no region-aware suggestion; fall back to type.',
7423
+ nullable: true,
7424
+ example: 'DigitalWallet'
7425
+ },
7426
+ matchType: {
7427
+ type: 'string',
7428
+ description: "How this row matched: 'exact' > 'prefix' > 'substring'",
7429
+ enum: ['exact', 'prefix', 'substring']
7430
+ }
7431
+ },
7432
+ required: [
7433
+ 'id',
7434
+ 'name',
7435
+ 'canonical',
7436
+ 'type',
7437
+ 'suggestedSegment',
7438
+ 'logoUrl',
7439
+ 'countryCode',
7440
+ 'category',
7441
+ 'matchType'
7442
+ ]
7443
+ } as const;
7444
+
7445
+ export const $PlatformMatchResponseDto = {
7446
+ type: 'object',
7447
+ properties: {
7448
+ platforms: {
7449
+ description: 'Ranked matches, best tier first (at most 10 rows)',
7450
+ type: 'array',
7451
+ items: {
7452
+ $ref: '#/components/schemas/PlatformMatchResultDto'
7453
+ }
7454
+ },
7455
+ matchType: {
7456
+ type: 'string',
7457
+ description:
7458
+ "Overall match quality — top row's tier, or 'none' when no hits",
7459
+ enum: ['none', 'exact', 'prefix', 'substring']
7460
+ },
7461
+ total: {
7462
+ type: 'number',
7463
+ description: 'Total matches before LIMIT (truncation transparency)'
7464
+ },
7465
+ hasMore: {
7466
+ type: 'boolean',
7467
+ description: 'true when total > platforms.length (more matches exist)'
7468
+ }
7469
+ },
7470
+ required: ['platforms', 'matchType', 'total', 'hasMore']
7471
+ } as const;
7472
+
7473
+ export const $PlatformStandardsPlatformDto = {
7474
+ type: 'object',
7475
+ properties: {
7476
+ id: {
7477
+ type: 'string',
7478
+ description: 'Global platform ID'
7479
+ },
7480
+ name: {
7481
+ type: 'string',
7482
+ description: 'Platform name (e.g., "ICBC")'
7483
+ },
7484
+ canonical: {
7485
+ type: 'string',
7486
+ description: 'Canonical identifier in ACCOUNT_RE format (e.g., "icbc")'
7487
+ },
7488
+ suggestedSegment: {
7489
+ type: 'string',
7490
+ description:
7491
+ 'Suggested path segment — canonical PascalCased per hyphen-part, hyphens preserved (e.g. "Apple-Pay")'
7492
+ },
7493
+ type: {
7494
+ type: 'string',
7495
+ description: 'Platform type',
7496
+ enum: [
7497
+ 'BANK',
7498
+ 'BROKERAGE',
7499
+ 'CRYPTO_EXCHANGE',
7500
+ 'PAYMENT',
7501
+ 'INVESTMENT',
7502
+ 'INSURANCE',
7503
+ 'OTHER'
7504
+ ]
7505
+ },
7506
+ category: {
7507
+ type: 'string',
6341
7508
  description:
6342
- 'Recurring rule creation suggestion (when action is "created"). Contains suggestion to create a recurring rule based on detected patterns. Only present when no existing rule matched and similar historical transactions were found.',
7509
+ 'Region-aware category (institution vocab, e.g. DigitalWallet/Bank) resolved against the final region. null = no region-aware suggestion; fall back to type.',
7510
+ nullable: true,
7511
+ example: 'Bank'
7512
+ }
7513
+ },
7514
+ required: ['id', 'name', 'canonical', 'suggestedSegment', 'type', 'category']
7515
+ } as const;
7516
+
7517
+ export const $PlatformStandardsResponseDto = {
7518
+ type: 'object',
7519
+ properties: {
7520
+ platform: {
7521
+ description: 'The selected platform (institution lock source)',
6343
7522
  allOf: [
6344
7523
  {
6345
- $ref: '#/components/schemas/RecurringSuggestionDto'
7524
+ $ref: '#/components/schemas/PlatformStandardsPlatformDto'
6346
7525
  }
6347
7526
  ]
6348
7527
  },
6349
- suggestedAccounts: {
7528
+ region: {
7529
+ type: 'string',
6350
7530
  description:
6351
- 'Suggested accounts for this transaction. Contains recommended source and destination accounts based on the detected intent and rules.',
6352
- allOf: [
6353
- {
6354
- $ref: '#/components/schemas/NlpSuggestedAccountsDto'
6355
- }
6356
- ]
7531
+ "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.",
7532
+ example: 'CN'
6357
7533
  },
6358
- defaultAccounts: {
7534
+ templates: {
6359
7535
  description:
6360
- 'Default accounts for the user/region. These are fallback accounts used when no specific suggestion is available.',
6361
- allOf: [
6362
- {
6363
- $ref: '#/components/schemas/NlpDefaultAccountsDto'
6364
- }
6365
- ]
7536
+ 'Candidate account-standard templates of the resolved region (groupable by productCategory client-side)',
7537
+ type: 'array',
7538
+ items: {
7539
+ $ref: '#/components/schemas/AccountStandardResponseDto'
7540
+ }
6366
7541
  }
6367
7542
  },
6368
- required: ['status', 'action']
7543
+ required: ['platform', 'region', 'templates']
7544
+ } as const;
7545
+
7546
+ export const $CreatePlatformDto = {
7547
+ type: 'object',
7548
+ properties: {
7549
+ name: {
7550
+ type: 'string',
7551
+ description: 'Platform name',
7552
+ example: 'Binance'
7553
+ },
7554
+ canonical: {
7555
+ type: 'string',
7556
+ description: 'Platform canonical identifier (lowercase, kebab-case)',
7557
+ example: 'binance'
7558
+ },
7559
+ aliases: {
7560
+ description: 'Platform aliases (multi-language names for lookup)',
7561
+ example: ['Binance', 'Binance Exchange', 'BNB'],
7562
+ type: 'array',
7563
+ items: {
7564
+ type: 'string'
7565
+ }
7566
+ },
7567
+ url: {
7568
+ type: 'string',
7569
+ description: 'Platform URL',
7570
+ example: 'https://www.binance.com'
7571
+ },
7572
+ type: {
7573
+ type: 'string',
7574
+ description: 'Platform type',
7575
+ enum: [
7576
+ 'BANK',
7577
+ 'BROKERAGE',
7578
+ 'CRYPTO_EXCHANGE',
7579
+ 'PAYMENT',
7580
+ 'INVESTMENT',
7581
+ 'INSURANCE',
7582
+ 'OTHER'
7583
+ ],
7584
+ example: 'CRYPTO_EXCHANGE'
7585
+ },
7586
+ logoUrl: {
7587
+ type: 'string',
7588
+ description: 'Platform logo URL',
7589
+ example: 'https://example.com/logos/binance.png'
7590
+ },
7591
+ isActive: {
7592
+ type: 'boolean',
7593
+ description: 'Whether the platform is active',
7594
+ default: true
7595
+ }
7596
+ },
7597
+ required: ['name', 'canonical', 'aliases', 'url', 'type']
7598
+ } as const;
7599
+
7600
+ export const $UpdatePlatformDto = {
7601
+ type: 'object',
7602
+ properties: {
7603
+ name: {
7604
+ type: 'string',
7605
+ description: 'Platform name',
7606
+ example: 'Binance'
7607
+ },
7608
+ canonical: {
7609
+ type: 'string',
7610
+ description: 'Platform canonical identifier (lowercase, kebab-case)',
7611
+ example: 'binance'
7612
+ },
7613
+ aliases: {
7614
+ description: 'Platform aliases (multi-language names for lookup)',
7615
+ example: ['Binance', 'Binance Exchange', 'BNB'],
7616
+ type: 'array',
7617
+ items: {
7618
+ type: 'string'
7619
+ }
7620
+ },
7621
+ url: {
7622
+ type: 'string',
7623
+ description: 'Platform URL',
7624
+ example: 'https://www.binance.com'
7625
+ },
7626
+ type: {
7627
+ type: 'string',
7628
+ description: 'Platform type',
7629
+ enum: [
7630
+ 'BANK',
7631
+ 'BROKERAGE',
7632
+ 'CRYPTO_EXCHANGE',
7633
+ 'PAYMENT',
7634
+ 'INVESTMENT',
7635
+ 'INSURANCE',
7636
+ 'OTHER'
7637
+ ],
7638
+ example: 'CRYPTO_EXCHANGE'
7639
+ },
7640
+ logoUrl: {
7641
+ type: 'string',
7642
+ description: 'Platform logo URL',
7643
+ example: 'https://example.com/logos/binance.png'
7644
+ },
7645
+ isActive: {
7646
+ type: 'boolean',
7647
+ description: 'Whether the platform is active',
7648
+ default: true
7649
+ }
7650
+ }
6369
7651
  } as const;
6370
7652
 
6371
7653
  export const $NetWorthByCurrencyDto = {
@@ -6522,11 +7804,12 @@ export const $AccountItemDto = {
6522
7804
  name: {
6523
7805
  type: 'string',
6524
7806
  description: 'Full account name',
6525
- example: 'Assets:Bank:CMB:Savings'
7807
+ example: 'Assets:CN:CMB:Savings'
6526
7808
  },
6527
7809
  displayName: {
6528
7810
  type: 'string',
6529
- description: 'Display name (last part of account path)',
7811
+ description:
7812
+ 'Display name: user-set name if provided (#762), else the ADR-0114 chain — request-locale catalog name, en pivot, then the last part of the account path (#771)',
6530
7813
  example: 'Savings'
6531
7814
  },
6532
7815
  balance: {
@@ -6562,7 +7845,8 @@ export const $PlatformGroupDto = {
6562
7845
  example: 'CMB Bank'
6563
7846
  },
6564
7847
  accounts: {
6565
- description: 'Accounts within this platform',
7848
+ description:
7849
+ 'Accounts within this platform (Assets and Liabilities rows, #696)',
6566
7850
  type: 'array',
6567
7851
  items: {
6568
7852
  $ref: '#/components/schemas/AccountItemDto'
@@ -6570,7 +7854,8 @@ export const $PlatformGroupDto = {
6570
7854
  },
6571
7855
  totalBalance: {
6572
7856
  type: 'string',
6573
- description: 'FX-converted total balance in base currency',
7857
+ description:
7858
+ 'FX-converted total balance in base currency (nets Assets + Liabilities rows; can be negative)',
6574
7859
  example: '100000.00'
6575
7860
  },
6576
7861
  balanceByCurrency: {
@@ -6589,7 +7874,7 @@ export const $PlatformGroupDto = {
6589
7874
  sharePct: {
6590
7875
  type: 'number',
6591
7876
  description:
6592
- 'Share of the grand converted total (0-100); 0 when grand total is 0',
7877
+ 'Share of the converted asset-side grand total (0-100); liability balances are excluded from the basis; 0 when grand total is 0 (#696)',
6593
7878
  example: 42.5
6594
7879
  }
6595
7880
  },
@@ -6637,7 +7922,8 @@ export const $AccountsSummaryDto = {
6637
7922
  properties: {
6638
7923
  totalAccounts: {
6639
7924
  type: 'number',
6640
- description: 'Total number of accounts'
7925
+ description:
7926
+ 'Total number of accounts (balance sheet: Assets + Liabilities, #696)'
6641
7927
  },
6642
7928
  totalPlatforms: {
6643
7929
  type: 'number',
@@ -6691,11 +7977,12 @@ export const $AccountItemWithAssetClassDto = {
6691
7977
  name: {
6692
7978
  type: 'string',
6693
7979
  description: 'Full account name',
6694
- example: 'Assets:Bank:CMB:Savings'
7980
+ example: 'Assets:CN:CMB:Savings'
6695
7981
  },
6696
7982
  displayName: {
6697
7983
  type: 'string',
6698
- description: 'Display name (last part of account path)',
7984
+ description:
7985
+ 'Display name: user-set name if provided (#762), else the ADR-0114 chain — request-locale catalog name, en pivot, then the last part of the account path (#771)',
6699
7986
  example: 'Savings'
6700
7987
  },
6701
7988
  balance: {
@@ -6866,7 +8153,7 @@ export const $HoldingAssetClassAccountSliceDto = {
6866
8153
  accountPath: {
6867
8154
  type: 'string',
6868
8155
  description: 'Full account path',
6869
- example: 'Assets:US:Investments:Brokerage'
8156
+ example: 'Assets:US:Fidelity:Brokerage'
6870
8157
  },
6871
8158
  accountCurrency: {
6872
8159
  type: 'string',
@@ -7181,7 +8468,7 @@ export const $MonetaryDto = {
7181
8468
  example: 'USD'
7182
8469
  },
7183
8470
  baseCcyEquivalent: {
7184
- type: 'object',
8471
+ type: 'string',
7185
8472
  description: 'Converted to user base currency (Decimal string)',
7186
8473
  example: '21600',
7187
8474
  nullable: true
@@ -7257,13 +8544,13 @@ export const $HoldingPnlRowDto = {
7257
8544
  example: 'Assets:US:Broker:AAPL'
7258
8545
  },
7259
8546
  accountCcy: {
7260
- type: 'object',
8547
+ type: 'string',
7261
8548
  description: 'Account settlement currency (ISO 4217), from cost currency',
7262
8549
  nullable: true,
7263
8550
  example: 'USD'
7264
8551
  },
7265
8552
  brokerType: {
7266
- type: 'object',
8553
+ type: 'string',
7267
8554
  description: 'Broker type derived from Platform.type',
7268
8555
  nullable: true,
7269
8556
  example: 'broker'
@@ -7284,7 +8571,7 @@ export const $HoldingPnlRowDto = {
7284
8571
  example: 'EQUITY'
7285
8572
  },
7286
8573
  assetSubClass: {
7287
- type: 'object',
8574
+ type: 'string',
7288
8575
  nullable: true,
7289
8576
  example: 'STOCK'
7290
8577
  },
@@ -7331,14 +8618,14 @@ export const $HoldingPnlRowDto = {
7331
8618
  ]
7332
8619
  },
7333
8620
  unrealizedPnlBase: {
7334
- type: 'object',
8621
+ type: 'string',
7335
8622
  description:
7336
8623
  'Unrealized P&L in base currency (Decimal string); null when any FX/price missing',
7337
8624
  nullable: true,
7338
8625
  example: '6000'
7339
8626
  },
7340
8627
  unrealizedPnlPct: {
7341
- type: 'object',
8628
+ type: 'string',
7342
8629
  description: 'Unrealized P&L % (Decimal string)',
7343
8630
  nullable: true,
7344
8631
  example: '25'
@@ -7362,7 +8649,7 @@ export const $HoldingPnlRowDto = {
7362
8649
  ]
7363
8650
  },
7364
8651
  pctOfInvestedAssets: {
7365
- type: 'object',
8652
+ type: 'string',
7366
8653
  description:
7367
8654
  'Share of invested assets % (Decimal string); only for invested chartTokens',
7368
8655
  nullable: true,
@@ -7407,15 +8694,15 @@ export const $HoldingPnlWarningDto = {
7407
8694
  ]
7408
8695
  },
7409
8696
  symbol: {
7410
- type: 'object',
8697
+ type: 'string',
7411
8698
  nullable: true
7412
8699
  },
7413
8700
  accountId: {
7414
- type: 'object',
8701
+ type: 'string',
7415
8702
  nullable: true
7416
8703
  },
7417
8704
  currency: {
7418
- type: 'object',
8705
+ type: 'string',
7419
8706
  nullable: true
7420
8707
  }
7421
8708
  },
@@ -7456,292 +8743,378 @@ export const $HoldingPnlResponseDto = {
7456
8743
  required: ['asOfDate', 'baseCurrency', 'method', 'rows', 'warnings']
7457
8744
  } as const;
7458
8745
 
7459
- export const $CurrencyBalanceDto = {
8746
+ export const $AnonymousLoginDto = {
7460
8747
  type: 'object',
7461
8748
  properties: {
7462
- currency: {
8749
+ accessToken: {
7463
8750
  type: 'string',
7464
- description: 'ISO 4217 currency code',
7465
- example: 'CNY'
7466
- },
7467
- balance: {
8751
+ description: 'Access token for anonymous login'
8752
+ }
8753
+ },
8754
+ required: ['accessToken']
8755
+ } as const;
8756
+
8757
+ export const $AnonymousLoginResponseDto = {
8758
+ type: 'object',
8759
+ properties: {
8760
+ authToken: {
7468
8761
  type: 'string',
7469
- description: 'Balance amount',
7470
- example: '500000.00'
8762
+ description: 'JWT auth token',
8763
+ example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
7471
8764
  }
7472
8765
  },
7473
- required: ['currency', 'balance']
8766
+ required: ['authToken']
7474
8767
  } as const;
7475
8768
 
7476
- export const $TimeSeriesPointDto = {
8769
+ export const $ParserContributionMetaDto = {
7477
8770
  type: 'object',
7478
8771
  properties: {
7479
- date: {
8772
+ institution: {
7480
8773
  type: 'string',
7481
- description: 'Date in YYYY-MM-DD format',
7482
- example: '2024-06-15'
8774
+ description: 'Institution slug (lowercase kebab-case)',
8775
+ pattern: '^[a-z0-9]+(-[a-z0-9]+)*$',
8776
+ example: 'icbc'
7483
8777
  },
7484
- value: {
8778
+ region: {
7485
8779
  type: 'string',
7486
- description: 'Value at this date (in base currency)',
7487
- example: '500000.00'
8780
+ enum: [
8781
+ 'cn',
8782
+ 'us',
8783
+ 'de',
8784
+ 'fr',
8785
+ 'gb',
8786
+ 'hk',
8787
+ 'jp',
8788
+ 'sg',
8789
+ 'au',
8790
+ 'ca',
8791
+ 'other'
8792
+ ]
7488
8793
  },
7489
- change: {
7490
- type: 'object',
7491
- description: 'Change from previous point',
7492
- example: '5000.00'
8794
+ accountType: {
8795
+ type: 'string',
8796
+ enum: ['checking', 'savings', 'credit', 'debit', 'investment']
7493
8797
  },
7494
- assets: {
8798
+ format: {
7495
8799
  type: 'string',
7496
- description: 'Total assets at this date (in base currency)',
7497
- example: '494338.00'
8800
+ enum: ['csv', 'xlsx', 'pdf', 'ofx', 'qif']
7498
8801
  },
7499
- liabilities: {
8802
+ institutionDisplayName: {
7500
8803
  type: 'string',
7501
- description: 'Total liabilities at this date (in base currency)',
7502
- example: '310098.00'
8804
+ example: '中国工商银行'
7503
8805
  },
7504
- byCurrency: {
7505
- description: 'Multi-currency breakdown for this point',
8806
+ encoding: {
8807
+ type: 'string',
8808
+ example: 'utf-8'
8809
+ },
8810
+ delimiter: {
8811
+ type: 'string',
8812
+ description: 'CSV delimiter character: ",", ";", "\\t" or "|"'
8813
+ },
8814
+ headerRows: {
8815
+ type: 'number',
8816
+ default: 1,
8817
+ description: 'Header row count; the client omits the field when it is 1'
8818
+ },
8819
+ notes: {
8820
+ type: 'string',
8821
+ maxLength: 2000
8822
+ }
8823
+ },
8824
+ required: ['institution', 'region', 'accountType', 'format']
8825
+ } as const;
8826
+
8827
+ export const $ParserContributionSamplesDto = {
8828
+ type: 'object',
8829
+ properties: {
8830
+ rows: {
8831
+ description:
8832
+ 'Client-sanitized sample rows (key = column name, value = cell)',
7506
8833
  type: 'array',
7507
8834
  items: {
7508
- $ref: '#/components/schemas/CurrencyBalanceDto'
8835
+ type: 'object'
7509
8836
  }
8837
+ },
8838
+ rawHeaders: {
8839
+ type: 'array',
8840
+ items: {
8841
+ type: 'string'
8842
+ }
8843
+ }
8844
+ },
8845
+ required: ['rows']
8846
+ } as const;
8847
+
8848
+ export const $FieldHintDto = {
8849
+ type: 'object',
8850
+ properties: {
8851
+ columnName: {
8852
+ type: 'string',
8853
+ example: '交易日期'
8854
+ },
8855
+ format: {
8856
+ type: 'string',
8857
+ description: 'Date format, e.g. yyyy-MM-dd HH:mm',
8858
+ example: 'yyyy-MM-dd'
8859
+ },
8860
+ signConvention: {
8861
+ type: 'string',
8862
+ enum: ['negative-expense', 'positive-expense', 'separate-columns']
8863
+ },
8864
+ creditColumn: {
8865
+ type: 'string'
8866
+ },
8867
+ debitColumn: {
8868
+ type: 'string'
8869
+ }
8870
+ },
8871
+ required: ['columnName']
8872
+ } as const;
8873
+
8874
+ export const $ParserContributionFieldHintsDto = {
8875
+ type: 'object',
8876
+ properties: {
8877
+ date: {
8878
+ $ref: '#/components/schemas/FieldHintDto'
8879
+ },
8880
+ amount: {
8881
+ $ref: '#/components/schemas/FieldHintDto'
8882
+ },
8883
+ description: {
8884
+ $ref: '#/components/schemas/FieldHintDto'
8885
+ },
8886
+ balance: {
8887
+ $ref: '#/components/schemas/FieldHintDto'
8888
+ },
8889
+ payee: {
8890
+ $ref: '#/components/schemas/FieldHintDto'
8891
+ },
8892
+ reference: {
8893
+ $ref: '#/components/schemas/FieldHintDto'
8894
+ },
8895
+ category: {
8896
+ $ref: '#/components/schemas/FieldHintDto'
7510
8897
  }
7511
8898
  },
7512
- required: ['date', 'value']
8899
+ required: ['date', 'amount']
7513
8900
  } as const;
7514
8901
 
7515
- export const $TrendSummaryDto = {
8902
+ export const $ExpectedTransactionDto = {
7516
8903
  type: 'object',
7517
8904
  properties: {
7518
- startValue: {
8905
+ date: {
7519
8906
  type: 'string',
7520
- description: 'Value at start of period',
7521
- example: '450000.00'
8907
+ example: '2026-08-01'
7522
8908
  },
7523
- endValue: {
7524
- type: 'string',
7525
- description: 'Value at end of period',
7526
- example: '500000.00'
8909
+ amount: {
8910
+ type: 'number',
8911
+ example: -45.5
7527
8912
  },
7528
- totalChange: {
8913
+ description: {
7529
8914
  type: 'string',
7530
- description: 'Total change over period',
7531
- example: '50000.00'
8915
+ example: '星巴克-***店'
7532
8916
  },
7533
- totalChangePercentage: {
7534
- type: 'string',
7535
- description: 'Total change percentage',
7536
- example: '+11.11%'
8917
+ payee: {
8918
+ type: 'string'
8919
+ },
8920
+ category: {
8921
+ type: 'string'
7537
8922
  }
7538
8923
  },
7539
- required: ['startValue', 'endValue', 'totalChange', 'totalChangePercentage']
8924
+ required: ['date', 'amount', 'description']
7540
8925
  } as const;
7541
8926
 
7542
- export const $MultiCurrencyPointDto = {
8927
+ export const $ParserContributionExamplesDto = {
7543
8928
  type: 'object',
7544
8929
  properties: {
7545
- date: {
7546
- type: 'string',
7547
- description: 'Date in YYYY-MM-DD format',
7548
- example: '2024-06-15'
7549
- },
7550
- byCurrency: {
7551
- description: 'Balances by currency',
8930
+ expectedTransactions: {
7552
8931
  type: 'array',
7553
8932
  items: {
7554
- $ref: '#/components/schemas/CurrencyBalanceDto'
8933
+ $ref: '#/components/schemas/ExpectedTransactionDto'
7555
8934
  }
7556
8935
  }
7557
8936
  },
7558
- required: ['date', 'byCurrency']
8937
+ required: ['expectedTransactions']
7559
8938
  } as const;
7560
8939
 
7561
- export const $PortfolioTrendsResponseDto = {
8940
+ export const $ParserContributionRequestDto = {
7562
8941
  type: 'object',
7563
8942
  properties: {
7564
- series: {
7565
- description: 'Time series data points',
7566
- type: 'array',
7567
- items: {
7568
- $ref: '#/components/schemas/TimeSeriesPointDto'
7569
- }
8943
+ meta: {
8944
+ $ref: '#/components/schemas/ParserContributionMetaDto'
7570
8945
  },
7571
- summary: {
7572
- description: 'Period summary',
8946
+ samples: {
8947
+ $ref: '#/components/schemas/ParserContributionSamplesDto'
8948
+ },
8949
+ fieldHints: {
8950
+ $ref: '#/components/schemas/ParserContributionFieldHintsDto'
8951
+ },
8952
+ examples: {
8953
+ description: 'Omitted entirely by the client when empty',
7573
8954
  allOf: [
7574
8955
  {
7575
- $ref: '#/components/schemas/TrendSummaryDto'
8956
+ $ref: '#/components/schemas/ParserContributionExamplesDto'
7576
8957
  }
7577
8958
  ]
7578
- },
7579
- period: {
7580
- type: 'string',
7581
- description: 'Period requested',
7582
- example: '6m'
7583
- },
7584
- granularity: {
7585
- type: 'string',
7586
- description: 'Data granularity',
7587
- example: 'month'
7588
- },
7589
- currency: {
8959
+ }
8960
+ },
8961
+ required: ['meta', 'samples', 'fieldHints']
8962
+ } as const;
8963
+
8964
+ export const $ParserContributionRelayResponseDto = {
8965
+ type: 'object',
8966
+ properties: {
8967
+ issueUrl: {
7590
8968
  type: 'string',
7591
- description: 'Base currency for converted values',
7592
- example: 'CNY'
7593
- },
7594
- byCurrency: {
7595
- description:
7596
- 'Multi-currency time series (each point has currency breakdown)',
7597
- type: 'array',
7598
- items: {
7599
- $ref: '#/components/schemas/MultiCurrencyPointDto'
7600
- }
8969
+ example: 'https://github.com/fire-zu/firela-vlt/issues/42'
7601
8970
  },
7602
- warnings: {
7603
- description: 'Exchange rate warnings',
7604
- type: 'array',
7605
- items: {
7606
- $ref: '#/components/schemas/ExchangeRateWarningDto'
7607
- }
8971
+ issueNumber: {
8972
+ type: 'number',
8973
+ example: 42
7608
8974
  }
7609
8975
  },
7610
- required: ['series', 'summary', 'period', 'granularity', 'currency']
8976
+ required: ['issueUrl', 'issueNumber']
7611
8977
  } as const;
7612
8978
 
7613
- export const $CashFlowPointDto = {
8979
+ export const $SymbolSearchResultDto = {
7614
8980
  type: 'object',
7615
8981
  properties: {
7616
- month: {
8982
+ symbol: {
7617
8983
  type: 'string',
7618
- description: 'Month key (YYYY-MM)',
7619
- example: '2024-03'
8984
+ example: 'AAPL'
7620
8985
  },
7621
- income: {
8986
+ name: {
7622
8987
  type: 'string',
7623
- description: 'Income in base currency (absolute, converted)',
7624
- example: '10000.00'
8988
+ example: 'Apple Inc.',
8989
+ nullable: true
7625
8990
  },
7626
- expense: {
8991
+ exchange: {
7627
8992
  type: 'string',
7628
- description: 'Expense in base currency (absolute, converted)',
7629
- example: '5000.00'
8993
+ example: 'US',
8994
+ nullable: true
7630
8995
  },
7631
- netSavings: {
8996
+ assetType: {
7632
8997
  type: 'string',
7633
- description: 'netSavings = income − expense (savings positive)',
7634
- example: '5000.00'
8998
+ description: 'OpenBB asset_type (e.g. stock, etf)',
8999
+ example: 'stock',
9000
+ nullable: true
9001
+ },
9002
+ assetClass: {
9003
+ type: 'string',
9004
+ description: 'IGN asset class (region.types.ts ASSET_CLASSES)',
9005
+ example: 'EQUITY',
9006
+ nullable: true
9007
+ },
9008
+ assetSubClass: {
9009
+ type: 'string',
9010
+ description: 'IGN asset sub-class (region.types.ts ASSET_SUB_CLASSES)',
9011
+ example: 'STOCK',
9012
+ nullable: true
9013
+ },
9014
+ currency: {
9015
+ type: 'string',
9016
+ description: 'Trading currency (extra_data or inferred from exchange)',
9017
+ example: 'USD',
9018
+ nullable: true
7635
9019
  }
7636
9020
  },
7637
- required: ['month', 'income', 'expense', 'netSavings']
9021
+ required: ['symbol']
7638
9022
  } as const;
7639
9023
 
7640
- export const $CashFlowTrendSummaryDto = {
9024
+ export const $SymbolQuoteDto = {
7641
9025
  type: 'object',
7642
9026
  properties: {
7643
- totalIncome: {
9027
+ symbol: {
7644
9028
  type: 'string',
7645
- description: 'Total income across the period',
7646
- example: '60000.00'
9029
+ example: 'AAPL'
7647
9030
  },
7648
- totalExpense: {
9031
+ name: {
7649
9032
  type: 'string',
7650
- description: 'Total expense across the period',
7651
- example: '30000.00'
9033
+ example: 'Apple Inc.',
9034
+ nullable: true
7652
9035
  },
7653
- totalNetSavings: {
9036
+ exchange: {
7654
9037
  type: 'string',
7655
- description: 'income − expense across the period',
7656
- example: '30000.00'
9038
+ example: 'US',
9039
+ nullable: true
7657
9040
  },
7658
- averageMonthlyNetSavings: {
9041
+ assetType: {
7659
9042
  type: 'string',
9043
+ description: 'OpenBB asset_type',
9044
+ example: 'stock',
9045
+ nullable: true
9046
+ },
9047
+ assetClass: {
9048
+ type: 'string',
9049
+ description: 'IGN asset class',
9050
+ example: 'EQUITY',
9051
+ nullable: true
9052
+ },
9053
+ assetSubClass: {
9054
+ type: 'string',
9055
+ description: 'IGN asset sub-class',
9056
+ example: 'STOCK',
9057
+ nullable: true
9058
+ },
9059
+ currency: {
9060
+ type: 'string',
9061
+ description: 'Trading currency (extra_data or inferred from exchange)',
9062
+ example: 'USD',
9063
+ nullable: true
9064
+ },
9065
+ price: {
9066
+ type: 'string',
9067
+ description: 'Latest price (Decimal string)',
9068
+ example: '189.84',
9069
+ nullable: true
9070
+ },
9071
+ priceDate: {
9072
+ type: 'string',
9073
+ description: 'Date the price was observed (ISO yyyy-MM-dd)',
9074
+ example: '2026-08-05',
9075
+ nullable: true
9076
+ },
9077
+ changePercent: {
9078
+ type: 'number',
7660
9079
  description:
7661
- 'totalNetSavings divided by the window length (N months, incl. zero-filled)',
7662
- example: '5000.00'
7663
- }
7664
- },
7665
- required: [
7666
- 'totalIncome',
7667
- 'totalExpense',
7668
- 'totalNetSavings',
7669
- 'averageMonthlyNetSavings'
7670
- ]
7671
- } as const;
7672
-
7673
- export const $CashFlowTrendsResponseDto = {
7674
- type: 'object',
7675
- properties: {
7676
- series: {
7677
- description:
7678
- 'Monthly cash-flow series (fixed N-month window, zero-filled)',
7679
- type: 'array',
7680
- items: {
7681
- $ref: '#/components/schemas/CashFlowPointDto'
7682
- }
9080
+ 'Change vs previous close, in percentage points (1.7 == 1.7%). openbb stores change_percent as a normalized decimal; this exposes percentage points for frontend convenience.',
9081
+ example: 1.7,
9082
+ nullable: true
7683
9083
  },
7684
- summary: {
7685
- description: 'Period totals',
7686
- allOf: [
7687
- {
7688
- $ref: '#/components/schemas/CashFlowTrendSummaryDto'
7689
- }
7690
- ]
9084
+ prevClose: {
9085
+ type: 'string',
9086
+ description: 'Previous close (Decimal string)',
9087
+ nullable: true
7691
9088
  },
7692
- period: {
9089
+ open: {
7693
9090
  type: 'string',
7694
- description: 'Period requested',
7695
- example: '6m'
9091
+ description: 'Day open (Decimal string)',
9092
+ nullable: true
7696
9093
  },
7697
- granularity: {
9094
+ high: {
7698
9095
  type: 'string',
7699
- description: 'Data granularity (v1 returns month buckets)',
7700
- example: 'month'
9096
+ description: 'Day high (Decimal string)',
9097
+ nullable: true
7701
9098
  },
7702
- currency: {
9099
+ low: {
7703
9100
  type: 'string',
7704
- description: 'Base currency for converted values',
7705
- example: 'CNY'
9101
+ description: 'Day low (Decimal string)',
9102
+ nullable: true
7706
9103
  },
7707
- warnings: {
7708
- description: 'Exchange rate warnings (e.g. missing rate for a currency)',
7709
- type: 'array',
7710
- items: {
7711
- $ref: '#/components/schemas/ExchangeRateWarningDto'
7712
- }
7713
- }
7714
- },
7715
- required: ['series', 'summary', 'period', 'granularity', 'currency']
7716
- } as const;
7717
-
7718
- export const $GenerateSnapshotBody = {
7719
- type: 'object',
7720
- properties: {}
7721
- } as const;
7722
-
7723
- export const $GenerateSnapshotResponse = {
7724
- type: 'object',
7725
- properties: {}
7726
- } as const;
7727
-
7728
- export const $BackfillSnapshotsBody = {
7729
- type: 'object',
7730
- properties: {}
7731
- } as const;
7732
-
7733
- export const $BackfillSnapshotsResponse = {
7734
- type: 'object',
7735
- properties: {}
7736
- } as const;
7737
-
7738
- export const $AnonymousLoginDto = {
7739
- type: 'object',
7740
- properties: {
7741
- accessToken: {
9104
+ volume: {
7742
9105
  type: 'string',
7743
- description: 'Access token for anonymous login'
9106
+ description: 'Day volume (Decimal string)',
9107
+ nullable: true
9108
+ },
9109
+ yearHigh: {
9110
+ type: 'string',
9111
+ description: '52-week high (Decimal string)',
9112
+ nullable: true
9113
+ },
9114
+ yearLow: {
9115
+ type: 'string',
9116
+ description: '52-week low (Decimal string)',
9117
+ nullable: true
7744
9118
  }
7745
- },
7746
- required: ['accessToken']
9119
+ }
7747
9120
  } as const;