# Module Development

#### 1. Notable AdonisJS-based Business Systems

* Akpoho Invoicing Software: This is one of the most complete open-source business apps built on AdonisJS. It handles invoicing, quotations, and receipts. It’s designed as a SaaS-grade application, making it a great reference for how to handle financial data and multi-tenancy in Adonis.
* MVP Starter (AdonisJS community): While not a full ERP, this is a highly recommended "base" for business apps. It includes pre-built User Management, Roles, Permissions (RBAC), and Email verification—the "plumbing" you'd otherwise have to build yourself for an ERP.
* AdonisJS AdminLTE 3 / HexaDash: These are "Admin Dashboard" templates pre-configured for Adonis. If you already have a Vue FE, you might not need these, but their backend controllers often show the "standard" way to handle ERP-style CRUD.

***

#### 2. Implementing a "Module System" in AdonisJS

In an ERP, you shouldn't just hide menu items in the UI; you should be able to "turn off" entire modules (e.g., Invoicing, Inventory, HR) at the server level.

Here is the professional way to structure this in your Adonis backend:

**Step A: The Module Middleware**

Create a middleware that checks if a specific ERP module is enabled before allowing access to its routes.

TypeScript

```
// app/Middleware/ModuleEnabledMiddleware.ts
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

export default class ModuleEnabledMiddleware {
  public async handle({ response }: HttpContextContract, next: () => Promise<void>, [moduleName]: string[]) {
    const isEnabled = await MyConfigService.isModuleActive(moduleName) // Your logic here
    
    if (!isEnabled) {
      return response.status(403).send({ error: `The ${moduleName} module is not active.` })
    }
    await next()
  }
}
```

**Step B: Tagging the Menu Items**

In your `menus` table, add a `module_key` column. When building your menu tree for the Vue frontend, filter out items belonging to inactive modules.

TypeScript

```
// Inside your buildTree logic:
const activeModules = await this.getActiveModules(); // e.g., ['CRM', 'INVENTORY']

const menu = items.filter(item => {
  // If the item doesn't belong to a module, show it. 
  // If it does, check if that module is active.
  return !item.moduleKey || activeModules.includes(item.moduleKey);
});
```

***

#### 3. Why stay with Adonis for your ERP?

Since you are already using it, here is why you have a "strategic advantage" over people using Next.js or Express for an ERP:

1. Lucid Transactions: In ERPs, you often update 5 tables at once (Invoice, Ledger, Stock, Customer, Tax). Lucid’s transaction handling is rock-solid.
2. Bouncer (Authorization): Adonis has a first-party package called `@adonisjs/bouncer`. It’s built specifically for complex "Can this user edit this specific Invoice?" logic, which is the heart of an ERP.
3. Task Scheduling: ERPs need background jobs (sending monthly reports, cleaning up logs). Adonis has built-in support for Queues and Cron jobs (via packages like `adonis-scheduler` or `bullmq`) that are more integrated than in other JS frameworks.

#### Next Step for you:

Since you already have a Vue FE and an Adonis base, would you like me to show you how to structure a "Global Search" API in Adonis? In an ERP, being able to search "Invoice #123" or "Client: John" from a single search bar is usually the most requested feature.
