
Overview
It started with the premise: a company sells a combination of products and services. It needed to manage human resources, finance, inventory, and sales in one centralized platform, rather than using various separate spreadsheets. However, behind that premise lay complex issues: a balanced accounting system, a payroll system that must comply with government regulations, consistent stock levels, and seamless integration of business processes. I designed this application to be entirely server-side rendered using Laravel Blade and Livewire, with no Single Page Applications, no mobile apps, and no third-party integrations consuming JSON APIs in the initial stages. It was a simple software design. However, the internal ERP tool used by some staff didn't require the operational burden of a separate frontend or the discipline of API version management. What was needed was rapid iteration and an intuitive, uncomplicated user interface. The combination of Blade and Livewire perfectly suited this. The system is structured into four business modules: Identity & Access Management, Finance & Accounting, Sales & Inventory, and HR & Payroll. Everything runs within a single Laravel application. Each module has its own migrations, routes, and service classes. These modules do not directly access each other's internal components. I made this decision solely because of the disciplines enforced by a microservices architecture: clear boundaries, prohibition on directly accessing tables belonging to other domains, and communication through explicit contracts. That's the approach offered by a modular monolith. The modules communicate with each other through Laravel events, rather than direct method calls. When a Sales Order is marked complete, the system doesn't immediately access the Finance module to create a journal entry. Instead, the system triggers the SalesOrderCompleted event. A listener within the Finance module then responds to the event through a queue, so slow or failed accounting operations don't hinder users from processing new Complete Orders. Because the boundaries between modules are event-based, adding another business module connected to the same accounting engine requires much less effort than if the Sales and Finance modules were tightly coupled from the start. Journal entry engine: Every financial transaction in the system—such as a completed sale, payroll processing, vendor invoice, or payment receipt—ultimately generates a journal entry with debit and credit lines that must balance precisely. The engine creating these entries rejects anything that is unbalanced, even down to the smallest cent. Once posted, the data becomes immutable. Errors are corrected through an explicit void action accompanied by a mandatory reason; the audit trail must withstand rigorous scrutiny. Indonesian employee income tax (PPh21): This is the part of the system I oversee most strictly. As of 2024, Indonesia calculates monthly income tax withholding using a scheme called TER (*Tarif Efektif Rata-rata* or Average Effective Rate)—a rate determined by a table of brackets based on the employee's marital status and number of dependents. I input the official rate table data directly from the relevant regulation (PMK 168/2023) and validate the calculation logic against the Indonesian tax authority's official calculator. The payroll module also handles prorated calculations based on attendance: if an employee is absent without authorization during a pay period, their base salary is reduced proportionally, whereas paid leave and sick days are not subject to deductions. Identity & Access Management: Role-based access control built upon granular permissions. Consequently, "Sales Staff" and "Finance Managers" possess genuinely distinct capabilities enforced at the policy layer, rather than merely having certain menu items hidden from view. Finance & Accounting: A hierarchical chart of accounts and the previously described journal entry engine with balance guarantees. Profit and loss statements and balance sheets are available; the balance sheet calculates retained earnings in real-time, as the system does not yet feature a year-end closing process. Sales & Inventory: A product catalog that distinguishes between physical goods and services; sales orders that can combine both within a single contract; and stock that is reserved when an order is created and subsequently released or fulfilled based on the order's completion status. Order completion triggers synchronous invoice generation and initiates an event that creates accounting entries. HR & Payroll: Management of employees, departments, and attendance, along with the previously described payroll system—complete with calculations for BPJS contributions (Indonesia's social security and health insurance scheme) that split the cost between the employee and the employer. User-customized dashboards: The displayed charts are determined by access rights and tailored to information relevant to the user's specific role. Sales staff view revenue trends and top-selling products; finance staff view cash flow and accounts receivable aging details; and HR staff view headcount and payroll cost breakdowns.

