Back to work
ERP / SaaS·2026

Muneem ERP

A complete ERP platform for one company — accounting, inventory, manufacturing, school, learning, CRM, HR and payments in a single branded workspace.

Role
Full-Stack Engineer & ERP Specialist
Year
2026
Category
ERP / SaaS
Platform
Web App
Stack
FrappeERPNextPythonMariaDBRedisVue 3nginxAWSCloudflare
Muneem ERP dashboard interface
01

Why I built this

The company behind Muneem wanted one cohesive business stack — accounting, inventory and manufacturing, sales and procurement, HR and payroll, school fee management, online learning, and customer relationships — without juggling disconnected tools. Muneem delivers all of it on a single platform, and the roadmap points at an agentic ERP: a natural-language copilot that executes permission-checked operations over chat, with confirmation gates and a full audit trail. The flagship use case is a school principal asking 'which students are behind on fees?' and dispatching reminder emails in one conversation.

02

How it works

Finance core with a three-ledger model

GL Entry, Payment Ledger Entry and Advance Payment Ledger Entry keep accounting consistent through a full payment-request lifecycle (Draft → Initiated → Requested → Partially Paid → Payment Ordered → Paid → Cancelled), with bank reconciliation synced from Plaid.

Muneem School fee engine

Student admission, programs, assessments, attendance and grading — with an outstanding-amount tracking fee engine and its own Razorpay billing implementation, plus a student portal for guardians.

Learning, CRM and HR

A Vue 3 LMS with courses, quizzes, live classes and certificates (paid enrollments gated through Razorpay); an account-centric CRM with lead-to-deal conversion, call handling and a built-in WhatsApp API; and full HRMS with attendance, leave ledgers, payroll and appraisals.

A gateway-agnostic payments layer

A Payment Gateway registry abstracts eight providers — Razorpay, Stripe, PayPal, Braintree, GoCardless, Paytm, M-Pesa and Paymob — through one flow: Integration Request → controller verification → on_payment_authorized callback.

03

Key decisions

All Muneem identity — product names, logos, routes, colors — lives in one config/branding.py dictionary applied by a hook-only app at boot. App trees stay pure, so upgrades and merges can never wipe the branding.

ERPNext v16 conflicts with standalone CRM and HRMS which require Frappe v17. Instead of forcing one version, two instances run behind a unified nginx portal with shared Redis session SSO and scheduled master-data sync.

Every release migrates to staging first, runs a smoke-test loop, then backs up and migrates production. The sync runbook records every gotcha 'learned the hard way' so a release never breaks prod again.

04

Backend architecture

Dual-instance portal with SSO

A Frappe v16 instance (erpnext, education, lms, payments on port 8000) and a Frappe v17 instance (crm, hrms on port 9000) route through nginx by path or subdomain, with a shared Redis session layer for single sign-on and scheduled webhook/API sync for master data.

Single-server production blueprint

AWS EC2 t3.large running Ubuntu, MariaDB 11.8 with InnoDB tuning, Redis (cache :13000, queue :11000), supervisor-managed gunicorn workers, S3 for attachments and encrypted backups, and Cloudflare for DNS/CDN/WAF — with a planned Hetzner migration to cut cost.

Boot-time branding patch

The muneem_branding app overrides boot_session and extend_bootinfo to swap app titles, logos and routes per product, plus CSS/JS includes and a post-build string patcher — driven entirely by the branding config dictionary.

Payments gateway registry

Each of eight payment gateways registers itself against a common interface; payment documents flow through Integration Request → controller verification → on_payment_authorized, which updates the ERP document on authorization.

05

Challenges

High

Version conflict between ERP and CRM/HRMS

ERPNext v16 dropped the built-in HR module, and both CRM v2 and HRMS require Frappe v17 — incompatible with the v16 ERP stack. The multi-instance architecture document was written specifically to solve this, and the route guide documents the legacy Module Def confusion that resulted.

Medium

AWS free-tier can't build the platform

Free-tier-eligible instances OOM during builds, while the minimum viable production instance isn't free-eligible. The deployment plan maps a credit-burn schedule and a month-3 migration to Hetzner (~$16/mo vs ~$72/mo).

Medium

Sync and release drift across seven repos

Keeping seven app repos in sync with version branches requires a strict procedure — staging migrate and smoke test first, files backup before prod migrate, pinned payments app that must never be re-synced, and OOM-prone frontend builds needing raised Node heap.

06

What I learned

  • A hook-based overlay beats forking: merges can never wipe branding, and upgrades stay near-conflict-free.

  • One source of truth — a branding config dictionary plus a tracked module inventory with explicit automation gaps — makes a huge platform handover-able.

  • Staging-first discipline with a copy-paste smoke-test loop prevents production breakage.

Code snippets

muneem_branding/overrides/boot_session.pypython
def patch_bootinfo(bootinfo):
    app_map = {info["app_name"]: info for info in bootinfo.app_data}
    for internal_name, product in BRANDING["products"].items():
        if internal_name in app_map:
            entry = app_map[internal_name]
            entry["app_title"] = product["name"]
            if product.get("icon"):
                entry["app_logo_url"] = product["icon"]
            entry["app_route"] = product.get("route", entry.get("app_route", ""))