@firela/api-types 0.0.0-canary.7cd70834 → 0.0.0-canary.8a8b3972

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.
@@ -8,6 +8,12 @@ export const $CreateAccountDto = {
8
8
  description: 'Account path (hierarchical, colon-separated)',
9
9
  example: 'Assets:CN:Bank:ICBC:Checking'
10
10
  },
11
+ displayName: {
12
+ type: 'string',
13
+ description:
14
+ 'Display name to distinguish accounts at the same path (default: "")',
15
+ example: '工资卡'
16
+ },
11
17
  openDate: {
12
18
  format: 'date-time',
13
19
  type: 'string',
@@ -86,6 +92,12 @@ export const $AccountResponseDto = {
86
92
  description: 'Account path (hierarchical, colon-separated)',
87
93
  example: 'Assets:CN:Bank:ICBC:Checking'
88
94
  },
95
+ displayName: {
96
+ type: 'string',
97
+ description:
98
+ 'Display name distinguishing multiple accounts at the same path',
99
+ example: '工资卡'
100
+ },
89
101
  type: {
90
102
  type: 'string',
91
103
  description: 'Account type (root segment)',
@@ -180,6 +192,7 @@ export const $AccountResponseDto = {
180
192
  required: [
181
193
  'id',
182
194
  'path',
195
+ 'displayName',
183
196
  'type',
184
197
  'status',
185
198
  'openDate',
@@ -212,6 +225,11 @@ export const $AccountListResponseDto = {
212
225
  export const $UpdateAccountDto = {
213
226
  type: 'object',
214
227
  properties: {
228
+ displayName: {
229
+ type: 'string',
230
+ description: 'Display name to distinguish accounts at the same path',
231
+ example: '招行工资卡'
232
+ },
215
233
  currencies: {
216
234
  description: 'Allowed currencies (null = no restriction)',
217
235
  example: ['CNY', 'USD'],
@@ -251,7 +269,7 @@ export const $UpdateAccountDto = {
251
269
  }
252
270
  },
253
271
  platformId: {
254
- type: 'object',
272
+ type: 'string',
255
273
  description:
256
274
  'Platform ID (references Platform.id), null to clear association',
257
275
  example: 'c98e5d4a-2f71-4a5a-bb3c-92c9f231d5e2',
@@ -292,6 +310,222 @@ export const $ReopenAccountDto = {
292
310
  }
293
311
  } as const;
294
312
 
313
+ export const $AccountStandardResponseDto = {
314
+ type: 'object',
315
+ properties: {
316
+ path: {
317
+ type: 'string',
318
+ description: 'Account path (hierarchical, colon-separated)',
319
+ example: 'Assets:CN:Bank:ICBC:Checking'
320
+ },
321
+ type: {
322
+ type: 'string',
323
+ description: 'Account type in Beancount hierarchy',
324
+ enum: ['Assets', 'Liabilities', 'Income', 'Expenses', 'Equity'],
325
+ example: 'Assets'
326
+ },
327
+ i18nKey: {
328
+ type: 'string',
329
+ description: 'i18n key for localized display name',
330
+ example: 'account.assets.cn.bank.icbc.checking'
331
+ },
332
+ name: {
333
+ type: 'string',
334
+ description: 'Short localized display name',
335
+ example: 'Housing Fund'
336
+ },
337
+ description: {
338
+ type: 'string',
339
+ description: 'Account description (stable semantics only)',
340
+ example: 'ICBC checking account for daily transactions'
341
+ },
342
+ tags: {
343
+ description: 'Account tags for categorization',
344
+ example: ['bank', 'checking', 'primary'],
345
+ type: 'array',
346
+ items: {
347
+ type: 'string'
348
+ }
349
+ },
350
+ icon: {
351
+ type: 'string',
352
+ description: 'Icon identifier for UI display',
353
+ example: 'bank-icbc'
354
+ }
355
+ },
356
+ required: ['path', 'type', 'i18nKey', 'description', 'tags', 'icon']
357
+ } as const;
358
+
359
+ export const $AccountStandardListResponseDto = {
360
+ type: 'object',
361
+ properties: {
362
+ items: {
363
+ description: 'Array of account templates',
364
+ type: 'array',
365
+ items: {
366
+ $ref: '#/components/schemas/AccountStandardResponseDto'
367
+ }
368
+ },
369
+ total: {
370
+ type: 'number',
371
+ description: 'Total number of account templates',
372
+ example: 150
373
+ },
374
+ region: {
375
+ type: 'string',
376
+ description: 'Region code',
377
+ example: 'CN'
378
+ }
379
+ },
380
+ required: ['items', 'total', 'region']
381
+ } as const;
382
+
383
+ export const $TemplateMetadataDto = {
384
+ type: 'object',
385
+ properties: {
386
+ extendable: {
387
+ type: 'boolean',
388
+ description: 'Whether this path can be extended',
389
+ example: true
390
+ },
391
+ rootType: {
392
+ type: 'string',
393
+ description: 'Root account type',
394
+ example: 'Assets'
395
+ }
396
+ },
397
+ required: ['extendable', 'rootType']
398
+ } as const;
399
+
400
+ export const $TemplateMetadataResponseDto = {
401
+ type: 'object',
402
+ properties: {
403
+ metadata: {
404
+ $ref: '#/components/schemas/TemplateMetadataDto'
405
+ }
406
+ }
407
+ } as const;
408
+
409
+ export const $RegionConfigDto = {
410
+ type: 'object',
411
+ properties: {
412
+ currency: {
413
+ type: 'string',
414
+ example: 'EUR'
415
+ },
416
+ dateFormat: {
417
+ type: 'string',
418
+ example: 'DD.MM.YYYY'
419
+ },
420
+ locale: {
421
+ type: 'string',
422
+ example: 'de-DE'
423
+ }
424
+ },
425
+ required: ['currency', 'dateFormat', 'locale']
426
+ } as const;
427
+
428
+ export const $RegionInfoDto = {
429
+ type: 'object',
430
+ properties: {
431
+ code: {
432
+ type: 'string',
433
+ example: 'de'
434
+ },
435
+ displayName: {
436
+ type: 'string',
437
+ example: 'Germany'
438
+ },
439
+ parent: {
440
+ type: 'string'
441
+ },
442
+ chain: {
443
+ example: ['de'],
444
+ type: 'array',
445
+ items: {
446
+ type: 'string'
447
+ }
448
+ },
449
+ config: {
450
+ $ref: '#/components/schemas/RegionConfigDto'
451
+ }
452
+ },
453
+ required: ['code', 'displayName', 'chain', 'config']
454
+ } as const;
455
+
456
+ export const $RegionsMetadataResponseDto = {
457
+ type: 'object',
458
+ properties: {
459
+ regions: {
460
+ type: 'array',
461
+ items: {
462
+ $ref: '#/components/schemas/RegionInfoDto'
463
+ }
464
+ }
465
+ },
466
+ required: ['regions']
467
+ } as const;
468
+
469
+ export const $CostSpecDto = {
470
+ type: 'object',
471
+ properties: {
472
+ mode: {
473
+ type: 'string',
474
+ enum: ['per-unit', 'total', 'date', 'label', 'auto'],
475
+ description: 'Cost specification mode (mirrors engine CostSpec)'
476
+ },
477
+ numberPerUnit: {
478
+ type: 'string',
479
+ description: 'Per-unit cost (required when mode is "per-unit")',
480
+ example: '240'
481
+ },
482
+ totalNumber: {
483
+ type: 'string',
484
+ description: 'Total cost for all units (required when mode is "total")',
485
+ example: '12000'
486
+ },
487
+ currency: {
488
+ type: 'string',
489
+ description: 'Cost currency (required in all modes)',
490
+ example: 'USD'
491
+ },
492
+ date: {
493
+ type: 'string',
494
+ description:
495
+ 'Lot acquisition date, ISO 8601 (required when mode is "date")',
496
+ example: '2024-01-15'
497
+ },
498
+ label: {
499
+ type: 'string',
500
+ description:
501
+ 'Lot label (required when mode is "label"; optional tag in buy modes)'
502
+ },
503
+ merge: {
504
+ type: 'boolean',
505
+ description: 'Merge lots for AVERAGE booking (mode: auto)'
506
+ }
507
+ },
508
+ required: ['mode', 'currency']
509
+ } as const;
510
+
511
+ export const $AmountDto = {
512
+ type: 'object',
513
+ properties: {
514
+ number: {
515
+ type: 'string',
516
+ description:
517
+ 'Amount as decimal string (max 15 integer + 15 decimal digits)',
518
+ example: '170.50'
519
+ },
520
+ currency: {
521
+ type: 'string',
522
+ description: 'Currency/commodity code',
523
+ example: 'USD'
524
+ }
525
+ },
526
+ required: ['number', 'currency']
527
+ } as const;
528
+
295
529
  export const $CreatePostingDto = {
296
530
  type: 'object',
297
531
  properties: {
@@ -321,6 +555,33 @@ export const $CreatePostingDto = {
321
555
  example: {
322
556
  'tax-lot': 'Q1-2024'
323
557
  }
558
+ },
559
+ cost: {
560
+ description:
561
+ 'Cost basis (Beancount `{...}`). Maps to engine costSpec. Required for commodity holdings so they carry a monetary weight that can balance.',
562
+ example: {
563
+ mode: 'per-unit',
564
+ numberPerUnit: '240',
565
+ currency: 'USD'
566
+ },
567
+ allOf: [
568
+ {
569
+ $ref: '#/components/schemas/CostSpecDto'
570
+ }
571
+ ]
572
+ },
573
+ price: {
574
+ description:
575
+ 'Price annotation (Beancount `@...`). Maps to engine price. Used for valuation; cost takes priority for balance weight.',
576
+ example: {
577
+ number: '170',
578
+ currency: 'USD'
579
+ },
580
+ allOf: [
581
+ {
582
+ $ref: '#/components/schemas/AmountDto'
583
+ }
584
+ ]
324
585
  }
325
586
  },
326
587
  required: ['account']
@@ -409,7 +670,8 @@ export const $PostingResponseDto = {
409
670
  },
410
671
  units: {
411
672
  type: 'string',
412
- description: 'Amount (may be null if interpolated)',
673
+ description:
674
+ 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned.',
413
675
  example: '100.50'
414
676
  },
415
677
  currency: {
@@ -607,36 +869,175 @@ export const $ApiProblemResponseDto = {
607
869
  required: ['type', 'title', 'status', 'detail']
608
870
  } as const;
609
871
 
610
- export const $PostingDetailDto = {
872
+ export const $BatchCreateTransactionDto = {
611
873
  type: 'object',
612
874
  properties: {
613
- id: {
614
- type: 'string',
615
- description: 'Posting ID',
616
- example: 'clh1234567890abcdef'
617
- },
618
- accountId: {
619
- type: 'string',
620
- description: 'Account ID',
621
- example: 'clh1234567890abcdef'
622
- },
623
- accountName: {
624
- type: 'string',
625
- description: 'Account name',
626
- example: 'Assets:Bank:Checking'
875
+ transactions: {
876
+ description: 'Array of transactions to create',
877
+ minItems: 1,
878
+ maxItems: 100,
879
+ type: 'array',
880
+ items: {
881
+ $ref: '#/components/schemas/CreateTransactionDto'
882
+ }
883
+ }
884
+ },
885
+ required: ['transactions']
886
+ } as const;
887
+
888
+ export const $BatchTransactionErrorDto = {
889
+ type: 'object',
890
+ properties: {
891
+ index: {
892
+ type: 'number',
893
+ description: 'Index of failed transaction in the input array',
894
+ example: 0
627
895
  },
628
- units: {
896
+ error: {
629
897
  type: 'string',
630
- description: 'Amount (may be null if interpolated)',
631
- example: '100.50'
898
+ description: 'Error message describing the failure',
899
+ example: 'Transaction does not balance'
632
900
  },
633
- currency: {
901
+ errorCode: {
634
902
  type: 'string',
635
- description: 'Currency',
636
- example: 'USD'
903
+ description: 'Structured error code for programmatic handling',
904
+ example: 'INSUFFICIENT_QUANTITY'
905
+ }
906
+ },
907
+ required: ['index', 'error']
908
+ } as const;
909
+
910
+ export const $BatchTransactionResponseDto = {
911
+ type: 'object',
912
+ properties: {
913
+ succeeded: {
914
+ description: 'Successfully created transactions',
915
+ type: 'array',
916
+ items: {
917
+ $ref: '#/components/schemas/TransactionResponseDto'
918
+ }
637
919
  },
638
- costAmount: {
639
- type: 'string',
920
+ failed: {
921
+ description: 'Failed transactions with error details',
922
+ type: 'array',
923
+ items: {
924
+ $ref: '#/components/schemas/BatchTransactionErrorDto'
925
+ }
926
+ }
927
+ },
928
+ required: ['succeeded', 'failed']
929
+ } as const;
930
+
931
+ export const $CorrectTransactionDto = {
932
+ type: 'object',
933
+ properties: {
934
+ date: {
935
+ type: 'string',
936
+ description: 'Transaction date (ISO 8601 format)',
937
+ example: '2024-11-28'
938
+ },
939
+ flag: {
940
+ type: 'string',
941
+ description: 'Transaction flag: * (cleared), ! (pending)',
942
+ enum: ['*', '!'],
943
+ example: '*'
944
+ },
945
+ payee: {
946
+ type: 'string',
947
+ description: 'Payee name',
948
+ example: 'Whole Foods Market'
949
+ },
950
+ narration: {
951
+ type: 'string',
952
+ description: 'Transaction narration/description',
953
+ example: 'Grocery shopping'
954
+ },
955
+ tags: {
956
+ description: 'Transaction tags (without # prefix)',
957
+ example: ['vacation', 'personal'],
958
+ type: 'array',
959
+ items: {
960
+ type: 'string'
961
+ }
962
+ },
963
+ links: {
964
+ description: 'Transaction links (without ^ prefix)',
965
+ example: ['invoice-123'],
966
+ type: 'array',
967
+ items: {
968
+ type: 'string'
969
+ }
970
+ },
971
+ postings: {
972
+ description:
973
+ 'Transaction postings (minimum 1, typically 2 for double-entry)',
974
+ type: 'array',
975
+ items: {
976
+ $ref: '#/components/schemas/CreatePostingDto'
977
+ }
978
+ },
979
+ meta: {
980
+ type: 'object',
981
+ description: 'Transaction-level metadata',
982
+ example: {
983
+ invoice: '12345'
984
+ }
985
+ },
986
+ idempotencyKey: {
987
+ type: 'string',
988
+ description:
989
+ 'Unique key for idempotent transaction creation. If provided, duplicate requests with the same key will return the existing transaction.',
990
+ example: 'import-2024-01-15-batch-001',
991
+ maxLength: 128
992
+ },
993
+ autoCreateAccounts: {
994
+ type: 'boolean',
995
+ description:
996
+ 'Auto-create accounts if not found. When true, missing accounts will be automatically created. When false (default for API), missing accounts will cause a validation error. Set to true for quick entry scenarios where you want to create accounts on-the-fly.',
997
+ default: true,
998
+ example: true
999
+ },
1000
+ correctionReason: {
1001
+ type: 'string',
1002
+ description: 'Reason for correcting/superseding the original transaction',
1003
+ example: 'Wrong amount — corrected from receipt',
1004
+ maxLength: 500
1005
+ }
1006
+ },
1007
+ required: ['date', 'narration', 'postings']
1008
+ } as const;
1009
+
1010
+ export const $PostingDetailDto = {
1011
+ type: 'object',
1012
+ properties: {
1013
+ id: {
1014
+ type: 'string',
1015
+ description: 'Posting ID',
1016
+ example: 'clh1234567890abcdef'
1017
+ },
1018
+ accountId: {
1019
+ type: 'string',
1020
+ description: 'Account ID',
1021
+ example: 'clh1234567890abcdef'
1022
+ },
1023
+ account: {
1024
+ type: 'string',
1025
+ description: 'Fully-qualified Beancount account path',
1026
+ example: 'Assets:Bank:Checking'
1027
+ },
1028
+ units: {
1029
+ type: 'string',
1030
+ description:
1031
+ 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned.',
1032
+ example: '100.50'
1033
+ },
1034
+ currency: {
1035
+ type: 'string',
1036
+ description: 'Currency',
1037
+ example: 'USD'
1038
+ },
1039
+ costAmount: {
1040
+ type: 'string',
640
1041
  description: 'Cost amount',
641
1042
  example: '98.00'
642
1043
  },
@@ -670,7 +1071,7 @@ export const $PostingDetailDto = {
670
1071
  description: 'Posting metadata'
671
1072
  }
672
1073
  },
673
- required: ['id', 'accountId', 'accountName']
1074
+ required: ['id', 'accountId', 'account']
674
1075
  } as const;
675
1076
 
676
1077
  export const $TransactionDetailDto = {
@@ -742,8 +1143,8 @@ export const $TransactionDetailDto = {
742
1143
  },
743
1144
  sourceType: {
744
1145
  type: 'string',
745
- description: 'Source type (how the transaction was created)',
746
- enum: ['NLP', 'CSV', 'OCR', 'API']
1146
+ description:
1147
+ 'Source type (free-form string from transaction metadata, e.g. import, api)'
747
1148
  },
748
1149
  sourcePlatform: {
749
1150
  type: 'string',
@@ -776,6 +1177,18 @@ export const $TransactionDetailDto = {
776
1177
  type: 'string',
777
1178
  description: 'Correction reason (if voided or superseded)',
778
1179
  example: 'Duplicate entry'
1180
+ },
1181
+ supersededBy: {
1182
+ type: 'string',
1183
+ description:
1184
+ 'ID of the transaction that supersedes this one (set when status=SUPERSEDED)',
1185
+ example: 'clh1234567890abcdef'
1186
+ },
1187
+ originalTxn: {
1188
+ type: 'string',
1189
+ description:
1190
+ 'ID of the transaction this one corrected/replaced (back-link on the replacement)',
1191
+ example: 'clh1234567890abcdef'
779
1192
  }
780
1193
  },
781
1194
  required: [
@@ -819,6 +1232,37 @@ export const $TransactionListResponseDto = {
819
1232
  required: ['data', 'total', 'limit', 'offset']
820
1233
  } as const;
821
1234
 
1235
+ export const $TagSuggestionDto = {
1236
+ type: 'object',
1237
+ properties: {
1238
+ tag: {
1239
+ type: 'string',
1240
+ description: 'Tag name',
1241
+ example: 'Monthly'
1242
+ },
1243
+ count: {
1244
+ type: 'number',
1245
+ description: 'Usage count across ACTIVE transactions',
1246
+ example: 12
1247
+ }
1248
+ },
1249
+ required: ['tag', 'count']
1250
+ } as const;
1251
+
1252
+ export const $TagSuggestionsResponseDto = {
1253
+ type: 'object',
1254
+ properties: {
1255
+ data: {
1256
+ description: 'Tag suggestions sorted as requested',
1257
+ type: 'array',
1258
+ items: {
1259
+ $ref: '#/components/schemas/TagSuggestionDto'
1260
+ }
1261
+ }
1262
+ },
1263
+ required: ['data']
1264
+ } as const;
1265
+
822
1266
  export const $UpdateTransactionDto = {
823
1267
  type: 'object',
824
1268
  properties: {
@@ -876,217 +1320,91 @@ export const $UpdateTransactionDto = {
876
1320
  }
877
1321
  } as const;
878
1322
 
879
- export const $AccountStandardResponseDto = {
1323
+ export const $BalanceResponseDto = {
880
1324
  type: 'object',
881
1325
  properties: {
882
- path: {
883
- type: 'string',
884
- description: 'Account path (hierarchical, colon-separated)',
885
- example: 'Assets:CN:Bank:ICBC:Checking'
886
- },
887
- type: {
1326
+ account: {
888
1327
  type: 'string',
889
- description: 'Account type in Beancount hierarchy',
890
- enum: ['Assets', 'Liabilities', 'Income', 'Expenses', 'Equity'],
891
- example: 'Assets'
1328
+ description: 'Account name',
1329
+ example: 'Assets:Bank:Checking'
892
1330
  },
893
- i18nKey: {
1331
+ balance: {
894
1332
  type: 'string',
895
- description: 'i18n key for localized display name',
896
- example: 'account.assets.cn.bank.icbc.checking'
1333
+ description: 'Balance amount (decimal string for precision)',
1334
+ example: '12345.67'
897
1335
  },
898
- description: {
1336
+ currency: {
899
1337
  type: 'string',
900
- description: 'Account description',
901
- example: 'ICBC checking account for daily transactions'
902
- },
903
- tags: {
904
- description: 'Account tags for categorization',
905
- example: ['bank', 'checking', 'primary'],
906
- type: 'array',
907
- items: {
908
- type: 'string'
909
- }
1338
+ description: 'Currency code',
1339
+ example: 'USD'
910
1340
  },
911
- icon: {
1341
+ date: {
912
1342
  type: 'string',
913
- description: 'Icon identifier for UI display',
914
- example: 'bank-icbc'
1343
+ description: 'Date of the balance calculation (ISO 8601)',
1344
+ example: '2024-12-31T00:00:00.000Z'
915
1345
  }
916
1346
  },
917
- required: ['path', 'type']
1347
+ required: ['account', 'balance', 'currency', 'date']
918
1348
  } as const;
919
1349
 
920
- export const $AccountStandardListResponseDto = {
1350
+ export const $MultiCurrencyBalanceResponseDto = {
921
1351
  type: 'object',
922
1352
  properties: {
923
- items: {
924
- description: 'Array of account templates',
925
- type: 'array',
926
- items: {
927
- $ref: '#/components/schemas/AccountStandardResponseDto'
928
- }
1353
+ account: {
1354
+ type: 'string',
1355
+ description: 'Account name',
1356
+ example: 'Assets:Bank:Checking'
929
1357
  },
930
- total: {
931
- type: 'number',
932
- description: 'Total number of account templates',
933
- example: 150
1358
+ balances: {
1359
+ type: 'object',
1360
+ description: 'Balances by currency',
1361
+ example: {
1362
+ USD: '12345.67',
1363
+ CNY: '100000.00'
1364
+ }
934
1365
  },
935
- region: {
1366
+ date: {
936
1367
  type: 'string',
937
- description: 'Region code',
938
- example: 'CN'
1368
+ description: 'Date of the balance calculation (ISO 8601)',
1369
+ example: '2024-12-31T00:00:00.000Z'
939
1370
  }
940
1371
  },
941
- required: ['items', 'total', 'region']
1372
+ required: ['account', 'balances', 'date']
942
1373
  } as const;
943
1374
 
944
- export const $RegionConfigDto = {
1375
+ export const $TransactionSummaryDto = {
945
1376
  type: 'object',
946
1377
  properties: {
947
- currency: {
1378
+ id: {
948
1379
  type: 'string',
949
- example: 'EUR'
1380
+ description: 'Transaction ID (null if transaction deleted)',
1381
+ example: 'clh1234567890abcdef',
1382
+ nullable: true
950
1383
  },
951
- dateFormat: {
1384
+ date: {
952
1385
  type: 'string',
953
- example: 'DD.MM.YYYY'
1386
+ description: 'Transaction date (YYYY-MM-DD)',
1387
+ example: '2024-03-15'
954
1388
  },
955
- locale: {
1389
+ amount: {
956
1390
  type: 'string',
957
- example: 'de-DE'
958
- }
959
- },
960
- required: ['currency', 'dateFormat', 'locale']
961
- } as const;
962
-
963
- export const $RegionInfoDto = {
964
- type: 'object',
965
- properties: {
966
- code: {
1391
+ description: 'Transaction amount (absolute value)',
1392
+ example: '128.50'
1393
+ },
1394
+ currency: {
967
1395
  type: 'string',
968
- example: 'de'
1396
+ description: 'Currency code',
1397
+ example: 'CNY'
969
1398
  },
970
- displayName: {
1399
+ payee: {
971
1400
  type: 'string',
972
- example: 'Germany'
1401
+ description: 'Payee/Merchant name',
1402
+ example: 'Starbucks'
973
1403
  },
974
- parent: {
1404
+ narration: {
975
1405
  type: 'string',
976
- example: 'eu-core'
977
- },
978
- chain: {
979
- example: ['eu-core', 'de'],
980
- type: 'array',
981
- items: {
982
- type: 'string'
983
- }
984
- },
985
- config: {
986
- $ref: '#/components/schemas/RegionConfigDto'
987
- }
988
- },
989
- required: ['code', 'displayName', 'chain', 'config']
990
- } as const;
991
-
992
- export const $RegionsMetadataResponseDto = {
993
- type: 'object',
994
- properties: {
995
- regions: {
996
- type: 'array',
997
- items: {
998
- $ref: '#/components/schemas/RegionInfoDto'
999
- }
1000
- }
1001
- },
1002
- required: ['regions']
1003
- } as const;
1004
-
1005
- export const $BalanceResponseDto = {
1006
- type: 'object',
1007
- properties: {
1008
- account: {
1009
- type: 'string',
1010
- description: 'Account name',
1011
- example: 'Assets:Bank:Checking'
1012
- },
1013
- balance: {
1014
- type: 'string',
1015
- description: 'Balance amount (decimal string for precision)',
1016
- example: '12345.67'
1017
- },
1018
- currency: {
1019
- type: 'string',
1020
- description: 'Currency code',
1021
- example: 'USD'
1022
- },
1023
- date: {
1024
- type: 'string',
1025
- description: 'Date of the balance calculation (ISO 8601)',
1026
- example: '2024-12-31T00:00:00.000Z'
1027
- }
1028
- },
1029
- required: ['account', 'balance', 'currency', 'date']
1030
- } as const;
1031
-
1032
- export const $MultiCurrencyBalanceResponseDto = {
1033
- type: 'object',
1034
- properties: {
1035
- account: {
1036
- type: 'string',
1037
- description: 'Account name',
1038
- example: 'Assets:Bank:Checking'
1039
- },
1040
- balances: {
1041
- type: 'object',
1042
- description: 'Balances by currency',
1043
- example: {
1044
- USD: '12345.67',
1045
- CNY: '100000.00'
1046
- }
1047
- },
1048
- date: {
1049
- type: 'string',
1050
- description: 'Date of the balance calculation (ISO 8601)',
1051
- example: '2024-12-31T00:00:00.000Z'
1052
- }
1053
- },
1054
- required: ['account', 'balances', 'date']
1055
- } as const;
1056
-
1057
- export const $TransactionSummaryDto = {
1058
- type: 'object',
1059
- properties: {
1060
- id: {
1061
- type: 'string',
1062
- description: 'Transaction ID (null if transaction deleted)',
1063
- example: 'clh1234567890abcdef',
1064
- nullable: true
1065
- },
1066
- date: {
1067
- type: 'string',
1068
- description: 'Transaction date (YYYY-MM-DD)',
1069
- example: '2024-03-15'
1070
- },
1071
- amount: {
1072
- type: 'string',
1073
- description: 'Transaction amount (absolute value)',
1074
- example: '128.50'
1075
- },
1076
- currency: {
1077
- type: 'string',
1078
- description: 'Currency code',
1079
- example: 'CNY'
1080
- },
1081
- payee: {
1082
- type: 'string',
1083
- description: 'Payee/Merchant name',
1084
- example: 'Starbucks'
1085
- },
1086
- narration: {
1087
- type: 'string',
1088
- description: 'Transaction narration',
1089
- example: 'Coffee purchase'
1406
+ description: 'Transaction narration',
1407
+ example: 'Coffee purchase'
1090
1408
  },
1091
1409
  accountName: {
1092
1410
  type: 'string',
@@ -1095,8 +1413,8 @@ export const $TransactionSummaryDto = {
1095
1413
  },
1096
1414
  sourceType: {
1097
1415
  type: 'string',
1098
- description: 'Source type (NLP, CSV, OCR, API)',
1099
- enum: ['NLP', 'CSV', 'OCR', 'API']
1416
+ description:
1417
+ 'Source type (free-form string from transaction metadata, e.g. import, api)'
1100
1418
  },
1101
1419
  sourcePlatform: {
1102
1420
  type: 'string',
@@ -1136,8 +1454,10 @@ export const $ReviewSummaryDto = {
1136
1454
  },
1137
1455
  confidenceLevel: {
1138
1456
  type: 'string',
1139
- description: 'Confidence level derived from score',
1140
- enum: ['HIGH', 'MEDIUM', 'LOW']
1457
+ description:
1458
+ 'Confidence level derived from score. Null for error-type reviews (ACCOUNT_VALIDATION/PIPELINE_ERROR) which carry no confidence.',
1459
+ enum: ['HIGH', 'MEDIUM', 'LOW'],
1460
+ nullable: true
1141
1461
  },
1142
1462
  summaryKey: {
1143
1463
  type: 'string',
@@ -1161,7 +1481,8 @@ export const $ReviewSummaryDto = {
1161
1481
  },
1162
1482
  sourceType: {
1163
1483
  type: 'string',
1164
- description: 'Source type (NLP, CSV, OCR, API)'
1484
+ description:
1485
+ 'Source type (free-form string from transaction metadata, e.g. import, api)'
1165
1486
  },
1166
1487
  sourcePlatform: {
1167
1488
  type: 'string',
@@ -1271,7 +1592,20 @@ export const $DecisionOptionDto = {
1271
1592
  properties: {
1272
1593
  value: {
1273
1594
  type: 'string',
1274
- description: 'The action value to submit (e.g., UPGRADE_REPLACE, ACCEPT)'
1595
+ description: 'The action value to submit (e.g., UPGRADE_REPLACE, ACCEPT)',
1596
+ enum: [
1597
+ 'UPGRADE_REPLACE',
1598
+ 'LINK_KEEP_BOTH',
1599
+ 'IGNORE_NEW',
1600
+ 'CONFIRM_DIFFERENT',
1601
+ 'ACCEPT',
1602
+ 'REJECT',
1603
+ 'ACCEPT_AND_LEARN',
1604
+ 'CHOOSE_OTHER',
1605
+ 'CANCEL',
1606
+ 'FIX',
1607
+ 'IGNORE'
1608
+ ]
1275
1609
  },
1276
1610
  labelKey: {
1277
1611
  type: 'string',
@@ -1319,8 +1653,10 @@ export const $ReviewDetailDto = {
1319
1653
  },
1320
1654
  confidenceLevel: {
1321
1655
  type: 'string',
1322
- description: 'Confidence level derived from score',
1323
- enum: ['HIGH', 'MEDIUM', 'LOW']
1656
+ description:
1657
+ 'Confidence level derived from score. Null for error-type reviews (ACCOUNT_VALIDATION/PIPELINE_ERROR) which carry no confidence.',
1658
+ enum: ['HIGH', 'MEDIUM', 'LOW'],
1659
+ nullable: true
1324
1660
  },
1325
1661
  summaryKey: {
1326
1662
  type: 'string',
@@ -1344,7 +1680,8 @@ export const $ReviewDetailDto = {
1344
1680
  },
1345
1681
  sourceType: {
1346
1682
  type: 'string',
1347
- description: 'Source type (NLP, CSV, OCR, API)'
1683
+ description:
1684
+ 'Source type (free-form string from transaction metadata, e.g. import, api)'
1348
1685
  },
1349
1686
  sourcePlatform: {
1350
1687
  type: 'string',
@@ -1418,6 +1755,208 @@ export const $ReviewDetailDto = {
1418
1755
  ]
1419
1756
  } as const;
1420
1757
 
1758
+ export const $ResolveReviewDto = {
1759
+ type: 'object',
1760
+ properties: {
1761
+ action: {
1762
+ type: 'string',
1763
+ description:
1764
+ 'Decision action. Valid actions vary by review type — see DecisionOptionDto.value returned by the review detail endpoint.',
1765
+ enum: [
1766
+ 'UPGRADE_REPLACE',
1767
+ 'LINK_KEEP_BOTH',
1768
+ 'IGNORE_NEW',
1769
+ 'CONFIRM_DIFFERENT',
1770
+ 'ACCEPT',
1771
+ 'REJECT',
1772
+ 'ACCEPT_AND_LEARN',
1773
+ 'CHOOSE_OTHER',
1774
+ 'CANCEL',
1775
+ 'FIX',
1776
+ 'IGNORE'
1777
+ ],
1778
+ example: 'ACCEPT'
1779
+ },
1780
+ data: {
1781
+ type: 'object',
1782
+ description:
1783
+ 'Additional data for the decision (e.g., selected account ID)',
1784
+ example: {
1785
+ accountId: 'acc-123'
1786
+ }
1787
+ }
1788
+ },
1789
+ required: ['action']
1790
+ } as const;
1791
+
1792
+ export const $ResolveResultDto = {
1793
+ type: 'object',
1794
+ properties: {
1795
+ success: {
1796
+ type: 'boolean',
1797
+ description: 'Whether resolution was successful'
1798
+ },
1799
+ messageKey: {
1800
+ type: 'string',
1801
+ description:
1802
+ 'i18n message key for result message (e.g., review.payee.result.mapped)'
1803
+ },
1804
+ messageParams: {
1805
+ type: 'object',
1806
+ description:
1807
+ 'Parameters for message interpolation (e.g., { name: "PayeeName" })',
1808
+ additionalProperties: {
1809
+ type: 'string'
1810
+ }
1811
+ },
1812
+ resolutionId: {
1813
+ type: 'string',
1814
+ description: 'Resolution ID for undo'
1815
+ },
1816
+ canUndo: {
1817
+ type: 'boolean',
1818
+ description: 'Whether this decision can be undone'
1819
+ },
1820
+ undoDeadline: {
1821
+ format: 'date-time',
1822
+ type: 'string',
1823
+ description: 'Deadline for undo (24h from resolution)'
1824
+ },
1825
+ learnedRuleId: {
1826
+ type: 'string',
1827
+ description:
1828
+ 'Rule ID if learning was triggered (ACCEPT_AND_LEARN actions). Use this to deep-link to the rule management page.',
1829
+ example: 'rule_01HXK5V8N2M3P4Q5R6S7T8U9V0'
1830
+ }
1831
+ },
1832
+ required: ['success', 'resolutionId', 'canUndo', 'undoDeadline']
1833
+ } as const;
1834
+
1835
+ export const $UndoResultDto = {
1836
+ type: 'object',
1837
+ properties: {
1838
+ success: {
1839
+ type: 'boolean',
1840
+ description: 'Whether undo was successful'
1841
+ },
1842
+ message: {
1843
+ type: 'string',
1844
+ description: 'Message'
1845
+ },
1846
+ reviewId: {
1847
+ type: 'string',
1848
+ description: 'Review item ID that was restored'
1849
+ }
1850
+ },
1851
+ required: ['success', 'reviewId']
1852
+ } as const;
1853
+
1854
+ export const $BatchResolveDto = {
1855
+ type: 'object',
1856
+ properties: {
1857
+ reviewIds: {
1858
+ description: 'Review item IDs to resolve',
1859
+ example: ['review-1', 'review-2', 'review-3'],
1860
+ type: 'array',
1861
+ items: {
1862
+ type: 'string'
1863
+ }
1864
+ },
1865
+ action: {
1866
+ type: 'string',
1867
+ description: 'Decision action to apply to all items',
1868
+ enum: [
1869
+ 'UPGRADE_REPLACE',
1870
+ 'LINK_KEEP_BOTH',
1871
+ 'IGNORE_NEW',
1872
+ 'CONFIRM_DIFFERENT',
1873
+ 'ACCEPT',
1874
+ 'REJECT',
1875
+ 'ACCEPT_AND_LEARN',
1876
+ 'CHOOSE_OTHER',
1877
+ 'CANCEL',
1878
+ 'FIX',
1879
+ 'IGNORE'
1880
+ ],
1881
+ example: 'ACCEPT'
1882
+ },
1883
+ data: {
1884
+ type: 'object',
1885
+ description: 'Additional data for the decision'
1886
+ }
1887
+ },
1888
+ required: ['reviewIds', 'action']
1889
+ } as const;
1890
+
1891
+ export const $BatchResolveResultDto = {
1892
+ type: 'object',
1893
+ properties: {
1894
+ successCount: {
1895
+ type: 'number',
1896
+ description: 'Number of successfully resolved items'
1897
+ },
1898
+ failedCount: {
1899
+ type: 'number',
1900
+ description: 'Number of failed items'
1901
+ },
1902
+ results: {
1903
+ description: 'Details for each item',
1904
+ type: 'array',
1905
+ items: {
1906
+ type: 'string'
1907
+ }
1908
+ }
1909
+ },
1910
+ required: ['successCount', 'failedCount', 'results']
1911
+ } as const;
1912
+
1913
+ export const $CreatePayeeDto = {
1914
+ type: 'object',
1915
+ properties: {
1916
+ payee: {
1917
+ type: 'string',
1918
+ description:
1919
+ "User's original payee name (e.g., 'Starbucks', 'McDonald'). This is the raw payee string as entered by the user.",
1920
+ example: 'Starbucks',
1921
+ maxLength: 200
1922
+ },
1923
+ payeeProfileId: {
1924
+ type: 'string',
1925
+ description:
1926
+ 'Optional reference to global PayeeProfile for standardized data (merchant info, i18n keys, categories)',
1927
+ example: 'uuid-123',
1928
+ format: 'uuid'
1929
+ },
1930
+ customCategory: {
1931
+ type: 'string',
1932
+ description:
1933
+ "User's custom category for this payee (overrides PayeeProfile category)",
1934
+ example: 'Dining:Coffee',
1935
+ maxLength: 100
1936
+ },
1937
+ customTags: {
1938
+ description:
1939
+ "User's custom tags for this payee (e.g., ['favorite', 'work_meal'])",
1940
+ example: ['favorite', 'work_meal'],
1941
+ type: 'array',
1942
+ items: {
1943
+ type: 'string'
1944
+ }
1945
+ },
1946
+ meta: {
1947
+ type: 'object',
1948
+ description:
1949
+ 'Metadata for extended information (location, notes, contact info, etc.)',
1950
+ example: {
1951
+ location: 'Zhongguancun',
1952
+ note: 'Near subway station',
1953
+ favorite: true
1954
+ }
1955
+ }
1956
+ },
1957
+ required: ['payee']
1958
+ } as const;
1959
+
1421
1960
  export const $PayeeResponseDto = {
1422
1961
  type: 'object',
1423
1962
  properties: {
@@ -1437,14 +1976,14 @@ export const $PayeeResponseDto = {
1437
1976
  example: 'Starbucks'
1438
1977
  },
1439
1978
  payeeProfileId: {
1440
- type: 'object',
1979
+ type: 'string',
1441
1980
  description:
1442
1981
  'Reference to global PayeeProfile (merchant info, i18n keys, categories)',
1443
1982
  example: 'uuid-789',
1444
1983
  nullable: true
1445
1984
  },
1446
1985
  customCategory: {
1447
- type: 'object',
1986
+ type: 'string',
1448
1987
  description:
1449
1988
  "User's custom category (overrides PayeeProfile category if set)",
1450
1989
  example: 'Dining:Coffee',
@@ -1568,15 +2107,180 @@ export const $PayeeStatsResponseDto = {
1568
2107
  required: ['payee', 'transactionCount', 'lastUsedAt']
1569
2108
  } as const;
1570
2109
 
1571
- export const $PayeeProfileResponseDto = {
2110
+ export const $UpdatePayeeDto = {
1572
2111
  type: 'object',
1573
2112
  properties: {
1574
- id: {
2113
+ payeeProfileId: {
1575
2114
  type: 'string',
1576
- description: 'Unique identifier (UUID)',
1577
- example: '550e8400-e29b-41d4-a716-446655440000'
2115
+ description:
2116
+ 'Optional reference to global PayeeProfile for standardized data (merchant info, i18n keys, categories)',
2117
+ example: 'uuid-123',
2118
+ format: 'uuid'
1578
2119
  },
1579
- canonical: {
2120
+ customCategory: {
2121
+ type: 'string',
2122
+ description:
2123
+ "User's custom category for this payee (overrides PayeeProfile category)",
2124
+ example: 'Dining:Coffee',
2125
+ maxLength: 100
2126
+ },
2127
+ customTags: {
2128
+ description:
2129
+ "User's custom tags for this payee (e.g., ['favorite', 'work_meal'])",
2130
+ example: ['favorite', 'work_meal'],
2131
+ type: 'array',
2132
+ items: {
2133
+ type: 'string'
2134
+ }
2135
+ },
2136
+ meta: {
2137
+ type: 'object',
2138
+ description:
2139
+ 'Metadata for extended information (location, notes, contact info, etc.). Will merge with existing metadata.',
2140
+ example: {
2141
+ location: 'Zhongguancun',
2142
+ note: 'Updated note',
2143
+ favorite: true
2144
+ }
2145
+ },
2146
+ isActive: {
2147
+ type: 'boolean',
2148
+ description:
2149
+ 'Enable or disable this payee. Disabled payees will not appear in autocomplete suggestions.',
2150
+ example: true
2151
+ }
2152
+ }
2153
+ } as const;
2154
+
2155
+ export const $CreatePayeeProfileDto = {
2156
+ type: 'object',
2157
+ properties: {
2158
+ canonical: {
2159
+ type: 'string',
2160
+ description:
2161
+ 'Canonical payee name (unique, case-insensitive). This is the primary identifier for the payee.',
2162
+ example: 'Starbucks',
2163
+ maxLength: 200
2164
+ },
2165
+ aliases: {
2166
+ description:
2167
+ 'Multi-language aliases for the payee. Used for matching user input in different languages.',
2168
+ example: ['Starbucks Coffee', 'SBUX'],
2169
+ type: 'array',
2170
+ items: {
2171
+ type: 'string'
2172
+ }
2173
+ },
2174
+ i18nKey: {
2175
+ type: 'string',
2176
+ description:
2177
+ 'Translation key for i18n integration (XLIFF translation system)',
2178
+ example: 'payee.starbucks',
2179
+ maxLength: 100
2180
+ },
2181
+ category: {
2182
+ type: 'string',
2183
+ description: 'Payee category classification',
2184
+ enum: [
2185
+ 'RESTAURANT',
2186
+ 'CAFE',
2187
+ 'FAST_FOOD',
2188
+ 'BAR',
2189
+ 'SUPERMARKET',
2190
+ 'CONVENIENCE_STORE',
2191
+ 'SHOPPING_MALL',
2192
+ 'ONLINE_SHOPPING',
2193
+ 'TAXI',
2194
+ 'RIDE_SHARING',
2195
+ 'PUBLIC_TRANSPORT',
2196
+ 'PARKING',
2197
+ 'GAS_STATION',
2198
+ 'UTILITIES',
2199
+ 'TELECOM',
2200
+ 'STREAMING',
2201
+ 'HEALTHCARE',
2202
+ 'EDUCATION',
2203
+ 'ENTERTAINMENT',
2204
+ 'SPORTS',
2205
+ 'TRAVEL',
2206
+ 'HOTEL',
2207
+ 'OTHER'
2208
+ ],
2209
+ example: 'CAFE'
2210
+ },
2211
+ subCategory: {
2212
+ type: 'string',
2213
+ description: 'Sub-category for more specific classification',
2214
+ example: 'coffee_chain',
2215
+ maxLength: 100
2216
+ },
2217
+ countries: {
2218
+ description:
2219
+ 'Country/region codes where the payee operates (ISO 3166-1 alpha-2)',
2220
+ example: ['CN', 'US', 'JP'],
2221
+ type: 'array',
2222
+ items: {
2223
+ type: 'string'
2224
+ }
2225
+ },
2226
+ primaryCountry: {
2227
+ type: 'string',
2228
+ description: 'Primary operating country (ISO 3166-1 alpha-2)',
2229
+ example: 'US',
2230
+ maxLength: 2
2231
+ },
2232
+ keywords: {
2233
+ description: 'Search keywords for fuzzy matching',
2234
+ example: ['coffee', 'cafe', 'drinks'],
2235
+ type: 'array',
2236
+ items: {
2237
+ type: 'string'
2238
+ }
2239
+ },
2240
+ logoUrl: {
2241
+ type: 'string',
2242
+ description: 'Payee logo URL',
2243
+ example: 'https://example.com/logo.png'
2244
+ },
2245
+ website: {
2246
+ type: 'string',
2247
+ description: 'Official website URL',
2248
+ example: 'https://www.starbucks.com'
2249
+ },
2250
+ description: {
2251
+ type: 'string',
2252
+ description: 'Payee description',
2253
+ example: 'Global coffeehouse chain headquartered in Seattle',
2254
+ maxLength: 1000
2255
+ },
2256
+ meta: {
2257
+ type: 'object',
2258
+ description:
2259
+ 'Extended metadata (business hours, contact info, additional details)',
2260
+ example: {
2261
+ businessHours: '07:00-22:00',
2262
+ phone: '+1-800-782-7282'
2263
+ }
2264
+ },
2265
+ dataSource: {
2266
+ type: 'string',
2267
+ description: 'Data source for this profile',
2268
+ enum: ['MANUAL', 'IMPORT', 'API', 'CROWDSOURCED'],
2269
+ default: 'MANUAL'
2270
+ }
2271
+ },
2272
+ required: ['canonical', 'category']
2273
+ } as const;
2274
+
2275
+ export const $PayeeProfileResponseDto = {
2276
+ type: 'object',
2277
+ properties: {
2278
+ id: {
2279
+ type: 'string',
2280
+ description: 'Unique identifier (UUID)',
2281
+ example: '550e8400-e29b-41d4-a716-446655440000'
2282
+ },
2283
+ canonical: {
1580
2284
  type: 'string',
1581
2285
  description: 'Canonical payee name (unique, case-insensitive)',
1582
2286
  example: 'Starbucks'
@@ -1590,7 +2294,7 @@ export const $PayeeProfileResponseDto = {
1590
2294
  }
1591
2295
  },
1592
2296
  i18nKey: {
1593
- type: 'object',
2297
+ type: 'string',
1594
2298
  description: 'Translation key for i18n',
1595
2299
  example: 'payee.starbucks',
1596
2300
  nullable: true
@@ -1626,7 +2330,7 @@ export const $PayeeProfileResponseDto = {
1626
2330
  example: 'CAFE'
1627
2331
  },
1628
2332
  subCategory: {
1629
- type: 'object',
2333
+ type: 'string',
1630
2334
  description: 'Sub-category',
1631
2335
  example: 'coffee_chain',
1632
2336
  nullable: true
@@ -1640,7 +2344,7 @@ export const $PayeeProfileResponseDto = {
1640
2344
  }
1641
2345
  },
1642
2346
  primaryCountry: {
1643
- type: 'object',
2347
+ type: 'string',
1644
2348
  description: 'Primary operating country',
1645
2349
  example: 'US',
1646
2350
  nullable: true
@@ -1654,19 +2358,19 @@ export const $PayeeProfileResponseDto = {
1654
2358
  }
1655
2359
  },
1656
2360
  logoUrl: {
1657
- type: 'object',
2361
+ type: 'string',
1658
2362
  description: 'Logo URL',
1659
2363
  example: 'https://example.com/logo.png',
1660
2364
  nullable: true
1661
2365
  },
1662
2366
  website: {
1663
- type: 'object',
2367
+ type: 'string',
1664
2368
  description: 'Official website',
1665
2369
  example: 'https://www.starbucks.com',
1666
2370
  nullable: true
1667
2371
  },
1668
2372
  description: {
1669
- type: 'object',
2373
+ type: 'string',
1670
2374
  description: 'Description',
1671
2375
  example: 'Global coffeehouse chain',
1672
2376
  nullable: true
@@ -1682,9 +2386,10 @@ export const $PayeeProfileResponseDto = {
1682
2386
  example: 'MANUAL'
1683
2387
  },
1684
2388
  verifiedAt: {
1685
- type: 'object',
2389
+ type: 'string',
1686
2390
  description: 'Verification timestamp (null if not verified)',
1687
2391
  example: '2025-01-01T00:00:00.000Z',
2392
+ format: 'date-time',
1688
2393
  nullable: true
1689
2394
  },
1690
2395
  isActive: {
@@ -1739,86 +2444,361 @@ export const $PayeeProfileListResponseDto = {
1739
2444
  required: ['items', 'total']
1740
2445
  } as const;
1741
2446
 
1742
- export const $CommodityResponseDto = {
2447
+ export const $UpdatePayeeProfileDto = {
1743
2448
  type: 'object',
1744
2449
  properties: {
1745
- id: {
1746
- type: 'string',
1747
- description: 'Unique identifier',
1748
- example: 'uuid-123-456'
2450
+ aliases: {
2451
+ description:
2452
+ 'Multi-language aliases for the payee. Used for matching user input in different languages.',
2453
+ example: ['Starbucks Coffee', 'SBUX'],
2454
+ type: 'array',
2455
+ items: {
2456
+ type: 'string'
2457
+ }
1749
2458
  },
1750
- userId: {
1751
- type: 'object',
1752
- description: 'User ID (owner of the commodity)',
1753
- example: 'user-123',
1754
- nullable: true
2459
+ i18nKey: {
2460
+ type: 'string',
2461
+ description:
2462
+ 'Translation key for i18n integration (XLIFF translation system)',
2463
+ example: 'payee.starbucks',
2464
+ maxLength: 100
1755
2465
  },
1756
- symbol: {
2466
+ category: {
1757
2467
  type: 'string',
1758
- description: 'Commodity symbol (corresponds to Beancount currency field)',
1759
- example: 'AAPL'
2468
+ description: 'Payee category classification',
2469
+ enum: [
2470
+ 'RESTAURANT',
2471
+ 'CAFE',
2472
+ 'FAST_FOOD',
2473
+ 'BAR',
2474
+ 'SUPERMARKET',
2475
+ 'CONVENIENCE_STORE',
2476
+ 'SHOPPING_MALL',
2477
+ 'ONLINE_SHOPPING',
2478
+ 'TAXI',
2479
+ 'RIDE_SHARING',
2480
+ 'PUBLIC_TRANSPORT',
2481
+ 'PARKING',
2482
+ 'GAS_STATION',
2483
+ 'UTILITIES',
2484
+ 'TELECOM',
2485
+ 'STREAMING',
2486
+ 'HEALTHCARE',
2487
+ 'EDUCATION',
2488
+ 'ENTERTAINMENT',
2489
+ 'SPORTS',
2490
+ 'TRAVEL',
2491
+ 'HOTEL',
2492
+ 'OTHER'
2493
+ ],
2494
+ example: 'CAFE'
1760
2495
  },
1761
- date: {
2496
+ subCategory: {
1762
2497
  type: 'string',
1763
- description:
1764
- 'Commodity definition date (required per Beancount spec). Represents when this commodity was first defined in the accounting system.',
1765
- example: '2024-01-01',
1766
- format: 'date'
2498
+ description: 'Sub-category for more specific classification',
2499
+ example: 'coffee_chain',
2500
+ maxLength: 100
1767
2501
  },
1768
- metadata: {
1769
- type: 'object',
2502
+ countries: {
1770
2503
  description:
1771
- 'Metadata (corresponds to Beancount meta field). Contains name, assetClass, precision, note, tags, etc.',
1772
- example: {
1773
- name: 'Apple Inc.',
1774
- assetClass: 'stock',
1775
- precision: 2,
1776
- note: 'Tech stock',
1777
- source: 'AUTO_CREATED'
2504
+ 'Country/region codes where the payee operates (ISO 3166-1 alpha-2)',
2505
+ example: ['CN', 'US', 'JP'],
2506
+ type: 'array',
2507
+ items: {
2508
+ type: 'string'
1778
2509
  }
1779
2510
  },
1780
- symbolProfileId: {
1781
- type: 'object',
1782
- description:
1783
- 'Reference to SymbolProfile (market data integration, SaaS feature)',
1784
- example: 'uuid-789',
1785
- nullable: true
1786
- },
1787
- createdAt: {
1788
- format: 'date-time',
2511
+ primaryCountry: {
1789
2512
  type: 'string',
1790
- description: 'Creation timestamp',
1791
- example: '2024-11-03T10:00:00Z'
2513
+ description: 'Primary operating country (ISO 3166-1 alpha-2)',
2514
+ example: 'US',
2515
+ maxLength: 2
1792
2516
  },
1793
- updatedAt: {
1794
- format: 'date-time',
1795
- type: 'string',
1796
- description: 'Last update timestamp',
1797
- example: '2024-11-03T10:00:00Z'
1798
- }
1799
- },
1800
- required: ['id', 'symbol', 'date', 'metadata', 'createdAt', 'updatedAt']
1801
- } as const;
1802
-
1803
- export const $CommodityListResponseDto = {
1804
- type: 'object',
1805
- properties: {
1806
- items: {
1807
- description: 'List of commodities',
2517
+ keywords: {
2518
+ description: 'Search keywords for fuzzy matching',
2519
+ example: ['coffee', 'cafe', 'drinks'],
1808
2520
  type: 'array',
1809
2521
  items: {
1810
- $ref: '#/components/schemas/CommodityResponseDto'
2522
+ type: 'string'
1811
2523
  }
1812
2524
  },
1813
- total: {
1814
- type: 'number',
1815
- description: 'Total number of commodities',
1816
- example: 42
1817
- }
2525
+ logoUrl: {
2526
+ type: 'string',
2527
+ description: 'Payee logo URL',
2528
+ example: 'https://example.com/logo.png'
2529
+ },
2530
+ website: {
2531
+ type: 'string',
2532
+ description: 'Official website URL',
2533
+ example: 'https://www.starbucks.com'
2534
+ },
2535
+ description: {
2536
+ type: 'string',
2537
+ description: 'Payee description',
2538
+ example: 'Global coffeehouse chain headquartered in Seattle',
2539
+ maxLength: 1000
2540
+ },
2541
+ meta: {
2542
+ type: 'object',
2543
+ description:
2544
+ 'Extended metadata (business hours, contact info, additional details)',
2545
+ example: {
2546
+ businessHours: '07:00-22:00',
2547
+ phone: '+1-800-782-7282'
2548
+ }
2549
+ },
2550
+ dataSource: {
2551
+ type: 'string',
2552
+ description: 'Data source for this profile',
2553
+ enum: ['MANUAL', 'IMPORT', 'API', 'CROWDSOURCED'],
2554
+ default: 'MANUAL'
2555
+ },
2556
+ isActive: {
2557
+ type: 'boolean',
2558
+ description: 'Whether the payee profile is active (soft delete)',
2559
+ example: true
2560
+ },
2561
+ verifiedAt: {
2562
+ type: 'string',
2563
+ description:
2564
+ 'Verification timestamp. Set to current time to verify, or null to unverify.',
2565
+ example: '2025-01-01T00:00:00.000Z',
2566
+ format: 'date-time',
2567
+ nullable: true
2568
+ }
2569
+ }
2570
+ } as const;
2571
+
2572
+ export const $CreateCommodityDto = {
2573
+ type: 'object',
2574
+ properties: {
2575
+ symbol: {
2576
+ type: 'string',
2577
+ description:
2578
+ 'Commodity symbol (e.g., AAPL, USD, BTC) - corresponds to Beancount currency field',
2579
+ example: 'AAPL',
2580
+ maxLength: 50
2581
+ },
2582
+ date: {
2583
+ type: 'string',
2584
+ description:
2585
+ 'Commodity definition date (ISO 8601, required per Beancount spec). Represents when this commodity was first defined in the accounting system.',
2586
+ example: '2024-01-01',
2587
+ format: 'date'
2588
+ },
2589
+ metadata: {
2590
+ type: 'object',
2591
+ description:
2592
+ 'Metadata (corresponds to Beancount meta field). Can contain name, assetClass, precision, note, tags, etc.',
2593
+ example: {
2594
+ name: 'Apple Inc.',
2595
+ assetClass: 'stock',
2596
+ precision: 2,
2597
+ note: 'Long-term investment',
2598
+ tags: ['tech', 'dividend']
2599
+ }
2600
+ }
2601
+ },
2602
+ required: ['symbol', 'date']
2603
+ } as const;
2604
+
2605
+ export const $CommodityResponseDto = {
2606
+ type: 'object',
2607
+ properties: {
2608
+ id: {
2609
+ type: 'string',
2610
+ description: 'Unique identifier',
2611
+ example: 'uuid-123-456'
2612
+ },
2613
+ userId: {
2614
+ type: 'string',
2615
+ description: 'User ID (owner of the commodity)',
2616
+ example: 'user-123',
2617
+ nullable: true
2618
+ },
2619
+ symbol: {
2620
+ type: 'string',
2621
+ description: 'Commodity symbol (corresponds to Beancount currency field)',
2622
+ example: 'AAPL'
2623
+ },
2624
+ date: {
2625
+ type: 'string',
2626
+ description:
2627
+ 'Commodity definition date (required per Beancount spec). Represents when this commodity was first defined in the accounting system.',
2628
+ example: '2024-01-01',
2629
+ format: 'date'
2630
+ },
2631
+ metadata: {
2632
+ type: 'object',
2633
+ description:
2634
+ 'Metadata (corresponds to Beancount meta field). Contains name, assetClass, precision, note, tags, etc.',
2635
+ example: {
2636
+ name: 'Apple Inc.',
2637
+ assetClass: 'stock',
2638
+ precision: 2,
2639
+ note: 'Tech stock',
2640
+ source: 'AUTO_CREATED'
2641
+ }
2642
+ },
2643
+ createdAt: {
2644
+ format: 'date-time',
2645
+ type: 'string',
2646
+ description: 'Creation timestamp',
2647
+ example: '2024-11-03T10:00:00Z'
2648
+ },
2649
+ updatedAt: {
2650
+ format: 'date-time',
2651
+ type: 'string',
2652
+ description: 'Last update timestamp',
2653
+ example: '2024-11-03T10:00:00Z'
2654
+ }
2655
+ },
2656
+ required: ['id', 'symbol', 'date', 'metadata', 'createdAt', 'updatedAt']
2657
+ } as const;
2658
+
2659
+ export const $CommodityListResponseDto = {
2660
+ type: 'object',
2661
+ properties: {
2662
+ items: {
2663
+ description: 'List of commodities',
2664
+ type: 'array',
2665
+ items: {
2666
+ $ref: '#/components/schemas/CommodityResponseDto'
2667
+ }
2668
+ },
2669
+ total: {
2670
+ type: 'number',
2671
+ description: 'Total number of commodities',
2672
+ example: 42
2673
+ }
1818
2674
  },
1819
2675
  required: ['items', 'total']
1820
2676
  } as const;
1821
2677
 
2678
+ export const $UpdateCommodityDto = {
2679
+ type: 'object',
2680
+ properties: {
2681
+ date: {
2682
+ type: 'string',
2683
+ description:
2684
+ 'Commodity definition date (ISO 8601). Represents when this commodity was first defined in the accounting system.',
2685
+ example: '2024-01-01',
2686
+ format: 'date'
2687
+ },
2688
+ metadata: {
2689
+ type: 'object',
2690
+ description:
2691
+ 'Metadata (corresponds to Beancount meta field). Will merge with existing metadata. Can contain name, assetClass, precision, note, tags, etc.',
2692
+ example: {
2693
+ name: 'Updated Apple Inc.',
2694
+ assetClass: 'equity',
2695
+ precision: 4,
2696
+ note: 'Updated investment strategy',
2697
+ lastReviewed: '2024-11-03'
2698
+ }
2699
+ }
2700
+ }
2701
+ } as const;
2702
+
2703
+ export const $CreateRecurringRuleDto = {
2704
+ type: 'object',
2705
+ properties: {
2706
+ name: {
2707
+ type: 'string',
2708
+ description: 'Rule name (unique per user)',
2709
+ maxLength: 100
2710
+ },
2711
+ icon: {
2712
+ type: 'string',
2713
+ description: 'Icon emoji',
2714
+ maxLength: 10
2715
+ },
2716
+ frequency: {
2717
+ type: 'string',
2718
+ description: 'Recurring frequency',
2719
+ enum: [
2720
+ 'WEEKLY',
2721
+ 'BIWEEKLY',
2722
+ 'MONTHLY',
2723
+ 'BIMONTHLY',
2724
+ 'QUARTERLY',
2725
+ 'YEARLY',
2726
+ 'CUSTOM'
2727
+ ]
2728
+ },
2729
+ expectedAmount: {
2730
+ type: 'number',
2731
+ description: 'Expected amount (positive number)',
2732
+ minimum: 0
2733
+ },
2734
+ expectedDay: {
2735
+ type: 'number',
2736
+ description: 'Expected day of month (1-31)',
2737
+ minimum: 1,
2738
+ maximum: 31
2739
+ },
2740
+ customIntervalDays: {
2741
+ type: 'number',
2742
+ description: 'Custom interval in days (required for CUSTOM frequency)',
2743
+ minimum: 1
2744
+ },
2745
+ currency: {
2746
+ type: 'string',
2747
+ description: 'Currency code',
2748
+ default: 'CNY',
2749
+ maxLength: 10
2750
+ },
2751
+ matchPayeePattern: {
2752
+ type: 'string',
2753
+ description: 'Payee matching pattern (supports wildcards)',
2754
+ maxLength: 200
2755
+ },
2756
+ matchAmountTolerance: {
2757
+ type: 'number',
2758
+ description: 'Amount tolerance percentage (0-1)',
2759
+ default: 0.075,
2760
+ minimum: 0,
2761
+ maximum: 1
2762
+ },
2763
+ defaultExpenseAccount: {
2764
+ type: 'string',
2765
+ description: 'Default expense account for auto-create',
2766
+ maxLength: 200
2767
+ },
2768
+ defaultPaymentAccount: {
2769
+ type: 'string',
2770
+ description: 'Default payment account for auto-create',
2771
+ maxLength: 200
2772
+ },
2773
+ defaultPayee: {
2774
+ type: 'string',
2775
+ description: 'Default payee for auto-create',
2776
+ maxLength: 200
2777
+ },
2778
+ autoCreate: {
2779
+ type: 'boolean',
2780
+ description: 'Auto-create transaction when expected date arrives',
2781
+ default: false
2782
+ },
2783
+ startDate: {
2784
+ type: 'string',
2785
+ description: 'Rule start date (ISO format)'
2786
+ },
2787
+ endDate: {
2788
+ type: 'string',
2789
+ description: 'Rule end date (ISO format)'
2790
+ }
2791
+ },
2792
+ required: [
2793
+ 'name',
2794
+ 'frequency',
2795
+ 'expectedAmount',
2796
+ 'currency',
2797
+ 'matchAmountTolerance',
2798
+ 'autoCreate'
2799
+ ]
2800
+ } as const;
2801
+
1822
2802
  export const $RecurringRuleResponseDto = {
1823
2803
  type: 'object',
1824
2804
  properties: {
@@ -1930,6 +2910,37 @@ export const $RecurringRuleResponseDto = {
1930
2910
  ]
1931
2911
  } as const;
1932
2912
 
2913
+ export const $CreateRuleFromTransactionDto = {
2914
+ type: 'object',
2915
+ properties: {
2916
+ frequency: {
2917
+ type: 'string',
2918
+ description: 'Recurring frequency',
2919
+ enum: [
2920
+ 'WEEKLY',
2921
+ 'BIWEEKLY',
2922
+ 'MONTHLY',
2923
+ 'BIMONTHLY',
2924
+ 'QUARTERLY',
2925
+ 'YEARLY',
2926
+ 'CUSTOM'
2927
+ ],
2928
+ example: 'MONTHLY'
2929
+ },
2930
+ name: {
2931
+ type: 'string',
2932
+ description: 'Optional name override (default: transaction payee)',
2933
+ maxLength: 100
2934
+ },
2935
+ icon: {
2936
+ type: 'string',
2937
+ description: 'Optional icon emoji',
2938
+ maxLength: 10
2939
+ }
2940
+ },
2941
+ required: ['frequency']
2942
+ } as const;
2943
+
1933
2944
  export const $RecurringRuleWithStatsResponseDto = {
1934
2945
  type: 'object',
1935
2946
  properties: {
@@ -2088,21 +3099,109 @@ export const $RecurringRuleWithStatsResponseDto = {
2088
3099
  ]
2089
3100
  } as const;
2090
3101
 
2091
- export const $ExpectedTransactionRuleDto = {
3102
+ export const $UpdateRecurringRuleDto = {
2092
3103
  type: 'object',
2093
3104
  properties: {
2094
3105
  name: {
2095
3106
  type: 'string',
2096
- description: 'Rule name'
3107
+ description: 'Rule name',
3108
+ maxLength: 100
2097
3109
  },
2098
3110
  icon: {
2099
- type: 'object',
2100
- description: 'Rule icon'
3111
+ type: 'string',
3112
+ description: 'Icon emoji',
3113
+ maxLength: 10
2101
3114
  },
2102
3115
  frequency: {
2103
3116
  type: 'string',
2104
- description: 'Rule frequency'
2105
- },
3117
+ description: 'Recurring frequency',
3118
+ enum: [
3119
+ 'WEEKLY',
3120
+ 'BIWEEKLY',
3121
+ 'MONTHLY',
3122
+ 'BIMONTHLY',
3123
+ 'QUARTERLY',
3124
+ 'YEARLY',
3125
+ 'CUSTOM'
3126
+ ]
3127
+ },
3128
+ expectedAmount: {
3129
+ type: 'number',
3130
+ description: 'Expected amount',
3131
+ minimum: 0
3132
+ },
3133
+ expectedDay: {
3134
+ type: 'number',
3135
+ description: 'Expected day of month (1-31)',
3136
+ minimum: 1,
3137
+ maximum: 31
3138
+ },
3139
+ customIntervalDays: {
3140
+ type: 'number',
3141
+ description: 'Custom interval in days',
3142
+ minimum: 1
3143
+ },
3144
+ currency: {
3145
+ type: 'string',
3146
+ description: 'Currency code',
3147
+ maxLength: 10
3148
+ },
3149
+ matchPayeePattern: {
3150
+ type: 'string',
3151
+ description: 'Payee matching pattern',
3152
+ maxLength: 200
3153
+ },
3154
+ matchAmountTolerance: {
3155
+ type: 'number',
3156
+ description: 'Amount tolerance percentage (0-1)',
3157
+ minimum: 0,
3158
+ maximum: 1
3159
+ },
3160
+ defaultExpenseAccount: {
3161
+ type: 'string',
3162
+ description: 'Default expense account',
3163
+ maxLength: 200
3164
+ },
3165
+ defaultPaymentAccount: {
3166
+ type: 'string',
3167
+ description: 'Default payment account',
3168
+ maxLength: 200
3169
+ },
3170
+ defaultPayee: {
3171
+ type: 'string',
3172
+ description: 'Default payee',
3173
+ maxLength: 200
3174
+ },
3175
+ autoCreate: {
3176
+ type: 'boolean',
3177
+ description: 'Auto-create transaction'
3178
+ },
3179
+ isActive: {
3180
+ type: 'boolean',
3181
+ description: 'Rule active status'
3182
+ },
3183
+ endDate: {
3184
+ type: 'string',
3185
+ description: 'Rule end date (ISO format)'
3186
+ }
3187
+ }
3188
+ } as const;
3189
+
3190
+ export const $ExpectedTransactionRuleDto = {
3191
+ type: 'object',
3192
+ properties: {
3193
+ name: {
3194
+ type: 'string',
3195
+ description: 'Rule name'
3196
+ },
3197
+ icon: {
3198
+ type: 'object',
3199
+ description: 'Rule icon'
3200
+ },
3201
+ frequency: {
3202
+ type: 'string',
3203
+ description: 'Rule frequency'
3204
+ },
2106
3205
  currency: {
2107
3206
  type: 'string',
2108
3207
  description: 'Currency code'
@@ -2204,6 +3303,50 @@ export const $ExpectedTransactionListResponseDto = {
2204
3303
  required: ['items', 'total']
2205
3304
  } as const;
2206
3305
 
3306
+ export const $ConfirmMatchDto = {
3307
+ type: 'object',
3308
+ properties: {
3309
+ transactionId: {
3310
+ type: 'string',
3311
+ description: 'Transaction ID to match with'
3312
+ }
3313
+ },
3314
+ required: ['transactionId']
3315
+ } as const;
3316
+
3317
+ export const $EnterNowDto = {
3318
+ type: 'object',
3319
+ properties: {
3320
+ expenseAccount: {
3321
+ type: 'string',
3322
+ description:
3323
+ 'Override expense account (uses rule default if not provided)',
3324
+ maxLength: 200
3325
+ },
3326
+ paymentAccount: {
3327
+ type: 'string',
3328
+ description:
3329
+ 'Override payment account (uses rule default if not provided)',
3330
+ maxLength: 200
3331
+ },
3332
+ amount: {
3333
+ type: 'number',
3334
+ description: 'Override amount (uses expected amount if not provided)',
3335
+ minimum: 0
3336
+ },
3337
+ payee: {
3338
+ type: 'string',
3339
+ description: 'Override payee (uses rule default if not provided)',
3340
+ maxLength: 200
3341
+ },
3342
+ narration: {
3343
+ type: 'string',
3344
+ description: 'Optional narration',
3345
+ maxLength: 500
3346
+ }
3347
+ }
3348
+ } as const;
3349
+
2207
3350
  export const $ForecastItemDto = {
2208
3351
  type: 'object',
2209
3352
  properties: {
@@ -2228,7 +3371,7 @@ export const $ForecastItemDto = {
2228
3371
  example: '2024-04-01'
2229
3372
  },
2230
3373
  icon: {
2231
- type: 'object',
3374
+ type: 'string',
2232
3375
  description: 'Rule icon emoji',
2233
3376
  example: '🏠',
2234
3377
  nullable: true
@@ -2328,6 +3471,107 @@ export const $ForecastResponseDto = {
2328
3471
  ]
2329
3472
  } as const;
2330
3473
 
3474
+ export const $CreateTransactionRuleDto = {
3475
+ type: 'object',
3476
+ properties: {
3477
+ name: {
3478
+ type: 'string',
3479
+ minLength: 1,
3480
+ maxLength: 100
3481
+ },
3482
+ description: {
3483
+ type: 'string',
3484
+ maxLength: 500
3485
+ },
3486
+ narrationKeywords: {
3487
+ items: {
3488
+ type: 'array'
3489
+ },
3490
+ maxItems: 50,
3491
+ type: 'array'
3492
+ },
3493
+ payeeKeywords: {
3494
+ items: {
3495
+ type: 'array'
3496
+ },
3497
+ maxItems: 50,
3498
+ type: 'array'
3499
+ },
3500
+ categoryKeywords: {
3501
+ items: {
3502
+ type: 'array'
3503
+ },
3504
+ maxItems: 50,
3505
+ type: 'array'
3506
+ },
3507
+ methodKeywords: {
3508
+ items: {
3509
+ type: 'array'
3510
+ },
3511
+ maxItems: 50,
3512
+ description: 'Payment method keywords (e.g., HuaBei, YuEBao)',
3513
+ type: 'array'
3514
+ },
3515
+ categoryAccount: {
3516
+ type: 'string',
3517
+ maxLength: 200,
3518
+ description:
3519
+ 'Destination account for expenses/income (e.g., Expenses:Food:Coffee)'
3520
+ },
3521
+ matchLogic: {
3522
+ type: 'string',
3523
+ enum: ['OR', 'AND'],
3524
+ default: 'OR'
3525
+ },
3526
+ amountMin: {
3527
+ type: 'number',
3528
+ minimum: 0,
3529
+ description: 'Minimum transaction amount (inclusive)'
3530
+ },
3531
+ amountMax: {
3532
+ type: 'number',
3533
+ minimum: 0,
3534
+ description: 'Maximum transaction amount (inclusive)'
3535
+ },
3536
+ priority: {
3537
+ type: 'number',
3538
+ default: 50,
3539
+ minimum: 0,
3540
+ maximum: 1000
3541
+ },
3542
+ additionalTags: {
3543
+ items: {
3544
+ type: 'array'
3545
+ },
3546
+ maxItems: 20,
3547
+ type: 'array'
3548
+ },
3549
+ additionalMetadata: {
3550
+ type: 'object'
3551
+ },
3552
+ upsertByPayee: {
3553
+ type: 'boolean',
3554
+ description:
3555
+ 'If true, update existing rule with matching payeeKeywords[0] instead of creating new rule'
3556
+ }
3557
+ },
3558
+ required: ['name', 'matchLogic', 'priority']
3559
+ } as const;
3560
+
3561
+ export const $AmountRangeDto = {
3562
+ type: 'object',
3563
+ properties: {
3564
+ min: {
3565
+ type: 'number',
3566
+ description: 'Minimum amount'
3567
+ },
3568
+ max: {
3569
+ type: 'number',
3570
+ description: 'Maximum amount'
3571
+ }
3572
+ }
3573
+ } as const;
3574
+
2331
3575
  export const $TransactionRuleResponseDto = {
2332
3576
  type: 'object',
2333
3577
  properties: {
@@ -2382,12 +3626,12 @@ export const $TransactionRuleResponseDto = {
2382
3626
  example: 'OR'
2383
3627
  },
2384
3628
  amountRange: {
2385
- type: 'object',
2386
3629
  description: 'Amount range for matching',
2387
- example: {
2388
- min: 0,
2389
- max: 100
2390
- }
3630
+ allOf: [
3631
+ {
3632
+ $ref: '#/components/schemas/AmountRangeDto'
3633
+ }
3634
+ ]
2391
3635
  },
2392
3636
  priority: {
2393
3637
  type: 'number',
@@ -2402,6 +3646,7 @@ export const $TransactionRuleResponseDto = {
2402
3646
  type: 'string',
2403
3647
  description: 'Learning source: NLP, REVIEW_CENTER, or null for manual',
2404
3648
  enum: ['NLP', 'REVIEW_CENTER'],
3649
+ nullable: true,
2405
3650
  example: 'REVIEW_CENTER'
2406
3651
  },
2407
3652
  autoApplyEnabled: {
@@ -2423,7 +3668,9 @@ export const $TransactionRuleResponseDto = {
2423
3668
  additionalMetadata: {
2424
3669
  type: 'object',
2425
3670
  description: 'Additional metadata',
2426
- example: {}
3671
+ additionalProperties: {
3672
+ type: 'string'
3673
+ }
2427
3674
  },
2428
3675
  createdAt: {
2429
3676
  format: 'date-time',
@@ -2596,6 +3843,64 @@ export const $ValidateRuleResponseDto = {
2596
3843
  required: ['valid', 'errors', 'warnings']
2597
3844
  } as const;
2598
3845
 
3846
+ export const $BulkCreateRulesDto = {
3847
+ type: 'object',
3848
+ properties: {
3849
+ rules: {
3850
+ items: {
3851
+ type: 'array'
3852
+ },
3853
+ description: 'Array of rules to import',
3854
+ type: 'array'
3855
+ },
3856
+ conflictStrategy: {
3857
+ type: 'string',
3858
+ enum: ['replace', 'skip'],
3859
+ default: 'skip',
3860
+ description:
3861
+ 'Conflict handling strategy: skip (default) ignores duplicates, replace soft-deletes existing rule'
3862
+ }
3863
+ },
3864
+ required: ['rules', 'conflictStrategy']
3865
+ } as const;
3866
+
3867
+ export const $BulkCreateRulesResponseDto = {
3868
+ type: 'object',
3869
+ properties: {
3870
+ successCount: {
3871
+ type: 'number',
3872
+ description: 'Number of successfully created rules'
3873
+ },
3874
+ failureCount: {
3875
+ type: 'number',
3876
+ description: 'Number of failed rules'
3877
+ },
3878
+ errors: {
3879
+ type: 'array',
3880
+ description: 'Error details for failed rules',
3881
+ items: {
3882
+ type: 'object',
3883
+ properties: {
3884
+ index: {
3885
+ type: 'number'
3886
+ },
3887
+ message: {
3888
+ type: 'string'
3889
+ }
3890
+ }
3891
+ }
3892
+ },
3893
+ createdRuleIds: {
3894
+ description: 'IDs of successfully created rules',
3895
+ type: 'array',
3896
+ items: {
3897
+ type: 'string'
3898
+ }
3899
+ }
3900
+ },
3901
+ required: ['successCount', 'failureCount', 'errors', 'createdRuleIds']
3902
+ } as const;
3903
+
2599
3904
  export const $ExportRulesResponseDto = {
2600
3905
  type: 'object',
2601
3906
  properties: {
@@ -2676,7 +3981,90 @@ export const $RuleStatisticsResponseDto = {
2676
3981
  ]
2677
3982
  } as const;
2678
3983
 
2679
- export const $TestRuleDto = {
3984
+ export const $UpdateTransactionRuleDto = {
3985
+ type: 'object',
3986
+ properties: {
3987
+ name: {
3988
+ type: 'string',
3989
+ minLength: 1,
3990
+ maxLength: 100
3991
+ },
3992
+ description: {
3993
+ type: 'string',
3994
+ maxLength: 500
3995
+ },
3996
+ narrationKeywords: {
3997
+ items: {
3998
+ type: 'array'
3999
+ },
4000
+ maxItems: 50,
4001
+ type: 'array'
4002
+ },
4003
+ payeeKeywords: {
4004
+ items: {
4005
+ type: 'array'
4006
+ },
4007
+ maxItems: 50,
4008
+ type: 'array'
4009
+ },
4010
+ categoryKeywords: {
4011
+ items: {
4012
+ type: 'array'
4013
+ },
4014
+ maxItems: 50,
4015
+ type: 'array'
4016
+ },
4017
+ methodKeywords: {
4018
+ items: {
4019
+ type: 'array'
4020
+ },
4021
+ maxItems: 50,
4022
+ description: 'Payment method keywords (e.g., HuaBei, YuEBao)',
4023
+ type: 'array'
4024
+ },
4025
+ categoryAccount: {
4026
+ type: 'string',
4027
+ maxLength: 200,
4028
+ description:
4029
+ 'Destination account for expenses/income (e.g., Expenses:Food:Coffee)'
4030
+ },
4031
+ matchLogic: {
4032
+ type: 'string',
4033
+ enum: ['OR', 'AND']
4034
+ },
4035
+ amountMin: {
4036
+ type: 'number',
4037
+ minimum: 0,
4038
+ description: 'Minimum transaction amount (inclusive)'
4039
+ },
4040
+ amountMax: {
4041
+ type: 'number',
4042
+ minimum: 0,
4043
+ description: 'Maximum transaction amount (inclusive)'
4044
+ },
4045
+ priority: {
4046
+ type: 'number',
4047
+ minimum: 0,
4048
+ maximum: 1000
4049
+ },
4050
+ enabled: {
4051
+ type: 'boolean',
4052
+ description: 'Enable or disable the rule'
4053
+ },
4054
+ additionalTags: {
4055
+ items: {
4056
+ type: 'array'
4057
+ },
4058
+ maxItems: 20,
4059
+ type: 'array'
4060
+ },
4061
+ additionalMetadata: {
4062
+ type: 'object'
4063
+ }
4064
+ }
4065
+ } as const;
4066
+
4067
+ export const $TestRuleDto = {
2680
4068
  type: 'object',
2681
4069
  properties: {
2682
4070
  narration: {
@@ -2868,6 +4256,17 @@ export const $UpdateUserSettingDto = {
2868
4256
  }
2869
4257
  } as const;
2870
4258
 
4259
+ export const $UpdatePropertyDto = {
4260
+ type: 'object',
4261
+ properties: {
4262
+ value: {
4263
+ type: 'string',
4264
+ description: 'Property value'
4265
+ }
4266
+ },
4267
+ required: ['value']
4268
+ } as const;
4269
+
2871
4270
  export const $FileImportDto = {
2872
4271
  type: 'object',
2873
4272
  properties: {
@@ -3214,6 +4613,181 @@ export const $ImporterConfigDto = {
3214
4613
  ]
3215
4614
  } as const;
3216
4615
 
4616
+ export const $UpdateMapperDefaultsDto = {
4617
+ type: 'object',
4618
+ properties: {
4619
+ sourceAccount: {
4620
+ type: 'string',
4621
+ description: 'Source account for transactions (Beancount format)',
4622
+ example: 'Assets:Alipay:Balance',
4623
+ pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
4624
+ },
4625
+ currency: {
4626
+ type: 'string',
4627
+ description: 'Default currency (ISO 4217 code)',
4628
+ example: 'CNY',
4629
+ minLength: 3,
4630
+ maxLength: 3,
4631
+ pattern: '^[A-Z]{3}$'
4632
+ },
4633
+ expenseAccount: {
4634
+ type: 'string',
4635
+ description: 'Default expense account (optional)',
4636
+ example: 'Expenses:Unknown',
4637
+ pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
4638
+ },
4639
+ incomeAccount: {
4640
+ type: 'string',
4641
+ description: 'Default income account (optional)',
4642
+ example: 'Income:Unknown',
4643
+ pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
4644
+ },
4645
+ methodAccountMapping: {
4646
+ type: 'object',
4647
+ description:
4648
+ '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).',
4649
+ example: {
4650
+ HuaBei: 'Liabilities:Alipay:Huabei',
4651
+ CreditCard: 'Liabilities:CreditCard'
4652
+ }
4653
+ }
4654
+ }
4655
+ } as const;
4656
+
4657
+ export const $UpdateConfigDataDto = {
4658
+ type: 'object',
4659
+ properties: {
4660
+ defaults: {
4661
+ description: 'Mapper defaults configuration',
4662
+ allOf: [
4663
+ {
4664
+ $ref: '#/components/schemas/UpdateMapperDefaultsDto'
4665
+ }
4666
+ ]
4667
+ }
4668
+ }
4669
+ } as const;
4670
+
4671
+ export const $UpdateImporterConfigDto = {
4672
+ type: 'object',
4673
+ properties: {
4674
+ data: {
4675
+ description: 'Configuration data (v1 schema)',
4676
+ allOf: [
4677
+ {
4678
+ $ref: '#/components/schemas/UpdateConfigDataDto'
4679
+ }
4680
+ ]
4681
+ }
4682
+ }
4683
+ } as const;
4684
+
4685
+ export const $CreatePlatformDto = {
4686
+ type: 'object',
4687
+ properties: {
4688
+ name: {
4689
+ type: 'string',
4690
+ description: 'Platform name',
4691
+ example: 'Binance'
4692
+ },
4693
+ canonical: {
4694
+ type: 'string',
4695
+ description: 'Platform canonical identifier (lowercase, kebab-case)',
4696
+ example: 'binance'
4697
+ },
4698
+ aliases: {
4699
+ description: 'Platform aliases (multi-language names for lookup)',
4700
+ example: ['Binance', 'Binance Exchange', 'BNB'],
4701
+ type: 'array',
4702
+ items: {
4703
+ type: 'string'
4704
+ }
4705
+ },
4706
+ url: {
4707
+ type: 'string',
4708
+ description: 'Platform URL',
4709
+ example: 'https://www.binance.com'
4710
+ },
4711
+ type: {
4712
+ type: 'string',
4713
+ description: 'Platform type',
4714
+ enum: [
4715
+ 'BANK',
4716
+ 'BROKERAGE',
4717
+ 'CRYPTO_EXCHANGE',
4718
+ 'PAYMENT',
4719
+ 'INVESTMENT',
4720
+ 'INSURANCE',
4721
+ 'OTHER'
4722
+ ],
4723
+ example: 'CRYPTO_EXCHANGE'
4724
+ },
4725
+ logoUrl: {
4726
+ type: 'string',
4727
+ description: 'Platform logo URL',
4728
+ example: 'https://example.com/logos/binance.png'
4729
+ },
4730
+ isActive: {
4731
+ type: 'boolean',
4732
+ description: 'Whether the platform is active',
4733
+ default: true
4734
+ }
4735
+ },
4736
+ required: ['name', 'canonical', 'aliases', 'url', 'type']
4737
+ } as const;
4738
+
4739
+ export const $UpdatePlatformDto = {
4740
+ type: 'object',
4741
+ properties: {
4742
+ name: {
4743
+ type: 'string',
4744
+ description: 'Platform name',
4745
+ example: 'Binance'
4746
+ },
4747
+ canonical: {
4748
+ type: 'string',
4749
+ description: 'Platform canonical identifier (lowercase, kebab-case)',
4750
+ example: 'binance'
4751
+ },
4752
+ aliases: {
4753
+ description: 'Platform aliases (multi-language names for lookup)',
4754
+ example: ['Binance', 'Binance Exchange', 'BNB'],
4755
+ type: 'array',
4756
+ items: {
4757
+ type: 'string'
4758
+ }
4759
+ },
4760
+ url: {
4761
+ type: 'string',
4762
+ description: 'Platform URL',
4763
+ example: 'https://www.binance.com'
4764
+ },
4765
+ type: {
4766
+ type: 'string',
4767
+ description: 'Platform type',
4768
+ enum: [
4769
+ 'BANK',
4770
+ 'BROKERAGE',
4771
+ 'CRYPTO_EXCHANGE',
4772
+ 'PAYMENT',
4773
+ 'INVESTMENT',
4774
+ 'INSURANCE',
4775
+ 'OTHER'
4776
+ ],
4777
+ example: 'CRYPTO_EXCHANGE'
4778
+ },
4779
+ logoUrl: {
4780
+ type: 'string',
4781
+ description: 'Platform logo URL',
4782
+ example: 'https://example.com/logos/binance.png'
4783
+ },
4784
+ isActive: {
4785
+ type: 'boolean',
4786
+ description: 'Whether the platform is active'
4787
+ }
4788
+ }
4789
+ } as const;
4790
+
3217
4791
  export const $ProviderSyncConfigDto = {
3218
4792
  type: 'object',
3219
4793
  properties: {
@@ -3365,6 +4939,11 @@ export const $ParserTelemetryReportDto = {
3365
4939
  properties: {}
3366
4940
  } as const;
3367
4941
 
4942
+ export const $UncoveredFormatMissDto = {
4943
+ type: 'object',
4944
+ properties: {}
4945
+ } as const;
4946
+
3368
4947
  export const $ProcessNlpDto = {
3369
4948
  type: 'object',
3370
4949
  properties: {
@@ -3379,6 +4958,16 @@ export const $ProcessNlpDto = {
3379
4958
  description:
3380
4959
  'Session ID for multi-turn conversation (auto-generated if not provided)',
3381
4960
  example: 'session_abc123'
4961
+ },
4962
+ parsedData: {
4963
+ type: 'object',
4964
+ description:
4965
+ 'Parsed data from previous NLP response for session recovery. Send back the parsedData received in confirm_payee/confirm responses.',
4966
+ example: {
4967
+ amount: 35,
4968
+ currency: 'CNY',
4969
+ payee: 'Starbucks'
4970
+ }
3382
4971
  }
3383
4972
  },
3384
4973
  required: ['message']
@@ -4482,6 +6071,12 @@ export const $AccountItemWithAssetClassDto = {
4482
6071
  type: 'string',
4483
6072
  description: 'Risk level',
4484
6073
  example: 'LOW'
6074
+ },
6075
+ source: {
6076
+ type: 'string',
6077
+ description:
6078
+ 'ADR-0105 classification provenance (holding level always; account level only on FALLBACK)',
6079
+ enum: ['USER_META', 'FIAT_CURRENCY', 'OPENBB_MAPPING', 'FALLBACK']
4485
6080
  }
4486
6081
  },
4487
6082
  required: ['id', 'name', 'displayName', 'balance', 'currency', 'assetClass']
@@ -4587,6 +6182,11 @@ export const $AssetClassSummaryDto = {
4587
6182
  items: {
4588
6183
  $ref: '#/components/schemas/AccountExchangeRateWarningDto'
4589
6184
  }
6185
+ },
6186
+ fallback: {
6187
+ type: 'object',
6188
+ description:
6189
+ 'ADR-0105 §4 fallback provenance stats (holding level only). valueRatio is the grey-area share of total converted value; count is the number of source=FALLBACK holdings.'
4590
6190
  }
4591
6191
  },
4592
6192
  required: ['totalAccounts', 'totalAssetClasses', 'baseCurrency']
@@ -4609,26 +6209,122 @@ export const $AssetClassAccountsResponseDto = {
4609
6209
  $ref: '#/components/schemas/AssetClassSummaryDto'
4610
6210
  }
4611
6211
  ]
6212
+ },
6213
+ uncategorized: {
6214
+ description:
6215
+ 'ADR-0105 §6 holding-level grey-area bucket (source=FALLBACK holdings peeled out of groups). Present only for groupBy=holdingAssetClass when FALLBACK holdings exist.',
6216
+ allOf: [
6217
+ {
6218
+ $ref: '#/components/schemas/AssetClassGroupDto'
6219
+ }
6220
+ ]
4612
6221
  }
4613
6222
  },
4614
6223
  required: ['groups', 'summary']
4615
6224
  } as const;
4616
6225
 
4617
- export const $CashFlowByCurrencyDto = {
6226
+ export const $HoldingAssetClassAccountSliceDto = {
4618
6227
  type: 'object',
4619
6228
  properties: {
4620
- income: {
4621
- description: 'Income by currency',
4622
- type: 'array',
4623
- items: {
4624
- $ref: '#/components/schemas/BalanceByCurrencyDto'
4625
- }
6229
+ accountId: {
6230
+ type: 'string',
6231
+ description: 'Account ID'
4626
6232
  },
4627
- expense: {
4628
- description: 'Expense by currency',
6233
+ accountPath: {
6234
+ type: 'string',
6235
+ description: 'Full account path',
6236
+ example: 'Assets:US:Investments:Brokerage'
6237
+ },
6238
+ accountCurrency: {
6239
+ type: 'string',
6240
+ description:
6241
+ 'Currency of the holding with the largest converted base value; undefined when no holding is convertible',
6242
+ example: 'USD'
6243
+ },
6244
+ marketValueBase: {
6245
+ type: 'string',
6246
+ description:
6247
+ "Account's market value in base currency (Σ converted holdings; grey bucket included)",
6248
+ example: '50000.00'
6249
+ },
6250
+ shareOfTotalPct: {
6251
+ type: 'number',
6252
+ description:
6253
+ 'Share of the global total (0-100). 0 when globalTotal is zero (no NaN/Infinity).',
6254
+ example: 42.5
6255
+ },
6256
+ groups: {
6257
+ description: 'Per-account asset-class breakdown',
4629
6258
  type: 'array',
4630
6259
  items: {
4631
- $ref: '#/components/schemas/BalanceByCurrencyDto'
6260
+ $ref: '#/components/schemas/AssetClassGroupDto'
6261
+ }
6262
+ },
6263
+ uncategorized: {
6264
+ description:
6265
+ 'Per-account grey bucket (source=FALLBACK holdings, incl. broker cash)',
6266
+ allOf: [
6267
+ {
6268
+ $ref: '#/components/schemas/AssetClassGroupDto'
6269
+ }
6270
+ ]
6271
+ },
6272
+ holdings: {
6273
+ description:
6274
+ 'Every holding row for this account (account ID in each row’s `id` field)',
6275
+ type: 'array',
6276
+ items: {
6277
+ $ref: '#/components/schemas/AccountItemWithAssetClassDto'
6278
+ }
6279
+ }
6280
+ },
6281
+ required: [
6282
+ 'accountId',
6283
+ 'accountPath',
6284
+ 'marketValueBase',
6285
+ 'shareOfTotalPct',
6286
+ 'groups',
6287
+ 'holdings'
6288
+ ]
6289
+ } as const;
6290
+
6291
+ export const $HoldingAssetClassCrossAccountResponseDto = {
6292
+ type: 'object',
6293
+ properties: {
6294
+ global: {
6295
+ description: 'Merged cross-account holding aggregation',
6296
+ allOf: [
6297
+ {
6298
+ $ref: '#/components/schemas/AssetClassAccountsResponseDto'
6299
+ }
6300
+ ]
6301
+ },
6302
+ byAccount: {
6303
+ description: 'Per-account slices',
6304
+ type: 'array',
6305
+ items: {
6306
+ $ref: '#/components/schemas/HoldingAssetClassAccountSliceDto'
6307
+ }
6308
+ }
6309
+ },
6310
+ required: ['global', 'byAccount']
6311
+ } as const;
6312
+
6313
+ export const $CashFlowByCurrencyDto = {
6314
+ type: 'object',
6315
+ properties: {
6316
+ income: {
6317
+ description: 'Income by currency',
6318
+ type: 'array',
6319
+ items: {
6320
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
6321
+ }
6322
+ },
6323
+ expense: {
6324
+ description: 'Expense by currency',
6325
+ type: 'array',
6326
+ items: {
6327
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
4632
6328
  }
4633
6329
  },
4634
6330
  netSavings: {
@@ -4743,6 +6439,452 @@ export const $CashFlowResponseDto = {
4743
6439
  ]
4744
6440
  } as const;
4745
6441
 
6442
+ export const $MonetaryDto = {
6443
+ type: 'object',
6444
+ properties: {
6445
+ amount: {
6446
+ type: 'string',
6447
+ description: 'Amount (Decimal string)',
6448
+ example: '3000'
6449
+ },
6450
+ currency: {
6451
+ type: 'string',
6452
+ description: 'ISO 4217 currency',
6453
+ example: 'USD'
6454
+ },
6455
+ baseCcyEquivalent: {
6456
+ type: 'object',
6457
+ description: 'Converted to user base currency (Decimal string)',
6458
+ example: '21600',
6459
+ nullable: true
6460
+ }
6461
+ },
6462
+ required: ['amount', 'currency']
6463
+ } as const;
6464
+
6465
+ export const $CurrentPriceDto = {
6466
+ type: 'object',
6467
+ properties: {
6468
+ amount: {
6469
+ type: 'string',
6470
+ description: 'Price amount (Decimal string)',
6471
+ example: '250'
6472
+ },
6473
+ currency: {
6474
+ type: 'string',
6475
+ description: 'Price currency (ISO 4217)',
6476
+ example: 'USD'
6477
+ },
6478
+ date: {
6479
+ type: 'string',
6480
+ description: 'Price date (ISO 8601)',
6481
+ example: '2024-06-01'
6482
+ },
6483
+ source: {
6484
+ type: 'string',
6485
+ description: 'Price source',
6486
+ example: 'USER_OVERRIDE',
6487
+ enum: ['USER_OVERRIDE', 'OPENBB_EQUITY', 'OPENBB_CURRENCY']
6488
+ }
6489
+ },
6490
+ required: ['amount', 'currency', 'date', 'source']
6491
+ } as const;
6492
+
6493
+ export const $FxRateDto = {
6494
+ type: 'object',
6495
+ properties: {
6496
+ from: {
6497
+ type: 'string',
6498
+ example: 'USD'
6499
+ },
6500
+ to: {
6501
+ type: 'string',
6502
+ example: 'CNY'
6503
+ },
6504
+ rate: {
6505
+ type: 'string',
6506
+ description: 'FX rate (Decimal string)',
6507
+ example: '7.2'
6508
+ },
6509
+ date: {
6510
+ type: 'string',
6511
+ description: 'Rate date (ISO 8601)',
6512
+ example: '2024-01-15'
6513
+ }
6514
+ },
6515
+ required: ['from', 'to', 'rate', 'date']
6516
+ } as const;
6517
+
6518
+ export const $HoldingPnlRowDto = {
6519
+ type: 'object',
6520
+ properties: {
6521
+ accountId: {
6522
+ type: 'string',
6523
+ description: 'Account UUID',
6524
+ example: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
6525
+ },
6526
+ accountPath: {
6527
+ type: 'string',
6528
+ description: 'Full account path',
6529
+ example: 'Assets:US:Broker:AAPL'
6530
+ },
6531
+ accountCcy: {
6532
+ type: 'object',
6533
+ description: 'Account settlement currency (ISO 4217), from cost currency',
6534
+ nullable: true,
6535
+ example: 'USD'
6536
+ },
6537
+ brokerType: {
6538
+ type: 'object',
6539
+ description: 'Broker type derived from Platform.type',
6540
+ nullable: true,
6541
+ example: 'broker'
6542
+ },
6543
+ symbol: {
6544
+ type: 'string',
6545
+ description: 'Commodity symbol',
6546
+ example: 'AAPL'
6547
+ },
6548
+ chartToken: {
6549
+ type: 'string',
6550
+ description: 'Chart segment token (libs/common resolver)',
6551
+ example: 'equity',
6552
+ enum: ['equity', 'fund', 'bond', 'cash', 'other']
6553
+ },
6554
+ assetClass: {
6555
+ type: 'string',
6556
+ example: 'EQUITY'
6557
+ },
6558
+ assetSubClass: {
6559
+ type: 'object',
6560
+ nullable: true,
6561
+ example: 'STOCK'
6562
+ },
6563
+ units: {
6564
+ type: 'string',
6565
+ description: 'Net held units (Decimal string)',
6566
+ example: '12'
6567
+ },
6568
+ averageCostPerUnit: {
6569
+ description:
6570
+ 'Average cost per unit; null when cost currency conflicts or no cost',
6571
+ nullable: true,
6572
+ allOf: [
6573
+ {
6574
+ $ref: '#/components/schemas/MonetaryDto'
6575
+ }
6576
+ ]
6577
+ },
6578
+ costBasis: {
6579
+ description: 'Cost basis of held units',
6580
+ nullable: true,
6581
+ allOf: [
6582
+ {
6583
+ $ref: '#/components/schemas/MonetaryDto'
6584
+ }
6585
+ ]
6586
+ },
6587
+ marketValue: {
6588
+ description: 'Market value at asOf price',
6589
+ nullable: true,
6590
+ allOf: [
6591
+ {
6592
+ $ref: '#/components/schemas/MonetaryDto'
6593
+ }
6594
+ ]
6595
+ },
6596
+ currentPrice: {
6597
+ description: 'Price used for market value',
6598
+ nullable: true,
6599
+ allOf: [
6600
+ {
6601
+ $ref: '#/components/schemas/CurrentPriceDto'
6602
+ }
6603
+ ]
6604
+ },
6605
+ unrealizedPnlBase: {
6606
+ type: 'object',
6607
+ description:
6608
+ 'Unrealized P&L in base currency (Decimal string); null when any FX/price missing',
6609
+ nullable: true,
6610
+ example: '6000'
6611
+ },
6612
+ unrealizedPnlPct: {
6613
+ type: 'object',
6614
+ description: 'Unrealized P&L % (Decimal string)',
6615
+ nullable: true,
6616
+ example: '25'
6617
+ },
6618
+ costFxRate: {
6619
+ description: 'Historical FX rate applied to cost basis',
6620
+ nullable: true,
6621
+ allOf: [
6622
+ {
6623
+ $ref: '#/components/schemas/FxRateDto'
6624
+ }
6625
+ ]
6626
+ },
6627
+ marketFxRate: {
6628
+ description: 'FX rate applied to market value',
6629
+ nullable: true,
6630
+ allOf: [
6631
+ {
6632
+ $ref: '#/components/schemas/FxRateDto'
6633
+ }
6634
+ ]
6635
+ },
6636
+ pctOfInvestedAssets: {
6637
+ type: 'object',
6638
+ description:
6639
+ 'Share of invested assets % (Decimal string); only for invested chartTokens',
6640
+ nullable: true,
6641
+ example: '40'
6642
+ },
6643
+ realizedPnl: {
6644
+ description:
6645
+ 'Cumulative realized P&L on sold lots (asOf-date cutoff); null when the method has no applicable sells, a sell lacks a price, or any required FX rate is missing (never-mix). When a sell spans multiple currencies (cross-currency sale), amount and currency reflect the base currency; baseCcyEquivalent is always the authoritative dual-FX figure',
6646
+ nullable: true,
6647
+ allOf: [
6648
+ {
6649
+ $ref: '#/components/schemas/MonetaryDto'
6650
+ }
6651
+ ]
6652
+ }
6653
+ },
6654
+ required: [
6655
+ 'accountId',
6656
+ 'accountPath',
6657
+ 'symbol',
6658
+ 'chartToken',
6659
+ 'assetClass',
6660
+ 'units'
6661
+ ]
6662
+ } as const;
6663
+
6664
+ export const $HoldingPnlWarningDto = {
6665
+ type: 'object',
6666
+ properties: {
6667
+ type: {
6668
+ type: 'string',
6669
+ description: 'Warning type',
6670
+ example: 'MISSING_COST_FX_RATE',
6671
+ enum: [
6672
+ 'MISSING_COST_FX_RATE',
6673
+ 'MISSING_MARKET_FX_RATE',
6674
+ 'MISSING_SALE_PRICE',
6675
+ 'MISSING_REALIZED_FX_RATE',
6676
+ 'OVERSOLD_LOTS',
6677
+ 'NO_PRICE',
6678
+ 'MIXED_COST_CURRENCY'
6679
+ ]
6680
+ },
6681
+ symbol: {
6682
+ type: 'object',
6683
+ nullable: true
6684
+ },
6685
+ accountId: {
6686
+ type: 'object',
6687
+ nullable: true
6688
+ },
6689
+ currency: {
6690
+ type: 'object',
6691
+ nullable: true
6692
+ }
6693
+ },
6694
+ required: ['type']
6695
+ } as const;
6696
+
6697
+ export const $HoldingPnlResponseDto = {
6698
+ type: 'object',
6699
+ properties: {
6700
+ asOfDate: {
6701
+ type: 'string',
6702
+ example: '2026-07-08'
6703
+ },
6704
+ baseCurrency: {
6705
+ type: 'string',
6706
+ example: 'CNY'
6707
+ },
6708
+ method: {
6709
+ type: 'string',
6710
+ description:
6711
+ 'Realized-P&L lot-matching method (FIFO or average). Unrealized cost basis remains average regardless of this value (#473).',
6712
+ enum: ['average', 'FIFO'],
6713
+ example: 'average'
6714
+ },
6715
+ rows: {
6716
+ type: 'array',
6717
+ items: {
6718
+ $ref: '#/components/schemas/HoldingPnlRowDto'
6719
+ }
6720
+ },
6721
+ warnings: {
6722
+ type: 'array',
6723
+ items: {
6724
+ $ref: '#/components/schemas/HoldingPnlWarningDto'
6725
+ }
6726
+ }
6727
+ },
6728
+ required: ['asOfDate', 'baseCurrency', 'method', 'rows', 'warnings']
6729
+ } as const;
6730
+
6731
+ export const $CreateBeanPriceDto = {
6732
+ type: 'object',
6733
+ properties: {
6734
+ currency: {
6735
+ type: 'string',
6736
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
6737
+ example: 'USD'
6738
+ },
6739
+ quoteCurrency: {
6740
+ type: 'string',
6741
+ description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
6742
+ example: 'CNY'
6743
+ },
6744
+ amount: {
6745
+ type: 'number',
6746
+ description:
6747
+ 'Price amount (MUST be >= 0 per Beancount spec, supports up to 15 decimal places). Zero allowed for conversion entries, negative strictly prohibited.',
6748
+ example: 175.5,
6749
+ minimum: 0
6750
+ },
6751
+ date: {
6752
+ type: 'string',
6753
+ description: 'Price date (ISO 8601 format)',
6754
+ example: '2024-11-05'
6755
+ },
6756
+ metadata: {
6757
+ type: 'object',
6758
+ description:
6759
+ 'Metadata (validated by Zod schema, max field lengths enforced)',
6760
+ example: {
6761
+ source: 'MANUAL',
6762
+ note: 'Bank valuation report',
6763
+ confidence: 0.95
6764
+ }
6765
+ }
6766
+ },
6767
+ required: ['currency', 'quoteCurrency', 'amount', 'date']
6768
+ } as const;
6769
+
6770
+ export const $PriceResponseDto = {
6771
+ type: 'object',
6772
+ properties: {
6773
+ id: {
6774
+ type: 'string',
6775
+ description: 'Unique identifier',
6776
+ example: 'uuid-123-456'
6777
+ },
6778
+ userId: {
6779
+ type: 'string',
6780
+ description: 'User ID (owner of the price)',
6781
+ example: 'user-123'
6782
+ },
6783
+ currency: {
6784
+ type: 'string',
6785
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
6786
+ example: 'BTC'
6787
+ },
6788
+ quoteCurrency: {
6789
+ type: 'string',
6790
+ description: 'Quote currency (pricing currency, e.g., USD, CNY)',
6791
+ example: 'USD'
6792
+ },
6793
+ amount: {
6794
+ type: 'number',
6795
+ description:
6796
+ 'Price amount (corresponds to Beancount Amount.number). Supports up to 15 decimal places.',
6797
+ example: 50000
6798
+ },
6799
+ date: {
6800
+ type: 'string',
6801
+ description:
6802
+ 'Price date (ISO 8601 format). Represents the date this price was valid.',
6803
+ example: '2024-01-01',
6804
+ format: 'date'
6805
+ },
6806
+ meta: {
6807
+ type: 'object',
6808
+ description:
6809
+ 'Metadata (corresponds to Beancount meta field). Contains source, confidence, note, etc.',
6810
+ example: {
6811
+ source: 'MANUAL',
6812
+ note: 'User-defined price',
6813
+ confidence: 1
6814
+ }
6815
+ },
6816
+ createdAt: {
6817
+ format: 'date-time',
6818
+ type: 'string',
6819
+ description: 'Creation timestamp',
6820
+ example: '2024-11-03T10:00:00Z'
6821
+ },
6822
+ updatedAt: {
6823
+ format: 'date-time',
6824
+ type: 'string',
6825
+ description: 'Last update timestamp',
6826
+ example: '2024-11-03T10:00:00Z'
6827
+ }
6828
+ },
6829
+ required: [
6830
+ 'id',
6831
+ 'userId',
6832
+ 'currency',
6833
+ 'quoteCurrency',
6834
+ 'amount',
6835
+ 'date',
6836
+ 'meta',
6837
+ 'createdAt',
6838
+ 'updatedAt'
6839
+ ]
6840
+ } as const;
6841
+
6842
+ export const $PriceListResponseDto = {
6843
+ type: 'object',
6844
+ properties: {
6845
+ items: {
6846
+ description: 'List of prices',
6847
+ type: 'array',
6848
+ items: {
6849
+ $ref: '#/components/schemas/PriceResponseDto'
6850
+ }
6851
+ },
6852
+ total: {
6853
+ type: 'number',
6854
+ description: 'Total number of prices',
6855
+ example: 42
6856
+ }
6857
+ },
6858
+ required: ['items', 'total']
6859
+ } as const;
6860
+
6861
+ export const $UpdateBeanPriceDto = {
6862
+ type: 'object',
6863
+ properties: {
6864
+ currency: {
6865
+ type: 'string',
6866
+ description: 'Currency being priced'
6867
+ },
6868
+ quoteCurrency: {
6869
+ type: 'string',
6870
+ description: 'Quote currency (pricing currency)'
6871
+ },
6872
+ amount: {
6873
+ type: 'number',
6874
+ description: 'Price amount (MUST be >= 0 per Beancount spec)',
6875
+ minimum: 0
6876
+ },
6877
+ date: {
6878
+ type: 'string',
6879
+ description: 'Price date (ISO 8601 format)'
6880
+ },
6881
+ metadata: {
6882
+ type: 'object',
6883
+ description: 'Metadata'
6884
+ }
6885
+ }
6886
+ } as const;
6887
+
4746
6888
  export const $CurrencyBalanceDto = {
4747
6889
  type: 'object',
4748
6890
  properties: {