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à Entitlement nên tách rõ hơn.
  • Provider ProfileTrust/Reputation nên tách thành hai domain khác nhau.
  • LMS Core nên tách thành Learning Delivery, Assessment/Gradebook, Learning Records.
  • PaymentsSaaS Billing không nên trộn.
  • Discovery/Search không nên được xem là source of truth của khóa học.
  • CRM/Ops nên tách khỏi Support/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.

DomainCó nên là backend module?Có nên tách service sớm?Ghi chú
Identity & AccessKhôngĐăng nhập, session, MFA sau này, role, permission
Tenant & OrganizationKhôngGiáo viên cá nhân, trung tâm, chi nhánh, staff
Authorization PolicyKhôngCó thể nằm chung Identity/Tenant, nhưng policy phải rõ
Subscription & SaaS BillingKhôngPlan, add-on, usage, invoice provider/center
Audit & ComplianceKhôngAudit 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.

DomainCó nên là backend module?Có nên tách service sớm?Ghi chú
Provider ManagementKhôngHồ sơ giáo viên/trung tâm, onboarding, profile
VerificationKhôngGiấy tờ/chứng chỉ/xác minh thủ công
Trust & ReputationKhôngReview thật, badge, complaint rate, trust signals
CatalogKhôngCourse template, skill, category, subject
Offering & ListingKhôngGói đem bán: giá, lịch, giáo viên, điều kiện
Discovery & RankingCó thể sauSearch/filter/ranking/read model, không sở hữu truth
Booking & SchedulingKhôngTrial booking, slot, lịch, đổi lịch
Order & CheckoutKhôngCart/order/checkout state machine
EntitlementKhôngAi đượ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.

DomainCó nên là backend module?Có nên tách service sớm?Ghi chú
Payment OrchestrationKhôngTạo payment intent/session, nhận webhook
LedgerKhôngSổ cái nội bộ: debit/credit, commission, payable
Refund & DisputeKhôngRefund workflow, dispute evidence
PayoutCó thể sauTrả tiền provider, hold window, reconciliation
ReconciliationCó thể tách workerĐối soát provider/payment gateway
Tax/InvoiceCó thểCó thể sauTù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ả.

DomainCó nên là backend module?Có nên tách service sớm?Ghi chú
Learning DeliveryKhôngClass/cohort/session/attendance/material access
Learning ContentKhôngLesson, material, resource, roadmap
AssessmentKhôngHomework, quiz, exam, question bank
GradebookKhôngĐiểm, nhận xét, kết quả chính thức
Learning RecordsCó thể sauProgress, activity events, xAPI-style records
Certificate/CredentialSauSauChứng nhận hoàn thành, badge sau này
LTI/OneRoster/QTI AdapterSauSauTí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.

DomainCó nên là backend module?Có nên tách service sớm?Ghi chú
CRM & Lead PipelineKhôngLead từ booking/enroll, stage, follow-up
Provider OperationsKhôngDashboard provider/center
Ops AdminKhôngNội bộ OPSKOO quản lý provider/course/order
Support TicketKhôngKhiếu nại, hỗ trợ, SLA
Dispute Case ManagementKhôngEvidence, decision, refund/payout impact
ModerationKhôngProfile, 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

DomainCó nên là backend module?Có nên tách service sớm?Ghi chú
NotificationCó thể sauEmail/SMS/push/in-app
MessagingSauCó thể sauChat learner-provider, moderation mạnh
Community/SocialSauCó thể sauFeed, 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

DomainCó nên là backend module?Có nên tách service sớm?Ghi chú
File AssetKhôngUpload, scan, metadata, signed URL
Image ProcessingCó thểCó thể sauThumbnail, resize
Video ProcessingSauCó thể sauTranscode, HLS, DRM, watermark
Live Class IntegrationKhôngZoom/Meet/external link ở MVP

MVP không nên tự build video streaming/live streaming/DRM.

3.8. Nhóm Intelligence & Data

DomainCó nên là backend module?Có nên tách service sớm?Ghi chú
AI WorkflowCó thể sauFormat tài liệu, gợi ý bài tập, human approval
Recommendation/MatchingSauCó thể sauCần dữ liệu thật trước
Analytics EventsCó thể sauEvent taxonomy, data contracts
Data PlatformSauCó thể sauWarehouse/lakehouse/dbt/BI
ExperimentationSauSauA/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

DomainCó nên là backend module?Có nên tách service sớm?Ghi chú
External Provider AdaptersKhôngPayment, email, storage, meeting, AI provider
Webhooks InboundKhôngPayment webhook, email events, meeting events
Webhooks OutboundSauSauCho đối tác/center enterprise
API ContractsKhôngOpenAPI cho REST, AsyncAPI cho event
EdTech Standards AdapterSauSauLTI/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ốDomainLoạiOwner truth
1Identity & AccessControlUser, credential, session, role assignment
2Tenant & OrganizationControlOrganization, branch, membership
3Authorization PolicyControlPermission/policy theo context
4Provider ManagementMarketplaceTeacher/center profile
5VerificationTrustVerification request, evidence, approval
6Trust & ReputationTrustReview, rating, badge, trust signals
7CatalogMarketplaceCourse template, subject, skill, taxonomy
8Offering & ListingMarketplaceSellable package, price, schedule, visibility
9Discovery & RankingRead/IntelligenceSearch index, ranking read model
10Booking & SchedulingMarketplaceTrial booking, appointment, availability
11Order & CheckoutCommerceOrder state, checkout state
12Payment OrchestrationMoneyPayment attempt, webhook, provider reference
13Ledger & PayoutMoneyLedger entries, payable, payout status
14Refund & DisputeMoney/OpsRefund request, dispute case
15EntitlementAccessLearning access rights
16Learning DeliveryLearningClass, cohort, session, attendance
17Learning ContentLearningLesson/resource/material roadmap
18Assessment & GradebookLearningAssignment, submission, grade, feedback
19Learning RecordsData/LearningProgress/activity/learning events
20CRM & Lead PipelineOpsLead, stage, follow-up
21Support & ModerationOpsTicket, moderation case, abuse report
22NotificationEngagementNotification intent, delivery status
23Messaging/CommunityEngagementConversation/post/comment later
24Media & File AssetPlatformFile metadata, signed access, processing status
25Subscription & SaaS BillingSaaSPlan, subscription, invoice, usage
26AI WorkflowIntelligenceAI job, prompt version, output, approval
27Analytics & Data PlatformDataEvent taxonomy, marts, metrics
28Integration PlatformPlatformExternal adapter config, webhook records
29Audit & CompliancePlatformAudit 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/checkout tự 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-client sinh từ OpenAPI, không viết tay lung tung.
  • ui không import business feature.
  • features có thể import ui, nhưng ui không import features.
  • i18n là 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, DomainEvent base 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ụ:

  • IdentityDbContext
  • CatalogDbContext
  • OrdersDbContext
  • PaymentsDbContext
  • LearningDbContext
  • CrmDbContext

Đá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:

  • ProviderVerified
  • OfferingPublished
  • TrialBooked
  • OrderCreated
  • PaymentSucceeded
  • OrderPaid
  • EntitlementGranted
  • ClassSessionScheduled
  • AssignmentSubmitted
  • RefundRequested
  • RefundApproved
  • ProviderPayoutCreated

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:

  • outbox
  • notifications
  • payments
  • ai
  • media
  • analytics

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.production trong 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_total
  • payment_succeeded_total
  • payment_webhook_duplicate_total
  • entitlement_grant_latency
  • booking_conversion_rate
  • provider_verification_sla
  • refund_request_count
  • class_session_join_success_rate
  • assignment_submission_count
  • ai_job_approval_rate
  • notification_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ó:

  • PaymentService sửa Enrollment.
  • CourseService tự tính quyền học.
  • UserService biết role của trung tâm quá sâu.
  • AIService chấm điểm chính thức.
  • AdminController update 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 courses chứa cả course, class, offering, enrollment, progress,
  • một bảng payments chứa cả order, transaction, refund, commission,
  • một cột status khô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/