Để hoàn thành dự án “Notopia - Ứng dụng ghi chú thông minh hỗ trợ quản lý tri thức bằng biểu đồ quan hệ”, bên cạnh sự nỗ lực của các thành viên, chúng em đã may mắn nhận được sự đồng hành và chỉ dẫn vô cùng quý giá.

Đặc biệt, chúng em xin bày tỏ lòng tri ân sâu sắc nhất tới cô Trần Thị Hồng Yến. Không chỉ là người định hướng chuyên môn, cô còn dành tâm huyết để khích lệ, giúp chúng em tháo gỡ những nút thắt kỹ thuật và tư duy hệ thống trong suốt quá trình nghiên cứu. Những góp ý đầy tận tâm của cô chính là kim chỉ nam giúp Notopia hình thành và hoàn thiện như ngày hôm nay.

Đồng thời, nhóm xin gửi lời cảm ơn chân thành đến Khoa Công nghệ Phần mềm, trường Đại học Công nghệ Thông tin – ĐHQG TP.HCM. Cảm ơn Nhà trường đã tạo dựng một môi trường học tập hiện đại, cung cấp nền tảng tri thức và cơ sở vật chất tốt nhất để chúng em thực hiện đề tài này.

Mặc dù đã dồn hết tâm sức, song đồ án chắc chắn vẫn còn những điểm cần cải thiện. Chúng em rất mong nhận được sự chỉ dẫn và đóng góp từ quý thầy cô để nhóm có thể phát triển ứng dụng ngày một hoàn thiện hơn.

STT Ký hiệu Ý nghĩa
1 ABAC Attribute-Based Access Control
2 ACL Access Control List
3 CI/CD Continuous Integration/Continuous Deployment
4 CLI Command-Line Interface
5 CRDT Conflict-free Replicated Data Type
6 DX Developer Experience
7 HTTP/2 Hypertext Transfer Protocol Version 2
8 ISR Incremental Static Regeneration
9 JSX JavaScript XML Syntax Extension
10 OAuth2 OAuth 2.0 Authorization Framework
11 OIDC OpenID Connect
12 ORM Object-Relational Mapping
13 OTLP OpenTelemetry Protocol
14 RBAC Role-Based Access Control
15 REST Representational State Transfer
16 RPC Remote Procedure Call
17 SSE Server-Sent Events
18 SSG Static Site Generation
19 SSO Single Sign-On
20 SSR Server-Side Rendering
21 gRPC Google Remote Procedure Call

Đề tài tập trung nghiên cứu và xây dựng “Notopia - Ứng dụng ghi chú thông minh hỗ trợ quản lý tri thức bằng biểu đồ quan hệ”, với mục đích giúp người dùng quản lý tri thức cá nhân trên một nền tảng web trực quan, cộng tác theo thời gian thực. Đề tài không hướng đến việc giải quyết các nhược điểm của các nền tảng sẵn có trên thị trường, mà thay vào đó tập trung nghiên cứu kiến trúc, phương pháp phát triển phần mềm, triển khai hệ thống, khai thác và sử dụng các công nghệ hiện đại.

Báo cáo trình bày các nghiên cứu, quy trình thiết kế, cài đặt và triển khai hệ thống thông qua các chương sau:

Chương này trình bày bối cảnh thực tiễn và lý do lựa chọn đề tài, từ đó làm rõ mục tiêu, phạm vi và đối tượng nghiên cứu của dự án. Nội dung của chương nhằm giúp người đọc có cái nhìn toàn diện về định hướng nghiên cứu, cơ sở khoa học và giá trị ứng dụng thực tiễn của đề tài trước khi đi sâu vào các chương phân tích và thiết kế chi tiết ở các phần tiếp theo.

1.1. Lý do chọn đề tài

Trong kỷ nguyên bùng nổ thông tin, việc quản lý kiến thức cá nhân (Personal Knowledge Management - PKM) trở thành một kỹ năng thiết yếu. Các phương pháp ghi chú truyền thống theo dạng danh sách hoặc thư mục dần bộc lộ hạn chế trong việc kết nối các ý tưởng rời rạc. Lấy cảm hứng từ các ứng dụng như Notion, Obsidian, chúng em xây dựng nền tảng ghi chú hiện đại hỗ trợ liên kết hai chiều1, kết hợp trực quan hóa kiến thức thành biểu đồ quan hệ.

1.2. Mục đích và mục tiêu nghiên cứu

1.2.1. Mục đích nghiên cứu

Xây dựng nền tảng web quản lý tri thức cá nhân, trực quan hoá bằng biểu đồ quan hệ (Graph View), cộng tác theo thời gian thực. Ứng dụng cung cấp các chức năng ghi chú cơ bản: tạo, sửa, xoá tạm thời, xoá vĩnh viễn, khôi phục, tìm kiếm toàn văn (full-text search) và phân quyền truy cập không gian làm việc (workspace).

1.2.2. Mục tiêu nghiên cứu

1.3. Đối tượng và phạm vi nghiên cứu

1.3.1. Đối tượng nghiên cứu

Đối tượng nghiên cứu về mặt nghiệp vụ

CRDT
Conflict-free Replicated Data Type, cấu trúc dữ liệu cho phép hợp nhất tự động các thay đổi từ nhiều người dùng mà không gây xung đột, phù hợp cho ứng dụng cộng tác thời gian thực.

Đối tượng nghiên cứu về mặt kỹ thuật

SSE
Server-Sent Events, công nghệ cho phép máy chủ gửi dữ liệu thời gian thực đến trình duyệt mà không cần WebSocket phức tạp.

1.3.2. Phạm vi nghiên cứu

Định danh người dùng (Identity)

Sử dụng dịch vụ thứ bên thứ 3 để quản lý đăng ký, đăng nhập, thông qua OAuth2/OpenID Connect, đảm bảo an toàn và dễ dàng tích hợp với các dịch vụ khác trong hệ thống.

Ghi chú (Note)

Quản lý không gian làm việc, sắp xếp các ghi chú theo cấu trúc thư mục, biểu diễn quan hệ giữa các ghi chú, hỗ trợ cộng tác theo thời gian thực ở góc độ lưu trữ và tổ chức thông tin.

Tài liệu (Document)

Nội dung ghi chú được lưu trữ dưới dạng tài liệu Block-based (BlockNote), cho phép trình bày và chỉnh sửa linh hoạt, đồng thời hỗ trợ cộng tác thời gian thực. Tệp tin đính kèm được lưu qua Object Storage.

Phân quyền (Authorization)

Quản lý quyền truy cập vào không gian làm việc. Không gian làm việc có thể chia sẻ với nhiều người dùng với quyền hạn khác nhau, đảm bảo an toàn và kiểm soát truy cập.

Tìm kiếm (Search)

Lắng nghe và đồng bộ nội dung ghi chú khi thay đổi đến dịch vụ tìm kiếm bên thứ ba.

Hạ tầng (Infrastructure)

1.4. Phương pháp nghiên cứu

Dự án áp dụng phương pháp tiếp cận kỹ thuật hệ thống, kết hợp nghiên cứu lý thuyết quản lý tri thức và triển khai thực nghiệm công nghệ phần mềm.

Phương pháp thu thập và phân tích yêu cầu

Khảo sát các ứng dụng quản lý ghi chú hiện có (Notion, Obsidian, jackyzha0/quartz) để rút ra các tính năng cần thiết.

Phương pháp thiết kế và mô hình hoá hệ thống

Sử dụng UML cho sơ đồ lớp (class diagram) và sơ đồ tuần tự (sequence diagram). Dùng D2 cho sơ đồ triển khai (deployment diagram) và cơ sở dữ liệu quan hệ. Trong đó:

Phương pháp phát triển API

Thiết kế API theo chuẩn RESTful, sử dụng OpenAPI 3.0 để mô tả API giữa Web App và API service, Protocol Buffers 3 cho giao tiếp giữa các service nội bộ. Áp dụng hướng tiếp cận “Contract First”, đảm bảo tính nhất quán từ giai đoạn thiết kế đến triển khai.

Nhờ đặc tả này, có thể tự động sinh mã nguồn client và server, giảm lỗi và tăng tốc phát triển.

1.5. Chức năng

Notopia là nền tảng quản lý tri thức cá nhân, hỗ trợ người dùng tổ chức, kết nối và trực quan hóa kiến thức trên web với khả năng cộng tác thời gian thực. Các nhóm chức năng chính bao gồm:

Tạo và quản lý không gian làm việc

Người dùng có thể tạo các không gian làm việc riêng biệt, chia sẻ và quản lý quyền truy cập linh hoạt. Mỗi không gian là vùng lưu trữ độc lập cho ghi chú và dự án.

Tổ chức ghi chú theo cấu trúc thư mục

Người dùng sắp xếp ghi chú thành thư mục lồng nhau, tạo cấu trúc dữ liệu rõ ràng, giúp quản lý số lượng lớn ghi chú hiệu quả.

Tạo các liên kết hai chiều giữa ghi chú

Người dùng liên kết ghi chú qua cơ chế liên kết hai chiều, tạo mạng lưới tri thức động. Hệ thống tự động ghi nhận backlink, giúp hiểu rõ mối quan hệ giữa các ý tưởng.

Soạn thảo nội dung dạng block-based

Nội dung ghi chú được tổ chức thành các khối độc lập, cho phép linh hoạt xây dựng và chỉnh sửa tài liệu. Mỗi khối có thể là văn bản, hình ảnh, mã code hoặc loại nội dung khác.

Cộng tác theo thời gian thực

Nhiều người dùng có thể làm việc đồng thời trên cùng ghi chú. Hệ thống đồng bộ thay đổi tức thời và giải quyết xung đột tự động.

Trực quan hóa mối quan hệ bằng biểu đồ quan hệ

Người dùng xem mạng lưới tri thức dưới dạng biểu đồ quan hệ (Graph View), hiển thị liên kết và mối quan hệ giữa các ghi chú, trực quan hơn cách tổ chức tuyến tính truyền thống.

Tìm kiếm nhanh chóng

Hệ thống hỗ trợ tìm kiếm toàn văn trên mọi nội dung ghi chú, giúp người dùng nhanh chóng tìm ra thông tin cần thiết.

Quản lý quyền truy cập và phân quyền

Chủ sở hữu không gian làm việc quản lý quyền từng thành viên (xem, chỉnh sửa, xóa) với nhiều cấp độ quyền, đảm bảo an toàn và kiểm soát truy cập.

Quản lý vòng đời tài liệu

Ghi chú có thể xóa tạm thời (vào thùng rác) hoặc xóa vĩnh viễn. Người dùng có thể khôi phục ghi chú đã xóa tạm thời, tránh mất dữ liệu.

1.6. Công nghệ sử dụng

Notopia ứng dụng bộ công nghệ được lựa chọn kỹ lưỡng, đảm bảo mở rộng, hiệu suất cao và bảo trì dài hạn.

Web App

Backend

Cơ sở dữ liệu

Cộng tác theo thời gian thực

Giao tiếp API

Bên cạnh đó, các dịch vụ không hỗ trợ gRPC có SDK hoặc REST API (ví dụ Authentik có SDK cho Go và NodeJS).

Kiến trúc sự kiện

NestJS hỗ trợ sẵn event-driven architecture, không cần thư viện ngoài.

Giám sát

Hạ tầng

2.1. Tổng quan về Go (Golang)

2.1.1. Giới thiệu

Go (còn gọi là Golang) là ngôn ngữ lập trình mã nguồn mở được phát triển bởi Google vào năm 2007 và chính thức phát hành vào năm 2009. Được thiết kế bởi Robert Griesemer, Rob Pike và Ken Thompson, Go nhằm mục tiêu tạo ra một ngôn ngữ hiệu quả, dễ học, và phù hợp cho lập trình hệ thống quy mô lớn.

Hình 2.1: Golang logo

Dự án sử dụng Go cùng với công cụ goforj/wire, một fork của google/wire, giúp dependencies injection có hỗ trợ cache fast để tối ưu thời gian build.

2.1.2. Ưu điểm

Go mang lại nhiều lợi ích trong phát triển backend:

2.1.3. Nhược điểm

Bên cạnh các ưu điểm, Go có một số hạn chế:

2.2. Tổng quan về TypeScript

2.2.1. Giới thiệu

TypeScript là một ngôn ngữ lập trình mã nguồn mở được phát triển và duy trì bởi Microsoft. TypeScript là một superset của JavaScript, nghĩa là mọi code JavaScript hợp lệ đều là code TypeScript hợp lệ. Được ra mắt lần đầu vào năm 2012 bởi Anders Hejlsberg (người thiết kế C#), TypeScript bổ sung hệ thống kiểu dữ liệu tĩnh trên nền tảng JavaScript để tăng độ tin cậy và khả năng duy trì của code.

TypeScript hoạt động thông qua một bước biên dịch: mã TypeScript được biên dịch thành mã JavaScript, sau đó được chạy trên JavaScript runtime (trình duyệt hoặc Node.js).

Hình 2.2: TypeScript logo

2.2.2. Ưu điểm

TypeScript mang lại nhiều lợi ích khi phát triển ứng dụng JavaScript:

2.2.3. Nhược điểm

Bên cạnh các ưu điểm, TypeScript có một số hạn chế:

2.2.4. Hệ sinh thái và công cụ

Dự án microsoft/typescript-go đang phát triển một implementation của TypeScript được viết hoàn toàn bằng Go, thay vì TypeScript hiện tại được viết bằng TypeScript. Dự án này hướng tới việc cải thiện hiệu suất.

Dự án được thiết lập với monorepo, các package được chia build riêng biệt (SWC, Rspack, tsgo, vite) để tăng tốc thời gian build, Oxlint thay cho ESLint, Oxfmt thay cho Prettier để tăng tốc độ linting và formatting, CI, ngoại trừ web vì sử dụng NextJS.

2.3. Tổng quan về React và NextJS

2.3.1. Giới thiệu

Frontend của dự án được xây dựng với React, một thư viện JavaScript cho xây dựng user interfaces với component-based architecture. Next.js được sử dụng như một framework trên React, cung cấp server-side rendering, static generation, và routing tích hợp.

Hình 2.3: React, NextJS Logo

2.3.2. React

React là thư viện JavaScript mã nguồn mở từ Meta (Facebook) cho xây dựng user interfaces. React sử dụng virtual DOM để tối ưu rendering, component-based architecture cho reusability, và declarative syntax làm cho code dễ đọc hơn.

2.3.3. Next.js

Next.js là framework React được phát triển bởi Vercel, cung cấp Server-Side Rendering (SSR), Static Site Generation (SSG), Incremental Static Regeneration (ISR), và API routes tích hợp. Next.js giúp tối ưu hiệu suất và SEO mà không cần setup phức tạp.

2.3.4. Ưu điểm

React và NextJS mang lại nhiều lợi ích cho phát triển frontend:

2.3.5. Nhược điểm

Bên cạnh các ưu điểm, các công nghệ frontend này có một số hạn chế:

2.4. Tổng quan về NestJS

2.4.1. Giới thiệu

NestJS là một framework progressive Node.js được xây dựng để phát triển các ứng dụng server-side hiệu quả, đáng tin cậy và có khả năng mở rộng cao. Được phát triển bởi Kamil Myśliwiec và ra mắt lần đầu vào năm 2017, NestJS kết hợp các khái niệm từ Angular, Spring Framework và các framework hiện đại khác.

NestJS được xây dựng trên nền tảng Express.js (hoặc Fastify) và sử dụng TypeScript làm ngôn ngữ chính. Framework này tổ chức code theo mô hình kiến trúc mô-đun rõ ràng, bao gồm controllers, services, middleware, guards, interceptors, và pipes, tương tự như Spring Framework của Java.

Trong dự án này, NestJS được xây dựng với:

Hình 2.4: NestJS logo

2.4.2. Ưu điểm

NestJS mang lại nhiều lợi ích cho phát triển backend:

2.4.3. Nhược điểm

Bên cạnh các ưu điểm, NestJS có một số hạn chế:

2.5. Tổng quan về PostgreSQL

2.5.1. Giới thiệu

PostgreSQL (còn gọi là Postgres) là một hệ quản trị cơ sở dữ liệu quan hệ đối tượng (ORDBMS) mã nguồn mở, mạnh mẽ và tiên tiến. PostgreSQL được phát triển từ dự án POSTGRES tại Đại học California, Berkeley vào năm 1986 và đã phát triển hơn 35 năm với cộng đồng đóng góp tích cực.

PostgreSQL nổi tiếng vì sự tuân thủ nghiêm ngặt các chuẩn SQL, hỗ trợ ACID transactions đầy đủ, và khả năng mở rộng cao thông qua các kiểu dữ liệu tùy chỉnh và extensions như PostGIS, pgcrypto, và full-text search.

Hình 2.5: PostgreSQL logo

2.5.2. Ưu điểm

PostgreSQL mang lại nhiều lợi ích cho phát triển ứng dụng:

2.5.3. Nhược điểm

Bên cạnh các ưu điểm, PostgreSQL có một số hạn chế:

2.6. Tổng quan về giải pháp chỉnh sửa cộng tác

2.6.1. Giới thiệu

Trong các ứng dụng cho phép nhiều người dùng cùng chỉnh sửa một tài liệu đồng thời, vấn đề cốt lõi là làm thế nào để đảm bảo tính nhất quán dữ liệu khi các thay đổi xảy ra song song từ nhiều nguồn khác nhau. Đây là bài toán đã được nghiên cứu sâu rộng trong lĩnh vực hệ thống phân tán và là nền tảng cho mọi công cụ cộng tác thời gian thực hiện đại.

Hiện nay có hai trường phái giải pháp được nghiên cứu và ứng dụng phổ biến nhất: Operational Transformation (OT) và Conflict-free Replicated Data Type (CRDT). Mỗi phương pháp tiếp cận bài toán theo một hướng khác nhau, với những đánh đổi riêng về độ phức tạp, hiệu suất và khả năng mở rộng.

2.6.2. Operational Transformation

Lịch sử

Operational Transformation được giới thiệu lần đầu vào năm 1989 bởi C. Ellis và S. Gibbs trong bài báo “Concurrency Control in Groupware Systems”. Bước ngoặt lớn đến vào năm 2009, khi Google công bố Google Wave và Google Docs sử dụng OT ở quy mô hàng triệu người dùng, đưa công nghệ này từ lý thuyết vào sản phẩm thương mại đại trà.

Nguyên lý hoạt động

Operational Transformation giải quyết xung đột bằng cách biến đổi các thao tác chỉnh sửa trước khi áp dụng chúng, sao cho kết quả cuối cùng luôn nhất quán bất kể thứ tự nhận được.

Khi người dùng A thực hiện thao tác X và người dùng B đồng thời thực hiện thao tác Y, hệ thống OT sẽ tính toán một phiên bản biến đổi X’ sao cho việc áp dụng X’ sau Y cho ra kết quả tương đương với việc áp dụng Y’ sau X. Quá trình biến đổi này thường được điều phối qua một máy chủ trung tâm đóng vai trò trọng tài, đảm bảo thứ tự các thao tác được xác định nhất quán trên tất cả các phiên làm việc.

Quay lại ví dụ trên, tài liệu đang có nội dung “Hello”. Người dùng A xóa ký tự tại vị trí 0, người dùng B chèn “!” vào vị trí 5. Khi máy chủ nhận được cả hai thao tác, nó nhận ra rằng xóa ký tự đầu đã thay đổi toàn bộ chỉ số vị trí, do đó sẽ biến đổi thao tác của B thành “chèn ‘!’ vào vị trí 4”. Kết quả cuối cùng trên cả hai phía là “ello!”, nhất quán và đúng đắn.

Ưu điểm

Nhược điểm

2.6.3. CRDT

Lịch sử

Conflict-free Replicated Data Type được định nghĩa chính thức vào năm 2011 bởi Marc Shapiro, Nuno Preguiça, Carlos Baquero và Marek Zawirski tại INRIA. Ý tưởng khởi nguồn từ nhu cầu điện toán phân tán và di động, nơi kết nối mạng không ổn định. Khác với OT, CRDT thiết kế cấu trúc dữ liệu sao cho mọi cách kết hợp thay đổi đều cho ra cùng một kết quả, đảm bảo về mặt toán học thay vì thông qua điều phối tập trung.

Nguyên lý hoạt động

CRDT giải quyết bài toán xung đột theo hướng hoàn toàn khác: thay vì biến đổi thao tác sau khi xung đột xảy ra, CRDT thiết kế cấu trúc dữ liệu sao cho xung đột không bao giờ thực sự tồn tại.

Nguyên tắc cốt lõi là mỗi phần tử dữ liệu được gán một định danh duy nhất và bất biến, thường kết hợp giữa mã định danh của thiết bị và dấu thời gian logic (logical clock). Khi hai người dùng chèn nội dung vào cùng một vị trí, thay vì phải quyết định ai ưu tiên hơn, hệ thống sử dụng thứ tự toàn phần dựa trên các định danh này để sắp xếp chúng theo một thứ tự xác định và có thể tái lập lại trên mọi thiết bị. Kết quả là tất cả các bản sao sẽ tự động hội tụ về cùng trạng thái mà không cần bất kỳ sự điều phối trung tâm nào.

Có hai nhánh chính của CRDT:

Ưu điểm

Nhược điểm

2.6.4. So sánh

Bảng 2.1: So sánh giữa Operational Transformation và CRDT

Tiêu chí OT CRDT
Kiến trúc Tập trung, máy chủ giữ thẩm quyền Phi tập trung, hỗ trợ ngang hàng
Mô hình nhất quán Mạnh (thứ tự do máy chủ quyết định) Tối thượng (ngữ nghĩa hợp nhất)
Giải quyết xung đột Biến đổi tất định qua máy chủ Quy tắc hợp nhất của CRDT
Chi phí bộ nhớ Số hiệu phiên bản và trạng thái hiện tại Nhãn xóa mềm, định danh duy nhất và đồng hồ vector cho mỗi phần tử
Hỗ trợ ngoại tuyến Hạn chế, đệm thao tác và phát lại khi kết nối lại Tự nhiên, được thiết kế cho chỉnh sửa khi ngắt kết nối
Độ phức tạp triển khai Hàm biến đổi cho từng cặp thao tác, độ phức tạp O(n²) Thiết kế cấu trúc dữ liệu và thu gom rác định kỳ
Độ trễ Một vòng phản hồi đến máy chủ cho mỗi lô thao tác Không có, áp dụng tức thì tại máy cục bộ rồi đồng bộ bất đồng bộ
Phù hợp nhất Ứng dụng SaaS có backend, dữ liệu có cấu trúc và kiểu rõ ràng Ứng dụng ưu tiên cục bộ, ngang hàng hoặc làm việc ngoại tuyến nhiều

Có thể tham khảo thêm video “CRDTs: The Hard Parts” của Martin Kleppmann [2] và “How Collaborative Text Editors Don’t Break” của PawelCodeStuff [3] để có cái nhìn sâu hơn về các khía cạnh kỹ thuật và thực tiễn của hai phương pháp này.

2.6.5. Ứng dụng trong thực tế

Trong thực tế, các sản phẩm lớn đưa ra những lựa chọn khác nhau dựa trên yêu cầu cụ thể của từng trường hợp sử dụng.

Google Docs sử dụng OT với kiến trúc tập trung, phù hợp với văn bản thuần túy. Figma ban đầu dùng OT nhưng chuyển sang CRDT vào năm 2019 vì thiết kế đồ họa có cấu trúc phức tạp hơn. Notion và Linear áp dụng cách tiếp cận kết hợp: CRDT cho cấu trúc tài liệu và OT cho nội dung văn bản bên trong mỗi khối.

2.6.6. Lý do lựa chọn CRDT cho dự án

Dự án lựa chọn CRDT thông qua thư viện Yjs (Chương 2.7) dựa trên một số yêu cầu cụ thể của ứng dụng ghi chú cộng tác.

Trước tiên, khả năng làm việc ngoại tuyến là yêu cầu quan trọng với người dùng ghi chú. Khác với Google Docs vốn luôn yêu cầu kết nối ổn định, người dùng cần tiếp tục ghi chú ngay cả khi mất mạng và dữ liệu phải đồng bộ tự động khi kết nối được khôi phục, không cần thao tác thủ công.

Tiếp theo, BlockNote (Chương 2.11), thư viện soạn thảo được lựa chọn cho dự án, có tích hợp sẵn với Yjs, giúp giảm đáng kể công sức triển khai tính năng cộng tác mà không cần xây dựng lại từ đầu.

Cuối cùng, kiến trúc không phụ thuộc vào một máy chủ điều phối duy nhất mang lại khả năng mở rộng và khả năng chịu lỗi tốt hơn so với kiến trúc OT truyền thống, đặc biệt khi số lượng người dùng đồng thời trên một tài liệu tăng cao.

2.7. Tổng quan về Yjs

2.7.1. Giới thiệu

Yjs là thư viện CRDT (Conflict-free Replicated Data Type) viết bằng JavaScript, hỗ trợ real-time collaboration [4]. CRDT cho phép thay đổi từ nhiều người dùng tự động hợp nhất mà không cần xử lý xung đột thủ công.

Hình 2.6: Yjs Logo

2.7.2. Kiến trúc

Yjs được tổ chức xoay quanh các khái niệm chính sau:

Bảng 2.2: Các thành phần kiến trúc chính của Yjs

Kiến trúc Mô tả Ví dụ Ghi chú
Y.Doc Tài liệu gốc new Y.Doc() Quản lý tất cả shared types
Shared Types Dữ liệu tự động đồng bộ Y.Array, Y.Map, Y.Text Có thể observe thay đổi
Provider Kết nối mạng WebsocketProvider, WebrtcProvider Chọn provider dựa trên nhu cầu
Editor Binding Tích hợp editor y-prosemirror, y-quill Biến editor thành collaborative

2.7.3. Shared Data Types

Yjs cung cấp sáu shared data types, mỗi loại phục vụ mục đích khác nhau. Có thể lấy từ Y.Doc qua getter hoặc khởi tạo trực tiếp làm nested types.

Bảng 2.3: Các shared data types chính của Yjs

Kiểu dữ liệu Mô tả Ứng dụng
Y.Array Mảng có thứ tự, hỗ trợ chèn/xóa theo chỉ số Danh sách, hàng đợi
Y.Map Key-value store, lồng ghép shared types khác Cấu hình, metadata
Y.Text Văn bản với hỗ trợ định dạng ký tự inline Nội dung text có style
Y.XmlFragment Fragment XML chứa nhiều node con Cấu trúc block-based editor

Mỗi shared type hỗ trợ observe để theo dõi thay đổi:

2.7.4. Editor Bindings

Yjs không đi kèm editor riêng mà tích hợp với editor phổ biến qua binding. Editor binding là cầu nối giữa Y.Text/Y.XmlFragment và editor, tự động đồng bộ nội dung và con trỏ.

Bảng 2.4: Editor bindings chính cho Yjs trong dự án

Editor Gói binding Mô tả
ProseMirror y-prosemirror Toolkit rich text editor với document model có cấu trúc
Tiptap @tiptap/extension-collaboration Framework headless rich text editor dựa trên ProseMirror

2.7.5. Connection Providers

Provider truyền tải thay đổi của Y.Doc giữa các peer, từ giao thức peer-to-peer đến dịch vụ đám mây có quản lý.

Bảng 2.5: Các connection providers chính của Yjs

Provider Giao thức Mô tả
y-websocket WebSocket Provider mặc định, client-server, hỗ trợ persistence và authentication
y-webrtc WebRTC Provider peer-to-peer, không cần server trung tâm
Hocuspocus WebSocket Server WebSocket chuyên dụng cho Yjs, hỗ trợ persistence, authentication, webhook và extension

Dự án chọn Hocuspocus [5] làm provider chính nhờ khả năng mở rộng và tích hợp sâu với Tiptap/BlockNote.

2.7.6. Undo/Redo Manager

Yjs cung cấp Y.UndoManager cho undo/redo trên shared types. Hỗ trợ scoped tracking (chỉ undo thay đổi từ nguồn cụ thể), capture timeout (gộp thay đổi trong 500ms), và metadata (ví dụ vị trí con trỏ).

2.7.7. Awareness

Awareness chia sẻ thông tin trạng thái tạm thời giữa người dùng (con trỏ, vùng chọn, tên, màu sắc) thông qua CRDT riêng trong y-protocols. Dữ liệu tự động xóa khi người dùng ngắt kết nối, client không gửi tín hiệu trong 30 giây bị đánh dấu offline.

2.7.8. Ưu điểm

Yjs mang lại nhiều lợi ích:

2.7.9. Nhược điểm

Yjs có một số hạn chế:

2.8. Tổng quan về ProseMirror

2.8.1. Giới thiệu

ProseMirror là toolkit xây dựng rich text editor trên nền tảng web, phát triển bởi Marijn Haverbeke [6]. Không giống editor truyền thống cung cấp sẵn giao diện soạn thảo, ProseMirror cung cấp các viên gạch nền tảng để tự xây dựng editor phù hợp.

ProseMirror sử dụng document model có cấu trúc chặt chẽ thay vì xử lý HTML tự do, cho phép kiểm soát chính xác nội dung và hỗ trợ các tính năng nâng cao như collaborative editing, schema validation và transform recording.

Hình 2.7: ProseMirror Logo

2.8.2. Kiến trúc

Bảng 2.6: Bốn thư viện cốt lõi của ProseMirror

Thư viện Chức năng Vai trò
prosemirror-model Schema, Document, Node, Mark Định nghĩa cấu trúc tài liệu hợp lệ
prosemirror-state EditorState, Transaction, Plugin Quản lý trạng thái và luồng thay đổi
prosemirror-view EditorView, DOM mapping, event handling Rendering và tương tác người dùng
prosemirror-transform Step, Transform, mapping Ghi lại thay đổi dạng step có thể replay

2.8.3. ProseMirror như một Editor Binding cho Yjs

Trong dự án, ProseMirror đóng vai trò editor binding cho Yjs qua y-prosemirror:

2.8.4. Vai trò so với Tiptap

ProseMirror là nền tảng cấp thấp xây dựng editor. Trong dự án, BlockNote sử dụng Tiptap làm lớp trung gian trên ProseMirror. Như vậy, ProseMirror là lõi hệ thống editor nhưng không dùng trực tiếp mà qua Tiptap.

2.9. Tổng quan về Tiptap

2.9.1. Giới thiệu

Tiptap là headless rich text editor framework trên nền tảng ProseMirror [7], thuộc tổ chức ueberdosis (Tiptap Collective), cùng tổ chức phát triển Hocuspocus.

Khác biệt cốt lõi với ProseMirror là mức độ trừu tượng: ProseMirror là toolkit cấp thấp cung cấp công cụ nền tảng, Tiptap là framework hoàn chỉnh với API thân thiện, kiến trúc extension linh hoạt và tích hợp sẵn nhiều UI framework.

Hình 2.8: Tiptap Logo

2.9.2. Kiến trúc

Tiptap được thiết kế theo ba trụ cột chính:

2.9.3. So sánh với ProseMirror

Bảng dưới đây phân biệt rõ vai trò của ProseMirror và Tiptap trong hệ sinh thái:

Bảng 2.7: So sánh giữa ProseMirror và Tiptap

Tiêu chí ProseMirror Tiptap
Mức độ Low-level toolkit High-level framework
Mục đích Cung cấp công cụ nền tảng Cho phép tạo editor nhanh, dễ dàng
Kiến trúc 4 thư viện riêng, tích hợp thủ công Thống nhất, extension-based
Sử dụng Cần tự xây dựng editor từ đầu Cấu hình qua extensions, dùng ngay
UI Framework Không hỗ trợ sẵn Hỗ trợ React, Vue, Svelte
Hệ sinh thái Cộng đồng, plugin rải rác Kho extension tập trung, Pro features

2.9.4. Tích hợp Yjs và Cộng tác

Tiptap cung cấp extension @tiptap/extension-collaboration tích hợp Yjs (Chương 2.7):

Kết hợp với Hocuspocus (Chương 2.10), Tiptap trở thành collaborative editor hoàn chỉnh với máy chủ đồng bộ qua WebSocket.

2.9.5. Vai trò với BlockNote

BlockNote (Chương 2.11) xây dựng trên Tiptap và ProseMirror: ProseMirror là động cơ (document model, transform, state management), Tiptap là khung gầm (extension system, commands, events), BlockNote là thân xe hoàn chỉnh (block component cho soạn thảo block-based).

2.10. Tổng quan về Hocuspocus

2.10.1. Giới thiệu

Hocuspocus là server WebSocket chuyên dụng cho Yjs, phát triển bởi Tiptap Collective (ueberdosis) [5] – cùng tổ chức đứng sau Tiptap, thiết kế làm backend collaboration cho editor dựa trên ProseMirror và Tiptap.

Hocuspocus đóng vai trò trung gian giữa các client, nhận và phân phối cập nhật Yjs document qua WebSocket, đồng thời quản lý persistence, authentication, awareness và cung cấp hệ thống extension.

2.10.2. Kiến trúc

Hocuspocus được thiết kế theo kiến trúc server-client đơn giản:

Mỗi tài liệu xác định bởi tên phòng (room name). Client kết nối cùng phòng tự động đồng bộ tài liệu Yjs tương ứng.

Luồng hoạt động:

  1. Client khởi tạo HocuspocusProvider với WebSocket server, tên phòng và Y.Doc
  2. Provider kết nối server qua WebSocket, kèm token xác thực (nếu cấu hình)
  3. Server xác thực qua hook onAuthenticate, nếu thành công mở phiên làm việc
  4. Server tải tài liệu từ persistence (nếu có) và đồng bộ với client
  5. Client thay đổi, Yjs update gửi lên server và phân phối đến client khác
  6. Server định kỳ lưu tài liệu xuống persistence qua extension

2.10.3. Extension System

Hocuspocus có hệ thống extension mở rộng chức năng server qua hook vòng đời:

2.10.4. Tính năng nổi bật

Tính năng chính:

2.10.5. Vai trò trong dự án

Trong dự án, Hocuspocus là provider chính cho Yjs (Chương 2.7) vì:

2.11. Tổng quan về BlockNote

2.11.1. Giới thiệu

BlockNote là một thư viện editor được xây dựng trên nền tảng Tiptap và ProseMirror [8]. BlockNote cung cấp một công cụ soạn thảo văn bản phong phú với kiến trúc block-based tương tự như Notion, cho phép người dùng xây dựng các khối nội dung một cách linh hoạt.

Hình 2.9: BlockNote logo

BlockNote được thiết kế để dễ tích hợp vào các ứng dụng React (Chương 2.3.2), với API rõ ràng và khả năng tùy chỉnh cao, tương thích với màu sắc của shadcnui . Thư viện này hoạt động dựa trên ProseMirror, một editor framework mạnh mẽ và có cấu trúc rõ ràng. Có thể hình dung ProseMirror như một bộ công cụ xây dựng editor, trong khi BlockNote là một implementation cụ thể, dễ dàng sử dụng nhanh.

BlockNote là một hệ sinh thái mã nguồn mở hoàn toàn, miễn phí sử dụng công cộng. Chỉ riêng các gói thư viện @blocknote/xl-* có giấy phép copyleft, yêu cầu mua giấy phép nếu sử dụng trong sản phẩm mã nguồn đóng, hoặc thương mại.

2.11.2. Model dữ liệu của BlockNote

Model dữ liệu của BlockNote được tổ chức thành các block, mỗi block đại diện cho một phần nội dung riêng biệt, như đoạn văn, hình ảnh, bảng,… Mỗi block có một cấu trúc dữ liệu riêng, bao gồm loại block, nội dung và các thuộc tính liên quan (xem thêm về cấu trúc dữ liệu của block trong BlockNote tại Phụ lục A.1).

2.11.3. Ưu điểm

BlockNote mang lại nhiều lợi ích cho phát triển editor:

2.11.4. Nhược điểm

Bên cạnh các ưu điểm, BlockNote có một số hạn chế:

2.12. Tổng quan về OpenAPI

2.12.1. Giới thiệu

OpenAPI là một specification cho mô tả HTTP APIs theo cách chuẩn hóa. OpenAPI cho phép sinh code từ contracts, tạo điều kiện cho contract-first development, và tự động tạo documentation.

OpenAPI (trước đây được gọi là Swagger) là một format standardized cho mô tả RESTful APIs. OpenAPI specification định nghĩa endpoints, parameters, request/response schemas, và error codes theo cách machine-readable.

Hình 2.10: OpenAPI, Redocly, Scalar Logo

2.12.2. Tooling Ecosystem

2.12.3. Contract-First Development

Contract-first approach định nghĩa API contracts trước khi implement logic, đảm bảo tính consistency, tạo điều kiện cho parallel development, và giảm integration issues.

2.12.4. Ưu điểm

2.12.5. Nhược điểm

2.13. Tổng quan về Casbin

2.13.1. Giới thiệu

Casbin là một framework authorization mã nguồn mở mạnh mẽ và linh hoạt, hiện thuộc Apache Software Foundation. Casbin hỗ trợ các mô hình kiểm soát truy cập như ACL, RBAC, ABAC, và các biến thể khác. Framework này cho phép định nghĩa các rule authorization một cách khai báo thông qua cấu hình, thay vì hardcode logic kiểm soát.

Hình 2.11: Casbin Logo

Casbin được thiết kế để hoạt động với nhiều ngôn ngữ lập trình, bao gồm Go, Java, Python, Node.js và hơn thế nữa, giúp đảm bảo tính nhất quán trong authorization logic trên toàn bộ hệ sinh thái.

So với các giải pháp authorization khác như OPA, SpiceDB (Google Zanzibar opensource), Casbin tập trung vào sự đơn giản và hiệu quả, cung cấp một cách tiếp cận.

2.13.2. Ưu điểm

Casbin mang lại nhiều lợi ích cho phát triển authorization:

2.13.3. Nhược điểm

Bên cạnh các ưu điểm, Casbin có một số hạn chế:

Chương 3 trình bày quá trình phân tích và thiết kế hệ thống nhằm xác định rõ cấu trúc và cách thức hoạt động của hệ thống. Nội dung chương bao gồm khảo sát hiện trạng, xác định yêu cầu chức năng và phi chức năng, từ đó xây dựng kiến trúc hệ thống và mô tả các thành phần chính. Bên cạnh đó, chương sử dụng các sơ đồ UML để mô hình hóa hành vi, luồng xử lý và mối quan hệ giữa các đối tượng trong hệ thống, thiết kế dữ liệu thông qua các bảng cơ sở dữ liệu. Hệ thống cũng phân tích BlockNote schema tuỳ chỉnh, và mô hình thư viện Casbin của hệ thống.

3.1. Khảo sát hiện trạng

3.1.1. Các hệ thống hiện có

Hiện nay có nhiều hệ thống quản lý kiến thức cá nhân khác nhau, mỗi hệ thống đều có những ưu điểm và nhược điểm riêng. Dưới đây là một số hệ thống phổ biến mà nhóm đã khảo sát.

Notion

Hình 3.1: Notion logo

Notion là một nền tảng làm việc tích hợp được ra mắt vào năm 2013, kết hợp tài liệu, cơ sở dữ liệu, wiki và quản lý dự án trong một nền tảng duy nhất. Với hơn 30 triệu người dùng toàn cầu, Notion đã phát triển từ một ứng dụng ghi chú đơn giản thành một hệ thống kiến thức toàn diện.

Lịch sử phát triển của Notion bắt đầu với phiên bản 1.0 tập trung vào hợp tác tài liệu thời gian thực và tổ chức tài liệu phong cách wiki. Điểm đột phá lớn nhất đến với phiên bản 2.0 vào tháng 3 năm 2018 khi giới thiệu tính năng Database, nâng cấp Notion lên một tầm cao mới và cho phép tạo ra các công cụ ứng dụng. Hiện tại, Notion liên tục được cập nhật với các tính năng mới như AI agents, hệ thống tự động hóa hoàn chỉnh và nhiều loại giao diện cơ sở dữ liệu mới.

Các tính năng chính bao gồm editor module hóa với các khối có thể sắp xếp linh hoạt, cơ sở dữ liệu đa dạng (bảng, Kanban, lịch trình, gallery), khả năng hợp tác thời gian thực, và tích hợp AI. Giao diện của Notion được đánh giá cao về tính thẩm mỹ và sự linh hoạt, cho phép người dùng tùy chỉnh không gian làm việc theo nhu cầu riêng.

Tuy nhiên, Notion cũng có những hạn chế nhất định, điển hình như không hỗ trợ graph view một cách trực quan.

Obsidian

Hình 3.2: Obsidian logo

Obsidian là một ứng dụng ghi chú và quản lý kiến thức dựa trên tệp Markdown, được phát triển bởi Shida Li và Erica Xu và ra mắt vào năm 2020. Với triết lý “local-first”, Obsidian đảm bảo dữ liệu của người dùng luôn nằm trên thiết bị của họ, mang lại quyền sở hữu và tính linh hoạt tối đa.

Obsidian hoạt động với một “vault” chứa các tài liệu văn bản, mỗi ghi chú mới tạo ra một tệp Markdown riêng. Điểm mạnh nổi bật nhất của Obsidian là khả năng liên kết hai chiều và chế độ xem graph giúp người dùng hình dung mối quan hệ giữa các ghi chú. Người dùng có thể tạo liên kết nội dung bằng Wikilinks hoặc liên kết Markdown thông thường, và tất cả các liên kết này đều được hiển thị trong graph view tương tác.

Các tính năng chính bao gồm chế độ xem graph giúp phân tích mối quan hệ giữa các ghi chú, Canvas cho phép sắp xếp ghi chú trực quan không giới hạn, hệ thống plugin mở rộng do cộng đồng phát triển, và khả năng tích hợp với nhiều công cụ khác. Obsidian cũng hỗ trợ chế độ chỉnh sửa song song giữa Source Mode và Live Preview, cùng với đầy đủ các công cụ tìm kiếm và tổ chức. Obsidian còn chính hỗ trợ vim motion cho những người dùng yêu thích trải nghiệm chỉnh sửa văn bản nâng cao.

Mặc dù mạnh mẽ, Obsidian cũng có những thách thức. Learning curve khá cao, đặc biệt với người mới bắt đầu. Thiếu tính năng hợp tác thời gian thực là một hạn chế quan trọng. Giao diện mặc định có thể trông đơn giản so với các đối thủ cạnh tranh. Obsidian phù hợp nhất với các nhà nghiên cứu, nhà văn, lập trình viên và người làm việc kiến thức muốn kiểm soát sâu sắc ghi chú của mình.

jackyzha0/quartz

Hình 3.3: Quartz logo

Quartz là một static-site generator nhanh, được thiết kế để biến nội dung Markdown thành các website hoàn toàn chức năng. Được phát triển bởi jackyzha0, Quartz hoạt động như một giải pháp self-hosted thay thế cho Obsidian Publish, cho phép người dùng xuất bản ghi chú và digital gardens của mình lên web một cách dễ dàng.

Quartz tương thích hoàn toàn với Obsidian, hỗ trợ đầy đủ các tính năng như wikilinks, backlinks, transclusions, graph view và full-text search. Nó được xây dựng trên công nghệ TypeScript và cung cấp khả năng tùy chỉnh cao thông qua JSX layouts và page components. Một trong những điểm mạnh của Quartz là tốc độ tải trang cực nhanh và kích thước bundle nhỏ.

Các tính năng chính bao gồm hỗ trợ LaTeX, Mermaid diagrams, dark mode, breadcrumbs, popover previews, internationalization, và hệ thống comments. Quartz cũng hỗ trợ Docker, RSS feeds, và có hệ thống plugin mở rộng. Nó đặc biệt phù hợp cho các cá nhân muốn chia sẻ kiến thức của mình dưới dạng website công khai hoặc digital garden.

Mặc dù mạnh mẽ, Quartz cũng có những hạn chế. Nó yêu cầu kiến thức kỹ thuật về Git và hosting để thiết lập. Không có tính năng hợp tác thời gian thực như Notion. Giao diện quản lý nội dung không trực quan bằng các ứng dụng desktop. Quartz phù hợp nhất với các nhà phát triển, sinh viên, và giáo viên muốn xuất bản ghi chú của mình dưới dạng website.

3.1.2. So sánh các hệ thống hiện có

Bảng 3.1: So sánh các hệ thống hiện có

Đặc tính


Notion


Obsidian


Quartz

Loại Nền tảng làm việc Ứng dụng ghi chú desktop Static site generator
Nền tảng hỗ trợ Web, Desktop, Mobile Desktop, Mobile CLI
Hợp tác thời gian thực Không Không
Graph View Không
Liên kết hai chiều
Markdown gốc Không (block-based)
Hệ thống Plugin Có (kho mẫu, AI) Có (cộng đồng)
Lưu trữ Đám mây Local-first Git-based
Self-hosted Không Không
Mã nguồn mở Không Không Có (MIT)
Xuất bản web Có (Notion Sites) Có (Obsidian Publish) Có (tính năng chính)

Xuất phát từ đó, nhóm đã xác định được những điểm mạnh và hạn chế của từng hệ thống, từ đó rút ra những bài học quan trọng để áp dụng vào thiết kế hệ thống của mình. Nhưng cũng cần nhấn mạnh rằng Notopia không nhằm mục đích thay thế hoàn toàn các hệ thống hiện có, mà chỉ thực hiện một số chức năng nhất định, mang tính chất nghiên cứu, học tập, áp dụng công nghệ và quy trình phát triển phần mềm.

3.2. Kiến trúc hệ thống

Dự án được chia thành nhiều service khác nhau, bao gồm note service, document service, authorization service, search-worker worker, và các thành phần tái sử dụng từ các dịch vụ sẵn có. Mỗi service có trách nhiệm riêng biệt và giao tiếp với nhau thông qua API và message queue để đảm bảo tính modular và dễ bảo trì.

3.2.1. Sơ đồ kiến trúc tổng quan

Dưới đây là sơ đồ kiến trúc tổng quan của hệ thống.

Hình 3.4: Sơ đồ kiến trúc tổng quan

Trong đó, các thành phần chính bao gồm:

Bảng 3.2: Các thành phần trong kiến trúc

Thành phần Mô tả
User Người dùng tương tác với hệ thống thông qua giao diện web
Gateway Điểm vào chính của hệ thống, chịu trách nhiệm định tuyến yêu cầu đến các service phù hợp
Web App Ứng dụng web cung cấp giao diện người dùng để tạo và quản lý ghi chú
Note Service Quản lý metadata và logic liên quan đến không gian làm việc và ghi chú
Document Service Quản lý nội dung của các ghi chú
Authorization Service Xác định quyền truy cập của người dùng đối với các tài nguyên
Identity Provider Dịch vụ xác thực và quản lý người dùng
Object Storage Lưu trữ các tệp liên quan đến ghi chú, như hình ảnh và tài liệu
Search Service Cung cấp khả năng tìm kiếm nội dung trong ghi chú
Event Bus Hệ thống message queue để giao tiếp giữa các service
Monitoring Giám sát hiệu suất và trạng thái của hệ thống

Chi tiết về các thành phần chính:

Gateway

Gateway là điểm vào chính của hệ thống, chịu trách nhiệm định tuyến các yêu cầu từ người dùng đến các service phù hợp. Nó cũng thực hiện các chức năng như xác thực, và cân bằng tải để đảm bảo hiệu suất và bảo mật của hệ thống.

Hệ thống sử dụng Traefik làm API Gateway, với đặc điểm gọn nhẹ và dễ cấu hình, tương thích tốt với docker compose. Sử dụng agilezebra/jwt-middleware [13] để xử lý xác thực JWT, chuyển hoá OIDC claim thành header HTTP, giúp các service phía sau có thể dễ dàng xác định người dùng, không cần phải tích hợp trực tiếp với Identity Provider.

Web App

Web App là giao diện người dùng chính, cho phép người dùng tạo, chỉnh sửa và quản lý ghi chú. Ứng dụng được xây dựng với React và NextJS (Chương 2.3).

Note Service

Note Service (note service), viết bằng Go, chịu trách nhiệm quản lý metadata và logic liên quan đến không gian làm việc và ghi chú. Dịch vụ này cung cấp API để Web App có thể tương tác với không gian làm việc và ghi chú, đồng thời tích hợp với Authorization Service để kiểm tra quyền truy cập của người dùng trước khi thực hiện các hành động liên quan đến thư mục, ghi chú.

Document Service

Document Service (document service), viết bằng Typescript và NestJS framework, chịu trách nhiệm quản lý nội dung của các ghi chú, bao gồm lưu trữ và truy xuất dữ liệu. Nó cung cấp API để Web App có thể tương tác với nội dung ghi chú, tích hợp với Object Storage để lưu trữ các tệp liên quan, và sử dụng Hocuspocus (Chương 2.7) để hỗ trợ cộng tác thời gian thực trên nội dung ghi chú.

Authorization Service

Authorization Service (authorization service), viết bằng Go, sử dụng thư viên Casbin (Chương 2.13) để quản lý quyền truy cập của người dùng đối với không gian làm việc và ghi chú. Dịch vụ này cung cấp API để các service khác có thể kiểm tra quyền truy cập của người dùng trước khi thực hiện các hành động liên quan đến thư mục, ghi chú.

Identity Provider

Identity Provider chịu trách nhiệm xác thực người dùng và quản lý thông tin tài khoản. Hệ thống sử dụng Authentik là giải pháp xác thực, cung cấp các tính năng như đăng nhập một lần (SSO), quản lý người dùng, và hỗ trợ nhiều phương thức xác thực. Hệ thống sử dụng OpenID Connect (OIDC) để tích hợp giữa Gateway, Web App với Identity Provider, giúp đơn giản hóa quá trình xác thực và quản lý người dùng.

Object Storage

Object Storage được sử dụng để lưu trữ các tệp liên quan đến ghi chú, như hình ảnh và tài liệu. Hệ thống sử dụng RustFS, một giải pháp lưu trữ đối tượng nhẹ và hiệu quả, cung cấp API tương thích với S3 để dễ dàng tích hợp với các service khác.

Search Service

Search Service (Meilisearch), viết bằng Rust, cung cấp khả năng tìm kiếm nội dung trong ghi chú. Trong đó, search-worker worker chịu trách nhiệm đồng bộ dữ liệu đến Search Service để đảm bảo dữ liệu tìm kiếm luôn được cập nhật.

Event Bus

Event Bus là hệ thống message queue được sử dụng để giao tiếp giữa các service, đảm bảo tính modular và giảm sự phụ thuộc trực tiếp giữa các service. Hệ thống sử dụng Redpanda, một giải pháp message queue hiệu suất cao, tương thích với Kafka API, giúp dễ dàng tích hợp với các service khác.

Monitoring

Monitoring là thành phần quan trọng để giám sát hiệu suất và trạng thái của hệ thống. Hệ thống sử dụng Grafana Stack và Prometheus để thu thập và hiển thị các chỉ số về hiệu suất.

3.2.2. Kiến trúc note service

Là thành phần trung tâm trong hệ thống, note service chịu trách nhiệm quản lý metadata và logic liên quan đến ghi chú. Dịch vụ này được thiết kế theo kiến trúc Clean Architecture, Domain Driven Design, và Event-Driven Architecture để đảm bảo tính modular, dễ bảo trì, và khả năng mở rộng trong tương lai4. Dưới đây là sơ đồ kiến trúc chi tiết của note service.

Hình 3.5: Kiến trúc của note service

3.2.3. Kiến trúc document service

document service áp dụng kiến trúc theo NestJS, với các module được tổ chức theo chức năng. Dưới đây là sơ đồ kiến trúc chi tiết của document service, mô tả đến cấp độ module.

Hình 3.6: Kiến trúc của document service

3.2.4. Kiến trúc authorization service

authorization service được thiết kế theo kiến trúc Layered Architecture, với tầng logic không phân tách rõ vì tính đặc thù của thư viện Casbin. Dưới đây là sơ đồ kiến trúc của authorization service.

Hình 3.7: Kiến trúc của authorization service

3.2.5. Kiến trúc search-worker worker

search-worker worker được thiết kế theo kiến trúc đơn giản, sử dụng trên 1 module chính của NestJS, không chia thành nhiều module nhỏ. Dưới đây là sơ đồ kiến trúc của search-worker worker.

Hình 3.8: Kiến trúc của search-worker worker

3.3. Mô tả các Use Case

Nhóm chỉ xác định một vài use case phức tạp, có nhiều luồng, tác động đến nhiều dịch vụ.

3.3.1. Mô tả use case Create Note

Hình 3.9: Sequence diagram mô tả create note use case

Bảng 3.3: Mô tả use case Create Note

Trường Nội dung
ID UC01
Name Create Note
Description Use case này mô tả quy trình tạo ghi chú mới
Actor(s) User
Priority Cao
Trigger Người dùng muốn tạo một ghi chú mới
Pre-condition(s)
  • Người dùng sử dụng thiết bị có kết nối internet
  • Người dùng đã đăng nhập vào hệ thống
  • Người dùng có quyền tạo ghi chú trong không gian làm việc hiện tại
Post-condition(s)
  • Người dùng tạo ghi chú thành công
Basic Flow
  1. Người dùng truy cập vào hệ thống
  2. Người dùng chọn nút “Tạo ghi chú mới” được hiển thị
  3. Người dùng nhập vào các trường thông tin của ghi chú (tiêu đề, v.v…)
  4. Hệ thống kiểm tra quyền của người dùng để tạo ghi chú
  5. Hệ thống tạo ghi chú mới và trả về ID của ghi chú
  6. Hệ thống publish domain event NoteCreatedEvent tới Message Broker
  7. Hệ thống chuyển đổi domain event thành workspace event và publish
  8. Hệ thống publish integration event NoteCreatedEvent tới Message Broker
  9. search-worker nhận integration event và xử lý
  10. search-worker gửi yêu cầu Index Note đến Search service
  11. Search service nhận yêu cầu Index Note và tiến hành indexing ghi chú mới
Alternate Flow
  1. Bước 6: Hệ thống gặp lỗi khi gửi domain event NoteCreatedEvent

    1. Hệ thống tự động retry publish domain event
  2. Bước 7: Hệ thống gặp lỗi khi chuyển đổi hoặc publish workspace event

    1. Hệ thống ghi log lỗi và bỏ qua việc publish workspace event
  3. Bước 8: Hệ thống gặp lỗi khi publish integration event

    1. Hệ thống tự động retry publish integration event
  4. Bước 9: search-worker gặp lỗi khi xử lý NoteCreatedEvent

    1. search-worker ghi log lỗi và bỏ qua event
  5. Bước 10: Search service gặp lỗi khi indexing ghi chú mới

    1. Search service ghi log lỗi và bỏ qua yêu cầu indexing
Exception Flow
  1. Bước 4: Người dùng không có quyền tạo ghi chú trong workspace hiện tại

    1. Hệ thống trả về lỗi forbidden
    2. Use case dừng lại
  2. Bước 5: Hệ thống gặp lỗi khi tạo ghi chú mới

    1. Hệ thống trả về lỗi
    2. Use case dừng lại

3.3.2. Mô tả use case Get Note

Hình 3.10: Sequence diagram mô tả get note use case

Bảng 3.4: Mô tả use case Get Note

Trường Nội dung
ID UC02
Name Get Note
Description Use case này mô tả quy trình lấy nội dung ghi chú và chuyển sang chế độ chỉnh sửa
Actor(s) User
Priority Cao
Trigger Người dùng chọn một ghi chú để xem hoặc chỉnh sửa
Pre-condition(s)
  • Người dùng sử dụng thiết bị có kết nối internet
  • Người dùng đã đăng nhập vào hệ thống
  • Người dùng có quyền xem ghi chú trong không gian làm việc hiện tại
Post-condition(s)
  • Người dùng nhận được thông tin ghi chú
  • Kết nối Hocuspocus được thiết lập để xem và (tùy chọn) chỉnh sửa ghi chú
Basic Flow
  1. Người dùng chọn ghi chú cần xem
  2. Hệ thống lấy thông tin ghi chú từ note service
  3. Hệ thống kiểm tra quyền xem ghi chú với authorization service
  4. Hệ thống trả về thông tin ghi chú cho người dùng
  5. Hệ thống thiết lập kết nối Hocuspocus để xem nội dung ghi chú
  6. Nếu người dùng chọn chỉnh sửa, Hệ thống sẽ giữ kết nối và cho phép gửi các thao tác chỉnh sửa
  7. document service kiểm tra bộ nhớ nội bộ trước
  8. Nếu tài liệu chưa tồn tại trong bộ nhớ nội bộ, document service kiểm tra với note service
  9. Nếu ghi chú tồn tại, document service khởi tạo tài liệu và lưu vào bộ nhớ nội bộ
  10. document service trả về kết nối Hocuspocus cho người dùng
  11. Nếu có thao tác chỉnh sửa, document service lưu thay đổi và phát sóng cho các client khác
Alternate Flow
  1. Bước 8-9: Tài liệu đã tồn tại trong bộ nhớ nội bộ của document service

    1. document service bỏ qua bước kiểm tra với note service
    2. document service trả về kết nối Hocuspocus trực tiếp
  2. Bước 12: Người dùng không chọn chỉnh sửa (chỉ xem)

    1. Kết nối Hocuspocus duy trì ở chế độ xem
    2. Không có thao tác chỉnh sửa nào được thực hiện
  3. Bước 13: Lỗi khi lưu thay đổi tài liệu trong quá trình debounce

    1. document service ghi log lỗi và thử lại sau thời gian debounce
Exception Flow
  1. Bước 4: Người dùng không có quyền xem ghi chú

    1. Hệ thống trả về lỗi forbidden
    2. Use case dừng lại
  2. Bước 9: Ghi chú không tồn tại trong note service

    1. Hệ thống trả về lỗi noteNotFound
    2. Use case dừng lại

3.3.3. Mô tả use case Commit Document

Hình 3.11: Sequence diagram mô tả commit document use case

Bảng 3.5: Mô tả use case Commit Document

Trường Nội dung
ID UC03
Name Commit Document
Description Use case này mô tả quy trình lưu và publish event cập nhật tài liệu (nội dung của ghi chú)
Actor(s) User
Priority Cao
Trigger Người dùng chọn lưu tài liệu để cập nhật
Pre-condition(s)
  • Người dùng đã đăng nhập vào hệ thống
  • Người dùng có quyền chỉnh sửa tài liệu trong không gian làm việc hiện tại
  • Tài liệu đã tồn tại trong hệ thống
Post-condition(s)
  • Tài liệu được tạo ra phiên bản lưu trữ (revision) mới
  • Integration Event DocumentCommittedEvent được publish
  • Việc cập nhật được phản ánh vào hệ thống nhận xét và tìm kiếm
Basic Flow
  1. Người dùng chọn hành động “Commit Document” trên giao diện
  2. document service tạo phiên bản lưu trữ mới của tài liệu
  3. document service publish integration event DocumentCommittedEvent vào Message Broker
  4. Message Broker phân phối event cho note service và search-worker
  5. note service nhận event và cập nhật các thông tin như size, tags
  6. search-worker nhận event và chuyển đổi thành markdownContent, tags
  7. Search service nhận yêu cầu index lại ghi chú và thực hiện indexing
  8. Các thay đổi được đăng báo lại cho các client thông qua Hocuspocus
Alternate Flow
  1. Bước 4: Lỗi khi tạo revision mới của tài liệu

    1. Hệ thống ghi log và thông báo lỗi cho người dùng
  2. Bước 6: Dữ liệu BlockNote không đúng với schema

    1. Hệ thống discard event và ghi log lỗi
Exception Flow
  1. Bước 2: Lỗi khi lấy quyền edit

    1. Trả về lỗi forbidden và dừng quy trình

3.4. Sơ đồ lớp (Class Diagram)

Dưới đây là sơ đồ lớp cho các service trong hệ thống, bao gồm note service và document service, không bao gồm authorization service vì tính đặc thù của service không thể biểu diễn một cách dễ dàng, và search-worker vì xử lý dữ liệu không phức tạp. Sơ đồ lớp giúp minh họa cấu trúc của các lớp, các thuộc tính và phương thức của chúng, cũng như mối quan hệ giữa các lớp.

3.4.1. Sơ đồ lớp cho note service

Sơ đồ lớp cho note service được chia thành hai phần: tầng application và tầng domain. Tầng application tập trung vào các lớp mô hình dữ liệu và interface của service, trong khi tầng domain tập trung vào các lớp đại diện cho các aggregate và logic nghiệp vụ.

Sơ đồ lớp tầng application

Hình 3.12: Sơ đồ lớp tầng application cho note service

Tầng application bao gồm các lớp mô hình dữ liệu (model) cho việc read (theo CQRS) và các interface của service. Các lớp mô hình dữ liệu đại diện cho các thực thể trong hệ thống như Note, Folder, Workspace, v.v. Các interface của service định nghĩa các phương thức mà tầng infrastructure sẽ triển khai.

Sơ đồ lớp tầng domain

Hình 3.13: Sơ đồ lớp tầng domain cho note service

Tầng domain, áp dụng Domain Driven Design Pattern, bao gồm các lớp đại diện cho các aggregate như Note, Folder, Workspace, v.v. Các lớp này chứa các thuộc tính và phương thức liên quan đến logic nghiệp vụ của chúng. Ngoài ra, tầng domain cũng bao gồm các interface của repository để truy cập dữ liệu. Tuy nhiên, tầng domain không được trực tiếp gọi service được định nghĩa hay repository interface được khai báo.

3.4.2. Sơ đồ lớp cho document service

Hình 3.14: Sơ đồ lớp cho document service

Sơ đồ tinh gọn cho document service, bao gồm các thực thể, services, và đối tượng liên quan. Ở thiết kế này không bao gồm repository vì đã được TypeORM abstract đi, tức, service sẽ trực tiếp gọi các phương thức của TypeORM để truy cập dữ liệu.

3.5. Thiết kế cơ sở dữ liệu

Các service trong hệ thống sẽ sử dụng cơ sở dữ liệu PostgreSQL để lưu trữ và quản lý dữ liệu. Dưới đây là thiết kế cơ sở dữ liệu cho các service, bao gồm các bảng chính và mối quan hệ giữa chúng.

3.5.1. Cơ sở dữ liệu cho note service

Hình 3.15: Sơ đồ cơ sở dữ liệu cho note service

Bảng workspaces

Bảng 3.6: Bảng workspaces – note service

Tên cột Kiểu dữ liệu Mô tả Khóa
id UUID Mã định danh duy nhất của workspace PK
slug TEXT URL-friendly slug của workspace UQ
name TEXT Tên của workspace
created_at TIMESTAMPTZ Thời gian tạo
updated_at TIMESTAMPTZ Thời gian cập nhật gần nhất
deleted_at TIMESTAMPTZ Thời gian xóa (soft delete, Nullable)

Bảng folders

Bảng 3.7: Bảng folders – note service

Tên cột Kiểu dữ liệu Mô tả Khóa
id UUID Mã định danh duy nhất của folder PK
name TEXT Tên của folder (Nullable)
icon TEXT Icon của folder (Nullable)
workspace_id UUID ID workspace chứa folder này FK
parent_id UUID ID folder cha (nested structure) (Nullable) FK
created_at TIMESTAMPTZ Thời gian tạo
updated_at TIMESTAMPTZ Thời gian cập nhật gần nhất
trashed_by ENUM Loại xóa (purpose|parent, Nullable)
trashed_at TIMESTAMPTZ Thời gian xóa (Nullable)

Bảng notes

Bảng 3.8: Bảng notes – note service

Tên cột Kiểu dữ liệu Mô tả Khóa
id UUID Mã định danh duy nhất của ghi chú PK
name TEXT Tên của ghi chú
icon TEXT Icon của ghi chú (Nullable)
folder_id UUID ID folder chứa ghi chú này FK
tags TEXT[] Danh sách tag của ghi chú (Nullable)
size INTEGER Kích thước của ghi chú (bytes)
created_at TIMESTAMPTZ Thời gian tạo
updated_at TIMESTAMPTZ Thời gian cập nhật gần nhất
trashed_by ENUM Loại xóa (purpose|parent, Nullable)
trashed_at TIMESTAMPTZ Thời gian xóa (Nullable)

Bảng note_links

Bảng 3.9: Bảng note_links – note service

Tên cột Kiểu dữ liệu Mô tả Khóa
source_id UUID ID ghi chú nguồn PK, FK
target_id UUID ID ghi chú đích PK, FK

3.5.2. Cơ sở dữ liệu cho document service

Hình 3.16: Sơ đồ cơ sở dữ liệu cho document service

Bảng documents

Bảng 3.10: Bảng documents – document service

Tên cột Kiểu dữ liệu Mô tả Khóa
id UUID Mã định danh duy nhất của document PK
data BYTEA Dữ liệu nhị phân yjs5
modified BOOLEAN Trạng thái đã được chỉnh sửa hay chưa

Bảng Revisions

Bảng 3.11: Bảng revisions – document service

Tên cột Kiểu dữ liệu Mô tả Khóa
id UUID Mã định danh duy nhất của revision PK
name TEXT Tên của revision (Nullable)
data JSON Dữ liệu BlockNote
document_id UUID ID document liên kết với revision FK
created_at TIMESTAMPTZ Thời gian tạo
deleted_at TIMESTAMPTZ Thời gian xóa (Nullable)

3.5.3. Cơ sở dữ liệu cho authorization service

Vì tính đặc thù của thư viện Casbin, bảng dữ liệu của service này không thuộc phạm vi quản lý của hệ thống, mà sẽ được Casbin tự động tạo ra và quản lý.

Hình 3.17: Sơ đồ cơ sở dữ liệu cho authorization service

Bảng casbin_rules

Bảng 3.12: Bảng casbin_rules – authorization service

Tên cột Kiểu dữ liệu Mô tả Khóa
id UUID Mã định danh duy nhất của rule PK
ptype TEXT Loại rule (p, g, g2, v.v…)
v0 TEXT Trường dữ liệu 0
v1 TEXT Trường dữ liệu 1
v2 TEXT Trường dữ liệu 2
v3 TEXT Trường dữ liệu 3 (Nullable)
v4 TEXT Trường dữ liệu 4 (Nullable)
v5 TEXT Trường dữ liệu 5 (Nullable)

3.6. Mô hình BlockNote tuỳ chỉnh trong hệ thống

BlockNote bao gồm nhiều schema nhiều schema, có thể xem tại Chương 2.11. Tuy nhiên, để có thể liên kết các ghi chú với nhau, cũng như hỗ trợ liên kết thông qua tag, hệ thống cần tuỳ chỉnh thêm hai config schema cho BlockNote, là referencetag. Tham khảo từ tài liệu schema tuỳ chỉnh của BlockNote [16], hai config này sẽ được định nghĩa như sau.

3.6.1. Mô hình BlockNote Reference tuỳ chỉnh

Chương trình 3.1: Cấu hình schema BlockNote tuỳ chỉnh cho reference

Một khối reference sẽ chứa một thuộc tính noteId để xác định ghi chú mà nó đang tham chiếu đến. Khi người dùng chèn một khối reference vào ghi chú, họ sẽ có thể chọn một ghi chú khác trong hệ thống để liên kết đến. Điều này cho phép tạo ra các mối quan hệ giữa các ghi chú.

Chương trình 3.2: Minh hoạ một khối reference trong BlockNote

3.6.2. Mô hình BlockNote Tag tuỳ chỉnh

Khối tag sẽ chứa một thuộc tính tag để lưu trữ tên của tag. Người dùng có thể chèn một khối tag vào ghi chú và gán cho nó một tên tag cụ thể.

Chương trình 3.3: Minh hoạ một khối tag trong BlockNote

3.7. Mô hình Casbin trong hệ thống

Casbin hỗ trợ biểu diễn nhiều mô hình kiểm soát truy cập khác nhau, chi tiết xem tại Chương 2.13. Trong đó, hệ thống tập trung sử dụng mô hình RBAC để quản lý quyền truy cập dựa trên vai trò (role) của người dùng, trong mỗi không gian làm việc. Đối với Casbin, workspace được xem như một domain.

3.7.1. Mô hình Casbin trong hệ thống

Chương trình 3.4: Model Casbin trong hệ thống

Trong đó, các phần được định nghĩa như sau:

3.7.2. Chính sách Casbin trong hệ thống

Chương trình 3.5: Policy Casbin trong hệ thống

Trong đó, các chính sách được định nghĩa như sau:

Ví dụ minh hoạ cụ thể về yêu cầu truy cập và quá trình so khớp chính sách có thể xem tại Phụ lục B.1.

3.8. Thiết kế health check ở các service

3.8.1. Mục tiêu của health check endpoint

Health check endpoint là cơ chế tự kiểm tra giúp hệ thống giám sát phát hiện sớm sự cố (lỗi kết nối DB, rò rỉ bộ nhớ, thành phần phụ thuộc sập). Từ đó, Kubernetes có thể tự động khởi động lại container hoặc ngừng gửi traffic đến service lỗi.

Có 3 loại probe theo Kubernetes:

Bảng dưới đây tóm tắt trạng thái triển khai health check. Do thời gian có hạn, nhóm chỉ triển khai đầy đủ cho các Go service; các service còn lại sẽ bổ sung sau.

Bảng 3.13: Trạng thái triển khai health check theo service

Service Startup Liveness Readiness
note (Go)
authorization (Go)
document (NestJS)
search-worker (NestJS)
web (NextJS)

Ví dụ chi tiết payload response của từng loại probe trên note service có thể xem tại Phụ lục C.1.

3.8.2. Health check ở các Go service

Sử dụng thư viện github.com/alexliesenfeld/health [17]. Thư viện hỗ trợ kiểm tra đồng bộ và bất đồng bộ (chạy tác vụ nặng trong nền theo chu kỳ, trả về kết quả từ cache), cấu hình TTL cho cache để giảm tải hạ tầng, và bọc tích hợp với các thư viện health check phổ biến khác (health-go, etherlabsio/healthcheck, heptiolabs/healthcheck, InVisionApp/go-health).

3.9. Hạn chế CI của Nx và giải pháp custom cache

Nx hướng developer dùng Nx Cloud cho CI, nhưng nhóm đã tự xây dựng giải pháp cache riêng cho GitHub Actions: KevinNitroG/nx-cache-action [18]. Script lấy cảm hứng từ raegen/nx [19] (đã deprecated), nhưng cơ chế khác biệt: khởi động NodeJS ExpressJS server implement OpenAPI Spec của Nx [20], forward lệnh Nx cho child process, server nhận request cache và giao tiếp với GitHub Actions cache API qua actions/toolkit/cache [21].

Vấn đề: Nx lưu cache task khoảng một tháng kể từ lần cuối sử dụng. Không dùng nx-cache-action, cache được lưu toàn bộ project task cache ( 5GB/lần). 10 commit thay đổi source code tạo 10 cache ( 50GB), vượt giới hạn 10GB của GitHub Actions. Chưa kể còn phải cache node modules, Go packages, system dependencies.

Với nx-cache-action, cache lưu theo từng project nhỏ (vài trăm KB đến hơn 10MB/task), chỉ tạo cache mới khi project đó thay đổi. Điều này tối ưu dung lượng, tránh vượt giới hạn GitHub Actions, tăng cache hit.

Nhược điểm: cache phải download qua actions/toolkit/cache rồi pipe vào lại Nx process qua HTTP, thay vì giao tiếp trực tiếp với GitHub Actions cache Rest API. Đây là cách dễ dàng nhất để triển khai.

Chương trình bày kết quả xây dựng Web App, bao gồm giao diện, các thành phần giao diện, và mô tả chức năng của từng thành phần.

4.1. Landing page

Hình 4.1: Giao diện landing page

4.2. Màn hình đăng nhập

Hình 4.2: Giao diện màn hình đăng nhập

4.3. Màn hình chọn không gian làm việc

Hình 4.3: Giao diện màn hình chọn không gian làm việc

4.4. Màn hình tổng quan không gian làm việc

Hình 4.4: Giao diện bố cục không gian làm việc

4.5. Màn hình soạn thảo ghi chú

Hình 4.5: Giao diện màn hình soạn thảo ghi chú

4.6. Màn hình đồ thị không gian làm việc

Hình 4.6: Giao diện màn hình đồ thị không gian làm việc

4.7. Màn hình đồ thị ghi chú

Hình 4.7: Giao diện màn hình đồ thị ghi chú

4.8. Màn hình cài đặt không gian làm việc

Hình 4.8: Giao diện màn hình cài đặt không gian làm việc

4.9. Màn hình thùng rác

Hình 4.9: Giao diện màn hình thùng rác

4.10. Màn hình lỗi / 404

Chương này trình bày phần kết luận của đồ án, nhằm tổng hợp và đánh giá các kết quả đạt được trong quá trình nghiên cứu, phân tích, thiết kế và xây dựng hệ thống. Nội dung chương tập trung vào việc đánh giá sản phẩm đã triển khai, nhận xét những thuận lợi, khó khăn, ưu điểm và hạn chế của hệ thống, đồng thời đề xuất các hướng phát triển trong tương lai nhằm nâng cao tính hoàn thiện và khả năng ứng dụng thực tế.

5.1. Kết quả đạt được

5.1.1. Về sản phẩm

Nhóm đã hoàn thiện hệ thống ghi chú với các tính năng:

5.1.2. Về công nghệ

Dự án áp dụng các công nghệ hiện đại:

5.2. Nhận xét

5.2.1. Thuận lợi

5.2.2. Khó khăn

5.2.3. Ưu điểm

5.2.4. Nhược điểm

5.3. Hướng phát triển

5.4. Lời kết

Dự án đã đạt được mục tiêu đề ra và mang lại nhiều bài học quý giá cho nhóm phát triển. Hệ thống “Notopia - Ứng dụng ghi chú thông minh hỗ trợ quản lý tri thức bằng biểu đồ quan hệ” không chỉ là sản phẩm hoàn chỉnh mà còn là nền tảng để tiếp tục nghiên cứu và phát triển trong tương lai.

Phụ lục A. BLOCKNOTE

A.1 BlockNote Model

Dưới đây là ví dụ về cấu trúc dữ liệu của một block trong BlockNote:

Chương trình A.1: Ví dụ về cấu trúc dữ liệu của một block trong BlockNote

Hình A.1: Ví dụ về cấu trúc dữ liệu của một block trong BlockNote

Phụ lục B. CASBIN

B.1 Ví dụ minh hoạ quy tắc Casbin trong hệ thống

Giả sử ta có ba người dùng: 110, 111112, với các vai trò và quyền truy cập như sau:

Chương trình B.1: Mẫu minh hoạ yêu cầu truy cập và so khớp chính sách Casbin

Trong đó:

Bảng B.1: Mẫu minh hoạ yêu cầu truy cập và kết quả so khớp chính sách

Loại Code
Request
Result
B.1.1 Giải thích cho yêu cầu truy cập đầu tiên

Người dùng 111 yêu cầu đọc không gian làm việc 111. Kết quả là true vì người dùng 111 có vai trò owner trong không gian làm việc 111 và có chính sách cho phép đọc không gian làm việc. Các bước suy luận dựa trên matcher m:

  1. Người dùng 111 có vai trò owner trong không gian làm việc 111 thông qua chính sách g. Ta có thể xác định rằng g(user:111, owner, workspace:111) là true.
  2. Đối tượng workspace cũng chứa trong workspace

    (

    )

    thông qua chính sách g2. Ta có thể xác định rằng g2(workspace, workspace) là true.
  3. Hành động read phù hợp với chính sách read của vai trò owner trên không gian làm việc. Ta có thể xác định rằng read == read là true.
B.1.2 Giải thích cho yêu cầu truy cập thứ ba

Người dùng 112 yêu cầu xóa không gian làm việc 111. Kết quả là false vì người dùng 112 chỉ có vai trò editor trong không gian làm việc 111 và không có chính sách nào cho phép editor xóa không gian làm việc. Các bước suy luận:

  1. Người dùng 112 có vai trò editor trong không gian làm việc 111 thông qua chính sách g. Ta có thể xác định rằng g(user:112, editor, workspace:111) là true.
  2. Đối tượng workspace cũng chứa trong workspace

    (

    )

    thông qua chính sách g2. Ta có thể xác định rằng g2(workspace, workspace) là true.
  3. Hành động delete không phù hợp với chính sách delete của vai trò editor trên không gian làm việc. Ta có thể xác định rằng delete == delete là true, nhưng vì không có chính sách nào cho phép editor xóa không gian làm việc, nên yêu cầu truy cập này bị từ chối.

Tương tự, các yêu cầu truy cập khác cũng được đánh giá dựa trên vai trò của người dùng trong không gian làm việc và các chính sách đã định nghĩa. Kết quả của mỗi yêu cầu sẽ cho biết liệu yêu cầu đó có được phép hay không, cùng với lý do dựa trên chính sách nào đã cho phép hoặc từ chối yêu cầu đó. Chi tiết có thể xem tại website playground của Casbin cho ví dụ trên tại https://editor.casbin.org/#E7VKBXR2T.

Phụ lục C. HEALTH CHECK

C.1 Ví dụ payload health check của note service

C.1.1 Startup

Chương trình C.1: Ví dụ response của startup check ở note service

C.1.2 Liveness

Chương trình C.2: Ví dụ response của live check ở note service

C.1.3 Readiness

Chương trình C.3: Ví dụ response của ready check ở note service

Phụ lục D. NX

Hình D.1 dưới đây thể hiện dependency graph của monorepo được sinh bởi Nx.

Hình D.1: Dependency graph của monorepo được sinh bởi Nx

Phụ lục E. OBSERVABILITY

E.1 Log xem từ Grafana

Hình E.1 dưới đây thể hiện log từ hệ thống được xem qua Grafana.

Hình E.1: Log xem từ Grafana

  1. 1Liên kết hai chiều gồm outgoing link – liên kết từ ghi chú này đến ghi chú khác – và backlink – liên kết ngược lại
  2. 2Thông tin theo thời gian thực sử dụng SSE bao gồm các sự kiện thay đổi tổng quát trong không gian làm việc (“metadata”), khác với CRDT dùng để đồng bộ nội dung ghi chú theo thời gian thực
  3. 3Generic proposal đã được phê duyệt, theo [1]
  4. 4Tham khảo cách tổ chức code từ [14], [15]
  5. 5Dành cho việc lưu trữ và truy xuất bởi Hocuspocus