Skip to main content

Modules

Modules are reusable packages of Stack9 resources (entities, screens, queries, automations, etc.) that can be shared across multiple Stack9 applications. They enable code reuse, standardization, and rapid development by packaging common functionality into distributable NPM packages.

What are Modules?

Modules are NPM packages that bundle:

  • Entities - Data models
  • Screens - UI configurations
  • Query Library - Data access queries
  • Automations - Workflow definitions
  • Action Types - Custom business logic
  • Entity Hooks - Validation logic
  • Connectors - External service integrations
  • Apps - Navigation structures

When you install a module, Stack9 automatically:

  • ✅ Registers all entities
  • ✅ Makes screens available
  • ✅ Loads queries into the library
  • ✅ Activates automations
  • ✅ Registers action types and hooks
  • ✅ Configures connectors

Why Use Modules?

Without Modules (Copy-Paste Approach)

# Manually copy files between projects
cp -r project-a/src/entities/user.json project-b/src/entities/
cp -r project-a/src/screens/user-list.json project-b/src/screens/
cp -r project-a/src/query-library/get-user.json project-b/src/query-library/
# ... copy 50+ more files
# Now maintain duplicates across projects

With Modules (NPM Package Approach)

# Install module
npm install @company/user-management-module

# Use immediately - no configuration needed
# All entities, screens, queries automatically available

Benefits:

  • DRY: Write once, use everywhere
  • Versioned: Semantic versioning for changes
  • Tested: Test once, trust everywhere
  • Maintainable: Update in one place
  • Shareable: Distribute via NPM registry

Core Modules

Stack9 provides essential core modules:

stack9-core-module

The foundational module required by all Stack9 applications.

{
"name": "@april9/stack9-core-module",
"version": "5.0.0",
"description": "Stack9 core module"
}

Provides:

  • Core entities (User, UserGroup, Media, etc.)
  • Settings app
  • User management screens
  • System administration screens
  • Core queries
  • Base automations

stack9-email-module

Email functionality and transactional email management.

{
"name": "@april9au/stack9-email-module",
"version": "1.1.0",
"dependencies": {
"@april9/stack9-core-module": "5.0.0",
"@april9/stack9-sdk": "5.0.0"
}
}

Provides:

  • Email template entities
  • Email log entities
  • Email sending automations
  • Template management screens
  • Email connector

stack9-marketing-module

Marketing automation and campaign management.

{
"name": "@april9au/stack9-marketing-module",
"version": "1.0.0",
"dependencies": {
"@april9/stack9-core-module": "5.0.0"
}
}

Provides:

  • Campaign entities
  • Lead management
  • Marketing automation workflows
  • Campaign analytics screens

stack9-pages-module

CMS functionality for managing web pages.

{
"name": "@april9au/stack9-pages-module",
"version": "1.0.0",
"dependencies": {
"@april9/stack9-core-module": "5.0.0"
}
}

Provides:

  • Page entities
  • Content management
  • Page builder screens
  • Publishing workflows

Module Structure

A Stack9 module follows this directory structure:

my-module/
├── package.json # NPM package configuration
├── tsconfig.json # TypeScript configuration
├── src/
│ ├── index.ts # Module entry point
│ ├── app.json # Module configuration
│ ├── entities/
│ │ ├── custom/ # Custom entities
│ │ │ ├── product.json
│ │ │ └── category.json
│ │ └── native/ # Native Stack9 entities
│ ├── screens/
│ │ ├── product-list.json
│ │ └── product-detail.json
│ ├── query-library/
│ │ ├── get-products.json
│ │ └── get-categories.json
│ ├── automations/
│ │ └── when-product-created.json
│ ├── action-types/
│ │ └── syncProductData.ts
│ ├── entity-hooks/
│ │ └── product.vat.ts
│ ├── connectors/
│ │ └── product-api.json
│ ├── apps/
│ │ └── products.json
│ ├── models/
│ │ └── stack9/ # Generated TypeScript models
│ └── utils/ # Utility functions
└── dist/ # Compiled output
├── index.js
├── index.d.ts
└── [all compiled resources]

Creating a Module

Step 1: Initialize Package

{
"name": "@company/product-management-module",
"version": "1.0.0",
"description": "Product management module",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist/**"
],
"dependencies": {
"@april9/stack9-core-module": "^5.0.0",
"@april9/stack9-sdk": "^5.0.0",
"knex": "^2.5.1",
"runtypes": "^6.7.0"
},
"devDependencies": {
"@april9/tsconfig": "^5.0.0",
"typescript": "^5.6.3",
"tsup": "^6.2.2"
},
"scripts": {
"build": "tsup",
"dev": "tsup --watch"
}
}

Step 2: Create app.json

{
"name": "Product Management Module",
"dateFormat": "DD-MM-YYYY",
"timeFormat": "h:mm a",
"timezone": "UTC",
"apps": [],
"cronJobs": [],
"mqHandlers": []
}

Step 3: Add Resources

Create entities, screens, queries as you normally would in a Stack9 app:

src/
├── entities/custom/
│ └── product.json
├── screens/
│ └── product-list.json
├── query-library/
│ └── get-products.json
└── apps/
└── products.json

Step 4: Build Module

# Build TypeScript and bundle resources
npm run build

# Output in dist/
dist/
├── entities/custom/product.json
├── screens/product-list.json
├── query-library/get-products.json
└── index.js

Step 5: Publish Module

# Publish to NPM registry
npm publish

# Or private registry
npm publish --registry=https://npm.pkg.github.com

Installing Modules

Install from NPM

npm install @company/product-management-module

Add to package.json

{
"dependencies": {
"@april9/stack9-core-module": "^5.0.0",
"@company/product-management-module": "^1.0.0"
}
}

Stack9 Auto-Discovery

Stack9 automatically discovers and loads modules from node_modules/:

// No configuration needed!
// Stack9 scans node_modules for *-module packages
// Automatically loads all resources

Module Configuration

Module Metadata (app.json)

{
"name": "Product Management",
"dateFormat": "DD/MM/YYYY",
"timeFormat": "HH:mm",
"timezone": "Australia/Sydney",
"logo": "https://example.com/logo.png",
"brandColor": "#3498db",
"theme": "light",
"apps": [
{
"name": "Products",
"key": "products",
"icon": "InboxOutlined"
}
],
"cronJobs": [
{
"name": "Sync products daily",
"schedule": "0 2 * * *",
"automationKey": "sync_products"
}
],
"mqHandlers": [
{
"queue": "process_product",
"actionTypeKey": "process_product_queue"
}
]
}

Module Dependencies

Modules can depend on other modules:

{
"name": "@company/advanced-products-module",
"dependencies": {
"@april9/stack9-core-module": "^5.0.0",
"@company/product-management-module": "^1.0.0",
"@company/inventory-module": "^2.0.0"
}
}

Stack9 resolves dependencies and loads in correct order.

Module Versioning

Follow semantic versioning:

{
"version": "1.2.3"
// MAJOR.MINOR.PATCH
// 1 = Breaking changes
// 2 = New features (backward compatible)
// 3 = Bug fixes
}

Version Ranges

{
"dependencies": {
"@company/product-module": "^1.0.0", // >=1.0.0 <2.0.0
"@company/inventory-module": "~1.2.0", // >=1.2.0 <1.3.0
"@company/shipping-module": "1.5.0" // Exact version
}
}

Module Best Practices

1. Single Responsibility

// ✅ Good - Focused module
{
"name": "@company/product-management-module",
"description": "Product catalog and management"
}

// ❌ Bad - Too broad
{
"name": "@company/everything-module",
"description": "Products, orders, customers, inventory, shipping..."
}

2. Clear Dependencies

// ✅ Good - Explicit dependencies
{
"dependencies": {
"@april9/stack9-core-module": "^5.0.0",
"@company/base-entities-module": "^1.0.0"
},
"peerDependencies": {
"@april9/stack9-sdk": "^5.0.0"
}
}

// ❌ Bad - Missing dependencies
{
"dependencies": {
// Assumes stack9-core-module is installed
}
}

3. Semantic Versioning

# Patch release (bug fixes)
1.0.0 → 1.0.1

# Minor release (new features, backward compatible)
1.0.1 → 1.1.0

# Major release (breaking changes)
1.1.0 → 2.0.0

4. Document Breaking Changes

# Changelog

## v2.0.0 (BREAKING)
- Renamed `Product` entity to `CatalogProduct`
- Changed query `getproducts` to require `category_id` parameter
- Removed deprecated `ProductCategory` entity

## v1.5.0
- Added `ProductReview` entity
- New query: `getproductreviews`

5. Test Before Publishing

# Link locally for testing
cd my-module
npm link

cd my-stack9-app
npm link @company/my-module

# Test in your app
npm start

# Unlink when done
npm unlink @company/my-module

6. Use Namespace Packages

# ✅ Good - Namespaced
@company/product-module
@company/inventory-module
@company/shipping-module

# ❌ Bad - Global namespace collision risk
product-module # Could conflict with other packages
inventory # Very generic name

Module Examples

Simple Module: Product Catalog

@company/product-catalog-module/
├── package.json
├── src/
│ ├── entities/custom/
│ │ ├── product.json
│ │ └── category.json
│ ├── screens/
│ │ ├── product-list.json
│ │ ├── product-detail.json
│ │ └── category-list.json
│ ├── query-library/
│ │ ├── get-products.json
│ │ └── get-categories.json
│ └── apps/
│ └── products.json

Complex Module: E-commerce

@company/ecommerce-module/
├── package.json
├── src/
│ ├── entities/custom/
│ │ ├── product.json
│ │ ├── cart.json
│ │ ├── order.json
│ │ ├── payment.json
│ │ └── shipping.json
│ ├── screens/
│ │ ├── product-catalog.json
│ │ ├── shopping-cart.json
│ │ ├── checkout.json
│ │ └── order-history.json
│ ├── automations/
│ │ ├── when-order-created.json
│ │ ├── when-payment-completed.json
│ │ └── when-order-shipped.json
│ ├── action-types/
│ │ ├── processPayment.ts
│ │ ├── calculateShipping.ts
│ │ └── sendOrderConfirmation.ts
│ ├── entity-hooks/
│ │ ├── order.vat.ts
│ │ └── payment.vat.ts
│ └── connectors/
│ ├── payment-gateway.json
│ └── shipping-api.json

Troubleshooting

Module Not Loading

Problem: Module installed but resources not appearing

Solutions:

  1. Verify package is in node_modules/
  2. Check module name ends with -module
  3. Restart Stack9 application
  4. Check logs for loading errors

Version Conflicts

Problem: Multiple modules require different versions of same dependency

Solutions:

  1. Use npm ls to see dependency tree
  2. Update modules to compatible versions
  3. Use resolutions in package.json (Yarn)

Resource Conflicts

Problem: Two modules define same entity/screen key

Solutions:

  1. Rename resources with module prefix
  2. Use unique keys: module1_customer vs module2_customer
  3. Choose which module to use

Next Steps

Now that you understand Modules, learn about: