--- sidebar_position: 5 title: System Architecture sidebar_label: Architecture description: MindSpace service boundaries, storage architecture, deployment, and repository integration --- # 系统架构与代码组织 ## 总体架构 ```text H5 / Web / Desktop | API Gateway Auth / CSRF / CORS / Rate Limit / Request ID | MindSpace Application Layer Account / Space / Asset / Page / Publish Security / Audit / Agent Job / Analytics / Template | Infrastructure SQL Database / Object Storage / Queue / Cache | goose Execution Layer Agent / Tools / Document Processing / Page Generation ``` ## 架构决策 ### MindSpace 是平台层 现有 goose 不直接承担公网多租户空间、用户配额或发布系统。MindSpace 通过受控接口调用 goose,把它作为 AI 和 CLI 执行层。 原因: - goose 的本地文件能力不等于多租户存储权限。 - 公网发布需要独立的 URL、版本、风控和审计模型。 - 用户空间生命周期与 Agent 会话生命周期不同。 - 平台服务需要独立扩缩容和安全边界。 ### 模块化单体优先 MVP 建议先使用模块化单体: - 一套部署。 - 一个主数据库。 - 清晰的模块接口和表归属。 - 异步任务通过队列或数据库任务表处理。 达到以下条件再拆微服务: - 发布流量与管理 API 的扩展模式明显不同。 - 文件处理任务影响在线请求稳定性。 - 安全扫描需要独立资源或合规隔离。 - 团队可以独立维护和部署模块。 ## 推荐代码边界 仓库最终目录以实际技术选型为准,但职责建议如下: ```text crates/ mindspace-domain/ # 领域类型、状态机、策略 mindspace-storage/ # 数据库和对象存储适配 mindspace-service/ # 应用服务和事务 mindspace-security/ # PII、HTML、资源和发布扫描 mindspace-agent/ # goose 任务适配 goose-server/ # HTTP 路由、认证和 OpenAPI ui/h5/ src/features/mindspace/ account/ dashboard/ assets/ pages/ publishing/ security/ templates/ ``` 如果 MVP 先落在现有 H5 Node 服务中,也要保持同样的领域边界,避免路由文件直接混合 SQL、磁盘路径、权限和业务状态。 ## 分层职责 ### HTTP 层 - 解析请求。 - 身份认证。 - DTO 校验。 - 调用应用服务。 - 映射错误和响应。 HTTP 路由不能直接拼接存储路径或更新多个业务表。 ### 应用服务层 - 事务边界。 - 权限和配额检查。 - 状态转换。 - 领域对象协调。 - 审计和事件写入。 ### 领域层 - 状态机。 - 可见性和发布策略。 - 套餐规则。 - 脱敏策略。 - 与框架和数据库无关的校验。 ### 基础设施层 - SQL repository。 - 对象存储。 - 缓存和队列。 - goose 调用。 - 安全扫描器。 ## 存储架构 ### 元数据 使用 SQL 数据库保存: - 用户和套餐。 - 空间和分类。 - 资产和版本。 - 页面和发布。 - 安全扫描。 - Agent job。 - 审计和统计。 ### 文件内容 MVP 可使用本地受控目录,生产建议对象存储。 存储 key 示例: ```text users/{user_uuid}/assets/{asset_uuid}/versions/{version_uuid} publications/{publication_uuid}/{version_uuid}/index.html publications/{publication_uuid}/{version_uuid}/assets/{resource_uuid} ``` 这些 key 仅供服务端使用,不能出现在公开 URL 中。 ### 页面发布包 发布时构建不可变 bundle: - `index.html` - 受控 CSS - 允许的本地 JavaScript - 图片和字体副本 - manifest - security report reference 线上访问永远读取发布 bundle,不读取草稿目录。 ## 一致性策略 ### 上传 1. 创建 upload session 并预留配额。 2. 写临时对象。 3. 计算 checksum 和扫描。 4. 创建资产版本。 5. 确认配额。 6. 提交事务。 7. 清理临时对象。 ### 发布 1. 锁定 Page。 2. 创建不可变版本。 3. 安全扫描。 4. 构建 bundle。 5. 写入发布存储。 6. 创建或更新 Publication。 7. 写审计和 outbox 事件。 8. 原子切换当前版本。 任何步骤失败,旧线上版本继续可用。 ## 异步任务 建议统一任务状态: ```text queued -> running -> succeeded -> failed -> cancelled -> timed_out ``` 任务字段: - id - type - user_id - idempotency_key - payload - attempts - max_attempts - available_at - started_at - finished_at - last_error_code - last_error_message ## 缓存 可缓存: - 公开用户主页。 - 公开页面 manifest。 - 套餐和模板配置。 - 访问统计聚合。 不可仅依赖缓存: - 所有权。 - 私人访问授权。 - 页面是否下线。 - Agent job token 是否有效。 下线操作必须主动失效公开缓存。 ## 外部发布隔离 建议正式页面使用独立静态域名或 sandbox 子域: ```text app.go.tkmind.cn # 登录和管理 pages.go.tkmind.cn # 公开页面 assets.go.tkmind.cn # 公开资源 ``` 如果首期仍使用同域: - 公开页面使用不同 cookie scope。 - 不向页面域发送管理会话 cookie。 - 设置严格 CSP。 - 预览 iframe 使用 sandbox。 ## 配置项 至少包括: - 数据库连接。 - 存储驱动和根路径/bucket。 - 免费套餐配额。 - 上传大小和类型。 - 页面数量限制。 - Agent 超时和并发。 - 发布域名。 - 分享 token 长度。 - 安全扫描规则版本。 - 审计保留期。 - 临时文件 TTL。 - 访问统计开关。 密钥不得写入仓库或公开页面 bundle。 ## 可观测性 每个请求和任务携带: - `request_id` - `user_id`,日志中按策略脱敏 - `job_id` - `asset_id` - `page_id` - `publication_id` 指标: - 上传成功率和耗时。 - 配额拒绝次数。 - Agent 队列长度和失败率。 - 安全扫描命中率。 - 发布成功率和构建耗时。 - 公开页面 4xx/5xx。 - 越权请求和限流次数。 日志不得记录文件正文、密码、分享 token、身份证、完整邮箱或完整路径。 ## 数据迁移 - 所有 schema 变更使用版本化迁移。 - 先添加兼容字段,再发布读写代码,最后清理旧字段。 - 大表回填使用批处理。 - 对象存储迁移保存旧新 key 映射。 - 每次迁移说明前向、回滚和数据验证步骤。