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

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.
@@ -97,6 +97,18 @@ import type {
97
97
  CommodityControllerGetOrCreateResponse,
98
98
  CommodityControllerBulkCreateData,
99
99
  CommodityControllerBulkCreateResponse,
100
+ PriceControllerCreateData,
101
+ PriceControllerCreateResponse,
102
+ PriceControllerFindAllData,
103
+ PriceControllerFindAllResponse,
104
+ PriceControllerFindOneData,
105
+ PriceControllerFindOneResponse,
106
+ PriceControllerUpdateData,
107
+ PriceControllerUpdateResponse,
108
+ PriceControllerDeleteData,
109
+ PriceControllerDeleteResponse,
110
+ PriceControllerBulkCreateData,
111
+ PriceControllerBulkCreateResponse,
100
112
  RecurringRuleControllerCreateData,
101
113
  RecurringRuleControllerCreateResponse,
102
114
  RecurringRuleControllerFindAllData,
@@ -171,6 +183,28 @@ import type {
171
183
  PropertyControllerUpdateResponse,
172
184
  PropertyControllerDeleteData,
173
185
  PropertyControllerDeleteResponse,
186
+ EventControllerCreateData,
187
+ EventControllerCreateResponse,
188
+ EventControllerFindAllData,
189
+ EventControllerFindAllResponse,
190
+ EventControllerFindOneData,
191
+ EventControllerFindOneResponse,
192
+ EventControllerUpdateData,
193
+ EventControllerUpdateResponse,
194
+ EventControllerDeleteData,
195
+ EventControllerDeleteResponse,
196
+ EventControllerGetSliceData,
197
+ EventControllerGetSliceResponse,
198
+ OnboardingControllerBootstrapData,
199
+ OnboardingControllerBootstrapResponse,
200
+ ReconciliationControllerComputeData,
201
+ ReconciliationControllerComputeResponse,
202
+ ReconciliationControllerAssertData,
203
+ ReconciliationControllerAssertResponse,
204
+ ReconciliationControllerPadData,
205
+ ReconciliationControllerPadResponse,
206
+ ReconciliationControllerHistoryData,
207
+ ReconciliationControllerHistoryResponse,
174
208
  ExportControllerExportBeancountResponse,
175
209
  FileImportControllerImportFileData,
176
210
  FileImportControllerImportFileResponse,
@@ -184,22 +218,20 @@ import type {
184
218
  ImporterConfigControllerUpdateConfigResponse,
185
219
  ImporterConfigControllerResetConfigData,
186
220
  ImporterConfigControllerResetConfigResponse,
187
- PlatformControllerFindAllResponse,
188
- PlatformControllerCreateData,
189
- PlatformControllerCreateResponse,
190
- PlatformControllerGetPlatformListResponse,
191
- PlatformControllerMatchPlatformsData,
192
- PlatformControllerMatchPlatformsResponse,
193
- PlatformControllerUpdateData,
194
- PlatformControllerUpdateResponse,
195
- PlatformControllerDeleteData,
196
- PlatformControllerDeleteResponse,
197
221
  ProviderSyncControllerSyncData,
198
222
  ProviderSyncControllerSyncResponse,
199
223
  ProviderSyncControllerGetSupportedProvidersData,
200
224
  ProviderSyncControllerGetSupportedProvidersResponse,
201
225
  ProviderSyncControllerIsProviderSupportedData,
202
226
  ProviderSyncControllerIsProviderSupportedResponse,
227
+ ExternalAccountLinkControllerCreateData,
228
+ ExternalAccountLinkControllerCreateResponse,
229
+ ExternalAccountLinkControllerFindAllData,
230
+ ExternalAccountLinkControllerFindAllResponse,
231
+ ExternalAccountLinkControllerFindOneData,
232
+ ExternalAccountLinkControllerFindOneResponse,
233
+ ExternalAccountLinkControllerRemoveData,
234
+ ExternalAccountLinkControllerRemoveResponse,
203
235
  TelemetryControllerReportTelemetryData,
204
236
  TelemetryControllerReportTelemetryResponse,
205
237
  TelemetryControllerReportCoverageMissData,
@@ -212,28 +244,30 @@ import type {
212
244
  NlpControllerClearSessionResponse,
213
245
  NlpControllerGetSessionData,
214
246
  NlpControllerGetSessionResponse,
247
+ PlatformControllerFindAllResponse,
248
+ PlatformControllerCreateData,
249
+ PlatformControllerCreateResponse,
250
+ PlatformControllerGetPlatformListResponse,
251
+ PlatformControllerMatchPlatformsData,
252
+ PlatformControllerMatchPlatformsResponse,
253
+ PlatformControllerUpdateData,
254
+ PlatformControllerUpdateResponse,
255
+ PlatformControllerDeleteData,
256
+ PlatformControllerDeleteResponse,
215
257
  DashboardControllerGetNetWorthData,
216
258
  DashboardControllerGetNetWorthResponse,
217
259
  DashboardControllerGetAccountsData,
218
260
  DashboardControllerGetAccountsResponse,
219
261
  DashboardControllerGetCashFlowData,
220
262
  DashboardControllerGetCashFlowResponse,
263
+ DashboardControllerGetExpensesData,
264
+ DashboardControllerGetExpensesResponse,
221
265
  HoldingPnlControllerGetHoldingPnlData,
222
266
  HoldingPnlControllerGetHoldingPnlResponse,
223
- PriceControllerCreateData,
224
- PriceControllerCreateResponse,
225
- PriceControllerFindAllData,
226
- PriceControllerFindAllResponse,
227
- PriceControllerFindOneData,
228
- PriceControllerFindOneResponse,
229
- PriceControllerUpdateData,
230
- PriceControllerUpdateResponse,
231
- PriceControllerDeleteData,
232
- PriceControllerDeleteResponse,
233
- PriceControllerBulkCreateData,
234
- PriceControllerBulkCreateResponse,
235
267
  ReportingControllerGetPortfolioTrendsData,
236
268
  ReportingControllerGetPortfolioTrendsResponse,
269
+ ReportingControllerGetCashFlowTrendsData,
270
+ ReportingControllerGetCashFlowTrendsResponse,
237
271
  ReportingControllerGenerateSnapshotData,
238
272
  ReportingControllerGenerateSnapshotResponse,
239
273
  ReportingControllerBackfillSnapshotsData,
@@ -290,7 +324,7 @@ export class BeanAccountsService {
290
324
  * @param data.type Filter by account type
291
325
  * @param data.status Filter by status
292
326
  * @param data.isCustom Filter by custom (user-created) accounts only
293
- * @param data.search Search term for path or i18nKey
327
+ * @param data.search Search term for account path
294
328
  * @param data.limit Maximum number of results
295
329
  * @param data.offset Number of results to skip
296
330
  * @returns AccountListResponseDto Accounts retrieved successfully
@@ -483,7 +517,7 @@ export class BeanAccountStandardsService {
483
517
 
484
518
  /**
485
519
  * Get template metadata for an account path
486
- * Returns extendable status and root type for a template path.
520
+ * Returns root type for a template path.
487
521
  * @param data The data for the request.
488
522
  * @param data.region Region code for tenant context
489
523
  * @param data.path Account path to check
@@ -569,6 +603,7 @@ export class BeanTransactionsService {
569
603
  * @param data.status Filter by transaction status
570
604
  * @param data.search Search in narration and payee fields (max 200 chars)
571
605
  * @param data.accountId Filter by account ID (transactions with postings to this account)
606
+ * @param data.category Filter by ADR-0075 functional category (Group segment); matches any posting to an Expenses/Income account whose derived Group segment equals this value
572
607
  * @returns TransactionListResponseDto Transaction list
573
608
  * @throws ApiError
574
609
  */
@@ -588,7 +623,8 @@ export class BeanTransactionsService {
588
623
  dateTo: data.dateTo,
589
624
  status: data.status,
590
625
  search: data.search,
591
- accountId: data.accountId
626
+ accountId: data.accountId,
627
+ category: data.category
592
628
  },
593
629
  errors: {
594
630
  400: 'Validation failed',
@@ -776,7 +812,7 @@ export class BeanBalancesService {
776
812
  * Query account balance
777
813
  * Calculate account balance at a specific date for a single currency
778
814
  * @param data The data for the request.
779
- * @param data.account Account name (e.g., "Assets:Bank:Checking")
815
+ * @param data.account Account name (e.g., "Assets:Checking")
780
816
  * @param data.region Region code for tenant context
781
817
  * @param data.date Date to calculate balance at (ISO 8601 format)
782
818
  * @param data.currency Currency to query (e.g., "USD", "CNY")
@@ -1497,6 +1533,173 @@ export class BeanCommoditiesService {
1497
1533
  }
1498
1534
  }
1499
1535
 
1536
+ export class BeanPricesService {
1537
+ /**
1538
+ * Create a new price
1539
+ * Creates a new price entry for the authenticated user
1540
+ * @param data The data for the request.
1541
+ * @param data.region Region code for tenant context
1542
+ * @param data.requestBody
1543
+ * @returns PriceResponseDto Price created successfully
1544
+ * @throws ApiError
1545
+ */
1546
+ public static priceControllerCreate(
1547
+ data: PriceControllerCreateData
1548
+ ): CancelablePromise<PriceControllerCreateResponse> {
1549
+ return __request(OpenAPI, {
1550
+ method: 'POST',
1551
+ url: '/api/v1/{region}/bean/prices',
1552
+ path: {
1553
+ region: data.region
1554
+ },
1555
+ body: data.requestBody,
1556
+ mediaType: 'application/json',
1557
+ errors: {
1558
+ 404: 'Currency or quoteCurrency commodity not found',
1559
+ 409: 'Price already exists for this currency pair and date'
1560
+ }
1561
+ });
1562
+ }
1563
+
1564
+ /**
1565
+ * List user prices
1566
+ * Returns all price entries for the authenticated user with optional filtering
1567
+ * @param data The data for the request.
1568
+ * @param data.region Region code for tenant context
1569
+ * @param data.currency Filter by currency (e.g., BTC, AAPL, USD)
1570
+ * @param data.quoteCurrency Filter by quote currency (pricing currency, e.g., USD, CNY)
1571
+ * @param data.dateFrom Filter prices from this date (ISO 8601 format)
1572
+ * @param data.dateTo Filter prices to this date (ISO 8601 format)
1573
+ * @param data.search Search term for currency or quoteCurrency (case-insensitive partial match)
1574
+ * @param data.page Page number for pagination (default: 1)
1575
+ * @param data.limit Number of items per page (default: 20, max: 100)
1576
+ * @returns PriceListResponseDto Prices retrieved successfully
1577
+ * @throws ApiError
1578
+ */
1579
+ public static priceControllerFindAll(
1580
+ data: PriceControllerFindAllData
1581
+ ): CancelablePromise<PriceControllerFindAllResponse> {
1582
+ return __request(OpenAPI, {
1583
+ method: 'GET',
1584
+ url: '/api/v1/{region}/bean/prices',
1585
+ path: {
1586
+ region: data.region
1587
+ },
1588
+ query: {
1589
+ currency: data.currency,
1590
+ quoteCurrency: data.quoteCurrency,
1591
+ dateFrom: data.dateFrom,
1592
+ dateTo: data.dateTo,
1593
+ search: data.search,
1594
+ page: data.page,
1595
+ limit: data.limit
1596
+ }
1597
+ });
1598
+ }
1599
+
1600
+ /**
1601
+ * Get price by ID
1602
+ * Returns a single price entry by its ID
1603
+ * @param data The data for the request.
1604
+ * @param data.id Price ID
1605
+ * @param data.region Region code for tenant context
1606
+ * @returns PriceResponseDto Price retrieved successfully
1607
+ * @throws ApiError
1608
+ */
1609
+ public static priceControllerFindOne(
1610
+ data: PriceControllerFindOneData
1611
+ ): CancelablePromise<PriceControllerFindOneResponse> {
1612
+ return __request(OpenAPI, {
1613
+ method: 'GET',
1614
+ url: '/api/v1/{region}/bean/prices/{id}',
1615
+ path: {
1616
+ id: data.id,
1617
+ region: data.region
1618
+ },
1619
+ errors: {
1620
+ 404: 'Price not found'
1621
+ }
1622
+ });
1623
+ }
1624
+
1625
+ /**
1626
+ * Update a price
1627
+ * Updates an existing price entry
1628
+ * @param data The data for the request.
1629
+ * @param data.id Price ID
1630
+ * @param data.region Region code for tenant context
1631
+ * @param data.requestBody
1632
+ * @returns PriceResponseDto Price updated successfully
1633
+ * @throws ApiError
1634
+ */
1635
+ public static priceControllerUpdate(
1636
+ data: PriceControllerUpdateData
1637
+ ): CancelablePromise<PriceControllerUpdateResponse> {
1638
+ return __request(OpenAPI, {
1639
+ method: 'PUT',
1640
+ url: '/api/v1/{region}/bean/prices/{id}',
1641
+ path: {
1642
+ id: data.id,
1643
+ region: data.region
1644
+ },
1645
+ body: data.requestBody,
1646
+ mediaType: 'application/json',
1647
+ errors: {
1648
+ 404: 'Price not found',
1649
+ 409: 'Updated price conflicts with existing price'
1650
+ }
1651
+ });
1652
+ }
1653
+
1654
+ /**
1655
+ * Delete a price
1656
+ * Deletes a price entry (hard delete)
1657
+ * @param data The data for the request.
1658
+ * @param data.id Price ID
1659
+ * @param data.region Region code for tenant context
1660
+ * @returns void Price deleted successfully
1661
+ * @throws ApiError
1662
+ */
1663
+ public static priceControllerDelete(
1664
+ data: PriceControllerDeleteData
1665
+ ): CancelablePromise<PriceControllerDeleteResponse> {
1666
+ return __request(OpenAPI, {
1667
+ method: 'DELETE',
1668
+ url: '/api/v1/{region}/bean/prices/{id}',
1669
+ path: {
1670
+ id: data.id,
1671
+ region: data.region
1672
+ },
1673
+ errors: {
1674
+ 404: 'Price not found'
1675
+ }
1676
+ });
1677
+ }
1678
+
1679
+ /**
1680
+ * Bulk create prices
1681
+ * Creates multiple price entries at once (skips duplicates)
1682
+ * @param data The data for the request.
1683
+ * @param data.region Region code for tenant context
1684
+ * @param data.requestBody
1685
+ * @returns PriceResponseDto Prices created successfully
1686
+ * @throws ApiError
1687
+ */
1688
+ public static priceControllerBulkCreate(
1689
+ data: PriceControllerBulkCreateData
1690
+ ): CancelablePromise<PriceControllerBulkCreateResponse> {
1691
+ return __request(OpenAPI, {
1692
+ method: 'POST',
1693
+ url: '/api/v1/{region}/bean/prices/bulk',
1694
+ path: {
1695
+ region: data.region
1696
+ },
1697
+ body: data.requestBody,
1698
+ mediaType: 'application/json'
1699
+ });
1700
+ }
1701
+ }
1702
+
1500
1703
  export class RecurringRulesService {
1501
1704
  /**
1502
1705
  * Create a new recurring rule
@@ -2460,294 +2663,487 @@ export class PropertiesService {
2460
2663
  }
2461
2664
  }
2462
2665
 
2463
- export class BeanExportService {
2464
- /**
2465
- * Export Beancount ledger as ZIP
2466
- * Export all user Beancount data as a ZIP file containing ledger.beancount and yearly files in community format.
2467
- * @returns unknown
2468
- * @throws ApiError
2469
- */
2470
- public static exportControllerExportBeancount(): CancelablePromise<ExportControllerExportBeancountResponse> {
2471
- return __request(OpenAPI, {
2472
- method: 'GET',
2473
- url: '/api/v1/{region}/bean/export/beancount'
2474
- });
2475
- }
2476
- }
2477
-
2478
- export class BeanImportService {
2666
+ export class LifeEventsService {
2479
2667
  /**
2480
- * Import a bill file
2481
- * Upload and process a bill file (CSV, PDF, OFX, etc.). The system automatically identifies the file type, extracts transactions, validates them, and stores only validated transactions to the database. Maximum file size: 50MB. Only 1 import per user at a time (concurrent imports rejected with 429).
2668
+ * Create a new life event
2669
+ * Creates a new life event entry for the authenticated user. Returns ETag header carrying the row updatedAt.
2482
2670
  * @param data The data for the request.
2483
- * @param data.region Region code for tenant context
2484
- * @param data.formData Bill file to import
2485
- * @returns ImportResultDto File imported successfully
2671
+ * @param data.region Region code for tenant context (decorative for life events)
2672
+ * @param data.requestBody
2673
+ * @returns EventResponseDto Life event created successfully
2486
2674
  * @throws ApiError
2487
2675
  */
2488
- public static fileImportControllerImportFile(
2489
- data: FileImportControllerImportFileData
2490
- ): CancelablePromise<FileImportControllerImportFileResponse> {
2676
+ public static eventControllerCreate(
2677
+ data: EventControllerCreateData
2678
+ ): CancelablePromise<EventControllerCreateResponse> {
2491
2679
  return __request(OpenAPI, {
2492
2680
  method: 'POST',
2493
- url: '/api/v1/{region}/bean/import/file',
2681
+ url: '/api/v1/{region}/bean/events',
2494
2682
  path: {
2495
2683
  region: data.region
2496
2684
  },
2497
- formData: data.formData,
2498
- mediaType: 'multipart/form-data',
2685
+ body: data.requestBody,
2686
+ mediaType: 'application/json',
2499
2687
  errors: {
2500
- 400: 'Bad request - file-format-unsupported or file-import-failed',
2501
- 413: 'Payload too large - file exceeds 50MB limit',
2502
- 429: 'Too many requests - user already has import in progress',
2503
- 500: 'Internal server error - DATABASE_ERROR'
2688
+ 409: 'Life event already exists for this (userId, type, date) combination'
2504
2689
  }
2505
2690
  });
2506
2691
  }
2507
2692
 
2508
2693
  /**
2509
- * Identify file type
2510
- * Upload a file to check if it can be processed by any registered importer. Does not perform actual import - useful for pre-validation. Uses user-specific importer configuration.
2694
+ * List user life events
2695
+ * Returns life events for the authenticated user with optional filtering by type, description search, and date range.
2511
2696
  * @param data The data for the request.
2512
- * @param data.region Region code for tenant context
2513
- * @param data.formData File to identify
2514
- * @returns IdentifyResultDto File identification result
2697
+ * @param data.region Region code for tenant context (decorative for life events)
2698
+ * @param data.type Filter by life event type (exact match)
2699
+ * @param data.q Search term for description (case-insensitive partial match)
2700
+ * @param data.from Filter life events from this date (ISO 8601 format)
2701
+ * @param data.to Filter life events to this date (ISO 8601 format)
2702
+ * @param data.page Page number for pagination (default: 1)
2703
+ * @param data.limit Number of items per page (default: 20, max: 100)
2704
+ * @returns EventListResponseDto Life events retrieved successfully
2515
2705
  * @throws ApiError
2516
2706
  */
2517
- public static fileImportControllerIdentifyFile(
2518
- data: FileImportControllerIdentifyFileData
2519
- ): CancelablePromise<FileImportControllerIdentifyFileResponse> {
2707
+ public static eventControllerFindAll(
2708
+ data: EventControllerFindAllData
2709
+ ): CancelablePromise<EventControllerFindAllResponse> {
2520
2710
  return __request(OpenAPI, {
2521
- method: 'POST',
2522
- url: '/api/v1/{region}/bean/import/identify',
2711
+ method: 'GET',
2712
+ url: '/api/v1/{region}/bean/events',
2523
2713
  path: {
2524
2714
  region: data.region
2525
2715
  },
2526
- formData: data.formData,
2527
- mediaType: 'multipart/form-data',
2716
+ query: {
2717
+ type: data.type,
2718
+ q: data.q,
2719
+ from: data.from,
2720
+ to: data.to,
2721
+ page: data.page,
2722
+ limit: data.limit
2723
+ }
2724
+ });
2725
+ }
2726
+
2727
+ /**
2728
+ * Get life event by ID
2729
+ * Returns a single life event by its ID. Returns ETag header.
2730
+ * @param data The data for the request.
2731
+ * @param data.id Life event ID
2732
+ * @param data.region Region code for tenant context (decorative for life events)
2733
+ * @returns EventResponseDto Life event retrieved successfully
2734
+ * @throws ApiError
2735
+ */
2736
+ public static eventControllerFindOne(
2737
+ data: EventControllerFindOneData
2738
+ ): CancelablePromise<EventControllerFindOneResponse> {
2739
+ return __request(OpenAPI, {
2740
+ method: 'GET',
2741
+ url: '/api/v1/{region}/bean/events/{id}',
2742
+ path: {
2743
+ id: data.id,
2744
+ region: data.region
2745
+ },
2528
2746
  errors: {
2529
- 400: 'Bad request - No file uploaded'
2747
+ 404: 'Life event not found'
2530
2748
  }
2531
2749
  });
2532
2750
  }
2533
2751
 
2534
2752
  /**
2535
- * Import a Beancount file in community format
2536
- * Upload a .beancount file to import. The system parses community-format paths, converts to internal format using category metadata, auto-creates accounts, and imports transactions with deduplication. Maximum file size: 50MB. Only 1 import per user at a time.
2753
+ * Update a life event
2754
+ * Updates an existing life event. If If-Match header is provided, performs optimistic concurrency check; mismatched updatedAt returns 412.
2537
2755
  * @param data The data for the request.
2538
- * @param data.region Region code for tenant context
2539
- * @param data.formData Beancount file to import
2540
- * @returns unknown Beancount file imported successfully
2756
+ * @param data.id Life event ID
2757
+ * @param data.region Region code for tenant context (decorative for life events)
2758
+ * @param data.requestBody
2759
+ * @returns EventResponseDto Life event updated successfully
2541
2760
  * @throws ApiError
2542
2761
  */
2543
- public static fileImportControllerImportBeancount(
2544
- data: FileImportControllerImportBeancountData
2545
- ): CancelablePromise<FileImportControllerImportBeancountResponse> {
2762
+ public static eventControllerUpdate(
2763
+ data: EventControllerUpdateData
2764
+ ): CancelablePromise<EventControllerUpdateResponse> {
2546
2765
  return __request(OpenAPI, {
2547
- method: 'POST',
2548
- url: '/api/v1/{region}/bean/import/beancount',
2766
+ method: 'PUT',
2767
+ url: '/api/v1/{region}/bean/events/{id}',
2549
2768
  path: {
2769
+ id: data.id,
2550
2770
  region: data.region
2551
2771
  },
2552
- formData: data.formData,
2553
- mediaType: 'multipart/form-data',
2772
+ body: data.requestBody,
2773
+ mediaType: 'application/json',
2554
2774
  errors: {
2555
- 400: 'Bad request - invalid file or no file uploaded'
2775
+ 400: 'If-Match header is not a valid ISO 8601 date',
2776
+ 404: 'Life event not found',
2777
+ 409: 'Updated event conflicts with an existing (userId, type, date) combination',
2778
+ 412: 'If-Match precondition failed (updatedAt mismatch)'
2556
2779
  }
2557
2780
  });
2558
2781
  }
2559
2782
 
2560
2783
  /**
2561
- * Get importer configuration
2562
- * Returns the current configuration for the specified importer. Creates default configuration if none exists.
2784
+ * Delete a life event
2785
+ * Deletes a life event entry (hard delete). Returns 204.
2563
2786
  * @param data The data for the request.
2564
- * @param data.importerId Importer identifier. Supported importers: alipay, alipay-web, wechat, boc, boc-credit, ccb, cmb, cmbc, cmbc-credit, icbc, icbc-credit, hsbc-hk-credit, hsbc-hk-debit
2565
- * @param data.region Region code for tenant context
2566
- * @returns ImporterConfigDto Configuration retrieved successfully
2787
+ * @param data.id Life event ID
2788
+ * @param data.region Region code for tenant context (decorative for life events)
2789
+ * @returns void Life event deleted successfully
2567
2790
  * @throws ApiError
2568
2791
  */
2569
- public static importerConfigControllerGetConfig(
2570
- data: ImporterConfigControllerGetConfigData
2571
- ): CancelablePromise<ImporterConfigControllerGetConfigResponse> {
2792
+ public static eventControllerDelete(
2793
+ data: EventControllerDeleteData
2794
+ ): CancelablePromise<EventControllerDeleteResponse> {
2795
+ return __request(OpenAPI, {
2796
+ method: 'DELETE',
2797
+ url: '/api/v1/{region}/bean/events/{id}',
2798
+ path: {
2799
+ id: data.id,
2800
+ region: data.region
2801
+ },
2802
+ errors: {
2803
+ 404: 'Life event not found'
2804
+ }
2805
+ });
2806
+ }
2807
+
2808
+ /**
2809
+ * Slice time-series by a life event (Phase 79)
2810
+ * Returns aggregated time-series for postings matching accountPattern within the half-open date range of the given life event.
2811
+ * @param data The data for the request.
2812
+ * @param data.id Life event ID
2813
+ * @param data.accountPattern
2814
+ * @param data.granularity
2815
+ * @param data.region Region code for tenant context (decorative for life events)
2816
+ * @returns unknown Time-series sliced by the life event range
2817
+ * @throws ApiError
2818
+ */
2819
+ public static eventControllerGetSlice(
2820
+ data: EventControllerGetSliceData
2821
+ ): CancelablePromise<EventControllerGetSliceResponse> {
2572
2822
  return __request(OpenAPI, {
2573
2823
  method: 'GET',
2574
- url: '/api/v1/{region}/bean/import/config/{importerId}',
2824
+ url: '/api/v1/{region}/bean/events/{id}/slice',
2575
2825
  path: {
2576
- importerId: data.importerId,
2826
+ id: data.id,
2577
2827
  region: data.region
2578
2828
  },
2829
+ query: {
2830
+ accountPattern: data.accountPattern,
2831
+ granularity: data.granularity
2832
+ },
2579
2833
  errors: {
2580
- 400: 'Invalid input - Unsupported importer',
2581
- 401: 'Unauthorized - Authentication required'
2834
+ 400: 'accountPattern query param is empty',
2835
+ 404: 'Life event not found'
2582
2836
  }
2583
2837
  });
2584
2838
  }
2839
+ }
2585
2840
 
2841
+ export class OnboardingService {
2586
2842
  /**
2587
- * Update importer configuration
2588
- * Updates the configuration for the specified importer. Partial updates are supported.
2843
+ * Bootstrap core accounts + register asset accounts with opening balances (ADR-0113)
2589
2844
  * @param data The data for the request.
2590
- * @param data.importerId Importer identifier. Supported importers: alipay, alipay-web, wechat, boc, boc-credit, ccb, cmb, cmbc, cmbc-credit, icbc, icbc-credit, hsbc-hk-credit, hsbc-hk-debit
2591
2845
  * @param data.region Region code for tenant context
2592
- * @param data.requestBody Partial configuration update. Only provided fields will be updated.
2593
- * @returns ImporterConfigDto Configuration updated successfully
2846
+ * @param data.requestBody
2847
+ * @returns unknown Onboarding bootstrap result.
2594
2848
  * @throws ApiError
2595
2849
  */
2596
- public static importerConfigControllerUpdateConfig(
2597
- data: ImporterConfigControllerUpdateConfigData
2598
- ): CancelablePromise<ImporterConfigControllerUpdateConfigResponse> {
2850
+ public static onboardingControllerBootstrap(
2851
+ data: OnboardingControllerBootstrapData
2852
+ ): CancelablePromise<OnboardingControllerBootstrapResponse> {
2599
2853
  return __request(OpenAPI, {
2600
- method: 'PUT',
2601
- url: '/api/v1/{region}/bean/import/config/{importerId}',
2854
+ method: 'POST',
2855
+ url: '/api/v1/{region}/bean/onboarding',
2602
2856
  path: {
2603
- importerId: data.importerId,
2604
2857
  region: data.region
2605
2858
  },
2606
2859
  body: data.requestBody,
2607
2860
  mediaType: 'application/json',
2608
2861
  errors: {
2609
- 400: 'Invalid input - Validation failed',
2610
- 404: 'Configuration not found'
2862
+ 422: 'Invalid region/account path/duplicate paths.'
2611
2863
  }
2612
2864
  });
2613
2865
  }
2866
+ }
2614
2867
 
2868
+ export class BalanceReconciliationService {
2615
2869
  /**
2616
- * Reset configuration to default
2617
- * Resets the configuration for the specified importer to default values. This operation overwrites all existing configuration.
2870
+ * Preview reconciliation (book vs actual)
2871
+ * Computes book balance, diff, Beancount-inferred tolerance, and suggested action without persisting.
2618
2872
  * @param data The data for the request.
2619
- * @param data.importerId Importer identifier. Supported importers: alipay, alipay-web, wechat, boc, boc-credit, ccb, cmb, cmbc, cmbc-credit, icbc, icbc-credit, hsbc-hk-credit, hsbc-hk-debit
2620
- * @param data.region Region code for tenant context
2621
- * @returns ImporterConfigDto Configuration reset successfully
2873
+ * @param data.region Region code for tenant context (decorative for reconciliation)
2874
+ * @param data.requestBody
2875
+ * @returns ReconciliationComputeResultDto Reconciliation preview
2622
2876
  * @throws ApiError
2623
2877
  */
2624
- public static importerConfigControllerResetConfig(
2625
- data: ImporterConfigControllerResetConfigData
2626
- ): CancelablePromise<ImporterConfigControllerResetConfigResponse> {
2878
+ public static reconciliationControllerCompute(
2879
+ data: ReconciliationControllerComputeData
2880
+ ): CancelablePromise<ReconciliationControllerComputeResponse> {
2627
2881
  return __request(OpenAPI, {
2628
2882
  method: 'POST',
2629
- url: '/api/v1/{region}/bean/import/config/{importerId}/reset',
2883
+ url: '/api/v1/{region}/bean/reconciliations',
2630
2884
  path: {
2631
- importerId: data.importerId,
2632
2885
  region: data.region
2633
2886
  },
2887
+ body: data.requestBody,
2888
+ mediaType: 'application/json',
2634
2889
  errors: {
2635
- 400: 'Invalid input - Unsupported importer'
2890
+ 404: 'Account not found'
2636
2891
  }
2637
2892
  });
2638
2893
  }
2639
- }
2640
2894
 
2641
- export class BeanPlatformsService {
2642
2895
  /**
2643
- * Get all platforms with statistics
2644
- * @returns unknown List of platforms with binding and account counts
2896
+ * Record a balance assertion
2897
+ * Persists the reconciliation as a BeanBalance assertion (amount = actual, diffAmount = book − actual). Re-reconciling the same day/currency upserts.
2898
+ * @param data The data for the request.
2899
+ * @param data.region Region code for tenant context (decorative for reconciliation)
2900
+ * @param data.requestBody
2901
+ * @returns ReconciliationRecordDto Balance assertion recorded
2645
2902
  * @throws ApiError
2646
2903
  */
2647
- public static platformControllerFindAll(): CancelablePromise<PlatformControllerFindAllResponse> {
2904
+ public static reconciliationControllerAssert(
2905
+ data: ReconciliationControllerAssertData
2906
+ ): CancelablePromise<ReconciliationControllerAssertResponse> {
2648
2907
  return __request(OpenAPI, {
2649
- method: 'GET',
2650
- url: '/api/v1/bean/platforms'
2908
+ method: 'POST',
2909
+ url: '/api/v1/{region}/bean/reconciliations/assert',
2910
+ path: {
2911
+ region: data.region
2912
+ },
2913
+ body: data.requestBody,
2914
+ mediaType: 'application/json',
2915
+ errors: {
2916
+ 404: 'Account not found'
2917
+ }
2651
2918
  });
2652
2919
  }
2653
2920
 
2654
2921
  /**
2655
- * Create a new platform
2922
+ * Generate a pad adjusting entry
2923
+ * When book is outside tolerance, synthesizes a Beancount pad transaction (flag P) booking the diff from source_account and persists it. Source defaults to Equity:Opening-Balances.
2656
2924
  * @param data The data for the request.
2925
+ * @param data.region Region code for tenant context (decorative for reconciliation)
2657
2926
  * @param data.requestBody
2658
- * @returns unknown Platform created successfully
2927
+ * @returns PadResultDto Pad adjusting entry generated
2659
2928
  * @throws ApiError
2660
2929
  */
2661
- public static platformControllerCreate(
2662
- data: PlatformControllerCreateData
2663
- ): CancelablePromise<PlatformControllerCreateResponse> {
2930
+ public static reconciliationControllerPad(
2931
+ data: ReconciliationControllerPadData
2932
+ ): CancelablePromise<ReconciliationControllerPadResponse> {
2664
2933
  return __request(OpenAPI, {
2665
2934
  method: 'POST',
2666
- url: '/api/v1/bean/platforms',
2935
+ url: '/api/v1/{region}/bean/reconciliations/pad',
2936
+ path: {
2937
+ region: data.region
2938
+ },
2667
2939
  body: data.requestBody,
2668
2940
  mediaType: 'application/json',
2669
2941
  errors: {
2670
- 409: 'Platform already exists'
2942
+ 400: 'Book already within tolerance — no pad needed',
2943
+ 404: 'Account not found'
2671
2944
  }
2672
2945
  });
2673
2946
  }
2674
2947
 
2675
2948
  /**
2676
- * Get platform list for current user
2677
- * @returns unknown List of platforms with user binding status
2949
+ * List reconciliation history for an account
2950
+ * Returns recorded balance assertions (most recent first). The latest drives the account-detail "Last <date>" badge.
2951
+ * @param data The data for the request.
2952
+ * @param data.accountId BeanAccount id
2953
+ * @param data.region Region code for tenant context (decorative for reconciliation)
2954
+ * @returns ReconciliationRecordDto Reconciliation history
2678
2955
  * @throws ApiError
2679
2956
  */
2680
- public static platformControllerGetPlatformList(): CancelablePromise<PlatformControllerGetPlatformListResponse> {
2957
+ public static reconciliationControllerHistory(
2958
+ data: ReconciliationControllerHistoryData
2959
+ ): CancelablePromise<ReconciliationControllerHistoryResponse> {
2681
2960
  return __request(OpenAPI, {
2682
2961
  method: 'GET',
2683
- url: '/api/v1/bean/platforms/list'
2962
+ url: '/api/v1/{region}/bean/accounts/{accountId}/reconciliations',
2963
+ path: {
2964
+ accountId: data.accountId,
2965
+ region: data.region
2966
+ },
2967
+ errors: {
2968
+ 404: 'Account not found'
2969
+ }
2684
2970
  });
2685
2971
  }
2972
+ }
2686
2973
 
2974
+ export class BeanExportService {
2687
2975
  /**
2688
- * Match platforms by name or alias
2976
+ * Export Beancount ledger as ZIP
2977
+ * Export all user Beancount data as a ZIP file containing ledger.beancount and yearly files in community format.
2978
+ * @returns unknown
2979
+ * @throws ApiError
2980
+ */
2981
+ public static exportControllerExportBeancount(): CancelablePromise<ExportControllerExportBeancountResponse> {
2982
+ return __request(OpenAPI, {
2983
+ method: 'GET',
2984
+ url: '/api/v1/{region}/bean/export/beancount'
2985
+ });
2986
+ }
2987
+ }
2988
+
2989
+ export class BeanImportService {
2990
+ /**
2991
+ * Import a bill file
2992
+ * Upload and process a bill file (CSV, PDF, OFX, etc.). The system automatically identifies the file type, extracts transactions, validates them, and stores only validated transactions to the database. Maximum file size: 50MB. Only 1 import per user at a time (concurrent imports rejected with 429).
2689
2993
  * @param data The data for the request.
2690
- * @param data.q Search query Chinese name, English name, or abbreviation
2691
- * @param data.region Region code for category override lookup
2692
- * @returns unknown List of matching platforms with suggested segment names
2994
+ * @param data.region Region code for tenant context
2995
+ * @param data.formData Bill file to import
2996
+ * @returns ImportResultDto File imported successfully
2693
2997
  * @throws ApiError
2694
2998
  */
2695
- public static platformControllerMatchPlatforms(
2696
- data: PlatformControllerMatchPlatformsData
2697
- ): CancelablePromise<PlatformControllerMatchPlatformsResponse> {
2999
+ public static fileImportControllerImportFile(
3000
+ data: FileImportControllerImportFileData
3001
+ ): CancelablePromise<FileImportControllerImportFileResponse> {
3002
+ return __request(OpenAPI, {
3003
+ method: 'POST',
3004
+ url: '/api/v1/{region}/bean/import/file',
3005
+ path: {
3006
+ region: data.region
3007
+ },
3008
+ formData: data.formData,
3009
+ mediaType: 'multipart/form-data',
3010
+ errors: {
3011
+ 400: 'Bad request - file-format-unsupported or file-import-failed',
3012
+ 413: 'Payload too large - file exceeds 50MB limit',
3013
+ 429: 'Too many requests - user already has import in progress',
3014
+ 500: 'Internal server error - DATABASE_ERROR'
3015
+ }
3016
+ });
3017
+ }
3018
+
3019
+ /**
3020
+ * Identify file type
3021
+ * Upload a file to check if it can be processed by any registered importer. Does not perform actual import - useful for pre-validation. Uses user-specific importer configuration.
3022
+ * @param data The data for the request.
3023
+ * @param data.region Region code for tenant context
3024
+ * @param data.formData File to identify
3025
+ * @returns IdentifyResultDto File identification result
3026
+ * @throws ApiError
3027
+ */
3028
+ public static fileImportControllerIdentifyFile(
3029
+ data: FileImportControllerIdentifyFileData
3030
+ ): CancelablePromise<FileImportControllerIdentifyFileResponse> {
3031
+ return __request(OpenAPI, {
3032
+ method: 'POST',
3033
+ url: '/api/v1/{region}/bean/import/identify',
3034
+ path: {
3035
+ region: data.region
3036
+ },
3037
+ formData: data.formData,
3038
+ mediaType: 'multipart/form-data',
3039
+ errors: {
3040
+ 400: 'Bad request - No file uploaded'
3041
+ }
3042
+ });
3043
+ }
3044
+
3045
+ /**
3046
+ * Import a Beancount file in community format
3047
+ * Upload a .beancount file to import. The system parses community-format paths, converts to internal format using category metadata, auto-creates accounts, and imports transactions with deduplication. Maximum file size: 50MB. Only 1 import per user at a time.
3048
+ * @param data The data for the request.
3049
+ * @param data.region Region code for tenant context
3050
+ * @param data.formData Beancount file to import
3051
+ * @returns unknown Beancount file imported successfully
3052
+ * @throws ApiError
3053
+ */
3054
+ public static fileImportControllerImportBeancount(
3055
+ data: FileImportControllerImportBeancountData
3056
+ ): CancelablePromise<FileImportControllerImportBeancountResponse> {
3057
+ return __request(OpenAPI, {
3058
+ method: 'POST',
3059
+ url: '/api/v1/{region}/bean/import/beancount',
3060
+ path: {
3061
+ region: data.region
3062
+ },
3063
+ formData: data.formData,
3064
+ mediaType: 'multipart/form-data',
3065
+ errors: {
3066
+ 400: 'Bad request - invalid file or no file uploaded'
3067
+ }
3068
+ });
3069
+ }
3070
+
3071
+ /**
3072
+ * Get importer configuration
3073
+ * Returns the current configuration for the specified importer. Creates default configuration if none exists.
3074
+ * @param data The data for the request.
3075
+ * @param data.importerId Importer identifier. Supported importers: alipay, alipay-web, wechat, boc, boc-credit, ccb, cmb, cmbc, cmbc-credit, icbc, icbc-credit, hsbc-hk-credit, hsbc-hk-debit
3076
+ * @param data.region Region code for tenant context
3077
+ * @returns ImporterConfigDto Configuration retrieved successfully
3078
+ * @throws ApiError
3079
+ */
3080
+ public static importerConfigControllerGetConfig(
3081
+ data: ImporterConfigControllerGetConfigData
3082
+ ): CancelablePromise<ImporterConfigControllerGetConfigResponse> {
2698
3083
  return __request(OpenAPI, {
2699
3084
  method: 'GET',
2700
- url: '/api/v1/bean/platforms/match',
2701
- query: {
2702
- q: data.q,
3085
+ url: '/api/v1/{region}/bean/import/config/{importerId}',
3086
+ path: {
3087
+ importerId: data.importerId,
2703
3088
  region: data.region
3089
+ },
3090
+ errors: {
3091
+ 400: 'Invalid input - Unsupported importer',
3092
+ 401: 'Unauthorized - Authentication required'
2704
3093
  }
2705
3094
  });
2706
3095
  }
2707
3096
 
2708
3097
  /**
2709
- * Update a platform
3098
+ * Update importer configuration
3099
+ * Updates the configuration for the specified importer. Partial updates are supported.
2710
3100
  * @param data The data for the request.
2711
- * @param data.id Platform ID
2712
- * @param data.requestBody
2713
- * @returns unknown Platform updated successfully
3101
+ * @param data.importerId Importer identifier. Supported importers: alipay, alipay-web, wechat, boc, boc-credit, ccb, cmb, cmbc, cmbc-credit, icbc, icbc-credit, hsbc-hk-credit, hsbc-hk-debit
3102
+ * @param data.region Region code for tenant context
3103
+ * @param data.requestBody Partial configuration update. Only provided fields will be updated.
3104
+ * @returns ImporterConfigDto Configuration updated successfully
2714
3105
  * @throws ApiError
2715
3106
  */
2716
- public static platformControllerUpdate(
2717
- data: PlatformControllerUpdateData
2718
- ): CancelablePromise<PlatformControllerUpdateResponse> {
3107
+ public static importerConfigControllerUpdateConfig(
3108
+ data: ImporterConfigControllerUpdateConfigData
3109
+ ): CancelablePromise<ImporterConfigControllerUpdateConfigResponse> {
2719
3110
  return __request(OpenAPI, {
2720
3111
  method: 'PUT',
2721
- url: '/api/v1/bean/platforms/{id}',
3112
+ url: '/api/v1/{region}/bean/import/config/{importerId}',
2722
3113
  path: {
2723
- id: data.id
3114
+ importerId: data.importerId,
3115
+ region: data.region
2724
3116
  },
2725
3117
  body: data.requestBody,
2726
3118
  mediaType: 'application/json',
2727
3119
  errors: {
2728
- 404: 'Platform not found'
3120
+ 400: 'Invalid input - Validation failed',
3121
+ 404: 'Configuration not found'
2729
3122
  }
2730
3123
  });
2731
3124
  }
2732
3125
 
2733
3126
  /**
2734
- * Delete a platform
3127
+ * Reset configuration to default
3128
+ * Resets the configuration for the specified importer to default values. This operation overwrites all existing configuration.
2735
3129
  * @param data The data for the request.
2736
- * @param data.id Platform ID
2737
- * @returns void Platform deleted successfully
3130
+ * @param data.importerId Importer identifier. Supported importers: alipay, alipay-web, wechat, boc, boc-credit, ccb, cmb, cmbc, cmbc-credit, icbc, icbc-credit, hsbc-hk-credit, hsbc-hk-debit
3131
+ * @param data.region Region code for tenant context
3132
+ * @returns ImporterConfigDto Configuration reset successfully
2738
3133
  * @throws ApiError
2739
3134
  */
2740
- public static platformControllerDelete(
2741
- data: PlatformControllerDeleteData
2742
- ): CancelablePromise<PlatformControllerDeleteResponse> {
3135
+ public static importerConfigControllerResetConfig(
3136
+ data: ImporterConfigControllerResetConfigData
3137
+ ): CancelablePromise<ImporterConfigControllerResetConfigResponse> {
2743
3138
  return __request(OpenAPI, {
2744
- method: 'DELETE',
2745
- url: '/api/v1/bean/platforms/{id}',
3139
+ method: 'POST',
3140
+ url: '/api/v1/{region}/bean/import/config/{importerId}/reset',
2746
3141
  path: {
2747
- id: data.id
3142
+ importerId: data.importerId,
3143
+ region: data.region
2748
3144
  },
2749
3145
  errors: {
2750
- 404: 'Platform not found'
3146
+ 400: 'Invalid input - Unsupported importer'
2751
3147
  }
2752
3148
  });
2753
3149
  }
@@ -2853,6 +3249,101 @@ export class ProviderSyncService {
2853
3249
  }
2854
3250
  }
2855
3251
 
3252
+ export class ExternalAccountLinksService {
3253
+ /**
3254
+ * Create an external account → BeanAccount mapping (ADR-0113)
3255
+ * @param data The data for the request.
3256
+ * @param data.region Region code for tenant context
3257
+ * @param data.requestBody
3258
+ * @returns ExternalAccountLinkResponseDto Link created.
3259
+ * @throws ApiError
3260
+ */
3261
+ public static externalAccountLinkControllerCreate(
3262
+ data: ExternalAccountLinkControllerCreateData
3263
+ ): CancelablePromise<ExternalAccountLinkControllerCreateResponse> {
3264
+ return __request(OpenAPI, {
3265
+ method: 'POST',
3266
+ url: '/api/v1/{region}/bean/external-account-links',
3267
+ path: {
3268
+ region: data.region
3269
+ },
3270
+ body: data.requestBody,
3271
+ mediaType: 'application/json',
3272
+ errors: {
3273
+ 422: 'beanAccountId not owned, or an active link already exists.'
3274
+ }
3275
+ });
3276
+ }
3277
+
3278
+ /**
3279
+ * List the user's active external account links
3280
+ * @param data The data for the request.
3281
+ * @param data.provider
3282
+ * @param data.region Region code for tenant context
3283
+ * @returns ExternalAccountLinkListResponseDto Links retrieved.
3284
+ * @throws ApiError
3285
+ */
3286
+ public static externalAccountLinkControllerFindAll(
3287
+ data: ExternalAccountLinkControllerFindAllData
3288
+ ): CancelablePromise<ExternalAccountLinkControllerFindAllResponse> {
3289
+ return __request(OpenAPI, {
3290
+ method: 'GET',
3291
+ url: '/api/v1/{region}/bean/external-account-links',
3292
+ path: {
3293
+ region: data.region
3294
+ },
3295
+ query: {
3296
+ provider: data.provider
3297
+ }
3298
+ });
3299
+ }
3300
+
3301
+ /**
3302
+ * Get a single external account link
3303
+ * @param data The data for the request.
3304
+ * @param data.id
3305
+ * @param data.region Region code for tenant context
3306
+ * @returns ExternalAccountLinkResponseDto Link retrieved.
3307
+ * @throws ApiError
3308
+ */
3309
+ public static externalAccountLinkControllerFindOne(
3310
+ data: ExternalAccountLinkControllerFindOneData
3311
+ ): CancelablePromise<ExternalAccountLinkControllerFindOneResponse> {
3312
+ return __request(OpenAPI, {
3313
+ method: 'GET',
3314
+ url: '/api/v1/{region}/bean/external-account-links/{id}',
3315
+ path: {
3316
+ id: data.id,
3317
+ region: data.region
3318
+ },
3319
+ errors: {
3320
+ 422: 'Link not found or not owned by the user.'
3321
+ }
3322
+ });
3323
+ }
3324
+
3325
+ /**
3326
+ * Soft-delete (disconnect) an external account link
3327
+ * @param data The data for the request.
3328
+ * @param data.id
3329
+ * @param data.region Region code for tenant context
3330
+ * @returns void Link soft-deleted; historical transactions are unaffected.
3331
+ * @throws ApiError
3332
+ */
3333
+ public static externalAccountLinkControllerRemove(
3334
+ data: ExternalAccountLinkControllerRemoveData
3335
+ ): CancelablePromise<ExternalAccountLinkControllerRemoveResponse> {
3336
+ return __request(OpenAPI, {
3337
+ method: 'DELETE',
3338
+ url: '/api/v1/{region}/bean/external-account-links/{id}',
3339
+ path: {
3340
+ id: data.id,
3341
+ region: data.region
3342
+ }
3343
+ });
3344
+ }
3345
+ }
3346
+
2856
3347
  export class ImportTelemetryService {
2857
3348
  /**
2858
3349
  * Receive anonymous parser failure telemetry
@@ -2965,47 +3456,162 @@ export class BeanNlpService {
2965
3456
  * @returns void Session cleared successfully
2966
3457
  * @throws ApiError
2967
3458
  */
2968
- public static nlpControllerClearSession(
2969
- data: NlpControllerClearSessionData
2970
- ): CancelablePromise<NlpControllerClearSessionResponse> {
3459
+ public static nlpControllerClearSession(
3460
+ data: NlpControllerClearSessionData
3461
+ ): CancelablePromise<NlpControllerClearSessionResponse> {
3462
+ return __request(OpenAPI, {
3463
+ method: 'DELETE',
3464
+ url: '/api/v1/{region}/bean/nlp/session',
3465
+ path: {
3466
+ region: data.region
3467
+ },
3468
+ query: {
3469
+ sessionId: data.sessionId
3470
+ },
3471
+ errors: {
3472
+ 401: 'Unauthorized'
3473
+ }
3474
+ });
3475
+ }
3476
+
3477
+ /**
3478
+ * Get current session state
3479
+ * Get the current NLP dialogue session state. Useful for debugging and displaying session context in UI.
3480
+ * @param data The data for the request.
3481
+ * @param data.region Region code for tenant context
3482
+ * @param data.sessionId Specific session ID to get (defaults to user session)
3483
+ * @returns unknown Current session state (or null if no active session)
3484
+ * @throws ApiError
3485
+ */
3486
+ public static nlpControllerGetSession(
3487
+ data: NlpControllerGetSessionData
3488
+ ): CancelablePromise<NlpControllerGetSessionResponse> {
3489
+ return __request(OpenAPI, {
3490
+ method: 'GET',
3491
+ url: '/api/v1/{region}/bean/nlp/session',
3492
+ path: {
3493
+ region: data.region
3494
+ },
3495
+ query: {
3496
+ sessionId: data.sessionId
3497
+ },
3498
+ errors: {
3499
+ 401: 'Unauthorized'
3500
+ }
3501
+ });
3502
+ }
3503
+ }
3504
+
3505
+ export class BeanPlatformsService {
3506
+ /**
3507
+ * Get all platforms with statistics
3508
+ * @returns unknown List of platforms with binding and account counts
3509
+ * @throws ApiError
3510
+ */
3511
+ public static platformControllerFindAll(): CancelablePromise<PlatformControllerFindAllResponse> {
3512
+ return __request(OpenAPI, {
3513
+ method: 'GET',
3514
+ url: '/api/v1/bean/platforms'
3515
+ });
3516
+ }
3517
+
3518
+ /**
3519
+ * Create a new platform
3520
+ * @param data The data for the request.
3521
+ * @param data.requestBody
3522
+ * @returns unknown Platform created successfully
3523
+ * @throws ApiError
3524
+ */
3525
+ public static platformControllerCreate(
3526
+ data: PlatformControllerCreateData
3527
+ ): CancelablePromise<PlatformControllerCreateResponse> {
3528
+ return __request(OpenAPI, {
3529
+ method: 'POST',
3530
+ url: '/api/v1/bean/platforms',
3531
+ body: data.requestBody,
3532
+ mediaType: 'application/json',
3533
+ errors: {
3534
+ 409: 'Platform already exists'
3535
+ }
3536
+ });
3537
+ }
3538
+
3539
+ /**
3540
+ * Get platform list for current user
3541
+ * @returns unknown List of platforms with user binding status
3542
+ * @throws ApiError
3543
+ */
3544
+ public static platformControllerGetPlatformList(): CancelablePromise<PlatformControllerGetPlatformListResponse> {
3545
+ return __request(OpenAPI, {
3546
+ method: 'GET',
3547
+ url: '/api/v1/bean/platforms/list'
3548
+ });
3549
+ }
3550
+
3551
+ /**
3552
+ * Match platforms by name or alias
3553
+ * @param data The data for the request.
3554
+ * @param data.q Search query — Chinese name, English name, or abbreviation
3555
+ * @param data.region Region code for category override lookup
3556
+ * @returns unknown List of matching platforms with suggested segment names
3557
+ * @throws ApiError
3558
+ */
3559
+ public static platformControllerMatchPlatforms(
3560
+ data: PlatformControllerMatchPlatformsData
3561
+ ): CancelablePromise<PlatformControllerMatchPlatformsResponse> {
3562
+ return __request(OpenAPI, {
3563
+ method: 'GET',
3564
+ url: '/api/v1/bean/platforms/match',
3565
+ query: {
3566
+ q: data.q,
3567
+ region: data.region
3568
+ }
3569
+ });
3570
+ }
3571
+
3572
+ /**
3573
+ * Update a platform
3574
+ * @param data The data for the request.
3575
+ * @param data.id Platform ID
3576
+ * @param data.requestBody
3577
+ * @returns unknown Platform updated successfully
3578
+ * @throws ApiError
3579
+ */
3580
+ public static platformControllerUpdate(
3581
+ data: PlatformControllerUpdateData
3582
+ ): CancelablePromise<PlatformControllerUpdateResponse> {
2971
3583
  return __request(OpenAPI, {
2972
- method: 'DELETE',
2973
- url: '/api/v1/{region}/bean/nlp/session',
3584
+ method: 'PUT',
3585
+ url: '/api/v1/bean/platforms/{id}',
2974
3586
  path: {
2975
- region: data.region
2976
- },
2977
- query: {
2978
- sessionId: data.sessionId
3587
+ id: data.id
2979
3588
  },
3589
+ body: data.requestBody,
3590
+ mediaType: 'application/json',
2980
3591
  errors: {
2981
- 401: 'Unauthorized'
3592
+ 404: 'Platform not found'
2982
3593
  }
2983
3594
  });
2984
3595
  }
2985
3596
 
2986
3597
  /**
2987
- * Get current session state
2988
- * Get the current NLP dialogue session state. Useful for debugging and displaying session context in UI.
3598
+ * Delete a platform
2989
3599
  * @param data The data for the request.
2990
- * @param data.region Region code for tenant context
2991
- * @param data.sessionId Specific session ID to get (defaults to user session)
2992
- * @returns unknown Current session state (or null if no active session)
3600
+ * @param data.id Platform ID
3601
+ * @returns void Platform deleted successfully
2993
3602
  * @throws ApiError
2994
3603
  */
2995
- public static nlpControllerGetSession(
2996
- data: NlpControllerGetSessionData
2997
- ): CancelablePromise<NlpControllerGetSessionResponse> {
3604
+ public static platformControllerDelete(
3605
+ data: PlatformControllerDeleteData
3606
+ ): CancelablePromise<PlatformControllerDeleteResponse> {
2998
3607
  return __request(OpenAPI, {
2999
- method: 'GET',
3000
- url: '/api/v1/{region}/bean/nlp/session',
3608
+ method: 'DELETE',
3609
+ url: '/api/v1/bean/platforms/{id}',
3001
3610
  path: {
3002
- region: data.region
3003
- },
3004
- query: {
3005
- sessionId: data.sessionId
3611
+ id: data.id
3006
3612
  },
3007
3613
  errors: {
3008
- 401: 'Unauthorized'
3614
+ 404: 'Platform not found'
3009
3615
  }
3010
3616
  });
3011
3617
  }
@@ -3097,207 +3703,72 @@ export class DashboardService {
3097
3703
  }
3098
3704
  });
3099
3705
  }
3100
- }
3101
3706
 
3102
- export class InvestmentService {
3103
3707
  /**
3104
- * Get per-holding unrealized + realized P&L
3105
- * Average-cost unrealized P&L per account × commodity, plus cumulative realized P&L on sold lots (method = FIFO | average, default average).
3708
+ * Get expenses/income grouped by functional category
3709
+ * Returns amounts pre-aggregated by functional category (account-path Group segment) with server-side multi-currency conversion. flow=expense (default) aggregates ^Expenses: accounts; flow=income aggregates ^Income: accounts (issue #518)
3106
3710
  * @param data The data for the request.
3107
3711
  * @param data.region Region code for tenant context
3108
- * @param data.asOf As-of date (ISO 8601), defaults to today
3109
- * @param data.accountId Scope to a single account
3110
- * @param data.method Realized-P&L lot-matching method (default average). Does not affect the average-cost unrealized basis.
3111
- * @returns HoldingPnlResponseDto Holding P&L retrieved successfully
3712
+ * @param data.groupBy Grouping strategy
3713
+ * @param data.period Time window (1m = current calendar month)
3714
+ * @param data.flow Account root to aggregate (expense ^Expenses:, income ^Income:)
3715
+ * @returns ExpensesByCategoryResponseDto Expenses retrieved successfully
3112
3716
  * @throws ApiError
3113
3717
  */
3114
- public static holdingPnlControllerGetHoldingPnl(
3115
- data: HoldingPnlControllerGetHoldingPnlData
3116
- ): CancelablePromise<HoldingPnlControllerGetHoldingPnlResponse> {
3718
+ public static dashboardControllerGetExpenses(
3719
+ data: DashboardControllerGetExpensesData
3720
+ ): CancelablePromise<DashboardControllerGetExpensesResponse> {
3117
3721
  return __request(OpenAPI, {
3118
3722
  method: 'GET',
3119
- url: '/api/v1/{region}/investment/holdings/pnl',
3723
+ url: '/api/v1/{region}/dashboard/expenses',
3120
3724
  path: {
3121
3725
  region: data.region
3122
3726
  },
3123
3727
  query: {
3124
- asOf: data.asOf,
3125
- accountId: data.accountId,
3126
- method: data.method
3728
+ groupBy: data.groupBy,
3729
+ period: data.period,
3730
+ flow: data.flow
3127
3731
  },
3128
3732
  errors: {
3129
- 400: 'Invalid asOf format/value/future date, invalid accountId format, or unsupported method',
3733
+ 400: 'Invalid groupBy or period',
3130
3734
  401: 'User not authenticated'
3131
3735
  }
3132
3736
  });
3133
3737
  }
3134
3738
  }
3135
3739
 
3136
- export class BeanPricesService {
3137
- /**
3138
- * Create a new price
3139
- * Creates a new price entry for the authenticated user
3140
- * @param data The data for the request.
3141
- * @param data.region Region code for tenant context
3142
- * @param data.requestBody
3143
- * @returns PriceResponseDto Price created successfully
3144
- * @throws ApiError
3145
- */
3146
- public static priceControllerCreate(
3147
- data: PriceControllerCreateData
3148
- ): CancelablePromise<PriceControllerCreateResponse> {
3149
- return __request(OpenAPI, {
3150
- method: 'POST',
3151
- url: '/api/v1/{region}/bean/prices',
3152
- path: {
3153
- region: data.region
3154
- },
3155
- body: data.requestBody,
3156
- mediaType: 'application/json',
3157
- errors: {
3158
- 404: 'Currency or quoteCurrency commodity not found',
3159
- 409: 'Price already exists for this currency pair and date'
3160
- }
3161
- });
3162
- }
3163
-
3740
+ export class InvestmentService {
3164
3741
  /**
3165
- * List user prices
3166
- * Returns all price entries for the authenticated user with optional filtering
3742
+ * Get per-holding unrealized + realized P&L
3743
+ * Average-cost unrealized P&L per account × commodity, plus cumulative realized P&L on sold lots (method = FIFO | average, default average).
3167
3744
  * @param data The data for the request.
3168
3745
  * @param data.region Region code for tenant context
3169
- * @param data.currency Filter by currency (e.g., BTC, AAPL, USD)
3170
- * @param data.quoteCurrency Filter by quote currency (pricing currency, e.g., USD, CNY)
3171
- * @param data.dateFrom Filter prices from this date (ISO 8601 format)
3172
- * @param data.dateTo Filter prices to this date (ISO 8601 format)
3173
- * @param data.search Search term for currency or quoteCurrency (case-insensitive partial match)
3174
- * @param data.page Page number for pagination (default: 1)
3175
- * @param data.limit Number of items per page (default: 20, max: 100)
3176
- * @returns PriceListResponseDto Prices retrieved successfully
3746
+ * @param data.asOf As-of date (ISO 8601), defaults to today
3747
+ * @param data.accountId Scope to a single account
3748
+ * @param data.method Realized-P&L lot-matching method (default average). Does not affect the average-cost unrealized basis.
3749
+ * @returns HoldingPnlResponseDto Holding P&L retrieved successfully
3177
3750
  * @throws ApiError
3178
3751
  */
3179
- public static priceControllerFindAll(
3180
- data: PriceControllerFindAllData
3181
- ): CancelablePromise<PriceControllerFindAllResponse> {
3752
+ public static holdingPnlControllerGetHoldingPnl(
3753
+ data: HoldingPnlControllerGetHoldingPnlData
3754
+ ): CancelablePromise<HoldingPnlControllerGetHoldingPnlResponse> {
3182
3755
  return __request(OpenAPI, {
3183
3756
  method: 'GET',
3184
- url: '/api/v1/{region}/bean/prices',
3757
+ url: '/api/v1/{region}/investment/holdings/pnl',
3185
3758
  path: {
3186
3759
  region: data.region
3187
3760
  },
3188
3761
  query: {
3189
- currency: data.currency,
3190
- quoteCurrency: data.quoteCurrency,
3191
- dateFrom: data.dateFrom,
3192
- dateTo: data.dateTo,
3193
- search: data.search,
3194
- page: data.page,
3195
- limit: data.limit
3196
- }
3197
- });
3198
- }
3199
-
3200
- /**
3201
- * Get price by ID
3202
- * Returns a single price entry by its ID
3203
- * @param data The data for the request.
3204
- * @param data.id Price ID
3205
- * @param data.region Region code for tenant context
3206
- * @returns PriceResponseDto Price retrieved successfully
3207
- * @throws ApiError
3208
- */
3209
- public static priceControllerFindOne(
3210
- data: PriceControllerFindOneData
3211
- ): CancelablePromise<PriceControllerFindOneResponse> {
3212
- return __request(OpenAPI, {
3213
- method: 'GET',
3214
- url: '/api/v1/{region}/bean/prices/{id}',
3215
- path: {
3216
- id: data.id,
3217
- region: data.region
3218
- },
3219
- errors: {
3220
- 404: 'Price not found'
3221
- }
3222
- });
3223
- }
3224
-
3225
- /**
3226
- * Update a price
3227
- * Updates an existing price entry
3228
- * @param data The data for the request.
3229
- * @param data.id Price ID
3230
- * @param data.region Region code for tenant context
3231
- * @param data.requestBody
3232
- * @returns PriceResponseDto Price updated successfully
3233
- * @throws ApiError
3234
- */
3235
- public static priceControllerUpdate(
3236
- data: PriceControllerUpdateData
3237
- ): CancelablePromise<PriceControllerUpdateResponse> {
3238
- return __request(OpenAPI, {
3239
- method: 'PUT',
3240
- url: '/api/v1/{region}/bean/prices/{id}',
3241
- path: {
3242
- id: data.id,
3243
- region: data.region
3244
- },
3245
- body: data.requestBody,
3246
- mediaType: 'application/json',
3247
- errors: {
3248
- 404: 'Price not found',
3249
- 409: 'Updated price conflicts with existing price'
3250
- }
3251
- });
3252
- }
3253
-
3254
- /**
3255
- * Delete a price
3256
- * Deletes a price entry (hard delete)
3257
- * @param data The data for the request.
3258
- * @param data.id Price ID
3259
- * @param data.region Region code for tenant context
3260
- * @returns void Price deleted successfully
3261
- * @throws ApiError
3262
- */
3263
- public static priceControllerDelete(
3264
- data: PriceControllerDeleteData
3265
- ): CancelablePromise<PriceControllerDeleteResponse> {
3266
- return __request(OpenAPI, {
3267
- method: 'DELETE',
3268
- url: '/api/v1/{region}/bean/prices/{id}',
3269
- path: {
3270
- id: data.id,
3271
- region: data.region
3762
+ asOf: data.asOf,
3763
+ accountId: data.accountId,
3764
+ method: data.method
3272
3765
  },
3273
3766
  errors: {
3274
- 404: 'Price not found'
3767
+ 400: 'Invalid asOf format/value/future date, invalid accountId format, or unsupported method',
3768
+ 401: 'User not authenticated'
3275
3769
  }
3276
3770
  });
3277
3771
  }
3278
-
3279
- /**
3280
- * Bulk create prices
3281
- * Creates multiple price entries at once (skips duplicates)
3282
- * @param data The data for the request.
3283
- * @param data.region Region code for tenant context
3284
- * @param data.requestBody
3285
- * @returns PriceResponseDto Prices created successfully
3286
- * @throws ApiError
3287
- */
3288
- public static priceControllerBulkCreate(
3289
- data: PriceControllerBulkCreateData
3290
- ): CancelablePromise<PriceControllerBulkCreateResponse> {
3291
- return __request(OpenAPI, {
3292
- method: 'POST',
3293
- url: '/api/v1/{region}/bean/prices/bulk',
3294
- path: {
3295
- region: data.region
3296
- },
3297
- body: data.requestBody,
3298
- mediaType: 'application/json'
3299
- });
3300
- }
3301
3772
  }
3302
3773
 
3303
3774
  export class ReportingService {
@@ -3341,6 +3812,42 @@ export class ReportingService {
3341
3812
  });
3342
3813
  }
3343
3814
 
3815
+ /**
3816
+ * Get cash-flow trends
3817
+ *
3818
+ * Monthly income / expense / netSavings over a fixed N-month window
3819
+ * (current month + N−1 prior). Missing months are zero-filled (flow metric).
3820
+ *
3821
+ * **Parameters:**
3822
+ * - `period`: 1m | 3m | 6m | 1y (default 6m)
3823
+ * - `granularity`: accepted for API symmetry; v1 returns month buckets
3824
+ *
3825
+ * @param data The data for the request.
3826
+ * @param data.region Region code for tenant context
3827
+ * @param data.period Time period
3828
+ * @param data.granularity Data granularity (accepted for API symmetry; v1 returns month buckets)
3829
+ * @returns CashFlowTrendsResponseDto Cash-flow trends retrieved successfully
3830
+ * @throws ApiError
3831
+ */
3832
+ public static reportingControllerGetCashFlowTrends(
3833
+ data: ReportingControllerGetCashFlowTrendsData
3834
+ ): CancelablePromise<ReportingControllerGetCashFlowTrendsResponse> {
3835
+ return __request(OpenAPI, {
3836
+ method: 'GET',
3837
+ url: '/api/v1/{region}/reporting/cash-flow/trends',
3838
+ path: {
3839
+ region: data.region
3840
+ },
3841
+ query: {
3842
+ period: data.period,
3843
+ granularity: data.granularity
3844
+ },
3845
+ errors: {
3846
+ 401: 'User not authenticated'
3847
+ }
3848
+ });
3849
+ }
3850
+
3344
3851
  /**
3345
3852
  * Generate portfolio snapshot
3346
3853
  *