docs: add speckle-compatible platform planning
This commit is contained in:
+28
-9
@@ -1,28 +1,44 @@
|
||||
# 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**:
|
||||
- **Tech Stack hiện tại**:
|
||||
- Backend: Node.js (TypeScript), Express, Apollo GraphQL.
|
||||
- Frontend: Vue 3, Nuxt 3 (SSR).
|
||||
- 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`). |
|
||||
| **Commit (Version)** | Một snapshot dữ liệu được đẩy lên Branch. Chứa metadata và tham chiếu tới một thẻ `objectId` gốc (root object). |
|
||||
| **Object** | Đơn vị dữ liệu nhỏ nhất. Khi lấy dữ liệu 3D, Client/Plugin phân tách các mặt cắt, vật liệu... thành các Object nhỏ và gửi lên server. Có tính Immutable và được băm (hash) thành ID. Chứa các tham chiếu (references) tới các mảng Object khác. |
|
||||
| **Workspace** | (Tính năng Enterprise) Không gian làm việc quản lý nhiều Project và Billing. |
|
||||
| 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`). |
|
||||
| **Commit (Version)** | Một snapshot dữ liệu được đẩy lên Branch. Chứa metadata và tham chiếu tới một thẻ `objectId` gốc (root object). |
|
||||
| **Object** | Đơn vị dữ liệu nhỏ nhất. Khi lấy dữ liệu 3D, Client/Plugin phân tách các mặt cắt, vật liệu... thành các Object nhỏ và gửi lên server. Có tính Immutable và được băm (hash) thành ID. Chứa các tham chiếu (references) tới các mảng Object khác. |
|
||||
| **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