Apps
Apps are navigation modules that organize your Stack9 application into logical sections. Each app defines a sidebar menu structure, grouping related screens, entities, and features into cohesive units.
What are Apps?
Apps are JSON configuration files that:
- Define navigation structure - Organize screens into hierarchical menus
- Group related functionality - Bundle entities, screens, and workflows
- Control access - Set visibility (public vs internal)
- Customize appearance - Icons, themes, and ordering
- Enable modularity - Split large applications into manageable pieces
When you define an app, Stack9 automatically:
- ✅ Creates sidebar navigation
- ✅ Routes to screens
- ✅ Applies access controls
- ✅ Manages menu state
- ✅ Handles breadcrumbs
Why Use Apps?
Without Apps (Flat Navigation)
// All screens in one massive flat list
<Nav>
<Link to="/customer-list">Customers</Link>
<Link to="/sales-order-list">Sales Orders</Link>
<Link to="/product-list">Products</Link>
<Link to="/user-list">Users</Link>
<Link to="/report-list">Reports</Link>
// ... 100+ more links
</Nav>
With Apps (Organized Navigation)
{
"name": "Customer Management",
"key": "crm",
"icon": "UserOutlined",
"children": [
{
"key": "customers",
"name": "Customers",
"nodeType": "menuGroup",
"children": [
{ "key": "customer_list", "name": "Customer List", "link": "/crm/customer-list" },
{ "key": "customer_matches", "name": "Possible Matches", "link": "/crm/matches" }
]
}
]
}
Benefits:
- ✅ Organized: Logical grouping of related features
- ✅ Scalable: Easy to add new features
- ✅ Discoverable: Clear navigation hierarchy
- ✅ Maintainable: Change navigation in one place
- ✅ Secure: Control access by app
App File Structure
Apps are defined in src/apps/{app_key}.json:
{
"name": "Human Readable Name",
"key": "unique_app_key",
"description": "What this app does",
"nodeType": "appNode",
"icon": "IconName",
"theme": "default",
"visibility": "PUBLIC | INTERNAL",
"order": 10,
"children": [
// Navigation items
]
}
App Properties
Core Properties
| Property | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name in navigation |
key | string | Yes | Unique identifier (lowercase, no spaces) |
description | string | No | App description |
nodeType | string | Yes | Must be "appNode" |
icon | string | No | Icon name (Ant Design icons) |
theme | string | No | Theme name ("default") |
visibility | string | No | "PUBLIC" or "INTERNAL" (default: PUBLIC) |
order | number | No | Sort order in sidebar (lower first) |
children | array | No | Navigation items |
Visibility
{
"visibility": "PUBLIC" // Available to all users
}
{
"visibility": "INTERNAL" // Only for authenticated internal users
}
Navigation Node Types
1. App Node (Top Level)
The app itself - appears as a top-level item in the sidebar.
{
"name": "Customer Management",
"key": "crm",
"nodeType": "appNode",
"icon": "UserOutlined",
"children": [...]
}
2. Menu Group
Groups related links together with a collapsible submenu.
{
"key": "customers",
"name": "Customers",
"nodeType": "menuGroup",
"children": [
{
"key": "customer_list",
"name": "Customer List",
"nodeType": "link",
"link": "/crm/customer-list"
},
{
"key": "customer_merge_history",
"name": "Merge History",
"nodeType": "link",
"link": "/crm/merge-history"
}
]
}
3. Link
Direct navigation link to a screen.
{
"key": "customer_list",
"name": "Customer List",
"nodeType": "link",
"link": "/crm/customer-list",
"description": "View and manage all customers"
}
Real-World Example
CRM App
From a production Stack9 application:
{
"name": "Customer Management",
"key": "crm",
"description": "Customer Management",
"nodeType": "appNode",
"icon": "UserOutlined",
"theme": "default",
"visibility": "PUBLIC",
"children": [
{
"key": "keyword_search",
"name": "Keyword Search",
"nodeType": "link",
"link": "/crm/keyword-search"
},
{
"key": "customers",
"name": "Customers",
"nodeType": "menuGroup",
"children": [
{
"key": "customer_list",
"name": "Customer List",
"nodeType": "link",
"link": "/crm/customer-list"
},
{
"key": "customer_possible_matches",
"name": "Customer possible matches",
"nodeType": "link",
"link": "/crm/customer-possible-match/list"
},
{
"key": "customer_merge_history",
"name": "Customer merge history",
"nodeType": "link",
"link": "/crm/customer-merge-history"
},
{
"key": "outbound_correspondence",
"name": "Outbound correspondence",
"nodeType": "link",
"link": "/crm/outbound-corro/list"
}
]
},
{
"key": "club_list",
"name": "Clubs",
"nodeType": "link",
"link": "/crm/club-list"
},
{
"key": "advanced",
"name": "Advanced",
"nodeType": "menuGroup",
"children": [
{
"key": "customer_bulk_updates",
"name": "Customer bulk updates",
"nodeType": "link",
"link": "/crm/customer-bulk-update/list"
},
{
"key": "dedup_job_request_history",
"name": "Dedup job request history",
"nodeType": "link",
"link": "/crm/dedup-job-requests/list"
}
]
}
]
}
This creates a navigation structure like:
📊 Customer Management
🔍 Keyword Search
👥 Customers ▼
• Customer List
• Customer possible matches
• Customer merge history
• Outbound correspondence
🎪 Clubs
⚙️ Advanced ▼
• Customer bulk updates
• Dedup job request history
Admin App
{
"name": "Administration",
"key": "admin",
"description": "System administration",
"nodeType": "appNode",
"order": 999,
"icon": "SettingFilled",
"visibility": "INTERNAL",
"children": [
{
"key": "system_alerts",
"name": "System alerts",
"nodeType": "link",
"link": "/admin/system-alert/list"
}
]
}
Settings App
{
"name": "Settings",
"key": "_settings",
"nodeType": "appNode",
"description": "User management, system administration and monitoring",
"icon": "ScrewdriverWrench",
"visibility": "INTERNAL",
"children": [
{
"key": "user_access_management",
"name": "User access management",
"nodeType": "menuGroup",
"children": [
{
"key": "users",
"name": "Users",
"nodeType": "link",
"link": "/_settings/user/list",
"description": "Manage individual user accounts"
},
{
"key": "user_groups",
"name": "User groups",
"nodeType": "link",
"link": "/_settings/user-group/list",
"description": "Organise users into groups"
},
{
"key": "app_permissions",
"name": "App permissions",
"nodeType": "link",
"link": "/_settings/app-permission",
"description": "Control user access rights"
}
]
},
{
"key": "system_administration",
"name": "System administration",
"nodeType": "menuGroup",
"children": [
{
"key": "system_alert",
"name": "System alerts",
"nodeType": "link",
"link": "/_settings/system-alert/list",
"description": "Monitor and configure alerts"
},
{
"key": "job_requests",
"name": "Job requests",
"nodeType": "link",
"link": "/_settings/job-request/list",
"description": "Manage user-submitted requests"
}
]
}
]
}
Icon Names
Stack9 uses Ant Design icons. Common icons:
| Icon | Name |
|---|---|
| 👤 | UserOutlined |
| 🛒 | ShoppingCartOutlined |
| 📦 | InboxOutlined |
| 📊 | BarChartOutlined |
| ⚙️ | SettingFilled |
| 🏠 | HomeOutlined |
| 📄 | FileOutlined |
| 🔔 | BellOutlined |
| 🔑 | KeyOutlined |
| 🔧 | ToolOutlined |
| 📧 | MailOutlined |
| 💰 | DollarOutlined |
| 🔒 | LockOutlined |
| 📈 | LineChartOutlined |
See Ant Design Icons for full list.
Link Paths
Link paths follow the pattern: /{app_key}/{screen_route}[/{params}]
Examples
// List view
{
"link": "/crm/customer-list"
}
// Detail view with parameter
{
"link": "/crm/customer-profile/:id"
}
// With query parameters
{
"link": "/crm/customer-possible-match/list?workflow=1"
}
// Drawer or modal
{
"link": "/crm/customer-create"
}
Common App Patterns
1. Standard CRUD App
{
"name": "Product Management",
"key": "products",
"icon": "InboxOutlined",
"children": [
{
"key": "product_list",
"name": "Products",
"nodeType": "link",
"link": "/products/product-list"
},
{
"key": "category_list",
"name": "Categories",
"nodeType": "link",
"link": "/products/category-list"
}
]
}
2. Grouped Features
{
"name": "Sales",
"key": "sales",
"icon": "ShoppingCartOutlined",
"children": [
{
"key": "orders",
"name": "Orders",
"nodeType": "menuGroup",
"children": [
{ "key": "order_list", "name": "All Orders", "link": "/sales/order-list" },
{ "key": "pending_orders", "name": "Pending", "link": "/sales/orders/pending" },
{ "key": "completed_orders", "name": "Completed", "link": "/sales/orders/completed" }
]
},
{
"key": "customers",
"name": "Customers",
"nodeType": "link",
"link": "/sales/customer-list"
}
]
}
3. Reports App
{
"name": "Reports",
"key": "reports",
"icon": "BarChartOutlined",
"children": [
{
"key": "sales_reports",
"name": "Sales Reports",
"nodeType": "menuGroup",
"children": [
{ "key": "daily_sales", "name": "Daily Sales", "link": "/reports/daily-sales" },
{ "key": "monthly_sales", "name": "Monthly Sales", "link": "/reports/monthly-sales" }
]
},
{
"key": "customer_reports",
"name": "Customer Reports",
"nodeType": "menuGroup",
"children": [
{ "key": "customer_growth", "name": "Growth", "link": "/reports/customer-growth" },
{ "key": "customer_churn", "name": "Churn", "link": "/reports/customer-churn" }
]
}
]
}
4. Admin/Settings App
{
"name": "Settings",
"key": "settings",
"icon": "SettingFilled",
"visibility": "INTERNAL",
"order": 999,
"children": [
{
"key": "users",
"name": "User Management",
"nodeType": "menuGroup",
"children": [
{ "key": "user_list", "name": "Users", "link": "/settings/user-list" },
{ "key": "role_list", "name": "Roles", "link": "/settings/role-list" }
]
},
{
"key": "system",
"name": "System",
"nodeType": "menuGroup",
"children": [
{ "key": "system_logs", "name": "Logs", "link": "/settings/logs" },
{ "key": "system_config", "name": "Configuration", "link": "/settings/config" }
]
}
]
}
App Organization Best Practices
1. Group by Business Domain
// ✅ Good - Clear business domains
{
"name": "Customer Management",
"key": "crm",
"children": [/* customer-related screens */]
}
{
"name": "Sales",
"key": "sales",
"children": [/* sales-related screens */]
}
// ❌ Bad - Generic grouping
{
"name": "Management",
"key": "mgmt",
"children": [/* everything mixed together */]
}
2. Use Menu Groups for Subtopics
// ✅ Good - Organized subtopics
{
"children": [
{
"key": "customers",
"name": "Customers",
"nodeType": "menuGroup",
"children": [
{ "name": "All Customers", "link": "/crm/customer-list" },
{ "name": "New Customers", "link": "/crm/customers/new" },
{ "name": "VIP Customers", "link": "/crm/customers/vip" }
]
}
]
}
// ❌ Bad - Flat structure
{
"children": [
{ "name": "All Customers", "link": "/crm/customer-list" },
{ "name": "New Customers", "link": "/crm/customers/new" },
{ "name": "VIP Customers", "link": "/crm/customers/vip" },
{ "name": "Orders", "link": "/crm/order-list" },
{ "name": "Invoices", "link": "/crm/invoice-list" }
]
}
3. Order Apps Logically
// ✅ Good - Logical ordering
{ "key": "dashboard", "order": 1 }
{ "key": "crm", "order": 10 }
{ "key": "sales", "order": 20 }
{ "key": "reports", "order": 30 }
{ "key": "settings", "order": 999 }
// ❌ Bad - Random ordering
{ "key": "settings", "order": 5 }
{ "key": "crm", "order": 100 }
{ "key": "dashboard", "order": 50 }
4. Use Descriptive Names
// ✅ Good - Clear and descriptive
{
"name": "Customer Management",
"key": "crm"
}
// ❌ Bad - Unclear abbreviations
{
"name": "CM",
"key": "cm"
}
5. Set Appropriate Visibility
// ✅ Good - Public for customer-facing
{
"name": "Customer Portal",
"visibility": "PUBLIC"
}
// ✅ Good - Internal for admin
{
"name": "Administration",
"visibility": "INTERNAL"
}
Permissions and Access Control
Apps respect Stack9's role-based access control:
// Users with "crm_read" permission can see CRM app
// Users without permission won't see the app in navigation
// Configure in user roles:
{
"role": "Sales User",
"permissions": ["crm_read", "sales_read"]
}
URL Structure
Apps define the base URL path:
/{app_key}/{screen_route}[/{params}]
Examples:
/crm/customer-list
/crm/customer-profile/123
/sales/order-create
/reports/monthly-sales?month=2024-01
Testing Navigation
Test your app navigation:
-
Verify Links Work
- Click each navigation item
- Ensure correct screen loads
- Check URL parameters
-
Test Permissions
- Log in as different user roles
- Verify visibility rules work
- Check restricted access
-
Test Responsiveness
- Mobile view (collapsed menu)
- Tablet view
- Desktop view
Next Steps
Now that you understand Apps, learn about:
- Screens - Create UI screens linked from apps
- Entities - Define data models for your app
- Modules - Package apps into reusable modules
- How-To: Structure Your Application