Files
ERP_Distribution/Distribution/docs/mainPlan.md
T
Kalana B. Thilakarathna 429a80b1ed Add planning docs for steps 10–23 and update roadmap
Added detailed implementation planning documents for steps 10–23, covering all major feature areas. Updated mainPlan.md to reference these steps, their dependencies, and planning files. No code changes—these documents clarify requirements and guide future development.
2026-08-20 10:04:09 +05:30

28 KiB
Raw Blame History

ERP Distribution — Master Plan

What Already Exists

Area Status Notes
JWT Authentication Done Token generation, claims, 120-min expiry
Permission-based Authorization Done Dynamic policy provider, role → permission mapping
User Management Done CRUD, role assignment, scope assignment (region/route/store)
Role Management Done (read-only) 6 roles seeded, no create/update via API
Region / Route / Vehicle CRUD Done Full API surface with permission checks
Store / Warehouse CRUD Done Full API surface with permission checks
Order CRUD Done Scope-aware (user only sees their assigned stores)
Unit of Work + Repositories Done Transaction support throughout
Soft Deletes Done IsActive pattern on all entities

Known Gaps in Existing System (Pre-Work)

These are not new features — they are fixable holes in what's already built. They must be resolved before new feature steps begin because later steps depend on correct foundations.

Gap Impact
Route DTOs missing RegionId Can't link routes to regions via API
Store DTOs missing RouteId Can't link stores to routes via API
Role endpoints have no [Authorize] Anyone can read roles without authentication
JWT key & DB credentials in appsettings.json Security risk in any shared/production environment
No input validation on any DTO Bad data can enter the system silently
Item model is empty (no properties) OrderItems reference items that have no data

Feature Steps

# Feature Status Depends On Detail File
00 Existing Gap Fixes Done — 00_existing_gaps.md
01 Item Catalog Done 00 01_item_catalog.md
02 Stock Ledger Done 01 02_stock_ledger.md
03 Ride Lifecycle Not Started 02 03_ride_lifecycle.md
04 Loading Event Not Started 03 04_loading_event.md
05 Delivery Ride Execution Not Started 04 05_delivery_ride.md
06 Sale Ride Execution Not Started 04 06_sale_ride.md
07 Ride Close & Reconciliation Not Started 05, 06 07_ride_reconciliation.md
08 Sales Agent Controls Not Started 07 08_sales_agent_controls.md
09 Fraud Controls & Audit Trail Not Started 08 09_fraud_controls.md
10 Region Management (Beyond CRUD) Not Started 00 10_region_management.md
11 Route & Sales Visit Management Not Started 00 11_route_sales_management.md
12 Store Management (Beyond CRUD) Not Started 00 12_store_management.md
13 Fleet Management (Beyond CRUD) Not Started 00 13_fleet_management.md
14 Pricing & Supplier Master Data Not Started 01 14_pricing_and_suppliers.md
15 Procurement / Purchasing Not Started 01, 14 15_procurement.md
16 Sales Force Automation / CRM Not Started 12 16_sfa_crm.md
17 Promotions & Trade Scheme Management Not Started 01, 14 17_promotions_schemes.md
18 Returns & Claims Management Not Started 05, 06 18_returns_claims.md
19 Finance & Accounting Not Started 05, 06, 18 19_finance_accounting.md
20 Reporting, Analytics & BI Not Started all prior 20_reporting_analytics.md
21 Notifications & Alerts Not Started 02, 12, 08 21_notifications_alerts.md
22 Integration & API Layer Not Started 19, 13 22_integration_api.md
23 Mobile & Offline Capability Not Started 05, 06 23_mobile_offline.md

Steps 00–09 are the original ride/stock-ledger roadmap and keep their strict dependency order. Steps 10–23 fill in every remaining area from the Function Reference by Feature section above that wasn't already covered by 00–09; they depend only on the specific earlier steps noted above, not on the full 00–09 chain, and can be resequenced relative to each other as priorities become clearer.


Function Reference by Feature

Reference only, not a build plan — background material to consult while planning/implementing the steps above and below. Service-layer function names and what each should do when implemented. Names are illustrative (camelCase) — adapt to your language/framework conventions. None of the functions below are implemented yet unless noted. User Management/RBAC functions aren't repeated here — see SRS_User_Management_Module.pdf.

1. Order Management

Function What it does Status
createOrder(storeId, items[], salesRepId) Validates stock/credit, creates a new order in pending state. Partially implemented — OrderService.CreateAsync exists but has no credit/stock validation or state machine yet.
validateCreditLimit(storeId, orderAmount) Checks store's outstanding balance + new order value against its credit limit. Not implemented — no credit limit field on Store yet.
checkStockAvailability(items[]) Confirms requested SKUs/quantities are available at the fulfilling warehouse. Not implemented — depends on 02_stock_ledger.md.
applyPricingAndDiscounts(orderId) Runs the active price list and eligible scheme rules against order lines. Not implemented — depends on §7 Master Data and §11 Promotions below.
submitOrderForApproval(orderId) Routes the order to the correct approver based on its value/discount threshold. Not implemented — depends on 08_sales_agent_controls.md.
approveOrder(orderId, approverId) / rejectOrder(orderId, reason) Moves order to approved or rejected, logging the actor. Not implemented.
updateOrderStatus(orderId, status) Transitions order through pending → approved → picked → dispatched → delivered → invoiced. Not implemented — Order has no status field or state machine today.
convertOrderToInvoice(orderId) Generates the invoice once the order is dispatched/delivered. Not implemented — depends on §13 Finance & Accounting.
createBackorder(orderId, unfulfilledItems[]) Splits unfulfillable quantity into a linked backorder. Not implemented.
cancelOrder(orderId, reason) Cancels an order pre-dispatch and releases any reserved stock. Not implemented — OrderController supports soft delete only, no reason code or stock release.
getOrdersByStore(storeId) / getOrdersBySalesRep(salesRepId) Scoped order listings. getOrdersByStore implemented (GET /api/orders/store/{storeId}). getOrdersBySalesRep not implemented.
getOrderAnalytics(filters) Returns fill rate, average order value, rejection rate over a period. Not implemented.

2. Region Management

Function What it does Status
createRegion(name, boundaries) Creates a new region record. Partially implemented — RegionController supports create with Name only, no boundaries field.
assignAreaToRegion(areaId, regionId) Links an existing area under a region. Not implemented — no Area entity exists in the schema.
setRegionalTarget(regionId, period, targetValue) Sets the sales target for a region for a given period. Not implemented.
setRegionalBudget(regionId, period, budgetAmount) Allocates budget at the regional level. Not implemented.
mapAgencyToRegion(agencyId, regionId) Assigns a Regional Agency's contract scope to a region. Not implemented — RegionalAgency is currently a Role, not a distinct agency entity; scope is via UserRegionScope.
setRegionalTaxRule(regionId, ruleConfig) Overrides tax/pricing rules for a specific region. Not implemented.
getRegionHierarchy(regionId) Returns all areas/territories nested under a region. Not implemented — see user_management_PLAN.md territory hierarchy prerequisite.
getRegionDashboard(regionId, period) Aggregated KPIs: sales, fill rate, agency performance for the region. Not implemented.

3. Route Management

Function What it does Status
createRoute(name, areaId) Creates a new sales visit route within an area. Partially implemented — RouteController supports create, but by RegionId not areaId (no Area entity exists).
assignOutletsToRoute(routeId, outletIds[]) Maps a set of stores to a route. Partially implemented — a Store has a single FK_RouteId, set via StoreController create/update; no bulk-assign endpoint.
assignRouteToSalesRep(routeId, salesRepId) Assigns ownership of a route to an SR. Not implemented — only UserRouteScope exists (scope grant), not a single-owner assignment.
optimizeRouteSequence(routeId) Reorders the visit sequence for efficiency (distance/priority-based). Not implemented.
recordRouteCheckIn(routeId, outletId, gpsCoords, timestamp) Logs an SR's arrival at an outlet. Not implemented.
recordRouteCheckOut(routeId, outletId, timestamp) Logs departure and closes out the visit. Not implemented.
getRouteAdherence(routeId, date) Compares planned vs. actual visits for a route/day. Not implemented — depends on check-in/check-out above.
reassignRoute(routeId, newSalesRepId) Moves a route to a different SR. Not implemented.
getRoutePerformance(routeId, period) Sales per route, strike rate, missed-visit count. Not implemented.
planDeliveryRoute(warehouseId, orderIds[]) Builds the warehouse-to-outlet dispatch route (separate from the sales visit route). Not implemented — this is the DeliveryRun concept; see 03_ride_lifecycle.md.

4. Store (Outlet) Management

Function What it does Status
createStore(storeData, kycDocs) Onboards a new outlet with required KYC. Partially implemented — StoreController create exists, no KYC document handling.
verifyStoreKyc(storeId) Marks KYC as verified/rejected by an approver. Not implemented.
updateStoreCreditLimit(storeId, newLimit, approverId) Changes a store's credit limit, subject to approval authority. Not implemented — no credit limit field on Store.
getStoreOutstandingBalance(storeId) Returns current receivables against the store. Not implemented — depends on §13 Finance & Accounting.
classifyStore(storeId, segment) Sets/updates the store's segment (key account, general trade, etc.). Not implemented — no segment field on Store.
deactivateStore(storeId, reason) Soft-deletes a store, blocking new orders against it. Partially implemented — DELETE /api/stores/{id} soft-deletes via IsActive, no reason code captured.
getStoreVisitHistory(storeId) Returns visit compliance history from Route Management. Not implemented — depends on route check-in/check-out (§3).
checkStoreSchemeEligibility(storeId, schemeId) Evaluates whether a store qualifies for a given promotion. Not implemented — depends on §11 Promotions.
getStoreSalesDashboard(storeId, period) Store-level sales and outstanding summary. Not implemented.

5. Vehicle / Fleet Management

Function What it does Status
registerVehicle(vehicleData) Creates the vehicle master record (registration, capacity, ownership). Partially implemented — VehicleController create exists with RegNumber/NumberPlate only, no capacity/ownership fields.
assignVehicleToRoute(vehicleId, routeId) Assigns a vehicle to a delivery/sales route. Not implemented — Vehicle has no route link; only DeliveryRun.FK_RouteId/FK_VehicleId model this, and DeliveryRun is unwired (see 03_ride_lifecycle.md).
assignDriverToVehicle(vehicleId, driverId) Links a driver to a vehicle, checking license validity. Not implemented — no Driver entity exists yet (DeliveryRun.FK_DriverId is commented out in the model).
scheduleMaintenance(vehicleId, maintenanceType, dueAt) Sets up a preventive maintenance task (mileage/calendar-based). Not implemented.
logFuelExpense(vehicleId, amount, liters, date) Records a fuel transaction against the vehicle. Not implemented.
recordVehicleTelemetry(vehicleId, gpsCoords, speed, timestamp) Ingests telematics data (location, driver behavior). Not implemented — see §16 Integration.
checkDriverCompliance(driverId) Validates license/permit status before dispatch. Not implemented — depends on a Driver entity.
calculateLoadPlan(vehicleId, orderIds[]) Matches order volume/weight to available vehicle capacity. Not implemented — depends on 04_loading_event.md.
getVehicleUtilization(vehicleId, period) Utilization and cost-per-delivery metrics. Not implemented.
retireVehicle(vehicleId, reason) Removes a vehicle from active fleet, retaining history. Partially implemented — DELETE /api/vehicles/{id} soft-deletes via IsActive, no reason code captured.

6. Warehouse Management

Function What it does Status
createGoodsReceipt(poId, receivedItems[]) Records inbound stock against a purchase order (GRN). Not implemented — depends on §9 Procurement.
inspectGoodsReceipt(grnId, inspectionResult) Logs quality-check outcome before putaway. Not implemented.
putawayStock(grnId, locationAssignments[]) Assigns received stock to warehouse locations (zone/ABC-based). Not implemented — depends on 02_stock_ledger.md.
getStockByLocation(warehouseId, sku) Returns real-time quantity and location for a SKU. Not implemented — depends on 02_stock_ledger.md.
generatePickList(orderIds[]) Creates a pick list/task for one or more orders. Not implemented — overlaps with 04_loading_event.md.
confirmPicking(pickListId, pickedItems[]) Marks items as picked, decrementing available stock. Not implemented.
packOrder(orderId, packageDetails) Records packing completion and package details. Not implemented.
createCrossDockTransfer(inboundId, outboundOrderId) Routes inbound stock directly to an outbound order, skipping storage. Not implemented.
runCycleCount(warehouseId, zoneId) Initiates a scheduled partial stock count. Not implemented — overlaps with 07_ride_reconciliation.md physical count concept.
reconcileStock(warehouseId, countResults) Adjusts system stock to match physical count results. Not implemented — see 07_ride_reconciliation.md.
buildDispatchLoad(vehicleId, orderIds[]) Groups orders into a dispatch load for a specific vehicle/route. Not implemented — see 04_loading_event.md.
receiveReturn(returnId, items[], condition) Processes returned goods back into the warehouse. Not implemented — see §12 Returns & Claims.
getWarehouseKpis(warehouseId, period) Dock-to-stock time, pick accuracy, turnover rate. Not implemented.

7. Master Data Management

Function What it does Status
createProduct(skuData) Creates a SKU with category, UOM, barcode, pack hierarchy. Not implemented — Item model exists but has no properties; see 01_item_catalog.md.
deactivateSku(sku, reason) Retires a SKU from active ordering. Not implemented.
createPriceList(name, region, effectiveDates) Defines a new price list scoped to a region/date range. Not implemented — no price list entity exists.
updateProductPricing(sku, priceListId, price) Sets/updates the price of a SKU within a price list. Not implemented.
createSupplierMaster(supplierData) Registers a new supplier/vendor. Not implemented — no Supplier entity exists.

8. Enterprise-wide Inventory & Stock

Function What it does Status
getMultiLocationStock(sku) Returns stock levels for a SKU across all warehouses/agencies. Not implemented — see 02_stock_ledger.md.
setReorderPoint(sku, warehouseId, threshold) Configures the auto-replenishment trigger level. Not implemented.
createStockTransfer(fromWarehouseId, toWarehouseId, items[]) Initiates an inter-warehouse stock movement. Not implemented.
trackBatchExpiry(sku, batchNo, expiryDate) Registers batch/expiry data for FEFO enforcement. Not implemented.
calculateStockValuation(warehouseId, method) Computes stock value using FIFO/weighted-average. Not implemented.

9. Procurement / Purchasing

Function What it does Status
createPurchaseRequisition(items[], requestedBy) Raises an internal request to purchase stock. Not implemented — no procurement entities exist.
createPurchaseOrder(supplierId, items[]) Issues a PO to a supplier. Not implemented.
matchInvoiceToPO(invoiceId, poId, grnId) Performs the 3-way match (PO–GRN–Invoice) before payment. Not implemented.
evaluateSupplier(supplierId, criteria) Scores a supplier on delivery/quality/price performance. Not implemented.
createPurchaseReturn(poId, items[], reason) Initiates a return of received goods to the supplier. Not implemented.

10. Sales Force Automation (SFA) / CRM

Function What it does Status
logCustomerInteraction(storeId, notes) Records a visit note or customer interaction. Not implemented.
trackTargetVsAchievement(userId, period) Compares a user's sales target to actuals. Not implemented.
calculateIncentive(userId, period) Computes commission/incentive payout based on performance. Not implemented.
createLead(prospectData) Captures a prospective new outlet. Not implemented — no Lead entity exists.
convertLeadToStore(leadId) Converts a qualified lead into an active store record. Not implemented.

11. Promotions & Trade Scheme Management

Function What it does Status
createScheme(schemeRules, eligibility, dateRange) Defines a promotion (buy-X-get-Y, slab discount, etc.). Not implemented — no scheme entity exists.
evaluateSchemeEligibility(storeId, orderId) Checks whether an order qualifies for a scheme. Not implemented.
applySchemeDiscount(orderId, schemeId) Applies the scheme's discount to order pricing. Not implemented.
trackSchemeSpend(schemeId) Aggregates total discount value given under a scheme. Not implemented.
getSchemeROI(schemeId) Compares scheme spend against incremental sales generated. Not implemented.

12. Returns & Claims Management

Function What it does Status
createReturnRequest(orderId, items[], reasonCode) Initiates a return against a delivered order. Not implemented — see 09_fraud_controls.md for the fraud-control angle on returns.
approveReturn(returnId, approverId) Approves/rejects the return request. Not implemented.
generateCreditNote(returnId) Issues a credit note against the original invoice. Not implemented.
createClaim(agencyId, claimDetails) Raises a claim against a Regional Agency (e.g., damaged stock). Not implemented.
settleClaim(claimId, settlementAmount) Closes out a claim with a final settlement amount. Not implemented.

13. Finance & Accounting

Function What it does Status
createInvoice(orderId) Generates a formal invoice from a fulfilled order. Not implemented — no invoice entity exists.
recordPayment(invoiceId, amount, method) Logs a payment/collection against an invoice. Not implemented.
postToGeneralLedger(transactionId) Posts a financial transaction to the GL. Not implemented.
generateTaxInvoice(invoiceId, jurisdiction) Produces a tax-compliant invoice (GST/VAT e-invoicing). Not implemented.
getFinancialReport(entityId, period, reportType) Returns P&L/cash-flow reports scoped to a region/area. Not implemented.

14. Reporting, Analytics & BI

Function What it does Status
getDashboardData(role, scope) Returns the role-appropriate dashboard payload. Not implemented.
generateKpiReport(kpiType, filters) Produces a specific KPI report (fill rate, OOS%, credit risk, etc.). Not implemented.
getPredictiveAlert(type, scope) Returns AI-flagged issues, e.g. a region's declining fill rate. Not implemented.

15. Notifications & Alerts

Function What it does Status
sendLowStockAlert(warehouseId, sku) Notifies relevant roles when stock drops below the reorder point. Not implemented.
sendCreditLimitBreachAlert(storeId) Notifies approvers when a store exceeds its credit limit. Not implemented.
sendApprovalPendingNotification(approverId, requestId) Notifies an approver of a pending action. Not implemented.
sendRouteDeviationAlert(routeId, salesRepId) Flags when an SR deviates materially from the planned route. Not implemented — see 09_fraud_controls.md geofencing check.

16. Integration & API Layer

Function What it does Status
syncToAccountingSystem(transactionId, targetSystem) Pushes a transaction to an external accounting platform (QuickBooks/SAP/Xero). Not implemented.
syncTelematicsData(vehicleId, provider) Pulls GPS/telematics data from a third-party provider. Not implemented.
pushOrderToDistributorPortal(orderId) Syncs order status to a distributor-facing B2B portal. Not implemented.

17. Mobile & Offline Capability

Function What it does Status
queueOfflineOrder(orderData) Stores an order locally on the device when offline. Not implemented — no mobile client in this repository.
syncOfflineQueue(deviceId) Pushes queued offline actions to the server once connectivity returns. Not implemented.
scanBarcode(barcodeValue) Resolves a scanned barcode to a SKU or warehouse location. Not implemented.

18. Compliance & Audit

Function What it does Status
logAuditEvent(userId, action, entityType, entityId) Writes an immutable audit trail entry for a state-changing action. Not implemented — see 09_fraud_controls.md, which scopes an audit log as part of Fraud Controls.
checkLicenseCompliance(entityId, licenseType) Validates a required license/permit is current (e.g., regulated goods). Not implemented.
generateComplianceReport(period) Produces a report of compliance status across the org for a period. Not implemented.

Feature Summaries

00 — Existing Gap Fixes

Fix all known holes in the current codebase before new features are layered on top. Includes DTO field gaps, missing authorization on role endpoints, secrets management, and adding input validation across all existing endpoints. Gate: All existing API endpoints behave correctly and securely before step 01 begins.

01 — Item Catalog

Define the Item entity with real properties (name, SKU, unit of measure, category, price tiers). Items are the unit of stock — nothing in the stock ledger makes sense without them. This step also covers the Item CRUD API and how items relate to orders. Gate: An item can be created, updated, and referenced in an order with quantity and price.

02 — Stock Ledger

Introduce the concept of stock per location. Every warehouse (fixed or vehicle) holds a quantity of each item. Stock is never edited directly — all changes happen through movement transactions (load, sale, return, damage, adjustment). The current balance is always the running sum. This is the single most important architectural decision for the whole system. Gate: Stock balance for any item at any location can be queried. Every change is a traceable transaction.

03 — Ride Lifecycle

A ride is a session that turns a vehicle into a temporary warehouse. It has a state machine: Draft → Open → Active → Closed. A vehicle can only be on one active ride at a time. Two ride types exist: Delivery (pre-orders) and Sale (van sales). The ride tracks who is driving, which route, which vehicle, and when it started and ended. Gate: A ride can be created, opened, and closed. A vehicle's stock ledger is created when a ride opens.

04 — Loading Event

When a ride opens, stock must be physically loaded from a source warehouse onto the vehicle. This is a two-party event: warehouse manager confirms what was dispatched, driver confirms what was received. Discrepancies between the two are flagged immediately and require resolution before the ride goes active. The loading event creates stock movement transactions that debit the warehouse and credit the vehicle. Gate: Stock moves from warehouse to vehicle via a confirmed loading event. Any discrepancy is logged.

05 — Delivery Ride Execution

On a delivery ride, the driver fulfills pre-confirmed orders. Each order becomes a delivery task. The driver marks each as delivered, partially delivered, or failed. Partially delivered orders generate a credit note for the undelivered quantity. Customer confirmation (signature or OTP) is required to mark a delivery complete. Stock movements are created per delivery event. Gate: A delivery ride can execute all orders on its route and produce a delivery report.

06 — Sale Ride Execution

On a sale ride, the driver visits customers and creates invoices on the spot. No pre-orders exist. The driver selects items, quantities, and prices (within approved discount limits), and the invoice is generated immediately. Payment is collected (cash or credit) at the point of sale. The vehicle's stock ledger decreases with each sale. The driver cannot sell more than what is loaded. Gate: A sale ride can generate invoices in the field. Stock on vehicle decreases with each sale.

07 — Ride Close & Reconciliation

When a ride ends, the system performs a full reconciliation. The equation must balance: Opening Stock − Sales − Damages + Returns = Closing Stock (physical count) Cash Collected + Credit Extended = Total Sales − Returns Any variance must be approved by a supervisor with a reason code before the ride can close. Unresolved variances are logged as discrepancies against the agent's record. Gate: A ride cannot close with an unexplained variance. All discrepancies are permanently recorded.

08 — Sales Agent Controls

Agents operate within boundaries set by their role level. This step wires role levels to business rules: discount limits per agent level, credit limits per customer, maximum single-transaction value, and approval chains for exceptions. Supervisors can grant one-time overrides logged against their account. Gate: An agent cannot exceed their limits without a logged, authorized override.

09 — Fraud Controls & Audit Trail

A dedicated audit log records every sensitive event (who, what, when, from where). Automated checks flag: returns without a matching prior sale, sales outside the geofenced route, agents with consistently high variance rates, and cash collected below invoiced amounts. Return approval requires supervisor sign-off before stock is credited. Anomaly reports are surfaced to area managers on a scheduled basis. Gate: Every sensitive event is logged immutably. Automated flags surface to the right level of management.


Rules

  1. A feature file must be filled in and reviewed before implementation begins on that step.
  2. Status must be updated in this file whenever a step transitions.
  3. If implementation reveals a design change, the feature file is updated and this plan is revised.
  4. Steps must be done in dependency order — no skipping.