feat: add persisted page insight platform
This commit is contained in:
@@ -638,6 +638,67 @@ paths:
|
||||
'401': {$ref: '#/components/responses/Unauthenticated'}
|
||||
'404': {$ref: '#/components/responses/ResourceNotFound'}
|
||||
|
||||
/analytics/ai-insights/{module}:
|
||||
get:
|
||||
tags: [AI page insights]
|
||||
operationId: getLatestAIInsight
|
||||
summary: Return the latest persisted insight without waiting for generation
|
||||
parameters:
|
||||
- {name: module, in: path, required: true, schema: {$ref: '#/components/schemas/AIInsightModule'}}
|
||||
- {name: terminalId, in: query, required: false, schema: {type: string, maxLength: 128}}
|
||||
- $ref: '#/components/parameters/RequestIdHeader'
|
||||
responses:
|
||||
'200': {description: Latest ready or deterministic-partial snapshot., content: {application/json: {schema: {$ref: '#/components/schemas/AIInsight'}}}}
|
||||
'401': {$ref: '#/components/responses/Unauthenticated'}
|
||||
'404': {$ref: '#/components/responses/ResourceNotFound'}
|
||||
'422': {$ref: '#/components/responses/ValidationFailed'}
|
||||
'503': {$ref: '#/components/responses/AnalyticsUnavailable'}
|
||||
/analytics/ai-insights/{module}/refreshes:
|
||||
post:
|
||||
tags: [AI page insights]
|
||||
operationId: refreshAIInsight
|
||||
summary: Enqueue an independent insight refresh
|
||||
parameters:
|
||||
- {name: module, in: path, required: true, schema: {$ref: '#/components/schemas/AIInsightModule'}}
|
||||
- $ref: '#/components/parameters/IdempotencyKeyHeader'
|
||||
- $ref: '#/components/parameters/CsrfTokenHeader'
|
||||
- $ref: '#/components/parameters/OriginHeader'
|
||||
requestBody:
|
||||
required: true
|
||||
content: {application/json: {schema: {$ref: '#/components/schemas/AIInsightRefreshRequest'}}}
|
||||
responses:
|
||||
'200': {description: Idempotent job reused., content: {application/json: {schema: {$ref: '#/components/schemas/AIInsightJob'}}}}
|
||||
'202': {description: Refresh accepted., content: {application/json: {schema: {$ref: '#/components/schemas/AIInsightJob'}}}}
|
||||
'401': {$ref: '#/components/responses/Unauthenticated'}
|
||||
'403': {$ref: '#/components/responses/Forbidden'}
|
||||
'404': {$ref: '#/components/responses/ResourceNotFound'}
|
||||
'409': {$ref: '#/components/responses/Conflict'}
|
||||
'422': {$ref: '#/components/responses/ValidationFailed'}
|
||||
'429': {$ref: '#/components/responses/RateLimited'}
|
||||
'503': {$ref: '#/components/responses/AnalyticsUnavailable'}
|
||||
/analytics/ai-insight-refreshes/{jobId}:
|
||||
get:
|
||||
tags: [AI page insights]
|
||||
operationId: getAIInsightRefresh
|
||||
parameters:
|
||||
- {name: jobId, in: path, required: true, schema: {type: string, pattern: '^insightjob_[a-f0-9]{24}$'}}
|
||||
responses:
|
||||
'200': {description: Tenant-scoped refresh job., content: {application/json: {schema: {$ref: '#/components/schemas/AIInsightJob'}}}}
|
||||
'401': {$ref: '#/components/responses/Unauthenticated'}
|
||||
'404': {$ref: '#/components/responses/ResourceNotFound'}
|
||||
/analytics/ai-insight-refreshes/{jobId}/events:
|
||||
get:
|
||||
tags: [AI page insights]
|
||||
operationId: streamAIInsightRefreshEvents
|
||||
summary: Replay up to one hour of durable job events and continue as SSE
|
||||
parameters:
|
||||
- {name: jobId, in: path, required: true, schema: {type: string, pattern: '^insightjob_[a-f0-9]{24}$'}}
|
||||
- {name: Last-Event-ID, in: header, required: false, schema: {type: integer, format: int64}}
|
||||
responses:
|
||||
'200': {description: Durable job events and heartbeats., content: {text/event-stream: {schema: {type: string}}}}
|
||||
'401': {$ref: '#/components/responses/Unauthenticated'}
|
||||
'404': {$ref: '#/components/responses/ResourceNotFound'}
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
merchantSession:
|
||||
@@ -1174,6 +1235,83 @@ components:
|
||||
createdAt: {type: string, format: date-time}
|
||||
updatedAt: {type: string, format: date-time}
|
||||
eventsUrl: {type: string, format: uri-reference}
|
||||
AIInsightModule:
|
||||
type: string
|
||||
enum: [overview, payments, fees, peers, transactions, growth]
|
||||
AIInsightNarrative:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [headline, body, evidenceIds]
|
||||
properties:
|
||||
headline: {type: string}
|
||||
body: {type: string}
|
||||
evidenceIds: {type: array, items: {type: string}}
|
||||
AIInsightFinding:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [evidenceId, title, summary, scoreBps, confidence]
|
||||
properties:
|
||||
evidenceId: {type: string}
|
||||
title: {type: string}
|
||||
summary: {type: string}
|
||||
scoreBps: {type: integer, minimum: 0, maximum: 10000}
|
||||
confidence: {type: string, enum: [HIGH, MEDIUM, LOW, INSUFFICIENT_DATA]}
|
||||
AIInsightOption:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [title, description, evidenceIds]
|
||||
properties:
|
||||
title: {type: string}
|
||||
description: {type: string}
|
||||
evidenceIds: {type: array, items: {type: string}}
|
||||
AIInsightCopy:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [past, latestObserved, future7Days, future30Days, findings, options]
|
||||
properties:
|
||||
past: {$ref: '#/components/schemas/AIInsightNarrative'}
|
||||
latestObserved: {$ref: '#/components/schemas/AIInsightNarrative'}
|
||||
future7Days: {$ref: '#/components/schemas/AIInsightNarrative'}
|
||||
future30Days: {$ref: '#/components/schemas/AIInsightNarrative'}
|
||||
future90Days: {$ref: '#/components/schemas/AIInsightNarrative'}
|
||||
findings: {type: array, maxItems: 3, items: {$ref: '#/components/schemas/AIInsightFinding'}}
|
||||
options: {type: array, items: {$ref: '#/components/schemas/AIInsightOption'}}
|
||||
AIInsight:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [insightId, module, revision, status, scope, asOfDate, dataThroughDate, forecastStartDate, freshness, dataLagDays, confidence, copy, evidence, calendarContext, refreshState, generatedAt]
|
||||
properties:
|
||||
insightId: {type: string}
|
||||
module: {$ref: '#/components/schemas/AIInsightModule'}
|
||||
revision: {type: integer, minimum: 1}
|
||||
status: {type: string, enum: [READY, PARTIAL]}
|
||||
scope: {type: object, properties: {terminalId: {type: [string, 'null']}}}
|
||||
asOfDate: {type: string, format: date}
|
||||
dataThroughDate: {type: string, format: date}
|
||||
forecastStartDate: {type: string, format: date}
|
||||
freshness: {type: string, enum: [FRESH, LAGGING, STALE]}
|
||||
dataLagDays: {type: integer, minimum: 0}
|
||||
confidence: {type: string, enum: [HIGH, MEDIUM, LOW, INSUFFICIENT_DATA]}
|
||||
copy: {$ref: '#/components/schemas/AIInsightCopy'}
|
||||
evidence: {type: object, additionalProperties: true}
|
||||
calendarContext: {type: array, items: {type: object, additionalProperties: true}}
|
||||
refreshState: {type: object, additionalProperties: true}
|
||||
generatedAt: {type: string, format: date-time}
|
||||
AIInsightRefreshRequest:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
properties: {terminalId: {type: string, maxLength: 128}}
|
||||
AIInsightJob:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [jobId, snapshotId, state, eventsUrl, createdAt, updatedAt]
|
||||
properties:
|
||||
jobId: {type: string}
|
||||
snapshotId: {type: string}
|
||||
state: {type: string, enum: [QUEUED, RUNNING, COMPLETED, FAILED]}
|
||||
eventsUrl: {type: string, format: uri-reference}
|
||||
createdAt: {type: string, format: date-time}
|
||||
updatedAt: {type: string, format: date-time}
|
||||
LoginRequest:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
Reference in New Issue
Block a user