Skip to content

Developer Documentation

BANA (BANA) is an enterprise Point of Sale (POS) system designed for multi-merchant event ticketing, retail, and hospitality environments. Built as a Bun monorepo, the platform leverages the IGNIS Framework for dependency injection-based microservices, Tauri for cross-platform desktop applications, and a modern React stack for web interfaces.

This documentation provides comprehensive technical reference for developers building with, extending, or integrating the BANA platform.

Developer Guides

New here? Start with these:

GuideWhat you'll learn
Getting StartedClone, install, build, run your first service
Build SystemMakefile targets, dependency graph, Docker builds
Environment ReferenceEvery environment variable across all services
Git WorkflowBranching, commits, MRs, code review, glab CLI
IGNIS PatternsApplication hierarchy, DI, controller factory, model patterns

Architecture & Reference

GuideWhat it covers
System ArchitectureService registry, dependency chain, database schema mapping, component matrix
Event ArchitectureKafka topics, CDC pipeline, WebSocket topics, webhook events
Database Guide11 PostgreSQL schemas, Drizzle ORM, migration workflow, column enrichers
Testing GuideBun test runner, preload mocking, Object.create pattern, mock factories
Frontend PatternsShared stack, app dependency graph, component library, i18n

Technology Stack

CategoryTechnologyVersionDescription
RuntimeBun>=1.3.8Fast all-in-one JavaScript runtime with native TypeScript support
FrameworkIGNIS0.0.7-7TypeScript-first DI framework (@venizia/ignis)
Web ServerHono4.11.3Ultra-fast web framework with type-safe routing
API SchemaZod4.1.13TypeScript-first schema validation library
API DocsHono Zod OpenAPI1.2.0OpenAPI 3.1 spec generation from Zod schemas
ORMDrizzle ORM0.45.1Type-safe SQL toolkit for PostgreSQL
ORM MigrationsDrizzle Kit0.31.8Schema migration tool for Drizzle
ValidationDrizzle Zod0.8.3Zod schema generation from Drizzle tables
DatabasePostgreSQL14+Multi-schema relational database (7 schemas, 55+ models)
Cache/QueueRedis6+In-memory data structure store (5 logical databases)
Job QueueBullMQLatestRedis-based distributed job queue (24 queues, 3 partitions each)
SearchTypesenseLatestFast, typo-tolerant search engine with real-time CDC sync
StorageMinioLatestS3-compatible object storage for media assets
API ReferenceScalar Hono0.9.28Modern API documentation UI for Hono
Password Hashingbcrypt6.0.0Adaptive hashing function for credentials
Date/TimeDay.js1.11.19Lightweight date manipulation library
PostgreSQL Clientnode-postgres8.16.3Non-blocking PostgreSQL client for Node.js
TypeScriptTypeScript~5.9.3Typed superset of JavaScript
HelpersIGNIS Helpers0.0.6-7IGNIS framework utility library (@venizia/ignis-helpers)
DesktopTauri2.xLightweight, secure desktop framework (Rust + WebView)
FrontendReact19.xDeclarative UI library for web and desktop apps
Build ToolVite7.xNext-generation frontend build tool with HMR
StylingTailwindCSS4.xUtility-first CSS framework
UI ComponentsRadix UI + shadcnLatestAccessible, composable component primitives

Architecture Overview

📱
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

System Architecture

Package Dependency Graph

Frontend Applications

ApplicationPackageStackDescription
client@nx-app/clientReact 19.2.1, Vite 7.1.7, TailwindCSS 4.1.16, Redux Toolkit, TanStack Query/TableMain admin dashboard with 28 screen modules: categories, products, sale orders, inventory, finance (wallets, transactions, categories), purchase orders, users, roles, merchants, organizers, devices, terminals, reports, settings
bo@nx-app/boReact 19, Vite 7, TailwindCSS 4Back Office for merchant/organizer staff with simplified admin interface (5 screens: home, merchant, organizer, sign-in, errors)
sale-renderer@nx-app/sale-rendererReact 19.2.0, Vite 7.2.4, TailwindCSS 4.1.18, Tauri 2.9.1, Socket.IO ClientPOS desktop app WebView: order creation, barcode scanning, receipt printing, payment integration, real-time updates via WebSocket
sale-main@nx-app/sale-mainTauri 2.x, Rust, SQLite (Sea-ORM)POS desktop backend (Tauri main process): USB peripheral handling (scanner, printer, card reader), local database, custom plugins (USB, Payment, External Display, Machine UID)
admin-ui-kit@nx-app/admin-ui-kitRadix UI, shadcn/ui, lucide-react, TailwindCSS 4Shared UI component library: 38 shadcn components + custom core/icon components. Consumed by client and bo
core@nx-app/coreReact 19Shared app core module: constants, hooks, locales (i18n), utilities. Peer dependency: ra-core, @minimaltech/ra-core-infra

Backend Packages

PackagePackage NamePortKey FeaturesDependenciesStatus
core@nx/coreN/AShared foundation: DefaultApplication, SoftDeletableRepository, 7 PostgreSQL schemas (55 models), Snowflake ID generator, cross-service auth, CryptoUtility (AES-256-GCM), bootstrap helpers (bootstrapApplication, bootstrapMigration, createAppConfig, createMigrationProcessLoader)N/AProduction
identity@nx/identity3001Authentication & authorization: JWT/Basic auth strategies, user CRUD with atomic creation (user + identifiers + profile + roles), employee management with organizer/merchant mapping, email verification (6-digit code, 10min expiry, rate-limited), password hashing (bcrypt), RBAC with 5 default roles (SUPER_ADMIN 999, ADMIN 998, OPERATOR 997, ORGANIZER_OWNER 899, EMPLOYEE 898)@nx/coreProduction
commerce@nx/commerce3002Product catalog & pricing engine: product aggregates (info, identifiers, variants), dynamic pricing with rule-based evaluation (OVERRIDE/DISCOUNT/MARKUP operators: EQ, NE, GT, GTE, LT, LTE, IN, NIN), multi-merchant support, categories, sale channels, role-based access filtering@nx/core, @nx/asset, @nx/inventory, @nx/search, @nx/t-vanProduction
sale@nx/sale3003Order management & checkout: order lifecycle (DRAFT → PROCESSING → PARTIAL → COMPLETED/CANCELLED), item management with auto-merge for duplicates, checkout validation (non-empty cart, valid items), MQ-Pay event handling for payment status updates, max constraints (9999 qty/item, 100 items/order)@nx/core, @nx/mq-payProduction
inventory@nx/inventoryN/AStock management & purchase orders: multi-location inventory tracking (quantityOnHand, quantityAvailable, quantityReserved), PO lifecycle (DRAFT → PROCESSING → CONFIRMED → COMPLETED), 20+ predefined tracking types (STOCK_IN, SALE, TRANSFER, RETURN, ADJUSTMENT, etc.), Redis-cached tracking type lookups@nx/coreProduction
search@nx/searchN/ATypesense search integration: real-time sync via Debezium CDC (PostgreSQL → Typesense), IGNIS filter to Typesense query conversion (eq, neq, gt, gte, lt, lte, between, inq, nin, and, or), 6 collections (products, organizers, merchants, categories, devices, sale-channels), diagnostic endpoints@nx/coreProduction
asset@nx/assetN/AFile & media storage: dual storage (Minio S3-compatible + local disk), MetaLink entity for metadata tracking (bucketName, objectName, link, mimetype, size, etag, storageType, principalId, principalType), presigned URL generation@nx/coreProduction
invoice@nx/invoiceN/AE-Invoice generation (Vietnam-compliant): invoice types (VAT, Sales, POS, delivery notes, receipts, PIT certificates), XML formatting, digital signature, PDF generation, sequential numbering@nx/core, @nx/iiapi, @nx/t-vanProduction
finance@nx/financeN/AFinancial management & accounting: wallets (CASH, BANK, EWALLET, CREDIT_CARD) with initial/current balance, income/expense transaction tracking, 20 seeded categories, event-driven processing (commerce initialized → create default wallet, payment success → record income, PO received → record expense) via Redis Pub/Sub + BullMQ@nx/coreProduction
payment@nx/paymentN/APayment orchestration layer: webhook configuration management (endpoint registration, event types, retry metadata), payment credential loading/decryption from Configuration table (AES-256-GCM), webhook dispatch with exponential backoff retry, MQ-Pay component initialization with dynamic credential getter@nx/core, @nx/mq-payProduction
signal@nx/signalN/AReal-time WebSocket communication: mandatory ECDH P-256 key exchange + AES-256-GCM encrypted messages, JWT authentication on handshake, REST API for broadcast/room/client messaging, Redis-backed state for cross-instance delivery (single or cluster mode), stateless (no database, no migrations)@nx/coreProduction
gateway@nx/gatewayN/AAPI Gateway: routing, load balancing, circuit breaker, rate limiting@nx/corePlanned

Third-Party Integrations

IntegrationPackage NameDescriptionKey FeaturesExternal Services
mq-pay@nx/mq-payMulti-provider payment systemProviders: SYSTEM (CASH, BANK_TRANSFER), VNPAY_QR_MMS, VNPAY_PHONE_POS, VNPAY_SMART_POS; Transaction lifecycle (NEW 100 → PARTIAL 300 → SETTLED 600 / CANCELLED 505 / BLOCKED 800 / CLOSED 900); Payment attempt types (MAKE_PAYMENT 100, CANCEL_PAYMENT 200, REFUND_PAYMENT 300); BullMQ 3-partition queues (scheduler, confirmation) with 10 concurrent jobs/partition; Event emitter with 11+ event types; AppRegistry singleton pattern (cannot use DI @inject())VNPAY
iiapi@nx/iiapiVNPAY E-Invoice integration (viiAPI)Invoice types: VAT, Sales, POS, internal delivery notes, receipts, PIT certificates; 15 services (VAT invoice, POS VAT invoice, POS sale invoice, invoice management, webhook, OTP); Multi-client registry with OAuth2 token auto-refresh (5min buffer); Request/response via VIIAPIRequestHelper; Test endpoint: https://invoice-api.vnpaytest.vn, Production: https://api.vnpayinvoice.vnVNPAY Invoice
t-van@nx/t-vanVietnam Tax VAN integrationQuery electronic invoices from Tax Authority (CQT); Tax payer info lookup by tax code/ID (4 query types: 00001 Citizen ID, 00003 Tax Code, 00130 ID Tax Payer, 00132 Personal Tax Code); Multi-client registry; Auto-batch splitting for large queries (VNPAY max 10 tax codes/request)CQT (via Viettel, VNPT T-VAN providers)

Infrastructure

Data Stores

ServicePortDatabase/IndexPurposeNotes
PostgreSQL5432N/ARelational database7 schemas, 55 models
Redis6379DB0CacheGeneral-purpose caching
Redis6379DB1BullMQ Queues24 queues (4 systems × 3 partitions × 2 types)
Redis6379DB2Pub/Sub SubscriberEvent subscription channel
Redis6379DB3Pub/Sub PublisherEvent publishing channel
Redis6379DB4WebSocket StateSignal service cross-instance state
Typesense8108N/ASearch engine6 collections: products, merchants, categories, organizers, devices, sale-channels
Minio9000N/AObject storageS3-compatible API, presigned URLs

PostgreSQL Database Schemas

SchemaModel CountDescriptionExample Models
public30Core business entitiesUser, Role, Product, ProductInfo, ProductIdentifier, ProductVariant, Merchant, Organizer, Category, Device, Terminal, SaleChannel, Configuration, Employee, Vendor
pricing7Pricing engineFare, FareRule, Cost, Tax
allocation4Event seating & venuesVenue, Section, Seat, Allocation
inventory8Stock managementInventory, PurchaseOrder, PurchaseOrderItem, InventoryTracking, InventoryTrackingType
sale2Sales ordersSaleOrder, SaleOrderItem
finance3Financial recordsFinanceWallet, FinanceCategory, FinanceTransaction
payment1Payment configurationWebhookConfig
Total557 schemas

BullMQ Queue Systems

SystemQueue TypesPartitionsTotal QueuesPurpose
Commerce236Product sync, catalog updates
Finance236Transaction processing, reconciliation
Inventory236Stock updates, PO processing
Sale236Order fulfillment, payment updates
Total8324

Note: Each queue type has 3 partitions (P01, P02, P03) for load distribution. Default: 10 concurrent jobs per partition.

Event-Driven Architecture

Redis Pub/Sub Channels

ChannelEvent TypePublisherSubscribersPayload
UserOnboardingEventChannels.COMMERCE_INITIALIZEDCommerce Initialized@nx/commerce@nx/finance{ merchantId: string, organizerId: string }
PaymentEventChannels.PAYMENT_SUCCESSPayment Success@nx/mq-pay@nx/sale, @nx/finance{ transactionId: string, amount: number, currency: string, referenceId: string, referenceType: string }
UserOnboardingEventChannels.SELLER_REGISTEREDSeller Registered@nx/identityN/A{ userId: string, email: string, roles: string[] }

MQ-Pay Event System

Event TypeTriggerPayloadSubscribers
mq-pay:transaction.createdTransaction created{ transactionId, amount, currency, provider }@nx/sale
mq-pay:transaction.settledPayment settled{ transactionId, settlementDate }@nx/sale, @nx/finance
mq-pay:transaction.cancelledPayment cancelled{ transactionId, reason }@nx/sale
mq-pay:attempt.createdPayment attempt created{ attemptId, transactionId, type }@nx/sale
mq-pay:attempt.sentPayment request sent{ attemptId, provider, sentAt }@nx/sale
mq-pay:attempt.successPayment successful{ attemptId, transactionId, paidAt }@nx/sale, @nx/finance
mq-pay:attempt.failedPayment failed{ attemptId, errorCode, errorMessage }@nx/sale
mq-pay:attempt.expiredPayment expired{ attemptId, expiredAt }@nx/sale
mq-pay:refund.successRefund successful{ refundId, transactionId, amount }@nx/sale, @nx/finance
mq-pay:refund.failedRefund failed{ refundId, errorCode }@nx/sale

Security

LayerMechanismImplementation
AuthenticationJWT + Basic AuthJWT tokens with configurable expiry (default: 3600s), Basic auth with bcrypt password hashing (cost factor: 6.0.0)
AuthorizationRBAC5 default roles: SUPER_ADMIN (999), ADMIN (998), OPERATOR (997), ORGANIZER_OWNER (899), EMPLOYEE (898). Role-based middleware via @authenticate decorator
WebSocket EncryptionECDH P-256 + AES-256-GCMMandatory key exchange on handshake, per-client shared keys, encrypted message envelopes { event: 'encrypted', data: { iv, ct } }
Credential StorageAES-256-GCM EncryptionPayment credentials encrypted in Configuration table using CryptoUtility, decrypted on-the-fly via PaymentConfigurationService
Password HashingbcryptAdaptive hashing function with salt rounds (bcrypt 6.0.0)
CORSHono CORS MiddlewareConfigured in DefaultApplication with environment-based allowed origins
Rate LimitingEmail Verification60s cooldown, 5 resends/day, 15min lockout after 3 failed attempts

Development Setup

Prerequisites

ToolVersionPurpose
Bun>=1.3.8Runtime, package manager, build tool
PostgreSQL14+Primary database
Redis6+Cache, queues, pub/sub, WebSocket state
TypesenseLatestSearch engine (optional for search features)
MinioLatestObject storage (optional for asset features)
Node.js18+Tauri tooling, some frontend build tools
RustLatestTauri backend compilation (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.development

Build Commands

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)

Linting & Testing

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.js

Git 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 packages

Environment Configuration

dotenv-flow Strategy

Each package uses dotenv-flow for environment-specific configuration:

FilePurposeGit Tracked
.env.exampleTemplate with all variablesYes
.env.developmentDevelopment settingsNo (copy from example)
.env.testTest environmentNo (copy from example)
.env.localLocal overrides (highest priority)No

Core Environment Variables

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>

Project Structure

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 });
  }
}

Component Structure

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);
  }
}

Application Lifecycle

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 (from @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 with 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>;

Backend Packages

PackageDocumentationDescription
CoreDocumentationShared foundation: base classes, 7 DB schemas, utilities
IdentityDocumentationAuthentication, RBAC, email verification
CommerceDocumentationProducts, pricing engine, merchants
SaleDocumentationOrders, checkout, MQ-Pay integration
PaymentDocumentationPayment orchestration, webhook dispatch
SignalDocumentationWebSocket communication, ECDH encryption
AssetDocumentationFile storage, Minio S3
InvoiceDocumentationE-Invoice generation, PDF
GatewayDocumentationAPI Gateway (planned)

Third-Party Integrations

IntegrationDocumentationDescription
MQ-PayDocumentationMulti-provider payment system (VNPAY, Cash)
IIAPIDocumentationVNPAY E-Invoice integration
T-VANDocumentationVietnam Tax VAN connector

Frontend Applications

ApplicationDocumentationDescription
ClientDocumentationAdmin dashboard (28 screens)
POS DesktopRenderer / MainTauri desktop app
Admin UI KitDocumentationShared component library

Next Steps

For New Developers

  1. Set up local environment: Install prerequisites (Bun, PostgreSQL, Redis)
  2. Build the monorepo: Run make install && make build
  3. Explore Core package: Read Core Documentation to understand shared infrastructure
  4. Run a service: Start Identity service with make dev-identity, explore Swagger at http://localhost:3001/docs
  5. Read IGNIS patterns: Study dependency injection, component structure, controller factory examples above

For Integration Developers

  1. Review MQ-Pay integration: MQ-Pay Documentation for payment flow
  2. Understand event system: Study Redis Pub/Sub channels and BullMQ queue architecture
  3. Implement webhooks: Use @nx/payment webhook dispatcher with exponential backoff retry
  4. Test with sandbox: Use VNPAY test endpoints from @nx/iiapi and @nx/t-van integrations

For Frontend Developers

  1. Set up client app: Run make dev-client and explore 28 screen modules
  2. Use Admin UI Kit: Import components from @nx-app/admin-ui-kit (38 shadcn components)
  3. Integrate with backend: Use TanStack Query for API calls, Redux Toolkit for state management
  4. Build POS desktop app: Explore Tauri architecture in sale-main and sale-renderer

For DevOps Engineers

  1. Review infrastructure: PostgreSQL 7 schemas, Redis 5 databases, Typesense, Minio
  2. Set up Docker Compose: Use infrastructure/deployments/develop/ for local stack
  3. Configure environments: Study .env.example files across packages
  4. Monitor queues: Set up BullMQ dashboard for 24 queue monitoring
  5. Deploy services: Each package has Dockerfile, deploy independently or as monolith

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.