Client-Side Web Applications

Marketplace Project: Browsing the Marketplace


Learning Objectives

  • You can organize a read interface into components and explicit network states.
  • You can transform category relationships into recursive navigation.
  • You can support detail links that work independently of earlier browser actions.
  • You can test those behaviors while preserving the accepted Part 1 marketplace project.

We have practiced components, state, requests and navigation in smaller examples. Now continue in your local marketplace repository (marketplace/) from Part 1. Its six accepted milestones are the starting point; this part adds milestones 7-12. Do not replace the marketplace repository with the practice application or copy laboratory routes into it.

Each card contains the contract, checks and submission instructions for one increment. Fetch the next milestone as instructed and keep working on master. Most milestone branches are comparison references containing the preceding accepted increment, not the new answer. Milestone 11’s handout marks the exception: its branch carries two contributed server modules that you integrate into master. Use compose.yaml and compose.test.yaml with a separate marketplace test Compose project name. The chapter examples use wsd-practice-test; wsd-marketplace-test is an example for the marketplace repository, not a shared name.

The read contract stays consistent: listing IDs and related IDs are positive integers, and prices are integer euro cents. Each listing includes its actual seller and category names. Collection reads are capped at 100; filtering here covers the loaded collection, not an unbounded server search.

Listing components and read modules

First separate obtaining data from displaying one listing. Keep the existing root heading, counter and todo controls. The card receives data, and its owner performs the collection request. Milestone 7 also makes the runtime response checks explicit.

Marketplace milestone 7: read modules and listing cards

0 / 35 points

Continue the marketplace project

Continue in the local marketplace repository after milestone 6 passes. Run git fetch origin and keep working on master. There is no new marketplace repository. The reference branch contains the preceding milestone, not the solution to this one. Inspect or merge it only when you need to recover a known baseline.

Objective

Refactor the existing listing view into a read module and a presentation component. Do not replace the marketplace project with the neutral practice application.

Create client/src/lib/marketplace/marketplace-api.ts and export Listing, Category, decodeListing, getListings, getCategories, and getListing. Listing retains id, title, description, startingPrice, sellerId, sellerName, categoryId, and categoryName; Category has id, parentId, name, and slug. Prices are whole euro cents. IDs are positive PostgreSQL integers. The decoder checks these fields at runtime and ignores additional fields rather than casting an unknown response. getCategories must likewise validate that the response is an array and that every category has the stated fields, including a positive integer ID and a null or positive integer parent ID. List operations return arrays; the detail operation returns one listing. Each accepts an optional abort signal, passes it to fetch, checks the HTTP status, and uses the existing configured public API base URL. For an HTTP failure, reject with an Error whose message includes the status. The detail operation will be used after the supplied bridge in milestone 11.

Create client/src/lib/marketplace/ListingCard.svelte with one listing prop. Render a list item containing a heading with a title link to /listings/<id>, plus Seller: name, Category: name, and Starting price: €7.25 for an amount of 725 cents. Use the supplied relationship names, not a guessed parent category. The detail page need not work yet.

Create client/src/lib/marketplace/ListingsBrowser.svelte; let it own the collection request and use one card per row. Modify the existing client/src/lib/ListingList.svelte so it remains a small wrapper around the new browser component and the existing root page still works. Keep Campus Marketplace, Load listings, the Counter and Todos sections, and their original controls. Full empty/error/retry behavior is the next milestone.

The supplied public observations use Jamie and Noor, but the component check uses unfamiliar data. Do not hardcode a title, category, seller, ID, or price.

Test and submit

Use the two Compose files and an unused, separate Compose test project name. Replace wsd-marketplace-test in the example commands with that name. During an increment, run the client test command first; it is the focused subsystem suite for this milestone. The complete sequence below is useful at the part acceptance checkpoint; do not repeat an unrelated build after every small edit. Never erase your development database merely to run a test. All shell commands belong to the marketplace repository, not the practice application.

Terminal window
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task test
# Optional local type diagnostics; not graded in this milestone.
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task check
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task build
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm api deno task test
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm e2e-tests
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml down

Run suites sequentially. If you reuse an already-running test API after editing its source, restart it: unlike the development service, it does not watch files. Do not commit real secrets, generated builds, test results, or node_modules. Inspect git diff, stage the specific source, migration and test files you changed, commit, and run git push origin master. The grader uses trusted runtime configuration; submitted Docker or package scripts are not executed as grading code.

Type checking is optional in this milestone and does not affect points. The grader assesses executable tests and application behavior.

Points

  • 20 points: Render varied listing relationships, euro-cent price, and detail link.
  • 15 points: Validate listing/category responses and preserve the configured, status-checked, abortable read contract.

Preserving the previously accepted read paths, counter and todo behavior, migration history, and a buildable client are readiness conditions. These conditions do not re-award points from earlier milestones.

Network states and recovery

Part 1 established a successful read. Now distinguish pending, empty and failed reads, clear stale rows, and recover with a later request. Test transitions within one mounted view rather than assuming isolated screenshots establish recovery.

Marketplace milestone 8: loading, empty results and recovery

0 / 30 points

Continue the marketplace project

Continue in the local marketplace repository after milestone 7 passes. Run git fetch origin and keep working on master. There is no new marketplace repository. The reference branch contains the preceding milestone, not the solution to this one. Inspect or merge it only when you need to recover a known baseline.

Objective

Extend ListingsBrowser.svelte with explicit idle, loading, ready, and error states. Keep Load listings available for a new request, including while another read is pending. Display Loading listings… in an element with role="status" while pending, No listings available. for a successful empty array, and an alert beginning Could not load listings. for a failure. Include the HTTP status for an HTTP failure and include the thrown Error.message for a network failure.

A new request clears previously shown rows. An empty response or failure must not leave old cards visible. A successful retry clears the old error. Abort obsolete requests, invalidate their generation, and cancel the outstanding read when the component is removed. A late success or rejection must not overwrite a newer view.

Use controlled response sequences when testing: data→empty→data and data→HTTP failure→network failure→successful retry. Do not assume that checking four separately mounted components establishes all those transitions.

Test and submit

Use the two Compose files and an unused, separate Compose test project name. Replace wsd-marketplace-test in the example commands with that name. During an increment, run the client test command first; it is the focused subsystem suite for this milestone. The complete sequence below is useful at the part acceptance checkpoint; do not repeat an unrelated build after every small edit. Never erase your development database merely to run a test. All shell commands belong to the marketplace repository, not the practice application.

Terminal window
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task test
# Optional local type diagnostics; not graded in this milestone.
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task check
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task build
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm api deno task test
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm e2e-tests
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml down

Run suites sequentially. If you reuse an already-running test API after editing its source, restart it: unlike the development service, it does not watch files. Do not commit real secrets, generated builds, test results, or node_modules. Inspect git diff, stage the specific source, migration and test files you changed, commit, and run git push origin master. The grader uses trusted runtime configuration; submitted Docker or package scripts are not executed as grading code.

Type checking is optional in this milestone and does not affect points. The grader assesses executable tests and application behavior.

Points

  • 5 points: Clear old rows after an empty result and restore them after another read.
  • 15 points: Distinguish HTTP/network failure and recover without stale cards or errors.
  • 10 points: Keep only the latest request and cancel obsolete reads.

Preserving the previously accepted read paths, counter and todo behavior, migration history, and a buildable client are readiness conditions. These conditions do not re-award points from earlier milestones.

Category relationships

The API gives us flat parent references. Turn them into a nested structure without assuming that parents arrive first, then identify a selected branch’s descendants. This data transformation supplies the hierarchy that the recursive component renders.

The result must preserve root and sibling input order, support several roots and more than two levels, and leave the source rows unchanged. A child-before-parent case prevents an implementation from treating arrival order as hierarchy. Keep tree construction and descendant traversal as separately testable operations; the exercise asks you to choose and implement an algorithm satisfying those invariants.

Marketplace milestone 9: category relationships as a tree

0 / 25 points

Continue the marketplace project

Continue in the local marketplace repository after milestone 8 passes. Run git fetch origin and keep working on master. There is no new marketplace repository. The reference branch contains the preceding milestone, not the solution to this one. Inspect or merge it only when you need to recover a known baseline.

Objective

Create client/src/lib/marketplace/categories.ts. Export CategoryNode (the existing category fields plus children), buildCategoryTree(rows), and descendantIds(node).

Inputs have unique positive IDs, existing parent references, and no cycles. They may be empty, have several roots, contain more than two levels, and place a child before its parent. Preserve root and sibling input order. Never mutate the input array or rows. A leaf has an empty children array. descendantIds returns the node’s own ID followed by descendants in depth-first sibling order.

For example, input (30→20), (10→null), (20→10), (40→null) has roots 10 and 40; 30 is below 20, below 10. Do not special-case these identifiers.

Create client/src/lib/marketplace/categories.test.ts and add your own Vitest cases for the stated cases. These tests are local regression evidence and are returned and reassessed in milestone 12; milestone 9’s points come from the grader’s independent unfamiliar trees. Defensive detection of invalid graphs is not required here.

Test and submit

Use the two Compose files and an unused, separate Compose test project name. Replace wsd-marketplace-test in the example commands with that name. During an increment, first run the category test directly:

Terminal window
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task test src/lib/marketplace/categories.test.ts

The complete sequence below is useful at the part acceptance checkpoint; do not repeat an unrelated build after every small edit. Never erase your development database merely to run a test. All shell commands belong to the marketplace repository, not the practice application.

Terminal window
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task test
# Optional local type diagnostics; not graded in this milestone.
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task check
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task build
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm api deno task test
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm e2e-tests
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml down

Run suites sequentially. If you reuse an already-running test API after editing its source, restart it: unlike the development service, it does not watch files. Do not commit real secrets, generated builds, test results, or node_modules. Inspect git diff, stage the specific source, migration and test files you changed, commit, and run git push origin master. The grader uses trusted runtime configuration; submitted Docker or package scripts are not executed as grading code.

Type checking is optional in this milestone and does not affect points. The grader assesses executable tests and application behavior.

Points

  • 15 points: Build ordered relationships for empty and parent-last multi-level input without mutation.
  • 10 points: Collect the selected category and all of its descendants.

Preserving the previously accepted read paths, counter and todo behavior, migration history, and a buildable client are readiness conditions. These conditions do not re-award points from earlier milestones.

Recursive category navigation

Use the recursive outline pattern from Chapter 2.5 to render native category buttons. Selecting a parent includes listings in its descendants. Keep selection separate from the underlying loaded collection so All categories can restore it.

Marketplace milestone 10: recursive navigation and filtered browsing

0 / 40 points

Continue the marketplace project

Continue in the local marketplace repository after milestone 9 passes. Run git fetch origin and keep working on master. There is no new marketplace repository. The reference branch contains the preceding milestone, not the solution to this one. Inspect or merge it only when you need to recover a known baseline.

Objective

Create client/src/lib/marketplace/CategoryBranch.svelte and client/src/lib/marketplace/CategoryNavigation.svelte. Use the category helpers in a recursive CategoryBranch and a small CategoryNavigation. Render native category buttons in nested lists inside navigation named Categories. Use aria-pressed to indicate the selected button; do not claim the ARIA tree interaction pattern. A branch receives node, selected (an ID or null), and an onselect: (id: number) => void callback.

Modify the existing client/src/lib/ListingList.svelte and client/src/lib/marketplace/ListingsBrowser.svelte. Connect navigation and browsing through their common ListingList owner. CategoryNavigation receives onselect: (ids: number[] | null) => void; invoke it with the selected node’s descendant IDs, or with null for All categories. ListingsBrowser accepts selectedIds: number[] | null, defaulting to null. Selecting a category displays rows assigned to that category or any descendant. All categories restores the full loaded collection. Retain the underlying collection; filtering must not destroy it. Empty filtered results display No listings match this category., not an API-failure message.

Fetch categories once when navigation mounts. Show Loading categories… in an element with role="status" inside the category navigation while pending. A failed category read shows an alert and Retry categories. Include the HTTP status for an HTTP failure and the thrown Error.message for a network failure. Keep the listing read independently usable. Cancel obsolete category reads. Continue to handle the listing response sequences required by milestone 8.

The sample Electronics parent contains Computers and Adapters. Tests use different categories and deeper trees, so a hardcoded two-level menu is insufficient.

Test and submit

Use the two Compose files and an unused, separate Compose test project name. Replace wsd-marketplace-test in the example commands with that name. During an increment, run the client test command first; it is the focused subsystem suite for this milestone. The complete sequence below is useful at the part acceptance checkpoint; do not repeat an unrelated build after every small edit. Never erase your development database merely to run a test. All shell commands belong to the marketplace repository, not the practice application.

Terminal window
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task test
# Optional local type diagnostics; not graded in this milestone.
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task check
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task build
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm api deno task test
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm e2e-tests
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml down

Run suites sequentially. If you reuse an already-running test API after editing its source, restart it: unlike the development service, it does not watch files. Do not commit real secrets, generated builds, test results, or node_modules. Inspect git diff, stage the specific source, migration and test files you changed, commit, and run git push origin master. The grader uses trusted runtime configuration; submitted Docker or package scripts are not executed as grading code.

Type checking is optional in this milestone and does not affect points. The grader assesses executable tests and application behavior.

Points

  • 25 points: Render and select nested categories with descendant filtering and cancel the category read when navigation is removed.
  • 15 points: Recover a failed category read, keep listing reads independent, distinguish empty filtered results, and restore the loaded collection.

Preserving the previously accepted read paths, counter and todo behavior, migration history, and a buildable client are readiness conditions. These conditions do not re-award points from earlier milestones.

Independently addressable listing details

Part 1 did not include a detail endpoint. Before beginning this milestone, open its exercise handout. The exercise makes two new server modules available through Git as work contributed by someone else. Follow the handout’s instructions to inspect and fast-forward to that contribution before you edit the milestone. The incoming commit does not replace an existing project file. After receiving it, register its router in api/src/app.ts; the rest of the milestone can then concentrate on browser navigation.

A detail read queries its ID independently of the collection cap. The browser page must work after direct navigation or refresh, distinguish a missing record, and cancel obsolete reads. Do not depend on the last card someone clicked.

Marketplace milestone 11: deep links and independent detail reads

0 / 30 points

Receive the contributed server modules

Continue in the local marketplace repository after milestone 10 passes. Before editing milestone 11, make sure git status --short is empty. Then fetch, inspect, and fast-forward your master branch to the contributed server modules:

Terminal window
git fetch origin
git diff --stat HEAD..origin/milestone-11
git diff HEAD..origin/milestone-11 -- \
api/src/marketplace/listing-detail-repository.ts \
api/src/marketplace/listing-detail-routes.ts
git merge --ff-only origin/milestone-11

The branch is based on the remote master present when the contribution is released after milestone 10, and it adds only those two new files. If the fast-forward is refused because you already made a local commit, do not reset or overwrite that work. Verify that the two paths do not exist locally, then replay the new-file commit with git cherry-pick origin/milestone-11.

Register the contributed route

The Part 1 API had no detail route. The contributed files supply an independent detail query and a Hono router without replacing files you have already edited. Register the router in api/src/app.ts by importing listingDetailRoutes from ./marketplace/listing-detail-routes.ts and mounting it with app.route("/api/listings", listingDetailRoutes). Keep all earlier routes and imports. The supplied route reads independently of the 100-row collection cap; invalid IDs return 400 and missing records return 404.

Objective

Create client/src/routes/listings/[id]/+page.svelte and client/src/lib/marketplace/ListingDetail.svelte. Use the current route parameter; key the detail component by it so one route cannot retain another route’s data. ListingDetail takes id: string, validates a positive PostgreSQL integer before requesting it, and cancels the request when removed.

Show Loading listing… in an element with role="status" while loading; show a heading Listing not found for 404; show an alert Could not load listing. with the status/error for other failures. Invalid parameters include Invalid listing ID in the alert. On success, display a heading with the title, the description, labelled seller and category, and the formatted starting price. Include Back to listings, a real link to /.

A direct visit and browser refresh must work without first selecting a card. The browser route is /listings/<id>; the JSON API route is /api/listings/<id>. They are not interchangeable. Use explicit browser fetch, not server actions.

Test and submit

Use the two Compose files and an unused, separate Compose test project name. Replace wsd-marketplace-test in the example commands with that name. During an increment, run the browser test command first when changing the detail flow, or the API test command first when changing route registration. The complete sequence below is useful at the part acceptance checkpoint; do not repeat an unrelated build after every small edit. Never erase your development database merely to run a test. All shell commands belong to the marketplace repository, not the practice application.

Terminal window
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task test
# Optional local type diagnostics; not graded in this milestone.
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task check
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task build
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm api deno task test
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm e2e-tests
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml down

Run suites sequentially. If you reuse an already-running test API after editing its source, restart it: unlike the development service, it does not watch files. Do not commit real secrets, generated builds, test results, or node_modules. Inspect git diff, stage the specific source, migration and test files you changed, commit, and run git push origin master. The grader uses trusted runtime configuration; submitted Docker or package scripts are not executed as grading code.

Type checking is optional in this milestone and does not affect points. The grader assesses executable tests and application behavior.

Points

  • 20 points: Load every required field at a direct address, reload it, and cancel the detail read when returning to the marketplace.
  • 10 points: Distinguish missing records, malformed route parameters, and other HTTP failures.

Preserving the previously accepted read paths, counter and todo behavior, migration history, and a buildable client are readiness conditions. These conditions do not re-award points from earlier milestones.

Regression tests and Part 2 acceptance

Finally, protect category construction, a changing component view and the browser navigation path. Keep Part 1’s relationship tests and original interactions. The final card checks both your evidence and the cumulative read-only marketplace project.

Marketplace milestone 12: Part 2 regression evidence and acceptance

0 / 40 points

Continue the marketplace project

Continue in the local marketplace repository after milestone 11 passes. Run git fetch origin and keep working on master. There is no new marketplace repository. The reference branch contains the preceding milestone, not the solution to this one. Inspect or merge it only when you need to recover a known baseline.

Objective

Keep the existing Part 1 tests. Review and extend the existing client/src/lib/marketplace/categories.test.ts, and create the other two student-owned test files at the exact paths below:

  • client/src/lib/marketplace/categories.test.ts: empty input, parent-last input, several roots and a third level; descendants include the selected node.
  • client/src/lib/marketplace/marketplace-view.test.ts: a card with unfamiliar values and at least one data→failure→retry sequence in a single mounted view.
  • e2e-tests/tests/student_browse.spec.ts: load listings, select Electronics, locate its Computers listing USB-C dock, follow its detail link, verify the seller and description, and reload the detail URL. Add a missing-record case.

Obtain IDs from links or API data; do not assume ID 1. Use role/label locators, scoped relationship assertions and web-first waiting. Public data stays below the current cap. A list filter is not a complete server search system.

The grader first runs your tests against a compatible reference. Only after that baseline passes does it award defect-detection credit. The category tests must fail when descendant collection omits children. The component tests must fail when a card displays the category as its seller. The browser test must fail when selecting a parent wrongly excludes child-category listings. A missing dependency or failed application startup is not a detected defect. Independent checks also test your actual cumulative application.

No public deployment, account, bid form, authentication, or typed HTTP client is required. Those belong to later parts. Keep runtime dependencies unchanged.

Test and submit

Use the two Compose files and an unused, separate Compose test project name. Replace wsd-marketplace-test in the example commands with that name. During an increment, run the two new focused suites first:

Terminal window
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task test src/lib/marketplace/categories.test.ts src/lib/marketplace/marketplace-view.test.ts
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm e2e-tests npx playwright test tests/student_browse.spec.ts

The complete sequence below is useful at the part acceptance checkpoint; do not repeat an unrelated build after every small edit. Never erase your development database merely to run a test. All shell commands belong to the marketplace repository, not the practice application.

Terminal window
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task test
# Optional local type diagnostics; not graded in this milestone.
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task check
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm --no-deps client deno task build
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm api deno task test
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml run --build --rm e2e-tests
docker compose -p wsd-marketplace-test -f compose.yaml -f compose.test.yaml down

Run suites sequentially. If you reuse an already-running test API after editing its source, restart it: unlike the development service, it does not watch files. Do not commit real secrets, generated builds, test results, or node_modules. Inspect git diff, stage the specific source, migration and test files you changed, commit, and run git push origin master. The grader uses trusted runtime configuration; submitted Docker or package scripts are not executed as grading code.

Type checking is optional in this milestone and does not affect points. The grader assesses executable tests and application behavior.

Points

  • 5 points: Returned category, component and browser tests pass the compatible reference.
  • 5 points: Returned category tests reject a descendant helper that omits children.
  • 5 points: Returned component tests reject a card with the wrong seller relationship.
  • 5 points: Returned browser test rejects a parent filter that omits descendants.
  • 20 points: The submitted cumulative application passes independent browsing checks.

Preserving the previously accepted read paths, counter and todo behavior, migration history, and a buildable client are readiness conditions. These conditions do not re-award points from earlier milestones.

No authentication, bid form, typed client or public deployment is required here. Keep the marketplace repository after Part 2 acceptance. In Part 3, you will continue the marketplace project there while preserving its read contract and changing the server implementation.

Check Your Understanding

  1. Why should a card receive its data instead of requesting the same collection itself?
  2. How does an empty filtered view differ from a failed API read?
  3. Why must category construction handle a child appearing before its parent?
  4. Why can a detail page not rely on searching only the first collection page?
  5. Which boundary does each of your category, component and browser tests observe?