# Backend Architecture Design: Rules, Data Flows & Modularization

## 📋 Table of Contents

1. [System Modularization Strategy](#system-modularization-strategy)
2. [Business Rules by Module](#business-rules-by-module)
3. [Data Flow Patterns](#data-flow-patterns)
4. [Transaction Boundaries](#transaction-boundaries)
5. [Validation Layers](#validation-layers)
6. [State Management](#state-management)

---

## 🏗️ System Modularization Strategy

### Module Structure Overview

```
modules/
├── auth/              # Authentication & Authorization
├── products/          # Product Management
├── inventory/         # Inventory Management (dual-layer)
├── categories/        # Category Management
├── pricing/           # Price List & Product Pricing
├── taxes/             # Tax Management
├── discounts/         # Discounts & Promotions
├── sales/             # Sales & POS Operations
├── payments/          # Payment Processing
├── customers/         # Customer Management (optional)
├── procurement/       # Purchase Orders & GRNs
├── production/        # BOM & Production
├── returns/           # Returns & Credit Notes
├── shifts/            # Shift & Cash Management
├── fiscal/            # KRA eTIMS Integration
└── reports/           # Reporting & Analytics
```

### Module Independence Principles

1. **Each module is self-contained:**
   - Own models (or clearly defined dependencies)
   - Own service layer (business logic)
   - Own controller layer (request handling)
   - Own validation rules
   - Own routes

2. **Inter-module communication:**
   - Through service layer calls (not direct model access)
   - Service-to-service communication
   - Events/hooks for side effects (optional future enhancement)

3. **Shared concerns:**
   - Database connection (models/index.js)
   - Authentication middleware
   - Error handling middleware
   - Response utilities
   - Logging utilities

---

## 📐 Business Rules by Module

### 1. Authentication Module (`auth`)

**Purpose:** User authentication, authorization, session management

**Business Rules:**
- Users must authenticate before accessing protected endpoints
- Roles: `cashier` → `manager` → `system_admin` (hierarchical permissions)
- Cashiers can only access POS functions
- Managers can access reports, inventory adjustments, price changes
- System admins have full access
- Passwords must be hashed (never stored plain text)
- PIN codes are optional for quick POS login
- JWT tokens expire after configured time
- Last login timestamp updated on successful authentication

**Dependencies:**
- User model
- SystemLog model (for audit trail)

**Data Flow:**
```
Login Request → Validate Credentials → Generate JWT → Return Token + User Info
```

---

### 2. Products Module (`products`)

**Purpose:** Product management, variants, product data

**Business Rules:**
- Products must have: name, product_type (FG/RM), SKU (optional but unique if provided)
- Product variants are optional (null variant_id means non-variant product)
- Variant attributes stored as JSON (flexible structure)
- Product can belong to multiple categories (via ProductCategory junction)
- One primary category per product (is_primary flag)
- Product can have tax_category_id OR use default_vat_rate (backward compatibility)
- Product description, default_vat_rate are optional
- Products can be active/inactive (soft delete via flag)
- SKU uniqueness enforced at product and variant level separately

**Dependencies:**
- Product, ProductVariant models
- Category, ProductCategory models (for categorization)
- TaxCategory model (for tax assignment)

**Data Flow:**
```
Create Product → Validate SKU uniqueness → Create Product → Create Variants (if any) → Link Categories → Return Product
```

---

### 3. Categories Module (`categories`)

**Purpose:** Product category management (hierarchical)

**Business Rules:**
- Categories can have parent categories (hierarchical structure)
- Root categories have parent_id = null
- Category slug must be unique (for URL-friendly identifiers)
- Categories can have images, descriptions, sort_order
- Products can be in multiple categories
- Each product must have exactly one primary category
- Category deletion: cascade delete ProductCategory links, but warn if products exist

**Dependencies:**
- Category model (self-referential)
- ProductCategory model (junction table)

**Data Flow:**
```
Create Category → Validate slug uniqueness → Set parent (if provided) → Return Category
Assign Product to Category → Check if primary exists → Create ProductCategory → Return
```

---

### 4. Pricing Module (`pricing`)

**Purpose:** Price list management, product pricing

**Business Rules:**
- Multiple price lists can exist (retail, wholesale, B2B, customer-specific)
- Only one default price list (is_default = true)
- Products can have prices in multiple price lists
- Prices can be at product level OR variant level (variant_id can be null)
- Prices have effective dates (effective_from, effective_to)
- Only one active price per product/variant/price_list at any given time
- Quantity-based pricing: min_quantity and max_quantity determine tier
- Price lookup order: variant price → product price → default price list
- When customer has price_list_id, use that price list first

**Dependencies:**
- PriceList model
- ProductPrice model
- Product, ProductVariant models
- Customer model (for customer-specific pricing)

**Data Flow:**
```
Price Lookup Request → Get Customer Price List (if customer) → Get Product/Variant Price in Price List → Check Effective Dates → Return Price
Create Price → Validate effective date overlap → Deactivate conflicting prices → Create new price → Return
```

---

### 5. Taxes Module (`taxes`)

**Purpose:** Tax rate management, tax categories, exemptions

**Business Rules:**
- Tax rates are system-wide (e.g., VAT 16%, Excise 8%)
- Tax categories link to tax rates (e.g., "Standard Rate" → VAT 16%)
- Products can have tax_category_id (inherits tax rate from category)
- Tax exemptions override product tax category
- Exemptions can be: customer-specific, product-specific, or both
- Exemptions have effective dates (can expire)
- When calculating tax: Check exemption first → Use product tax_category → Use default_vat_rate (legacy)
- Tax calculation happens at SaleItem level (each item can have different tax)

**Dependencies:**
- TaxRate, TaxCategory, TaxExemption models
- Product model (for product exemptions)
- Customer model (for customer exemptions)

**Data Flow:**
```
Tax Calculation Request → Check TaxExemption (customer + product) → Get TaxCategory from Product → Get TaxRate from TaxCategory → Calculate Tax → Return
```

---

### 6. Discounts Module (`discounts`)

**Purpose:** Discount codes, promotions, discount rules

**Business Rules:**
- Discounts have codes (optional, but must be unique if provided)
- Discount types: PERCENTAGE, FIXED_AMOUNT, BUY_X_GET_Y
- Discount rules define scope: PRODUCT, CATEGORY, CUSTOMER, or ALL
- Multiple rules per discount (can combine: product + category)
- Discounts have minimum purchase amount requirement
- Maximum discount amount limits the discount (e.g., 20% off max $50)
- Effective dates control when discount is active
- Usage limits: max_uses_per_customer, max_total_uses
- Usage tracking: usage_count incremented on each application
- Discount validation: Check dates → Check usage limits → Check minimum purchase → Check rules → Apply discount

**Dependencies:**
- Discount, DiscountRule models
- Product, Category, Customer models (via DiscountRule)

**Data Flow:**
```
Apply Discount Request → Validate Discount (dates, usage, rules) → Check Sale Items Match Rules → Calculate Discount Amount → Apply to Sale → Increment Usage Count → Return
```

---

### 7. Inventory Module (`inventory`)

**Purpose:** Dual-layer inventory management (quantity + UID)

**Business Rules:**
- **Layer 1 (Inventory):** Quantity-based, one record per product/variant combination
- **Layer 2 (InventoryItem):** UID-based, one record per physical unit
- Both layers must stay in sync (via InventoryMovement)
- Inventory quantity = count of InventoryItems with status IN_STOCK
- InventoryItems can be: IN_STOCK, RESERVED, SOLD, RETURNED, DAMAGED, SCRAPPED
- InventoryItems have UID (unique barcode/QR code)
- Every inventory change must create InventoryMovement record
- Reorder level alerts when quantity < reorder_level
- Can't sell more than available quantity (check both layers)
- Inventory adjustments require manager or admin role
- All movements are audit-trailed (can't delete movements)

**Dependencies:**
- Inventory, InventoryItem, InventoryMovement models
- Product, ProductVariant models

**Data Flow:**
```
Stock Addition (GRN/Production) → Create InventoryItems with UIDs → Update Inventory quantity → Create InventoryMovement records → Return
Stock Sale → Check available quantity → Reserve InventoryItems (status RESERVED) → Update Inventory quantity → Create InventoryMovement → Mark items SOLD after payment
Stock Return → Validate original sale → Change InventoryItem status to RETURNED → Update Inventory quantity → Create InventoryMovement → Return
```

---

### 8. Sales Module (`sales`)

**Purpose:** Sales transactions, POS operations

**Business Rules:**
- Sales can be POS (walk-in) or INVOICE (B2B)
- Sales require: user_id (cashier), shift_id (optional but recommended)
- Customer is optional (customer_id can be null for walk-ins)
- Sale status: DRAFT → PAID → (CANCELLED)
- SaleItems link to products, variants, and optionally inventory_item_id (for UID traceability)
- SaleItems store unit_price at time of sale (price snapshot)
- SaleItems have vat_rate (tax rate at time of sale)
- Sale totals: subtotal (sum of line items), vat (sum of taxes), total (subtotal + vat)
- Invoice numbers are auto-generated if not provided (unique)
- Sales can't be deleted (only cancelled) - audit requirement
- Sale can have multiple payments (partial payments allowed)
- Sale is PAID when sum of payments >= total
- Discounts applied at sale level, distributed to items

**Dependencies:**
- Sale, SaleItem models
- Product, ProductVariant, InventoryItem models
- Customer model (optional)
- Shift model (optional)
- Payment, Discount models

**Data Flow:**
```
Create Sale → Validate inventory availability → Create SaleItems → Reserve inventory → Calculate totals (with discounts, taxes) → Save Sale → Return
Add Payment → Update payment status → Check if sale is fully paid → Update sale status to PAID → Finalize inventory (mark items SOLD) → Return
```

---

### 9. Payments Module (`payments`)

**Purpose:** Payment processing, multiple payment methods

**Business Rules:**
- Payments are independent records (one sale can have many payments)
- Payment providers: PAYSTACK, CASH, MOBILE, BANK
- Cash payments: reference is null
- Electronic payments: reference stores transaction ID
- Payment status: PENDING → SUCCESS → (FAILED)
- Payment amount can't exceed remaining sale balance
- paid_at timestamp set when status changes to SUCCESS
- Payment failure doesn't affect sale (can retry or use different method)
- Total payments can exceed sale total (for tips/rounding)

**Dependencies:**
- Payment model
- Sale model

**Data Flow:**
```
Create Payment → Validate sale exists → Check payment amount <= remaining balance → Create payment (PENDING) → Process payment (external API if needed) → Update status → Update paid_at → Return
```

---

### 10. Procurement Module (`procurement`)

**Purpose:** Purchase orders, GRNs, vendor management

**Business Rules:**
- Vendors can be REGISTERED or OPEN_MARKET
- Purchase orders are optional (GRN can exist without PO)
- PO status: DRAFT → CONFIRMED → CLOSED
- GRN records goods received (can reference PO or be standalone)
- GRN items add stock to inventory
- GRN items generate InventoryItems with UIDs
- GRN items update Inventory quantity
- GRN items create InventoryMovement records (reason: GRN)
- Vendor_id can be null in GRN (for open-market purchases)
- Unit costs stored in GRNItems for inventory valuation

**Dependencies:**
- Vendor, PurchaseOrder, GRN, GRNItem models
- Product, ProductVariant, Inventory, InventoryItem, InventoryMovement models

**Data Flow:**
```
Create GRN → Create GRNItems → For each item: Generate UIDs → Create InventoryItems (status IN_STOCK, source GRN) → Update Inventory quantity → Create InventoryMovement → Return GRN
```

---

### 11. Production Module (`production`)

**Purpose:** BOM management, production orders

**Business Rules:**
- BOM defines recipe: FG variant → list of RM products with quantities
- Production order: user specifies quantity to produce
- System checks: sufficient RM inventory available
- If insufficient: deny production, suggest maximum producible quantity
- On confirmation: consume RM inventory → create FG inventory
- Production order status: DRAFT → CONFIRMED
- When confirmed: RM inventory reduced, FG inventory created
- FG items created with source = PRODUCTION
- Inventory movements: PRODUCTION_CONSUME (RM) and PRODUCTION_OUTPUT (FG)
- Production is atomic transaction (all or nothing)

**Dependencies:**
- BOM, BOMItem, ProductionOrder models
- Product, ProductVariant, Inventory, InventoryItem, InventoryMovement models

**Data Flow:**
```
Create Production Order → Get BOM for FG variant → Check RM inventory availability → Calculate max producible → If insufficient, return error → If sufficient, confirm production → Consume RM (create movements) → Create FG items → Create FG movements → Update ProductionOrder status → Return
```

---

### 12. Returns Module (`returns`)

**Purpose:** Customer returns, credit notes

**Business Rules:**
- Returns must reference original sale
- ReturnItems link to original SaleItems (for traceability)
- ReturnItems link to InventoryItems (UIDs of returned items)
- Return status: DRAFT → COMPLETED
- When completed: InventoryItems status → RETURNED, inventory quantity increased
- InventoryMovement created (reason: SALE_RETURN)
- Total_amount calculated from returned items
- Credit notes are fiscal receipts (receipt_category: CREDIT_NOTE)
- Credit notes link to return via return_id
- Returns can be partial (some items from sale)

**Dependencies:**
- Return, ReturnItem models
- Sale, SaleItem models
- InventoryItem, InventoryMovement models
- FiscalReceipt model (for credit notes)

**Data Flow:**
```
Create Return → Validate sale exists → Create ReturnItems → Scan returned UIDs → Validate UIDs belong to original sale → Calculate return amount → Save Return (DRAFT) → Complete Return → Update InventoryItem status to RETURNED → Update Inventory quantity → Create InventoryMovement → Generate Credit Note (if needed) → Return
```

---

### 13. Shifts Module (`shifts`)

**Purpose:** Cashier shift management, cash drawer tracking

**Business Rules:**
- Each cashier can have one OPEN shift at a time
- Shift must be opened before sales can be recorded (shift_id required for sales)
- Opening cash amount recorded when shift opens
- Cash counts can be recorded: OPENING, CLOSING, MID_SHIFT
- Expected closing cash = opening cash + cash sales - cash refunds
- Actual closing cash recorded when shift closes
- Cash discrepancy = actual_closing_cash - expected_closing_cash
- Shifts can have notes (discrepancy explanations, etc.)
- Shift status: OPEN → CLOSED
- Only OPEN shifts can have sales
- Closing shift finalizes all sales in that shift

**Dependencies:**
- Shift, CashCount models
- User model (cashier)
- Sale model (for shift-based sales tracking)

**Data Flow:**
```
Open Shift → Get cashier user → Check for existing OPEN shift → Record opening cash → Create CashCount (OPENING) → Create Shift (status OPEN) → Return
Close Shift → Get shift → Record actual closing cash → Calculate expected vs actual → Record discrepancy → Create CashCount (CLOSING) → Update Shift status to CLOSED → Set ended_at → Return
Mid-Shift Count → Get current shift → Record count amount → Create CashCount (MID_SHIFT) → Return
```

---

### 14. Fiscal Module (`fiscal`)

**Purpose:** KRA eTIMS integration, fiscal receipts

**Business Rules:**
- Fiscal receipts are decoupled from sales (sale can exist without fiscal receipt)
- Fiscal receipt can be for SALE or CREDIT_NOTE
- Receipt type: B2C (no PIN) or B2B (with PIN)
- Customer PIN stored only in fiscal receipt (not in customer table)
- Fiscal status: PENDING → FISCALISED → FAILED
- QR code and KRA receipt number stored after fiscalisation
- Fiscal receipts link to sale via sale_id OR to return via return_id (for credit notes)
- Not all sales need to be fiscalised (optional fiscalisation)
- Fiscalisation happens asynchronously (doesn't block sale completion)
- Failed fiscalisation doesn't affect sale validity

**Dependencies:**
- FiscalReceipt model
- Sale, Return models

**Data Flow:**
```
Fiscalise Sale → Check if already fiscalised → Get sale details → Determine receipt type (B2C/B2B) → Get customer PIN (if B2B) → Call KRA API → Store receipt number and QR → Update fiscal_status to FISCALISED → Set fiscalised_at → Return
Generate Credit Note → Link to return → Follow fiscalisation flow → Mark as CREDIT_NOTE → Return
```

---

### 15. Customers Module (`customers`)

**Purpose:** Customer management (optional customers)

**Business Rules:**
- Customers are optional (sales can happen without customer)
- Customer type: B2C or B2B
- B2B customers can have credit_limit and price_list_id
- KRA PIN stored in customer (optional)
- Customer active flag for soft delete
- Customers used for: invoices, credit sales, customer-specific pricing, tax exemptions
- Walk-in customers don't require customer record

**Dependencies:**
- Customer model
- PriceList model (for customer-specific pricing)
- Sale, TaxExemption, DiscountRule models

**Data Flow:**
```
Create Customer → Validate KRA PIN format (if provided) → Set price_list (if B2B) → Set credit_limit → Save Customer → Return
Update Customer → Validate changes → Update customer → Return
```

---

### 16. Reports Module (`reports`)

**Purpose:** Reporting, analytics, data aggregation

**Business Rules:**
- Reports aggregate data from multiple modules
- Common reports: sales by date/product/customer, inventory levels, profit margins, tax reports
- Reports can be filtered by date range, product category, customer, etc.
- Reports respect user permissions (cashiers see limited reports)
- Reports can be exported (CSV, PDF, Excel)
- Inventory reports: fast-moving, slow-moving, below reorder level
- Sales reports: by shift, by cashier, by payment method
- Tax reports: for KRA compliance

**Dependencies:**
- All models (read-only access)
- SystemLog for audit reports

**Data Flow:**
```
Generate Report Request → Validate user permissions → Build query with filters → Aggregate data from multiple tables → Calculate metrics → Format results → Return report data
```

---

## 🔄 Data Flow Patterns

### Pattern 1: Sale Creation Flow

```
1. User Authentication (auth module)
   ↓
2. Shift Validation (shifts module) - Ensure OPEN shift exists
   ↓
3. Product Lookup (products module) - Get product details
   ↓
4. Price Calculation (pricing module) - Get current price for customer's price list
   ↓
5. Tax Calculation (taxes module) - Calculate tax based on product tax category
   ↓
6. Discount Application (discounts module) - Apply discount code if provided
   ↓
7. Inventory Check (inventory module) - Verify stock availability
   ↓
8. Sale Creation (sales module) - Create Sale and SaleItems
   ↓
9. Inventory Reservation (inventory module) - Reserve inventory items
   ↓
10. Payment Processing (payments module) - Process payment
    ↓
11. Inventory Finalization (inventory module) - Mark items as SOLD
    ↓
12. Fiscalisation (fiscal module) - Generate fiscal receipt (async)
```

### Pattern 2: Stock Addition Flow (GRN)

```
1. GRN Creation (procurement module) - Create GRN record
   ↓
2. GRN Items Addition (procurement module) - Add items received
   ↓
3. UID Generation (inventory module) - Generate unique UIDs for each unit
   ↓
4. InventoryItem Creation (inventory module) - Create InventoryItems (status IN_STOCK, source GRN)
   ↓
5. Inventory Update (inventory module) - Update Inventory quantity
   ↓
6. InventoryMovement Creation (inventory module) - Create movement record (reason: GRN)
```

### Pattern 3: Production Flow

```
1. Production Order Creation (production module) - User specifies FG and quantity
   ↓
2. BOM Lookup (production module) - Get BOM for FG variant
   ↓
3. RM Inventory Check (inventory module) - Check if sufficient RM available
   ↓
4. Production Confirmation (production module) - User confirms production
   ↓
5. RM Consumption (inventory module) - Reduce RM inventory, create movements (PRODUCTION_CONSUME)
   ↓
6. FG Creation (inventory module) - Create FG InventoryItems, update inventory (PRODUCTION_OUTPUT)
   ↓
7. Production Order Update (production module) - Mark as CONFIRMED
```

### Pattern 4: Return Flow

```
1. Return Creation (returns module) - User scans returned item UID
   ↓
2. Sale Validation (sales module) - Verify UID belongs to original sale
   ↓
3. ReturnItem Creation (returns module) - Create return items
   ↓
4. Return Completion (returns module) - Mark return as COMPLETED
   ↓
5. Inventory Update (inventory module) - Change InventoryItem status to RETURNED, increase quantity
   ↓
6. InventoryMovement Creation (inventory module) - Create movement (reason: SALE_RETURN)
   ↓
7. Credit Note Generation (fiscal module) - Generate fiscal credit note
```

---

## 🔒 Transaction Boundaries

### Critical Transactions (Must be Atomic)

1. **Sale Creation:**
   - Create Sale + SaleItems + Reserve Inventory + Create Payments
   - If any step fails → Rollback all

2. **Production Confirmation:**
   - Consume RM + Create FG + Create Movements
   - If any step fails → Rollback all

3. **GRN Processing:**
   - Create InventoryItems + Update Inventory + Create Movements
   - If any step fails → Rollback all

4. **Return Processing:**
   - Update InventoryItems + Update Inventory + Create Movements + Generate Credit Note
   - If any step fails → Rollback all

5. **Payment Processing:**
   - Update Payment status + Update Sale status + Finalize Inventory
   - If any step fails → Rollback all

### Non-Critical Operations (Can be Retried)

1. **Fiscalisation:** Async operation, failure doesn't affect sale
2. **System Logging:** Failure in logging shouldn't block main operation
3. **Inventory Alerts:** Non-blocking, can be queued

### Transaction Isolation Levels

- **Default:** READ COMMITTED (MySQL default)
- **Critical Operations:** Use explicit transactions with BEGIN/COMMIT
- **Read Operations:** Use consistent reads for reports

---

## ✅ Validation Layers

### Layer 1: Request Validation (Input Validation)

**Location:** `modules/{module}/validations/`

**Purpose:** Validate request data structure and basic rules

**Examples:**
- Required fields present
- Data types correct (string, number, date)
- String length limits
- Enum values valid
- Date formats correct
- Email format (if applicable)
- Numeric ranges (min/max)

**When:** Before data reaches service layer

---

### Layer 2: Business Rule Validation (Service Layer)

**Location:** `modules/{module}/services/`

**Purpose:** Validate business logic and constraints

**Examples:**
- Inventory availability check
- Price list validity
- Discount applicability
- Tax exemption eligibility
- Shift status (must be OPEN for sales)
- User permissions
- Uniqueness constraints (SKU, invoice number)
- Referential integrity (foreign keys exist)
- State transitions (can't close already closed shift)

**When:** During business logic execution

---

### Layer 3: Database Constraints (Model Level)

**Location:** Model definitions

**Purpose:** Database-level data integrity

**Examples:**
- Foreign key constraints
- Unique constraints
- Not null constraints
- Check constraints (via Sequelize validators)
- Enum constraints

**When:** On database insert/update

---

### Validation Flow

```
Request → Validation Middleware (Layer 1) → Controller → Service (Layer 2) → Model (Layer 3) → Database
```

---

## 📊 State Management

### Sale States

```
DRAFT → (add items, apply discounts) → DRAFT → (process payment) → PAID
DRAFT → CANCELLED (can cancel before payment)
```

### Payment States

```
PENDING → (processing) → SUCCESS
PENDING → (failed) → FAILED
```

### Shift States

```
OPEN → (close shift) → CLOSED
(Only one OPEN shift per cashier at a time)
```

### Production Order States

```
DRAFT → (confirm production) → CONFIRMED
```

### Return States

```
DRAFT → (complete return) → COMPLETED
```

### Fiscal Receipt States

```
PENDING → (fiscalisation success) → FISCALISED
PENDING → (fiscalisation failed) → FAILED
```

### Inventory Item States

```
IN_STOCK → (sale reservation) → RESERVED → (payment) → SOLD
IN_STOCK → (adjustment) → DAMAGED/SCRAPPED
SOLD → (return) → RETURNED → (can be resold or scrapped)
```

### Purchase Order States

```
DRAFT → (confirm) → CONFIRMED → (all items received) → CLOSED
```

---

## 🔐 Permission Matrix

### Cashier Permissions

**Can:**
- Open/close own shifts
- Create POS sales
- Process payments (cash, card, mobile)
- View own sales
- Scan products
- Apply discounts (if code provided)

**Cannot:**
- Create invoices (B2B sales)
- Adjust inventory
- Create/modify products
- Create production orders
- Create GRNs
- View reports (except own sales)
- Manage customers
- Modify prices

---

### Manager Permissions

**Can:**
- All cashier permissions, plus:
- Create invoices (B2B sales)
- Adjust inventory (with approval workflow)
- Create/modify products
- Create production orders
- Create GRNs
- View all reports
- Manage customers
- Modify prices
- Apply discounts manually
- Process returns
- View all shifts
- Manage categories

**Cannot:**
- Delete sales (only cancel)
- Modify system settings
- Manage users
- Delete audit logs

---

### System Admin Permissions

**Can:**
- All manager permissions, plus:
- Manage users (create, update, delete)
- Manage roles
- System settings
- Delete records (with proper audit trail)
- View audit logs
- Manage tax rates
- Manage price lists
- System configuration

---

## 📝 Module Interaction Rules

### Rule 1: Service-to-Service Communication Only

- Controllers call Services
- Services can call other Services
- Never: Controller → Model (must go through Service)
- Never: Service → Controller

### Rule 2: Single Responsibility

- Each module handles one domain
- Cross-domain operations use multiple services
- Services coordinate, don't duplicate logic

### Rule 3: Dependency Direction

```
Controller → Service → Model → Database
```

### Rule 4: Error Handling

- Services throw custom errors (ValidationError, NotFoundError, etc.)
- Controllers catch errors and use response utilities
- Errors propagate up, handled at controller level

### Rule 5: Data Transformation

- Models: Raw database structure
- Services: Business logic + data transformation
- Controllers: HTTP request/response transformation

---

## 🎯 Key Design Principles

1. **Modularity:** Each module is independent and testable
2. **Separation of Concerns:** Clear boundaries between layers
3. **Transaction Safety:** Critical operations are atomic
4. **Audit Trail:** All changes logged (SystemLog, InventoryMovement)
5. **Flexibility:** Support multiple business scenarios (walk-ins, B2B, etc.)
6. **Performance:** Efficient queries with proper indexes
7. **Scalability:** Stateless services, database handles state
8. **Security:** Role-based access, input validation, SQL injection prevention
9. **Compliance:** KRA eTIMS integration, tax reporting, audit trails

---

## 📚 Module Dependencies Map

```
auth (no dependencies)
products → categories, taxes
categories → (self-referential)
pricing → products, customers
taxes → products, customers
discounts → products, categories, customers
inventory → products
sales → products, inventory, customers, shifts, discounts, taxes, pricing
payments → sales
procurement → products, inventory, vendors
production → products, inventory
returns → sales, inventory, fiscal
shifts → users, sales
fiscal → sales, returns
customers → pricing
reports → (reads from all modules)
```

This architecture ensures:
- Clear module boundaries
- Reusable services
- Testable components
- Maintainable codebase
- Scalable system