3.0.1 • Published 5 months ago

@asaidimu/erp-types v3.0.1

Weekly downloads
-
License
MIT
Repository
github
Last release
5 months ago

@asaidimu/erp-types

NPM Version License TypeScript Built with Bun Last Updated

Table of Contents


Overview & Features

What is @asaidimu/erp-types?

@asaidimu/erp-types is a comprehensive, modular standard library of TypeScript data model interfaces for building robust and scalable Enterprise Resource Planning (ERP) systems. It provides flexible, type-safe definitions for core business domains, enabling developers to create consistent and interoperable applications across various industries, from manufacturing and retail to service industries and specialized sectors.

This library defines the structure of ERP data without imposing implementation details, allowing for diverse architectural choices (monolithic, microservices) and deployment options (web, mobile, desktop). Its design prioritizes flexibility, strong typing, and audit readiness, making it an ideal foundation for modern business management solutions.

Beyond just TypeScript types, @asaidimu/erp-types also provides corresponding anansi schema definitions. These schemas offer a powerful layer for runtime data validation, documentation generation, and dynamic UI forms, ensuring that your application's data conforms to its defined structure not just at compile-time, but also at runtime.

Why Use These Types?

ERP systems are inherently complex, managing deeply interconnected business processes such as inventory tracking, financial auditing, human resources, and project execution. Without a unified and well-defined type system, development can quickly lead to:

  • Inconsistency: Ad-hoc data structures result in mismatched APIs and brittle integrations between modules.
  • Errors: Lack of type safety increases the likelihood of runtime bugs, such as misinterpreting stock units, mishandling transaction states, or incorrectly assigning roles.
  • Redundancy: Developers often find themselves reinventing similar data structures across different parts of the system, leading to wasted effort and increased maintenance burden.

@asaidimu/erp-types addresses these challenges by:

  • Standardizing: Providing a reusable, canonical foundation for common ERP domains, significantly reducing duplication and promoting consistency.
  • Ensuring Safety: Leveraging TypeScript's powerful type system to enforce strict type checks at compile-time, catching potential errors before they reach production. The accompanying anansi schemas provide a mechanism for robust runtime validation.
  • Enabling Flexibility: Utilizing extensible generics and abstract interfaces to support both traditional business use cases (e.g., warehouse inventory) and highly unconventional or specialized scenarios (e.g., modeling "nuts" as a currency in a custom economy).

In essence, this library acts as a robust blueprint, ensuring that your ERP's data model is consistent, scalable, maintainable, and adaptable to evolving business needs.

Key Features

  • Comprehensive Coverage: Includes TypeScript interfaces and anansi schema definitions for 12 core ERP domains, from Logistics and Finance to HR and Project Management.
  • Dual-Layer Type Safety: Provides strong compile-time type checking with TypeScript and enables robust runtime data validation through anansi schema definitions.
  • Modular Design: Each core module is independent, allowing for progressive adoption and deployment based on specific business requirements.
  • Extensibility: Designed with open patterns and generics, making it easy to customize and extend types without modifying the core library.
  • Cross-Module Integration: Provides consistent interfaces that facilitate seamless data flow and integration between different business functions.
  • Audit Readiness: Supports comprehensive versioning and history tracking capabilities across various modules, crucial for compliance and accountability.
  • JSON Compatibility: Types and schemas are aligned with JSON formats for straightforward data exchange, serialization, and storage in modern data systems.
  • Unconventional Use Case Support: Generics and flexible data structures enable modeling diverse scenarios beyond traditional enterprise environments (e.g., a "squirrel's nut-based economy").

Core Modules

The library is structured into the following key domains, each offering a rich set of interfaces and schemas:

  1. Logistics Management: Manages physical flow of goods, inventory, storage, and transportation.

    • Key Components: Product Management, Inventory Control, Storage Facility Management, Transport Management, Route Planning, Event Tracking.
    • Use Cases: Retail inventory, manufacturing supply chain, warehouse operations, fleet management.
  2. Financial Management: Handles monetary aspects with flexible currency support.

    • Key Components: Transaction Processing, Account Management, Asset Tracking, Liability Management, Multi-currency Support, Financial History.
    • Use Cases: General ledger, accounts receivable/payable, asset management, financial reporting, budget tracking.
  3. Human Resources Management: Manages employee data, compensation, and workforce planning.

    • Key Components: Employee Records, Payroll Processing, Benefits Administration, Time & Attendance, Performance Management, Recruitment, Training & Development.
    • Use Cases: Employee lifecycle, compensation, workforce analytics, compliance reporting.
  4. Customer Relationship Management (CRM): Manages customer interactions, sales processes, and service delivery.

    • Key Components: Contact Management, Sales Pipeline, Interaction History, Service Management, Marketing Integration, Contract Management.
    • Use Cases: Sales force automation, customer service, marketing campaign tracking, customer retention.
  5. Project Management: Handles planning, execution, and monitoring of business initiatives.

    • Key Components: Project Planning, Resource Allocation, Task Management, Time Tracking, Budget Management, Milestone Tracking.
    • Use Cases: Product development, client engagements, internal initiatives, software development.
  6. Manufacturing & Production: Manages creation of goods from raw materials to finished products.

    • Key Components: Bill of Materials, Production Planning, Work Orders, Machine Management, Quality Control, Production Reporting.
    • Use Cases: Discrete manufacturing, process manufacturing, job shop operations.
  7. Procurement Management: Manages purchasing processes and supplier relationships.

    • Key Components: Requisition Management, Supplier Management, Purchase Order Processing, Receiving, Invoice Matching, Contract Management.
    • Use Cases: Strategic sourcing, supplier relationship management, purchase approval workflows.
  8. Document Management: Handles creation, storage, and retrieval of business documents.

    • Key Components: Document Repository, Version Control, Access Control, Workflow Processing, Template Management, Retention Policies.
    • Use Cases: Contract management, policy documentation, technical documentation, legal compliance.
  9. Reporting & Analytics: Provides business intelligence and data visualization capabilities.

    • Key Components: Dashboard Creation, Standard Reports, Custom Report Builder, Data Export, Alert System, Predictive Analytics.
    • Use Cases: Executive dashboards, operational reporting, financial analysis, sales performance tracking.
  10. Integration Framework: Enables communication between modules and external systems.

    • Key Components: API Management, Data Synchronization, Event Processing, External Connectors, Data Transformation, Message Queuing.
    • Use Cases: E-commerce platform integration, payment gateway connections, IoT device data collection.
  11. User & Access Management: Controls system security and access rights.

    • Key Components: User Authentication, Role-Based Access Control, Multi-factor Authentication, Single Sign-On, Session Management, Audit Logging.
    • Use Cases: Security compliance, departmental access restrictions, sensitive information protection.
  12. Compliance & Governance: Ensures adherence to regulations and internal policies.

    • Key Components: Regulatory Tracking, Policy Management, Audit Management, Risk Assessment, Compliance Reporting, Issue Management.
    • Use Cases: Industry-specific regulation compliance, financial reporting requirements, data protection standards.

System Design Principles

The library is built upon several foundational principles to ensure its robustness and adaptability:

  1. Flexibility First: Utilizes generic types and extensive metadata support to adapt to diverse business contexts without requiring source code changes.
  2. Type Safety: Employs strong typing with TypeScript to ensure reliable data handling and minimize runtime errors, providing compile-time guarantees. The inclusion of anansi schemas further enforces this at runtime.
  3. Modularity: Designed with independent modules that can be adopted and deployed separately or as a unified system, promoting a microservices-friendly approach.
  4. Extensibility: Follows open design patterns to easily accommodate future growth, custom data requirements, and domain-specific extensions.
  5. Cross-Module Integration: Provides consistent interfaces that enable seamless data flow and interaction between different business functions.
  6. Audit Readiness: Incorporates comprehensive versioning and history tracking capabilities across all modules, essential for compliance, debugging, and historical analysis.
  7. JSON Compatibility: Ensures direct alignment with JSON schemas, facilitating easy data exchange, serialization, and storage in modern data systems.

Installation & Setup

Prerequisites

To use @asaidimu/erp-types in your project, you'll need:

  • Node.js: Version 14 or higher (recommended: LTS version).
  • TypeScript: Version 5.0.3 or higher.
  • Bun: (Optional, but recommended for development scripts) Version 1.0.0 or higher.

Installation Steps

Install the package using your preferred package manager:

# Using npm
npm install @asaidimu/erp-types

# Using yarn
yarn add @asaidimu/erp-types

# Using bun
bun add @asaidimu/erp-types

Verification

To verify that the types are correctly installed and accessible in your project, create a simple TypeScript file (e.g., test-types.ts):

import { Person, ISOStringDate } from '@asaidimu/erp-types/types';

interface MyEmployeeData {
  name: string;
  employeeId: string;
}

interface MyEmployeeMetadata {
  hireDate: ISOStringDate;
  department: string;
}

// Define a concrete type using the generic `Person` interface
type MyEmployee = Person<MyEmployeeData, 'hr-system', MyEmployeeMetadata>;

// Instantiate an object conforming to the defined type
const employee: MyEmployee = {
  id: "EMP789",
  data: {
    type: "natural", // 'natural' or 'artificial' as per Person type
    name: "Jane Doe",
    employeeId: "A1B2C3D4",
  },
  metadata: {
    'data-role': 'hr-system', // Matches the DataRole generic argument
    hireDate: "2024-01-15T09:00:00Z",
    department: "Sales",
  },
};

console.log(`Employee Name: ${employee.data.name}`);
console.log(`Employee ID: ${employee.data.employeeId}`);
console.log(`Hire Date: ${employee.metadata.hireDate}`);

// This line would cause a TypeScript compilation error, demonstrating type safety:
// employee.data.nonExistentField = "value";

Compile and run the file:

# Compile
npx tsc test-types.ts

# Run (requires Node.js or Bun)
node test-types.js
# Or with Bun:
bun run test-types.ts

If the compilation succeeds without errors and the script runs, the types are correctly integrated into your project.


Usage Documentation

These types are designed to model ERP data declaratively, providing a strong structural foundation for your application. They do not include any runtime logic or validation, which should be handled by your application layer, optionally using the provided anansi schemas for robust runtime checks.

Basic Usage Example

Here's how you might import and use a few basic types, specializing them for your domain:

import {
  ISOStringDate,
  Address,
  Geolocation,
  Currency,
  Transaction,
  Account,
  Item,
  Stock,
  Facility,
  DATA_ROLE_SALES, // Specific data role for sales transactions
} from '@asaidimu/erp-types/types';

// 1. Define custom data shapes for generic type parameters
//    These interfaces hold your domain-specific properties.
interface MyProductData {
  material: string;
  size: "S" | "M" | "L" | "XL";
}

interface MyProductMetadata {
  supplierSKU: string;
}

interface MyProductGroupMetadata {
  collection: string;
}

// 2. Define concrete types by applying your custom shapes to the generic ERP interfaces
type ApparelProduct = Item<MyProductData, MyProductMetadata, MyProductGroupMetadata>;

type WarehouseMetadata = { managerId: string };
type WarehouseFacility = Facility<"warehouse", "active" | "inactive", { areaCode: string }, WarehouseMetadata>;

type WarehouseStock = Stock<
  ApparelProduct,
  "available" | "reserved" | "defective", // Custom stock states
  "warehouse",                           // Custom facility category
  "active" | "inactive",                 // Custom facility states
  WarehouseMetadata,                     // Facility-specific metadata
  { lastInspected: ISOStringDate }       // Stock-specific metadata
>;

// For a sales transaction, specify the medium, metadata shape, and data role.
type CashTransaction = Transaction<"cash" | "card", { customerId: string }, unknown, typeof DATA_ROLE_SALES>;


// 3. Create instances of your specialized types
const usd: Currency = {
  code: "USD",
  symbol: "$",
  precision: 2, // 'decimalPlaces' changed to 'precision' based on finance.ts
};

const mainWarehouse: WarehouseFacility = {
  id: "WH-NYC-001",
  label: "NYC Main Distribution Center",
  category: "warehouse",
  status: "active",
  area: { unit: "sqm", value: 50000 },
  data: { floorAreaSqM: 50000 }, // 'floorAreaSqM' added to FacilityData
  metadata: { managerId: "EMP-007" },
  location: {
    latitude: 40.7128,
    longitude: -74.0060,
    source: "geocoded" // 'source' is an enum in common.ts
  }
};

const blueTShirt: ApparelProduct = {
  id: "TSHIRT-BLUE-M",
  label: "Blue T-Shirt",
  description: "Cotton crew neck, medium size, blue color.",
  data: {
    material: "cotton",
    size: "M",
  },
  metadata: {
    supplierSKU: "SUP-A-TSHIRTM-BLUE",
  },
  group: { // 'group' can be an object or ID. Here, demonstrating as an object.
    id: "GRP-TSHIRTS",
    label: "T-Shirts",
    description: "All t-shirts",
    metadata: {
      collection: "Summer 2025",
    },
    parent: undefined // Optional parent group
  },
  type: "fungible", // 'fungible' or 'non-fungible'
  tags: ["apparel", "casual"],
};

const tShirtStock: WarehouseStock = {
  id: "STK-TSHIRT-001",
  product: blueTShirt, // Can reference the full product object
  quantity: 250,
  reserved: 10, // Optional reserved quantity
  acquired: "2025-03-01T10:00:00Z",
  storage: mainWarehouse, // Can reference the full facility object
  state: "available",
  batch: "BATCH-2025-Q1-TSHIRTS",
  expires: "2027-03-01T00:00:00Z", // Example: if apparel had a shelf life
  unit: "pieces",
  metadata: {
    lastInspected: "2025-03-10T14:30:00Z",
  },
};

const customerPayment: CashTransaction = {
  id: "TXN-SALES-9876",
  description: "Customer purchase for 3 T-shirts",
  amount: 45.00,
  type: "credit", // 'credit' or 'debit'
  medium: "card", // Specific medium 'card'
  currency: usd,
  state: "completed", // Transaction state
  metadata: { // Custom metadata for sales transactions
    'data-role': DATA_ROLE_SALES, // Required data-role property as per schema
    customerId: "CUST-XYZ-123",
    transactionChannel: "POS",
  },
  group: { id: "GRP-SALES", label: "Retail Sales", description: "All retail sales" }, // Optional transaction group
  recurrence: undefined, // Not a recurring transaction
  gateway: { // Payment gateway details
    id: "GATEWAY-STRIPE-TXN-ABC",
    status: "success",
    direction: "in", // 'in' or 'out'
    response: { approvalCode: "ABC123XYZ" } // Example gateway response metadata
  },
};

console.log(`Product: ${tShirtStock.product.label}`);
console.log(`Stock Quantity: ${tShirtStock.quantity} ${tShirtStock.unit}`);
console.log(`Transaction Amount: ${customerPayment.currency.symbol}${customerPayment.amount}`);

Real-World Use Case: Managing a Small Retail Chain

Let's illustrate how various modules seamlessly integrate using a scenario where you're building an ERP for a retail chain with two stores, tracking inventory, sales, employee shifts, and a restocking project.

import {
  ISOStringDate,
  Timespan,
  Address,
  Geolocation,
  Currency,
  Person,
  WorkLog,
  CareerShift,
  OrganisationalUnit,
  Item,
  Facility,
  Stock,
  StockMovement,
  Sale,
  Project,
  Task,
  DATA_ROLE_REAL,
  DATA_ROLE_SALES,
} from '@asaidimu/erp-types/types';

// 1. Define Domain-Specific Concrete Types for the Retail Chain
//    These types specialize the generic ERP interfaces for our retail business context.

// Logistics Module Types
type RetailProductData = { unit: string; packaging: string };
type RetailProductMetadata = { brand: string; seasonality: string };
type RetailProductGroupMetadata = { category: string; department: string };
type RetailProduct = Item<RetailProductData, RetailProductMetadata, RetailProductGroupMetadata>;

type StoreCategory = "retail-store" | "warehouse-hub" | "returns-center";
type StoreStatus = "open" | "closed" | "under-renovation";
type StoreFacilityData = { floorAreaSqM: number };
type StoreFacilityMetadata = { managerName: string; contactPhone: string };
type RetailFacility = Facility<StoreCategory, StoreStatus, StoreFacilityData, StoreFacilityMetadata>;

type StockState = "available" | "reserved" | "sold" | "defective" | "in-transit" | "on-hold";
type ProductStock = Stock<
  RetailProduct,
  StockState,
  StoreCategory,
  StoreStatus,
  StoreFacilityMetadata,
  { lastAuditDate: ISOStringDate }
>;

type StockMovementType = "sale" | "transfer-out" | "transfer-in" | "return" | "waste" | "restock";
type ProductStockMovement = StockMovement<
  StockState,
  StockMovementType,
  { orderId?: string; customerId?: string },
  StoreCategory,
  StoreStatus,
  StoreFacilityMetadata
>;

// Finance Module Types (simplified for this example)
type RetailMedium = "cash" | "card" | "mobile-payment" | "store-credit";
type RetailAccountType = "sales-revenue" | "operating-expenses" | "payroll" | "inventory-asset";
type RetailAccountMetadata = { branchId: string; openedBy: string };
type RetailAccount = Account<RetailAccountType, RetailMedium, RetailAccountMetadata>;

// Human Resources Module Types
type EmployeeRole = "cashier" | "manager" | "stocker" | "security";
interface EmployeePersonalInfo extends Record<string, unknown> { // Extend RealPersonData structure for specific HR data
  bio: { name: { first: string; last: string; other?: string[] }; dateOfBirth: ISOStringDate; gender: string; placeOfBirth: Address<any, any>; appearance: any[] };
  relationships: any[]; groups: any[]; affiliations: any[]; nationality: any[]; address: any; contact: any[]; history: any; personality: any;
  employeeId: string;
  currentRole: EmployeeRole;
}
type EmployeeMetadata = { hireDate: ISOStringDate; departmentId: string; status: "active" | "on-leave" | "terminated" };
type RetailEmployee = Person<EmployeePersonalInfo, typeof DATA_ROLE_REAL, EmployeeMetadata>;

type ShiftLogData = { hoursWorked: number; shiftType: "morning" | "afternoon" | "night" };
type ShiftLogMetadata = { approvedByManagerId?: string; clockInLocation?: Geolocation };
type EmployeeShiftLog = WorkLog<ShiftLogData, ShiftLogMetadata>;

type OrgUnitData = { headId: string; budgetCode: string };
type OrgUnitMembershipData = { role: string; startDate: ISOStringDate };
type RetailOrgUnit = OrganisationalUnit<OrgUnitData, OrgUnitMembershipData, { locationId: string }>;

// Sales Module Types
// Re-using Party from sales.ts, which is a specialized Person.
type RetailPartyData =
  | ({ type: "natural"; identity: { name: { first: string; last: string; other?: string[] }; }; nationality: { country: string; id?: { number: string; document?: string; }; }; occupation?: string; role?: string; organization?: string; }
  | { type: "artificial"; name: string; industry: "retail" | "distribution"; incorporation: { type: "LLC" | "Inc"; number: string; date: string; country: string; document?: string; }; })
  & { contact: { email: string; phone?: string; }; address: Address<any, any>; tax: { number: string; document?: string; }; accounts: (string | Account)[]; };

type RetailParty = Person<RetailPartyData, typeof DATA_ROLE_SALES>;

type RetailSaleMetadata = { salesChannel: "in-store" | "online"; registerId?: string };
type RetailSale = Sale<RetailSaleMetadata>;

// Project Management Module Types
type RetailProjectMetadata = { customerPriority: "high" | "medium" | "low"; targetRevenue?: number };
type RestockTaskStatus = "planned" | "picking" | "in-transit" | "received" | "cancelled";
type RetailTask = Task<RestockTaskStatus, { requiredSkills: string[] }>;
type RetailProject = Project<RetailProjectMetadata>;


// 2. Instantiate and Link Data in a Cohesive Scenario

// Currencies
const USD: Currency = { code: "USD", symbol: "$", precision: 2 };

// Facilities (Logistics)
const mainStore: RetailFacility = {
  id: "STORE-NYC-001",
  label: "Flagship NYC Store",
  category: "retail-store",
  status: "open",
  area: { unit: "sqm", value: 1500 },
  data: { floorAreaSqM: 1500 }, // Specific data for a store facility
  metadata: { managerName: "Alice Smith", contactPhone: "+12125551000" },
  location: { latitude: 40.748817, longitude: -73.985428, source: "geocoded" },
};

const warehouse: RetailFacility = {
  id: "WH-NJ-001",
  label: "New Jersey Regional Warehouse",
  category: "warehouse-hub",
  status: "active",
  area: { unit: "sqm", value: 10000 },
  data: { floorAreaSqM: 10000 },
  metadata: { managerName: "Bob Johnson", contactPhone: "+12015552000" },
  location: { latitude: 40.7834, longitude: -74.0089, source: "geocoded" },
};

// Products (Logistics)
const summerDress: RetailProduct = {
  id: "DRS-SUMMER-RED-M",
  label: "Summer Midi Dress (Red)",
  description: "Lightweight red midi dress, 100% cotton.",
  data: { unit: "pieces", packaging: "polybag" },
  metadata: { brand: "FashionFlow", seasonality: "Summer" },
  group: { id: "GRP-DRESSES", label: "Dresses", description: "All dress styles", metadata: { category: "Women's Apparel", department: "Clothing" }, parent: undefined },
  type: "fungible", // Though dresses could be non-fungible based on specific SKUs
  tags: ["new-arrival", "cotton"],
};

// Stock (Logistics)
const storeDressStock: ProductStock = {
  id: "STOCK-DRS-001-NYC",
  product: summerDress, // Reference full product object
  quantity: 25,
  reserved: 5,
  acquired: "2025-03-25T10:00:00Z",
  storage: mainStore.id, // Reference facility by ID
  state: "available",
  batch: "SS2025-BATCH-A",
  unit: "pieces",
  expires: undefined,
  metadata: { lastAuditDate: "2025-04-01T15:00:00Z" },
};

const warehouseDressStock: ProductStock = {
  id: "STOCK-DRS-001-NJ",
  product: summerDress.id, // Reference product by ID string
  quantity: 500,
  acquired: "2025-03-20T08:00:00Z",
  storage: warehouse, // Reference facility by object
  state: "available",
  batch: "SS2025-BATCH-A",
  unit: "pieces",
  expires: undefined,
  metadata: { lastAuditDate: "2025-04-01T09:00:00Z" },
};

// Stock Movement (Logistics) - Transfer from warehouse to store
const transferMovement: ProductStockMovement = {
  id: "MVMT-TRANS-001",
  stock: warehouseDressStock.id, // The specific stock batch being moved
  type: "transfer-out",
  quantity: 100,
  unit: "pieces",
  source: warehouse.id,
  destination: mainStore.id,
  timestamp: "2025-04-02T11:00:00Z",
  description: "Transfer 100 summer dresses from NJ warehouse to NYC store for peak season.",
  metadata: { transferRequest: "REQ-456" }
};

// Financial Accounts (Finance)
const mainSalesAccount: RetailAccount = {
  id: "ACC-SALES-NYC",
  name: "NYC Store Sales Revenue",
  type: "sales-revenue",
  // Ledger and balance would be populated by actual transactions
  ledger: {
    "cash": [], "card": [], "mobile-payment": [], "store-credit": []
  },
  balance: { "cash": 0, "card": 0, "mobile-payment": 0, "store-credit": 0 },
  currency: USD,
  groups: undefined,
  metadata: { branchId: mainStore.id, openedBy: "finance-team" },
};

// HR - Employee and Organizational Unit
const storeManager: RetailEmployee = {
  id: "EMP-SM-001",
  data: {
    type: "natural",
    bio: {
      name: { first: "Alice", last: "Smith", other: [] },
      dateOfBirth: "1985-05-20T00:00:00Z",
      gender: "Female",
      placeOfBirth: { country: "USA", metadata: {} },
      appearance: []
    },
    currentRole: "manager",
    employeeId: "EMP-SM-001",
    address: {
      residence: {
        street: "123 Main St", city: "New York", state: "NY", postalCode: "10001", country: "USA",
        residency: { start: "2020-01-01T00:00:00Z" }, priority: 1, metadata: {}
      }, currentLocation: undefined
    },
    affiliations: [], contact: [], groups: [], history: { finance: { accounts: [], transactions: [], taxInfo: [], income: [], debts: [] }, health: { weight: [], height: [], medicalHistory: [], allergies: [], medications: [], surgeries: [] }, legal: [] },
    nationality: [{ country: "USA", status: "citizen", ids: [] }], personality: {}, relationships: [],
  },
  metadata: {
    'data-role': DATA_ROLE_REAL, // Required for Person metadata
    hireDate: "2020-01-01T09:00:00Z",
    departmentId: "DEPT-NYC-MGT",
    status: "active"
  },
};

const salesDepartment: RetailOrgUnit = {
  id: "DEPT-NYC-SALES",
  name: "NYC Sales Department",
  parent: mainStore.id, // Parent facility reference
  members: [{ person: storeManager.id, role: "Department Head", startDate: "2022-03-01T00:00:00Z" }],
  data: { headId: storeManager.id, budgetCode: "SLS-NYC-BUDGET" },
  metadata: { locationId: mainStore.id },
};

// Sales - Parties
const supplierParty: RetailParty = {
  id: "PARTY-SUPP-FABRIC",
  data: {
    type: "artificial",
    name: "Global Fabric Co.",
    industry: "distribution",
    incorporation: { type: "Inc", number: "INC98765", date: "2000-01-01T00:00:00Z", country: "USA" },
    contact: { email: "info@globalfabric.com", phone: "+1800FABRIC" },
    address: { country: "USA", area: "Los Angeles", region: "CA", postalCode: "90001", metadata: {} },
    tax: { number: "TAXFABC001", document: "EIN-GFABC001" },
    accounts: ["ACC-SUPP-FABRIC-001"], // Assuming supplier has an account
  },
  metadata: { 'data-role': DATA_ROLE_SALES },
};

const ourCompanyParty: RetailParty = {
  id: "PARTY-OUR-RETAIL",
  data: {
    type: "artificial",
    name: "Our Retail Inc.",
    industry: "retail",
    incorporation: { type: "Inc", number: "INC12345", date: "2015-07-10T00:00:00Z", country: "USA" },
    contact: { email: "purchasing@ourretail.com", phone: "+1888RETAIL" },
    address: { country: "USA", area: "New York", region: "NY", postalCode: "10001", metadata: {} },
    tax: { number: "TAXRETAIL001", document: "EIN-RETAIL001" },
    accounts: [mainSalesAccount.id],
  },
  metadata: { 'data-role': DATA_ROLE_SALES },
};

// Sales - Purchase Order (our company purchasing from supplier)
const purchaseOrder: PurchaseOrder = {
  id: "PO-2025-001",
  issuer: mainSalesAccount.id, // Our company's account issuing the PO
  recipient: "ACC-SUPP-FABRIC-001", // Supplier's account
  status: "pending",
  date: "2025-04-01T00:00:00Z",
  items: [{ description: "Summer Dress (Red, M)", quantity: 100, price: 15.00, total: 1500.00, metadata: { productId: summerDress.id } }],
  deliveryDate: "2025-04-15T00:00:00Z",
  terms: "Net 30",
  notes: undefined, attachments: undefined, references: undefined,
};

// Sales - Customer Sale
const customerSale: RetailSale = {
  id: "SALE-CUST-001",
  state: "completed",
  documents: {
    invoices: [{
      id: "INV-CUST-001", type: "invoice", issuer: mainSalesAccount.id, recipient: "ACC-CUST-001", status: "completed",
      items: [{ description: "Summer Midi Dress (Red)", quantity: 1, price: 59.99, total: 59.99 }],
      subtotal: 59.99, taxes: [{ id: "TAX-SALES-001", type: "sales", amount: 5.32, rate: 8.875, description: "NYC Sales Tax" }],
      total: 65.31, currency: USD.code, date: "2025-04-03T14:30:00Z",
      validity: undefined, terms: undefined, due: undefined, complete: undefined, notes: undefined, attachments: undefined, references: undefined,
    }],
    receipts: [], quotations: [], proformas: [], credits: [], orders: [], deliveries: [], returns: [], billsOfLading: []
  },
  buyer: { // Direct object for a casual customer (often just their `Party` data)
    id: "PARTY-CUST-JANE",
    data: {
      type: "natural",
      identity: { name: { first: "Jane", last: "Doe" } },
      nationality: { country: "USA", id: undefined },
      contact: { email: "jane.doe@example.com", phone: undefined },
      address: { country: "USA", area: "New York", region: "NY", postalCode: "10001", geolocation: undefined, metadata: {} },
      tax: { number: "N/A", document: undefined },
      accounts: ["ACC-CUST-001"], // Fictional customer account
      occupation: undefined, role: undefined, organization: undefined
    },
    metadata: { 'data-role': DATA_ROLE_SALES },
  },
  seller: ourCompanyParty.id,
  created: "2025-04-03T14:25:00Z",
  status: { payment: "complete", fulfillment: "complete" },
  payments: ["TXN-SALES-9876"], // Assuming 'TXN-SALES-9876' is the transaction ID from the basic example
  metadata: { salesChannel: "in-store", registerId: "REG-01" },
  notes: undefined, attachments: undefined, modified: undefined, completed: undefined,
};


// Connections and implications:
// - `storeDressStock.quantity` would implicitly decrease after `customerSale` is completed (handled by application logic).
// - `mainSalesAccount.balance` would implicitly increase from the `customerSale`'s payment transaction.
// - `purchaseOrder` from `ourCompanyParty` to `supplierParty` might trigger a `ProductStockMovement` for `warehouseDressStock`.
// - `storeManager` is part of `salesDepartment` and their performance/shift logs (`EmployeeShiftLog`) are tracked in HR.

How This Fits Together

This example demonstrates the power of interlinked, generic types:

  • Logistics: ProductStock tracks inventory (summerDress) in RetailFacility locations (mainStore, warehouse). ProductStockMovement logs the movement of stock between these facilities.
  • Finance: RetailAccounts manage financial balances, and their ledger implicitly tracks Transactions that result from sales or purchases.
  • Human Resources: RetailEmployee (storeManager) is a Person with HR-specific metadata. They belong to an OrganisationalUnit (salesDepartment). EmployeeShiftLog tracks their time.
  • Sales: RetailSale orchestrates the entire process, referencing RetailParty for buyer/seller, TransactionDocument for invoicing, and linking implicitly to ProductStock for inventory.
  • Generics in Action: Notice how types like Item, Stock, Facility, Person, and Sale are specialized with domain-specific type arguments (e.g., RetailProductData, StoreCategory, RetailMedium) to fit the retail business context without changing the core library interfaces.

This interconnectedness, enforced by TypeScript at compile-time and supportable by anansi schemas at runtime, ensures data integrity and consistency across your ERP system.

Integration Tips

  • API Definitions: Use these types directly to define your REST API request and response payloads. For example, a POST /inventory/stock endpoint could accept ProductStock as its body.
  • Database Schemas: Map these TypeScript interfaces to your chosen database schemas (e.g., MongoDB documents, PostgreSQL tables). The JSON compatibility facilitates this.
  • Runtime Validation: Complement TypeScript's compile-time checks with runtime validation using the provided anansi schemas. This ensures incoming data (e.g., from external APIs, user input) conforms to the expected structure and constraints (e.g., quantity must be positive).

    import { getDefinition, validate } from '@asaidimu/anansi';
    import { SaleSchema } from '@asaidimu/erp-types/schema'; // Import schema directly
    
    // Get the Anansi schema definition for Sale
    const saleDefinition = getDefinition(SaleSchema);
    
    // Example: Validate an incoming sales object
    const incomingSaleData = {
      id: "SALE-XYZ",
      state: "completed",
      // ... rest of the sale data
      status: { payment: "complete", fulfillment: "complete" },
      buyer: { id: "CUST-001", data: { type: "natural", /* ... */ }, metadata: { 'data-role': 'sales' } },
      seller: { id: "OUR-BIZ", data: { type: "artificial", /* ... */ }, metadata: { 'data-role': 'sales' } },
      created: "2025-01-01T10:00:00Z",
      payments: ["TXN-123"],
      documents: { invoices: [] }
    };
    
    const validationResult = validate(saleDefinition, incomingSaleData);
    
    if (validationResult.success) {
      console.log("Data is valid:", validationResult.data);
    } else {
      console.error("Validation errors:", validationResult.errors);
    }
  • Domain-Driven Design: Leverage the modularity to build your application around these domains. Each module (src/finance.ts, src/logistics.ts, etc.) can correspond to a microservice or a distinct component in a monolithic architecture.

Best Practices

  1. Declarative Typing:

    • Do: Define named types for generic parameters (e.g., type MyProductData = { unit: string } then Item<MyProductData, ...>).
    • Why: Improves readability, reusability, and makes complex type signatures easier to manage.
    • Don't: Inline generic parameters directly (e.g., Item<{ unit: string }, ...>).
  2. Separation of Concerns:

    • Do: Separate core data (data), optional context (metadata), and finite states (union types).
    • Why: Keeps concerns distinct, allowing data to hold essential properties, metadata for flexible extensions, and union types for strict state management.
    • Don't: Lump all properties into a single, un-categorized object.
  3. Thoughtful Union Types:

    • Do: Use union types for finite, well-defined states or categories (e.g., type StockStatus = "available" | "sold" | "restocking").
    • Why: Clarifies constraints, prevents invalid values, and improves code comprehension.
    • Don't: Rely on raw string types where a limited set of values is expected.
  4. Referencing by ID or Object:

    • Do: Utilize the string | Type pattern (e.g., storage: string | Facility).
    • Why: Provides flexibility for API design (send just ID) and internal graph traversal (load full object).
    • Don't: Exclusively use string if you sometimes need to embed the full object, or exclusively use the full object if you only need the ID.

Anti-Patterns to Avoid

  • Ad-Hoc Generics: Creating types like const x: Stock<Item<{ unit: string }, { brand: string }>, ...> is cumbersome and hinders reusability. Always define named types for your generic arguments.
  • Ignoring Union Types: Allowing any string value where a specific set of statuses is expected (e.g., status: string instead of status: "active" | "inactive").
  • Overloading Domains: Adding fields that belong to another domain (e.g., price directly to Stock instead of Transaction or a separate ProductPrice interface). This violates modularity.
  • Mixing Runtime Logic with Types: Never embed validation logic or business rules directly into these interfaces. They are purely for data structure definition.

Project Architecture

This project does not implement a runtime application. Instead, it provides a structured collection of TypeScript interfaces and their corresponding anansi schema definitions that define the data models for an ERP system.

Core Components

The "core components" of this library are its TypeScript interface definitions and their corresponding anansi schema definitions, organized logically by business domain within the src/ directory.

  • src/types/: Contains pure TypeScript interfaces (.ts files), providing compile-time type safety and defining the structural contracts for all ERP data entities.
  • src/schema/: Contains anansi schema definitions, which are JavaScript/TypeScript objects that formally describe the structure and constraints of the data. These are crucial for runtime validation, API documentation generation, and dynamic form rendering.
  • common.ts (in both types and schema): Holds fundamental, cross-cutting types and their schemas (e.g., ISOStringDate, Address, Geolocation, Timespan), ensuring consistency across multiple modules.
  • index.ts (root level): Serves as the public API, re-exporting all primary interfaces from src/types and all schema definitions from src/schema, making them easy to import from the @asaidimu/erp-types package.

Data Flow

As a types-only library, @asaidimu/erp-types does not define runtime data flow or application logic. Instead, it provides the blueprint for how data should be structured and how different entities relate to each other.

  • Cross-Module Referencing: Types frequently reference entities from other modules using either their id: string or the full object (e.g., person: string | Person<any, any>). This pattern facilitates the creation of interconnected graphs of business data, where an entity in one domain (e.g., an Employee in HR) can be referenced in another (e.g., an Assignment in Project Management).
  • Generics for Flexibility: Extensive use of generics (<TData>, <TMetadata>, <TState>) allows consumers to define specific data shapes for their unique business contexts while adhering to the library's core structure. This means the "data flow" is defined by your application's implementation, guided by these flexible type contracts.

For example, a Sale type in the sales module might implicitly "flow" data to Account types in the finance module (for revenue recording) and Stock types in the logistics module (for inventory reduction). The library dictates what that data looks like, but your application code handles how it is moved and processed.

Extension Points

The library is designed for maximum extensibility:

  • Named Generics: By using named generic type parameters (e.g., Person<PersonData, DataRole, PersonMetadata>), consumers can inject their own specific data shapes without modifying the base interfaces. This allows for deep customization while retaining compatibility.
  • Metadata Fields: Most core interfaces include a metadata?: Record<string, unknown> field (or similar generic types). This provides a flexible escape hatch for adding arbitrary, context-specific properties to any entity without extending the core type itself.
  • Union Types as Customization: For fields like type or status, many interfaces use string or a default generic type (TState extends string). This allows developers to define union types (e.g., type MyOrderStatus = "pending" | "shipped" | "delivered") in their own projects and pass them as generic arguments, tailoring the schema to their specific state machines.
  • anansi Schemas: The modular nature of anansi schemas means you can extend or compose existing schemas to define more complex validation rules or to generate specialized forms/documentation without altering the core library.

This design philosophy means that rather than forking the library for minor adjustments, users can extend and specialize the types and their validation rules directly within their own codebase.


Development & Contributing

We welcome contributions to @asaidimu/erp-types! Whether it's adding new modules, improving existing type definitions, or enhancing documentation, your input is valuable.

Development Setup

To set up the project for local development:

  1. Clone the repository:
    git clone https://github.com/asaidimu/erp-types.git
    cd erp-types
  2. Install dependencies: This project uses bun for package management and scripts.
    bun install
    (If you don't have Bun, you can use npm install, but Bun is recommended for script execution speed.)

Available Scripts

The package.json defines several useful scripts for development:

  • bun ci: Installs project dependencies.
  • bun clean: Removes the dist/ directory, cleaning up previous build artifacts.
  • bun prebuild: Executes bun clean and then runs a custom sync-package.ts script (not provided, but implied to prepare dist.package.json).
  • bun build: Compiles TypeScript files from index.ts to dist/ in CommonJS and ES Module formats, and generates TypeScript declaration files (.d.ts). This command internally uses tsup.
  • bun postbuild: Copies README.md and LICENSE.md to the dist/ directory, and moves dist.package.json to dist/package.json for proper package publishing.

To build the project:

bun run build

Testing

This library primarily consists of TypeScript interfaces and schema definitions, and its "testing" largely relies on:

  • TypeScript Compiler Checks: The bun run build command (which internally uses tsup and typescript) will perform comprehensive type checking across all files, ensuring that all interfaces are correctly defined and used. Any type errors indicate a problem in the definitions.
  • ESLint: The project uses ESLint with @typescript-eslint/eslint-plugin for code quality and consistency. While not explicitly defined as a separate lint script in package.json, running eslint src/ would apply these checks to enforce style and identify potential issues.

We encourage contributors to ensure their changes pass TypeScript compilation without errors and adhere to the project's coding style and eslint rules.

Contributing Guidelines

We appreciate your contributions! Please follow these guidelines:

  1. Fork the Repository: Start by forking the asaidimu/erp-types repository on GitHub.
  2. Create a Branch: Create a new branch for your feature or bug fix (e.g., feature/add-crm-types, fix/logistics-typo).
  3. Code Changes:
    • Pure Types: This library is strictly for TypeScript interfaces (src/types) and anansi schema definitions (src/schema). Do not add any runtime logic, utility functions, or data validation implementations directly into these files.
    • Consistency: Adhere to the existing coding style and naming conventions.
    • Generics & Extensibility: Favor using generics and metadata fields for flexible extensions rather than hardcoding specific values.
    • Documentation: Add JSDoc comments to new interfaces, types, properties, and schema definitions, explaining their purpose, usage, and any constraints.
    • Atomic Commits: Make small, focused commits with clear, descriptive messages following conventional commits (e.g., feat(sales): add sales order interface, fix(logistics): correct typo in stock field).
  4. Build & Verify: Run bun run build to ensure your changes compile without errors.
  5. Submit a Pull Request:
    • Open a Pull Request (PR) to the main branch of the original repository.
    • Provide a clear title and description for your PR, summarizing your changes and their purpose.
    • Reference any related issues (e.g., Fixes #123, Closes #456).

Issue Reporting

If you encounter any bugs, have feature requests, or suggestions for improvement, please open an issue on GitHub:

  • Report Bugs: Provide a clear, concise description of the bug, steps to reproduce it, expected behavior, and your environment details (TypeScript version, Node.js/Bun version).
  • Request Features: Describe the feature you'd like to see, explaining its use case and why it would be beneficial to the library.
  • General Questions: Feel free to open an issue for questions about usage or design decisions.

All issues can be reported at the official GitHub repository: https://github.com/asaidimu/erp-types/issues.


Additional Information

Troubleshooting

  • TypeScript Errors:

    • Type 'X' is not assignable to type 'Y': This indicates a mismatch between your data structure and the expected interface. Double-check the generic parameters you're using.
    • Missing Properties: Ensure all required properties in an interface are provided.
    • Excess Properties: If you're encountering Object literal may only specify known properties errors, it means your object has properties not explicitly defined in the interface. Utilize metadata fields or extend interfaces if you need to add custom properties.
    • Dependency Issues: If bun install or npm install fails, clear your package manager cache (bun cache clean or npm cache clean --force) and try again.
  • Build Failures:

    • Ensure TypeScript is installed globally or locally (typescript in devDependencies).
    • Check your tsconfig.json for correct paths and compiler options.
    • Verify that tsup is installed and correctly configured.

FAQ

  • Q: Can I use this library with JavaScript? A: While the library itself is written in TypeScript and provides type definitions, you can use it in a JavaScript project. However, you won't benefit from the compile-time type safety. Your IDE (if it supports TypeScript definitions) might still provide type hints. For runtime validation in JavaScript, you can leverage the anansi schemas.

  • Q: Does this library include any runtime logic or validation? A: No, @asaidimu/erp-types is primarily a collection of TypeScript interfaces. It defines data shapes, not behavior. While it provides anansi schemas for validation, you'll need to implement your own runtime logic, data processing, and business rules.

  • Q: How do I add custom fields to an existing type? A: Many interfaces include a metadata?: Record<string, unknown> field (or a more specific generic type for metadata). This is the recommended way to add custom, application-specific data without modifying the core library. If you need to add a fundamental, non-optional field to a core type, consider opening an issue or a pull request to discuss its inclusion in the library.

  • Q: Can I use this with frameworks like NestJS, Express, or React? A: Absolutely! These types are framework-agnostic. You can use them to define DTOs (Data Transfer Objects) in your NestJS/Express APIs, model state in React components, or define data structures for any part of your application. The anansi schemas can also be integrated into API middleware for request body validation.

Changelog & Roadmap

For a detailed history of changes and new features, please refer to the CHANGELOG.md file.

Future Extensions (Roadmap):

Based on the strategic vision, potential future extensions for this ERP type library include:

  1. Machine Learning Integration: Predictive analytics models for inventory, sales forecasting, and resource planning.
  2. Blockchain Support: Immutable transaction records for critical business processes, enhancing transparency and auditability.
  3. IoT Connectivity: Direct integration with smart devices and sensors for real-time data collection in logistics and manufacturing.
  4. Augmented Reality (AR): Visual interfaces for warehouse management, maintenance, and field operations.
  5. Voice Interfaces: Natural language processing capabilities for hands-free operation and improved user interaction.
  6. Containerized Deployment: Enhanced types and considerations for microservice architectures with Kubernetes orchestration, facilitating cloud-native deployments.

License

This project is licensed under the MIT License. See the LICENSE.md file for full details.

Acknowledgments

Developed by asaidimu. Inspired by the need for robust, flexible, and type-safe data models in enterprise systems.

Last Updated: March 2025

3.0.1

5 months ago

3.0.0

5 months ago

2.0.0

5 months ago

1.0.1

7 months ago

1.0.0

7 months ago