Skip to main content

Designing a Work Item Engine: Six Questions That Define Healthy Recipes

Think of a project tool as a recipe box. Every work item type, field, workflow, and layout answers six questions. This article breaks them down with real examples.

A project management tool is a lot like a well-organized recipe box. You have different types of dishes (work items), each with its own list of ingredients (fields), a set of steps to follow (workflows), and a layout that tells you what to do at each stage. But when you're building such a tool, you quickly realize that the real challenge isn't the ingredients—it's figuring out how to define them so they don't fall apart when you mix them.

Take a simple request from a tester: "When I close a bug, I should be required to fill in the verification result." That sounds reasonable. But if you swap "verification result" for "root cause," the rule might not work. Root cause analysis often happens before the fix is even submitted, and some low-severity bugs don't warrant a full investigation. So the design needs to be smarter: require the verification result at closure, but only require a root cause if the severity is high enough. That's not just a field—it's a set of rules that live in different layers of the system.

Six Questions Every Work Item Must Answer

From first principles, a work item type should answer six questions. These are the six layers of a healthy recipe, if you will:

  • What is this object? (Type identity: name, icon, lifecycle)
  • What can it store? (Attribute model: text, people, enums, hours, attachments)
  • How do users fill it out? (Forms and layouts)
  • How can it change? (Workflow: states, transitions, permissions)
  • What can it connect to? (Relationships: parent-child, dependencies)
  • Where do these rules apply? (Configuration scope: org, space, type, version)

You can combine these layers, but you shouldn't mush them into one giant "type configuration table." Each layer changes at a different pace and gets reused in different ways. For example, you can rename "Defect" to "Issue," but the API references should stay stable. The "Assignee" attribute can appear on requirements, tasks, and bugs, but the candidate pool might differ by space. That's why you separate them.

Type Defines Identity, Not Defaults

Many new project tools let you create a type with just a name and an icon. That's misleading. A type is the stable identity of a class of work objects, and it's the entry point for mounting other configurations. But it should not own a "default assignee."

Why? Because the default assignee is a rule on the assignee attribute, not on the type. Different teams using the same "requirement" type might have different default assignees. The product space might default to the creator, the delivery space might use the business line owner, and the functional space might not have a default at all. If you bake the default into the type, you'd have to create separate types for each scenario—a mess.

Also, default values are just computed results at creation time. If the fixed person leaves or the role becomes empty, the system should recalculate or prompt, not change the type definition. And eligibility should be an intersection of permissions, space membership, and account status. So the type only answers "what is this object?" The assignee attribute answers "who is responsible?" And the attribute rules answer "how do we get the default and who can be chosen?"

From Fields to Attributes: A Unified Form Model

Early tools called this "custom fields." That's intuitive, but it limits you to text boxes and dropdowns. Real work items are more complex: the assignee is a person object, attachments are resources with names and permissions, hours include estimates and logs, and parent items are references to other objects. So call it the "attribute model." The idea is: everything is an attribute, and attributes compose forms.

Common attribute types include text, number, date, person, enum, hours, attachment, reference, and computed. But the key is that the attribute definition is more stable than the control. "Severity" might be a dropdown on the page, but the platform also uses it for filtering, grouping, statistics, and automation. The control determines how the user inputs; the attribute determines how the system understands and stores that fact.

A full attribute definition includes a stable ID, name, description, data type, value structure, cardinality, default rules, null rules, server-side validation, applicable spaces, query capabilities, and references from layouts, workflows, reports, and APIs. Changing an attribute type after data exists is not a simple edit. If you change a free-text priority to a dropdown, you have to handle historical values like "high" or "P0." If you change hours from "hours" to "person-days," you need a conversion rule. So treat attribute changes as data migrations, not casual edits.

Field Scope: Global vs. Space

In the old days, you had global fields and project fields. But if you've defined a long-term container called a Space, you don't need a second container called "project" underneath. In this model, there are only two levels of attribute definitions: organization-level (for cross-space reuse) and space-level (for team-specific needs). A one-off delivery might need a "migration batch" field, but that's still a space attribute, just scoped to a version or iteration.

The governance principle is: the organization maintains the common language, the space maintains the business language, and the work item instance stores the current facts. Don't duplicate an attribute just for a temporary need, and don't promote every local concept to a global one. A good test: can the values from two spaces be compared in a single cross-space report? If not, don't share the same attribute ID.

Page Layouts Are Not Tables—They're Compositions

Once you have a unified attribute library, page layouts don't define data; they answer: "What should the user see, fill in, and do in this scenario?" For example, when closing a bug, the verification result should be required, but the root cause might only be required for high-severity bugs. The layout should reflect that.

There are at least five types of layouts: create, detail, edit, transition, and list. A common mistake is making the create form a mini-version of the detail page. That leads to users filling in junk just to submit. The create form should first establish the object: space, type, title, and essential context. Then, it should determine initial responsibility and workflow routing. If a "business line" determines the workflow, it must appear at creation. If a "root cause" only makes sense after analysis, don't force it upfront.

The detail page should let users first understand the item, then edit it. Put identity, status, and legal actions at the top; main content in the middle; high-frequency info in the sidebar; and tabs for child items, attachments, and comments. And remember: attribute configuration handles long-term data rules, page layout handles interaction, and workflow steps handle specific action requirements. Server-side validation must enforce data legality, not just front-end required flags.

Workflows Define Lifecycle, Steps Define Change

A workflow isn't a side config for page layouts. States represent stable phases, and steps (or transitions) represent actions that move an item from one state to another. "Pending Verification" and "Closed" are states; "Verify and Close" is a step. That step can require a tester role, open a transition form, collect the verification result, check if a root cause exists for severe bugs, update the closer and timestamp, and write an audit record.

A step includes: start state, target state, action name, allowed roles, fields to display, preconditions, server-side checks, post-actions (notifications, automations), and entry points (e.g., API). Just configuring a list of states isn't enough—users can change states arbitrarily. Steps let the platform explain "who did what, under what conditions, and why they moved to the next state."

When people talk about "multiple workflows per type," they often mix three things: whether the config layer allows multiple candidate workflows, what condition selects one at creation, and whether the selected workflow supports parallel nodes. Jira maps types to workflows via schemes; ONES has one workflow per type per project; Feishu uses a business line field to route to different templates; TAPD lets a category choose a workflow, which can be serial or parallel. Each choice has trade-offs: fixed mapping is simple and auditable, conditional routing is flexible but needs priority handling, and parallel nodes express cross-role collaboration but require merging and rollback logic.

Regardless of the approach, running instances must save the workflow version. Otherwise, changing the config could leave live items in limbo.

How a Work Item Gets "Cooked"

Defining types, attributes, layouts, and workflows isn't enough. The runtime must link them together. The admin defines the type, connects attributes, layouts, workflow mapping, relationships, and permissions. Before publishing, the platform checks for a unique initial state, that required attributes have a place to be filled, that default assignees fall within the legal candidate pool, and that routing rules don't conflict.

When a user clicks "Create," the system resolves the unique configuration based on org, space, type, and business context, computes defaults and candidate pools, matches the workflow version, and only then creates the instance. After creation, every change goes through step permissions, action inputs, business checks, atomic updates, and audit logs. Layouts are just a translation of runtime rules into a UI. Batch operations, imports, APIs, automations, and agents must all use the same server-side capabilities.

Relationship Rules Turn Forms into a Network

Work items aren't isolated records. A requirement splits into sub-tasks, a backend task might block integration, and a bug might relate to a requirement and a test case. You need at least two types of relationships: hierarchical (parent-child) and associative (named links like "blocks" or "depends on").

Hierarchical relationships aren't just a parent ID. The platform must define which types can be parents/children, whether multiple parents are allowed, max depth, cross-space allowance, how progress and hours roll up, and whether closing a child triggers a parent check. Associative relationships need names, direction, type ranges, cardinality, cross-domain scope, permissions, and business effects. "Blocks" and "is blocked by" are two sides of one directed relationship; "similar requirement" is undirected. From the attribute model, parent and related version can be reference attributes, but the relationship model validates whether the reference is legal.

Configuration Scope: From Project to Space

Here's a correction: in this article's terminology, Space and Project are not two layers. At least in Jira Cloud's current definition, Space is the old Project—the same container. Atlassian renamed it because "project" implies a start and end, but these containers often last for years. A Space is a long-term working boundary for a team, a product line, or a functional team. You don't create a "project" inside a space; you organize a delivery using goals, versions, iterations, milestones, or tags within the space.

So the configuration scope narrows to three layers: organization (global standards), space (team rules), and delivery context (versions, iterations, goals). These delivery contexts can participate in filtering and routing, but they shouldn't become a new configuration container. Otherwise, you'll have duplicated fields and divergent workflows for each project.

At runtime, the platform should read the org standard, parse the space's enabled config, select rules based on type and business context, and overlay user permissions to produce a single page. It should also be able to explain why: "This attribute comes from the org, this type matches this workflow, only these three people can be assignees because of your space role." Without such diagnostics, flexibility becomes a mystery.

Config Changes Are Rule Changes, Not Form Edits

Attributes, workflows, and layouts are referenced by many live items. Making "verification result" required on close might break a bulk close API. Deleting the "Pending Verification" state could leave existing bugs lost. Changing a 1:n relationship to n:n alters rollup and permissions. So you need a lifecycle for the configuration itself.

Give stable IDs to types, attributes, states, steps, layouts, relationships, and schemes. Show reverse references: which spaces, filters, reports, automations, and running instances use this config. Without that, impact analysis is guesswork. Use drafts, publishing, and versions for high-risk changes. Deleting a state or changing an attribute type should go through a versioned process, and you must decide whether existing instances stay on the old version or migrate to the new one.

When converting a Task to a Bug, you're not just switching a dropdown. You need to remap attributes, layouts, workflows, and relationships. Missing required attributes, source states that don't exist in the target workflow, parent-child validity, and attachments—all need handling. Type conversion is a constrained data migration, not a free action.

The Bottom Line: Type Is the Entry, Attribute Is the Fact, Workflow Is the Rule

When you look at a project tool's settings, it seems like you're just creating types, dragging fields, and drawing flowcharts. But what really sets a platform apart is how clearly it separates these layers. The type defines identity; attributes hold facts; layouts organize interaction; workflows constrain change; relationships connect objects; and configuration scope decides who's affected.

Going back to the opening question: "Require verification result when closing a bug" isn't about adding a required field to the detail page—it's about adding an action input to the "Close Bug" step. "Severe bugs must have a root cause before closing" isn't making root cause globally required—it's adding a conditional server-side check. They might appear on the same transition form, but they belong to different rule layers.

When a project management platform can consistently answer "what is this object, what facts does it store, how does it interact, how can it change, what can it connect to, and where do the rules apply," it graduates from a configurable table to an enterprise-grade work item platform. And just like a recipe, the secret isn't in any single ingredient—it's in how you define and combine them.

Share this article:

Comments (0)

No comments yet. Be the first to comment!