docs: add speckle-compatible platform planning
This commit is contained in:
+20
-1
@@ -1,8 +1,22 @@
|
||||
# Speckle Server - Business Logic & Architecture
|
||||
|
||||
## Tài liệu nền tảng mới ASP.NET/Blazor
|
||||
|
||||
Bộ tài liệu dưới đây dùng cho hướng xây mới một nền tảng Speckle-compatible bằng Blazor WebAssembly, ASP.NET Core, PostgreSQL và C++ services:
|
||||
|
||||
- [Business Requirements](./aspnet-blazor-speckle-platform-business-requirements.md)
|
||||
- [Technical Architecture](./aspnet-blazor-speckle-platform-technical-architecture.md)
|
||||
- [Speckle Compatibility Contract](./speckle-compatibility-contract.md)
|
||||
- [Data Model](./aspnet-blazor-speckle-platform-data-model.md)
|
||||
- [API Spec](./aspnet-blazor-speckle-platform-api-spec.md)
|
||||
- [Upload, Convert và Viewer Pipeline](./upload-convert-viewer-pipeline.md)
|
||||
- [Blazor UI Module Spec](./blazor-ui-module-spec.md)
|
||||
- [MVP Implementation Plan](./mvp-implementation-plan.md)
|
||||
|
||||
Đây là tài liệu tập trung vào Business Logic của toàn bộ giải pháp **Speckle Server**, dùng để tái thiết kế, chuyển đổi nền tảng hoặc để onboarding thành viên mới một cách nhanh nhất.
|
||||
|
||||
## 1. Quick Info
|
||||
|
||||
Speckle là một "Data Hub" mã nguồn mở dành cho ngành AEC (Architecture, Engineering, Construction). Speckle không lưu trữ file tĩnh mà **băm nhỏ (decompose) các model 3D thành dữ liệu Object/JSON**.
|
||||
|
||||
- **Tech Stack hiện tại**:
|
||||
@@ -11,10 +25,11 @@ Speckle là một "Data Hub" mã nguồn mở dành cho ngành AEC (Architecture
|
||||
- Khác: Three.js (Viewer), Postgres (DB), Redis (Cache/PubSub), Minio/S3 (Blob storage).
|
||||
|
||||
## 2. Các thực thể cốt lõi (Core Entities)
|
||||
|
||||
Bạn cần hiểu các thuật ngữ sau vì chúng là xương sống của business:
|
||||
|
||||
| Thực thể | Mô tả |
|
||||
| --- | --- |
|
||||
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **User** | Người dùng hệ thống. Có Role (ServerAdmin, ServerUser). |
|
||||
| **Stream (Project)** | Tương tự như một kho chứa (Repository) lưu trữ model. |
|
||||
| **Branch (Model)** | Một nhánh của Stream, đại diện cho những phiên bản của một thiết kế hoặc một category (ví dụ: `architectural`, `structural`). |
|
||||
@@ -23,6 +38,7 @@ Bạn cần hiểu các thuật ngữ sau vì chúng là xương sống của bu
|
||||
| **Workspace** | (Tính năng Enterprise) Không gian làm việc quản lý nhiều Project và Billing. |
|
||||
|
||||
## 3. Kiến trúc luồng hệ thống
|
||||
|
||||
1. **Desktop Client / Web App** sử dụng REST API (hoặc SDK) kết nối với Server với token.
|
||||
2. Dữ liệu khi Push được gọi là **Commit**, dữ liệu payload được chia thành nhiều Objects và push đồng thời lên backend.
|
||||
3. Backend GraphQL xử lý Metadata, còn dữ liệu thô (Object payload) được gửi lên Server theo lô (batch) và nhét vào **Blob storage (S3)** hoặc lưu trực tiếp vào cơ sở dữ liệu `objects`.
|
||||
@@ -33,6 +49,7 @@ Bạn cần hiểu các thuật ngữ sau vì chúng là xương sống của bu
|
||||
- **Automate:** Trigger các function tự động hóa của user trên server.
|
||||
|
||||
## 4. Documentation Structure
|
||||
|
||||
Chi tiết luồng hoạt động từng hệ thống con được ghi trong các thư mục sau:
|
||||
|
||||
- [Backend API & DB (Node.js)](./server/README.md)
|
||||
@@ -41,7 +58,9 @@ Chi tiết luồng hoạt động từng hệ thống con được ghi trong cá
|
||||
- [Core 3D Engine (Viewer)](./viewer/README.md)
|
||||
|
||||
## 5. Portability Note (Viết lại ngôn ngữ)
|
||||
|
||||
**Tính tái định tuyến khả thi (High Portability)**:
|
||||
|
||||
- Logic backend tương đối stateless nhưng phụ thuộc nặng vào **GraphQL Federation/Apollo** và Postgres DB Schema.
|
||||
- Có thể rewrite qua Go / C# / Rust nhưng phải đảm bảo:
|
||||
1. Kế thừa chuẩn xác thuật toán Hash Object của Speckle (để objectId luôn khớp).
|
||||
|
||||
@@ -0,0 +1,541 @@
|
||||
# API Spec nền tảng Speckle-compatible ASP.NET/Blazor
|
||||
|
||||
## 1. Phạm vi
|
||||
|
||||
Tài liệu này mô tả API mục tiêu cho backend ASP.NET Core. Có hai lớp API:
|
||||
|
||||
- Speckle-compatible API: giữ để connector/viewer/SDK hiện tại chạy được.
|
||||
- Product API mới: phục vụ Blazor UI và các tính năng riêng như issue, review, dashboard, admin.
|
||||
|
||||
Chi tiết contract legacy nằm trong `speckle-compatibility-contract.md`. Tài liệu này tập trung vào cấu trúc API tổng thể và các endpoint nghiệp vụ mới.
|
||||
|
||||
## 2. Chuẩn chung
|
||||
|
||||
Base URL:
|
||||
|
||||
```text
|
||||
https://{server-host}
|
||||
```
|
||||
|
||||
Auth:
|
||||
|
||||
```http
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
Response lỗi REST:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": {
|
||||
"code": "project_not_found",
|
||||
"message": "Project was not found.",
|
||||
"traceId": "..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Pagination:
|
||||
|
||||
```json
|
||||
{
|
||||
"totalCount": 120,
|
||||
"cursor": "next-cursor",
|
||||
"items": []
|
||||
}
|
||||
```
|
||||
|
||||
Quy tắc:
|
||||
|
||||
- API trả UTC ISO timestamp.
|
||||
- JSON field dùng camelCase.
|
||||
- Endpoint stream/file lớn không trả payload qua GraphQL.
|
||||
- Mọi request có `X-Correlation-Id` nếu client truyền; nếu không server tự tạo.
|
||||
|
||||
## 3. Auth API
|
||||
|
||||
### `GET /auth/accesscode`
|
||||
|
||||
Speckle-compatible browser auth flow.
|
||||
|
||||
### `POST /auth/token`
|
||||
|
||||
Đổi access code lấy bearer token.
|
||||
|
||||
### `POST /auth/logout`
|
||||
|
||||
Logout/revoke current session.
|
||||
|
||||
### `GET /api/me`
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "user-id",
|
||||
"email": "user@example.com",
|
||||
"name": "User",
|
||||
"serverRole": "user"
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /api/me/tokens`
|
||||
|
||||
List personal tokens.
|
||||
|
||||
### `POST /api/me/tokens`
|
||||
|
||||
Create personal token.
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "CI token",
|
||||
"scopes": ["streams:read", "streams:write"],
|
||||
"expiresAt": "2026-12-31T00:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
## 4. GraphQL endpoint
|
||||
|
||||
### `POST /graphql`
|
||||
|
||||
Dùng cho:
|
||||
|
||||
- Speckle-compatible metadata.
|
||||
- Blazor queries nếu đội chọn GraphQL cho UI.
|
||||
- Connector legacy mutations.
|
||||
|
||||
Schema tối thiểu:
|
||||
|
||||
- `Query.project`
|
||||
- `Query.stream`
|
||||
- `Query.streams`
|
||||
- `Project.models`
|
||||
- `Project.versions`
|
||||
- `Project.object`
|
||||
- `Mutation.projectMutations`
|
||||
- `Mutation.modelMutations`
|
||||
- `Mutation.versionMutations`
|
||||
- legacy `streamCreate`, `branchCreate`, `commitCreate`
|
||||
|
||||
## 5. Project API mới
|
||||
|
||||
### `GET /api/projects`
|
||||
|
||||
Query params:
|
||||
|
||||
- `search`
|
||||
- `role`
|
||||
- `limit`
|
||||
- `cursor`
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"totalCount": 1,
|
||||
"cursor": null,
|
||||
"items": [
|
||||
{
|
||||
"id": "project-id",
|
||||
"name": "Hospital A",
|
||||
"description": "BIM coordination",
|
||||
"visibility": "private",
|
||||
"role": "owner",
|
||||
"updatedAt": "2026-05-12T00:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `POST /api/projects`
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Hospital A",
|
||||
"description": "BIM coordination",
|
||||
"visibility": "private"
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /api/projects/{projectId}`
|
||||
|
||||
Trả project detail kèm role hiện tại.
|
||||
|
||||
### `PATCH /api/projects/{projectId}`
|
||||
|
||||
Cập nhật name, description, visibility, allowPublicComments.
|
||||
|
||||
### `DELETE /api/projects/{projectId}`
|
||||
|
||||
Soft delete project. Chỉ owner/admin.
|
||||
|
||||
## 6. Project members API
|
||||
|
||||
### `GET /api/projects/{projectId}/members`
|
||||
|
||||
List collaborator.
|
||||
|
||||
### `POST /api/projects/{projectId}/invites`
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"email": "reviewer@example.com",
|
||||
"role": "reviewer"
|
||||
}
|
||||
```
|
||||
|
||||
### `PATCH /api/projects/{projectId}/members/{userId}`
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"role": "contributor"
|
||||
}
|
||||
```
|
||||
|
||||
### `DELETE /api/projects/{projectId}/members/{userId}`
|
||||
|
||||
Revoke access.
|
||||
|
||||
## 7. Model API mới
|
||||
|
||||
### `GET /api/projects/{projectId}/models`
|
||||
|
||||
Query params:
|
||||
|
||||
- `search`
|
||||
- `sourceApp`
|
||||
- `contributorId`
|
||||
- `withVersionsOnly`
|
||||
- `limit`
|
||||
- `cursor`
|
||||
|
||||
### `POST /api/projects/{projectId}/models`
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Architecture/Walls",
|
||||
"description": "Architectural wall model"
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /api/projects/{projectId}/models/{modelId}`
|
||||
|
||||
### `PATCH /api/projects/{projectId}/models/{modelId}`
|
||||
|
||||
### `DELETE /api/projects/{projectId}/models/{modelId}`
|
||||
|
||||
Soft delete model nếu policy cho phép.
|
||||
|
||||
## 8. Version API mới
|
||||
|
||||
### `GET /api/projects/{projectId}/models/{modelId}/versions`
|
||||
|
||||
List version.
|
||||
|
||||
### `POST /api/projects/{projectId}/models/{modelId}/versions`
|
||||
|
||||
Tạo version sau khi object đã upload.
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"objectId": "root-object-id",
|
||||
"message": "Initial upload",
|
||||
"sourceApplication": "Revit",
|
||||
"totalChildrenCount": 12345,
|
||||
"parents": []
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /api/projects/{projectId}/versions/{versionId}`
|
||||
|
||||
### `PATCH /api/projects/{projectId}/versions/{versionId}`
|
||||
|
||||
Cập nhật message.
|
||||
|
||||
### `DELETE /api/projects/{projectId}/versions/{versionId}`
|
||||
|
||||
Soft delete version.
|
||||
|
||||
## 9. Object API
|
||||
|
||||
Giữ nguyên Speckle-compatible endpoints:
|
||||
|
||||
| Method | Path | Mục tiêu |
|
||||
| ------ | -------------------------------------------- | ------------------------- |
|
||||
| POST | `/objects/{projectId}` | Upload object batch. |
|
||||
| GET | `/objects/{projectId}/{objectId}` | Pull object graph. |
|
||||
| GET | `/objects/{projectId}/{objectId}/single` | Pull single object. |
|
||||
| POST | `/api/diff/{projectId}` | Hỏi object còn thiếu. |
|
||||
| POST | `/api/getobjects/{projectId}` | Pull nhiều object legacy. |
|
||||
| POST | `/api/v2/projects/{projectId}/object-stream` | Pull object stream v2. |
|
||||
|
||||
API mới không nên thay thế các endpoint này trong MVP.
|
||||
|
||||
## 10. Blob/File API
|
||||
|
||||
### `POST /api/stream/{projectId}/blob`
|
||||
|
||||
Legacy-compatible blob upload.
|
||||
|
||||
### `GET /api/stream/{projectId}/blob/{blobId}`
|
||||
|
||||
Download blob.
|
||||
|
||||
### `GET /api/stream/{projectId}/blobs`
|
||||
|
||||
List blob.
|
||||
|
||||
### `POST /api/files/upload-url`
|
||||
|
||||
API mới để tạo upload URL.
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"projectId": "project-id",
|
||||
"fileName": "model.ifc",
|
||||
"contentType": "application/octet-stream",
|
||||
"sizeBytes": 123456
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"fileId": "file-id",
|
||||
"uploadUrl": "https://...",
|
||||
"expiresAt": "2026-05-12T01:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### `POST /api/files/{fileId}/start-import`
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"projectId": "project-id",
|
||||
"modelName": "Imported/IFC",
|
||||
"sourceApplication": "IFC Importer"
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /api/file-uploads/{fileUploadId}`
|
||||
|
||||
Trả trạng thái import.
|
||||
|
||||
## 11. Viewer API
|
||||
|
||||
### `GET /api/viewer/projects/{projectId}/resources`
|
||||
|
||||
Query params:
|
||||
|
||||
- `resourceIdString`
|
||||
- `savedViewId`
|
||||
- `applyHomeView`
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"resourceIdString": "model-id@version-id",
|
||||
"groups": [
|
||||
{
|
||||
"projectId": "project-id",
|
||||
"items": [
|
||||
{
|
||||
"modelId": "model-id",
|
||||
"versionId": "version-id",
|
||||
"objectId": "root-object-id"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /api/viewer-derivatives/{projectId}/{versionId}/manifest`
|
||||
|
||||
### `GET /api/viewer-derivatives/{projectId}/{versionId}/artifacts/*`
|
||||
|
||||
### `POST /api/projects/{projectId}/saved-views`
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Coordination view",
|
||||
"resourceIds": "model-id@version-id",
|
||||
"viewerState": {}
|
||||
}
|
||||
```
|
||||
|
||||
## 12. Issue API
|
||||
|
||||
### `GET /api/projects/{projectId}/issues`
|
||||
|
||||
Query params:
|
||||
|
||||
- `status`
|
||||
- `priority`
|
||||
- `assigneeUserId`
|
||||
- `modelId`
|
||||
- `versionId`
|
||||
- `search`
|
||||
|
||||
### `POST /api/projects/{projectId}/issues`
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Pipe clashes with beam",
|
||||
"description": "Check level 3 corridor.",
|
||||
"priority": "high",
|
||||
"modelId": "model-id",
|
||||
"versionId": "version-id",
|
||||
"objectIds": ["object-a", "object-b"],
|
||||
"viewerState": {}
|
||||
}
|
||||
```
|
||||
|
||||
### `PATCH /api/projects/{projectId}/issues/{issueId}`
|
||||
|
||||
Cập nhật title, status, priority, assignee, due date.
|
||||
|
||||
### `POST /api/projects/{projectId}/issues/{issueId}/comments`
|
||||
|
||||
Thêm comment vào issue.
|
||||
|
||||
## 13. Review API
|
||||
|
||||
### `POST /api/projects/{projectId}/reviews`
|
||||
|
||||
Tạo review session.
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "MEP coordination review",
|
||||
"dueAt": "2026-06-01T00:00:00Z",
|
||||
"items": [
|
||||
{
|
||||
"modelId": "model-id",
|
||||
"versionId": "version-id",
|
||||
"reviewerUserId": "user-id"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /api/projects/{projectId}/reviews`
|
||||
|
||||
### `GET /api/projects/{projectId}/reviews/{reviewId}`
|
||||
|
||||
### `POST /api/projects/{projectId}/reviews/{reviewId}/items/{itemId}/decision`
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "approved_with_comments",
|
||||
"decisionNote": "Approved after fixing issue #123"
|
||||
}
|
||||
```
|
||||
|
||||
## 14. Dashboard API
|
||||
|
||||
### `GET /api/dashboard/summary`
|
||||
|
||||
Trả summary cho user hiện tại:
|
||||
|
||||
```json
|
||||
{
|
||||
"projectCount": 12,
|
||||
"openIssueCount": 34,
|
||||
"pendingReviewCount": 5,
|
||||
"recentVersionCount": 8
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /api/projects/{projectId}/dashboard`
|
||||
|
||||
Trả health của project: latest models, open issues, conversion jobs, storage usage.
|
||||
|
||||
## 15. Admin API
|
||||
|
||||
### `GET /api/admin/system-info`
|
||||
|
||||
### `GET /api/admin/users`
|
||||
|
||||
### `PATCH /api/admin/users/{userId}`
|
||||
|
||||
### `GET /api/admin/jobs`
|
||||
|
||||
### `POST /api/admin/jobs/{jobId}/retry`
|
||||
|
||||
### `GET /api/admin/audit-logs`
|
||||
|
||||
Admin API cần server role admin và audit đầy đủ.
|
||||
|
||||
## 16. Webhook API
|
||||
|
||||
### `GET /api/projects/{projectId}/webhooks`
|
||||
|
||||
### `POST /api/projects/{projectId}/webhooks`
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "https://example.com/webhook",
|
||||
"events": ["version.created", "issue.updated"],
|
||||
"secret": "plain-secret-only-on-create"
|
||||
}
|
||||
```
|
||||
|
||||
### `POST /api/projects/{projectId}/webhooks/{webhookId}/test`
|
||||
|
||||
### `DELETE /api/projects/{projectId}/webhooks/{webhookId}`
|
||||
|
||||
## 17. Internal worker API
|
||||
|
||||
Các endpoint này không public:
|
||||
|
||||
- `POST /internal/jobs/{jobId}/heartbeat`
|
||||
- `POST /internal/file-imports/{fileUploadId}/progress`
|
||||
- `POST /internal/file-imports/{fileUploadId}/complete`
|
||||
- `POST /internal/file-imports/{fileUploadId}/fail`
|
||||
- `PUT /api/viewer-derivatives/{projectId}/{versionId}/artifacts/*`
|
||||
- `POST /api/viewer-derivatives/{projectId}/{versionId}/publish`
|
||||
- `POST /api/viewer-derivatives/{projectId}/{versionId}/fail`
|
||||
|
||||
Bảo mật:
|
||||
|
||||
- Dùng worker token riêng.
|
||||
- Chỉ allow từ internal network nếu có thể.
|
||||
- Log mọi callback.
|
||||
|
||||
## 18. API acceptance criteria
|
||||
|
||||
- Swagger/OpenAPI sinh được cho REST API mới.
|
||||
- GraphQL schema export được để connector test.
|
||||
- Contract test cho Speckle endpoints chạy trong CI.
|
||||
- API lỗi trả JSON chuẩn, không trả HTML.
|
||||
- Upload/pull object lớn không vượt memory threshold đã định.
|
||||
@@ -0,0 +1,953 @@
|
||||
# Tài liệu nghiệp vụ nền tảng quản lý mô hình Speckle-compatible
|
||||
|
||||
## 1. Mục tiêu sản phẩm
|
||||
|
||||
Xây dựng một nền tảng quản lý, chia sẻ, versioning và xem mô hình 3D/BIM/CAD tương tự Speckle Server, nhưng phát triển mới theo hướng:
|
||||
|
||||
- Frontend dùng Blazor WebAssembly.
|
||||
- Backend dùng ASP.NET Core.
|
||||
- Database chính dùng PostgreSQL.
|
||||
- Service xử lý nặng dùng C++ native cho upload object, file import, convert và viewer derivative.
|
||||
- Viewer 3D dùng lại Speckle Viewer thông qua JavaScript interop thay vì viết lại engine 3D.
|
||||
- Tương thích Speckle connector ở mức API contract cần thiết để connector hiện tại có thể đăng nhập, upload, pull và tạo version/model.
|
||||
|
||||
Mục tiêu nghiệp vụ không phải clone toàn bộ Speckle Server, mà xây một "Speckle-compatible model platform" có core upload/view/version ổn định, sau đó mở rộng thêm các tính năng nghiệp vụ riêng như issue, approval, review, dashboard, kiểm tra BIM, báo cáo và tích hợp nội bộ.
|
||||
|
||||
## 2. Phạm vi tổng thể
|
||||
|
||||
### 2.1 Trong phạm vi
|
||||
|
||||
- Quản lý người dùng, đăng nhập, token, app/connector access.
|
||||
- Quản lý project.
|
||||
- Quản lý model trong project.
|
||||
- Quản lý version của model.
|
||||
- Upload/pull object graph theo contract tương thích Speckle.
|
||||
- File upload và file import IFC/STL/OBJ.
|
||||
- View model 3D trên web.
|
||||
- Large model streaming bằng viewer derivative/tile.
|
||||
- Comment, issue, markup, review.
|
||||
- Phân quyền theo project/model/action.
|
||||
- Dashboard, báo cáo, hoạt động gần đây.
|
||||
- Webhook/API cho tích hợp.
|
||||
- Admin configuration, quota, audit log.
|
||||
|
||||
### 2.2 Ngoài phạm vi MVP
|
||||
|
||||
- Billing/subscription thương mại đầy đủ.
|
||||
- Marketplace plugin.
|
||||
- Full clone workspace/automation/gendo/ACC của Speckle.
|
||||
- Viết lại Speckle Viewer bằng C# hoặc WebGL thuần.
|
||||
- Desktop connector mới nếu connector Speckle hiện tại đã đáp ứng.
|
||||
|
||||
## 3. Vai trò người dùng
|
||||
|
||||
| Vai trò | Mô tả | Quyền chính |
|
||||
| ------------------ | --------------------------- | --------------------------------------------- |
|
||||
| System Admin | Quản trị toàn hệ thống | Cấu hình server, user, quota, storage, audit |
|
||||
| Organization Admin | Quản trị tổ chức/công ty | Quản lý thành viên, workspace, policy |
|
||||
| Project Owner | Chủ dự án | Quản lý project, phân quyền, xóa/sửa project |
|
||||
| Project Manager | Quản lý dự án | Theo dõi model, review, issue, approval |
|
||||
| Model Author | Người upload/cập nhật model | Upload model, tạo version, sửa metadata |
|
||||
| Reviewer | Người kiểm tra/phản hồi | Xem model, comment, issue, approval |
|
||||
| Viewer | Người xem | Xem model được cấp quyền |
|
||||
| Connector App | Ứng dụng desktop/plugin | Auth, upload object, pull object, tạo version |
|
||||
| Conversion Worker | Worker hệ thống | Lấy job import, convert file, publish kết quả |
|
||||
|
||||
## 4. Khái niệm nghiệp vụ lõi
|
||||
|
||||
| Khái niệm | Ý nghĩa trong nền tảng mới | Tương đương Speckle |
|
||||
| ----------------- | -------------------------------------------------------------- | ---------------------- |
|
||||
| Project | Không gian chứa model, version, team, issue | Stream/Project |
|
||||
| Model | Một nhánh dữ liệu trong project, ví dụ Architecture, Structure | Branch/Model |
|
||||
| Version | Một bản phát hành/snapshot của model | Commit/Version |
|
||||
| Object | Đơn vị dữ liệu bất biến, lưu JSON object graph | Object |
|
||||
| Root Object | Object gốc mà version trỏ tới | referencedObject |
|
||||
| Blob | File thô/attachment được upload | Blob storage item |
|
||||
| File Import | Quy trình convert file thô thành model/version | File upload/import |
|
||||
| Viewer Resource | Thông tin để viewer biết cần load model/version/object nào | Viewer resource |
|
||||
| Viewer Derivative | Dữ liệu render tối ưu cho model lớn | Large model derivative |
|
||||
| Issue | Vấn đề gắn với model/version/view/camera | Comment/issue mở rộng |
|
||||
| Review | Phiên kiểm tra/phê duyệt model/version | Custom |
|
||||
|
||||
## 5. Feature 01 - Đăng nhập, tài khoản và token
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Cho phép người dùng và connector đăng nhập an toàn, nhận token, refresh token và sử dụng API theo scope.
|
||||
|
||||
### Tác nhân
|
||||
|
||||
- Người dùng web.
|
||||
- Speckle connector.
|
||||
- Admin.
|
||||
- Ứng dụng tích hợp bên thứ ba.
|
||||
|
||||
### Chức năng
|
||||
|
||||
- Đăng nhập bằng email/password.
|
||||
- Đăng nhập SSO/OIDC ở phase sau.
|
||||
- Tạo token cá nhân.
|
||||
- Tạo app token cho connector.
|
||||
- Refresh token.
|
||||
- Logout/revoke token.
|
||||
- Quản lý session web bằng cookie hoặc bearer token.
|
||||
- Hỗ trợ OAuth-like flow tương thích Speckle connector:
|
||||
- `/auth/accesscode`
|
||||
- `/auth/token`
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- Token gồm token id và secret, secret chỉ hiển thị một lần khi tạo.
|
||||
- Token phải có scope rõ ràng: `streams:read`, `streams:write`, `profile:read`, `tokens:write`, `users:read`.
|
||||
- Token có thể giới hạn theo project/workspace.
|
||||
- Token hết hạn phải tự động invalid.
|
||||
- Connector chỉ được upload/pull project mà user có quyền.
|
||||
- Admin có thể revoke token khi cần.
|
||||
|
||||
### Luồng chính
|
||||
|
||||
1. User đăng nhập web.
|
||||
2. Connector mở browser để xin quyền.
|
||||
3. Server trả access code về redirect URL của connector.
|
||||
4. Connector đổi access code lấy token và refresh token.
|
||||
5. Connector dùng token gọi object/GraphQL API.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- Connector hiện tại đăng nhập được mà không cần sửa code connector.
|
||||
- Token bị revoke không thể gọi API.
|
||||
- Token thiếu scope bị từ chối đúng lỗi 403.
|
||||
- Token hết hạn không còn hợp lệ.
|
||||
|
||||
## 6. Feature 02 - Quản lý ứng dụng/connector
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Cho phép hệ thống nhận diện các ứng dụng như web app, desktop manager, connector, Excel, PowerBI hoặc app nội bộ.
|
||||
|
||||
### Chức năng
|
||||
|
||||
- Seed sẵn default apps tương thích Speckle connector.
|
||||
- Admin tạo app mới.
|
||||
- App có id, secret, redirect URL, scope mặc định.
|
||||
- User xem danh sách app đã cấp quyền.
|
||||
- User revoke quyền app.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- Default connector app ID phải ổn định để connector cũ dùng được.
|
||||
- App trusted có thể bỏ qua màn hình consent nếu policy cho phép.
|
||||
- Khi app scope thay đổi, token cũ phải được xem xét revoke hoặc yêu cầu re-consent.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- Connector Desktop/Auth Service đăng nhập bằng app id tương thích.
|
||||
- App bị xóa không thể tạo token mới.
|
||||
- User revoke app thì token app hết hiệu lực.
|
||||
|
||||
## 7. Feature 03 - Quản lý Project
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Project là container chính cho mô hình, team, issue, file, version, dashboard và quyền truy cập.
|
||||
|
||||
### Chức năng
|
||||
|
||||
- Tạo project.
|
||||
- Cập nhật tên, mô tả, visibility.
|
||||
- Xóa project.
|
||||
- Archive project.
|
||||
- Clone/copy project ở phase sau.
|
||||
- Danh sách project của user.
|
||||
- Tìm kiếm project theo tên/mô tả/mã dự án.
|
||||
|
||||
### Thuộc tính chính
|
||||
|
||||
- Project ID.
|
||||
- Name.
|
||||
- Description.
|
||||
- Visibility: Private, Public, Organization, Workspace.
|
||||
- Owner.
|
||||
- CreatedAt, UpdatedAt.
|
||||
- Region/storage location nếu triển khai multi-region.
|
||||
- Project code/client/job number.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- Project Private chỉ người được mời mới xem được.
|
||||
- Project Public có thể xem không cần đăng nhập nếu policy cho phép.
|
||||
- Chỉ Owner/Admin được xóa project.
|
||||
- Xóa project phải trigger cleanup object/blob/derivative theo job nền.
|
||||
- Project có model/version thì không hard delete ngay, nên chuyển sang archived hoặc soft delete trước.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- User chỉ thấy project mình có quyền.
|
||||
- Project mới có model mặc định `main` hoặc cho phép tạo model đầu tiên khi upload.
|
||||
- Xóa/Archive project không làm connector nhìn thấy project trong danh sách.
|
||||
|
||||
## 8. Feature 04 - Thành viên và phân quyền project
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Quản lý ai được xem, upload, review, approve và quản trị dữ liệu trong project.
|
||||
|
||||
### Vai trò project
|
||||
|
||||
| Role | Quyền |
|
||||
| ----------- | --------------------------------------------- |
|
||||
| Owner | Toàn quyền, phân quyền, xóa project |
|
||||
| Manager | Quản lý model/version/issue/review |
|
||||
| Contributor | Upload model, tạo version, comment |
|
||||
| Reviewer | Xem, comment, tạo issue, approve nếu được cấp |
|
||||
| Viewer | Chỉ xem |
|
||||
|
||||
### Chức năng
|
||||
|
||||
- Mời user bằng email.
|
||||
- Cập nhật role.
|
||||
- Thu hồi quyền.
|
||||
- Rời project.
|
||||
- Danh sách thành viên.
|
||||
- Pending invitation.
|
||||
- Public access toggle.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- Project phải luôn có ít nhất một Owner.
|
||||
- User không thể tự hạ quyền nếu là Owner cuối cùng.
|
||||
- Role cao hơn kế thừa quyền role thấp hơn.
|
||||
- Connector dùng quyền của user sở hữu token.
|
||||
- Public project vẫn có thể giới hạn comment/upload.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- Viewer không upload được.
|
||||
- Contributor upload được nhưng không đổi quyền người khác.
|
||||
- Reviewer tạo issue/comment nhưng không xóa version nếu không có quyền.
|
||||
|
||||
## 9. Feature 05 - Quản lý Model
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Model là đơn vị dữ liệu có version riêng trong project, ví dụ `Architecture`, `Structure`, `MEP`, `Site`, hoặc `A/B/C`.
|
||||
|
||||
### Chức năng
|
||||
|
||||
- Tạo model.
|
||||
- Đổi tên model.
|
||||
- Xóa/archive model.
|
||||
- Hiển thị tree model theo dấu `/`.
|
||||
- Lọc model theo source app, contributor, trạng thái import.
|
||||
- Pending imported model khi file import chưa xong.
|
||||
|
||||
### Thuộc tính chính
|
||||
|
||||
- Model ID.
|
||||
- Project ID.
|
||||
- Name/fullName.
|
||||
- Display name.
|
||||
- Description.
|
||||
- Author.
|
||||
- CreatedAt, UpdatedAt.
|
||||
- Preview image.
|
||||
- Source app gần nhất.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- Trong cùng project, tên model phải unique theo case-insensitive.
|
||||
- Tên model có thể dùng `/` để tạo cây thư mục ảo.
|
||||
- Xóa model phải xử lý version liên quan.
|
||||
- Model do connector tạo phải map được với branch/model name cũ.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- Connector upload vào branch/model `main` tự tạo nếu chưa có.
|
||||
- UI hiển thị model tree đúng với tên có `/`.
|
||||
- Không cho tạo hai model trùng tên.
|
||||
|
||||
## 10. Feature 06 - Quản lý Version
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Version là snapshot bất biến của model tại một thời điểm, trỏ tới root object đã upload.
|
||||
|
||||
### Chức năng
|
||||
|
||||
- Tạo version từ connector hoặc web.
|
||||
- Cập nhật message của version.
|
||||
- Xóa/archive version.
|
||||
- Move version sang model khác.
|
||||
- Danh sách version theo model.
|
||||
- So sánh version.
|
||||
- Mark version received khi connector pull.
|
||||
|
||||
### Thuộc tính chính
|
||||
|
||||
- Version ID.
|
||||
- Project ID.
|
||||
- Model ID.
|
||||
- Root object ID.
|
||||
- Message.
|
||||
- Source application.
|
||||
- Author.
|
||||
- Parents.
|
||||
- Total children count.
|
||||
- CreatedAt.
|
||||
- Preview URL.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- Version immutable về root object; chỉ metadata như message có thể sửa.
|
||||
- Root object phải tồn tại trong project trước khi tạo version.
|
||||
- Version có parent dùng để dựng lịch sử/diff.
|
||||
- Xóa version không xóa ngay object vì object có thể được version khác dùng.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- Connector tạo commit/version thành công sau khi upload object.
|
||||
- Pull latest version lấy đúng root object.
|
||||
- Version list phân trang và sắp xếp theo thời gian mới nhất.
|
||||
|
||||
## 11. Feature 07 - Object Upload/Pull Core
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Đây là lõi quan trọng nhất. Hệ thống phải lưu object graph bất biến, dedup theo object id/hash và stream object hiệu quả cho connector/viewer.
|
||||
|
||||
### Chức năng
|
||||
|
||||
- Diff object IDs: client hỏi object nào server đã có.
|
||||
- Upload batch object.
|
||||
- Download single object.
|
||||
- Download root object cùng closure.
|
||||
- Download batch object theo danh sách ID.
|
||||
- Stream object dạng gzip.
|
||||
- Stream object dạng `id<TAB>json`.
|
||||
- Hỗ trợ attribute mask cho object stream.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- Object ID phải dài 32 ký tự nếu theo Speckle hash.
|
||||
- Object là immutable: object cùng ID không được update nội dung.
|
||||
- Nếu object đã tồn tại thì bỏ qua insert.
|
||||
- Object thuộc project nào thì chỉ user có quyền project đó đọc/ghi.
|
||||
- Batch upload phải reject object quá lớn theo cấu hình.
|
||||
- Không dùng GraphQL cho object payload lớn.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- Upload lại cùng model không duplicate object.
|
||||
- Connector có thể `diff -> upload missing -> create version`.
|
||||
- Viewer có thể stream model mà không tải toàn bộ vào memory backend.
|
||||
- Response format tương thích objectloader Speckle.
|
||||
|
||||
## 12. Feature 08 - File Upload và Blob Storage
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Cho phép upload file thô như IFC, STL, OBJ, PDF, ảnh attachment, comment attachment.
|
||||
|
||||
### Chức năng
|
||||
|
||||
- Upload blob qua REST multipart.
|
||||
- Generate presigned upload URL.
|
||||
- Download blob.
|
||||
- List blob theo project.
|
||||
- Delete blob.
|
||||
- Blob diff để kiểm tra file đã tồn tại.
|
||||
- Attachment cho comment/issue.
|
||||
|
||||
### Thuộc tính chính
|
||||
|
||||
- Blob ID.
|
||||
- Project ID.
|
||||
- User ID.
|
||||
- File name.
|
||||
- File type.
|
||||
- File size.
|
||||
- File hash.
|
||||
- Upload status.
|
||||
- Object storage key.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- Blob upload phải kiểm tra quyền ghi project.
|
||||
- File import blob không nên hiện lẫn với derivative artifacts.
|
||||
- Attachment nhỏ có thể hiển thị trong comment/issue.
|
||||
- Blob bị xóa phải xóa metadata và object storage theo job nền nếu cần.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- User upload IFC qua web thành công.
|
||||
- Worker tải được file từ blob storage bằng token nội bộ hoặc app token.
|
||||
- User không có quyền không tải được blob private.
|
||||
|
||||
## 13. Feature 09 - File Import và Conversion
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Chuyển file thô thành model/version có thể xem trên web và pull qua connector nếu cần.
|
||||
|
||||
### File type ưu tiên
|
||||
|
||||
- IFC.
|
||||
- STL.
|
||||
- OBJ.
|
||||
- GLTF/GLB ở phase sau.
|
||||
- RVT/DWG không xử lý trực tiếp nếu không có license/SDK hợp lệ.
|
||||
|
||||
### Chức năng
|
||||
|
||||
- Start file import sau khi upload.
|
||||
- Queue job import.
|
||||
- Worker nhận job.
|
||||
- Convert file thành Speckle object graph hoặc viewer derivative.
|
||||
- Tạo model nếu chưa có.
|
||||
- Tạo version mới.
|
||||
- Update trạng thái import.
|
||||
- Trả warning/error cho UI.
|
||||
|
||||
### Trạng thái import
|
||||
|
||||
- Queued.
|
||||
- Processing.
|
||||
- Succeeded.
|
||||
- Failed.
|
||||
- TimedOut.
|
||||
- Cancelled.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- File nhỏ/trung bình: convert thành object graph đầy đủ.
|
||||
- File lớn: tạo root object tối thiểu và viewer derivative/tile.
|
||||
- Import thất bại không được tạo version lỗi.
|
||||
- Retry có giới hạn số lần và compute budget.
|
||||
- User phải thấy tiến độ/trạng thái rõ ràng.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- Upload IFC tạo version xem được.
|
||||
- File lỗi có thông báo dễ hiểu.
|
||||
- Worker restart không làm mất job.
|
||||
- Một job không bị hai worker xử lý đồng thời.
|
||||
|
||||
## 14. Feature 10 - Viewer Web bằng Speckle Viewer
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Người dùng xem, kiểm tra, đo đạc, lọc, comment và review model trong Blazor WebAssembly.
|
||||
|
||||
### Chức năng
|
||||
|
||||
- Load một hoặc nhiều model/version.
|
||||
- Orbit/pan/zoom.
|
||||
- Select object.
|
||||
- Isolate/hide/show object.
|
||||
- Color by property.
|
||||
- Section box.
|
||||
- Measurements: point, distance, perpendicular, area.
|
||||
- Object snap cho đo đạc.
|
||||
- Explode.
|
||||
- View modes.
|
||||
- Screenshot.
|
||||
- Saved views.
|
||||
- Comment bubble/issue marker.
|
||||
- Compare version/diff.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- Viewer engine dùng `@speckle/viewer`, Blazor chỉ điều khiển qua JS interop.
|
||||
- Viewer không tự quyết quyền; backend phải xác thực resource trước.
|
||||
- Private model cần token hợp lệ để tải object/derivative.
|
||||
- Saved view phải lưu camera, filter, section box, resource ID.
|
||||
- Comment/issue phải gắn với resource/version/object/viewer state.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- Model upload từ connector mở được trong Blazor viewer.
|
||||
- Selection trả về object id và property.
|
||||
- Section/measurement hoạt động trên model bình thường.
|
||||
- Large model không làm browser full-load object graph nếu derivative có sẵn.
|
||||
|
||||
## 15. Feature 11 - Large Model Viewer Derivative
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Cho phép mở IFC/model lớn hàng trăm MB bằng tiled binary streaming, tránh browser OOM.
|
||||
|
||||
### Chức năng
|
||||
|
||||
- Detect large model.
|
||||
- Generate manifest.
|
||||
- Generate binary tiles.
|
||||
- Publish derivative artifacts.
|
||||
- Load manifest.
|
||||
- Stream tiles theo nhu cầu viewer.
|
||||
- LOD theo camera/frustum.
|
||||
- Evict tile theo memory budget.
|
||||
- Metadata on-demand khi select.
|
||||
|
||||
### Trạng thái derivative
|
||||
|
||||
- Missing.
|
||||
- Queued.
|
||||
- Processing.
|
||||
- Ready.
|
||||
- Failed.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- Large model không fallback sang full object graph nếu rủi ro OOM.
|
||||
- Manifest chỉ public khi status Ready.
|
||||
- Tile/artifact phải immutable theo version.
|
||||
- Derivative artifacts không tính như user blob thường.
|
||||
- Selection trên derivative phải map được về element/global ID.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- Model lớn hiển thị first render nhanh.
|
||||
- Browser không tải toàn bộ geometry.
|
||||
- User thấy thông báo nếu derivative đang processing/failed.
|
||||
- Tile private không tải được nếu thiếu quyền project.
|
||||
|
||||
## 16. Feature 12 - Comment, Issue và Markup
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Cho phép trao đổi, phản hồi, tạo vấn đề và lưu ngữ cảnh viewer trên model/version.
|
||||
|
||||
### Chức năng
|
||||
|
||||
- Tạo comment thread.
|
||||
- Reply comment.
|
||||
- Edit comment.
|
||||
- Archive/resolve comment.
|
||||
- Tạo issue từ viewer.
|
||||
- Gắn screenshot.
|
||||
- Gắn camera/viewer state.
|
||||
- Gắn selected object IDs.
|
||||
- Mention user.
|
||||
- Attachment blob.
|
||||
- Lọc issue theo trạng thái, người phụ trách, model/version.
|
||||
|
||||
### Issue status
|
||||
|
||||
- Open.
|
||||
- In Review.
|
||||
- Resolved.
|
||||
- Closed.
|
||||
- Reopened.
|
||||
|
||||
### Issue fields
|
||||
|
||||
- Title.
|
||||
- Description.
|
||||
- Status.
|
||||
- Priority.
|
||||
- Assignee.
|
||||
- Due date.
|
||||
- Project/model/version/resource.
|
||||
- Viewer state.
|
||||
- Selected object IDs.
|
||||
- Screenshot.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- Comment thường dùng cho trao đổi nhẹ.
|
||||
- Issue dùng cho việc cần theo dõi trạng thái.
|
||||
- Issue phải giữ được viewer context để mở lại đúng vị trí.
|
||||
- User chỉ thấy issue trong project mình có quyền.
|
||||
- Archive không hard delete.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- Click issue mở viewer đúng camera/section/selection.
|
||||
- Người được mention nhận notification.
|
||||
- Reviewer không có quyền edit issue người khác nếu policy không cho phép.
|
||||
|
||||
## 17. Feature 13 - Review và Approval Workflow
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Cho phép kiểm tra và phê duyệt version/model theo quy trình dự án.
|
||||
|
||||
### Chức năng
|
||||
|
||||
- Tạo review session cho version.
|
||||
- Chọn reviewer.
|
||||
- Reviewer approve/reject/request changes.
|
||||
- Ghi nhận quyết định, ghi chú và thời gian.
|
||||
- Khóa version khi đã approved nếu policy yêu cầu.
|
||||
- Dashboard pending reviews.
|
||||
|
||||
### Trạng thái review
|
||||
|
||||
- Draft.
|
||||
- Submitted.
|
||||
- In Review.
|
||||
- Approved.
|
||||
- Rejected.
|
||||
- Changes Requested.
|
||||
- Cancelled.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- Một version có thể có nhiều review session, nhưng chỉ một session active theo loại review.
|
||||
- Người tạo version không nên tự approve nếu policy yêu cầu separation of duties.
|
||||
- Approval phải được audit log.
|
||||
- Reject/Changes Requested nên yêu cầu comment.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- Project Manager tạo review cho version.
|
||||
- Reviewer nhận notification và approve/reject.
|
||||
- Version hiển thị badge approval status.
|
||||
- Audit log lưu đầy đủ người quyết định và thời điểm.
|
||||
|
||||
## 18. Feature 14 - Metadata, Property và Search
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Cho phép tìm kiếm, lọc, thống kê và khai thác property của object/model.
|
||||
|
||||
### Chức năng
|
||||
|
||||
- Xem property object khi select.
|
||||
- Search object theo name/type/category/property.
|
||||
- Filter object theo property.
|
||||
- Group/count theo property.
|
||||
- Export property table.
|
||||
- Index metadata sau khi upload/import.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- Metadata object graph có thể rất lớn, cần indexing async.
|
||||
- Search phải giới hạn theo quyền project.
|
||||
- Với large derivative, metadata tải on-demand.
|
||||
- Property key cần normalize để tránh trùng do casing/source app.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- User chọn object thấy property.
|
||||
- User lọc được object theo category/type.
|
||||
- Search không trả object thuộc project không có quyền.
|
||||
|
||||
## 19. Feature 15 - Dashboard và báo cáo
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Cung cấp tổng quan dự án, tiến độ model, vấn đề, review và hoạt động.
|
||||
|
||||
### Chức năng
|
||||
|
||||
- Project dashboard.
|
||||
- Model/version statistics.
|
||||
- Recent activity.
|
||||
- Open issue count.
|
||||
- Review pending count.
|
||||
- Upload/import status.
|
||||
- Storage usage.
|
||||
- Contributor activity.
|
||||
- Export report PDF/Excel ở phase sau.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- Dashboard phải tôn trọng quyền user.
|
||||
- Số liệu nặng nên tính async/cache.
|
||||
- Admin dashboard thấy toàn hệ thống, user dashboard chỉ thấy project liên quan.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- Project Manager thấy model mới nhất, issue mở, review pending.
|
||||
- Admin thấy storage/quota/user activity.
|
||||
|
||||
## 20. Feature 16 - Notification
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Thông báo cho người dùng khi có hoạt động quan trọng trong project.
|
||||
|
||||
### Kênh
|
||||
|
||||
- In-app notification.
|
||||
- Email.
|
||||
- Webhook.
|
||||
- Slack/Teams ở phase sau.
|
||||
|
||||
### Sự kiện thông báo
|
||||
|
||||
- Được mời vào project.
|
||||
- Có version mới.
|
||||
- File import hoàn tất/lỗi.
|
||||
- Comment reply/mention.
|
||||
- Issue assigned.
|
||||
- Review requested.
|
||||
- Review approved/rejected.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- User có thể cấu hình notification preference.
|
||||
- Không gửi notification cho hành động do chính user tạo nếu policy không yêu cầu.
|
||||
- Notification phải có deep link đến project/model/version/issue.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- Mention user tạo notification.
|
||||
- File import fail gửi notification cho uploader.
|
||||
- User tắt email thì không nhận email nhưng vẫn có in-app.
|
||||
|
||||
## 21. Feature 17 - Activity Stream và Audit Log
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Ghi nhận hoạt động để truy vết, báo cáo và kiểm tra bảo mật.
|
||||
|
||||
### Activity cho user/project
|
||||
|
||||
- Project created/updated/deleted.
|
||||
- Model created/updated/deleted.
|
||||
- Version created/deleted.
|
||||
- File uploaded/imported.
|
||||
- Comment/issue/review changes.
|
||||
|
||||
### Audit bảo mật
|
||||
|
||||
- Login/logout.
|
||||
- Token created/revoked.
|
||||
- Permission changed.
|
||||
- Admin configuration changed.
|
||||
- Failed auth attempts.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- Audit log không cho user thường sửa/xóa.
|
||||
- Activity có thể public theo project, audit chỉ admin xem.
|
||||
- Dữ liệu nhạy cảm trong audit phải mask.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- Admin xem được ai đổi quyền project.
|
||||
- Project timeline hiển thị version/comment/issue mới.
|
||||
|
||||
## 22. Feature 18 - Webhook và tích hợp
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Cho hệ thống khác nhận sự kiện từ nền tảng.
|
||||
|
||||
### Chức năng
|
||||
|
||||
- Tạo webhook endpoint theo project.
|
||||
- Chọn event types.
|
||||
- Gửi payload ký chữ ký HMAC.
|
||||
- Retry khi lỗi.
|
||||
- Xem delivery history.
|
||||
- Disable webhook lỗi liên tục.
|
||||
|
||||
### Event types
|
||||
|
||||
- Project updated.
|
||||
- Model created/updated/deleted.
|
||||
- Version created/deleted.
|
||||
- File import completed/failed.
|
||||
- Issue created/updated.
|
||||
- Review completed.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- Webhook phải retry có backoff.
|
||||
- Timeout không được ảnh hưởng request chính.
|
||||
- Secret chỉ hiển thị khi tạo/rotate.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- Tạo webhook và nhận event version created.
|
||||
- Delivery lỗi được retry.
|
||||
- Payload có signature để bên nhận verify.
|
||||
|
||||
## 23. Feature 19 - Admin, cấu hình và quota
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Cho admin vận hành hệ thống an toàn, kiểm soát tài nguyên và policy.
|
||||
|
||||
### Chức năng
|
||||
|
||||
- Quản lý user.
|
||||
- Quản lý role server.
|
||||
- Cấu hình đăng ký/mời.
|
||||
- Cấu hình file size limit.
|
||||
- Cấu hình object size limit.
|
||||
- Cấu hình storage provider.
|
||||
- Quota theo user/project/org.
|
||||
- Feature flags.
|
||||
- Health/status page.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- Chỉ System Admin được đổi global config.
|
||||
- Config quan trọng phải ghi audit.
|
||||
- Quota vượt giới hạn thì chặn upload/import mới nhưng vẫn cho đọc dữ liệu.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- Admin khóa user thì token user không còn dùng được.
|
||||
- Project vượt quota không upload file mới được.
|
||||
- Feature flag large model có thể bật/tắt.
|
||||
|
||||
## 24. Feature 20 - API, SDK và Developer Experience
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Cho developer nội bộ hoặc bên thứ ba tích hợp với nền tảng.
|
||||
|
||||
### Chức năng
|
||||
|
||||
- GraphQL endpoint.
|
||||
- REST object/blob endpoints.
|
||||
- OpenAPI cho REST API mới.
|
||||
- C# SDK chính thức cho backend mới.
|
||||
- API token management.
|
||||
- API explorer.
|
||||
- Rate limit.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- Speckle-compatible endpoints phải ổn định.
|
||||
- API mới có thể REST/gRPC nhưng không làm connector cũ gãy.
|
||||
- Breaking change phải versioned.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- C# SDK có thể tạo project, upload object, tạo version, load object.
|
||||
- Connector Speckle gọi endpoint cũ vẫn chạy.
|
||||
|
||||
## 25. Feature 21 - Migration từ Speckle Server hiện tại
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Chuyển dữ liệu từ Speckle Server hiện tại sang nền tảng mới hoặc chạy song song trong giai đoạn chuyển đổi.
|
||||
|
||||
### Chức năng
|
||||
|
||||
- Import users.
|
||||
- Import projects/streams.
|
||||
- Import models/branches.
|
||||
- Import versions/commits.
|
||||
- Import objects.
|
||||
- Import blobs/file uploads.
|
||||
- Import comments.
|
||||
- Validate object counts/hash.
|
||||
- Report migration errors.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- Không đổi object ID khi migrate.
|
||||
- Version phải trỏ đúng root object cũ.
|
||||
- Quyền user/project phải giữ tương đương.
|
||||
- Migration nên chạy repeatable/idempotent.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- Project migrated mở được trong viewer mới.
|
||||
- Connector pull version migrated được.
|
||||
- Object count và root object match server cũ.
|
||||
|
||||
## 26. Feature 22 - Vận hành, monitoring và reliability
|
||||
|
||||
### Mục tiêu
|
||||
|
||||
Đảm bảo hệ thống ổn định khi upload model lớn, nhiều connector và nhiều worker.
|
||||
|
||||
### Chức năng
|
||||
|
||||
- Health checks.
|
||||
- Metrics.
|
||||
- Structured logs.
|
||||
- Queue monitoring.
|
||||
- Worker heartbeat.
|
||||
- Dead-letter jobs.
|
||||
- Retry policy.
|
||||
- Backup/restore.
|
||||
- Storage cleanup jobs.
|
||||
|
||||
### Quy tắc nghiệp vụ
|
||||
|
||||
- Request upload lớn không được làm backend OOM.
|
||||
- Worker lỗi phải mark job failed hoặc retry được.
|
||||
- Cleanup không được xóa object/blob còn version tham chiếu.
|
||||
- Monitoring phải phân biệt lỗi user input và lỗi hệ thống.
|
||||
|
||||
### Tiêu chí chấp nhận
|
||||
|
||||
- Admin thấy worker nào đang offline.
|
||||
- Job import timeout được retry hoặc failed rõ ràng.
|
||||
- Backup restore được project mẫu.
|
||||
|
||||
## 27. Roadmap đề xuất
|
||||
|
||||
### Phase 1 - Core Speckle-compatible MVP
|
||||
|
||||
- Auth/token connector.
|
||||
- Project/model/version.
|
||||
- Object diff/upload/download.
|
||||
- Blazor viewer shell nhúng Speckle Viewer.
|
||||
- Basic permission.
|
||||
- Upload model từ connector và xem trên web.
|
||||
|
||||
### Phase 2 - File import và viewer hoàn chỉnh
|
||||
|
||||
- Blob upload.
|
||||
- IFC/STL/OBJ import.
|
||||
- Comment/issue cơ bản.
|
||||
- Saved views.
|
||||
- Preview image.
|
||||
- Activity stream.
|
||||
|
||||
### Phase 3 - Large model và C++ native optimization
|
||||
|
||||
- C++ conversion worker.
|
||||
- Viewer derivative manifest/tile.
|
||||
- Large model loader.
|
||||
- Metadata on-demand.
|
||||
- Memory budget/eviction.
|
||||
|
||||
### Phase 4 - Nghiệp vụ mở rộng
|
||||
|
||||
- Review/approval workflow.
|
||||
- Dashboard/report.
|
||||
- Webhook/integration.
|
||||
- BIM checking.
|
||||
- Advanced permissions/quota.
|
||||
|
||||
### Phase 5 - Production hardening
|
||||
|
||||
- Migration tools.
|
||||
- Monitoring/alerting.
|
||||
- HA deployment.
|
||||
- Backup/restore.
|
||||
- API/SDK documentation.
|
||||
|
||||
## 28. MVP definition of done
|
||||
|
||||
MVP chỉ được xem là đạt nếu:
|
||||
|
||||
- Connector đăng nhập được.
|
||||
- Connector tạo project/model/version hoặc dùng project/model có sẵn.
|
||||
- Connector upload object qua diff/upload đúng contract.
|
||||
- Web Blazor mở version và nhúng Speckle Viewer xem được model.
|
||||
- User có quyền mới xem/upload được.
|
||||
- Object lưu trong PostgreSQL có hash/dedup đúng.
|
||||
- File import cơ bản tạo được version mới.
|
||||
- Không cần clone toàn bộ frontend Speckle hiện tại.
|
||||
|
||||
## 29. Nguyên tắc thiết kế sản phẩm
|
||||
|
||||
- Giữ core data contract ổn định trước khi mở rộng UI.
|
||||
- Không đưa geometry nặng qua GraphQL.
|
||||
- Không viết lại Speckle Viewer ở giai đoạn đầu.
|
||||
- Không trộn derivative artifacts với user-visible blob listing.
|
||||
- Mọi tính năng mới phải gắn được với Project/Model/Version.
|
||||
- API tương thích connector phải được test bằng golden tests.
|
||||
- Tính năng nghiệp vụ mới nên xây quanh viewer context: resource, camera, object selection, version.
|
||||
@@ -0,0 +1,515 @@
|
||||
# Data Model nền tảng Speckle-compatible ASP.NET/Blazor
|
||||
|
||||
## 1. Mục tiêu
|
||||
|
||||
Tài liệu này mô tả mô hình dữ liệu mục tiêu cho PostgreSQL. Thiết kế ưu tiên:
|
||||
|
||||
- Tương thích Speckle concepts: Stream/Branch/Commit/Object.
|
||||
- API mới dùng thuật ngữ Project/Model/Version.
|
||||
- Object graph immutable và deduplicate.
|
||||
- Hỗ trợ upload/pull/viewer hiệu năng cao.
|
||||
- Mở rộng được cho issue, review, dashboard, audit và integration.
|
||||
|
||||
## 2. Quy ước chung
|
||||
|
||||
- Primary key dùng `text` hoặc `uuid` tuỳ compatibility. Với Project/Model/Version nên dùng `text`/base62 nếu cần giống Speckle.
|
||||
- Tất cả bảng nghiệp vụ có `created_at`, `updated_at`.
|
||||
- Soft delete dùng `deleted_at` khi dữ liệu cần audit.
|
||||
- JSON linh hoạt dùng `jsonb`.
|
||||
- Dữ liệu lớn không nhét vào row nếu có thể đưa sang object storage.
|
||||
- Các bảng object/version cần index kỹ vì là điểm nóng.
|
||||
|
||||
## 3. Nhóm identity/auth
|
||||
|
||||
### 3.1 `users`
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| ------------- | ----------- | -------------------------------- |
|
||||
| `id` | text/uuid | User id. |
|
||||
| `email` | citext | Unique. |
|
||||
| `name` | text | Display name. |
|
||||
| `company` | text | Optional. |
|
||||
| `avatar_url` | text | Optional. |
|
||||
| `server_role` | text | `admin`, `user`, `guest`. |
|
||||
| `status` | text | `active`, `invited`, `disabled`. |
|
||||
| `created_at` | timestamptz | |
|
||||
| `updated_at` | timestamptz | |
|
||||
|
||||
Index:
|
||||
|
||||
- Unique `email`.
|
||||
- Index `status`.
|
||||
|
||||
### 3.2 `server_apps`
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| ------------------ | ----------- | --------------------------------- |
|
||||
| `id` | text | Ví dụ `sdm`, `sca`, `connectrV3`. |
|
||||
| `secret_digest` | text | Hash nếu app confidential. |
|
||||
| `name` | text | |
|
||||
| `redirect_url` | text | |
|
||||
| `is_public` | boolean | Public app không giữ secret thật. |
|
||||
| `trust_by_default` | boolean | Auto approve hay không. |
|
||||
| `scopes` | text[] | Scope app được xin. |
|
||||
| `created_at` | timestamptz | |
|
||||
|
||||
### 3.3 `api_tokens`
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| --------------- | ----------- | ----------------------------------------- |
|
||||
| `id` | text | 10 ký tự token id nếu giữ format Speckle. |
|
||||
| `owner_user_id` | text | FK users. |
|
||||
| `app_id` | text | FK server_apps, nullable cho PAT. |
|
||||
| `token_digest` | text | Hash secret. |
|
||||
| `last_chars` | text | 6 ký tự cuối để hiển thị. |
|
||||
| `name` | text | |
|
||||
| `expires_at` | timestamptz | Nullable. |
|
||||
| `revoked_at` | timestamptz | Nullable. |
|
||||
| `created_at` | timestamptz | |
|
||||
|
||||
### 3.4 `api_token_scopes`
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| ---------- | ---- | --------------------- |
|
||||
| `token_id` | text | FK api_tokens. |
|
||||
| `scope` | text | Ví dụ `streams:read`. |
|
||||
|
||||
Primary key: `(token_id, scope)`.
|
||||
|
||||
### 3.5 `auth_access_codes`
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| -------------- | ----------- | ------------------------ |
|
||||
| `code` | text | Short lived. |
|
||||
| `user_id` | text | |
|
||||
| `app_id` | text | |
|
||||
| `redirect_url` | text | |
|
||||
| `challenge` | text | Optional PKCE/challenge. |
|
||||
| `expires_at` | timestamptz | |
|
||||
| `used_at` | timestamptz | Nullable. |
|
||||
| `created_at` | timestamptz | |
|
||||
|
||||
## 4. Nhóm project/model/version
|
||||
|
||||
### 4.1 `projects`
|
||||
|
||||
Tương đương Speckle Stream.
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| ----------------------- | ----------- | ----------------------------------- |
|
||||
| `id` | text | Dùng làm `streamId` legacy. |
|
||||
| `name` | text | |
|
||||
| `description` | text | |
|
||||
| `visibility` | text | `private`, `public`, `workspace`. |
|
||||
| `allow_public_comments` | boolean | |
|
||||
| `owner_user_id` | text | FK users. |
|
||||
| `workspace_id` | text | Nullable nếu chưa làm workspace. |
|
||||
| `source_apps` | text[] | Cache app sources, có thể tính lại. |
|
||||
| `created_at` | timestamptz | |
|
||||
| `updated_at` | timestamptz | |
|
||||
| `deleted_at` | timestamptz | |
|
||||
|
||||
Index:
|
||||
|
||||
- `owner_user_id`.
|
||||
- `visibility`.
|
||||
- Full text index cho `name`, `description`.
|
||||
|
||||
### 4.2 `project_members`
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| ------------ | ----------- | --------------------------------------------- |
|
||||
| `project_id` | text | FK projects. |
|
||||
| `user_id` | text | FK users. |
|
||||
| `role` | text | `owner`, `contributor`, `reviewer`, `viewer`. |
|
||||
| `created_at` | timestamptz | |
|
||||
| `updated_at` | timestamptz | |
|
||||
|
||||
Primary key: `(project_id, user_id)`.
|
||||
|
||||
### 4.3 `project_invites`
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| -------------------- | ----------- | ----------------------------------------------- |
|
||||
| `id` | text/uuid | |
|
||||
| `project_id` | text | |
|
||||
| `email` | citext | |
|
||||
| `user_id` | text | Nullable. |
|
||||
| `role` | text | |
|
||||
| `token_digest` | text | |
|
||||
| `status` | text | `pending`, `accepted`, `declined`, `cancelled`. |
|
||||
| `invited_by_user_id` | text | |
|
||||
| `expires_at` | timestamptz | |
|
||||
| `created_at` | timestamptz | |
|
||||
|
||||
### 4.4 `models`
|
||||
|
||||
Tương đương Speckle Branch.
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| ---------------- | ----------- | -------------------------------------- |
|
||||
| `id` | text | Dùng làm model id. |
|
||||
| `project_id` | text | FK projects. |
|
||||
| `name` | text | Full name, ví dụ `Architecture/Walls`. |
|
||||
| `display_name` | text | Segment cuối. |
|
||||
| `description` | text | |
|
||||
| `author_user_id` | text | |
|
||||
| `created_at` | timestamptz | |
|
||||
| `updated_at` | timestamptz | |
|
||||
| `deleted_at` | timestamptz | |
|
||||
|
||||
Index:
|
||||
|
||||
- Unique `(project_id, name)` where `deleted_at is null`.
|
||||
- Index `(project_id, updated_at desc)`.
|
||||
|
||||
### 4.5 `versions`
|
||||
|
||||
Tương đương Speckle Commit.
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| ---------------------- | ----------- | --------------------------- |
|
||||
| `id` | text | Dùng làm commit/version id. |
|
||||
| `project_id` | text | FK projects. |
|
||||
| `model_id` | text | FK models. |
|
||||
| `referenced_object` | text | Root object id. |
|
||||
| `message` | text | Commit message. |
|
||||
| `source_application` | text | Revit/Rhino/IFC importer... |
|
||||
| `author_user_id` | text | |
|
||||
| `total_children_count` | integer | |
|
||||
| `parents` | text[] | Parent version ids. |
|
||||
| `preview_url` | text | Optional. |
|
||||
| `created_at` | timestamptz | |
|
||||
| `updated_at` | timestamptz | |
|
||||
| `deleted_at` | timestamptz | |
|
||||
|
||||
Index:
|
||||
|
||||
- `(project_id, model_id, created_at desc)`.
|
||||
- `(project_id, referenced_object)`.
|
||||
- GIN `parents`.
|
||||
|
||||
## 5. Nhóm object graph
|
||||
|
||||
### 5.1 `objects`
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| ---------------------- | ----------- | ------------------------------------- |
|
||||
| `project_id` | text | Partition/shard key. |
|
||||
| `id` | text | Speckle object id/hash. |
|
||||
| `speckle_type` | text | Từ `speckle_type` hoặc `speckleType`. |
|
||||
| `data` | jsonb | Object JSON nguyên gốc. |
|
||||
| `total_children_count` | integer | Optional. |
|
||||
| `created_at` | timestamptz | |
|
||||
|
||||
Primary key: `(project_id, id)`.
|
||||
|
||||
Index:
|
||||
|
||||
- `(project_id, speckle_type)`.
|
||||
- GIN `data jsonb_path_ops` nếu cần query property.
|
||||
- BRIN/partition theo `project_id` hoặc hash partition khi rất lớn.
|
||||
|
||||
Ghi chú:
|
||||
|
||||
- Đây là bảng điểm nóng nhất.
|
||||
- Insert phải dùng upsert/ignore conflict.
|
||||
- Không update `data` sau khi insert trừ migration có kiểm soát.
|
||||
|
||||
### 5.2 `object_children`
|
||||
|
||||
Tuỳ chọn. Nếu cần traversal nhanh thay vì parse JSON mỗi lần.
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| ----------------- | ------- | ---------------------- |
|
||||
| `project_id` | text | |
|
||||
| `object_id` | text | Parent object. |
|
||||
| `child_object_id` | text | Child reference. |
|
||||
| `path` | text | Property path nếu cần. |
|
||||
| `depth_hint` | integer | Optional. |
|
||||
|
||||
Primary key: `(project_id, object_id, child_object_id, path)`.
|
||||
|
||||
### 5.3 `object_properties_index`
|
||||
|
||||
Tuỳ chọn cho search/filter BIM.
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| ----------------------- | ------- | ------------------------------------ |
|
||||
| `project_id` | text | |
|
||||
| `version_id` | text | |
|
||||
| `object_id` | text | |
|
||||
| `property_key` | text | Ví dụ `category`, `level`, `family`. |
|
||||
| `property_value_text` | text | |
|
||||
| `property_value_number` | numeric | Nullable. |
|
||||
| `property_value_bool` | boolean | Nullable. |
|
||||
|
||||
Index:
|
||||
|
||||
- `(project_id, property_key, property_value_text)`.
|
||||
- `(project_id, version_id, property_key)`.
|
||||
|
||||
## 6. Nhóm blob/file/import
|
||||
|
||||
### 6.1 `blobs`
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| -------------------- | ----------- | ------------------------- |
|
||||
| `id` | text | Blob id. |
|
||||
| `project_id` | text | |
|
||||
| `file_name` | text | |
|
||||
| `content_type` | text | |
|
||||
| `size_bytes` | bigint | |
|
||||
| `storage_key` | text | Key trong object storage. |
|
||||
| `hash` | text | Optional checksum. |
|
||||
| `created_by_user_id` | text | |
|
||||
| `created_at` | timestamptz | |
|
||||
| `deleted_at` | timestamptz | |
|
||||
|
||||
### 6.2 `file_uploads`
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| -------------------------- | ----------- | ---------------------------------------------------------- |
|
||||
| `id` | text | File upload id. |
|
||||
| `project_id` | text | |
|
||||
| `model_id` | text | Nullable cho pending model. |
|
||||
| `model_name` | text | Dùng khi model chưa có. |
|
||||
| `blob_id` | text | FK blobs. |
|
||||
| `file_name` | text | |
|
||||
| `file_type` | text | `ifc`, `stl`, `obj`, ... |
|
||||
| `file_size` | bigint | |
|
||||
| `status` | text | `queued`, `converting`, `completed`, `error`, `cancelled`. |
|
||||
| `converted_version_id` | text | Nullable. |
|
||||
| `converted_root_object_id` | text | Nullable. |
|
||||
| `error_code` | text | Nullable. |
|
||||
| `error_message` | text | Nullable. |
|
||||
| `metadata` | jsonb | |
|
||||
| `performance_data` | jsonb | |
|
||||
| `created_by_user_id` | text | |
|
||||
| `created_at` | timestamptz | |
|
||||
| `updated_at` | timestamptz | |
|
||||
|
||||
Index:
|
||||
|
||||
- `(project_id, status)`.
|
||||
- `(project_id, model_id, created_at desc)`.
|
||||
|
||||
### 6.3 `jobs`
|
||||
|
||||
Generic background job state.
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| --------------- | ----------- | ----------------------------------------------------------- |
|
||||
| `id` | uuid/text | |
|
||||
| `type` | text | `file-import`, `viewer-derivative`, `preview`, `bim-check`. |
|
||||
| `status` | text | `queued`, `running`, `succeeded`, `failed`, `cancelled`. |
|
||||
| `project_id` | text | Nullable. |
|
||||
| `resource_type` | text | `file_upload`, `version`, ... |
|
||||
| `resource_id` | text | |
|
||||
| `payload` | jsonb | |
|
||||
| `attempt_count` | integer | |
|
||||
| `max_attempts` | integer | |
|
||||
| `run_after` | timestamptz | |
|
||||
| `locked_by` | text | Worker id. |
|
||||
| `locked_at` | timestamptz | |
|
||||
| `error_code` | text | |
|
||||
| `error_message` | text | |
|
||||
| `created_at` | timestamptz | |
|
||||
| `updated_at` | timestamptz | |
|
||||
|
||||
## 7. Nhóm viewer
|
||||
|
||||
### 7.1 `viewer_derivatives`
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| ----------------- | ----------- | -------------------------------------------------- |
|
||||
| `id` | uuid/text | |
|
||||
| `project_id` | text | |
|
||||
| `model_id` | text | |
|
||||
| `version_id` | text | |
|
||||
| `derivative_type` | text | `large-model`. |
|
||||
| `schema_version` | integer | Version format derivative. |
|
||||
| `status` | text | `queued`, `processing`, `ready`, `failed`. |
|
||||
| `stage` | text | `extracting`, `tiling`, `uploading-artifacts`, ... |
|
||||
| `progress` | numeric | 0..1. |
|
||||
| `manifest_key` | text | Object storage key. |
|
||||
| `manifest_hash` | text | |
|
||||
| `tile_count` | integer | |
|
||||
| `tile_bytes` | bigint | |
|
||||
| `metadata_bytes` | bigint | |
|
||||
| `stats` | jsonb | |
|
||||
| `error_code` | text | |
|
||||
| `error_message` | text | |
|
||||
| `published_at` | timestamptz | |
|
||||
| `created_at` | timestamptz | |
|
||||
| `updated_at` | timestamptz | |
|
||||
|
||||
Unique: `(project_id, version_id, derivative_type, schema_version)`.
|
||||
|
||||
### 7.2 `saved_views`
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| -------------------- | ----------- | ------------------------------------ |
|
||||
| `id` | text/uuid | |
|
||||
| `project_id` | text | |
|
||||
| `name` | text | |
|
||||
| `description` | text | |
|
||||
| `resource_ids` | text | Viewer resource string. |
|
||||
| `viewer_state` | jsonb | Camera, section, filters, selection. |
|
||||
| `is_home_view` | boolean | |
|
||||
| `created_by_user_id` | text | |
|
||||
| `created_at` | timestamptz | |
|
||||
| `updated_at` | timestamptz | |
|
||||
|
||||
## 8. Nhóm comment/issue/review
|
||||
|
||||
### 8.1 `comments`
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| -------------------- | ----------- | ------------------------------------------------- |
|
||||
| `id` | text/uuid | |
|
||||
| `project_id` | text | |
|
||||
| `parent_comment_id` | text | Thread reply. |
|
||||
| `target_type` | text | `project`, `model`, `version`, `object`, `issue`. |
|
||||
| `target_id` | text | |
|
||||
| `body` | jsonb/text | Rich text hoặc markdown. |
|
||||
| `viewer_state` | jsonb | Camera/selection tại lúc comment. |
|
||||
| `created_by_user_id` | text | |
|
||||
| `created_at` | timestamptz | |
|
||||
| `updated_at` | timestamptz | |
|
||||
| `deleted_at` | timestamptz | |
|
||||
|
||||
### 8.2 `issues`
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| -------------------- | ----------- | -------------------------------------------- |
|
||||
| `id` | text/uuid | |
|
||||
| `project_id` | text | |
|
||||
| `model_id` | text | Nullable. |
|
||||
| `version_id` | text | Nullable. |
|
||||
| `title` | text | |
|
||||
| `description` | text/jsonb | |
|
||||
| `status` | text | `open`, `in_progress`, `resolved`, `closed`. |
|
||||
| `priority` | text | `low`, `medium`, `high`, `critical`. |
|
||||
| `assignee_user_id` | text | Nullable. |
|
||||
| `created_by_user_id` | text | |
|
||||
| `due_date` | date | Nullable. |
|
||||
| `viewer_state` | jsonb | Camera/selection/markup. |
|
||||
| `object_ids` | text[] | Related objects. |
|
||||
| `created_at` | timestamptz | |
|
||||
| `updated_at` | timestamptz | |
|
||||
| `closed_at` | timestamptz | |
|
||||
|
||||
### 8.3 `review_sessions`
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| -------------------- | ----------- | -------------------------------------------- |
|
||||
| `id` | text/uuid | |
|
||||
| `project_id` | text | |
|
||||
| `name` | text | |
|
||||
| `status` | text | `draft`, `active`, `completed`, `cancelled`. |
|
||||
| `created_by_user_id` | text | |
|
||||
| `starts_at` | timestamptz | Nullable. |
|
||||
| `due_at` | timestamptz | Nullable. |
|
||||
| `created_at` | timestamptz | |
|
||||
| `updated_at` | timestamptz | |
|
||||
|
||||
### 8.4 `review_items`
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| ------------------- | ----------- | ------------------------------------------------------------ |
|
||||
| `id` | text/uuid | |
|
||||
| `review_session_id` | text | |
|
||||
| `project_id` | text | |
|
||||
| `model_id` | text | |
|
||||
| `version_id` | text | |
|
||||
| `status` | text | `pending`, `approved`, `rejected`, `approved_with_comments`. |
|
||||
| `reviewer_user_id` | text | |
|
||||
| `decision_note` | text | |
|
||||
| `decided_at` | timestamptz | |
|
||||
|
||||
## 9. Nhóm audit/integration
|
||||
|
||||
### 9.1 `activity_events`
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| --------------- | ----------- | ----------------------------------------- |
|
||||
| `id` | uuid | |
|
||||
| `project_id` | text | Nullable. |
|
||||
| `actor_user_id` | text | Nullable cho system. |
|
||||
| `event_type` | text | `project.created`, `version.created`, ... |
|
||||
| `resource_type` | text | |
|
||||
| `resource_id` | text | |
|
||||
| `payload` | jsonb | |
|
||||
| `created_at` | timestamptz | |
|
||||
|
||||
### 9.2 `audit_logs`
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| --------------- | ----------- | --------- |
|
||||
| `id` | uuid | |
|
||||
| `actor_user_id` | text | |
|
||||
| `action` | text | |
|
||||
| `target_type` | text | |
|
||||
| `target_id` | text | |
|
||||
| `ip_address` | inet | |
|
||||
| `user_agent` | text | |
|
||||
| `before` | jsonb | Nullable. |
|
||||
| `after` | jsonb | Nullable. |
|
||||
| `created_at` | timestamptz | |
|
||||
|
||||
### 9.3 `webhooks`
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| -------------------- | ----------- | --------- |
|
||||
| `id` | text/uuid | |
|
||||
| `project_id` | text | Nullable. |
|
||||
| `url` | text | |
|
||||
| `secret_digest` | text | |
|
||||
| `events` | text[] | |
|
||||
| `is_active` | boolean | |
|
||||
| `created_by_user_id` | text | |
|
||||
| `created_at` | timestamptz | |
|
||||
|
||||
### 9.4 `webhook_deliveries`
|
||||
|
||||
| Cột | Kiểu | Ghi chú |
|
||||
| ----------------- | ----------- | --------------------------------- |
|
||||
| `id` | uuid | |
|
||||
| `webhook_id` | text | |
|
||||
| `event_id` | uuid | |
|
||||
| `status` | text | `pending`, `succeeded`, `failed`. |
|
||||
| `attempt_count` | integer | |
|
||||
| `response_status` | integer | |
|
||||
| `response_body` | text | Cắt ngắn. |
|
||||
| `created_at` | timestamptz | |
|
||||
| `delivered_at` | timestamptz | |
|
||||
|
||||
## 10. View/report đề xuất
|
||||
|
||||
- `project_latest_versions`: latest version per model.
|
||||
- `project_storage_usage`: object bytes, blob bytes, derivative bytes.
|
||||
- `user_recent_projects`: project activity per user.
|
||||
- `issue_summary_by_project`: open/resolved/overdue issues.
|
||||
- `conversion_job_summary`: conversion status and duration.
|
||||
|
||||
## 11. Migration mapping từ Speckle Server
|
||||
|
||||
| Speckle table/concept | Bảng mới |
|
||||
| ------------------------ | --------------------------- |
|
||||
| streams | projects |
|
||||
| stream_acl/collaborators | project_members |
|
||||
| branches | models |
|
||||
| commits | versions |
|
||||
| objects | objects |
|
||||
| blobs | blobs |
|
||||
| file_uploads | file_uploads |
|
||||
| api_tokens/token scopes | api_tokens/api_token_scopes |
|
||||
| comments | comments/issues tuỳ loại |
|
||||
|
||||
Migration cần:
|
||||
|
||||
- Preserve IDs nếu muốn URL/connector reference cũ tiếp tục hoạt động.
|
||||
- Preserve object data nguyên gốc.
|
||||
- Validate count: project, model, version, object, blob.
|
||||
- Checksum object id/data trước và sau migration.
|
||||
@@ -0,0 +1,328 @@
|
||||
# Kiến trúc kỹ thuật nền tảng Speckle-compatible ASP.NET/Blazor
|
||||
|
||||
## 1. Mục tiêu kiến trúc
|
||||
|
||||
Tài liệu này mô tả kiến trúc kỹ thuật mục tiêu cho nền tảng quản lý mô hình 3D/BIM/CAD tương thích Speckle, xây mới bằng Blazor WebAssembly, ASP.NET Core, PostgreSQL và các service native C++ cho xử lý nặng.
|
||||
|
||||
Mục tiêu chính:
|
||||
|
||||
- Giữ tương thích API ở mức đủ để Speckle Connector hiện tại đăng nhập, upload, pull, tạo project/model/version.
|
||||
- Giữ lại Speckle Viewer làm engine hiển thị 3D trên web, tích hợp qua JavaScript interop trong Blazor.
|
||||
- Chuyển backend nghiệp vụ sang ASP.NET Core để phù hợp hệ sinh thái .NET.
|
||||
- Dùng PostgreSQL làm nguồn dữ liệu chính cho metadata, object graph, permission, job state và audit.
|
||||
- Tách các tác vụ nặng như object ingestion, file import, geometry conversion, viewer derivative sang C++ service để kiểm soát hiệu năng và bộ nhớ.
|
||||
- Thiết kế theo hướng modular monolith trước, có đường mở rộng sang service độc lập khi tải tăng.
|
||||
|
||||
## 2. Nguyên tắc thiết kế
|
||||
|
||||
| Nguyên tắc | Ý nghĩa |
|
||||
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
|
||||
| Compatibility first | Endpoint và schema mà connector đang dùng phải được ưu tiên hơn UI mới. |
|
||||
| Object immutability | Object model sau khi lưu không sửa trực tiếp; thay đổi phải tạo object/version mới. |
|
||||
| Streaming by default | Upload/pull object và file lớn không đi qua GraphQL payload lớn. |
|
||||
| Metadata qua GraphQL/REST nhẹ | Project, model, version, user, issue, review dùng API nhẹ; dữ liệu lớn dùng stream/blob. |
|
||||
| C++ for heavy compute | C++ xử lý parse file, convert geometry, tạo tile/derivative, validate BIM. |
|
||||
| Blazor owns workflow, Speckle Viewer owns 3D | Blazor quản lý màn hình và nghiệp vụ; viewer JS quản lý WebGL, camera, selection, section, measurement. |
|
||||
| PostgreSQL as source of truth | Cache/queue/object storage có thể rebuild từ DB hoặc artifact gốc nếu cần. |
|
||||
|
||||
## 3. Kiến trúc tổng thể
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
C[Speckle Connector / Desktop App] -->|OAuth/token + GraphQL + REST objects| API[ASP.NET Core API]
|
||||
B[Blazor WebAssembly] -->|GraphQL/REST| API
|
||||
B -->|JS interop| V[Speckle Viewer JS]
|
||||
V -->|object stream / derivative manifest| API
|
||||
|
||||
API --> PG[(PostgreSQL)]
|
||||
API --> OS[(Object Storage S3/MinIO/File)]
|
||||
API --> R[(Redis Cache)]
|
||||
API --> Q[(Job Queue)]
|
||||
|
||||
Q --> CPP1[C++ Object Upload Service]
|
||||
Q --> CPP2[C++ File Import Service]
|
||||
Q --> CPP3[C++ Viewer Derivative Service]
|
||||
CPP1 --> PG
|
||||
CPP2 --> PG
|
||||
CPP2 --> OS
|
||||
CPP3 --> OS
|
||||
CPP3 --> PG
|
||||
```
|
||||
|
||||
## 4. Thành phần hệ thống
|
||||
|
||||
| Thành phần | Công nghệ đề xuất | Trách nhiệm |
|
||||
| --------------- | ------------------------------------------------------- | -------------------------------------------------------------------------------- |
|
||||
| Web Client | Blazor WebAssembly | UI quản lý project/model/version, viewer page, issue, review, dashboard, admin. |
|
||||
| Viewer Bridge | TypeScript/JavaScript module | Khởi tạo `@speckle/viewer`, expose API cho Blazor qua JS interop. |
|
||||
| API Host | ASP.NET Core 9+ | Auth, compatibility API, business API, GraphQL, REST streaming, webhook, admin. |
|
||||
| GraphQL Layer | Hot Chocolate hoặc GraphQL.NET | Phục vụ Speckle-compatible schema và query/mutation metadata. |
|
||||
| Object REST API | ASP.NET Core Minimal API/Controllers | Upload/pull object stream, diff object, object streaming gzip. |
|
||||
| PostgreSQL | PostgreSQL 16+ | Metadata, object graph, permissions, tokens, job state, audit. |
|
||||
| Object Storage | S3/MinIO/Azure Blob/File | File thô, blob attachment, viewer derivative artifacts. |
|
||||
| Redis | Redis | Cache, rate limit, distributed lock, pub/sub notification. |
|
||||
| Queue | PostgreSQL queue, RabbitMQ, Redis Streams hoặc Hangfire | Điều phối convert/import/derivative/background jobs. |
|
||||
| C++ Services | Native C++ + gRPC/HTTP | Upload optimization, file parse/convert, derivative/tile generation, BIM checks. |
|
||||
|
||||
## 5. Module backend ASP.NET Core
|
||||
|
||||
### 5.1 Auth Module
|
||||
|
||||
Trách nhiệm:
|
||||
|
||||
- Đăng nhập web user.
|
||||
- OAuth-like flow cho connector qua `/auth/accesscode` và `/auth/token`.
|
||||
- Personal access token, app token, refresh token.
|
||||
- Token scope: `streams:read`, `streams:write`, `profile:read`, `profile:email`, `users:read`, `users:invite`.
|
||||
- Mapping default Speckle app IDs như `spklwebapp`, `sdm`, `sca`, `sdas`, `sdui`, `connectrV3`.
|
||||
|
||||
Khuyến nghị:
|
||||
|
||||
- Lưu token secret dạng hash, không lưu plain text.
|
||||
- Giữ token bearer tương thích Speckle: token public trả về cho client, DB chỉ giữ digest.
|
||||
- Tách auth web nội bộ và auth connector nhưng dùng chung permission engine.
|
||||
|
||||
### 5.2 Project/Model/Version Module
|
||||
|
||||
Mapping nghiệp vụ:
|
||||
|
||||
| Nền tảng mới | Speckle legacy |
|
||||
| ------------ | ---------------- |
|
||||
| Project | Stream |
|
||||
| Model | Branch |
|
||||
| Version | Commit |
|
||||
| Root Object | referencedObject |
|
||||
|
||||
Trách nhiệm:
|
||||
|
||||
- CRUD project, model, version.
|
||||
- Phân quyền collaborator theo project.
|
||||
- Giữ GraphQL legacy `stream`, `branch`, `commit` để connector cũ không gãy.
|
||||
- Expose API mới `project`, `model`, `version` cho Blazor.
|
||||
|
||||
### 5.3 Object Module
|
||||
|
||||
Trách nhiệm:
|
||||
|
||||
- Nhận object batch từ connector.
|
||||
- Tính/kiểm tra object id theo Speckle hash contract.
|
||||
- Deduplicate object theo `(projectId, objectId)`.
|
||||
- Stream object ra cho connector/viewer.
|
||||
- Hỗ trợ diff để client chỉ upload/download object còn thiếu.
|
||||
|
||||
Điểm quan trọng:
|
||||
|
||||
- Không dùng GraphQL cho payload object lớn.
|
||||
- Endpoint upload phải chấp nhận multipart form, file part có MIME `application/gzip`, `text/plain`, `application/json`, `application/octet-stream`.
|
||||
- Download phải hỗ trợ gzip và định dạng text stream `id<TAB>json\n` khi viewer/client yêu cầu.
|
||||
|
||||
### 5.4 File/Blob Module
|
||||
|
||||
Trách nhiệm:
|
||||
|
||||
- Upload blob attachment.
|
||||
- Upload file import như IFC, STL, OBJ, SKP, RVT nếu sau này có converter.
|
||||
- Quản lý presigned upload URL.
|
||||
- Lưu metadata file và trạng thái import.
|
||||
- Trigger conversion job.
|
||||
|
||||
### 5.5 Conversion Module
|
||||
|
||||
Trách nhiệm:
|
||||
|
||||
- Tạo job convert file.
|
||||
- Giao job cho C++ File Import Service.
|
||||
- Nhận kết quả convert: root object, model/version mới, logs, error.
|
||||
- Đảm bảo retry/idempotency.
|
||||
|
||||
### 5.6 Viewer Module
|
||||
|
||||
Trách nhiệm:
|
||||
|
||||
- Cung cấp metadata viewer resources.
|
||||
- Cung cấp object stream hoặc viewer derivative manifest.
|
||||
- Quản lý saved view, camera, section box, filter state, selection state nếu cần lưu.
|
||||
- Tích hợp comment/issue với camera và selected object ids.
|
||||
|
||||
### 5.7 Review/Issue Module
|
||||
|
||||
Trách nhiệm:
|
||||
|
||||
- Comment, issue, markup.
|
||||
- Review session.
|
||||
- Approval workflow cho version.
|
||||
- Gắn issue vào project/model/version/object/view.
|
||||
|
||||
### 5.8 Integration Module
|
||||
|
||||
Trách nhiệm:
|
||||
|
||||
- Webhook.
|
||||
- API token cho hệ thống ngoài.
|
||||
- Event outbox.
|
||||
- Tích hợp PowerBI/ERP/CDE nếu cần.
|
||||
|
||||
### 5.9 Admin/Operations Module
|
||||
|
||||
Trách nhiệm:
|
||||
|
||||
- Cấu hình server.
|
||||
- Quota storage/object.
|
||||
- Audit log.
|
||||
- Job monitoring.
|
||||
- Health check.
|
||||
- Rate limit.
|
||||
|
||||
## 6. Cấu trúc solution đề xuất
|
||||
|
||||
```text
|
||||
src/
|
||||
Web/
|
||||
Platform.Web.Blazor/
|
||||
Platform.Web.ViewerInterop/
|
||||
Backend/
|
||||
Platform.Api/
|
||||
Platform.GraphQL/
|
||||
Platform.Compatibility/
|
||||
Platform.Auth/
|
||||
Platform.Projects/
|
||||
Platform.Objects/
|
||||
Platform.Files/
|
||||
Platform.Viewer/
|
||||
Platform.Reviews/
|
||||
Platform.Integrations/
|
||||
Platform.Admin/
|
||||
Platform.Persistence.Postgres/
|
||||
Platform.Storage/
|
||||
Platform.Queue/
|
||||
Native/
|
||||
object-ingestion-service/
|
||||
file-import-service/
|
||||
viewer-derivative-service/
|
||||
tests/
|
||||
Platform.Api.Tests/
|
||||
Platform.Compatibility.Tests/
|
||||
Platform.Objects.Tests/
|
||||
Platform.E2E.Tests/
|
||||
```
|
||||
|
||||
Quy tắc phụ thuộc:
|
||||
|
||||
- Module nghiệp vụ không phụ thuộc trực tiếp vào ASP.NET Controller.
|
||||
- Persistence nằm sau repository/unit of work hoặc query service.
|
||||
- Compatibility layer được phép mapping sang domain mới, nhưng domain mới không phụ thuộc vào tên legacy Stream/Branch/Commit.
|
||||
- C++ service giao tiếp qua contract versioned, không truy cập DB tuỳ tiện nếu không cần. Nếu service cần ghi artifact/job status thì dùng internal API hoặc queue callback.
|
||||
|
||||
## 7. Luồng chính
|
||||
|
||||
### 7.1 Connector login
|
||||
|
||||
1. Connector mở browser tới `/auth/accesscode` với `appId`, `challenge`, `redirectUrl`.
|
||||
2. User đăng nhập và approve app.
|
||||
3. Server tạo access code ngắn hạn.
|
||||
4. Connector gọi `POST /auth/token` để đổi access code lấy bearer token.
|
||||
5. Connector dùng token gọi GraphQL và REST object endpoints.
|
||||
|
||||
### 7.2 Connector upload model
|
||||
|
||||
1. Connector tạo hoặc chọn Project/Model qua GraphQL.
|
||||
2. Connector tính Speckle object graph và object ids.
|
||||
3. Connector gọi `POST /api/diff/{projectId}` để hỏi object nào server còn thiếu.
|
||||
4. Connector upload batch object thiếu qua `POST /objects/{projectId}`.
|
||||
5. Connector gọi mutation tạo Version với `objectId` root.
|
||||
6. Server ghi version, phát event, enqueue preview/derivative nếu cần.
|
||||
|
||||
### 7.3 Viewer load model
|
||||
|
||||
1. Blazor page lấy Project/Model/Version metadata.
|
||||
2. Blazor gọi JS interop khởi tạo Speckle Viewer.
|
||||
3. Viewer nhận server URL, token, projectId, objectId/version resource.
|
||||
4. Viewer ưu tiên lấy derivative manifest nếu có.
|
||||
5. Nếu chưa có derivative, viewer load object stream qua REST.
|
||||
6. Blazor nhận callback selection/camera để mở issue/comment panel.
|
||||
|
||||
### 7.4 File import
|
||||
|
||||
1. User upload file qua presigned URL hoặc legacy `/api/file/{fileType}/{projectId}/{modelName}`.
|
||||
2. Server ghi file upload record và enqueue import job.
|
||||
3. C++ service tải file, parse geometry/properties.
|
||||
4. Service tạo object graph tương thích Speckle hoặc intermediate model rồi đẩy vào object store.
|
||||
5. Server tạo Version mới và cập nhật trạng thái import.
|
||||
6. Viewer derivative job chạy sau khi version sẵn sàng.
|
||||
|
||||
## 8. Chiến lược dữ liệu
|
||||
|
||||
- PostgreSQL lưu object JSONB để giữ tương thích và query metadata cơ bản.
|
||||
- Object lớn cần index theo `project_id`, `object_id`, `speckle_type`, `created_at`.
|
||||
- Không update object data sau khi lưu.
|
||||
- Version giữ `referenced_object`, `total_children_count`, `source_application`, `parents`.
|
||||
- Blob và viewer derivative artifact lưu ngoài DB, DB chỉ giữ key/hash/size/status.
|
||||
- Audit/event outbox dùng bảng riêng để đảm bảo phát event không mất.
|
||||
|
||||
## 9. Chiến lược API
|
||||
|
||||
Có hai bề mặt API:
|
||||
|
||||
| Bề mặt | Mục tiêu | Đối tượng |
|
||||
| ---------------------- | --------------------------------- | -------------------------------------- |
|
||||
| Speckle-compatible API | Giữ connector/viewer cũ chạy được | Speckle Connector, Speckle SDK, Viewer |
|
||||
| Product API mới | Phục vụ UI và tính năng riêng | Blazor app, tích hợp nội bộ |
|
||||
|
||||
Không nên phá contract legacy. Nếu cần thay đổi, thêm API mới và giữ adapter legacy.
|
||||
|
||||
## 10. Bảo mật
|
||||
|
||||
- Bearer token cho API.
|
||||
- Cookie/session hoặc OIDC cho Blazor web user.
|
||||
- CSRF cho flow dùng cookie.
|
||||
- CORS chỉ mở cho connector redirect/localhost và domain được cấu hình.
|
||||
- Rate limit endpoint upload/download.
|
||||
- Quota theo project/user.
|
||||
- Virus scan hoặc content validation cho file upload nếu triển khai production.
|
||||
- Audit các hành động: login, token create/revoke, project role change, upload, delete, approval.
|
||||
|
||||
## 11. Hiệu năng và mở rộng
|
||||
|
||||
Các điểm nóng:
|
||||
|
||||
- `POST /objects/{projectId}`: cần streaming multipart, batch insert, dedup, không load toàn bộ request quá lớn vào RAM.
|
||||
- `POST /api/getobjects/{projectId}` và `/api/v2/projects/{projectId}/object-stream`: cần DB cursor/stream, gzip, backpressure.
|
||||
- Viewer derivative: cần queue, artifact cache, CDN nếu model lớn.
|
||||
- Search metadata: cân nhắc PostgreSQL GIN/JSONB trước, Elasticsearch/OpenSearch sau.
|
||||
|
||||
Mốc mở rộng:
|
||||
|
||||
- MVP: modular monolith + PostgreSQL + object storage + 1 queue worker.
|
||||
- Sau MVP: tách C++ services và object API thành service độc lập.
|
||||
- Enterprise: multi-region object storage, read replica, CDN, autoscaling worker.
|
||||
|
||||
## 12. Observability
|
||||
|
||||
Bắt buộc có:
|
||||
|
||||
- Structured logs với `correlationId`, `userId`, `projectId`, `jobId`.
|
||||
- Metrics: request duration, upload bytes, object count, DB time, queue depth, conversion time, derivative tile count.
|
||||
- Traces cho upload/import/viewer load.
|
||||
- Health checks: DB, Redis, object storage, queue, C++ worker.
|
||||
- Admin job dashboard để retry/fail/cancel job.
|
||||
|
||||
## 13. Rủi ro kỹ thuật chính
|
||||
|
||||
| Rủi ro | Tác động | Giảm thiểu |
|
||||
| ----------------------------------------- | ---------------------------------------- | ------------------------------------------------------- |
|
||||
| Sai Speckle object hash | Connector upload/pull lỗi hoặc dedup sai | Viết compatibility test bằng payload thật từ connector. |
|
||||
| GraphQL schema thiếu field legacy | Connector cũ không chạy | Có contract test theo query thực tế của connector. |
|
||||
| Upload object làm đầy RAM | Server crash với model lớn | Streaming, chunking, C++ ingestion, giới hạn batch. |
|
||||
| Viewer interop không ổn định | Viewer Blazor khó debug | Tách JS bridge rõ ràng, test bằng Playwright. |
|
||||
| C++ service ghi dữ liệu không idempotent | Retry tạo version/object trùng | Job idempotency key, transaction, upsert. |
|
||||
| Migration từ Speckle Server thiếu mapping | Mất dữ liệu lịch sử | Tài liệu migration riêng, dry-run, checksum. |
|
||||
|
||||
## 14. Quyết định cần chốt ở phase thiết kế
|
||||
|
||||
- Dùng Hot Chocolate hay GraphQL.NET.
|
||||
- Queue chính: Hangfire/PostgreSQL, RabbitMQ hay Redis Streams.
|
||||
- Object storage: S3/MinIO/Azure Blob/local filesystem.
|
||||
- C++ service giao tiếp bằng gRPC hay internal HTTP.
|
||||
- Có cần giữ GraphQL subscriptions trong MVP không.
|
||||
- Có cần multi-tenant organization/workspace ngay từ đầu không.
|
||||
- Danh sách connector version chính thức được support trong MVP.
|
||||
@@ -0,0 +1,429 @@
|
||||
# Blazor UI Module Spec
|
||||
|
||||
## 1. Mục tiêu UI
|
||||
|
||||
Blazor WebAssembly là giao diện chính cho nền tảng mới. UI cần phục vụ công việc hằng ngày của nhóm BIM/CAD/AEC:
|
||||
|
||||
- Quản lý project/model/version.
|
||||
- Xem mô hình 3D bằng Speckle Viewer.
|
||||
- Upload file và theo dõi import.
|
||||
- Tạo issue/comment/review trên model.
|
||||
- Theo dõi dashboard và hoạt động dự án.
|
||||
- Quản trị user, quota, job, integration.
|
||||
|
||||
UI không phải landing page. Màn hình đầu tiên sau login phải là workspace làm việc.
|
||||
|
||||
## 2. Kiến trúc frontend
|
||||
|
||||
| Thành phần | Trách nhiệm |
|
||||
| ---------------- | ------------------------------------------------------------- |
|
||||
| Blazor WASM App | Routing, layout, state UI, form, table, panel. |
|
||||
| API Client | Typed client gọi REST/GraphQL. |
|
||||
| Auth State | Token/session, current user, permission. |
|
||||
| Viewer JS Bridge | Wrapper cho `@speckle/viewer`. |
|
||||
| Design System | Component button, table, tabs, dialog, toolbar, status badge. |
|
||||
| Realtime Client | SignalR/WebSocket hoặc polling cho job/import/review. |
|
||||
|
||||
## 3. Layout tổng thể
|
||||
|
||||
### 3.1 App shell
|
||||
|
||||
Thành phần:
|
||||
|
||||
- Top bar: project switcher, search, notification, user menu.
|
||||
- Left navigation: Dashboard, Projects, Issues, Reviews, Files, Admin.
|
||||
- Main content: route content.
|
||||
- Right panel: context panel trong viewer hoặc detail pages.
|
||||
|
||||
Nguyên tắc:
|
||||
|
||||
- Giao diện làm việc dày thông tin, rõ phân cấp.
|
||||
- Không dùng hero marketing.
|
||||
- Table/list phải scan nhanh.
|
||||
- Viewer page ưu tiên không gian model, panel có thể collapse.
|
||||
|
||||
## 4. Route đề xuất
|
||||
|
||||
| Route | Màn hình |
|
||||
| -------------------------------------------- | ------------------------------ |
|
||||
| `/login` | Đăng nhập. |
|
||||
| `/auth/approve` | Approve connector/app. |
|
||||
| `/` | Dashboard cá nhân. |
|
||||
| `/projects` | Danh sách project. |
|
||||
| `/projects/{projectId}` | Project overview. |
|
||||
| `/projects/{projectId}/models` | Model list/tree. |
|
||||
| `/projects/{projectId}/models/{modelId}` | Model detail + versions. |
|
||||
| `/projects/{projectId}/versions/{versionId}` | Version detail. |
|
||||
| `/projects/{projectId}/viewer/{resourceId}` | Viewer page. |
|
||||
| `/projects/{projectId}/issues` | Issue board/list. |
|
||||
| `/projects/{projectId}/reviews` | Review sessions. |
|
||||
| `/projects/{projectId}/files` | File uploads/import jobs. |
|
||||
| `/projects/{projectId}/settings` | Project settings/team/webhook. |
|
||||
| `/admin` | Admin dashboard. |
|
||||
| `/admin/users` | User management. |
|
||||
| `/admin/jobs` | Job monitor. |
|
||||
| `/admin/audit` | Audit logs. |
|
||||
|
||||
## 5. Module Login/Auth
|
||||
|
||||
### 5.1 Login page
|
||||
|
||||
Chức năng:
|
||||
|
||||
- Email/password hoặc SSO nếu có.
|
||||
- Remember session.
|
||||
- Error state rõ.
|
||||
- Redirect về URL trước đó.
|
||||
|
||||
### 5.2 Connector approve page
|
||||
|
||||
Chức năng:
|
||||
|
||||
- Hiển thị app name, scopes, redirect URL.
|
||||
- Nút Approve/Deny.
|
||||
- Nếu app `trustByDefault`, có thể auto approve theo policy.
|
||||
- Sau approve redirect về connector callback.
|
||||
|
||||
## 6. Module Dashboard
|
||||
|
||||
Mục tiêu: người dùng thấy nhanh việc cần làm.
|
||||
|
||||
Widget:
|
||||
|
||||
- Recent projects.
|
||||
- Recent versions.
|
||||
- My open issues.
|
||||
- Pending reviews.
|
||||
- Failed imports.
|
||||
- Storage usage nếu có quyền.
|
||||
|
||||
Filters:
|
||||
|
||||
- Project.
|
||||
- Date range.
|
||||
- Assigned to me.
|
||||
|
||||
## 7. Module Projects
|
||||
|
||||
### 7.1 Project list
|
||||
|
||||
Hiển thị:
|
||||
|
||||
- Name, visibility, role, latest activity, model count, issue count.
|
||||
- Search.
|
||||
- Filter by role/visibility.
|
||||
- Create project button.
|
||||
|
||||
Actions:
|
||||
|
||||
- Open.
|
||||
- Favorite/pin nếu triển khai.
|
||||
- Archive/delete nếu owner.
|
||||
|
||||
### 7.2 Project overview
|
||||
|
||||
Sections:
|
||||
|
||||
- Project summary.
|
||||
- Latest models.
|
||||
- Latest versions.
|
||||
- Open issues.
|
||||
- Pending reviews.
|
||||
- File import status.
|
||||
- Activity feed.
|
||||
|
||||
## 8. Module Models
|
||||
|
||||
### 8.1 Model tree/list
|
||||
|
||||
Chức năng:
|
||||
|
||||
- Hiển thị model theo cây `Architecture/Walls`, `Structure/Beams`.
|
||||
- Search/filter source app/contributor.
|
||||
- Create model.
|
||||
- Rename/update description.
|
||||
- Delete/archive model.
|
||||
|
||||
### 8.2 Model detail
|
||||
|
||||
Tabs:
|
||||
|
||||
- Versions.
|
||||
- Files.
|
||||
- Issues.
|
||||
- Reviews.
|
||||
- Settings.
|
||||
|
||||
Version table columns:
|
||||
|
||||
- Version id.
|
||||
- Message.
|
||||
- Author.
|
||||
- Source app.
|
||||
- Created at.
|
||||
- Total children.
|
||||
- Status derivative/import.
|
||||
- Open in viewer.
|
||||
|
||||
## 9. Module Version
|
||||
|
||||
Version detail hiển thị:
|
||||
|
||||
- Metadata: id, root object, source app, author, created time.
|
||||
- Parent versions.
|
||||
- Object count.
|
||||
- Preview/viewer entry.
|
||||
- Import/derivative status.
|
||||
- Related issues/comments/reviews.
|
||||
|
||||
Actions:
|
||||
|
||||
- Open viewer.
|
||||
- Mark received nếu cần compatibility.
|
||||
- Move to model.
|
||||
- Delete version nếu có quyền.
|
||||
- Create review.
|
||||
|
||||
## 10. Module Viewer
|
||||
|
||||
### 10.1 Viewer layout
|
||||
|
||||
Màn hình:
|
||||
|
||||
- Full-height viewer canvas.
|
||||
- Top toolbar: model/version selector, view mode, section, measure, isolate, fit, saved views.
|
||||
- Left panel: model/resource tree, filters.
|
||||
- Right panel: properties, issue/comment/review.
|
||||
- Bottom status: loading progress, selected count, derivative status.
|
||||
|
||||
### 10.2 Speckle Viewer JS bridge
|
||||
|
||||
Blazor gọi JS bridge thay vì gọi trực tiếp viewer internals.
|
||||
|
||||
API JS bridge đề xuất:
|
||||
|
||||
```ts
|
||||
createViewer(containerId, options)
|
||||
loadResources(viewerId, resources)
|
||||
disposeViewer(viewerId)
|
||||
fitToView(viewerId)
|
||||
setSectionBox(viewerId, section)
|
||||
getViewerState(viewerId)
|
||||
setViewerState(viewerId, state)
|
||||
getSelection(viewerId)
|
||||
isolateObjects(viewerId, objectIds)
|
||||
clearIsolation(viewerId)
|
||||
```
|
||||
|
||||
Events gửi về Blazor:
|
||||
|
||||
- `viewerLoaded`
|
||||
- `loadProgress`
|
||||
- `selectionChanged`
|
||||
- `cameraChanged`
|
||||
- `objectDoubleClicked`
|
||||
- `error`
|
||||
|
||||
### 10.3 Viewer states
|
||||
|
||||
State cần lưu cho issue/saved view:
|
||||
|
||||
- Camera position/target.
|
||||
- Section box.
|
||||
- Selected object ids.
|
||||
- Isolated/hidden object ids.
|
||||
- Filters.
|
||||
- Resource ids.
|
||||
- Screenshot/thumbnail optional.
|
||||
|
||||
## 11. Module File Uploads
|
||||
|
||||
Màn hình:
|
||||
|
||||
- Upload dropzone.
|
||||
- File list.
|
||||
- Import queue.
|
||||
- Import detail/log.
|
||||
|
||||
States:
|
||||
|
||||
- Uploading.
|
||||
- Queued.
|
||||
- Converting.
|
||||
- Creating version.
|
||||
- Completed.
|
||||
- Failed.
|
||||
- Cancelled.
|
||||
|
||||
Actions:
|
||||
|
||||
- Upload file.
|
||||
- Start import.
|
||||
- Retry failed.
|
||||
- Cancel queued/running nếu worker support.
|
||||
- Open created version.
|
||||
|
||||
## 12. Module Issues
|
||||
|
||||
Views:
|
||||
|
||||
- List view.
|
||||
- Board by status.
|
||||
- Viewer side panel.
|
||||
|
||||
Issue fields:
|
||||
|
||||
- Title.
|
||||
- Description.
|
||||
- Status.
|
||||
- Priority.
|
||||
- Assignee.
|
||||
- Due date.
|
||||
- Related model/version/object ids.
|
||||
- Viewer state.
|
||||
- Comments.
|
||||
|
||||
Actions:
|
||||
|
||||
- Create issue from viewer selection.
|
||||
- Update status/assignee/priority.
|
||||
- Add comment.
|
||||
- Open issue in viewer.
|
||||
- Resolve/close.
|
||||
|
||||
## 13. Module Reviews
|
||||
|
||||
Review list:
|
||||
|
||||
- Name.
|
||||
- Status.
|
||||
- Due date.
|
||||
- Progress.
|
||||
- Reviewer.
|
||||
|
||||
Review detail:
|
||||
|
||||
- Items: model/version.
|
||||
- Viewer open button.
|
||||
- Decision: approve, reject, approve with comments.
|
||||
- Related issues.
|
||||
- Activity.
|
||||
|
||||
Workflow:
|
||||
|
||||
1. Project manager creates review session.
|
||||
2. Adds versions and reviewers.
|
||||
3. Reviewers inspect model in viewer.
|
||||
4. Reviewers create issues or decision.
|
||||
5. Manager closes review.
|
||||
|
||||
## 14. Module Search/Properties
|
||||
|
||||
Search scopes:
|
||||
|
||||
- Projects.
|
||||
- Models.
|
||||
- Versions.
|
||||
- Issues.
|
||||
- Object properties within current version.
|
||||
|
||||
Property panel:
|
||||
|
||||
- Object id.
|
||||
- Speckle type.
|
||||
- Application id if present.
|
||||
- Category/level/family/type if indexed.
|
||||
- Raw JSON expandable for technical users.
|
||||
|
||||
## 15. Module Notifications
|
||||
|
||||
Notification types:
|
||||
|
||||
- Version created.
|
||||
- Issue assigned.
|
||||
- Issue commented.
|
||||
- Review requested.
|
||||
- Import failed/completed.
|
||||
- Approval decision.
|
||||
|
||||
Delivery:
|
||||
|
||||
- In-app notification.
|
||||
- Email later.
|
||||
- Webhook for integrations.
|
||||
|
||||
## 16. Module Admin
|
||||
|
||||
Screens:
|
||||
|
||||
- System overview.
|
||||
- Users.
|
||||
- Apps/connectors.
|
||||
- Tokens.
|
||||
- Jobs.
|
||||
- Storage/quota.
|
||||
- Audit logs.
|
||||
- Server settings.
|
||||
|
||||
Admin actions:
|
||||
|
||||
- Disable user.
|
||||
- Revoke token.
|
||||
- Retry/cancel job.
|
||||
- Configure allowed file types.
|
||||
- Configure storage limits.
|
||||
- View audit.
|
||||
|
||||
## 17. Permission behavior in UI
|
||||
|
||||
UI phải ẩn hoặc disable action theo quyền:
|
||||
|
||||
| Permission | UI behavior |
|
||||
| --------------- | ------------------------------------------------------ |
|
||||
| No project read | Không hiện project hoặc hiện 403. |
|
||||
| Viewer only | Không hiện upload/create/delete. |
|
||||
| Reviewer | Hiện issue/review action, không hiện project settings. |
|
||||
| Contributor | Hiện upload/model/version action. |
|
||||
| Owner | Hiện team/settings/delete. |
|
||||
| Admin | Hiện admin global. |
|
||||
|
||||
Quan trọng: UI chỉ hỗ trợ trải nghiệm; backend vẫn là nơi enforce quyền.
|
||||
|
||||
## 18. Loading/error/empty states
|
||||
|
||||
Mọi màn hình chính cần:
|
||||
|
||||
- Loading skeleton hoặc progress.
|
||||
- Empty state có action phù hợp.
|
||||
- Error state có retry.
|
||||
- Permission denied state.
|
||||
- Offline/token expired handling.
|
||||
|
||||
Viewer riêng cần:
|
||||
|
||||
- Load progress.
|
||||
- Object stream error.
|
||||
- Derivative not ready fallback.
|
||||
- WebGL unsupported message.
|
||||
- Large model warning nếu browser yếu.
|
||||
|
||||
## 19. MVP UI scope
|
||||
|
||||
MVP nên gồm:
|
||||
|
||||
- Login/connector approve.
|
||||
- Project list/create/detail.
|
||||
- Model list/create/detail.
|
||||
- Version list/create via connector.
|
||||
- Viewer page load model.
|
||||
- File upload/import status.
|
||||
- Issue create/list/detail.
|
||||
- Basic review decision.
|
||||
- Admin jobs basic.
|
||||
|
||||
Không cần MVP:
|
||||
|
||||
- Full custom dashboard analytics.
|
||||
- Complex BIM rule builder.
|
||||
- Advanced saved view groups.
|
||||
- Real-time collaborative cursor.
|
||||
@@ -0,0 +1,373 @@
|
||||
# MVP Implementation Plan
|
||||
|
||||
## 1. Mục tiêu MVP
|
||||
|
||||
MVP phải chứng minh hệ thống mới có thể thay thế core Speckle Server cho các luồng quan trọng:
|
||||
|
||||
- Speckle Connector đăng nhập được.
|
||||
- Connector tạo project/model/version được.
|
||||
- Connector upload và pull object được.
|
||||
- Blazor web xem được model bằng Speckle Viewer.
|
||||
- User upload file IFC/STL/OBJ cơ bản và convert thành version.
|
||||
- Có issue/review cơ bản để thể hiện giá trị nghiệp vụ mở rộng.
|
||||
|
||||
## 2. Nguyên tắc triển khai
|
||||
|
||||
- Làm compatibility contract trước UI nâng cao.
|
||||
- Test bằng connector thật sớm.
|
||||
- Không viết lại Speckle Viewer.
|
||||
- Không tối ưu C++ quá sâu trước khi contract object ổn định.
|
||||
- Mỗi milestone phải có demo chạy được.
|
||||
|
||||
## 3. Milestone 0 - Foundation
|
||||
|
||||
Thời lượng gợi ý: 1-2 tuần.
|
||||
|
||||
Deliverables:
|
||||
|
||||
- Repo solution ASP.NET/Blazor.
|
||||
- Docker compose local: API, PostgreSQL, Redis/Queue, MinIO.
|
||||
- Migration framework.
|
||||
- Logging, health check, config.
|
||||
- CI build/test basic.
|
||||
|
||||
Tasks:
|
||||
|
||||
- Tạo solution structure.
|
||||
- Chọn GraphQL library.
|
||||
- Chọn queue.
|
||||
- Tạo base entities và DbContext/migrations.
|
||||
- Tạo OpenAPI/Swagger.
|
||||
- Tạo seed default apps.
|
||||
|
||||
Done khi:
|
||||
|
||||
- `docker compose up` chạy local.
|
||||
- API health check OK.
|
||||
- Blazor gọi được `/api/me` mock hoặc real.
|
||||
|
||||
## 4. Milestone 1 - Auth và connector login
|
||||
|
||||
Thời lượng gợi ý: 2-3 tuần.
|
||||
|
||||
Deliverables:
|
||||
|
||||
- User login.
|
||||
- Token storage.
|
||||
- Default Speckle apps.
|
||||
- `/auth/accesscode`.
|
||||
- `/auth/token`.
|
||||
- Scope/role authorization.
|
||||
|
||||
Tasks:
|
||||
|
||||
- Implement user/password hoặc SSO stub.
|
||||
- Implement app registry.
|
||||
- Implement access code flow.
|
||||
- Implement bearer token validation.
|
||||
- Implement token scope checks.
|
||||
- Tạo connector approve UI.
|
||||
- Viết contract tests cho auth flow.
|
||||
|
||||
Done khi:
|
||||
|
||||
- Speckle Desktop/Connector có thể add account tới server mới.
|
||||
- Token dùng được để gọi `/graphql`.
|
||||
- Token revoke/logout hoạt động.
|
||||
|
||||
## 5. Milestone 2 - Project/Model/Version GraphQL compatibility
|
||||
|
||||
Thời lượng gợi ý: 3-4 tuần.
|
||||
|
||||
Deliverables:
|
||||
|
||||
- Project CRUD.
|
||||
- Model CRUD.
|
||||
- Version CRUD.
|
||||
- GraphQL schema mới và legacy.
|
||||
- Mapping Stream/Branch/Commit sang Project/Model/Version.
|
||||
|
||||
Tasks:
|
||||
|
||||
- Implement tables: projects, project_members, models, versions.
|
||||
- Implement GraphQL `project`, `stream`, `streams`.
|
||||
- Implement `projectMutations`, `modelMutations`, `versionMutations`.
|
||||
- Implement legacy `streamCreate`, `branchCreate`, `commitCreate`.
|
||||
- Implement permission rules.
|
||||
- Write GraphQL contract tests from real connector queries.
|
||||
|
||||
Done khi:
|
||||
|
||||
- Connector tạo project/model/version metadata được.
|
||||
- Blazor project/model/version list hiển thị dữ liệu thật.
|
||||
|
||||
## 6. Milestone 3 - Object upload/pull core
|
||||
|
||||
Thời lượng gợi ý: 4-6 tuần.
|
||||
|
||||
Deliverables:
|
||||
|
||||
- Object table and repository.
|
||||
- `POST /objects/{projectId}`.
|
||||
- `GET /objects/{projectId}/{objectId}`.
|
||||
- `GET /objects/{projectId}/{objectId}/single`.
|
||||
- `POST /api/diff/{projectId}`.
|
||||
- `POST /api/getobjects/{projectId}`.
|
||||
- `POST /api/v2/projects/{projectId}/object-stream`.
|
||||
|
||||
Tasks:
|
||||
|
||||
- Implement object id validation/hash compatibility.
|
||||
- Implement multipart/gzip parsing.
|
||||
- Implement batch upsert.
|
||||
- Implement object diff.
|
||||
- Implement object stream gzip.
|
||||
- Implement DB cursor/backpressure.
|
||||
- Implement rate limits and upload size limits.
|
||||
- Add integration tests with real Speckle object payload.
|
||||
|
||||
Done khi:
|
||||
|
||||
- Connector push model nhỏ thành công.
|
||||
- Connector pull model vừa push thành công.
|
||||
- Upload lại không duplicate object.
|
||||
- Viewer hoặc test client stream object được.
|
||||
|
||||
## 7. Milestone 4 - Blazor viewer MVP
|
||||
|
||||
Thời lượng gợi ý: 3-4 tuần.
|
||||
|
||||
Deliverables:
|
||||
|
||||
- Blazor app shell.
|
||||
- Project/model/version pages basic.
|
||||
- Viewer page.
|
||||
- JS bridge cho `@speckle/viewer`.
|
||||
- Selection/property panel cơ bản.
|
||||
|
||||
Tasks:
|
||||
|
||||
- Add viewer package/build pipeline.
|
||||
- Implement JS bridge lifecycle.
|
||||
- Implement viewer load resources.
|
||||
- Implement load progress/error states.
|
||||
- Implement selection callback.
|
||||
- Implement property panel from selected object.
|
||||
- Playwright smoke test viewer page.
|
||||
|
||||
Done khi:
|
||||
|
||||
- User mở version từ Blazor và thấy model 3D.
|
||||
- Fit/selection/properties hoạt động cơ bản.
|
||||
- Viewer dispose không leak khi đổi route.
|
||||
|
||||
## 8. Milestone 5 - File upload/import C++ MVP
|
||||
|
||||
Thời lượng gợi ý: 4-6 tuần.
|
||||
|
||||
Deliverables:
|
||||
|
||||
- Blob storage.
|
||||
- File upload API.
|
||||
- File upload status UI.
|
||||
- C++ file import worker MVP.
|
||||
- Convert ít nhất một định dạng ưu tiên, nên là IFC hoặc OBJ/STL.
|
||||
|
||||
Tasks:
|
||||
|
||||
- Implement blob metadata and storage.
|
||||
- Implement presigned upload URL.
|
||||
- Implement legacy `/api/file/{fileType}/{projectId}/{branchName?}`.
|
||||
- Implement file_uploads table and job queue.
|
||||
- Implement C++ worker job polling/claim.
|
||||
- Implement conversion output to Speckle-compatible object graph.
|
||||
- Implement complete/fail callback.
|
||||
- Create version after conversion.
|
||||
|
||||
Done khi:
|
||||
|
||||
- User upload file từ Blazor.
|
||||
- Job chạy và tạo version.
|
||||
- Version mở được trong viewer.
|
||||
- File lỗi hiển thị failed và message.
|
||||
|
||||
## 9. Milestone 6 - Viewer derivative MVP
|
||||
|
||||
Thời lượng gợi ý: 4-6 tuần, có thể song song sau Milestone 4.
|
||||
|
||||
Deliverables:
|
||||
|
||||
- `viewer_derivatives` table.
|
||||
- Derivative queue.
|
||||
- C++ derivative worker.
|
||||
- Manifest/artifact endpoints.
|
||||
- Viewer fallback logic.
|
||||
|
||||
Tasks:
|
||||
|
||||
- Implement derivative status.
|
||||
- Enqueue derivative on version created.
|
||||
- Implement worker pull object stream.
|
||||
- Generate manifest/artifacts MVP.
|
||||
- Upload artifacts.
|
||||
- Publish/fail endpoints.
|
||||
- Viewer checks manifest and loads derivative if ready.
|
||||
|
||||
Done khi:
|
||||
|
||||
- Model lớn có derivative ready.
|
||||
- Viewer load derivative artifact.
|
||||
- Nếu derivative chưa ready, viewer fallback object stream.
|
||||
|
||||
## 10. Milestone 7 - Issue/Review MVP
|
||||
|
||||
Thời lượng gợi ý: 3-4 tuần.
|
||||
|
||||
Deliverables:
|
||||
|
||||
- Issue CRUD.
|
||||
- Comment thread basic.
|
||||
- Review session and decision.
|
||||
- Viewer create issue from selection.
|
||||
|
||||
Tasks:
|
||||
|
||||
- Implement issues/comments/review tables.
|
||||
- Implement issue API.
|
||||
- Implement review API.
|
||||
- Implement issue list and side panel.
|
||||
- Store viewer state in issue.
|
||||
- Open issue in viewer restores camera/selection.
|
||||
|
||||
Done khi:
|
||||
|
||||
- Reviewer tạo issue từ model.
|
||||
- PM tạo review và reviewer approve/reject version.
|
||||
- Issue/review hiện trên project dashboard.
|
||||
|
||||
## 11. Milestone 8 - Admin/Operations MVP
|
||||
|
||||
Thời lượng gợi ý: 2-3 tuần.
|
||||
|
||||
Deliverables:
|
||||
|
||||
- Admin users basic.
|
||||
- Job dashboard.
|
||||
- Audit log.
|
||||
- Storage usage.
|
||||
- Retry failed job.
|
||||
|
||||
Tasks:
|
||||
|
||||
- Implement audit logging.
|
||||
- Implement admin APIs.
|
||||
- Implement job list/retry/cancel.
|
||||
- Implement metrics dashboards or endpoint.
|
||||
- Add health checks for DB/storage/queue/worker.
|
||||
|
||||
Done khi:
|
||||
|
||||
- Admin thấy failed jobs và retry được.
|
||||
- Admin revoke token/disable user được.
|
||||
- Audit log ghi hành động quan trọng.
|
||||
|
||||
## 12. Workstream song song
|
||||
|
||||
| Workstream | Có thể chạy song song với |
|
||||
| --------------------------- | --------------------------------- |
|
||||
| Blazor UI shell | Auth/backend foundation. |
|
||||
| C++ file importer prototype | Object API design. |
|
||||
| Viewer JS bridge prototype | Project/model/version API. |
|
||||
| Contract test harness | Tất cả milestone. |
|
||||
| Data migration research | Sau khi data model draft ổn định. |
|
||||
|
||||
## 13. Backlog ưu tiên P0
|
||||
|
||||
P0 bắt buộc cho MVP:
|
||||
|
||||
- Auth connector.
|
||||
- GraphQL legacy project/model/version.
|
||||
- Object upload/pull REST.
|
||||
- Blazor viewer.
|
||||
- File upload/import một định dạng.
|
||||
- Permission core.
|
||||
- Contract tests.
|
||||
|
||||
## 14. Backlog ưu tiên P1
|
||||
|
||||
P1 sau MVP:
|
||||
|
||||
- Large model derivative.
|
||||
- Issue/review đầy đủ.
|
||||
- Search property.
|
||||
- Webhook.
|
||||
- Admin quota.
|
||||
- Migration tool từ Speckle Server.
|
||||
- Notifications.
|
||||
|
||||
## 15. Backlog ưu tiên P2
|
||||
|
||||
P2:
|
||||
|
||||
- BIM rule engine.
|
||||
- Advanced dashboard/report.
|
||||
- Saved view groups.
|
||||
- Multi-tenant organization/workspace.
|
||||
- SSO enterprise.
|
||||
- CDN/multi-region.
|
||||
|
||||
## 16. Test strategy
|
||||
|
||||
### 16.1 Unit tests
|
||||
|
||||
- Token creation/validation.
|
||||
- Permission engine.
|
||||
- Object hash/id validation.
|
||||
- Project/model/version mapping.
|
||||
- Job state transitions.
|
||||
|
||||
### 16.2 Integration tests
|
||||
|
||||
- GraphQL `streamCreate -> branchCreate -> commitCreate`.
|
||||
- Object `diff -> upload -> getobjects`.
|
||||
- File upload/import job callbacks.
|
||||
- Viewer derivative publish/fail.
|
||||
|
||||
### 16.3 Contract tests
|
||||
|
||||
- Capture real connector requests.
|
||||
- Replay against new server.
|
||||
- Assert status, shape, required fields.
|
||||
|
||||
### 16.4 E2E tests
|
||||
|
||||
- Login.
|
||||
- Create project.
|
||||
- Upload/push model.
|
||||
- Open viewer.
|
||||
- Create issue.
|
||||
- Create review decision.
|
||||
|
||||
## 17. Definition of Done MVP
|
||||
|
||||
MVP hoàn thành khi:
|
||||
|
||||
- Connector thật login và push/pull được model.
|
||||
- Blazor viewer mở được model push từ connector.
|
||||
- File import tạo version xem được.
|
||||
- Object API pass contract tests.
|
||||
- User roles ngăn hành động sai quyền.
|
||||
- Admin xem được job/import lỗi.
|
||||
- Logs/metrics đủ để debug upload/import/viewer.
|
||||
- Tài liệu API, data model, pipeline được cập nhật theo implementation thực tế.
|
||||
|
||||
## 18. Rủi ro và phương án giảm
|
||||
|
||||
| Rủi ro | Giảm thiểu |
|
||||
| ----------------------------------------- | ------------------------------------------------------------------------------- |
|
||||
| Connector dùng GraphQL field chưa liệt kê | Dùng proxy/log capture query thật, bổ sung contract tests. |
|
||||
| Object hash không tương thích | Chấp nhận id client gửi, test bằng payload thật, port thuật toán hash cẩn thận. |
|
||||
| Viewer khó bundle trong Blazor | Tách JS bridge/build riêng, prototype sớm. |
|
||||
| C++ importer mất nhiều thời gian | Bắt đầu với OBJ/STL hoặc IFC subset, giữ IFC đầy đủ sang phase sau nếu cần. |
|
||||
| Object stream chậm | Dùng DB cursor/gzip, benchmark sớm, derivative cho model lớn. |
|
||||
| Scope MVP phình to | P0/P1/P2 rõ, không đưa dashboard nâng cao vào P0. |
|
||||
@@ -0,0 +1,477 @@
|
||||
# Speckle Compatibility Contract
|
||||
|
||||
## 1. Mục tiêu
|
||||
|
||||
Tài liệu này định nghĩa contract tối thiểu mà nền tảng ASP.NET/Blazor mới phải giữ để Speckle Connector, Speckle SDK và Speckle Viewer hiện tại có thể làm việc với server mới.
|
||||
|
||||
Mục tiêu không phải clone toàn bộ Speckle Server. Mục tiêu là giữ đúng các điểm chạm quan trọng:
|
||||
|
||||
- Connector đăng nhập được.
|
||||
- Connector đọc danh sách project/model/version được.
|
||||
- Connector tạo project/model/version được.
|
||||
- Connector upload object graph được.
|
||||
- Connector pull object graph được.
|
||||
- Viewer load được model/version/object.
|
||||
- File upload/import cơ bản hoạt động.
|
||||
|
||||
## 2. Mapping thuật ngữ
|
||||
|
||||
| Speckle legacy | API mới | Ý nghĩa |
|
||||
| ---------------- | ----------- | ------------------------------------------ |
|
||||
| Stream | Project | Không gian chứa model, version, user role. |
|
||||
| Branch | Model | Nhánh dữ liệu trong project. |
|
||||
| Commit | Version | Snapshot trỏ tới root object. |
|
||||
| Object | Object | JSON object immutable, có id hash. |
|
||||
| referencedObject | Root Object | Object gốc của version. |
|
||||
| Blob | Blob/File | File thô hoặc attachment. |
|
||||
|
||||
Quy tắc:
|
||||
|
||||
- API mới nên dùng Project/Model/Version.
|
||||
- Compatibility API vẫn phải trả Stream/Branch/Commit cho client legacy.
|
||||
- ID có thể dùng cùng giá trị giữa Project và Stream để giảm mapping phức tạp.
|
||||
|
||||
## 3. Client cần support
|
||||
|
||||
| Client | Mức support MVP |
|
||||
| --------------------------------- | ----------------------------------------------------------------------------- |
|
||||
| Speckle Connector Desktop Manager | Login và lưu account. |
|
||||
| Speckle Connectors v2/v3 | Push/Pull cơ bản. |
|
||||
| Speckle SDK | Auth, stream/project query, object upload/download. |
|
||||
| Speckle Viewer | Load object stream và viewer resource. |
|
||||
| Speckle Web cũ | Không phải mục tiêu chính, chỉ support nếu không phát sinh thêm contract lớn. |
|
||||
|
||||
## 4. Auth contract
|
||||
|
||||
### 4.1 Default app IDs
|
||||
|
||||
Server mới cần pre-register các app ID phổ biến:
|
||||
|
||||
| App ID | Vai trò |
|
||||
| ------------ | ----------------------------- |
|
||||
| `spklwebapp` | Speckle Web Manager. |
|
||||
| `sdm` | Speckle Desktop Manager. |
|
||||
| `sca` | Speckle Connector legacy. |
|
||||
| `sdas` | Speckle Desktop Auth Service. |
|
||||
| `sdui` | Desktop connector UI. |
|
||||
| `connectrV3` | Desktop Connectors v3. |
|
||||
| `spklexcel` | Excel connector nếu cần. |
|
||||
| `spklpwerbi` | PowerBI connector nếu cần. |
|
||||
|
||||
### 4.2 OAuth-like flow
|
||||
|
||||
#### `GET /auth/accesscode`
|
||||
|
||||
Mục tiêu: browser flow để user approve connector/app.
|
||||
|
||||
Yêu cầu:
|
||||
|
||||
- Nhận query params tương thích Speckle app flow.
|
||||
- Nếu user chưa đăng nhập, chuyển đến trang login.
|
||||
- Nếu app chưa trusted, hiển thị màn approve.
|
||||
- Tạo access code ngắn hạn.
|
||||
- Redirect về `redirectUrl` của app hoặc localhost callback connector.
|
||||
|
||||
#### `POST /auth/token`
|
||||
|
||||
Mục tiêu: đổi access code thành bearer token.
|
||||
|
||||
Yêu cầu:
|
||||
|
||||
- Nhận payload tương thích connector.
|
||||
- Validate app ID, access code, redirect URL/challenge nếu có.
|
||||
- Trả token dạng bearer để dùng với GraphQL và REST.
|
||||
- Token phải có scope đúng.
|
||||
|
||||
Token storage:
|
||||
|
||||
- Token public trả cho client có thể giữ format Speckle: `10 ký tự id + 32 ký tự secret`.
|
||||
- DB chỉ lưu token id, token digest, owner, scopes, appId, expiry, last chars.
|
||||
- Không lưu plain token secret.
|
||||
|
||||
#### `POST /auth/logout`
|
||||
|
||||
Mục tiêu: revoke session web hoặc token hiện tại nếu client gọi.
|
||||
|
||||
## 5. Scope và permission
|
||||
|
||||
Scope tối thiểu:
|
||||
|
||||
| Scope | Ý nghĩa |
|
||||
| --------------- | --------------------------------------------- |
|
||||
| `streams:read` | Đọc project/model/version/object. |
|
||||
| `streams:write` | Tạo/sửa project/model/version, upload object. |
|
||||
| `profile:read` | Đọc thông tin user hiện tại. |
|
||||
| `profile:email` | Đọc email user. |
|
||||
| `users:read` | Đọc collaborator/team. |
|
||||
| `users:invite` | Invite user nếu connector/web cần. |
|
||||
|
||||
Project role tối thiểu:
|
||||
|
||||
| Role | Quyền |
|
||||
| ----------- | -------------------------------------------- |
|
||||
| Owner | Full quyền project. |
|
||||
| Contributor | Upload, tạo model/version, comment. |
|
||||
| Reviewer | Xem, comment, issue, approval nếu được giao. |
|
||||
| Viewer | Chỉ xem/pull. |
|
||||
|
||||
## 6. REST object endpoints
|
||||
|
||||
### 6.1 `POST /objects/{streamId}`
|
||||
|
||||
Mục tiêu: upload object batch.
|
||||
|
||||
Yêu cầu compatibility:
|
||||
|
||||
- `streamId` được map sang `projectId`.
|
||||
- Auth cần `streams:write` và quyền ghi project.
|
||||
- Request là `multipart/form-data`.
|
||||
- Mỗi file part chứa JSON array object.
|
||||
- MIME hợp lệ: `application/gzip`, `text/plain`, `application/json`, `application/octet-stream`.
|
||||
- Nếu gzip, server phải gunzip rồi parse JSON.
|
||||
- Mỗi object phải có id/hash hợp lệ hoặc server tính theo rule Speckle.
|
||||
- Server lưu object dạng immutable và deduplicate.
|
||||
- Response thành công: HTTP `201`.
|
||||
|
||||
Lỗi tối thiểu:
|
||||
|
||||
| Điều kiện | Status |
|
||||
| ------------------------ | ----------------- |
|
||||
| Không có quyền | `401` hoặc `403`. |
|
||||
| Project không tồn tại | `404`. |
|
||||
| Payload không parse được | `400`. |
|
||||
| Batch quá lớn | `413`. |
|
||||
|
||||
### 6.2 `GET /objects/{streamId}/{objectId}`
|
||||
|
||||
Mục tiêu: download object và children phục vụ connector/viewer legacy.
|
||||
|
||||
Yêu cầu:
|
||||
|
||||
- Auth cần `streams:read` hoặc project public.
|
||||
- Trả dữ liệu object dạng JSON/gzip theo hành vi Speckle hiện tại.
|
||||
- Phải support object root và traversal children nếu client yêu cầu qua query hiện có.
|
||||
|
||||
### 6.3 `GET /objects/{streamId}/{objectId}/single`
|
||||
|
||||
Mục tiêu: download một object đơn lẻ.
|
||||
|
||||
Yêu cầu:
|
||||
|
||||
- Không expand children.
|
||||
- Dùng cho client cần object cụ thể.
|
||||
|
||||
### 6.4 `POST /api/diff/{streamId}`
|
||||
|
||||
Mục tiêu: client gửi danh sách object id, server trả danh sách object còn thiếu.
|
||||
|
||||
Yêu cầu:
|
||||
|
||||
- Auth cần `streams:write`.
|
||||
- Body nhận danh sách object ids theo format Speckle legacy.
|
||||
- Response là danh sách object ids server chưa có.
|
||||
- Endpoint này giúp giảm upload trùng.
|
||||
|
||||
### 6.5 `POST /api/getobjects/{streamId}`
|
||||
|
||||
Mục tiêu: client pull nhiều object theo danh sách id.
|
||||
|
||||
Yêu cầu:
|
||||
|
||||
- Auth cần `streams:read`.
|
||||
- Body có field `objects` là JSON string của array object ids.
|
||||
- Response gzip.
|
||||
- Nếu `Accept: text/plain`, response content type là `text/plain; charset=UTF-8`.
|
||||
- Format text stream: mỗi dòng `objectId<TAB>json`.
|
||||
|
||||
### 6.6 `POST /api/v2/projects/{streamId}/object-stream`
|
||||
|
||||
Mục tiêu: object streaming v2 cho viewer/client mới.
|
||||
|
||||
Yêu cầu:
|
||||
|
||||
- Auth cần `streams:read` hoặc project public.
|
||||
- Body:
|
||||
|
||||
```json
|
||||
{
|
||||
"objectIds": ["object-id-1", "object-id-2"],
|
||||
"attributeMask": {
|
||||
"include": ["id", "speckle_type"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `attributeMask` có thể là `include` hoặc `exclude`.
|
||||
- Response gzip text stream.
|
||||
- `streamId` vẫn dùng tên route legacy nhưng map sang `projectId`.
|
||||
|
||||
## 7. Blob/file endpoints
|
||||
|
||||
### 7.1 `POST /api/stream/{streamId}/blob`
|
||||
|
||||
Upload blob vào project.
|
||||
|
||||
Yêu cầu:
|
||||
|
||||
- Auth cần quyền ghi comment/blob.
|
||||
- Request multipart.
|
||||
- Response `201` với `uploadResults`.
|
||||
|
||||
### 7.2 `POST /api/stream/{streamId}/blob/diff`
|
||||
|
||||
Client gửi danh sách blob ids, server trả blob ids chưa có.
|
||||
|
||||
### 7.3 `GET /api/stream/{streamId}/blob/{blobId}`
|
||||
|
||||
Download blob.
|
||||
|
||||
Yêu cầu:
|
||||
|
||||
- Support public project nếu policy cho phép.
|
||||
- Header `Content-Disposition` theo filename.
|
||||
|
||||
### 7.4 `DELETE /api/stream/{streamId}/blob/{blobId}`
|
||||
|
||||
Xóa blob nếu user có quyền.
|
||||
|
||||
### 7.5 `GET /api/stream/{streamId}/blobs`
|
||||
|
||||
List blob metadata, có thể filter bằng `fileName`.
|
||||
|
||||
### 7.6 `POST /api/file/{fileType}/{streamId}/{branchName?}`
|
||||
|
||||
Legacy file upload/import endpoint.
|
||||
|
||||
Yêu cầu:
|
||||
|
||||
- Giữ cho connector/client cũ.
|
||||
- `branchName` mặc định `main`.
|
||||
- Sau upload phải tạo file upload record và enqueue import job.
|
||||
- Response `201` với `uploadResults`.
|
||||
- Nên trả warning deprecation nhưng không phá client.
|
||||
|
||||
## 8. Viewer derivative endpoints
|
||||
|
||||
### 8.1 `GET /api/viewer-derivatives/{projectId}/{versionId}/manifest`
|
||||
|
||||
Mục tiêu: viewer lấy manifest derivative nếu có.
|
||||
|
||||
Response khi chưa sẵn sàng:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "queued-or-processing",
|
||||
"progress": 0.5,
|
||||
"stage": "generating-tiles"
|
||||
}
|
||||
```
|
||||
|
||||
Response khi sẵn sàng:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ready",
|
||||
"manifest": {}
|
||||
}
|
||||
```
|
||||
|
||||
### 8.2 `GET /api/viewer-derivatives/{projectId}/{versionId}/artifacts/*`
|
||||
|
||||
Mục tiêu: viewer tải tile/buffer/metadata artifact.
|
||||
|
||||
Yêu cầu:
|
||||
|
||||
- Auth đọc project.
|
||||
- Cache immutable cho artifact đã publish.
|
||||
|
||||
### 8.3 Worker publish endpoints
|
||||
|
||||
Các endpoint nội bộ cho worker:
|
||||
|
||||
- `PUT /api/viewer-derivatives/{projectId}/{versionId}/artifacts/*`
|
||||
- `POST /api/viewer-derivatives/{projectId}/{versionId}/publish`
|
||||
- `POST /api/viewer-derivatives/{projectId}/{versionId}/fail`
|
||||
|
||||
Chỉ internal worker token có quyền gọi.
|
||||
|
||||
## 9. GraphQL compatibility surface
|
||||
|
||||
### 9.1 Query tối thiểu
|
||||
|
||||
Server mới cần support tối thiểu:
|
||||
|
||||
```graphql
|
||||
type Query {
|
||||
activeUser: User
|
||||
serverInfo: ServerInfo
|
||||
project(id: String!): Project!
|
||||
stream(id: String!): Stream
|
||||
streams(query: String, limit: Int, cursor: String): UserStreamCollection
|
||||
}
|
||||
```
|
||||
|
||||
Project fields tối thiểu:
|
||||
|
||||
```graphql
|
||||
type Project {
|
||||
id: ID!
|
||||
name: String!
|
||||
description: String
|
||||
visibility: ProjectVisibility!
|
||||
role: String
|
||||
createdAt: DateTime!
|
||||
updatedAt: DateTime!
|
||||
models(cursor: String, limit: Int, filter: ProjectModelsFilter): ModelCollection!
|
||||
model(id: String!): Model!
|
||||
modelByName(name: String!): Model!
|
||||
versions(limit: Int, cursor: String): VersionCollection!
|
||||
version(id: String!): Version!
|
||||
object(id: String!): Object
|
||||
}
|
||||
```
|
||||
|
||||
Legacy Stream fields tối thiểu:
|
||||
|
||||
```graphql
|
||||
type Stream {
|
||||
id: String!
|
||||
name: String!
|
||||
description: String
|
||||
isPublic: Boolean!
|
||||
role: String
|
||||
branches(limit: Int, cursor: String): BranchCollection
|
||||
branch(name: String): Branch
|
||||
commits(limit: Int, cursor: String): CommitCollection
|
||||
commit(id: String): Commit
|
||||
object(id: String!): Object
|
||||
}
|
||||
```
|
||||
|
||||
### 9.2 Mutation tối thiểu
|
||||
|
||||
API mới:
|
||||
|
||||
```graphql
|
||||
type Mutation {
|
||||
projectMutations: ProjectMutations!
|
||||
modelMutations: ModelMutations!
|
||||
versionMutations: VersionMutations!
|
||||
fileUploadMutations: FileUploadMutations!
|
||||
}
|
||||
```
|
||||
|
||||
Legacy:
|
||||
|
||||
```graphql
|
||||
type Mutation {
|
||||
streamCreate(stream: StreamCreateInput!): String
|
||||
streamUpdate(stream: StreamUpdateInput!): Boolean!
|
||||
streamDelete(id: String!): Boolean!
|
||||
branchCreate(branch: BranchCreateInput!): String!
|
||||
branchUpdate(branch: BranchUpdateInput!): Boolean!
|
||||
branchDelete(branch: BranchDeleteInput!): Boolean!
|
||||
commitCreate(commit: CommitCreateInput!): String!
|
||||
commitUpdate(commit: CommitUpdateInput!): Boolean!
|
||||
commitDelete(commit: CommitDeleteInput!): Boolean!
|
||||
commitReceive(input: CommitReceivedInput!): Boolean!
|
||||
objectCreate(objectInput: ObjectCreateInput!): [String!]!
|
||||
}
|
||||
```
|
||||
|
||||
### 9.3 Model/Version fields tối thiểu
|
||||
|
||||
```graphql
|
||||
type Model {
|
||||
id: ID!
|
||||
name: String!
|
||||
displayName: String!
|
||||
description: String
|
||||
createdAt: DateTime!
|
||||
updatedAt: DateTime!
|
||||
versions(limit: Int, cursor: String, filter: ModelVersionsFilter): VersionCollection!
|
||||
version(id: String!): Version!
|
||||
projectId: String!
|
||||
}
|
||||
|
||||
type Version {
|
||||
id: ID!
|
||||
referencedObject: String
|
||||
message: String
|
||||
sourceApplication: String
|
||||
createdAt: DateTime!
|
||||
totalChildrenCount: Int
|
||||
parents: [String]
|
||||
model: Model!
|
||||
}
|
||||
```
|
||||
|
||||
Legacy:
|
||||
|
||||
```graphql
|
||||
type Branch {
|
||||
id: String!
|
||||
name: String!
|
||||
commits(limit: Int, cursor: String): CommitCollection
|
||||
}
|
||||
|
||||
type Commit {
|
||||
id: String!
|
||||
referencedObject: String!
|
||||
message: String
|
||||
sourceApplication: String
|
||||
totalChildrenCount: Int
|
||||
branchName: String
|
||||
parents: [String]
|
||||
createdAt: DateTime
|
||||
}
|
||||
```
|
||||
|
||||
## 10. Object identity contract
|
||||
|
||||
Yêu cầu:
|
||||
|
||||
- Object id phải dài 32 ký tự nếu client gửi theo Speckle hash legacy.
|
||||
- Nếu object có `id` hoặc `hash`, server phải tôn trọng nếu hợp lệ.
|
||||
- Nếu thiếu id, server tính hash theo thuật toán tương thích Speckle.
|
||||
- Dedup key tối thiểu: `(projectId, objectId)`.
|
||||
- Object data lưu nguyên JSON để pull ra không mất field.
|
||||
- Không normalize JSON làm thay đổi semantic object khi trả về client.
|
||||
|
||||
Acceptance test:
|
||||
|
||||
- Dùng cùng một object JSON, server mới phải tạo cùng object id như Speckle Server hoặc chấp nhận id client gửi.
|
||||
- Upload cùng batch hai lần không tạo bản ghi trùng.
|
||||
- Pull object sau upload trả data tương đương payload ban đầu.
|
||||
|
||||
## 11. Error compatibility
|
||||
|
||||
Không cần clone toàn bộ error message, nhưng cần giữ:
|
||||
|
||||
- HTTP status đúng.
|
||||
- JSON body có `error` hoặc GraphQL `errors`.
|
||||
- Không trả HTML error page cho API.
|
||||
- Validation lỗi payload phải rõ để connector log được.
|
||||
|
||||
## 12. Contract test bắt buộc
|
||||
|
||||
MVP chỉ được xem là tương thích khi pass các test:
|
||||
|
||||
- Connector login qua `/auth/accesscode` và `/auth/token`.
|
||||
- Tạo project bằng legacy `streamCreate`.
|
||||
- Tạo model bằng legacy `branchCreate`.
|
||||
- Upload object qua `POST /objects/{projectId}`.
|
||||
- Diff object qua `POST /api/diff/{projectId}`.
|
||||
- Tạo version bằng legacy `commitCreate`.
|
||||
- Pull version object bằng `GET /objects/{projectId}/{objectId}`.
|
||||
- Pull nhiều object bằng `POST /api/getobjects/{projectId}`.
|
||||
- Viewer load version qua object stream.
|
||||
- Token read-only không được upload.
|
||||
- Private project không đọc được nếu thiếu quyền.
|
||||
|
||||
## 13. Chính sách thay đổi contract
|
||||
|
||||
- Mọi endpoint trong tài liệu này là compatibility contract, không xoá trong MVP.
|
||||
- Nếu cần thay đổi request/response, thêm version route mới thay vì sửa route cũ.
|
||||
- Ghi contract test trước khi implement.
|
||||
- Khi support thêm connector version mới, bổ sung query/mutation/endpoint thật vào tài liệu này.
|
||||
@@ -0,0 +1,319 @@
|
||||
# Upload, Convert và Viewer Pipeline
|
||||
|
||||
## 1. Mục tiêu
|
||||
|
||||
Tài liệu này mô tả pipeline quan trọng nhất của hệ thống: đưa dữ liệu mô hình từ connector/file vào server, lưu thành object/version, convert nếu cần và hiển thị trên web bằng Speckle Viewer.
|
||||
|
||||
Pipeline có bốn nhánh chính:
|
||||
|
||||
- Connector object upload.
|
||||
- Connector pull/download.
|
||||
- File upload/import bằng C++ service.
|
||||
- Viewer load object stream hoặc viewer derivative.
|
||||
|
||||
## 2. Thành phần tham gia
|
||||
|
||||
| Thành phần | Vai trò |
|
||||
| ----------------------------- | -------------------------------------------------------- |
|
||||
| Speckle Connector | Tạo object graph từ phần mềm desktop và push/pull model. |
|
||||
| Blazor Web | UI upload file, xem model, issue/review. |
|
||||
| ASP.NET Core API | Auth, validate, metadata, object endpoint, queue job. |
|
||||
| PostgreSQL | Lưu metadata, object JSON, job state. |
|
||||
| Object Storage | Lưu blob, file gốc, derivative artifact. |
|
||||
| C++ Object Service | Tối ưu xử lý object batch lớn nếu cần. |
|
||||
| C++ File Import Service | Parse/convert IFC/STL/OBJ thành object graph. |
|
||||
| C++ Viewer Derivative Service | Tạo manifest/tile/buffer cho large model streaming. |
|
||||
| Speckle Viewer JS | Render model trong browser. |
|
||||
|
||||
## 3. Connector upload object pipeline
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant C as Connector
|
||||
participant API as ASP.NET Core API
|
||||
participant DB as PostgreSQL
|
||||
participant Q as Queue
|
||||
|
||||
C->>API: POST /api/diff/{projectId}
|
||||
API->>DB: Check existing object ids
|
||||
DB-->>API: Existing ids
|
||||
API-->>C: Missing object ids
|
||||
C->>API: POST /objects/{projectId}
|
||||
API->>API: Parse multipart/gzip batches
|
||||
API->>DB: Upsert missing objects
|
||||
API-->>C: 201 Created
|
||||
C->>API: GraphQL commitCreate/versionMutations.create
|
||||
API->>DB: Insert version
|
||||
API->>Q: Enqueue preview/derivative jobs
|
||||
API-->>C: versionId
|
||||
```
|
||||
|
||||
### 3.1 Quy tắc nghiệp vụ
|
||||
|
||||
- Connector là nguồn tạo object graph chính.
|
||||
- Server không sửa object data.
|
||||
- Nếu object id đã tồn tại trong project, server bỏ qua insert.
|
||||
- Version chỉ được tạo nếu root object tồn tại hoặc policy cho phép lazy validation.
|
||||
- `sourceApplication` phải được lưu để dashboard/filter biết dữ liệu đến từ Revit/Rhino/IFC...
|
||||
|
||||
### 3.2 Quy tắc kỹ thuật
|
||||
|
||||
- Upload endpoint dùng streaming multipart.
|
||||
- Batch JSON có thể gzip.
|
||||
- Server giới hạn kích thước batch nhưng không giới hạn tổng model nếu chia batch hợp lý.
|
||||
- Insert DB dùng batch + `ON CONFLICT DO NOTHING`.
|
||||
- Log mỗi batch: object count, bytes, elapsed, projectId, userId.
|
||||
|
||||
### 3.3 Trạng thái lỗi
|
||||
|
||||
| Lỗi | Cách xử lý |
|
||||
| --------------------- | ---------------------------------------------- |
|
||||
| Token thiếu scope | Trả 403, không ghi object. |
|
||||
| Project không tồn tại | Trả 404. |
|
||||
| JSON batch invalid | Trả 400, không tạo version. |
|
||||
| Batch quá lớn | Trả 413, connector có thể retry batch nhỏ hơn. |
|
||||
| DB conflict | Ignore nếu object giống id đã tồn tại. |
|
||||
| DB lỗi tạm thời | Trả 500/503, connector retry. |
|
||||
|
||||
## 4. Connector pull pipeline
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant C as Connector/Viewer
|
||||
participant API as ASP.NET Core API
|
||||
participant DB as PostgreSQL
|
||||
|
||||
C->>API: GraphQL query version/commit
|
||||
API->>DB: Load version metadata
|
||||
API-->>C: referencedObject
|
||||
C->>API: POST /api/getobjects/{projectId}
|
||||
API->>DB: Stream objects by ids
|
||||
API-->>C: gzip text stream id<TAB>json
|
||||
```
|
||||
|
||||
Yêu cầu:
|
||||
|
||||
- Pull nhiều object phải dùng DB cursor/stream, không load toàn bộ object vào memory.
|
||||
- Response hỗ trợ gzip.
|
||||
- Nếu client đóng kết nối, server phải dừng DB stream.
|
||||
- Object missing cần log để điều tra nhưng không làm crash toàn server.
|
||||
|
||||
## 5. File upload/import pipeline
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant U as User/Blazor
|
||||
participant API as ASP.NET Core API
|
||||
participant OS as Object Storage
|
||||
participant Q as Queue
|
||||
participant CPP as C++ File Import Service
|
||||
participant DB as PostgreSQL
|
||||
|
||||
U->>API: Request upload URL
|
||||
API-->>U: fileId + presigned URL
|
||||
U->>OS: PUT file
|
||||
U->>API: Start import
|
||||
API->>DB: Insert file_upload queued
|
||||
API->>Q: Enqueue file-import job
|
||||
CPP->>Q: Take job
|
||||
CPP->>OS: Download source file
|
||||
CPP->>CPP: Parse/convert
|
||||
CPP->>API: Upload objects or callback result
|
||||
API->>DB: Insert objects + version
|
||||
API->>DB: Mark file_upload completed
|
||||
```
|
||||
|
||||
### 5.1 Job states
|
||||
|
||||
| State | Ý nghĩa |
|
||||
| ------------------- | --------------------------------- |
|
||||
| `queued` | Job đã tạo, chưa worker nào nhận. |
|
||||
| `running` | Worker đang xử lý. |
|
||||
| `converting` | File đang parse/convert. |
|
||||
| `uploading_objects` | Worker đang publish object graph. |
|
||||
| `creating_version` | Server đang tạo version. |
|
||||
| `completed` | Import thành công. |
|
||||
| `failed` | Import lỗi. |
|
||||
| `cancelled` | User/admin hủy. |
|
||||
|
||||
### 5.2 C++ File Import Service contract
|
||||
|
||||
Input job:
|
||||
|
||||
```json
|
||||
{
|
||||
"jobId": "job-id",
|
||||
"fileUploadId": "file-id",
|
||||
"projectId": "project-id",
|
||||
"modelId": "model-id",
|
||||
"modelName": "Imported/IFC",
|
||||
"sourceFile": {
|
||||
"storageKey": "uploads/project/file.ifc",
|
||||
"fileName": "file.ifc",
|
||||
"fileType": "ifc"
|
||||
},
|
||||
"callbackBaseUrl": "https://server/internal"
|
||||
}
|
||||
```
|
||||
|
||||
Output success:
|
||||
|
||||
```json
|
||||
{
|
||||
"rootObjectId": "object-id",
|
||||
"totalChildrenCount": 12345,
|
||||
"sourceApplication": "IFC Importer",
|
||||
"stats": {
|
||||
"elementCount": 1000,
|
||||
"geometryCount": 5000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Output fail:
|
||||
|
||||
```json
|
||||
{
|
||||
"errorCode": "ifc_parse_failed",
|
||||
"errorMessage": "Invalid IFC schema or corrupted file."
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 Idempotency
|
||||
|
||||
- `fileUploadId` là idempotency key.
|
||||
- Retry cùng job không được tạo nhiều version nếu lần trước đã completed.
|
||||
- Nếu worker upload object rồi fail trước khi tạo version, retry phải reuse object đã có.
|
||||
- Callback complete phải transaction: tạo version và mark upload completed cùng lúc hoặc có cơ chế recover.
|
||||
|
||||
## 6. Viewer object stream pipeline
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant B as Blazor
|
||||
participant JS as Viewer JS Bridge
|
||||
participant API as ASP.NET Core API
|
||||
participant DB as PostgreSQL
|
||||
|
||||
B->>API: Get version metadata
|
||||
B->>JS: initViewer(container, token, projectId, objectId)
|
||||
JS->>API: POST /api/v2/projects/{projectId}/object-stream
|
||||
API->>DB: Stream object data
|
||||
API-->>JS: gzip text stream
|
||||
JS->>JS: Speckle Viewer renders model
|
||||
JS-->>B: selection/camera events
|
||||
```
|
||||
|
||||
Blazor không xử lý geometry trực tiếp. Blazor chỉ:
|
||||
|
||||
- Tạo viewer container.
|
||||
- Gửi cấu hình/token/resource cho JS bridge.
|
||||
- Nhận event selection, camera, load progress.
|
||||
- Hiển thị side panel issue/property/review.
|
||||
|
||||
## 7. Viewer derivative pipeline
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant API as ASP.NET Core API
|
||||
participant Q as Queue
|
||||
participant CPP as C++ Derivative Service
|
||||
participant OS as Object Storage
|
||||
participant V as Speckle Viewer
|
||||
|
||||
API->>Q: Enqueue derivative for version
|
||||
CPP->>Q: Take job
|
||||
CPP->>API: Pull object stream
|
||||
CPP->>CPP: Build tiles/manifest
|
||||
CPP->>API: PUT artifacts
|
||||
CPP->>API: POST publish
|
||||
V->>API: GET manifest
|
||||
V->>API: GET artifacts/*
|
||||
```
|
||||
|
||||
### 7.1 Khi nào tạo derivative
|
||||
|
||||
Tạo derivative nếu:
|
||||
|
||||
- `totalChildrenCount` vượt ngưỡng cấu hình.
|
||||
- File import là IFC/model lớn.
|
||||
- User mở viewer và derivative chưa có.
|
||||
- Admin bật precompute derivative cho project.
|
||||
|
||||
Không cần tạo derivative cho model nhỏ trong MVP nếu object stream đủ nhanh.
|
||||
|
||||
### 7.2 Derivative artifact
|
||||
|
||||
Artifact đề xuất:
|
||||
|
||||
- `manifest.json`
|
||||
- geometry tiles/buffers
|
||||
- metadata index
|
||||
- bounding volume hierarchy
|
||||
- material table
|
||||
- property lookup nếu cần
|
||||
|
||||
Storage key:
|
||||
|
||||
```text
|
||||
viewer-derivatives/{projectId}/{versionId}/published/{artifactPath}
|
||||
```
|
||||
|
||||
### 7.3 Manifest response
|
||||
|
||||
Manifest cần đủ để viewer biết:
|
||||
|
||||
- schema version.
|
||||
- tile list.
|
||||
- bounding boxes.
|
||||
- artifact paths.
|
||||
- property metadata.
|
||||
- fallback object id/version id.
|
||||
|
||||
## 8. BIM check pipeline mở rộng
|
||||
|
||||
Sau MVP có thể thêm BIM check:
|
||||
|
||||
1. Version created event.
|
||||
2. Enqueue BIM check job.
|
||||
3. C++ hoặc .NET worker pull object/property index.
|
||||
4. Chạy rules: missing parameter, category check, clash precheck, naming convention.
|
||||
5. Ghi issue hoặc report.
|
||||
6. Dashboard hiển thị kết quả.
|
||||
|
||||
## 9. Monitoring pipeline
|
||||
|
||||
Metrics bắt buộc:
|
||||
|
||||
- Object upload duration.
|
||||
- Object upload batch size.
|
||||
- Object insert count/conflict count.
|
||||
- Object stream duration and bytes.
|
||||
- File import queue wait time.
|
||||
- File import processing time.
|
||||
- Derivative generation time.
|
||||
- Viewer manifest hit/miss.
|
||||
- Error rate theo endpoint/job type.
|
||||
|
||||
Log bắt buộc:
|
||||
|
||||
- `correlationId`
|
||||
- `projectId`
|
||||
- `modelId`
|
||||
- `versionId`
|
||||
- `fileUploadId`
|
||||
- `jobId`
|
||||
- `workerId`
|
||||
- `objectCount`
|
||||
- `bytes`
|
||||
|
||||
## 10. Checklist nghiệm thu pipeline
|
||||
|
||||
- Upload/pull bằng connector thật thành công.
|
||||
- Upload lại cùng model không nhân đôi object.
|
||||
- File IFC nhỏ import ra version xem được.
|
||||
- File lỗi hiển thị trạng thái failed và error message rõ.
|
||||
- Viewer load được object stream khi derivative chưa có.
|
||||
- Viewer dùng derivative khi derivative ready.
|
||||
- Hủy kết nối download giữa chừng không giữ DB cursor treo.
|
||||
- Worker crash giữa job có thể retry.
|
||||
Reference in New Issue
Block a user