Tài liệu Developer
BANA (BANA) là hệ thống Point of Sale (POS) cấp doanh nghiệp được thiết kế cho môi trường bán vé sự kiện đa merchant, bán lẻ và dịch vụ lưu trú. Được xây dựng dưới dạng Bun monorepo, nền tảng tận dụng IGNIS Framework cho các microservice dựa trên dependency injection, Tauri cho ứng dụng desktop đa nền tảng và stack React hiện đại cho giao diện web.
Tài liệu này cung cấp tham khảo kỹ thuật toàn diện cho các developer xây dựng, mở rộng hoặc tích hợp với nền tảng BANA.
Hướng dẫn cho Developer
Mới bắt đầu? Hãy bắt đầu với những hướng dẫn này:
| Hướng dẫn | Bạn sẽ học được gì |
|---|---|
| Getting Started | Clone, cài đặt, build, chạy service đầu tiên của bạn |
| Build System | Makefile targets, dependency graph, Docker builds |
| Environment Reference | Mọi biến môi trường trên tất cả các service |
| Git Workflow | Branching, commits, MRs, code review, glab CLI |
| IGNIS Patterns | Application hierarchy, DI, controller factory, model patterns |
Kiến trúc & Tham khảo
| Hướng dẫn | Nội dung bao gồm |
|---|---|
| System Architecture | Service registry, dependency chain, ánh xạ database schema, component matrix |
| Event Architecture | Kafka topics, CDC pipeline, WebSocket topics, webhook events |
| Database Guide | 11 PostgreSQL schemas, Drizzle ORM, quy trình migration, column enrichers |
| Testing Guide | Bun test runner, preload mocking, Object.create pattern, mock factories |
| Frontend Patterns | Shared stack, app dependency graph, thư viện component, i18n |
Technology Stack
| Phân loại | Công nghệ | Phiên bản | Mô tả |
|---|---|---|---|
| Runtime | Bun | >=1.3.8 | Runtime JavaScript all-in-one nhanh với hỗ trợ TypeScript native |
| Framework | IGNIS | 0.0.7-7 | Framework DI TypeScript-first (@venizia/ignis) |
| Web Server | Hono | 4.11.3 | Framework web siêu nhanh với routing type-safe |
| API Schema | Zod | 4.1.13 | Thư viện validate schema TypeScript-first |
| API Docs | Hono Zod OpenAPI | 1.2.0 | Sinh spec OpenAPI 3.1 từ Zod schemas |
| ORM | Drizzle ORM | 0.45.1 | Bộ công cụ SQL type-safe cho PostgreSQL |
| ORM Migrations | Drizzle Kit | 0.31.8 | Công cụ migrate schema cho Drizzle |
| Validation | Drizzle Zod | 0.8.3 | Sinh Zod schema từ Drizzle tables |
| Database | PostgreSQL | 14+ | Cơ sở dữ liệu quan hệ đa schema (7 schemas, 55+ models) |
| Cache/Queue | Redis | 6+ | Kho dữ liệu trong bộ nhớ (5 logical databases) |
| Job Queue | BullMQ | Latest | Hàng đợi công việc phân tán dựa trên Redis (24 queues, 3 partitions mỗi queue) |
| Search | Typesense | Latest | Search engine nhanh, chịu lỗi chính tả với đồng bộ CDC real-time |
| Storage | Minio | Latest | Object storage tương thích S3 cho tài sản media |
| API Reference | Scalar Hono | 0.9.28 | UI tài liệu API hiện đại cho Hono |
| Password Hashing | bcrypt | 6.0.0 | Hàm băm adaptive cho credentials |
| Date/Time | Day.js | 1.11.19 | Thư viện xử lý ngày giờ nhẹ |
| PostgreSQL Client | node-postgres | 8.16.3 | Client PostgreSQL non-blocking cho Node.js |
| TypeScript | TypeScript | ~5.9.3 | Superset có kiểu của JavaScript |
| Helpers | IGNIS Helpers | 0.0.6-7 | Thư viện tiện ích framework IGNIS (@venizia/ignis-helpers) |
| Desktop | Tauri | 2.x | Framework desktop nhẹ, an toàn (Rust + WebView) |
| Frontend | React | 19.x | Thư viện UI khai báo cho web và desktop apps |
| Build Tool | Vite | 7.x | Công cụ build frontend thế hệ mới với HMR |
| Styling | TailwindCSS | 4.x | Framework CSS utility-first |
| UI Components | Radix UI + shadcn | Latest | Component primitive accessible, composable |
Tổng quan Kiến trúc
Frontend Applications
React 19 + Vite 7 + TailwindCSS 4 + shadcn/ui
client
Admin Dashboard
sale-renderer
POS Desktop UI
sale-main
Tauri Backend (Rust)
bo
Back Office
shared
admin-ui-kit
UI Component Library
shared
core
App Constants, Hooks
▼ HTTP REST / WebSocket / Tauri IPC
Backend Microservices
IGNIS Framework (Bun + Hono + Drizzle + Zod)
identity
Auth, Users, RBAC
commerce
Products, Pricing
sale
Orders, Checkout
inventory
Stock, PO, Tracking
search
Typesense + CDC
asset
Media, Minio S3
invoice
E-Invoice, PDF
finance
Wallets, Transactions
payment
Orchestration Layer
signal
WebSocket, E2E ECDH
shared
core
Base Classes, Utils
▼ IGNIS Components (Dependency Injection)
Third-Party Integrations
External service connectors and adapters
mq-pay
Multi-Provider Payments
iiapi
VNPAY E-Invoice API
t-van
Tax VAN / CQT
▼ HTTPS / REST API
External Services
Third-party providers and government authorities
VNPAY
Payment Gateway
VNPAY Invoice
E-Invoice Provider
CQT
General Tax Dept
T-VAN Providers
Viettel, VNPT
Kiến trúc Hệ thống
Package Dependency Graph
Frontend Applications
| Ứng dụng | Package | Stack | Mô tả |
|---|---|---|---|
| client | @nx-app/client | React 19.2.1, Vite 7.1.7, TailwindCSS 4.1.16, Redux Toolkit, TanStack Query/Table | Admin dashboard chính với 28 screen module: categories, products, sale orders, inventory, finance (wallets, transactions, categories), purchase orders, users, roles, merchants, organizers, devices, terminals, reports, settings |
| bo | @nx-app/bo | React 19, Vite 7, TailwindCSS 4 | Back Office cho nhân viên merchant/organizer với giao diện admin đơn giản (5 screens: home, merchant, organizer, sign-in, errors) |
| sale-renderer | @nx-app/sale-renderer | React 19.2.0, Vite 7.2.4, TailwindCSS 4.1.18, Tauri 2.9.1, Socket.IO Client | POS desktop app WebView: tạo đơn hàng, quét barcode, in hóa đơn, tích hợp thanh toán, cập nhật real-time qua WebSocket |
| sale-main | @nx-app/sale-main | Tauri 2.x, Rust, SQLite (Sea-ORM) | Backend POS desktop (Tauri main process): xử lý thiết bị ngoại vi USB (scanner, printer, card reader), local database, custom plugins (USB, Payment, External Display, Machine UID) |
| admin-ui-kit | @nx-app/admin-ui-kit | Radix UI, shadcn/ui, lucide-react, TailwindCSS 4 | Thư viện component UI dùng chung: 38 shadcn components + custom core/icon components. Được dùng bởi client và bo |
| core | @nx-app/core | React 19 | Module app core dùng chung: constants, hooks, locales (i18n), utilities. Peer dependency: ra-core, @minimaltech/ra-core-infra |
Backend Packages
| Package | Tên Package | Port | Tính năng chính | Dependencies | Trạng thái |
|---|---|---|---|---|---|
| core | @nx/core | N/A | Foundation dùng chung: DefaultApplication, SoftDeletableRepository, 7 PostgreSQL schemas (55 models), Snowflake ID generator, xác thực cross-service, CryptoUtility (AES-256-GCM), bootstrap helpers (bootstrapApplication, bootstrapMigration, createAppConfig, createMigrationProcessLoader) | N/A | Production |
| identity | @nx/identity | 3001 | Xác thực & phân quyền: chiến lược JWT/Basic auth, CRUD user với tạo atomic (user + identifiers + profile + roles), quản lý employee với mapping organizer/merchant, xác minh email (mã 6 chữ số, hết hạn 10 phút, giới hạn tần suất), băm mật khẩu (bcrypt), RBAC với 5 vai trò mặc định (SUPER_ADMIN 999, ADMIN 998, OPERATOR 997, ORGANIZER_OWNER 899, EMPLOYEE 898) | @nx/core | Production |
| commerce | @nx/commerce | 3002 | Product catalog & pricing engine: product aggregates (info, identifiers, variants), định giá động với đánh giá dựa trên rule (OVERRIDE/DISCOUNT/MARKUP operators: EQ, NE, GT, GTE, LT, LTE, IN, NIN), hỗ trợ đa merchant, categories, sale channels, lọc truy cập dựa trên role | @nx/core, @nx/asset, @nx/inventory, @nx/search, @nx/t-van | Production |
| sale | @nx/sale | 3003 | Quản lý đơn hàng & checkout: vòng đời đơn hàng (DRAFT → PROCESSING → PARTIAL → COMPLETED/CANCELLED), quản lý item với tự động merge cho duplicate, validate checkout (giỏ không rỗng, item hợp lệ), xử lý sự kiện MQ-Pay cho cập nhật trạng thái thanh toán, ràng buộc tối đa (9999 qty/item, 100 items/order) | @nx/core, @nx/mq-pay | Production |
| inventory | @nx/inventory | N/A | Quản lý tồn kho & purchase orders: theo dõi tồn kho đa địa điểm (quantityOnHand, quantityAvailable, quantityReserved), vòng đời PO (DRAFT → PROCESSING → CONFIRMED → COMPLETED), 20+ tracking type định nghĩa sẵn (STOCK_IN, SALE, TRANSFER, RETURN, ADJUSTMENT, v.v.), tra cứu tracking type được cache bằng Redis | @nx/core | Production |
| search | @nx/search | N/A | Tích hợp search Typesense: đồng bộ real-time qua Debezium CDC (PostgreSQL → Typesense), chuyển đổi filter IGNIS sang Typesense query (eq, neq, gt, gte, lt, lte, between, inq, nin, and, or), 6 collections (products, organizers, merchants, categories, devices, sale-channels), endpoint chẩn đoán | @nx/core | Production |
| asset | @nx/asset | N/A | Lưu trữ file & media: dual storage (Minio S3-compatible + local disk), entity MetaLink cho theo dõi metadata (bucketName, objectName, link, mimetype, size, etag, storageType, principalId, principalType), sinh presigned URL | @nx/core | Production |
| invoice | @nx/invoice | N/A | Sinh E-Invoice (tuân thủ Việt Nam): các loại hóa đơn (VAT, Bán hàng, POS, phiếu xuất kho, biên lai, chứng từ PIT), định dạng XML, chữ ký số, sinh PDF, đánh số tuần tự | @nx/core, @nx/iiapi, @nx/t-van | Production |
| finance | @nx/finance | N/A | Quản lý tài chính & kế toán: ví (CASH, BANK, EWALLET, CREDIT_CARD) với số dư ban đầu/hiện tại, theo dõi giao dịch thu/chi, 20 category đã seed, xử lý theo sự kiện (commerce initialized → tạo ví mặc định, payment success → ghi nhận thu, PO received → ghi nhận chi) qua Redis Pub/Sub + BullMQ | @nx/core | Production |
| payment | @nx/payment | N/A | Lớp orchestration thanh toán: quản lý cấu hình webhook (đăng ký endpoint, loại sự kiện, metadata retry), tải/giải mã payment credential từ bảng Configuration (AES-256-GCM), dispatch webhook với retry exponential backoff, khởi tạo MQ-Pay component với credential getter động | @nx/core, @nx/mq-pay | Production |
| signal | @nx/signal | N/A | Giao tiếp WebSocket real-time: trao đổi khóa ECDH P-256 bắt buộc + thông điệp mã hóa AES-256-GCM, xác thực JWT khi handshake, REST API cho broadcast/room/client messaging, state backed bởi Redis cho cross-instance delivery (chế độ single hoặc cluster), stateless (không database, không migrations) | @nx/core | Production |
| gateway | @nx/gateway | N/A | API Gateway: routing, cân bằng tải, circuit breaker, rate limiting | @nx/core | Planned |
Third-Party Integrations
| Tích hợp | Tên Package | Mô tả | Tính năng chính | External Services |
|---|---|---|---|---|
| mq-pay | @nx/mq-pay | Hệ thống thanh toán đa provider | Providers: SYSTEM (CASH, BANK_TRANSFER), VNPAY_QR_MMS, VNPAY_PHONE_POS, VNPAY_SMART_POS; Vòng đời giao dịch (NEW 100 → PARTIAL 300 → SETTLED 600 / CANCELLED 505 / BLOCKED 800 / CLOSED 900); Loại payment attempt (MAKE_PAYMENT 100, CANCEL_PAYMENT 200, REFUND_PAYMENT 300); BullMQ 3-partition queues (scheduler, confirmation) với 10 job đồng thời/partition; Event emitter với 11+ loại sự kiện; Mẫu singleton AppRegistry (không dùng được DI @inject()) | VNPAY |
| iiapi | @nx/iiapi | Tích hợp VNPAY E-Invoice (viiAPI) | Loại hóa đơn: VAT, Bán hàng, POS, phiếu xuất kho nội bộ, biên lai, chứng từ PIT; 15 services (VAT invoice, POS VAT invoice, POS sale invoice, invoice management, webhook, OTP); Multi-client registry với OAuth2 token tự động refresh (buffer 5 phút); Request/response qua VIIAPIRequestHelper; Test endpoint: https://invoice-api.vnpaytest.vn, Production: https://api.vnpayinvoice.vn | VNPAY Invoice |
| t-van | @nx/t-van | Tích hợp Vietnam Tax VAN | Truy vấn hóa đơn điện tử từ Tax Authority (CQT); Tra cứu thông tin người nộp thuế theo tax code/ID (4 loại query: 00001 Citizen ID, 00003 Tax Code, 00130 ID Tax Payer, 00132 Personal Tax Code); Multi-client registry; Tự động chia batch cho query lớn (VNPAY tối đa 10 tax codes/request) | CQT (qua providers Viettel, VNPT T-VAN) |
Infrastructure
Data Stores
| Dịch vụ | Port | Database/Index | Mục đích | Ghi chú |
|---|---|---|---|---|
| PostgreSQL | 5432 | N/A | Cơ sở dữ liệu quan hệ | 7 schemas, 55 models |
| Redis | 6379 | DB0 | Cache | Caching đa mục đích |
| Redis | 6379 | DB1 | BullMQ Queues | 24 queues (4 systems × 3 partitions × 2 types) |
| Redis | 6379 | DB2 | Pub/Sub Subscriber | Kênh subscribe sự kiện |
| Redis | 6379 | DB3 | Pub/Sub Publisher | Kênh publish sự kiện |
| Redis | 6379 | DB4 | WebSocket State | State cross-instance của dịch vụ Signal |
| Typesense | 8108 | N/A | Search engine | 6 collections: products, merchants, categories, organizers, devices, sale-channels |
| Minio | 9000 | N/A | Object storage | API tương thích S3, presigned URLs |
PostgreSQL Database Schemas
| Schema | Số lượng Model | Mô tả | Model ví dụ |
|---|---|---|---|
public | 30 | Core business entities | User, Role, Product, ProductInfo, ProductIdentifier, ProductVariant, Merchant, Organizer, Category, Device, Terminal, SaleChannel, Configuration, Employee, Vendor |
pricing | 7 | Pricing engine | Fare, FareRule, Cost, Tax |
allocation | 4 | Chỗ ngồi & venues sự kiện | Venue, Section, Seat, Allocation |
inventory | 8 | Quản lý tồn kho | Inventory, PurchaseOrder, PurchaseOrderItem, InventoryTracking, InventoryTrackingType |
sale | 2 | Đơn bán hàng | SaleOrder, SaleOrderItem |
finance | 3 | Bản ghi tài chính | FinanceWallet, FinanceCategory, FinanceTransaction |
payment | 1 | Cấu hình thanh toán | WebhookConfig |
| Tổng | 55 | 7 schemas |
BullMQ Queue Systems
| System | Queue Types | Partitions | Tổng Queues | Mục đích |
|---|---|---|---|---|
| Commerce | 2 | 3 | 6 | Đồng bộ product, cập nhật catalog |
| Finance | 2 | 3 | 6 | Xử lý giao dịch, đối soát |
| Inventory | 2 | 3 | 6 | Cập nhật tồn, xử lý PO |
| Sale | 2 | 3 | 6 | Xử lý đơn hàng, cập nhật thanh toán |
| Tổng | 8 | 3 | 24 |
Lưu ý: Mỗi queue type có 3 partitions (P01, P02, P03) để phân tải. Mặc định: 10 job đồng thời mỗi partition.
Kiến trúc theo Sự kiện
Redis Pub/Sub Channels
| Channel | Loại sự kiện | Publisher | Subscribers | Payload |
|---|---|---|---|---|
UserOnboardingEventChannels.COMMERCE_INITIALIZED | Commerce Initialized | @nx/commerce | @nx/finance | { merchantId: string, organizerId: string } |
PaymentEventChannels.PAYMENT_SUCCESS | Payment Success | @nx/mq-pay | @nx/sale, @nx/finance | { transactionId: string, amount: number, currency: string, referenceId: string, referenceType: string } |
UserOnboardingEventChannels.SELLER_REGISTERED | Seller Registered | @nx/identity | N/A | { userId: string, email: string, roles: string[] } |
MQ-Pay Event System
| Loại sự kiện | Trigger | Payload | Subscribers |
|---|---|---|---|
mq-pay:transaction.created | Giao dịch được tạo | { transactionId, amount, currency, provider } | @nx/sale |
mq-pay:transaction.settled | Thanh toán đã settle | { transactionId, settlementDate } | @nx/sale, @nx/finance |
mq-pay:transaction.cancelled | Thanh toán bị huỷ | { transactionId, reason } | @nx/sale |
mq-pay:attempt.created | Payment attempt được tạo | { attemptId, transactionId, type } | @nx/sale |
mq-pay:attempt.sent | Payment request đã gửi | { attemptId, provider, sentAt } | @nx/sale |
mq-pay:attempt.success | Thanh toán thành công | { attemptId, transactionId, paidAt } | @nx/sale, @nx/finance |
mq-pay:attempt.failed | Thanh toán thất bại | { attemptId, errorCode, errorMessage } | @nx/sale |
mq-pay:attempt.expired | Thanh toán hết hạn | { attemptId, expiredAt } | @nx/sale |
mq-pay:refund.success | Hoàn tiền thành công | { refundId, transactionId, amount } | @nx/sale, @nx/finance |
mq-pay:refund.failed | Hoàn tiền thất bại | { refundId, errorCode } | @nx/sale |
Bảo mật
| Lớp | Cơ chế | Triển khai |
|---|---|---|
| Xác thực | JWT + Basic Auth | JWT token với expiry cấu hình được (mặc định: 3600s), Basic auth với băm mật khẩu bcrypt (cost factor: 6.0.0) |
| Phân quyền | RBAC | 5 vai trò mặc định: SUPER_ADMIN (999), ADMIN (998), OPERATOR (997), ORGANIZER_OWNER (899), EMPLOYEE (898). Middleware dựa trên role qua decorator @authenticate |
| WebSocket Encryption | ECDH P-256 + AES-256-GCM | Trao đổi khóa bắt buộc khi handshake, shared key mỗi client, envelope thông điệp mã hóa { event: 'encrypted', data: { iv, ct } } |
| Lưu trữ Credential | AES-256-GCM Encryption | Payment credentials được mã hóa trong bảng Configuration bằng CryptoUtility, giải mã on-the-fly qua PaymentConfigurationService |
| Băm mật khẩu | bcrypt | Hàm băm adaptive với salt rounds (bcrypt 6.0.0) |
| CORS | Hono CORS Middleware | Cấu hình trong DefaultApplication với origin cho phép dựa trên môi trường |
| Rate Limiting | Xác minh Email | Cooldown 60s, 5 lần gửi lại/ngày, khoá 15 phút sau 3 lần thử thất bại |
Setup môi trường phát triển
Yêu cầu tiên quyết
| Công cụ | Phiên bản | Mục đích |
|---|---|---|
| Bun | >=1.3.8 | Runtime, package manager, build tool |
| PostgreSQL | 14+ | Cơ sở dữ liệu chính |
| Redis | 6+ | Cache, queues, pub/sub, WebSocket state |
| Typesense | Latest | Search engine (tùy chọn cho tính năng search) |
| Minio | Latest | Object storage (tùy chọn cho tính năng asset) |
| Node.js | 18+ | Tauri tooling, một số công cụ build frontend |
| Rust | Latest | Biên dịch Tauri backend (sale-main) |
Quick Start
bash
# Clone repository
git clone https://git.nexpando.com/bana/bana.git
cd bana
# Install dependencies
make install # or: bun install
# Set up environment variables
cd packages/core # or any package
cp .env.example .env.development
# Build all packages (respects dependency order)
make build # Builds: core → asset,search,identity,inventory,finance,sale,signal → commerce → payment
# Run database migrations (from any package directory)
cd packages/identity
bun run migrate:dev
# Start development server (from package directory)
bun run server:dev # Uses .env.developmentLệnh Build
bash
# Root-level build (respects dependency order)
make build # Build all: third-parties → packages
make build-packages # Build only packages/*
make build-3rd # Build only third-parties/*
# Individual package builds
make core # @nx/core (build first)
make identity # @nx/identity
make sale-order # @nx/sale
make commerce # @nx/commerce (requires asset, search, inventory)
make inventory # @nx/inventory
make finance # @nx/finance
make payment # @nx/payment (requires mq-pay)
make signal # @nx/signal
make mq-pay # @nx/mq-pay
make iiapi # @nx/iiapi
make t-van # @nx/t-van
# Per-package build (inside package directory)
cd packages/sale
bun run rebuild # ALWAYS use this (clean + tsc + tsc-alias)
# NEVER run `tsc` directly (path aliases won't resolve)Development Servers
bash
# Backend services
make dev-sale-order # Start @nx/sale (http://localhost:3003)
make dev-commerce # Start @nx/commerce (http://localhost:3002)
make dev-identity # Start @nx/identity (http://localhost:3001)
make dev-finance # Start @nx/finance
make dev-payment # Start @nx/payment
make dev-signal # Start @nx/signal (WebSocket)
# Frontend apps
make dev-client # Start admin dashboard (Vite HMR)
make dev-bo # Start back office (Vite HMR)
make dev-wiki # Start VitePress docs (http://localhost:5173)
# Tauri desktop app
cd apps/sale-renderer
bunx tauri dev # Start POS desktop app (hot reload)Lint & Test
bash
# Linting (root level)
make lint # Lint everything
make lint-packages # Lint all packages/*
make lint-3rd # Lint all third-parties/*
make lint-sale-order # Lint @nx/sale
make lint-finance # Lint @nx/finance
make lint-mq-pay # Lint @nx/mq-pay
# Linting (per package)
cd packages/sale
bun run lint:fix # ESLint + Prettier auto-fix
# Testing (per package)
cd packages/sale
bun run rebuild # Build first
bun run test # Run all tests (requires .env.test)
bun run test:watch # Watch mode
# Single test file
bun test --env-file=.env.test dist/__tests__/path/to/file.test.jsGit Hooks
bash
# Set up git hooks (run once)
make setup-tools # Configure git to use .githooks directory
# Pre-commit hook runs automatically on `git commit`
make pre-commit # Run manually: lints all packagesCấu hình Môi trường
Chiến lược dotenv-flow
Mỗi package dùng dotenv-flow cho cấu hình theo môi trường:
| File | Mục đích | Được Git tracking |
|---|---|---|
.env.example | Template với tất cả biến | Có |
.env.development | Cài đặt development | Không (copy từ example) |
.env.test | Môi trường test | Không (copy từ example) |
.env.local | Override local (ưu tiên cao nhất) | Không |
Biến môi trường Core
bash
# Application
APP_ENV_NODE_ENV=development
APP_ENV_APPLICATION_SECRET=<secret-key-32-chars>
APP_ENV_JWT_SECRET=<jwt-secret-key>
APP_ENV_JWT_EXPIRES_IN=3600
# PostgreSQL
APP_ENV_POSTGRES_HOST=localhost
APP_ENV_POSTGRES_PORT=5432
APP_ENV_POSTGRES_DATABASE=bana
APP_ENV_POSTGRES_USERNAME=postgres
APP_ENV_POSTGRES_PASSWORD=password
# Redis - Cache (DB0)
APP_ENV_CACHE_REDIS_HOST=localhost
APP_ENV_CACHE_REDIS_PORT=6379
APP_ENV_CACHE_REDIS_DB=0
APP_ENV_CACHE_REDIS_PASSWORD=
# Redis - Queue (DB1)
APP_ENV_QUEUE_REDIS_HOST=localhost
APP_ENV_QUEUE_REDIS_PORT=6379
APP_ENV_QUEUE_REDIS_DB=1
APP_ENV_QUEUE_REDIS_PASSWORD=
# Redis - WebSocket (DB4)
APP_ENV_WEBSOCKET_REDIS_MODE=single # or: cluster
APP_ENV_WEBSOCKET_REDIS_HOST=localhost
APP_ENV_WEBSOCKET_REDIS_PORT=6379
APP_ENV_WEBSOCKET_REDIS_DB=4
APP_ENV_WEBSOCKET_REDIS_PASSWORD=
APP_ENV_WEBSOCKET_REDIS_MAX_RETRY=5
APP_ENV_WEBSOCKET_ECDH_INFO=<HKDF-info-string>
# Typesense
APP_ENV_TYPESENSE_API_KEY=<api-key>
APP_ENV_TYPESENSE_NODES=http:localhost:8108 # format: protocol:host:port, comma-separated
# Minio
APP_ENV_MINIO_HOST=localhost
APP_ENV_MINIO_API_PORT=9000
APP_ENV_MINIO_CONSOLE_PORT=9001
APP_ENV_MINIO_ACCESS_KEY=minioadmin
APP_ENV_MINIO_SECRET_KEY=minioadmin
APP_ENV_MINIO_USE_SSL=false
# Snowflake ID Generator
APP_ENV_SNOWFLAKE_WORKER_ID=1
APP_ENV_SNOWFLAKE_EPOCH_CHECKPOINT=1704067200000 # 2024-01-01 00:00:00 UTC
# Cross-Service URLs
APP_ENV_IDENTITY_SERVICE_URL=http://localhost:3001
APP_ENV_COMMERCE_SERVICE_URL=http://localhost:3002
APP_ENV_SALE_SERVICE_URL=http://localhost:3003
# VNPAY (via mq-pay)
APP_ENV_VNPAY_TVAN_API_KEY=<api-key>
# Email (for identity email verification)
APP_ENV_SMTP_HOST=smtp.gmail.com
APP_ENV_SMTP_PORT=587
APP_ENV_SMTP_USER=<email@example.com>
APP_ENV_SMTP_PASSWORD=<app-password>Cấu trúc Dự án
bana/
├── apps/ # Frontend applications
│ ├── client/ # Admin dashboard (React 19, Vite 7, TailwindCSS 4)
│ │ ├── src/screens/ # 28 screen modules (products, orders, finance, users, etc.)
│ │ ├── src/layouts/ # Layout components
│ │ └── package.json
│ ├── bo/ # Back office (simplified admin)
│ │ ├── src/screens/ # 5 screens (home, merchant, organizer, sign-in, errors)
│ │ └── package.json
│ ├── sale-renderer/ # POS desktop UI (Tauri WebView)
│ │ ├── src/ # React app
│ │ └── package.json
│ ├── sale-main/ # POS desktop backend (Tauri Rust)
│ │ ├── src-tauri/ # Rust source
│ │ ├── src-tauri/tauri-plugin-*/ # Custom plugins (USB, Payment, Display, Machine UID)
│ │ └── package.json
│ ├── admin-ui-kit/ # Shared UI library (Radix UI + shadcn)
│ │ ├── components/shadcn/ # 38 shadcn components
│ │ ├── components/core/ # Custom core components
│ │ ├── components/icons/ # Icon components
│ │ └── package.json
│ └── core/ # Shared app core (constants, hooks, locales, utilities)
│ └── package.json
│
├── packages/ # Backend microservices (IGNIS-based)
│ ├── core/ # Foundation package
│ │ ├── src/default-application.ts # Base application class
│ │ ├── src/repositories/soft-deletable.repository.ts
│ │ ├── src/utilities/id-generator.utility.ts
│ │ ├── src/helpers/bootstraps/ # bootstrapApplication, bootstrapMigration
│ │ ├── src/models/schemas/ # 7 PostgreSQL schemas (55 models)
│ │ │ ├── public/ # 30 models
│ │ │ ├── pricing/ # 7 models
│ │ │ ├── allocation/ # 4 models
│ │ │ ├── inventory/ # 8 models
│ │ │ ├── sale/ # 2 models
│ │ │ ├── finance/ # 3 models
│ │ │ └── payment/ # 1 model
│ │ └── package.json
│ ├── identity/ # Auth, users, RBAC (port 3001)
│ │ ├── src/application.ts
│ │ ├── src/components/
│ │ ├── src/services/
│ │ └── package.json
│ ├── commerce/ # Products, pricing (port 3002)
│ ├── sale/ # Orders, checkout (port 3003)
│ ├── inventory/ # Stock, purchase orders
│ ├── search/ # Typesense integration
│ ├── asset/ # Minio storage
│ ├── invoice/ # E-Invoice generation
│ ├── finance/ # Wallets, transactions
│ ├── payment/ # Payment orchestration
│ └── signal/ # WebSocket service
│
├── third-parties/ # External integrations
│ ├── mq-pay/ # Multi-provider payments
│ │ ├── src/component.ts # MQPayComponent
│ │ ├── src/services/payment/ # Payment execution, cancellation, refund, verification
│ │ ├── src/helpers/app-registry.helper.ts # Singleton registry
│ │ └── package.json
│ ├── iiapi/ # VNPAY E-Invoice API
│ │ ├── src/iiapi.component.ts
│ │ └── package.json
│ └── t-van/ # Tax VAN connector
│ ├── src/t-van.component.ts
│ └── package.json
│
├── docs/wiki/ # VitePress documentation
│ ├── content/en/developer/ # English docs
│ └── content/vi/developer/ # Vietnamese docs
│
├── infrastructure/ # Infrastructure & deployment configs
│ └── deployments/
│ └── develop/ # Docker Compose configs per service
│
├── Makefile # Build automation
├── package.json # Root package (workspaces, overrides)
├── tsconfig.json # TypeScript config
├── .githooks/ # Git hooks (pre-commit)
└── AGENTS.md # AI agent instructions (project rules, architecture)IGNIS Framework Patterns
Dependency Injection
typescript
import { inject, BaseService, BindingKeys, BindingNamespaces } from '@venizia/ignis';
export class MyService extends BaseService {
constructor(
// String key pattern
@inject({ key: 'repositories.UserRepository' })
private userRepository: UserRepository,
// Or with BindingKeys helper
@inject({ key: BindingKeys.build({ namespace: BindingNamespaces.REPOSITORY, key: 'ProductRepository' }) })
private productRepository: ProductRepository,
) {
super({ scope: MyService.name });
}
async findUser(id: string): Promise<User> {
return this.userRepository.findById({ id });
}
}Cấu trúc Component
typescript
import { BaseComponent, inject, CoreBindings, BaseApplication } from '@venizia/ignis';
export class MyComponent extends BaseComponent {
constructor(
@inject({ key: CoreBindings.APPLICATION_INSTANCE })
protected application: BaseApplication,
) {
super({
scope: MyComponent.name,
initDefault: { enable: true, container: application },
bindings: {},
});
}
override async binding(): Promise<void> {
// Register repositories, services, controllers in correct order
this.application.repository(MyRepository);
this.application.service(MyService);
this.application.controller(MyController);
}
}Vòng đời Application
typescript
import { DefaultApplication } from '@nx/core';
export class Application extends DefaultApplication {
override preConfigure(): void {
// Execute BEFORE boot phase
this.configureServices();
this.configureComponents();
this.configureSecurity();
}
override configureComponents(): void {
super.configureComponents(); // Call parent to register core components
this.component(MyComponent); // Register custom components
}
override async postConfigure(): Promise<void> {
// Execute AFTER all components are bound
await this.initializeExternalServices();
}
}Bootstrap Helpers (từ @nx/core)
typescript
// packages/*/src/index.ts - Application entry point
import { bootstrapApplication } from '@nx/core';
import { Application } from './application.js';
import { appConfig } from './common/app-config.js';
import { resolve } from 'node:path';
bootstrapApplication({
ApplicationClass: Application,
config: appConfig,
options: { bannerPath: resolve(__dirname, '../resources/banner.txt') },
});
// packages/*/src/migrate.ts - Migration entry point
import { bootstrapMigration } from '@nx/core';
import { Application } from './application.js';
import { getMigrationProcesses } from './migrations/processes/migration-process.js';
bootstrapMigration({
ApplicationClass: Application,
getMigrationProcesses,
});
// packages/*/src/common/app-config.ts - Centralized config
import { createAppConfig } from '@nx/core';
export const appConfig = createAppConfig();
// packages/*/src/migrations/processes/migration-process.ts
import { createMigrationProcessLoader } from '@nx/core';
export const getMigrationProcesses = createMigrationProcessLoader({
seedPaths: ['my-package-0001-seed-data', 'my-package-0002-seed-roles'],
importFn: path => import(`../processes/${path}.js`),
});Controller Factory (Auto CRUD)
typescript
import { controller } from '@venizia/ignis';
import { ControllerFactory } from '@venizia/ignis';
import { inject } from '@venizia/ignis';
import { MyRepository } from '../repositories/my.repository.js';
import { MyEntity } from '../models/entities/my.entity.js';
@controller({ path: '/my-entities' })
export class MyController extends ControllerFactory.defineCrudController({
repository: { name: MyRepository.name },
authenticate: { strategies: ['jwt', 'basic'] }, // Optional: require auth
controller: { name: 'MyController', basePath: '/my-entities' },
entity: () => MyEntity,
}) {
constructor(
@inject({ key: 'repositories.MyRepository' })
repository: MyRepository,
) {
super(repository);
}
// Auto-generated routes:
// GET /my-entities - List with pagination, filtering, sorting
// GET /my-entities/:id - Get by ID
// POST /my-entities - Create
// PATCH /my-entities/:id - Update
// DELETE /my-entities/:id - Delete (soft-delete if using SoftDeletableRepository)
// Override or add custom routes as needed
}Drizzle ORM Patterns
typescript
// Schema definition
import { pgTable, uuid, text, timestamp, decimal, integer } from 'drizzle-orm/pg-core';
export const products = pgTable('products', {
id: uuid('id').primaryKey().defaultRandom(),
name: text('name').notNull(),
price: decimal('price', { precision: 10, scale: 4 }).notNull(),
quantity: integer('quantity').default(0),
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),
modifiedAt: timestamp('modified_at', { withTimezone: true }).defaultNow(),
deletedAt: timestamp('deleted_at', { withTimezone: true }), // For soft-delete
});
// Repository with soft-delete
import { repository } from '@venizia/ignis';
import { SoftDeletableRepository } from '@nx/core';
import { PostgresCoreDataSource } from '@/datasources';
import { Product } from '../models/entities/product.entity.js';
@repository({ dataSource: PostgresCoreDataSource, model: Product })
export class ProductRepository extends SoftDeletableRepository<typeof products, Product, TProductPersist> {
// Built-in methods:
// - deleteById (sets deletedAt, not physical delete)
// - restoreById (clears deletedAt)
// - findById (excludes soft-deleted by default)
// - find (excludes soft-deleted by default)
}
// Transactions
await this.productRepository.dataSource.withTransaction(async tx => {
await this.productRepository.create({ data: productData, options: { transaction: tx } });
await this.inventoryRepository.create({ data: inventoryData, options: { transaction: tx } });
// Both succeed or both rollback
});Zod Validation với Drizzle
typescript
import { createSelectSchema, createInsertSchema } from 'drizzle-zod';
import { products } from '../schemas/product.schema.js';
// Auto-generate Zod schemas from Drizzle tables
export const ProductSelectSchema = createSelectSchema(products);
export const ProductInsertSchema = createInsertSchema(products);
// Custom validation
import { z } from 'zod';
export const CreateProductSchema = ProductInsertSchema.omit({ id: true, createdAt: true, modifiedAt: true }).extend({
name: z.string().min(2).max(255),
price: z.number().positive().max(9999999.9999),
quantity: z.number().int().nonnegative(),
});
export type CreateProductInput = z.infer<typeof CreateProductSchema>;Liên kết nhanh
Backend Packages
| Package | Tài liệu | Mô tả |
|---|---|---|
| Core | Tài liệu | Foundation dùng chung: base classes, 7 DB schemas, utilities |
| Identity | Tài liệu | Xác thực, RBAC, xác minh email |
| Commerce | Tài liệu | Products, pricing engine, merchants |
| Sale | Tài liệu | Đơn hàng, checkout, tích hợp MQ-Pay |
| Payment | Tài liệu | Orchestration thanh toán, dispatch webhook |
| Signal | Tài liệu | Giao tiếp WebSocket, mã hóa ECDH |
| Asset | Tài liệu | Lưu trữ file, Minio S3 |
| Invoice | Tài liệu | Sinh E-Invoice, PDF |
| Gateway | Tài liệu | API Gateway (planned) |
Third-Party Integrations
| Tích hợp | Tài liệu | Mô tả |
|---|---|---|
| MQ-Pay | Tài liệu | Hệ thống thanh toán đa provider (VNPAY, Cash) |
| IIAPI | Tài liệu | Tích hợp VNPAY E-Invoice |
| T-VAN | Tài liệu | Vietnam Tax VAN connector |
Frontend Applications
| Ứng dụng | Tài liệu | Mô tả |
|---|---|---|
| Client | Tài liệu | Admin dashboard (28 screens) |
| POS Desktop | Renderer / Main | Tauri desktop app |
| Admin UI Kit | Tài liệu | Thư viện component dùng chung |
Bước tiếp theo
Cho Developer mới
- Setup môi trường local: Cài đặt các yêu cầu (Bun, PostgreSQL, Redis)
- Build monorepo: Chạy
make install && make build - Khám phá package Core: Đọc Core Documentation để hiểu hạ tầng dùng chung
- Chạy một service: Khởi động dịch vụ Identity với
make dev-identity, khám phá Swagger tạihttp://localhost:3001/docs - Đọc IGNIS patterns: Nghiên cứu dependency injection, cấu trúc component, ví dụ controller factory ở trên
Cho Developer tích hợp
- Review tích hợp MQ-Pay: MQ-Pay Documentation cho luồng thanh toán
- Hiểu hệ thống sự kiện: Nghiên cứu Redis Pub/Sub channels và kiến trúc queue BullMQ
- Triển khai webhooks: Dùng dispatcher webhook
@nx/paymentvới retry exponential backoff - Test với sandbox: Dùng endpoint VNPAY test từ các tích hợp
@nx/iiapivà@nx/t-van
Cho Frontend Developer
- Setup client app: Chạy
make dev-clientvà khám phá 28 screen module - Dùng Admin UI Kit: Import component từ
@nx-app/admin-ui-kit(38 shadcn components) - Tích hợp với backend: Dùng TanStack Query cho API call, Redux Toolkit cho quản lý state
- Build POS desktop app: Khám phá kiến trúc Tauri trong
sale-mainvàsale-renderer
Cho DevOps Engineer
- Review infrastructure: PostgreSQL 7 schemas, Redis 5 databases, Typesense, Minio
- Setup Docker Compose: Dùng
infrastructure/deployments/develop/cho stack local - Cấu hình môi trường: Nghiên cứu các file
.env.exampletrong các package - Giám sát queues: Setup dashboard BullMQ để giám sát 24 queue
- Triển khai services: Mỗi package có Dockerfile, triển khai độc lập hoặc dạng monolith