@firela/api-types 0.0.0-canary.14a6ef5a → 0.0.0-canary.19fa1e7e

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.
@@ -466,6 +466,66 @@ export const $RegionsMetadataResponseDto = {
466
466
  required: ['regions']
467
467
  } as const;
468
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
+
469
529
  export const $CreatePostingDto = {
470
530
  type: 'object',
471
531
  properties: {
@@ -495,6 +555,33 @@ export const $CreatePostingDto = {
495
555
  example: {
496
556
  'tax-lot': 'Q1-2024'
497
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
+ ]
498
585
  }
499
586
  },
500
587
  required: ['account']
@@ -573,6 +660,32 @@ export const $CreateTransactionDto = {
573
660
  required: ['date', 'narration', 'postings']
574
661
  } as const;
575
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
+
576
689
  export const $PostingResponseDto = {
577
690
  type: 'object',
578
691
  properties: {
@@ -591,6 +704,15 @@ export const $PostingResponseDto = {
591
704
  type: 'string',
592
705
  description: 'Currency',
593
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
+ ]
594
716
  }
595
717
  },
596
718
  required: ['account']
@@ -841,6 +963,85 @@ export const $BatchTransactionResponseDto = {
841
963
  required: ['succeeded', 'failed']
842
964
  } as const;
843
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
+
844
1045
  export const $PostingDetailDto = {
845
1046
  type: 'object',
846
1047
  properties: {
@@ -854,9 +1055,9 @@ export const $PostingDetailDto = {
854
1055
  description: 'Account ID',
855
1056
  example: 'clh1234567890abcdef'
856
1057
  },
857
- accountName: {
1058
+ account: {
858
1059
  type: 'string',
859
- description: 'Account name',
1060
+ description: 'Fully-qualified Beancount account path',
860
1061
  example: 'Assets:Bank:Checking'
861
1062
  },
862
1063
  units: {
@@ -885,6 +1086,15 @@ export const $PostingDetailDto = {
885
1086
  description: 'Cost date',
886
1087
  example: '2024-01-15'
887
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
+ },
888
1098
  priceAmount: {
889
1099
  type: 'string',
890
1100
  description: 'Price amount',
@@ -905,7 +1115,7 @@ export const $PostingDetailDto = {
905
1115
  description: 'Posting metadata'
906
1116
  }
907
1117
  },
908
- required: ['id', 'accountId', 'accountName']
1118
+ required: ['id', 'accountId', 'account']
909
1119
  } as const;
910
1120
 
911
1121
  export const $TransactionDetailDto = {
@@ -1011,6 +1221,18 @@ export const $TransactionDetailDto = {
1011
1221
  type: 'string',
1012
1222
  description: 'Correction reason (if voided or superseded)',
1013
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'
1014
1236
  }
1015
1237
  },
1016
1238
  required: [
@@ -1633,7 +1855,8 @@ export const $ResolveResultDto = {
1633
1855
  },
1634
1856
  resolutionId: {
1635
1857
  type: 'string',
1636
- description: 'Resolution ID for undo'
1858
+ description:
1859
+ 'Resolution ID for undo. Absent when the resolver rejected the decision (review stayed PENDING).'
1637
1860
  },
1638
1861
  canUndo: {
1639
1862
  type: 'boolean',
@@ -1651,7 +1874,7 @@ export const $ResolveResultDto = {
1651
1874
  example: 'rule_01HXK5V8N2M3P4Q5R6S7T8U9V0'
1652
1875
  }
1653
1876
  },
1654
- required: ['success', 'resolutionId', 'canUndo', 'undoDeadline']
1877
+ required: ['success']
1655
1878
  } as const;
1656
1879
 
1657
1880
  export const $UndoResultDto = {
@@ -4089,82 +4312,220 @@ export const $UpdatePropertyDto = {
4089
4312
  required: ['value']
4090
4313
  } as const;
4091
4314
 
4092
- export const $FileImportDto = {
4315
+ export const $CreateBeanEventDto = {
4093
4316
  type: 'object',
4094
4317
  properties: {
4095
- file: {
4318
+ date: {
4096
4319
  type: 'string',
4097
- format: 'binary',
4098
- description: 'Bill file to import (CSV, PDF, OFX, etc.)',
4099
- example: 'alipay.csv'
4100
- }
4101
- },
4102
- required: ['file']
4103
- } as const;
4104
-
4105
- export const $ImportErrorDto = {
4106
- type: 'object',
4107
- properties: {
4108
- index: {
4109
- type: 'number',
4110
- description: 'Index of failed transaction in the file',
4111
- example: 5
4320
+ description: 'Life event date (ISO 8601)',
4321
+ example: '2024-03-15'
4112
4322
  },
4113
- error: {
4323
+ type: {
4114
4324
  type: 'string',
4115
- description: 'Error message',
4116
- example: 'Transaction does not balance: -100 USD != 0'
4325
+ description:
4326
+ 'Life event type (e.g., "employer", "location", "marital-status") — user-defined, no enum constraint at engine layer',
4327
+ example: 'employer'
4328
+ },
4329
+ description: {
4330
+ type: 'string',
4331
+ description:
4332
+ 'Life event description. Empty string is a VALID value (distinct from absence).',
4333
+ example: 'Acme Corp'
4334
+ },
4335
+ meta: {
4336
+ type: 'object',
4337
+ description:
4338
+ 'Product-side metadata (lives in BeanEvent.meta JSON, never in engine Event fields)',
4339
+ example: {
4340
+ note: 'Promotion'
4341
+ }
4117
4342
  }
4118
4343
  },
4119
- required: ['index', 'error']
4344
+ required: ['date', 'type', 'description']
4120
4345
  } as const;
4121
4346
 
4122
- export const $ReviewItemPreviewDto = {
4347
+ export const $EventResponseDto = {
4123
4348
  type: 'object',
4124
4349
  properties: {
4125
- index: {
4126
- type: 'number',
4127
- description: 'Index in the import batch (for tracking)',
4128
- example: 0
4129
- },
4130
- date: {
4350
+ id: {
4131
4351
  type: 'string',
4132
- description: 'Transaction date (ISO format)',
4133
- example: '2026-03-05'
4134
- },
4135
- amount: {
4136
- type: 'number',
4137
- description: 'Transaction amount (absolute value)',
4138
- example: 99
4352
+ description: 'Unique identifier',
4353
+ example: 'uuid-123-456'
4139
4354
  },
4140
- currency: {
4355
+ userId: {
4141
4356
  type: 'string',
4142
- description: 'Currency code',
4143
- example: 'CNY'
4357
+ description: 'User ID (owner of the life event)',
4358
+ example: 'user-123'
4144
4359
  },
4145
- narration: {
4360
+ date: {
4146
4361
  type: 'string',
4147
- description: 'Transaction narration/description',
4148
- example: 'Restaurant expense'
4362
+ description: 'Life event date (ISO 8601 format)',
4363
+ example: '2024-03-15',
4364
+ format: 'date'
4149
4365
  },
4150
- payee: {
4366
+ type: {
4151
4367
  type: 'string',
4152
- description: 'Payee name',
4153
- example: 'Restaurant ABC'
4368
+ description:
4369
+ 'Life event type (user-defined, e.g., "employer", "location")',
4370
+ example: 'employer'
4154
4371
  },
4155
- category: {
4372
+ description: {
4156
4373
  type: 'string',
4157
- description: 'Inferred category from rule matching',
4158
- example: 'food'
4374
+ description:
4375
+ 'Life event description. May be an empty string (a valid value distinct from absence).',
4376
+ example: 'Acme Corp'
4159
4377
  },
4160
- confidence: {
4161
- type: 'number',
4162
- description: 'Confidence score for the match (0-1)',
4163
- example: 0.85
4378
+ meta: {
4379
+ type: 'object',
4380
+ description: 'Product-side metadata (free-form JSON)',
4381
+ example: {
4382
+ note: 'Promotion'
4383
+ }
4164
4384
  },
4165
- branchType: {
4385
+ createdAt: {
4386
+ format: 'date-time',
4166
4387
  type: 'string',
4167
- description: 'Type of branch requiring review',
4388
+ description: 'Creation timestamp',
4389
+ example: '2024-03-15T10:00:00Z'
4390
+ },
4391
+ updatedAt: {
4392
+ format: 'date-time',
4393
+ type: 'string',
4394
+ description:
4395
+ 'Last update timestamp. Also emitted as the ETag response header for If-Match optimistic concurrency.',
4396
+ example: '2024-03-15T10:00:00Z'
4397
+ }
4398
+ },
4399
+ required: [
4400
+ 'id',
4401
+ 'userId',
4402
+ 'date',
4403
+ 'type',
4404
+ 'description',
4405
+ 'meta',
4406
+ 'createdAt',
4407
+ 'updatedAt'
4408
+ ]
4409
+ } as const;
4410
+
4411
+ export const $EventListResponseDto = {
4412
+ type: 'object',
4413
+ properties: {
4414
+ items: {
4415
+ description: 'List of life events',
4416
+ type: 'array',
4417
+ items: {
4418
+ $ref: '#/components/schemas/EventResponseDto'
4419
+ }
4420
+ },
4421
+ total: {
4422
+ type: 'number',
4423
+ description: 'Total number of life events matching the query',
4424
+ example: 42
4425
+ }
4426
+ },
4427
+ required: ['items', 'total']
4428
+ } as const;
4429
+
4430
+ export const $UpdateBeanEventDto = {
4431
+ type: 'object',
4432
+ properties: {
4433
+ date: {
4434
+ type: 'string',
4435
+ description: 'Life event date (ISO 8601)'
4436
+ },
4437
+ type: {
4438
+ type: 'string',
4439
+ description: 'Life event type (user-defined)'
4440
+ },
4441
+ description: {
4442
+ type: 'string',
4443
+ description:
4444
+ 'Life event description. Empty string is a VALID value (distinct from absence).'
4445
+ },
4446
+ meta: {
4447
+ type: 'object',
4448
+ description: 'Product-side metadata (free-form JSON)'
4449
+ }
4450
+ }
4451
+ } as const;
4452
+
4453
+ export const $FileImportDto = {
4454
+ type: 'object',
4455
+ properties: {
4456
+ file: {
4457
+ type: 'string',
4458
+ format: 'binary',
4459
+ description: 'Bill file to import (CSV, PDF, OFX, etc.)',
4460
+ example: 'alipay.csv'
4461
+ }
4462
+ },
4463
+ required: ['file']
4464
+ } as const;
4465
+
4466
+ export const $ImportErrorDto = {
4467
+ type: 'object',
4468
+ properties: {
4469
+ index: {
4470
+ type: 'number',
4471
+ description: 'Index of failed transaction in the file',
4472
+ example: 5
4473
+ },
4474
+ error: {
4475
+ type: 'string',
4476
+ description: 'Error message',
4477
+ example: 'Transaction does not balance: -100 USD != 0'
4478
+ }
4479
+ },
4480
+ required: ['index', 'error']
4481
+ } as const;
4482
+
4483
+ export const $ReviewItemPreviewDto = {
4484
+ type: 'object',
4485
+ properties: {
4486
+ index: {
4487
+ type: 'number',
4488
+ description: 'Index in the import batch (for tracking)',
4489
+ example: 0
4490
+ },
4491
+ date: {
4492
+ type: 'string',
4493
+ description: 'Transaction date (ISO format)',
4494
+ example: '2026-03-05'
4495
+ },
4496
+ amount: {
4497
+ type: 'number',
4498
+ description: 'Transaction amount (absolute value)',
4499
+ example: 99
4500
+ },
4501
+ currency: {
4502
+ type: 'string',
4503
+ description: 'Currency code',
4504
+ example: 'CNY'
4505
+ },
4506
+ narration: {
4507
+ type: 'string',
4508
+ description: 'Transaction narration/description',
4509
+ example: 'Restaurant expense'
4510
+ },
4511
+ payee: {
4512
+ type: 'string',
4513
+ description: 'Payee name',
4514
+ example: 'Restaurant ABC'
4515
+ },
4516
+ category: {
4517
+ type: 'string',
4518
+ description: 'Inferred category from rule matching',
4519
+ example: 'food'
4520
+ },
4521
+ confidence: {
4522
+ type: 'number',
4523
+ description: 'Confidence score for the match (0-1)',
4524
+ example: 0.85
4525
+ },
4526
+ branchType: {
4527
+ type: 'string',
4528
+ description: 'Type of branch requiring review',
4168
4529
  enum: [
4169
4530
  'DUPLICATE',
4170
4531
  'PAYEE_MATCH',
@@ -4761,6 +5122,11 @@ export const $ParserTelemetryReportDto = {
4761
5122
  properties: {}
4762
5123
  } as const;
4763
5124
 
5125
+ export const $UncoveredFormatMissDto = {
5126
+ type: 'object',
5127
+ properties: {}
5128
+ } as const;
5129
+
4764
5130
  export const $ProcessNlpDto = {
4765
5131
  type: 'object',
4766
5132
  properties: {
@@ -5888,6 +6254,12 @@ export const $AccountItemWithAssetClassDto = {
5888
6254
  type: 'string',
5889
6255
  description: 'Risk level',
5890
6256
  example: 'LOW'
6257
+ },
6258
+ source: {
6259
+ type: 'string',
6260
+ description:
6261
+ 'ADR-0105 classification provenance (holding level always; account level only on FALLBACK)',
6262
+ enum: ['USER_META', 'FIAT_CURRENCY', 'OPENBB_MAPPING', 'FALLBACK']
5891
6263
  }
5892
6264
  },
5893
6265
  required: ['id', 'name', 'displayName', 'balance', 'currency', 'assetClass']
@@ -5993,6 +6365,11 @@ export const $AssetClassSummaryDto = {
5993
6365
  items: {
5994
6366
  $ref: '#/components/schemas/AccountExchangeRateWarningDto'
5995
6367
  }
6368
+ },
6369
+ fallback: {
6370
+ type: 'object',
6371
+ description:
6372
+ '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.'
5996
6373
  }
5997
6374
  },
5998
6375
  required: ['totalAccounts', 'totalAssetClasses', 'baseCurrency']
@@ -6015,11 +6392,107 @@ export const $AssetClassAccountsResponseDto = {
6015
6392
  $ref: '#/components/schemas/AssetClassSummaryDto'
6016
6393
  }
6017
6394
  ]
6395
+ },
6396
+ uncategorized: {
6397
+ description:
6398
+ 'ADR-0105 §6 holding-level grey-area bucket (source=FALLBACK holdings peeled out of groups). Present only for groupBy=holdingAssetClass when FALLBACK holdings exist.',
6399
+ allOf: [
6400
+ {
6401
+ $ref: '#/components/schemas/AssetClassGroupDto'
6402
+ }
6403
+ ]
6018
6404
  }
6019
6405
  },
6020
6406
  required: ['groups', 'summary']
6021
6407
  } as const;
6022
6408
 
6409
+ export const $HoldingAssetClassAccountSliceDto = {
6410
+ type: 'object',
6411
+ properties: {
6412
+ accountId: {
6413
+ type: 'string',
6414
+ description: 'Account ID'
6415
+ },
6416
+ accountPath: {
6417
+ type: 'string',
6418
+ description: 'Full account path',
6419
+ example: 'Assets:US:Investments:Brokerage'
6420
+ },
6421
+ accountCurrency: {
6422
+ type: 'string',
6423
+ description:
6424
+ 'Currency of the holding with the largest converted base value; undefined when no holding is convertible',
6425
+ example: 'USD'
6426
+ },
6427
+ marketValueBase: {
6428
+ type: 'string',
6429
+ description:
6430
+ "Account's market value in base currency (Σ converted holdings; grey bucket included)",
6431
+ example: '50000.00'
6432
+ },
6433
+ shareOfTotalPct: {
6434
+ type: 'number',
6435
+ description:
6436
+ 'Share of the global total (0-100). 0 when globalTotal is zero (no NaN/Infinity).',
6437
+ example: 42.5
6438
+ },
6439
+ groups: {
6440
+ description: 'Per-account asset-class breakdown',
6441
+ type: 'array',
6442
+ items: {
6443
+ $ref: '#/components/schemas/AssetClassGroupDto'
6444
+ }
6445
+ },
6446
+ uncategorized: {
6447
+ description:
6448
+ 'Per-account grey bucket (source=FALLBACK holdings, incl. broker cash)',
6449
+ allOf: [
6450
+ {
6451
+ $ref: '#/components/schemas/AssetClassGroupDto'
6452
+ }
6453
+ ]
6454
+ },
6455
+ holdings: {
6456
+ description:
6457
+ 'Every holding row for this account (account ID in each row’s `id` field)',
6458
+ type: 'array',
6459
+ items: {
6460
+ $ref: '#/components/schemas/AccountItemWithAssetClassDto'
6461
+ }
6462
+ }
6463
+ },
6464
+ required: [
6465
+ 'accountId',
6466
+ 'accountPath',
6467
+ 'marketValueBase',
6468
+ 'shareOfTotalPct',
6469
+ 'groups',
6470
+ 'holdings'
6471
+ ]
6472
+ } as const;
6473
+
6474
+ export const $HoldingAssetClassCrossAccountResponseDto = {
6475
+ type: 'object',
6476
+ properties: {
6477
+ global: {
6478
+ description: 'Merged cross-account holding aggregation',
6479
+ allOf: [
6480
+ {
6481
+ $ref: '#/components/schemas/AssetClassAccountsResponseDto'
6482
+ }
6483
+ ]
6484
+ },
6485
+ byAccount: {
6486
+ description: 'Per-account slices',
6487
+ type: 'array',
6488
+ items: {
6489
+ $ref: '#/components/schemas/HoldingAssetClassAccountSliceDto'
6490
+ }
6491
+ }
6492
+ },
6493
+ required: ['global', 'byAccount']
6494
+ } as const;
6495
+
6023
6496
  export const $CashFlowByCurrencyDto = {
6024
6497
  type: 'object',
6025
6498
  properties: {
@@ -6149,65 +6622,615 @@ export const $CashFlowResponseDto = {
6149
6622
  ]
6150
6623
  } as const;
6151
6624
 
6152
- export const $CurrencyBalanceDto = {
6625
+ export const $CategoryGroupDto = {
6153
6626
  type: 'object',
6154
6627
  properties: {
6155
- currency: {
6628
+ category: {
6156
6629
  type: 'string',
6157
- description: 'ISO 4217 currency code',
6158
- example: 'CNY'
6630
+ description:
6631
+ 'Functional category (account-path Group segment); regional and universal account paths merge under it',
6632
+ example: 'Food'
6159
6633
  },
6160
- balance: {
6634
+ totalExpense: {
6161
6635
  type: 'string',
6162
- description: 'Balance amount',
6163
- example: '500000.00'
6636
+ description: 'Converted total expense in base currency',
6637
+ example: '1200.00'
6638
+ },
6639
+ sharePct: {
6640
+ type: 'number',
6641
+ description: 'Share of grand total (0-100); 0 when grand total is 0',
6642
+ example: 42.5
6643
+ },
6644
+ balanceByCurrency: {
6645
+ description: 'Raw (unconverted) expense per currency',
6646
+ type: 'array',
6647
+ items: {
6648
+ $ref: '#/components/schemas/BalanceByCurrencyDto'
6649
+ }
6650
+ },
6651
+ convertedBalance: {
6652
+ type: 'string',
6653
+ description:
6654
+ 'Converted total in base currency (omitted when FX missing for all currencies in this category)',
6655
+ example: '1200.00'
6164
6656
  }
6165
6657
  },
6166
- required: ['currency', 'balance']
6658
+ required: ['category', 'totalExpense', 'sharePct', 'balanceByCurrency']
6167
6659
  } as const;
6168
6660
 
6169
- export const $TimeSeriesPointDto = {
6661
+ export const $ExpensesByCategorySummaryDto = {
6170
6662
  type: 'object',
6171
6663
  properties: {
6172
- date: {
6173
- type: 'string',
6174
- description: 'Date in YYYY-MM-DD format',
6175
- example: '2024-06-15'
6176
- },
6177
- value: {
6664
+ totalExpense: {
6178
6665
  type: 'string',
6179
- description: 'Value at this date (in base currency)',
6180
- example: '500000.00'
6181
- },
6182
- change: {
6183
- type: 'object',
6184
- description: 'Change from previous point',
6666
+ description:
6667
+ 'Total expense across all categories (converted; convertible categories only)',
6185
6668
  example: '5000.00'
6186
6669
  },
6187
- byCurrency: {
6188
- description: 'Multi-currency breakdown for this point',
6189
- type: 'array',
6190
- items: {
6191
- $ref: '#/components/schemas/CurrencyBalanceDto'
6192
- }
6670
+ categoryCount: {
6671
+ type: 'number',
6672
+ description: 'Number of categories',
6673
+ example: 8
6193
6674
  }
6194
6675
  },
6195
- required: ['date', 'value']
6676
+ required: ['totalExpense', 'categoryCount']
6196
6677
  } as const;
6197
6678
 
6198
- export const $TrendSummaryDto = {
6679
+ export const $ExpensesByCategoryResponseDto = {
6199
6680
  type: 'object',
6200
6681
  properties: {
6201
- startValue: {
6682
+ period: {
6202
6683
  type: 'string',
6203
- description: 'Value at start of period',
6204
- example: '450000.00'
6684
+ description: 'Period requested',
6685
+ example: '1m'
6205
6686
  },
6206
- endValue: {
6687
+ baseCurrency: {
6207
6688
  type: 'string',
6208
- description: 'Value at end of period',
6209
- example: '500000.00'
6210
- },
6689
+ description: 'Base currency for converted values',
6690
+ example: 'CNY'
6691
+ },
6692
+ groups: {
6693
+ description:
6694
+ 'Expense groups by functional category, sorted by converted total desc',
6695
+ type: 'array',
6696
+ items: {
6697
+ $ref: '#/components/schemas/CategoryGroupDto'
6698
+ }
6699
+ },
6700
+ summary: {
6701
+ description: 'Summary statistics',
6702
+ allOf: [
6703
+ {
6704
+ $ref: '#/components/schemas/ExpensesByCategorySummaryDto'
6705
+ }
6706
+ ]
6707
+ },
6708
+ warnings: {
6709
+ description: 'Exchange rate warnings (e.g. missing rate for a currency)',
6710
+ type: 'array',
6711
+ items: {
6712
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
6713
+ }
6714
+ }
6715
+ },
6716
+ required: ['period', 'baseCurrency', 'groups', 'summary']
6717
+ } as const;
6718
+
6719
+ export const $MonetaryDto = {
6720
+ type: 'object',
6721
+ properties: {
6722
+ amount: {
6723
+ type: 'string',
6724
+ description: 'Amount (Decimal string)',
6725
+ example: '3000'
6726
+ },
6727
+ currency: {
6728
+ type: 'string',
6729
+ description: 'ISO 4217 currency',
6730
+ example: 'USD'
6731
+ },
6732
+ baseCcyEquivalent: {
6733
+ type: 'object',
6734
+ description: 'Converted to user base currency (Decimal string)',
6735
+ example: '21600',
6736
+ nullable: true
6737
+ }
6738
+ },
6739
+ required: ['amount', 'currency']
6740
+ } as const;
6741
+
6742
+ export const $CurrentPriceDto = {
6743
+ type: 'object',
6744
+ properties: {
6745
+ amount: {
6746
+ type: 'string',
6747
+ description: 'Price amount (Decimal string)',
6748
+ example: '250'
6749
+ },
6750
+ currency: {
6751
+ type: 'string',
6752
+ description: 'Price currency (ISO 4217)',
6753
+ example: 'USD'
6754
+ },
6755
+ date: {
6756
+ type: 'string',
6757
+ description: 'Price date (ISO 8601)',
6758
+ example: '2024-06-01'
6759
+ },
6760
+ source: {
6761
+ type: 'string',
6762
+ description: 'Price source',
6763
+ example: 'USER_OVERRIDE',
6764
+ enum: ['USER_OVERRIDE', 'OPENBB_EQUITY', 'OPENBB_CURRENCY']
6765
+ }
6766
+ },
6767
+ required: ['amount', 'currency', 'date', 'source']
6768
+ } as const;
6769
+
6770
+ export const $FxRateDto = {
6771
+ type: 'object',
6772
+ properties: {
6773
+ from: {
6774
+ type: 'string',
6775
+ example: 'USD'
6776
+ },
6777
+ to: {
6778
+ type: 'string',
6779
+ example: 'CNY'
6780
+ },
6781
+ rate: {
6782
+ type: 'string',
6783
+ description: 'FX rate (Decimal string)',
6784
+ example: '7.2'
6785
+ },
6786
+ date: {
6787
+ type: 'string',
6788
+ description: 'Rate date (ISO 8601)',
6789
+ example: '2024-01-15'
6790
+ }
6791
+ },
6792
+ required: ['from', 'to', 'rate', 'date']
6793
+ } as const;
6794
+
6795
+ export const $HoldingPnlRowDto = {
6796
+ type: 'object',
6797
+ properties: {
6798
+ accountId: {
6799
+ type: 'string',
6800
+ description: 'Account UUID',
6801
+ example: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
6802
+ },
6803
+ accountPath: {
6804
+ type: 'string',
6805
+ description: 'Full account path',
6806
+ example: 'Assets:US:Broker:AAPL'
6807
+ },
6808
+ accountCcy: {
6809
+ type: 'object',
6810
+ description: 'Account settlement currency (ISO 4217), from cost currency',
6811
+ nullable: true,
6812
+ example: 'USD'
6813
+ },
6814
+ brokerType: {
6815
+ type: 'object',
6816
+ description: 'Broker type derived from Platform.type',
6817
+ nullable: true,
6818
+ example: 'broker'
6819
+ },
6820
+ symbol: {
6821
+ type: 'string',
6822
+ description: 'Commodity symbol',
6823
+ example: 'AAPL'
6824
+ },
6825
+ chartToken: {
6826
+ type: 'string',
6827
+ description: 'Chart segment token (libs/common resolver)',
6828
+ example: 'equity',
6829
+ enum: ['equity', 'fund', 'bond', 'cash', 'other']
6830
+ },
6831
+ assetClass: {
6832
+ type: 'string',
6833
+ example: 'EQUITY'
6834
+ },
6835
+ assetSubClass: {
6836
+ type: 'object',
6837
+ nullable: true,
6838
+ example: 'STOCK'
6839
+ },
6840
+ units: {
6841
+ type: 'string',
6842
+ description: 'Net held units (Decimal string)',
6843
+ example: '12'
6844
+ },
6845
+ averageCostPerUnit: {
6846
+ description:
6847
+ 'Average cost per unit; null when cost currency conflicts or no cost',
6848
+ nullable: true,
6849
+ allOf: [
6850
+ {
6851
+ $ref: '#/components/schemas/MonetaryDto'
6852
+ }
6853
+ ]
6854
+ },
6855
+ costBasis: {
6856
+ description: 'Cost basis of held units',
6857
+ nullable: true,
6858
+ allOf: [
6859
+ {
6860
+ $ref: '#/components/schemas/MonetaryDto'
6861
+ }
6862
+ ]
6863
+ },
6864
+ marketValue: {
6865
+ description: 'Market value at asOf price',
6866
+ nullable: true,
6867
+ allOf: [
6868
+ {
6869
+ $ref: '#/components/schemas/MonetaryDto'
6870
+ }
6871
+ ]
6872
+ },
6873
+ currentPrice: {
6874
+ description: 'Price used for market value',
6875
+ nullable: true,
6876
+ allOf: [
6877
+ {
6878
+ $ref: '#/components/schemas/CurrentPriceDto'
6879
+ }
6880
+ ]
6881
+ },
6882
+ unrealizedPnlBase: {
6883
+ type: 'object',
6884
+ description:
6885
+ 'Unrealized P&L in base currency (Decimal string); null when any FX/price missing',
6886
+ nullable: true,
6887
+ example: '6000'
6888
+ },
6889
+ unrealizedPnlPct: {
6890
+ type: 'object',
6891
+ description: 'Unrealized P&L % (Decimal string)',
6892
+ nullable: true,
6893
+ example: '25'
6894
+ },
6895
+ costFxRate: {
6896
+ description: 'Historical FX rate applied to cost basis',
6897
+ nullable: true,
6898
+ allOf: [
6899
+ {
6900
+ $ref: '#/components/schemas/FxRateDto'
6901
+ }
6902
+ ]
6903
+ },
6904
+ marketFxRate: {
6905
+ description: 'FX rate applied to market value',
6906
+ nullable: true,
6907
+ allOf: [
6908
+ {
6909
+ $ref: '#/components/schemas/FxRateDto'
6910
+ }
6911
+ ]
6912
+ },
6913
+ pctOfInvestedAssets: {
6914
+ type: 'object',
6915
+ description:
6916
+ 'Share of invested assets % (Decimal string); only for invested chartTokens',
6917
+ nullable: true,
6918
+ example: '40'
6919
+ },
6920
+ realizedPnl: {
6921
+ description:
6922
+ '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',
6923
+ nullable: true,
6924
+ allOf: [
6925
+ {
6926
+ $ref: '#/components/schemas/MonetaryDto'
6927
+ }
6928
+ ]
6929
+ }
6930
+ },
6931
+ required: [
6932
+ 'accountId',
6933
+ 'accountPath',
6934
+ 'symbol',
6935
+ 'chartToken',
6936
+ 'assetClass',
6937
+ 'units'
6938
+ ]
6939
+ } as const;
6940
+
6941
+ export const $HoldingPnlWarningDto = {
6942
+ type: 'object',
6943
+ properties: {
6944
+ type: {
6945
+ type: 'string',
6946
+ description: 'Warning type',
6947
+ example: 'MISSING_COST_FX_RATE',
6948
+ enum: [
6949
+ 'MISSING_COST_FX_RATE',
6950
+ 'MISSING_MARKET_FX_RATE',
6951
+ 'MISSING_SALE_PRICE',
6952
+ 'MISSING_REALIZED_FX_RATE',
6953
+ 'OVERSOLD_LOTS',
6954
+ 'NO_PRICE',
6955
+ 'MIXED_COST_CURRENCY'
6956
+ ]
6957
+ },
6958
+ symbol: {
6959
+ type: 'object',
6960
+ nullable: true
6961
+ },
6962
+ accountId: {
6963
+ type: 'object',
6964
+ nullable: true
6965
+ },
6966
+ currency: {
6967
+ type: 'object',
6968
+ nullable: true
6969
+ }
6970
+ },
6971
+ required: ['type']
6972
+ } as const;
6973
+
6974
+ export const $HoldingPnlResponseDto = {
6975
+ type: 'object',
6976
+ properties: {
6977
+ asOfDate: {
6978
+ type: 'string',
6979
+ example: '2026-07-08'
6980
+ },
6981
+ baseCurrency: {
6982
+ type: 'string',
6983
+ example: 'CNY'
6984
+ },
6985
+ method: {
6986
+ type: 'string',
6987
+ description:
6988
+ 'Realized-P&L lot-matching method (FIFO or average). Unrealized cost basis remains average regardless of this value (#473).',
6989
+ enum: ['average', 'FIFO'],
6990
+ example: 'average'
6991
+ },
6992
+ rows: {
6993
+ type: 'array',
6994
+ items: {
6995
+ $ref: '#/components/schemas/HoldingPnlRowDto'
6996
+ }
6997
+ },
6998
+ warnings: {
6999
+ type: 'array',
7000
+ items: {
7001
+ $ref: '#/components/schemas/HoldingPnlWarningDto'
7002
+ }
7003
+ }
7004
+ },
7005
+ required: ['asOfDate', 'baseCurrency', 'method', 'rows', 'warnings']
7006
+ } as const;
7007
+
7008
+ export const $CreateBeanPriceDto = {
7009
+ type: 'object',
7010
+ properties: {
7011
+ currency: {
7012
+ type: 'string',
7013
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
7014
+ example: 'USD'
7015
+ },
7016
+ quoteCurrency: {
7017
+ type: 'string',
7018
+ description: 'Quote currency (pricing currency, e.g., CNY, EUR)',
7019
+ example: 'CNY'
7020
+ },
7021
+ amount: {
7022
+ type: 'number',
7023
+ description:
7024
+ 'Price amount (MUST be >= 0 per Beancount spec, supports up to 15 decimal places). Zero allowed for conversion entries, negative strictly prohibited.',
7025
+ example: 175.5,
7026
+ minimum: 0
7027
+ },
7028
+ date: {
7029
+ type: 'string',
7030
+ description: 'Price date (ISO 8601 format)',
7031
+ example: '2024-11-05'
7032
+ },
7033
+ metadata: {
7034
+ type: 'object',
7035
+ description:
7036
+ 'Metadata (validated by Zod schema, max field lengths enforced)',
7037
+ example: {
7038
+ source: 'MANUAL',
7039
+ note: 'Bank valuation report',
7040
+ confidence: 0.95
7041
+ }
7042
+ }
7043
+ },
7044
+ required: ['currency', 'quoteCurrency', 'amount', 'date']
7045
+ } as const;
7046
+
7047
+ export const $PriceResponseDto = {
7048
+ type: 'object',
7049
+ properties: {
7050
+ id: {
7051
+ type: 'string',
7052
+ description: 'Unique identifier',
7053
+ example: 'uuid-123-456'
7054
+ },
7055
+ userId: {
7056
+ type: 'string',
7057
+ description: 'User ID (owner of the price)',
7058
+ example: 'user-123'
7059
+ },
7060
+ currency: {
7061
+ type: 'string',
7062
+ description: 'Currency being priced (e.g., USD, AAPL, BTC)',
7063
+ example: 'BTC'
7064
+ },
7065
+ quoteCurrency: {
7066
+ type: 'string',
7067
+ description: 'Quote currency (pricing currency, e.g., USD, CNY)',
7068
+ example: 'USD'
7069
+ },
7070
+ amount: {
7071
+ type: 'number',
7072
+ description:
7073
+ 'Price amount (corresponds to Beancount Amount.number). Supports up to 15 decimal places.',
7074
+ example: 50000
7075
+ },
7076
+ date: {
7077
+ type: 'string',
7078
+ description:
7079
+ 'Price date (ISO 8601 format). Represents the date this price was valid.',
7080
+ example: '2024-01-01',
7081
+ format: 'date'
7082
+ },
7083
+ meta: {
7084
+ type: 'object',
7085
+ description:
7086
+ 'Metadata (corresponds to Beancount meta field). Contains source, confidence, note, etc.',
7087
+ example: {
7088
+ source: 'MANUAL',
7089
+ note: 'User-defined price',
7090
+ confidence: 1
7091
+ }
7092
+ },
7093
+ createdAt: {
7094
+ format: 'date-time',
7095
+ type: 'string',
7096
+ description: 'Creation timestamp',
7097
+ example: '2024-11-03T10:00:00Z'
7098
+ },
7099
+ updatedAt: {
7100
+ format: 'date-time',
7101
+ type: 'string',
7102
+ description: 'Last update timestamp',
7103
+ example: '2024-11-03T10:00:00Z'
7104
+ }
7105
+ },
7106
+ required: [
7107
+ 'id',
7108
+ 'userId',
7109
+ 'currency',
7110
+ 'quoteCurrency',
7111
+ 'amount',
7112
+ 'date',
7113
+ 'meta',
7114
+ 'createdAt',
7115
+ 'updatedAt'
7116
+ ]
7117
+ } as const;
7118
+
7119
+ export const $PriceListResponseDto = {
7120
+ type: 'object',
7121
+ properties: {
7122
+ items: {
7123
+ description: 'List of prices',
7124
+ type: 'array',
7125
+ items: {
7126
+ $ref: '#/components/schemas/PriceResponseDto'
7127
+ }
7128
+ },
7129
+ total: {
7130
+ type: 'number',
7131
+ description: 'Total number of prices',
7132
+ example: 42
7133
+ }
7134
+ },
7135
+ required: ['items', 'total']
7136
+ } as const;
7137
+
7138
+ export const $UpdateBeanPriceDto = {
7139
+ type: 'object',
7140
+ properties: {
7141
+ currency: {
7142
+ type: 'string',
7143
+ description: 'Currency being priced'
7144
+ },
7145
+ quoteCurrency: {
7146
+ type: 'string',
7147
+ description: 'Quote currency (pricing currency)'
7148
+ },
7149
+ amount: {
7150
+ type: 'number',
7151
+ description: 'Price amount (MUST be >= 0 per Beancount spec)',
7152
+ minimum: 0
7153
+ },
7154
+ date: {
7155
+ type: 'string',
7156
+ description: 'Price date (ISO 8601 format)'
7157
+ },
7158
+ metadata: {
7159
+ type: 'object',
7160
+ description: 'Metadata'
7161
+ }
7162
+ }
7163
+ } as const;
7164
+
7165
+ export const $CurrencyBalanceDto = {
7166
+ type: 'object',
7167
+ properties: {
7168
+ currency: {
7169
+ type: 'string',
7170
+ description: 'ISO 4217 currency code',
7171
+ example: 'CNY'
7172
+ },
7173
+ balance: {
7174
+ type: 'string',
7175
+ description: 'Balance amount',
7176
+ example: '500000.00'
7177
+ }
7178
+ },
7179
+ required: ['currency', 'balance']
7180
+ } as const;
7181
+
7182
+ export const $TimeSeriesPointDto = {
7183
+ type: 'object',
7184
+ properties: {
7185
+ date: {
7186
+ type: 'string',
7187
+ description: 'Date in YYYY-MM-DD format',
7188
+ example: '2024-06-15'
7189
+ },
7190
+ value: {
7191
+ type: 'string',
7192
+ description: 'Value at this date (in base currency)',
7193
+ example: '500000.00'
7194
+ },
7195
+ change: {
7196
+ type: 'object',
7197
+ description: 'Change from previous point',
7198
+ example: '5000.00'
7199
+ },
7200
+ assets: {
7201
+ type: 'string',
7202
+ description: 'Total assets at this date (in base currency)',
7203
+ example: '494338.00'
7204
+ },
7205
+ liabilities: {
7206
+ type: 'string',
7207
+ description: 'Total liabilities at this date (in base currency)',
7208
+ example: '310098.00'
7209
+ },
7210
+ byCurrency: {
7211
+ description: 'Multi-currency breakdown for this point',
7212
+ type: 'array',
7213
+ items: {
7214
+ $ref: '#/components/schemas/CurrencyBalanceDto'
7215
+ }
7216
+ }
7217
+ },
7218
+ required: ['date', 'value']
7219
+ } as const;
7220
+
7221
+ export const $TrendSummaryDto = {
7222
+ type: 'object',
7223
+ properties: {
7224
+ startValue: {
7225
+ type: 'string',
7226
+ description: 'Value at start of period',
7227
+ example: '450000.00'
7228
+ },
7229
+ endValue: {
7230
+ type: 'string',
7231
+ description: 'Value at end of period',
7232
+ example: '500000.00'
7233
+ },
6211
7234
  totalChange: {
6212
7235
  type: 'string',
6213
7236
  description: 'Total change over period',
@@ -6293,6 +7316,111 @@ export const $PortfolioTrendsResponseDto = {
6293
7316
  required: ['series', 'summary', 'period', 'granularity', 'currency']
6294
7317
  } as const;
6295
7318
 
7319
+ export const $CashFlowPointDto = {
7320
+ type: 'object',
7321
+ properties: {
7322
+ month: {
7323
+ type: 'string',
7324
+ description: 'Month key (YYYY-MM)',
7325
+ example: '2024-03'
7326
+ },
7327
+ income: {
7328
+ type: 'string',
7329
+ description: 'Income in base currency (absolute, converted)',
7330
+ example: '10000.00'
7331
+ },
7332
+ expense: {
7333
+ type: 'string',
7334
+ description: 'Expense in base currency (absolute, converted)',
7335
+ example: '5000.00'
7336
+ },
7337
+ netSavings: {
7338
+ type: 'string',
7339
+ description: 'netSavings = income − expense (savings positive)',
7340
+ example: '5000.00'
7341
+ }
7342
+ },
7343
+ required: ['month', 'income', 'expense', 'netSavings']
7344
+ } as const;
7345
+
7346
+ export const $CashFlowTrendSummaryDto = {
7347
+ type: 'object',
7348
+ properties: {
7349
+ totalIncome: {
7350
+ type: 'string',
7351
+ description: 'Total income across the period',
7352
+ example: '60000.00'
7353
+ },
7354
+ totalExpense: {
7355
+ type: 'string',
7356
+ description: 'Total expense across the period',
7357
+ example: '30000.00'
7358
+ },
7359
+ totalNetSavings: {
7360
+ type: 'string',
7361
+ description: 'income − expense across the period',
7362
+ example: '30000.00'
7363
+ },
7364
+ averageMonthlyNetSavings: {
7365
+ type: 'string',
7366
+ description:
7367
+ 'totalNetSavings divided by the window length (N months, incl. zero-filled)',
7368
+ example: '5000.00'
7369
+ }
7370
+ },
7371
+ required: [
7372
+ 'totalIncome',
7373
+ 'totalExpense',
7374
+ 'totalNetSavings',
7375
+ 'averageMonthlyNetSavings'
7376
+ ]
7377
+ } as const;
7378
+
7379
+ export const $CashFlowTrendsResponseDto = {
7380
+ type: 'object',
7381
+ properties: {
7382
+ series: {
7383
+ description:
7384
+ 'Monthly cash-flow series (fixed N-month window, zero-filled)',
7385
+ type: 'array',
7386
+ items: {
7387
+ $ref: '#/components/schemas/CashFlowPointDto'
7388
+ }
7389
+ },
7390
+ summary: {
7391
+ description: 'Period totals',
7392
+ allOf: [
7393
+ {
7394
+ $ref: '#/components/schemas/CashFlowTrendSummaryDto'
7395
+ }
7396
+ ]
7397
+ },
7398
+ period: {
7399
+ type: 'string',
7400
+ description: 'Period requested',
7401
+ example: '6m'
7402
+ },
7403
+ granularity: {
7404
+ type: 'string',
7405
+ description: 'Data granularity (v1 returns month buckets)',
7406
+ example: 'month'
7407
+ },
7408
+ currency: {
7409
+ type: 'string',
7410
+ description: 'Base currency for converted values',
7411
+ example: 'CNY'
7412
+ },
7413
+ warnings: {
7414
+ description: 'Exchange rate warnings (e.g. missing rate for a currency)',
7415
+ type: 'array',
7416
+ items: {
7417
+ $ref: '#/components/schemas/ExchangeRateWarningDto'
7418
+ }
7419
+ }
7420
+ },
7421
+ required: ['series', 'summary', 'period', 'granularity', 'currency']
7422
+ } as const;
7423
+
6296
7424
  export const $GenerateSnapshotBody = {
6297
7425
  type: 'object',
6298
7426
  properties: {}