Skip to main content

Step 2: Create your first module

With the base app running, add a custom inventory package that the generators can pick up.

1. Scaffold the package

mkdir -p packages/inventory/src/modules/inventory
touch packages/inventory/src/modules/inventory/{index.ts,acl.ts,di.ts}

Populate the metadata in index.ts so the module shows up in registries:

packages/inventory/src/modules/inventory/index.ts
import type { ModuleInfo } from '@open-mercato/shared/modules/registry';

export const metadata: ModuleInfo = {
id: 'inventory',
title: 'Inventory',
version: '0.1.0',
description: 'Track stock levels for sellable items.',
};

Declare the RBAC features you plan to enforce:

packages/inventory/src/modules/inventory/acl.ts
export const features = [
'inventory.view',
'inventory.create',
'inventory.edit',
'inventory.delete',
];

Create an Awilix registrar even if you do not wire services yet—the file keeps the structure predictable:

packages/inventory/src/modules/inventory/di.ts
import type { AppContainer } from '@open-mercato/shared/lib/di/container';

export function register(_: AppContainer) {
// Register services when you introduce business logic.
}

2. Enable the module

Open src/modules.ts and reference the new package:

src/modules.ts
import { defineModules } from '@open-mercato/shared/modules';

export default defineModules([
{ id: 'auth', from: '@open-mercato/core' },
{ id: 'directory', from: '@open-mercato/core' },
{ id: 'entities', from: '@open-mercato/core' },
{ id: 'inventory', from: '@open-mercato/inventory' }, // 👈 new module
]);

Run the generators so the new module is included in the registry:

yarn modules:prepare

3. Add the first page

Create the backend page directory and metadata:

mkdir -p packages/inventory/src/modules/inventory/backend/inventory
touch packages/inventory/src/modules/inventory/backend/inventory/page.tsx
touch packages/inventory/src/modules/inventory/backend/inventory/page.meta.ts
backend/inventory/page.tsx
const InventoryLanding = () => {
return (
<div className="container">
<h1 className="margin-bottom--md">Inventory</h1>
<p>Welcome! You will add data grids and forms in the next steps.</p>
</div>
);
};

export default InventoryLanding;
backend/inventory/page.meta.ts
import type { PageMetadata } from '@open-mercato/shared/modules/registry';

export const metadata: PageMetadata = {
title: 'Inventory',
group: 'Operations',
order: 20,
requireAuth: true,
requireFeatures: ['inventory.view'],
};

Restart the dev server (or wait for hot reload) and open /backend. You should now see an Inventory link in the sidebar that leads to the placeholder page.

ℹ️ Override packaged pages by creating a file under src/modules/<module>/backend. Because your inventory module lives in a package you control, you can edit it directly. Core modules from @open-mercato/core can be replaced by adding files under src/modules/auth, src/modules/directory, etc.