StockLedger Retail is a retail inventory engine built on a ledger-based approach: every stock movement is recorded as a StockTransaction, and CurrentStock is derived from approved transactions.
The project targets real retail scenarios — multi-warehouse stock, procurement, POS integration, and future inventory decision support.
InventoryDocument (Draft → Approved)
↓
InventoryDocumentLine
↓
StockTransaction ← source of truth for audit
↓
CurrentStock ← fast lookup
Golden rule: never update CurrentStock without a StockTransaction.
| Phase | Scope | Status |
|---|---|---|
| Phase 1 | Product, SKU, Warehouse, Stock In/Out, Adjustment, Current Stock, Stock History, POS integration | ✅ Done |
| Phase 2 | Transfer, Stock Count, Update Draft document | ✅ Done |
| Phase 3 | Supplier, Purchase Order, Goods Receipt, Analytics dashboard | ✅ Done |
| Sprint 2 | Concurrency (xmin), WAC valuation, stock reconciliation | ✅ Done |
| Omni-channel | Multi-warehouse ATP, allocate warehouse, stock reservation | ✅ Done |
| Multi-brand (MB-1→4) | Brand entity, transfer policy, in-transit transfer, brand-scoped insights & fulfillment, scope headers | ✅ Done |
| RBAC | Email users, permission groups in DB, teams, document authorization | ✅ Done |
| Login | POST /api/auth/login, frontend /login, JWT Bearer + refresh token |
✅ Done |
| Valuation | CostPrice on SKU; ProductCostHistory; cost history report API | ✅ Done |
| Insights | Executive summary, 7 analytics tabs (dead stock, velocity, transfer, markdown, promotion/reorder risk, trend), pricing-aware DTOs, snapshot cache, drill-down CTAs | ✅ Done |
| Reports | Inventory value, NXT, near-expiry lots, lot stocks, cost history | ✅ Done |
| Stock reservations | POS/OMS holds — list & manual release API + UI | ✅ Done |
| Approval workflow | 2-step approval for high-value inventory documents & POs | ✅ Done |
| Lot / expiry | StockLot, LotStock, FEFO (TrackLotExpiry on SKU) |
✅ Done |
| Transfer policy admin | CRUD API + admin UI | ✅ Done |
| Markdown policy | Per-brand markdown tiers, policy engine, insights CTAs, admin UI | ✅ Done |
| Admin UI | Brands, users, teams, permissions, transfer policies, operations | ✅ Done |
| Demo seed | Optional sample multi-brand data (Seed:Fb:Enabled) |
✅ Done |
| Warehouse scope | Per-user warehouse assignments; filtered lists & mutations on PO/GR/reports/stock | ✅ Done |
| Pricing authority | Shared PricingCalculator; BE validates before-VAT; contract tests BE+FE |
✅ Done |
| Ops readiness | /health, /health/ready, rollout smoke scripts, integration tests PO→GR→Stock-in |
✅ Done |
| AI Copilot | Natural-language Q&A on insight APIs | 🔜 Planned |
- Brand — multi-brand master (
Code,Name,Status); scopes products, SKUs, and warehouses - Product — parent product (code, name, brand text, optional
BrandId, category) - ProductVariant (SKU) — actual inventory unit; optional
BrandId; SKU unique per(BrandId, Sku); optionalTrackLotExpiryfor batch/FEFO - StockLot / LotStock — lot code, expiry date, quantity per warehouse (when lot tracking enabled)
- Warehouse — DC, Store, Sub-warehouse, Defect, Return, InTransit; hierarchy via
ParentWarehouseId; optionalBrandId,RegionCode,FulfillmentPriority - Supplier — procurement partner master data
- TransferPolicy — rules for cross-brand transfers
All documents start as Draft; stock changes only after Approve.
| Type | API route | Effect on stock |
|---|---|---|
| Stock In | POST /api/inventory-documents/stock-in |
+IN |
| Stock Out | POST /api/inventory-documents/stock-out |
-OUT |
| Adjustment | POST /api/inventory-documents/adjustment |
+/- ADJUSTMENT |
| Transfer | POST /api/inventory-documents/transfer |
Ship on approve: OUT source + IN in-transit |
| Stock Count | POST /api/inventory-documents/stock-count |
COUNT_ADJUSTMENT if variance ≠ 0 |
Transfer (in-transit): POST .../approve ships to in-transit warehouse; POST .../{id}/receive-transfer completes receipt at destination.
Additional: PUT /api/inventory-documents/{id} (update draft), POST .../submit-for-approval, POST .../approve, POST .../receive-transfer, POST .../cancel.
Approval workflow: documents above ApprovalWorkflow:DocumentValueThreshold (default 10M VND) require submit-for-approval then two approval steps before stock is posted.
Supplier → Purchase Order (Draft → Submitted)
↓
Goods Receipt (Draft → Approved)
↓
Stock In document (auto-created & approved)
↓
CurrentStock updated; PO received qty updated
POST /api/integration/sales/check-availability— read-only stock check (hỗ trợsafetyStockBuffer)POST /api/integration/sales/confirm-sale— create + approve Stock Out (idempotent theosourceSystem+orderReference)POST /api/integration/sales/batch-confirm-sales— đồng bộ hàng loạt đơn bán (hỗ trợ POS offline đồng bộ khi có kết nối lại)POST /api/integration/sales/confirm-return— create + approve Stock In (idempotent theosourceSystem+returnReference)POST /api/integration/sales/check-availability-multi-warehouse— ATP across warehouses (hỗ trợbrandId,regionCode,safetyStockBuffer)POST /api/integration/sales/allocate-warehouse— auto-select ship-from warehouse (Store-first / DC-first)GET /api/integration/stocks/delta— Delta sync tồn kho theo timestampsinceUtc(dành cho OMS/Ecom/ERP poll định kỳ)POST /api/integration/stocks/webhooks/test— bắn thử nghiệm webhook thông báo biến động tồn kho (stock.changed)
Optional scope headers (RBAC-lite): X-Brand-Id, X-Warehouse-Ids, X-Region-Code.
Warehouse scope (DB): assign warehouses per user in Admin → Users; clerks see only their store(s). See docs/RBAC.md and docs/BusinessRules.vi.md (BR1307–BR1308).
- Login:
POST /api/auth/login(stub:admin/1234) → frontend session; API calls sendX-User-Email - Identify users via header
X-User-Email(registered inapp_users) - Permission groups:
SYSTEM_ADMIN,TEAM_LEADER,WAREHOUSE_CLERK,VIEWER - Team leaders can update/cancel/approve documents created by team members
- Admin APIs:
/api/admin/users,/api/admin/permissions,/api/admin/teams,GET /api/auth/me
See docs/RBAC.md.
GET/POST /api/brands,GET/PUT /api/brands/{id}GET/POST/PUT /api/admin/transfer-policies— cross-brand transfer rulesGET/POST/PUT /api/admin/markdown-policies— per-brand markdown / discount rulesGET/PUT/POST /api/admin/operations— background jobs (reconciliation, insight refresh)
GET /api/reports/inventory-value— on-hand value by SKU/warehouseGET /api/reports/nxt— opening / in / out / closing for a date rangeGET /api/reports/near-expiry-lots— lots expiring within N daysGET /api/reports/lot-stocks— lot balances by warehouseGET /api/reports/cost-history— SKU cost history
GET /api/stock-reservations— list POS/OMS holdsPOST /api/stock-reservations/{id}/release— manual release
Pricing-aware decision support with executive KPIs, seven analytics views, rule-based recommendation cards, and MarkdownPolicyEngine for per-brand discount suggestions. See docs/Insights.md (EN) and docs/Insights.vi.md (VI). Policy config: docs/MarkdownPolicy.md.
GET /api/inventory-insights/executive-summary— aggregated KPIs for current scopeGET /api/inventory-insights/dead-stock— no outbound in N daysGET /api/inventory-insights/sales-velocity— outbound rate and cover daysGET /api/inventory-insights/transfer-suggestions— surplus → deficit warehouse pairsGET /api/inventory-insights/markdown-candidates— slow movers with margin/value contextGET /api/inventory-insights/promotion-risk— promotion price vs velocity/coverGET /api/inventory-insights/reorder-risk— low cover + open PO/GR pipelineGET /api/inventory-insights/trend-summary— period-over-period inventory deltas
Common filters: warehouseId, brandId, regionCode, lookbackDays, daysWithoutOutbound
GET /api/analytics/summary— totals, open POs, pending GRsGET /api/analytics/stock-by-warehouseGET /api/analytics/movements— in/out over date rangeGET /api/analytics/low-stock— SKUs below threshold
Bilingual UI (VI / EN): login, dashboard, products, SKUs, warehouses, suppliers, purchase orders, goods receipts, inventory documents (incl. receive-transfer & multi-step approval), current stock, stock history, insights (executive summary + 7 tabs, drill-down CTAs), reports, stock reservations, admin (brands, users, teams, permissions, transfer policies, operations).
Default locale: vi — http://localhost:3000/vi
Dev tip: if Next.js shows Internal Server Error after npm run build while dev is running, run npm run dev:fresh in frontend/ (clears .next cache).
Clean Architecture layers:
host/StockLedgerRetail.HttpApi.Host ← ASP.NET host
src/StockLedgerRetail.HttpApi ← Controllers
src/StockLedgerRetail.Application ← App services, StockLedgerService
src/StockLedgerRetail.Application.Contracts
src/StockLedgerRetail.Domain ← Entities, repository interfaces
src/StockLedgerRetail.Domain.Shared ← Enums
src/StockLedgerRetail.EntityFrameworkCore
frontend/ ← Next.js 15 + TypeScript + Tailwind
| Layer | Stack |
|---|---|
| Backend | .NET 10, ASP.NET Core Web API, EF Core |
| Database | PostgreSQL |
| Frontend | Next.js 15, TypeScript, Tailwind CSS, next-intl, TanStack Query |
| API docs | Swagger — http://localhost:5270/swagger |
Install all required items below. After installing, run the Verify commands to confirm.
| # | Software | Recommended version | Used for | Download |
|---|---|---|---|---|
| 1 | .NET SDK | 10.x (matches net10.0 in this repo) |
Build & run API | https://dotnet.microsoft.com/download |
| 2 | Node.js | 20 LTS or newer | Next.js frontend | https://nodejs.org/ |
| 3 | PostgreSQL | 14+ (16 recommended) | Database | https://www.postgresql.org/download/ |
| 4 | Git | Latest | Clone repo | https://git-scm.com/downloads |
| 5 | EF Core CLI | Same major as EF in the project (~10.x) | Database migrations | See install step below |
Optional (IDE): Visual Studio 2022+, VS Code, or Rider.
dotnet --version # e.g. 10.0.x
node --version # e.g. v20.x
npm --version
psql --version # or use pgAdmin
git --versiondotnet tool install --global dotnet-ef
# or update:
dotnet tool update --global dotnet-ef
dotnet ef --versionAfter installing PostgreSQL, create an empty database (any name, e.g. stockledger_retail):
CREATE DATABASE stockledger_retail;Note your Host, Port, Username, and Password — you will need them when configuring the API.
| File | Purpose |
|---|---|
host/StockLedgerRetail.HttpApi.Host/appsettings.json |
PostgreSQL connection string (ConnectionStrings:Default) |
frontend/.env.local |
API URL for the UI (copy from .env.local.example) |
Connection string (example):
"ConnectionStrings": {
"Default": "Host=localhost;Port=5432;Database=stockledger_retail;Username=postgres;Password=YOUR_PASSWORD"
}Frontend (frontend/.env.local):
NEXT_PUBLIC_API_URL=http://localhost:5270Do not commit real passwords to Git. You can use
appsettings.Development.local.json(already in.gitignore) for local secrets.
- Run commands from the repository root (folders
host,src,frontend). - If your user path contains
(, always wrap paths in quotes when usingcd:cd "C:\Users\...\stockledger-retail" - If
npmis blocked by execution policy, use:npm.cmd run dev - Run the API:
dotnet run --project host\StockLedgerRetail.HttpApi.Host --launch-profile http
1. Clone & enter the project
git clone https://github.com/Cuong2000aa/stockledger-retail.git
cd stockledger-retail2. Configure the database — edit appsettings.json (or a local override) with your PostgreSQL connection string.
3. Apply migrations (run from repository root):
dotnet ef database update \
--project src/StockLedgerRetail.EntityFrameworkCore/StockLedgerRetail.EntityFrameworkCore.csproj \
--startup-project host/StockLedgerRetail.HttpApi.Host/StockLedgerRetail.HttpApi.Host.csprojOr from the EF project folder:
cd src/StockLedgerRetail.EntityFrameworkCore
dotnet ef database update --project . --startup-project ../../host/StockLedgerRetail.HttpApi.Host/StockLedgerRetail.HttpApi.Host.csproj
cd ../..4. Run the API (terminal 1)
dotnet run --project host/StockLedgerRetail.HttpApi.Host --launch-profile httpAPI: http://localhost:5270 · Swagger: http://localhost:5270/swagger
5. Run the frontend (terminal 2)
cd frontend
cp .env.local.example .env.local # Windows: copy .env.local.example .env.local
npm install
npm run devUI: http://localhost:3000/vi (default locale is Vietnamese; use /en for English)
6. Optional demo data — on first API start, Seed:Fb:Enabled: true seeds sample brands, warehouses, SKUs, stock, and near-expiry lots. To load manually after migrations:
.\scripts\seed-fnb-data.ps1Set Seed:Fb:Enabled: false in production.
7. Verify (optional)
.\scripts\rollout-smoke.ps1
dotnet test tests/StockLedgerRetail.Integration.TestsAfter pulling new API code, restart the API host so new endpoints (e.g.
/health,/api/reports/*) are available.
dotnet run --project host/StockLedgerRetail.HttpApi.Host --launch-profile httpConfigure the connection string in host/StockLedgerRetail.HttpApi.Host/appsettings.json (or a *.local.json file).
Apply migrations (from repo root):
dotnet ef database update \
--project src/StockLedgerRetail.EntityFrameworkCore/StockLedgerRetail.EntityFrameworkCore.csproj \
--startup-project host/StockLedgerRetail.HttpApi.Host/StockLedgerRetail.HttpApi.Host.csprojcd frontend
npm install
npm run devSet NEXT_PUBLIC_API_URL=http://localhost:5270 in frontend/.env.local if needed.
| File | Audience | Content |
|---|---|---|
| docs/Development.md | Developer / DevOps | Tests, smoke scripts, health, scope service, pricing contract, migrations |
| docs/RBAC.md | Admin / Dev | Email RBAC, teams, warehouse assignments |
| docs/MultiBrand.md | Dev / BA | Multi-brand phases, scope headers (EN) |
| docs/MultiBrand.vi.md | BA / User | Đa thương hiệu (VI) |
| docs/UseCases.md | BA / User | Use cases UC001–UC016 (business flows) |
| docs/BusinessRules.md | BA / User | Business rules (EN) |
| docs/BusinessRules.vi.md | User / BA | Quy tắc nghiệp vụ (VI) |
| docs/Entities.md | Dev | Entity dictionary (EN) |
| docs/Entities.vn.md | BA | Entities_VN (VI) |
| docs/ERD.md | Dev | Database tables & relationships |
| docs/InventoryDomain.md | Dev / BA | Domain overview |
| docs/MarkdownPolicy.md | Dev / BA | Markdown policy engine (EN) |
| docs/MarkdownPolicy.vi.md | User / BA | Chính sách giảm giá (VI) |
| docs/Insights.md | Dev / BA | Inventory insights (EN) |
| docs/Insights.vi.md | User / BA | Phân tích tồn kho (VI) |
Items below are not done yet (or only partially done). See the Implementation Status table for what is already shipped.
| Item | Notes |
|---|---|
| Docker deployment | docker-compose for API + PostgreSQL + frontend |
🚧 Active development — Core inventory, omni-channel, multi-brand, RBAC, reports, lot/expiry, approval workflow, JWT auth, and admin UI are done. Next: OAuth/SSO, AI copilot, Docker full stack.