Reusable issue / case / ticket management for the MemberJunction platform
Install · Entity Model · How It Fits · Implementation Plan
⚠️ Status: early development. This repository is being built out from the implementation plan. The entities, packages, and components described below are the v1 design target, not yet a shipped release. See the plan for the phased build order and current scope.
Issue, case, and ticket tracking is a universal need -- products collect bug reports and feature requests, support teams manage cases, and apps need a way for users to send feedback and hear back. BizApps Issues provides this as a reusable MemberJunction Open App: a thin, shared foundation of issue/case primitives that any MJ application can depend on, rather than each app reinventing its own ticketing tables and workflow.
It is deliberately thin by design. Heavy ticketing experiences (SLAs, queues, customer portals, knowledge bases) are expected to be built on top of this app -- most notably by Izzy -- and external trackers (GitHub, Zendesk, Jira) plug in through a provider abstraction rather than being hardcoded into the framework core.
BizApps Issues sits in the BizApps layer cake, building on BizApps Tasks and BizApps Common:
bizapps-common People, Organizations, Addresses __mj_BizAppsCommon
▲
bizapps-tasks Tasks, Task Types (action hooks), links __mj_BizAppsTasks
▲
bizapps-issues Issues, Issue Types, Statuses, Comments __mj_BizAppsIssues ◄── this app
▲
Izzy SLAs, queues, portal, KB, agent triage
An Issue is the case; Tasks are the work. Rather than reinventing assignment, dependencies,
and Kanban/Gantt, BizApps Issues reuses BizApps Tasks: resolving an issue spawns Task records
linked back to the issue via the existing polymorphic TaskLink. IssueType mirrors the proven
TaskType action-hook pattern (OnCreate, OnStatusChange, OnAssign, OnClose) so issue
lifecycle automation is declarative.
BizApps Issues is a MemberJunction Open App. Once published, install it into any MJ environment using the MJ CLI:
mj app install https://github.com/MemberJunction/bizapps-issuesThis single command:
- Fetches the
mj-app.jsonmanifest from this repository - Validates MJ version compatibility (
>=5.0.0 <6.0.0) - Installs the dependencies BizApps Tasks and BizApps Common if not already present
- Creates the
__mj_BizAppsIssuesdatabase schema - Runs Skyway migrations to create the tables
- Loads seed data (issue types + statuses) via mj-sync metadata
- Installs npm packages into your MJAPI and MJExplorer workspaces
- Configures server bootstrap (
@mj-biz-apps/issues-server) inmj.config.cjs - Adds client bootstrap (
@mj-biz-apps/issues-ng) toopen-app-bootstrap.generated.ts
After installation, restart MJAPI and rebuild MJExplorer to activate.
mj app list # See installed apps
mj app info bizapps-issues # Show details and version
mj app upgrade bizapps-issues # Upgrade to latest release
mj app disable bizapps-issues # Temporarily disable
mj app enable bizapps-issues # Re-enable
mj app remove bizapps-issues # Uninstall (--keep-data to preserve schema)All tables live in the __mj_BizAppsIssues SQL schema, deployed via migrations.
| Category | Tables | Purpose |
|---|---|---|
| Core | Issue | The case / ticket / feedback record, with polymorphic reporter, assignee, and source |
| Classification | IssueType, IssueStatus | Lifecycle automation (action hooks) and workflow states |
| Collaboration | IssueComment | Threaded discussion (internal / email; external reserved for sync) |
Work items are not a new table. Issues produce
Taskrecords from BizApps Tasks, linked back via the existing polymorphicTaskLink-- so sub-tasks, multi-person assignment, dependencies, and Kanban/Gantt come for free.
Planned for v1.1 (external sync): IssueProvider and IssueExternalLink, backing a pluggable
BaseIssueProvider abstraction (GitHub first; Zendesk / Jira / Izzy later) plus a generic webhook
endpoint and reporter email notifications.
| Package | NPM Name | Role |
|---|---|---|
| Entities | @mj-biz-apps/issues-entities |
Strongly-typed entity classes with Zod validation |
| Actions | @mj-biz-apps/issues-actions |
Server-side action handlers |
| Core | @mj-biz-apps/issues-core |
IssueEngine, IssueService, issue→task spawning, lifecycle hooks |
| Server | @mj-biz-apps/issues-server |
GraphQL resolvers and server bootstrap |
| Angular | @mj-biz-apps/issues-ng |
UI components, generated forms, the "Report an Issue" entry point |
┌────────────┐ ┌──────────────────────┐ ┌───────────────┐
│ IssueType │────►│ Issue │◄────│ IssueStatus │
│ │ │ │ │ (workflow) │
│ On…ActionID│ │ Severity / Priority │ └───────────────┘
│ Default- │ │ Reporter (Person / │
│ TaskTypeID │ │ email) │
└─────┬──────┘ │ Assignee (poly: │ ┌───────────────┐
│ │ Person or Agent) │────►│ IssueComment │
│ │ Source (poly: any │ │ (internal / │
│ │ record) │ │ email) │
▼ └──────────┬───────────┘ └───────────────┘
BizApps Tasks │ spawns + links via TaskLink
TaskType ▼
BizApps Tasks: Task
Polymorphic assignee -- AssigneeEntityID + AssigneeRecordID (copied from BizApps Tasks) let
an issue be assigned to a Person or an AI Agent, so agent-driven triage needs no schema change.
Polymorphic source -- SourceEntityID + SourceRecordID capture what the issue is about --
any record in the system -- so feedback can point at the exact thing it concerns.
Type-driven lifecycle -- IssueType carries OnCreate / OnStatusChange / OnAssign / OnClose
action FKs (the BizApps Tasks TaskType pattern) plus an optional DefaultTaskTypeID, so triaging
an issue can auto-create work of the right type.
Pluggable external trackers (v1.1) -- a BaseIssueProvider abstraction keeps GitHub/Zendesk/Jira
sync out of the framework core. Each provider implements create/update/comment + webhook
verify/normalize; a single generic endpoint routes by provider type.
See the Implementation Plan for the complete schema-level field lists, migration conventions, and phased build order.
Loaded via mj-sync metadata files (metadata/), not SQL inserts -- so values are
version-controlled, declarative, and customizable per deployment.
| Type Table | Included Records |
|---|---|
| IssueType | Bug, Feature Request, Question, Feedback |
| IssueStatus | New, Triaged, In Progress, Waiting on Reporter, Resolved, Closed, Won't Fix |
API names below reflect the v1 design target and will be confirmed once CodeGen runs.
import { Metadata } from '@memberjunction/core';
import { IssueEntity } from '@mj-biz-apps/issues-entities';
const md = new Metadata();
const issue = await md.GetEntityObject<IssueEntity>('MJ.BizApps.Issues: Issues');
issue.Title = 'Export to CSV fails on large datasets';
issue.Description = 'Times out above ~50k rows.';
issue.ReporterEmail = 'user@example.com';
// IssueTypeID / StatusID resolved to the seeded "Bug" / "New" defaults
await issue.Save();import { RunView } from '@memberjunction/core';
const rv = new RunView();
const result = await rv.RunView<IssueEntity>({
EntityName: 'MJ.BizApps.Issues: Issues',
ExtraFilter: "Severity = 'High'",
OrderBy: '__mj_CreatedAt DESC',
ResultType: 'entity_object'
});This app is the shared substrate for two consumers:
- Izzy builds its Freshdesk/Zendesk-style support experience on top of these entities (extending, not duplicating), and can register itself as an issue provider.
- MJC cloud feedback uses BizApps Issues as the destination for in-product "Report an Issue / Submit Feedback" -- the entry point is surfaced through a framework Shell Extension rather than being hardcoded into MJ core. This supersedes the bespoke feedback machinery proposed in MJ PR #2699, re-homing it as the GitHub provider.
Declare the dependency in your mj-app.json:
{
"dependencies": [
{
"name": "mj-bizapps-issues",
"repository": "https://github.com/MemberJunction/bizapps-issues",
"versionRange": ">=1.0.0 <2.0.0"
}
]
}When users install your app, the MJ CLI installs BizApps Issues (and its own dependencies, BizApps Tasks and BizApps Common) first if they aren't already present.
git clone https://github.com/MemberJunction/bizapps-issues.git
cd bizapps-issues
npm installCreate a .env file at the repo root:
DB_HOST=localhost
DB_PORT=1433
DB_DATABASE=YourDatabase
DB_USERNAME=sa
DB_PASSWORD=yourpassword
GRAPHQL_PORT=4101npm run mj:migrate # Create schema and tables
npx mj-sync push --dir ./metadata # Load seed data (issue types + statuses)
npm run mj:codegen # Generate TypeScript/GraphQL/Angular code
npm run build # Build all packages (Turborepo)npm run start:api # GraphQL server at localhost:4101
npm run start:explorer # Angular app at localhost:4301bizapps-issues/
├── mj-app.json # MJ Open App manifest
├── apps/
│ ├── MJAPI/ # GraphQL API server (port 4101)
│ └── MJExplorer/ # Angular UI application (port 4301)
├── packages/
│ ├── Entities/ # @mj-biz-apps/issues-entities
│ ├── Actions/ # @mj-biz-apps/issues-actions
│ ├── Core/ # @mj-biz-apps/issues-core
│ ├── Server/ # @mj-biz-apps/issues-server
│ └── Angular/ # @mj-biz-apps/issues-ng
├── migrations/ # Skyway SQL migrations
├── metadata/ # Seed data (synced via mj-sync)
└── plans/
└── IMPLEMENTATION_PLAN.md # Design + phased build plan
Entities ──► Actions ──► Server ──► MJAPI
│ │
│ └──► Core
└──────► Angular ────────────► MJExplorer
| Layer | Technology | Version |
|---|---|---|
| Platform | MemberJunction | >=5.0.0 <6.0.0 |
| Runtime | Node.js | 18+ |
| Language | TypeScript | 5.9 |
| Database | SQL Server / Azure SQL | 2019+ |
| API | GraphQL (Apollo Server) | -- |
| UI Framework | Angular | 21 |
| Build | Turborepo | 2.x |
| Validation | Zod | 3.x |
ISC
Built on MemberJunction -- the open-source metadata-driven application platform.
