Báo cáo cấu trúc dự án và chia domain OPSKOO Global
Ngày lập: 2026-05-30
Mục tiêu: đề xuất cấu trúc dự án đầy đủ cho OPSKOO Global, bao gồm frontend, backend, worker/service, database, integration, data platform, infra, observability, security, testing và tài liệu vận hành.
Bản này trả lời trực tiếp câu hỏi:
Chia domain như trước đã ổn chưa?
Cấu trúc project nên chia thế nào để không rối khi hệ thống lớn lên?
1. Kết luận ngắn
Domain split trước đó đúng hướng, nhưng vẫn còn hơi thô.
Nếu chấm theo mức dùng được cho MVP/V1:
Domain split cũ: 7/10.
Domain split sau khi chỉnh: 9/10 cho giai đoạn V1.
Các điểm đúng của bản cũ:
- Đã nhận ra OPSKOO không chỉ là LMS.
- Đã tách marketplace, trust, payment, LMS, CRM, AI, media, SaaS billing.
- Đã không nhét payment trực tiếp vào LMS.
- Đã không để AI sở hữu sự thật cốt lõi.
- Đã chọn modular monolith thay vì microservices sớm.
Các điểm cần chỉnh:
Marketplace Booking, Order và Entitlementnên tách rõ hơn.Provider ProfilevàTrust/Reputationnên tách thành hai domain khác nhau.LMS Corenên tách thànhLearning Delivery,Assessment/Gradebook,Learning Records.PaymentsvàSaaS Billingkhông nên trộn.Discovery/Searchkhông nên được xem là source of truth của khóa học.CRM/Opsnên tách khỏiSupport/Dispute/Moderation.- Cần thêm domain rõ ràng cho
Communication,Integration Platform,Audit/Compliance,Data Platform.
Kết luận kiến trúc:
OPSKOO nên dùng monorepo có cấu trúc rõ.
Backend là ASP.NET Core modular monolith.
Frontend là Next.js, tách public web và ops console.
Worker chạy cùng domain modules, chưa tách service sớm.
Database là PostgreSQL managed, chia schema/module boundary.
Search, AI, Media, Notification, Data pipeline có thể tách service sau.
2. Nguyên tắc chia cấu trúc
Cấu trúc dự án tốt không phải là cây thư mục đẹp. Cấu trúc tốt phải giúp trả lời:
- Ai sở hữu sự thật nào?
- Module nào được sửa dữ liệu nào?
- Module nào chỉ là read model?
- Module nào được deploy riêng?
- Module nào chỉ là adapter tới dịch vụ ngoài?
- Nếu AI agent viết code, nó có bị ép đi đúng ranh giới không?
- Nếu sau này tách service, có đường tách không?
Các nguồn chuẩn đều đi về cùng một ý:
- DDD nhấn mạnh bounded context, ubiquitous language và ranh giới domain.[^ms-ddd]
- Microsoft Clean Architecture nhấn mạnh UI phụ thuộc vào Application Core qua interface, còn Infrastructure là chi tiết triển khai.[^ms-clean]
- Fowler cảnh báo microservices cần automation, monitoring và deployment maturity; dùng sớm dễ tăng chi phí vận hành.[^fowler-prereq]
- AWS SaaS nhấn mạnh tenant isolation khác với authentication/authorization; có đăng nhập đúng chưa chắc đã chống lộ dữ liệu tenant.[^aws-tenant-isolation]
- Next.js App Router cho phép colocate code theo route, nhưng vẫn không ép cấu trúc; team phải tự đặt convention.[^next-project]
- OpenTelemetry khuyến nghị chuẩn hóa logs, metrics, traces để không mù khi vận hành.[^otel]
- OWASP ASVS/NIST SSDF giúp đưa security vào cấu trúc dự án, không để security thành việc vá cuối cùng.[^owasp-asvs][^nist-ssdf]
Nguyên tắc cho OPSKOO:
Domain trước, framework sau.
Core truth trước, UI sau.
Modular monolith trước, microservices sau.
Provider trước, tự build sau.
Audit trước, automation sau.
Human approval trước, AI autonomy sau.
3. Bản đồ domain chuẩn đề xuất
3.1. Nhóm Control Plane
Control Plane là phần quản lý nền tảng, tenant, tổ chức, quyền, plan, audit.
| Domain | Có nên là backend module? | Có nên tách service sớm? | Ghi chú |
|---|---|---|---|
| Identity & Access | Có | Không | Đăng nhập, session, MFA sau này, role, permission |
| Tenant & Organization | Có | Không | Giáo viên cá nhân, trung tâm, chi nhánh, staff |
| Authorization Policy | Có | Không | Có thể nằm chung Identity/Tenant, nhưng policy phải rõ |
| Subscription & SaaS Billing | Có | Không | Plan, add-on, usage, invoice provider/center |
| Audit & Compliance | Có | Không | Audit log xuyên hệ thống, support access, evidence |
Lưu ý:
Identity trả lời "bạn là ai".
Tenant trả lời "bạn thuộc tổ chức nào".
Authorization trả lời "bạn được làm gì trong ngữ cảnh nào".
Ba thứ này không giống nhau.
3.2. Nhóm Marketplace Core
Đây là lõi kiếm tiền ban đầu của OPSKOO.
| Domain | Có nên là backend module? | Có nên tách service sớm? | Ghi chú |
|---|---|---|---|
| Provider Management | Có | Không | Hồ sơ giáo viên/trung tâm, onboarding, profile |
| Verification | Có | Không | Giấy tờ/chứng chỉ/xác minh thủ công |
| Trust & Reputation | Có | Không | Review thật, badge, complaint rate, trust signals |
| Catalog | Có | Không | Course template, skill, category, subject |
| Offering & Listing | Có | Không | Gói đem bán: giá, lịch, giáo viên, điều kiện |
| Discovery & Ranking | Có | Có thể sau | Search/filter/ranking/read model, không sở hữu truth |
| Booking & Scheduling | Có | Không | Trial booking, slot, lịch, đổi lịch |
| Order & Checkout | Có | Không | Cart/order/checkout state machine |
| Entitlement | Có | Không | Ai được quyền học cái gì, từ khi nào đến khi nào |
Điểm chỉnh quan trọng:
Catalog không phải LMS.
Offering không phải Class.
Order không phải Payment.
Payment không phải Entitlement.
Search không phải source of truth.
Nếu trộn các khái niệm này, hệ thống sẽ chạy được demo nhưng rất khó xử lý refund, đổi lớp, học thử, khóa nhiều lịch, trung tâm nhiều chi nhánh, hoặc học viên được cấp quyền học theo gói.
3.3. Nhóm Payment & Money
Đây là nhóm phải nghiêm túc từ đầu.
| Domain | Có nên là backend module? | Có nên tách service sớm? | Ghi chú |
|---|---|---|---|
| Payment Orchestration | Có | Không | Tạo payment intent/session, nhận webhook |
| Ledger | Có | Không | Sổ cái nội bộ: debit/credit, commission, payable |
| Refund & Dispute | Có | Không | Refund workflow, dispute evidence |
| Payout | Có | Có thể sau | Trả tiền provider, hold window, reconciliation |
| Reconciliation | Có | Có thể tách worker | Đối soát provider/payment gateway |
| Tax/Invoice | Có thể | Có thể sau | Tùy quốc gia, B2B/B2C |
Không nên làm:
paid = true
Nên làm:
OrderPaid event
PaymentTransaction
LedgerEntry
EntitlementGranted
ProviderPayableCreated
3.4. Nhóm Learning Platform
LMS nên tách bên trong, không để một module LMS ôm tất cả.
| Domain | Có nên là backend module? | Có nên tách service sớm? | Ghi chú |
|---|---|---|---|
| Learning Delivery | Có | Không | Class/cohort/session/attendance/material access |
| Learning Content | Có | Không | Lesson, material, resource, roadmap |
| Assessment | Có | Không | Homework, quiz, exam, question bank |
| Gradebook | Có | Không | Điểm, nhận xét, kết quả chính thức |
| Learning Records | Có | Có thể sau | Progress, activity events, xAPI-style records |
| Certificate/Credential | Sau | Sau | Chứng nhận hoàn thành, badge sau này |
| LTI/OneRoster/QTI Adapter | Sau | Sau | Tích hợp chuẩn eLearning khi cần |
1EdTech OneRoster định nghĩa dữ liệu người học, course, enrollment, organization và grades cho trao đổi hệ thống giáo dục; QTI dùng cho trao đổi item/test/result; LTI dùng cho tích hợp tool học tập.[^oneroster][^qti][^lti]
Vì vậy OPSKOO nên standards-aware, nhưng không cần implement đầy đủ OneRoster/QTI/LTI ở MVP.
3.5. Nhóm Operations
Đây là phần nhiều người mới đánh giá thấp.
| Domain | Có nên là backend module? | Có nên tách service sớm? | Ghi chú |
|---|---|---|---|
| CRM & Lead Pipeline | Có | Không | Lead từ booking/enroll, stage, follow-up |
| Provider Operations | Có | Không | Dashboard provider/center |
| Ops Admin | Có | Không | Nội bộ OPSKOO quản lý provider/course/order |
| Support Ticket | Có | Không | Khiếu nại, hỗ trợ, SLA |
| Dispute Case Management | Có | Không | Evidence, decision, refund/payout impact |
| Moderation | Có | Không | Profile, review, post, abuse report |
Không nên nhét tất cả vào Admin.
Admin là UI/quyền truy cập.
Support, Dispute, Moderation là domain có workflow, evidence và audit riêng.
3.6. Nhóm Engagement
| Domain | Có nên là backend module? | Có nên tách service sớm? | Ghi chú |
|---|---|---|---|
| Notification | Có | Có thể sau | Email/SMS/push/in-app |
| Messaging | Sau | Có thể sau | Chat learner-provider, moderation mạnh |
| Community/Social | Sau | Có thể sau | Feed, comment, report, ranking |
MVP chỉ nên có notification và profile post đơn giản. Social feed lớn nên để sau.
3.7. Nhóm Media
| Domain | Có nên là backend module? | Có nên tách service sớm? | Ghi chú |
|---|---|---|---|
| File Asset | Có | Không | Upload, scan, metadata, signed URL |
| Image Processing | Có thể | Có thể sau | Thumbnail, resize |
| Video Processing | Sau | Có thể sau | Transcode, HLS, DRM, watermark |
| Live Class Integration | Có | Không | Zoom/Meet/external link ở MVP |
MVP không nên tự build video streaming/live streaming/DRM.
3.8. Nhóm Intelligence & Data
| Domain | Có nên là backend module? | Có nên tách service sớm? | Ghi chú |
|---|---|---|---|
| AI Workflow | Có | Có thể sau | Format tài liệu, gợi ý bài tập, human approval |
| Recommendation/Matching | Sau | Có thể sau | Cần dữ liệu thật trước |
| Analytics Events | Có | Có thể sau | Event taxonomy, data contracts |
| Data Platform | Sau | Có thể sau | Warehouse/lakehouse/dbt/BI |
| Experimentation | Sau | Sau | A/B test, ranking experiment |
AI không được sở hữu sự thật như order, payment, grade, entitlement, refund.
AI chỉ nên:
Đọc dữ liệu được phép đọc.
Tạo đề xuất.
Ghi log.
Chờ người hoặc workflow duyệt nếu ảnh hưởng quyền/tiền/đánh giá.
NIST AI RMF và OWASP LLM Top 10 đều nhấn mạnh governance, measurement, excessive agency, prompt injection và data leakage.[^nist-ai-rmf][^owasp-llm]
3.9. Nhóm Integration Platform
| Domain | Có nên là backend module? | Có nên tách service sớm? | Ghi chú |
|---|---|---|---|
| External Provider Adapters | Có | Không | Payment, email, storage, meeting, AI provider |
| Webhooks Inbound | Có | Không | Payment webhook, email events, meeting events |
| Webhooks Outbound | Sau | Sau | Cho đối tác/center enterprise |
| API Contracts | Có | Không | OpenAPI cho REST, AsyncAPI cho event |
| EdTech Standards Adapter | Sau | Sau | LTI/OneRoster/QTI/xAPI |
OpenAPI là chuẩn phổ biến để mô tả REST API; AsyncAPI làm việc tương tự cho asynchronous/event-driven API.[^openapi][^asyncapi]
4. Domain split cuối cùng nên dùng
Đây là danh sách domain đề xuất cho OPSKOO V1:
| Số | Domain | Loại | Owner truth |
|---|---|---|---|
| 1 | Identity & Access | Control | User, credential, session, role assignment |
| 2 | Tenant & Organization | Control | Organization, branch, membership |
| 3 | Authorization Policy | Control | Permission/policy theo context |
| 4 | Provider Management | Marketplace | Teacher/center profile |
| 5 | Verification | Trust | Verification request, evidence, approval |
| 6 | Trust & Reputation | Trust | Review, rating, badge, trust signals |
| 7 | Catalog | Marketplace | Course template, subject, skill, taxonomy |
| 8 | Offering & Listing | Marketplace | Sellable package, price, schedule, visibility |
| 9 | Discovery & Ranking | Read/Intelligence | Search index, ranking read model |
| 10 | Booking & Scheduling | Marketplace | Trial booking, appointment, availability |
| 11 | Order & Checkout | Commerce | Order state, checkout state |
| 12 | Payment Orchestration | Money | Payment attempt, webhook, provider reference |
| 13 | Ledger & Payout | Money | Ledger entries, payable, payout status |
| 14 | Refund & Dispute | Money/Ops | Refund request, dispute case |
| 15 | Entitlement | Access | Learning access rights |
| 16 | Learning Delivery | Learning | Class, cohort, session, attendance |
| 17 | Learning Content | Learning | Lesson/resource/material roadmap |
| 18 | Assessment & Gradebook | Learning | Assignment, submission, grade, feedback |
| 19 | Learning Records | Data/Learning | Progress/activity/learning events |
| 20 | CRM & Lead Pipeline | Ops | Lead, stage, follow-up |
| 21 | Support & Moderation | Ops | Ticket, moderation case, abuse report |
| 22 | Notification | Engagement | Notification intent, delivery status |
| 23 | Messaging/Community | Engagement | Conversation/post/comment later |
| 24 | Media & File Asset | Platform | File metadata, signed access, processing status |
| 25 | Subscription & SaaS Billing | SaaS | Plan, subscription, invoice, usage |
| 26 | AI Workflow | Intelligence | AI job, prompt version, output, approval |
| 27 | Analytics & Data Platform | Data | Event taxonomy, marts, metrics |
| 28 | Integration Platform | Platform | External adapter config, webhook records |
| 29 | Audit & Compliance | Platform | Audit trail, evidence, retention |
Không nhất thiết phải tạo 29 .NET projects ngay.
Cách hiểu đúng:
29 domain boundary để suy nghĩ.
Khoảng 14-18 backend modules cho V1.
Một số domain nhỏ có thể nằm chung module nhưng phải tách namespace/folder/model rõ.
5. Container map toàn hệ thống
Ở mức container, OPSKOO nên có:
Người dùng
|
|-- Public learner/provider traffic
v
apps/web - Next.js public + learner/provider/center portal
|
v
backend/Opskoo.Api - ASP.NET Core API
|
|-- PostgreSQL
|-- Redis/cache
|-- Object Storage
|-- Payment Provider
|-- Email/SMS/Push Provider
|-- Meeting Provider
|-- AI Provider
|-- Search Engine later
|-- Data Warehouse later
Opskoo internal staff
|
v
apps/ops - Next.js internal ops console
|
v
backend/Opskoo.Api
Background processing
|
v
backend/Opskoo.Worker
|
|-- outbox processing
|-- webhook retry
|-- notification delivery
|-- payment reconciliation
|-- AI jobs
|-- media jobs
|-- analytics event export
MVP deployable nên là:
1. apps/web
2. apps/ops
3. backend/Opskoo.Api
4. backend/Opskoo.Worker
5. backend/Opskoo.Migrator
Chưa cần:
Search service riêng.
AI service riêng.
Payment service riêng.
Media service riêng.
Notification service riêng.
Các service này có thể có folder định hướng/contract, nhưng chưa deploy riêng nếu chưa có pain thật.
6. Cấu trúc repo đề xuất
Tôi khuyến nghị monorepo cho giai đoạn đầu.
Lý do:
- Team nhỏ, thay đổi sản phẩm còn đi ngang qua frontend/backend/domain cùng lúc.
- AI agent dễ đọc đủ bối cảnh hơn.
- API contract, UI, backend, infra, docs đi cùng nhau.
- Dễ giữ ADR, C4, runbook, test, CI trong cùng một nơi.
Đánh đổi:
- CI có thể chậm nếu không path filter/build cache.
- Dễ tạo shared package bừa bãi nếu không có rule.
- Repo lớn cần CODEOWNERS và convention nghiêm túc.
Cấu trúc root:
opskoo/
README.md
CONTRIBUTING.md
CODEOWNERS
.editorconfig
.gitignore
.github/
workflows/
ci.yml
backend.yml
frontend.yml
security.yml
deploy-staging.yml
deploy-prod.yml
docs/
product/
architecture/
adr/
c4/
domain-glossary/
runbooks/
security/
compliance/
api/
apps/
web/
ops/
mobile/
packages/
ui/
design-tokens/
api-client/
auth-client/
i18n/
analytics-client/
test-utils/
eslint-config/
typescript-config/
backend/
Opskoo.sln
global.json
Directory.Build.props
Directory.Packages.props
NuGet.Config
src/
tests/
services/
README.md
search-indexer/
ai-worker/
media-processor/
data-ingestor/
contracts/
openapi/
asyncapi/
webhooks/
edtech/
schemas/
infra/
docker/
terraform/
environments/
dev/
staging/
prod/
policies/
deploy/
compose/
k8s/
helm/
data/
events/
warehouse/
dbt/
quality/
seeds/
observability/
dashboards/
alerts/
otel-collector/
slo/
security/
threat-models/
asvs/
ssdf/
sbom/
secrets-management/
pentest/
tests/
e2e/
contract/
load/
security/
tools/
generators/
scripts/
local-dev/
7. Cấu trúc frontend
7.1. Tách app frontend thế nào?
Đề xuất:
apps/web
apps/ops
apps/mobile later
Không nên tách quá sớm thành:
apps/learner
apps/provider
apps/center
apps/marketplace
Lý do:
- Learner/provider/center có nhiều UI chung: auth, layout, course cards, schedule, notification.
- Tách quá sớm tăng duplication.
- Next.js App Router hỗ trợ route groups và colocated files, đủ tốt cho V1.[^next-project]
Nhưng ops nên là app riêng.
Lý do:
- Ops console có security profile khác.
- Internal admin có quyền mạnh hơn.
- Có thể deploy sau VPN/allowlist/SSO sau này.
- Tránh nhét quyền admin sâu trong public app.
7.2. apps/web đề xuất
apps/web/
src/
app/
(public)/
page.tsx
search/
teachers/
centers/
courses/
pricing/
(auth)/
login/
register/
forgot-password/
(learner)/
learner/
dashboard/
bookings/
purchases/
classes/
assignments/
progress/
(provider)/
provider/
dashboard/
profile/
offerings/
bookings/
classes/
students/
crm/
revenue/
(center)/
center/
dashboard/
branches/
staff/
teachers/
offerings/
classes/
crm/
billing/
api/
health/
features/
marketplace/
provider-profile/
catalog/
booking/
checkout/
learning/
crm/
notifications/
account/
shared/
components/
hooks/
lib/
styles/
constants/
server/
api/
auth/
analytics/
tests/
playwright/
next.config.ts
package.json
Rule:
app/là route composition.features/chứa UI/logic theo domain trải nghiệm.shared/chỉ chứa thứ thật sự dùng chung.server/chứa server-only client/wrapper.- Không để business truth trong Next.js.
- Không để
features/checkouttự quyết định order/payment; chỉ gọi backend.
7.3. apps/ops đề xuất
apps/ops/
src/
app/
(ops)/
dashboard/
providers/
verification/
listings/
orders/
payments/
disputes/
refunds/
support/
moderation/
audit/
system-health/
features/
verification-review/
payment-ops/
dispute-case/
support-ticket/
moderation/
audit-log/
platform-metrics/
shared/
server/
Rule:
- Ops app không gọi database trực tiếp.
- Mọi action có tác động mạnh phải đi qua backend API.
- Các action như duyệt verification, refund, khóa listing, xử lý dispute phải có audit reason.
- Có thể thêm step-up auth/MFA cho action nhạy cảm sau này.
7.4. packages/ frontend
packages/
ui/
src/
button/
dialog/
form/
table/
navigation/
charts/
design-tokens/
colors.ts
spacing.ts
typography.ts
api-client/
src/
generated/
client.ts
auth-client/
src/
session.ts
permissions.ts
i18n/
src/
locales/
formatCurrency.ts
formatDateTime.ts
analytics-client/
src/
track.ts
events.ts
Rule:
api-clientsinh từ OpenAPI, không viết tay lung tung.uikhông import business feature.featurescó thể importui, nhưnguikhông importfeatures.i18nlà bắt buộc sớm vì OPSKOO muốn global.
Turborepo/pnpm workspace có thể dùng cho JS/TS monorepo; Turborepo phân biệt application packages và library packages, giúp cache/build theo dependency graph.[^turbo][^pnpm]
8. Cấu trúc backend .NET
8.1. Phiên bản .NET
Tính đến ngày 2026-05-30, .NET 10 là LTS active, hỗ trợ đến 2028-11-14; .NET 8 LTS còn hỗ trợ đến 2026-11-10.[^dotnet-support]
Nếu bắt đầu dự án mới bây giờ:
Chọn .NET 10 LTS.
Nếu có lý do ecosystem/library chưa sẵn sàng:
.NET 8 LTS vẫn dùng được nhưng phải có kế hoạch nâng cấp sớm.
8.2. Backend solution root
backend/
Opskoo.sln
global.json
Directory.Build.props
Directory.Packages.props
NuGet.Config
src/
Opskoo.Api/
Opskoo.Worker/
Opskoo.Migrator/
BuildingBlocks/
Opskoo.BuildingBlocks.Domain/
Opskoo.BuildingBlocks.Application/
Opskoo.BuildingBlocks.Infrastructure/
Opskoo.BuildingBlocks.Contracts/
Opskoo.BuildingBlocks.Observability/
Opskoo.BuildingBlocks.Testing/
Modules/
Opskoo.Modules.Identity/
Opskoo.Modules.Tenancy/
Opskoo.Modules.Providers/
Opskoo.Modules.Trust/
Opskoo.Modules.Catalog/
Opskoo.Modules.Discovery/
Opskoo.Modules.Scheduling/
Opskoo.Modules.Orders/
Opskoo.Modules.Payments/
Opskoo.Modules.Entitlements/
Opskoo.Modules.Learning/
Opskoo.Modules.Assessments/
Opskoo.Modules.Crm/
Opskoo.Modules.Support/
Opskoo.Modules.Notifications/
Opskoo.Modules.Media/
Opskoo.Modules.Billing/
Opskoo.Modules.Ai/
Opskoo.Modules.Integrations/
Opskoo.Modules.Audit/
tests/
Opskoo.ArchitectureTests/
Opskoo.Api.Tests/
Opskoo.Worker.Tests/
Modules/
Opskoo.Modules.Identity.Tests/
Opskoo.Modules.Payments.Tests/
Opskoo.Modules.Learning.Tests/
Opskoo.Modules.Orders.Tests/
Opskoo.Modules.Entitlements.Tests/
8.3. Deployable projects
Opskoo.Api
Composition root cho HTTP API:
- auth middleware,
- tenant resolution,
- API endpoints,
- OpenAPI,
- dependency injection,
- rate limiting,
- request logging,
- module registration.
Opskoo.Worker
Chạy background jobs:
- outbox dispatch,
- notification delivery,
- payment webhook retry,
- reconciliation,
- AI jobs,
- media processing nhẹ,
- data export.
Opskoo.Migrator
Chạy migration có kiểm soát:
- migrate module schemas,
- seed reference data,
- verify migration state.
Không nên để app startup tự migrate production một cách tùy tiện.
8.4. Cấu trúc bên trong mỗi module
Đề xuất V1:
Opskoo.Modules.Orders/
ModuleRegistration.cs
Domain/
Orders/
Order.cs
OrderLine.cs
OrderStatus.cs
OrderPaid.cs
OrderCancelled.cs
Checkout/
Policies/
Application/
Commands/
CreateCheckout/
MarkOrderPaid/
CancelOrder/
Queries/
GetOrderDetail/
ListOrders/
Services/
Validators/
Contracts/
Infrastructure/
Persistence/
OrdersDbContext.cs
Configurations/
Migrations/
Integrations/
ReadModels/
Api/
OrdersEndpoints.cs
CheckoutEndpoints.cs
Contracts/
Events/
OrderPaidIntegrationEvent.cs
OrderCancelledIntegrationEvent.cs
Dtos/
Không nhất thiết mỗi module phải tách thành 4 .csproj ngay.
Khuyến nghị thực dụng:
Một module = một .NET project.
Bên trong chia Domain/Application/Infrastructure/Api/Contracts.
Khi module lớn và cần ép boundary mạnh hơn, tách tiếp thành nhiều project.
Ví dụ Payments, Learning, Orders có thể cần tách project sớm hơn Notifications.
8.5. BuildingBlocks
BuildingBlocks là nơi rất dễ thành thùng rác. Phải cực kỳ hạn chế.
Được phép để trong BuildingBlocks:
Entity,ValueObject,DomainEventbase rất mỏng.Result,Error,PagedResult.Clock,IdGenerator,TenantContext.OutboxMessage.IntegrationEvent.AuditContext.- observability helpers.
- test fixtures chung.
Không được để:
- business rules,
- constants theo domain,
- DTO của module,
- service biết quá nhiều domain,
- helper mơ hồ như
CommonService,DataHelper,UserHelper.
Rule:
Nếu một class dùng từ ngữ domain, nó không nằm trong BuildingBlocks.
8.6. Dependency rules backend
Rule đề xuất:
Opskoo.Api
-> Modules.*
-> BuildingBlocks.*
Opskoo.Worker
-> Modules.*
-> BuildingBlocks.*
Module A
-> BuildingBlocks.*
-> Module A internal code
-> Không reference trực tiếp Module B internal code
Module A có thể dùng:
-> Contracts của Module B nếu cần
-> Integration event
-> Application public facade được cho phép
Không được:
Payments sửa bảng Entitlements trực tiếp.
Learning query bảng Orders trực tiếp.
AI ghi điểm chính thức trực tiếp.
Discovery sửa Course/Offering trực tiếp.
Ops Admin update database bypass domain workflow.
Được:
Payments phát event PaymentSucceeded.
Orders nhận/handle để mark order paid.
Orders phát event OrderPaid.
Entitlements nhận event OrderPaid để grant access.
Learning hỏi Entitlements để kiểm tra access.
9. Database structure
9.1. Một PostgreSQL, nhiều schema
MVP/V1 nên dùng:
Một managed PostgreSQL database.
Mỗi module lớn có schema riêng.
Ví dụ:
identity.users
tenancy.organizations
providers.provider_profiles
trust.verification_requests
catalog.courses
catalog.offerings
discovery.search_documents
scheduling.bookings
orders.orders
payments.payment_transactions
payments.ledger_entries
entitlements.entitlements
learning.classes
learning.sessions
assessment.assignments
crm.leads
support.tickets
notifications.notification_intents
media.file_assets
billing.subscriptions
ai.ai_jobs
integrations.webhook_inbox
audit.audit_logs
Lý do:
- Một DB giúp transaction đơn giản hơn.
- Schema riêng giúp boundary rõ hơn.
- Sau này module nào cần tách service/database, đường tách dễ hơn.
Không nên:
Một schema public chứa tất cả bảng.
Một DbContext khổng lồ cho toàn hệ thống.
Database per service ngay từ đầu.
9.2. DbContext
Đề xuất:
Một DbContext cho mỗi module lớn.
Ví dụ:
IdentityDbContextCatalogDbContextOrdersDbContextPaymentsDbContextLearningDbContextCrmDbContext
Đánh đổi:
- Nhiều DbContext/migration hơn.
- Nhưng boundary rõ hơn.
- AI agent khó viết query xuyên domain bừa bãi hơn.
9.3. Cross-module data
Không nên join trực tiếp xuyên module cho business write path.
Nên dùng:
- integration events,
- outbox,
- read model/projection,
- application query/facade có kiểm soát.
Ví dụ:
Catalog sở hữu Offering.
Discovery nhận OfferingPublished event và build search document.
Discovery không sửa Offering.
9.4. Outbox
Các event quan trọng phải đi qua outbox:
ProviderVerifiedOfferingPublishedTrialBookedOrderCreatedPaymentSucceededOrderPaidEntitlementGrantedClassSessionScheduledAssignmentSubmittedRefundRequestedRefundApprovedProviderPayoutCreated
Transactional outbox giúp tránh tình huống database đã commit nhưng event không gửi, hoặc event gửi rồi database fail.[^outbox]
10. Services và workers
10.1. MVP services
MVP chỉ cần:
Opskoo.Api
Opskoo.Worker
Opskoo.Migrator
Opskoo.Worker có thể chạy nhiều queue/job type:
outboxnotificationspaymentsaimediaanalytics
10.2. Future services
Folder services/ nên có README để ghi rõ:
Không tạo service riêng nếu chưa có lý do vận hành thật.
Các service có thể tách sau:
services/search-indexer
Khi search scale lớn, cần OpenSearch/Meilisearch/vector index, indexing pipeline riêng.
services/ai-worker
Khi AI cần Python/OCR/ML pipeline riêng, hoặc workload quá nặng cho .NET worker.
services/media-processor
Khi có video processing, thumbnail, virus scan, transcription, DRM/watermark.
services/data-ingestor
Khi analytics/event pipeline lớn, cần warehouse/lakehouse.
services/notification-service
Khi notification throughput cao, nhiều provider, retry/routing phức tạp.
Điều kiện tách service:
- module có owner rõ,
- data contract rõ,
- failure mode rõ,
- observability đủ,
- deploy độc lập có giá trị,
- load hoặc compliance bắt buộc tách,
- không chỉ tách vì "cho giống hệ thống lớn".
11. Contracts và API
Cấu trúc:
contracts/
openapi/
public-api.yaml
ops-api.yaml
provider-api.yaml
asyncapi/
domain-events.yaml
integration-events.yaml
webhooks/
inbound/
stripe/
vnpay/
momo/
zoom/
outbound/
provider-webhooks/
edtech/
lti/
oneroster/
qti/
xapi/
schemas/
common/
analytics-events/
Rule:
- Frontend API client sinh từ OpenAPI.
- Event payload quan trọng có schema.
- Webhook inbound lưu raw payload + signature verification result.
- Không sửa contract phá client mà không versioning.
12. Infra, deploy và environment
12.1. Infra folder
infra/
docker/
Dockerfile.api
Dockerfile.worker
Dockerfile.web
Dockerfile.ops
terraform/
modules/
network/
postgres/
redis/
object-storage/
cdn/
container-app/
secrets/
monitoring/
environments/
dev/
staging/
prod/
policies/
iam/
network/
backup/
retention/
12-Factor nhấn mạnh config nên tách khỏi code, dependencies khai báo rõ, backing services được xem như attached resources.[^twelve-factor]
12.2. Environments
Nên có:
local
dev
staging
prod
Không nên có:
prod-like bằng miệng nhưng khác prod quá nhiều.
Staging cần giống prod nhất có thể ở:
- auth flow,
- payment sandbox,
- storage/CDN,
- background jobs,
- observability,
- migration,
- feature flags.
12.3. Secrets
Không để:
.env.productiontrong repo,- key JSON trong repo,
- payment secret trong config file,
- AI provider key trong frontend.
Nên dùng:
- cloud secret manager,
- local
.env.example, - rotation policy,
- secret scanning CI.
13. Observability
Cấu trúc:
observability/
dashboards/
api/
worker/
payments/
marketplace/
learning/
ai/
alerts/
api-latency.yml
payment-webhook-failures.yml
entitlement-lag.yml
background-job-deadletter.yml
otel-collector/
collector.yaml
slo/
marketplace.md
payments.md
learning.md
ops.md
Metrics domain quan trọng:
order_created_totalpayment_succeeded_totalpayment_webhook_duplicate_totalentitlement_grant_latencybooking_conversion_rateprovider_verification_slarefund_request_countclass_session_join_success_rateassignment_submission_countai_job_approval_ratenotification_delivery_failure_rate
OpenTelemetry là vendor-neutral framework cho traces, metrics, logs.[^otel]
Rule:
Nếu một workflow kiếm tiền hoặc ảnh hưởng quyền học,
nó phải có metric, log, trace, audit.
14. Security và compliance structure
Cấu trúc:
security/
threat-models/
marketplace.md
payments.md
tenant-isolation.md
ai.md
media.md
asvs/
level-target.md
checklist.md
ssdf/
secure-development-practices.md
release-evidence.md
sbom/
backend/
frontend/
containers/
secrets-management/
rotation.md
incident-response.md
pentest/
scope.md
findings/
Mục tiêu ban đầu:
- OWASP ASVS Level 1/2 tùy khu vực nhạy cảm.
- OWASP API Security checklist.
- NIST SSDF practice cơ bản.
- SBOM cho backend/frontend/container.
- Threat model cho payment, tenant isolation, AI.
NIST SSDF đưa secure software development vào SDLC để giảm vulnerability và xử lý nguyên nhân gốc.[^nist-ssdf]
OWASP ASVS là bộ yêu cầu kiểm thử/security control cho web app và API.[^owasp-asvs]
15. Data platform structure
MVP chưa cần data platform lớn, nhưng phải chuẩn bị event taxonomy.
Cấu trúc:
data/
events/
taxonomy.md
marketplace-events.md
learning-events.md
payment-events.md
ai-events.md
warehouse/
README.md
marts/
marketplace/
learning/
revenue/
trust/
dbt/
models/
tests/
docs/
quality/
data-contracts.md
freshness-checks.md
pii-classification.md
seeds/
countries.csv
currencies.csv
subjects.csv
skills.csv
Không nên để analytics phát triển bằng cách:
Mỗi dev tự bắn event một kiểu.
Tên event không chuẩn.
Không biết event nào chứa PII.
Không có event version.
Nên chuẩn hóa từ đầu:
Event name.
Actor.
Tenant.
Object.
Timestamp.
Source.
Correlation id.
PII classification.
Schema version.
16. Testing structure
Cấu trúc:
tests/
e2e/
marketplace-checkout.spec.ts
provider-onboarding.spec.ts
learner-class-access.spec.ts
ops-refund-flow.spec.ts
contract/
openapi/
events/
webhooks/
load/
search-load.js
checkout-load.js
webhook-load.js
security/
api-authz/
tenant-isolation/
file-upload/
Backend tests:
backend/tests/
Opskoo.ArchitectureTests/
Opskoo.Api.Tests/
Modules/
Opskoo.Modules.Orders.Tests/
Opskoo.Modules.Payments.Tests/
Opskoo.Modules.Entitlements.Tests/
Opskoo.Modules.Learning.Tests/
Test quan trọng nhất cho OPSKOO:
- architecture tests: module không reference sai.
- tenant isolation tests.
- order/payment/entitlement state machine tests.
- webhook idempotency tests.
- refund/dispute tests.
- permission tests.
- file upload security tests.
- AI approval workflow tests.
- E2E checkout-to-class-access.
17. Documentation structure
Cấu trúc:
docs/
product/
vision.md
mvp-scope.md
personas.md
glossary.md
architecture/
overview.md
system-context.md
container-diagram.md
module-map.md
data-flow.md
deployment.md
adr/
0001-use-monorepo.md
0002-use-aspnet-core-modular-monolith.md
0003-use-nextjs-app-router.md
0004-use-postgresql-pooled-tenancy.md
0005-payment-provider-first.md
0006-do-not-build-native-video-in-mvp.md
c4/
level-1-system-context.md
level-2-containers.md
level-3-backend-components.md
domain-glossary/
marketplace.md
payments.md
learning.md
trust.md
tenancy.md
runbooks/
payment-webhook-failure.md
entitlement-not-granted.md
provider-verification-backlog.md
rollback-release.md
restore-database.md
C4 giúp mô tả kiến trúc bằng các mức context, container, component, code; với đa số team, context và container diagram đã rất hữu ích.[^c4]
ADR ghi lại quyết định và lý do/đánh đổi, tránh sau 6 tháng không ai nhớ vì sao chọn cách đó.[^adr]
18. Cấu trúc module theo phase
Phase 0: Foundation
Tạo:
- repo structure,
- apps/web,
- apps/ops,
- backend solution,
- Identity,
- Tenancy,
- Audit,
- BuildingBlocks,
- CI/CD,
- observability skeleton,
- docs/adr,
- contracts/openapi.
Phase 1: Provider onboarding
Tạo modules:
- Providers,
- Verification,
- Trust basic,
- Media/FileAsset,
- Notifications basic,
- Ops verification UI.
Phase 2: Marketplace discovery
Tạo modules:
- Catalog,
- Offering/Listing,
- Discovery,
- Search read model,
- public marketplace UI.
Phase 3: Booking/payment/access
Tạo modules:
- Scheduling,
- Orders,
- Payments,
- Ledger,
- Entitlements,
- Refund/Dispute basic.
Đây là phase phải test kỹ nhất.
Phase 4: Learning MVP
Tạo modules:
- Learning Delivery,
- Learning Content,
- Assessment basic,
- Gradebook basic,
- Learning Records basic.
Phase 5: CRM/Ops
Tạo modules:
- CRM,
- Support,
- Moderation,
- provider dashboard,
- ops dashboard.
Phase 6: AI/data
Tạo:
- AI Workflow,
- prompt/output logging,
- human approval,
- event taxonomy,
- analytics export.
Phase 7: Extract services nếu cần
Chỉ tách khi có dữ liệu:
- Search Indexer,
- AI Worker,
- Media Processor,
- Data Ingestor,
- Notification Service,
- Payment Reconciliation Worker.
19. Các quyết định cụ thể
19.1. Monorepo hay polyrepo?
Chọn:
Monorepo.
Vì:
- product còn biến động,
- team nhỏ,
- domain liên quan chặt,
- AI agent cần context,
- API contract/UI/backend cần đi cùng nhau.
Đánh đổi:
- cần CI tốt,
- cần CODEOWNERS,
- cần path filter,
- cần dependency rules.
19.2. Một Next app hay nhiều Next app?
Chọn:
apps/web cho public + learner/provider/center.
apps/ops cho internal ops/admin.
Vì:
- public/user-facing UI dùng nhiều component chung,
- ops cần security boundary riêng.
19.3. Một backend hay nhiều backend?
Chọn:
Một ASP.NET Core backend modular monolith.
Một worker.
Một migrator.
Vì:
- domain chưa ổn định,
- microservices quá sớm sẽ tăng chi phí,
- có thể tách sau nếu module boundary tốt.
19.4. Một DB hay nhiều DB?
Chọn:
Một PostgreSQL managed.
Nhiều schema/module boundary.
Một số DbContext theo module.
Vì:
- giảm complexity,
- giữ transaction đơn giản,
- vẫn tạo đường tách sau này.
19.5. Có tạo service AI riêng không?
Chưa.
MVP:
AI module trong backend + background jobs trong Worker.
Tách riêng khi:
- cần Python ML/OCR pipeline,
- workload AI nặng,
- cần scaling riêng,
- cần sandbox/tool permission riêng.
19.6. Có tạo search service riêng không?
Chưa.
MVP:
PostgreSQL full-text search + Discovery read model.
Tách riêng khi:
- search latency kém,
- ranking phức tạp,
- index lớn,
- cần vector/hybrid search,
- cần dedicated relevance evaluation.
19.7. Có tạo payment service riêng không?
Chưa.
Nhưng payment module phải nghiêm túc như một service tương lai:
- state machine,
- outbox,
- ledger,
- idempotency,
- webhook inbox,
- reconciliation,
- audit.
20. Những lỗi cấu trúc cần tránh
20.1. Backend lỗi
Không nên:
src/
Controllers/
Services/
Models/
Repositories/
Helpers/
Với OPSKOO, cấu trúc này quá chung. Nó làm mọi domain trộn vào nhau.
Không nên có:
PaymentServicesửaEnrollment.CourseServicetự tính quyền học.UserServicebiết role của trung tâm quá sâu.AIServicechấm điểm chính thức.AdminControllerupdate mọi bảng.
20.2. Frontend lỗi
Không nên:
components/
Button.tsx
CourseCard.tsx
PaymentForm.tsx
ProviderTable.tsx
AdminRefundModal.tsx
Tức là một folder component khổng lồ chứa cả domain.
Nên colocate theo feature/domain experience.
20.3. Shared package lỗi
Không nên tạo:
packages/common
packages/utils
backend/BuildingBlocks/Common
rồi nhét mọi thứ vào đó.
Rule:
Shared chỉ chứa thứ thật sự không thuộc domain nào.
Nếu có từ domain, đưa về module/domain đó.
20.4. Database lỗi
Không nên:
- một bảng
courseschứa cả course, class, offering, enrollment, progress, - một bảng
paymentschứa cả order, transaction, refund, commission, - một cột
statuskhông có state machine, - không có audit,
- không có idempotency key,
- không có webhook inbox.
21. Domain dependency map
Map khuyến nghị:
Identity
<- Tenancy
<- Authorization
Providers
-> Tenancy
-> Media
Verification
-> Providers
-> Media
-> Audit
Trust
-> Providers
-> Orders/Entitlements evidence
Catalog
-> Providers
Offerings
-> Catalog
-> Providers
-> Scheduling
Discovery
<- Providers events
<- Offerings events
<- Trust events
Scheduling
-> Providers
-> Offerings
Orders
-> Offerings
-> Scheduling
-> Promotions later
Payments
-> Orders by contract/event only
-> Payment provider adapter
Ledger
-> Payments
-> Orders
Entitlements
<- Orders paid events
<- Refund/cancel events
Learning
-> Entitlements for access check
-> Media
Assessment
-> Learning
CRM
<- Booking events
<- Order events
<- Learning risk events
Support/Dispute
-> Orders
-> Payments
-> Learning evidence
-> Audit
AI
-> allowed data only
-> human approval workflow
Mũi tên không có nghĩa là reference trực tiếp code nội bộ. Nó chỉ là dependency về business/context.
22. Cấu trúc gợi ý để AI agent làm việc an toàn
Vì bạn muốn tận dụng AI agent, repo nên có guardrails:
docs/domain-glossary/
docs/architecture/module-map.md
docs/adr/
backend/tests/Opskoo.ArchitectureTests/
contracts/openapi/
contracts/asyncapi/
Thêm file hướng dẫn:
AGENTS.md
Nội dung nên ghi:
- Không sửa module khác nếu task không yêu cầu.
- Không bypass domain workflow.
- Không thêm shared helper nếu chưa chứng minh dùng chung thật.
- Không tạo API mới nếu contract chưa rõ.
- Không ghi AI output thành quyết định chính thức nếu chưa có approval.
- Không query xuyên tenant.
- Không log PII/secrets.
- Mọi payment/order/entitlement thay đổi phải có test.
23. Blueprint cuối cùng
Nếu bắt đầu scaffold OPSKOO mới, dùng cấu trúc:
opskoo/
apps/
web/ # Next.js public + learner/provider/center
ops/ # Next.js internal ops console
mobile/ # later
backend/
src/
Opskoo.Api/ # ASP.NET Core API composition root
Opskoo.Worker/ # outbox/jobs/retry/reconciliation/AI/media
Opskoo.Migrator/ # controlled DB migration
BuildingBlocks/
Modules/
Identity/
Tenancy/
Providers/
Trust/
Catalog/
Discovery/
Scheduling/
Orders/
Payments/
Entitlements/
Learning/
Assessments/
Crm/
Support/
Notifications/
Media/
Billing/
Ai/
Integrations/
Audit/
packages/
ui/
design-tokens/
api-client/
auth-client/
i18n/
analytics-client/
contracts/
openapi/
asyncapi/
webhooks/
edtech/
schemas/
infra/
deploy/
data/
observability/
security/
tests/
docs/
tools/
Đây là cấu trúc đủ nghiêm túc cho hệ thống lớn, nhưng chưa quá nặng như enterprise platform bị over-engineering từ ngày đầu.
24. Kết luận cuối
Chia domain trước đó ổn về hướng, nhưng cần tinh chỉnh để OPSKOO không bị rối ở các điểm chết:
- course/class/offering/enrollment/entitlement,
- order/payment/ledger/refund/payout,
- provider profile/trust/review/verification,
- LMS/assessment/gradebook/progress,
- tenant/identity/authorization,
- AI workflow/domain truth.
Tôi khuyến nghị:
Monorepo.
Next.js apps/web + apps/ops.
ASP.NET Core modular monolith.
Một PostgreSQL, nhiều schema.
Một API, một Worker, một Migrator.
Contracts rõ bằng OpenAPI/AsyncAPI.
Observability/security/docs/tests là một phần của repo, không phải thứ làm sau.
Điều quan trọng nhất:
Đừng chia theo màn hình.
Đừng chia theo bảng.
Đừng chia theo tên framework.
Hãy chia theo sự thật nghiệp vụ mà mỗi domain sở hữu.
Nếu giữ được nguyên tắc đó, OPSKOO có thể đi từ MVP nhỏ sang hệ thống global mà không phải đập đi xây lại quá sớm.
25. Nguồn tham khảo
[^ms-ddd]: Microsoft Learn, "Design a DDD-oriented microservice": https://learn.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/ddd-oriented-microservice [^ms-clean]: Microsoft Learn, "Common web application architectures": https://learn.microsoft.com/en-us/dotnet/architecture/modern-web-apps-azure/common-web-application-architectures [^fowler-prereq]: Martin Fowler, "Microservice Prerequisites": https://martinfowler.com/bliki/MicroservicePrerequisites.html [^aws-tenant-isolation]: AWS, "Tenant isolation - SaaS Architecture Fundamentals": https://docs.aws.amazon.com/whitepapers/latest/saas-architecture-fundamentals/tenant-isolation.html [^next-project]: Next.js Docs, "Project Organization and File Colocation": https://nextjs.org/docs/app/getting-started/project-structure [^otel]: OpenTelemetry Documentation: https://opentelemetry.io/docs/ [^owasp-asvs]: OWASP, "Application Security Verification Standard": https://owasp.org/www-project-application-security-verification-standard/ [^nist-ssdf]: NIST SP 800-218, "Secure Software Development Framework (SSDF) Version 1.1": https://csrc.nist.gov/pubs/sp/800/218/final [^oneroster]: 1EdTech, "OneRoster": https://www.1edtech.org/standards/oneroster [^qti]: 1EdTech, "Question and Test Interoperability": https://www.1edtech.org/standards/qti/index [^lti]: 1EdTech, "Learning Tools Interoperability": https://www.1edtech.org/standards/lti [^nist-ai-rmf]: NIST, "AI Risk Management Framework": https://www.nist.gov/itl/ai-risk-management-framework [^owasp-llm]: OWASP, "Top 10 for LLM Applications": https://owasp.org/www-project-top-10-for-large-language-model-applications/ [^openapi]: OpenAPI Initiative, "The OpenAPI Specification Explained": https://learn.openapis.org/specification/ [^asyncapi]: AsyncAPI Initiative: https://www.asyncapi.com/en [^turbo]: Turborepo Documentation: https://turborepo.com/repo/docs [^pnpm]: pnpm Documentation, "Workspace": https://pnpm.io/workspaces [^dotnet-support]: Microsoft .NET Support Policy: https://dotnet.microsoft.com/en-us/platform/support/policy [^twelve-factor]: The Twelve-Factor App: https://12factor.net/ [^outbox]: Microservices.io, "Transactional outbox": https://microservices.io/patterns/data/transactional-outbox.html [^c4]: C4 Model: https://c4model.com/ [^adr]: Architectural Decision Records: https://adr.github.io/