Tôi xây dựng hệ thống chuyển đổi số cho doanh nghiệp
Tech Lead · Fullstack Engineer · Product Owner Domain: Enterprise Document Management Stack: Next.js · NestJS · PostgreSQL · Redis · Docker · Linux Focus: Architecture · Workflow · RBAC · Digital Signature · DevOps

Building an Enterprise Document Management System
The Context
Trong một dự án chuyển đổi số cho một đơn vị khai thác cảng quy mô lớn, tôi tham gia xây dựng một nền tảng quản lý tài liệu và quy trình nghiệp vụ dành cho môi trường doanh nghiệp.
Bài toán ban đầu nhìn khá quen thuộc:
Quản lý tài liệu.
Nhưng khi đi sâu vào nghiệp vụ, đây không còn là một hệ thống CRUD đơn thuần.
Một tài liệu có thể được tạo, phân loại, lưu trữ, phân quyền, trình ký, ký số, chuyển qua nhiều bộ phận và cuối cùng trở thành một phần của hồ sơ nghiệp vụ.
Mỗi bước đều có người thực hiện, trạng thái, quyền hạn và lịch sử.
Vì vậy, bài toán thực sự không phải là:
"Làm một hệ thống upload và download file."
Mà là:
Làm thế nào để biến một quy trình nghiệp vụ phức tạp thành một hệ thống có thể kiểm soát, truy vết và vận hành ổn định trong môi trường enterprise?
Đó là phần tôi quan tâm nhất trong dự án này.
My Role
Trong dự án, tôi tham gia ở nhiều lớp khác nhau của sản phẩm.
Không chỉ development.

Tôi tham gia từ việc phân tích yêu cầu, trao đổi với stakeholder, thiết kế solution, phát triển backend/frontend, thiết kế permission model, triển khai infrastructure cho đến hỗ trợ production và go-live.
Vai trò của tôi có thể được nhìn ở ba góc độ:
Engineering
Thiết kế và phát triển các thành phần của hệ thống bằng:
- Next.js
- NestJS
- PostgreSQL
- Redis
- Docker
- Linux
- Nginx
Product
Chuyển những yêu cầu nghiệp vụ từ phía người dùng thành:
Business Requirement
↓
Workflow
↓
System Behavior
↓
Technical Design
↓
Implementation
Đây là phần tôi nhận ra quan trọng hơn rất nhiều so với việc chỉ nhận một ticket rồi viết code.
Operations
Tôi cũng tham gia vào quá trình triển khai và vận hành hệ thống.
Một hệ thống enterprise không kết thúc ở:
git push
↓
build
↓
done
Nó chỉ thực sự bắt đầu khi người dùng sử dụng hệ thống trong môi trường thực tế.
Designing Around Business Processes
Một trong những bài toán lớn nhất là chuyển workflow ngoài đời thành workflow trong phần mềm.
Ví dụ, một tài liệu có thể trải qua:
Create
↓
Submit
↓
Review
↓
Approve
↓
Digital Signature
↓
Archive
Nhưng thực tế luôn có ngoại lệ.
Có thể:
- trả lại;
- chỉnh sửa;
- trình ký lại;
- thay đổi người xử lý;
- thay đổi quyền;
- chuyển bộ phận;
- hoặc phát sinh một nhánh nghiệp vụ khác.
Do đó, tôi không xem workflow đơn giản là một danh sách trạng thái.
Tôi xem nó như một state transition system.
┌───────────┐
│ Draft │
└─────┬─────┘
↓
┌───────────┐
│ Submitted │
└─────┬─────┘
↓
┌───────────┐
│ Review │
└───┬───┬───┘
│ │
Reject Approve
│ │
↓ ↓
Draft Signing
↓
Completed
Cách suy nghĩ này giúp hệ thống dễ kiểm soát hơn khi nghiệp vụ phát triển.
RBAC Is More Than Role = Permission
Một bài toán khác là phân quyền.
Ở những ứng dụng nhỏ, authorization thường bắt đầu bằng:
Admin
User
Manager
Nhưng trong enterprise system, như vậy là chưa đủ.
Quyền truy cập có thể phụ thuộc vào:
- user;
- role;
- department;
- resource;
- folder;
- document;
- action;
- scope.
Do đó, authorization cần được thiết kế như một phần của architecture thay vì rải các điều kiện permission khắp source code.
Một request không đơn giản chỉ là:
Can this user access this API?
Mà gần hơn với:
Can
this user
perform this action
on this resource
within this scope
?
Đây là một trong những bài học quan trọng của tôi khi làm enterprise software.
Document Management Is a Lifecycle Problem
Quản lý document cũng không chỉ là lưu file.
Một document có lifecycle riêng:
Metadata
↓
Storage
↓
Version
↓
Workflow
↓
Approval
↓
Signature
↓
Audit
↓
Archive
Điều đó khiến database design, permission model, storage architecture và workflow phải được thiết kế cùng nhau.
Một thay đổi nhỏ ở document model đôi khi có thể ảnh hưởng đến:
- permission;
- workflow;
- search;
- audit;
- notification;
- digital signature;
- reporting.
Đây là lý do tôi ngày càng nhìn database và domain model từ góc độ business domain, thay vì chỉ nhìn chúng như những bảng dữ liệu.
Integrating Digital Signature
Digital signature là một ví dụ điển hình của việc business requirement trở thành technical problem.
Ở góc nhìn người dùng:
"Tôi muốn ký tài liệu."
Nhưng ở góc nhìn hệ thống, phía sau đó là:
Document
↓
Signature Request
↓
Authentication
↓
Signing Provider
↓
Signature Result
↓
Document Update
↓
Audit Trail
Hệ thống phải quan tâm đến trạng thái, lỗi, retry, tính toàn vẹn và khả năng truy vết.
Những bài toán như vậy khiến tôi nhận ra một điều:
Enterprise software thường khó ở integration và state management hơn là ở UI.
Asynchronous Processing
Một số tác vụ xử lý tài liệu không phù hợp để thực hiện trực tiếp trong HTTP request.
Ví dụ:
Upload Document
↓
Create Job
↓
Redis Queue
↓
Worker
↓
OCR / Processing
↓
Update Result
Thay vì bắt người dùng chờ toàn bộ quá trình xử lý hoàn thành, hệ thống có thể chuyển công việc nặng sang background processing.
Redis trở thành một phần quan trọng trong architecture để quản lý asynchronous jobs.
Điều này cũng đặt ra những bài toán khác:
- retry;
- failed jobs;
- idempotency;
- queue monitoring;
- resource consumption;
- worker stability.
Đây là những vấn đề rất khác với việc chỉ viết một API CRUD.
AI Is Not the Product
Trong quá trình xây dựng hệ thống, AI/OCR có thể được sử dụng để hỗ trợ xử lý tài liệu.
Nhưng tôi không xem AI là trung tâm của hệ thống.
Architecture mà tôi quan tâm hơn là:
┌── OCR
│
Document ───────────┼── AI Processing
│
└── Metadata Extraction
↓
Business System
AI nên là một capability có thể thay thế hoặc nâng cấp.
Domain system vẫn phải hoạt động ngay cả khi model hoặc AI provider thay đổi.
Đó là một nguyên tắc tôi muốn giữ trong những hệ thống có tích hợp AI:
Do not let the AI layer own the business domain.
Production Changes the Way You Think
Một trong những điều giá trị nhất tôi nhận được từ dự án không đến từ một framework.
Nó đến từ production.
Khi một hệ thống đang được sử dụng thật, một bug không còn là:
"Bug này fix sau."
Nó có thể trở thành:
"Người dùng đang chờ."
Trong một lần training/demo, hệ thống phát sinh vấn đề ngay trước thời điểm trình bày một chức năng.
Tôi phải chuyển từ context:
Presentation
sang:
Production debugging
Tôi truy cập server, xác định nguyên nhân, thực hiện thay đổi cần thiết và đưa hệ thống trở lại trạng thái hoạt động trong thời gian ngắn.
Trải nghiệm đó nhắc tôi rằng:
Một engineer giỏi không chỉ biết xây hệ thống. Họ phải biết hệ thống của mình đang thực sự chạy như thế nào.
Working With Stakeholders
Một phần khác của dự án mà tôi đánh giá rất cao là quá trình làm việc trực tiếp với stakeholder.
Ở những dự án enterprise, specification hiếm khi hoàn hảo ngay từ đầu.
Có những requirement chỉ thực sự rõ khi người dùng nhìn thấy software.
Vì vậy, vòng lặp thường là:
Requirement
↓
Prototype
↓
User Feedback
↓
Clarification
↓
Technical Solution
↓
Implementation
↓
Validation
Vai trò của Tech Lead trong trường hợp này không chỉ là quyết định framework hay database.
Mà còn phải làm cầu nối giữa:
Business
↕
Product
↕
Engineering
↕
Infrastructure
Đó là phần khiến tôi hứng thú với vai trò Tech Lead và Solution Architect.
What I Learned
Sau dự án này, cách tôi nhìn về software development thay đổi khá nhiều.
1. Enterprise software is a system, not a collection of features.
Một hệ thống lớn không thể được thiết kế bằng cách cộng dồn các feature.
Các domain phải liên kết với nhau thông qua những nguyên tắc rõ ràng.
2. Architecture starts with business constraints.
Không có architecture "tốt nhất" trong chân không.
Architecture phải trả lời được:
- Business cần gì?
- User cần gì?
- Security cần gì?
- Infrastructure chịu được gì?
- Team có thể maintain gì?
3. Production experience changes engineering decisions.
Một solution nhìn rất đẹp trên diagram có thể trở thành vấn đề khi chạy thật.
Production buộc engineer phải quan tâm đến:
Failure
Observability
Recovery
Performance
Security
Deployment
Maintenance
4. Communication is part of engineering.
Một Tech Lead không chỉ giao tiếp với developer.
Họ phải có khả năng giải thích technical decisions cho người không viết code.
Và ngược lại, phải biến business problems thành những vấn đề kỹ thuật mà team có thể giải quyết.
Beyond CRUD
Dự án này giúp tôi bước thêm một bước trong quá trình trở thành một engineer mà tôi muốn hướng tới.
Tôi vẫn thích viết code.
Nhưng tôi không còn nhìn software engineering chỉ từ góc độ:
API
Database
UI
Deploy
Tôi bắt đầu nhìn nó như một hệ thống lớn hơn:
Business
↓
Process
↓
Domain
↓
Architecture
↙ ↘
Application Infrastructure
↘ ↙
Production
↓
Users
Và có lẽ đây là điều quan trọng nhất tôi mang ra khỏi dự án:
Code chỉ là một phần của software engineering.
Giá trị lớn hơn nằm ở khả năng hiểu bài toán, thiết kế hệ thống, đưa nó vào production và chịu trách nhiệm khi hệ thống thực sự được sử dụng.
Confidentiality
This case study describes my role, engineering experience and general technical approach.
Due to client and project confidentiality requirements, it intentionally excludes client data, source code, credentials, internal infrastructure details, proprietary documents and other non-public information.
The technical descriptions are presented at a general level to document my professional experience without disclosing confidential project information.