Files
TallyNote/artifacts/tallynote.architecture.json
T
Qiufeng 9719429f4a
TallyNote release / linux-x64 (push) Failing after 2m41s
feat: add TallyNote local reimbursement ledger
2026-08-29 01:02:29 +08:00

193 lines
7.5 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"schema_version": 1,
"diagram_type": "architecture",
"meta": {
"title": "TallyNote 本地优先报销账本架构",
"locale": "zh-CN",
"output": "tallynote-architecture.html",
"quality_profile": "showcase",
"viewBox": [1360, 800],
"views": [
{
"id": "request-path",
"label": "主请求路径",
"focus": ["operator", "web", "api", "security", "expense", "db"],
"note": "从管理员在浏览器快速记账,到安全会话和 SQLite 持久化。"
},
{
"id": "attachment-consistency",
"label": "附件一致性",
"focus": ["api", "expense", "attachment", "filesystem", "db", "audit"],
"note": "查看 staging、内容校验、原子晋级与事务回滚如何保持记录和文件一致。"
},
{
"id": "export-recovery",
"label": "导出与恢复",
"focus": ["api", "export", "db", "filesystem", "janitor", "audit"],
"note": "跟踪筛选快照、异步 ZIP 构建、会话绑定下载和重启恢复。"
},
{
"id": "admin-governance",
"label": "管理员治理",
"focus": ["operator", "web", "api", "admin", "security", "audit"],
"note": "查看管理员初始化、停用、重置密码和全局审计边界。"
}
]
},
"components": [
{
"id": "operator",
"type": "external",
"label": "使用者 / 管理员",
"sublabel": "Chrome 浏览器",
"pos": [30, 250],
"size": [150, 80]
},
{
"id": "web",
"type": "frontend",
"label": "React 工作台",
"sublabel": "React 19 + Vite",
"tag": "桌面优先",
"pos": [220, 250],
"size": [190, 80]
},
{
"id": "api",
"type": "backend",
"label": "Fastify REST API",
"sublabel": "/api/* + 静态托管",
"tag": "单进程入口",
"pos": [450, 250],
"size": [190, 80]
},
{
"id": "security",
"type": "security",
"label": "认证与请求防护",
"sublabel": "Argon2id · Cookie · CSRF",
"tag": "HttpOnly / Origin",
"pos": [450, 50],
"size": [190, 80]
},
{
"id": "expense",
"type": "backend",
"label": "账目业务服务",
"sublabel": "筛选 · 状态 · 乐观锁",
"tag": "至少一张凭证",
"pos": [680, 250],
"size": [190, 80]
},
{
"id": "db",
"type": "database",
"label": "SQLite + Drizzle",
"sublabel": "WAL · 外键 · 事务",
"tag": "同机持久化",
"pos": [910, 250],
"size": [190, 80]
},
{
"id": "attachment",
"type": "backend",
"label": "附件流水线",
"sublabel": "staging · 内容识别 · 晋级",
"tag": "20 MB / 文件",
"pos": [680, 430],
"size": [190, 80]
},
{
"id": "filesystem",
"type": "cloud",
"label": "本地数据文件系统",
"sublabel": "files / staging / exports",
"tag": "同一卷 · UUID 路径",
"pos": [910, 430],
"size": [190, 80]
},
{
"id": "export",
"type": "backend",
"label": "异步导出构建器",
"sublabel": "Excel · ZIP · manifest",
"tag": "会话绑定任务",
"pos": [910, 50],
"size": [190, 80]
},
{
"id": "audit",
"type": "backend",
"label": "审计子系统",
"sublabel": "追加写入 · 前后值 · 请求 ID",
"tag": "只读查询",
"pos": [680, 50],
"size": [190, 80]
},
{
"id": "admin",
"type": "backend",
"label": "管理员管理",
"sublabel": "初始化 · 停用 · 重置",
"tag": "最后管理员保护",
"pos": [450, 590],
"size": [190, 80]
},
{
"id": "janitor",
"type": "backend",
"label": "启动清理与恢复",
"sublabel": "孤儿文件 · 过期任务 · 会话",
"tag": "每 60 秒 + 重启",
"pos": [30, 590],
"size": [150, 80]
}
],
"boundaries": [
{
"kind": "region",
"label": "TallyNote 单实例本地运行时(localhost / Docker)",
"wraps": ["web", "api", "security", "expense", "db", "attachment", "filesystem", "export", "audit", "admin", "janitor"],
"pad": 28
},
{
"kind": "security-group",
"label": "受保护 API 边界",
"wraps": ["api", "security", "admin", "expense", "attachment", "export", "audit"],
"pad": 18
}
],
"connections": [
{ "id": "operator-web", "from": "operator", "to": "web", "label": "浏览器交互", "variant": "emphasis", "fromSide": "right", "toSide": "left", "labelAt": [200, 210] },
{ "id": "web-api", "from": "web", "to": "api", "label": "HTTP / REST", "variant": "emphasis", "fromSide": "right", "toSide": "left", "labelAt": [430, 210] },
{ "id": "security-api", "from": "security", "to": "api", "label": "Cookie + CSRF / Origin", "variant": "security", "fromSide": "bottom", "toSide": "top", "labelAt": [900, 195] },
{ "id": "api-expense", "from": "api", "to": "expense", "label": "账目路由", "fromSide": "right", "toSide": "left", "labelAt": [700, 210] },
{ "id": "expense-db", "from": "expense", "to": "db", "label": "SQLite transaction", "variant": "emphasis", "fromSide": "right", "toSide": "left", "labelAt": [890, 210] },
{ "id": "expense-attachment", "from": "expense", "to": "attachment", "label": "multipart 上传", "fromSide": "bottom", "toSide": "top", "labelAt": [880, 380] },
{ "id": "attachment-files", "from": "attachment", "to": "filesystem", "label": "staging → atomic promote", "variant": "emphasis", "fromSide": "right", "toSide": "left", "labelAt": [890, 405] },
{ "id": "api-export", "from": "api", "to": "export", "label": "snapshot → async job", "variant": "dashed", "fromSide": "right", "toSide": "left", "via": [[660, 290], [660, 25], [890, 25], [890, 90]], "labelAt": [775, 12] },
{ "id": "export-db", "from": "export", "to": "db", "label": "快照读取", "fromSide": "bottom", "toSide": "top", "labelAt": [1070, 195] },
{ "id": "export-files", "from": "export", "to": "filesystem", "label": "ZIP / Excel / manifest", "variant": "dashed", "fromSide": "right", "toSide": "bottom", "via": [[1280, 90], [1280, 700], [1005, 700]], "labelAt": [1170, 720] },
{ "id": "expense-audit", "from": "expense", "to": "audit", "label": "操作审计", "variant": "dashed", "fromSide": "top", "toSide": "bottom", "labelAt": [620, 195] },
{ "id": "admin-api", "from": "admin", "to": "api", "label": "管理员管理", "fromSide": "top", "toSide": "bottom", "labelAt": [700, 530] },
{ "id": "janitor-files", "from": "janitor", "to": "filesystem", "label": "孤儿文件 / 过期任务", "variant": "dashed", "fromSide": "bottom", "toSide": "bottom", "via": [[105, 735], [1005, 735]], "labelAt": [555, 715] }
],
"cards": [
{
"dot": "cyan",
"title": "请求与数据",
"items": ["前端通过统一 API 客户端携带会话 Cookie 和 CSRF 令牌", "账目写入、附件元数据和审计在 SQLite 事务内保持一致"]
},
{
"dot": "emerald",
"title": "文件可靠性",
"items": ["附件先落 staging,完成格式、大小和内容校验后原子晋级", "失败路径删除已晋级字节,启动时继续清理孤儿文件"]
},
{
"dot": "amber",
"title": "导出与治理",
"items": ["导出冻结不可变快照,后台生成 Excel、ZIP 和可选 manifest", "管理员变更、记录操作、附件和导出都进入只读审计日志"]
}
]
}