协议版本:zhixu.data-package/v1。更新日期:2026-10-17。个人与组织导出使用同一种公开格式;本文说明归档的结构、校验规则和可恢复边界。接口基础路径为 /question-bank/data-transfers。
从应用里导出或迁入
- 个人空间在题库页打开“导出与迁入”;组织负责人或管理员在“服务与套餐”中打开“导出组织数据”。
- 选择“导出资料”,保留清单和全部数据分片、原文件;迁入时切换到“迁入资料”,先上传文件并完成预检,再核对目标空间和转换清单。
- 未完成的任务可在“继续任务”中读取原任务编号。结果不确定时沿用原任务重试,避免重复创建。
迁入会创建新资料,历史考试成绩和个人学习事实仅归档。目标空间、权限和容量仍须满足下文约束。普通使用者可先完成上述操作;后续章节供需要核对协议、字段或开发对接的读者查阅。
身份与权限
使用真实 Accounts JWT、scoped PAT 或 MCP OAuth Authorization: Bearer …。组织本地员工登录不能调用此接口。任务绑定实际用户、认证类型、凭据/连接/授权 ID;换凭据不会取得原任务。服务在创建、状态查询、同键回读、文件下载/Range、上传、确认、重试、每次 worker 事务重新核验当前身份、scope、组织成员/商业读取或写入权限、组织授权和冻结题库集合。包不含令牌、密码或存储地址。
个人导出包含自己可读的个人题库,可选原件、自己的练习/错题档案。组织导出需要当前 owner/admin:成员、岗位及考试需要全组织 all_banks 授权且不允许显式 bankIds。不能通过选题库隐式取得组织全量成员/考试,不能导出员工个人练习。组织保留期限制也适用于已生成的下载包;下载不会延长保留期。
导出 scopes:banks:read;原件增加 sources:read;个人 learning 增加 practice:read;成员/岗位增加 organizations:read;考试增加 organizations:read、exams:read、results:read。迁入需要 banks:write、imports:write,含发布版本增加 banks:publish,含成员/岗位增加 organizations:manage。迁入只接受 all_banks 目标授权。目标组织必须可写、无题库、无岗位、仅有现有真实 owner;个人迁入新建个人题库。
路由与 DTO
响应是直接 JSON DTO,不套 success/data。时间为 UTC ISO 字符串,byteSize 为十进制字符串。失败遵循现有异常格式 {code,message,...}。
| 方法与路径 | 输入 | 成功响应 |
|---|---|---|
POST /exports |
ExportInput | TransferJob |
GET /exports |
organizationId?、limit?、before? |
`{items:TransferJob[],nextCursor:string |
GET /exports/:id |
TransferJob | |
GET /exports/:id/files |
`{jobId,manifest:Manifest | |
GET /exports/:id/files/:fileId |
可选单字节 Range | 200/206 文件流 |
POST /imports |
ImportInput | {job:TransferJob,uploads:UploadDescriptor[]} |
PUT /imports/:id/files/:fileId |
application/octet-stream 原始字节 |
{jobId,fileId,status:'uploaded',byteSize,sha256} |
POST /imports/:id/preview |
空 body | TransferJob;异步 validating |
POST /imports/:id/confirm |
ConfirmInput | TransferJob |
GET /imports/:id |
TransferJob | |
POST /:kind/:id/retry |
{idempotencyKey};kind=exports/imports |
TransferJob |
POST /imports/:id/verify |
空 body | `{jobId,status,report:VerificationReport |
type ExportInput = {
organizationId?: string | null;
bankIds?: string[];
components?: ('banks'|'sources'|'members'|'positions'|'exams'|'learning')[];
idempotencyKey: string; // 8..100 chars
}; // default components=['banks','sources']; banks is mandatory
type ImportInput = {organizationId?:string|null;manifest:Manifest;idempotencyKey:string};
type ConfirmInput = {planHash:string;confirmationToken:string;idempotencyKey:string};
type UploadDescriptor = {fileId:string;method:'PUT';url:string;
headers:{'Content-Type':'application/octet-stream'};byteSize:string;sha256:string};
type TransferJob = {id:string;kind:'export'|'import';status:string;
schemaVersion:'zhixu.data-package/v1';organizationId:string|null;
progress:{stage:string;processed:number;total:number|null};snapshotAt:string|null;
expiresAt:string;manifestHash:string|null;preview:ImportPreview|null;
report:VerificationReport|null;error:{code:string;message:string;retryable:boolean}|null;
createdAt:string;updatedAt:string};
type ImportPreview = {planHash:string;confirmationToken:string;expiresAt:string;
target:{organizationId:string|null;fingerprint:string};counts:Record<string,number>;
restorableSections:string[];archivedSections:string[];
transformations:{code:string;count:number;message:string}[];
blockers:{code:string;message:string}[]};
type VerificationReport = {verifiedAt:string;counts:Record<string,number>;
restored:Record<string,number>;archived:Record<string,number>;
transformations:{code:string;count:number;message:string}[];
differences:{section:string;sourceRef:string;field:string}[];passed:boolean};
organizationId 省略时按现凭据/身份的默认组织,显式 null 表示个人。包内源 scope.organizationId 只作来源元数据,不选择迁入目标。members 自动带入岗位以闭合位置引用。导出分页默认20、最大100。create 同主体同类已有活跃任务会拒绝;retry/verify 按自身 job 串行,不承诺跨 job 的全局并发配额。
首次相同幂等键和相同输入回读原任务,改变 body 返回 TRANSFER_IDEMPOTENCY_CONFLICT。确认 token 有效10分钟,绑定原主体、manifest、目标 fingerprint 和当前 plan;确认重放比较完整原 body(含 token)。已经接受的相同确认不因原10分钟过去而重复执行,任务 TTL 和当前权限仍须有效。
文件和恢复协议
导出 queued → snapshotting → exporting → ready,失败为 failed。GET files 仅 ready 且未过期返回 manifest/文件,包含 delivery-only id:'manifest' 的 JSON descriptor。客户下载 manifest 和全部 JSONL.gz/原件,逐个按实际字节 SHA256 校验并保留文件。
迁入 uploading → validating → awaiting_confirmation → queued/importing → completed。POST imports 后使用返回的认证 PUT 路由上传每个文件,声明字节大小/SHA 来自 immutable manifest,服务器核实际流。确认前 POST preview 并轮询 GET;服务器再次校验全部 JSONL 和原件真实字节/摘要、schema、引用、原选项顺序/答案/版本摘要、容量、目标冲突,才能返回可执行 preview。预检不写业务行。
新确认需要严格剩余24小时+120秒以上的七天任务 TTL;不足会事务持久化 expired 后返回 TRANSFER_CONFIRMATION_TIME_WINDOW,释放创建名额,目标不变。请用新键创建任务。首次确认启动新24小时绝对执行期限。每个最多250行事务内业务行、ID map、cursor 一起提交;generation/token/lease/expiry 在入口和提交前检查。任务崩溃可沿同 job/map 有界恢复,目标题库/组织保持 restoring,完整内容、引用与文件独立再读核对通过才开放。
TRANSFER_VERIFICATION_FAILED 的已确认隔离任务,在原期限/TTL 内、当前权限仍有效时可公开 retry 新键:保留原 IDs/map,从指针和原时间 metadata 修复后再比较;若仍不符则保持隔离。已开放目标不能走此封存恢复。其他可重试失败以 error.retryable 和实际领域判断为准。过期或期限已结束的半成品保持隔离与清理保护,不承诺永久可恢复,也不会自动删业务数据。
POST verify 会排队独立的新核对,返回 verifying 和 report=null,轮询 GET import 获得本轮结果。已完成目标的 verify-only 不重新 seal,不改变开放状态;不能把上次 passed 当实时核对。
所有文件 I/O 包含开始请求到完成,最多120秒;object delete 最多10秒并保留可重试 ledger。下载返回 Content-Length、Content-Disposition、ETag(SHA)、Accept-Ranges、private/no-store。Range 支持单范围及 suffix;bytes=0-99 对8字节文件截断为0-7,首位置>=size、多范围/不安全整数/无效格式返回416及 Content-Range: bytes */size。每次恢复下载重新认证和核验保留期。
v1 公开包格式
type Manifest = {schemaVersion:'zhixu.data-package/v1';packageId:string;capturedAt:string;
scope:{organizationId:string|null;bankIds:string[]};sections:Record<string,number>;
restorableSections:string[];archivedSections:string[];
omitted:{component:string;reason:string}[];files:FileDescriptor[]};
type FileDescriptor = {id:string;section:string;kind:'jsonl-gzip'|'source';filename:string;
mimeType:string;byteSize:string;sha256:string;rowCount:number};
type JsonlRow = {section:string;sourceRef:string;record:Record<string,unknown>};
所有原 ID 为 UUID,通过 sourceRef 引用;迁入新 ID 持久映射,引用/hash 同步重算。文件名不含路径;不从包中抓取 URL,也不接受内部 objectKey。JSONL gzip 每行一个完整对象,UTF8(非法编码拒绝),必须末尾换行。字段必须完整且只来自以下白名单;可空字段以 null 表示,日期须 canonical UTC ISO(毫秒)。JSON 内容保持原值,整数/布尔值按字段类型,原字节大小为十进制字符串。
每个原件 descriptor 的 id 等于 sources.sourceRef、section=sources、rowCount=0,真实 bytes/SHA/mimeType 对应 sources 行;delivery 文件名 source-<sourceUUID>-<safe original basename> 唯一且≤255 UTF16 units,完整原 originalFilename 保留在 JSONL。manifest 自身 descriptor 不写回 manifest,避免自引用 hash。
| section | 精确 record 字段 |
|---|---|
banks |
id, name, description, status, usageMode, currentBankVersionId, workingRevision, createdAt, updatedAt |
questions |
id, bankId, status, createdSource, currentWorkingVersionId, createdAt, updatedAt |
questionVersions |
id, questionId, versionNo, schemaVersion, questionType, stemJson, explanationJson, answerKeyHash, optionOrderPolicy, optionOrderReason, sourceLocatorJson, contentHash, changeImpact, createdByType, createdById, changeSetId, createdAt |
options |
id, questionId, semantic, createdAt |
optionVersions |
id, questionVersionId, optionId, contentJson, originalPosition, contentHash, createdAt |
answerKeys |
questionVersionId, optionIdsJson, judgeRuleVersion, createdAt |
workingItems |
id, bankId, questionId, questionVersionId, position, included, createdAt, updatedAt |
bankVersions |
id, bankId, versionNo, workingRevision, questionCount, contentDigest, publishedByUserId, publishedByAdminId, publishedAt |
bankVersionItems |
id, bankVersionId, questionId, questionVersionId, position, publishedStatus, createdAt |
sources |
id, bankId, originalFilename, mimeType, byteSize, sha256, status, uploadSource, uploadedAt, createdAt, updatedAt |
positions |
id, name, status, createdAt, updatedAt |
members |
id, employeeNo, displayName, department, positionId, email, phone, role, status, joinedAt, leftAt, createdAt, updatedAt |
exams |
id, status, revision, opensAt, closesAt, configJson, poolJson, paperIdsJson, bankVersionId, participantCount, publishedAt, canceledAt, createdAt, updatedAt |
examParticipations |
id, examId, memberId, employeeNo, displayName, department, positionSnapshotJson, status, attemptNumber, effectiveScore, startedAt, deadlineAt, submittedAt, submitReason, paperJson, answersJson, score, passed, createdAt, updatedAt |
examAttempts |
id, participationId, attemptNumber, revision, startedAt, deadlineAt, submittedAt, submitReason, paperJson, answersJson, score, passed, createdAt |
practiceSessions |
id, bankId, bankVersionId, mode, feedbackMode, requestedCount, actualCount, filtersJson, seed, status, revision, startedAt, submittedAt, abandonedAt, createdAt, updatedAt |
sessionQuestions |
id, sessionId, queueIndex, questionId, questionVersionId, presentedOptionIdsJson, selectionReason, createdAt |
attempts |
id, sessionQuestionId, sessionId, bankId, answerStatus, selectedOptionIdsJson, originalOutcome, answerKeyHash, judgeRuleVersion, clientSubmittedAt, submittedAt, createdAt |
questionUserStates |
id, bankId, questionId, questionVersionId, totalAttempts, correctCount, incorrectCount, skippedCount, lastOutcome, lastAttemptedAt, lastWrongAt, correctStreakAfterError, masteryState, userOverride, disputed, projectionVersion, createdAt, updatedAt |
前12个领域(banks 到 members,按领域依赖顺序)可恢复业务。组织考试与终态考试作答、个人练习/错题均仅保存迁入历史档案,不构造或写入正式考试/练习作答。进行中/未开始/取消的考试参与事实被 omitted 明示排除;组织导出不取员工个人学习。当前 active 授权题库闭包在同一 REPEATABLE READ 快照内选取/冻结,后续下载还核冻结 IDs 当前授权。
源 owner/admin 不映射账户或授权,普通迁入成员为 role=member;原 active/pending → pending 需重新激活,suspended/left 保持状态,原身份/角色/时间保存在 lineage。仅源 owner 与真实目标 owner 同工号时 OWNER_RECORD_ARCHIVED_COLLISION:完整源行只归档,不改工号、不建成员、不绑定 owner、不占新容量。其他工号冲突阻断。report.restored.members+report.archived.members 等于源数量。岗位名称/状态及成员位置引用按映射保留。
确认后 lineage 和 archive payload 持久保留;档案不在普通成员/考试列表,也没有独立公开 archive-read API。客户应保留完整下载包。七天结束仅清理临时 export/unconfirmed-import staging payload/交付对象;真实已恢复原件以及 confirmed lineage 保留。业务保留期清理由 lifecycle 独立契约约束;本次不提供生产业务删除入口。
下载字段类型目录
record-fields.json:19 个分区、202 个公开字段(34,120 字节,SHA256 1b16d336c24e28add9073c85e9010c192f7ce9b7f241970442e5404b0f46ad36)。它仅包含字段定义、类型、限额和说明,不含表名、内部实体、账号、客户资料或凭据。该文件是额外的格式参考,不在示例 manifest 的 files 中,不需要作为迁入分片上传。
fields[section]是该分区 record 的完整必填字段名;没有列出的字段不接受。可空字段也不能省略,应显式写null。fieldTypes[section][field]提供type(string / integer / boolean / json)与nullable;按字段需要增加maxLength、unsigned、format、日期precision/canonical。- 日期字段的
format=date-time要求 canonical UTC ISO 字符串并带毫秒,例如2026-10-14T00:00:00.000Z。原件 byteSize 的format=unsigned-decimal是无符号十进制字符串,不能转换为浮点数。 restorableSections、archivedSections和limits说明 v1 分类和传输上限。它是公开字段参考,不是完整 JSON Schema;枚举、题目/答案、引用、顺序、内容摘要、目标容量和权限等语义校验仍由实际 API 的正常预检决定。
限额与合成示例
总行数1,000,000、题库10,000、文件10,000、总交付字节5GiB;manifest8MiB;每行1MiB;每 gzip 分片最多1,000行,压缩/展开分别≤16MiB;单原件≤20MiB(沿已有原件上传限额)。这些是公开上限,不代表已做满容量性能验收。导出SQL批次500、迁入事务250,七天任务 TTL、24小时执行期限、120秒 CAS lease。源文件 hold 每次最多5分钟且不超过执行绝对期限,复制后 artifact 独立,不延长组织保留期。
公共合成包包含21rows/11files:1题固定 C-A-B 顺序、A 正确身份、两版解析、working 与两个合法 published versions、纯合成原JSON。没有客户数据、账户绑定或正式作答。manifest 与各文件摘要按实际字节生成;题目、发布版本和引用图按同一规则校验。静态 ZIP 仅方便下载,客户解压后使用 manifest+files,API 不解析 ZIP 上传。
示例内容完全合成,供检查格式与在授权测试空间体验迁入。实际迁入仍须按下面步骤上传、预检、确认和核对;不会使用示例中的源标识覆盖现有题库。
下载并使用纯合成资料包
下载合成示例 ZIP(10,075 字节)。ZIP 仅用于集中下载,当前页面和 API 都不接受直接上传 ZIP。先解压,不重新压缩其中的 JSONL.gz;再选择 manifest.json 和全部 11 个数据分片/原件。
ZIP 的 SHA256:
698301b6fba92b6c55ed5118b4af2e2faaf26f90c85c31536f80a5ee813f0b18
也可以逐个保存下表文件到同一目录。浏览器可能给重名下载加后缀;迁入按实际长度和 SHA256 匹配文件,不依赖本地改名或 File.type。
| 文件 | 内容 | 原字节长度 | SHA256 |
|---|---|---|---|
| manifest.json | 资料清单 | 4394 | 5b9d201897b4eacdfec575723ed02410c561923e6ed186bd5b843d7f6079ba72 |
| part-000001.jsonl.gz | banks:1 行 |
299 | 3e1409ab04086aa02f36d79e6b6efd6537a30c1a339648b9ab30c669096f02b6 |
| part-000002.jsonl.gz | sources:1 行 |
273 | ee52dd03b464514524ccbed0fec8f969a79b67c74df7ec709dae4fddf14cba30 |
| part-000003.jsonl.gz | questions:1 行 |
177 | 7b90ee68aaf8b515105f4020efe3ef8a5a10dd1e6fa446652e5fb45b4a3744a3 |
| part-000004.jsonl.gz | options:3 行 |
162 | a3c30a885c4438f6aaab75b9dcfc8cfda49f88792737cb39d51fc5aa3f14f625 |
| part-000005.jsonl.gz | questionVersions:2 行 |
660 | b03fe6dc8e1cdc25a79d374e02890dd27ca9b759e443db726fb0dc094b594d7f |
| part-000006.jsonl.gz | optionVersions:6 行 |
430 | 73ba1ce448477441896c5292f5dfe452a5e4287eeec13b929440690d63568c24 |
| part-000007.jsonl.gz | answerKeys:2 行 |
178 | 4c51dc64684048eafbb5424253b5065b5430562c473d44f8720f83d819d80f58 |
| part-000008.jsonl.gz | bankVersions:2 行 |
316 | 7c83407c6387735a6f90cb0a0aa97bd4ed94ae28b12a1d2366497f4da16f094a |
| part-000009.jsonl.gz | bankVersionItems:2 行 |
195 | 32a358a7a1bc8f6b80c540d3265e5238376ec20e3e323f5dc9af94f43a640a09 |
| part-000010.jsonl.gz | workingItems:1 行 |
178 | 03124c4bbb7379f281228d94b1a8cfc5025481b9dcb3c13b3f7c5564fd34909e |
| source-00000000-0000-4000-8000-000000000003-minimal-source.json | sources:0 行,原文件 |
151 | 7570b1a38b91d6777f24ac2aa9de9b5ad4a1c2f56aa0c699d50a30899250389b |
- 登录知序,进入明确选定的个人测试空间;或使用满足空组织与服务条件、且已授权的目标组织。源 manifest 中的 scope 只是来源说明,不替你选择目标。
- 打开“导出与迁入”,选中解压后的 manifest.json,再多选全部数据分片和原 JSON。页面逐个核对原字节摘要并上传,不能仅上传 ZIP 或解压后的 JSONL 文本。
- 开始预检,等待状态进入 awaiting_confirmation。核对当前目标、转换/归档清单和 blockers;预检没有写入业务资料。通过后在十分钟内显式确认。
- 等待后台处理完成,读取本轮核对报告。核对 restored、archived、differences 与 passed,不能把之前的 passed 代替本轮结果。
原件与 gzip 文件的 SHA256 都计算实际文件字节。JSONL 内容或压缩参数改变,即使题目文字看似相同,文件 SHA 也可能改变;不能只修改清单中的 SHA 绕过内容、答案身份、版本和引用校验。
Linux/macOS 可对每个文件执行 shasum -a 256 文件名;Windows PowerShell 可执行 Get-FileHash -Algorithm SHA256 文件名,再与上表和 manifest 对照。题目 contentHash、answerKeyHash、题库 contentDigest 属于内容/版本校验,不是 gzip 文件 SHA,不能互换。
清单和 JSONL 原行示例
以下是下载包中真实清单;不包含令牌、账号绑定、存储地址或客户资料。生成新来源包时请以完整导出或公开示例结构为起点;是否受支持由正常预检决定,未知 schema、字段、状态或摘要不会被静默接受。
展开完整 manifest.json
{
"schemaVersion": "zhixu.data-package/v1",
"packageId": "00000000-0000-4000-8000-000000000100",
"capturedAt": "2026-10-14T00:00:00.000Z",
"scope": {
"organizationId": null,
"bankIds": [
"00000000-0000-4000-8000-000000000001"
]
},
"sections": {
"banks": 1,
"sources": 1,
"questions": 1,
"options": 3,
"questionVersions": 2,
"optionVersions": 6,
"answerKeys": 2,
"bankVersions": 2,
"bankVersionItems": 2,
"workingItems": 1
},
"restorableSections": [
"banks",
"sources",
"questions",
"options",
"questionVersions",
"optionVersions",
"answerKeys",
"bankVersions",
"bankVersionItems",
"workingItems"
],
"archivedSections": [],
"omitted": [
{
"component": "members,positions,exams,learning",
"reason": "This synthetic personal package contains no identities or activity facts"
}
],
"files": [
{
"id": "part-000001",
"section": "banks",
"kind": "jsonl-gzip",
"filename": "part-000001.jsonl.gz",
"mimeType": "application/gzip",
"byteSize": "299",
"sha256": "3e1409ab04086aa02f36d79e6b6efd6537a30c1a339648b9ab30c669096f02b6",
"rowCount": 1
},
{
"id": "part-000002",
"section": "sources",
"kind": "jsonl-gzip",
"filename": "part-000002.jsonl.gz",
"mimeType": "application/gzip",
"byteSize": "273",
"sha256": "ee52dd03b464514524ccbed0fec8f969a79b67c74df7ec709dae4fddf14cba30",
"rowCount": 1
},
{
"id": "part-000003",
"section": "questions",
"kind": "jsonl-gzip",
"filename": "part-000003.jsonl.gz",
"mimeType": "application/gzip",
"byteSize": "177",
"sha256": "7b90ee68aaf8b515105f4020efe3ef8a5a10dd1e6fa446652e5fb45b4a3744a3",
"rowCount": 1
},
{
"id": "part-000004",
"section": "options",
"kind": "jsonl-gzip",
"filename": "part-000004.jsonl.gz",
"mimeType": "application/gzip",
"byteSize": "162",
"sha256": "a3c30a885c4438f6aaab75b9dcfc8cfda49f88792737cb39d51fc5aa3f14f625",
"rowCount": 3
},
{
"id": "part-000005",
"section": "questionVersions",
"kind": "jsonl-gzip",
"filename": "part-000005.jsonl.gz",
"mimeType": "application/gzip",
"byteSize": "660",
"sha256": "b03fe6dc8e1cdc25a79d374e02890dd27ca9b759e443db726fb0dc094b594d7f",
"rowCount": 2
},
{
"id": "part-000006",
"section": "optionVersions",
"kind": "jsonl-gzip",
"filename": "part-000006.jsonl.gz",
"mimeType": "application/gzip",
"byteSize": "430",
"sha256": "73ba1ce448477441896c5292f5dfe452a5e4287eeec13b929440690d63568c24",
"rowCount": 6
},
{
"id": "part-000007",
"section": "answerKeys",
"kind": "jsonl-gzip",
"filename": "part-000007.jsonl.gz",
"mimeType": "application/gzip",
"byteSize": "178",
"sha256": "4c51dc64684048eafbb5424253b5065b5430562c473d44f8720f83d819d80f58",
"rowCount": 2
},
{
"id": "part-000008",
"section": "bankVersions",
"kind": "jsonl-gzip",
"filename": "part-000008.jsonl.gz",
"mimeType": "application/gzip",
"byteSize": "316",
"sha256": "7c83407c6387735a6f90cb0a0aa97bd4ed94ae28b12a1d2366497f4da16f094a",
"rowCount": 2
},
{
"id": "part-000009",
"section": "bankVersionItems",
"kind": "jsonl-gzip",
"filename": "part-000009.jsonl.gz",
"mimeType": "application/gzip",
"byteSize": "195",
"sha256": "32a358a7a1bc8f6b80c540d3265e5238376ec20e3e323f5dc9af94f43a640a09",
"rowCount": 2
},
{
"id": "part-000010",
"section": "workingItems",
"kind": "jsonl-gzip",
"filename": "part-000010.jsonl.gz",
"mimeType": "application/gzip",
"byteSize": "178",
"sha256": "03124c4bbb7379f281228d94b1a8cfc5025481b9dcb3c13b3f7c5564fd34909e",
"rowCount": 1
},
{
"id": "00000000-0000-4000-8000-000000000003",
"section": "sources",
"kind": "source",
"filename": "source-00000000-0000-4000-8000-000000000003-minimal-source.json",
"mimeType": "application/json",
"byteSize": "151",
"sha256": "7570b1a38b91d6777f24ac2aa9de9b5ad4a1c2f56aa0c699d50a30899250389b",
"rowCount": 0
}
]
}
下面是第一个 gzip 分片解压后唯一一行的 JSON 对象(为阅读换行显示,原 JSONL 中整条对象占一行,文件末尾为 LF):
{
"section": "banks",
"sourceRef": "00000000-0000-4000-8000-000000000001",
"record": {
"id": "00000000-0000-4000-8000-000000000001",
"name": "迁移格式合成示例",
"description": "纯合成资料;固定选项顺序与两版解析",
"status": "active",
"usageMode": "practice_and_exam",
"currentBankVersionId": "00000000-0000-4000-8000-000000000011",
"workingRevision": 2,
"createdAt": "2026-10-14T00:00:00.000Z",
"updatedAt": "2026-10-14T00:00:00.000Z"
}
}
section 与该分片的 descriptor 一致;sourceRef 等于 record 的原主键。answerKeys 的原主键为 questionVersionId,其他分区为 id。迁入为新资源生成新 ID,并保持同包引用、题目/答案身份和发布版本闭合。选项使用 originalPosition 表示原顺序;发布/工作顺序分别用 position,不按显示字母重新排序。
示例中一个题目有两版题目内容和两个发布版本,三个选项的原顺序为 C、A、B,正确身份为 A。完整图谱已按同一题目策略和引用校验生成,不代表曾有员工完成过考试或作答。