系统架构
理解宿主、Vue 客户端、表单运行时、数据访问、模块、迁移与部署边界。
FormPlatform 系统架构
English: SYSTEM_ARCHITECTURE.md
1. 系统定位
FormPlatform 是一个表单驱动的 .NET 10 Web 平台。服务器提供身份、权限、表单存储、动态 ORM、提交/Trigger、问卷、Commerce 和扩展模块能力;Vue 3/Vite 客户端提供 Designer、Viewer、运行时控件和系统外壳。多数业务 UI 应由表单构成,只有需要复杂交互或可复用能力时才编写 Vue 控件或独立客户端模块。
核心目标是把四类内容分开演进:
- 平台 Host:闭源运行时、官方服务与系统端点;
- FormPlatform SDK:ORM、表单、Action/Trigger、migration 和错误协议;
- 表单资产:可在线编辑的 schema、metadata、action code 和全局 CSS;
- 客户模块:独立编译的服务器 DLL、配置、migration、API 和浏览器扩展。
2. 运行时全景
flowchart TB
Browser["Browser: Vue 3 SPA"] --> Router["Vue Router + system layout forms"]
Router --> Runtime["FormReader / FormRenderer / Form Runtime"]
Runtime --> Http["Unified HTTP client"]
Http --> Host["ASP.NET Core .NET 10 Host"]
Host --> Endpoints["Hosting/Endpoints domain route groups"]
Endpoints --> Services["Domain services"]
Services --> ORM["FormPlatform.Sdk DataAccess ORM"]
Services --> Store["IFormStore"]
ORM --> DB[("PostgreSQL / MySQL / SQL Server")]
Store --> Memory["Memory"]
Store --> File["File"]
Store --> DB
Modules["Trusted modules"] --> Host
Modules --> ORM
Modules --> ClientExt["Client extension modules"]
ClientExt --> Runtime
浏览器永远不应直接知道表名、连接字符串或拼接 SQL。端点负责认证和输入边界,领域服务负责业务规则,ORM/Store 负责持久化。
3. 服务器组合根与启动顺序
`src/FormPlatform.Host/Program.cs` 仅负责组合:加载配置和模块、注册官方服务、认证授权、中间件、端点组与 SPA fallback。业务路由位于 `src/FormPlatform.Host/Hosting/Endpoints/*Endpoints.cs`;认证配置位于 `src/FormPlatform.Host/Hosting/FormPlatformAuthenticationRegistration.cs`。
启动顺序是:
1. 创建 `WebApplicationBuilder`,读取基础配置。
2. 扫描 `src/FormPlatform.Host/Modules/**/module.json`,验证 manifest 和程序集兼容性。
3. 让模块加入自己的配置源。
4. 注册 Core、Survey、Commerce、Feature、认证和模块服务。
5. 构建应用,安装统一异常、状态码、认证和授权中间件。
6. 映射官方端点,再映射模块端点,最后映射静态文件和 SPA fallback。
7. Hosted Services 先执行数据库 migrations,再执行角色、Data Model、系统表单和种子数据初始化。
固定 schema 的顺序尤其重要:
ModuleDatabaseMigrationRunner
-> FormPlatform.Core migrations
-> FormPlatform.Commerce migrations
-> customer module migrations
ManagementDatabaseInitializer (identity/role seed only)
other idempotent seeders and system-form initializers
4. 客户端架构
`src/FormPlatform.Host/ClientApp` 是 Vue 3 SPA。`vue-router` 处理 Designer、Viewer、管理页、受访者和模块路由;Header、Left Pane、Right Pane、Footer 等系统外壳也可由系统表单提供。
关键层次:
- `FormReader`:加载 schema、建立数据状态、验证和 Runtime API;
- `FormRenderer`:递归选择并呈现控件;
- `formComponentRegistry`:内置和扩展控件注册表,支持按需加载;
- `actionRuntime`:Action Code 的稳定 Application Context 与临时 Form Action Context;
- `httpClient.js`:JSON/blob 请求、语言 header 和统一错误解析;
- `i18n.js`:客户端消息目录,支持 `@key` 系统内容;
- `globalFormStyles`:加载合并后的 `/api/assets/forms.css`。
Designer 模式不得读取真实业务 API。集合控件在 Designer 中应呈现稳定模拟数据,避免无权限请求和误删空控件。
5. 表单资产与生命周期
一个表单由以下逻辑资产组成:
- `FormDefinition`:控件树、属性、事件和 `usedCssClasses`;
- `FormMetadata`:类型、匿名状态、数据映射、Action/Trigger、实体等;
- Action module:客户端 action code;
- 全局 CSS:保存表单时提取 Tailwind 类;后台服务从持久化候选索引生成带 fingerprint 的全局 CSS 工件。
`IFormStore` 支持 Memory、File 和关系数据库。管理用户、安全、Data Model、ACL、Survey/Commerce 管理数据始终使用 Management Database,不随 FormStorage 改成文件。
典型提交链:
Viewer/Pagination submit
-> client validation
-> POST form/survey endpoint
-> ACL/deployment checks
-> FormSubmissionDispatcher
-> validate trigger
-> before transaction/batch/entity/collection triggers
-> ORM transaction
-> after triggers
-> commit
-> Platform response + toast/navigation
Hidden 控件不提交;空的可空输入应省略或转换为 null;服务器仍必须重新验证,不能信任客户端结果。
6. 数据与 ORM
数据分为三类:
1. 平台管理数据:用户、角色、ACL、Data Model、系统 metadata;
2. 表单资产:schema、metadata、Action Code;
3. 业务记录:普通实体、问卷响应、模块数据。
Data Model 把逻辑实体映射到表/视图:Attribute 对应列,Reference 描述跨实体关系,Collection 描述一对多。表单控件的 `propertyName` 通过 Form/Data Mapping 指向 Attribute,而不是让控件直接指定数据库列。
ORM 提供 provider dialect、参数化查询、投影、filter、sort、分页、reference join、insert/update/delete、事务、schema inspection 和 migration 计划。查询只投影请求字段;关联显示应使用 Reference 路径,例如不同外键分别定义 `createdBy`、`updatedBy`,而不是共享 `REFERENCE__TABLENAME__`。
只有 provider metadata、锁、DDL、动态 deployment 表或 ORM 尚未表达的数据库能力才保留手写 SQL。业务输入绝不能直接成为标识符或 SQL 片段。
7. 数据库迁移与动态表
固定表由 `IDatabaseMigrationModule` 声明,每个 migration 包含 PostgreSQL、MySQL、SQL Server 三套有序语句。Runner 使用数据库锁、`app_schema_migrations` 和 SHA-256 checksum;已经发布的 migration 永远不能修改,只能增加更大的 ID。
以下不属于固定 migration:
- deployment 根据问卷字段生成的 `data_*` 响应表;
- 可替换关系型 FormStore 自己的存储结构;
- 幂等种子数据。
`DatabaseMigrations:Enabled=false` 只适用于发布流水线已经先行迁移的环境。
8. 模块与 SDK 边界
可信模块实现 SDK 中的 `IFormPlatformSdkModule`,可参与四个阶段:配置、服务注册、中间件、端点映射。模块通过 `FormPlatform.Sdk.dll` 使用 ORM、表单、Action/Trigger、migration、错误协议和模块入口契约;`FormPlatform.Extension.Abstractions.dll` 保留为底层共享加载契约。
`module.json` 固定模块名、版本、入口程序集、入口类型及 SDK/Host 兼容范围。Host 拒绝重复名称、越界路径、版本不符、引用 Host DLL 或加载第二份 SDK 的模块。模块与 Host 在同一进程中运行,是可信扩展,不是安全沙箱。
浏览器扩展在 Vue mount 前加载,可以注册控件、事件、路由、Action API、Runtime API 和 i18n 消息。静态资产由 `/extension-assets/{module}/...` 提供。
9. 身份与权限
系统用户使用默认 Cookie;受访者使用独立 Cookie,并可通过 Google/Facebook OIDC 建立外部身份。管理员代填时必须保持系统用户身份与受访者业务上下文分离。
表单能力包括 read、edit、delete 和 survey assistance。拒绝规则优先;Administrator 拥有平台默认能力;FormDesigner 和 SurveyAssistant 根据表单类型获得不同默认权限。所有服务器端入口都必须再次鉴权,客户端按钮可见性只是 UX。
Form Center 使用数据库端 ACL 候选 ID 和 cursor pagination,避免读取全部表单后在客户端过滤。
10. 错误、日志与国际化
所有 API 失败使用 `PlatformErrorResponse`:`code`、`messageKey`、`fallback`、`parameters`、`fieldErrors`、`status`、`traceId`。端点使用 `PlatformResults`;可复用领域/模块代码抛出 `PlatformApiException`;未捕获异常由 `PlatformExceptionHandler` 记录并隐藏 500 内部细节。
客户端只通过 `httpClient.js` 解析错误。`messageKey` 是稳定协议,`fallback` 保证未知语言仍可读;字段错误交给 FormReader/inline editor,不应错误显示在主表单。
日志包括 Console、Debug 和可选 Rolling File。SQL 日志由 `DataAccess:LogQuerySql`/`LogMutationSql` 控制;生产环境通常关闭参数值,避免泄露密码和问卷内容。
11. 官方业务子系统
- Survey:respondent、list、deployment、动态响应表、附件、进度/完成状态、管理员代填、匿名/外部身份。
- Commerce:product、cart、order、payment、PayPal/Stripe/WeChat provider 和地理树。
- System Forms:布局、Form Center、Data Model、Mapping、ACL、Survey 管理等可编辑系统 UI。
这些是官方模块化服务,但仍与 Host 同仓库;第三方功能应优先做成独立模块。
12. 部署拓扑
开发环境通常使用 Vite dev server 5173 代理 .NET 5080;发布后 ASP.NET Core 直接提供 `wwwroot`。Linux/Raspberry Pi 推荐 systemd + Nginx/HTTPS;Windows 推荐 IIS reverse proxy。秘密使用 User Secrets、环境变量、systemd credentials 或受 ACL 保护的外部 JSON,不提交到 `appsettings.json`。
13. 目录导航
| 目录 | 职责 |
|---|---|
| `src/FormPlatform.Host/Program.cs`, `src/FormPlatform.Host/Hosting/` | 组合根、中间件、端点、模块加载 |
| `src/FormPlatform.Host/Data/` | 官方领域服务、Store、系统表单、migration/seed |
| `src/FormPlatform.Sdk/` | 公共 SDK:ORM、metadata、query、transaction、trigger 和共享契约 |
| `src/FormPlatform.Extension.Abstractions/` | 模块生命周期/manifest 契约 |
| `src/FormPlatform.Licensing/` | 签名/加密许可证基础组件 |
| `src/FormPlatform.Host/ClientApp/src/` | Vue SPA、Designer、Viewer、控件和 Runtime |
| `src/FormPlatform.Host/Modules/` | 开发期已部署可信模块包 |
| `samples/` | 可独立阅读的扩展示例 |
| `tests/` | PostgreSQL 集成测试和 Playwright E2E |
| `docs/` | 核心手册、专题文档和变更日志 |
14. 不可破坏的架构规则
1. 服务器是权限和验证的最终裁决者。
2. Vue/表单 JSON 不拼 SQL、不接触连接字符串。
3. 固定 DDL 进入 migration;initializer 只 seed。
4. 模块引用 SDK/Abstractions,不引用 Host。
5. API 错误使用统一协议;系统文本使用 message key。
6. Designer 不读取运行时数据。
7. 表单保存经过 `PublishingFormStore`,保持 CSS 和缓存一致。
8. 新功能优先复用表单和现有控件,再考虑新控件或独立 Vue 页面。