@firela/api-types 0.0.0-canary.209967 → 0.0.0-canary.2b8fcbd8

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']
@@ -399,6 +660,32 @@ export const $CreateTransactionDto = {
399
660
  required: ['date', 'narration', 'postings']
400
661
  } as const;
401
662
 
663
+ export const $CostDetailDto = {
664
+ type: 'object',
665
+ properties: {
666
+ number: {
667
+ type: 'string',
668
+ description: 'Per-unit cost basis (mirrors engine Cost.number)',
669
+ example: '240'
670
+ },
671
+ currency: {
672
+ type: 'string',
673
+ description: 'Cost currency',
674
+ example: 'USD'
675
+ },
676
+ date: {
677
+ type: 'string',
678
+ description: 'Lot acquisition date (ISO yyyy-mm-dd)',
679
+ example: '2024-01-15'
680
+ },
681
+ label: {
682
+ type: 'string',
683
+ description: 'Lot label',
684
+ example: 'lot-2024-01'
685
+ }
686
+ }
687
+ } as const;
688
+
402
689
  export const $PostingResponseDto = {
403
690
  type: 'object',
404
691
  properties: {
@@ -409,13 +696,23 @@ export const $PostingResponseDto = {
409
696
  },
410
697
  units: {
411
698
  type: 'string',
412
- description: 'Amount (may be null if interpolated)',
699
+ description:
700
+ 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned.',
413
701
  example: '100.50'
414
702
  },
415
703
  currency: {
416
704
  type: 'string',
417
705
  description: 'Currency',
418
706
  example: 'USD'
707
+ },
708
+ cost: {
709
+ description:
710
+ 'Booking-resolved cost (mirrors engine Cost). Undefined when the posting has no cost basis.',
711
+ allOf: [
712
+ {
713
+ $ref: '#/components/schemas/CostDetailDto'
714
+ }
715
+ ]
419
716
  }
420
717
  },
421
718
  required: ['account']
@@ -607,27 +904,166 @@ export const $ApiProblemResponseDto = {
607
904
  required: ['type', 'title', 'status', 'detail']
608
905
  } as const;
609
906
 
610
- export const $PostingDetailDto = {
907
+ export const $BatchCreateTransactionDto = {
611
908
  type: 'object',
612
909
  properties: {
613
- id: {
614
- type: 'string',
615
- description: 'Posting ID',
616
- example: 'clh1234567890abcdef'
910
+ transactions: {
911
+ description: 'Array of transactions to create',
912
+ minItems: 1,
913
+ maxItems: 100,
914
+ type: 'array',
915
+ items: {
916
+ $ref: '#/components/schemas/CreateTransactionDto'
917
+ }
918
+ }
919
+ },
920
+ required: ['transactions']
921
+ } as const;
922
+
923
+ export const $BatchTransactionErrorDto = {
924
+ type: 'object',
925
+ properties: {
926
+ index: {
927
+ type: 'number',
928
+ description: 'Index of failed transaction in the input array',
929
+ example: 0
617
930
  },
618
- accountId: {
931
+ error: {
619
932
  type: 'string',
620
- description: 'Account ID',
621
- example: 'clh1234567890abcdef'
933
+ description: 'Error message describing the failure',
934
+ example: 'Transaction does not balance'
622
935
  },
623
- accountName: {
936
+ errorCode: {
624
937
  type: 'string',
625
- description: 'Account name',
938
+ description: 'Structured error code for programmatic handling',
939
+ example: 'INSUFFICIENT_QUANTITY'
940
+ }
941
+ },
942
+ required: ['index', 'error']
943
+ } as const;
944
+
945
+ export const $BatchTransactionResponseDto = {
946
+ type: 'object',
947
+ properties: {
948
+ succeeded: {
949
+ description: 'Successfully created transactions',
950
+ type: 'array',
951
+ items: {
952
+ $ref: '#/components/schemas/TransactionResponseDto'
953
+ }
954
+ },
955
+ failed: {
956
+ description: 'Failed transactions with error details',
957
+ type: 'array',
958
+ items: {
959
+ $ref: '#/components/schemas/BatchTransactionErrorDto'
960
+ }
961
+ }
962
+ },
963
+ required: ['succeeded', 'failed']
964
+ } as const;
965
+
966
+ export const $CorrectTransactionDto = {
967
+ type: 'object',
968
+ properties: {
969
+ date: {
970
+ type: 'string',
971
+ description: 'Transaction date (ISO 8601 format)',
972
+ example: '2024-11-28'
973
+ },
974
+ flag: {
975
+ type: 'string',
976
+ description: 'Transaction flag: * (cleared), ! (pending)',
977
+ enum: ['*', '!'],
978
+ example: '*'
979
+ },
980
+ payee: {
981
+ type: 'string',
982
+ description: 'Payee name',
983
+ example: 'Whole Foods Market'
984
+ },
985
+ narration: {
986
+ type: 'string',
987
+ description: 'Transaction narration/description',
988
+ example: 'Grocery shopping'
989
+ },
990
+ tags: {
991
+ description: 'Transaction tags (without # prefix)',
992
+ example: ['vacation', 'personal'],
993
+ type: 'array',
994
+ items: {
995
+ type: 'string'
996
+ }
997
+ },
998
+ links: {
999
+ description: 'Transaction links (without ^ prefix)',
1000
+ example: ['invoice-123'],
1001
+ type: 'array',
1002
+ items: {
1003
+ type: 'string'
1004
+ }
1005
+ },
1006
+ postings: {
1007
+ description:
1008
+ 'Transaction postings (minimum 1, typically 2 for double-entry)',
1009
+ type: 'array',
1010
+ items: {
1011
+ $ref: '#/components/schemas/CreatePostingDto'
1012
+ }
1013
+ },
1014
+ meta: {
1015
+ type: 'object',
1016
+ description: 'Transaction-level metadata',
1017
+ example: {
1018
+ invoice: '12345'
1019
+ }
1020
+ },
1021
+ idempotencyKey: {
1022
+ type: 'string',
1023
+ description:
1024
+ 'Unique key for idempotent transaction creation. If provided, duplicate requests with the same key will return the existing transaction.',
1025
+ example: 'import-2024-01-15-batch-001',
1026
+ maxLength: 128
1027
+ },
1028
+ autoCreateAccounts: {
1029
+ type: 'boolean',
1030
+ description:
1031
+ '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.',
1032
+ default: true,
1033
+ example: true
1034
+ },
1035
+ correctionReason: {
1036
+ type: 'string',
1037
+ description: 'Reason for correcting/superseding the original transaction',
1038
+ example: 'Wrong amount — corrected from receipt',
1039
+ maxLength: 500
1040
+ }
1041
+ },
1042
+ required: ['date', 'narration', 'postings']
1043
+ } as const;
1044
+
1045
+ export const $PostingDetailDto = {
1046
+ type: 'object',
1047
+ properties: {
1048
+ id: {
1049
+ type: 'string',
1050
+ description: 'Posting ID',
1051
+ example: 'clh1234567890abcdef'
1052
+ },
1053
+ accountId: {
1054
+ type: 'string',
1055
+ description: 'Account ID',
1056
+ example: 'clh1234567890abcdef'
1057
+ },
1058
+ account: {
1059
+ type: 'string',
1060
+ description: 'Fully-qualified Beancount account path',
626
1061
  example: 'Assets:Bank:Checking'
627
1062
  },
628
1063
  units: {
629
1064
  type: 'string',
630
- description: 'Amount (may be null if interpolated)',
1065
+ description:
1066
+ 'Amount as decimal string. Typed optional but always present in responses: interpolation fills any MISSING posting before it is persisted or returned.',
631
1067
  example: '100.50'
632
1068
  },
633
1069
  currency: {
@@ -650,6 +1086,15 @@ export const $PostingDetailDto = {
650
1086
  description: 'Cost date',
651
1087
  example: '2024-01-15'
652
1088
  },
1089
+ cost: {
1090
+ description:
1091
+ 'Booking-resolved cost (mirrors engine Cost). Undefined when the posting has no cost basis.',
1092
+ allOf: [
1093
+ {
1094
+ $ref: '#/components/schemas/CostDetailDto'
1095
+ }
1096
+ ]
1097
+ },
653
1098
  priceAmount: {
654
1099
  type: 'string',
655
1100
  description: 'Price amount',
@@ -670,7 +1115,7 @@ export const $PostingDetailDto = {
670
1115
  description: 'Posting metadata'
671
1116
  }
672
1117
  },
673
- required: ['id', 'accountId', 'accountName']
1118
+ required: ['id', 'accountId', 'account']
674
1119
  } as const;
675
1120
 
676
1121
  export const $TransactionDetailDto = {
@@ -742,8 +1187,8 @@ export const $TransactionDetailDto = {
742
1187
  },
743
1188
  sourceType: {
744
1189
  type: 'string',
745
- description: 'Source type (how the transaction was created)',
746
- enum: ['NLP', 'CSV', 'OCR', 'API']
1190
+ description:
1191
+ 'Source type (free-form string from transaction metadata, e.g. import, api)'
747
1192
  },
748
1193
  sourcePlatform: {
749
1194
  type: 'string',
@@ -776,6 +1221,18 @@ export const $TransactionDetailDto = {
776
1221
  type: 'string',
777
1222
  description: 'Correction reason (if voided or superseded)',
778
1223
  example: 'Duplicate entry'
1224
+ },
1225
+ supersededBy: {
1226
+ type: 'string',
1227
+ description:
1228
+ 'ID of the transaction that supersedes this one (set when status=SUPERSEDED)',
1229
+ example: 'clh1234567890abcdef'
1230
+ },
1231
+ originalTxn: {
1232
+ type: 'string',
1233
+ description:
1234
+ 'ID of the transaction this one corrected/replaced (back-link on the replacement)',
1235
+ example: 'clh1234567890abcdef'
779
1236
  }
780
1237
  },
781
1238
  required: [
@@ -819,6 +1276,37 @@ export const $TransactionListResponseDto = {
819
1276
  required: ['data', 'total', 'limit', 'offset']
820
1277
  } as const;
821
1278
 
1279
+ export const $TagSuggestionDto = {
1280
+ type: 'object',
1281
+ properties: {
1282
+ tag: {
1283
+ type: 'string',
1284
+ description: 'Tag name',
1285
+ example: 'Monthly'
1286
+ },
1287
+ count: {
1288
+ type: 'number',
1289
+ description: 'Usage count across ACTIVE transactions',
1290
+ example: 12
1291
+ }
1292
+ },
1293
+ required: ['tag', 'count']
1294
+ } as const;
1295
+
1296
+ export const $TagSuggestionsResponseDto = {
1297
+ type: 'object',
1298
+ properties: {
1299
+ data: {
1300
+ description: 'Tag suggestions sorted as requested',
1301
+ type: 'array',
1302
+ items: {
1303
+ $ref: '#/components/schemas/TagSuggestionDto'
1304
+ }
1305
+ }
1306
+ },
1307
+ required: ['data']
1308
+ } as const;
1309
+
822
1310
  export const $UpdateTransactionDto = {
823
1311
  type: 'object',
824
1312
  properties: {
@@ -876,212 +1364,86 @@ export const $UpdateTransactionDto = {
876
1364
  }
877
1365
  } as const;
878
1366
 
879
- export const $AccountStandardResponseDto = {
1367
+ export const $BalanceResponseDto = {
880
1368
  type: 'object',
881
1369
  properties: {
882
- path: {
883
- type: 'string',
884
- description: 'Account path (hierarchical, colon-separated)',
885
- example: 'Assets:CN:Bank:ICBC:Checking'
886
- },
887
- type: {
1370
+ account: {
888
1371
  type: 'string',
889
- description: 'Account type in Beancount hierarchy',
890
- enum: ['Assets', 'Liabilities', 'Income', 'Expenses', 'Equity'],
891
- example: 'Assets'
1372
+ description: 'Account name',
1373
+ example: 'Assets:Bank:Checking'
892
1374
  },
893
- i18nKey: {
1375
+ balance: {
894
1376
  type: 'string',
895
- description: 'i18n key for localized display name',
896
- example: 'account.assets.cn.bank.icbc.checking'
1377
+ description: 'Balance amount (decimal string for precision)',
1378
+ example: '12345.67'
897
1379
  },
898
- description: {
1380
+ currency: {
899
1381
  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
- }
1382
+ description: 'Currency code',
1383
+ example: 'USD'
910
1384
  },
911
- icon: {
1385
+ date: {
912
1386
  type: 'string',
913
- description: 'Icon identifier for UI display',
914
- example: 'bank-icbc'
1387
+ description: 'Date of the balance calculation (ISO 8601)',
1388
+ example: '2024-12-31T00:00:00.000Z'
915
1389
  }
916
1390
  },
917
- required: ['path', 'type']
1391
+ required: ['account', 'balance', 'currency', 'date']
918
1392
  } as const;
919
1393
 
920
- export const $AccountStandardListResponseDto = {
1394
+ export const $MultiCurrencyBalanceResponseDto = {
921
1395
  type: 'object',
922
1396
  properties: {
923
- items: {
924
- description: 'Array of account templates',
925
- type: 'array',
926
- items: {
927
- $ref: '#/components/schemas/AccountStandardResponseDto'
928
- }
1397
+ account: {
1398
+ type: 'string',
1399
+ description: 'Account name',
1400
+ example: 'Assets:Bank:Checking'
929
1401
  },
930
- total: {
931
- type: 'number',
932
- description: 'Total number of account templates',
933
- example: 150
1402
+ balances: {
1403
+ type: 'object',
1404
+ description: 'Balances by currency',
1405
+ example: {
1406
+ USD: '12345.67',
1407
+ CNY: '100000.00'
1408
+ }
934
1409
  },
935
- region: {
1410
+ date: {
936
1411
  type: 'string',
937
- description: 'Region code',
938
- example: 'CN'
1412
+ description: 'Date of the balance calculation (ISO 8601)',
1413
+ example: '2024-12-31T00:00:00.000Z'
939
1414
  }
940
1415
  },
941
- required: ['items', 'total', 'region']
1416
+ required: ['account', 'balances', 'date']
942
1417
  } as const;
943
1418
 
944
- export const $RegionConfigDto = {
1419
+ export const $TransactionSummaryDto = {
945
1420
  type: 'object',
946
1421
  properties: {
947
- currency: {
1422
+ id: {
948
1423
  type: 'string',
949
- example: 'EUR'
1424
+ description: 'Transaction ID (null if transaction deleted)',
1425
+ example: 'clh1234567890abcdef',
1426
+ nullable: true
950
1427
  },
951
- dateFormat: {
1428
+ date: {
952
1429
  type: 'string',
953
- example: 'DD.MM.YYYY'
1430
+ description: 'Transaction date (YYYY-MM-DD)',
1431
+ example: '2024-03-15'
954
1432
  },
955
- locale: {
956
- 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: {
1433
+ amount: {
967
1434
  type: 'string',
968
- example: 'de'
1435
+ description: 'Transaction amount (absolute value)',
1436
+ example: '128.50'
969
1437
  },
970
- displayName: {
1438
+ currency: {
971
1439
  type: 'string',
972
- example: 'Germany'
1440
+ description: 'Currency code',
1441
+ example: 'CNY'
973
1442
  },
974
- parent: {
1443
+ payee: {
975
1444
  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'
1445
+ description: 'Payee/Merchant name',
1446
+ example: 'Starbucks'
1085
1447
  },
1086
1448
  narration: {
1087
1449
  type: 'string',
@@ -1095,8 +1457,8 @@ export const $TransactionSummaryDto = {
1095
1457
  },
1096
1458
  sourceType: {
1097
1459
  type: 'string',
1098
- description: 'Source type (NLP, CSV, OCR, API)',
1099
- enum: ['NLP', 'CSV', 'OCR', 'API']
1460
+ description:
1461
+ 'Source type (free-form string from transaction metadata, e.g. import, api)'
1100
1462
  },
1101
1463
  sourcePlatform: {
1102
1464
  type: 'string',
@@ -1136,12 +1498,23 @@ export const $ReviewSummaryDto = {
1136
1498
  },
1137
1499
  confidenceLevel: {
1138
1500
  type: 'string',
1139
- description: 'Confidence level derived from score',
1140
- enum: ['HIGH', 'MEDIUM', 'LOW']
1501
+ description:
1502
+ 'Confidence level derived from score. Null for error-type reviews (ACCOUNT_VALIDATION/PIPELINE_ERROR) which carry no confidence.',
1503
+ enum: ['HIGH', 'MEDIUM', 'LOW'],
1504
+ nullable: true
1141
1505
  },
1142
- summary: {
1506
+ summaryKey: {
1143
1507
  type: 'string',
1144
- description: 'Human-readable summary of the review item'
1508
+ description:
1509
+ 'i18n message key for summary (e.g., review.summary.duplicate). Translate on frontend with summaryParams.'
1510
+ },
1511
+ summaryParams: {
1512
+ type: 'object',
1513
+ description:
1514
+ 'Parameters for summary message interpolation (e.g., { date: "2024-01-15", amount: "50" })',
1515
+ additionalProperties: {
1516
+ type: 'string'
1517
+ }
1145
1518
  },
1146
1519
  matchReasons: {
1147
1520
  description: 'Human-readable reasons for branching',
@@ -1152,7 +1525,8 @@ export const $ReviewSummaryDto = {
1152
1525
  },
1153
1526
  sourceType: {
1154
1527
  type: 'string',
1155
- description: 'Source type (NLP, CSV, OCR, API)'
1528
+ description:
1529
+ 'Source type (free-form string from transaction metadata, e.g. import, api)'
1156
1530
  },
1157
1531
  sourcePlatform: {
1158
1532
  type: 'string',
@@ -1201,7 +1575,7 @@ export const $ReviewSummaryDto = {
1201
1575
  'status',
1202
1576
  'confidence',
1203
1577
  'confidenceLevel',
1204
- 'summary',
1578
+ 'summaryKey',
1205
1579
  'matchReasons',
1206
1580
  'sourceType',
1207
1581
  'createdAt'
@@ -1262,7 +1636,20 @@ export const $DecisionOptionDto = {
1262
1636
  properties: {
1263
1637
  value: {
1264
1638
  type: 'string',
1265
- description: 'The action value to submit (e.g., UPGRADE_REPLACE, ACCEPT)'
1639
+ description: 'The action value to submit (e.g., UPGRADE_REPLACE, ACCEPT)',
1640
+ enum: [
1641
+ 'UPGRADE_REPLACE',
1642
+ 'LINK_KEEP_BOTH',
1643
+ 'IGNORE_NEW',
1644
+ 'CONFIRM_DIFFERENT',
1645
+ 'ACCEPT',
1646
+ 'REJECT',
1647
+ 'ACCEPT_AND_LEARN',
1648
+ 'CHOOSE_OTHER',
1649
+ 'CANCEL',
1650
+ 'FIX',
1651
+ 'IGNORE'
1652
+ ]
1266
1653
  },
1267
1654
  labelKey: {
1268
1655
  type: 'string',
@@ -1310,12 +1697,23 @@ export const $ReviewDetailDto = {
1310
1697
  },
1311
1698
  confidenceLevel: {
1312
1699
  type: 'string',
1313
- description: 'Confidence level derived from score',
1314
- enum: ['HIGH', 'MEDIUM', 'LOW']
1700
+ description:
1701
+ 'Confidence level derived from score. Null for error-type reviews (ACCOUNT_VALIDATION/PIPELINE_ERROR) which carry no confidence.',
1702
+ enum: ['HIGH', 'MEDIUM', 'LOW'],
1703
+ nullable: true
1315
1704
  },
1316
- summary: {
1705
+ summaryKey: {
1317
1706
  type: 'string',
1318
- description: 'Human-readable summary of the review item'
1707
+ description:
1708
+ 'i18n message key for summary (e.g., review.summary.duplicate). Translate on frontend with summaryParams.'
1709
+ },
1710
+ summaryParams: {
1711
+ type: 'object',
1712
+ description:
1713
+ 'Parameters for summary message interpolation (e.g., { date: "2024-01-15", amount: "50" })',
1714
+ additionalProperties: {
1715
+ type: 'string'
1716
+ }
1319
1717
  },
1320
1718
  matchReasons: {
1321
1719
  description: 'Human-readable reasons for branching',
@@ -1326,7 +1724,8 @@ export const $ReviewDetailDto = {
1326
1724
  },
1327
1725
  sourceType: {
1328
1726
  type: 'string',
1329
- description: 'Source type (NLP, CSV, OCR, API)'
1727
+ description:
1728
+ 'Source type (free-form string from transaction metadata, e.g. import, api)'
1330
1729
  },
1331
1730
  sourcePlatform: {
1332
1731
  type: 'string',
@@ -1391,7 +1790,7 @@ export const $ReviewDetailDto = {
1391
1790
  'status',
1392
1791
  'confidence',
1393
1792
  'confidenceLevel',
1394
- 'summary',
1793
+ 'summaryKey',
1395
1794
  'matchReasons',
1396
1795
  'sourceType',
1397
1796
  'createdAt',
@@ -1400,141 +1799,344 @@ export const $ReviewDetailDto = {
1400
1799
  ]
1401
1800
  } as const;
1402
1801
 
1403
- export const $PayeeResponseDto = {
1802
+ export const $ResolveReviewDto = {
1404
1803
  type: 'object',
1405
1804
  properties: {
1406
- id: {
1805
+ action: {
1407
1806
  type: 'string',
1408
- description: 'Unique identifier (UUID)',
1409
- example: 'uuid-123-456'
1807
+ description:
1808
+ 'Decision action. Valid actions vary by review type — see DecisionOptionDto.value returned by the review detail endpoint.',
1809
+ enum: [
1810
+ 'UPGRADE_REPLACE',
1811
+ 'LINK_KEEP_BOTH',
1812
+ 'IGNORE_NEW',
1813
+ 'CONFIRM_DIFFERENT',
1814
+ 'ACCEPT',
1815
+ 'REJECT',
1816
+ 'ACCEPT_AND_LEARN',
1817
+ 'CHOOSE_OTHER',
1818
+ 'CANCEL',
1819
+ 'FIX',
1820
+ 'IGNORE'
1821
+ ],
1822
+ example: 'ACCEPT'
1410
1823
  },
1411
- userId: {
1412
- type: 'string',
1413
- description: 'User ID (owner of this payee mapping)',
1414
- example: 'user-123'
1824
+ data: {
1825
+ type: 'object',
1826
+ description:
1827
+ 'Additional data for the decision (e.g., selected account ID)',
1828
+ example: {
1829
+ accountId: 'acc-123'
1830
+ }
1831
+ }
1832
+ },
1833
+ required: ['action']
1834
+ } as const;
1835
+
1836
+ export const $ResolveResultDto = {
1837
+ type: 'object',
1838
+ properties: {
1839
+ success: {
1840
+ type: 'boolean',
1841
+ description: 'Whether resolution was successful'
1415
1842
  },
1416
- payee: {
1843
+ messageKey: {
1417
1844
  type: 'string',
1418
- description: "User's original payee name (e.g., 'Starbucks', 'McDonald')",
1419
- example: 'Starbucks'
1420
- },
1421
- payeeProfileId: {
1422
- type: 'object',
1423
1845
  description:
1424
- 'Reference to global PayeeProfile (merchant info, i18n keys, categories)',
1425
- example: 'uuid-789',
1426
- nullable: true
1846
+ 'i18n message key for result message (e.g., review.payee.result.mapped)'
1427
1847
  },
1428
- customCategory: {
1848
+ messageParams: {
1429
1849
  type: 'object',
1430
1850
  description:
1431
- "User's custom category (overrides PayeeProfile category if set)",
1432
- example: 'Dining:Coffee',
1433
- nullable: true
1434
- },
1435
- customTags: {
1436
- description: "User's custom tags (e.g., ['favorite', 'work_meal'])",
1437
- example: ['favorite', 'work_meal'],
1438
- type: 'array',
1439
- items: {
1851
+ 'Parameters for message interpolation (e.g., { name: "PayeeName" })',
1852
+ additionalProperties: {
1440
1853
  type: 'string'
1441
1854
  }
1442
1855
  },
1443
- useCount: {
1444
- type: 'number',
1856
+ resolutionId: {
1857
+ type: 'string',
1445
1858
  description:
1446
- 'Usage count (number of times this payee was used in transactions)',
1447
- example: 42
1859
+ 'Resolution ID for undo. Absent when the resolver rejected the decision (review stayed PENDING).'
1448
1860
  },
1449
- lastUsedAt: {
1861
+ canUndo: {
1862
+ type: 'boolean',
1863
+ description: 'Whether this decision can be undone'
1864
+ },
1865
+ undoDeadline: {
1450
1866
  format: 'date-time',
1451
1867
  type: 'string',
1452
- description: 'Last used timestamp',
1453
- example: '2024-11-20T10:00:00Z'
1454
- },
1455
- meta: {
1456
- type: 'object',
1457
- description: 'Extended metadata (location, notes, contact info, etc.)',
1458
- example: {
1459
- location: 'Zhongguancun',
1460
- note: 'Near subway station',
1461
- favorite: true
1462
- }
1868
+ description: 'Deadline for undo (24h from resolution)'
1463
1869
  },
1464
- isActive: {
1870
+ learnedRuleId: {
1871
+ type: 'string',
1872
+ description:
1873
+ 'Rule ID if learning was triggered (ACCEPT_AND_LEARN actions). Use this to deep-link to the rule management page.',
1874
+ example: 'rule_01HXK5V8N2M3P4Q5R6S7T8U9V0'
1875
+ }
1876
+ },
1877
+ required: ['success']
1878
+ } as const;
1879
+
1880
+ export const $UndoResultDto = {
1881
+ type: 'object',
1882
+ properties: {
1883
+ success: {
1465
1884
  type: 'boolean',
1466
- description: 'Active status (inactive payees hidden from autocomplete)',
1467
- example: true
1885
+ description: 'Whether undo was successful'
1468
1886
  },
1469
- createdAt: {
1470
- format: 'date-time',
1887
+ message: {
1471
1888
  type: 'string',
1472
- description: 'Creation timestamp (first time this payee was used)',
1473
- example: '2024-01-01T10:00:00Z'
1889
+ description: 'Message'
1474
1890
  },
1475
- updatedAt: {
1476
- format: 'date-time',
1891
+ reviewId: {
1477
1892
  type: 'string',
1478
- description: 'Last update timestamp',
1479
- example: '2024-11-20T10:00:00Z'
1893
+ description: 'Review item ID that was restored'
1480
1894
  }
1481
1895
  },
1482
- required: [
1483
- 'id',
1484
- 'userId',
1485
- 'payee',
1486
- 'customTags',
1487
- 'useCount',
1488
- 'lastUsedAt',
1489
- 'meta',
1490
- 'isActive',
1491
- 'createdAt',
1492
- 'updatedAt'
1493
- ]
1896
+ required: ['success', 'reviewId']
1494
1897
  } as const;
1495
1898
 
1496
- export const $PayeeListResponseDto = {
1899
+ export const $BatchResolveDto = {
1497
1900
  type: 'object',
1498
1901
  properties: {
1499
- items: {
1500
- description: 'List of payees',
1902
+ reviewIds: {
1903
+ description: 'Review item IDs to resolve',
1904
+ example: ['review-1', 'review-2', 'review-3'],
1501
1905
  type: 'array',
1502
1906
  items: {
1503
- $ref: '#/components/schemas/PayeeResponseDto'
1907
+ type: 'string'
1504
1908
  }
1505
1909
  },
1506
- total: {
1507
- type: 'number',
1508
- description: 'Total number of payees',
1509
- example: 42
1910
+ action: {
1911
+ type: 'string',
1912
+ description: 'Decision action to apply to all items',
1913
+ enum: [
1914
+ 'UPGRADE_REPLACE',
1915
+ 'LINK_KEEP_BOTH',
1916
+ 'IGNORE_NEW',
1917
+ 'CONFIRM_DIFFERENT',
1918
+ 'ACCEPT',
1919
+ 'REJECT',
1920
+ 'ACCEPT_AND_LEARN',
1921
+ 'CHOOSE_OTHER',
1922
+ 'CANCEL',
1923
+ 'FIX',
1924
+ 'IGNORE'
1925
+ ],
1926
+ example: 'ACCEPT'
1927
+ },
1928
+ data: {
1929
+ type: 'object',
1930
+ description: 'Additional data for the decision'
1510
1931
  }
1511
1932
  },
1512
- required: ['items', 'total']
1933
+ required: ['reviewIds', 'action']
1513
1934
  } as const;
1514
1935
 
1515
- export const $PayeeAutocompleteResponseDto = {
1936
+ export const $BatchResolveResultDto = {
1516
1937
  type: 'object',
1517
1938
  properties: {
1518
- suggestions: {
1519
- description: 'List of matching payee names',
1520
- example: ['Starbucks', 'Starbucks Coffee', 'Starbucks Reserve'],
1939
+ successCount: {
1940
+ type: 'number',
1941
+ description: 'Number of successfully resolved items'
1942
+ },
1943
+ failedCount: {
1944
+ type: 'number',
1945
+ description: 'Number of failed items'
1946
+ },
1947
+ results: {
1948
+ description: 'Details for each item',
1521
1949
  type: 'array',
1522
1950
  items: {
1523
1951
  type: 'string'
1524
1952
  }
1525
1953
  }
1526
1954
  },
1527
- required: ['suggestions']
1955
+ required: ['successCount', 'failedCount', 'results']
1528
1956
  } as const;
1529
1957
 
1530
- export const $PayeeStatsResponseDto = {
1958
+ export const $CreatePayeeDto = {
1531
1959
  type: 'object',
1532
1960
  properties: {
1533
1961
  payee: {
1534
1962
  type: 'string',
1535
- description: 'Payee name',
1536
- example: 'Starbucks'
1537
- },
1963
+ description:
1964
+ "User's original payee name (e.g., 'Starbucks', 'McDonald'). This is the raw payee string as entered by the user.",
1965
+ example: 'Starbucks',
1966
+ maxLength: 200
1967
+ },
1968
+ payeeProfileId: {
1969
+ type: 'string',
1970
+ description:
1971
+ 'Optional reference to global PayeeProfile for standardized data (merchant info, i18n keys, categories)',
1972
+ example: 'uuid-123',
1973
+ format: 'uuid'
1974
+ },
1975
+ customCategory: {
1976
+ type: 'string',
1977
+ description:
1978
+ "User's custom category for this payee (overrides PayeeProfile category)",
1979
+ example: 'Dining:Coffee',
1980
+ maxLength: 100
1981
+ },
1982
+ customTags: {
1983
+ description:
1984
+ "User's custom tags for this payee (e.g., ['favorite', 'work_meal'])",
1985
+ example: ['favorite', 'work_meal'],
1986
+ type: 'array',
1987
+ items: {
1988
+ type: 'string'
1989
+ }
1990
+ },
1991
+ meta: {
1992
+ type: 'object',
1993
+ description:
1994
+ 'Metadata for extended information (location, notes, contact info, etc.)',
1995
+ example: {
1996
+ location: 'Zhongguancun',
1997
+ note: 'Near subway station',
1998
+ favorite: true
1999
+ }
2000
+ }
2001
+ },
2002
+ required: ['payee']
2003
+ } as const;
2004
+
2005
+ export const $PayeeResponseDto = {
2006
+ type: 'object',
2007
+ properties: {
2008
+ id: {
2009
+ type: 'string',
2010
+ description: 'Unique identifier (UUID)',
2011
+ example: 'uuid-123-456'
2012
+ },
2013
+ userId: {
2014
+ type: 'string',
2015
+ description: 'User ID (owner of this payee mapping)',
2016
+ example: 'user-123'
2017
+ },
2018
+ payee: {
2019
+ type: 'string',
2020
+ description: "User's original payee name (e.g., 'Starbucks', 'McDonald')",
2021
+ example: 'Starbucks'
2022
+ },
2023
+ payeeProfileId: {
2024
+ type: 'string',
2025
+ description:
2026
+ 'Reference to global PayeeProfile (merchant info, i18n keys, categories)',
2027
+ example: 'uuid-789',
2028
+ nullable: true
2029
+ },
2030
+ customCategory: {
2031
+ type: 'string',
2032
+ description:
2033
+ "User's custom category (overrides PayeeProfile category if set)",
2034
+ example: 'Dining:Coffee',
2035
+ nullable: true
2036
+ },
2037
+ customTags: {
2038
+ description: "User's custom tags (e.g., ['favorite', 'work_meal'])",
2039
+ example: ['favorite', 'work_meal'],
2040
+ type: 'array',
2041
+ items: {
2042
+ type: 'string'
2043
+ }
2044
+ },
2045
+ useCount: {
2046
+ type: 'number',
2047
+ description:
2048
+ 'Usage count (number of times this payee was used in transactions)',
2049
+ example: 42
2050
+ },
2051
+ lastUsedAt: {
2052
+ format: 'date-time',
2053
+ type: 'string',
2054
+ description: 'Last used timestamp',
2055
+ example: '2024-11-20T10:00:00Z'
2056
+ },
2057
+ meta: {
2058
+ type: 'object',
2059
+ description: 'Extended metadata (location, notes, contact info, etc.)',
2060
+ example: {
2061
+ location: 'Zhongguancun',
2062
+ note: 'Near subway station',
2063
+ favorite: true
2064
+ }
2065
+ },
2066
+ isActive: {
2067
+ type: 'boolean',
2068
+ description: 'Active status (inactive payees hidden from autocomplete)',
2069
+ example: true
2070
+ },
2071
+ createdAt: {
2072
+ format: 'date-time',
2073
+ type: 'string',
2074
+ description: 'Creation timestamp (first time this payee was used)',
2075
+ example: '2024-01-01T10:00:00Z'
2076
+ },
2077
+ updatedAt: {
2078
+ format: 'date-time',
2079
+ type: 'string',
2080
+ description: 'Last update timestamp',
2081
+ example: '2024-11-20T10:00:00Z'
2082
+ }
2083
+ },
2084
+ required: [
2085
+ 'id',
2086
+ 'userId',
2087
+ 'payee',
2088
+ 'customTags',
2089
+ 'useCount',
2090
+ 'lastUsedAt',
2091
+ 'meta',
2092
+ 'isActive',
2093
+ 'createdAt',
2094
+ 'updatedAt'
2095
+ ]
2096
+ } as const;
2097
+
2098
+ export const $PayeeListResponseDto = {
2099
+ type: 'object',
2100
+ properties: {
2101
+ items: {
2102
+ description: 'List of payees',
2103
+ type: 'array',
2104
+ items: {
2105
+ $ref: '#/components/schemas/PayeeResponseDto'
2106
+ }
2107
+ },
2108
+ total: {
2109
+ type: 'number',
2110
+ description: 'Total number of payees',
2111
+ example: 42
2112
+ }
2113
+ },
2114
+ required: ['items', 'total']
2115
+ } as const;
2116
+
2117
+ export const $PayeeAutocompleteResponseDto = {
2118
+ type: 'object',
2119
+ properties: {
2120
+ suggestions: {
2121
+ description: 'List of matching payee names',
2122
+ example: ['Starbucks', 'Starbucks Coffee', 'Starbucks Reserve'],
2123
+ type: 'array',
2124
+ items: {
2125
+ type: 'string'
2126
+ }
2127
+ }
2128
+ },
2129
+ required: ['suggestions']
2130
+ } as const;
2131
+
2132
+ export const $PayeeStatsResponseDto = {
2133
+ type: 'object',
2134
+ properties: {
2135
+ payee: {
2136
+ type: 'string',
2137
+ description: 'Payee name',
2138
+ example: 'Starbucks'
2139
+ },
1538
2140
  transactionCount: {
1539
2141
  type: 'number',
1540
2142
  description: 'Total transaction count',
@@ -1550,21 +2152,64 @@ export const $PayeeStatsResponseDto = {
1550
2152
  required: ['payee', 'transactionCount', 'lastUsedAt']
1551
2153
  } as const;
1552
2154
 
1553
- export const $PayeeProfileResponseDto = {
2155
+ export const $UpdatePayeeDto = {
1554
2156
  type: 'object',
1555
2157
  properties: {
1556
- id: {
2158
+ payeeProfileId: {
1557
2159
  type: 'string',
1558
- description: 'Unique identifier (UUID)',
1559
- example: '550e8400-e29b-41d4-a716-446655440000'
2160
+ description:
2161
+ 'Optional reference to global PayeeProfile for standardized data (merchant info, i18n keys, categories)',
2162
+ example: 'uuid-123',
2163
+ format: 'uuid'
2164
+ },
2165
+ customCategory: {
2166
+ type: 'string',
2167
+ description:
2168
+ "User's custom category for this payee (overrides PayeeProfile category)",
2169
+ example: 'Dining:Coffee',
2170
+ maxLength: 100
2171
+ },
2172
+ customTags: {
2173
+ description:
2174
+ "User's custom tags for this payee (e.g., ['favorite', 'work_meal'])",
2175
+ example: ['favorite', 'work_meal'],
2176
+ type: 'array',
2177
+ items: {
2178
+ type: 'string'
2179
+ }
2180
+ },
2181
+ meta: {
2182
+ type: 'object',
2183
+ description:
2184
+ 'Metadata for extended information (location, notes, contact info, etc.). Will merge with existing metadata.',
2185
+ example: {
2186
+ location: 'Zhongguancun',
2187
+ note: 'Updated note',
2188
+ favorite: true
2189
+ }
1560
2190
  },
2191
+ isActive: {
2192
+ type: 'boolean',
2193
+ description:
2194
+ 'Enable or disable this payee. Disabled payees will not appear in autocomplete suggestions.',
2195
+ example: true
2196
+ }
2197
+ }
2198
+ } as const;
2199
+
2200
+ export const $CreatePayeeProfileDto = {
2201
+ type: 'object',
2202
+ properties: {
1561
2203
  canonical: {
1562
2204
  type: 'string',
1563
- description: 'Canonical payee name (unique, case-insensitive)',
1564
- example: 'Starbucks'
2205
+ description:
2206
+ 'Canonical payee name (unique, case-insensitive). This is the primary identifier for the payee.',
2207
+ example: 'Starbucks',
2208
+ maxLength: 200
1565
2209
  },
1566
2210
  aliases: {
1567
- description: 'Multi-language aliases',
2211
+ description:
2212
+ 'Multi-language aliases for the payee. Used for matching user input in different languages.',
1568
2213
  example: ['Starbucks Coffee', 'SBUX'],
1569
2214
  type: 'array',
1570
2215
  items: {
@@ -1572,14 +2217,15 @@ export const $PayeeProfileResponseDto = {
1572
2217
  }
1573
2218
  },
1574
2219
  i18nKey: {
1575
- type: 'object',
1576
- description: 'Translation key for i18n',
2220
+ type: 'string',
2221
+ description:
2222
+ 'Translation key for i18n integration (XLIFF translation system)',
1577
2223
  example: 'payee.starbucks',
1578
- nullable: true
2224
+ maxLength: 100
1579
2225
  },
1580
2226
  category: {
1581
2227
  type: 'string',
1582
- description: 'Payee category',
2228
+ description: 'Payee category classification',
1583
2229
  enum: [
1584
2230
  'RESTAURANT',
1585
2231
  'CAFE',
@@ -1608,13 +2254,14 @@ export const $PayeeProfileResponseDto = {
1608
2254
  example: 'CAFE'
1609
2255
  },
1610
2256
  subCategory: {
1611
- type: 'object',
1612
- description: 'Sub-category',
2257
+ type: 'string',
2258
+ description: 'Sub-category for more specific classification',
1613
2259
  example: 'coffee_chain',
1614
- nullable: true
2260
+ maxLength: 100
1615
2261
  },
1616
2262
  countries: {
1617
- description: 'Country codes where payee operates',
2263
+ description:
2264
+ 'Country/region codes where the payee operates (ISO 3166-1 alpha-2)',
1618
2265
  example: ['CN', 'US', 'JP'],
1619
2266
  type: 'array',
1620
2267
  items: {
@@ -1622,51 +2269,172 @@ export const $PayeeProfileResponseDto = {
1622
2269
  }
1623
2270
  },
1624
2271
  primaryCountry: {
1625
- type: 'object',
1626
- description: 'Primary operating country',
2272
+ type: 'string',
2273
+ description: 'Primary operating country (ISO 3166-1 alpha-2)',
1627
2274
  example: 'US',
1628
- nullable: true
2275
+ maxLength: 2
1629
2276
  },
1630
2277
  keywords: {
1631
- description: 'Search keywords',
1632
- example: ['coffee', 'cafe'],
2278
+ description: 'Search keywords for fuzzy matching',
2279
+ example: ['coffee', 'cafe', 'drinks'],
1633
2280
  type: 'array',
1634
2281
  items: {
1635
2282
  type: 'string'
1636
2283
  }
1637
2284
  },
1638
2285
  logoUrl: {
1639
- type: 'object',
1640
- description: 'Logo URL',
1641
- example: 'https://example.com/logo.png',
1642
- nullable: true
2286
+ type: 'string',
2287
+ description: 'Payee logo URL',
2288
+ example: 'https://example.com/logo.png'
1643
2289
  },
1644
2290
  website: {
1645
- type: 'object',
1646
- description: 'Official website',
1647
- example: 'https://www.starbucks.com',
1648
- nullable: true
2291
+ type: 'string',
2292
+ description: 'Official website URL',
2293
+ example: 'https://www.starbucks.com'
1649
2294
  },
1650
2295
  description: {
1651
- type: 'object',
1652
- description: 'Description',
1653
- example: 'Global coffeehouse chain',
1654
- nullable: true
2296
+ type: 'string',
2297
+ description: 'Payee description',
2298
+ example: 'Global coffeehouse chain headquartered in Seattle',
2299
+ maxLength: 1000
1655
2300
  },
1656
2301
  meta: {
1657
2302
  type: 'object',
1658
- description: 'Extended metadata'
2303
+ description:
2304
+ 'Extended metadata (business hours, contact info, additional details)',
2305
+ example: {
2306
+ businessHours: '07:00-22:00',
2307
+ phone: '+1-800-782-7282'
2308
+ }
1659
2309
  },
1660
2310
  dataSource: {
1661
2311
  type: 'string',
1662
- description: 'Data source',
2312
+ description: 'Data source for this profile',
1663
2313
  enum: ['MANUAL', 'IMPORT', 'API', 'CROWDSOURCED'],
1664
- example: 'MANUAL'
1665
- },
1666
- verifiedAt: {
1667
- type: 'object',
2314
+ default: 'MANUAL'
2315
+ }
2316
+ },
2317
+ required: ['canonical', 'category']
2318
+ } as const;
2319
+
2320
+ export const $PayeeProfileResponseDto = {
2321
+ type: 'object',
2322
+ properties: {
2323
+ id: {
2324
+ type: 'string',
2325
+ description: 'Unique identifier (UUID)',
2326
+ example: '550e8400-e29b-41d4-a716-446655440000'
2327
+ },
2328
+ canonical: {
2329
+ type: 'string',
2330
+ description: 'Canonical payee name (unique, case-insensitive)',
2331
+ example: 'Starbucks'
2332
+ },
2333
+ aliases: {
2334
+ description: 'Multi-language aliases',
2335
+ example: ['Starbucks Coffee', 'SBUX'],
2336
+ type: 'array',
2337
+ items: {
2338
+ type: 'string'
2339
+ }
2340
+ },
2341
+ i18nKey: {
2342
+ type: 'string',
2343
+ description: 'Translation key for i18n',
2344
+ example: 'payee.starbucks',
2345
+ nullable: true
2346
+ },
2347
+ category: {
2348
+ type: 'string',
2349
+ description: 'Payee category',
2350
+ enum: [
2351
+ 'RESTAURANT',
2352
+ 'CAFE',
2353
+ 'FAST_FOOD',
2354
+ 'BAR',
2355
+ 'SUPERMARKET',
2356
+ 'CONVENIENCE_STORE',
2357
+ 'SHOPPING_MALL',
2358
+ 'ONLINE_SHOPPING',
2359
+ 'TAXI',
2360
+ 'RIDE_SHARING',
2361
+ 'PUBLIC_TRANSPORT',
2362
+ 'PARKING',
2363
+ 'GAS_STATION',
2364
+ 'UTILITIES',
2365
+ 'TELECOM',
2366
+ 'STREAMING',
2367
+ 'HEALTHCARE',
2368
+ 'EDUCATION',
2369
+ 'ENTERTAINMENT',
2370
+ 'SPORTS',
2371
+ 'TRAVEL',
2372
+ 'HOTEL',
2373
+ 'OTHER'
2374
+ ],
2375
+ example: 'CAFE'
2376
+ },
2377
+ subCategory: {
2378
+ type: 'string',
2379
+ description: 'Sub-category',
2380
+ example: 'coffee_chain',
2381
+ nullable: true
2382
+ },
2383
+ countries: {
2384
+ description: 'Country codes where payee operates',
2385
+ example: ['CN', 'US', 'JP'],
2386
+ type: 'array',
2387
+ items: {
2388
+ type: 'string'
2389
+ }
2390
+ },
2391
+ primaryCountry: {
2392
+ type: 'string',
2393
+ description: 'Primary operating country',
2394
+ example: 'US',
2395
+ nullable: true
2396
+ },
2397
+ keywords: {
2398
+ description: 'Search keywords',
2399
+ example: ['coffee', 'cafe'],
2400
+ type: 'array',
2401
+ items: {
2402
+ type: 'string'
2403
+ }
2404
+ },
2405
+ logoUrl: {
2406
+ type: 'string',
2407
+ description: 'Logo URL',
2408
+ example: 'https://example.com/logo.png',
2409
+ nullable: true
2410
+ },
2411
+ website: {
2412
+ type: 'string',
2413
+ description: 'Official website',
2414
+ example: 'https://www.starbucks.com',
2415
+ nullable: true
2416
+ },
2417
+ description: {
2418
+ type: 'string',
2419
+ description: 'Description',
2420
+ example: 'Global coffeehouse chain',
2421
+ nullable: true
2422
+ },
2423
+ meta: {
2424
+ type: 'object',
2425
+ description: 'Extended metadata'
2426
+ },
2427
+ dataSource: {
2428
+ type: 'string',
2429
+ description: 'Data source',
2430
+ enum: ['MANUAL', 'IMPORT', 'API', 'CROWDSOURCED'],
2431
+ example: 'MANUAL'
2432
+ },
2433
+ verifiedAt: {
2434
+ type: 'string',
1668
2435
  description: 'Verification timestamp (null if not verified)',
1669
2436
  example: '2025-01-01T00:00:00.000Z',
2437
+ format: 'date-time',
1670
2438
  nullable: true
1671
2439
  },
1672
2440
  isActive: {
@@ -1721,6 +2489,164 @@ export const $PayeeProfileListResponseDto = {
1721
2489
  required: ['items', 'total']
1722
2490
  } as const;
1723
2491
 
2492
+ export const $UpdatePayeeProfileDto = {
2493
+ type: 'object',
2494
+ properties: {
2495
+ aliases: {
2496
+ description:
2497
+ 'Multi-language aliases for the payee. Used for matching user input in different languages.',
2498
+ example: ['Starbucks Coffee', 'SBUX'],
2499
+ type: 'array',
2500
+ items: {
2501
+ type: 'string'
2502
+ }
2503
+ },
2504
+ i18nKey: {
2505
+ type: 'string',
2506
+ description:
2507
+ 'Translation key for i18n integration (XLIFF translation system)',
2508
+ example: 'payee.starbucks',
2509
+ maxLength: 100
2510
+ },
2511
+ category: {
2512
+ type: 'string',
2513
+ description: 'Payee category classification',
2514
+ enum: [
2515
+ 'RESTAURANT',
2516
+ 'CAFE',
2517
+ 'FAST_FOOD',
2518
+ 'BAR',
2519
+ 'SUPERMARKET',
2520
+ 'CONVENIENCE_STORE',
2521
+ 'SHOPPING_MALL',
2522
+ 'ONLINE_SHOPPING',
2523
+ 'TAXI',
2524
+ 'RIDE_SHARING',
2525
+ 'PUBLIC_TRANSPORT',
2526
+ 'PARKING',
2527
+ 'GAS_STATION',
2528
+ 'UTILITIES',
2529
+ 'TELECOM',
2530
+ 'STREAMING',
2531
+ 'HEALTHCARE',
2532
+ 'EDUCATION',
2533
+ 'ENTERTAINMENT',
2534
+ 'SPORTS',
2535
+ 'TRAVEL',
2536
+ 'HOTEL',
2537
+ 'OTHER'
2538
+ ],
2539
+ example: 'CAFE'
2540
+ },
2541
+ subCategory: {
2542
+ type: 'string',
2543
+ description: 'Sub-category for more specific classification',
2544
+ example: 'coffee_chain',
2545
+ maxLength: 100
2546
+ },
2547
+ countries: {
2548
+ description:
2549
+ 'Country/region codes where the payee operates (ISO 3166-1 alpha-2)',
2550
+ example: ['CN', 'US', 'JP'],
2551
+ type: 'array',
2552
+ items: {
2553
+ type: 'string'
2554
+ }
2555
+ },
2556
+ primaryCountry: {
2557
+ type: 'string',
2558
+ description: 'Primary operating country (ISO 3166-1 alpha-2)',
2559
+ example: 'US',
2560
+ maxLength: 2
2561
+ },
2562
+ keywords: {
2563
+ description: 'Search keywords for fuzzy matching',
2564
+ example: ['coffee', 'cafe', 'drinks'],
2565
+ type: 'array',
2566
+ items: {
2567
+ type: 'string'
2568
+ }
2569
+ },
2570
+ logoUrl: {
2571
+ type: 'string',
2572
+ description: 'Payee logo URL',
2573
+ example: 'https://example.com/logo.png'
2574
+ },
2575
+ website: {
2576
+ type: 'string',
2577
+ description: 'Official website URL',
2578
+ example: 'https://www.starbucks.com'
2579
+ },
2580
+ description: {
2581
+ type: 'string',
2582
+ description: 'Payee description',
2583
+ example: 'Global coffeehouse chain headquartered in Seattle',
2584
+ maxLength: 1000
2585
+ },
2586
+ meta: {
2587
+ type: 'object',
2588
+ description:
2589
+ 'Extended metadata (business hours, contact info, additional details)',
2590
+ example: {
2591
+ businessHours: '07:00-22:00',
2592
+ phone: '+1-800-782-7282'
2593
+ }
2594
+ },
2595
+ dataSource: {
2596
+ type: 'string',
2597
+ description: 'Data source for this profile',
2598
+ enum: ['MANUAL', 'IMPORT', 'API', 'CROWDSOURCED'],
2599
+ default: 'MANUAL'
2600
+ },
2601
+ isActive: {
2602
+ type: 'boolean',
2603
+ description: 'Whether the payee profile is active (soft delete)',
2604
+ example: true
2605
+ },
2606
+ verifiedAt: {
2607
+ type: 'string',
2608
+ description:
2609
+ 'Verification timestamp. Set to current time to verify, or null to unverify.',
2610
+ example: '2025-01-01T00:00:00.000Z',
2611
+ format: 'date-time',
2612
+ nullable: true
2613
+ }
2614
+ }
2615
+ } as const;
2616
+
2617
+ export const $CreateCommodityDto = {
2618
+ type: 'object',
2619
+ properties: {
2620
+ symbol: {
2621
+ type: 'string',
2622
+ description:
2623
+ 'Commodity symbol (e.g., AAPL, USD, BTC) - corresponds to Beancount currency field',
2624
+ example: 'AAPL',
2625
+ maxLength: 50
2626
+ },
2627
+ date: {
2628
+ type: 'string',
2629
+ description:
2630
+ 'Commodity definition date (ISO 8601, required per Beancount spec). Represents when this commodity was first defined in the accounting system.',
2631
+ example: '2024-01-01',
2632
+ format: 'date'
2633
+ },
2634
+ metadata: {
2635
+ type: 'object',
2636
+ description:
2637
+ 'Metadata (corresponds to Beancount meta field). Can contain name, assetClass, precision, note, tags, etc.',
2638
+ example: {
2639
+ name: 'Apple Inc.',
2640
+ assetClass: 'stock',
2641
+ precision: 2,
2642
+ note: 'Long-term investment',
2643
+ tags: ['tech', 'dividend']
2644
+ }
2645
+ }
2646
+ },
2647
+ required: ['symbol', 'date']
2648
+ } as const;
2649
+
1724
2650
  export const $CommodityResponseDto = {
1725
2651
  type: 'object',
1726
2652
  properties: {
@@ -1730,7 +2656,7 @@ export const $CommodityResponseDto = {
1730
2656
  example: 'uuid-123-456'
1731
2657
  },
1732
2658
  userId: {
1733
- type: 'object',
2659
+ type: 'string',
1734
2660
  description: 'User ID (owner of the commodity)',
1735
2661
  example: 'user-123',
1736
2662
  nullable: true
@@ -1759,13 +2685,6 @@ export const $CommodityResponseDto = {
1759
2685
  source: 'AUTO_CREATED'
1760
2686
  }
1761
2687
  },
1762
- symbolProfileId: {
1763
- type: 'object',
1764
- description:
1765
- 'Reference to SymbolProfile (market data integration, SaaS feature)',
1766
- example: 'uuid-789',
1767
- nullable: true
1768
- },
1769
2688
  createdAt: {
1770
2689
  format: 'date-time',
1771
2690
  type: 'string',
@@ -1801,12 +2720,136 @@ export const $CommodityListResponseDto = {
1801
2720
  required: ['items', 'total']
1802
2721
  } as const;
1803
2722
 
1804
- export const $RecurringRuleResponseDto = {
2723
+ export const $UpdateCommodityDto = {
1805
2724
  type: 'object',
1806
2725
  properties: {
1807
- id: {
2726
+ date: {
1808
2727
  type: 'string',
1809
- description: 'Rule ID'
2728
+ description:
2729
+ 'Commodity definition date (ISO 8601). Represents when this commodity was first defined in the accounting system.',
2730
+ example: '2024-01-01',
2731
+ format: 'date'
2732
+ },
2733
+ metadata: {
2734
+ type: 'object',
2735
+ description:
2736
+ 'Metadata (corresponds to Beancount meta field). Will merge with existing metadata. Can contain name, assetClass, precision, note, tags, etc.',
2737
+ example: {
2738
+ name: 'Updated Apple Inc.',
2739
+ assetClass: 'equity',
2740
+ precision: 4,
2741
+ note: 'Updated investment strategy',
2742
+ lastReviewed: '2024-11-03'
2743
+ }
2744
+ }
2745
+ }
2746
+ } as const;
2747
+
2748
+ export const $CreateRecurringRuleDto = {
2749
+ type: 'object',
2750
+ properties: {
2751
+ name: {
2752
+ type: 'string',
2753
+ description: 'Rule name (unique per user)',
2754
+ maxLength: 100
2755
+ },
2756
+ icon: {
2757
+ type: 'string',
2758
+ description: 'Icon emoji',
2759
+ maxLength: 10
2760
+ },
2761
+ frequency: {
2762
+ type: 'string',
2763
+ description: 'Recurring frequency',
2764
+ enum: [
2765
+ 'WEEKLY',
2766
+ 'BIWEEKLY',
2767
+ 'MONTHLY',
2768
+ 'BIMONTHLY',
2769
+ 'QUARTERLY',
2770
+ 'YEARLY',
2771
+ 'CUSTOM'
2772
+ ]
2773
+ },
2774
+ expectedAmount: {
2775
+ type: 'number',
2776
+ description: 'Expected amount (positive number)',
2777
+ minimum: 0
2778
+ },
2779
+ expectedDay: {
2780
+ type: 'number',
2781
+ description: 'Expected day of month (1-31)',
2782
+ minimum: 1,
2783
+ maximum: 31
2784
+ },
2785
+ customIntervalDays: {
2786
+ type: 'number',
2787
+ description: 'Custom interval in days (required for CUSTOM frequency)',
2788
+ minimum: 1
2789
+ },
2790
+ currency: {
2791
+ type: 'string',
2792
+ description: 'Currency code',
2793
+ default: 'CNY',
2794
+ maxLength: 10
2795
+ },
2796
+ matchPayeePattern: {
2797
+ type: 'string',
2798
+ description: 'Payee matching pattern (supports wildcards)',
2799
+ maxLength: 200
2800
+ },
2801
+ matchAmountTolerance: {
2802
+ type: 'number',
2803
+ description: 'Amount tolerance percentage (0-1)',
2804
+ default: 0.075,
2805
+ minimum: 0,
2806
+ maximum: 1
2807
+ },
2808
+ defaultExpenseAccount: {
2809
+ type: 'string',
2810
+ description: 'Default expense account for auto-create',
2811
+ maxLength: 200
2812
+ },
2813
+ defaultPaymentAccount: {
2814
+ type: 'string',
2815
+ description: 'Default payment account for auto-create',
2816
+ maxLength: 200
2817
+ },
2818
+ defaultPayee: {
2819
+ type: 'string',
2820
+ description: 'Default payee for auto-create',
2821
+ maxLength: 200
2822
+ },
2823
+ autoCreate: {
2824
+ type: 'boolean',
2825
+ description: 'Auto-create transaction when expected date arrives',
2826
+ default: false
2827
+ },
2828
+ startDate: {
2829
+ type: 'string',
2830
+ description: 'Rule start date (ISO format)'
2831
+ },
2832
+ endDate: {
2833
+ type: 'string',
2834
+ description: 'Rule end date (ISO format)'
2835
+ }
2836
+ },
2837
+ required: [
2838
+ 'name',
2839
+ 'frequency',
2840
+ 'expectedAmount',
2841
+ 'currency',
2842
+ 'matchAmountTolerance',
2843
+ 'autoCreate'
2844
+ ]
2845
+ } as const;
2846
+
2847
+ export const $RecurringRuleResponseDto = {
2848
+ type: 'object',
2849
+ properties: {
2850
+ id: {
2851
+ type: 'string',
2852
+ description: 'Rule ID'
1810
2853
  },
1811
2854
  userId: {
1812
2855
  type: 'string',
@@ -1912,6 +2955,37 @@ export const $RecurringRuleResponseDto = {
1912
2955
  ]
1913
2956
  } as const;
1914
2957
 
2958
+ export const $CreateRuleFromTransactionDto = {
2959
+ type: 'object',
2960
+ properties: {
2961
+ frequency: {
2962
+ type: 'string',
2963
+ description: 'Recurring frequency',
2964
+ enum: [
2965
+ 'WEEKLY',
2966
+ 'BIWEEKLY',
2967
+ 'MONTHLY',
2968
+ 'BIMONTHLY',
2969
+ 'QUARTERLY',
2970
+ 'YEARLY',
2971
+ 'CUSTOM'
2972
+ ],
2973
+ example: 'MONTHLY'
2974
+ },
2975
+ name: {
2976
+ type: 'string',
2977
+ description: 'Optional name override (default: transaction payee)',
2978
+ maxLength: 100
2979
+ },
2980
+ icon: {
2981
+ type: 'string',
2982
+ description: 'Optional icon emoji',
2983
+ maxLength: 10
2984
+ }
2985
+ },
2986
+ required: ['frequency']
2987
+ } as const;
2988
+
1915
2989
  export const $RecurringRuleWithStatsResponseDto = {
1916
2990
  type: 'object',
1917
2991
  properties: {
@@ -2070,6 +3144,94 @@ export const $RecurringRuleWithStatsResponseDto = {
2070
3144
  ]
2071
3145
  } as const;
2072
3146
 
3147
+ export const $UpdateRecurringRuleDto = {
3148
+ type: 'object',
3149
+ properties: {
3150
+ name: {
3151
+ type: 'string',
3152
+ description: 'Rule name',
3153
+ maxLength: 100
3154
+ },
3155
+ icon: {
3156
+ type: 'string',
3157
+ description: 'Icon emoji',
3158
+ maxLength: 10
3159
+ },
3160
+ frequency: {
3161
+ type: 'string',
3162
+ description: 'Recurring frequency',
3163
+ enum: [
3164
+ 'WEEKLY',
3165
+ 'BIWEEKLY',
3166
+ 'MONTHLY',
3167
+ 'BIMONTHLY',
3168
+ 'QUARTERLY',
3169
+ 'YEARLY',
3170
+ 'CUSTOM'
3171
+ ]
3172
+ },
3173
+ expectedAmount: {
3174
+ type: 'number',
3175
+ description: 'Expected amount',
3176
+ minimum: 0
3177
+ },
3178
+ expectedDay: {
3179
+ type: 'number',
3180
+ description: 'Expected day of month (1-31)',
3181
+ minimum: 1,
3182
+ maximum: 31
3183
+ },
3184
+ customIntervalDays: {
3185
+ type: 'number',
3186
+ description: 'Custom interval in days',
3187
+ minimum: 1
3188
+ },
3189
+ currency: {
3190
+ type: 'string',
3191
+ description: 'Currency code',
3192
+ maxLength: 10
3193
+ },
3194
+ matchPayeePattern: {
3195
+ type: 'string',
3196
+ description: 'Payee matching pattern',
3197
+ maxLength: 200
3198
+ },
3199
+ matchAmountTolerance: {
3200
+ type: 'number',
3201
+ description: 'Amount tolerance percentage (0-1)',
3202
+ minimum: 0,
3203
+ maximum: 1
3204
+ },
3205
+ defaultExpenseAccount: {
3206
+ type: 'string',
3207
+ description: 'Default expense account',
3208
+ maxLength: 200
3209
+ },
3210
+ defaultPaymentAccount: {
3211
+ type: 'string',
3212
+ description: 'Default payment account',
3213
+ maxLength: 200
3214
+ },
3215
+ defaultPayee: {
3216
+ type: 'string',
3217
+ description: 'Default payee',
3218
+ maxLength: 200
3219
+ },
3220
+ autoCreate: {
3221
+ type: 'boolean',
3222
+ description: 'Auto-create transaction'
3223
+ },
3224
+ isActive: {
3225
+ type: 'boolean',
3226
+ description: 'Rule active status'
3227
+ },
3228
+ endDate: {
3229
+ type: 'string',
3230
+ description: 'Rule end date (ISO format)'
3231
+ }
3232
+ }
3233
+ } as const;
3234
+
2073
3235
  export const $ExpectedTransactionRuleDto = {
2074
3236
  type: 'object',
2075
3237
  properties: {
@@ -2186,6 +3348,50 @@ export const $ExpectedTransactionListResponseDto = {
2186
3348
  required: ['items', 'total']
2187
3349
  } as const;
2188
3350
 
3351
+ export const $ConfirmMatchDto = {
3352
+ type: 'object',
3353
+ properties: {
3354
+ transactionId: {
3355
+ type: 'string',
3356
+ description: 'Transaction ID to match with'
3357
+ }
3358
+ },
3359
+ required: ['transactionId']
3360
+ } as const;
3361
+
3362
+ export const $EnterNowDto = {
3363
+ type: 'object',
3364
+ properties: {
3365
+ expenseAccount: {
3366
+ type: 'string',
3367
+ description:
3368
+ 'Override expense account (uses rule default if not provided)',
3369
+ maxLength: 200
3370
+ },
3371
+ paymentAccount: {
3372
+ type: 'string',
3373
+ description:
3374
+ 'Override payment account (uses rule default if not provided)',
3375
+ maxLength: 200
3376
+ },
3377
+ amount: {
3378
+ type: 'number',
3379
+ description: 'Override amount (uses expected amount if not provided)',
3380
+ minimum: 0
3381
+ },
3382
+ payee: {
3383
+ type: 'string',
3384
+ description: 'Override payee (uses rule default if not provided)',
3385
+ maxLength: 200
3386
+ },
3387
+ narration: {
3388
+ type: 'string',
3389
+ description: 'Optional narration',
3390
+ maxLength: 500
3391
+ }
3392
+ }
3393
+ } as const;
3394
+
2189
3395
  export const $ForecastItemDto = {
2190
3396
  type: 'object',
2191
3397
  properties: {
@@ -2210,7 +3416,7 @@ export const $ForecastItemDto = {
2210
3416
  example: '2024-04-01'
2211
3417
  },
2212
3418
  icon: {
2213
- type: 'object',
3419
+ type: 'string',
2214
3420
  description: 'Rule icon emoji',
2215
3421
  example: '🏠',
2216
3422
  nullable: true
@@ -2310,37 +3516,138 @@ export const $ForecastResponseDto = {
2310
3516
  ]
2311
3517
  } as const;
2312
3518
 
2313
- export const $TransactionRuleResponseDto = {
3519
+ export const $CreateTransactionRuleDto = {
2314
3520
  type: 'object',
2315
3521
  properties: {
2316
- id: {
2317
- type: 'string',
2318
- description: 'Rule ID'
2319
- },
2320
3522
  name: {
2321
3523
  type: 'string',
2322
- description: 'Rule name'
3524
+ minLength: 1,
3525
+ maxLength: 100
2323
3526
  },
2324
3527
  description: {
2325
3528
  type: 'string',
2326
- description: 'Rule description'
3529
+ maxLength: 500
2327
3530
  },
2328
3531
  narrationKeywords: {
2329
- description: 'Keywords to match in transaction narration',
2330
- type: 'array',
2331
3532
  items: {
2332
- type: 'string'
2333
- }
3533
+ type: 'array'
3534
+ },
3535
+ maxItems: 50,
3536
+ type: 'array'
2334
3537
  },
2335
3538
  payeeKeywords: {
2336
- description: 'Keywords to match in payee name',
2337
- type: 'array',
2338
3539
  items: {
2339
- type: 'string'
2340
- }
3540
+ type: 'array'
3541
+ },
3542
+ maxItems: 50,
3543
+ type: 'array'
2341
3544
  },
2342
3545
  categoryKeywords: {
2343
- description: 'Keywords to match in category',
3546
+ items: {
3547
+ type: 'array'
3548
+ },
3549
+ maxItems: 50,
3550
+ type: 'array'
3551
+ },
3552
+ methodKeywords: {
3553
+ items: {
3554
+ type: 'array'
3555
+ },
3556
+ maxItems: 50,
3557
+ description: 'Payment method keywords (e.g., HuaBei, YuEBao)',
3558
+ type: 'array'
3559
+ },
3560
+ categoryAccount: {
3561
+ type: 'string',
3562
+ maxLength: 200,
3563
+ description:
3564
+ 'Destination account for expenses/income (e.g., Expenses:Food:Coffee)'
3565
+ },
3566
+ matchLogic: {
3567
+ type: 'string',
3568
+ enum: ['OR', 'AND'],
3569
+ default: 'OR'
3570
+ },
3571
+ amountMin: {
3572
+ type: 'number',
3573
+ minimum: 0,
3574
+ description: 'Minimum transaction amount (inclusive)'
3575
+ },
3576
+ amountMax: {
3577
+ type: 'number',
3578
+ minimum: 0,
3579
+ description: 'Maximum transaction amount (inclusive)'
3580
+ },
3581
+ priority: {
3582
+ type: 'number',
3583
+ default: 50,
3584
+ minimum: 0,
3585
+ maximum: 1000
3586
+ },
3587
+ additionalTags: {
3588
+ items: {
3589
+ type: 'array'
3590
+ },
3591
+ maxItems: 20,
3592
+ type: 'array'
3593
+ },
3594
+ additionalMetadata: {
3595
+ type: 'object'
3596
+ },
3597
+ upsertByPayee: {
3598
+ type: 'boolean',
3599
+ description:
3600
+ 'If true, update existing rule with matching payeeKeywords[0] instead of creating new rule'
3601
+ }
3602
+ },
3603
+ required: ['name', 'matchLogic', 'priority']
3604
+ } as const;
3605
+
3606
+ export const $AmountRangeDto = {
3607
+ type: 'object',
3608
+ properties: {
3609
+ min: {
3610
+ type: 'number',
3611
+ description: 'Minimum amount'
3612
+ },
3613
+ max: {
3614
+ type: 'number',
3615
+ description: 'Maximum amount'
3616
+ }
3617
+ }
3618
+ } as const;
3619
+
3620
+ export const $TransactionRuleResponseDto = {
3621
+ type: 'object',
3622
+ properties: {
3623
+ id: {
3624
+ type: 'string',
3625
+ description: 'Rule ID'
3626
+ },
3627
+ name: {
3628
+ type: 'string',
3629
+ description: 'Rule name'
3630
+ },
3631
+ description: {
3632
+ type: 'string',
3633
+ description: 'Rule description'
3634
+ },
3635
+ narrationKeywords: {
3636
+ description: 'Keywords to match in transaction narration',
3637
+ type: 'array',
3638
+ items: {
3639
+ type: 'string'
3640
+ }
3641
+ },
3642
+ payeeKeywords: {
3643
+ description: 'Keywords to match in payee name',
3644
+ type: 'array',
3645
+ items: {
3646
+ type: 'string'
3647
+ }
3648
+ },
3649
+ categoryKeywords: {
3650
+ description: 'Keywords to match in category',
2344
3651
  type: 'array',
2345
3652
  items: {
2346
3653
  type: 'string'
@@ -2364,12 +3671,12 @@ export const $TransactionRuleResponseDto = {
2364
3671
  example: 'OR'
2365
3672
  },
2366
3673
  amountRange: {
2367
- type: 'object',
2368
3674
  description: 'Amount range for matching',
2369
- example: {
2370
- min: 0,
2371
- max: 100
2372
- }
3675
+ allOf: [
3676
+ {
3677
+ $ref: '#/components/schemas/AmountRangeDto'
3678
+ }
3679
+ ]
2373
3680
  },
2374
3681
  priority: {
2375
3682
  type: 'number',
@@ -2384,6 +3691,7 @@ export const $TransactionRuleResponseDto = {
2384
3691
  type: 'string',
2385
3692
  description: 'Learning source: NLP, REVIEW_CENTER, or null for manual',
2386
3693
  enum: ['NLP', 'REVIEW_CENTER'],
3694
+ nullable: true,
2387
3695
  example: 'REVIEW_CENTER'
2388
3696
  },
2389
3697
  autoApplyEnabled: {
@@ -2405,7 +3713,9 @@ export const $TransactionRuleResponseDto = {
2405
3713
  additionalMetadata: {
2406
3714
  type: 'object',
2407
3715
  description: 'Additional metadata',
2408
- example: {}
3716
+ additionalProperties: {
3717
+ type: 'string'
3718
+ }
2409
3719
  },
2410
3720
  createdAt: {
2411
3721
  format: 'date-time',
@@ -2578,6 +3888,64 @@ export const $ValidateRuleResponseDto = {
2578
3888
  required: ['valid', 'errors', 'warnings']
2579
3889
  } as const;
2580
3890
 
3891
+ export const $BulkCreateRulesDto = {
3892
+ type: 'object',
3893
+ properties: {
3894
+ rules: {
3895
+ items: {
3896
+ type: 'array'
3897
+ },
3898
+ description: 'Array of rules to import',
3899
+ type: 'array'
3900
+ },
3901
+ conflictStrategy: {
3902
+ type: 'string',
3903
+ enum: ['replace', 'skip'],
3904
+ default: 'skip',
3905
+ description:
3906
+ 'Conflict handling strategy: skip (default) ignores duplicates, replace soft-deletes existing rule'
3907
+ }
3908
+ },
3909
+ required: ['rules', 'conflictStrategy']
3910
+ } as const;
3911
+
3912
+ export const $BulkCreateRulesResponseDto = {
3913
+ type: 'object',
3914
+ properties: {
3915
+ successCount: {
3916
+ type: 'number',
3917
+ description: 'Number of successfully created rules'
3918
+ },
3919
+ failureCount: {
3920
+ type: 'number',
3921
+ description: 'Number of failed rules'
3922
+ },
3923
+ errors: {
3924
+ type: 'array',
3925
+ description: 'Error details for failed rules',
3926
+ items: {
3927
+ type: 'object',
3928
+ properties: {
3929
+ index: {
3930
+ type: 'number'
3931
+ },
3932
+ message: {
3933
+ type: 'string'
3934
+ }
3935
+ }
3936
+ }
3937
+ },
3938
+ createdRuleIds: {
3939
+ description: 'IDs of successfully created rules',
3940
+ type: 'array',
3941
+ items: {
3942
+ type: 'string'
3943
+ }
3944
+ }
3945
+ },
3946
+ required: ['successCount', 'failureCount', 'errors', 'createdRuleIds']
3947
+ } as const;
3948
+
2581
3949
  export const $ExportRulesResponseDto = {
2582
3950
  type: 'object',
2583
3951
  properties: {
@@ -2658,6 +4026,89 @@ export const $RuleStatisticsResponseDto = {
2658
4026
  ]
2659
4027
  } as const;
2660
4028
 
4029
+ export const $UpdateTransactionRuleDto = {
4030
+ type: 'object',
4031
+ properties: {
4032
+ name: {
4033
+ type: 'string',
4034
+ minLength: 1,
4035
+ maxLength: 100
4036
+ },
4037
+ description: {
4038
+ type: 'string',
4039
+ maxLength: 500
4040
+ },
4041
+ narrationKeywords: {
4042
+ items: {
4043
+ type: 'array'
4044
+ },
4045
+ maxItems: 50,
4046
+ type: 'array'
4047
+ },
4048
+ payeeKeywords: {
4049
+ items: {
4050
+ type: 'array'
4051
+ },
4052
+ maxItems: 50,
4053
+ type: 'array'
4054
+ },
4055
+ categoryKeywords: {
4056
+ items: {
4057
+ type: 'array'
4058
+ },
4059
+ maxItems: 50,
4060
+ type: 'array'
4061
+ },
4062
+ methodKeywords: {
4063
+ items: {
4064
+ type: 'array'
4065
+ },
4066
+ maxItems: 50,
4067
+ description: 'Payment method keywords (e.g., HuaBei, YuEBao)',
4068
+ type: 'array'
4069
+ },
4070
+ categoryAccount: {
4071
+ type: 'string',
4072
+ maxLength: 200,
4073
+ description:
4074
+ 'Destination account for expenses/income (e.g., Expenses:Food:Coffee)'
4075
+ },
4076
+ matchLogic: {
4077
+ type: 'string',
4078
+ enum: ['OR', 'AND']
4079
+ },
4080
+ amountMin: {
4081
+ type: 'number',
4082
+ minimum: 0,
4083
+ description: 'Minimum transaction amount (inclusive)'
4084
+ },
4085
+ amountMax: {
4086
+ type: 'number',
4087
+ minimum: 0,
4088
+ description: 'Maximum transaction amount (inclusive)'
4089
+ },
4090
+ priority: {
4091
+ type: 'number',
4092
+ minimum: 0,
4093
+ maximum: 1000
4094
+ },
4095
+ enabled: {
4096
+ type: 'boolean',
4097
+ description: 'Enable or disable the rule'
4098
+ },
4099
+ additionalTags: {
4100
+ items: {
4101
+ type: 'array'
4102
+ },
4103
+ maxItems: 20,
4104
+ type: 'array'
4105
+ },
4106
+ additionalMetadata: {
4107
+ type: 'object'
4108
+ }
4109
+ }
4110
+ } as const;
4111
+
2661
4112
  export const $TestRuleDto = {
2662
4113
  type: 'object',
2663
4114
  properties: {
@@ -2850,6 +4301,17 @@ export const $UpdateUserSettingDto = {
2850
4301
  }
2851
4302
  } as const;
2852
4303
 
4304
+ export const $UpdatePropertyDto = {
4305
+ type: 'object',
4306
+ properties: {
4307
+ value: {
4308
+ type: 'string',
4309
+ description: 'Property value'
4310
+ }
4311
+ },
4312
+ required: ['value']
4313
+ } as const;
4314
+
2853
4315
  export const $FileImportDto = {
2854
4316
  type: 'object',
2855
4317
  properties: {
@@ -3149,7 +4611,8 @@ export const $ImporterConfigDto = {
3149
4611
  'cmbc-credit',
3150
4612
  'icbc',
3151
4613
  'icbc-credit',
3152
- 'hsbc-hk'
4614
+ 'hsbc-hk-credit',
4615
+ 'hsbc-hk-debit'
3153
4616
  ]
3154
4617
  },
3155
4618
  version: {
@@ -3195,30 +4658,205 @@ export const $ImporterConfigDto = {
3195
4658
  ]
3196
4659
  } as const;
3197
4660
 
3198
- export const $ProviderSyncConfigDto = {
4661
+ export const $UpdateMapperDefaultsDto = {
3199
4662
  type: 'object',
3200
4663
  properties: {
3201
4664
  sourceAccount: {
3202
4665
  type: 'string',
3203
- description: 'Source account for the first posting',
3204
- example: 'Assets:Bank:Chase'
4666
+ description: 'Source account for transactions (Beancount format)',
4667
+ example: 'Assets:Alipay:Balance',
4668
+ pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
3205
4669
  },
3206
- defaultCurrency: {
4670
+ currency: {
3207
4671
  type: 'string',
3208
- description: 'Default currency for transactions',
3209
- example: 'USD'
4672
+ description: 'Default currency (ISO 4217 code)',
4673
+ example: 'CNY',
4674
+ minLength: 3,
4675
+ maxLength: 3,
4676
+ pattern: '^[A-Z]{3}$'
3210
4677
  },
3211
- defaultExpenseAccount: {
4678
+ expenseAccount: {
3212
4679
  type: 'string',
3213
- description: 'Default expense account for the second posting',
3214
- example: 'Expenses:Unknown'
4680
+ description: 'Default expense account (optional)',
4681
+ example: 'Expenses:Unknown',
4682
+ pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
3215
4683
  },
3216
- defaultIncomeAccount: {
4684
+ incomeAccount: {
3217
4685
  type: 'string',
3218
- description: 'Default income account for the second posting',
3219
- example: 'Income:Unknown'
4686
+ description: 'Default income account (optional)',
4687
+ example: 'Income:Unknown',
4688
+ pattern: '^[A-Z][a-zA-Z0-9-]*:[a-zA-Z0-9-:]+$'
3220
4689
  },
3221
- filterPending: {
4690
+ methodAccountMapping: {
4691
+ type: 'object',
4692
+ description:
4693
+ '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).',
4694
+ example: {
4695
+ HuaBei: 'Liabilities:Alipay:Huabei',
4696
+ CreditCard: 'Liabilities:CreditCard'
4697
+ }
4698
+ }
4699
+ }
4700
+ } as const;
4701
+
4702
+ export const $UpdateConfigDataDto = {
4703
+ type: 'object',
4704
+ properties: {
4705
+ defaults: {
4706
+ description: 'Mapper defaults configuration',
4707
+ allOf: [
4708
+ {
4709
+ $ref: '#/components/schemas/UpdateMapperDefaultsDto'
4710
+ }
4711
+ ]
4712
+ }
4713
+ }
4714
+ } as const;
4715
+
4716
+ export const $UpdateImporterConfigDto = {
4717
+ type: 'object',
4718
+ properties: {
4719
+ data: {
4720
+ description: 'Configuration data (v1 schema)',
4721
+ allOf: [
4722
+ {
4723
+ $ref: '#/components/schemas/UpdateConfigDataDto'
4724
+ }
4725
+ ]
4726
+ }
4727
+ }
4728
+ } as const;
4729
+
4730
+ export const $CreatePlatformDto = {
4731
+ type: 'object',
4732
+ properties: {
4733
+ name: {
4734
+ type: 'string',
4735
+ description: 'Platform name',
4736
+ example: 'Binance'
4737
+ },
4738
+ canonical: {
4739
+ type: 'string',
4740
+ description: 'Platform canonical identifier (lowercase, kebab-case)',
4741
+ example: 'binance'
4742
+ },
4743
+ aliases: {
4744
+ description: 'Platform aliases (multi-language names for lookup)',
4745
+ example: ['Binance', 'Binance Exchange', 'BNB'],
4746
+ type: 'array',
4747
+ items: {
4748
+ type: 'string'
4749
+ }
4750
+ },
4751
+ url: {
4752
+ type: 'string',
4753
+ description: 'Platform URL',
4754
+ example: 'https://www.binance.com'
4755
+ },
4756
+ type: {
4757
+ type: 'string',
4758
+ description: 'Platform type',
4759
+ enum: [
4760
+ 'BANK',
4761
+ 'BROKERAGE',
4762
+ 'CRYPTO_EXCHANGE',
4763
+ 'PAYMENT',
4764
+ 'INVESTMENT',
4765
+ 'INSURANCE',
4766
+ 'OTHER'
4767
+ ],
4768
+ example: 'CRYPTO_EXCHANGE'
4769
+ },
4770
+ logoUrl: {
4771
+ type: 'string',
4772
+ description: 'Platform logo URL',
4773
+ example: 'https://example.com/logos/binance.png'
4774
+ },
4775
+ isActive: {
4776
+ type: 'boolean',
4777
+ description: 'Whether the platform is active',
4778
+ default: true
4779
+ }
4780
+ },
4781
+ required: ['name', 'canonical', 'aliases', 'url', 'type']
4782
+ } as const;
4783
+
4784
+ export const $UpdatePlatformDto = {
4785
+ type: 'object',
4786
+ properties: {
4787
+ name: {
4788
+ type: 'string',
4789
+ description: 'Platform name',
4790
+ example: 'Binance'
4791
+ },
4792
+ canonical: {
4793
+ type: 'string',
4794
+ description: 'Platform canonical identifier (lowercase, kebab-case)',
4795
+ example: 'binance'
4796
+ },
4797
+ aliases: {
4798
+ description: 'Platform aliases (multi-language names for lookup)',
4799
+ example: ['Binance', 'Binance Exchange', 'BNB'],
4800
+ type: 'array',
4801
+ items: {
4802
+ type: 'string'
4803
+ }
4804
+ },
4805
+ url: {
4806
+ type: 'string',
4807
+ description: 'Platform URL',
4808
+ example: 'https://www.binance.com'
4809
+ },
4810
+ type: {
4811
+ type: 'string',
4812
+ description: 'Platform type',
4813
+ enum: [
4814
+ 'BANK',
4815
+ 'BROKERAGE',
4816
+ 'CRYPTO_EXCHANGE',
4817
+ 'PAYMENT',
4818
+ 'INVESTMENT',
4819
+ 'INSURANCE',
4820
+ 'OTHER'
4821
+ ],
4822
+ example: 'CRYPTO_EXCHANGE'
4823
+ },
4824
+ logoUrl: {
4825
+ type: 'string',
4826
+ description: 'Platform logo URL',
4827
+ example: 'https://example.com/logos/binance.png'
4828
+ },
4829
+ isActive: {
4830
+ type: 'boolean',
4831
+ description: 'Whether the platform is active'
4832
+ }
4833
+ }
4834
+ } as const;
4835
+
4836
+ export const $ProviderSyncConfigDto = {
4837
+ type: 'object',
4838
+ properties: {
4839
+ sourceAccount: {
4840
+ type: 'string',
4841
+ description: 'Source account for the first posting',
4842
+ example: 'Assets:Bank:Chase'
4843
+ },
4844
+ defaultCurrency: {
4845
+ type: 'string',
4846
+ description: 'Default currency for transactions',
4847
+ example: 'USD'
4848
+ },
4849
+ defaultExpenseAccount: {
4850
+ type: 'string',
4851
+ description: 'Default expense account for the second posting',
4852
+ example: 'Expenses:Unknown'
4853
+ },
4854
+ defaultIncomeAccount: {
4855
+ type: 'string',
4856
+ description: 'Default income account for the second posting',
4857
+ example: 'Income:Unknown'
4858
+ },
4859
+ filterPending: {
3222
4860
  type: 'boolean',
3223
4861
  description: 'Filter pending transactions',
3224
4862
  default: true
@@ -3329,7 +4967,8 @@ export const $SupportedProvidersResponseDto = {
3329
4967
  'gocardless',
3330
4968
  'simplefin',
3331
4969
  'yodlee',
3332
- 'beancount-direct'
4970
+ 'beancount-direct',
4971
+ 'parsed-bill'
3333
4972
  ],
3334
4973
  type: 'array',
3335
4974
  items: {
@@ -3340,6 +4979,16 @@ export const $SupportedProvidersResponseDto = {
3340
4979
  required: ['providers']
3341
4980
  } as const;
3342
4981
 
4982
+ export const $ParserTelemetryReportDto = {
4983
+ type: 'object',
4984
+ properties: {}
4985
+ } as const;
4986
+
4987
+ export const $UncoveredFormatMissDto = {
4988
+ type: 'object',
4989
+ properties: {}
4990
+ } as const;
4991
+
3343
4992
  export const $ProcessNlpDto = {
3344
4993
  type: 'object',
3345
4994
  properties: {
@@ -3354,6 +5003,16 @@ export const $ProcessNlpDto = {
3354
5003
  description:
3355
5004
  'Session ID for multi-turn conversation (auto-generated if not provided)',
3356
5005
  example: 'session_abc123'
5006
+ },
5007
+ parsedData: {
5008
+ type: 'object',
5009
+ description:
5010
+ 'Parsed data from previous NLP response for session recovery. Send back the parsedData received in confirm_payee/confirm responses.',
5011
+ example: {
5012
+ amount: 35,
5013
+ currency: 'CNY',
5014
+ payee: 'Starbucks'
5015
+ }
3357
5016
  }
3358
5017
  },
3359
5018
  required: ['message']
@@ -4457,6 +6116,12 @@ export const $AccountItemWithAssetClassDto = {
4457
6116
  type: 'string',
4458
6117
  description: 'Risk level',
4459
6118
  example: 'LOW'
6119
+ },
6120
+ source: {
6121
+ type: 'string',
6122
+ description:
6123
+ 'ADR-0105 classification provenance (holding level always; account level only on FALLBACK)',
6124
+ enum: ['USER_META', 'FIAT_CURRENCY', 'OPENBB_MAPPING', 'FALLBACK']
4460
6125
  }
4461
6126
  },
4462
6127
  required: ['id', 'name', 'displayName', 'balance', 'currency', 'assetClass']
@@ -4562,6 +6227,11 @@ export const $AssetClassSummaryDto = {
4562
6227
  items: {
4563
6228
  $ref: '#/components/schemas/AccountExchangeRateWarningDto'
4564
6229
  }
6230
+ },
6231
+ fallback: {
6232
+ type: 'object',
6233
+ description:
6234
+ '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.'
4565
6235
  }
4566
6236
  },
4567
6237
  required: ['totalAccounts', 'totalAssetClasses', 'baseCurrency']
@@ -4584,11 +6254,107 @@ export const $AssetClassAccountsResponseDto = {
4584
6254
  $ref: '#/components/schemas/AssetClassSummaryDto'
4585
6255
  }
4586
6256
  ]
6257
+ },
6258
+ uncategorized: {
6259
+ description:
6260
+ 'ADR-0105 §6 holding-level grey-area bucket (source=FALLBACK holdings peeled out of groups). Present only for groupBy=holdingAssetClass when FALLBACK holdings exist.',
6261
+ allOf: [
6262
+ {
6263
+ $ref: '#/components/schemas/AssetClassGroupDto'
6264
+ }
6265
+ ]
4587
6266
  }
4588
6267
  },
4589
6268
  required: ['groups', 'summary']
4590
6269
  } as const;
4591
6270
 
6271
+ export const $HoldingAssetClassAccountSliceDto = {
6272
+ type: 'object',
6273
+ properties: {
6274
+ accountId: {
6275
+ type: 'string',
6276
+ description: 'Account ID'
6277
+ },
6278
+ accountPath: {
6279
+ type: 'string',
6280
+ description: 'Full account path',
6281
+ example: 'Assets:US:Investments:Brokerage'
6282
+ },
6283
+ accountCurrency: {
6284
+ type: 'string',
6285
+ description:
6286
+ 'Currency of the holding with the largest converted base value; undefined when no holding is convertible',
6287
+ example: 'USD'
6288
+ },
6289
+ marketValueBase: {
6290
+ type: 'string',
6291
+ description:
6292
+ "Account's market value in base currency (Σ converted holdings; grey bucket included)",
6293
+ example: '50000.00'
6294
+ },
6295
+ shareOfTotalPct: {
6296
+ type: 'number',
6297
+ description:
6298
+ 'Share of the global total (0-100). 0 when globalTotal is zero (no NaN/Infinity).',
6299
+ example: 42.5
6300
+ },
6301
+ groups: {
6302
+ description: 'Per-account asset-class breakdown',
6303
+ type: 'array',
6304
+ items: {
6305
+ $ref: '#/components/schemas/AssetClassGroupDto'
6306
+ }
6307
+ },
6308
+ uncategorized: {
6309
+ description:
6310
+ 'Per-account grey bucket (source=FALLBACK holdings, incl. broker cash)',
6311
+ allOf: [
6312
+ {
6313
+ $ref: '#/components/schemas/AssetClassGroupDto'
6314
+ }
6315
+ ]
6316
+ },
6317
+ holdings: {
6318
+ description:
6319
+ 'Every holding row for this account (account ID in each row’s `id` field)',
6320
+ type: 'array',
6321
+ items: {
6322
+ $ref: '#/components/schemas/AccountItemWithAssetClassDto'
6323
+ }
6324
+ }
6325
+ },
6326
+ required: [
6327
+ 'accountId',
6328
+ 'accountPath',
6329
+ 'marketValueBase',
6330
+ 'shareOfTotalPct',
6331
+ 'groups',
6332
+ 'holdings'
6333
+ ]
6334
+ } as const;
6335
+
6336
+ export const $HoldingAssetClassCrossAccountResponseDto = {
6337
+ type: 'object',
6338
+ properties: {
6339
+ global: {
6340
+ description: 'Merged cross-account holding aggregation',
6341
+ allOf: [
6342
+ {
6343
+ $ref: '#/components/schemas/AssetClassAccountsResponseDto'
6344
+ }
6345
+ ]
6346
+ },
6347
+ byAccount: {
6348
+ description: 'Per-account slices',
6349
+ type: 'array',
6350
+ items: {
6351
+ $ref: '#/components/schemas/HoldingAssetClassAccountSliceDto'
6352
+ }
6353
+ }
6354
+ },
6355
+ required: ['global', 'byAccount']
6356
+ } as const;
6357
+
4592
6358
  export const $CashFlowByCurrencyDto = {
4593
6359
  type: 'object',
4594
6360
  properties: {
@@ -4718,6 +6484,452 @@ export const $CashFlowResponseDto = {
4718
6484
  ]
4719
6485
  } as const;
4720
6486
 
6487
+ export const $MonetaryDto = {
6488
+ type: 'object',
6489
+ properties: {
6490
+ amount: {
6491
+ type: 'string',
6492
+ description: 'Amount (Decimal string)',
6493
+ example: '3000'
6494
+ },
6495
+ currency: {
6496
+ type: 'string',
6497
+ description: 'ISO 4217 currency',
6498
+ example: 'USD'
6499
+ },
6500
+ baseCcyEquivalent: {
6501
+ type: 'object',
6502
+ description: 'Converted to user base currency (Decimal string)',
6503
+ example: '21600',
6504
+ nullable: true
6505
+ }
6506
+ },
6507
+ required: ['amount', 'currency']
6508
+ } as const;
6509
+
6510
+ export const $CurrentPriceDto = {
6511
+ type: 'object',
6512
+ properties: {
6513
+ amount: {
6514
+ type: 'string',
6515
+ description: 'Price amount (Decimal string)',
6516
+ example: '250'
6517
+ },
6518
+ currency: {
6519
+ type: 'string',
6520
+ description: 'Price currency (ISO 4217)',
6521
+ example: 'USD'
6522
+ },
6523
+ date: {
6524
+ type: 'string',
6525
+ description: 'Price date (ISO 8601)',
6526
+ example: '2024-06-01'
6527
+ },
6528
+ source: {
6529
+ type: 'string',
6530
+ description: 'Price source',
6531
+ example: 'USER_OVERRIDE',
6532
+ enum: ['USER_OVERRIDE', 'OPENBB_EQUITY', 'OPENBB_CURRENCY']
6533
+ }
6534
+ },
6535
+ required: ['amount', 'currency', 'date', 'source']
6536
+ } as const;
6537
+
6538
+ export const $FxRateDto = {
6539
+ type: 'object',
6540
+ properties: {
6541
+ from: {
6542
+ type: 'string',
6543
+ example: 'USD'
6544
+ },
6545
+ to: {
6546
+ type: 'string',
6547
+ example: 'CNY'
6548
+ },
6549
+ rate: {
6550
+ type: 'string',
6551
+ description: 'FX rate (Decimal string)',
6552
+ example: '7.2'
6553
+ },
6554
+ date: {
6555
+ type: 'string',
6556
+ description: 'Rate date (ISO 8601)',
6557
+ example: '2024-01-15'
6558
+ }
6559
+ },
6560
+ required: ['from', 'to', 'rate', 'date']
6561
+ } as const;
6562
+
6563
+ export const $HoldingPnlRowDto = {
6564
+ type: 'object',
6565
+ properties: {
6566
+ accountId: {
6567
+ type: 'string',
6568
+ description: 'Account UUID',
6569
+ example: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
6570
+ },
6571
+ accountPath: {
6572
+ type: 'string',
6573
+ description: 'Full account path',
6574
+ example: 'Assets:US:Broker:AAPL'
6575
+ },
6576
+ accountCcy: {
6577
+ type: 'object',
6578
+ description: 'Account settlement currency (ISO 4217), from cost currency',
6579
+ nullable: true,
6580
+ example: 'USD'
6581
+ },
6582
+ brokerType: {
6583
+ type: 'object',
6584
+ description: 'Broker type derived from Platform.type',
6585
+ nullable: true,
6586
+ example: 'broker'
6587
+ },
6588
+ symbol: {
6589
+ type: 'string',
6590
+ description: 'Commodity symbol',
6591
+ example: 'AAPL'
6592
+ },
6593
+ chartToken: {
6594
+ type: 'string',
6595
+ description: 'Chart segment token (libs/common resolver)',
6596
+ example: 'equity',
6597
+ enum: ['equity', 'fund', 'bond', 'cash', 'other']
6598
+ },
6599
+ assetClass: {
6600
+ type: 'string',
6601
+ example: 'EQUITY'
6602
+ },
6603
+ assetSubClass: {
6604
+ type: 'object',
6605
+ nullable: true,
6606
+ example: 'STOCK'
6607
+ },
6608
+ units: {
6609
+ type: 'string',
6610
+ description: 'Net held units (Decimal string)',
6611
+ example: '12'
6612
+ },
6613
+ averageCostPerUnit: {
6614
+ description:
6615
+ 'Average cost per unit; null when cost currency conflicts or no cost',
6616
+ nullable: true,
6617
+ allOf: [
6618
+ {
6619
+ $ref: '#/components/schemas/MonetaryDto'
6620
+ }
6621
+ ]
6622
+ },
6623
+ costBasis: {
6624
+ description: 'Cost basis of held units',
6625
+ nullable: true,
6626
+ allOf: [
6627
+ {
6628
+ $ref: '#/components/schemas/MonetaryDto'
6629
+ }
6630
+ ]
6631
+ },
6632
+ marketValue: {
6633
+ description: 'Market value at asOf price',
6634
+ nullable: true,
6635
+ allOf: [
6636
+ {
6637
+ $ref: '#/components/schemas/MonetaryDto'
6638
+ }
6639
+ ]
6640
+ },
6641
+ currentPrice: {
6642
+ description: 'Price used for market value',
6643
+ nullable: true,
6644
+ allOf: [
6645
+ {
6646
+ $ref: '#/components/schemas/CurrentPriceDto'
6647
+ }
6648
+ ]
6649
+ },
6650
+ unrealizedPnlBase: {
6651
+ type: 'object',
6652
+ description:
6653
+ 'Unrealized P&L in base currency (Decimal string); null when any FX/price missing',
6654
+ nullable: true,
6655
+ example: '6000'
6656
+ },
6657
+ unrealizedPnlPct: {
6658
+ type: 'object',
6659
+ description: 'Unrealized P&L % (Decimal string)',
6660
+ nullable: true,
6661
+ example: '25'
6662
+ },
6663
+ costFxRate: {
6664
+ description: 'Historical FX rate applied to cost basis',
6665
+ nullable: true,
6666
+ allOf: [
6667
+ {
6668
+ $ref: '#/components/schemas/FxRateDto'
6669
+ }
6670
+ ]
6671
+ },
6672
+ marketFxRate: {
6673
+ description: 'FX rate applied to market value',
6674
+ nullable: true,
6675
+ allOf: [
6676
+ {
6677
+ $ref: '#/components/schemas/FxRateDto'
6678
+ }
6679
+ ]
6680
+ },
6681
+ pctOfInvestedAssets: {
6682
+ type: 'object',
6683
+ description:
6684
+ 'Share of invested assets % (Decimal string); only for invested chartTokens',
6685
+ nullable: true,
6686
+ example: '40'
6687
+ },
6688
+ realizedPnl: {
6689
+ description:
6690
+ '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',
6691
+ nullable: true,
6692
+ allOf: [
6693
+ {
6694
+ $ref: '#/components/schemas/MonetaryDto'
6695
+ }
6696
+ ]
6697
+ }
6698
+ },
6699
+ required: [
6700
+ 'accountId',
6701
+ 'accountPath',
6702
+ 'symbol',
6703
+ 'chartToken',
6704
+ 'assetClass',
6705
+ 'units'
6706
+ ]
6707
+ } as const;
6708
+
6709
+ export const $HoldingPnlWarningDto = {
6710
+ type: 'object',
6711
+ properties: {
6712
+ type: {
6713
+ type: 'string',
6714
+ description: 'Warning type',
6715
+ example: 'MISSING_COST_FX_RATE',
6716
+ enum: [
6717
+ 'MISSING_COST_FX_RATE',
6718
+ 'MISSING_MARKET_FX_RATE',
6719
+ 'MISSING_SALE_PRICE',
6720
+ 'MISSING_REALIZED_FX_RATE',
6721
+ 'OVERSOLD_LOTS',
6722
+ 'NO_PRICE',
6723
+ 'MIXED_COST_CURRENCY'
6724
+ ]
6725
+ },
6726
+ symbol: {
6727
+ type: 'object',
6728
+ nullable: true
6729
+ },
6730
+ accountId: {
6731
+ type: 'object',
6732
+ nullable: true
6733
+ },
6734
+ currency: {
6735
+ type: 'object',
6736
+ nullable: true
6737
+ }
6738
+ },
6739
+ required: ['type']
6740
+ } as const;
6741
+
6742
+ export const $HoldingPnlResponseDto = {
6743
+ type: 'object',
6744
+ properties: {
6745
+ asOfDate: {
6746
+ type: 'string',
6747
+ example: '2026-07-08'
6748
+ },
6749
+ baseCurrency: {
6750
+ type: 'string',
6751
+ example: 'CNY'
6752
+ },
6753
+ method: {
6754
+ type: 'string',
6755
+ description:
6756
+ 'Realized-P&L lot-matching method (FIFO or average). Unrealized cost basis remains average regardless of this value (#473).',
6757
+ enum: ['average', 'FIFO'],
6758
+ example: 'average'
6759
+ },
6760
+ rows: {
6761
+ type: 'array',
6762
+ items: {
6763
+ $ref: '#/components/schemas/HoldingPnlRowDto'
6764
+ }
6765
+ },
6766
+ warnings: {
6767
+ type: 'array',
6768
+ items: {
6769
+ $ref: '#/components/schemas/HoldingPnlWarningDto'
6770
+ }
6771
+ }
6772
+ },
6773
+ required: ['asOfDate', 'baseCurrency', 'method', 'rows', 'warnings']
6774
+ } as const;
6775
+
6776
+ export const $CreateBeanPriceDto = {
6777
+ type: 'object',
6778
+ properties: {
6779
+ currency: {
6780
+ type: 'string',
6781
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
6782
+ example: 'USD'
6783
+ },
6784
+ quoteCurrency: {
6785
+ type: 'string',
6786
+ description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
6787
+ example: 'CNY'
6788
+ },
6789
+ amount: {
6790
+ type: 'number',
6791
+ description:
6792
+ 'Price amount (MUST be >= 0 per Beancount spec, supports up to 15 decimal places). Zero allowed for conversion entries, negative strictly prohibited.',
6793
+ example: 175.5,
6794
+ minimum: 0
6795
+ },
6796
+ date: {
6797
+ type: 'string',
6798
+ description: 'Price date (ISO 8601 format)',
6799
+ example: '2024-11-05'
6800
+ },
6801
+ metadata: {
6802
+ type: 'object',
6803
+ description:
6804
+ 'Metadata (validated by Zod schema, max field lengths enforced)',
6805
+ example: {
6806
+ source: 'MANUAL',
6807
+ note: 'Bank valuation report',
6808
+ confidence: 0.95
6809
+ }
6810
+ }
6811
+ },
6812
+ required: ['currency', 'quoteCurrency', 'amount', 'date']
6813
+ } as const;
6814
+
6815
+ export const $PriceResponseDto = {
6816
+ type: 'object',
6817
+ properties: {
6818
+ id: {
6819
+ type: 'string',
6820
+ description: 'Unique identifier',
6821
+ example: 'uuid-123-456'
6822
+ },
6823
+ userId: {
6824
+ type: 'string',
6825
+ description: 'User ID (owner of the price)',
6826
+ example: 'user-123'
6827
+ },
6828
+ currency: {
6829
+ type: 'string',
6830
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
6831
+ example: 'BTC'
6832
+ },
6833
+ quoteCurrency: {
6834
+ type: 'string',
6835
+ description: 'Quote currency (pricing currency, e.g., USD, CNY)',
6836
+ example: 'USD'
6837
+ },
6838
+ amount: {
6839
+ type: 'number',
6840
+ description:
6841
+ 'Price amount (corresponds to Beancount Amount.number). Supports up to 15 decimal places.',
6842
+ example: 50000
6843
+ },
6844
+ date: {
6845
+ type: 'string',
6846
+ description:
6847
+ 'Price date (ISO 8601 format). Represents the date this price was valid.',
6848
+ example: '2024-01-01',
6849
+ format: 'date'
6850
+ },
6851
+ meta: {
6852
+ type: 'object',
6853
+ description:
6854
+ 'Metadata (corresponds to Beancount meta field). Contains source, confidence, note, etc.',
6855
+ example: {
6856
+ source: 'MANUAL',
6857
+ note: 'User-defined price',
6858
+ confidence: 1
6859
+ }
6860
+ },
6861
+ createdAt: {
6862
+ format: 'date-time',
6863
+ type: 'string',
6864
+ description: 'Creation timestamp',
6865
+ example: '2024-11-03T10:00:00Z'
6866
+ },
6867
+ updatedAt: {
6868
+ format: 'date-time',
6869
+ type: 'string',
6870
+ description: 'Last update timestamp',
6871
+ example: '2024-11-03T10:00:00Z'
6872
+ }
6873
+ },
6874
+ required: [
6875
+ 'id',
6876
+ 'userId',
6877
+ 'currency',
6878
+ 'quoteCurrency',
6879
+ 'amount',
6880
+ 'date',
6881
+ 'meta',
6882
+ 'createdAt',
6883
+ 'updatedAt'
6884
+ ]
6885
+ } as const;
6886
+
6887
+ export const $PriceListResponseDto = {
6888
+ type: 'object',
6889
+ properties: {
6890
+ items: {
6891
+ description: 'List of prices',
6892
+ type: 'array',
6893
+ items: {
6894
+ $ref: '#/components/schemas/PriceResponseDto'
6895
+ }
6896
+ },
6897
+ total: {
6898
+ type: 'number',
6899
+ description: 'Total number of prices',
6900
+ example: 42
6901
+ }
6902
+ },
6903
+ required: ['items', 'total']
6904
+ } as const;
6905
+
6906
+ export const $UpdateBeanPriceDto = {
6907
+ type: 'object',
6908
+ properties: {
6909
+ currency: {
6910
+ type: 'string',
6911
+ description: 'Currency being priced'
6912
+ },
6913
+ quoteCurrency: {
6914
+ type: 'string',
6915
+ description: 'Quote currency (pricing currency)'
6916
+ },
6917
+ amount: {
6918
+ type: 'number',
6919
+ description: 'Price amount (MUST be >= 0 per Beancount spec)',
6920
+ minimum: 0
6921
+ },
6922
+ date: {
6923
+ type: 'string',
6924
+ description: 'Price date (ISO 8601 format)'
6925
+ },
6926
+ metadata: {
6927
+ type: 'object',
6928
+ description: 'Metadata'
6929
+ }
6930
+ }
6931
+ } as const;
6932
+
4721
6933
  export const $CurrencyBalanceDto = {
4722
6934
  type: 'object',
4723
6935
  properties: {