Joining the Backend Team

Creating Our Initial Engineering Backlog

LuettavaEsikatselu

Katselet ilmaista esikatseluoppituntia.

So far, we have done a significant amount of engineering work without writing production code.

We have:

  • understood the Product requirement
  • identified ambiguity
  • separated functional and non-functional requirements
  • written User Stories and Acceptance Criteria
  • established the engineering context
  • defined our Definition of Done

Our next responsibility is:

Break the larger Product requirement into engineering work that an engineer can realistically pick up, implement, test, review, and complete.

In this lesson, we will create the first engineering backlog for our Order Management Backend.

This will not be just a list of tasks.

We will think about:

  • which work should happen first
  • which tasks depend on other tasks
  • how large a ticket should be
  • how Product Stories differ from engineering tickets
  • how foundational work and feature work should be balanced
  • how to keep unnecessary scope out of the backlog
  • how to preserve traceability from requirement to implementation

By the end of the lesson, we will have a realistic initial backlog.

After that, we can move into technical design.


What Is a Backlog?

A backlog is an ordered collection of planned work.

A software team's backlog may contain:

features

bugs

technical work

documentation

operational work

investigations

Our application is new, so the initial backlog will contain mostly:

foundation
+
first Product capabilities

But a backlog should not simply be:

things we might build someday

A useful backlog contains work that is:

  • understood enough
  • scoped enough
  • prioritized enough
  • actionable enough

for an engineer to begin meaningful work.


Product Backlog vs Engineering Backlog

We already have Product-level Stories:

Browse Available Products

Create an Order

View Order History

Cancel an Eligible Order

Pay for an Order

Manage Products

Manage Inventory

These describe user value.

But they are still too broad to function directly as engineering implementation tickets.

For example:

Create an Order

eventually involves several concerns:

Domain model

Persistence

Product validation

Inventory handling

Price calculation

Transactions

API

Validation

Tests

The Product Story expresses what the user needs.

The engineering backlog breaks that need into implementable changes.


A Ticket Should Represent a Coherent Change

A good ticket should ideally be:

understandable

bounded

reviewable

testable

Bad:

BACKEND-100

Build backend.

That is a project goal, not an engineering ticket.

Another bad example:

BACKEND-101

Implement Orders, Payments, Authentication,
Inventory, Tests, and Deployment.

That contains far too much scope.

Tickets like this are difficult to:

  • review
  • estimate
  • parallelize
  • test
  • recover from when something goes wrong
  • reason about in terms of progress

Tickets Can Also Be Too Small

The opposite extreme is equally unhelpful.

For example:

BACKEND-201
Create Product.java.
BACKEND-202
Add name field.
BACKEND-203
Add price field.
BACKEND-204
Add getter.

At that point, the process overhead becomes larger than the engineering value of the ticket.

A ticket should represent a meaningful engineering outcome.


Prefer Outcome-Oriented Tickets

Compare:

Weak:

Add JPA.

Better:

Persist Products in PostgreSQL.

Weak:

Create Handler.

Better:

Expose Product creation through the administration API.

Weak:

Add tests.

Better:

Add integration coverage for Product persistence and validation.

Technology may appear inside the implementation.

The ticket title should usually describe the engineering result.


Ticket Structure

For the course project, we will use a lightweight format:

# BACKEND-XXX — Ticket Title

## Context

Why does this work exist?

## Scope

What should be implemented?

## Acceptance Criteria

What behaviour must be true?

## Out of Scope

What should not be added as part of this ticket?

## Dependencies

What must already exist before this work can be completed?

Not every ticket needs every section.

But this structure is useful when the work has meaningful scope or dependencies.


Ticket IDs

We will use identifiers such as:

BACKEND-101

BACKEND-102

BACKEND-103

These IDs do not require any particular project-management tool.

A real team might use:

Jira

Linear

GitHub Issues

another issue tracker

The ID simply gives us a stable reference.

For example:

This Pull Request implements BACKEND-104.

Start With Dependencies, Not Only Product Priority

Suppose the highest-value Product capability is:

Create an Order

That does not necessarily make it the first implementation ticket.

Order creation needs other concepts to exist first:

running application

database foundation

Products

Inventory

authenticated Customer identity

The dependency structure matters.

Conceptually:

Application Foundation
        ↓
Persistence Foundation
        ↓
Products
        ↓
Inventory
        ↓
Orders
        ↓
Payments

Authenticated identity is a cross-cutting prerequisite for protected Customer and Administrator operations, but we are not building a local Customer-management subsystem.

Some work can happen in parallel.

Still, dependencies influence backlog ordering.


First, We Need a Running Application

Our first technical milestone is:

A clean Spring Boot repository that builds and starts successfully.

So our first ticket is:

BACKEND-101
Bootstrap Order Management Backend

This is not a business feature.

It is the foundation for every business feature that follows.


BACKEND-101 — Bootstrap Order Management Backend

Context

We need a working Spring Boot application before feature implementation can begin.

Scope

Create the Gradle project.

Configure Spring Boot.

Create the application entry point.

Add baseline project configuration.

Verify the application builds and starts locally.

Acceptance Criteria

The project builds successfully with Gradle.

The Spring Boot application starts successfully.

The repository contains the agreed baseline structure.

A clean checkout can be built without IDE-specific setup.

Out of Scope

Product APIs

Database schema

Authentication

Order workflows

Payment integration

Production Dockerfile

We deliberately do not place half of the course inside the bootstrap ticket.


Do Not Create the Entire Package Structure Up Front

We could create empty packages immediately for:

product

inventory

order

payment

and many speculative subpackages.

But empty future-looking structure often creates architecture before we actually understand the need.

A better approach is:

Let structure emerge as real capabilities are implemented.

We can have an architectural direction without generating dozens of unused classes and interfaces.


Database Foundation

Products, Inventory, and Orders require durable persistence.

So we need an early database foundation ticket:

BACKEND-102
Configure PostgreSQL and Flyway

BACKEND-102 — Configure PostgreSQL and Flyway

Context

Transactional application data will be stored in PostgreSQL.

Schema changes must be versioned using Flyway.

Scope

Configure PostgreSQL connectivity.

Add required persistence dependencies.

Configure Flyway.

Verify migrations run correctly.

Provide a repeatable local-development PostgreSQL setup.

Establish isolated PostgreSQL support for integration testing.

Acceptance Criteria

The application can connect to PostgreSQL.

Flyway is enabled.

A migration can be applied successfully.

Local development can start the required database consistently.

Integration tests do not depend on a developer
manually preparing a local database.

Out of Scope

Product schema

Inventory schema

Order schema

Production database provisioning

For local development, Docker Compose may be used for supporting infrastructure such as PostgreSQL.

The Spring application itself can continue running through Gradle or the IDE until we reach the containerization module.


Product Capability Comes Before Orders

Orders reference Products.

So Product is our first meaningful business capability.

An initial breakdown could be:

BACKEND-103
Model the Product Domain

BACKEND-104
Persist Products

BACKEND-105
Implement Product Administration

BACKEND-106
Expose Available Product Browsing

BACKEND-103 — Model the Product Domain

Context

Before Inventory and Orders can use Product information, we need to define the Product concept required by v1.

Scope

The Product model should represent only the information currently required by the ordering flow.

Conceptually, the Product needs:

stable identity

name

price

active/inactive state

The exact Java representation will be decided during technical design.

Acceptance Criteria

A Product has a stable identity.

A Product has the information required
by the current ordering flow.

A Product can be active or inactive.

Invalid Product state is prevented where appropriate.

Domain behaviour has focused tests.

Out of Scope

Inventory quantity

Categories

Images

Variants

Discounts

Physical deletion

We do not add generic ecommerce features simply because they might exist in another commerce system.


BACKEND-104 — Persist Products

Context

Product data must survive application restarts.

Scope

Create the required Product database migration.

Map Product persistence.

Provide Repository operations required
by current Product UseCases.

Acceptance Criteria

Products can be stored in PostgreSQL.

Products can be retrieved by identifier.

Product active/inactive state is persisted.

Product price is persisted using
the agreed server-side monetary representation.

Schema creation is managed through Flyway.

Persistence behaviour is covered by integration tests.

Dependencies

BACKEND-102
BACKEND-103

BACKEND-105 — Implement Product Administration

The Product Management Story includes several Administrator operations.

Instead of forcing all operations into a single massive implementation, this area may later be refined into smaller tickets.

At backlog level, the expected capability includes:

create Product

view Product

update Product

deactivate Product

Physical deletion is not required.


Product Creation as the First Vertical Slice

One early implementation ticket may be:

BACKEND-105A
Expose Product Creation

Context

Administrators need to add Products to the catalog.

Scope

Accept Product creation input.

Validate supported fields.

Execute CreateProductUseCase.

Persist the Product.

Return the created Product representation.

Acceptance Criteria

A valid Product can be created.

Invalid required input is rejected.

Price cannot be negative.

The created Product is persisted.

A newly created Product is active.

Product creation does not automatically create Inventory.

That final point matters.

Product existence and Inventory availability are separate concepts.


Product Update and Deactivation

Later Product administration tickets can cover:

Update Product

Deactivate Product

The important business rule is that deactivation prevents future ordering but does not rewrite historical Orders.

We still do not introduce:

DELETE Product

for v1.


Product Browsing Depends on Inventory

An important refinement is that a Customer-facing Product is not orderable merely because:

active = true

For v1, Product browsing eventually needs both:

Product active
AND
Inventory available_quantity > 0

So Product browsing depends on the Inventory capability as well.

That affects backlog dependencies.


Inventory Is Separate From Product

Product and Inventory are related but represent different responsibilities.

Conceptually:

Product
    identity
    name
    price
    active state

Inventory
    available quantity

Inventory changes frequently for operational reasons.

Product metadata changes for different reasons.

Keeping them separate makes the model clearer.

Our initial Inventory backlog:

BACKEND-106
Model and Persist Inventory

BACKEND-107
Implement Inventory Administration

We can move Customer-facing Product browsing after those foundations exist.


BACKEND-106 — Model and Persist Inventory

Context

Orderability depends on available Inventory.

Scope

Represent Inventory for a Product.

Persist available quantity.

Prevent invalid negative quantity.

Acceptance Criteria

Inventory is identified by Product identity.

Available quantity can be stored and retrieved.

Available quantity cannot be negative.

Inventory schema is managed through Flyway.

Persistence behaviour is integration-tested.

Out of Scope

Multiple warehouses

Backorders

Reservation subsystem

Inventory movement ledger

Audit history

Inventory does not need a separate InventoryId.

The Product identity is sufficient for the Inventory record.


BACKEND-107 — Implement Inventory Administration

Context

Administrators need to control the current available quantity.

Scope

Expose current Inventory.

Allow an Administrator to set
the exact available quantity.

Reject invalid negative values.

Acceptance Criteria

Current Inventory can be viewed.

Available quantity can be set
to a non-negative whole number.

Setting quantity to the same value
is safe and has the same resulting state.

Inventory cannot become negative
through the administrative operation.

Out of Scope

Inventory delta commands

Stock ledger

Warehouse transfers

Automatic replenishment

For v1, the administrative operation sets the authoritative current quantity.


BACKEND-108 — Expose Available Product Browsing

Context

Customers need to see Products they can actually order.

Scope

Expose bounded Product browsing.

Return Product information required
to make an ordering decision.

Filter based on Product and Inventory state.

Acceptance Criteria

Only active Products are returned.

Only Products with available Inventory
greater than zero are returned.

A Product without an Inventory record
is not presented as orderable.

Product price is included.

Results are bounded.

Ordering is deterministic.

Dependencies

BACKEND-104
BACKEND-106

The concrete pagination contract will be defined during API design.


Customer Identity Is Not a Local Subsystem

Orders must belong to a Customer.

But we already established:

Authentication is provided by an existing identity capability.

Therefore, we do not create tickets for:

Customer table

Customer registration

Customer persistence

Password management

Customer creation API

What we need inside application workflows is much smaller:

a stable authenticated Customer identity

BACKEND-109 — Represent Customer Identity for Application Workflows

Context

Order workflows need to associate Orders with the authenticated Customer without owning identity management.

Scope

Represent the stable Customer identifier used by application UseCases.

Acceptance Criteria

The application can represent
a stable Customer identifier.

Order workflows can associate data
with that Customer identity.

The representation does not assume
that Customer identity is locally managed.

No password, registration, or account
lifecycle responsibilities are introduced.

Out of Scope

Customer table

Registration

Password storage

Password reset

Email verification

Identity provider implementation

The actual authenticated identity will later be supplied through Spring Security.

Until then, UseCases can receive an already-resolved CustomerId.


Order Domain Comes Next

Once Product, Inventory, and Customer identity concepts are available, we can model Orders.

Order-related backlog:

BACKEND-110
Model Order and OrderItem Domain

BACKEND-111
Persist Orders and OrderItems

BACKEND-112
Implement Order Creation Workflow

BACKEND-113
Expose Order Creation API

BACKEND-114
Expose Customer Order History and Detail

BACKEND-115
Implement Order Cancellation

BACKEND-110 — Model Order and OrderItem Domain

Context

Order creation, history, Payment, and cancellation all depend on the Order lifecycle.

Scope

Model:

Order

OrderItem

Customer ownership

purchase-time pricing

Order lifecycle

For v1, the lifecycle is intentionally small:

UNPAID
PAID
CANCELLED

Conceptually:

UNPAID
 ├──→ PAID
 └──→ CANCELLED

PAID and CANCELLED are terminal in v1.

Acceptance Criteria

An Order belongs to one Customer.

An Order contains at least one OrderItem.

An OrderItem contains Product identity,
quantity, and purchase-time unit price.

Quantity must be positive.

The Order total can be derived from its items.

A new Order starts as UNPAID.

Only valid state transitions are allowed.

PAID and CANCELLED Orders do not transition
back into an active state.

Out of Scope

Shipping states

Processing state

Refund state

Fulfilment workflow

Returns

Transition history

We model only the lifecycle our current Product requirements actually need.


BACKEND-111 — Persist Orders and OrderItems

Context

Orders must remain available for history, Payment, and cancellation.

Scope

Create Order-related Flyway migrations.

Persist Orders.

Persist OrderItems.

Persist Customer ownership.

Preserve purchase-time pricing.

Persist Order status and creation time.

Acceptance Criteria

Orders can be stored with Customer identity.

OrderItems persist Product identity,
quantity, and historical unit price.

Order status is persisted.

Order creation time is persisted.

Persisted Orders can be reconstructed
with data required by application UseCases.

Database constraints protect relevant
data integrity.

Persistence behaviour is integration-tested.

Dependencies

BACKEND-102
BACKEND-110

No Customer table dependency exists.

The Order stores the stable Customer identifier directly.


BACKEND-112 — Implement Order Creation Workflow

This is the first major business workflow.

Context

Customers need to create valid Orders without violating Product, pricing, or Inventory rules.

Scope

The UseCase must:

validate requested items

verify Products exist

verify Products are active

validate quantities

reject duplicate Product lines

consume available Inventory safely

determine authoritative Product prices

capture purchase-time unit prices

create the Order

persist the complete result atomically

Acceptance Criteria

An Order contains at least one item.

Every referenced Product exists.

A Product appears at most once
in the request.

Quantity is a positive whole number.

Inactive Products cannot be ordered.

Requested quantity must be available.

The backend determines Product pricing.

Purchase-time prices are preserved.

The Order total is derived from OrderItems.

The resulting Order belongs
to the requesting Customer.

Successful creation reduces Inventory.

Any invalid item causes the whole
operation to fail.

Failure does not leave partial Inventory
or Order state.

This is a larger ticket than some earlier ones, but it still represents one coherent workflow.


Why We Do Not Split Order Creation Into Tiny Tickets

We could create separate tickets for:

validate quantity

check Product

calculate total

consume Inventory

save Order

But those pieces are strongly connected.

Individually, they provide little useful behaviour.

A better boundary is:

Domain foundation

Persistence foundation

Business workflow

HTTP exposure

That produces coherent and reviewable changes.


BACKEND-113 — Expose Order Creation API

Context

The completed Order creation workflow must be exposed through the REST API.

Scope

Define request representation.

Validate transport-level input.

Resolve Customer identity at the boundary
once Security is integrated.

Invoke CreateOrderUseCase.

Return the created Order representation.

Map expected failures to the
standard API error contract.

Acceptance Criteria

A valid request invokes
the existing Order creation UseCase.

Malformed or invalid request shapes
are rejected.

Client-provided Product prices
are not accepted as authoritative pricing.

Known business failures are represented
through the standard API error contract.

The public API is documented.

Dependencies

BACKEND-112

Security enforcement will be wired when the Authentication and Authorization epic is implemented.


Why API and UseCase Are Separate

They own different responsibilities.

The workflow should be testable without HTTP.

The API boundary handles:

HTTP

JSON

request validation

response mapping

error representation

The UseCase handles:

application workflow

business decisions

Repository coordination

transaction boundary

Our architectural direction is:

Handler
   ↓
UseCase
   ↓
Repository / Domain

Service remains reserved for external integrations.


BACKEND-114 — Expose Customer Order History and Detail

Context

Customers need to review their previous Orders.

Scope

Retrieve Orders belonging
to a specific Customer identity.

Provide bounded history retrieval.

Provide Order detail.

Preserve historical item information.

Acceptance Criteria

Only the Customer's own Orders
are visible through Customer-facing access.

History is bounded.

History ordering is deterministic,
newest first.

Historical unit prices remain unchanged
when current Product prices change.

Cancelled and PAID Orders remain
visible in history.

Order detail exposes the data required
to understand the historical Order.

No Product price lookup is used to reconstruct historical pricing.


BACKEND-115 — Implement Order Cancellation

Context

Customers may cancel eligible UNPAID Orders.

Scope

Load the Customer-owned Order.

Validate cancellation eligibility.

Transition the Order to CANCELLED.

Restore Inventory consumed by that Order.

Maintain transactional consistency.

Prevent double restoration.

Acceptance Criteria

A Customer can cancel their own UNPAID Order.

A PAID Order cannot be cancelled in v1.

An already-CANCELLED Order
cannot be cancelled again.

Successful cancellation restores
the consumed Inventory.

Order state and Inventory restoration
are atomic.

Concurrent cancellation attempts
must not restore Inventory twice.

Paid cancellation and refunds remain outside v1.


Security Work

The Product Stories require authenticated Customer and Administrator behaviour.

Security backlog:

BACKEND-116
Integrate Authenticated Identity

BACKEND-117
Enforce Customer Resource Ownership

BACKEND-118
Enforce Administrator Permissions

BACKEND-116 — Integrate Authenticated Identity

Context

An external identity capability authenticates users.

Our backend must consume the authenticated identity.

Scope

Configure Spring Security.

Resolve authenticated identity.

Provide CustomerId to Customer UseCases.

Reject protected requests
without valid authentication.

Out of Scope

User registration

Password storage

Password reset

Identity provider implementation

BACKEND-117 — Enforce Customer Resource Ownership

Context

Customers must not view or mutate another Customer's Orders.

Acceptance Criteria

A Customer can access their own Orders.

A Customer cannot retrieve
another Customer's Order.

A Customer cannot cancel
another Customer's Order.

A Customer cannot pay
another Customer's Order.

Ownership behaviour is
integration-tested.

For Customer-facing Order lookup, missing and non-owned resources may intentionally produce the same public ORDER_NOT_FOUND result.

That avoids exposing another Customer's resource existence.


BACKEND-118 — Enforce Administrator Permissions

Context

Product and Inventory administration must be restricted to Administrators.

Acceptance Criteria

Authorized Administrators can perform
supported Product operations.

Authorized Administrators can perform
supported Inventory operations.

Regular Customers cannot create,
update, or deactivate Products.

Regular Customers cannot modify Inventory.

Authorization behaviour is
integration-tested.

Payment Work

Payment crosses an external system boundary and deserves its own sequence.

The initial backlog can include:

BACKEND-119
Define Payment Integration Boundary

BACKEND-120
Implement Payment Provider Integration

BACKEND-121
Implement Order Payment Workflow

BACKEND-122
Expose Order Payment API

Why Start With an Integration Boundary?

We do not want provider-specific HTTP code inside Order business logic.

Our application should depend on the capability it needs.

Conceptually:

PayOrderUseCase
       ↓
PaymentService
       ↓
External Payment Provider

Here, PaymentService is an appropriate use of the word Service because it represents an external integration.


BACKEND-119 — Define Payment Integration Boundary

Context

Order Payment logic needs an external payment capability without depending on provider-specific HTTP details.

Scope

Define only the application-facing Payment contract required by v1.

Acceptance Criteria

Order Payment logic can request
the provider capability it needs.

Provider-specific HTTP details
do not leak into the Order Domain.

The boundary is limited to
current Payment requirements.

Successful and failed provider outcomes
can be represented.

Out of Scope

Refunds

Multiple Payment providers

Stored cards

General-purpose Payment platform

Unrequired webhook architecture

BACKEND-120 — Implement Payment Provider Integration

Context

The external Payment boundary must communicate with the configured provider.

Scope

Call the external provider.

Externalize provider configuration.

Handle expected responses.

Apply timeout behaviour.

Keep provider-specific mapping
inside the integration layer.

Acceptance Criteria

The configured provider can be called.

Successful provider responses
are translated into application results.

Provider failures are not interpreted
as successful Payment.

Timeouts are handled explicitly.

Provider URL and credentials
are not hardcoded.

Retry and idempotency behaviour will be designed carefully in the external-services module rather than guessed here.


BACKEND-121 — Implement Order Payment Workflow

Context

A Customer needs to pay an eligible Order.

Scope

Validate Customer ownership.

Validate that the Order is UNPAID.

Interact with PaymentService.

Apply confirmed successful Payment.

Do not mark the Order PAID
when Payment fails.

Prevent invalid state transitions.

Acceptance Criteria

A Customer may pay only
for their own Order.

Only an UNPAID Order is payable.

A CANCELLED Order cannot be paid.

An already-PAID Order cannot
transition to PAID again as a new action.

Confirmed successful Payment
marks the Order PAID.

Failed or unconfirmed Payment
does not mark the Order PAID.

External idempotency and the difficult pay-vs-cancel concurrency problem will be addressed during Payment integration design.

We will not hold a database row lock across a remote provider call.


BACKEND-122 — Expose Order Payment API

Scope

Expose the Payment workflow through the REST API.

Acceptance Criteria

A valid request invokes
the existing Payment workflow.

Expected Payment failures
use the API error contract.

Provider-specific internals
are not unnecessarily exposed.

The API is documented.

Production Readiness Work

Later modules introduce deliberate operational capabilities.

High-level backlog items can already exist:

BACKEND-123
Add Structured Application Logging

BACKEND-124
Add Request Correlation

BACKEND-125
Expose Application Health Checks

BACKEND-126
Add Application Metrics

BACKEND-127
Containerize the Application

BACKEND-128
Create CI Build and Test Pipeline

These tickets do not need every implementation detail now.

We will refine them when their modules begin.


Testing Is Not a Final Ticket

A poor backlog might say:

Build all features.

Then:

BACKEND-999
Add tests.

We will not work that way.

Testing is part of every relevant ticket's Definition of Done.

For example:

BACKEND-112
Implement Order Creation Workflow

already includes relevant automated testing.

The dedicated Testing module will teach test strategy in greater depth and strengthen the system further.

But automated testing begins during implementation.


Documentation Is Not a Final Cleanup Ticket Either

Likewise:

Build everything.

Document it later.

is a poor strategy.

Relevant documentation evolves with the code.

For example:

API change
→ API documentation
important architecture decision
→ ADR
larger technical proposal
→ RFC

The dedicated documentation/workflow lessons improve the practice later, but context should not be postponed until everyone forgets why a decision was made.


We Are Not Ready to Implement Every Ticket Yet

We now have a backlog.

That does not mean every ticket is immediately ready to start.

For example:

BACKEND-112
Implement Order Creation Workflow

requires design decisions around:

Domain model

Inventory concurrency

transaction boundary

Repository contracts

Those decisions belong in the technical-design modules.

This is realistic.

A backlog can exist before every implementation detail has been finalized.


Backlog Does Not Mean Ready

A future ticket may exist as:

BACKEND-121
Implement Order Payment Workflow

while still being:

Not Ready

because external integration behaviour has unresolved questions.

The backlog represents planned work.

Ready work is a subset of the backlog.


Key Dependencies

Let's summarize the dependency structure.

Foundation:

BACKEND-101 Bootstrap
        ↓
BACKEND-102 PostgreSQL + Flyway

Product:

BACKEND-103 Product Domain
        ↓
BACKEND-104 Product Persistence

Inventory:

BACKEND-106 Inventory Model + Persistence
        ↓
BACKEND-107 Inventory Administration

Product browsing:

Product Persistence
        +
Inventory Persistence
        ↓
BACKEND-108 Product Browsing

Orders:

Product
+
Inventory
+
CustomerId representation
        ↓
BACKEND-110 Order Domain
        ↓
BACKEND-111 Order Persistence
        ↓
BACKEND-112 Order Creation UseCase
        ↓
BACKEND-113 Order Creation API

History and cancellation:

Order Persistence / Workflow
        ↓
BACKEND-114 Order History + Detail
        ↓
BACKEND-115 Cancellation

Security:

Authenticated Identity
        ↓
Customer ownership enforcement
        +
Administrator authorization

Payment:

Order Domain
        +
Payment Integration Boundary
        ↓
Payment Provider Integration
        ↓
PayOrderUseCase
        ↓
Payment API

Not Every Dependency Is a Hard Code Dependency

For example, Product browsing does not necessarily require authentication.

The Product brief says Customers browse Products.

It does not say Product browsing must be authenticated.

So we should not invent that restriction.

By contrast:

view own Orders

cancel own Order

pay own Order

administer Products

administer Inventory

clearly require identity or authorization enforcement.

Backlog dependencies should follow actual requirements rather than blanket rules.


Prioritizing the Backlog

A practical implementation sequence after design might be:

1. Bootstrap application

2. PostgreSQL and Flyway foundation

3. Product Domain

4. Product persistence

5. Product administration

6. Inventory Domain and persistence

7. Inventory administration

8. Product browsing

9. CustomerId application representation

10. Order Domain

11. Order persistence

12. Order creation UseCase

13. Order creation API

14. Order history and detail

15. Order cancellation

16. Authentication and authorization

17. Payment integration

18. Production-readiness work

19. Shipping

The exact order may change slightly after technical design.

That is normal.


Why Payment Is Not First

Payment sounds important.

But Payment requires an Order.

An Order requires Products and Inventory.

Building Payment first would either:

force temporary mocks and fake Domain objects everywhere

or:

encourage abstractions before we understand
the actual application workflow

Stable prerequisites should come first.


Why Production Concerns Are Not Ignored Until the End

The dedicated Production Readiness module comes later.

That does not mean early code should have no logs, error handling, or operational awareness.

Basic engineering hygiene exists from the beginning.

Later modules make those capabilities intentional and systematic.

The balance is:

Do not ignore production concerns, but do not front-load advanced operational complexity before the core application exists.


Vertical Slices

After the minimum foundation exists, feature work should generally move vertically.

For example, Product creation may involve:

HTTP
 ↓
Handler
 ↓
CreateProductUseCase
 ↓
Product Domain
 ↓
ProductRepository
 ↓
PostgreSQL

plus:

tests

migration

API documentation

After that change is complete, one real capability works end to end.

That is more valuable than completing:

all Handlers

then:

all Repositories

while no actual business capability works.


Horizontal Foundation vs Vertical Feature

Some work is naturally horizontal:

Spring Boot bootstrap

PostgreSQL configuration

Flyway configuration

security framework setup

API error foundation

Feature work is often better implemented vertically.

A healthy application uses both.

Bad extreme:

Build six months of infrastructure
before the first feature.

Other bad extreme:

Duplicate every shared concern
inside every feature.

Our backlog aims for:

minimal shared foundation
+
meaningful vertical capabilities

Tickets Should Be Reviewable

Imagine a Pull Request containing:

4,000 changed lines

database schema

security

Orders

Payments

Docker

CI

The reviewer's cognitive load is enormous.

Review quality drops even if the code is technically good.

Smaller coherent tickets tend to produce focused PRs.

For example:

BACKEND-104
Persist Products

might result in a PR containing:

migration

persistence mapping

Repository adapter

integration tests

One meaningful change.

One understandable review.


But Do Not Optimize for the Smallest Possible Diff

A tiny PR can be good.

But splitting one cohesive feature into ten dependent PRs can create:

temporary inconsistent states

review overhead

coordination overhead

The goal is:

The smallest change that still makes engineering sense.

Not:

The smallest possible diff.


Ticket Scope and Pull Request Scope

A practical guideline is:

one bounded ticket
≈
one focused Pull Request

It is not an absolute rule.

Some larger tickets may require several PRs.

Sometimes several tiny related tickets may share a PR.

But one-ticket-to-one-primary-PR is useful for course traceability.


Tickets Should Explain Why

Weak:

Add unitPriceCents to OrderItem.

Better:

Preserve purchase-time pricing
for OrderItems.

Context:

Historical Orders must not change
when current Product prices change.

Now an engineer understands the intent.

If the implementation changes later, the underlying requirement remains clear.


Avoid Solution-First Tickets Too Early

Suppose we add:

Use pessimistic locking for Inventory.

to the backlog before concurrency design is complete.

We have silently converted an implementation guess into a plan.

Better:

Ensure concurrent Order creation
cannot oversell Inventory.

Then technical design determines the mechanism.

In our eventual design, that problem can be solved using an atomic conditional Inventory update.

The backlog should describe the problem before design chooses the solution.


Spikes and Investigations

Sometimes an implementation ticket cannot be made ready because important technical information is unknown.

A team may create a short investigation or spike.

Example:

Investigate Payment provider
idempotency support.

Useful output might include:

provider capabilities

limitations

recommended integration approach

But spikes should exist only for genuine uncertainty.

We do not create fake research tickets simply to make the workflow appear more realistic.


Avoid Bureaucratic Theatre

A poor simulation might create:

Investigate whether PostgreSQL supports transactions.

We already know that.

There is no real uncertainty.

Authentic engineering process means investigating genuine unknowns, not pretending established facts are mysterious.


Bugs Are Backlog Items Too

Once the application exists, the backlog evolves.

A production issue may create:

BUG-201

Prevent duplicate Order creation
under an identified retry scenario.

An incident may create corrective work:

BACKEND-240

Add monitoring for a specific
Payment reconciliation failure.

Backlogs evolve with the system.

They are never permanently finished.


Product Change Creates Backlog Change

Later, when a production change request arrives, we will not restart planning from zero.

We will:

understand the new requirement
        ↓
assess impact
        ↓
update design where necessary
        ↓
add, modify, or remove backlog items

That is how long-lived systems evolve.


Initial Backlog by Epic

We can now organize the work into larger groups.

Epic 1 — Application Foundation

BACKEND-101
Bootstrap Order Management Backend

BACKEND-102
Configure PostgreSQL and Flyway

Epic 2 — Product Management

BACKEND-103
Model the Product Domain

BACKEND-104
Persist Products

BACKEND-105
Implement Product Administration

Epic 3 — Inventory Management

BACKEND-106
Model and Persist Inventory

BACKEND-107
Implement Inventory Administration

Epic 4 — Product Discovery

BACKEND-108
Expose Available Product Browsing

Epic 5 — Customer Identity Context

BACKEND-109
Represent Customer Identity
for Application Workflows

This is not a Customer management subsystem.


Epic 6 — Ordering

BACKEND-110
Model Order and OrderItem Domain

BACKEND-111
Persist Orders and OrderItems

BACKEND-112
Implement Order Creation Workflow

BACKEND-113
Expose Order Creation API

BACKEND-114
Expose Customer Order History and Detail

BACKEND-115
Implement Order Cancellation

Epic 7 — Security

BACKEND-116
Integrate Authenticated Identity

BACKEND-117
Enforce Customer Resource Ownership

BACKEND-118
Enforce Administrator Permissions

Epic 8 — Payment

BACKEND-119
Define Payment Integration Boundary

BACKEND-120
Implement Payment Provider Integration

BACKEND-121
Implement Order Payment Workflow

BACKEND-122
Expose Order Payment API

Epic 9 — Production Readiness

BACKEND-123
Add Structured Application Logging

BACKEND-124
Add Request Correlation

BACKEND-125
Expose Application Health Checks

BACKEND-126
Add Application Metrics

Epic 10 — Delivery

BACKEND-127
Containerize the Application

BACKEND-128
Create CI Build and Test Pipeline

This is our initial backlog.

It will evolve as our understanding improves.

What should not evolve casually is the Product scope.


What Is Missing From the Backlog?

Notice that several course topics are not represented as standalone tickets:

Dependency Injection

Spring Beans

HTTP status codes

JPA

JUnit

Mockito

@Transactional

Why?

Because these are learning topics, not Product work.

We will learn them while implementing real engineering tickets.

For example:

Dependency Injection

appears naturally while wiring Handlers, UseCases, Repositories, and external Services.

JPA

appears while implementing persistence.

JUnit

appears while satisfying the Definition of Done.

@Transactional

appears when Order workflows create a real atomicity requirement.

This is an important course-design principle.


Curriculum and Backlog Are Different

The curriculum asks:

What engineering concept
does the learner need to understand?

The backlog asks:

What does the engineering team
need to deliver?

They intersect.

They are not the same.

Example:

Course lesson:

Database Transactions

Engineering ticket:

BACKEND-112
Implement Order Creation Workflow

We learn transactions because the real workflow creates an atomicity problem.

We do not invent work simply to demonstrate a technology.


Backlog Refinement

The backlog is not created once and then frozen forever.

Before implementation, a team may refine a ticket by:

clarifying scope

adding Acceptance Criteria

identifying dependencies

splitting oversized work

removing unnecessary work

raising technical questions

For example, technical design may show that:

BACKEND-105
Implement Product Administration

should become separate tickets for:

Product creation

Product update

Product deactivation

That would be a reasonable refinement.


Do Not Split Before Understanding the Design

If we split too early into implementation details such as:

BACKEND-X
Lock Inventory row

BACKEND-Y
Use transaction propagation X

BACKEND-Z
Add Repository method Y

we have already assumed the solution.

A healthier sequence is:

Understand requirement
        ↓
Design solution
        ↓
Refine implementation work

Design and backlog refinement inform each other.


Ready Ticket Example

A reasonably ready ticket might look like this:

# BACKEND-108 — Expose Available Product Browsing

## Context

Customers need to browse Products that can currently be ordered.

## Scope

Expose bounded retrieval of Products that satisfy
the v1 orderability rules.

## Acceptance Criteria

- Product is active.
- Product has available Inventory greater than zero.
- Product price is included.
- Retrieval is bounded.
- Results are deterministic.

## Out of Scope

- Product search
- Recommendations
- Categories
- Full-text filtering

## Dependencies

- BACKEND-104
- BACKEND-106

An engineer can understand the expected outcome without inventing hidden features.


Not-Ready Ticket Example

# BACKEND-121 — Implement Order Payment Workflow

## Open Questions

- Exact provider idempotency behaviour is not yet confirmed.
- Timeout and retry semantics require integration design.
- Provider-success / local-state-failure behaviour needs a design.

The ticket can exist in the backlog without being ready to start.

That is better than hiding uncertainty.


Backlog Priority Can Change

Suppose we discover that the Payment provider requires a long external onboarding process.

The team may move Payment investigation earlier even though Payment implementation remains later.

Priority depends on:

business value

dependencies

risk

uncertainty

Ticket number does not determine execution order.


Risk-Driven Planning

Sometimes a technically risky question deserves early design attention.

For example:

Can concurrent Order creation
oversell Inventory?

That question affects fundamental correctness.

It should be understood before we spend time polishing low-risk details.

Good planning balances:

value
+
dependencies
+
risk

Avoid Infrastructure “Just in Case”

Our backlog should not contain:

Add Kafka for future events.

Add Redis in case reads become slow.

Create Elasticsearch cluster.

Add Kubernetes manifests
before deployment requires them.

None of those satisfy a current requirement.

A future possibility is not a current need.


Every Ticket Creates Maintenance Cost

A useful mental model:

More functionality
        ↓
More code
        ↓
More tests
        ↓
More operational surface
        ↓
More future maintenance

Every backlog item should earn its existence.

Ask:

Which Product requirement or engineering need does this ticket satisfy?

If there is no clear answer, the ticket may not belong in the backlog.


Traceability

Our work is now traceable.

For Product browsing:

Product Requirement
Customers can browse available Products.
        ↓
STORY-1
Browse Available Products
        ↓
BACKEND-103
Product Domain
        ↓
BACKEND-104
Product Persistence
        ↓
BACKEND-106
Inventory Persistence
        ↓
BACKEND-108
Product Browsing
        ↓
Pull Requests
        ↓
Tests

For Order creation:

Product Requirement
Customers can place Orders.
        ↓
STORY-2
Create an Order
        ↓
BACKEND-110
Order Domain
        ↓
BACKEND-111
Order Persistence
        ↓
BACKEND-112
CreateOrderUseCase
        ↓
BACKEND-113
Order Creation API

Traceability helps engineers answer:

Why does this code exist?

Backlog Is Not Architecture

We now have tickets such as:

Persist Orders

But the backlog still does not answer:

What exact tables?

Which Java classes?

Which package structure?

What Repository contracts?

Where is the transaction boundary?

How should modules depend on each other?

How is Inventory concurrency handled?

Those are technical-design questions.

That is why the next module exists.


Our First Planned Milestones

A reasonable first milestone could be:

Application starts
        +
PostgreSQL works
        +
Products can be managed
        +
Inventory can be managed
        +
Available Products can be browsed

Then:

Order creation works

Then:

Order history
+
Order cancellation

Then:

Authentication / Authorization
+
Payment

Then:

Production readiness
+
Shipping

The exact release boundaries may evolve.

But incremental milestones make progress visible.


What “Milestone” Means Here

A milestone is not a new Product feature.

It represents a meaningful state of the project.

For example:

Milestone 1

Catalog and Inventory foundation works.

This is useful for learning as well.

The learner sees the application evolve instead of waiting until the end of the course for a runnable system.


Backlog and Definition of Done Work Together

A ticket tells us:

What change are we making?

Acceptance Criteria tell us:

What behaviour must it satisfy?

Definition of Done tells us:

What quality conditions
must be satisfied?

Together:

Ticket
  +
Acceptance Criteria
  +
Definition of Done
        ↓
Meaningful engineering work

A Ticket Is Not Done Because Every Subtask Is Checked

Suppose a ticket contains:

[x] Handler
[x] UseCase
[x] Repository
[x] Migration

but inactive Products can still be ordered.

The feature is not Done.

Subtasks describe implementation activity.

Acceptance Criteria describe behaviour.

When they conflict:

Behaviour wins.


Avoid Ticket-Driven Design

Suppose a backlog item says:

Create Repository.

After design, we realize that exact abstraction is unnecessary.

We should refine the ticket.

We should not preserve a poor implementation decision merely because someone typed it into the backlog earlier.

The backlog is a planning tool.

It is not an architectural law.


The Backlog Will Change

Backlogs evolve because:

requirements change

technical discovery happens

dependencies shift

risks appear

tickets are split

tickets become unnecessary

Changes should be deliberate.

We should not casually rewrite Product scope or introduce new features without a reason.


Module 1 Deliverables

At the end of Module 1, our project conceptually has:

Product Brief

Requirement Analysis

Functional Requirements

Non-Functional Concerns

User Stories

Acceptance Criteria

Engineering Context

Definition of Done

Initial Engineering Backlog

That is substantial engineering preparation.

But none of it exists simply for paperwork.

Each artifact answers a different question.