@hasna/treasury 0.1.2

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.
Files changed (110) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +85 -0
  3. package/dist/adapters/fixtures.d.ts +31 -0
  4. package/dist/adapters/fixtures.d.ts.map +1 -0
  5. package/dist/adapters/types.d.ts +42 -0
  6. package/dist/adapters/types.d.ts.map +1 -0
  7. package/dist/api/index.d.ts +37 -0
  8. package/dist/api/index.d.ts.map +1 -0
  9. package/dist/cli/context.d.ts +9 -0
  10. package/dist/cli/context.d.ts.map +1 -0
  11. package/dist/cli/dashboard.d.ts +5 -0
  12. package/dist/cli/dashboard.d.ts.map +1 -0
  13. package/dist/cli/index.d.ts +3 -0
  14. package/dist/cli/index.d.ts.map +1 -0
  15. package/dist/cli/index.js +4353 -0
  16. package/dist/cli/namespaces.d.ts +7 -0
  17. package/dist/cli/namespaces.d.ts.map +1 -0
  18. package/dist/config.d.ts +42 -0
  19. package/dist/config.d.ts.map +1 -0
  20. package/dist/core/app-home.d.ts +9 -0
  21. package/dist/core/app-home.d.ts.map +1 -0
  22. package/dist/core/errors.d.ts +8 -0
  23. package/dist/core/errors.d.ts.map +1 -0
  24. package/dist/db/audit.d.ts +16 -0
  25. package/dist/db/audit.d.ts.map +1 -0
  26. package/dist/db/backup.d.ts +14 -0
  27. package/dist/db/backup.d.ts.map +1 -0
  28. package/dist/db/database.d.ts +40 -0
  29. package/dist/db/database.d.ts.map +1 -0
  30. package/dist/db/migration-plan.d.ts +14 -0
  31. package/dist/db/migration-plan.d.ts.map +1 -0
  32. package/dist/db/schema.d.ts +8 -0
  33. package/dist/db/schema.d.ts.map +1 -0
  34. package/dist/generated/storage-kit/health.d.ts +20 -0
  35. package/dist/generated/storage-kit/health.d.ts.map +1 -0
  36. package/dist/generated/storage-kit/index.d.ts +8 -0
  37. package/dist/generated/storage-kit/index.d.ts.map +1 -0
  38. package/dist/generated/storage-kit/migrations.d.ts +48 -0
  39. package/dist/generated/storage-kit/migrations.d.ts.map +1 -0
  40. package/dist/generated/storage-kit/mode.d.ts +48 -0
  41. package/dist/generated/storage-kit/mode.d.ts.map +1 -0
  42. package/dist/generated/storage-kit/pool.d.ts +34 -0
  43. package/dist/generated/storage-kit/pool.d.ts.map +1 -0
  44. package/dist/generated/storage-kit/query.d.ts +36 -0
  45. package/dist/generated/storage-kit/query.d.ts.map +1 -0
  46. package/dist/generated/storage-kit/tls.d.ts +26 -0
  47. package/dist/generated/storage-kit/tls.d.ts.map +1 -0
  48. package/dist/index.d.ts +22 -0
  49. package/dist/index.d.ts.map +1 -0
  50. package/dist/index.js +23773 -0
  51. package/dist/mcp/compact.d.ts +12 -0
  52. package/dist/mcp/compact.d.ts.map +1 -0
  53. package/dist/mcp/http.d.ts +38 -0
  54. package/dist/mcp/http.d.ts.map +1 -0
  55. package/dist/mcp/index.d.ts +32 -0
  56. package/dist/mcp/index.d.ts.map +1 -0
  57. package/dist/mcp/index.js +6243 -0
  58. package/dist/mcp/tools/domain.d.ts +10 -0
  59. package/dist/mcp/tools/domain.d.ts.map +1 -0
  60. package/dist/mcp/tools/standard.d.ts +4 -0
  61. package/dist/mcp/tools/standard.d.ts.map +1 -0
  62. package/dist/mcp/tools/storage.d.ts +4 -0
  63. package/dist/mcp/tools/storage.d.ts.map +1 -0
  64. package/dist/release/package-smoke.d.ts +11 -0
  65. package/dist/release/package-smoke.d.ts.map +1 -0
  66. package/dist/server/app.d.ts +19 -0
  67. package/dist/server/app.d.ts.map +1 -0
  68. package/dist/server/auth-constants.d.ts +22 -0
  69. package/dist/server/auth-constants.d.ts.map +1 -0
  70. package/dist/server/auth.d.ts +147 -0
  71. package/dist/server/auth.d.ts.map +1 -0
  72. package/dist/server/health.d.ts +23 -0
  73. package/dist/server/health.d.ts.map +1 -0
  74. package/dist/server/index.d.ts +11 -0
  75. package/dist/server/index.d.ts.map +1 -0
  76. package/dist/server/index.js +2094 -0
  77. package/dist/server/list-query.d.ts +7 -0
  78. package/dist/server/list-query.d.ts.map +1 -0
  79. package/dist/services/authorization-constants.d.ts +14 -0
  80. package/dist/services/authorization-constants.d.ts.map +1 -0
  81. package/dist/services/authorization.d.ts +95 -0
  82. package/dist/services/authorization.d.ts.map +1 -0
  83. package/dist/services/balances.d.ts +33 -0
  84. package/dist/services/balances.d.ts.map +1 -0
  85. package/dist/services/context.d.ts +24 -0
  86. package/dist/services/context.d.ts.map +1 -0
  87. package/dist/services/entities.d.ts +14 -0
  88. package/dist/services/entities.d.ts.map +1 -0
  89. package/dist/services/forecast.d.ts +10 -0
  90. package/dist/services/forecast.d.ts.map +1 -0
  91. package/dist/services/fx.d.ts +33 -0
  92. package/dist/services/fx.d.ts.map +1 -0
  93. package/dist/services/ingest.d.ts +19 -0
  94. package/dist/services/ingest.d.ts.map +1 -0
  95. package/dist/services/registry.d.ts +33 -0
  96. package/dist/services/registry.d.ts.map +1 -0
  97. package/dist/services/runway.d.ts +28 -0
  98. package/dist/services/runway.d.ts.map +1 -0
  99. package/dist/services/storage.d.ts +35 -0
  100. package/dist/services/storage.d.ts.map +1 -0
  101. package/dist/services/sweeps.d.ts +26 -0
  102. package/dist/services/sweeps.d.ts.map +1 -0
  103. package/dist/types/index.d.ts +133 -0
  104. package/dist/types/index.d.ts.map +1 -0
  105. package/dist/version.d.ts +3 -0
  106. package/dist/version.d.ts.map +1 -0
  107. package/docker-compose.yml +53 -0
  108. package/hasna.contract.json +20 -0
  109. package/openapi.json +615 -0
  110. package/package.json +80 -0
@@ -0,0 +1,53 @@
1
+ services:
2
+ db:
3
+ image: postgres:16
4
+ environment:
5
+ POSTGRES_DB: treasury
6
+ POSTGRES_USER: treasury
7
+ POSTGRES_PASSWORD_FILE: /run/secrets/pg_password
8
+ secrets: [pg_password]
9
+ volumes: ["pgdata:/var/lib/postgresql/data"]
10
+ healthcheck:
11
+ test: ["CMD-SHELL", "pg_isready -U treasury"]
12
+ interval: 5s
13
+ retries: 10
14
+ serve:
15
+ image: oven/bun:1
16
+ # --package selects the serve bin; a bare `bunx @hasna/treasury treasury-serve`
17
+ # would run the CLI and treat "treasury-serve" as a bogus argument.
18
+ command: ["bunx", "--package", "@hasna/treasury", "treasury-serve"]
19
+ environment:
20
+ HASNA_TREASURY_STORAGE_MODE: cloud
21
+ HASNA_TREASURY_DATABASE_URL_FILE: /run/secrets/database_url
22
+ HASNA_TREASURY_PORT: "3486"
23
+ HASNA_TREASURY_BIND_HOST: "0.0.0.0"
24
+ HASNA_TREASURY_CORS_ORIGINS: ${CORS_ORIGINS:-}
25
+ HASNA_TREASURY_API_CREDENTIALS: ${TREASURY_API_CREDENTIALS:-}
26
+ secrets: [database_url]
27
+ depends_on: { db: { condition: service_healthy } }
28
+ ports: ["3486:3486"]
29
+ mcp:
30
+ image: oven/bun:1
31
+ # --package selects the MCP bin; a bare `bunx @hasna/treasury treasury-mcp` would run
32
+ # the CLI and treat "treasury-mcp" as a bogus argument. (BUILD-SPEC §6.4)
33
+ command: ["bunx", "--package", "@hasna/treasury", "treasury-mcp", "--http", "--port", "8890"]
34
+ environment:
35
+ HASNA_TREASURY_STORAGE_MODE: cloud
36
+ HASNA_TREASURY_DATABASE_URL_FILE: /run/secrets/database_url
37
+ MCP_HTTP: "1"
38
+ MCP_HTTP_PORT: "8890"
39
+ # Bind 0.0.0.0 so the published 8890 port is reachable; the default loopback
40
+ # bind is invisible to Docker port forwarding. A non-loopback bind forces auth
41
+ # ON and is asserted fail-closed at startup (assertMcpServeSafety), satisfied
42
+ # here by wiring API_CREDENTIALS. Never publish this port without credentials.
43
+ HASNA_TREASURY_MCP_BIND_HOST: "0.0.0.0"
44
+ HASNA_TREASURY_API_CREDENTIALS: ${TREASURY_API_CREDENTIALS:-}
45
+ secrets: [database_url]
46
+ depends_on: { db: { condition: service_healthy } }
47
+ ports: ["8890:8890"]
48
+ secrets:
49
+ pg_password:
50
+ file: ./secrets/pg_password
51
+ database_url:
52
+ file: ./secrets/database_url # postgres://treasury:<pw>@db:5432/treasury?sslmode=verify-full
53
+ volumes: { pgdata: {} }
@@ -0,0 +1,20 @@
1
+ {
2
+ "schema": "hasna.service_contract.v1",
3
+ "name": "treasury",
4
+ "class": "cli-with-store",
5
+ "contractVersion": "v1",
6
+ "kitVersion": "0.4.1",
7
+ "description": "Multi-entity cash/treasury cockpit CLI + MCP + serve. Local mode uses SQLite at ~/.hasna/treasury/treasury.db; cloud mode (HASNA_TREASURY_STORAGE_MODE=cloud) is PURE REMOTE per Amendment A1 with all reads/writes hitting the shared cloud Postgres.",
8
+ "bins": [
9
+ "treasury",
10
+ "treasury-mcp",
11
+ "treasury-serve"
12
+ ],
13
+ "storage": {
14
+ "mode": "local",
15
+ "envPrefix": "HASNA_TREASURY_",
16
+ "aliasEnvPrefix": "TREASURY_",
17
+ "databaseUrlSecretRef": "hasna/oss/treasury/database-url",
18
+ "sqlitePath": "~/.hasna/treasury/treasury.db"
19
+ }
20
+ }
package/openapi.json ADDED
@@ -0,0 +1,615 @@
1
+ {
2
+ "openapi": "3.1.0",
3
+ "info": {
4
+ "title": "@hasna/treasury API",
5
+ "version": "0.1.2",
6
+ "description": "Multi-entity cash/treasury cockpit — consolidated balances, FX exposure, runway, forecast, and advisory sweep recommendations."
7
+ },
8
+ "paths": {
9
+ "/health": {
10
+ "get": {
11
+ "operationId": "getHealth",
12
+ "summary": "Liveness",
13
+ "responses": {
14
+ "200": {
15
+ "description": "OK"
16
+ }
17
+ }
18
+ }
19
+ },
20
+ "/ready": {
21
+ "get": {
22
+ "operationId": "getReady",
23
+ "summary": "Readiness",
24
+ "responses": {
25
+ "200": {
26
+ "description": "OK"
27
+ }
28
+ }
29
+ }
30
+ },
31
+ "/version": {
32
+ "get": {
33
+ "operationId": "getVersion",
34
+ "summary": "Version",
35
+ "responses": {
36
+ "200": {
37
+ "description": "OK"
38
+ }
39
+ }
40
+ }
41
+ },
42
+ "/v1/entities": {
43
+ "get": {
44
+ "operationId": "listEntities",
45
+ "summary": "List entities the caller is authorized to see.",
46
+ "responses": {
47
+ "200": {
48
+ "description": "OK"
49
+ },
50
+ "4XX": {
51
+ "description": "Error envelope { code, message, suggestion }"
52
+ }
53
+ }
54
+ },
55
+ "post": {
56
+ "operationId": "createEntity",
57
+ "summary": "Create (cache) an entity anchor.",
58
+ "responses": {
59
+ "200": {
60
+ "description": "OK"
61
+ },
62
+ "4XX": {
63
+ "description": "Error envelope { code, message, suggestion }"
64
+ }
65
+ },
66
+ "requestBody": {
67
+ "required": true,
68
+ "content": {
69
+ "application/json": {
70
+ "schema": {
71
+ "type": "object",
72
+ "required": [
73
+ "name",
74
+ "base_currency"
75
+ ],
76
+ "properties": {
77
+ "name": {
78
+ "type": "string"
79
+ },
80
+ "base_currency": {
81
+ "type": "string"
82
+ },
83
+ "entity_slug": {
84
+ "type": "string"
85
+ }
86
+ }
87
+ }
88
+ }
89
+ }
90
+ }
91
+ }
92
+ },
93
+ "/v1/entities/{entity_id}": {
94
+ "get": {
95
+ "operationId": "getEntity",
96
+ "summary": "Get a single entity by entity_id.",
97
+ "responses": {
98
+ "200": {
99
+ "description": "OK"
100
+ },
101
+ "4XX": {
102
+ "description": "Error envelope { code, message, suggestion }"
103
+ }
104
+ },
105
+ "parameters": [
106
+ {
107
+ "name": "entity_id",
108
+ "in": "path",
109
+ "required": true,
110
+ "schema": {
111
+ "type": "string"
112
+ }
113
+ }
114
+ ]
115
+ }
116
+ },
117
+ "/v1/balances": {
118
+ "get": {
119
+ "operationId": "listBalances",
120
+ "summary": "List cached balance snapshots (optionally for one entity).",
121
+ "responses": {
122
+ "200": {
123
+ "description": "OK"
124
+ },
125
+ "4XX": {
126
+ "description": "Error envelope { code, message, suggestion }"
127
+ }
128
+ },
129
+ "parameters": [
130
+ {
131
+ "name": "entity_id",
132
+ "in": "query",
133
+ "required": false,
134
+ "schema": {
135
+ "type": "string"
136
+ }
137
+ }
138
+ ]
139
+ },
140
+ "post": {
141
+ "operationId": "recordBalance",
142
+ "summary": "Cache a balance snapshot with provenance.",
143
+ "responses": {
144
+ "200": {
145
+ "description": "OK"
146
+ },
147
+ "4XX": {
148
+ "description": "Error envelope { code, message, suggestion }"
149
+ }
150
+ },
151
+ "requestBody": {
152
+ "required": true,
153
+ "content": {
154
+ "application/json": {
155
+ "schema": {
156
+ "type": "object",
157
+ "required": [
158
+ "entity_id",
159
+ "account_ref",
160
+ "account_kind",
161
+ "currency",
162
+ "amount_minor"
163
+ ],
164
+ "properties": {
165
+ "entity_id": {
166
+ "type": "string"
167
+ },
168
+ "account_ref": {
169
+ "type": "string"
170
+ },
171
+ "account_kind": {
172
+ "type": "string"
173
+ },
174
+ "currency": {
175
+ "type": "string"
176
+ },
177
+ "amount_minor": {
178
+ "type": "integer"
179
+ },
180
+ "source": {
181
+ "type": "string"
182
+ }
183
+ }
184
+ }
185
+ }
186
+ }
187
+ }
188
+ }
189
+ },
190
+ "/v1/balances/consolidated": {
191
+ "get": {
192
+ "operationId": "consolidatedBalances",
193
+ "summary": "Consolidated balances across visible entities, converted to a base.",
194
+ "responses": {
195
+ "200": {
196
+ "description": "OK"
197
+ },
198
+ "4XX": {
199
+ "description": "Error envelope { code, message, suggestion }"
200
+ }
201
+ },
202
+ "parameters": [
203
+ {
204
+ "name": "base",
205
+ "in": "query",
206
+ "required": false,
207
+ "schema": {
208
+ "type": "string"
209
+ }
210
+ }
211
+ ]
212
+ }
213
+ },
214
+ "/v1/fx-rates": {
215
+ "get": {
216
+ "operationId": "listFxRates",
217
+ "summary": "List cached FX rates.",
218
+ "responses": {
219
+ "200": {
220
+ "description": "OK"
221
+ },
222
+ "4XX": {
223
+ "description": "Error envelope { code, message, suggestion }"
224
+ }
225
+ }
226
+ },
227
+ "post": {
228
+ "operationId": "recordFxRate",
229
+ "summary": "Cache an FX rate (1 base = rate quote).",
230
+ "responses": {
231
+ "200": {
232
+ "description": "OK"
233
+ },
234
+ "4XX": {
235
+ "description": "Error envelope { code, message, suggestion }"
236
+ }
237
+ },
238
+ "requestBody": {
239
+ "required": true,
240
+ "content": {
241
+ "application/json": {
242
+ "schema": {
243
+ "type": "object",
244
+ "required": [
245
+ "base_currency",
246
+ "quote_currency",
247
+ "rate"
248
+ ],
249
+ "properties": {
250
+ "base_currency": {
251
+ "type": "string"
252
+ },
253
+ "quote_currency": {
254
+ "type": "string"
255
+ },
256
+ "rate": {
257
+ "type": "number"
258
+ },
259
+ "source": {
260
+ "type": "string"
261
+ }
262
+ }
263
+ }
264
+ }
265
+ }
266
+ }
267
+ }
268
+ },
269
+ "/v1/exposure": {
270
+ "get": {
271
+ "operationId": "fxExposure",
272
+ "summary": "FX exposure across visible balances, converted to a base.",
273
+ "responses": {
274
+ "200": {
275
+ "description": "OK"
276
+ },
277
+ "4XX": {
278
+ "description": "Error envelope { code, message, suggestion }"
279
+ }
280
+ },
281
+ "parameters": [
282
+ {
283
+ "name": "base",
284
+ "in": "query",
285
+ "required": false,
286
+ "schema": {
287
+ "type": "string"
288
+ }
289
+ }
290
+ ]
291
+ }
292
+ },
293
+ "/v1/cost-feeds": {
294
+ "post": {
295
+ "operationId": "recordCostFeed",
296
+ "summary": "Record an entity's monthly net cash burn.",
297
+ "responses": {
298
+ "200": {
299
+ "description": "OK"
300
+ },
301
+ "4XX": {
302
+ "description": "Error envelope { code, message, suggestion }"
303
+ }
304
+ },
305
+ "requestBody": {
306
+ "required": true,
307
+ "content": {
308
+ "application/json": {
309
+ "schema": {
310
+ "type": "object",
311
+ "required": [
312
+ "entity_id",
313
+ "currency",
314
+ "monthly_burn_minor"
315
+ ],
316
+ "properties": {
317
+ "entity_id": {
318
+ "type": "string"
319
+ },
320
+ "currency": {
321
+ "type": "string"
322
+ },
323
+ "monthly_burn_minor": {
324
+ "type": "integer"
325
+ },
326
+ "source": {
327
+ "type": "string"
328
+ }
329
+ }
330
+ }
331
+ }
332
+ }
333
+ }
334
+ },
335
+ "get": {
336
+ "operationId": "listCostFeeds",
337
+ "summary": "List cached cost feeds (optionally for one entity).",
338
+ "responses": {
339
+ "200": {
340
+ "description": "OK"
341
+ },
342
+ "4XX": {
343
+ "description": "Error envelope { code, message, suggestion }"
344
+ }
345
+ },
346
+ "parameters": [
347
+ {
348
+ "name": "entity_id",
349
+ "in": "query",
350
+ "required": false,
351
+ "schema": {
352
+ "type": "string"
353
+ }
354
+ }
355
+ ]
356
+ }
357
+ },
358
+ "/v1/runway/{entity_id}": {
359
+ "get": {
360
+ "operationId": "entityRunway",
361
+ "summary": "Runway (months) for a single entity.",
362
+ "responses": {
363
+ "200": {
364
+ "description": "OK"
365
+ },
366
+ "4XX": {
367
+ "description": "Error envelope { code, message, suggestion }"
368
+ }
369
+ },
370
+ "parameters": [
371
+ {
372
+ "name": "entity_id",
373
+ "in": "path",
374
+ "required": true,
375
+ "schema": {
376
+ "type": "string"
377
+ }
378
+ },
379
+ {
380
+ "name": "base",
381
+ "in": "query",
382
+ "required": false,
383
+ "schema": {
384
+ "type": "string"
385
+ }
386
+ }
387
+ ]
388
+ }
389
+ },
390
+ "/v1/runway": {
391
+ "get": {
392
+ "operationId": "groupRunway",
393
+ "summary": "Consolidated group runway (months).",
394
+ "responses": {
395
+ "200": {
396
+ "description": "OK"
397
+ },
398
+ "4XX": {
399
+ "description": "Error envelope { code, message, suggestion }"
400
+ }
401
+ },
402
+ "parameters": [
403
+ {
404
+ "name": "base",
405
+ "in": "query",
406
+ "required": false,
407
+ "schema": {
408
+ "type": "string"
409
+ }
410
+ }
411
+ ]
412
+ }
413
+ },
414
+ "/v1/forecast": {
415
+ "get": {
416
+ "operationId": "cashForecast",
417
+ "summary": "Short-horizon cash projection (entity or group).",
418
+ "responses": {
419
+ "200": {
420
+ "description": "OK"
421
+ },
422
+ "4XX": {
423
+ "description": "Error envelope { code, message, suggestion }"
424
+ }
425
+ },
426
+ "parameters": [
427
+ {
428
+ "name": "entity_id",
429
+ "in": "query",
430
+ "required": false,
431
+ "schema": {
432
+ "type": "string"
433
+ }
434
+ },
435
+ {
436
+ "name": "base",
437
+ "in": "query",
438
+ "required": false,
439
+ "schema": {
440
+ "type": "string"
441
+ }
442
+ },
443
+ {
444
+ "name": "horizon_months",
445
+ "in": "query",
446
+ "required": false,
447
+ "schema": {
448
+ "type": "integer"
449
+ }
450
+ }
451
+ ]
452
+ }
453
+ },
454
+ "/v1/sweeps": {
455
+ "get": {
456
+ "operationId": "listSweeps",
457
+ "summary": "List sweep / intercompany-funding recommendations.",
458
+ "responses": {
459
+ "200": {
460
+ "description": "OK"
461
+ },
462
+ "4XX": {
463
+ "description": "Error envelope { code, message, suggestion }"
464
+ }
465
+ },
466
+ "parameters": [
467
+ {
468
+ "name": "status",
469
+ "in": "query",
470
+ "required": false,
471
+ "schema": {
472
+ "type": "string"
473
+ }
474
+ }
475
+ ]
476
+ }
477
+ },
478
+ "/v1/sweeps/{id}": {
479
+ "get": {
480
+ "operationId": "getSweep",
481
+ "summary": "Get a single sweep recommendation.",
482
+ "responses": {
483
+ "200": {
484
+ "description": "OK"
485
+ },
486
+ "4XX": {
487
+ "description": "Error envelope { code, message, suggestion }"
488
+ }
489
+ },
490
+ "parameters": [
491
+ {
492
+ "name": "id",
493
+ "in": "path",
494
+ "required": true,
495
+ "schema": {
496
+ "type": "string"
497
+ }
498
+ }
499
+ ]
500
+ },
501
+ "patch": {
502
+ "operationId": "updateSweepStatus",
503
+ "summary": "Acknowledge or dismiss a sweep recommendation (advisory only).",
504
+ "responses": {
505
+ "200": {
506
+ "description": "OK"
507
+ },
508
+ "4XX": {
509
+ "description": "Error envelope { code, message, suggestion }"
510
+ }
511
+ },
512
+ "parameters": [
513
+ {
514
+ "name": "id",
515
+ "in": "path",
516
+ "required": true,
517
+ "schema": {
518
+ "type": "string"
519
+ }
520
+ }
521
+ ],
522
+ "requestBody": {
523
+ "required": true,
524
+ "content": {
525
+ "application/json": {
526
+ "schema": {
527
+ "type": "object",
528
+ "required": [
529
+ "status"
530
+ ],
531
+ "properties": {
532
+ "status": {
533
+ "type": "string"
534
+ }
535
+ }
536
+ }
537
+ }
538
+ }
539
+ }
540
+ }
541
+ },
542
+ "/v1/sweeps/generate": {
543
+ "post": {
544
+ "operationId": "generateSweeps",
545
+ "summary": "Generate intercompany-funding recommendations (advisory only).",
546
+ "responses": {
547
+ "200": {
548
+ "description": "OK"
549
+ },
550
+ "4XX": {
551
+ "description": "Error envelope { code, message, suggestion }"
552
+ }
553
+ },
554
+ "requestBody": {
555
+ "required": false,
556
+ "content": {
557
+ "application/json": {
558
+ "schema": {
559
+ "type": "object",
560
+ "required": [],
561
+ "properties": {
562
+ "base": {
563
+ "type": "string"
564
+ },
565
+ "min_runway_months": {
566
+ "type": "number"
567
+ },
568
+ "healthy_runway_months": {
569
+ "type": "number"
570
+ }
571
+ }
572
+ }
573
+ }
574
+ }
575
+ }
576
+ }
577
+ },
578
+ "/v1/ingest": {
579
+ "post": {
580
+ "operationId": "ingestFixtures",
581
+ "summary": "Ingest balances/FX/cost from the v0 fixture adapters for two demo entities.",
582
+ "responses": {
583
+ "200": {
584
+ "description": "OK"
585
+ },
586
+ "4XX": {
587
+ "description": "Error envelope { code, message, suggestion }"
588
+ }
589
+ },
590
+ "requestBody": {
591
+ "required": true,
592
+ "content": {
593
+ "application/json": {
594
+ "schema": {
595
+ "type": "object",
596
+ "required": [
597
+ "us_entity_id",
598
+ "ro_entity_id"
599
+ ],
600
+ "properties": {
601
+ "us_entity_id": {
602
+ "type": "string"
603
+ },
604
+ "ro_entity_id": {
605
+ "type": "string"
606
+ }
607
+ }
608
+ }
609
+ }
610
+ }
611
+ }
612
+ }
613
+ }
614
+ }
615
+ }