mirror of
https://github.com/we-promise/sure.git
synced 2026-06-06 03:09:02 +00:00
feat(imports): add SureImport session batches (#1785)
* feat(imports): add SureImport session batches Add first-class SureImport sessions for ordered multi-file NDJSON imports. Persist source mappings across chunks, make session/chunk processing idempotent, expose progress readback, and keep existing single-file import behavior compatible. Includes the devcontainer libvips runtime dependency needed by ActiveStorage variant tests. Addresses #1610. Related to #1458. * fix(imports): avoid scanner-like API key test data * test(imports): assert skipped balances are not persisted * fix(imports): harden session publish retries Validate expected import chunk sequences exactly before publish, and restore session state with error details when enqueueing the publish job fails. * fix(imports): close session retry edge cases Backfill expected chunk counts after client-session insert races and enqueue import-session jobs after the status transition commits. Persist a safe enqueue failure body so API readback does not expose raw queue errors. * fix(imports): address session publish review gaps Remove dead transaction external-id assignment, harden session publish retry/sync behavior, align session chunk status docs, and add regression coverage for partial retries and safe enqueue error readback. * fix(imports): include sessions in family reset Clear import sessions through the family reset job so chunk imports and source mappings do not survive a reset. Expose import session and source mapping counts in the reset status response and regenerated OpenAPI schema so polling reflects the full reset surface. * test(imports): cover split import mapping invariants * test(imports): cover session verification invariants * fix(imports): scope SureImport session reimports * Tighten SureImport session batching * fix(imports): export rule source ids for sessions * test(imports): stabilize rule id export assertion * test(imports): restore reset status session fixture
This commit is contained in:
@@ -2086,6 +2086,115 @@ components:
|
||||
properties:
|
||||
data:
|
||||
"$ref": "#/components/schemas/ImportDetail"
|
||||
ImportSessionChunk:
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
- sequence
|
||||
- status
|
||||
- rows_count
|
||||
- summary
|
||||
- created_at
|
||||
- updated_at
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
sequence:
|
||||
type: integer
|
||||
minimum: 1
|
||||
client_chunk_id:
|
||||
type: string
|
||||
nullable: true
|
||||
status:
|
||||
type: string
|
||||
enum:
|
||||
- pending
|
||||
- importing
|
||||
- complete
|
||||
- failed
|
||||
rows_count:
|
||||
type: integer
|
||||
minimum: 0
|
||||
summary:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: integer
|
||||
error:
|
||||
type: object
|
||||
nullable: true
|
||||
additionalProperties: true
|
||||
created_at:
|
||||
type: string
|
||||
format: date-time
|
||||
updated_at:
|
||||
type: string
|
||||
format: date-time
|
||||
ImportSession:
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
- type
|
||||
- status
|
||||
- chunks_count
|
||||
- summary
|
||||
- chunks
|
||||
- created_at
|
||||
- updated_at
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- SureImport
|
||||
status:
|
||||
type: string
|
||||
enum:
|
||||
- pending
|
||||
- importing
|
||||
- complete
|
||||
- failed
|
||||
client_session_id:
|
||||
type: string
|
||||
nullable: true
|
||||
expected_chunks:
|
||||
type: integer
|
||||
nullable: true
|
||||
minimum: 1
|
||||
chunks_count:
|
||||
type: integer
|
||||
minimum: 0
|
||||
summary:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: integer
|
||||
error:
|
||||
type: object
|
||||
nullable: true
|
||||
additionalProperties: true
|
||||
chunks:
|
||||
type: array
|
||||
items:
|
||||
"$ref": "#/components/schemas/ImportSessionChunk"
|
||||
created_at:
|
||||
type: string
|
||||
format: date-time
|
||||
updated_at:
|
||||
type: string
|
||||
format: date-time
|
||||
ImportSessionResponse:
|
||||
type: object
|
||||
required:
|
||||
- data
|
||||
properties:
|
||||
data:
|
||||
"$ref": "#/components/schemas/ImportSession"
|
||||
ProviderConnectionInstitution:
|
||||
type: object
|
||||
required:
|
||||
@@ -2892,6 +3001,8 @@ components:
|
||||
- account_statements
|
||||
- family_exports
|
||||
- imports
|
||||
- import_sessions
|
||||
- import_source_mappings
|
||||
- import_rows
|
||||
- import_mappings
|
||||
- accounts
|
||||
@@ -2933,6 +3044,12 @@ components:
|
||||
imports:
|
||||
type: integer
|
||||
minimum: 0
|
||||
import_sessions:
|
||||
type: integer
|
||||
minimum: 0
|
||||
import_source_mappings:
|
||||
type: integer
|
||||
minimum: 0
|
||||
import_rows:
|
||||
type: integer
|
||||
minimum: 0
|
||||
@@ -4607,6 +4724,266 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
"/api/v1/import_sessions":
|
||||
post:
|
||||
summary: Create import session
|
||||
description: Create or idempotently retrieve a multi-file SureImport session
|
||||
keyed by client_session_id.
|
||||
tags:
|
||||
- Import Sessions
|
||||
security:
|
||||
- apiKeyAuth: []
|
||||
parameters: []
|
||||
responses:
|
||||
'201':
|
||||
description: import session created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ImportSessionResponse"
|
||||
'401':
|
||||
description: unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
'403':
|
||||
description: insufficient scope
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
'409':
|
||||
description: client session conflict
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
'422':
|
||||
description: validation error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- SureImport
|
||||
description: Import session type. Only SureImport is supported.
|
||||
client_session_id:
|
||||
type: string
|
||||
nullable: true
|
||||
description: Client-provided idempotency key for the full import
|
||||
session.
|
||||
expected_chunks:
|
||||
type: integer
|
||||
minimum: 1
|
||||
nullable: true
|
||||
description: Expected number of ordered chunks before publish is
|
||||
allowed.
|
||||
"/api/v1/import_sessions/{id}":
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
description: Import session ID
|
||||
schema:
|
||||
type: string
|
||||
get:
|
||||
summary: Retrieve import session
|
||||
description: Retrieve import session status, chunk status, per-entity summary
|
||||
counts, and safe error details.
|
||||
tags:
|
||||
- Import Sessions
|
||||
security:
|
||||
- apiKeyAuth: []
|
||||
responses:
|
||||
'200':
|
||||
description: import session retrieved
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ImportSessionResponse"
|
||||
'401':
|
||||
description: unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
'403':
|
||||
description: insufficient scope
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
'404':
|
||||
description: import session not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
"/api/v1/import_sessions/{id}/chunks":
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
description: Import session ID
|
||||
schema:
|
||||
type: string
|
||||
post:
|
||||
summary: Upload import session chunk
|
||||
description: Attach an ordered Sure NDJSON chunk to an import session. Chunks
|
||||
are idempotent by sequence and client_chunk_id with content verification.
|
||||
tags:
|
||||
- Import Sessions
|
||||
security:
|
||||
- apiKeyAuth: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- sequence
|
||||
- raw_file_content
|
||||
properties:
|
||||
sequence:
|
||||
type: integer
|
||||
minimum: 1
|
||||
description: One-based chunk sequence. Earlier dependency chunks
|
||||
must have lower sequence numbers.
|
||||
client_chunk_id:
|
||||
type: string
|
||||
nullable: true
|
||||
description: Client-provided idempotency key for this chunk.
|
||||
raw_file_content:
|
||||
type: string
|
||||
description: Raw Sure NDJSON content. Each chunk is limited to 10MB.
|
||||
multipart/form-data:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- sequence
|
||||
- file
|
||||
properties:
|
||||
sequence:
|
||||
type: integer
|
||||
minimum: 1
|
||||
description: One-based chunk sequence. Earlier dependency chunks
|
||||
must have lower sequence numbers.
|
||||
client_chunk_id:
|
||||
type: string
|
||||
nullable: true
|
||||
description: Client-provided idempotency key for this chunk.
|
||||
file:
|
||||
type: string
|
||||
format: binary
|
||||
description: Multipart Sure NDJSON file upload. Each chunk is limited
|
||||
to 10MB.
|
||||
parameters: []
|
||||
responses:
|
||||
'201':
|
||||
description: chunk uploaded
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ImportSessionResponse"
|
||||
'401':
|
||||
description: unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
'403':
|
||||
description: insufficient scope
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
'409':
|
||||
description: chunk conflict
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
'404':
|
||||
description: import session not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
'422':
|
||||
description: missing or invalid content
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
"/api/v1/import_sessions/{id}/publish":
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
description: Import session ID
|
||||
schema:
|
||||
type: string
|
||||
post:
|
||||
summary: Publish import session
|
||||
description: Queue ordered chunk processing for a SureImport session. Later
|
||||
chunks can reference source IDs mapped by earlier chunks.
|
||||
tags:
|
||||
- Import Sessions
|
||||
security:
|
||||
- apiKeyAuth: []
|
||||
responses:
|
||||
'202':
|
||||
description: import session publish queued
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ImportSessionResponse"
|
||||
'401':
|
||||
description: unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
'403':
|
||||
description: insufficient scope
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
'422':
|
||||
description: max_row_count_exceeded
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
'409':
|
||||
description: missing expected chunks
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
'503':
|
||||
description: enqueue failed
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
'404':
|
||||
description: import session not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
"/api/v1/imports":
|
||||
get:
|
||||
summary: List imports
|
||||
|
||||
Reference in New Issue
Block a user