rishabh954/erp-system Turns Django Into an Enterprise Control Plane
A modular monolith for accounting, HR, inventory, and CRM, built around tenant isolation, auditability, and locked-down business workflows.
- This repo treats ERP as a coordination problem, with company scoping, service boundaries, and locking rules doing the real work.
- Its strongest idea is not the module list but the safety rails around business records, from soft delete to transaction-level sequence generation.
- The architecture is more disciplined than many larger ERP demos because it centralizes rules outside the view layer and keeps automation running in the background.
- It reads like a Django ERP blueprint with serious engineering intent, even if ecosystem maturity is still thin.
The hidden contract: every record belongs to a company
Most ERP projects start with modules. This one starts with control. The important question is not whether it can show invoices, employees, or stock. It is whether every record stays inside the right company boundary, even when the system is busy, automated, and shared across teams.
That is why the CompanyScoped pattern matters so much. It is the quiet foundation of the repo: business objects inherit company ownership, and the system treats cross-tenant leakage as a bug, not a feature gap. Soft delete fits the same logic. In ERP, deletion is rarely simple. Preserving history is part of the product.
What this buys the project: a record is never just a row. It is a row plus ownership, lifecycle, and audit context. That is the difference between a demo and a system you would trust with payroll or stock counts.
Why the service layer matters more than Django views
The repo makes a strong architectural bet. Views stay thin. Business logic lives in services. Repositories handle access patterns. That is not fashionable ceremony. In ERP software, it is how you keep one rule from being rewritten ten different ways across forms, APIs, and tasks.
class BaseService:
def __init__(self, repository):
self.repository = repository
def create(self, data, company):
self.validate(data, company)
self.log_activity("create", company)
return self.repository.create_for_company(data, company)
class BaseRepository:
def get_by_company(self, company, **filters):
return self.model.objects.filter(company=company, **filters)
The pattern is plain, but the effect is not. Once validation, logging, and notification sit above the repository, every module gets the same enforcement model. Accounting does not invent its own rules. HR does not bypass them. Inventory does not sneak around them because someone needed a faster view.
| Layer | Job | Risk if you skip it |
|---|---|---|
| View | Collect input and return responses | Rules spread everywhere |
| Service | Own business logic and side effects | Inconsistent workflows |
| Repository | Read and write scoped data | Tenant leaks and duplicated query code |
| Database transaction | Protect concurrency and integrity | Duplicate records and race conditions |
That table is the real story. The repo is trying to keep each layer honest.
The part most ERPs get wrong: concurrency
The most satisfying detail in the codebase is also the least glamorous: sequence generation is treated as a correctness problem. Invoice numbers, purchase orders, and similar identifiers cannot collide just because two users clicked at the same time. In business software, that is not a corner case. It is a production incident waiting to happen.
The nice part is that the repo does not solve this with hand-wavy uniqueness checks. It uses transaction boundaries and row locking. That is the right shape for the problem, because correctness has to live where the race condition lives.
A system that keeps working after the user logs out
A credible ERP does work in the background. This repo leans into that with scheduled tasks for depreciation, low-stock alerts, and audit-log cleanup. That matters because a business system is not only a place where people type things. It is also a machine that must keep accounting for time, inventory, and retention rules when nobody is watching.
@shared_task
def process_depreciation():
# update fixed asset values on schedule
...
@shared_task
def low_stock_alerts():
# notify when inventory crosses a threshold
...
@shared_task
def cleanup_audit_logs():
# enforce retention policy without manual intervention
...
That background layer gives the project real operating depth. It is not just a CRUD app with a scheduler bolted on. It is trying to behave like a system of record that continues to reconcile itself after users leave for the day.
What the module map reveals about the product
The repository is organized like a business, not like a generic web app. You can see the separation between core infrastructure and domain modules such as accounting, HRMS, inventory, sales, and authentication. That modular monolith shape is a smart fit here. ERP domains share data and rules constantly, so splitting them into microservices too early would only add friction.
| Aspect | This repo | Typical CRUD app |
|---|---|---|
| Structure | Core platform plus domain apps | One app, one view layer, one pile of models |
| Data model | Company-scoped and auditable | Often globally shared by default |
| Automation | Celery tasks for real business jobs | Ad hoc scripts or none at all |
| UI strategy | Server-rendered web app plus API parity | Usually one channel only |
| Business logic | Centralized in services | Leaks into views and serializers |
That shape also explains the product’s ambition. It is trying to be a reusable ERP foundation, not a single-purpose internal tool. The difference shows up in the boundaries.
Where it sits in the ERP landscape
Against the bigger open-source ERPs, this repo is not competing on breadth. It is competing on clarity of architecture. Odoo and ERPNext bring years of ecosystem gravity, mature modules, and distribution. IDURAR is closer in spirit as a modern web-stack ERP. Tryton is the clean Python comparison if you care most about modular design.
| Project | Architecture style | Stack | Tenant isolation | Automation | Ecosystem maturity | Best fit |
|---|---|---|---|---|---|---|
| rishabh954/erp-system | Modular monolith with service layer | Django, Python, Celery, PostgreSQL | Strong by design | Practical, task-driven | Early | A Django ERP blueprint |
| ERPNext | Full ERP platform | Frappe, Python, MariaDB | Built in | Broad | High | Teams wanting a mature open-source ERP |
| Odoo | Large modular platform | Python, PostgreSQL, custom frontend | Strong | Very broad | Very high | Companies that want reach and polish |
| IDURAR | Modern web ERP | Node, React, MongoDB | Project-specific | Useful but narrower | Growing | JavaScript teams wanting a similar stack |
| Tryton | Modular ERP framework | Python, PostgreSQL | Strong | Solid | Mature | Python shops that value lean modularity |
The honest read is that this repo is closer to a structured Django blueprint than a full ecosystem rival. That is not a weakness. It is the reason the codebase is interesting to study.
The verdict
This is a serious architectural sketch of an ERP, not yet a battle-proven platform. Its best ideas are the boring ones done well: isolate companies, centralize rules, lock critical writes, and keep background jobs alive. That discipline is rare, and it is the main reason the project stands out.
If you are evaluating it as a product, you should be cautious. The public footprint is thin, the ecosystem signals are limited, and there is not yet evidence of broad adoption. If you are evaluating it as a Django ERP design study, though, it is sharp, coherent, and worth learning from.