Joining the Backend Team

User Stories and Acceptance Criteria

LuettavaEsikatselu

Katselet ilmaista esikatseluoppituntia.

In the previous lesson, we separated our requirements into functional and non-functional concerns.

We now have a broad understanding of the capabilities the system needs to support.

But a broad requirement is usually too vague to use directly as an implementation ticket.

For example:

Customers should be able to place orders.

This is an important requirement.

But if an engineer starts implementing based only on that sentence, many behaviours remain undefined.

Real software teams therefore break broad requirements into smaller, understandable, and testable units.

In this lesson, we will work with two common concepts:

User Story

and:

Acceptance Criteria

Their purpose is not to create process-heavy documentation.

Their purpose is to make sure everyone understands the same expected behaviour and knows when a change can reasonably be considered complete.


From Product Requirement to Engineering Work

Our current progression looks like this:

Product Requirement
        ↓
Requirement Analysis
        ↓
Functional Requirements
        ↓
User Stories
        ↓
Acceptance Criteria
        ↓
Engineering Tickets
        ↓
Implementation

This is not a rigid process.

Different companies work differently.

A small team may skip formal User Stories and move directly from a requirement to an engineering ticket.

But the underlying principle remains the same:

Before implementation starts, the expected behaviour must be sufficiently clear.


What Is a User Story?

A User Story is a short description of a desired capability from the perspective of a user.

A common format is:

As a <type of user>,
I want <some capability>,
so that <some outcome>.

For example:

As a Customer,
I want to place an Order,
so that I can purchase available Products.

This tells us three things.

Who?

Customer
What?

Place an Order
Why?

Purchase available Products

It does not describe the implementation.

It captures the intent behind the behaviour.


A User Story Is Not a Technical Specification

This distinction is important.

Consider:

As a Customer,
I want to view my previous Orders,
so that I can review my purchase history.

The story does not say:

GET /api/v1/orders

It does not say:

Use Spring Data JPA.

And it does not say:

Query orders by customer_id.

Those are implementation decisions.

A User Story primarily answers:

Who needs what, and why?

Technical design later answers:

How will we provide it?

Why the “Why” Matters

Consider this shorter story:

As a Customer,
I want to view my Orders.

It is understandable.

But adding:

so that I can review my purchase history

makes the intent clearer.

Why does that matter?

Because the underlying need influences later design decisions.

If the Customer only needed to check the status of their latest Order, the required API behaviour might be different.

If they need complete purchase history, then concerns such as:

pagination

historical data

sorting

become more important.

User intent provides context for technical decisions.


User Stories Are Not Mandatory Everywhere

Real engineering teams use different terminology.

One team may use:

User Story

Another may use:

Feature

Another:

Product Requirement

And another may go directly to:

Engineering Ticket

We use User Stories in this course because they are useful for learning how to decompose requirements.

We are not treating the process itself as the goal.

The important principle is:

The user-facing purpose of the work should be clear.


Our First User Stories

We can derive several User Stories from the initial Product requirement.

Browse Products

As a Customer,
I want to browse available Products,
so that I can decide what to order.

Create an Order

As a Customer,
I want to place an Order containing one or more Products,
so that I can purchase available items.

View Order History

As a Customer,
I want to view my previous Orders,
so that I can review my purchase history.

Cancel an Order

As a Customer,
I want to cancel an eligible Order,
so that I can stop an Order I no longer want.

Pay for an Order

As a Customer,
I want to pay for an Order,
so that the Order can proceed after payment.

Manage Products

As an Administrator,
I want to manage Products,
so that Customers can access the current Product catalog.

Manage Inventory

As an Administrator,
I want to manage Inventory,
so that available stock remains accurate.

These stories are useful.

But they are still not implementation-ready.

Important details are missing.

That is where Acceptance Criteria become useful.


What Are Acceptance Criteria?

Acceptance Criteria describe the conditions that must be satisfied before a Story or feature can be considered correctly implemented.

A simple way to think about them is:

How will we know that the requested behaviour has been implemented correctly?

Consider the User Story:

As a Customer,
I want to place an Order,
so that I can purchase available Products.

Possible Acceptance Criteria:

- An Order must contain at least one item.
- Every item must reference an existing Product.
- Every requested quantity must be valid.
- Requested Inventory must be available.
- The backend calculates the Order total.
- A valid request creates an Order.

The expected behaviour is now much more concrete.


Acceptance Criteria Do Not Describe Implementation

Acceptance Criterion:

Requested Inventory must be available.

That is appropriate.

But:

Use SELECT ... FOR UPDATE on the Inventory row.

is not an Acceptance Criterion.

That is a technical design decision.

The same requirement could potentially be satisfied through:

pessimistic locking

or:

optimistic concurrency control

or:

an atomic conditional database update

The Acceptance Criterion should remain implementation-independent unless the implementation technique itself is a genuine constraint.


Good Acceptance Criteria Are Testable

Weak:

Order creation should work correctly.

What does correctly mean?

Better:

Given sufficient Inventory,
when a Customer submits a valid Order,
then the system creates the Order.

And:

Given insufficient Inventory,
when a Customer requests more units than are available,
then the system rejects the Order.

Now the behaviour can be verified.


Given / When / Then

One common format for Acceptance Criteria is:

Given <initial condition>
When <action>
Then <expected outcome>

For example:

Given a Product with 10 units available
When a Customer orders 2 units
Then the Order is accepted

Negative scenario:

Given a Product with 1 unit available
When a Customer orders 2 units
Then the Order is rejected

This format is common in Behaviour-Driven Development, or BDD.

It is useful because it makes the sequence explicit:

initial state
    ↓
action
    ↓
expected outcome

But not every Acceptance Criterion needs to use this format.

For simple rules, a direct statement may be clearer.


Avoid Ceremonial Given / When / Then

Weak example:

Given that the system exists
When the Customer wants to browse Products
Then Products should be browsable

The format is present.

The clarity is not.

The purpose of Given / When / Then is not ceremony.

It is useful when:

initial state

action

result

all matter.

For a simple validation rule:

Order quantity must be greater than zero.

is perfectly sufficient.


Let’s Refine the Create Order Story

One of the most important capabilities in the first version is:

Create Order

User Story:

As a Customer,
I want to place an Order containing one or more Products,
so that I can purchase available items.

From our previous requirement analysis, we know several behaviours are still ambiguous.

To move the course project forward, we now establish concrete first-release rules.

From this point onward, the following rules are treated as agreed Product behaviour for v1.


An Order Must Have at Least One Item

An empty Order has no business value.

Therefore:

An Order must contain at least one item.

Invalid:

{
  "items": []
}

Quantity Must Be Positive

Each OrderItem quantity must satisfy:

quantity >= 1

Valid:

1
2
5

Invalid:

0
-1
-5

Fractional quantities are outside the scope of this system.

Products are treated as discrete units.


Referenced Product Must Exist

If the Customer references a Product that does not exist:

productId = unknown

the Order must not be created.

Criterion:

Every OrderItem must reference an existing Product.

Product Must Be Available for Ordering

For the initial version, an orderable Product must be active.

Later, Product browsing will refine availability further using Inventory.

But one rule is already clear:

Inactive Products cannot be ordered.

Product lifecycle will be modeled explicitly later.


Inventory Must Be Sufficient

Suppose:

Available Inventory = 5
Requested quantity = 3

The Order can proceed.

But:

Available Inventory = 5
Requested quantity = 6

must be rejected.

Important invariant:

Successful Order creation must not make
available Inventory negative.

We are not choosing the concurrency mechanism yet.

That belongs to technical design later.


The Backend Determines Price

The client is not the authoritative source of Product pricing.

Suppose a client sends:

{
  "productId": "9ed4c9a9-8761-4e4f-9f50-aef83f14c13d",
  "quantity": 2,
  "unitPriceCents": 100
}

but the actual Product price is:

5000 cents

The backend must not use the client's:

100

The backend loads the authoritative current Product price.

Criterion:

The backend determines the price of each OrderItem
and calculates the Order total.

In our eventual implementation, monetary values will use:

long cents

throughout the backend.


Purchase-Time Price Must Be Preserved

This is an important business clarification.

Suppose the Product price when the Order is created is:

2000 cents

Later, the Product price changes to:

2500 cents

The historical Order must still represent:

2000 cents

The past Order must not be rewritten because the current catalog price changed.

Requirement:

The price used when an Order is created
must remain part of that historical Order.

The implementation will later determine how that value is persisted.


Duplicate Product Entries

Suppose the same Product appears multiple times in one request:

Product A × 2

Product A × 3

For the initial version, we will not allow duplicate Product lines in the same Order request.

The client should combine them:

Product A × 5

Criterion:

A Product may appear at most once
in a single Order request.

This keeps the first version simple and unambiguous.


What Happens If One Item Is Invalid?

Suppose the Order contains:

Product A × 2

Product B × 3

Product C × 1

and Product C does not have sufficient Inventory.

We do not create a partial Order.

The entire request fails.

Criterion:

Order creation is all-or-nothing.

Either:

the entire Order succeeds

or:

no Order is created

This requirement will later become important when we design database transactions.


Order Creation Acceptance Criteria

Our complete first-pass Acceptance Criteria are now:

AC-1

An Order must contain at least one item.
AC-2

Each OrderItem must reference an existing Product.
AC-3

Each Product may appear at most once in the request.
AC-4

Each quantity must be a positive whole number.
AC-5

Only Products available for ordering may be included.
AC-6

Requested quantity must not exceed available Inventory.
AC-7

The backend determines the price of each OrderItem.
AC-8

The backend calculates the Order total.
AC-9

The purchase-time Product price must remain
part of the historical Order.
AC-10

If any item is invalid,
the complete Order request fails.
AC-11

A successful Order belongs to
the requesting authenticated Customer.

The Story is now far more actionable.


Notice What We Still Have Not Decided

We still have not defined:

database tables
JPA entities
Handler classes
Repository interfaces
HTTP status codes
locking strategy
transaction implementation

Acceptance Criteria define behaviour precisely enough to work with.

They do not dictate the technical solution.

That is exactly what we want.


Product Browsing Story

User Story:

As a Customer,
I want to browse available Products,
so that I can decide what to order.

Initial Acceptance Criteria:

AC-1

Only Products available for ordering are returned.
AC-2

Each result includes the Product information
required to make an ordering decision.
AC-3

Product price is included.
AC-4

The result supports multiple Products
without requiring the entire Product catalog
to be returned in one response.

The last criterion suggests that we will probably need bounded list results.

The concrete pagination contract belongs to API design later.


Why Pagination Appears Early

Suppose there are:

20 Products

Returning all of them may be harmless.

But later there could be:

100,000 Products

Returning every row in a single response would be poor design.

That means the need for bounded list behaviour can appear during requirement analysis even before we decide the exact pagination API.

We still do not invent:

page size = 20

at this stage.

That decision comes during API design.


Order History Story

User Story:

As a Customer,
I want to view my previous Orders,
so that I can review my purchase history.

Acceptance Criteria:

AC-1

A Customer can access only their own Orders.
AC-2

Previous Orders contain enough information
to understand what was ordered.
AC-3

Historical item prices remain unchanged
when current Product prices change.
AC-4

Order history supports multiple Orders
without requiring the entire history
to be returned in one response.

Notice that security is part of the user-facing behaviour:

A Customer can access only their own Orders.

That is not something we should postpone as somebody else's problem.


Order Cancellation Story

User Story:

As a Customer,
I want to cancel an eligible Order,
so that I can stop an Order I no longer want.

Previously:

eligible

was ambiguous.

For the initial release, the agreed rule is:

Only UNPAID Orders may be cancelled.

Paid-Order cancellation and refunds remain outside v1 scope.

Acceptance Criteria:

AC-1

A Customer may cancel their own UNPAID Order.
AC-2

A Customer may not cancel another Customer's Order.
AC-3

A PAID Order cannot be cancelled in v1.
AC-4

An already-CANCELLED Order cannot be cancelled again.
AC-5

Cancelling an Order restores the Inventory
consumed by that Order.
AC-6

A successfully cancelled Order remains CANCELLED.

An important consequence is now explicit:

cancel Order
    ↓
restore consumed Inventory

This will later become transactional behaviour.


Payment Story

User Story:

As a Customer,
I want to pay for my Order,
so that the Order can proceed after payment.

Initial Acceptance Criteria:

AC-1

A Customer may pay only for their own Order.
AC-2

Only an UNPAID Order is eligible for payment.
AC-3

Payment is processed through
the configured external Payment provider.
AC-4

A successfully confirmed payment
marks the Order as PAID.
AC-5

A failed payment must not mark
the Order as PAID.
AC-6

The same successful payment outcome
must not be applied twice.

The external integration will later introduce concerns such as:

timeout

retry

idempotency

partial failure

But the Acceptance Criteria establish the business expectation first.


Product Management Story

User Story:

As an Administrator,
I want to manage Products,
so that Customers can access
the current Product catalog.

The word:

manage

is too broad by itself.

For the initial version, we narrow it to:

create Product

view Product

update Product

deactivate Product

Physical deletion is not required.

Historical Orders may still reference that Product.

Acceptance Criteria:

AC-1

An Administrator can create a Product.
AC-2

An Administrator can update
supported Product information.
AC-3

An Administrator can deactivate a Product.
AC-4

A deactivated Product cannot be ordered.
AC-5

Deactivating a Product must not remove
historical Order information.
AC-6

Regular Customers cannot perform
administrative Product operations.

Product deletion is deliberately outside the current scope.


Inventory Management Story

User Story:

As an Administrator,
I want to manage Inventory,
so that available stock remains accurate.

For the initial version:

An Administrator can view
and set current Inventory quantity.

Acceptance Criteria:

AC-1

An Administrator can view current Inventory.
AC-2

An Administrator can set
the current available Inventory quantity.
AC-3

Inventory quantity cannot be set below zero.
AC-4

Regular Customers cannot modify Inventory.
AC-5

Inventory changes affect future Product availability.

We do not introduce:

Inventory audit ledger

warehouse management

stock movement history

because those capabilities are not part of the initial requirement.


Acceptance Criteria Should Cover Permissions

Ignoring permissions when defining backend behaviour is dangerous.

Suppose the Story is:

Customer can view an Order.

Weak Acceptance Criterion:

Order details are returned.

Better:

The requesting Customer owns the Order.

and:

Another Customer cannot access it.

Security behaviour is part of the feature.

It should not be postponed until someone later remembers to “add security.”


The Happy Path Is Not Enough

Consider:

Create Order

Happy path:

authenticated Customer
+
valid items
+
sufficient Inventory
=
Order created

If this is the only behaviour we define, we may miss important cases:

empty items

unknown Product

inactive Product

quantity = 0

negative quantity

insufficient Inventory

duplicate Product entry

Strong Acceptance Criteria cover both:

meaningful success behaviour

and:

meaningful failure behaviour

But Do Not Turn Every Test Case Into an Acceptance Criterion

We still need balance.

Acceptance Criterion:

Quantity must be a positive whole number.

That is enough.

We do not need separate criteria saying:

quantity = 0 fails

quantity = -1 fails

quantity = -10 fails

quantity = -999 fails

Those are test cases.

The requirement defines the rule.

The test suite verifies representative cases.


Acceptance Criteria vs Test Cases

Acceptance Criterion:

Requested quantity must not exceed
available Inventory.

Potential test cases:

available = 10
requested = 1

→ success
available = 10
requested = 10

→ success
available = 10
requested = 11

→ failure

Acceptance Criteria describe the rule.

Test cases verify the rule using concrete examples.

They are related, but they are not the same thing.


Boundary Cases Matter

Backend bugs often appear at boundaries.

Requirement:

Requested quantity must not exceed
available Inventory.

Suppose:

available = 5

Important cases include:

requested = 4
requested = 5
requested = 6

The boundary:

requested == available

must be clear.

Our rule is:

requested <= available

So ordering the final available units is valid.


Acceptance Criteria Can Reveal Missing Requirements

Suppose we are writing the cancellation Story:

A Customer can cancel an eligible Order.

While writing a criterion, we say:

Cancelling an Order restores
the Inventory consumed by that Order.

That immediately raises another question:

When was Inventory consumed?

This tells us that the Inventory lifecycle itself must be defined.

Acceptance Criteria do not merely record requirements.

They can expose missing requirements.


User Stories Should Be Small Enough

Weak Story:

As a Customer,
I want to use the commerce platform,
so that I can shop online.

That describes nearly the entire Product.

It includes:

browse Products

create Order

pay

cancel

view history

Such a Story is too broad for implementation planning.

Better Stories represent independently understandable user capabilities.


But Do Not Split Stories Artificially

The opposite extreme is also unhelpful.

Bad:

As a Customer,
I want the Product ID field to exist.

Or:

As a Customer,
I want an OrderRepository.

The Customer does not care about Repository interfaces.

Those may be technical tasks.

They are not User Stories.


User Story vs Engineering Task

Story:

As a Customer,
I want to place an Order,
so that I can purchase available Products.

Later, engineering tasks may include:

Create Order domain model
Add Order persistence
Implement CreateOrderUseCase
Expose Order creation API
Add integration tests

The Story captures user value.

Engineering tasks break down the implementation work.


One Story Can Require Multiple Tickets

Suppose the Story is:

Customer can place an Order.

In a real codebase, this may require several engineering tickets.

For example:

BACKEND-121

Create Order domain model
BACKEND-122

Add Order persistence
BACKEND-123

Implement Inventory validation and consumption
BACKEND-124

Implement CreateOrderUseCase
BACKEND-125

Expose Create Order endpoint
BACKEND-126

Add Order creation integration tests

Later in Module 1, we will create the initial engineering backlog.


Definition of Done Is Different

Acceptance Criteria answer:

What behaviour must this feature satisfy?

Definition of Done answers:

What minimum quality bar must the team meet before work is considered complete?

For example:

Acceptance Criterion:

A Customer cannot create an Order
with insufficient Inventory.

Definition of Done may later include:

implementation complete

tests added

code reviewed

documentation updated where needed

CI passes

These are related, but they are not the same thing.

We will cover Definition of Done separately.


Avoid Mixing Team Process Into Product Behaviour

This does not belong in Acceptance Criteria:

PR must have two reviewers.

That is team process.

This does belong:

Order creation must reject
insufficient Inventory.

That is Product behaviour.

Keeping them separate makes documentation clearer.


A Practical Story Template

For this course, we can use a lightweight format:

# Story

## User Story

As a ...
I want ...
so that ...

## Context

Why is this capability needed?

## Acceptance Criteria

- ...
- ...
- ...

## Out of Scope

- ...

## Open Questions

- ...

Not every Story needs every section.

But Context, Out of Scope, and Open Questions can be useful for more complex capabilities.


Example: Create Order Story Document

# Create Order

## User Story

As a Customer,
I want to place an Order containing one or more Products,
so that I can purchase available items.

## Acceptance Criteria

- An Order must contain at least one item.
- Every item must reference an existing Product.
- Each Product may appear at most once.
- Quantity must be a positive whole number.
- Only Products available for ordering may be included.
- Requested quantity must not exceed available Inventory.
- The backend determines item prices.
- The backend calculates the Order total.
- Purchase-time prices remain part of the historical Order.
- If any item is invalid, the complete request fails.
- The created Order belongs to the requesting authenticated Customer.

## Out of Scope

- Discounts
- Coupons
- Shipping
- Tax calculation
- Multiple currencies

This provides much more useful engineering context than the original high-level Product sentence.


Avoid Over-Specifying Error Messages

Acceptance Criterion:

Invalid quantity must be rejected.

That is appropriate.

But writing this in an early Product Story:

Return HTTP 400 with code INVALID_ORDER_ITEM_QUANTITY
and exact message:
"Quantity must be greater than zero."

may be premature.

The API error contract should later be standardized as part of technical/API design.

An exception would be when exact public error behaviour is itself part of the agreed API contract.

At this stage, it is not.


Avoid Designing the Database Through Acceptance Criteria

Bad:

OrderItem must have product_id,
quantity, and unit_price_cents columns.

That is database design.

Better:

Historical OrderItem pricing must remain unchanged
when the current Product price changes.

Later, an engineer may decide to persist:

unit_price_cents

which is indeed the design we eventually use.

But the requirement should remain behaviour-first.


Out of Scope Is Part of Clarity

The Create Order Story includes:

basic Product ordering

Inventory validation

price calculation

Out of scope:

discounts

tax calculation

shipping

coupon codes

gift cards

This matters because it prevents accidental scope expansion.

An engineer should not think:

“This is a commerce Order system, so I should probably build a tax engine too.”

No.

We build what the current problem requires.


Do User Stories Need Estimates?

Many teams use Story Points or time estimates.

For example:

3 points

5 points

8 points

We will not go deeply into estimation methodology in this course.

Our focus is:

requirements

design

implementation

engineering workflow

We may discuss work size during planning.

But an artificial estimation framework is not one of the course goals.


Story Priority

Not every Story needs to be built at the same time.

A rough capability dependency is:

Products
   ↓
Inventory
   ↓
Orders
   ↓
Payments

Order history becomes meaningful after Orders exist.

Cancellation depends on the Order lifecycle.

Payment also depends on Orders.

These dependencies will influence backlog ordering.


Vertical Slice vs Technical Layer

An important planning question is whether we build:

all Domain classes

then all Repositories

then all UseCases

then all Handlers

or build a small capability end-to-end.

Real teams often prefer a vertical slice.

For example:

Create Product

HTTP/API
    ↓
Handler
    ↓
UseCase
    ↓
Repository
    ↓
Database
    ↓
Tests

Then move to the next capability.

This makes the system incrementally usable.

We will use this approach extensively during implementation.


But Some Foundation Work Comes First

Vertical slicing does not mean there is no shared foundation.

For example, we still need some setup such as:

Spring Boot bootstrap

database migration setup

API error-handling foundation

Some foundational work is created once.

After that, feature-by-feature vertical development becomes much more effective.


Acceptance Criteria and Code Review

Good Acceptance Criteria are useful during code review too.

A reviewer should not ask only:

Does this code look clean?

They should also ask:

Does this change satisfy
the intended behaviour?

Suppose the criterion says:

A Customer may not cancel
another Customer's Order.

The reviewer should look for:

ownership enforcement

and corresponding tests.

Requirement review and code review are connected.


Acceptance Criteria and Testing

Later, our test strategy will often follow:

Acceptance Criteria
        ↓
Test Scenarios
        ↓
Automated Tests

Criterion:

Each quantity must be a positive whole number.

Potential tests:

quantity = 1
→ valid
quantity = 0
→ rejected
quantity = -1
→ rejected

Another criterion:

A Customer may not access
another Customer's Order.

Possible integration scenario:

Customer A creates an Order.

Customer B requests that Order.

→ resource is unavailable according
  to the API access contract.

The exact HTTP semantics will be defined during API/security design.


Product Manager and Engineer Collaboration

Suppose Product says:

Customers should be able to cancel Orders.

An engineer might respond:

For v1, I propose allowing cancellation
only before payment.

Cancellation will restore the Inventory
consumed by that Order.

Paid-Order cancellation and refunds
will remain out of scope.

Does that match the intended behaviour?

Product confirms.

Now the Acceptance Criteria can be recorded.

The engineer did not silently invent a business rule.

They:

identified ambiguity

proposed concrete behaviour

explained the consequence

received confirmation

That is healthy Product–Engineering collaboration.


Not Every Criterion Comes Directly From Product

Some criteria emerge from engineering correctness.

For example:

Order creation should be atomic.

A Product Manager may never use the phrase:

atomic transaction

But the Product expectation may be:

We should never create half an Order.

Engineering can translate that into:

Order creation must not leave partial state.

The technical solution may later be a database transaction.

A backend engineer's job includes deriving correctness requirements from business intent.


Don’t Hide Technical Risk Behind a Simple Story

A Story may sound simple:

Customer pays for Order.

But an engineer may know the external Payment provider can:

time out

fail

return an uncertain result

The Story's simplicity does not eliminate those risks.

Acceptance Criteria can capture the business expectation:

A failed Payment must not mark
the Order as PAID.

Technical design later handles:

timeout

retry

idempotency

provider success / local failure

Our Initial Story Set

For v1, our current Story set is:

STORY-1

Browse Available Products
STORY-2

Create an Order
STORY-3

View Order History
STORY-4

Cancel an Eligible Order
STORY-5

Pay for an Order
STORY-6

Manage Products
STORY-7

Manage Inventory

Authentication is a technical/security prerequisite for Customer and Administrator permissions.

It is not a separate local Customer-management capability.


Are These Engineering Tickets Yet?

No.

These are still Product-level Stories.

The next stages are:

Story
    ↓
Technical Design
    ↓
Engineering Breakdown
    ↓
Tickets

For example:

STORY-2
Create an Order

will later become several implementation tickets.

That separation is intentional.


A Simple Quality Check for User Stories

After reading a Story, we should ideally be able to answer:

Who benefits?
What capability do they need?
Why do they need it?
What behaviour makes it acceptable?

If these are unclear, the Story needs refinement.


A Simple Quality Check for Acceptance Criteria

For every criterion, ask:

Is it clear?
Can we verify it?
Is it actually required?
Is it behaviour rather than implementation?
Does it conflict with another criterion?
Does it reveal an unresolved question?

These checks catch many ambiguities early.


Engineering Principle

The core principle from this lesson is:

A requirement becomes useful engineering input when the expected behaviour is clear enough that different people can independently recognize whether it has been satisfied.

A User Story tells us:

who

what

why

Acceptance Criteria tell us:

what must be true
for the work to be accepted

Their purpose is not paperwork.

Their purpose is shared understanding.


Where We Are Now

Our project has progressed through:

Initial Product Requirement
          ↓
Requirement Analysis
          ↓
Functional / Non-Functional Requirements
          ↓
User Stories
          ↓
Acceptance Criteria

We now understand the expected behaviour of the major Customer and Administrator capabilities much more clearly.

But an important question remains:

What environment, constraints, dependencies, and existing engineering context are we building this system within?

A backend is rarely created in complete isolation.

The next lesson is:

Understanding the Existing Engineering Context

There, we will treat the project as something a new engineer has joined rather than as an isolated greenfield coding exercise.

We will examine:

existing technical constraints

organizational context

system boundaries

external dependencies

development environment

deployment assumptions

After that, we can move toward the Definition of Done and the initial engineering backlog.