This commit is contained in:
Dhananjaya99
2026-07-18 23:42:58 +05:30
parent 80b130dffb
commit 92c4b14a6c
55 changed files with 8815 additions and 43 deletions
+9 -6
View File
@@ -194,7 +194,7 @@ One base currency; invoicing/3-way match in Accounting (GRN carries data); users
| FR-X-05 | No editing/deleting confirmed/posted transactions; corrections via reversing entries. | M |
## B.4 Data Model (summary)
Key entities and relationships are enumerated in **Part C**. The commitment: Item, UOM/UOMConversion, Category, SubCategory, Brand, ItemType, ProductConfig, Vendor, Warehouse/Bin, ItemReorder, Requisition(+Line), RFQ(+Line)/VendorQuotation, PurchaseOrder(+Line), GRN(+Line), PurchaseReturn(+Line), StockLayer (FIFO), StockLedger (immutable), Batch, Serial, StockTransfer(+Line), StockAdjustment(+Line), StockCount(+Line), User, ReasonCode, NumberSequence, AuditLog, JournalEntryStub, and reserved RBAC (Role, Permission, UserRole, RolePermission).
Key entities and relationships are enumerated in **Part C**. The commitment: Item, UOM/UOMConversion, Category, SubCategory, Brand, ItemType, ProductConfig, Vendor, Warehouse/Bin, ItemReorder, Requisition(+Line), RFQ(+Line)/VendorQuotation, PurchaseOrder(+Line), GRN(+Line), PurchaseReturn(+Line), StockLayer (FIFO), StockLedger (immutable), Batch, Serial, StockTransfer(+Line), StockAdjustment(+Line), StockCount(+Line), User, ReasonCode, NumberSequence, AuditLog, JournalEntryStub, and RBAC for sidebar visibility (Role, NavItem, SubNavItem, Permission, RolePermission — see C.8; per-endpoint enforcement still deferred).
## B.5 External Interfaces
UI: responsive; count/pick screens handheld-friendly; status badges; mandatory-field validation. Hardware: barcode/QR (designed-for). Software: relational DB with transactional integrity + row locking; internal service interfaces/events for Phase-2+ modules.
@@ -348,13 +348,16 @@ AUDIT_LOG(audit_id PK, user_id FK→USER, entity_type, entity_id, action, change
JOURNAL_ENTRY_STUB(journal_id PK, source_doc_type, source_doc_id, debit_account, credit_account, amount)
```
## C.8 Reserved (RBAC — deferred, schema placeholder only)
## C.8 RBAC — sidebar-visibility only (implemented 2026-07-18); per-endpoint enforcement still deferred
```
ROLE(role_id PK, name)
PERMISSION(permission_id PK, code)
USER_ROLE(user_id FK→USER, role_id FK→ROLE)
ROLE(role_id PK, auth_role_id [GUID, unique] → AuthHex Role, code, name, is_system_role, status, created_at, updated_at, row_version) -- local shadow/projection of AuthHex's Role, same pattern as USER
NAV_ITEM(nav_item_id PK, code, label, icon, href, sort_order, status) -- top-level sidebar entry; seeded to match the frontend
SUB_NAV_ITEM(sub_nav_item_id PK, nav_item_id FK→NAV_ITEM, code, label, icon, href, sort_order, status)
PERMISSION(permission_id PK, code, nav_item_id FK→NAV_ITEM [nullable], sub_nav_item_id FK→SUB_NAV_ITEM [nullable]) -- exactly one of the two FKs is set
ROLE_PERMISSION(role_id FK→ROLE, permission_id FK→PERMISSION)
USER(..., role_id FK→ROLE [nullable]) -- added to the existing USER shadow (see C.7)
```
Note: `USER_ROLE` from the original placeholder sketch was dropped — a user has at most one role (`USER.role_id`), matching AuthHex's own `User.RoleId` being a single scalar FK, not a many-to-many.
## C.9 Modeling notes (load-bearing)
- **Item types are a dropdown, not a relationship.** `ITEM_TYPE` (Color, Size, Material) exists **only** to populate the frontend item-builder's dropdown via `GET /item-types`. Nothing references it and it references nothing — there is no value table and no join to `ITEM`. The builder cross-products the checked types into **one standalone item per combination**; the chosen values (Red, S, M) are encoded by the **client** into the generated SKU (`BL-0002` for one type, `BL-100-0003` for two) and the server only checks that SKU for uniqueness. **The item list is the record of what was built.** This is not a product-variation model: there is no parent-product entity and no variant hierarchy.
@@ -366,7 +369,7 @@ ROLE_PERMISSION(role_id FK→ROLE, permission_id FK→PERMISSION)
- **In-transit + cost-preserving transfer.** `STOCK_TRANSFER` holds `src`/`dest` warehouse; dispatch consumes source layers into in-transit, receive creates the destination layer at the **inherited** source cost.
- **FEFO ≠ FIFO.** FIFO governs *costing*; FEFO governs *physical picking* of perishables via `BATCH.expiry_date`.
- **External IdP + shadow user.** Authentication is delegated to **AuthHex** (RS256, issuer `AuthHex`/audience `AuthHexClient`, static public key). `USER` is a **local shadow** of AuthHex identities: `auth_user_id` (GUID from the token's `UserId` claim) is JIT-mapped to the local `int` `user_id` that every `created_by`/`requested_by`/`AUDIT_LOG.user_id`/`STOCK_LEDGER.user_id` FK references — no FK type change. A door policy admits only ERP `UserType`/`Role` holders.
- **Reserved RBAC.** Role/Permission/UserRole/RolePermission exist for schema-completeness only; only `USER` is live (audit stamp). AuthHex's `RoleCode`/`UserTypeCode` claims drive the door gate today; per-endpoint RBAC is future work.
- **RBAC — sidebar visibility, not endpoint enforcement (2026-07-18).** `Role`/`NavItem`/`SubNavItem`/`Permission`/`RolePermission` are now live tables backing Role CRUD (`RolesController`) and a permission-assignment UI. AuthHex remains the source of truth for `Role` identity (Guid PK, referenced by its JWT `RoleId`/`RoleCode` claims); ERPCore's `Role` is a **local shadow synced on write**`RolesController` calls AuthHex's new `/api/role` functions first, then mirrors the result into the local int-keyed row (`auth_role_id` maps the two), exactly like `USER`/`auth_user_id`. `GET /api/v1/auth/me` resolves the caller's `RoleCode` claim to its local `Role`, joins `RolePermission`, and returns the permitted `NavItem`/`SubNavItem` codes for the frontend to filter its sidebar by. **This is deliberately UI-only**: no endpoint in this API (including the new Role/User/Nav ones) gained an authorization check from this work — AR-01 in `02-SECURITY.md` is unchanged, and per-endpoint RBAC remains future work (Part D there).
- **Reorder alerts are a query**, not an entity — computed from `ITEM_REORDER` vs available. Add a table only if alert history is required.
## C.10 Entity → implementation mapping