Course image English for Software Engineers and IT Teams

Writing User Stories and Acceptance Criteria in Jira.

English for Software Engineers and IT Teams. Lesson 3.
Avatar - Clara

After the call, the real work starts: the ticket. If the story is unclear, developers build the wrong thing, QA tests the wrong thing, and everyone loses time. In this lesson you take rough notes from Northbank Digital’s backlog and turn them into a clean Jira user story with acceptance criteria that a cross-functional team can follow. You will read a short example ticket thread and notice what makes it actionable: clear context, precise wording, and testable outcomes. You will practise tightening vague phrases, adding edge cases, and separating “must-have” from “nice-to-have” in a diplomatic way. You will also practise writing a short comment that explains what changed and why, so the team does not need to guess. Your artefact is a completed user story with 4–6 acceptance criteria plus a short Jira comment that confirms scope, assumptions and next steps.

1. Spot what makes a Jira ticket actionable.

Clara

Today you’re doing something genuinely useful: turning rough backlog notes into a Jira user story that a developer and a QA engineer can actually work from without endless back-and-forth. We’ll stay in one situation the whole time: a Northbank Digital ticket for exporting invoices. In this first block, I want you to notice what “actionable” looks like on the page. Not fancy English, just clear context, clear scope, and outcomes you can test. You’ll read a short ticket thread. As you read, keep asking yourself three questions. One: do I understand who the user is and why they want this? Two: can I tell what’s in scope and what’s out? And three: could QA verify it without guessing? After you’ve read, you’ll answer a few focused questions, and I’ll help you tighten your language so it sounds crisp and professional in Jira.

The situation.

You’ve just had a quick call with Product. The call felt clear… but now comes the risky bit: writing the ticket. In real teams, the ticket becomes the “source of truth”. If it’s vague, people implement different versions in their heads.

In this lesson we’re working on one realistic backlog item at Northbank Digital:

  • Feature: export invoices as a CSV file
  • Where it will live: the Billing area in the web app
  • Why it matters: finance teams need the data for reporting

A model Jira ticket thread (read and notice).

Ticket: NB-2147 — “CSV export for invoices”

Leila (PM):

> Can we add a CSV export for invoices? Customers keep asking for it. Ideally soon.

Sam (Engineer):

> Happy to do it, but we need to define “invoices”. Are we exporting the list view only, or also invoice line items? Also, what date range should it cover?

Leila (PM):

> Let’s start with the list view only. Date range should be whatever is currently filtered in the UI. We need invoice number, date, total, currency, status, and customer name.

Marta (QA):

> Two edge cases to confirm:

> 1) What if there are 0 invoices in the filtered results?

> 2) What if the user doesn’t have permission to view Billing?

Sam (Engineer):

> Great. I’ll write this as a user story and add acceptance criteria. Out of scope: line items for now.

What makes it actionable?.

Notice the difference between “add CSV export” and the clarified version.

  • The team named the exact scope (“list view only”).
  • They aligned it with existing UI behaviour (“whatever is currently filtered”).
  • They listed fields (so engineering and QA don’t invent their own).
  • QA added edge cases (0 results, permissions).

Mini checklist you can reuse.

A ticket becomes actionable when it answers:

  1. Who is the user?
  2. What do they want to do?
  3. Why is it valuable?
  4. What is in scope / out of scope?
  5. How will we test it? (acceptance criteria)

In the next blocks, you’ll write your own story and criteria using useful chunks like:

  • “As a [user], I want to… so that…”
  • “Out of scope for now: …”
  • “Acceptance criteria:”
  • “Edge case to confirm: …”

For now, let’s check you really saw the “actionable” details in the model.

Practice & Feedback

Answer the questions in your own words (3–7 short lines total). Keep the same ticket situation (CSV export for invoices) and be specific.

  1. Who is the user in this ticket (or which team), and what do they need the export for?
  2. What is explicitly in scope?
  3. What is explicitly out of scope?
  4. Write one edge case QA raised, using the phrase “Edge case to confirm:”.

Don’t worry about perfect English yet. Focus on meaning and clarity, like a real Jira comment.

Reference phrases (from today’s chunk bank).

  • "As a [user], I want to… so that…"
  • "Out of scope for now: …"
  • "Acceptance criteria:"
  • "Edge case to confirm: …"

Tip.

In Jira writing, short sentences and concrete nouns usually beat long explanations. Prefer “list view only” to “the thing users see on the page”.

2. Turn rough notes into a clean user story.

Clara

Now let’s move from ‘understanding the ticket’ to actually writing the user story line. A good user story is not marketing and it’s not a technical design. It’s a simple sentence that tells the team who the user is, what they want to do, and why it matters. That’s it. You’re going to hear a short voice note-style recap from the PM, like the kind of thing you might get after a call: slightly messy, a few priorities mixed together, and one or two vague words. Your job is to extract the essentials and write one strong user story using the pattern “As a…, I want to…, so that…”. As you listen, don’t try to capture every word. Listen for: the user, the action, the value. Then we’ll tighten the wording so it’s plain English and it doesn’t accidentally promise more than we can deliver in this first iteration.

The micro-skill: a user story that doesn’t overpromise.

In Jira, the user story line is a contract. If it’s too broad, you’ve just created invisible scope. If it’s too technical, Product and QA struggle to validate it.

A strong B2 user story usually has:

  • User (a real role: finance admin, account owner, support agent)
  • Goal (one main action)
  • Value (why they care)

Useful pattern.

As a [user], I want to [do X] so that [value].

Notice the difference:

  • Weak: “As a user, I want invoices exported.” (Which user? Export how? For what?)
  • Better: “As a finance admin, I want to export the invoice list as CSV so that I can reconcile invoices in a spreadsheet.”

Keep it aligned with scope.

You already saw the team agree: list view only and use the current UI filters.

So your story should not accidentally include:

  • invoice line items
  • multiple export formats
  • scheduled exports
  • API endpoints (unless that’s explicitly the deliverable)

Example story options (all valid).

Option A (very direct):

> As a finance admin, I want to export the filtered invoice list as a CSV so that I can run monthly reporting in Excel.

Option B (more general value):

> As a finance admin, I want a CSV export of the invoice list so that I can process invoice data outside the app.

Option A is often better because it anchors the value and makes it easier to prioritise.

Your task in this block.

You’ll listen to Leila’s recap and write one user story line. After that, in the next block, we’ll turn it into acceptance criteria using “Given / when / then”.

Practice & Feedback

Listen to Leila’s recap of the requirement. Then write one user story line using exactly this pattern:

As a [user], I want to… so that…

Keep it aligned with the agreed scope: export invoices from the list view as CSV, using the current UI filters. Avoid adding new features such as line-item export or scheduled exports.

Write 1–2 sentences total. Aim for plain English, not technical implementation details. If you’re unsure which user role to choose, pick the most realistic one and be consistent.

Clara

3. Write testable acceptance criteria with edge cases.

Clara

Good. Once the story line is clear, acceptance criteria do the heavy lifting. Think of them as a testable agreement between Product, Engineering and QA. The simplest way to keep them unambiguous is to write them as observable behaviour: what the user does, and what the system does in response. In this block we’ll use two very common patterns. One is “The expected behaviour is…”, which is great for straightforward UI behaviour. The other is “Given… when… then…”, which is brilliant for avoiding misunderstandings because it forces you to define the starting state and the trigger. We’re still on the same ticket: invoice CSV export from the list view with current filters. You’ll write four acceptance criteria, and at least one should be an edge case. Don’t try to sound clever. Try to sound testable: someone should be able to say ‘pass’ or ‘fail’.

Why acceptance criteria reduce rework.

A user story tells us what and why. Acceptance criteria tell us what “done” looks like. Without them, engineers guess, QA guesses, and Product is surprised.

For NB-2147 (invoice CSV export), your criteria should answer:

  • Where does the export happen?
  • What does the CSV include?
  • What should happen when there’s nothing to export?
  • What happens if the user has no access?

Two practical formats (both are acceptable).

Format A: “The expected behaviour is…”.

Use it when the behaviour is simple and you want speed.

Example:

  • The expected behaviour is that the CSV contains one row per invoice in the current list.

Format B: “Given… when… then…”.

Use it when you want to eliminate ambiguity.

Example:

  • Given the user has applied a date filter, when they export as CSV, then the CSV includes only invoices within that date range.

A worked example set (notice the testable wording).

Acceptance criteria:

  1. Given I am on the invoice list page, when I click Export CSV, then a CSV file is downloaded.
  2. The CSV includes these columns: invoice number, invoice date, customer name, currency, total amount, status.
  3. Given filters are applied (date/status), when I export, then the CSV contains only the invoices shown in the list.
  4. Edge case to confirm: Given the filtered results are empty, when I export, then I still get a CSV with headers only (no rows).
  5. Given the user does not have Billing permission, when they attempt to access the invoice list, then they cannot see the export option.

“Must-have” vs “nice-to-have” (quietly built into AC).

Acceptance criteria should mostly be must-have. If you put nice-to-haves in AC, they stop being nice-to-haves.

If you want to protect scope, you can add a separate line later:

  • Out of scope for now: exporting invoice line items.

Now it’s your turn: write four acceptance criteria that a QA engineer can run as tests.

Practice & Feedback

Write 4 acceptance criteria for ticket NB-2147 (invoice CSV export).

Requirements:

  • Use the heading “Acceptance criteria:”.
  • Write at least 2 criteria using Given… when… then….
  • Include at least 1 edge case using “Edge case to confirm:”.
  • Keep them testable and aligned with scope (list view only, current filters, the agreed columns).

Aim for 6–10 lines total. You don’t need to include every possible detail, but each line should be something QA can verify without guessing.

Column list (agreed).

  • invoice number
  • invoice date
  • customer name
  • currency
  • total amount
  • status

Helpful starters.

  • "Given… when… then…"
  • "The expected behaviour is…"
  • "Edge case to confirm: …"

4. Clarify scope, assumptions and dependencies politely.

Clara

Acceptance criteria give clarity, but real tickets also need a small amount of ‘project hygiene’: what’s in scope, what’s out, what we’re assuming, and what we’re dependent on. This is where teams often create friction, because it can sound like you’re refusing work. Your goal is to be diplomatic: you’re not blocking, you’re protecting shared understanding. We’ll practise three very Jira-friendly lines: “This ticket is in scope for this release if…”, “Out of scope for now: …”, and “Dependency: we need… before we can…”. These phrases are calm and factual. They also prevent a common problem: someone merging extra requirements into the ticket later without noticing. In the activity you’ll do a short chat-style simulation. You’ll reply as the engineer in the ticket thread, with Product asking for an extra ‘nice-to-have’. Your job is to keep the tone helpful while still keeping scope under control.

Why this part matters.

Even with a good story and criteria, tickets still go wrong when:

  • “Nice-to-have” items quietly become “must-have”.
  • People assume behaviour that was never agreed.
  • A dependency blocks delivery, but nobody wrote it down.

The fix is not a long essay. It’s 3–6 lines of calm, explicit ticket hygiene.

High-value phrases (and what they do).

1) Protect the release scope.

  • This ticket is in scope for this release if…

Use this when you need a condition, not an argument.

Example:

> This ticket is in scope for this release if we reuse the existing invoice list API and don’t add line-item export.

2) Say “no” without sounding negative.

  • Out of scope for now: …

This doesn’t reject the idea. It parks it.

Example:

> Out of scope for now: exporting invoice line items and scheduled exports.

3) Stop hidden blockers.

  • Dependency: we need… before we can…

Example:

> Dependency: we need confirmation of the CSV column order before we can finalise QA tests.

Assumptions and open questions.

Two more Jira-friendly lines:

  • Assumption:
  • Open question:

Examples:

  • Assumption: the CSV uses the same currency formatting as the invoice list.
  • Open question: should the export include cancelled invoices by default?

Micro-template you can paste into Jira.

You can literally drop this into a ticket comment:

> Scope check:

> - This ticket is in scope for this release if…

> - Out of scope for now: …

> - Assumption: …

> - Dependency: …

> - Open question: …

Next, you’ll practise this as a short Slack/Jira-style thread, keeping the same NB-2147 scenario.

Practice & Feedback

Chat-style task: reply as Sam (Engineer) in the ticket thread.

Situation: Leila (PM) has just added a message: “Can we also include invoice line items in the CSV? It would be amazing for customers.”

Write a short, professional reply (6–10 lines) that:

  • stays friendly and collaborative,
  • clearly keeps the first version in scope (list view only),
  • uses all three of these phrases exactly once: “Out of scope for now:”, “Assumption:”, “Dependency: we need… before we can…”,
  • ends with a simple next step (for example, what you need Leila to confirm).

Keep it realistic for a Jira comment or Slack thread.

Language bank for a diplomatic scope reply.

  • "That makes sense. For the first iteration, I suggest we…"
  • "To keep this deliverable, can we treat X as a follow-up?"
  • "Out of scope for now: …"
  • "Assumption: …"
  • "Dependency: we need… before we can…"
  • "Open question: …"
  • "If you’re happy with that, I’ll update the ticket."

5. Draft the full ticket: story plus 4–6 criteria.

Clara

You’ve now built the components: a user story line, acceptance criteria that are testable, and a way to control scope diplomatically. In this block we’re going to assemble those pieces into a single clean Jira ticket description. I’ll give you a set of rough backlog notes, the kind you might receive in a hurry. Your job is to write a draft ticket description with a clear story and four to six acceptance criteria. Don’t worry, you’re not writing a perfect spec. You’re writing something the team can pick up in the next sprint without a meeting. As you write, keep checking: can someone implement this without guessing? Could QA verify it? Is anything important missing, like permission behaviour or empty states? And are you accidentally adding new scope? After you submit, I’ll help you tighten phrasing, remove ambiguity, and make sure your criteria are in a consistent format.

Your draft ticket description (what “good” looks like).

A clean Jira description is usually short and structured. Here’s a practical structure you can copy:

  1. User story (one sentence)
  2. Context (2–3 lines: where, why now)
  3. Acceptance criteria (4–6 lines, testable)

Example layout (formatting you can reuse).

User story

> As a finance admin, I want to export the filtered invoice list as a CSV so that I can run monthly reporting in a spreadsheet.

Context

  • Customers currently copy and paste invoice data manually.
  • First version is list view only.

Acceptance criteria:

  1. Given…, when…, then…
  2. The CSV includes columns: …

Rough backlog notes (your input).

Use these notes to draft your ticket. Some parts are vague on purpose; your job is to make the deliverable clear.

  • Add “Export CSV” on invoice list.
  • Needs to match whatever filters are applied (status, date range).
  • Columns: invoice number, date, customer, currency, total, status.
  • Should work for large customers too (some have lots of invoices).
  • Don’t include line items in v1.
  • If user can’t access Billing, they shouldn’t be able to export.
  • If there are no results, still download something useful.

A note on “large customers”.

This is where B2 writers often go too vague. “Should work” is not testable. If you don’t have a number, you can either:

  • turn it into an open question for Product, or
  • define a conservative target if the team already has a standard.

For example:

  • Open question: what is the maximum invoice count we should support for export?

In the final block, you’ll add a Jira comment that explains what changed and why. For now, focus on a solid draft description.

Practice & Feedback

Write a draft Jira ticket description for NB-2147 using the notes above.

Your draft must include:

  • A User story line using “As a…, I want to… so that…”.
  • A short Context section (2–4 lines).
  • Acceptance criteria: with 4–6 criteria. Make at least 2 of them “Given… when… then…”.

Optional but recommended: add one line starting with “Open question:” if you think something is not testable yet (for example, what “large customers” means).

Keep the scope consistent: list view export only, no line items in v1.

Quick self-check before you submit.

  • Could QA test each criterion as pass/fail?
  • Are the CSV columns clearly listed?
  • Did you cover permissions and empty results?
  • Did you avoid adding line items or scheduled exports?

Useful chunks.

  • "As a [user], I want to… so that…"
  • "Acceptance criteria:"
  • "Given… when… then…"
  • "Open question: …"

6. Post the update comment: what changed and next steps.

Clara

Final step: you’ve written the ticket content, but teams still need a short comment that explains what changed and why. This is especially important when several people have discussed the ticket, because otherwise someone returns two days later and asks, ‘Why is this out of scope?’ or ‘Who agreed this?’ Your comment should be brief and operational. You’re not writing a novel. You’re showing the team: here’s what I updated, here’s what we’re assuming, here’s the dependency, and here are the next steps. That’s how you reduce noise in Slack and keep Jira as a reliable record. In the task, you’ll write the actual comment you would post on NB-2147. Then I’ll respond like a reviewer: I’ll check tone, completeness, and whether your comment is easy to act on. Aim for something you’d be happy to send today in a real sprint.

The artefact: a Jira comment that prevents confusion.

A good ticket comment after a discussion does three jobs:

  1. Confirms the latest agreement (so nobody relies on memory).
  2. Protects scope (so nice-to-haves don’t sneak in).
  3. Creates next actions (so the ticket moves forward).

A simple, high-trust comment template.

Use this template when you’ve updated a story and AC:

> I’ve updated the ticket with the latest agreement.

> - Scope: …

> - Out of scope for now: …

> - Assumption: …

> - Dependency: …

> - Open question: …

> Next step: …

Model comment (for NB-2147).

> I’ve updated the ticket with the latest agreement.

> - Scope: CSV export from invoice list, using current UI filters.

> - Out of scope for now: invoice line items.

> - Assumption: CSV uses the same formatting as the invoice list (dates/currency).

> - Dependency: we need confirmation of the expected behaviour for empty results.

> - Open question: what maximum invoice count should we support for export in v1?

> Next step: Leila to confirm empty-state behaviour and max count; then we can size the ticket.

What “good” sounds like.

Notice the tone: factual and collaborative. No blame, no drama, no overconfidence.

Also notice the verbs:

  • “I’ve updated…” (done)
  • “we need confirmation…” (clear ask)
  • “then we can…” (next action)

Your final performance.

Now you will write your own Jira comment for NB-2147. Use your draft from the previous block as the basis, and make sure the comment matches your scope and criteria. Treat it as something your team will read quickly on a busy day.

Practice & Feedback

Write a single Jira comment you would post on ticket NB-2147 after updating the story and acceptance criteria.

Requirements:

  • 8–12 lines.
  • Must include the sentence: “I’ve updated the ticket with the latest agreement.”
  • Must include these labels (each on its own line): Scope:, Out of scope for now:, Assumption:, Dependency:, Next step:
  • Optional (recommended): add Open question: if something still needs confirmation.

Keep it calm and practical. Imagine Marta (QA) and Leila (PM) will read it and act on it without another meeting.

Quick reference: chunks from this lesson.

  • "I’ve updated the ticket with the latest agreement."
  • "This ticket is in scope for this release if…"
  • "Out of scope for now: …"
  • "Assumption: …"
  • "Dependency: we need… before we can…"
  • "Open question: …"

Reminder.

Your comment should match the ticket: invoice list export as CSV, current filters, agreed columns, and at least one edge case covered.

👈 Previous lesson Next lesson 👉