GuidesDesign process and tickets
How to write a product ticket engineers can build from
A product ticket template for e-commerce SaaS teams: problem, evidence, design, states, pass or fail acceptance criteria, out of scope and analytics.
In short: A product ticket engineers can build from states the problem, who has it, the evidence that it is real, the design, every state the screen can be in, acceptance criteria written as pass or fail sentences, what is out of scope, and which analytics events to fire. Given/When/Then helps for flows with a clear trigger. Five to twelve criteria is the healthy range for a feature-sized ticket, and more than that usually means it should be two tickets.
Why do engineers send tickets back with questions?
A ticket that says "Add CSV export to the affiliates table" is a title, not a ticket. The engineer who picks it up has to decide which columns, what happens with 50,000 rows, whether staff accounts can export, what the file is called, and what the merchant sees while it generates. Each of those is a question, and each question is a day of latency while it waits in Slack.
I shipped 80+ features end to end at Social Snowball and built the engineering support function there, which meant I saw both sides: the tickets I wrote and the questions they produced. In my experience the questions are rarely about the feature's purpose. They are about the edges: states, permissions, limits, and what "done" meant. The template below exists to answer those before anyone asks.
What goes in a product ticket?
Eight sections, in this order. The order matters because it forces you to justify the work before you describe it.
1. Problem
One or two sentences in the merchant's words, not yours. "Merchants cannot tell which affiliate drove an order without opening each order in Shopify" is a problem. "Improve attribution visibility" is a wish. If you cannot write the problem as something a merchant said or did, the ticket is not ready.
2. Who it is for
Name the segment. Stores on the Growth plan with more than 20 active affiliates. Merchants in their first week after install. Agencies managing several stores. "All users" is almost never true, and it hides the trade-offs you will have to make about defaults.
3. Evidence
Link to the thing that proves the problem exists. A support ticket. A Shopify App Store review. A PostHog funnel showing where merchants drop. A count of how many stores hit the condition last month. PostHog's funnels docs describe funnels as a way to visualise your flows and understand where the friction points are, and a screenshot of one with the drop-off step circled is worth more than a paragraph of reasoning. If there is no evidence, say so. "Founder request, no data yet" is honest and tells the engineer how firm the spec is.
4. Design
A link to the Figma frame marked Ready for dev, plus a sentence on what the design covers. If the ticket needs no design (a backend job, a limit change), say that too. What makes a design ready for this section is its own topic, covered in developer-ready design handoff.
5. States
List every state the screen or flow can be in, with a line each: empty, loading, error, partial, success. For the CSV export example: no affiliates yet (button disabled with a message), generating (progress indicator, button disabled), failed (error with retry, nothing downloaded), more than 10,000 rows (email the file instead), done (download starts, toast confirms). Engineers build the states you list and skip the ones you do not.
6. Acceptance criteria
Pass or fail sentences. The next section is about how to write them.
7. Out of scope
Say what this ticket does not do, especially the obvious next thing. "Scheduled exports are not included." "Does not change the affiliate detail page." This stops scope creep in review and stops the engineer from building something you did not want.
8. Analytics
The event names, when they fire, and their properties. affiliates_export_started with row_count and plan. affiliates_export_failed with reason. If you want to know in three months whether the feature was worth building, this is the only place to decide that. It also feeds the next round of prioritisation.
How do you write acceptance criteria as pass or fail?
An acceptance criterion is a sentence that an engineer, a QA tester or you can mark true or false by looking at the running product. It has three properties:
- It names an observable outcome, not an intention. "The export downloads as a .csv" passes. "The export works well" cannot be tested.
- It includes the condition. "When a store has zero affiliates, the export button is disabled and shows the message 'Add your first affiliate to export'." The state is part of the criterion.
- It has no adverbs. "Quickly", "clearly" and "properly" are opinions. Replace them with a number or a specific behaviour, or cut them.
Two formats work. A plain checklist is right for settings pages, tables and most UI work:
- Staff accounts without the Export permission do not see the export button.
- Exports over 10,000 rows send an email with a download link instead of downloading in the browser.
- The file name is
affiliates-{store-name}-{YYYY-MM-DD}.csv.
Given/When/Then is right when there is a clear starting state, a trigger and a result, which describes most multi-step flows. The Cucumber project's Gherkin reference defines Given as the initial context, When as an event or action, and Then as an expected outcome, and recommends three to five steps per example. In practice:
- Given a merchant on the Growth plan with 1,200 affiliates
- When they click Export on the affiliates table
- Then a .csv with 1,200 rows downloads within 10 seconds
- And a toast reads "Export complete"
Use Given/When/Then for the flows, and a checklist for the rules that apply everywhere. Mixing both in one ticket is fine. Writing everything as Given/When/Then is not, because a permission rule does not need a scenario wrapped around it.
A worked example
Here is an invented ticket for a Shopify affiliate app, shaped the way a real one would be. The numbers are illustrative.
| Section | Content |
|---|---|
| Problem | Merchants cannot see which affiliate drove an order without opening each order in Shopify. |
| Who | Merchants with 20+ active affiliates, mostly Growth plan. |
| Evidence | 14 support tickets in September tagged "attribution". Link to PostHog: 61% of merchants who open the Orders tab leave within 10 seconds. |
| Design | Figma frame "Orders table, affiliate column", Ready for dev. |
| States | Empty (no attributed orders yet), loading (orders syncing), error (Shopify sync failed), partial (some orders unattributed), success. |
| Criteria | 7 lines, one per state plus two permission rules. |
| Out of scope | Filtering orders by affiliate. Exporting the column. |
| Analytics | orders_affiliate_column_viewed, orders_affiliate_clicked with affiliate_id. |
The ticket reads in under two minutes and the engineer can start.
How many acceptance criteria is too many?
My range for a feature-sized ticket is five to twelve. Fewer than five usually means states or permissions are missing, not that the feature is simple. More than twelve usually means the ticket is two features, and the fix is to split it along the seam where the extra criteria cluster. If a ticket has twenty criteria and eight of them are about the email, the email is its own ticket.
This is a working rule, not a measured one. The nearest published guidance I know of is the Gherkin recommendation of three to five steps per scenario, which is about scenario length rather than count, but it points the same direction: short, specific, and many small ones over one long one.
Count also depends on who reads the ticket. A senior engineer who built the affiliates table last quarter needs fewer lines than a contractor who joined on Monday. Write for the contractor. The senior engineer skims and loses nothing.
Putting the template in Linear
A template only works if it is the default. Linear's issue templates docs explain that a template can be set as the default for a team, so each new issue in that team is created from it unless manually changed, and that standard templates can set issue properties and include placeholder text to prompt the issue creator for input. Put the eight headings in as placeholders. A blank heading that says "Evidence: link the ticket, review or funnel" gets filled in. A blank description does not.
One rule to pair with the template: no ticket moves to Todo with an empty Evidence or Criteria section. The founder's idea is still allowed in. It just goes in as a draft until someone has written down why and how you will know it is done.
Where to start
- Open the last five tickets your team shipped and count the Slack questions each one generated. Match each question to one of the eight sections. That tells you which section your team skips.
- Create the eight-section template in Linear and set it as the team default with placeholder prompts.
- Rewrite one upcoming ticket's acceptance criteria as pass or fail sentences, one state per line. Have the engineer read it and tell you what they would still ask.
- Add the two analytics events to that ticket before it starts, not after it ships.
- After a month, check the question count again.
Frequently asked questions
Should a product ticket include a user story?
Only if the "as a merchant, I want" line adds something the Problem and Who sections do not. In most e-commerce SaaS tickets it repeats them. A plain problem statement in the merchant's words is shorter and harder to fake.
Who writes the acceptance criteria, product or engineering?
Product or design writes the first draft, because they own the merchant outcome. Engineering reviews before the ticket starts and adds technical criteria, like rate limits or sync timing, that product would not know to include.
What if we have no usage data for the evidence section?
Write what you do have: a support ticket, a review, a sales call note, or "founder request, no data". The point of the section is honesty about how certain the problem is, not a requirement for a chart. Then add the analytics events so the next version of the ticket has data.
Does every bug ticket need all eight sections?
No. A bug needs the problem, steps to reproduce, the expected and actual behaviour, and the evidence. The eight sections are for feature work where there are decisions to make.